From 2e7235d10c6dbff81960282e1a1e2e798f9b8db8 Mon Sep 17 00:00:00 2001 From: guowenxue <guowenxue@gmail.com> Date: Mon, 19 Aug 2019 19:55:15 +0800 Subject: [PATCH] Add mt7601u-sta and rtl8188eus driver in drivers --- linux-bsp/drivers/rtl8188eus/hal/rtl8188e/usb/rtl8188eu_xmit.c | 1297 linux-bsp/drivers/rtl8188eus/include/rtw_br_ext.h | 74 linux-bsp/drivers/rtl8188eus/include/Hal8814PhyCfg.h | 269 linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_USB.c | 100 linux-bsp/drivers/rtl8188eus/include/rtw_cmd.h | 1320 linux-bsp/drivers/rtl8188eus/os_dep/linux/rtw_proc.h | 65 linux-bsp/drivers/rtl8188eus/core/rtw_ap.c | 4171 linux-bsp/drivers/rtl8188eus/os_dep/linux/rtw_proc.c | 3216 linux-bsp/drivers/rtl8188eus/include/drv_types_ce.h | 91 linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_USB.h | 39 linux-bsp/drivers/rtl8188eus/include/rtw_p2p.h | 176 linux-bsp/drivers/mt7601u-sta/usb.c | 362 linux-bsp/drivers/mt7601u-sta/tx.c | 322 linux-bsp/drivers/rtl8188eus/include/hal_ic_cfg.h | 205 linux-bsp/drivers/rtl8188eus/core/rtw_btcoex.c | 1717 linux-bsp/drivers/rtl8188eus/hal/hal_halmac.c | 2635 linux-bsp/drivers/rtl8188eus/include/rtw_ioctl_set.h | 75 linux-bsp/drivers/rtl8188eus/core/rtw_btcoex_wifionly.c | 42 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_HWConfig.c | 2363 linux-bsp/drivers/rtl8188eus/include/rtl8821a_xmit.h | 178 linux-bsp/drivers/mt7601u-sta/usb.h | 79 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_HWConfig.h | 237 linux-bsp/drivers/rtl8188eus/include/rtl8192c_spec.h | 143 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.h | 141 linux-bsp/drivers/rtl8188eus/hal/hal_btcoex.c | 4474 linux-bsp/drivers/rtl8188eus/include/rtw_tdls.h | 173 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a2Ant.h | 180 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_xmit.c | 306 linux-bsp/drivers/rtl8188eus/include/sta_info.h | 671 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.c | 3299 linux-bsp/drivers/rtl8188eus/hal/hal_btcoex_wifionly.c | 156 linux-bsp/drivers/rtl8188eus/include/rtl8188e_hal.h | 320 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_reg.h | 214 linux-bsp/drivers/rtl8188eus/hal/phydm/mp_precomp.h | 19 linux-bsp/drivers/rtl8188eus/include/rtl8192c_hal.h | 415 linux-bsp/drivers/rtl8188eus/include/Hal8723BPhyCfg.h | 137 linux-bsp/drivers/rtl8188eus/include/linux/wireless.h | 92 linux-bsp/drivers/rtl8188eus/include/rtl8192e_recv.h | 173 linux-bsp/drivers/rtl8188eus/include/ip.h | 140 linux-bsp/drivers/rtl8188eus/core/rtw_iol.c | 387 linux-bsp/drivers/rtl8188eus/include/rtl8723a_xmit.h | 237 linux-bsp/drivers/rtl8188eus/include/rtl8814a_rf.h | 33 linux-bsp/drivers/rtl8188eus/os_dep/linux/os_intfs.c | 4489 linux-bsp/drivers/rtl8188eus/core/efuse/rtw_efuse.c | 2949 linux-bsp/drivers/rtl8188eus/include/rtl8192d_cmd.h | 97 linux-bsp/drivers/rtl8188eus/include/rtw_mlme_ext.h | 1290 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/usb/rtl8188eu_recv.c | 33 linux-bsp/drivers/rtl8188eus/include/rtl8192d_led.h | 38 linux-bsp/drivers/rtl8188eus/include/rtw_version.h | 1 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a2Ant.c | 4222 linux-bsp/drivers/rtl8188eus/platform/platform_ARM_SUN50IW1P1_sdio.c | 91 linux-bsp/drivers/rtl8188eus/platform/platform_ops.h | 31 linux-bsp/drivers/rtl8188eus/include/rtw_android.h | 115 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_regdefine11ac.h | 93 linux-bsp/drivers/rtl8188eus/platform/platform_ops.c | 37 linux-bsp/drivers/rtl8188eus/include/hal_com_h2c.h | 551 linux-bsp/drivers/rtl8188eus/include/rtl8188f_xmit.h | 338 linux-bsp/drivers/rtl8188eus/include/rtl8723b_dm.h | 47 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbf8814a.h | 89 linux-bsp/drivers/rtl8188eus/include/rtw_ioctl_rtl.h | 80 linux-bsp/drivers/rtl8188eus/include/rtl8812a_dm.h | 32 linux-bsp/drivers/rtl8188eus/include/rtl8192e_xmit.h | 451 linux-bsp/drivers/rtl8188eus/include/circ_buf.h | 28 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/PhyDM_Adaptivity.h | 157 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/PhyDM_Adaptivity.c | 873 linux-bsp/drivers/rtl8188eus/include/if_ether.h | 111 linux-bsp/drivers/rtl8188eus/include/rtl8723a_led.h | 45 linux-bsp/drivers/rtl8188eus/include/rtl8723a_sreset.h | 30 linux-bsp/drivers/rtl8188eus/core/rtw_sdio.c | 98 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RTL8188E.c | 459 linux-bsp/drivers/rtl8188eus/include/rtl8723a_recv.h | 41 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RTL8188E.h | 64 linux-bsp/drivers/rtl8188eus/core/rtw_bt_mp.c | 1580 linux-bsp/drivers/rtl8188eus/include/osdep_service_linux.h | 476 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/hal8188e_s_fw.h | 45 linux-bsp/drivers/rtl8188eus/include/rtw_io.h | 576 linux-bsp/drivers/rtl8188eus/include/Hal8192DPhyCfg.h | 293 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/hal8188e_s_fw.c | 7303 linux-bsp/drivers/rtl8188eus/include/rtl8814a_xmit.h | 310 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_sreset.c | 121 linux-bsp/drivers/mt7601u-sta/regs.h | 639 linux-bsp/drivers/rtl8188eus/include/hal_com_reg.h | 1823 linux-bsp/drivers/rtl8188eus/hal/phydm/halhwimg.h | 123 linux-bsp/drivers/rtl8188eus/include/rtl8703b_led.h | 48 linux-bsp/drivers/rtl8188eus/include/rtl8822b_hal.h | 218 linux-bsp/drivers/rtl8188eus/include/rtw_event.h | 135 linux-bsp/drivers/rtl8188eus/include/Hal8703BPhyCfg.h | 137 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a2ant.c | 5624 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a2ant.h | 227 linux-bsp/drivers/rtl8188eus/include/rtl8812a_hal.h | 361 linux-bsp/drivers/mt7601u-sta/trace.c | 21 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_mac.c | 288 linux-bsp/drivers/mt7601u-sta/README.md | 64 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_mac.h | 38 linux-bsp/drivers/rtl8188eus/include/rtl8821c_dm.h | 30 linux-bsp/drivers/rtl8188eus/LICENSE | 12 linux-bsp/drivers/rtl8188eus/include/osdep_service.h | 703 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.c | 1404 linux-bsp/drivers/rtl8188eus/core/rtw_odm.c | 446 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_iqk.h | 65 linux-bsp/drivers/rtl8188eus/include/mlme_osdep.h | 36 linux-bsp/drivers/mt7601u-sta/trace.h | 400 linux-bsp/drivers/rtl8188eus/core/rtw_recv.c | 4724 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/Hal8188EPwrSeq.c | 87 linux-bsp/drivers/rtl8188eus/include/pci_ops.h | 96 linux-bsp/drivers/rtl8188eus/include/usb_hal.h | 67 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8703b1ant.h | 404 linux-bsp/drivers/rtl8188eus/include/rtl8703b_rf.h | 30 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8703b1ant.c | 4293 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/phydm_hal_txbf_api.h | 69 linux-bsp/drivers/rtl8188eus/include/rtl8188f_recv.h | 73 linux-bsp/drivers/rtl8188eus/include/rtl8822bu_hal.h | 63 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b2ant.c | 5543 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b2ant.h | 493 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.h | 83 linux-bsp/drivers/rtl8188eus/include/rtl8192e_rf.h | 33 linux-bsp/drivers/rtl8188eus/include/Hal8723BPhyReg.h | 1136 linux-bsp/drivers/rtl8188eus/include/rtl8188f_rf.h | 30 linux-bsp/drivers/rtl8188eus/os_dep/linux/wifi_regd.c | 549 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.h | 96 linux-bsp/drivers/rtl8188eus/os_dep/linux/rtw_cfgvendor.h | 245 linux-bsp/drivers/rtl8188eus/include/rtl8188f_led.h | 48 linux-bsp/drivers/rtl8188eus/include/rtl8723a_dm.h | 46 linux-bsp/drivers/rtl8188eus/include/rtw_odm.h | 55 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/phydm_hal_txbf_api.c | 179 linux-bsp/drivers/rtl8188eus/os_dep/linux/rtw_cfgvendor.c | 1328 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.c | 234 linux-bsp/drivers/rtl8188eus/include/rtl8814a_sreset.h | 29 linux-bsp/drivers/rtl8188eus/include/Hal8703BPwrSeq.h | 184 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_rxdesc.c | 94 linux-bsp/drivers/rtl8188eus/include/rtl8188f_sreset.h | 29 linux-bsp/drivers/rtl8188eus/include/rtl8812a_led.h | 41 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a1Ant.h | 201 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_rf.c | 2370 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/version_rtl8188e.h | 10 linux-bsp/drivers/rtl8188eus/include/Hal8814PhyReg.h | 866 linux-bsp/drivers/mt7601u-sta/mt7601u.h | 396 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_rf.h | 128 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_phycfg.c | 2021 linux-bsp/drivers/rtl8188eus/include/Hal8188FPhyReg.h | 1170 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.c | 1250 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_antdect.c | 864 linux-bsp/drivers/rtl8188eus/include/rtl8723d_rf.h | 26 linux-bsp/drivers/rtl8188eus/include/rtw_sreset.h | 60 linux-bsp/drivers/rtl8188eus/include/rtw_wifi_regd.h | 25 linux-bsp/drivers/rtl8188eus/core/rtw_sreset.c | 346 linux-bsp/drivers/rtl8188eus/include/osdep_service_xp.h | 202 linux-bsp/drivers/rtl8188eus/include/rtl8188e_rf.h | 32 linux-bsp/drivers/rtl8188eus/include/rtl8822bs_hal.h | 32 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188EReg.h | 54 linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_query.c | 171 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.h | 108 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_antdect.h | 95 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_interface.h | 416 linux-bsp/drivers/rtl8188eus/include/gspi_ops_linux.h | 23 linux-bsp/drivers/rtl8188eus/include/drv_types.h | 1593 linux-bsp/drivers/rtl8188eus/hal/hal_dm.h | 25 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a1ant.h | 230 linux-bsp/drivers/rtl8188eus/hal/hal_dm.c | 224 linux-bsp/drivers/rtl8188eus/include/rtl8723b_sreset.h | 29 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a1ant.c | 3461 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_interface.c | 1005 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/usb/usb_ops_linux.c | 293 linux-bsp/drivers/rtl8188eus/include/Hal8188EPhyReg.h | 1105 linux-bsp/drivers/rtl8188eus/include/rtl8812a_rf.h | 33 linux-bsp/drivers/rtl8188eus/hal/efuse/efuse_mask.h | 106 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dfs.c | 257 linux-bsp/drivers/rtl8188eus/include/usb_osintf.h | 31 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a1Ant.h | 210 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dfs.h | 75 linux-bsp/drivers/rtl8188eus/include/rtw_mp_ioctl.h | 575 linux-bsp/drivers/rtl8188eus/include/rtl8192e_hal.h | 332 linux-bsp/drivers/rtl8188eus/include/Hal8723DPwrSeq.h | 193 linux-bsp/drivers/rtl8188eus/include/rtl8703b_xmit.h | 338 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a1Ant.c | 3223 linux-bsp/drivers/rtl8188eus/include/byteorder/generic.h | 212 linux-bsp/drivers/rtl8188eus/include/sdio_hal.h | 54 linux-bsp/drivers/rtl8188eus/os_dep/linux/recv_linux.c | 885 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dig.c | 2142 linux-bsp/drivers/rtl8188eus/include/ieee80211.h | 1935 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821cwifionly.c | 186 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723bwifionly.h | 8 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821cwifionly.h | 70 linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_SDIO.h | 39 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c1ant.h | 473 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/phydm_rtl8188e.c | 388 linux-bsp/drivers/rtl8188eus/include/hal_btcoex_wifionly.h | 47 linux-bsp/drivers/rtl8188eus/include/rtl8192c_event.h | 28 linux-bsp/drivers/rtl8188eus/include/rtw_mlme.h | 1205 linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_SDIO.c | 101 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c1ant.c | 6674 linux-bsp/drivers/rtl8188eus/include/rtw_sdio.h | 30 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a1Ant.c | 2973 linux-bsp/drivers/mt7601u-sta/eeprom.c | 418 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/phydm_rtl8188e.h | 78 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_reg.h | 122 linux-bsp/drivers/rtl8188eus/core/rtw_debug.c | 5215 linux-bsp/drivers/mt7601u-sta/eeprom.h | 151 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e2ant.h | 211 linux-bsp/drivers/rtl8188eus/hal/hal_mcc.c | 1877 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_cmd.c | 825 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e2ant.c | 4377 linux-bsp/drivers/rtl8188eus/include/rtl8188e_sreset.h | 29 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/HalPhyRf.h | 89 linux-bsp/drivers/rtl8188eus/include/rtw_mp.h | 946 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/HalPhyRf.c | 530 linux-bsp/drivers/rtl8188eus/include/Hal8192CPhyCfg.h | 241 linux-bsp/drivers/rtl8188eus/include/rtl8821ce_hal.h | 28 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbfinterface.c | 1502 linux-bsp/drivers/rtl8188eus/include/rtw_mem.h | 41 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbfinterface.h | 165 linux-bsp/drivers/rtl8188eus/os_dep/linux/ioctl_mp.c | 2412 linux-bsp/drivers/rtl8188eus/include/cmd_osdep.h | 31 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_noisemonitor.h | 47 linux-bsp/drivers/rtl8188eus/include/gspi_ops.h | 185 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_debug.h | 898 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_noisemonitor.c | 292 linux-bsp/drivers/rtl8188eus/core/rtw_security.c | 3197 linux-bsp/drivers/rtl8188eus/hal/led/hal_usb_led.c | 4287 linux-bsp/drivers/rtl8188eus/include/gspi_hal.h | 35 linux-bsp/drivers/rtl8188eus/include/mp_custom_oid.h | 353 linux-bsp/drivers/rtl8188eus/os_dep/linux/ioctl_cfg80211.h | 323 linux-bsp/drivers/rtl8188eus/include/rtl8188e_xmit.h | 300 linux-bsp/drivers/rtl8188eus/include/rtl8703b_hal.h | 277 linux-bsp/drivers/rtl8188eus/include/rtw_btcoex.h | 444 linux-bsp/drivers/rtl8188eus/os_dep/linux/ioctl_cfg80211.c | 7281 linux-bsp/drivers/rtl8188eus/core/rtw_io.c | 701 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_debug.c | 629 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723bwifionly.c | 68 linux-bsp/drivers/rtl8188eus/core/rtw_mlme_ext.c | 15724 + linux-bsp/drivers/rtl8188eus/core/rtw_p2p.c | 5310 linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ce.h | 117 linux-bsp/drivers/rtl8188eus/include/rtl8192c_cmd.h | 99 linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ce.c | 799 linux-bsp/drivers/rtl8188eus/include/Hal8192DPhyReg.h | 1167 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dig.h | 368 linux-bsp/drivers/rtl8188eus/include/rtl8821a_spec.h | 96 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_hal_init.c | 4867 linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_set.c | 1254 linux-bsp/drivers/mt7601u-sta/util.h | 77 linux-bsp/drivers/mt7601u-sta/util.c | 42 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/usb/rtl8188eu_led.c | 160 linux-bsp/drivers/rtl8188eus/core/rtw_wlan_util.c | 4656 linux-bsp/drivers/rtl8188eus/include/gspi_osintf.h | 30 linux-bsp/drivers/rtl8188eus/include/rtl8192d_recv.h | 103 linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_rtl.c | 904 linux-bsp/drivers/rtl8188eus/include/sdio_ops_linux.h | 53 linux-bsp/drivers/mt7601u-sta/dma.h | 127 linux-bsp/drivers/rtl8188eus/include/sdio_osintf.h | 30 linux-bsp/drivers/rtl8188eus/include/pci_hal.h | 53 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dynamicbbpowersaving.h | 57 linux-bsp/drivers/mt7601u-sta/dma.c | 529 linux-bsp/drivers/rtl8188eus/core/rtw_vht.c | 803 linux-bsp/drivers/rtl8188eus/include/h2clbk.h | 31 linux-bsp/drivers/rtl8188eus/include/drv_types_gspi.h | 54 linux-bsp/drivers/rtl8188eus/include/rtl8723b_rf.h | 30 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/hal8188ereg.h | 64 linux-bsp/drivers/rtl8188eus/include/rtw_efuse.h | 245 linux-bsp/drivers/rtl8188eus/include/usb_ops.h | 133 linux-bsp/drivers/rtl8188eus/include/rtl8192d_hal.h | 409 linux-bsp/drivers/rtl8188eus/platform/platform_arm_act_sdio.c | 58 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e2Ant.c | 4398 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b1Ant.h | 211 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_s_fw.c | 3647 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e2Ant.h | 201 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b1Ant.c | 3669 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_s_fw.h | 61 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dynamicbbpowersaving.c | 111 linux-bsp/drivers/rtl8188eus/hal/hal_mp.c | 2212 linux-bsp/drivers/rtl8188eus/include/rtl8812a_sreset.h | 29 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbf8814a.c | 700 linux-bsp/drivers/rtl8188eus/include/HalPwrSeqCmd.h | 135 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_pre_define.h | 677 linux-bsp/drivers/rtl8188eus/include/byteorder/swab.h | 141 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_AntDiv.h | 136 linux-bsp/drivers/rtl8188eus/include/rtl8723d_sreset.h | 29 linux-bsp/drivers/rtl8188eus/platform/platform_ARM_WMT_sdio.c | 51 linux-bsp/drivers/rtl8188eus/include/hal_sdio.h | 36 linux-bsp/drivers/rtl8188eus/include/rtl8812a_cmd.h | 171 linux-bsp/drivers/rtl8188eus/os_dep/linux/usb_ops_linux.c | 1105 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_AntDiv.c | 2269 linux-bsp/drivers/rtl8188eus/include/rtl8188f_dm.h | 47 linux-bsp/drivers/rtl8188eus/include/nic_spec.h | 46 linux-bsp/drivers/rtl8188eus/include/Hal8192CPhyReg.h | 1132 linux-bsp/drivers/rtl8188eus/include/rtw_ap.h | 88 linux-bsp/drivers/rtl8188eus/include/hal_com_phycfg.h | 348 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_debug.c | 3061 linux-bsp/drivers/rtl8188eus/include/hal_pg.h | 801 linux-bsp/drivers/rtl8188eus/include/rtw_ioctl.h | 323 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_debug.h | 359 linux-bsp/drivers/rtl8188eus/include/rtl8723d_lps_poff.h | 61 linux-bsp/drivers/rtl8188eus/include/Hal8814PwrSeq.h | 236 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192d2Ant.h | 165 linux-bsp/drivers/rtl8188eus/hal/HalPwrSeqCmd.c | 161 linux-bsp/drivers/rtl8188eus/platform/custom_country_chplan.h | 28 linux-bsp/drivers/rtl8188eus/include/rtl8723b_spec.h | 284 linux-bsp/drivers/mt7601u-sta/initvals_phy.h | 291 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_bb.h | 58 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192d2Ant.c | 2058 linux-bsp/drivers/rtl8188eus/include/rtw_vht.h | 144 linux-bsp/drivers/rtl8188eus/include/rtl8192c_sreset.h | 30 linux-bsp/drivers/rtl8188eus/include/rtl8703b_dm.h | 47 linux-bsp/drivers/rtl8188eus/include/drv_types_linux.h | 24 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtcOutSrc.h | 681 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_precomp.h | 307 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_bb.c | 1764 linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_PCIE.h | 39 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d1ant.h | 413 linux-bsp/drivers/rtl8188eus/include/rtl8192c_rf.h | 45 linux-bsp/drivers/rtl8188eus/README.md | 61 linux-bsp/drivers/rtl8188eus/include/sdio_ops_xp.h | 54 linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_PCIE.c | 101 linux-bsp/drivers/rtl8188eus/hal/hal_halmac.h | 121 linux-bsp/drivers/mt7601u-sta/Makefile | 10 linux-bsp/drivers/rtl8188eus/include/rtl8703b_cmd.h | 218 linux-bsp/drivers/rtl8188eus/include/rtl8192c_xmit.h | 166 linux-bsp/drivers/rtl8188eus/include/rtl8723d_led.h | 48 linux-bsp/drivers/rtl8188eus/include/hal_com.h | 685 linux-bsp/drivers/rtl8188eus/include/sdio_ops.h | 161 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d1ant.c | 6225 linux-bsp/drivers/rtl8188eus/include/rtw_eeprom.h | 121 linux-bsp/drivers/rtl8188eus/include/usb_vendor_req.h | 61 linux-bsp/drivers/mt7601u-sta/initvals.h | 164 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halphyrf_8188e_ap.c | 2996 linux-bsp/drivers/rtl8188eus/include/Hal8703BPhyReg.h | 1138 linux-bsp/drivers/rtl8188eus/include/Hal8723APhyReg.h | 74 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halphyrf_8188e_ap.h | 135 linux-bsp/drivers/rtl8188eus/include/rtl8723d_xmit.h | 522 linux-bsp/drivers/rtl8188eus/include/basic_types.h | 384 linux-bsp/drivers/rtl8188eus/include/ieee80211_ext.h | 476 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c2ant.c | 6936 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halphyrf_8188e_ce.c | 3150 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c2ant.h | 478 linux-bsp/drivers/rtl8188eus/include/rtl8814a_spec.h | 643 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.h | 47 linux-bsp/drivers/rtl8188eus/include/rtl8812a_xmit.h | 371 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a1Ant.c | 1598 linux-bsp/drivers/rtl8188eus/include/drv_conf.h | 313 linux-bsp/drivers/rtl8188eus/include/rtl8723b_led.h | 48 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a2Ant.c | 4826 linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ap.h | 178 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dynamic_rx_path.c | 357 linux-bsp/drivers/rtl8188eus/include/rtl8821cs_hal.h | 28 linux-bsp/drivers/rtl8188eus/include/Hal8192EPhyReg.h | 1132 linux-bsp/drivers/rtl8188eus/include/Hal8812PhyReg.h | 738 linux-bsp/drivers/rtl8188eus/include/rtl8192e_spec.h | 317 linux-bsp/drivers/rtl8188eus/core/rtw_mp_ioctl.c | 2534 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/halcomtxbf.c | 538 linux-bsp/drivers/rtl8188eus/include/rtw_pwrctrl.h | 559 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a2Ant.h | 213 linux-bsp/drivers/rtl8188eus/hal/hal_com_phycfg.c | 5452 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/halcomtxbf.h | 179 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_dm.c | 434 linux-bsp/drivers/rtl8188eus/include/rtl8192e_cmd.h | 161 linux-bsp/drivers/mt7601u-sta/init.c | 639 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b1ant.h | 293 linux-bsp/drivers/rtl8188eus/include/rtl8192e_led.h | 40 linux-bsp/drivers/mt7601u-sta/main.c | 432 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b1ant.c | 5113 linux-bsp/drivers/rtl8188eus/include/rtl8192c_recv.h | 106 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b1ant.c | 6840 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/hal8188erateadaptive.h | 110 linux-bsp/drivers/rtl8188eus/include/rtl8812a_recv.h | 158 linux-bsp/drivers/rtl8188eus/core/rtw_mi.c | 1286 linux-bsp/drivers/rtl8188eus/include/wifi.h | 1399 linux-bsp/drivers/rtl8188eus/include/rtl8723a_spec.h | 103 linux-bsp/drivers/rtl8188eus/include/rtw_wapi.h | 214 linux-bsp/drivers/rtl8188eus/include/Hal8812PwrSeq.h | 209 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b1ant.h | 433 linux-bsp/drivers/rtl8188eus/include/rtw_byteorder.h | 38 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_rainfo.h | 585 linux-bsp/drivers/rtl8188eus/os_dep/osdep_service.c | 2769 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_edcaturbocheck.h | 102 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_rainfo.c | 3429 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_edcaturbocheck.c | 698 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/hal8188erateadaptive.c | 1417 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_rf6052.c | 325 linux-bsp/drivers/rtl8188eus/include/hal_phy.h | 243 linux-bsp/drivers/rtl8188eus/include/rtl8188e_spec.h | 152 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dynamic_rx_path.h | 137 linux-bsp/drivers/rtl8188eus/core/rtw_mem.c | 114 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_acs.h | 105 linux-bsp/drivers/rtl8188eus/include/ethernet.h | 41 linux-bsp/drivers/rtl8188eus/include/Hal8188EPhyCfg.h | 265 linux-bsp/drivers/rtl8188eus/include/rtl8723b_cmd.h | 218 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a1Ant.h | 171 linux-bsp/drivers/rtl8188eus/platform/platform_sprd_sdio.c | 89 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.c | 608 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a1ant.h | 214 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_acs.c | 1154 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halphyrf_8188e_ce.h | 142 linux-bsp/drivers/rtl8188eus/include/rtl8192d_dm.h | 50 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a1ant.c | 3289 linux-bsp/drivers/rtl8188eus/include/xmit_osdep.h | 99 linux-bsp/drivers/rtl8188eus/Kconfig | 6 linux-bsp/drivers/rtl8188eus/include/rtl8188f_hal.h | 271 linux-bsp/drivers/rtl8188eus/include/usb_ops_linux.h | 103 linux-bsp/drivers/rtl8188eus/include/rtw_rf.h | 293 linux-bsp/drivers/rtl8188eus/include/Hal8812PhyCfg.h | 148 linux-bsp/drivers/rtl8188eus/include/rtw_bt_mp.h | 293 linux-bsp/drivers/rtl8188eus/include/custom_gpio.h | 32 linux-bsp/drivers/rtl8188eus/include/rtl8703b_sreset.h | 29 linux-bsp/drivers/rtl8188eus/include/rtl8814a_hal.h | 324 linux-bsp/drivers/rtl8188eus/include/rtl8703b_spec.h | 468 linux-bsp/drivers/rtl8188eus/include/rtl8723d_cmd.h | 211 linux-bsp/drivers/mt7601u-sta/mac.h | 178 linux-bsp/drivers/rtl8188eus/include/drv_types_sdio.h | 91 linux-bsp/drivers/rtl8188eus/core/rtw_wapi_sms4.c | 908 linux-bsp/drivers/rtl8188eus/include/Hal8723DPhyCfg.h | 136 linux-bsp/drivers/mt7601u-sta/mac.c | 581 linux-bsp/drivers/rtl8188eus/include/rtl8814a_cmd.h | 170 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_cfotracking.h | 69 linux-bsp/drivers/rtl8188eus/include/rtl8192d_xmit.h | 184 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_types.h | 282 linux-bsp/drivers/rtl8188eus/include/hal_btcoex.h | 93 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_cfotracking.c | 360 linux-bsp/drivers/rtl8188eus/os_dep/linux/mlme_linux.c | 604 linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_win.c | 784 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_powertracking_win.c | 776 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_powertracking_win.h | 299 linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_win.h | 119 linux-bsp/drivers/rtl8188eus/include/pci_osintf.h | 43 linux-bsp/drivers/rtl8188eus/platform/platform_ARM_SUNxI_usb.c | 141 linux-bsp/drivers/rtl8188eus/include/rtl8192c_dm.h | 104 linux-bsp/drivers/mt7601u-sta/core.c | 78 linux-bsp/drivers/rtl8188eus/include/rtw_ioctl_query.h | 30 linux-bsp/drivers/rtl8188eus/include/hal_intf.h | 775 linux-bsp/drivers/rtl8188eus/hal/hal_hci/hal_usb.c | 529 linux-bsp/drivers/rtl8188eus/include/rtw_beamforming.h | 390 linux-bsp/drivers/rtl8188eus/include/rtw_qos.h | 34 linux-bsp/drivers/rtl8188eus/hal/hal_phy.c | 260 linux-bsp/drivers/rtl8188eus/include/rtw_xmit.h | 991 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm.h | 2409 linux-bsp/drivers/rtl8188eus/platform/platform_RTK_DMP_usb.c | 35 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm.c | 14017 + linux-bsp/drivers/rtl8188eus/include/rtl8188e_led.h | 40 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbfjaguar.c | 526 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbfjaguar.h | 74 linux-bsp/drivers/rtl8188eus/core/rtw_ieee80211.c | 2736 linux-bsp/drivers/mt7601u-sta/mcu.c | 536 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbf8822b.c | 1099 linux-bsp/drivers/rtl8188eus/include/rtl8192e_sreset.h | 29 linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ap.c | 2665 linux-bsp/drivers/mt7601u-sta/mcu.h | 94 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbf8822b.h | 79 linux-bsp/drivers/rtl8188eus/include/Hal8723APhyCfg.h | 39 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8188c2Ant.h | 144 linux-bsp/drivers/rtl8188eus/include/rtl8723a_pg.h | 24 linux-bsp/drivers/rtl8188eus/include/sdio_ops_ce.h | 54 linux-bsp/drivers/rtl8188eus/include/byteorder/little_endian.h | 89 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8188c2Ant.c | 2053 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/phydm_regconfig8188e.h | 95 linux-bsp/drivers/rtl8188eus/include/rtw_debug.h | 650 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/hal8188e_t_fw.c | 7749 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_features.h | 189 linux-bsp/drivers/rtl8188eus/include/Hal8723DPhyReg.h | 1139 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/hal8188e_t_fw.h | 43 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/phydm_regconfig8188e.c | 219 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a2Ant.h | 179 linux-bsp/drivers/rtl8188eus/include/drv_types_xp.h | 93 linux-bsp/drivers/rtl8188eus/hal/btc/halbtcoutsrc.h | 1003 linux-bsp/drivers/rtl8188eus/include/rtw_mcc.h | 220 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822bwifionly.h | 22 linux-bsp/drivers/rtl8188eus/hal/hal_com_c2h.h | 119 linux-bsp/drivers/rtl8188eus/platform/platform_ARM_SUNnI_sdio.c | 135 linux-bsp/drivers/rtl8188eus/include/hal_data.h | 1050 linux-bsp/drivers/rtl8188eus/include/byteorder/big_endian.h | 87 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_RegDefine11N.h | 187 linux-bsp/drivers/rtl8188eus/include/osdep_intf.h | 171 linux-bsp/drivers/rtl8188eus/core/rtw_beamforming.c | 3157 linux-bsp/drivers/rtl8188eus/include/rtl8822be_hal.h | 30 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dynamictxpower.h | 110 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_precomp.h | 351 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbf8192e.c | 391 linux-bsp/drivers/rtl8188eus/include/rtl8814a_dm.h | 28 linux-bsp/drivers/rtl8188eus/include/rtl8723d_recv.h | 120 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_types.h | 292 linux-bsp/drivers/rtl8188eus/hal/phydm/txbf/haltxbf8192e.h | 60 linux-bsp/drivers/rtl8188eus/include/rtl8723b_recv.h | 91 linux-bsp/drivers/rtl8188eus/include/rtl8723d_spec.h | 445 linux-bsp/drivers/rtl8188eus/include/rtl8821cu_hal.h | 29 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_dynamictxpower.c | 535 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_kfree.h | 45 linux-bsp/drivers/rtl8188eus/include/Hal8188EPwrSeq.h | 175 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_hwconfig.h | 574 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_kfree.c | 190 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a2Ant.c | 3780 linux-bsp/drivers/rtl8188eus/Makefile | 1957 linux-bsp/drivers/rtl8188eus/core/rtw_br_ext.c | 1585 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_ccx.c | 392 linux-bsp/drivers/rtl8188eus/include/rtl8723b_xmit.h | 338 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_ccx.h | 102 linux-bsp/drivers/rtl8188eus/include/Hal8821APwrSeq.h | 186 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halphyrf_8188e_win.c | 3189 linux-bsp/drivers/rtl8188eus/include/osdep_service_bsd.h | 749 linux-bsp/drivers/rtl8188eus/os_dep/linux/rtw_android.c | 1278 linux-bsp/drivers/mt7601u-sta/debugfs.c | 172 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halphyrf_8188e_win.h | 143 linux-bsp/drivers/rtl8188eus/os_dep/linux/custom_gpio_linux.c | 346 linux-bsp/drivers/rtl8188eus/core/rtw_pwrctrl.c | 2528 linux-bsp/drivers/rtl8188eus/include/rtl8814a_led.h | 40 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_regdefine11n.h | 212 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_powertracking_ce.h | 334 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_powertracking_ce.c | 745 linux-bsp/drivers/rtl8188eus/include/rtl8192d_spec.h | 115 linux-bsp/drivers/rtl8188eus/include/rtw_mi.h | 240 linux-bsp/drivers/mt7601u-sta/phy.c | 1251 linux-bsp/drivers/rtl8188eus/include/HalVerDef.h | 199 linux-bsp/drivers/rtl8188eus/include/rtl8188e_recv.h | 166 linux-bsp/drivers/rtl8188eus/include/rtl8192c_led.h | 37 linux-bsp/drivers/rtl8188eus/include/rtw_btcoex_wifionly.h | 27 linux-bsp/drivers/rtl8188eus/hal/hal_intf.c | 1416 linux-bsp/drivers/rtl8188eus/include/rtl8703b_recv.h | 91 linux-bsp/drivers/rtl8188eus/include/rtl8723a_cmd.h | 215 linux-bsp/drivers/rtl8188eus/include/rtl8812a_spec.h | 264 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.h | 74 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_t_fw.h | 72 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/Mp_Precomp.h | 56 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d2ant.c | 6774 linux-bsp/drivers/rtl8188eus/include/Hal8723PwrSeq.h | 169 linux-bsp/drivers/rtl8188eus/include/Hal8192EPhyCfg.h | 153 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d2ant.h | 418 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_adaptivity.c | 1130 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_RegDefine11AC.h | 81 linux-bsp/drivers/rtl8188eus/include/rtl8192d_rf.h | 50 linux-bsp/drivers/rtl8188eus/hal/btc/mp_precomp.h | 90 linux-bsp/drivers/rtl8188eus/include/rtl8192e_dm.h | 33 linux-bsp/drivers/rtl8188eus/include/Hal8723BPwrSeq.h | 232 linux-bsp/drivers/rtl8188eus/platform/platform_ARM_SUNxI_sdio.c | 95 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_adaptivity.h | 219 linux-bsp/drivers/rtl8188eus/hal/phydm/rtl8188e/halhwimg8188e_t_fw.c | 3901 linux-bsp/drivers/rtl8188eus/include/Hal8188FPhyCfg.h | 139 linux-bsp/drivers/rtl8188eus/include/hal_com_led.h | 396 linux-bsp/drivers/mt7601u-sta/Kbuild | 10 linux-bsp/drivers/rtl8188eus/core/rtw_mp.c | 3569 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm.h | 1336 linux-bsp/drivers/rtl8188eus/os_dep/linux/ioctl_linux.c | 13390 + linux-bsp/drivers/rtl8188eus/hal/hal_com.c | 11422 + linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_powertracking_ap.h | 351 linux-bsp/drivers/rtl8188eus/include/rtw_iol.h | 136 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/usb/usb_halinit.c | 2610 linux-bsp/drivers/rtl8188eus/hal/phydm/rtchnlplan.c | 475 linux-bsp/drivers/rtl8188eus/include/rtw_security.h | 494 linux-bsp/drivers/rtl8188eus/include/rtw_mp_phy_regdef.h | 1099 linux-bsp/drivers/rtl8188eus/include/byteorder/swabb.h | 156 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_adc_sampling.h | 147 linux-bsp/drivers/rtl8188eus/include/autoconf.h | 361 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e1Ant.h | 209 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.c | 1652 linux-bsp/drivers/rtl8188eus/include/rtl8723d_hal.h | 316 linux-bsp/drivers/rtl8188eus/include/rtl8723a_hal.h | 467 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_adc_sampling.c | 764 linux-bsp/drivers/rtl8188eus/core/rtw_sta_mgt.c | 1187 linux-bsp/drivers/rtl8188eus/include/hal_gspi.h | 31 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e1Ant.c | 3281 linux-bsp/drivers/rtl8188eus/hal/phydm/rtchnlplan.h | 682 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_hwconfig.c | 3628 linux-bsp/drivers/rtl8188eus/core/rtw_wapi.c | 1240 linux-bsp/drivers/rtl8188eus/include/Hal8192EPwrSeq.h | 155 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.c | 5010 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_beamforming.h | 374 linux-bsp/drivers/rtl8188eus/include/rtl8814a_recv.h | 191 linux-bsp/drivers/rtl8188eus/os_dep/linux/usb_intf.c | 1647 linux-bsp/drivers/rtl8188eus/include/rtw_ht.h | 219 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b2ant.c | 4958 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a2ant.h | 211 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_powertracking_ap.c | 1205 linux-bsp/drivers/rtl8188eus/include/rtl8723b_hal.h | 283 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b2Ant.c | 4155 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b2ant.h | 217 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.h | 83 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_beamforming.c | 1880 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a2ant.c | 4637 linux-bsp/drivers/rtl8188eus/include/drv_types_pci.h | 271 linux-bsp/drivers/rtl8188eus/include/ioctl_cfg80211.h | 179 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_pathdiv.c | 696 linux-bsp/drivers/rtl8188eus/core/rtw_cmd.c | 4803 linux-bsp/drivers/rtl8188eus/include/rtl8188f_cmd.h | 219 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm.c | 3425 linux-bsp/drivers/rtl8188eus/include/rtl8188f_spec.h | 291 linux-bsp/drivers/rtl8188eus/core/rtw_xmit.c | 5545 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_pathdiv.h | 319 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_antdiv.c | 5234 linux-bsp/drivers/rtl8188eus/include/hal_phy_reg.h | 30 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e1ant.c | 3417 linux-bsp/drivers/rtl8188eus/os_dep/linux/xmit_linux.c | 535 linux-bsp/drivers/rtl8188eus/core/rtw_mlme.c | 4669 linux-bsp/drivers/rtl8188eus/core/rtw_tdls.c | 3332 linux-bsp/drivers/rtl8188eus/hal/rtl8188e/rtl8188e_mp.c | 1153 linux-bsp/drivers/rtl8188eus/include/rtl8723a_rf.h | 27 linux-bsp/drivers/rtl8188eus/include/recv_osdep.h | 68 linux-bsp/drivers/rtl8188eus/core/rtw_eeprom.c | 374 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_interface.h | 394 linux-bsp/drivers/rtl8188eus/hal/phydm/phydm_antdiv.h | 632 linux-bsp/drivers/rtl8188eus/include/rtl8821c_spec.h | 195 linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b2Ant.h | 186 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e1ant.h | 226 linux-bsp/drivers/rtl8188eus/include/osdep_service_ce.h | 192 linux-bsp/drivers/rtl8188eus/core/rtw_rf.c | 1164 linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822bwifionly.c | 54 linux-bsp/drivers/rtl8188eus/include/rtl8188e_dm.h | 32 linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_interface.c | 751 linux-bsp/drivers/rtl8188eus/include/rtl8188e_cmd.h | 179 linux-bsp/drivers/rtl8188eus/include/wlan_bssdef.h | 690 linux-bsp/drivers/rtl8188eus/include/rtw_recv.h | 898 linux-bsp/drivers/rtl8188eus/include/rtl8821c_hal.h | 86 linux-bsp/drivers/rtl8188eus/include/Hal8188FPwrSeq.h | 198 linux-bsp/drivers/rtl8188eus/include/rtl8723d_dm.h | 47 608 files changed, 531,198 insertions(+), 0 deletions(-) diff --git a/linux-bsp/drivers/mt7601u-sta/Kbuild b/linux-bsp/drivers/mt7601u-sta/Kbuild new file mode 100644 index 0000000..087c06c --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/Kbuild @@ -0,0 +1,10 @@ +EXTRA_CFLAGS += -Werror -Wenum-compare +ccflags-y += -D__CHECK_ENDIAN__ + +obj-m := mt7601u.o + +mt7601u-y := \ + usb.o init.o main.o mcu.o trace.o dma.o core.o eeprom.o phy.o \ + mac.o util.o debugfs.o tx.o + +CFLAGS_trace.o := -I$(src) diff --git a/linux-bsp/drivers/mt7601u-sta/Makefile b/linux-bsp/drivers/mt7601u-sta/Makefile new file mode 100644 index 0000000..f1bc38b --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/Makefile @@ -0,0 +1,10 @@ + +KDIR ?= ../../linux-at91/ +CROSS_COMPILE=/opt/buildroot/cortex-a5/bin/arm-linux- + +default: + $(MAKE) -C $(KDIR) M=$$PWD +clean: + $(MAKE) -C $(KDIR) M=$$PWD clean +install: + $(MAKE) -C $(KDIR) M=$$PWD modules_install diff --git a/linux-bsp/drivers/mt7601u-sta/README.md b/linux-bsp/drivers/mt7601u-sta/README.md new file mode 100644 index 0000000..98490cc --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/README.md @@ -0,0 +1,64 @@ + +### Download: +Download from: https://github.com/kuba-moo/mt7601u.git +MT7601 driver builtin linux kernel since version v4.2, the kernel under the version need this driver. And it's just only server for wpa_supplicant but not hostapd + +### ChangeLog: + +1, Updata Makefile to support SAMA5D4 build + + + +This is a Linux driver for MediaTek MT7601U USB dongle. It was written from scratch based on the vendor GPL-driver. Unlike the vendor driver this driver uses modern Linux WiFi infrastructure and should work flawlessly with NetworkManager, wicd, wpa_supplicant and such. This driver was merged into mainline and is part of official Linux kernel since version v4.2. If you are using Linux 4.2 or later there is no need to install this driver. + +### Building and using +To use this driver you need to upgrade your kernel to at least **Linux 3.19**. You also have to grab a copy of the firmware from the vendor driver. Download the vendor driver (see section below) and copy file *MT7601U.bin* to */lib/firmware*: + +```sh +# cd where-you-put-the-vendor-driver +# cp src/mcu/bin/MT7601.bin /lib/firmware/mt7601u.bin +``` +Note that name of the file in */lib/firmware* is in lowercase. + +After that **make sure you have installed all packages required by your distro to build kernel modules** (```apt-get install linux-headers-$(uname -r)``` or ```yum install kernel-devel``` etc). Build the driver and load it: + +```sh +$ git clone https://github.com/kuba-moo/mt7601u.git +$ cd mt7601u +$ make +# modprobe mac80211 +# insmod ./mt7601u.ko +``` + +Now when you connect your device a new network interface should be created. Something like this should appear in your kernel logs: + +``` +[ 5515.098424] mt7601u 1-6:1.0: ASIC revision: 76010001 MAC revision: 76010500 +[ 5515.100954] mt7601u 1-6:1.0: Firmware Version: 0.1.00 Build: 7640 Build time: 201302052146____ +[ 5515.466817] mt7601u 1-6:1.0: Warning: unsupported EEPROM version 0d +[ 5515.466876] mt7601u 1-6:1.0: EEPROM ver:0d fae:00 +[ 5515.467561] mt7601u 1-6:1.0: EEPROM country region 01 (channels 1-13) +[ 5515.713155] ieee80211 phy26: Selected rate control algorithm 'minstrel_ht' +[ 5515.718977] usbcore: registered new interface driver mt7601u +``` + +The warning about EEPROM version is harmless but keep an eye on the logs and if you spot any errors please report them here. + +If you want the driver to load automatically you can do the following: +``` +$ make && sudo make install && depmod +``` +However, please remember that this installs the driver *only for your current kernel* and you will have to redo this every time your kernel is updated! + +### Supported hardware +The driver was tested for devices with USB ID of 148f:7601. Specifically I tested it with: + * TP-LINK TL-WN727N v4; + * Xiaomi Mini USB; + * the no-name black&red device from ebay with small detachable antenna. + +Also tested with USB ID of 148f:760b wich has MT7601UM chip and works fine with this driver. + +But in principle it *should* work with any device supported by the vendor driver. + +### Vendor driver +The original vendor driver can be downloaded from MediaTek's website (http://www.mediatek.com/en/downloads1/downloads/mt7601u-usb/). However, version 3.0.0.4 is broken on recent kernels so you may want to grab one of the improved versions which people put up on GH (like this one: https://github.com/porjo/mt7601u). diff --git a/linux-bsp/drivers/mt7601u-sta/core.c b/linux-bsp/drivers/mt7601u-sta/core.c new file mode 100644 index 0000000..0aabd79 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/core.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "mt7601u.h" + +int mt7601u_wait_asic_ready(struct mt7601u_dev *dev) +{ + int i = 100; + u32 val; + + do { + if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) + return -EIO; + + val = mt7601u_rr(dev, MT_MAC_CSR0); + if (val && ~val) + return 0; + + udelay(10); + } while (i--); + + return -EIO; +} + +bool mt76_poll(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val, + int timeout) +{ + u32 cur; + + timeout /= 10; + do { + if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) + return false; + + cur = mt7601u_rr(dev, offset) & mask; + if (cur == val) + return true; + + udelay(10); + } while (timeout-- > 0); + + dev_err(dev->dev, "Error: Time out with reg %08x\n", offset); + + return false; +} + +bool mt76_poll_msec(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val, + int timeout) +{ + u32 cur; + + timeout /= 10; + do { + if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) + return false; + + cur = mt7601u_rr(dev, offset) & mask; + if (cur == val) + return true; + + msleep(10); + } while (timeout-- > 0); + + dev_err(dev->dev, "Error: Time out with reg %08x\n", offset); + + return false; +} diff --git a/linux-bsp/drivers/mt7601u-sta/debugfs.c b/linux-bsp/drivers/mt7601u-sta/debugfs.c new file mode 100644 index 0000000..fc00847 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/debugfs.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/debugfs.h> + +#include "mt7601u.h" +#include "eeprom.h" + +static int +mt76_reg_set(void *data, u64 val) +{ + struct mt7601u_dev *dev = data; + + mt76_wr(dev, dev->debugfs_reg, val); + return 0; +} + +static int +mt76_reg_get(void *data, u64 *val) +{ + struct mt7601u_dev *dev = data; + + *val = mt76_rr(dev, dev->debugfs_reg); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); + +static int +mt7601u_ampdu_stat_read(struct seq_file *file, void *data) +{ + struct mt7601u_dev *dev = file->private; + int i, j; + +#define stat_printf(grp, off, name) \ + seq_printf(file, #name ":\t%llu\n", dev->stats.grp[off]) + + stat_printf(rx_stat, 0, rx_crc_err); + stat_printf(rx_stat, 1, rx_phy_err); + stat_printf(rx_stat, 2, rx_false_cca); + stat_printf(rx_stat, 3, rx_plcp_err); + stat_printf(rx_stat, 4, rx_fifo_overflow); + stat_printf(rx_stat, 5, rx_duplicate); + + stat_printf(tx_stat, 0, tx_fail_cnt); + stat_printf(tx_stat, 1, tx_bcn_cnt); + stat_printf(tx_stat, 2, tx_success); + stat_printf(tx_stat, 3, tx_retransmit); + stat_printf(tx_stat, 4, tx_zero_len); + stat_printf(tx_stat, 5, tx_underflow); + + stat_printf(aggr_stat, 0, non_aggr_tx); + stat_printf(aggr_stat, 1, aggr_tx); + + stat_printf(zero_len_del, 0, tx_zero_len_del); + stat_printf(zero_len_del, 1, rx_zero_len_del); +#undef stat_printf + + seq_puts(file, "Aggregations stats:\n"); + for (i = 0; i < 4; i++) { + for (j = 0; j < 8; j++) + seq_printf(file, "%08llx ", + dev->stats.aggr_n[i * 8 + j]); + seq_putc(file, '\n'); + } + + seq_printf(file, "recent average AMPDU len: %d\n", + atomic_read(&dev->avg_ampdu_len)); + + return 0; +} + +static int +mt7601u_ampdu_stat_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt7601u_ampdu_stat_read, inode->i_private); +} + +static const struct file_operations fops_ampdu_stat = { + .open = mt7601u_ampdu_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int +mt7601u_eeprom_param_read(struct seq_file *file, void *data) +{ + struct mt7601u_dev *dev = file->private; + struct mt7601u_rate_power *rp = &dev->ee->power_rate_table; + struct tssi_data *td = &dev->ee->tssi_data; + int i; + + seq_printf(file, "RF freq offset: %hhx\n", dev->ee->rf_freq_off); + seq_printf(file, "RSSI offset: %hhx %hhx\n", + dev->ee->rssi_offset[0], dev->ee->rssi_offset[1]); + seq_printf(file, "Reference temp: %hhx\n", dev->ee->ref_temp); + seq_printf(file, "LNA gain: %hhx\n", dev->ee->lna_gain); + seq_printf(file, "Reg channels: %hhu-%hhu\n", dev->ee->reg.start, + dev->ee->reg.start + dev->ee->reg.num - 1); + + seq_puts(file, "Per rate power:\n"); + for (i = 0; i < 2; i++) + seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n", + rp->cck[i].raw, rp->cck[i].bw20, rp->cck[i].bw40); + for (i = 0; i < 4; i++) + seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n", + rp->ofdm[i].raw, rp->ofdm[i].bw20, rp->ofdm[i].bw40); + for (i = 0; i < 4; i++) + seq_printf(file, "\t raw:%02hhx bw20:%02hhx bw40:%02hhx\n", + rp->ht[i].raw, rp->ht[i].bw20, rp->ht[i].bw40); + + seq_puts(file, "Per channel power:\n"); + for (i = 0; i < 7; i++) + seq_printf(file, "\t tx_power ch%u:%02hhx ch%u:%02hhx\n", + i * 2 + 1, dev->ee->chan_pwr[i * 2], + i * 2 + 2, dev->ee->chan_pwr[i * 2 + 1]); + + if (!dev->ee->tssi_enabled) + return 0; + + seq_puts(file, "TSSI:\n"); + seq_printf(file, "\t slope:%02hhx\n", td->slope); + seq_printf(file, "\t offset=%02hhx %02hhx %02hhx\n", + td->offset[0], td->offset[1], td->offset[2]); + seq_printf(file, "\t delta_off:%08x\n", td->tx0_delta_offset); + + return 0; +} + +static int +mt7601u_eeprom_param_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt7601u_eeprom_param_read, inode->i_private); +} + +static const struct file_operations fops_eeprom_param = { + .open = mt7601u_eeprom_param_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void mt7601u_init_debugfs(struct mt7601u_dev *dev) +{ + struct dentry *dir; + + dir = debugfs_create_dir("mt7601u", dev->hw->wiphy->debugfsdir); + if (!dir) + return; + + debugfs_create_u8("temperature", S_IRUSR, dir, &dev->raw_temp); + debugfs_create_u32("temp_mode", S_IRUSR, dir, &dev->temp_mode); + + debugfs_create_u32("regidx", S_IRUSR | S_IWUSR, dir, &dev->debugfs_reg); + debugfs_create_file("regval", S_IRUSR | S_IWUSR, dir, dev, + &fops_regval); + debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat); + debugfs_create_file("eeprom_param", S_IRUSR, dir, dev, + &fops_eeprom_param); +} diff --git a/linux-bsp/drivers/mt7601u-sta/dma.c b/linux-bsp/drivers/mt7601u-sta/dma.c new file mode 100644 index 0000000..f08a0be --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/dma.c @@ -0,0 +1,529 @@ +/* + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "mt7601u.h" +#include "dma.h" +#include "usb.h" +#include "trace.h" + +static int mt7601u_submit_rx_buf(struct mt7601u_dev *dev, + struct mt7601u_dma_buf_rx *e, gfp_t gfp); + +static unsigned int ieee80211_get_hdrlen_from_buf(const u8 *data, unsigned len) +{ + const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)data; + unsigned int hdrlen; + + if (unlikely(len < 10)) + return 0; + hdrlen = ieee80211_hdrlen(hdr->frame_control); + if (unlikely(hdrlen > len)) + return 0; + return hdrlen; +} + +static struct sk_buff * +mt7601u_rx_skb_from_seg(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, + void *data, u32 seg_len, u32 truesize, struct page *p) +{ + struct sk_buff *skb; + u32 true_len, hdr_len = 0, copy, frag; + + skb = alloc_skb(p ? 128 : seg_len, GFP_ATOMIC); + if (!skb) + return NULL; + + true_len = mt76_mac_process_rx(dev, skb, data, rxwi); + if (!true_len || true_len > seg_len) + goto bad_frame; + + hdr_len = ieee80211_get_hdrlen_from_buf(data, true_len); + if (!hdr_len) + goto bad_frame; + + if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_L2PAD)) { + memcpy(skb_put(skb, hdr_len), data, hdr_len); + + data += hdr_len + 2; + true_len -= hdr_len; + hdr_len = 0; + } + + /* If not doing paged RX allocated skb will always have enough space */ + copy = (true_len <= skb_tailroom(skb)) ? true_len : hdr_len + 8; + frag = true_len - copy; + + memcpy(skb_put(skb, copy), data, copy); + data += copy; + + if (frag) { + skb_add_rx_frag(skb, 0, p, data - page_address(p), + frag, truesize); + get_page(p); + } + + return skb; + +bad_frame: + dev_err(dev->dev, "Error: incorrect frame len:%u hdr:%u\n", + true_len, hdr_len); + dev_kfree_skb(skb); + return NULL; +} + +static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data, + u32 seg_len, struct page *p) +{ + struct sk_buff *skb; + struct mt7601u_rxwi *rxwi; + u32 fce_info, truesize = seg_len; + + /* DMA_INFO field at the beginning of the segment contains only some of + * the information, we need to read the FCE descriptor from the end. + */ + fce_info = get_unaligned_le32(data + seg_len - MT_FCE_INFO_LEN); + seg_len -= MT_FCE_INFO_LEN; + + data += MT_DMA_HDR_LEN; + seg_len -= MT_DMA_HDR_LEN; + + rxwi = (struct mt7601u_rxwi *) data; + data += sizeof(struct mt7601u_rxwi); + seg_len -= sizeof(struct mt7601u_rxwi); + + if (unlikely(rxwi->zero[0] || rxwi->zero[1] || rxwi->zero[2])) + dev_err_once(dev->dev, "Error: RXWI zero fields are set\n"); + if (unlikely(MT76_GET(MT_RXD_INFO_TYPE, fce_info))) + dev_err_once(dev->dev, "Error: RX path seen a non-pkt urb\n"); + + trace_mt_rx(dev, rxwi, fce_info); + + skb = mt7601u_rx_skb_from_seg(dev, rxwi, data, seg_len, truesize, p); + if (!skb) + return; + + spin_lock(&dev->mac_lock); + ieee80211_rx(dev->hw, skb); + spin_unlock(&dev->mac_lock); +} + +static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len) +{ + u32 min_seg_len = MT_DMA_HDR_LEN + MT_RX_INFO_LEN + + sizeof(struct mt7601u_rxwi) + MT_FCE_INFO_LEN; + u16 dma_len = get_unaligned_le16(data); + + if (data_len < min_seg_len || + WARN_ON(!dma_len) || + WARN_ON(dma_len + MT_DMA_HDRS > data_len) || + WARN_ON(dma_len & 0x3)) + return 0; + + return MT_DMA_HDRS + dma_len; +} + +static void +mt7601u_rx_process_entry(struct mt7601u_dev *dev, struct mt7601u_dma_buf_rx *e) +{ + u32 seg_len, data_len = e->urb->actual_length; + u8 *data = page_address(e->p); + struct page *new_p = NULL; + int cnt = 0; + + if (!test_bit(MT7601U_STATE_INITIALIZED, &dev->state)) + return; + + /* Copy if there is very little data in the buffer. */ + if (data_len > 512) + new_p = dev_alloc_pages(MT_RX_ORDER); + + while ((seg_len = mt7601u_rx_next_seg_len(data, data_len))) { + mt7601u_rx_process_seg(dev, data, seg_len, new_p ? e->p : NULL); + + data_len -= seg_len; + data += seg_len; + cnt++; + } + + if (cnt > 1) + trace_mt_rx_dma_aggr(dev, cnt, !!new_p); + + if (new_p) { + /* we have one extra ref from the allocator */ + __free_pages(e->p, MT_RX_ORDER); + + e->p = new_p; + } +} + +static struct mt7601u_dma_buf_rx * +mt7601u_rx_get_pending_entry(struct mt7601u_dev *dev) +{ + struct mt7601u_rx_queue *q = &dev->rx_q; + struct mt7601u_dma_buf_rx *buf = NULL; + unsigned long flags; + + spin_lock_irqsave(&dev->rx_lock, flags); + + if (!q->pending) + goto out; + + buf = &q->e[q->start]; + q->pending--; + q->start = (q->start + 1) % q->entries; +out: + spin_unlock_irqrestore(&dev->rx_lock, flags); + + return buf; +} + +static void mt7601u_complete_rx(struct urb *urb) +{ + struct mt7601u_dev *dev = urb->context; + struct mt7601u_rx_queue *q = &dev->rx_q; + unsigned long flags; + + spin_lock_irqsave(&dev->rx_lock, flags); + + if (mt7601u_urb_has_error(urb)) + dev_err(dev->dev, "Error: RX urb failed:%d\n", urb->status); + if (WARN_ONCE(q->e[q->end].urb != urb, "RX urb mismatch")) + goto out; + + q->end = (q->end + 1) % q->entries; + q->pending++; + tasklet_schedule(&dev->rx_tasklet); +out: + spin_unlock_irqrestore(&dev->rx_lock, flags); +} + +static void mt7601u_rx_tasklet(unsigned long data) +{ + struct mt7601u_dev *dev = (struct mt7601u_dev *) data; + struct mt7601u_dma_buf_rx *e; + + while ((e = mt7601u_rx_get_pending_entry(dev))) { + if (e->urb->status) + continue; + + mt7601u_rx_process_entry(dev, e); + mt7601u_submit_rx_buf(dev, e, GFP_ATOMIC); + } +} + +static void mt7601u_complete_tx(struct urb *urb) +{ + struct mt7601u_tx_queue *q = urb->context; + struct mt7601u_dev *dev = q->dev; + struct sk_buff *skb; + unsigned long flags; + + spin_lock_irqsave(&dev->tx_lock, flags); + + if (mt7601u_urb_has_error(urb)) + dev_err(dev->dev, "Error: TX urb failed:%d\n", urb->status); + if (WARN_ONCE(q->e[q->start].urb != urb, "TX urb mismatch")) + goto out; + + skb = q->e[q->start].skb; + trace_mt_tx_dma_done(dev, skb); + + __skb_queue_tail(&dev->tx_skb_done, skb); + tasklet_schedule(&dev->tx_tasklet); + + if (q->used == q->entries - q->entries / 8) + ieee80211_wake_queue(dev->hw, skb_get_queue_mapping(skb)); + + q->start = (q->start + 1) % q->entries; + q->used--; +out: + spin_unlock_irqrestore(&dev->tx_lock, flags); +} + +static void mt7601u_tx_tasklet(unsigned long data) +{ + struct mt7601u_dev *dev = (struct mt7601u_dev *) data; + struct sk_buff_head skbs; + unsigned long flags; + + __skb_queue_head_init(&skbs); + + spin_lock_irqsave(&dev->tx_lock, flags); + + set_bit(MT7601U_STATE_MORE_STATS, &dev->state); + if (!test_and_set_bit(MT7601U_STATE_READING_STATS, &dev->state)) + queue_delayed_work(dev->stat_wq, &dev->stat_work, + msecs_to_jiffies(10)); + + skb_queue_splice_init(&dev->tx_skb_done, &skbs); + + spin_unlock_irqrestore(&dev->tx_lock, flags); + + while (!skb_queue_empty(&skbs)) { + struct sk_buff *skb = __skb_dequeue(&skbs); + + mt7601u_tx_status(dev, skb); + } +} + +static int mt7601u_dma_submit_tx(struct mt7601u_dev *dev, + struct sk_buff *skb, u8 ep) +{ + struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); + unsigned snd_pipe = usb_sndbulkpipe(usb_dev, dev->out_eps[ep]); + struct mt7601u_dma_buf_tx *e; + struct mt7601u_tx_queue *q = &dev->tx_q[ep]; + unsigned long flags; + int ret; + + spin_lock_irqsave(&dev->tx_lock, flags); + + if (WARN_ON(q->entries <= q->used)) { + ret = -ENOSPC; + goto out; + } + + e = &q->e[q->end]; + e->skb = skb; + usb_fill_bulk_urb(e->urb, usb_dev, snd_pipe, skb->data, skb->len, + mt7601u_complete_tx, q); + ret = usb_submit_urb(e->urb, GFP_ATOMIC); + if (ret) { + /* Special-handle ENODEV from TX urb submission because it will + * often be the first ENODEV we see after device is removed. + */ + if (ret == -ENODEV) + set_bit(MT7601U_STATE_REMOVED, &dev->state); + else + dev_err(dev->dev, "Error: TX urb submit failed:%d\n", + ret); + goto out; + } + + q->end = (q->end + 1) % q->entries; + q->used++; + + if (q->used >= q->entries) + ieee80211_stop_queue(dev->hw, skb_get_queue_mapping(skb)); +out: + spin_unlock_irqrestore(&dev->tx_lock, flags); + + return ret; +} + +/* Map hardware Q to USB endpoint number */ +static u8 q2ep(u8 qid) +{ + /* TODO: take management packets to queue 5 */ + return qid + 1; +} + +/* Map USB endpoint number to Q id in the DMA engine */ +static enum mt76_qsel ep2dmaq(u8 ep) +{ + if (ep == 5) + return MT_QSEL_MGMT; + return MT_QSEL_EDCA; +} + +int mt7601u_dma_enqueue_tx(struct mt7601u_dev *dev, struct sk_buff *skb, + struct mt76_wcid *wcid, int hw_q) +{ + u8 ep = q2ep(hw_q); + u32 dma_flags; + int ret; + + dma_flags = MT_TXD_PKT_INFO_80211; + if (wcid->hw_key_idx == 0xff) + dma_flags |= MT_TXD_PKT_INFO_WIV; + + ret = mt7601u_dma_skb_wrap_pkt(skb, ep2dmaq(ep), dma_flags); + if (ret) + return ret; + + ret = mt7601u_dma_submit_tx(dev, skb, ep); + if (ret) { + ieee80211_free_txskb(dev->hw, skb); + return ret; + } + + return 0; +} + +static void mt7601u_kill_rx(struct mt7601u_dev *dev) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&dev->rx_lock, flags); + + for (i = 0; i < dev->rx_q.entries; i++) { + int next = dev->rx_q.end; + + spin_unlock_irqrestore(&dev->rx_lock, flags); + usb_poison_urb(dev->rx_q.e[next].urb); + spin_lock_irqsave(&dev->rx_lock, flags); + } + + spin_unlock_irqrestore(&dev->rx_lock, flags); +} + +static int mt7601u_submit_rx_buf(struct mt7601u_dev *dev, + struct mt7601u_dma_buf_rx *e, gfp_t gfp) +{ + struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); + u8 *buf = page_address(e->p); + unsigned pipe; + int ret; + + pipe = usb_rcvbulkpipe(usb_dev, dev->in_eps[MT_EP_IN_PKT_RX]); + + usb_fill_bulk_urb(e->urb, usb_dev, pipe, buf, MT_RX_URB_SIZE, + mt7601u_complete_rx, dev); + + trace_mt_submit_urb(dev, e->urb); + ret = usb_submit_urb(e->urb, gfp); + if (ret) + dev_err(dev->dev, "Error: submit RX URB failed:%d\n", ret); + + return ret; +} + +static int mt7601u_submit_rx(struct mt7601u_dev *dev) +{ + int i, ret; + + for (i = 0; i < dev->rx_q.entries; i++) { + ret = mt7601u_submit_rx_buf(dev, &dev->rx_q.e[i], GFP_KERNEL); + if (ret) + return ret; + } + + return 0; +} + +static void mt7601u_free_rx(struct mt7601u_dev *dev) +{ + int i; + + for (i = 0; i < dev->rx_q.entries; i++) { + __free_pages(dev->rx_q.e[i].p, MT_RX_ORDER); + usb_free_urb(dev->rx_q.e[i].urb); + } +} + +static int mt7601u_alloc_rx(struct mt7601u_dev *dev) +{ + int i; + + memset(&dev->rx_q, 0, sizeof(dev->rx_q)); + dev->rx_q.dev = dev; + dev->rx_q.entries = N_RX_ENTRIES; + + for (i = 0; i < N_RX_ENTRIES; i++) { + dev->rx_q.e[i].urb = usb_alloc_urb(0, GFP_KERNEL); + dev->rx_q.e[i].p = dev_alloc_pages(MT_RX_ORDER); + + if (!dev->rx_q.e[i].urb || !dev->rx_q.e[i].p) + return -ENOMEM; + } + + return 0; +} + +static void mt7601u_free_tx_queue(struct mt7601u_tx_queue *q) +{ + int i; + + WARN_ON(q->used); + + for (i = 0; i < q->entries; i++) { + usb_poison_urb(q->e[i].urb); + usb_free_urb(q->e[i].urb); + } +} + +static void mt7601u_free_tx(struct mt7601u_dev *dev) +{ + int i; + + for (i = 0; i < __MT_EP_OUT_MAX; i++) + mt7601u_free_tx_queue(&dev->tx_q[i]); +} + +static int mt7601u_alloc_tx_queue(struct mt7601u_dev *dev, + struct mt7601u_tx_queue *q) +{ + int i; + + q->dev = dev; + q->entries = N_TX_ENTRIES; + + for (i = 0; i < N_TX_ENTRIES; i++) { + q->e[i].urb = usb_alloc_urb(0, GFP_KERNEL); + if (!q->e[i].urb) + return -ENOMEM; + } + + return 0; +} + +static int mt7601u_alloc_tx(struct mt7601u_dev *dev) +{ + int i; + + dev->tx_q = devm_kcalloc(dev->dev, __MT_EP_OUT_MAX, + sizeof(*dev->tx_q), GFP_KERNEL); + + for (i = 0; i < __MT_EP_OUT_MAX; i++) + if (mt7601u_alloc_tx_queue(dev, &dev->tx_q[i])) + return -ENOMEM; + + return 0; +} + +int mt7601u_dma_init(struct mt7601u_dev *dev) +{ + int ret = -ENOMEM; + + tasklet_init(&dev->tx_tasklet, mt7601u_tx_tasklet, (unsigned long) dev); + tasklet_init(&dev->rx_tasklet, mt7601u_rx_tasklet, (unsigned long) dev); + + ret = mt7601u_alloc_tx(dev); + if (ret) + goto err; + ret = mt7601u_alloc_rx(dev); + if (ret) + goto err; + + ret = mt7601u_submit_rx(dev); + if (ret) + goto err; + + return 0; +err: + mt7601u_dma_cleanup(dev); + return ret; +} + +void mt7601u_dma_cleanup(struct mt7601u_dev *dev) +{ + mt7601u_kill_rx(dev); + + tasklet_kill(&dev->rx_tasklet); + + mt7601u_free_rx(dev); + mt7601u_free_tx(dev); + + tasklet_kill(&dev->tx_tasklet); +} diff --git a/linux-bsp/drivers/mt7601u-sta/dma.h b/linux-bsp/drivers/mt7601u-sta/dma.h new file mode 100644 index 0000000..978e8a9 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/dma.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT7601U_DMA_H +#define __MT7601U_DMA_H + +#include <asm/unaligned.h> +#include <linux/skbuff.h> + +#include "util.h" + +#define MT_DMA_HDR_LEN 4 +#define MT_RX_INFO_LEN 4 +#define MT_FCE_INFO_LEN 4 +#define MT_DMA_HDRS (MT_DMA_HDR_LEN + MT_RX_INFO_LEN) + +/* Common Tx DMA descriptor fields */ +#define MT_TXD_INFO_LEN GENMASK(15, 0) +#define MT_TXD_INFO_D_PORT GENMASK(29, 27) +#define MT_TXD_INFO_TYPE GENMASK(31, 30) + +enum mt76_msg_port { + WLAN_PORT, + CPU_RX_PORT, + CPU_TX_PORT, + HOST_PORT, + VIRTUAL_CPU_RX_PORT, + VIRTUAL_CPU_TX_PORT, + DISCARD, +}; + +enum mt76_info_type { + DMA_PACKET, + DMA_COMMAND, +}; + +/* Tx DMA packet specific flags */ +#define MT_TXD_PKT_INFO_NEXT_VLD BIT(16) +#define MT_TXD_PKT_INFO_TX_BURST BIT(17) +#define MT_TXD_PKT_INFO_80211 BIT(19) +#define MT_TXD_PKT_INFO_TSO BIT(20) +#define MT_TXD_PKT_INFO_CSO BIT(21) +#define MT_TXD_PKT_INFO_WIV BIT(24) +#define MT_TXD_PKT_INFO_QSEL GENMASK(26, 25) + +enum mt76_qsel { + MT_QSEL_MGMT, + MT_QSEL_HCCA, + MT_QSEL_EDCA, + MT_QSEL_EDCA_2, +}; + +/* Tx DMA MCU command specific flags */ +#define MT_TXD_CMD_INFO_SEQ GENMASK(19, 16) +#define MT_TXD_CMD_INFO_TYPE GENMASK(26, 20) + +static inline int mt7601u_dma_skb_wrap(struct sk_buff *skb, + enum mt76_msg_port d_port, + enum mt76_info_type type, u32 flags) +{ + u32 info; + + /* Buffer layout: + * | 4B | xfer len | pad | 4B | + * | TXINFO | pkt/cmd | zero pad to 4B | zero | + * + * length field of TXINFO should be set to 'xfer len'. + */ + + info = flags | + MT76_SET(MT_TXD_INFO_LEN, round_up(skb->len, 4)) | + MT76_SET(MT_TXD_INFO_D_PORT, d_port) | + MT76_SET(MT_TXD_INFO_TYPE, type); + + put_unaligned_le32(info, skb_push(skb, sizeof(info))); + return skb_put_padto(skb, round_up(skb->len, 4) + 4); +} + +static inline int +mt7601u_dma_skb_wrap_pkt(struct sk_buff *skb, enum mt76_qsel qsel, u32 flags) +{ + flags |= MT76_SET(MT_TXD_PKT_INFO_QSEL, qsel); + return mt7601u_dma_skb_wrap(skb, WLAN_PORT, DMA_PACKET, flags); +} + +/* Common Rx DMA descriptor fields */ +#define MT_RXD_INFO_LEN GENMASK(13, 0) +#define MT_RXD_INFO_PCIE_INTR BIT(24) +#define MT_RXD_INFO_QSEL GENMASK(26, 25) +#define MT_RXD_INFO_PORT GENMASK(29, 27) +#define MT_RXD_INFO_TYPE GENMASK(31, 30) + +/* Rx DMA packet specific flags */ +#define MT_RXD_PKT_INFO_UDP_ERR BIT(16) +#define MT_RXD_PKT_INFO_TCP_ERR BIT(17) +#define MT_RXD_PKT_INFO_IP_ERR BIT(18) +#define MT_RXD_PKT_INFO_PKT_80211 BIT(19) +#define MT_RXD_PKT_INFO_L3L4_DONE BIT(20) +#define MT_RXD_PKT_INFO_MAC_LEN GENMASK(23, 21) + +/* Rx DMA MCU command specific flags */ +#define MT_RXD_CMD_INFO_SELF_GEN BIT(15) +#define MT_RXD_CMD_INFO_CMD_SEQ GENMASK(19, 16) +#define MT_RXD_CMD_INFO_EVT_TYPE GENMASK(23, 20) + +enum mt76_evt_type { + CMD_DONE, + CMD_ERROR, + CMD_RETRY, + EVENT_PWR_RSP, + EVENT_WOW_RSP, + EVENT_CARRIER_DETECT_RSP, + EVENT_DFS_DETECT_RSP, +}; + +#endif diff --git a/linux-bsp/drivers/mt7601u-sta/eeprom.c b/linux-bsp/drivers/mt7601u-sta/eeprom.c new file mode 100644 index 0000000..8d8ee03 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/eeprom.c @@ -0,0 +1,418 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/of.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/etherdevice.h> +#include <asm/unaligned.h> +#include "mt7601u.h" +#include "eeprom.h" + +static bool +field_valid(u8 val) +{ + return val != 0xff; +} + +static s8 +field_validate(u8 val) +{ + if (!field_valid(val)) + return 0; + + return val; +} + +static int +mt7601u_efuse_read(struct mt7601u_dev *dev, u16 addr, u8 *data, + enum mt7601u_eeprom_access_modes mode) +{ + u32 val; + int i; + + val = mt76_rr(dev, MT_EFUSE_CTRL); + val &= ~(MT_EFUSE_CTRL_AIN | + MT_EFUSE_CTRL_MODE); + val |= MT76_SET(MT_EFUSE_CTRL_AIN, addr & ~0xf) | + MT76_SET(MT_EFUSE_CTRL_MODE, mode) | + MT_EFUSE_CTRL_KICK; + mt76_wr(dev, MT_EFUSE_CTRL, val); + + if (!mt76_poll(dev, MT_EFUSE_CTRL, MT_EFUSE_CTRL_KICK, 0, 1000)) + return -ETIMEDOUT; + + val = mt76_rr(dev, MT_EFUSE_CTRL); + if ((val & MT_EFUSE_CTRL_AOUT) == MT_EFUSE_CTRL_AOUT) { + /* Parts of eeprom not in the usage map (0x80-0xc0,0xf0) + * will not return valid data but it's ok. + */ + memset(data, 0xff, 16); + return 0; + } + + for (i = 0; i < 4; i++) { + val = mt76_rr(dev, MT_EFUSE_DATA(i)); + put_unaligned_le32(val, data + 4 * i); + } + + return 0; +} + +static int +mt7601u_efuse_physical_size_check(struct mt7601u_dev *dev) +{ + const int map_reads = DIV_ROUND_UP(MT_EFUSE_USAGE_MAP_SIZE, 16); + u8 data[map_reads * 16]; + int ret, i; + u32 start = 0, end = 0, cnt_free; + + for (i = 0; i < map_reads; i++) { + ret = mt7601u_efuse_read(dev, MT_EE_USAGE_MAP_START + i * 16, + data + i * 16, MT_EE_PHYSICAL_READ); + if (ret) + return ret; + } + + for (i = 0; i < MT_EFUSE_USAGE_MAP_SIZE; i++) + if (!data[i]) { + if (!start) + start = MT_EE_USAGE_MAP_START + i; + end = MT_EE_USAGE_MAP_START + i; + } + cnt_free = end - start + 1; + + if (MT_EFUSE_USAGE_MAP_SIZE - cnt_free < 5) { + dev_err(dev->dev, "Error: your device needs default EEPROM file and this driver doesn't support it!\n"); + return -EINVAL; + } + + return 0; +} + +static bool +mt7601u_has_tssi(struct mt7601u_dev *dev, u8 *eeprom) +{ + u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1); + + return ~nic_conf1 && (nic_conf1 & MT_EE_NIC_CONF_1_TX_ALC_EN); +} + +static void +mt7601u_set_chip_cap(struct mt7601u_dev *dev, u8 *eeprom) +{ + u16 nic_conf0 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_0); + u16 nic_conf1 = get_unaligned_le16(eeprom + MT_EE_NIC_CONF_1); + + if (!field_valid(nic_conf1 & 0xff)) + nic_conf1 &= 0xff00; + + dev->ee->tssi_enabled = mt7601u_has_tssi(dev, eeprom) && + !(nic_conf1 & MT_EE_NIC_CONF_1_TEMP_TX_ALC); + + if (nic_conf1 & MT_EE_NIC_CONF_1_HW_RF_CTRL) + dev_err(dev->dev, + "Error: this driver does not support HW RF ctrl\n"); + + if (!field_valid(nic_conf0 >> 8)) + return; + + if (MT76_GET(MT_EE_NIC_CONF_0_RX_PATH, nic_conf0) > 1 || + MT76_GET(MT_EE_NIC_CONF_0_TX_PATH, nic_conf0) > 1) + dev_err(dev->dev, + "Error: device has more than 1 RX/TX stream!\n"); +} + +static int +mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *eeprom) +{ + const void *src = eeprom + MT_EE_MAC_ADDR; + + ether_addr_copy(dev->macaddr, src); + + if (!is_valid_ether_addr(dev->macaddr)) { + eth_random_addr(dev->macaddr); + dev_info(dev->dev, + "Invalid MAC address, using random address %pM\n", + dev->macaddr); + } + + mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr)); + mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) | + MT76_SET(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); + + return 0; +} + +static void mt7601u_set_channel_target_power(struct mt7601u_dev *dev, + u8 *eeprom, u8 max_pwr) +{ + u8 trgt_pwr = eeprom[MT_EE_TX_TSSI_TARGET_POWER]; + + if (trgt_pwr > max_pwr || !trgt_pwr) { + dev_warn(dev->dev, "Error: EEPROM trgt power invalid %hhx!\n", + trgt_pwr); + trgt_pwr = 0x20; + } + + memset(dev->ee->chan_pwr, trgt_pwr, sizeof(dev->ee->chan_pwr)); +} + +static void +mt7601u_set_channel_power(struct mt7601u_dev *dev, u8 *eeprom) +{ + u32 i, val; + u8 max_pwr; + + val = mt7601u_rr(dev, MT_TX_ALC_CFG_0); + max_pwr = MT76_GET(MT_TX_ALC_CFG_0_LIMIT_0, val); + + if (mt7601u_has_tssi(dev, eeprom)) { + mt7601u_set_channel_target_power(dev, eeprom, max_pwr); + return; + } + + for (i = 0; i < 14; i++) { + s8 power = field_validate(eeprom[MT_EE_TX_POWER_OFFSET + i]); + + if (power > max_pwr || power < 0) + power = MT7601U_DEFAULT_TX_POWER; + + dev->ee->chan_pwr[i] = power; + } +} + +static void +mt7601u_set_country_reg(struct mt7601u_dev *dev, u8 *eeprom) +{ + /* Note: - region 31 is not valid for mt7601u (see rtmp_init.c) + * - comments in rtmp_def.h are incorrect (see rt_channel.c) + */ + static const struct reg_channel_bounds chan_bounds[] = { + /* EEPROM country regions 0 - 7 */ + { 1, 11 }, { 1, 13 }, { 10, 2 }, { 10, 4 }, + { 14, 1 }, { 1, 14 }, { 3, 7 }, { 5, 9 }, + /* EEPROM country regions 32 - 33 */ + { 1, 11 }, { 1, 14 } + }; + u8 val = eeprom[MT_EE_COUNTRY_REGION]; + int idx = -1; + + if (val < 8) + idx = val; + if (val > 31 && val < 33) + idx = val - 32 + 8; + + if (idx != -1) + dev_info(dev->dev, + "EEPROM country region %02hhx (channels %hhd-%hhd)\n", + val, chan_bounds[idx].start, + chan_bounds[idx].start + chan_bounds[idx].num - 1); + else + idx = 5; /* channels 1 - 14 */ + + dev->ee->reg = chan_bounds[idx]; + + /* TODO: country region 33 is special - phy should be set to B-mode + * before entering channel 14 (see sta/connect.c) + */ +} + +static void +mt7601u_set_rf_freq_off(struct mt7601u_dev *dev, u8 *eeprom) +{ + u8 comp; + + dev->ee->rf_freq_off = field_validate(eeprom[MT_EE_FREQ_OFFSET]); + comp = field_validate(eeprom[MT_EE_FREQ_OFFSET_COMPENSATION]); + + if (comp & BIT(7)) + dev->ee->rf_freq_off -= comp & 0x7f; + else + dev->ee->rf_freq_off += comp; +} + +static void +mt7601u_set_rssi_offset(struct mt7601u_dev *dev, u8 *eeprom) +{ + int i; + s8 *rssi_offset = dev->ee->rssi_offset; + + for (i = 0; i < 2; i++) { + rssi_offset[i] = eeprom[MT_EE_RSSI_OFFSET + i]; + + if (rssi_offset[i] < -10 || rssi_offset[i] > 10) { + dev_warn(dev->dev, + "Warning: EEPROM RSSI is invalid %02hhx\n", + rssi_offset[i]); + rssi_offset[i] = 0; + } + } +} + +static void +mt7601u_extra_power_over_mac(struct mt7601u_dev *dev) +{ + u32 val; + + val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_1) & 0x0000ff00) >> 8); + val |= ((mt7601u_rr(dev, MT_TX_PWR_CFG_2) & 0x0000ff00) << 8); + mt7601u_wr(dev, MT_TX_PWR_CFG_7, val); + + val = ((mt7601u_rr(dev, MT_TX_PWR_CFG_4) & 0x0000ff00) >> 8); + mt7601u_wr(dev, MT_TX_PWR_CFG_9, val); +} + +static void +mt7601u_set_power_rate(struct power_per_rate *rate, s8 delta, u8 value) +{ + /* Invalid? Note: vendor driver does not handle this */ + if (value == 0xff) + return; + + rate->raw = s6_validate(value); + rate->bw20 = s6_to_int(value); + /* Note: vendor driver does cap the value to s6 right away */ + rate->bw40 = rate->bw20 + delta; +} + +static void +mt7601u_save_power_rate(struct mt7601u_dev *dev, s8 delta, u32 val, int i) +{ + struct mt7601u_rate_power *t = &dev->ee->power_rate_table; + + switch (i) { + case 0: + mt7601u_set_power_rate(&t->cck[0], delta, (val >> 0) & 0xff); + mt7601u_set_power_rate(&t->cck[1], delta, (val >> 8) & 0xff); + /* Save cck bw20 for fixups of channel 14 */ + dev->ee->real_cck_bw20[0] = t->cck[0].bw20; + dev->ee->real_cck_bw20[1] = t->cck[1].bw20; + + mt7601u_set_power_rate(&t->ofdm[0], delta, (val >> 16) & 0xff); + mt7601u_set_power_rate(&t->ofdm[1], delta, (val >> 24) & 0xff); + break; + case 1: + mt7601u_set_power_rate(&t->ofdm[2], delta, (val >> 0) & 0xff); + mt7601u_set_power_rate(&t->ofdm[3], delta, (val >> 8) & 0xff); + mt7601u_set_power_rate(&t->ht[0], delta, (val >> 16) & 0xff); + mt7601u_set_power_rate(&t->ht[1], delta, (val >> 24) & 0xff); + break; + case 2: + mt7601u_set_power_rate(&t->ht[2], delta, (val >> 0) & 0xff); + mt7601u_set_power_rate(&t->ht[3], delta, (val >> 8) & 0xff); + break; + } +} + +static s8 +get_delta(u8 val) +{ + s8 ret; + + if (!field_valid(val) || !(val & BIT(7))) + return 0; + + ret = val & 0x1f; + if (ret > 8) + ret = 8; + if (val & BIT(6)) + ret = -ret; + + return ret; +} + +static void +mt7601u_config_tx_power_per_rate(struct mt7601u_dev *dev, u8 *eeprom) +{ + u32 val; + s8 bw40_delta; + int i; + + bw40_delta = get_delta(eeprom[MT_EE_TX_POWER_DELTA_BW40]); + + for (i = 0; i < 5; i++) { + val = get_unaligned_le32(eeprom + MT_EE_TX_POWER_BYRATE(i)); + + mt7601u_save_power_rate(dev, bw40_delta, val, i); + + if (~val) + mt7601u_wr(dev, MT_TX_PWR_CFG_0 + i * 4, val); + } + + mt7601u_extra_power_over_mac(dev); +} + +static void +mt7601u_init_tssi_params(struct mt7601u_dev *dev, u8 *eeprom) +{ + struct tssi_data *d = &dev->ee->tssi_data; + + if (!dev->ee->tssi_enabled) + return; + + d->slope = eeprom[MT_EE_TX_TSSI_SLOPE]; + d->tx0_delta_offset = eeprom[MT_EE_TX_TSSI_OFFSET] * 1024; + d->offset[0] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP]; + d->offset[1] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 1]; + d->offset[2] = eeprom[MT_EE_TX_TSSI_OFFSET_GROUP + 2]; +} + +int +mt7601u_eeprom_init(struct mt7601u_dev *dev) +{ + u8 *eeprom; + int i, ret; + + ret = mt7601u_efuse_physical_size_check(dev); + if (ret) + return ret; + + dev->ee = devm_kzalloc(dev->dev, sizeof(*dev->ee), GFP_KERNEL); + if (!dev->ee) + return -ENOMEM; + + eeprom = kmalloc(MT7601U_EEPROM_SIZE, GFP_KERNEL); + if (!eeprom) + return -ENOMEM; + + for (i = 0; i + 16 <= MT7601U_EEPROM_SIZE; i += 16) { + ret = mt7601u_efuse_read(dev, i, eeprom + i, MT_EE_READ); + if (ret) + goto out; + } + + if (eeprom[MT_EE_VERSION_EE] > MT7601U_EE_MAX_VER) + dev_warn(dev->dev, + "Warning: unsupported EEPROM version %02hhx\n", + eeprom[MT_EE_VERSION_EE]); + dev_info(dev->dev, "EEPROM ver:%02hhx fae:%02hhx\n", + eeprom[MT_EE_VERSION_EE], eeprom[MT_EE_VERSION_FAE]); + + mt7601u_set_macaddr(dev, eeprom); + mt7601u_set_chip_cap(dev, eeprom); + mt7601u_set_channel_power(dev, eeprom); + mt7601u_set_country_reg(dev, eeprom); + mt7601u_set_rf_freq_off(dev, eeprom); + mt7601u_set_rssi_offset(dev, eeprom); + dev->ee->ref_temp = eeprom[MT_EE_REF_TEMP]; + dev->ee->lna_gain = eeprom[MT_EE_LNA_GAIN]; + + mt7601u_config_tx_power_per_rate(dev, eeprom); + + mt7601u_init_tssi_params(dev, eeprom); +out: + kfree(eeprom); + return ret; +} diff --git a/linux-bsp/drivers/mt7601u-sta/eeprom.h b/linux-bsp/drivers/mt7601u-sta/eeprom.h new file mode 100644 index 0000000..662d127 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/eeprom.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT7601U_EEPROM_H +#define __MT7601U_EEPROM_H + +struct mt7601u_dev; + +#define MT7601U_EE_MAX_VER 0x0c +#define MT7601U_EEPROM_SIZE 256 + +#define MT7601U_DEFAULT_TX_POWER 6 + +enum mt76_eeprom_field { + MT_EE_CHIP_ID = 0x00, + MT_EE_VERSION_FAE = 0x02, + MT_EE_VERSION_EE = 0x03, + MT_EE_MAC_ADDR = 0x04, + MT_EE_NIC_CONF_0 = 0x34, + MT_EE_NIC_CONF_1 = 0x36, + MT_EE_COUNTRY_REGION = 0x39, + MT_EE_FREQ_OFFSET = 0x3a, + MT_EE_NIC_CONF_2 = 0x42, + + MT_EE_LNA_GAIN = 0x44, + MT_EE_RSSI_OFFSET = 0x46, + + MT_EE_TX_POWER_DELTA_BW40 = 0x50, + MT_EE_TX_POWER_OFFSET = 0x52, + + MT_EE_TX_TSSI_SLOPE = 0x6e, + MT_EE_TX_TSSI_OFFSET_GROUP = 0x6f, + MT_EE_TX_TSSI_OFFSET = 0x76, + + MT_EE_TX_TSSI_TARGET_POWER = 0xd0, + MT_EE_REF_TEMP = 0xd1, + MT_EE_FREQ_OFFSET_COMPENSATION = 0xdb, + MT_EE_TX_POWER_BYRATE_BASE = 0xde, + + MT_EE_USAGE_MAP_START = 0x1e0, + MT_EE_USAGE_MAP_END = 0x1fc, +}; + +#define MT_EE_NIC_CONF_0_RX_PATH GENMASK(3, 0) +#define MT_EE_NIC_CONF_0_TX_PATH GENMASK(7, 4) +#define MT_EE_NIC_CONF_0_BOARD_TYPE GENMASK(13, 12) + +#define MT_EE_NIC_CONF_1_HW_RF_CTRL BIT(0) +#define MT_EE_NIC_CONF_1_TEMP_TX_ALC BIT(1) +#define MT_EE_NIC_CONF_1_LNA_EXT_2G BIT(2) +#define MT_EE_NIC_CONF_1_LNA_EXT_5G BIT(3) +#define MT_EE_NIC_CONF_1_TX_ALC_EN BIT(13) + +#define MT_EE_NIC_CONF_2_RX_STREAM GENMASK(3, 0) +#define MT_EE_NIC_CONF_2_TX_STREAM GENMASK(7, 4) +#define MT_EE_NIC_CONF_2_HW_ANTDIV BIT(8) +#define MT_EE_NIC_CONF_2_XTAL_OPTION GENMASK(10, 9) +#define MT_EE_NIC_CONF_2_TEMP_DISABLE BIT(11) +#define MT_EE_NIC_CONF_2_COEX_METHOD GENMASK(15, 13) + +#define MT_EE_TX_POWER_BYRATE(i) (MT_EE_TX_POWER_BYRATE_BASE + \ + (i) * 4) + +#define MT_EFUSE_USAGE_MAP_SIZE (MT_EE_USAGE_MAP_END - \ + MT_EE_USAGE_MAP_START + 1) + +enum mt7601u_eeprom_access_modes { + MT_EE_READ = 0, + MT_EE_PHYSICAL_READ = 1, +}; + +struct power_per_rate { + u8 raw; /* validated s6 value */ + s8 bw20; /* sign-extended int */ + s8 bw40; /* sign-extended int */ +}; + +/* Power per rate - one value per two rates */ +struct mt7601u_rate_power { + struct power_per_rate cck[2]; + struct power_per_rate ofdm[4]; + struct power_per_rate ht[4]; +}; + +struct reg_channel_bounds { + u8 start; + u8 num; +}; + +struct mt7601u_eeprom_params { + bool tssi_enabled; + u8 rf_freq_off; + s8 rssi_offset[2]; + s8 ref_temp; + s8 lna_gain; + + u8 chan_pwr[14]; + struct mt7601u_rate_power power_rate_table; + s8 real_cck_bw20[2]; + + /* TSSI stuff - only with internal TX ALC */ + struct tssi_data { + int tx0_delta_offset; + u8 slope; + u8 offset[3]; + } tssi_data; + + struct reg_channel_bounds reg; +}; + +int mt7601u_eeprom_init(struct mt7601u_dev *dev); + +static inline u32 s6_validate(u32 reg) +{ + WARN_ON(reg & ~GENMASK(5, 0)); + return reg & GENMASK(5, 0); +} + +static inline int s6_to_int(u32 reg) +{ + int s6; + + s6 = s6_validate(reg); + if (s6 & BIT(5)) + s6 -= BIT(6); + + return s6; +} + +static inline u32 int_to_s6(int val) +{ + if (val < -0x20) + return 0x20; + if (val > 0x1f) + return 0x1f; + + return val & 0x3f; +} + +#endif diff --git a/linux-bsp/drivers/mt7601u-sta/init.c b/linux-bsp/drivers/mt7601u-sta/init.c new file mode 100644 index 0000000..5f0f562 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/init.c @@ -0,0 +1,639 @@ +/* + * (c) Copyright 2002-2010, Ralink Technology, Inc. + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/version.h> + +#include "mt7601u.h" +#include "eeprom.h" +#include "trace.h" +#include "mcu.h" + +#include "initvals.h" + +static void +mt7601u_set_wlan_state(struct mt7601u_dev *dev, u32 val, bool enable) +{ + int i; + + /* Note: we don't turn off WLAN_CLK because that makes the device + * not respond properly on the probe path. + * In case anyone (PSM?) wants to use this function we can + * bring the clock stuff back and fixup the probe path. + */ + + if (enable) + val |= (MT_WLAN_FUN_CTRL_WLAN_EN | + MT_WLAN_FUN_CTRL_WLAN_CLK_EN); + else + val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN); + + mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); + udelay(20); + + if (enable) { + set_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state); + } else { + clear_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state); + return; + } + + for (i = 200; i; i--) { + val = mt7601u_rr(dev, MT_CMB_CTRL); + + if (val & MT_CMB_CTRL_XTAL_RDY && val & MT_CMB_CTRL_PLL_LD) + break; + + udelay(20); + } + + /* Note: vendor driver tries to disable/enable wlan here and retry + * but the code which does it is so buggy it must have never + * triggered, so don't bother. + */ + if (!i) + dev_err(dev->dev, "Error: PLL and XTAL check failed!\n"); +} + +static void mt7601u_chip_onoff(struct mt7601u_dev *dev, bool enable, bool reset) +{ + u32 val; + + mutex_lock(&dev->hw_atomic_mutex); + + val = mt7601u_rr(dev, MT_WLAN_FUN_CTRL); + + if (reset) { + val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN; + val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; + + if (val & MT_WLAN_FUN_CTRL_WLAN_EN) { + val |= (MT_WLAN_FUN_CTRL_WLAN_RESET | + MT_WLAN_FUN_CTRL_WLAN_RESET_RF); + mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); + udelay(20); + + val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET | + MT_WLAN_FUN_CTRL_WLAN_RESET_RF); + } + } + + mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); + udelay(20); + + mt7601u_set_wlan_state(dev, val, enable); + + mutex_unlock(&dev->hw_atomic_mutex); +} + +static void mt7601u_reset_csr_bbp(struct mt7601u_dev *dev) +{ + mt7601u_wr(dev, MT_MAC_SYS_CTRL, (MT_MAC_SYS_CTRL_RESET_CSR | + MT_MAC_SYS_CTRL_RESET_BBP)); + mt7601u_wr(dev, MT_USB_DMA_CFG, 0); + msleep(1); + mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0); +} + +static void mt7601u_init_usb_dma(struct mt7601u_dev *dev) +{ + u32 val; + + val = MT76_SET(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, MT_USB_AGGR_TIMEOUT) | + MT76_SET(MT_USB_DMA_CFG_RX_BULK_AGG_LMT, MT_USB_AGGR_SIZE_LIMIT) | + MT_USB_DMA_CFG_RX_BULK_EN | + MT_USB_DMA_CFG_TX_BULK_EN; + if (dev->in_max_packet == 512) + val |= MT_USB_DMA_CFG_RX_BULK_AGG_EN; + mt7601u_wr(dev, MT_USB_DMA_CFG, val); + + val |= MT_USB_DMA_CFG_UDMA_RX_WL_DROP; + mt7601u_wr(dev, MT_USB_DMA_CFG, val); + val &= ~MT_USB_DMA_CFG_UDMA_RX_WL_DROP; + mt7601u_wr(dev, MT_USB_DMA_CFG, val); +} + +static int mt7601u_init_bbp(struct mt7601u_dev *dev) +{ + int ret; + + ret = mt7601u_wait_bbp_ready(dev); + if (ret) + return ret; + + ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, bbp_common_vals, + ARRAY_SIZE(bbp_common_vals)); + if (ret) + return ret; + + return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, bbp_chip_vals, + ARRAY_SIZE(bbp_chip_vals)); +} + +static void +mt76_init_beacon_offsets(struct mt7601u_dev *dev) +{ + u16 base = MT_BEACON_BASE; + u32 regs[4] = {}; + int i; + + for (i = 0; i < 16; i++) { + u16 addr = dev->beacon_offsets[i]; + + regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4)); + } + + for (i = 0; i < 4; i++) + mt7601u_wr(dev, MT_BCN_OFFSET(i), regs[i]); +} + +static int mt7601u_write_mac_initvals(struct mt7601u_dev *dev) +{ + int ret; + + ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, mac_common_vals, + ARRAY_SIZE(mac_common_vals)); + if (ret) + return ret; + ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, + mac_chip_vals, ARRAY_SIZE(mac_chip_vals)); + if (ret) + return ret; + + mt76_init_beacon_offsets(dev); + + mt7601u_wr(dev, MT_AUX_CLK_CFG, 0); + + return 0; +} + +static int mt7601u_init_wcid_mem(struct mt7601u_dev *dev) +{ + u32 *vals; + int i, ret; + + vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL); + if (!vals) + return -ENOMEM; + + for (i = 0; i < N_WCIDS; i++) { + vals[i * 2] = 0xffffffff; + vals[i * 2 + 1] = 0x00ffffff; + } + + ret = mt7601u_burst_write_regs(dev, MT_WCID_ADDR_BASE, + vals, N_WCIDS * 2); + kfree(vals); + + return ret; +} + +static int mt7601u_init_key_mem(struct mt7601u_dev *dev) +{ + u32 vals[4] = {}; + + return mt7601u_burst_write_regs(dev, MT_SKEY_MODE_BASE_0, + vals, ARRAY_SIZE(vals)); +} + +static int mt7601u_init_wcid_attr_mem(struct mt7601u_dev *dev) +{ + u32 *vals; + int i, ret; + + vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL); + if (!vals) + return -ENOMEM; + + for (i = 0; i < N_WCIDS * 2; i++) + vals[i] = 1; + + ret = mt7601u_burst_write_regs(dev, MT_WCID_ATTR_BASE, + vals, N_WCIDS * 2); + kfree(vals); + + return ret; +} + +static void mt7601u_reset_counters(struct mt7601u_dev *dev) +{ + mt7601u_rr(dev, MT_RX_STA_CNT0); + mt7601u_rr(dev, MT_RX_STA_CNT1); + mt7601u_rr(dev, MT_RX_STA_CNT2); + mt7601u_rr(dev, MT_TX_STA_CNT0); + mt7601u_rr(dev, MT_TX_STA_CNT1); + mt7601u_rr(dev, MT_TX_STA_CNT2); +} + +int mt7601u_mac_start(struct mt7601u_dev *dev) +{ + mt7601u_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); + + if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | + MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 200000)) + return -ETIMEDOUT; + + dev->rxfilter = MT_RX_FILTR_CFG_CRC_ERR | + MT_RX_FILTR_CFG_PHY_ERR | MT_RX_FILTR_CFG_PROMISC | + MT_RX_FILTR_CFG_VER_ERR | MT_RX_FILTR_CFG_DUP | + MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_CFEND | + MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS | + MT_RX_FILTR_CFG_RTS | MT_RX_FILTR_CFG_PSPOLL | + MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV; + mt7601u_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); + + mt7601u_wr(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); + + if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | + MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 50)) + return -ETIMEDOUT; + + return 0; +} + +static void mt7601u_mac_stop_hw(struct mt7601u_dev *dev) +{ + int i, ok; + + if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) + return; + + mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN | + MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN | + MT_BEACON_TIME_CFG_BEACON_TX); + + if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000)) + dev_warn(dev->dev, "Warning: TX DMA did not stop!\n"); + + /* Page count on TxQ */ + i = 200; + while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) || + (mt76_rr(dev, 0x0a30) & 0x000000ff) || + (mt76_rr(dev, 0x0a34) & 0x00ff00ff))) + msleep(10); + + if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000)) + dev_warn(dev->dev, "Warning: MAC TX did not stop!\n"); + + mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX | + MT_MAC_SYS_CTRL_ENABLE_TX); + + /* Page count on RxQ */ + ok = 0; + i = 200; + while (i--) { + if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) && + !mt76_rr(dev, 0x0a30) && + !mt76_rr(dev, 0x0a34)) { + if (ok++ > 5) + break; + continue; + } + msleep(1); + } + + if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000)) + dev_warn(dev->dev, "Warning: MAC RX did not stop!\n"); + + if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000)) + dev_warn(dev->dev, "Warning: RX DMA did not stop!\n"); +} + +void mt7601u_mac_stop(struct mt7601u_dev *dev) +{ + mt7601u_mac_stop_hw(dev); + flush_delayed_work(&dev->stat_work); + cancel_delayed_work_sync(&dev->stat_work); +} + +static void mt7601u_stop_hardware(struct mt7601u_dev *dev) +{ + mt7601u_chip_onoff(dev, false, false); +} + +int mt7601u_init_hardware(struct mt7601u_dev *dev) +{ + static const u16 beacon_offsets[16] = { + /* 512 byte per beacon */ + 0xc000, 0xc200, 0xc400, 0xc600, + 0xc800, 0xca00, 0xcc00, 0xce00, + 0xd000, 0xd200, 0xd400, 0xd600, + 0xd800, 0xda00, 0xdc00, 0xde00 + }; + int ret; + + dev->beacon_offsets = beacon_offsets; + + mt7601u_chip_onoff(dev, true, false); + + ret = mt7601u_wait_asic_ready(dev); + if (ret) + goto err; + ret = mt7601u_mcu_init(dev); + if (ret) + goto err; + + if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG, + MT_WPDMA_GLO_CFG_TX_DMA_BUSY | + MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) { + ret = -EIO; + goto err; + } + + /* Wait for ASIC ready after FW load. */ + ret = mt7601u_wait_asic_ready(dev); + if (ret) + goto err; + + mt7601u_reset_csr_bbp(dev); + mt7601u_init_usb_dma(dev); + + ret = mt7601u_mcu_cmd_init(dev); + if (ret) + goto err; + ret = mt7601u_dma_init(dev); + if (ret) + goto err_mcu; + ret = mt7601u_write_mac_initvals(dev); + if (ret) + goto err_rx; + + if (!mt76_poll_msec(dev, MT_MAC_STATUS, + MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 100)) { + ret = -EIO; + goto err_rx; + } + + ret = mt7601u_init_bbp(dev); + if (ret) + goto err_rx; + ret = mt7601u_init_wcid_mem(dev); + if (ret) + goto err_rx; + ret = mt7601u_init_key_mem(dev); + if (ret) + goto err_rx; + ret = mt7601u_init_wcid_attr_mem(dev); + if (ret) + goto err_rx; + + mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN | + MT_BEACON_TIME_CFG_SYNC_MODE | + MT_BEACON_TIME_CFG_TBTT_EN | + MT_BEACON_TIME_CFG_BEACON_TX)); + + mt7601u_reset_counters(dev); + + mt7601u_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); + + mt7601u_wr(dev, MT_TXOP_CTRL_CFG, MT76_SET(MT_TXOP_TRUN_EN, 0x3f) | + MT76_SET(MT_TXOP_EXT_CCA_DLY, 0x58)); + + ret = mt7601u_eeprom_init(dev); + if (ret) + goto err_rx; + + ret = mt7601u_phy_init(dev); + if (ret) + goto err_rx; + + mt7601u_set_rx_path(dev, 0); + mt7601u_set_tx_dac(dev, 0); + + mt7601u_mac_set_ctrlch(dev, false); + mt7601u_bbp_set_ctrlch(dev, false); + mt7601u_bbp_set_bw(dev, MT_BW_20); + + return 0; + +err_rx: + mt7601u_dma_cleanup(dev); +err_mcu: + mt7601u_mcu_cmd_deinit(dev); +err: + mt7601u_chip_onoff(dev, false, false); + return ret; +} + +void mt7601u_cleanup(struct mt7601u_dev *dev) +{ + if (!test_and_clear_bit(MT7601U_STATE_INITIALIZED, &dev->state)) + return; + + mt7601u_stop_hardware(dev); + mt7601u_dma_cleanup(dev); + mt7601u_mcu_cmd_deinit(dev); +} + +struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev) +{ + struct ieee80211_hw *hw; + struct mt7601u_dev *dev; + + hw = ieee80211_alloc_hw(sizeof(*dev), &mt7601u_ops); + if (!hw) + return NULL; + + dev = hw->priv; + dev->dev = pdev; + dev->hw = hw; + mutex_init(&dev->vendor_req_mutex); + mutex_init(&dev->reg_atomic_mutex); + mutex_init(&dev->hw_atomic_mutex); + mutex_init(&dev->mutex); + spin_lock_init(&dev->tx_lock); + spin_lock_init(&dev->rx_lock); + spin_lock_init(&dev->lock); + spin_lock_init(&dev->mac_lock); + spin_lock_init(&dev->con_mon_lock); + atomic_set(&dev->avg_ampdu_len, 1); + skb_queue_head_init(&dev->tx_skb_done); + + dev->stat_wq = alloc_workqueue("mt7601u", WQ_UNBOUND, 0); + if (!dev->stat_wq) { + ieee80211_free_hw(hw); + return NULL; + } + + return dev; +} + +#define CHAN2G(_idx, _freq) { \ + .band = NL80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_idx), \ + .max_power = 30, \ +} + +static const struct ieee80211_channel mt76_channels_2ghz[] = { + CHAN2G(1, 2412), + CHAN2G(2, 2417), + CHAN2G(3, 2422), + CHAN2G(4, 2427), + CHAN2G(5, 2432), + CHAN2G(6, 2437), + CHAN2G(7, 2442), + CHAN2G(8, 2447), + CHAN2G(9, 2452), + CHAN2G(10, 2457), + CHAN2G(11, 2462), + CHAN2G(12, 2467), + CHAN2G(13, 2472), + CHAN2G(14, 2484), +}; + +#define CCK_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ + .hw_value = (MT_PHY_TYPE_CCK << 8) | _idx, \ + .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + _idx), \ +} + +#define OFDM_RATE(_idx, _rate) { \ + .bitrate = _rate, \ + .hw_value = (MT_PHY_TYPE_OFDM << 8) | _idx, \ + .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | _idx, \ +} + +static struct ieee80211_rate mt76_rates[] = { + CCK_RATE(0, 10), + CCK_RATE(1, 20), + CCK_RATE(2, 55), + CCK_RATE(3, 110), + OFDM_RATE(0, 60), + OFDM_RATE(1, 90), + OFDM_RATE(2, 120), + OFDM_RATE(3, 180), + OFDM_RATE(4, 240), + OFDM_RATE(5, 360), + OFDM_RATE(6, 480), + OFDM_RATE(7, 540), +}; + +static int +mt76_init_sband(struct mt7601u_dev *dev, struct ieee80211_supported_band *sband, + const struct ieee80211_channel *chan, int n_chan, + struct ieee80211_rate *rates, int n_rates) +{ + struct ieee80211_sta_ht_cap *ht_cap; + void *chanlist; + int size; + + size = n_chan * sizeof(*chan); + chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); + if (!chanlist) + return -ENOMEM; + + sband->channels = chanlist; + sband->n_channels = n_chan; + sband->bitrates = rates; + sband->n_bitrates = n_rates; + + ht_cap = &sband->ht_cap; + ht_cap->ht_supported = true; + ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | + (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + + ht_cap->mcs.rx_mask[0] = 0xff; + ht_cap->mcs.rx_mask[4] = 0x1; + ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_2; + + dev->chandef.chan = &sband->channels[0]; + + return 0; +} + +static int +mt76_init_sband_2g(struct mt7601u_dev *dev) +{ + dev->sband_2g = devm_kzalloc(dev->dev, sizeof(*dev->sband_2g), + GFP_KERNEL); + dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = dev->sband_2g; + + WARN_ON(dev->ee->reg.start - 1 + dev->ee->reg.num > + ARRAY_SIZE(mt76_channels_2ghz)); + + return mt76_init_sband(dev, dev->sband_2g, + &mt76_channels_2ghz[dev->ee->reg.start - 1], + dev->ee->reg.num, + mt76_rates, ARRAY_SIZE(mt76_rates)); +} + +int mt7601u_register_device(struct mt7601u_dev *dev) +{ + struct ieee80211_hw *hw = dev->hw; + struct wiphy *wiphy = hw->wiphy; + int ret; + + /* Reserve WCID 0 for mcast - thanks to this APs WCID will go to + * entry no. 1 like it does in the vendor driver. + */ + dev->wcid_mask[0] |= 1; + + /* init fake wcid for monitor interfaces */ + dev->mon_wcid = devm_kmalloc(dev->dev, sizeof(*dev->mon_wcid), + GFP_KERNEL); + if (!dev->mon_wcid) + return -ENOMEM; + dev->mon_wcid->idx = 0xff; + dev->mon_wcid->hw_key_idx = -1; + + SET_IEEE80211_DEV(hw, dev->dev); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) +#define ieee80211_hw_set(hw, flag) (hw)->flags |= IEEE80211_HW_ ## flag; +#endif + + hw->queues = 4; + ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, PS_NULLFUNC_STACK); + ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); + ieee80211_hw_set(hw, AMPDU_AGGREGATION); +#ifdef MAC80211_IS_PATCHED + ieee80211_hw_set(hw, TX_STATS_EVERY_MPDU); +#endif + ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); + hw->max_rates = 1; + hw->max_report_rates = 7; + hw->max_rate_tries = 1; + + hw->sta_data_size = sizeof(struct mt76_sta); + hw->vif_data_size = sizeof(struct mt76_vif); + + SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); + + wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + + ret = mt76_init_sband_2g(dev); + if (ret) + return ret; + + INIT_DELAYED_WORK(&dev->mac_work, mt7601u_mac_work); + INIT_DELAYED_WORK(&dev->stat_work, mt7601u_tx_stat); + + ret = ieee80211_register_hw(hw); + if (ret) + return ret; + + mt7601u_init_debugfs(dev); + + return 0; +} diff --git a/linux-bsp/drivers/mt7601u-sta/initvals.h b/linux-bsp/drivers/mt7601u-sta/initvals.h new file mode 100644 index 0000000..ec11ff6 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/initvals.h @@ -0,0 +1,164 @@ +/* + * (c) Copyright 2002-2010, Ralink Technology, Inc. + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT7601U_INITVALS_H +#define __MT7601U_INITVALS_H + +static const struct mt76_reg_pair bbp_common_vals[] = { + { 65, 0x2c }, + { 66, 0x38 }, + { 68, 0x0b }, + { 69, 0x12 }, + { 70, 0x0a }, + { 73, 0x10 }, + { 81, 0x37 }, + { 82, 0x62 }, + { 83, 0x6a }, + { 84, 0x99 }, + { 86, 0x00 }, + { 91, 0x04 }, + { 92, 0x00 }, + { 103, 0x00 }, + { 105, 0x05 }, + { 106, 0x35 }, +}; + +static const struct mt76_reg_pair bbp_chip_vals[] = { + { 1, 0x04 }, { 4, 0x40 }, { 20, 0x06 }, { 31, 0x08 }, + /* CCK Tx Control */ + { 178, 0xff }, + /* AGC/Sync controls */ + { 66, 0x14 }, { 68, 0x8b }, { 69, 0x12 }, { 70, 0x09 }, + { 73, 0x11 }, { 75, 0x60 }, { 76, 0x44 }, { 84, 0x9a }, + { 86, 0x38 }, { 91, 0x07 }, { 92, 0x02 }, + /* Rx Path Controls */ + { 99, 0x50 }, { 101, 0x00 }, { 103, 0xc0 }, { 104, 0x92 }, + { 105, 0x3c }, { 106, 0x03 }, { 128, 0x12 }, + /* Change RXWI content: Gain Report */ + { 142, 0x04 }, { 143, 0x37 }, + /* Change RXWI content: Antenna Report */ + { 142, 0x03 }, { 143, 0x99 }, + /* Calibration Index Register */ + /* CCK Receiver Control */ + { 160, 0xeb }, { 161, 0xc4 }, { 162, 0x77 }, { 163, 0xf9 }, + { 164, 0x88 }, { 165, 0x80 }, { 166, 0xff }, { 167, 0xe4 }, + /* Added AGC controls - these AGC/GLRT registers are accessed + * through R195 and R196. + */ + { 195, 0x00 }, { 196, 0x00 }, + { 195, 0x01 }, { 196, 0x04 }, + { 195, 0x02 }, { 196, 0x20 }, + { 195, 0x03 }, { 196, 0x0a }, + { 195, 0x06 }, { 196, 0x16 }, + { 195, 0x07 }, { 196, 0x05 }, + { 195, 0x08 }, { 196, 0x37 }, + { 195, 0x0a }, { 196, 0x15 }, + { 195, 0x0b }, { 196, 0x17 }, + { 195, 0x0c }, { 196, 0x06 }, + { 195, 0x0d }, { 196, 0x09 }, + { 195, 0x0e }, { 196, 0x05 }, + { 195, 0x0f }, { 196, 0x09 }, + { 195, 0x10 }, { 196, 0x20 }, + { 195, 0x20 }, { 196, 0x17 }, + { 195, 0x21 }, { 196, 0x06 }, + { 195, 0x22 }, { 196, 0x09 }, + { 195, 0x23 }, { 196, 0x17 }, + { 195, 0x24 }, { 196, 0x06 }, + { 195, 0x25 }, { 196, 0x09 }, + { 195, 0x26 }, { 196, 0x17 }, + { 195, 0x27 }, { 196, 0x06 }, + { 195, 0x28 }, { 196, 0x09 }, + { 195, 0x29 }, { 196, 0x05 }, + { 195, 0x2a }, { 196, 0x09 }, + { 195, 0x80 }, { 196, 0x8b }, + { 195, 0x81 }, { 196, 0x12 }, + { 195, 0x82 }, { 196, 0x09 }, + { 195, 0x83 }, { 196, 0x17 }, + { 195, 0x84 }, { 196, 0x11 }, + { 195, 0x85 }, { 196, 0x00 }, + { 195, 0x86 }, { 196, 0x00 }, + { 195, 0x87 }, { 196, 0x18 }, + { 195, 0x88 }, { 196, 0x60 }, + { 195, 0x89 }, { 196, 0x44 }, + { 195, 0x8a }, { 196, 0x8b }, + { 195, 0x8b }, { 196, 0x8b }, + { 195, 0x8c }, { 196, 0x8b }, + { 195, 0x8d }, { 196, 0x8b }, + { 195, 0x8e }, { 196, 0x09 }, + { 195, 0x8f }, { 196, 0x09 }, + { 195, 0x90 }, { 196, 0x09 }, + { 195, 0x91 }, { 196, 0x09 }, + { 195, 0x92 }, { 196, 0x11 }, + { 195, 0x93 }, { 196, 0x11 }, + { 195, 0x94 }, { 196, 0x11 }, + { 195, 0x95 }, { 196, 0x11 }, + /* PPAD */ + { 47, 0x80 }, { 60, 0x80 }, { 150, 0xd2 }, { 151, 0x32 }, + { 152, 0x23 }, { 153, 0x41 }, { 154, 0x00 }, { 155, 0x4f }, + { 253, 0x7e }, { 195, 0x30 }, { 196, 0x32 }, { 195, 0x31 }, + { 196, 0x23 }, { 195, 0x32 }, { 196, 0x45 }, { 195, 0x35 }, + { 196, 0x4a }, { 195, 0x36 }, { 196, 0x5a }, { 195, 0x37 }, + { 196, 0x5a }, +}; + +static const struct mt76_reg_pair mac_common_vals[] = { + { MT_LEGACY_BASIC_RATE, 0x0000013f }, + { MT_HT_BASIC_RATE, 0x00008003 }, + { MT_MAC_SYS_CTRL, 0x00000000 }, + { MT_RX_FILTR_CFG, 0x00017f97 }, + { MT_BKOFF_SLOT_CFG, 0x00000209 }, + { MT_TX_SW_CFG0, 0x00000000 }, + { MT_TX_SW_CFG1, 0x00080606 }, + { MT_TX_LINK_CFG, 0x00001020 }, + { MT_TX_TIMEOUT_CFG, 0x000a2090 }, + { MT_MAX_LEN_CFG, 0x00003fff }, + { MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f }, + { MT_PBF_RX_MAX_PCNT, 0x0000009f }, + { MT_TX_RETRY_CFG, 0x47d01f0f }, + { MT_AUTO_RSP_CFG, 0x00000013 }, + { MT_CCK_PROT_CFG, 0x05740003 }, + { MT_OFDM_PROT_CFG, 0x05740003 }, + { MT_MM40_PROT_CFG, 0x03f44084 }, + { MT_GF20_PROT_CFG, 0x01744004 }, + { MT_GF40_PROT_CFG, 0x03f44084 }, + { MT_MM20_PROT_CFG, 0x01744004 }, + { MT_TXOP_CTRL_CFG, 0x0000583f }, + { MT_TX_RTS_CFG, 0x01092b20 }, + { MT_EXP_ACK_TIME, 0x002400ca }, + { MT_TXOP_HLDR_ET, 0x00000002 }, + { MT_XIFS_TIME_CFG, 0x33a41010 }, + { MT_PWR_PIN_CFG, 0x00000000 }, +}; + +static const struct mt76_reg_pair mac_chip_vals[] = { + { MT_TSO_CTRL, 0x00006050 }, + { MT_BCN_OFFSET(0), 0x18100800 }, + { MT_BCN_OFFSET(1), 0x38302820 }, + { MT_PBF_SYS_CTRL, 0x00080c00 }, + { MT_PBF_CFG, 0x7f723c1f }, + { MT_FCE_PSE_CTRL, 0x00000001 }, + { MT_PAUSE_ENABLE_CONTROL1, 0x00000000 }, + { MT_TX0_RF_GAIN_CORR, 0x003b0005 }, + { MT_TX0_RF_GAIN_ATTEN, 0x00006900 }, + { MT_TX0_BB_GAIN_ATTEN, 0x00000400 }, + { MT_TX_ALC_VGA3, 0x00060006 }, + { MT_TX_SW_CFG0, 0x00000402 }, + { MT_TX_SW_CFG1, 0x00000000 }, + { MT_TX_SW_CFG2, 0x00000000 }, + { MT_HEADER_TRANS_CTRL_REG, 0x00000000 }, + { MT_FCE_CSO, 0x0000030f }, + { MT_FCE_PARAMETERS, 0x00256f0f }, +}; + +#endif diff --git a/linux-bsp/drivers/mt7601u-sta/initvals_phy.h b/linux-bsp/drivers/mt7601u-sta/initvals_phy.h new file mode 100644 index 0000000..a2bdc3e --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/initvals_phy.h @@ -0,0 +1,291 @@ +/* + * (c) Copyright 2002-2010, Ralink Technology, Inc. + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT7601U_PHY_INITVALS_H +#define __MT7601U_PHY_INITVALS_H + +#define RF_REG_PAIR(bank, reg, value) \ + { MT_MCU_MEMMAP_RF | (bank) << 16 | (reg), value } + +static const struct mt76_reg_pair rf_central[] = { + /* Bank 0 - for central blocks: BG, PLL, XTAL, LO, ADC/DAC */ + RF_REG_PAIR(0, 0, 0x02), + RF_REG_PAIR(0, 1, 0x01), + RF_REG_PAIR(0, 2, 0x11), + RF_REG_PAIR(0, 3, 0xff), + RF_REG_PAIR(0, 4, 0x0a), + RF_REG_PAIR(0, 5, 0x20), + RF_REG_PAIR(0, 6, 0x00), + /* B/G */ + RF_REG_PAIR(0, 7, 0x00), + RF_REG_PAIR(0, 8, 0x00), + RF_REG_PAIR(0, 9, 0x00), + RF_REG_PAIR(0, 10, 0x00), + RF_REG_PAIR(0, 11, 0x21), + /* XO */ + RF_REG_PAIR(0, 13, 0x00), /* 40mhz xtal */ + /* RF_REG_PAIR(0, 13, 0x13), */ /* 20mhz xtal */ + RF_REG_PAIR(0, 14, 0x7c), + RF_REG_PAIR(0, 15, 0x22), + RF_REG_PAIR(0, 16, 0x80), + /* PLL */ + RF_REG_PAIR(0, 17, 0x99), + RF_REG_PAIR(0, 18, 0x99), + RF_REG_PAIR(0, 19, 0x09), + RF_REG_PAIR(0, 20, 0x50), + RF_REG_PAIR(0, 21, 0xb0), + RF_REG_PAIR(0, 22, 0x00), + RF_REG_PAIR(0, 23, 0xc5), + RF_REG_PAIR(0, 24, 0xfc), + RF_REG_PAIR(0, 25, 0x40), + RF_REG_PAIR(0, 26, 0x4d), + RF_REG_PAIR(0, 27, 0x02), + RF_REG_PAIR(0, 28, 0x72), + RF_REG_PAIR(0, 29, 0x01), + RF_REG_PAIR(0, 30, 0x00), + RF_REG_PAIR(0, 31, 0x00), + /* test ports */ + RF_REG_PAIR(0, 32, 0x00), + RF_REG_PAIR(0, 33, 0x00), + RF_REG_PAIR(0, 34, 0x23), + RF_REG_PAIR(0, 35, 0x01), /* change setting to reduce spurs */ + RF_REG_PAIR(0, 36, 0x00), + RF_REG_PAIR(0, 37, 0x00), + /* ADC/DAC */ + RF_REG_PAIR(0, 38, 0x00), + RF_REG_PAIR(0, 39, 0x20), + RF_REG_PAIR(0, 40, 0x00), + RF_REG_PAIR(0, 41, 0xd0), + RF_REG_PAIR(0, 42, 0x1b), + RF_REG_PAIR(0, 43, 0x02), + RF_REG_PAIR(0, 44, 0x00), +}; + +static const struct mt76_reg_pair rf_channel[] = { + RF_REG_PAIR(4, 0, 0x01), + RF_REG_PAIR(4, 1, 0x00), + RF_REG_PAIR(4, 2, 0x00), + RF_REG_PAIR(4, 3, 0x00), + /* LDO */ + RF_REG_PAIR(4, 4, 0x00), + RF_REG_PAIR(4, 5, 0x08), + RF_REG_PAIR(4, 6, 0x00), + /* RX */ + RF_REG_PAIR(4, 7, 0x5b), + RF_REG_PAIR(4, 8, 0x52), + RF_REG_PAIR(4, 9, 0xb6), + RF_REG_PAIR(4, 10, 0x57), + RF_REG_PAIR(4, 11, 0x33), + RF_REG_PAIR(4, 12, 0x22), + RF_REG_PAIR(4, 13, 0x3d), + RF_REG_PAIR(4, 14, 0x3e), + RF_REG_PAIR(4, 15, 0x13), + RF_REG_PAIR(4, 16, 0x22), + RF_REG_PAIR(4, 17, 0x23), + RF_REG_PAIR(4, 18, 0x02), + RF_REG_PAIR(4, 19, 0xa4), + RF_REG_PAIR(4, 20, 0x01), + RF_REG_PAIR(4, 21, 0x12), + RF_REG_PAIR(4, 22, 0x80), + RF_REG_PAIR(4, 23, 0xb3), + RF_REG_PAIR(4, 24, 0x00), /* reserved */ + RF_REG_PAIR(4, 25, 0x00), /* reserved */ + RF_REG_PAIR(4, 26, 0x00), /* reserved */ + RF_REG_PAIR(4, 27, 0x00), /* reserved */ + /* LOGEN */ + RF_REG_PAIR(4, 28, 0x18), + RF_REG_PAIR(4, 29, 0xee), + RF_REG_PAIR(4, 30, 0x6b), + RF_REG_PAIR(4, 31, 0x31), + RF_REG_PAIR(4, 32, 0x5d), + RF_REG_PAIR(4, 33, 0x00), /* reserved */ + /* TX */ + RF_REG_PAIR(4, 34, 0x96), + RF_REG_PAIR(4, 35, 0x55), + RF_REG_PAIR(4, 36, 0x08), + RF_REG_PAIR(4, 37, 0xbb), + RF_REG_PAIR(4, 38, 0xb3), + RF_REG_PAIR(4, 39, 0xb3), + RF_REG_PAIR(4, 40, 0x03), + RF_REG_PAIR(4, 41, 0x00), /* reserved */ + RF_REG_PAIR(4, 42, 0x00), /* reserved */ + RF_REG_PAIR(4, 43, 0xc5), + RF_REG_PAIR(4, 44, 0xc5), + RF_REG_PAIR(4, 45, 0xc5), + RF_REG_PAIR(4, 46, 0x07), + RF_REG_PAIR(4, 47, 0xa8), + RF_REG_PAIR(4, 48, 0xef), + RF_REG_PAIR(4, 49, 0x1a), + /* PA */ + RF_REG_PAIR(4, 54, 0x07), + RF_REG_PAIR(4, 55, 0xa7), + RF_REG_PAIR(4, 56, 0xcc), + RF_REG_PAIR(4, 57, 0x14), + RF_REG_PAIR(4, 58, 0x07), + RF_REG_PAIR(4, 59, 0xa8), + RF_REG_PAIR(4, 60, 0xd7), + RF_REG_PAIR(4, 61, 0x10), + RF_REG_PAIR(4, 62, 0x1c), + RF_REG_PAIR(4, 63, 0x00), /* reserved */ +}; + +static const struct mt76_reg_pair rf_vga[] = { + RF_REG_PAIR(5, 0, 0x47), + RF_REG_PAIR(5, 1, 0x00), + RF_REG_PAIR(5, 2, 0x00), + RF_REG_PAIR(5, 3, 0x08), + RF_REG_PAIR(5, 4, 0x04), + RF_REG_PAIR(5, 5, 0x20), + RF_REG_PAIR(5, 6, 0x3a), + RF_REG_PAIR(5, 7, 0x3a), + RF_REG_PAIR(5, 8, 0x00), + RF_REG_PAIR(5, 9, 0x00), + RF_REG_PAIR(5, 10, 0x10), + RF_REG_PAIR(5, 11, 0x10), + RF_REG_PAIR(5, 12, 0x10), + RF_REG_PAIR(5, 13, 0x10), + RF_REG_PAIR(5, 14, 0x10), + RF_REG_PAIR(5, 15, 0x20), + RF_REG_PAIR(5, 16, 0x22), + RF_REG_PAIR(5, 17, 0x7c), + RF_REG_PAIR(5, 18, 0x00), + RF_REG_PAIR(5, 19, 0x00), + RF_REG_PAIR(5, 20, 0x00), + RF_REG_PAIR(5, 21, 0xf1), + RF_REG_PAIR(5, 22, 0x11), + RF_REG_PAIR(5, 23, 0x02), + RF_REG_PAIR(5, 24, 0x41), + RF_REG_PAIR(5, 25, 0x20), + RF_REG_PAIR(5, 26, 0x00), + RF_REG_PAIR(5, 27, 0xd7), + RF_REG_PAIR(5, 28, 0xa2), + RF_REG_PAIR(5, 29, 0x20), + RF_REG_PAIR(5, 30, 0x49), + RF_REG_PAIR(5, 31, 0x20), + RF_REG_PAIR(5, 32, 0x04), + RF_REG_PAIR(5, 33, 0xf1), + RF_REG_PAIR(5, 34, 0xa1), + RF_REG_PAIR(5, 35, 0x01), + RF_REG_PAIR(5, 41, 0x00), + RF_REG_PAIR(5, 42, 0x00), + RF_REG_PAIR(5, 43, 0x00), + RF_REG_PAIR(5, 44, 0x00), + RF_REG_PAIR(5, 45, 0x00), + RF_REG_PAIR(5, 46, 0x00), + RF_REG_PAIR(5, 47, 0x00), + RF_REG_PAIR(5, 48, 0x00), + RF_REG_PAIR(5, 49, 0x00), + RF_REG_PAIR(5, 50, 0x00), + RF_REG_PAIR(5, 51, 0x00), + RF_REG_PAIR(5, 52, 0x00), + RF_REG_PAIR(5, 53, 0x00), + RF_REG_PAIR(5, 54, 0x00), + RF_REG_PAIR(5, 55, 0x00), + RF_REG_PAIR(5, 56, 0x00), + RF_REG_PAIR(5, 57, 0x00), + RF_REG_PAIR(5, 58, 0x31), + RF_REG_PAIR(5, 59, 0x31), + RF_REG_PAIR(5, 60, 0x0a), + RF_REG_PAIR(5, 61, 0x02), + RF_REG_PAIR(5, 62, 0x00), + RF_REG_PAIR(5, 63, 0x00), +}; + +/* TODO: BBP178 is set to 0xff for "CCK CH14 OBW" which overrides the settings + * from channel switching. Seems stupid at best. + */ +static const struct mt76_reg_pair bbp_high_temp[] = { + { 75, 0x60 }, + { 92, 0x02 }, + { 178, 0xff }, /* For CCK CH14 OBW */ + { 195, 0x88 }, { 196, 0x60 }, +}, bbp_high_temp_bw20[] = { + { 69, 0x12 }, + { 91, 0x07 }, + { 195, 0x23 }, { 196, 0x17 }, + { 195, 0x24 }, { 196, 0x06 }, + { 195, 0x81 }, { 196, 0x12 }, + { 195, 0x83 }, { 196, 0x17 }, +}, bbp_high_temp_bw40[] = { + { 69, 0x15 }, + { 91, 0x04 }, + { 195, 0x23 }, { 196, 0x12 }, + { 195, 0x24 }, { 196, 0x08 }, + { 195, 0x81 }, { 196, 0x15 }, + { 195, 0x83 }, { 196, 0x16 }, +}, bbp_low_temp[] = { + { 178, 0xff }, /* For CCK CH14 OBW */ +}, bbp_low_temp_bw20[] = { + { 69, 0x12 }, + { 75, 0x5e }, + { 91, 0x07 }, + { 92, 0x02 }, + { 195, 0x23 }, { 196, 0x17 }, + { 195, 0x24 }, { 196, 0x06 }, + { 195, 0x81 }, { 196, 0x12 }, + { 195, 0x83 }, { 196, 0x17 }, + { 195, 0x88 }, { 196, 0x5e }, +}, bbp_low_temp_bw40[] = { + { 69, 0x15 }, + { 75, 0x5c }, + { 91, 0x04 }, + { 92, 0x03 }, + { 195, 0x23 }, { 196, 0x10 }, + { 195, 0x24 }, { 196, 0x08 }, + { 195, 0x81 }, { 196, 0x15 }, + { 195, 0x83 }, { 196, 0x16 }, + { 195, 0x88 }, { 196, 0x5b }, +}, bbp_normal_temp[] = { + { 75, 0x60 }, + { 92, 0x02 }, + { 178, 0xff }, /* For CCK CH14 OBW */ + { 195, 0x88 }, { 196, 0x60 }, +}, bbp_normal_temp_bw20[] = { + { 69, 0x12 }, + { 91, 0x07 }, + { 195, 0x23 }, { 196, 0x17 }, + { 195, 0x24 }, { 196, 0x06 }, + { 195, 0x81 }, { 196, 0x12 }, + { 195, 0x83 }, { 196, 0x17 }, +}, bbp_normal_temp_bw40[] = { + { 69, 0x15 }, + { 91, 0x04 }, + { 195, 0x23 }, { 196, 0x12 }, + { 195, 0x24 }, { 196, 0x08 }, + { 195, 0x81 }, { 196, 0x15 }, + { 195, 0x83 }, { 196, 0x16 }, +}; + +#define BBP_TABLE(arr) { arr, ARRAY_SIZE(arr), } + +static const struct reg_table { + const struct mt76_reg_pair *regs; + size_t n; +} bbp_mode_table[3][3] = { + { + BBP_TABLE(bbp_normal_temp_bw20), + BBP_TABLE(bbp_normal_temp_bw40), + BBP_TABLE(bbp_normal_temp), + }, { + BBP_TABLE(bbp_high_temp_bw20), + BBP_TABLE(bbp_high_temp_bw40), + BBP_TABLE(bbp_high_temp), + }, { + BBP_TABLE(bbp_low_temp_bw20), + BBP_TABLE(bbp_low_temp_bw40), + BBP_TABLE(bbp_low_temp), + } +}; + +#endif diff --git a/linux-bsp/drivers/mt7601u-sta/mac.c b/linux-bsp/drivers/mt7601u-sta/mac.c new file mode 100644 index 0000000..3a4b604 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/mac.c @@ -0,0 +1,581 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "mt7601u.h" +#include "trace.h" +#include <linux/etherdevice.h> + +static void +mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate) +{ + u8 idx = MT76_GET(MT_TXWI_RATE_MCS, rate); + + txrate->idx = 0; + txrate->flags = 0; + txrate->count = 1; + + switch (MT76_GET(MT_TXWI_RATE_PHY_MODE, rate)) { + case MT_PHY_TYPE_OFDM: + txrate->idx = idx + 4; + return; + case MT_PHY_TYPE_CCK: + if (idx >= 8) + idx -= 8; + + txrate->idx = idx; + return; + case MT_PHY_TYPE_HT_GF: + txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; + /* fall through */ + case MT_PHY_TYPE_HT: + txrate->flags |= IEEE80211_TX_RC_MCS; + txrate->idx = idx; + break; + default: + WARN_ON(1); + return; + } + + if (MT76_GET(MT_TXWI_RATE_BW, rate) == MT_PHY_BW_40) + txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + + if (rate & MT_TXWI_RATE_SGI) + txrate->flags |= IEEE80211_TX_RC_SHORT_GI; +} + +static void +mt76_mac_fill_tx_status(struct mt7601u_dev *dev, struct ieee80211_tx_info *info, + struct mt76_tx_status *st) +{ + struct ieee80211_tx_rate *rate = info->status.rates; + int cur_idx, last_rate; + int i; + + last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1); + mt76_mac_process_tx_rate(&rate[last_rate], st->rate); + if (last_rate < IEEE80211_TX_MAX_RATES - 1) + rate[last_rate + 1].idx = -1; + + cur_idx = rate[last_rate].idx + st->retry; + for (i = 0; i <= last_rate; i++) { + rate[i].flags = rate[last_rate].flags; + rate[i].idx = max_t(int, 0, cur_idx - i); + rate[i].count = 1; + } + + if (last_rate > 0) + rate[last_rate - 1].count = st->retry + 1 - last_rate; + +#ifdef MAC80211_IS_PATCHED + info->status.ampdu_len = atomic_read(&dev->avg_ampdu_len); +#else + info->status.ampdu_len = 1; +#endif + info->status.ampdu_ack_len = st->success; + + if (st->is_probe) + info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; + + if (st->aggr) + info->flags |= IEEE80211_TX_CTL_AMPDU | + IEEE80211_TX_STAT_AMPDU; + + if (!st->ack_req) + info->flags |= IEEE80211_TX_CTL_NO_ACK; + else if (st->success) + info->flags |= IEEE80211_TX_STAT_ACK; +} + +u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev, + const struct ieee80211_tx_rate *rate, u8 *nss_val) +{ + u16 rateval; + u8 phy, rate_idx; + u8 nss = 1; + u8 bw = 0; + + if (rate->flags & IEEE80211_TX_RC_MCS) { + rate_idx = rate->idx; + nss = 1 + (rate->idx >> 3); + phy = MT_PHY_TYPE_HT; + if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) + phy = MT_PHY_TYPE_HT_GF; + if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + bw = 1; + } else { + const struct ieee80211_rate *r; + int band = dev->chandef.chan->band; + u16 val; + + r = &dev->hw->wiphy->bands[band]->bitrates[rate->idx]; + if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + val = r->hw_value_short; + else + val = r->hw_value; + + phy = val >> 8; + rate_idx = val & 0xff; + bw = 0; + } + + rateval = MT76_SET(MT_RXWI_RATE_MCS, rate_idx); + rateval |= MT76_SET(MT_RXWI_RATE_PHY, phy); + rateval |= MT76_SET(MT_RXWI_RATE_BW, bw); + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + rateval |= MT_RXWI_RATE_SGI; + + *nss_val = nss; + return rateval; +} + +void mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid, + const struct ieee80211_tx_rate *rate) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + wcid->tx_rate = mt76_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss); + wcid->tx_rate_set = true; + spin_unlock_irqrestore(&dev->lock, flags); +} + +struct mt76_tx_status mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev) +{ + struct mt76_tx_status stat = {}; + u32 val; + + val = mt7601u_rr(dev, MT_TX_STAT_FIFO); + stat.valid = !!(val & MT_TX_STAT_FIFO_VALID); + stat.success = !!(val & MT_TX_STAT_FIFO_SUCCESS); + stat.aggr = !!(val & MT_TX_STAT_FIFO_AGGR); + stat.ack_req = !!(val & MT_TX_STAT_FIFO_ACKREQ); + stat.pktid = MT76_GET(MT_TX_STAT_FIFO_PID_TYPE, val); + stat.wcid = MT76_GET(MT_TX_STAT_FIFO_WCID, val); + stat.rate = MT76_GET(MT_TX_STAT_FIFO_RATE, val); + + return stat; +} + +void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat) +{ + struct ieee80211_tx_info info = {}; + struct ieee80211_sta *sta = NULL; + struct mt76_wcid *wcid = NULL; + void *msta; + + rcu_read_lock(); + if (stat->wcid < ARRAY_SIZE(dev->wcid)) + wcid = rcu_dereference(dev->wcid[stat->wcid]); + + if (wcid) { + msta = container_of(wcid, struct mt76_sta, wcid); + sta = container_of(msta, struct ieee80211_sta, + drv_priv); + } + + mt76_mac_fill_tx_status(dev, &info, stat); + + spin_lock_bh(&dev->mac_lock); + ieee80211_tx_status_noskb(dev->hw, sta, &info); + spin_unlock_bh(&dev->mac_lock); + + rcu_read_unlock(); +} + +void mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot, + int ht_mode) +{ + int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION; + bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + u32 prot[6]; + bool ht_rts[4] = {}; + int i; + + prot[0] = MT_PROT_NAV_SHORT | + MT_PROT_TXOP_ALLOW_ALL | + MT_PROT_RTS_THR_EN; + prot[1] = prot[0]; + if (legacy_prot) + prot[1] |= MT_PROT_CTRL_CTS2SELF; + + prot[2] = prot[4] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_BW20; + prot[3] = prot[5] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_ALL; + + if (legacy_prot) { + prot[2] |= MT_PROT_RATE_CCK_11; + prot[3] |= MT_PROT_RATE_CCK_11; + prot[4] |= MT_PROT_RATE_CCK_11; + prot[5] |= MT_PROT_RATE_CCK_11; + } else { + prot[2] |= MT_PROT_RATE_OFDM_24; + prot[3] |= MT_PROT_RATE_DUP_OFDM_24; + prot[4] |= MT_PROT_RATE_OFDM_24; + prot[5] |= MT_PROT_RATE_DUP_OFDM_24; + } + + switch (mode) { + case IEEE80211_HT_OP_MODE_PROTECTION_NONE: + break; + + case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: + ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true; + break; + + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + ht_rts[1] = ht_rts[3] = true; + break; + + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true; + break; + } + + if (non_gf) + ht_rts[2] = ht_rts[3] = true; + + for (i = 0; i < 4; i++) + if (ht_rts[i]) + prot[i + 2] |= MT_PROT_CTRL_RTS_CTS; + + for (i = 0; i < 6; i++) + mt7601u_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]); +} + +void mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb) +{ + if (short_preamb) + mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); + else + mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); +} + +void mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval) +{ + u32 val = mt7601u_rr(dev, MT_BEACON_TIME_CFG); + + val &= ~(MT_BEACON_TIME_CFG_TIMER_EN | + MT_BEACON_TIME_CFG_SYNC_MODE | + MT_BEACON_TIME_CFG_TBTT_EN); + + if (!enable) { + mt7601u_wr(dev, MT_BEACON_TIME_CFG, val); + return; + } + + val &= ~MT_BEACON_TIME_CFG_INTVAL; + val |= MT76_SET(MT_BEACON_TIME_CFG_INTVAL, interval << 4) | + MT_BEACON_TIME_CFG_TIMER_EN | + MT_BEACON_TIME_CFG_SYNC_MODE | + MT_BEACON_TIME_CFG_TBTT_EN; +} + +static void mt7601u_check_mac_err(struct mt7601u_dev *dev) +{ + u32 val = mt7601u_rr(dev, 0x10f4); + + if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5)))) + return; + + dev_err(dev->dev, "Error: MAC specific condition occurred\n"); + + mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); + udelay(10); + mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); +} + +void mt7601u_mac_work(struct work_struct *work) +{ + struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, + mac_work.work); + struct { + u32 addr_base; + u32 span; + u64 *stat_base; + } spans[] = { + { MT_RX_STA_CNT0, 3, dev->stats.rx_stat }, + { MT_TX_STA_CNT0, 3, dev->stats.tx_stat }, + { MT_TX_AGG_STAT, 1, dev->stats.aggr_stat }, + { MT_MPDU_DENSITY_CNT, 1, dev->stats.zero_len_del }, + { MT_TX_AGG_CNT_BASE0, 8, &dev->stats.aggr_n[0] }, + { MT_TX_AGG_CNT_BASE1, 8, &dev->stats.aggr_n[16] }, + }; + u32 sum, n; + int i, j, k; + + /* Note: using MCU_RANDOM_READ is actually slower then reading all the + * registers by hand. MCU takes ca. 20ms to complete read of 24 + * registers while reading them one by one will takes roughly + * 24*200us =~ 5ms. + */ + + k = 0; + n = 0; + sum = 0; + for (i = 0; i < ARRAY_SIZE(spans); i++) + for (j = 0; j < spans[i].span; j++) { + u32 val = mt7601u_rr(dev, spans[i].addr_base + j * 4); + + spans[i].stat_base[j * 2] += val & 0xffff; + spans[i].stat_base[j * 2 + 1] += val >> 16; + + /* Calculate average AMPDU length */ + if (spans[i].addr_base != MT_TX_AGG_CNT_BASE0 && + spans[i].addr_base != MT_TX_AGG_CNT_BASE1) + continue; + + n += (val >> 16) + (val & 0xffff); + sum += (val & 0xffff) * (1 + k * 2) + + (val >> 16) * (2 + k * 2); + k++; + } + + atomic_set(&dev->avg_ampdu_len, n ? DIV_ROUND_CLOSEST(sum, n) : 1); + + mt7601u_check_mac_err(dev); + + ieee80211_queue_delayed_work(dev->hw, &dev->mac_work, 10 * HZ); +} + +void +mt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac) +{ + u8 zmac[ETH_ALEN] = {}; + u32 attr; + + attr = MT76_SET(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) | + MT76_SET(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8)); + + mt76_wr(dev, MT_WCID_ATTR(idx), attr); + + if (mac) + memcpy(zmac, mac, sizeof(zmac)); + + mt7601u_addr_wr(dev, MT_WCID_ADDR(idx), zmac); +} + +void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev) +{ + struct ieee80211_sta *sta; + struct mt76_wcid *wcid; + void *msta; + u8 min_factor = 3; + int i; + + rcu_read_lock(); + for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) { + wcid = rcu_dereference(dev->wcid[i]); + if (!wcid) + continue; + + msta = container_of(wcid, struct mt76_sta, wcid); + sta = container_of(msta, struct ieee80211_sta, drv_priv); + + min_factor = min(min_factor, sta->ht_cap.ampdu_factor); + } + rcu_read_unlock(); + + mt7601u_wr(dev, MT_MAX_LEN_CFG, 0xa0fff | + MT76_SET(MT_MAX_LEN_CFG_AMPDU, min_factor)); +} + +static void +mt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate) +{ + u8 idx = MT76_GET(MT_RXWI_RATE_MCS, rate); + + switch (MT76_GET(MT_RXWI_RATE_PHY, rate)) { + case MT_PHY_TYPE_OFDM: + if (WARN_ON(idx >= 8)) + idx = 0; + idx += 4; + + status->rate_idx = idx; + return; + case MT_PHY_TYPE_CCK: + if (idx >= 8) { + idx -= 8; + status->flag |= RX_FLAG_SHORTPRE; + } + + if (WARN_ON(idx >= 4)) + idx = 0; + + status->rate_idx = idx; + return; + case MT_PHY_TYPE_HT_GF: + status->flag |= RX_FLAG_HT_GF; + /* fall through */ + case MT_PHY_TYPE_HT: + status->flag |= RX_FLAG_HT; + status->rate_idx = idx; + break; + default: + WARN_ON(1); + return; + } + + if (rate & MT_RXWI_RATE_SGI) + status->flag |= RX_FLAG_SHORT_GI; + + if (rate & MT_RXWI_RATE_STBC) + status->flag |= 1 << RX_FLAG_STBC_SHIFT; + + if (rate & MT_RXWI_RATE_BW) + status->flag |= RX_FLAG_40MHZ; +} + +static void +mt7601u_rx_monitor_beacon(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, + u16 rate, int rssi) +{ + dev->bcn_freq_off = rxwi->freq_off; + dev->bcn_phy_mode = MT76_GET(MT_RXWI_RATE_PHY, rate); + dev->avg_rssi = (dev->avg_rssi * 15) / 16 + (rssi << 8); +} + +static int +mt7601u_rx_is_our_beacon(struct mt7601u_dev *dev, u8 *data) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data; + + return ieee80211_is_beacon(hdr->frame_control) && + ether_addr_equal(hdr->addr2, dev->ap_bssid); +} + +u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb, + u8 *data, void *rxi) +{ + struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + struct mt7601u_rxwi *rxwi = rxi; + u32 len, ctl = le32_to_cpu(rxwi->ctl); + u16 rate = le16_to_cpu(rxwi->rate); + int rssi; + + len = MT76_GET(MT_RXWI_CTL_MPDU_LEN, ctl); + if (len < 10) + return 0; + + if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) { + status->flag |= RX_FLAG_DECRYPTED; + status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; + } + + status->chains = BIT(0); + rssi = mt7601u_phy_get_rssi(dev, rxwi, rate); + status->chain_signal[0] = status->signal = rssi; + status->freq = dev->chandef.chan->center_freq; + status->band = dev->chandef.chan->band; + + mt76_mac_process_rate(status, rate); + + spin_lock_bh(&dev->con_mon_lock); + if (mt7601u_rx_is_our_beacon(dev, data)) + mt7601u_rx_monitor_beacon(dev, rxwi, rate, rssi); + else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M)) + dev->avg_rssi = (dev->avg_rssi * 15) / 16 + (rssi << 8); + spin_unlock_bh(&dev->con_mon_lock); + + return len; +} + +static enum mt76_cipher_type +mt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) +{ + memset(key_data, 0, 32); + if (!key) + return MT_CIPHER_NONE; + + if (key->keylen > 32) + return MT_CIPHER_NONE; + + memcpy(key_data, key->key, key->keylen); + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return MT_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return MT_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return MT_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_CCMP: + return MT_CIPHER_AES_CCMP; + default: + return MT_CIPHER_NONE; + } +} + +int mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx, + struct ieee80211_key_conf *key) +{ + enum mt76_cipher_type cipher; + u8 key_data[32]; + u8 iv_data[8]; + u32 val; + + cipher = mt76_mac_get_key_info(key, key_data); + if (cipher == MT_CIPHER_NONE && key) + return -EINVAL; + + trace_set_key(dev, idx); + + mt7601u_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); + + memset(iv_data, 0, sizeof(iv_data)); + if (key) { + iv_data[3] = key->keyidx << 6; + if (cipher >= MT_CIPHER_TKIP) { + /* Note: start with 1 to comply with spec, + * (see comment on common/cmm_wpa.c:4291). + */ + iv_data[0] |= 1; + iv_data[3] |= 0x20; + } + } + mt7601u_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data)); + + val = mt7601u_rr(dev, MT_WCID_ATTR(idx)); + val &= ~MT_WCID_ATTR_PKEY_MODE & ~MT_WCID_ATTR_PKEY_MODE_EXT; + val |= MT76_SET(MT_WCID_ATTR_PKEY_MODE, cipher & 7) | + MT76_SET(MT_WCID_ATTR_PKEY_MODE_EXT, cipher >> 3); + val &= ~MT_WCID_ATTR_PAIRWISE; + val |= MT_WCID_ATTR_PAIRWISE * + !!(key && key->flags & IEEE80211_KEY_FLAG_PAIRWISE); + mt7601u_wr(dev, MT_WCID_ATTR(idx), val); + + return 0; +} + +int mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx, + struct ieee80211_key_conf *key) +{ + enum mt76_cipher_type cipher; + u8 key_data[32]; + u32 val; + + cipher = mt76_mac_get_key_info(key, key_data); + if (cipher == MT_CIPHER_NONE && key) + return -EINVAL; + + trace_set_shared_key(dev, vif_idx, key_idx); + + mt7601u_wr_copy(dev, MT_SKEY(vif_idx, key_idx), + key_data, sizeof(key_data)); + + val = mt76_rr(dev, MT_SKEY_MODE(vif_idx)); + val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx)); + val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx); + mt76_wr(dev, MT_SKEY_MODE(vif_idx), val); + + return 0; +} diff --git a/linux-bsp/drivers/mt7601u-sta/mac.h b/linux-bsp/drivers/mt7601u-sta/mac.h new file mode 100644 index 0000000..2c22d63 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/mac.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT76_MAC_H +#define __MT76_MAC_H + +struct mt76_tx_status { + u8 valid:1; + u8 success:1; + u8 aggr:1; + u8 ack_req:1; + u8 is_probe:1; + u8 wcid; + u8 pktid; + u8 retry; + u16 rate; +} __packed __aligned(2); + +/* Note: values in original "RSSI" and "SNR" fields are not actually what they + * are called for MT7601U, names used by this driver are educated guesses + * (see vendor mac/ral_omac.c). + */ +struct mt7601u_rxwi { + __le32 rxinfo; + + __le32 ctl; + + __le16 frag_sn; + __le16 rate; + + u8 unknown; + u8 zero[3]; + + u8 snr; + u8 ant; + u8 gain; + u8 freq_off; + + __le32 resv2; + __le32 expert_ant; +} __packed __aligned(4); + +#define MT_RXINFO_BA BIT(0) +#define MT_RXINFO_DATA BIT(1) +#define MT_RXINFO_NULL BIT(2) +#define MT_RXINFO_FRAG BIT(3) +#define MT_RXINFO_U2M BIT(4) +#define MT_RXINFO_MULTICAST BIT(5) +#define MT_RXINFO_BROADCAST BIT(6) +#define MT_RXINFO_MYBSS BIT(7) +#define MT_RXINFO_CRCERR BIT(8) +#define MT_RXINFO_ICVERR BIT(9) +#define MT_RXINFO_MICERR BIT(10) +#define MT_RXINFO_AMSDU BIT(11) +#define MT_RXINFO_HTC BIT(12) +#define MT_RXINFO_RSSI BIT(13) +#define MT_RXINFO_L2PAD BIT(14) +#define MT_RXINFO_AMPDU BIT(15) +#define MT_RXINFO_DECRYPT BIT(16) +#define MT_RXINFO_BSSIDX3 BIT(17) +#define MT_RXINFO_WAPI_KEY BIT(18) +#define MT_RXINFO_PN_LEN GENMASK(21, 19) +#define MT_RXINFO_SW_PKT_80211 BIT(22) +#define MT_RXINFO_TCP_SUM_BYPASS BIT(28) +#define MT_RXINFO_IP_SUM_BYPASS BIT(29) +#define MT_RXINFO_TCP_SUM_ERR BIT(30) +#define MT_RXINFO_IP_SUM_ERR BIT(31) + +#define MT_RXWI_CTL_WCID GENMASK(7, 0) +#define MT_RXWI_CTL_KEY_IDX GENMASK(9, 8) +#define MT_RXWI_CTL_BSS_IDX GENMASK(12, 10) +#define MT_RXWI_CTL_UDF GENMASK(15, 13) +#define MT_RXWI_CTL_MPDU_LEN GENMASK(27, 16) +#define MT_RXWI_CTL_TID GENMASK(31, 28) + +#define MT_RXWI_FRAG GENMASK(3, 0) +#define MT_RXWI_SN GENMASK(15, 4) + +#define MT_RXWI_RATE_MCS GENMASK(6, 0) +#define MT_RXWI_RATE_BW BIT(7) +#define MT_RXWI_RATE_SGI BIT(8) +#define MT_RXWI_RATE_STBC GENMASK(10, 9) +#define MT_RXWI_RATE_ETXBF BIT(11) +#define MT_RXWI_RATE_SND BIT(12) +#define MT_RXWI_RATE_ITXBF BIT(13) +#define MT_RXWI_RATE_PHY GENMASK(15, 14) + +#define MT_RXWI_GAIN_RSSI_VAL GENMASK(5, 0) +#define MT_RXWI_GAIN_RSSI_LNA_ID GENMASK(7, 6) +#define MT_RXWI_ANT_AUX_LNA BIT(7) + +#define MT_RXWI_EANT_ENC_ANT_ID GENMASK(7, 0) + +enum mt76_phy_type { + MT_PHY_TYPE_CCK, + MT_PHY_TYPE_OFDM, + MT_PHY_TYPE_HT, + MT_PHY_TYPE_HT_GF, +}; + +enum mt76_phy_bandwidth { + MT_PHY_BW_20, + MT_PHY_BW_40, +}; + +struct mt76_txwi { + __le16 flags; + __le16 rate_ctl; + + u8 ack_ctl; + u8 wcid; + __le16 len_ctl; + + __le32 iv; + + __le32 eiv; + + u8 aid; + u8 txstream; + __le16 ctl; +} __packed __aligned(4); + +#define MT_TXWI_FLAGS_FRAG BIT(0) +#define MT_TXWI_FLAGS_MMPS BIT(1) +#define MT_TXWI_FLAGS_CFACK BIT(2) +#define MT_TXWI_FLAGS_TS BIT(3) +#define MT_TXWI_FLAGS_AMPDU BIT(4) +#define MT_TXWI_FLAGS_MPDU_DENSITY GENMASK(7, 5) +#define MT_TXWI_FLAGS_TXOP GENMASK(9, 8) +#define MT_TXWI_FLAGS_CWMIN GENMASK(12, 10) +#define MT_TXWI_FLAGS_NO_RATE_FALLBACK BIT(13) +#define MT_TXWI_FLAGS_TX_RPT BIT(14) +#define MT_TXWI_FLAGS_TX_RATE_LUT BIT(15) + +#define MT_TXWI_RATE_MCS GENMASK(6, 0) +#define MT_TXWI_RATE_BW BIT(7) +#define MT_TXWI_RATE_SGI BIT(8) +#define MT_TXWI_RATE_STBC GENMASK(10, 9) +#define MT_TXWI_RATE_PHY_MODE GENMASK(15, 14) + +#define MT_TXWI_ACK_CTL_REQ BIT(0) +#define MT_TXWI_ACK_CTL_NSEQ BIT(1) +#define MT_TXWI_ACK_CTL_BA_WINDOW GENMASK(7, 2) + +#define MT_TXWI_LEN_BYTE_CNT GENMASK(11, 0) +#define MT_TXWI_LEN_PKTID GENMASK(15, 12) + +#define MT_TXWI_CTL_TX_POWER_ADJ GENMASK(3, 0) +#define MT_TXWI_CTL_CHAN_CHECK_PKT BIT(4) +#define MT_TXWI_CTL_PIFS_REV BIT(6) + +u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb, + u8 *data, void *rxi); +int mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx, + struct ieee80211_key_conf *key); +void mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid, + const struct ieee80211_tx_rate *rate); + +int mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx, + struct ieee80211_key_conf *key); +u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev, + const struct ieee80211_tx_rate *rate, u8 *nss_val); +struct mt76_tx_status +mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev); +void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat); + +#endif diff --git a/linux-bsp/drivers/mt7601u-sta/main.c b/linux-bsp/drivers/mt7601u-sta/main.c new file mode 100644 index 0000000..5687a66 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/main.c @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "mt7601u.h" +#include "mac.h" +#include <linux/etherdevice.h> +#include <linux/version.h> + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) +#error Your kernel is too old, please upgrade to at least 3.19 +#endif + +static int mt7601u_start(struct ieee80211_hw *hw) +{ + struct mt7601u_dev *dev = hw->priv; + int ret; + + mutex_lock(&dev->mutex); + + ret = mt7601u_mac_start(dev); + if (ret) + goto out; + + ieee80211_queue_delayed_work(dev->hw, &dev->mac_work, + MT_CALIBRATE_INTERVAL); + ieee80211_queue_delayed_work(dev->hw, &dev->cal_work, + MT_CALIBRATE_INTERVAL); +out: + mutex_unlock(&dev->mutex); + return ret; +} + +static void mt7601u_stop(struct ieee80211_hw *hw) +{ + struct mt7601u_dev *dev = hw->priv; + + mutex_lock(&dev->mutex); + + cancel_delayed_work_sync(&dev->cal_work); + cancel_delayed_work_sync(&dev->mac_work); + mt7601u_mac_stop(dev); + + mutex_unlock(&dev->mutex); +} + +static int mt7601u_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7601u_dev *dev = hw->priv; + struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv; + unsigned int idx = 0; + unsigned int wcid = GROUP_WCID(idx); + + /* Note: for AP do the AP-STA things mt76 does: + * - beacon offsets + * - do mac address tricks + * - shift vif idx + */ + mvif->idx = idx; + + if (dev->wcid_mask[wcid / BITS_PER_LONG] & BIT(wcid % BITS_PER_LONG)) + return -ENOSPC; + dev->wcid_mask[wcid / BITS_PER_LONG] |= BIT(wcid % BITS_PER_LONG); + mvif->group_wcid.idx = wcid; + mvif->group_wcid.hw_key_idx = -1; + + return 0; +} + +static void mt7601u_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7601u_dev *dev = hw->priv; + struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv; + unsigned int wcid = mvif->group_wcid.idx; + + dev->wcid_mask[wcid / BITS_PER_LONG] &= ~BIT(wcid % BITS_PER_LONG); +} + +static int mt7601u_config(struct ieee80211_hw *hw, u32 changed) +{ + struct mt7601u_dev *dev = hw->priv; + int ret = 0; + + mutex_lock(&dev->mutex); + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ieee80211_stop_queues(hw); + ret = mt7601u_phy_set_channel(dev, &hw->conf.chandef); + ieee80211_wake_queues(hw); + } + + mutex_unlock(&dev->mutex); + + return ret; +} + +static void +mt76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, + unsigned int *total_flags, u64 multicast) +{ + struct mt7601u_dev *dev = hw->priv; + u32 flags = 0; + +#define MT76_FILTER(_flag, _hw) do { \ + flags |= *total_flags & FIF_##_flag; \ + dev->rxfilter &= ~(_hw); \ + dev->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ + } while (0) + + mutex_lock(&dev->mutex); + + dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS; + + MT76_FILTER(OTHER_BSS, MT_RX_FILTR_CFG_PROMISC); + MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR); + MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR); + MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK | + MT_RX_FILTR_CFG_CTS | + MT_RX_FILTR_CFG_CFEND | + MT_RX_FILTR_CFG_CFACK | + MT_RX_FILTR_CFG_BA | + MT_RX_FILTR_CFG_CTRL_RSV); + MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL); + + *total_flags = flags; + mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); + + mutex_unlock(&dev->mutex); +} + +static void +mt7601u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) +{ + struct mt7601u_dev *dev = hw->priv; + + mutex_lock(&dev->mutex); + + if (changed & BSS_CHANGED_ASSOC) + mt7601u_phy_con_cal_onoff(dev, info); + + if (changed & BSS_CHANGED_BSSID) { + mt7601u_addr_wr(dev, MT_MAC_BSSID_DW0, info->bssid); + + /* Note: this is a hack because beacon_int is not changed + * on leave nor is any more appropriate event generated. + * rt2x00 doesn't seem to be bothered though. + */ + if (is_zero_ether_addr(info->bssid)) + mt7601u_mac_config_tsf(dev, false, 0); + } + + if (changed & BSS_CHANGED_BASIC_RATES) { + mt7601u_wr(dev, MT_LEGACY_BASIC_RATE, info->basic_rates); + mt7601u_wr(dev, MT_HT_FBK_CFG0, 0x65432100); + mt7601u_wr(dev, MT_HT_FBK_CFG1, 0xedcba980); + mt7601u_wr(dev, MT_LG_FBK_CFG0, 0xedcba988); + mt7601u_wr(dev, MT_LG_FBK_CFG1, 0x00002100); + } + + if (changed & BSS_CHANGED_BEACON_INT) + mt7601u_mac_config_tsf(dev, true, info->beacon_int); + + if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) + mt7601u_mac_set_protection(dev, info->use_cts_prot, + info->ht_operation_mode); + + if (changed & BSS_CHANGED_ERP_PREAMBLE) + mt7601u_mac_set_short_preamble(dev, info->use_short_preamble); + + if (changed & BSS_CHANGED_ERP_SLOT) { + int slottime = info->use_short_slot ? 9 : 20; + + mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, + MT_BKOFF_SLOT_CFG_SLOTTIME, slottime); + } + + if (changed & BSS_CHANGED_ASSOC) + mt7601u_phy_recalibrate_after_assoc(dev); + + mutex_unlock(&dev->mutex); +} + +static int +mt76_wcid_alloc(struct mt7601u_dev *dev) +{ + int i, idx = 0; + + for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) { + idx = ffs(~dev->wcid_mask[i]); + if (!idx) + continue; + + idx--; + dev->wcid_mask[i] |= BIT(idx); + break; + } + + idx = i * BITS_PER_LONG + idx; + if (idx > 119) + return -1; + + return idx; +} + +static int +mt7601u_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7601u_dev *dev = hw->priv; + struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; + struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv; + int ret = 0; + int idx = 0; + + mutex_lock(&dev->mutex); + + idx = mt76_wcid_alloc(dev); + if (idx < 0) { + ret = -ENOSPC; + goto out; + } + + msta->wcid.idx = idx; + msta->wcid.hw_key_idx = -1; + mt7601u_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); + mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx)); + rcu_assign_pointer(dev->wcid[idx], &msta->wcid); + mt7601u_mac_set_ampdu_factor(dev); + +out: + mutex_unlock(&dev->mutex); + + return ret; +} + +static int +mt7601u_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7601u_dev *dev = hw->priv; + struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; + int idx = msta->wcid.idx; + + mutex_lock(&dev->mutex); + rcu_assign_pointer(dev->wcid[idx], NULL); + mt76_set(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx)); + dev->wcid_mask[idx / BITS_PER_LONG] &= ~BIT(idx % BITS_PER_LONG); + mt7601u_mac_wcid_setup(dev, idx, 0, NULL); + mt7601u_mac_set_ampdu_factor(dev); + mutex_unlock(&dev->mutex); + + return 0; +} + +static void +mt7601u_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, struct ieee80211_sta *sta) +{ +} + +static void +mt7601u_sw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *mac_addr) +{ + struct mt7601u_dev *dev = hw->priv; + + mt7601u_agc_save(dev); + set_bit(MT7601U_STATE_SCANNING, &dev->state); +} + +static void +mt7601u_sw_scan_complete(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mt7601u_dev *dev = hw->priv; + + mt7601u_agc_restore(dev); + clear_bit(MT7601U_STATE_SCANNING, &dev->state); +} + +static int +mt7601u_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct mt7601u_dev *dev = hw->priv; + struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv; + struct mt76_sta *msta = sta ? (struct mt76_sta *) sta->drv_priv : NULL; + struct mt76_wcid *wcid = msta ? &msta->wcid : &mvif->group_wcid; + int idx = key->keyidx; + int ret; + + if (cmd == SET_KEY) { + key->hw_key_idx = wcid->idx; + wcid->hw_key_idx = idx; + } else { + if (idx == wcid->hw_key_idx) + wcid->hw_key_idx = -1; + + key = NULL; + } + + if (!msta) { + if (key || wcid->hw_key_idx == idx) { + ret = mt76_mac_wcid_set_key(dev, wcid->idx, key); + if (ret) + return ret; + } + + return mt76_mac_shared_key_setup(dev, mvif->idx, idx, key); + } + + return mt76_mac_wcid_set_key(dev, msta->wcid.idx, key); +} + +static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct mt7601u_dev *dev = hw->priv; + + mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, value); + + return 0; +} + +static int +mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) + struct ieee80211_ampdu_params *params +#else + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) + , bool amsdu +#endif +#endif + ) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) + enum ieee80211_ampdu_mlme_action action = params->action; + struct ieee80211_sta *sta = params->sta; + u16 *ssn = ¶ms->ssn; + u16 tid = params->tid; +#endif + struct mt7601u_dev *dev = hw->priv; + struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; + + WARN_ON(msta->wcid.idx > GROUP_WCID(0)); + + switch (action) { + case IEEE80211_AMPDU_RX_START: + mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); + break; + case IEEE80211_AMPDU_RX_STOP: + mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, + BIT(16 + tid)); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + ieee80211_send_bar(vif, sta->addr, tid, msta->agg_ssn[tid]); + break; + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + break; + case IEEE80211_AMPDU_TX_START: + msta->agg_ssn[tid] = *ssn << 4; + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + case IEEE80211_AMPDU_TX_STOP_CONT: + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + } + + return 0; +} + +static void +mt76_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7601u_dev *dev = hw->priv; + struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; + struct ieee80211_sta_rates *rates; + struct ieee80211_tx_rate rate = {}; + + rcu_read_lock(); + rates = rcu_dereference(sta->rates); + + if (!rates) + goto out; + + rate.idx = rates->rate[0].idx; + rate.flags = rates->rate[0].flags; + mt76_mac_wcid_set_rate(dev, &msta->wcid, &rate); + +out: + rcu_read_unlock(); +} + +const struct ieee80211_ops mt7601u_ops = { + .tx = mt7601u_tx, + .start = mt7601u_start, + .stop = mt7601u_stop, + .add_interface = mt7601u_add_interface, + .remove_interface = mt7601u_remove_interface, + .config = mt7601u_config, + .configure_filter = mt76_configure_filter, + .bss_info_changed = mt7601u_bss_info_changed, + .sta_add = mt7601u_sta_add, + .sta_remove = mt7601u_sta_remove, + .sta_notify = mt7601u_sta_notify, + .set_key = mt7601u_set_key, + .conf_tx = mt7601u_conf_tx, + .sw_scan_start = mt7601u_sw_scan, + .sw_scan_complete = mt7601u_sw_scan_complete, +/* .flush = mt7601u_flush,*/ + .ampdu_action = mt76_ampdu_action, + .sta_rate_tbl_update = mt76_sta_rate_tbl_update, + .set_rts_threshold = mt7601u_set_rts_threshold, +}; diff --git a/linux-bsp/drivers/mt7601u-sta/mcu.c b/linux-bsp/drivers/mt7601u-sta/mcu.c new file mode 100644 index 0000000..91c4b34 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/mcu.c @@ -0,0 +1,536 @@ +/* + * (c) Copyright 2002-2010, Ralink Technology, Inc. + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/firmware.h> +#include <linux/delay.h> +#include <linux/usb.h> +#include <linux/skbuff.h> + +#include "mt7601u.h" +#include "dma.h" +#include "mcu.h" +#include "usb.h" +#include "trace.h" + +#define MCU_FW_URB_MAX_PAYLOAD 0x3800 +#define MCU_FW_URB_SIZE (MCU_FW_URB_MAX_PAYLOAD + 12) +#define MCU_RESP_URB_SIZE 1024 + +static inline int firmware_running(struct mt7601u_dev *dev) +{ + return mt7601u_rr(dev, MT_MCU_COM_REG0) == 1; +} + +static inline void skb_put_le32(struct sk_buff *skb, u32 val) +{ + put_unaligned_le32(val, skb_put(skb, 4)); +} + +static inline void mt7601u_dma_skb_wrap_cmd(struct sk_buff *skb, + u8 seq, enum mcu_cmd cmd) +{ + WARN_ON(mt7601u_dma_skb_wrap(skb, CPU_TX_PORT, DMA_COMMAND, + MT76_SET(MT_TXD_CMD_INFO_SEQ, seq) | + MT76_SET(MT_TXD_CMD_INFO_TYPE, cmd))); +} + +static inline void trace_mt_mcu_msg_send_cs(struct mt7601u_dev *dev, + struct sk_buff *skb, bool need_resp) +{ + u32 i, csum = 0; + + for (i = 0; i < skb->len / 4; i++) + csum ^= get_unaligned_le32(skb->data + i * 4); + + trace_mt_mcu_msg_send(dev, skb, csum, need_resp); +} + +static struct sk_buff * +mt7601u_mcu_msg_alloc(struct mt7601u_dev *dev, const void *data, int len) +{ + struct sk_buff *skb; + + WARN_ON(len % 4); /* if length is not divisible by 4 we need to pad */ + + skb = alloc_skb(len + MT_DMA_HDR_LEN + 4, GFP_KERNEL); + skb_reserve(skb, MT_DMA_HDR_LEN); + memcpy(skb_put(skb, len), data, len); + + return skb; +} + +static int mt7601u_mcu_wait_resp(struct mt7601u_dev *dev, u8 seq) +{ + struct urb *urb = dev->mcu.resp.urb; + u32 rxfce; + int urb_status, ret, i = 5; + + while (i--) { + if (!wait_for_completion_timeout(&dev->mcu.resp_cmpl, + msecs_to_jiffies(300))) { + dev_warn(dev->dev, "Warning: %s retrying\n", __func__); + continue; + } + + /* Make copies of important data before reusing the urb */ + rxfce = get_unaligned_le32(dev->mcu.resp.buf); + urb_status = urb->status * mt7601u_urb_has_error(urb); + + ret = mt7601u_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP, + &dev->mcu.resp, GFP_KERNEL, + mt7601u_complete_urb, + &dev->mcu.resp_cmpl); + if (ret) + return ret; + + if (urb_status) + dev_err(dev->dev, "Error: MCU resp urb failed:%d\n", + urb_status); + + if (MT76_GET(MT_RXD_CMD_INFO_CMD_SEQ, rxfce) == seq && + MT76_GET(MT_RXD_CMD_INFO_EVT_TYPE, rxfce) == CMD_DONE) + return 0; + + dev_err(dev->dev, "Error: MCU resp evt:%hhx seq:%hhx-%hhx!\n", + MT76_GET(MT_RXD_CMD_INFO_EVT_TYPE, rxfce), + seq, MT76_GET(MT_RXD_CMD_INFO_CMD_SEQ, rxfce)); + } + + dev_err(dev->dev, "Error: %s timed out\n", __func__); + return -ETIMEDOUT; +} + +static int +mt7601u_mcu_msg_send(struct mt7601u_dev *dev, struct sk_buff *skb, + enum mcu_cmd cmd, bool wait_resp) +{ + struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); + unsigned cmd_pipe = usb_sndbulkpipe(usb_dev, + dev->out_eps[MT_EP_OUT_INBAND_CMD]); + int sent, ret; + u8 seq = 0; + + if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) + return 0; + + mutex_lock(&dev->mcu.mutex); + + if (wait_resp) + while (!seq) + seq = ++dev->mcu.msg_seq & 0xf; + + mt7601u_dma_skb_wrap_cmd(skb, seq, cmd); + + if (dev->mcu.resp_cmpl.done) + dev_err(dev->dev, "Error: MCU response pre-completed!\n"); + + trace_mt_mcu_msg_send_cs(dev, skb, wait_resp); + trace_mt_submit_urb_sync(dev, cmd_pipe, skb->len); + ret = usb_bulk_msg(usb_dev, cmd_pipe, skb->data, skb->len, &sent, 500); + if (ret) { + dev_err(dev->dev, "Error: send MCU cmd failed:%d\n", ret); + goto out; + } + if (sent != skb->len) + dev_err(dev->dev, "Error: %s sent != skb->len\n", __func__); + + if (wait_resp) + ret = mt7601u_mcu_wait_resp(dev, seq); +out: + mutex_unlock(&dev->mcu.mutex); + + consume_skb(skb); + + return ret; +} + +static int mt7601u_mcu_function_select(struct mt7601u_dev *dev, + enum mcu_function func, u32 val) +{ + struct sk_buff *skb; + struct { + __le32 id; + __le32 value; + } __packed __aligned(4) msg = { + .id = cpu_to_le32(func), + .value = cpu_to_le32(val), + }; + + skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt7601u_mcu_msg_send(dev, skb, CMD_FUN_SET_OP, func == 5); +} + +int mt7601u_mcu_tssi_read_kick(struct mt7601u_dev *dev, int use_hvga) +{ + int ret; + + if (!test_bit(MT7601U_STATE_MCU_RUNNING, &dev->state)) + return 0; + + ret = mt7601u_mcu_function_select(dev, ATOMIC_TSSI_SETTING, + use_hvga); + if (ret) { + dev_warn(dev->dev, "Warning: MCU TSSI read kick failed\n"); + return ret; + } + + dev->tssi_read_trig = true; + + return 0; +} + +int +mt7601u_mcu_calibrate(struct mt7601u_dev *dev, enum mcu_calibrate cal, u32 val) +{ + struct sk_buff *skb; + struct { + __le32 id; + __le32 value; + } __packed __aligned(4) msg = { + .id = cpu_to_le32(cal), + .value = cpu_to_le32(val), + }; + + skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg)); + return mt7601u_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP, true); +} + +int mt7601u_write_reg_pairs(struct mt7601u_dev *dev, u32 base, + const struct mt76_reg_pair *data, int n) +{ + const int max_vals_per_cmd = INBAND_PACKET_MAX_LEN / 8; + struct sk_buff *skb; + int cnt, i, ret; + + if (!n) + return 0; + + cnt = min(max_vals_per_cmd, n); + + skb = alloc_skb(cnt * 8 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); + if (!skb) + return -ENOMEM; + skb_reserve(skb, MT_DMA_HDR_LEN); + + for (i = 0; i < cnt; i++) { + skb_put_le32(skb, base + data[i].reg); + skb_put_le32(skb, data[i].value); + } + + ret = mt7601u_mcu_msg_send(dev, skb, CMD_RANDOM_WRITE, cnt == n); + if (ret) + return ret; + + return mt7601u_write_reg_pairs(dev, base, data + cnt, n - cnt); +} + +int mt7601u_burst_write_regs(struct mt7601u_dev *dev, u32 offset, + const u32 *data, int n) +{ + const int max_regs_per_cmd = INBAND_PACKET_MAX_LEN / 4 - 1; + struct sk_buff *skb; + int cnt, i, ret; + + if (!n) + return 0; + + cnt = min(max_regs_per_cmd, n); + + skb = alloc_skb(cnt * 4 + MT_DMA_HDR_LEN + 4, GFP_KERNEL); + if (!skb) + return -ENOMEM; + skb_reserve(skb, MT_DMA_HDR_LEN); + + skb_put_le32(skb, MT_MCU_MEMMAP_WLAN + offset); + for (i = 0; i < cnt; i++) + skb_put_le32(skb, data[i]); + + ret = mt7601u_mcu_msg_send(dev, skb, CMD_BURST_WRITE, cnt == n); + if (ret) + return ret; + + return mt7601u_burst_write_regs(dev, offset + cnt * 4, + data + cnt, n - cnt); +} + +struct mt76_fw_header { + __le32 ilm_len; + __le32 dlm_len; + __le16 build_ver; + __le16 fw_ver; + u8 pad[4]; + char build_time[16]; +}; + +struct mt76_fw { + struct mt76_fw_header hdr; + u8 ivb[MT_MCU_IVB_SIZE]; + u8 ilm[]; +}; + +static int __mt7601u_dma_fw(struct mt7601u_dev *dev, + const struct mt7601u_dma_buf *dma_buf, + const void *data, u32 len, u32 dst_addr) +{ + DECLARE_COMPLETION_ONSTACK(cmpl); + struct mt7601u_dma_buf buf = *dma_buf; /* we need to fake length */ + __le32 reg; + u32 val; + int ret; + + reg = cpu_to_le32(MT76_SET(MT_TXD_INFO_TYPE, DMA_PACKET) | + MT76_SET(MT_TXD_INFO_D_PORT, CPU_TX_PORT) | + MT76_SET(MT_TXD_INFO_LEN, len)); + memcpy(buf.buf, ®, sizeof(reg)); + memcpy(buf.buf + sizeof(reg), data, len); + memset(buf.buf + sizeof(reg) + len, 0, 8); + + ret = mt7601u_vendor_single_wr(dev, MT_VEND_WRITE_FCE, + MT_FCE_DMA_ADDR, dst_addr); + if (ret) + return ret; + len = roundup(len, 4); + ret = mt7601u_vendor_single_wr(dev, MT_VEND_WRITE_FCE, + MT_FCE_DMA_LEN, len << 16); + if (ret) + return ret; + + buf.len = MT_DMA_HDR_LEN + len + 4; + ret = mt7601u_usb_submit_buf(dev, USB_DIR_OUT, MT_EP_OUT_INBAND_CMD, + &buf, GFP_KERNEL, + mt7601u_complete_urb, &cmpl); + if (ret) + return ret; + + if (!wait_for_completion_timeout(&cmpl, msecs_to_jiffies(1000))) { + dev_err(dev->dev, "Error: firmware upload timed out\n"); + usb_kill_urb(buf.urb); + return -ETIMEDOUT; + } + if (mt7601u_urb_has_error(buf.urb)) { + dev_err(dev->dev, "Error: firmware upload urb failed:%d\n", + buf.urb->status); + return buf.urb->status; + } + + val = mt7601u_rr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX); + val++; + mt7601u_wr(dev, MT_TX_CPU_FROM_FCE_CPU_DESC_IDX, val); + + return 0; +} + +static int +mt7601u_dma_fw(struct mt7601u_dev *dev, struct mt7601u_dma_buf *dma_buf, + const void *data, int len, u32 dst_addr) +{ + int n, ret; + + if (len == 0) + return 0; + + n = min(MCU_FW_URB_MAX_PAYLOAD, len); + ret = __mt7601u_dma_fw(dev, dma_buf, data, n, dst_addr); + if (ret) + return ret; + + if (!mt76_poll_msec(dev, MT_MCU_COM_REG1, BIT(31), BIT(31), 500)) + return -ETIMEDOUT; + + return mt7601u_dma_fw(dev, dma_buf, data + n, len - n, dst_addr + n); +} + +static int +mt7601u_upload_firmware(struct mt7601u_dev *dev, const struct mt76_fw *fw) +{ + struct mt7601u_dma_buf dma_buf; + void *ivb; + u32 ilm_len, dlm_len; + int i, ret; + + ivb = kmemdup(fw->ivb, sizeof(fw->ivb), GFP_KERNEL); + if (!ivb) + return -ENOMEM; + if (mt7601u_usb_alloc_buf(dev, MCU_FW_URB_SIZE, &dma_buf)) { + ret = -ENOMEM; + goto error; + } + + ilm_len = le32_to_cpu(fw->hdr.ilm_len) - sizeof(fw->ivb); + dev_dbg(dev->dev, "loading FW - ILM %u + IVB %zu\n", + ilm_len, sizeof(fw->ivb)); + ret = mt7601u_dma_fw(dev, &dma_buf, fw->ilm, ilm_len, sizeof(fw->ivb)); + if (ret) + goto error; + + dlm_len = le32_to_cpu(fw->hdr.dlm_len); + dev_dbg(dev->dev, "loading FW - DLM %u\n", dlm_len); + ret = mt7601u_dma_fw(dev, &dma_buf, fw->ilm + ilm_len, + dlm_len, MT_MCU_DLM_OFFSET); + if (ret) + goto error; + + ret = mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT, + 0x12, 0, ivb, sizeof(fw->ivb)); + if (ret < 0) + goto error; + ret = 0; + + for (i = 100; i && !firmware_running(dev); i--) + msleep(10); + if (!i) { + ret = -ETIMEDOUT; + goto error; + } + + dev_dbg(dev->dev, "Firmware running!\n"); +error: + kfree(ivb); + mt7601u_usb_free_buf(dev, &dma_buf); + + return ret; +} + +static int mt7601u_load_firmware(struct mt7601u_dev *dev) +{ + const struct firmware *fw; + const struct mt76_fw_header *hdr; + int len, ret; + u32 val; + + mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | + MT_USB_DMA_CFG_TX_BULK_EN)); + + if (firmware_running(dev)) + return 0; + + ret = request_firmware(&fw, MT7601U_FIRMWARE, dev->dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) + goto err_inv_fw; + + hdr = (const struct mt76_fw_header *) fw->data; + + if (le32_to_cpu(hdr->ilm_len) <= MT_MCU_IVB_SIZE) + goto err_inv_fw; + + len = sizeof(*hdr); + len += le32_to_cpu(hdr->ilm_len); + len += le32_to_cpu(hdr->dlm_len); + + if (fw->size != len) + goto err_inv_fw; + + val = le16_to_cpu(hdr->fw_ver); + dev_info(dev->dev, + "Firmware Version: %d.%d.%02d Build: %x Build time: %.16s\n", + (val >> 12) & 0xf, (val >> 8) & 0xf, val & 0xf, + le16_to_cpu(hdr->build_ver), hdr->build_time); + + len = le32_to_cpu(hdr->ilm_len); + + mt7601u_wr(dev, 0x94c, 0); + mt7601u_wr(dev, MT_FCE_PSE_CTRL, 0); + + mt7601u_vendor_reset(dev); + msleep(5); + + mt7601u_wr(dev, 0xa44, 0); + mt7601u_wr(dev, 0x230, 0x84210); + mt7601u_wr(dev, 0x400, 0x80c00); + mt7601u_wr(dev, 0x800, 1); + + mt7601u_rmw(dev, MT_PBF_CFG, 0, (MT_PBF_CFG_TX0Q_EN | + MT_PBF_CFG_TX1Q_EN | + MT_PBF_CFG_TX2Q_EN | + MT_PBF_CFG_TX3Q_EN)); + + mt7601u_wr(dev, MT_FCE_PSE_CTRL, 1); + + mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | + MT_USB_DMA_CFG_TX_BULK_EN)); + val = mt76_set(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_CLR); + val &= ~MT_USB_DMA_CFG_TX_CLR; + mt7601u_wr(dev, MT_USB_DMA_CFG, val); + + /* FCE tx_fs_base_ptr */ + mt7601u_wr(dev, MT_TX_CPU_FROM_FCE_BASE_PTR, 0x400230); + /* FCE tx_fs_max_cnt */ + mt7601u_wr(dev, MT_TX_CPU_FROM_FCE_MAX_COUNT, 1); + /* FCE pdma enable */ + mt7601u_wr(dev, MT_FCE_PDMA_GLOBAL_CONF, 0x44); + /* FCE skip_fs_en */ + mt7601u_wr(dev, MT_FCE_SKIP_FS, 3); + + ret = mt7601u_upload_firmware(dev, (const struct mt76_fw *)fw->data); + + release_firmware(fw); + + return ret; + +err_inv_fw: + dev_err(dev->dev, "Invalid firmware image\n"); + release_firmware(fw); + return -ENOENT; +} + +int mt7601u_mcu_init(struct mt7601u_dev *dev) +{ + int ret; + + mutex_init(&dev->mcu.mutex); + + ret = mt7601u_load_firmware(dev); + if (ret) + return ret; + + set_bit(MT7601U_STATE_MCU_RUNNING, &dev->state); + + return 0; +} + +int mt7601u_mcu_cmd_init(struct mt7601u_dev *dev) +{ + int ret; + + ret = mt7601u_mcu_function_select(dev, Q_SELECT, 1); + if (ret) + return ret; + + init_completion(&dev->mcu.resp_cmpl); + if (mt7601u_usb_alloc_buf(dev, MCU_RESP_URB_SIZE, &dev->mcu.resp)) { + mt7601u_usb_free_buf(dev, &dev->mcu.resp); + return -ENOMEM; + } + + ret = mt7601u_usb_submit_buf(dev, USB_DIR_IN, MT_EP_IN_CMD_RESP, + &dev->mcu.resp, GFP_KERNEL, + mt7601u_complete_urb, &dev->mcu.resp_cmpl); + if (ret) { + mt7601u_usb_free_buf(dev, &dev->mcu.resp); + return ret; + } + + return 0; +} + +void mt7601u_mcu_cmd_deinit(struct mt7601u_dev *dev) +{ + usb_kill_urb(dev->mcu.resp.urb); + mt7601u_usb_free_buf(dev, &dev->mcu.resp); +} diff --git a/linux-bsp/drivers/mt7601u-sta/mcu.h b/linux-bsp/drivers/mt7601u-sta/mcu.h new file mode 100644 index 0000000..4a66d10 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/mcu.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT7601U_MCU_H +#define __MT7601U_MCU_H + +struct mt7601u_dev; + +/* Register definitions */ +#define MT_MCU_RESET_CTL 0x070C +#define MT_MCU_INT_LEVEL 0x0718 +#define MT_MCU_COM_REG0 0x0730 +#define MT_MCU_COM_REG1 0x0734 +#define MT_MCU_COM_REG2 0x0738 +#define MT_MCU_COM_REG3 0x073C + +#define MT_MCU_IVB_SIZE 0x40 +#define MT_MCU_DLM_OFFSET 0x80000 + +#define MT_MCU_MEMMAP_WLAN 0x00410000 +#define MT_MCU_MEMMAP_BBP 0x40000000 +#define MT_MCU_MEMMAP_RF 0x80000000 + +#define INBAND_PACKET_MAX_LEN 192 + +enum mcu_cmd { + CMD_FUN_SET_OP = 1, + CMD_LOAD_CR = 2, + CMD_INIT_GAIN_OP = 3, + CMD_DYNC_VGA_OP = 6, + CMD_TDLS_CH_SW = 7, + CMD_BURST_WRITE = 8, + CMD_READ_MODIFY_WRITE = 9, + CMD_RANDOM_READ = 10, + CMD_BURST_READ = 11, + CMD_RANDOM_WRITE = 12, + CMD_LED_MODE_OP = 16, + CMD_POWER_SAVING_OP = 20, + CMD_WOW_CONFIG = 21, + CMD_WOW_QUERY = 22, + CMD_WOW_FEATURE = 24, + CMD_CARRIER_DETECT_OP = 28, + CMD_RADOR_DETECT_OP = 29, + CMD_SWITCH_CHANNEL_OP = 30, + CMD_CALIBRATION_OP = 31, + CMD_BEACON_OP = 32, + CMD_ANTENNA_OP = 33, +}; + +enum mcu_function { + Q_SELECT = 1, + ATOMIC_TSSI_SETTING = 5, +}; + +enum mcu_power_mode { + RADIO_OFF = 0x30, + RADIO_ON = 0x31, + RADIO_OFF_AUTO_WAKEUP = 0x32, + RADIO_OFF_ADVANCE = 0x33, + RADIO_ON_ADVANCE = 0x34, +}; + +enum mcu_calibrate { + MCU_CAL_R = 1, + MCU_CAL_DCOC, + MCU_CAL_LC, + MCU_CAL_LOFT, + MCU_CAL_TXIQ, + MCU_CAL_BW, + MCU_CAL_DPD, + MCU_CAL_RXIQ, + MCU_CAL_TXDCOC, +}; + +int mt7601u_mcu_init(struct mt7601u_dev *dev); +int mt7601u_mcu_cmd_init(struct mt7601u_dev *dev); +void mt7601u_mcu_cmd_deinit(struct mt7601u_dev *dev); + +int +mt7601u_mcu_calibrate(struct mt7601u_dev *dev, enum mcu_calibrate cal, u32 val); +int mt7601u_mcu_tssi_read_kick(struct mt7601u_dev *dev, int use_hvga); + +#endif diff --git a/linux-bsp/drivers/mt7601u-sta/mt7601u.h b/linux-bsp/drivers/mt7601u-sta/mt7601u.h new file mode 100644 index 0000000..428bd2f --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/mt7601u.h @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MT7601U_H +#define MT7601U_H + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/mutex.h> +#include <linux/usb.h> +#include <linux/completion.h> +#include <net/mac80211.h> +#include <linux/debugfs.h> + +#include "regs.h" +#include "util.h" + +#define MT_CALIBRATE_INTERVAL (4 * HZ) + +#define MT_FREQ_CAL_INIT_DELAY (30 * HZ) +#define MT_FREQ_CAL_CHECK_INTERVAL (10 * HZ) +#define MT_FREQ_CAL_ADJ_INTERVAL (HZ / 2) + +#define MT_BBP_REG_VERSION 0x00 + +#define MT_USB_AGGR_SIZE_LIMIT 28 /* * 1024B */ +#define MT_USB_AGGR_TIMEOUT 0x80 /* * 33ns */ +#define MT_RX_ORDER 3 +#define MT_RX_URB_SIZE (PAGE_SIZE << MT_RX_ORDER) + +struct mt7601u_dma_buf { + struct urb *urb; + void *buf; + dma_addr_t dma; + size_t len; +}; + +struct mt7601u_mcu { + struct mutex mutex; + + u8 msg_seq; + + struct mt7601u_dma_buf resp; + struct completion resp_cmpl; +}; + +struct mt7601u_freq_cal { + struct delayed_work work; + u8 freq; + bool enabled; + bool adjusting; +}; + +struct mac_stats { + u64 rx_stat[6]; + u64 tx_stat[6]; + u64 aggr_stat[2]; + u64 aggr_n[32]; + u64 zero_len_del[2]; +}; + +#define N_RX_ENTRIES 16 +struct mt7601u_rx_queue { + struct mt7601u_dev *dev; + + struct mt7601u_dma_buf_rx { + struct urb *urb; + struct page *p; + } e[N_RX_ENTRIES]; + + unsigned int start; + unsigned int end; + unsigned int entries; + unsigned int pending; +}; + +#define N_TX_ENTRIES 64 + +struct mt7601u_tx_queue { + struct mt7601u_dev *dev; + + struct mt7601u_dma_buf_tx { + struct urb *urb; + struct sk_buff *skb; + } e[N_TX_ENTRIES]; + + unsigned int start; + unsigned int end; + unsigned int entries; + unsigned int used; + unsigned int fifo_seq; +}; + +/* WCID allocation: + * 0: mcast wcid + * 1: bssid wcid + * 1...: STAs + * ...7e: group wcids + * 7f: reserved + */ +#define N_WCIDS 128 +#define GROUP_WCID(idx) (N_WCIDS - 2 - idx) + +struct mt7601u_eeprom_params; + +#define MT_EE_TEMPERATURE_SLOPE 39 +#define MT_FREQ_OFFSET_INVALID -128 + +enum mt_temp_mode { + MT_TEMP_MODE_NORMAL, + MT_TEMP_MODE_HIGH, + MT_TEMP_MODE_LOW, +}; + +enum mt_bw { + MT_BW_20, + MT_BW_40, +}; + +enum { + MT7601U_STATE_INITIALIZED, + MT7601U_STATE_REMOVED, + MT7601U_STATE_WLAN_RUNNING, + MT7601U_STATE_MCU_RUNNING, + MT7601U_STATE_SCANNING, + MT7601U_STATE_READING_STATS, + MT7601U_STATE_MORE_STATS, +}; + +/** + * struct mt7601u_dev - adapter structure + * @lock: protects @wcid->tx_rate. + * @mac_lock: locks out mac80211's tx status and rx paths. + * @tx_lock: protects @tx_q and changes of MT7601U_STATE_*_STATS + * flags in @state. + * @rx_lock: protects @rx_q. + * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. + * @mutex: ensures exclusive access from mac80211 callbacks. + * @vendor_req_mutex: protects @vend_buf, ensures atomicity of split writes. + * @reg_atomic_mutex: ensures atomicity of indirect register accesses + * (accesses to RF and BBP). + * @hw_atomic_mutex: ensures exclusive access to HW during critical + * operations (power management, channel switch). + */ +struct mt7601u_dev { + struct ieee80211_hw *hw; + struct device *dev; + + unsigned long state; + + struct mutex mutex; + + unsigned long wcid_mask[N_WCIDS / BITS_PER_LONG]; + + struct cfg80211_chan_def chandef; + struct ieee80211_supported_band *sband_2g; + + struct mt7601u_mcu mcu; + + struct delayed_work cal_work; + struct delayed_work mac_work; + + struct workqueue_struct *stat_wq; + struct delayed_work stat_work; + + struct mt76_wcid *mon_wcid; + struct mt76_wcid __rcu *wcid[N_WCIDS]; + + spinlock_t lock; + spinlock_t mac_lock; + + const u16 *beacon_offsets; + + u8 macaddr[ETH_ALEN]; + struct mt7601u_eeprom_params *ee; + + struct mutex vendor_req_mutex; + void *vend_buf; + + struct mutex reg_atomic_mutex; + struct mutex hw_atomic_mutex; + + u32 rxfilter; + u32 debugfs_reg; + + u8 out_eps[8]; + u8 in_eps[8]; + u16 out_max_packet; + u16 in_max_packet; + + /* TX */ + spinlock_t tx_lock; + struct tasklet_struct tx_tasklet; + struct mt7601u_tx_queue *tx_q; + struct sk_buff_head tx_skb_done; + + atomic_t avg_ampdu_len; + + /* RX */ + spinlock_t rx_lock; + struct tasklet_struct rx_tasklet; + struct mt7601u_rx_queue rx_q; + + /* Connection monitoring things */ + spinlock_t con_mon_lock; + u8 ap_bssid[ETH_ALEN]; + + s8 bcn_freq_off; + u8 bcn_phy_mode; + + int avg_rssi; /* starts at 0 and converges */ + + u8 agc_save; + + struct mt7601u_freq_cal freq_cal; + + bool tssi_read_trig; + + s8 tssi_init; + s8 tssi_init_hvga; + s16 tssi_init_hvga_offset_db; + + int prev_pwr_diff; + + enum mt_temp_mode temp_mode; + int curr_temp; + int dpd_temp; + s8 raw_temp; + bool pll_lock_protect; + + u8 bw; + bool chan_ext_below; + + /* PA mode */ + u32 rf_pa_mode[2]; + + struct mac_stats stats; +}; + +struct mt7601u_tssi_params { + char tssi0; + int trgt_power; +}; + +struct mt76_wcid { + u8 idx; + u8 hw_key_idx; + + u16 tx_rate; + bool tx_rate_set; + u8 tx_rate_nss; +}; + +struct mt76_vif { + u8 idx; + + struct mt76_wcid group_wcid; +}; + +struct mt76_sta { + struct mt76_wcid wcid; + u16 agg_ssn[IEEE80211_NUM_TIDS]; +}; + +struct mt76_reg_pair { + u32 reg; + u32 value; +}; + +struct mt7601u_rxwi; + +extern const struct ieee80211_ops mt7601u_ops; + +void mt7601u_init_debugfs(struct mt7601u_dev *dev); + +u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset); +void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val); +u32 mt7601u_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val); +u32 mt7601u_rmc(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val); +void mt7601u_wr_copy(struct mt7601u_dev *dev, u32 offset, + const void *data, int len); + +int mt7601u_wait_asic_ready(struct mt7601u_dev *dev); +bool mt76_poll(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val, + int timeout); +bool mt76_poll_msec(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val, + int timeout); + +/* Compatibility with mt76 */ +#define mt76_rmw_field(_dev, _reg, _field, _val) \ + mt76_rmw(_dev, _reg, _field, MT76_SET(_field, _val)) + +static inline u32 mt76_rr(struct mt7601u_dev *dev, u32 offset) +{ + return mt7601u_rr(dev, offset); +} + +static inline void mt76_wr(struct mt7601u_dev *dev, u32 offset, u32 val) +{ + return mt7601u_wr(dev, offset, val); +} + +static inline u32 +mt76_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val) +{ + return mt7601u_rmw(dev, offset, mask, val); +} + +static inline u32 mt76_set(struct mt7601u_dev *dev, u32 offset, u32 val) +{ + return mt76_rmw(dev, offset, 0, val); +} + +static inline u32 mt76_clear(struct mt7601u_dev *dev, u32 offset, u32 val) +{ + return mt76_rmw(dev, offset, val, 0); +} + +int mt7601u_write_reg_pairs(struct mt7601u_dev *dev, u32 base, + const struct mt76_reg_pair *data, int len); +int mt7601u_burst_write_regs(struct mt7601u_dev *dev, u32 offset, + const u32 *data, int n); +void mt7601u_addr_wr(struct mt7601u_dev *dev, const u32 offset, const u8 *addr); + +/* Init */ +struct mt7601u_dev *mt7601u_alloc_device(struct device *dev); +int mt7601u_init_hardware(struct mt7601u_dev *dev); +int mt7601u_register_device(struct mt7601u_dev *dev); +void mt7601u_cleanup(struct mt7601u_dev *dev); + +int mt7601u_mac_start(struct mt7601u_dev *dev); +void mt7601u_mac_stop(struct mt7601u_dev *dev); + +/* PHY */ +int mt7601u_phy_init(struct mt7601u_dev *dev); +int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev); +void mt7601u_set_rx_path(struct mt7601u_dev *dev, u8 path); +void mt7601u_set_tx_dac(struct mt7601u_dev *dev, u8 path); +int mt7601u_bbp_set_bw(struct mt7601u_dev *dev, int bw); +void mt7601u_agc_save(struct mt7601u_dev *dev); +void mt7601u_agc_restore(struct mt7601u_dev *dev); +int mt7601u_phy_set_channel(struct mt7601u_dev *dev, + struct cfg80211_chan_def *chandef); +void mt7601u_phy_recalibrate_after_assoc(struct mt7601u_dev *dev); +int mt7601u_phy_get_rssi(struct mt7601u_dev *dev, + struct mt7601u_rxwi *rxwi, u16 rate); +void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev, + struct ieee80211_bss_conf *info); + +/* MAC */ +void mt7601u_mac_work(struct work_struct *work); +void mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot, + int ht_mode); +void mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb); +void mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval); +void +mt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac); +void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev); + +/* TX */ +void mt7601u_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb); +int mt7601u_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u16 queue, const struct ieee80211_tx_queue_params *params); +void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb); +void mt7601u_tx_stat(struct work_struct *work); + +/* util */ +void mt76_remove_hdr_pad(struct sk_buff *skb); +int mt76_insert_hdr_pad(struct sk_buff *skb); + +u32 mt7601u_bbp_set_ctrlch(struct mt7601u_dev *dev, bool below); + +static inline u32 mt7601u_mac_set_ctrlch(struct mt7601u_dev *dev, bool below) +{ + return mt7601u_rmc(dev, MT_TX_BAND_CFG, 1, below); +} + +int mt7601u_dma_init(struct mt7601u_dev *dev); +void mt7601u_dma_cleanup(struct mt7601u_dev *dev); + +int mt7601u_dma_enqueue_tx(struct mt7601u_dev *dev, struct sk_buff *skb, + struct mt76_wcid *wcid, int hw_q); + +#endif diff --git a/linux-bsp/drivers/mt7601u-sta/phy.c b/linux-bsp/drivers/mt7601u-sta/phy.c new file mode 100644 index 0000000..1908af6 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/phy.c @@ -0,0 +1,1251 @@ +/* + * (c) Copyright 2002-2010, Ralink Technology, Inc. + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "mt7601u.h" +#include "mcu.h" +#include "eeprom.h" +#include "trace.h" +#include "initvals_phy.h" + +#include <linux/etherdevice.h> + +static void mt7601u_agc_reset(struct mt7601u_dev *dev); + +static int +mt7601u_rf_wr(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 value) +{ + int ret = 0; + + if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) || + WARN_ON(offset > 63)) + return -EINVAL; + if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) + return 0; + + mutex_lock(&dev->reg_atomic_mutex); + + if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) { + ret = -ETIMEDOUT; + goto out; + } + + mt7601u_wr(dev, MT_RF_CSR_CFG, MT76_SET(MT_RF_CSR_CFG_DATA, value) | + MT76_SET(MT_RF_CSR_CFG_REG_BANK, bank) | + MT76_SET(MT_RF_CSR_CFG_REG_ID, offset) | + MT_RF_CSR_CFG_WR | + MT_RF_CSR_CFG_KICK); + trace_rf_write(dev, bank, offset, value); +out: + mutex_unlock(&dev->reg_atomic_mutex); + + if (ret < 0) + dev_err(dev->dev, "Error: RF write %02hhx:%02hhx failed:%d!!\n", + bank, offset, ret); + + return ret; +} + +static int +mt7601u_rf_rr(struct mt7601u_dev *dev, u8 bank, u8 offset) +{ + int ret = -ETIMEDOUT; + u32 val; + + if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) || + WARN_ON(offset > 63)) + return -EINVAL; + if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) + return 0xff; + + mutex_lock(&dev->reg_atomic_mutex); + + if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) + goto out; + + mt7601u_wr(dev, MT_RF_CSR_CFG, MT76_SET(MT_RF_CSR_CFG_REG_BANK, bank) | + MT76_SET(MT_RF_CSR_CFG_REG_ID, offset) | + MT_RF_CSR_CFG_KICK); + + if (!mt76_poll(dev, MT_RF_CSR_CFG, MT_RF_CSR_CFG_KICK, 0, 100)) + goto out; + + val = mt7601u_rr(dev, MT_RF_CSR_CFG); + if (MT76_GET(MT_RF_CSR_CFG_REG_ID, val) == offset && + MT76_GET(MT_RF_CSR_CFG_REG_BANK, val) == bank) { + ret = MT76_GET(MT_RF_CSR_CFG_DATA, val); + trace_rf_read(dev, bank, offset, ret); + } +out: + mutex_unlock(&dev->reg_atomic_mutex); + + if (ret < 0) + dev_err(dev->dev, "Error: RF read %02hhx:%02hhx failed:%d!!\n", + bank, offset, ret); + + return ret; +} + +static int +mt7601u_rf_rmw(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 mask, u8 val) +{ + int ret; + + ret = mt7601u_rf_rr(dev, bank, offset); + if (ret < 0) + return ret; + val |= ret & ~mask; + ret = mt7601u_rf_wr(dev, bank, offset, val); + if (ret) + return ret; + + return val; +} + +static int +mt7601u_rf_set(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 val) +{ + return mt7601u_rf_rmw(dev, bank, offset, 0, val); +} + +static int +mt7601u_rf_clear(struct mt7601u_dev *dev, u8 bank, u8 offset, u8 mask) +{ + return mt7601u_rf_rmw(dev, bank, offset, mask, 0); +} + +static void mt7601u_bbp_wr(struct mt7601u_dev *dev, u8 offset, u8 val) +{ + if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state)) || + test_bit(MT7601U_STATE_REMOVED, &dev->state)) + return; + + mutex_lock(&dev->reg_atomic_mutex); + + if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000)) { + dev_err(dev->dev, "Error: BBP write %02hhx failed!!\n", offset); + goto out; + } + + mt7601u_wr(dev, MT_BBP_CSR_CFG, + MT76_SET(MT_BBP_CSR_CFG_VAL, val) | + MT76_SET(MT_BBP_CSR_CFG_REG_NUM, offset) | + MT_BBP_CSR_CFG_RW_MODE | MT_BBP_CSR_CFG_BUSY); + trace_bbp_write(dev, offset, val); +out: + mutex_unlock(&dev->reg_atomic_mutex); +} + +static int mt7601u_bbp_rr(struct mt7601u_dev *dev, u8 offset) +{ + u32 val; + int ret = -ETIMEDOUT; + + if (WARN_ON(!test_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state))) + return -EINVAL; + if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) + return 0xff; + + mutex_lock(&dev->reg_atomic_mutex); + + if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000)) + goto out; + + mt7601u_wr(dev, MT_BBP_CSR_CFG, + MT76_SET(MT_BBP_CSR_CFG_REG_NUM, offset) | + MT_BBP_CSR_CFG_RW_MODE | MT_BBP_CSR_CFG_BUSY | + MT_BBP_CSR_CFG_READ); + + if (!mt76_poll(dev, MT_BBP_CSR_CFG, MT_BBP_CSR_CFG_BUSY, 0, 1000)) + goto out; + + val = mt7601u_rr(dev, MT_BBP_CSR_CFG); + if (MT76_GET(MT_BBP_CSR_CFG_REG_NUM, val) == offset) { + ret = MT76_GET(MT_BBP_CSR_CFG_VAL, val); + trace_bbp_read(dev, offset, ret); + } +out: + mutex_unlock(&dev->reg_atomic_mutex); + + if (ret < 0) + dev_err(dev->dev, "Error: BBP read %02hhx failed:%d!!\n", + offset, ret); + + return ret; +} + +static int mt7601u_bbp_rmw(struct mt7601u_dev *dev, u8 offset, u8 mask, u8 val) +{ + int ret; + + ret = mt7601u_bbp_rr(dev, offset); + if (ret < 0) + return ret; + val |= ret & ~mask; + mt7601u_bbp_wr(dev, offset, val); + + return val; +} + +static u8 mt7601u_bbp_rmc(struct mt7601u_dev *dev, u8 offset, u8 mask, u8 val) +{ + int ret; + + ret = mt7601u_bbp_rr(dev, offset); + if (ret < 0) + return ret; + val |= ret & ~mask; + if (ret != val) + mt7601u_bbp_wr(dev, offset, val); + + return val; +} + +int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev) +{ + int i = 20; + u8 val; + + do { + val = mt7601u_bbp_rr(dev, MT_BBP_REG_VERSION); + if (val && ~val) + break; + } while (--i); + + if (!i) { + dev_err(dev->dev, "Error: BBP is not ready\n"); + return -EIO; + } + + return 0; +} + +u32 mt7601u_bbp_set_ctrlch(struct mt7601u_dev *dev, bool below) +{ + return mt7601u_bbp_rmc(dev, 3, 0x20, below ? 0x20 : 0); +} + +int mt7601u_phy_get_rssi(struct mt7601u_dev *dev, + struct mt7601u_rxwi *rxwi, u16 rate) +{ + static const s8 lna[2][2][3] = { + /* main LNA */ { + /* bw20 */ { -2, 15, 33 }, + /* bw40 */ { 0, 16, 34 } + }, + /* aux LNA */ { + /* bw20 */ { -2, 15, 33 }, + /* bw40 */ { -2, 16, 34 } + } + }; + int bw = MT76_GET(MT_RXWI_RATE_BW, rate); + int aux_lna = MT76_GET(MT_RXWI_ANT_AUX_LNA, rxwi->ant); + int lna_id = MT76_GET(MT_RXWI_GAIN_RSSI_LNA_ID, rxwi->gain); + int val; + + if (lna_id) /* LNA id can be 0, 2, 3. */ + lna_id--; + + val = 8; + val -= lna[aux_lna][bw][lna_id]; + val -= MT76_GET(MT_RXWI_GAIN_RSSI_VAL, rxwi->gain); + val -= dev->ee->lna_gain; + val -= dev->ee->rssi_offset[0]; + + return val; +} + +static void mt7601u_vco_cal(struct mt7601u_dev *dev) +{ + mt7601u_rf_wr(dev, 0, 4, 0x0a); + mt7601u_rf_wr(dev, 0, 5, 0x20); + mt7601u_rf_set(dev, 0, 4, BIT(7)); + msleep(2); +} + +static int mt7601u_set_bw_filter(struct mt7601u_dev *dev, bool cal) +{ + u32 filter = 0; + int ret; + + if (!cal) + filter |= 0x10000; + if (dev->bw != MT_BW_20) + filter |= 0x00100; + + /* TX */ + ret = mt7601u_mcu_calibrate(dev, MCU_CAL_BW, filter | 1); + if (ret) + return ret; + /* RX */ + return mt7601u_mcu_calibrate(dev, MCU_CAL_BW, filter); +} + +static int mt7601u_load_bbp_temp_table_bw(struct mt7601u_dev *dev) +{ + const struct reg_table *t; + + if (WARN_ON(dev->temp_mode > MT_TEMP_MODE_LOW)) + return -EINVAL; + + t = &bbp_mode_table[dev->temp_mode][dev->bw]; + + return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, t->regs, t->n); +} + +static int mt7601u_bbp_temp(struct mt7601u_dev *dev, int mode, const char *name) +{ + const struct reg_table *t; + int ret; + + if (dev->temp_mode == mode) + return 0; + + dev->temp_mode = mode; + trace_temp_mode(dev, mode); + + t = bbp_mode_table[dev->temp_mode]; + ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, + t[2].regs, t[2].n); + if (ret) + return ret; + + return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, + t[dev->bw].regs, t[dev->bw].n); +} + +static void mt7601u_apply_ch14_fixup(struct mt7601u_dev *dev, int hw_chan) +{ + struct mt7601u_rate_power *t = &dev->ee->power_rate_table; + + if (hw_chan != 14 || dev->bw != MT_BW_20) { + mt7601u_bbp_rmw(dev, 4, 0x20, 0); + mt7601u_bbp_wr(dev, 178, 0xff); + + t->cck[0].bw20 = dev->ee->real_cck_bw20[0]; + t->cck[1].bw20 = dev->ee->real_cck_bw20[1]; + } else { /* Apply CH14 OBW fixup */ + mt7601u_bbp_wr(dev, 4, 0x60); + mt7601u_bbp_wr(dev, 178, 0); + + /* Note: vendor code is buggy here for negative values */ + t->cck[0].bw20 = dev->ee->real_cck_bw20[0] - 2; + t->cck[1].bw20 = dev->ee->real_cck_bw20[1] - 2; + } +} + +static int __mt7601u_phy_set_channel(struct mt7601u_dev *dev, + struct cfg80211_chan_def *chandef) +{ +#define FREQ_PLAN_REGS 4 + static const u8 freq_plan[14][FREQ_PLAN_REGS] = { + { 0x99, 0x99, 0x09, 0x50 }, + { 0x46, 0x44, 0x0a, 0x50 }, + { 0xec, 0xee, 0x0a, 0x50 }, + { 0x99, 0x99, 0x0b, 0x50 }, + { 0x46, 0x44, 0x08, 0x51 }, + { 0xec, 0xee, 0x08, 0x51 }, + { 0x99, 0x99, 0x09, 0x51 }, + { 0x46, 0x44, 0x0a, 0x51 }, + { 0xec, 0xee, 0x0a, 0x51 }, + { 0x99, 0x99, 0x0b, 0x51 }, + { 0x46, 0x44, 0x08, 0x52 }, + { 0xec, 0xee, 0x08, 0x52 }, + { 0x99, 0x99, 0x09, 0x52 }, + { 0x33, 0x33, 0x0b, 0x52 }, + }; + struct mt76_reg_pair channel_freq_plan[FREQ_PLAN_REGS] = { + { 17, 0 }, { 18, 0 }, { 19, 0 }, { 20, 0 }, + }; + struct mt76_reg_pair bbp_settings[3] = { + { 62, 0x37 - dev->ee->lna_gain }, + { 63, 0x37 - dev->ee->lna_gain }, + { 64, 0x37 - dev->ee->lna_gain }, + }; + + struct ieee80211_channel *chan = chandef->chan; + enum nl80211_channel_type chan_type = + cfg80211_get_chandef_type(chandef); + struct mt7601u_rate_power *t = &dev->ee->power_rate_table; + int chan_idx; + bool chan_ext_below; + u8 bw; + int i, ret; + + bw = MT_BW_20; + chan_ext_below = (chan_type == NL80211_CHAN_HT40MINUS); + chan_idx = chan->hw_value - 1; + + if (chandef->width == NL80211_CHAN_WIDTH_40) { + bw = MT_BW_40; + + if (chan_idx > 1 && chan_type == NL80211_CHAN_HT40MINUS) + chan_idx -= 2; + else if (chan_idx < 12 && chan_type == NL80211_CHAN_HT40PLUS) + chan_idx += 2; + else + dev_err(dev->dev, "Error: invalid 40MHz channel!!\n"); + } + + if (bw != dev->bw || chan_ext_below != dev->chan_ext_below) { + dev_dbg(dev->dev, "Info: switching HT mode bw:%d below:%d\n", + bw, chan_ext_below); + + mt7601u_bbp_set_bw(dev, bw); + + mt7601u_bbp_set_ctrlch(dev, chan_ext_below); + mt7601u_mac_set_ctrlch(dev, chan_ext_below); + dev->chan_ext_below = chan_ext_below; + } + + for (i = 0; i < FREQ_PLAN_REGS; i++) + channel_freq_plan[i].value = freq_plan[chan_idx][i]; + + ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_RF, + channel_freq_plan, FREQ_PLAN_REGS); + if (ret) + return ret; + + mt7601u_rmw(dev, MT_TX_ALC_CFG_0, 0x3f3f, + dev->ee->chan_pwr[chan_idx] & 0x3f); + + ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, + bbp_settings, ARRAY_SIZE(bbp_settings)); + if (ret) + return ret; + + mt7601u_vco_cal(dev); + mt7601u_bbp_set_bw(dev, bw); + ret = mt7601u_set_bw_filter(dev, false); + if (ret) + return ret; + + mt7601u_apply_ch14_fixup(dev, chan->hw_value); + mt7601u_wr(dev, MT_TX_PWR_CFG_0, int_to_s6(t->ofdm[1].bw20) << 24 | + int_to_s6(t->ofdm[0].bw20) << 16 | + int_to_s6(t->cck[1].bw20) << 8 | + int_to_s6(t->cck[0].bw20)); + + if (test_bit(MT7601U_STATE_SCANNING, &dev->state)) + mt7601u_agc_reset(dev); + + dev->chandef = *chandef; + + return 0; +} + +int mt7601u_phy_set_channel(struct mt7601u_dev *dev, + struct cfg80211_chan_def *chandef) +{ + int ret; + + cancel_delayed_work_sync(&dev->cal_work); + cancel_delayed_work_sync(&dev->freq_cal.work); + + mutex_lock(&dev->hw_atomic_mutex); + ret = __mt7601u_phy_set_channel(dev, chandef); + mutex_unlock(&dev->hw_atomic_mutex); + if (ret) + return ret; + + if (test_bit(MT7601U_STATE_SCANNING, &dev->state)) + return 0; + + ieee80211_queue_delayed_work(dev->hw, &dev->cal_work, + MT_CALIBRATE_INTERVAL); + if (dev->freq_cal.enabled) + ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, + MT_FREQ_CAL_INIT_DELAY); + return 0; +} + +#define BBP_R47_FLAG GENMASK(2, 0) +#define BBP_R47_F_TSSI 0 +#define BBP_R47_F_PKT_T 1 +#define BBP_R47_F_TX_RATE 2 +#define BBP_R47_F_TEMP 4 +/** + * mt7601u_bbp_r47_get - read value through BBP R47/R49 pair + * @dev: pointer to adapter structure + * @reg: value of BBP R47 before the operation + * @flag: one of the BBP_R47_F_* flags + * + * Convenience helper for reading values through BBP R47/R49 pair. + * Takes old value of BBP R47 as @reg, because callers usually have it + * cached already. + * + * Return: value of BBP R49. + */ +static u8 mt7601u_bbp_r47_get(struct mt7601u_dev *dev, u8 reg, u8 flag) +{ + flag |= reg & ~BBP_R47_FLAG; + mt7601u_bbp_wr(dev, 47, flag); + usleep_range(500, 700); + return mt7601u_bbp_rr(dev, 49); +} + +static s8 mt7601u_read_bootup_temp(struct mt7601u_dev *dev) +{ + u8 bbp_val, temp; + u32 rf_bp, rf_set; + int i; + + rf_set = mt7601u_rr(dev, MT_RF_SETTING_0); + rf_bp = mt7601u_rr(dev, MT_RF_BYPASS_0); + + mt7601u_wr(dev, MT_RF_BYPASS_0, 0); + mt7601u_wr(dev, MT_RF_SETTING_0, 0x00000010); + mt7601u_wr(dev, MT_RF_BYPASS_0, 0x00000010); + + bbp_val = mt7601u_bbp_rmw(dev, 47, 0, 0x10); + + mt7601u_bbp_wr(dev, 22, 0x40); + + for (i = 100; i && (bbp_val & 0x10); i--) + bbp_val = mt7601u_bbp_rr(dev, 47); + + temp = mt7601u_bbp_r47_get(dev, bbp_val, BBP_R47_F_TEMP); + + mt7601u_bbp_wr(dev, 22, 0); + + bbp_val = mt7601u_bbp_rr(dev, 21); + bbp_val |= 0x02; + mt7601u_bbp_wr(dev, 21, bbp_val); + bbp_val &= ~0x02; + mt7601u_bbp_wr(dev, 21, bbp_val); + + mt7601u_wr(dev, MT_RF_BYPASS_0, 0); + mt7601u_wr(dev, MT_RF_SETTING_0, rf_set); + mt7601u_wr(dev, MT_RF_BYPASS_0, rf_bp); + + trace_read_temp(dev, temp); + return temp; +} + +static s8 mt7601u_read_temp(struct mt7601u_dev *dev) +{ + int i; + u8 val; + s8 temp; + + val = mt7601u_bbp_rmw(dev, 47, 0x7f, 0x10); + + /* Note: this rarely succeeds, temp can change even if it fails. */ + for (i = 100; i && (val & 0x10); i--) + val = mt7601u_bbp_rr(dev, 47); + + temp = mt7601u_bbp_r47_get(dev, val, BBP_R47_F_TEMP); + + trace_read_temp(dev, temp); + return temp; +} + +static void mt7601u_rxdc_cal(struct mt7601u_dev *dev) +{ + static const struct mt76_reg_pair intro[] = { + { 158, 0x8d }, { 159, 0xfc }, + { 158, 0x8c }, { 159, 0x4c }, + }, outro[] = { + { 158, 0x8d }, { 159, 0xe0 }, + }; + u32 mac_ctrl; + int i, ret; + + mac_ctrl = mt7601u_rr(dev, MT_MAC_SYS_CTRL); + mt7601u_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX); + + ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, + intro, ARRAY_SIZE(intro)); + if (ret) + dev_err(dev->dev, "%s intro failed:%d\n", __func__, ret); + + for (i = 20; i; i--) { + usleep_range(300, 500); + + mt7601u_bbp_wr(dev, 158, 0x8c); + if (mt7601u_bbp_rr(dev, 159) == 0x0c) + break; + } + if (!i) + dev_err(dev->dev, "%s timed out\n", __func__); + + mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0); + + ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, + outro, ARRAY_SIZE(outro)); + if (ret) + dev_err(dev->dev, "%s outro failed:%d\n", __func__, ret); + + mt7601u_wr(dev, MT_MAC_SYS_CTRL, mac_ctrl); +} + +void mt7601u_phy_recalibrate_after_assoc(struct mt7601u_dev *dev) +{ + mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->curr_temp); + + mt7601u_rxdc_cal(dev); +} + +/* Note: function copied from vendor driver */ +static s16 lin2dBd(u16 linear) +{ + short exp = 0; + unsigned int mantisa; + int app, dBd; + + if (WARN_ON(!linear)) + return -10000; + + mantisa = linear; + + exp = fls(mantisa) - 16; + if (exp > 0) + mantisa >>= exp; + else + mantisa <<= abs(exp); + + if (mantisa <= 0xb800) + app = (mantisa + (mantisa >> 3) + (mantisa >> 4) - 0x9600); + else + app = (mantisa - (mantisa >> 3) - (mantisa >> 6) - 0x5a00); + if (app < 0) + app = 0; + + dBd = ((15 + exp) << 15) + app; + dBd = (dBd << 2) + (dBd << 1) + (dBd >> 6) + (dBd >> 7); + dBd = (dBd >> 10); + + return dBd; +} + +static void +mt7601u_set_initial_tssi(struct mt7601u_dev *dev, s16 tssi_db, s16 tssi_hvga_db) +{ + struct tssi_data *d = &dev->ee->tssi_data; + int init_offset; + + init_offset = -((tssi_db * d->slope + d->offset[1]) / 4096) + 10; + + mt76_rmw(dev, MT_TX_ALC_CFG_1, MT_TX_ALC_CFG_1_TEMP_COMP, + int_to_s6(init_offset) & MT_TX_ALC_CFG_1_TEMP_COMP); +} + +static void mt7601u_tssi_dc_gain_cal(struct mt7601u_dev *dev) +{ + u8 rf_vga, rf_mixer, bbp_r47; + int i, j; + s8 res[4]; + s16 tssi_init_db, tssi_init_hvga_db; + + mt7601u_wr(dev, MT_RF_SETTING_0, 0x00000030); + mt7601u_wr(dev, MT_RF_BYPASS_0, 0x000c0030); + mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0); + + mt7601u_bbp_wr(dev, 58, 0); + mt7601u_bbp_wr(dev, 241, 0x2); + mt7601u_bbp_wr(dev, 23, 0x8); + bbp_r47 = mt7601u_bbp_rr(dev, 47); + + /* Set VGA gain */ + rf_vga = mt7601u_rf_rr(dev, 5, 3); + mt7601u_rf_wr(dev, 5, 3, 8); + + /* Mixer disable */ + rf_mixer = mt7601u_rf_rr(dev, 4, 39); + mt7601u_rf_wr(dev, 4, 39, 0); + + for (i = 0; i < 4; i++) { + mt7601u_rf_wr(dev, 4, 39, (i & 1) ? rf_mixer : 0); + + mt7601u_bbp_wr(dev, 23, (i < 2) ? 0x08 : 0x02); + mt7601u_rf_wr(dev, 5, 3, (i < 2) ? 0x08 : 0x11); + + /* BBP TSSI initial and soft reset */ + mt7601u_bbp_wr(dev, 22, 0); + mt7601u_bbp_wr(dev, 244, 0); + + mt7601u_bbp_wr(dev, 21, 1); + udelay(1); + mt7601u_bbp_wr(dev, 21, 0); + + /* TSSI measurement */ + mt7601u_bbp_wr(dev, 47, 0x50); + mt7601u_bbp_wr(dev, (i & 1) ? 244 : 22, (i & 1) ? 0x31 : 0x40); + + for (j = 20; j; j--) + if (!(mt7601u_bbp_rr(dev, 47) & 0x10)) + break; + if (!j) + dev_err(dev->dev, "%s timed out\n", __func__); + + /* TSSI read */ + mt7601u_bbp_wr(dev, 47, 0x40); + res[i] = mt7601u_bbp_rr(dev, 49); + } + + tssi_init_db = lin2dBd((short)res[1] - res[0]); + tssi_init_hvga_db = lin2dBd(((short)res[3] - res[2]) * 4); + dev->tssi_init = res[0]; + dev->tssi_init_hvga = res[2]; + dev->tssi_init_hvga_offset_db = tssi_init_hvga_db - tssi_init_db; + + dev_dbg(dev->dev, + "TSSI_init:%hhx db:%hx hvga:%hhx hvga_db:%hx off_db:%hx\n", + dev->tssi_init, tssi_init_db, dev->tssi_init_hvga, + tssi_init_hvga_db, dev->tssi_init_hvga_offset_db); + + mt7601u_bbp_wr(dev, 22, 0); + mt7601u_bbp_wr(dev, 244, 0); + + mt7601u_bbp_wr(dev, 21, 1); + udelay(1); + mt7601u_bbp_wr(dev, 21, 0); + + mt7601u_wr(dev, MT_RF_BYPASS_0, 0); + mt7601u_wr(dev, MT_RF_SETTING_0, 0); + + mt7601u_rf_wr(dev, 5, 3, rf_vga); + mt7601u_rf_wr(dev, 4, 39, rf_mixer); + mt7601u_bbp_wr(dev, 47, bbp_r47); + + mt7601u_set_initial_tssi(dev, tssi_init_db, tssi_init_hvga_db); +} + +static int mt7601u_temp_comp(struct mt7601u_dev *dev, bool on) +{ + int ret, temp, hi_temp = 400, lo_temp = -200; + + temp = (dev->raw_temp - dev->ee->ref_temp) * MT_EE_TEMPERATURE_SLOPE; + dev->curr_temp = temp; + + /* DPD Calibration */ + if (temp - dev->dpd_temp > 450 || temp - dev->dpd_temp < -450) { + dev->dpd_temp = temp; + + ret = mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->dpd_temp); + if (ret) + return ret; + + mt7601u_vco_cal(dev); + + dev_dbg(dev->dev, "Recalibrate DPD\n"); + } + + /* PLL Lock Protect */ + if (temp < -50 && !dev->pll_lock_protect) { /* < 20C */ + dev->pll_lock_protect = true; + + mt7601u_rf_wr(dev, 4, 4, 6); + mt7601u_rf_clear(dev, 4, 10, 0x30); + + dev_dbg(dev->dev, "PLL lock protect on - too cold\n"); + } else if (temp > 50 && dev->pll_lock_protect) { /* > 30C */ + dev->pll_lock_protect = false; + + mt7601u_rf_wr(dev, 4, 4, 0); + mt7601u_rf_rmw(dev, 4, 10, 0x30, 0x10); + + dev_dbg(dev->dev, "PLL lock protect off\n"); + } + + if (on) { + hi_temp -= 50; + lo_temp -= 50; + } + + /* BBP CR for H, L, N temperature */ + if (temp > hi_temp) + return mt7601u_bbp_temp(dev, MT_TEMP_MODE_HIGH, "high"); + else if (temp > lo_temp) + return mt7601u_bbp_temp(dev, MT_TEMP_MODE_NORMAL, "normal"); + else + return mt7601u_bbp_temp(dev, MT_TEMP_MODE_LOW, "low"); +} + +/* Note: this is used only with TSSI, we can just use trgt_pwr from eeprom. */ +static int mt7601u_current_tx_power(struct mt7601u_dev *dev) +{ + return dev->ee->chan_pwr[dev->chandef.chan->hw_value - 1]; +} + +static bool mt7601u_use_hvga(struct mt7601u_dev *dev) +{ + return !(mt7601u_current_tx_power(dev) > 20); +} + +static s16 +mt7601u_phy_rf_pa_mode_val(struct mt7601u_dev *dev, int phy_mode, int tx_rate) +{ + static const s16 decode_tb[] = { 0, 8847, -5734, -5734 }; + u32 reg; + + switch (phy_mode) { + case MT_PHY_TYPE_OFDM: + tx_rate += 4; + case MT_PHY_TYPE_CCK: + reg = dev->rf_pa_mode[0]; + break; + default: + reg = dev->rf_pa_mode[1]; + break; + } + + return decode_tb[(reg >> (tx_rate * 2)) & 0x3]; +} + +static struct mt7601u_tssi_params +mt7601u_tssi_params_get(struct mt7601u_dev *dev) +{ + static const u8 ofdm_pkt2rate[8] = { 6, 4, 2, 0, 7, 5, 3, 1 }; + static const int static_power[4] = { 0, -49152, -98304, 49152 }; + struct mt7601u_tssi_params p; + u8 bbp_r47, pkt_type, tx_rate; + struct power_per_rate *rate_table; + + bbp_r47 = mt7601u_bbp_rr(dev, 47); + + p.tssi0 = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TSSI); + dev->raw_temp = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TEMP); + pkt_type = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_PKT_T); + + p.trgt_power = mt7601u_current_tx_power(dev); + + switch (pkt_type & 0x03) { + case MT_PHY_TYPE_CCK: + tx_rate = (pkt_type >> 4) & 0x03; + rate_table = dev->ee->power_rate_table.cck; + break; + + case MT_PHY_TYPE_OFDM: + tx_rate = ofdm_pkt2rate[(pkt_type >> 4) & 0x07]; + rate_table = dev->ee->power_rate_table.ofdm; + break; + + default: + tx_rate = mt7601u_bbp_r47_get(dev, bbp_r47, BBP_R47_F_TX_RATE); + tx_rate &= 0x7f; + rate_table = dev->ee->power_rate_table.ht; + break; + } + + if (dev->bw == MT_BW_20) + p.trgt_power += rate_table[tx_rate / 2].bw20; + else + p.trgt_power += rate_table[tx_rate / 2].bw40; + + p.trgt_power <<= 12; + + dev_dbg(dev->dev, "tx_rate:%02hhx pwr:%08x\n", tx_rate, p.trgt_power); + + p.trgt_power += mt7601u_phy_rf_pa_mode_val(dev, pkt_type & 0x03, + tx_rate); + + /* Channel 14, cck, bw20 */ + if ((pkt_type & 0x03) == MT_PHY_TYPE_CCK) { + if (mt7601u_bbp_rr(dev, 4) & 0x20) + p.trgt_power += mt7601u_bbp_rr(dev, 178) ? 18022 : 9830; + else + p.trgt_power += mt7601u_bbp_rr(dev, 178) ? 819 : 24576; + } + + p.trgt_power += static_power[mt7601u_bbp_rr(dev, 1) & 0x03]; + + p.trgt_power += dev->ee->tssi_data.tx0_delta_offset; + + dev_dbg(dev->dev, + "tssi:%02hhx t_power:%08x temp:%02hhx pkt_type:%02hhx\n", + p.tssi0, p.trgt_power, dev->raw_temp, pkt_type); + + return p; +} + +static bool mt7601u_tssi_read_ready(struct mt7601u_dev *dev) +{ + return !(mt7601u_bbp_rr(dev, 47) & 0x10); +} + +static int mt7601u_tssi_cal(struct mt7601u_dev *dev) +{ + struct mt7601u_tssi_params params; + int curr_pwr, diff_pwr; + char tssi_offset; + s8 tssi_init; + s16 tssi_m_dc, tssi_db; + bool hvga; + u32 val; + + if (!dev->ee->tssi_enabled) + return 0; + + hvga = mt7601u_use_hvga(dev); + if (!dev->tssi_read_trig) + return mt7601u_mcu_tssi_read_kick(dev, hvga); + + if (!mt7601u_tssi_read_ready(dev)) + return 0; + + params = mt7601u_tssi_params_get(dev); + + tssi_init = (hvga ? dev->tssi_init_hvga : dev->tssi_init); + tssi_m_dc = params.tssi0 - tssi_init; + tssi_db = lin2dBd(tssi_m_dc); + dev_dbg(dev->dev, "tssi dc:%04hx db:%04hx hvga:%d\n", + tssi_m_dc, tssi_db, hvga); + + if (dev->chandef.chan->hw_value < 5) + tssi_offset = dev->ee->tssi_data.offset[0]; + else if (dev->chandef.chan->hw_value < 9) + tssi_offset = dev->ee->tssi_data.offset[1]; + else + tssi_offset = dev->ee->tssi_data.offset[2]; + + if (hvga) + tssi_db -= dev->tssi_init_hvga_offset_db; + + curr_pwr = tssi_db * dev->ee->tssi_data.slope + (tssi_offset << 9); + diff_pwr = params.trgt_power - curr_pwr; + dev_dbg(dev->dev, "Power curr:%08x diff:%08x\n", curr_pwr, diff_pwr); + + if (params.tssi0 > 126 && diff_pwr > 0) { + dev_err(dev->dev, "Error: TSSI upper saturation\n"); + diff_pwr = 0; + } + if (params.tssi0 - tssi_init < 1 && diff_pwr < 0) { + dev_err(dev->dev, "Error: TSSI lower saturation\n"); + diff_pwr = 0; + } + + if ((dev->prev_pwr_diff ^ diff_pwr) < 0 && abs(diff_pwr) < 4096 && + (abs(diff_pwr) > abs(dev->prev_pwr_diff) || + (diff_pwr > 0 && diff_pwr == -dev->prev_pwr_diff))) + diff_pwr = 0; + else + dev->prev_pwr_diff = diff_pwr; + + diff_pwr += (diff_pwr > 0) ? 2048 : -2048; + diff_pwr /= 4096; + + dev_dbg(dev->dev, "final diff: %08x\n", diff_pwr); + + val = mt7601u_rr(dev, MT_TX_ALC_CFG_1); + curr_pwr = s6_to_int(MT76_GET(MT_TX_ALC_CFG_1_TEMP_COMP, val)); + diff_pwr += curr_pwr; + val = (val & ~MT_TX_ALC_CFG_1_TEMP_COMP) | int_to_s6(diff_pwr); + mt7601u_wr(dev, MT_TX_ALC_CFG_1, val); + + return mt7601u_mcu_tssi_read_kick(dev, hvga); +} + +static u8 mt7601u_agc_default(struct mt7601u_dev *dev) +{ + return (dev->ee->lna_gain - 8) * 2 + 0x34; +} + +static void mt7601u_agc_reset(struct mt7601u_dev *dev) +{ + u8 agc = mt7601u_agc_default(dev); + + mt7601u_bbp_wr(dev, 66, agc); +} + +void mt7601u_agc_save(struct mt7601u_dev *dev) +{ + dev->agc_save = mt7601u_bbp_rr(dev, 66); +} + +void mt7601u_agc_restore(struct mt7601u_dev *dev) +{ + mt7601u_bbp_wr(dev, 66, dev->agc_save); +} + +static void mt7601u_agc_tune(struct mt7601u_dev *dev) +{ + u8 val = mt7601u_agc_default(dev); + + if (test_bit(MT7601U_STATE_SCANNING, &dev->state)) + return; + + /* Note: only in STA mode and not dozing; perhaps do this only if + * there is enough rssi updates since last run? + * Rssi updates are only on beacons and U2M so should work... + */ + spin_lock_bh(&dev->con_mon_lock); + if (dev->avg_rssi <= -70) + val -= 0x20; + else if (dev->avg_rssi <= -60) + val -= 0x10; + spin_unlock_bh(&dev->con_mon_lock); + + if (val != mt7601u_bbp_rr(dev, 66)) + mt7601u_bbp_wr(dev, 66, val); + + /* TODO: also if lost a lot of beacons try resetting + * (see RTMPSetAGCInitValue() call in mlme.c). + */ +} + +static void mt7601u_phy_calibrate(struct work_struct *work) +{ + struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, + cal_work.work); + + mt7601u_agc_tune(dev); + mt7601u_tssi_cal(dev); + /* If TSSI calibration was run it already updated temperature. */ + if (!dev->ee->tssi_enabled) + dev->raw_temp = mt7601u_read_temp(dev); + mt7601u_temp_comp(dev, true); /* TODO: find right value for @on */ + + ieee80211_queue_delayed_work(dev->hw, &dev->cal_work, + MT_CALIBRATE_INTERVAL); +} + +static unsigned long +__mt7601u_phy_freq_cal(struct mt7601u_dev *dev, s8 last_offset, u8 phy_mode) +{ + u8 activate_threshold, deactivate_threshold; + + trace_freq_cal_offset(dev, phy_mode, last_offset); + + /* No beacons received - reschedule soon */ + if (last_offset == MT_FREQ_OFFSET_INVALID) + return MT_FREQ_CAL_ADJ_INTERVAL; + + switch (phy_mode) { + case MT_PHY_TYPE_CCK: + activate_threshold = 19; + deactivate_threshold = 5; + break; + case MT_PHY_TYPE_OFDM: + activate_threshold = 102; + deactivate_threshold = 32; + break; + case MT_PHY_TYPE_HT: + case MT_PHY_TYPE_HT_GF: + activate_threshold = 82; + deactivate_threshold = 20; + break; + default: + WARN_ON(1); + return MT_FREQ_CAL_CHECK_INTERVAL; + } + + if (abs(last_offset) >= activate_threshold) + dev->freq_cal.adjusting = true; + else if (abs(last_offset) <= deactivate_threshold) + dev->freq_cal.adjusting = false; + + if (!dev->freq_cal.adjusting) + return MT_FREQ_CAL_CHECK_INTERVAL; + + if (last_offset > deactivate_threshold) { + if (dev->freq_cal.freq > 0) + dev->freq_cal.freq--; + else + dev->freq_cal.adjusting = false; + } else if (last_offset < -deactivate_threshold) { + if (dev->freq_cal.freq < 0xbf) + dev->freq_cal.freq++; + else + dev->freq_cal.adjusting = false; + } + + trace_freq_cal_adjust(dev, dev->freq_cal.freq); + mt7601u_rf_wr(dev, 0, 12, dev->freq_cal.freq); + mt7601u_vco_cal(dev); + + return dev->freq_cal.adjusting ? MT_FREQ_CAL_ADJ_INTERVAL : + MT_FREQ_CAL_CHECK_INTERVAL; +} + +static void mt7601u_phy_freq_cal(struct work_struct *work) +{ + struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, + freq_cal.work.work); + s8 last_offset; + u8 phy_mode; + unsigned long delay; + + spin_lock_bh(&dev->con_mon_lock); + last_offset = dev->bcn_freq_off; + phy_mode = dev->bcn_phy_mode; + spin_unlock_bh(&dev->con_mon_lock); + + delay = __mt7601u_phy_freq_cal(dev, last_offset, phy_mode); + ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, delay); + + spin_lock_bh(&dev->con_mon_lock); + dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID; + spin_unlock_bh(&dev->con_mon_lock); +} + +void mt7601u_phy_con_cal_onoff(struct mt7601u_dev *dev, + struct ieee80211_bss_conf *info) +{ + if (!info->assoc) + cancel_delayed_work_sync(&dev->freq_cal.work); + + /* Start/stop collecting beacon data */ + spin_lock_bh(&dev->con_mon_lock); + ether_addr_copy(dev->ap_bssid, info->bssid); + dev->avg_rssi = 0; + dev->bcn_freq_off = MT_FREQ_OFFSET_INVALID; + spin_unlock_bh(&dev->con_mon_lock); + + dev->freq_cal.freq = dev->ee->rf_freq_off; + dev->freq_cal.enabled = info->assoc; + dev->freq_cal.adjusting = false; + + if (info->assoc) + ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work, + MT_FREQ_CAL_INIT_DELAY); +} + +static int mt7601u_init_cal(struct mt7601u_dev *dev) +{ + u32 mac_ctrl; + int ret; + + dev->raw_temp = mt7601u_read_bootup_temp(dev); + dev->curr_temp = (dev->raw_temp - dev->ee->ref_temp) * + MT_EE_TEMPERATURE_SLOPE; + dev->dpd_temp = dev->curr_temp; + + mac_ctrl = mt7601u_rr(dev, MT_MAC_SYS_CTRL); + + ret = mt7601u_mcu_calibrate(dev, MCU_CAL_R, 0); + if (ret) + return ret; + + ret = mt7601u_rf_rr(dev, 0, 4); + if (ret < 0) + return ret; + ret |= 0x80; + ret = mt7601u_rf_wr(dev, 0, 4, ret); + if (ret) + return ret; + msleep(2); + + ret = mt7601u_mcu_calibrate(dev, MCU_CAL_TXDCOC, 0); + if (ret) + return ret; + + mt7601u_rxdc_cal(dev); + + ret = mt7601u_set_bw_filter(dev, true); + if (ret) + return ret; + ret = mt7601u_mcu_calibrate(dev, MCU_CAL_LOFT, 0); + if (ret) + return ret; + ret = mt7601u_mcu_calibrate(dev, MCU_CAL_TXIQ, 0); + if (ret) + return ret; + ret = mt7601u_mcu_calibrate(dev, MCU_CAL_RXIQ, 0); + if (ret) + return ret; + ret = mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->dpd_temp); + if (ret) + return ret; + + mt7601u_rxdc_cal(dev); + + mt7601u_tssi_dc_gain_cal(dev); + + mt7601u_wr(dev, MT_MAC_SYS_CTRL, mac_ctrl); + + mt7601u_temp_comp(dev, true); + + return 0; +} + +int mt7601u_bbp_set_bw(struct mt7601u_dev *dev, int bw) +{ + u32 val, old; + + if (bw == dev->bw) { + /* Vendor driver does the rmc even when no change is needed. */ + mt7601u_bbp_rmc(dev, 4, 0x18, bw == MT_BW_20 ? 0 : 0x10); + + return 0; + } + dev->bw = bw; + + /* Stop MAC for the time of bw change */ + old = mt7601u_rr(dev, MT_MAC_SYS_CTRL); + val = old & ~(MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); + mt7601u_wr(dev, MT_MAC_SYS_CTRL, val); + mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, + 0, 500000); + + mt7601u_bbp_rmc(dev, 4, 0x18, bw == MT_BW_20 ? 0 : 0x10); + + mt7601u_wr(dev, MT_MAC_SYS_CTRL, old); + + return mt7601u_load_bbp_temp_table_bw(dev); +} + +/** + * mt7601u_set_rx_path - set rx path in BBP + * @dev: pointer to adapter structure + * @path: rx path to set values are 0-based + */ +void mt7601u_set_rx_path(struct mt7601u_dev *dev, u8 path) +{ + mt7601u_bbp_rmw(dev, 3, 0x18, path << 3); +} + +/** + * mt7601u_set_tx_dac - set which tx DAC to use + * @dev: pointer to adapter structure + * @path: DAC index, values are 0-based + */ +void mt7601u_set_tx_dac(struct mt7601u_dev *dev, u8 dac) +{ + mt7601u_bbp_rmc(dev, 1, 0x18, dac << 3); +} + +int mt7601u_phy_init(struct mt7601u_dev *dev) +{ + int ret; + + dev->rf_pa_mode[0] = mt7601u_rr(dev, MT_RF_PA_MODE_CFG0); + dev->rf_pa_mode[1] = mt7601u_rr(dev, MT_RF_PA_MODE_CFG1); + + ret = mt7601u_rf_wr(dev, 0, 12, dev->ee->rf_freq_off); + if (ret) + return ret; + ret = mt7601u_write_reg_pairs(dev, 0, rf_central, + ARRAY_SIZE(rf_central)); + if (ret) + return ret; + ret = mt7601u_write_reg_pairs(dev, 0, rf_channel, + ARRAY_SIZE(rf_channel)); + if (ret) + return ret; + ret = mt7601u_write_reg_pairs(dev, 0, rf_vga, ARRAY_SIZE(rf_vga)); + if (ret) + return ret; + + ret = mt7601u_init_cal(dev); + if (ret) + return ret; + + dev->prev_pwr_diff = 100; + + INIT_DELAYED_WORK(&dev->cal_work, mt7601u_phy_calibrate); + INIT_DELAYED_WORK(&dev->freq_cal.work, mt7601u_phy_freq_cal); + + return 0; +} diff --git a/linux-bsp/drivers/mt7601u-sta/regs.h b/linux-bsp/drivers/mt7601u-sta/regs.h new file mode 100644 index 0000000..ce0b23d --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/regs.h @@ -0,0 +1,639 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT76_REGS_H +#define __MT76_REGS_H + +#include <linux/bitops.h> + +#ifndef GENMASK +#define GENMASK(h, l) (((U32_C(1) << ((h) - (l) + 1)) - 1) << (l)) +#endif + +#define MT_ASIC_VERSION 0x0000 + +#define MT76XX_REV_E3 0x22 +#define MT76XX_REV_E4 0x33 + +#define MT_CMB_CTRL 0x0020 +#define MT_CMB_CTRL_XTAL_RDY BIT(22) +#define MT_CMB_CTRL_PLL_LD BIT(23) + +#define MT_EFUSE_CTRL 0x0024 +#define MT_EFUSE_CTRL_AOUT GENMASK(5, 0) +#define MT_EFUSE_CTRL_MODE GENMASK(7, 6) +#define MT_EFUSE_CTRL_LDO_OFF_TIME GENMASK(13, 8) +#define MT_EFUSE_CTRL_LDO_ON_TIME GENMASK(15, 14) +#define MT_EFUSE_CTRL_AIN GENMASK(25, 16) +#define MT_EFUSE_CTRL_KICK BIT(30) +#define MT_EFUSE_CTRL_SEL BIT(31) + +#define MT_EFUSE_DATA_BASE 0x0028 +#define MT_EFUSE_DATA(_n) (MT_EFUSE_DATA_BASE + ((_n) << 2)) + +#define MT_COEXCFG0 0x0040 +#define MT_COEXCFG0_COEX_EN BIT(0) + +#define MT_WLAN_FUN_CTRL 0x0080 +#define MT_WLAN_FUN_CTRL_WLAN_EN BIT(0) +#define MT_WLAN_FUN_CTRL_WLAN_CLK_EN BIT(1) +#define MT_WLAN_FUN_CTRL_WLAN_RESET_RF BIT(2) + +#define MT_WLAN_FUN_CTRL_WLAN_RESET BIT(3) /* MT76x0 */ +#define MT_WLAN_FUN_CTRL_CSR_F20M_CKEN BIT(3) /* MT76x2 */ + +#define MT_WLAN_FUN_CTRL_PCIE_CLK_REQ BIT(4) +#define MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL BIT(5) +#define MT_WLAN_FUN_CTRL_INV_ANT_SEL BIT(6) +#define MT_WLAN_FUN_CTRL_WAKE_HOST BIT(7) + +#define MT_WLAN_FUN_CTRL_THERM_RST BIT(8) /* MT76x2 */ +#define MT_WLAN_FUN_CTRL_THERM_CKEN BIT(9) /* MT76x2 */ + +#define MT_WLAN_FUN_CTRL_GPIO_IN GENMASK(15, 8) /* MT76x0 */ +#define MT_WLAN_FUN_CTRL_GPIO_OUT GENMASK(23, 16) /* MT76x0 */ +#define MT_WLAN_FUN_CTRL_GPIO_OUT_EN GENMASK(31, 24) /* MT76x0 */ + +#define MT_XO_CTRL0 0x0100 +#define MT_XO_CTRL1 0x0104 +#define MT_XO_CTRL2 0x0108 +#define MT_XO_CTRL3 0x010c +#define MT_XO_CTRL4 0x0110 + +#define MT_XO_CTRL5 0x0114 +#define MT_XO_CTRL5_C2_VAL GENMASK(14, 8) + +#define MT_XO_CTRL6 0x0118 +#define MT_XO_CTRL6_C2_CTRL GENMASK(14, 8) + +#define MT_XO_CTRL7 0x011c + +#define MT_WLAN_MTC_CTRL 0x10148 +#define MT_WLAN_MTC_CTRL_MTCMOS_PWR_UP BIT(0) +#define MT_WLAN_MTC_CTRL_PWR_ACK BIT(12) +#define MT_WLAN_MTC_CTRL_PWR_ACK_S BIT(13) +#define MT_WLAN_MTC_CTRL_BBP_MEM_PD GENMASK(19, 16) +#define MT_WLAN_MTC_CTRL_PBF_MEM_PD BIT(20) +#define MT_WLAN_MTC_CTRL_FCE_MEM_PD BIT(21) +#define MT_WLAN_MTC_CTRL_TSO_MEM_PD BIT(22) +#define MT_WLAN_MTC_CTRL_BBP_MEM_RB BIT(24) +#define MT_WLAN_MTC_CTRL_PBF_MEM_RB BIT(25) +#define MT_WLAN_MTC_CTRL_FCE_MEM_RB BIT(26) +#define MT_WLAN_MTC_CTRL_TSO_MEM_RB BIT(27) +#define MT_WLAN_MTC_CTRL_STATE_UP BIT(28) + +#define MT_INT_SOURCE_CSR 0x0200 +#define MT_INT_MASK_CSR 0x0204 + +#define MT_INT_RX_DONE(_n) BIT(_n) +#define MT_INT_RX_DONE_ALL GENMASK(1, 0) +#define MT_INT_TX_DONE_ALL GENMASK(13, 4) +#define MT_INT_TX_DONE(_n) BIT(_n + 4) +#define MT_INT_RX_COHERENT BIT(16) +#define MT_INT_TX_COHERENT BIT(17) +#define MT_INT_ANY_COHERENT BIT(18) +#define MT_INT_MCU_CMD BIT(19) +#define MT_INT_TBTT BIT(20) +#define MT_INT_PRE_TBTT BIT(21) +#define MT_INT_TX_STAT BIT(22) +#define MT_INT_AUTO_WAKEUP BIT(23) +#define MT_INT_GPTIMER BIT(24) +#define MT_INT_RXDELAYINT BIT(26) +#define MT_INT_TXDELAYINT BIT(27) + +#define MT_WPDMA_GLO_CFG 0x0208 +#define MT_WPDMA_GLO_CFG_TX_DMA_EN BIT(0) +#define MT_WPDMA_GLO_CFG_TX_DMA_BUSY BIT(1) +#define MT_WPDMA_GLO_CFG_RX_DMA_EN BIT(2) +#define MT_WPDMA_GLO_CFG_RX_DMA_BUSY BIT(3) +#define MT_WPDMA_GLO_CFG_DMA_BURST_SIZE GENMASK(5, 4) +#define MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE BIT(6) +#define MT_WPDMA_GLO_CFG_BIG_ENDIAN BIT(7) +#define MT_WPDMA_GLO_CFG_HDR_SEG_LEN GENMASK(15, 8) +#define MT_WPDMA_GLO_CFG_CLK_GATE_DIS BIT(30) +#define MT_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31) + +#define MT_WPDMA_RST_IDX 0x020c + +#define MT_WPDMA_DELAY_INT_CFG 0x0210 + +#define MT_WMM_AIFSN 0x0214 +#define MT_WMM_AIFSN_MASK GENMASK(3, 0) +#define MT_WMM_AIFSN_SHIFT(_n) ((_n) * 4) + +#define MT_WMM_CWMIN 0x0218 +#define MT_WMM_CWMIN_MASK GENMASK(3, 0) +#define MT_WMM_CWMIN_SHIFT(_n) ((_n) * 4) + +#define MT_WMM_CWMAX 0x021c +#define MT_WMM_CWMAX_MASK GENMASK(3, 0) +#define MT_WMM_CWMAX_SHIFT(_n) ((_n) * 4) + +#define MT_WMM_TXOP_BASE 0x0220 +#define MT_WMM_TXOP(_n) (MT_WMM_TXOP_BASE + (((_n) / 2) << 2)) +#define MT_WMM_TXOP_SHIFT(_n) ((_n & 1) * 16) +#define MT_WMM_TXOP_MASK GENMASK(15, 0) + +#define MT_FCE_DMA_ADDR 0x0230 +#define MT_FCE_DMA_LEN 0x0234 + +#define MT_USB_DMA_CFG 0x238 +#define MT_USB_DMA_CFG_RX_BULK_AGG_TOUT GENMASK(7, 0) +#define MT_USB_DMA_CFG_RX_BULK_AGG_LMT GENMASK(15, 8) +#define MT_USB_DMA_CFG_PHY_CLR BIT(16) +#define MT_USB_DMA_CFG_TX_CLR BIT(19) +#define MT_USB_DMA_CFG_TXOP_HALT BIT(20) +#define MT_USB_DMA_CFG_RX_BULK_AGG_EN BIT(21) +#define MT_USB_DMA_CFG_RX_BULK_EN BIT(22) +#define MT_USB_DMA_CFG_TX_BULK_EN BIT(23) +#define MT_USB_DMA_CFG_UDMA_RX_WL_DROP BIT(25) +#define MT_USB_DMA_CFG_EP_OUT_VALID GENMASK(29, 27) +#define MT_USB_DMA_CFG_RX_BUSY BIT(30) +#define MT_USB_DMA_CFG_TX_BUSY BIT(31) + +#define MT_TSO_CTRL 0x0250 +#define MT_HEADER_TRANS_CTRL_REG 0x0260 + +#define MT_US_CYC_CFG 0x02a4 +#define MT_US_CYC_CNT GENMASK(7, 0) + +#define MT_TX_RING_BASE 0x0300 +#define MT_RX_RING_BASE 0x03c0 +#define MT_RING_SIZE 0x10 + +#define MT_TX_HW_QUEUE_MCU 8 +#define MT_TX_HW_QUEUE_MGMT 9 + +#define MT_PBF_SYS_CTRL 0x0400 +#define MT_PBF_SYS_CTRL_MCU_RESET BIT(0) +#define MT_PBF_SYS_CTRL_DMA_RESET BIT(1) +#define MT_PBF_SYS_CTRL_MAC_RESET BIT(2) +#define MT_PBF_SYS_CTRL_PBF_RESET BIT(3) +#define MT_PBF_SYS_CTRL_ASY_RESET BIT(4) + +#define MT_PBF_CFG 0x0404 +#define MT_PBF_CFG_TX0Q_EN BIT(0) +#define MT_PBF_CFG_TX1Q_EN BIT(1) +#define MT_PBF_CFG_TX2Q_EN BIT(2) +#define MT_PBF_CFG_TX3Q_EN BIT(3) +#define MT_PBF_CFG_RX0Q_EN BIT(4) +#define MT_PBF_CFG_RX_DROP_EN BIT(8) + +#define MT_PBF_TX_MAX_PCNT 0x0408 +#define MT_PBF_RX_MAX_PCNT 0x040c + +#define MT_BCN_OFFSET_BASE 0x041c +#define MT_BCN_OFFSET(_n) (MT_BCN_OFFSET_BASE + ((_n) << 2)) + +#define MT_RXQ_STA 0x0430 +#define MT_TXQ_STA 0x0434 + +#define MT_RF_CSR_CFG 0x0500 +#define MT_RF_CSR_CFG_DATA GENMASK(7, 0) +#define MT_RF_CSR_CFG_REG_ID GENMASK(13, 8) +#define MT_RF_CSR_CFG_REG_BANK GENMASK(17, 14) +#define MT_RF_CSR_CFG_WR BIT(30) +#define MT_RF_CSR_CFG_KICK BIT(31) + +#define MT_RF_BYPASS_0 0x0504 +#define MT_RF_BYPASS_1 0x0508 +#define MT_RF_SETTING_0 0x050c + +#define MT_RF_DATA_WRITE 0x0524 + +#define MT_RF_CTRL 0x0528 +#define MT_RF_CTRL_ADDR GENMASK(11, 0) +#define MT_RF_CTRL_WRITE BIT(12) +#define MT_RF_CTRL_BUSY BIT(13) +#define MT_RF_CTRL_IDX BIT(16) + +#define MT_RF_DATA_READ 0x052c + +#define MT_FCE_PSE_CTRL 0x0800 +#define MT_FCE_PARAMETERS 0x0804 +#define MT_FCE_CSO 0x0808 + +#define MT_FCE_L2_STUFF 0x080c +#define MT_FCE_L2_STUFF_HT_L2_EN BIT(0) +#define MT_FCE_L2_STUFF_QOS_L2_EN BIT(1) +#define MT_FCE_L2_STUFF_RX_STUFF_EN BIT(2) +#define MT_FCE_L2_STUFF_TX_STUFF_EN BIT(3) +#define MT_FCE_L2_STUFF_WR_MPDU_LEN_EN BIT(4) +#define MT_FCE_L2_STUFF_MVINV_BSWAP BIT(5) +#define MT_FCE_L2_STUFF_TS_CMD_QSEL_EN GENMASK(15, 8) +#define MT_FCE_L2_STUFF_TS_LEN_EN GENMASK(23, 16) +#define MT_FCE_L2_STUFF_OTHER_PORT GENMASK(25, 24) + +#define MT_FCE_WLAN_FLOW_CONTROL1 0x0824 + +#define MT_TX_CPU_FROM_FCE_BASE_PTR 0x09a0 +#define MT_TX_CPU_FROM_FCE_MAX_COUNT 0x09a4 +#define MT_TX_CPU_FROM_FCE_CPU_DESC_IDX 0x09a8 + +#define MT_FCE_PDMA_GLOBAL_CONF 0x09c4 + +#define MT_PAUSE_ENABLE_CONTROL1 0x0a38 + +#define MT_FCE_SKIP_FS 0x0a6c + +#define MT_MAC_CSR0 0x1000 + +#define MT_MAC_SYS_CTRL 0x1004 +#define MT_MAC_SYS_CTRL_RESET_CSR BIT(0) +#define MT_MAC_SYS_CTRL_RESET_BBP BIT(1) +#define MT_MAC_SYS_CTRL_ENABLE_TX BIT(2) +#define MT_MAC_SYS_CTRL_ENABLE_RX BIT(3) + +#define MT_MAC_ADDR_DW0 0x1008 +#define MT_MAC_ADDR_DW1 0x100c +#define MT_MAC_ADDR_DW1_U2ME_MASK GENMASK(23, 16) + +#define MT_MAC_BSSID_DW0 0x1010 +#define MT_MAC_BSSID_DW1 0x1014 +#define MT_MAC_BSSID_DW1_ADDR GENMASK(15, 0) +#define MT_MAC_BSSID_DW1_MBSS_MODE GENMASK(17, 16) +#define MT_MAC_BSSID_DW1_MBEACON_N GENMASK(20, 18) +#define MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT BIT(21) +#define MT_MAC_BSSID_DW1_MBSS_MODE_B2 BIT(22) +#define MT_MAC_BSSID_DW1_MBEACON_N_B3 BIT(23) +#define MT_MAC_BSSID_DW1_MBSS_IDX_BYTE GENMASK(26, 24) + +#define MT_MAX_LEN_CFG 0x1018 +#define MT_MAX_LEN_CFG_AMPDU GENMASK(13, 12) + +#define MT_BBP_CSR_CFG 0x101c +#define MT_BBP_CSR_CFG_VAL GENMASK(7, 0) +#define MT_BBP_CSR_CFG_REG_NUM GENMASK(15, 8) +#define MT_BBP_CSR_CFG_READ BIT(16) +#define MT_BBP_CSR_CFG_BUSY BIT(17) +#define MT_BBP_CSR_CFG_PAR_DUR BIT(18) +#define MT_BBP_CSR_CFG_RW_MODE BIT(19) + +#define MT_AMPDU_MAX_LEN_20M1S 0x1030 +#define MT_AMPDU_MAX_LEN_20M2S 0x1034 +#define MT_AMPDU_MAX_LEN_40M1S 0x1038 +#define MT_AMPDU_MAX_LEN_40M2S 0x103c +#define MT_AMPDU_MAX_LEN 0x1040 + +#define MT_WCID_DROP_BASE 0x106c +#define MT_WCID_DROP(_n) (MT_WCID_DROP_BASE + ((_n) >> 5) * 4) +#define MT_WCID_DROP_MASK(_n) BIT((_n) % 32) + +#define MT_BCN_BYPASS_MASK 0x108c + +#define MT_MAC_APC_BSSID_BASE 0x1090 +#define MT_MAC_APC_BSSID_L(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8)) +#define MT_MAC_APC_BSSID_H(_n) (MT_MAC_APC_BSSID_BASE + ((_n) * 8 + 4)) +#define MT_MAC_APC_BSSID_H_ADDR GENMASK(15, 0) +#define MT_MAC_APC_BSSID0_H_EN BIT(16) + +#define MT_XIFS_TIME_CFG 0x1100 +#define MT_XIFS_TIME_CFG_CCK_SIFS GENMASK(7, 0) +#define MT_XIFS_TIME_CFG_OFDM_SIFS GENMASK(15, 8) +#define MT_XIFS_TIME_CFG_OFDM_XIFS GENMASK(19, 16) +#define MT_XIFS_TIME_CFG_EIFS GENMASK(28, 20) +#define MT_XIFS_TIME_CFG_BB_RXEND_EN BIT(29) + +#define MT_BKOFF_SLOT_CFG 0x1104 +#define MT_BKOFF_SLOT_CFG_SLOTTIME GENMASK(7, 0) +#define MT_BKOFF_SLOT_CFG_CC_DELAY GENMASK(11, 8) + +#define MT_BEACON_TIME_CFG 0x1114 +#define MT_BEACON_TIME_CFG_INTVAL GENMASK(15, 0) +#define MT_BEACON_TIME_CFG_TIMER_EN BIT(16) +#define MT_BEACON_TIME_CFG_SYNC_MODE GENMASK(18, 17) +#define MT_BEACON_TIME_CFG_TBTT_EN BIT(19) +#define MT_BEACON_TIME_CFG_BEACON_TX BIT(20) +#define MT_BEACON_TIME_CFG_TSF_COMP GENMASK(31, 24) + +#define MT_TBTT_SYNC_CFG 0x1118 +#define MT_TBTT_TIMER_CFG 0x1124 + +#define MT_INT_TIMER_CFG 0x1128 +#define MT_INT_TIMER_CFG_PRE_TBTT GENMASK(15, 0) +#define MT_INT_TIMER_CFG_GP_TIMER GENMASK(31, 16) + +#define MT_INT_TIMER_EN 0x112c +#define MT_INT_TIMER_EN_PRE_TBTT_EN BIT(0) +#define MT_INT_TIMER_EN_GP_TIMER_EN BIT(1) + +#define MT_MAC_STATUS 0x1200 +#define MT_MAC_STATUS_TX BIT(0) +#define MT_MAC_STATUS_RX BIT(1) + +#define MT_PWR_PIN_CFG 0x1204 +#define MT_AUX_CLK_CFG 0x120c + +#define MT_BB_PA_MODE_CFG0 0x1214 +#define MT_BB_PA_MODE_CFG1 0x1218 +#define MT_RF_PA_MODE_CFG0 0x121c +#define MT_RF_PA_MODE_CFG1 0x1220 + +#define MT_RF_PA_MODE_ADJ0 0x1228 +#define MT_RF_PA_MODE_ADJ1 0x122c + +#define MT_DACCLK_EN_DLY_CFG 0x1264 + +#define MT_EDCA_CFG_BASE 0x1300 +#define MT_EDCA_CFG_AC(_n) (MT_EDCA_CFG_BASE + ((_n) << 2)) +#define MT_EDCA_CFG_TXOP GENMASK(7, 0) +#define MT_EDCA_CFG_AIFSN GENMASK(11, 8) +#define MT_EDCA_CFG_CWMIN GENMASK(15, 12) +#define MT_EDCA_CFG_CWMAX GENMASK(19, 16) + +#define MT_TX_PWR_CFG_0 0x1314 +#define MT_TX_PWR_CFG_1 0x1318 +#define MT_TX_PWR_CFG_2 0x131c +#define MT_TX_PWR_CFG_3 0x1320 +#define MT_TX_PWR_CFG_4 0x1324 + +#define MT_TX_BAND_CFG 0x132c +#define MT_TX_BAND_CFG_UPPER_40M BIT(0) +#define MT_TX_BAND_CFG_5G BIT(1) +#define MT_TX_BAND_CFG_2G BIT(2) + +#define MT_HT_FBK_TO_LEGACY 0x1384 +#define MT_TX_MPDU_ADJ_INT 0x1388 + +#define MT_TX_PWR_CFG_7 0x13d4 +#define MT_TX_PWR_CFG_8 0x13d8 +#define MT_TX_PWR_CFG_9 0x13dc + +#define MT_TX_SW_CFG0 0x1330 +#define MT_TX_SW_CFG1 0x1334 +#define MT_TX_SW_CFG2 0x1338 + +#define MT_TXOP_CTRL_CFG 0x1340 +#define MT_TXOP_TRUN_EN GENMASK(5, 0) +#define MT_TXOP_EXT_CCA_DLY GENMASK(15, 8) +#define MT_TXOP_CTRL + +#define MT_TX_RTS_CFG 0x1344 +#define MT_TX_RTS_CFG_RETRY_LIMIT GENMASK(7, 0) +#define MT_TX_RTS_CFG_THRESH GENMASK(23, 8) +#define MT_TX_RTS_FALLBACK BIT(24) + +#define MT_TX_TIMEOUT_CFG 0x1348 +#define MT_TX_RETRY_CFG 0x134c +#define MT_TX_LINK_CFG 0x1350 +#define MT_HT_FBK_CFG0 0x1354 +#define MT_HT_FBK_CFG1 0x1358 +#define MT_LG_FBK_CFG0 0x135c +#define MT_LG_FBK_CFG1 0x1360 + +#define MT_CCK_PROT_CFG 0x1364 +#define MT_OFDM_PROT_CFG 0x1368 +#define MT_MM20_PROT_CFG 0x136c +#define MT_MM40_PROT_CFG 0x1370 +#define MT_GF20_PROT_CFG 0x1374 +#define MT_GF40_PROT_CFG 0x1378 + +#define MT_PROT_RATE GENMASK(15, 0) +#define MT_PROT_CTRL_RTS_CTS BIT(16) +#define MT_PROT_CTRL_CTS2SELF BIT(17) +#define MT_PROT_NAV_SHORT BIT(18) +#define MT_PROT_NAV_LONG BIT(19) +#define MT_PROT_TXOP_ALLOW_CCK BIT(20) +#define MT_PROT_TXOP_ALLOW_OFDM BIT(21) +#define MT_PROT_TXOP_ALLOW_MM20 BIT(22) +#define MT_PROT_TXOP_ALLOW_MM40 BIT(23) +#define MT_PROT_TXOP_ALLOW_GF20 BIT(24) +#define MT_PROT_TXOP_ALLOW_GF40 BIT(25) +#define MT_PROT_RTS_THR_EN BIT(26) +#define MT_PROT_RATE_CCK_11 0x0003 +#define MT_PROT_RATE_OFDM_6 0x4000 +#define MT_PROT_RATE_OFDM_24 0x4004 +#define MT_PROT_RATE_DUP_OFDM_24 0x4084 +#define MT_PROT_TXOP_ALLOW_ALL GENMASK(25, 20) +#define MT_PROT_TXOP_ALLOW_BW20 (MT_PROT_TXOP_ALLOW_ALL & \ + ~MT_PROT_TXOP_ALLOW_MM40 & \ + ~MT_PROT_TXOP_ALLOW_GF40) + +#define MT_EXP_ACK_TIME 0x1380 + +#define MT_TX_PWR_CFG_0_EXT 0x1390 +#define MT_TX_PWR_CFG_1_EXT 0x1394 + +#define MT_TX_FBK_LIMIT 0x1398 +#define MT_TX_FBK_LIMIT_MPDU_FBK GENMASK(7, 0) +#define MT_TX_FBK_LIMIT_AMPDU_FBK GENMASK(15, 8) +#define MT_TX_FBK_LIMIT_MPDU_UP_CLEAR BIT(16) +#define MT_TX_FBK_LIMIT_AMPDU_UP_CLEAR BIT(17) +#define MT_TX_FBK_LIMIT_RATE_LUT BIT(18) + +#define MT_TX0_RF_GAIN_CORR 0x13a0 +#define MT_TX1_RF_GAIN_CORR 0x13a4 +#define MT_TX0_RF_GAIN_ATTEN 0x13a8 + +#define MT_TX_ALC_CFG_0 0x13b0 +#define MT_TX_ALC_CFG_0_CH_INIT_0 GENMASK(5, 0) +#define MT_TX_ALC_CFG_0_CH_INIT_1 GENMASK(13, 8) +#define MT_TX_ALC_CFG_0_LIMIT_0 GENMASK(21, 16) +#define MT_TX_ALC_CFG_0_LIMIT_1 GENMASK(29, 24) + +#define MT_TX_ALC_CFG_1 0x13b4 +#define MT_TX_ALC_CFG_1_TEMP_COMP GENMASK(5, 0) + +#define MT_TX_ALC_CFG_2 0x13a8 +#define MT_TX_ALC_CFG_2_TEMP_COMP GENMASK(5, 0) + +#define MT_TX0_BB_GAIN_ATTEN 0x13c0 + +#define MT_TX_ALC_VGA3 0x13c8 + +#define MT_TX_PROT_CFG6 0x13e0 +#define MT_TX_PROT_CFG7 0x13e4 +#define MT_TX_PROT_CFG8 0x13e8 + +#define MT_PIFS_TX_CFG 0x13ec + +#define MT_RX_FILTR_CFG 0x1400 + +#define MT_RX_FILTR_CFG_CRC_ERR BIT(0) +#define MT_RX_FILTR_CFG_PHY_ERR BIT(1) +#define MT_RX_FILTR_CFG_PROMISC BIT(2) +#define MT_RX_FILTR_CFG_OTHER_BSS BIT(3) +#define MT_RX_FILTR_CFG_VER_ERR BIT(4) +#define MT_RX_FILTR_CFG_MCAST BIT(5) +#define MT_RX_FILTR_CFG_BCAST BIT(6) +#define MT_RX_FILTR_CFG_DUP BIT(7) +#define MT_RX_FILTR_CFG_CFACK BIT(8) +#define MT_RX_FILTR_CFG_CFEND BIT(9) +#define MT_RX_FILTR_CFG_ACK BIT(10) +#define MT_RX_FILTR_CFG_CTS BIT(11) +#define MT_RX_FILTR_CFG_RTS BIT(12) +#define MT_RX_FILTR_CFG_PSPOLL BIT(13) +#define MT_RX_FILTR_CFG_BA BIT(14) +#define MT_RX_FILTR_CFG_BAR BIT(15) +#define MT_RX_FILTR_CFG_CTRL_RSV BIT(16) + +#define MT_AUTO_RSP_CFG 0x1404 + +#define MT_AUTO_RSP_PREAMB_SHORT BIT(4) + +#define MT_LEGACY_BASIC_RATE 0x1408 +#define MT_HT_BASIC_RATE 0x140c + +#define MT_RX_PARSER_CFG 0x1418 +#define MT_RX_PARSER_RX_SET_NAV_ALL BIT(0) + +#define MT_EXT_CCA_CFG 0x141c +#define MT_EXT_CCA_CFG_CCA0 GENMASK(1, 0) +#define MT_EXT_CCA_CFG_CCA1 GENMASK(3, 2) +#define MT_EXT_CCA_CFG_CCA2 GENMASK(5, 4) +#define MT_EXT_CCA_CFG_CCA3 GENMASK(7, 6) +#define MT_EXT_CCA_CFG_CCA_MASK GENMASK(11, 8) +#define MT_EXT_CCA_CFG_ED_CCA_MASK GENMASK(15, 12) + +#define MT_TX_SW_CFG3 0x1478 + +#define MT_PN_PAD_MODE 0x150c + +#define MT_TXOP_HLDR_ET 0x1608 + +#define MT_PROT_AUTO_TX_CFG 0x1648 + +#define MT_RX_STA_CNT0 0x1700 +#define MT_RX_STA_CNT1 0x1704 +#define MT_RX_STA_CNT2 0x1708 +#define MT_TX_STA_CNT0 0x170c +#define MT_TX_STA_CNT1 0x1710 +#define MT_TX_STA_CNT2 0x1714 + +/* Vendor driver defines content of the second word of STAT_FIFO as follows: + * MT_TX_STAT_FIFO_RATE GENMASK(26, 16) + * MT_TX_STAT_FIFO_ETXBF BIT(27) + * MT_TX_STAT_FIFO_SND BIT(28) + * MT_TX_STAT_FIFO_ITXBF BIT(29) + * However, tests show that b16-31 have the same layout as TXWI rate_ctl + * with rate set to rate at which frame was acked. + */ +#define MT_TX_STAT_FIFO 0x1718 +#define MT_TX_STAT_FIFO_VALID BIT(0) +#define MT_TX_STAT_FIFO_PID_TYPE GENMASK(4, 1) +#define MT_TX_STAT_FIFO_SUCCESS BIT(5) +#define MT_TX_STAT_FIFO_AGGR BIT(6) +#define MT_TX_STAT_FIFO_ACKREQ BIT(7) +#define MT_TX_STAT_FIFO_WCID GENMASK(15, 8) +#define MT_TX_STAT_FIFO_RATE GENMASK(31, 16) + +#define MT_TX_AGG_STAT 0x171c + +#define MT_TX_AGG_CNT_BASE0 0x1720 + +#define MT_MPDU_DENSITY_CNT 0x1740 + +#define MT_TX_AGG_CNT_BASE1 0x174c + +#define MT_TX_AGG_CNT(_id) ((_id) < 8 ? \ + MT_TX_AGG_CNT_BASE0 + ((_id) << 2) : \ + MT_TX_AGG_CNT_BASE1 + ((_id - 8) << 2)) + +#define MT_TX_STAT_FIFO_EXT 0x1798 +#define MT_TX_STAT_FIFO_EXT_RETRY GENMASK(7, 0) + +#define MT_BBP_CORE_BASE 0x2000 +#define MT_BBP_IBI_BASE 0x2100 +#define MT_BBP_AGC_BASE 0x2300 +#define MT_BBP_TXC_BASE 0x2400 +#define MT_BBP_RXC_BASE 0x2500 +#define MT_BBP_TXO_BASE 0x2600 +#define MT_BBP_TXBE_BASE 0x2700 +#define MT_BBP_RXFE_BASE 0x2800 +#define MT_BBP_RXO_BASE 0x2900 +#define MT_BBP_DFS_BASE 0x2a00 +#define MT_BBP_TR_BASE 0x2b00 +#define MT_BBP_CAL_BASE 0x2c00 +#define MT_BBP_DSC_BASE 0x2e00 +#define MT_BBP_PFMU_BASE 0x2f00 + +#define MT_BBP(_type, _n) (MT_BBP_##_type##_BASE + ((_n) << 2)) + +#define MT_BBP_CORE_R1_BW GENMASK(4, 3) + +#define MT_BBP_AGC_R0_CTRL_CHAN GENMASK(9, 8) +#define MT_BBP_AGC_R0_BW GENMASK(14, 12) + +/* AGC, R4/R5 */ +#define MT_BBP_AGC_LNA_GAIN GENMASK(21, 16) + +/* AGC, R8/R9 */ +#define MT_BBP_AGC_GAIN GENMASK(14, 8) + +#define MT_BBP_AGC20_RSSI0 GENMASK(7, 0) +#define MT_BBP_AGC20_RSSI1 GENMASK(15, 8) + +#define MT_BBP_TXBE_R0_CTRL_CHAN GENMASK(1, 0) + +#define MT_WCID_ADDR_BASE 0x1800 +#define MT_WCID_ADDR(_n) (MT_WCID_ADDR_BASE + (_n) * 8) + +#define MT_SRAM_BASE 0x4000 + +#define MT_WCID_KEY_BASE 0x8000 +#define MT_WCID_KEY(_n) (MT_WCID_KEY_BASE + (_n) * 32) + +#define MT_WCID_IV_BASE 0xa000 +#define MT_WCID_IV(_n) (MT_WCID_IV_BASE + (_n) * 8) + +#define MT_WCID_ATTR_BASE 0xa800 +#define MT_WCID_ATTR(_n) (MT_WCID_ATTR_BASE + (_n) * 4) + +#define MT_WCID_ATTR_PAIRWISE BIT(0) +#define MT_WCID_ATTR_PKEY_MODE GENMASK(3, 1) +#define MT_WCID_ATTR_BSS_IDX GENMASK(6, 4) +#define MT_WCID_ATTR_RXWI_UDF GENMASK(9, 7) +#define MT_WCID_ATTR_PKEY_MODE_EXT BIT(10) +#define MT_WCID_ATTR_BSS_IDX_EXT BIT(11) +#define MT_WCID_ATTR_WAPI_MCBC BIT(15) +#define MT_WCID_ATTR_WAPI_KEYID GENMASK(31, 24) + +#define MT_SKEY_BASE_0 0xac00 +#define MT_SKEY_BASE_1 0xb400 +#define MT_SKEY_0(_bss, _idx) \ + (MT_SKEY_BASE_0 + (4 * (_bss) + _idx) * 32) +#define MT_SKEY_1(_bss, _idx) \ + (MT_SKEY_BASE_1 + (4 * ((_bss) & 7) + _idx) * 32) +#define MT_SKEY(_bss, _idx) \ + ((_bss & 8) ? MT_SKEY_1(_bss, _idx) : MT_SKEY_0(_bss, _idx)) + +#define MT_SKEY_MODE_BASE_0 0xb000 +#define MT_SKEY_MODE_BASE_1 0xb3f0 +#define MT_SKEY_MODE_0(_bss) \ + (MT_SKEY_MODE_BASE_0 + ((_bss / 2) << 2)) +#define MT_SKEY_MODE_1(_bss) \ + (MT_SKEY_MODE_BASE_1 + ((((_bss) & 7) / 2) << 2)) +#define MT_SKEY_MODE(_bss) \ + ((_bss & 8) ? MT_SKEY_MODE_1(_bss) : MT_SKEY_MODE_0(_bss)) +#define MT_SKEY_MODE_MASK GENMASK(3, 0) +#define MT_SKEY_MODE_SHIFT(_bss, _idx) (4 * ((_idx) + 4 * (_bss & 1))) + +#define MT_BEACON_BASE 0xc000 + +#define MT_TEMP_SENSOR 0x1d000 +#define MT_TEMP_SENSOR_VAL GENMASK(6, 0) + +enum mt76_cipher_type { + MT_CIPHER_NONE, + MT_CIPHER_WEP40, + MT_CIPHER_WEP104, + MT_CIPHER_TKIP, + MT_CIPHER_AES_CCMP, + MT_CIPHER_CKIP40, + MT_CIPHER_CKIP104, + MT_CIPHER_CKIP128, + MT_CIPHER_WAPI, +}; + +#endif diff --git a/linux-bsp/drivers/mt7601u-sta/trace.c b/linux-bsp/drivers/mt7601u-sta/trace.c new file mode 100644 index 0000000..8abdd3c --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/trace.c @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> + +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "trace.h" + +#endif diff --git a/linux-bsp/drivers/mt7601u-sta/trace.h b/linux-bsp/drivers/mt7601u-sta/trace.h new file mode 100644 index 0000000..2898973 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/trace.h @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#if !defined(__MT7601U_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define __MT7601U_TRACE_H + +#include <linux/tracepoint.h> +#include "mt7601u.h" +#include "mac.h" + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mt7601u + +#define MAXNAME 32 +#define DEV_ENTRY __array(char, wiphy_name, 32) +#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ + wiphy_name(dev->hw->wiphy), MAXNAME) +#define DEV_PR_FMT "%s " +#define DEV_PR_ARG __entry->wiphy_name + +#define REG_ENTRY __field(u32, reg) __field(u32, val) +#define REG_ASSIGN __entry->reg = reg; __entry->val = val +#define REG_PR_FMT "%04x=%08x" +#define REG_PR_ARG __entry->reg, __entry->val + +DECLARE_EVENT_CLASS(dev_reg_evt, + TP_PROTO(struct mt7601u_dev *dev, u32 reg, u32 val), + TP_ARGS(dev, reg, val), + TP_STRUCT__entry( + DEV_ENTRY + REG_ENTRY + ), + TP_fast_assign( + DEV_ASSIGN; + REG_ASSIGN; + ), + TP_printk( + DEV_PR_FMT REG_PR_FMT, + DEV_PR_ARG, REG_PR_ARG + ) +); + +DEFINE_EVENT(dev_reg_evt, reg_read, + TP_PROTO(struct mt7601u_dev *dev, u32 reg, u32 val), + TP_ARGS(dev, reg, val) +); + +DEFINE_EVENT(dev_reg_evt, reg_write, + TP_PROTO(struct mt7601u_dev *dev, u32 reg, u32 val), + TP_ARGS(dev, reg, val) +); + +TRACE_EVENT(mt_submit_urb, + TP_PROTO(struct mt7601u_dev *dev, struct urb *u), + TP_ARGS(dev, u), + TP_STRUCT__entry( + DEV_ENTRY __field(unsigned, pipe) __field(u32, len) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->pipe = u->pipe; + __entry->len = u->transfer_buffer_length; + ), + TP_printk(DEV_PR_FMT "p:%08x len:%u", + DEV_PR_ARG, __entry->pipe, __entry->len) +); + +#define trace_mt_submit_urb_sync(__dev, __pipe, __len) ({ \ + struct urb u; \ + u.pipe = __pipe; \ + u.transfer_buffer_length = __len; \ + trace_mt_submit_urb(__dev, &u); \ +}) + +TRACE_EVENT(mt_mcu_msg_send, + TP_PROTO(struct mt7601u_dev *dev, + struct sk_buff *skb, u32 csum, bool resp), + TP_ARGS(dev, skb, csum, resp), + TP_STRUCT__entry( + DEV_ENTRY + __field(u32, info) + __field(u32, csum) + __field(bool, resp) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->info = *(u32 *)skb->data; + __entry->csum = csum; + __entry->resp = resp; + ), + TP_printk(DEV_PR_FMT "i:%08x c:%08x r:%d", + DEV_PR_ARG, __entry->info, __entry->csum, __entry->resp) +); + +TRACE_EVENT(mt_vend_req, + TP_PROTO(struct mt7601u_dev *dev, unsigned pipe, u8 req, u8 req_type, + u16 val, u16 offset, void *buf, size_t buflen, int ret), + TP_ARGS(dev, pipe, req, req_type, val, offset, buf, buflen, ret), + TP_STRUCT__entry( + DEV_ENTRY + __field(unsigned, pipe) __field(u8, req) __field(u8, req_type) + __field(u16, val) __field(u16, offset) __field(void*, buf) + __field(int, buflen) __field(int, ret) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->pipe = pipe; + __entry->req = req; + __entry->req_type = req_type; + __entry->val = val; + __entry->offset = offset; + __entry->buf = buf; + __entry->buflen = buflen; + __entry->ret = ret; + ), + TP_printk(DEV_PR_FMT + "%d p:%08x req:%02hhx %02hhx val:%04hx %04hx buf:%d %d", + DEV_PR_ARG, __entry->ret, __entry->pipe, __entry->req, + __entry->req_type, __entry->val, __entry->offset, + !!__entry->buf, __entry->buflen) +); + +TRACE_EVENT(ee_read, + TP_PROTO(struct mt7601u_dev *dev, int offset, u16 val), + TP_ARGS(dev, offset, val), + TP_STRUCT__entry( + DEV_ENTRY + __field(int, o) __field(u16, v) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->o = offset; + __entry->v = val; + ), + TP_printk(DEV_PR_FMT "%04x=%04x", DEV_PR_ARG, __entry->o, __entry->v) +); + +DECLARE_EVENT_CLASS(dev_rf_reg_evt, + TP_PROTO(struct mt7601u_dev *dev, u8 bank, u8 reg, u8 val), + TP_ARGS(dev, bank, reg, val), + TP_STRUCT__entry( + DEV_ENTRY + __field(u8, bank) + __field(u8, reg) + __field(u8, val) + ), + TP_fast_assign( + DEV_ASSIGN; + REG_ASSIGN; + __entry->bank = bank; + ), + TP_printk( + DEV_PR_FMT "%02hhx:%02hhx=%02hhx", + DEV_PR_ARG, __entry->bank, __entry->reg, __entry->val + ) +); + +DEFINE_EVENT(dev_rf_reg_evt, rf_read, + TP_PROTO(struct mt7601u_dev *dev, u8 bank, u8 reg, u8 val), + TP_ARGS(dev, bank, reg, val) +); + +DEFINE_EVENT(dev_rf_reg_evt, rf_write, + TP_PROTO(struct mt7601u_dev *dev, u8 bank, u8 reg, u8 val), + TP_ARGS(dev, bank, reg, val) +); + +DECLARE_EVENT_CLASS(dev_bbp_reg_evt, + TP_PROTO(struct mt7601u_dev *dev, u8 reg, u8 val), + TP_ARGS(dev, reg, val), + TP_STRUCT__entry( + DEV_ENTRY + __field(u8, reg) + __field(u8, val) + ), + TP_fast_assign( + DEV_ASSIGN; + REG_ASSIGN; + ), + TP_printk( + DEV_PR_FMT "%02hhx=%02hhx", + DEV_PR_ARG, __entry->reg, __entry->val + ) +); + +DEFINE_EVENT(dev_bbp_reg_evt, bbp_read, + TP_PROTO(struct mt7601u_dev *dev, u8 reg, u8 val), + TP_ARGS(dev, reg, val) +); + +DEFINE_EVENT(dev_bbp_reg_evt, bbp_write, + TP_PROTO(struct mt7601u_dev *dev, u8 reg, u8 val), + TP_ARGS(dev, reg, val) +); + +DECLARE_EVENT_CLASS(dev_simple_evt, + TP_PROTO(struct mt7601u_dev *dev, u8 val), + TP_ARGS(dev, val), + TP_STRUCT__entry( + DEV_ENTRY + __field(u8, val) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->val = val; + ), + TP_printk( + DEV_PR_FMT "%02hhx", DEV_PR_ARG, __entry->val + ) +); + +DEFINE_EVENT(dev_simple_evt, temp_mode, + TP_PROTO(struct mt7601u_dev *dev, u8 val), + TP_ARGS(dev, val) +); + +DEFINE_EVENT(dev_simple_evt, read_temp, + TP_PROTO(struct mt7601u_dev *dev, u8 val), + TP_ARGS(dev, val) +); + +DEFINE_EVENT(dev_simple_evt, freq_cal_adjust, + TP_PROTO(struct mt7601u_dev *dev, u8 val), + TP_ARGS(dev, val) +); + +TRACE_EVENT(freq_cal_offset, + TP_PROTO(struct mt7601u_dev *dev, u8 phy_mode, s8 freq_off), + TP_ARGS(dev, phy_mode, freq_off), + TP_STRUCT__entry( + DEV_ENTRY + __field(u8, phy_mode) + __field(s8, freq_off) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->phy_mode = phy_mode; + __entry->freq_off = freq_off; + ), + TP_printk(DEV_PR_FMT "phy:%02hhx off:%02hhx", + DEV_PR_ARG, __entry->phy_mode, __entry->freq_off) +); + +TRACE_EVENT(mt_rx, + TP_PROTO(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, u32 f), + TP_ARGS(dev, rxwi, f), + TP_STRUCT__entry( + DEV_ENTRY + __field_struct(struct mt7601u_rxwi, rxwi) + __field(u32, fce_info) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->rxwi = *rxwi; + __entry->fce_info = f; + ), + TP_printk(DEV_PR_FMT "rxi:%08x ctl:%08x frag_sn:%04hx rate:%04hx " + "uknw:%02hhx z:%02hhx%02hhx%02hhx snr:%02hhx " + "ant:%02hhx gain:%02hhx freq_o:%02hhx " + "r:%08x ea:%08x fce:%08x", DEV_PR_ARG, + le32_to_cpu(__entry->rxwi.rxinfo), + le32_to_cpu(__entry->rxwi.ctl), + le16_to_cpu(__entry->rxwi.frag_sn), + le16_to_cpu(__entry->rxwi.rate), + __entry->rxwi.unknown, + __entry->rxwi.zero[0], __entry->rxwi.zero[1], + __entry->rxwi.zero[2], + __entry->rxwi.snr, __entry->rxwi.ant, + __entry->rxwi.gain, __entry->rxwi.freq_off, + __entry->rxwi.resv2, __entry->rxwi.expert_ant, + __entry->fce_info) +); + +TRACE_EVENT(mt_tx, + TP_PROTO(struct mt7601u_dev *dev, struct sk_buff *skb, + struct mt76_sta *sta, struct mt76_txwi *h), + TP_ARGS(dev, skb, sta, h), + TP_STRUCT__entry( + DEV_ENTRY + __field_struct(struct mt76_txwi, h) + __field(struct sk_buff *, skb) + __field(struct mt76_sta *, sta) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->h = *h; + __entry->skb = skb; + __entry->sta = sta; + ), + TP_printk(DEV_PR_FMT "skb:%p sta:%p flg:%04hx rate_ctl:%04hx " + "ack:%02hhx wcid:%02hhx len_ctl:%05hx", DEV_PR_ARG, + __entry->skb, __entry->sta, + le16_to_cpu(__entry->h.flags), + le16_to_cpu(__entry->h.rate_ctl), + __entry->h.ack_ctl, __entry->h.wcid, + le16_to_cpu(__entry->h.len_ctl)) +); + +TRACE_EVENT(mt_tx_dma_done, + TP_PROTO(struct mt7601u_dev *dev, struct sk_buff *skb), + TP_ARGS(dev, skb), + TP_STRUCT__entry( + DEV_ENTRY + __field(struct sk_buff *, skb) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->skb = skb; + ), + TP_printk(DEV_PR_FMT "%p", DEV_PR_ARG, __entry->skb) +); + +TRACE_EVENT(mt_tx_status_cleaned, + TP_PROTO(struct mt7601u_dev *dev, int cleaned), + TP_ARGS(dev, cleaned), + TP_STRUCT__entry( + DEV_ENTRY + __field(int, cleaned) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->cleaned = cleaned; + ), + TP_printk(DEV_PR_FMT "%d", DEV_PR_ARG, __entry->cleaned) +); + +TRACE_EVENT(mt_tx_status, + TP_PROTO(struct mt7601u_dev *dev, u32 stat1, u32 stat2), + TP_ARGS(dev, stat1, stat2), + TP_STRUCT__entry( + DEV_ENTRY + __field(u32, stat1) __field(u32, stat2) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->stat1 = stat1; + __entry->stat2 = stat2; + ), + TP_printk(DEV_PR_FMT "%08x %08x", + DEV_PR_ARG, __entry->stat1, __entry->stat2) +); + +TRACE_EVENT(mt_rx_dma_aggr, + TP_PROTO(struct mt7601u_dev *dev, int cnt, bool paged), + TP_ARGS(dev, cnt, paged), + TP_STRUCT__entry( + DEV_ENTRY + __field(u8, cnt) + __field(bool, paged) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->cnt = cnt; + __entry->paged = paged; + ), + TP_printk(DEV_PR_FMT "cnt:%d paged:%d", + DEV_PR_ARG, __entry->cnt, __entry->paged) +); + +DEFINE_EVENT(dev_simple_evt, set_key, + TP_PROTO(struct mt7601u_dev *dev, u8 val), + TP_ARGS(dev, val) +); + +TRACE_EVENT(set_shared_key, + TP_PROTO(struct mt7601u_dev *dev, u8 vid, u8 key), + TP_ARGS(dev, vid, key), + TP_STRUCT__entry( + DEV_ENTRY + __field(u8, vid) + __field(u8, key) + ), + TP_fast_assign( + DEV_ASSIGN; + __entry->vid = vid; + __entry->key = key; + ), + TP_printk(DEV_PR_FMT "phy:%02hhx off:%02hhx", + DEV_PR_ARG, __entry->vid, __entry->key) +); + +#endif + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include <trace/define_trace.h> diff --git a/linux-bsp/drivers/mt7601u-sta/tx.c b/linux-bsp/drivers/mt7601u-sta/tx.c new file mode 100644 index 0000000..a0a33dc --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/tx.c @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "mt7601u.h" +#include "trace.h" + +enum mt76_txq_id { + MT_TXQ_VO = IEEE80211_AC_VO, + MT_TXQ_VI = IEEE80211_AC_VI, + MT_TXQ_BE = IEEE80211_AC_BE, + MT_TXQ_BK = IEEE80211_AC_BK, + MT_TXQ_PSD, + MT_TXQ_MCU, + __MT_TXQ_MAX +}; + +/* Hardware uses mirrored order of queues with Q0 having the highest priority */ +static u8 q2hwq(u8 q) +{ + return q ^ 0x3; +} + +/* Take mac80211 Q id from the skb and translate it to hardware Q id */ +static u8 skb2q(struct sk_buff *skb) +{ + int qid = skb_get_queue_mapping(skb); + + if (WARN_ON(qid >= MT_TXQ_PSD)) { + qid = MT_TXQ_BE; + skb_set_queue_mapping(skb, qid); + } + + return q2hwq(qid); +} + +/* Note: TX retry reporting is a bit broken. + * Retries are reported only once per AMPDU and often come a frame early + * i.e. they are reported in the last status preceding the AMPDU. Apart + * from the fact that it's hard to know the length of the AMPDU (which is + * required to know to how many consecutive frames retries should be + * applied), if status comes early on full FIFO it gets lost and retries + * of the whole AMPDU become invisible. + * As a work-around encode the desired rate in PKT_ID of TX descriptor + * and based on that guess the retries (every rate is tried once). + * Only downside here is that for MCS0 we have to rely solely on + * transmission failures as no retries can ever be reported. + * Not having to read EXT_FIFO has a nice effect of doubling the number + * of reports which can be fetched. + * Also the vendor driver never uses the EXT_FIFO register so it may be + * undertested. + */ +static u8 mt7601u_tx_pktid_enc(struct mt7601u_dev *dev, u8 rate, bool is_probe) +{ + u8 encoded = (rate + 1) + is_probe * 8; + + /* Because PKT_ID 0 disables status reporting only 15 values are + * available but 16 are needed (8 MCS * 2 for encoding is_probe) + * - we need to cram together two rates. MCS0 and MCS7 with is_probe + * share PKT_ID 9. + */ + if (is_probe && rate == 7) + return encoded - 7; + + return encoded; +} + +static void +mt7601u_tx_pktid_dec(struct mt7601u_dev *dev, struct mt76_tx_status *stat) +{ + u8 req_rate = stat->pktid; + u8 eff_rate = stat->rate & 0x7; + + req_rate -= 1; + + if (req_rate > 7) { + stat->is_probe = true; + req_rate -= 8; + + /* Decide between MCS0 and MCS7 which share pktid 9 */ + if (!req_rate && eff_rate) + req_rate = 7; + } + + stat->retry = req_rate - eff_rate; +} + +static void mt7601u_tx_skb_remove_dma_overhead(struct sk_buff *skb, + struct ieee80211_tx_info *info) +{ + int pkt_len = (unsigned long)info->status.status_driver_data[0]; + + skb_pull(skb, sizeof(struct mt76_txwi) + 4); + if (ieee80211_get_hdrlen_from_skb(skb) % 4) + mt76_remove_hdr_pad(skb); + + skb_trim(skb, pkt_len); +} + +void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + mt7601u_tx_skb_remove_dma_overhead(skb, info); + + ieee80211_tx_info_clear_status(info); + info->status.rates[0].idx = -1; + info->flags |= IEEE80211_TX_STAT_ACK; + + spin_lock(&dev->mac_lock); + ieee80211_tx_status(dev->hw, skb); + spin_unlock(&dev->mac_lock); +} + +static int mt7601u_skb_rooms(struct mt7601u_dev *dev, struct sk_buff *skb) +{ + int hdr_len = ieee80211_get_hdrlen_from_skb(skb); + u32 need_head; + + need_head = sizeof(struct mt76_txwi) + 4; + if (hdr_len % 4) + need_head += 2; + + return skb_cow(skb, need_head); +} + +static struct mt76_txwi * +mt7601u_push_txwi(struct mt7601u_dev *dev, struct sk_buff *skb, + struct ieee80211_sta *sta, struct mt76_wcid *wcid, + int pkt_len) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rate = &info->control.rates[0]; + struct mt76_txwi *txwi; + unsigned long flags; + bool is_probe; + u32 pkt_id; + u16 rate_ctl; + u8 nss; + + txwi = (struct mt76_txwi *)skb_push(skb, sizeof(struct mt76_txwi)); + memset(txwi, 0, sizeof(*txwi)); + + if (!wcid->tx_rate_set) + ieee80211_get_tx_rates(info->control.vif, sta, skb, + info->control.rates, 1); + + spin_lock_irqsave(&dev->lock, flags); + if (rate->idx < 0 || !rate->count) + rate_ctl = wcid->tx_rate; + else + rate_ctl = mt76_mac_tx_rate_val(dev, rate, &nss); + spin_unlock_irqrestore(&dev->lock, flags); + txwi->rate_ctl = cpu_to_le16(rate_ctl); + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ; + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ; + + if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) { + u8 ba_size = IEEE80211_MIN_AMPDU_BUF; + + ba_size <<= sta->ht_cap.ampdu_factor; + ba_size = min_t(int, 63, ba_size); + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + ba_size = 0; + txwi->ack_ctl |= MT76_SET(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size); + + txwi->flags = cpu_to_le16(MT_TXWI_FLAGS_AMPDU | + MT76_SET(MT_TXWI_FLAGS_MPDU_DENSITY, + sta->ht_cap.ampdu_density)); + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + txwi->flags = 0; + } + + txwi->wcid = wcid->idx; + + is_probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE); + pkt_id = mt7601u_tx_pktid_enc(dev, rate_ctl & 0x7, is_probe); + pkt_len |= MT76_SET(MT_TXWI_LEN_PKTID, pkt_id); + txwi->len_ctl = cpu_to_le16(pkt_len); + + return txwi; +} + +void mt7601u_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct mt7601u_dev *dev = hw->priv; + struct ieee80211_vif *vif = info->control.vif; + struct ieee80211_sta *sta = control->sta; + struct mt76_sta *msta = NULL; + struct mt76_wcid *wcid = dev->mon_wcid; + struct mt76_txwi *txwi; + int pkt_len = skb->len; + int hw_q = skb2q(skb); + + BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1); + info->status.status_driver_data[0] = (void *)(unsigned long)pkt_len; + + if (mt7601u_skb_rooms(dev, skb) || mt76_insert_hdr_pad(skb)) { + ieee80211_free_txskb(dev->hw, skb); + return; + } + + if (sta) { + msta = (struct mt76_sta *) sta->drv_priv; + wcid = &msta->wcid; + } else if (vif) { + struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; + + wcid = &mvif->group_wcid; + } + + txwi = mt7601u_push_txwi(dev, skb, sta, wcid, pkt_len); + + if (mt7601u_dma_enqueue_tx(dev, skb, wcid, hw_q)) + return; + + trace_mt_tx(dev, skb, msta, txwi); +} + +void mt7601u_tx_stat(struct work_struct *work) +{ + struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, + stat_work.work); + struct mt76_tx_status stat; + unsigned long flags; + int cleaned = 0; + + while (!test_bit(MT7601U_STATE_REMOVED, &dev->state)) { + stat = mt7601u_mac_fetch_tx_status(dev); + if (!stat.valid) + break; + + mt7601u_tx_pktid_dec(dev, &stat); + mt76_send_tx_status(dev, &stat); + + cleaned++; + } + trace_mt_tx_status_cleaned(dev, cleaned); + + spin_lock_irqsave(&dev->tx_lock, flags); + if (cleaned) + queue_delayed_work(dev->stat_wq, &dev->stat_work, + msecs_to_jiffies(10)); + else if (test_and_clear_bit(MT7601U_STATE_MORE_STATS, &dev->state)) + queue_delayed_work(dev->stat_wq, &dev->stat_work, + msecs_to_jiffies(20)); + else + clear_bit(MT7601U_STATE_READING_STATS, &dev->state); + spin_unlock_irqrestore(&dev->tx_lock, flags); +} + +int mt7601u_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u16 queue, const struct ieee80211_tx_queue_params *params) +{ + struct mt7601u_dev *dev = hw->priv; + u8 cw_min = 5, cw_max = 10, hw_q = q2hwq(queue); + u32 val; + + /* TODO: should we do funny things with the parameters? + * See what mt7601u_set_default_edca() used to do in init.c. + */ + + if (params->cw_min) + cw_min = fls(params->cw_min); + if (params->cw_max) + cw_max = fls(params->cw_max); + + WARN_ON(params->txop > 0xff); + WARN_ON(params->aifs > 0xf); + WARN_ON(cw_min > 0xf); + WARN_ON(cw_max > 0xf); + + val = MT76_SET(MT_EDCA_CFG_AIFSN, params->aifs) | + MT76_SET(MT_EDCA_CFG_CWMIN, cw_min) | + MT76_SET(MT_EDCA_CFG_CWMAX, cw_max); + /* TODO: based on user-controlled EnableTxBurst var vendor drv sets + * a really long txop on AC0 (see connect.c:2009) but only on + * connect? When not connected should be 0. + */ + if (!hw_q) + val |= 0x60; + else + val |= MT76_SET(MT_EDCA_CFG_TXOP, params->txop); + mt76_wr(dev, MT_EDCA_CFG_AC(hw_q), val); + + val = mt76_rr(dev, MT_WMM_TXOP(hw_q)); + val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(hw_q)); + val |= params->txop << MT_WMM_TXOP_SHIFT(hw_q); + mt76_wr(dev, MT_WMM_TXOP(hw_q), val); + + val = mt76_rr(dev, MT_WMM_AIFSN); + val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(hw_q)); + val |= params->aifs << MT_WMM_AIFSN_SHIFT(hw_q); + mt76_wr(dev, MT_WMM_AIFSN, val); + + val = mt76_rr(dev, MT_WMM_CWMIN); + val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(hw_q)); + val |= cw_min << MT_WMM_CWMIN_SHIFT(hw_q); + mt76_wr(dev, MT_WMM_CWMIN, val); + + val = mt76_rr(dev, MT_WMM_CWMAX); + val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(hw_q)); + val |= cw_max << MT_WMM_CWMAX_SHIFT(hw_q); + mt76_wr(dev, MT_WMM_CWMAX, val); + + return 0; +} diff --git a/linux-bsp/drivers/mt7601u-sta/usb.c b/linux-bsp/drivers/mt7601u-sta/usb.c new file mode 100644 index 0000000..416c604 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/usb.c @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/usb.h> + +#include "mt7601u.h" +#include "usb.h" +#include "trace.h" + +static struct usb_device_id mt7601u_device_table[] = { + { USB_DEVICE(0x0b05, 0x17d3) }, + { USB_DEVICE(0x0e8d, 0x760a) }, + { USB_DEVICE(0x0e8d, 0x760b) }, + { USB_DEVICE(0x13d3, 0x3431) }, + { USB_DEVICE(0x13d3, 0x3434) }, + { USB_DEVICE(0x148f, 0x7601) }, + { USB_DEVICE(0x148f, 0x760a) }, + { USB_DEVICE(0x148f, 0x760b) }, + { USB_DEVICE(0x148f, 0x760c) }, + { USB_DEVICE(0x148f, 0x760d) }, + { USB_DEVICE(0x2001, 0x3d04) }, + { USB_DEVICE(0x2717, 0x4106) }, + { USB_DEVICE(0x2955, 0x0001) }, + { USB_DEVICE(0x2955, 0x1001) }, + { USB_DEVICE(0x2a5f, 0x1000) }, + { USB_DEVICE(0x7392, 0x7710) }, + { 0, } +}; + +bool mt7601u_usb_alloc_buf(struct mt7601u_dev *dev, size_t len, + struct mt7601u_dma_buf *buf) +{ + struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); + + buf->len = len; + buf->urb = usb_alloc_urb(0, GFP_KERNEL); + buf->buf = usb_alloc_coherent(usb_dev, buf->len, GFP_KERNEL, &buf->dma); + + return !buf->urb || !buf->buf; +} + +void mt7601u_usb_free_buf(struct mt7601u_dev *dev, struct mt7601u_dma_buf *buf) +{ + struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); + + usb_free_coherent(usb_dev, buf->len, buf->buf, buf->dma); + usb_free_urb(buf->urb); +} + +int mt7601u_usb_submit_buf(struct mt7601u_dev *dev, int dir, int ep_idx, + struct mt7601u_dma_buf *buf, gfp_t gfp, + usb_complete_t complete_fn, void *context) +{ + struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); + unsigned pipe; + int ret; + + if (dir == USB_DIR_IN) + pipe = usb_rcvbulkpipe(usb_dev, dev->in_eps[ep_idx]); + else + pipe = usb_sndbulkpipe(usb_dev, dev->out_eps[ep_idx]); + + usb_fill_bulk_urb(buf->urb, usb_dev, pipe, buf->buf, buf->len, + complete_fn, context); + buf->urb->transfer_dma = buf->dma; + buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + trace_mt_submit_urb(dev, buf->urb); + ret = usb_submit_urb(buf->urb, gfp); + if (ret) + dev_err(dev->dev, "Error: submit URB dir:%d ep:%d failed:%d\n", + dir, ep_idx, ret); + return ret; +} + +void mt7601u_complete_urb(struct urb *urb) +{ + struct completion *cmpl = urb->context; + + complete(cmpl); +} + +int mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, + const u8 direction, const u16 val, const u16 offset, + void *buf, const size_t buflen) +{ + int i, ret; + struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); + const u8 req_type = direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE; + const unsigned int pipe = (direction == USB_DIR_IN) ? + usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0); + + for (i = 0; i < MT_VEND_REQ_MAX_RETRY; i++) { + ret = usb_control_msg(usb_dev, pipe, req, req_type, + val, offset, buf, buflen, + MT_VEND_REQ_TOUT_MS); + trace_mt_vend_req(dev, pipe, req, req_type, val, offset, + buf, buflen, ret); + + if (ret == -ENODEV) + set_bit(MT7601U_STATE_REMOVED, &dev->state); + if (ret >= 0 || ret == -ENODEV) + return ret; + + msleep(5); + } + + dev_err(dev->dev, "Vendor request req:%02x off:%04x failed:%d\n", + req, offset, ret); + + return ret; +} + +void mt7601u_vendor_reset(struct mt7601u_dev *dev) +{ + mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT, + MT_VEND_DEV_MODE_RESET, 0, NULL, 0); +} + +u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset) +{ + int ret; + u32 val = ~0; + + WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset); + + mutex_lock(&dev->vendor_req_mutex); + + ret = mt7601u_vendor_request(dev, MT_VEND_MULTI_READ, USB_DIR_IN, + 0, offset, dev->vend_buf, MT_VEND_BUF); + if (ret == MT_VEND_BUF) + val = get_unaligned_le32(dev->vend_buf); + else if (ret > 0) + dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n", + ret, offset); + + mutex_unlock(&dev->vendor_req_mutex); + + trace_reg_read(dev, offset, val); + return val; +} + +int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, + const u16 offset, const u32 val) +{ + int ret; + + mutex_lock(&dev->vendor_req_mutex); + + ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, + val & 0xffff, offset, NULL, 0); + if (!ret) + ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, + val >> 16, offset + 2, NULL, 0); + + mutex_unlock(&dev->vendor_req_mutex); + + return ret; +} + +void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val) +{ + WARN_ONCE(offset > USHRT_MAX, "write high off:%08x", offset); + + mt7601u_vendor_single_wr(dev, MT_VEND_WRITE, offset, val); + trace_reg_write(dev, offset, val); +} + +u32 mt7601u_rmw(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val) +{ + val |= mt7601u_rr(dev, offset) & ~mask; + mt7601u_wr(dev, offset, val); + return val; +} + +u32 mt7601u_rmc(struct mt7601u_dev *dev, u32 offset, u32 mask, u32 val) +{ + u32 reg = mt7601u_rr(dev, offset); + + val |= reg & ~mask; + if (reg != val) + mt7601u_wr(dev, offset, val); + return val; +} + +void mt7601u_wr_copy(struct mt7601u_dev *dev, u32 offset, + const void *data, int len) +{ + WARN_ONCE(offset & 3, "unaligned write copy off:%08x", offset); + WARN_ONCE(len & 3, "short write copy off:%08x", offset); + + mt7601u_burst_write_regs(dev, offset, data, len / 4); +} + +void mt7601u_addr_wr(struct mt7601u_dev *dev, const u32 offset, const u8 *addr) +{ + mt7601u_wr(dev, offset, get_unaligned_le32(addr)); + mt7601u_wr(dev, offset + 4, addr[4] | addr[5] << 8); +} + +static int mt7601u_assign_pipes(struct usb_interface *usb_intf, + struct mt7601u_dev *dev) +{ + struct usb_endpoint_descriptor *ep_desc; + struct usb_host_interface *intf_desc = usb_intf->cur_altsetting; + unsigned i, ep_i = 0, ep_o = 0; + + BUILD_BUG_ON(sizeof(dev->in_eps) < __MT_EP_IN_MAX); + BUILD_BUG_ON(sizeof(dev->out_eps) < __MT_EP_OUT_MAX); + + for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) { + ep_desc = &intf_desc->endpoint[i].desc; + + if (usb_endpoint_is_bulk_in(ep_desc) && + ep_i++ < __MT_EP_IN_MAX) { + dev->in_eps[ep_i - 1] = usb_endpoint_num(ep_desc); + dev->in_max_packet = usb_endpoint_maxp(ep_desc); + /* Note: this is ignored by usb sub-system but vendor + * code does it. We can drop this at some point. + */ + dev->in_eps[ep_i - 1] |= USB_DIR_IN; + } else if (usb_endpoint_is_bulk_out(ep_desc) && + ep_o++ < __MT_EP_OUT_MAX) { + dev->out_eps[ep_o - 1] = usb_endpoint_num(ep_desc); + dev->out_max_packet = usb_endpoint_maxp(ep_desc); + } + } + + if (ep_i != __MT_EP_IN_MAX || ep_o != __MT_EP_OUT_MAX) { + dev_err(dev->dev, "Error: wrong pipe number in:%d out:%d\n", + ep_i, ep_o); + return -EINVAL; + } + + return 0; +} + +static int mt7601u_probe(struct usb_interface *usb_intf, + const struct usb_device_id *id) +{ + struct usb_device *usb_dev = interface_to_usbdev(usb_intf); + struct mt7601u_dev *dev; + u32 asic_rev, mac_rev; + int ret; + + dev = mt7601u_alloc_device(&usb_intf->dev); + if (!dev) + return -ENOMEM; + + usb_dev = usb_get_dev(usb_dev); + usb_reset_device(usb_dev); + + usb_set_intfdata(usb_intf, dev); + + dev->vend_buf = devm_kmalloc(dev->dev, MT_VEND_BUF, GFP_KERNEL); + if (!dev->vend_buf) { + ret = -ENOMEM; + goto err; + } + + ret = mt7601u_assign_pipes(usb_intf, dev); + if (ret) + goto err; + ret = mt7601u_wait_asic_ready(dev); + if (ret) + goto err; + + asic_rev = mt7601u_rr(dev, MT_ASIC_VERSION); + mac_rev = mt7601u_rr(dev, MT_MAC_CSR0); + dev_info(dev->dev, "ASIC revision: %08x MAC revision: %08x\n", + asic_rev, mac_rev); + + /* Note: vendor driver skips this check for MT7601U */ + if (!(mt7601u_rr(dev, MT_EFUSE_CTRL) & MT_EFUSE_CTRL_SEL)) + dev_warn(dev->dev, "Warning: eFUSE not present\n"); + + ret = mt7601u_init_hardware(dev); + if (ret) + goto err; + ret = mt7601u_register_device(dev); + if (ret) + goto err_hw; + + set_bit(MT7601U_STATE_INITIALIZED, &dev->state); + + return 0; +err_hw: + mt7601u_cleanup(dev); +err: + usb_set_intfdata(usb_intf, NULL); + usb_put_dev(interface_to_usbdev(usb_intf)); + + destroy_workqueue(dev->stat_wq); + ieee80211_free_hw(dev->hw); + return ret; +} + +static void mt7601u_disconnect(struct usb_interface *usb_intf) +{ + struct mt7601u_dev *dev = usb_get_intfdata(usb_intf); + + ieee80211_unregister_hw(dev->hw); + mt7601u_cleanup(dev); + + usb_set_intfdata(usb_intf, NULL); + usb_put_dev(interface_to_usbdev(usb_intf)); + + destroy_workqueue(dev->stat_wq); + ieee80211_free_hw(dev->hw); +} + +static int mt7601u_suspend(struct usb_interface *usb_intf, pm_message_t state) +{ + struct mt7601u_dev *dev = usb_get_intfdata(usb_intf); + + mt7601u_cleanup(dev); + + return 0; +} + +static int mt7601u_resume(struct usb_interface *usb_intf) +{ + struct mt7601u_dev *dev = usb_get_intfdata(usb_intf); + int ret; + + ret = mt7601u_init_hardware(dev); + if (ret) + return ret; + + set_bit(MT7601U_STATE_INITIALIZED, &dev->state); + + return 0; +} + +MODULE_DEVICE_TABLE(usb, mt7601u_device_table); +MODULE_FIRMWARE(MT7601U_FIRMWARE); +MODULE_LICENSE("GPL"); + +static struct usb_driver mt7601u_driver = { + .name = KBUILD_MODNAME, + .id_table = mt7601u_device_table, + .probe = mt7601u_probe, + .disconnect = mt7601u_disconnect, + .suspend = mt7601u_suspend, + .resume = mt7601u_resume, + .reset_resume = mt7601u_resume, + .soft_unbind = 1, + .disable_hub_initiated_lpm = 1, +}; +module_usb_driver(mt7601u_driver); diff --git a/linux-bsp/drivers/mt7601u-sta/usb.h b/linux-bsp/drivers/mt7601u-sta/usb.h new file mode 100644 index 0000000..bc18202 --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/usb.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT7601U_USB_H +#define __MT7601U_USB_H + +#include "mt7601u.h" + +#define MT7601U_FIRMWARE "mt7601u.bin" + +#define MT_VEND_REQ_MAX_RETRY 10 +#define MT_VEND_REQ_TOUT_MS 300 + +#define MT_VEND_DEV_MODE_RESET 1 + +#define MT_VEND_BUF sizeof(__le32) + +enum mt_vendor_req { + MT_VEND_DEV_MODE = 1, + MT_VEND_WRITE = 2, + MT_VEND_MULTI_READ = 7, + MT_VEND_WRITE_FCE = 0x42, +}; + +enum mt_usb_ep_in { + MT_EP_IN_PKT_RX, + MT_EP_IN_CMD_RESP, + __MT_EP_IN_MAX, +}; + +enum mt_usb_ep_out { + MT_EP_OUT_INBAND_CMD, + MT_EP_OUT_AC_BK, + MT_EP_OUT_AC_BE, + MT_EP_OUT_AC_VI, + MT_EP_OUT_AC_VO, + MT_EP_OUT_HCCA, + __MT_EP_OUT_MAX, +}; + +static inline struct usb_device *mt7601u_to_usb_dev(struct mt7601u_dev *mt7601u) +{ + return interface_to_usbdev(to_usb_interface(mt7601u->dev)); +} + +static inline bool mt7601u_urb_has_error(struct urb *urb) +{ + return urb->status && + urb->status != -ENOENT && + urb->status != -ECONNRESET && + urb->status != -ESHUTDOWN; +} + +bool mt7601u_usb_alloc_buf(struct mt7601u_dev *dev, size_t len, + struct mt7601u_dma_buf *buf); +void mt7601u_usb_free_buf(struct mt7601u_dev *dev, struct mt7601u_dma_buf *buf); +int mt7601u_usb_submit_buf(struct mt7601u_dev *dev, int dir, int ep_idx, + struct mt7601u_dma_buf *buf, gfp_t gfp, + usb_complete_t complete_fn, void *context); +void mt7601u_complete_urb(struct urb *urb); + +int mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, + const u8 direction, const u16 val, const u16 offset, + void *buf, const size_t buflen); +void mt7601u_vendor_reset(struct mt7601u_dev *dev); +int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, + const u16 offset, const u32 val); + +#endif diff --git a/linux-bsp/drivers/mt7601u-sta/util.c b/linux-bsp/drivers/mt7601u-sta/util.c new file mode 100644 index 0000000..7c1787c --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/util.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "mt7601u.h" + +void mt76_remove_hdr_pad(struct sk_buff *skb) +{ + int len = ieee80211_get_hdrlen_from_skb(skb); + + memmove(skb->data + 2, skb->data, len); + skb_pull(skb, 2); +} + +int mt76_insert_hdr_pad(struct sk_buff *skb) +{ + int len = ieee80211_get_hdrlen_from_skb(skb); + int ret; + + if (len % 4 == 0) + return 0; + + ret = skb_cow(skb, 2); + if (ret) + return ret; + + skb_push(skb, 2); + memmove(skb->data, skb->data + 2, len); + + skb->data[len] = 0; + skb->data[len + 1] = 0; + return 0; +} diff --git a/linux-bsp/drivers/mt7601u-sta/util.h b/linux-bsp/drivers/mt7601u-sta/util.h new file mode 100644 index 0000000..b89140b --- /dev/null +++ b/linux-bsp/drivers/mt7601u-sta/util.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT76_UTIL_H +#define __MT76_UTIL_H + +/* + * Power of two check, this will check + * if the mask that has been given contains and contiguous set of bits. + * Note that we cannot use the is_power_of_2() function since this + * check must be done at compile-time. + */ +#define is_power_of_two(x) ( !((x) & ((x)-1)) ) +#define low_bit_mask(x) ( ((x)-1) & ~(x) ) +#define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x)) + +/* + * Macros to find first set bit in a variable. + * These macros behave the same as the __ffs() functions but + * the most important difference that this is done during + * compile-time rather then run-time. + */ +#define compile_ffs2(__x) \ + __builtin_choose_expr(((__x) & 0x1), 0, 1) + +#define compile_ffs4(__x) \ + __builtin_choose_expr(((__x) & 0x3), \ + (compile_ffs2((__x))), \ + (compile_ffs2((__x) >> 2) + 2)) + +#define compile_ffs8(__x) \ + __builtin_choose_expr(((__x) & 0xf), \ + (compile_ffs4((__x))), \ + (compile_ffs4((__x) >> 4) + 4)) + +#define compile_ffs16(__x) \ + __builtin_choose_expr(((__x) & 0xff), \ + (compile_ffs8((__x))), \ + (compile_ffs8((__x) >> 8) + 8)) + +#define compile_ffs32(__x) \ + __builtin_choose_expr(((__x) & 0xffff), \ + (compile_ffs16((__x))), \ + (compile_ffs16((__x) >> 16) + 16)) + +/* + * This macro will check the requirements for the FIELD{8,16,32} macros + * The mask should be a constant non-zero contiguous set of bits which + * does not exceed the given typelimit. + */ +#define FIELD_CHECK(__mask) \ + BUILD_BUG_ON(!(__mask) || !is_valid_mask(__mask)) + +#define MT76_SET(_mask, _val) \ + ({ \ + FIELD_CHECK(_mask); \ + (((u32) (_val)) << compile_ffs32(_mask)) & _mask; \ + }) + +#define MT76_GET(_mask, _val) \ + ({ \ + FIELD_CHECK(_mask); \ + (u32) (((_val) & _mask) >> compile_ffs32(_mask)); \ + }) + +#endif diff --git a/linux-bsp/drivers/rtl8188eus/Kconfig b/linux-bsp/drivers/rtl8188eus/Kconfig new file mode 100644 index 0000000..013175c --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/Kconfig @@ -0,0 +1,6 @@ +config RTL8188EU + tristate "Realtek 8188E USB WiFi" + depends on USB + ---help--- + Help message of RTL8188EU + diff --git a/linux-bsp/drivers/rtl8188eus/LICENSE b/linux-bsp/drivers/rtl8188eus/LICENSE new file mode 100644 index 0000000..47c6544 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/LICENSE @@ -0,0 +1,12 @@ +SOUI License + +The MIT License (MIT) +Copyright (c) 2016 ������� + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + diff --git a/linux-bsp/drivers/rtl8188eus/Makefile b/linux-bsp/drivers/rtl8188eus/Makefile new file mode 100644 index 0000000..41a14e8 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/Makefile @@ -0,0 +1,1957 @@ +EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS) +EXTRA_CFLAGS += -O2 +#EXTRA_CFLAGS += -O3 +#EXTRA_CFLAGS += -Wall +#EXTRA_CFLAGS += -Wextra +#EXTRA_CFLAGS += -Werror +#EXTRA_CFLAGS += -pedantic +#EXTRA_CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes + +EXTRA_CFLAGS += -Wno-unused-variable +EXTRA_CFLAGS += -Wno-unused-value +EXTRA_CFLAGS += -Wno-unused-label +EXTRA_CFLAGS += -Wno-unused-parameter +EXTRA_CFLAGS += -Wno-unused-function +EXTRA_CFLAGS += -Wno-unused +#EXTRA_CFLAGS += -Wno-uninitialized + +GCC_VER_49 := $(shell echo `$(CC) -dumpversion | cut -f1-2 -d.` \>= 4.9 | bc ) +ifeq ($(GCC_VER_49),1) +EXTRA_CFLAGS += -Wno-date-time # Fix compile error && warning on gcc 4.9 and later +endif + +EXTRA_CFLAGS += -I$(src)/include +EXTRA_CFLAGS += -I$(src)/hal/phydm + +EXTRA_LDFLAGS += --strip-debug + +CONFIG_AUTOCFG_CP = n + +########################## WIFI IC ############################ +CONFIG_MULTIDRV = n +CONFIG_RTL8188E = y +CONFIG_RTL8812A = n +CONFIG_RTL8821A = n +CONFIG_RTL8192E = n +CONFIG_RTL8723B = n +CONFIG_RTL8814A = n +CONFIG_RTL8723C = n +CONFIG_RTL8188F = n +CONFIG_RTL8822B = n +CONFIG_RTL8723D = n +CONFIG_RTL8821C = n +######################### Interface ########################### +CONFIG_USB_HCI = y +CONFIG_PCI_HCI = n +CONFIG_SDIO_HCI = n +CONFIG_GSPI_HCI = n +########################## Features ########################### +CONFIG_MP_INCLUDED = y +CONFIG_POWER_SAVING = y +CONFIG_USB_AUTOSUSPEND = n +CONFIG_HW_PWRP_DETECTION = n +CONFIG_WIFI_TEST = n +CONFIG_BT_COEXIST = n +CONFIG_INTEL_WIDI = n +CONFIG_WAPI_SUPPORT = n +CONFIG_EFUSE_CONFIG_FILE = y +CONFIG_EXT_CLK = n +CONFIG_TRAFFIC_PROTECT = y +CONFIG_LOAD_PHY_PARA_FROM_FILE = y +CONFIG_TXPWR_BY_RATE_EN = n +CONFIG_TXPWR_LIMIT_EN = n +CONFIG_RTW_ADAPTIVITY_EN = disable +CONFIG_RTW_ADAPTIVITY_MODE = normal +CONFIG_SIGNAL_SCALE_MAPPING = n +CONFIG_80211W = n +CONFIG_REDUCE_TX_CPU_LOADING = n +CONFIG_BR_EXT = y +CONFIG_TDLS = n +CONFIG_WIFI_MONITOR = y +CONFIG_MCC_MODE = n +CONFIG_APPEND_VENDOR_IE_ENABLE = n +CONFIG_RTW_NAPI = y +CONFIG_RTW_GRO = y +########################## Debug ########################### +CONFIG_RTW_DEBUG = n +# default log level is _DRV_INFO_ = 4, +# please refer to "How_to_set_driver_debug_log_level.doc" to set the available level. +CONFIG_RTW_LOG_LEVEL = 4 +######################## Wake On Lan ########################## +CONFIG_WOWLAN = n +CONFIG_GPIO_WAKEUP = n +CONFIG_DEFAULT_PATTERNS_EN = n +CONFIG_WAKEUP_GPIO_IDX = default +CONFIG_HIGH_ACTIVE = n +CONFIG_PNO_SUPPORT = n +CONFIG_PNO_SET_DEBUG = n +CONFIG_AP_WOWLAN = n +######### Notify SDIO Host Keep Power During Syspend ########## +CONFIG_RTW_SDIO_PM_KEEP_POWER = y +###################### MP HW TX MODE FOR VHT ####################### +CONFIG_MP_VHT_HW_TX_MODE = n +###################### Platform Related ####################### +CONFIG_PLATFORM_I386_PC = n +CONFIG_PLATFORM_ARM_SAMA5D4 = y +CONFIG_PLATFORM_BCM2709 = n +CONFIG_PLATFORM_ANDROID_X86 = n +CONFIG_PLATFORM_ANDROID_X86_N70 = n +CONFIG_PLATFORM_ANDROID_INTEL_X86 = n +CONFIG_PLATFORM_JB_X86 = n +CONFIG_PLATFORM_ARM_S3C2K4 = n +CONFIG_PLATFORM_ARM_PXA2XX = n +CONFIG_PLATFORM_ARM_S3C6K4 = n +CONFIG_PLATFORM_MIPS_RMI = n +CONFIG_PLATFORM_RTD2880B = n +CONFIG_PLATFORM_MIPS_AR9132 = n +CONFIG_PLATFORM_RTK_DMP = n +CONFIG_PLATFORM_MIPS_PLM = n +CONFIG_PLATFORM_MSTAR389 = n +CONFIG_PLATFORM_MT53XX = n +CONFIG_PLATFORM_ARM_MX51_241H = n +CONFIG_PLATFORM_FS_MX61 = n +CONFIG_PLATFORM_ACTIONS_ATJ227X = n +CONFIG_PLATFORM_TEGRA3_CARDHU = n +CONFIG_PLATFORM_TEGRA4_DALMORE = n +CONFIG_PLATFORM_ARM_TCC8900 = n +CONFIG_PLATFORM_ARM_TCC8920 = n +CONFIG_PLATFORM_ARM_TCC8920_JB42 = n +CONFIG_PLATFORM_ARM_TCC8930_JB42 = n +CONFIG_PLATFORM_ARM_RK2818 = n +CONFIG_PLATFORM_ARM_RK3066 = n +CONFIG_PLATFORM_ARM_RK3188 = n +CONFIG_PLATFORM_ARM_URBETTER = n +CONFIG_PLATFORM_ARM_TI_PANDA = n +CONFIG_PLATFORM_MIPS_JZ4760 = n +CONFIG_PLATFORM_DMP_PHILIPS = n +CONFIG_PLATFORM_MSTAR_TITANIA12 = n +CONFIG_PLATFORM_MSTAR = n +CONFIG_PLATFORM_SZEBOOK = n +CONFIG_PLATFORM_ARM_SUNxI = n +CONFIG_PLATFORM_ARM_SUN6I = n +CONFIG_PLATFORM_ARM_SUN7I = n +CONFIG_PLATFORM_ARM_SUN8I_W3P1 = n +CONFIG_PLATFORM_ARM_SUN8I_W5P1 = n +CONFIG_PLATFORM_ACTIONS_ATM702X = n +CONFIG_PLATFORM_ACTIONS_ATV5201 = n +CONFIG_PLATFORM_ACTIONS_ATM705X = n +CONFIG_PLATFORM_ARM_SUN50IW1P1 = n +CONFIG_PLATFORM_ARM_RTD299X = n +CONFIG_PLATFORM_ARM_SPREADTRUM_6820 = n +CONFIG_PLATFORM_ARM_SPREADTRUM_8810 = n +CONFIG_PLATFORM_ARM_WMT = n +CONFIG_PLATFORM_TI_DM365 = n +CONFIG_PLATFORM_MOZART = n +CONFIG_PLATFORM_RTK119X = n +CONFIG_PLATFORM_RTK129X = n +CONFIG_PLATFORM_NOVATEK_NT72668 = n +CONFIG_PLATFORM_HISILICON = n +CONFIG_PLATFORM_NV_TK1 = n +############################################################### + +CONFIG_DRVEXT_MODULE = n + +ifeq ($(CONFIG_PLATFORM_ANDROID_X86_N70), y) +export TopDIR := $(shell pwd)/../../../../../../kernel/drivers/net/wireless/rtl8188ee/ +endif + +export TopDIR ?= $(shell pwd) + +########### COMMON ################################# +ifeq ($(CONFIG_GSPI_HCI), y) +HCI_NAME = gspi +endif + +ifeq ($(CONFIG_SDIO_HCI), y) +HCI_NAME = sdio +endif + +ifeq ($(CONFIG_USB_HCI), y) +HCI_NAME = usb +endif + +ifeq ($(CONFIG_PCI_HCI), y) +HCI_NAME = pci +endif + + +_OS_INTFS_FILES := os_dep/osdep_service.o \ + os_dep/linux/os_intfs.o \ + os_dep/linux/$(HCI_NAME)_intf.o \ + os_dep/linux/$(HCI_NAME)_ops_linux.o \ + os_dep/linux/ioctl_linux.o \ + os_dep/linux/xmit_linux.o \ + os_dep/linux/mlme_linux.o \ + os_dep/linux/recv_linux.o \ + os_dep/linux/ioctl_cfg80211.o \ + os_dep/linux/rtw_cfgvendor.o \ + os_dep/linux/wifi_regd.o \ + os_dep/linux/rtw_android.o \ + os_dep/linux/rtw_proc.o + +ifeq ($(CONFIG_MP_INCLUDED), y) +_OS_INTFS_FILES += os_dep/linux/ioctl_mp.o +endif + +ifeq ($(CONFIG_SDIO_HCI), y) +_OS_INTFS_FILES += os_dep/linux/custom_gpio_linux.o +_OS_INTFS_FILES += os_dep/linux/$(HCI_NAME)_ops_linux.o +endif + +ifeq ($(CONFIG_GSPI_HCI), y) +_OS_INTFS_FILES += os_dep/linux/custom_gpio_linux.o +_OS_INTFS_FILES += os_dep/linux/$(HCI_NAME)_ops_linux.o +endif + + +_HAL_INTFS_FILES := hal/hal_intf.o \ + hal/hal_com.o \ + hal/hal_com_phycfg.o \ + hal/hal_phy.o \ + hal/hal_dm.o \ + hal/hal_btcoex_wifionly.o \ + hal/hal_btcoex.o \ + hal/hal_mp.o \ + hal/hal_mcc.o \ + hal/hal_hci/hal_$(HCI_NAME).o \ + hal/led/hal_$(HCI_NAME)_led.o + + +_OUTSRC_FILES := hal/phydm/phydm_debug.o \ + hal/phydm/phydm_antdiv.o\ + hal/phydm/phydm_antdect.o\ + hal/phydm/phydm_interface.o\ + hal/phydm/phydm_hwconfig.o\ + hal/phydm/phydm.o\ + hal/phydm/halphyrf_ce.o\ + hal/phydm/phydm_edcaturbocheck.o\ + hal/phydm/phydm_dig.o\ + hal/phydm/phydm_pathdiv.o\ + hal/phydm/phydm_rainfo.o\ + hal/phydm/phydm_dynamicbbpowersaving.o\ + hal/phydm/phydm_powertracking_ce.o\ + hal/phydm/phydm_dynamictxpower.o\ + hal/phydm/phydm_adaptivity.o\ + hal/phydm/phydm_cfotracking.o\ + hal/phydm/phydm_noisemonitor.o\ + hal/phydm/phydm_acs.o\ + hal/phydm/phydm_beamforming.o\ + hal/phydm/phydm_dfs.o\ + hal/phydm/txbf/halcomtxbf.o\ + hal/phydm/txbf/haltxbfinterface.o\ + hal/phydm/txbf/phydm_hal_txbf_api.o\ + hal/phydm/phydm_adc_sampling.o\ + hal/phydm/phydm_kfree.o\ + hal/phydm/phydm_ccx.o + + +EXTRA_CFLAGS += -I$(src)/platform +_PLATFORM_FILES := platform/platform_ops.o + +EXTRA_CFLAGS += -I$(src)/hal/btc +_OUTSRC_FILES += hal/btc/halbtc8723bwifionly.o \ + hal/btc/halbtc8822bwifionly.o \ + hal/btc/halbtc8821cwifionly.o +ifeq ($(CONFIG_BT_COEXIST), y) +_OUTSRC_FILES += hal/btc/halbtc8192e1ant.o \ + hal/btc/halbtc8192e2ant.o \ + hal/btc/halbtc8723b1ant.o \ + hal/btc/halbtc8723b2ant.o \ + hal/btc/halbtc8812a1ant.o \ + hal/btc/halbtc8812a2ant.o \ + hal/btc/halbtc8821a1ant.o \ + hal/btc/halbtc8821a2ant.o \ + hal/btc/halbtc8703b1ant.o \ + hal/btc/halbtc8723d1ant.o \ + hal/btc/halbtc8723d2ant.o \ + hal/btc/halbtc8822b1ant.o \ + hal/btc/halbtc8822b2ant.o \ + hal/btc/halbtc8821c1ant.o \ + hal/btc/halbtc8821c2ant.o +endif + + +########### HAL_RTL8188E ################################# +ifeq ($(CONFIG_RTL8188E), y) + +RTL871X = rtl8188e +ifeq ($(CONFIG_SDIO_HCI), y) +MODULE_NAME = 8189es +endif + +ifeq ($(CONFIG_GSPI_HCI), y) +MODULE_NAME = 8189es +endif + +ifeq ($(CONFIG_USB_HCI), y) +MODULE_NAME = 8188eu +endif + +ifeq ($(CONFIG_PCI_HCI), y) +MODULE_NAME = 8188ee +endif +EXTRA_CFLAGS += -DCONFIG_RTL8188E + +_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ + hal/$(RTL871X)/Hal8188EPwrSeq.o\ + hal/$(RTL871X)/$(RTL871X)_xmit.o\ + hal/$(RTL871X)/$(RTL871X)_sreset.o + +_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ + hal/$(RTL871X)/$(RTL871X)_phycfg.o \ + hal/$(RTL871X)/$(RTL871X)_rf6052.o \ + hal/$(RTL871X)/$(RTL871X)_dm.o \ + hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ + hal/$(RTL871X)/$(RTL871X)_cmd.o \ + hal/$(RTL871X)/hal8188e_s_fw.o \ + hal/$(RTL871X)/hal8188e_t_fw.o \ + hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o + +ifeq ($(CONFIG_SDIO_HCI), y) +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o +else +ifeq ($(CONFIG_GSPI_HCI), y) +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o +else +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o +endif +endif + +ifeq ($(CONFIG_USB_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_USB.o +endif +ifeq ($(CONFIG_PCI_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_PCIE.o +endif +ifeq ($(CONFIG_SDIO_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188E_SDIO.o +endif + +#hal/OUTSRC/$(RTL871X)/Hal8188EFWImg_CE.o +_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8188e_mac.o\ + hal/phydm/$(RTL871X)/halhwimg8188e_bb.o\ + hal/phydm/$(RTL871X)/halhwimg8188e_rf.o\ + hal/phydm/$(RTL871X)/halphyrf_8188e_ce.o\ + hal/phydm/$(RTL871X)/phydm_regconfig8188e.o\ + hal/phydm/$(RTL871X)/hal8188erateadaptive.o\ + hal/phydm/$(RTL871X)/phydm_rtl8188e.o + +endif + +########### HAL_RTL8192E ################################# +ifeq ($(CONFIG_RTL8192E), y) + +RTL871X = rtl8192e +ifeq ($(CONFIG_SDIO_HCI), y) +MODULE_NAME = 8192es +endif + +ifeq ($(CONFIG_USB_HCI), y) +MODULE_NAME = 8192eu +endif + +ifeq ($(CONFIG_PCI_HCI), y) +MODULE_NAME = 8192ee +endif +EXTRA_CFLAGS += -DCONFIG_RTL8192E +_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ + hal/$(RTL871X)/Hal8192EPwrSeq.o\ + hal/$(RTL871X)/$(RTL871X)_xmit.o\ + hal/$(RTL871X)/$(RTL871X)_sreset.o + +_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ + hal/$(RTL871X)/$(RTL871X)_phycfg.o \ + hal/$(RTL871X)/$(RTL871X)_rf6052.o \ + hal/$(RTL871X)/$(RTL871X)_dm.o \ + hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ + hal/$(RTL871X)/$(RTL871X)_cmd.o \ + hal/$(RTL871X)/hal8192e_fw.o \ + hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o + +ifeq ($(CONFIG_SDIO_HCI), y) +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o +else +ifeq ($(CONFIG_GSPI_HCI), y) +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o +else +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o +endif +endif + +ifeq ($(CONFIG_USB_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8192E_USB.o +endif +ifeq ($(CONFIG_PCI_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8192E_PCIE.o +endif + +#hal/OUTSRC/$(RTL871X)/HalHWImg8188E_FW.o +_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8192e_mac.o\ + hal/phydm/$(RTL871X)/halhwimg8192e_bb.o\ + hal/phydm/$(RTL871X)/halhwimg8192e_rf.o\ + hal/phydm/$(RTL871X)/halphyrf_8192e_ce.o\ + hal/phydm/$(RTL871X)/phydm_regconfig8192e.o\ + hal/phydm/$(RTL871X)/phydm_rtl8192e.o + +endif + +########### HAL_RTL8812A_RTL8821A ################################# + +ifneq ($(CONFIG_RTL8812A)_$(CONFIG_RTL8821A), n_n) + +RTL871X = rtl8812a +ifeq ($(CONFIG_USB_HCI), y) +MODULE_NAME = 8812au +endif +ifeq ($(CONFIG_PCI_HCI), y) +MODULE_NAME = 8812ae +endif +ifeq ($(CONFIG_SDIO_HCI), y) +MODULE_NAME = 8812as +endif + +_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ + hal/$(RTL871X)/Hal8812PwrSeq.o \ + hal/$(RTL871X)/Hal8821APwrSeq.o\ + hal/$(RTL871X)/$(RTL871X)_xmit.o\ + hal/$(RTL871X)/$(RTL871X)_sreset.o + +_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ + hal/$(RTL871X)/$(RTL871X)_phycfg.o \ + hal/$(RTL871X)/$(RTL871X)_rf6052.o \ + hal/$(RTL871X)/$(RTL871X)_dm.o \ + hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ + hal/$(RTL871X)/$(RTL871X)_cmd.o \ + hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o + +ifeq ($(CONFIG_SDIO_HCI), y) +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o +else +ifeq ($(CONFIG_GSPI_HCI), y) +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o +else +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o +endif +endif + +ifeq ($(CONFIG_RTL8812A), y) +ifeq ($(CONFIG_USB_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8812A_USB.o +endif +ifeq ($(CONFIG_PCI_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8812A_PCIE.o +endif +endif +ifeq ($(CONFIG_RTL8821A), y) +ifeq ($(CONFIG_USB_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_USB.o +endif +ifeq ($(CONFIG_PCI_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8821A_PCIE.o +endif +endif + +ifeq ($(CONFIG_RTL8812A), y) +EXTRA_CFLAGS += -DCONFIG_RTL8812A +_HAL_INTFS_FILES += hal/rtl8812a/hal8812a_fw.o + +_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8812a_mac.o\ + hal/phydm/$(RTL871X)/halhwimg8812a_bb.o\ + hal/phydm/$(RTL871X)/halhwimg8812a_rf.o\ + hal/phydm/$(RTL871X)/halphyrf_8812a_ce.o\ + hal/phydm/$(RTL871X)/phydm_regconfig8812a.o\ + hal/phydm/$(RTL871X)/phydm_rtl8812a.o\ + hal/phydm/txbf/haltxbfjaguar.o +endif + +ifeq ($(CONFIG_RTL8821A), y) + +ifeq ($(CONFIG_RTL8812A), n) + +RTL871X = rtl8821a +ifeq ($(CONFIG_USB_HCI), y) +ifeq ($(CONFIG_BT_COEXIST), y) +MODULE_NAME := 8821au +else +MODULE_NAME := 8811au +endif +endif +ifeq ($(CONFIG_PCI_HCI), y) +MODULE_NAME := 8821ae +endif +ifeq ($(CONFIG_SDIO_HCI), y) +MODULE_NAME := 8821as +endif + +endif + +EXTRA_CFLAGS += -DCONFIG_RTL8821A + +_HAL_INTFS_FILES += hal/rtl8812a/hal8821a_fw.o +_OUTSRC_FILES += hal/phydm/rtl8821a/halhwimg8821a_mac.o\ + hal/phydm/rtl8821a/halhwimg8821a_bb.o\ + hal/phydm/rtl8821a/halhwimg8821a_rf.o\ + hal/phydm/rtl8812a/halphyrf_8812a_ce.o\ + hal/phydm/rtl8821a/halphyrf_8821a_ce.o\ + hal/phydm/rtl8821a/phydm_regconfig8821a.o\ + hal/phydm/rtl8821a/phydm_rtl8821a.o\ + hal/phydm/rtl8821a/phydm_iqk_8821a_ce.o\ + hal/phydm/txbf/haltxbfjaguar.o + +endif + +endif + +########### HAL_RTL8723B ################################# +ifeq ($(CONFIG_RTL8723B), y) + +RTL871X = rtl8723b +ifeq ($(CONFIG_USB_HCI), y) +MODULE_NAME = 8723bu +endif +ifeq ($(CONFIG_PCI_HCI), y) +MODULE_NAME = 8723be +endif +ifeq ($(CONFIG_SDIO_HCI), y) +MODULE_NAME = 8723bs +endif + +EXTRA_CFLAGS += -DCONFIG_RTL8723B + +_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ + hal/$(RTL871X)/Hal8723BPwrSeq.o\ + hal/$(RTL871X)/$(RTL871X)_sreset.o + +_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ + hal/$(RTL871X)/$(RTL871X)_phycfg.o \ + hal/$(RTL871X)/$(RTL871X)_rf6052.o \ + hal/$(RTL871X)/$(RTL871X)_dm.o \ + hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ + hal/$(RTL871X)/$(RTL871X)_cmd.o \ + hal/$(RTL871X)/hal8723b_fw.o + +_HAL_INTFS_FILES += \ + hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o + +ifeq ($(CONFIG_PCI_HCI), y) +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o +else +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o +endif + +ifeq ($(CONFIG_USB_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_USB.o +endif +ifeq ($(CONFIG_PCI_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723B_PCIE.o +endif + +_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8723b_bb.o\ + hal/phydm/$(RTL871X)/halhwimg8723b_mac.o\ + hal/phydm/$(RTL871X)/halhwimg8723b_rf.o\ + hal/phydm/$(RTL871X)/halhwimg8723b_mp.o\ + hal/phydm/$(RTL871X)/phydm_regconfig8723b.o\ + hal/phydm/$(RTL871X)/halphyrf_8723b_ce.o\ + hal/phydm/$(RTL871X)/phydm_rtl8723b.o + +endif + +########### HAL_RTL8814A ################################# +ifeq ($(CONFIG_RTL8814A), y) +## ADD NEW VHT MP HW TX MODE ## +#EXTRA_CFLAGS += -DCONFIG_MP_VHT_HW_TX_MODE +#CONFIG_MP_VHT_HW_TX_MODE = y +########################################## +RTL871X = rtl8814a +ifeq ($(CONFIG_USB_HCI), y) +MODULE_NAME = 8814au +endif +ifeq ($(CONFIG_PCI_HCI), y) +MODULE_NAME = 8814ae +endif +ifeq ($(CONFIG_SDIO_HCI), y) +MODULE_NAME = 8814as +endif + +EXTRA_CFLAGS += -DCONFIG_RTL8814A + +_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ + hal/$(RTL871X)/Hal8814PwrSeq.o \ + hal/$(RTL871X)/$(RTL871X)_xmit.o\ + hal/$(RTL871X)/$(RTL871X)_sreset.o + +_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ + hal/$(RTL871X)/$(RTL871X)_phycfg.o \ + hal/$(RTL871X)/$(RTL871X)_rf6052.o \ + hal/$(RTL871X)/$(RTL871X)_dm.o \ + hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ + hal/$(RTL871X)/$(RTL871X)_cmd.o \ + hal/$(RTL871X)/hal8814a_fw.o + + +_HAL_INTFS_FILES += \ + hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o + +ifeq ($(CONFIG_SDIO_HCI), y) +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o +else +ifeq ($(CONFIG_GSPI_HCI), y) +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o +else +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o +endif +endif + +ifeq ($(CONFIG_USB_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8814A_USB.o +endif +ifeq ($(CONFIG_PCI_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8814A_PCIE.o +endif + +_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8814a_bb.o\ + hal/phydm/$(RTL871X)/halhwimg8814a_mac.o\ + hal/phydm/$(RTL871X)/halhwimg8814a_rf.o\ + hal/phydm/$(RTL871X)/phydm_iqk_8814a.o\ + hal/phydm/$(RTL871X)/phydm_regconfig8814a.o\ + hal/phydm/$(RTL871X)/halphyrf_8814a_ce.o\ + hal/phydm/$(RTL871X)/phydm_rtl8814a.o\ + hal/phydm/txbf/haltxbf8814a.o + +endif + +########### HAL_RTL8723C ################################# +ifeq ($(CONFIG_RTL8723C), y) + +RTL871X = rtl8703b +ifeq ($(CONFIG_USB_HCI), y) +MODULE_NAME = 8723cu +MODULE_SUB_NAME = 8703bu +endif +ifeq ($(CONFIG_PCI_HCI), y) +MODULE_NAME = 8723ce +MODULE_SUB_NAME = 8703be +endif +ifeq ($(CONFIG_SDIO_HCI), y) +MODULE_NAME = 8723cs +MODULE_SUB_NAME = 8703bs +endif + +EXTRA_CFLAGS += -DCONFIG_RTL8703B + +_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ + hal/$(RTL871X)/Hal8703BPwrSeq.o\ + hal/$(RTL871X)/$(RTL871X)_sreset.o + +_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ + hal/$(RTL871X)/$(RTL871X)_phycfg.o \ + hal/$(RTL871X)/$(RTL871X)_rf6052.o \ + hal/$(RTL871X)/$(RTL871X)_dm.o \ + hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ + hal/$(RTL871X)/$(RTL871X)_cmd.o \ + hal/$(RTL871X)/hal8703b_fw.o + +_HAL_INTFS_FILES += \ + hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o + +ifeq ($(CONFIG_PCI_HCI), y) +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o +else +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o +endif + +ifeq ($(CONFIG_USB_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8703B_USB.o +endif +ifeq ($(CONFIG_PCI_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8703B_PCIE.o +endif + +_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8703b_bb.o\ + hal/phydm/$(RTL871X)/halhwimg8703b_mac.o\ + hal/phydm/$(RTL871X)/halhwimg8703b_rf.o\ + hal/phydm/$(RTL871X)/phydm_regconfig8703b.o\ + hal/phydm/$(RTL871X)/halphyrf_8703b.o +endif + +########### HAL_RTL8723D ################################# +ifeq ($(CONFIG_RTL8723D), y) + +RTL871X = rtl8723d +ifeq ($(CONFIG_USB_HCI), y) +MODULE_NAME = 8723du +MODULE_SUB_NAME = 8723du +endif +ifeq ($(CONFIG_PCI_HCI), y) +MODULE_NAME = 8723de +MODULE_SUB_NAME = 8723de +endif +ifeq ($(CONFIG_SDIO_HCI), y) +MODULE_NAME = 8723ds +MODULE_SUB_NAME = 8723ds +endif + +EXTRA_CFLAGS += -DCONFIG_RTL8723D + +_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ + hal/$(RTL871X)/Hal8723DPwrSeq.o\ + hal/$(RTL871X)/$(RTL871X)_sreset.o + +_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ + hal/$(RTL871X)/$(RTL871X)_phycfg.o \ + hal/$(RTL871X)/$(RTL871X)_rf6052.o \ + hal/$(RTL871X)/$(RTL871X)_dm.o \ + hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ + hal/$(RTL871X)/$(RTL871X)_cmd.o \ + hal/$(RTL871X)/hal8723d_fw.o \ + hal/$(RTL871X)/$(RTL871X)_lps_poff.o + + +_HAL_INTFS_FILES += \ + hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_led.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_xmit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_SUB_NAME)_recv.o + +ifeq ($(CONFIG_PCI_HCI), y) +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o +else +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o +endif + +ifeq ($(CONFIG_USB_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723D_USB.o +endif +ifeq ($(CONFIG_PCI_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8723D_PCIE.o +endif + +_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8723d_bb.o\ + hal/phydm/$(RTL871X)/halhwimg8723d_mac.o\ + hal/phydm/$(RTL871X)/halhwimg8723d_rf.o\ + hal/phydm/$(RTL871X)/phydm_regconfig8723d.o\ + hal/phydm/$(RTL871X)/phydm_rtl8723d.o\ + hal/phydm/$(RTL871X)/halphyrf_8723d.o +endif + +########### HAL_RTL8188F ################################# +ifeq ($(CONFIG_RTL8188F), y) + +RTL871X = rtl8188f +ifeq ($(CONFIG_USB_HCI), y) +MODULE_NAME = 8188fu +endif +ifeq ($(CONFIG_PCI_HCI), y) +MODULE_NAME = 8188fe +endif +ifeq ($(CONFIG_SDIO_HCI), y) +MODULE_NAME = 8189fs +endif + +EXTRA_CFLAGS += -DCONFIG_RTL8188F + +_HAL_INTFS_FILES += hal/HalPwrSeqCmd.o \ + hal/$(RTL871X)/Hal8188FPwrSeq.o\ + hal/$(RTL871X)/$(RTL871X)_sreset.o + +_HAL_INTFS_FILES += hal/$(RTL871X)/$(RTL871X)_hal_init.o \ + hal/$(RTL871X)/$(RTL871X)_phycfg.o \ + hal/$(RTL871X)/$(RTL871X)_rf6052.o \ + hal/$(RTL871X)/$(RTL871X)_dm.o \ + hal/$(RTL871X)/$(RTL871X)_rxdesc.o \ + hal/$(RTL871X)/$(RTL871X)_cmd.o \ + hal/$(RTL871X)/hal8188f_fw.o + +_HAL_INTFS_FILES += \ + hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_halinit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_led.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_xmit.o \ + hal/$(RTL871X)/$(HCI_NAME)/rtl$(MODULE_NAME)_recv.o + +ifeq ($(CONFIG_PCI_HCI), y) +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops_linux.o +else +_HAL_INTFS_FILES += hal/$(RTL871X)/$(HCI_NAME)/$(HCI_NAME)_ops.o +endif + +ifeq ($(CONFIG_USB_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188F_USB.o +endif + +ifeq ($(CONFIG_SDIO_HCI), y) +_HAL_INTFS_FILES +=hal/efuse/$(RTL871X)/HalEfuseMask8188F_SDIO.o +endif + +_OUTSRC_FILES += hal/phydm/$(RTL871X)/halhwimg8188f_bb.o\ + hal/phydm/$(RTL871X)/halhwimg8188f_mac.o\ + hal/phydm/$(RTL871X)/halhwimg8188f_rf.o\ + hal/phydm/$(RTL871X)/phydm_regconfig8188f.o\ + hal/phydm/$(RTL871X)/halphyrf_8188f.o \ + hal/phydm/$(RTL871X)/phydm_rtl8188f.o + +endif + +########### HAL_RTL8822B ################################# +ifeq ($(CONFIG_RTL8822B), y) +include $(TopDIR)/rtl8822b.mk +endif + +########### HAL_RTL8821C ################################# +ifeq ($(CONFIG_RTL8821C), y) +include $(TopDIR)/rtl8821c.mk + +_OUTSRC_FILES += hal/phydm/rtl8821c/halhwimg8821c_bb.o \ + hal/phydm/rtl8821c/halhwimg8821c_mac.o \ + hal/phydm/rtl8821c/halhwimg8821c_rf.o \ + hal/phydm/rtl8821c/phydm_hal_api8821c.o \ + hal/phydm/rtl8821c/phydm_regconfig8821c.o\ + hal/phydm/rtl8821c/halphyrf_8821c.o\ + hal/phydm/rtl8821c/phydm_iqk_8821c.o +endif + +########### AUTO_CFG ################################# + +ifeq ($(CONFIG_AUTOCFG_CP), y) + +ifeq ($(CONFIG_MULTIDRV), y) +$(shell cp $(TopDIR)/autoconf_multidrv_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) +else +ifeq ($(CONFIG_RTL8188E)$(CONFIG_SDIO_HCI),yy) +$(shell cp $(TopDIR)/autoconf_rtl8189e_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) +else ifeq ($(CONFIG_RTL8188F)$(CONFIG_SDIO_HCI),yy) +$(shell cp $(TopDIR)/autoconf_rtl8189f_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) +else ifeq ($(CONFIG_RTL8723C),y) +$(shell cp $(TopDIR)/autoconf_rtl8723c_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) +else +$(shell cp $(TopDIR)/autoconf_$(RTL871X)_$(HCI_NAME)_linux.h $(TopDIR)/include/autoconf.h) +endif +endif + +endif + +########### END OF PATH ################################# + +ifeq ($(CONFIG_USB_HCI), y) +ifeq ($(CONFIG_USB_AUTOSUSPEND), y) +EXTRA_CFLAGS += -DCONFIG_USB_AUTOSUSPEND +endif +endif + +ifeq ($(CONFIG_MP_INCLUDED), y) +#MODULE_NAME := $(MODULE_NAME)_mp +EXTRA_CFLAGS += -DCONFIG_MP_INCLUDED +endif + +ifeq ($(CONFIG_POWER_SAVING), y) +EXTRA_CFLAGS += -DCONFIG_POWER_SAVING +endif + +ifeq ($(CONFIG_HW_PWRP_DETECTION), y) +EXTRA_CFLAGS += -DCONFIG_HW_PWRP_DETECTION +endif + +ifeq ($(CONFIG_WIFI_TEST), y) +EXTRA_CFLAGS += -DCONFIG_WIFI_TEST +endif + +ifeq ($(CONFIG_BT_COEXIST), y) +EXTRA_CFLAGS += -DCONFIG_BT_COEXIST +endif + +ifeq ($(CONFIG_INTEL_WIDI), y) +EXTRA_CFLAGS += -DCONFIG_INTEL_WIDI +endif + +ifeq ($(CONFIG_WAPI_SUPPORT), y) +EXTRA_CFLAGS += -DCONFIG_WAPI_SUPPORT +endif + + +ifeq ($(CONFIG_EFUSE_CONFIG_FILE), y) +EXTRA_CFLAGS += -DCONFIG_EFUSE_CONFIG_FILE + +#EFUSE_MAP_PATH +USER_EFUSE_MAP_PATH ?= +ifneq ($(USER_EFUSE_MAP_PATH),) +EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"$(USER_EFUSE_MAP_PATH)\" +else ifeq ($(MODULE_NAME), 8189es) +EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_8189e.map\" +else ifeq ($(MODULE_NAME), 8723bs) +EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_8723bs.map\" +else +EXTRA_CFLAGS += -DEFUSE_MAP_PATH=\"/system/etc/wifi/wifi_efuse_$(MODULE_NAME).map\" +endif + +#WIFIMAC_PATH +USER_WIFIMAC_PATH ?= +ifneq ($(USER_WIFIMAC_PATH),) +EXTRA_CFLAGS += -DWIFIMAC_PATH=\"$(USER_WIFIMAC_PATH)\" +else +EXTRA_CFLAGS += -DWIFIMAC_PATH=\"/data/wifimac.txt\" +endif + +endif + +ifeq ($(CONFIG_EXT_CLK), y) +EXTRA_CFLAGS += -DCONFIG_EXT_CLK +endif + +ifeq ($(CONFIG_TRAFFIC_PROTECT), y) +EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT +endif + +ifeq ($(CONFIG_LOAD_PHY_PARA_FROM_FILE), y) +EXTRA_CFLAGS += -DCONFIG_LOAD_PHY_PARA_FROM_FILE +#EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH_WITH_IC_NAME_FOLDER +#EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH=\"/lib/firmware/\" +EXTRA_CFLAGS += -DREALTEK_CONFIG_PATH=\"\" +endif + +ifeq ($(CONFIG_TXPWR_BY_RATE_EN), n) +EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=0 +else ifeq ($(CONFIG_TXPWR_BY_RATE_EN), y) +EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=1 +else ifeq ($(CONFIG_TXPWR_BY_RATE_EN), auto) +EXTRA_CFLAGS += -DCONFIG_TXPWR_BY_RATE_EN=2 +endif + +ifeq ($(CONFIG_TXPWR_LIMIT_EN), n) +EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=0 +else ifeq ($(CONFIG_TXPWR_LIMIT_EN), y) +EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=1 +else ifeq ($(CONFIG_TXPWR_LIMIT_EN), auto) +EXTRA_CFLAGS += -DCONFIG_TXPWR_LIMIT_EN=2 +endif + +ifeq ($(CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY), y) +EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_BY_REGULATORY +endif + +ifeq ($(CONFIG_CALIBRATE_TX_POWER_TO_MAX), y) +EXTRA_CFLAGS += -DCONFIG_CALIBRATE_TX_POWER_TO_MAX +endif + +ifeq ($(CONFIG_RTW_ADAPTIVITY_EN), disable) +EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_EN=0 +else ifeq ($(CONFIG_RTW_ADAPTIVITY_EN), enable) +EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_EN=1 +endif + +ifeq ($(CONFIG_RTW_ADAPTIVITY_MODE), normal) +EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_MODE=0 +else ifeq ($(CONFIG_RTW_ADAPTIVITY_MODE), carrier_sense) +EXTRA_CFLAGS += -DCONFIG_RTW_ADAPTIVITY_MODE=1 +endif + +ifeq ($(CONFIG_SIGNAL_SCALE_MAPPING), y) +EXTRA_CFLAGS += -DCONFIG_SIGNAL_SCALE_MAPPING +endif + +ifeq ($(CONFIG_80211W), y) +EXTRA_CFLAGS += -DCONFIG_IEEE80211W +endif + +ifeq ($(CONFIG_WOWLAN), y) +EXTRA_CFLAGS += -DCONFIG_WOWLAN +ifeq ($(CONFIG_SDIO_HCI), y) +EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER +endif +ifeq ($(CONFIG_DEFAULT_PATTERNS_EN), y) +EXTRA_CFLAGS += -DCONFIG_DEFAULT_PATTERNS_EN +endif +endif + +ifeq ($(CONFIG_AP_WOWLAN), y) +EXTRA_CFLAGS += -DCONFIG_AP_WOWLAN +ifeq ($(CONFIG_SDIO_HCI), y) +EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER +endif +endif + +ifeq ($(CONFIG_PNO_SUPPORT), y) +EXTRA_CFLAGS += -DCONFIG_PNO_SUPPORT +ifeq ($(CONFIG_PNO_SET_DEBUG), y) +EXTRA_CFLAGS += -DCONFIG_PNO_SET_DEBUG +endif +endif + +ifeq ($(CONFIG_GPIO_WAKEUP), y) +EXTRA_CFLAGS += -DCONFIG_GPIO_WAKEUP +ifeq ($(CONFIG_HIGH_ACTIVE), y) +EXTRA_CFLAGS += -DHIGH_ACTIVE=1 +else +EXTRA_CFLAGS += -DHIGH_ACTIVE=0 +endif +endif + +ifneq ($(CONFIG_WAKEUP_GPIO_IDX), default) +EXTRA_CFLAGS += -DWAKEUP_GPIO_IDX=$(CONFIG_WAKEUP_GPIO_IDX) +endif + +ifeq ($(CONFIG_RTW_SDIO_PM_KEEP_POWER), y) +ifeq ($(CONFIG_SDIO_HCI), y) +EXTRA_CFLAGS += -DCONFIG_RTW_SDIO_PM_KEEP_POWER +endif +endif + +ifeq ($(CONFIG_REDUCE_TX_CPU_LOADING), y) +EXTRA_CFLAGS += -DCONFIG_REDUCE_TX_CPU_LOADING +endif + +ifeq ($(CONFIG_BR_EXT), y) +BR_NAME = br0 +EXTRA_CFLAGS += -DCONFIG_BR_EXT +EXTRA_CFLAGS += '-DCONFIG_BR_EXT_BRNAME="'$(BR_NAME)'"' +endif + + +ifeq ($(CONFIG_TDLS), y) +EXTRA_CFLAGS += -DCONFIG_TDLS +endif + +ifeq ($(CONFIG_WIFI_MONITOR), y) +EXTRA_CFLAGS += -DCONFIG_WIFI_MONITOR +endif + +ifeq ($(CONFIG_MCC_MODE), y) +EXTRA_CFLAGS += -DCONFIG_MCC_MODE +endif + +ifeq ($(CONFIG_RTW_NAPI), y) +EXTRA_CFLAGS += -DCONFIG_RTW_NAPI +endif + +ifeq ($(CONFIG_RTW_GRO), y) +EXTRA_CFLAGS += -DCONFIG_RTW_GRO +endif + +ifeq ($(CONFIG_MP_VHT_HW_TX_MODE), y) +EXTRA_CFLAGS += -DCONFIG_MP_VHT_HW_TX_MODE +ifeq ($(CONFIG_PLATFORM_I386_PC), y) +## For I386 X86 ToolChain use Hardware FLOATING +EXTRA_CFLAGS += -mhard-float +else +## For ARM ToolChain use Hardware FLOATING +EXTRA_CFLAGS += -mfloat-abi=hard +endif +endif + +ifeq ($(CONFIG_APPEND_VENDOR_IE_ENABLE), y) +EXTRA_CFLAGS += -DCONFIG_APPEND_VENDOR_IE_ENABLE +endif + +ifeq ($(CONFIG_RTW_DEBUG), y) +EXTRA_CFLAGS += -DCONFIG_RTW_DEBUG +EXTRA_CFLAGS += -DRTW_LOG_LEVEL=$(CONFIG_RTW_LOG_LEVEL) +endif + +EXTRA_CFLAGS += -DDM_ODM_SUPPORT_TYPE=0x04 + +ifeq ($(CONFIG_PLATFORM_I386_PC), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) +ARCH ?= $(SUBARCH) +CROSS_COMPILE ?= +KVER := $(shell uname -r) +KSRC := /lib/modules/$(KVER)/build +MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ +INSTALL_PREFIX := +endif + +ifeq ($(CONFIG_PLATFORM_ARM_SAMA5D4), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +ARCH := arm +CROSS_COMPILE := /opt/buildroot/cortex-a5/bin/arm-linux- +KVER := 4.9.151 +KSRC ?= ../../linux-at91/ +endif + + +ifeq ($(CONFIG_PLATFORM_BCM2709), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +ARCH ?= arm +CROSS_COMPILE ?= +KVER := $(shell uname -r) +KSRC := /lib/modules/$(KVER)/build +MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ +INSTALL_PREFIX := +endif +ifeq ($(CONFIG_PLATFORM_NV_TK1), y) +EXTRA_CFLAGS += -DCONFIG_PLATFORM_NV_TK1 +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +ARCH ?= arm +CROSS_COMPILE ?= +KVER := $(shell uname -r) +KSRC := /lib/modules/$(KVER)/build +MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ +INSTALL_PREFIX := +endif + +ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM702X), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ACTIONS_ATM702X +#ARCH := arm +ARCH := $(R_ARCH) +#CROSS_COMPILE := arm-none-linux-gnueabi- +CROSS_COMPILE := $(R_CROSS_COMPILE) +KVER:= 3.4.0 +#KSRC := ../../../../build/out/kernel +KSRC := $(KERNEL_BUILD_PATH) +MODULE_NAME :=wlan +endif + + +ifeq ($(CONFIG_PLATFORM_ACTIONS_ATM705X), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +#EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC +# default setting for Android 4.1, 4.2, 4.3, 4.4 +EXTRA_CFLAGS += -DCONFIG_PLATFORM_ACTIONS_ATM705X +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT + +# Enable this for Android 5.0 +EXTRA_CFLAGS += -DCONFIG_RADIO_WORK + +ifeq ($(CONFIG_SDIO_HCI), y) +EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS +_PLATFORM_FILES += platform/platform_arm_act_sdio.o +endif + +ARCH := arm +CROSS_COMPILE := /opt/arm-2011.09/bin/arm-none-linux-gnueabi- +KSRC := /home/android_sdk/Action-semi/705a_android_L/android/kernel +endif + +ifeq ($(CONFIG_PLATFORM_ARM_SUN50IW1P1), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN50IW1P1 +EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT +# default setting for Android 4.1, 4.2 +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +EXTRA_CFLAGS += -DCONFIG_RESUME_IN_WORKQUEUE +EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS + +# Enable this for Android 5.0 +EXTRA_CFLAGS += -DCONFIG_RADIO_WORK + +ifeq ($(CONFIG_USB_HCI), y) +EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX +_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o +endif +ifeq ($(CONFIG_SDIO_HCI), y) +_PLATFORM_FILES += platform/platform_ARM_SUN50IW1P1_sdio.o +endif + +ARCH := arm64 +# ===Cross compile setting for Android 5.1(64) SDK === +CROSS_COMPILE := /home/android_sdk/Allwinner/a64/android-51/lichee/out/sun50iw1p1/android/common/buildroot/external-toolchain/bin/aarch64-linux-gnu- +KSRC :=/home/android_sdk/Allwinner/a64/android-51/lichee/linux-3.10/ +endif + +ifeq ($(CONFIG_PLATFORM_TI_AM3517), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_SHUTTLE +CROSS_COMPILE := arm-eabi- +KSRC := $(shell pwd)/../../../Android/kernel +ARCH := arm +endif + +ifeq ($(CONFIG_PLATFORM_MSTAR_TITANIA12), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR -DCONFIG_PLATFORM_MSTAR_TITANIA12 +ARCH:=mips +CROSS_COMPILE:= /usr/src/Mstar_kernel/mips-4.3/bin/mips-linux-gnu- +KVER:= 2.6.28.9 +KSRC:= /usr/src/Mstar_kernel/2.6.28.9/ +endif + +ifeq ($(CONFIG_PLATFORM_MSTAR), y) +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR -DCONFIG_USE_USB_BUFFER_ALLOC_TX -DCONFIG_FIX_NR_BULKIN_BUFFER +EXTRA_CFLAGS += -DCONFIG_PLATFORM_MSTAR_HIGH +ARCH:=arm +CROSS_COMPILE:= /usr/src/bin/arm-none-linux-gnueabi- +KVER:= 3.1.10 +KSRC:= /usr/src/Mstar_kernel/3.1.10/ +endif + +ifeq ($(CONFIG_PLATFORM_ANDROID_X86), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) +ARCH := $(SUBARCH) +CROSS_COMPILE := /media/DATA-2/android-x86/ics-x86_20120130/prebuilt/linux-x86/toolchain/i686-unknown-linux-gnu-4.2.1/bin/i686-unknown-linux-gnu- +KSRC := /media/DATA-2/android-x86/ics-x86_20120130/out/target/product/generic_x86/obj/kernel +MODULE_NAME :=wlan +endif + +ifeq ($(CONFIG_PLATFORM_ANDROID_X86_N70), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +EXTRA_CFLAGS += -DCONFIG_RADIO_WORK +EXTRA_CFLAGS += -DCONFIG_PLATFORM_ANDROID +ARCH := x86 +#CROSS_COMPILE := /work/android-x86/android-x86/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7/bin/i686-linux-android- +CROSS_COMPILE := /home/work/android-N/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin/x86_64-linux-android- +#CROSS_COMPILE := /work/78/android-x86/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin/x86_64-linux-android- +KSRC := /home/work/android-N/out/target/product/x86/obj/kernel/ +#KSRC := /work/78/android-x86/out/target/product/x86/obj/kernel/ +MODULE_NAME :=wlan-8188ee +endif + +ifeq ($(CONFIG_PLATFORM_ANDROID_INTEL_X86), y) +EXTRA_CFLAGS += -DCONFIG_PLATFORM_ANDROID_INTEL_X86 +EXTRA_CFLAGS += -DCONFIG_PLATFORM_INTEL_BYT +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +EXTRA_CFLAGS += -DCONFIG_SKIP_SIGNAL_SCALE_MAPPING +ifeq ($(CONFIG_SDIO_HCI), y) +EXTRA_CFLAGS += -DCONFIG_RESUME_IN_WORKQUEUE +endif +endif + +ifeq ($(CONFIG_PLATFORM_JB_X86), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) +ARCH := $(SUBARCH) +CROSS_COMPILE := /home/android_sdk/android-x86_JB/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7/bin/i686-linux-android- +KSRC := /home/android_sdk/android-x86_JB/out/target/product/x86/obj/kernel/ +MODULE_NAME :=wlan +endif + +ifeq ($(CONFIG_PLATFORM_ARM_PXA2XX), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +ARCH := arm +CROSS_COMPILE := arm-none-linux-gnueabi- +KVER := 2.6.34.1 +KSRC ?= /usr/src/linux-2.6.34.1 +endif + +ifeq ($(CONFIG_PLATFORM_ARM_S3C2K4), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +ARCH := arm +CROSS_COMPILE := arm-linux- +KVER := 2.6.24.7_$(ARCH) +KSRC := /usr/src/kernels/linux-$(KVER) +endif + +ifeq ($(CONFIG_PLATFORM_ARM_S3C6K4), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +ARCH := arm +CROSS_COMPILE := arm-none-linux-gnueabi- +KVER := 2.6.34.1 +KSRC ?= /usr/src/linux-2.6.34.1 +endif + +ifeq ($(CONFIG_PLATFORM_RTD2880B), y) +EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN -DCONFIG_PLATFORM_RTD2880B +ARCH:= +CROSS_COMPILE:= +KVER:= +KSRC:= +endif + +ifeq ($(CONFIG_PLATFORM_MIPS_RMI), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +ARCH:=mips +CROSS_COMPILE:=mipsisa32r2-uclibc- +KVER:= +KSRC:= /root/work/kernel_realtek +endif + +ifeq ($(CONFIG_PLATFORM_MIPS_PLM), y) +EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN +ARCH:=mips +CROSS_COMPILE:=mipsisa32r2-uclibc- +KVER:= +KSRC:= /root/work/kernel_realtek +endif + +ifeq ($(CONFIG_PLATFORM_MSTAR389), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MSTAR389 +ARCH:=mips +CROSS_COMPILE:= mips-linux-gnu- +KVER:= 2.6.28.10 +KSRC:= /home/mstar/mstar_linux/2.6.28.9/ +endif + +ifeq ($(CONFIG_PLATFORM_MIPS_AR9132), y) +EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN +ARCH := mips +CROSS_COMPILE := mips-openwrt-linux- +KSRC := /home/alex/test_openwrt/tmp/linux-2.6.30.9 +endif + +ifeq ($(CONFIG_PLATFORM_DMP_PHILIPS), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM +ARCH := mips +#CROSS_COMPILE:=/usr/local/msdk-4.3.6-mips-EL-2.6.12.6-0.9.30.3/bin/mipsel-linux- +CROSS_COMPILE:=/usr/local/toolchain_mipsel/bin/mipsel-linux- +KSRC ?=/usr/local/Jupiter/linux-2.6.12 +endif + +ifeq ($(CONFIG_PLATFORM_RTK_DMP), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DRTK_DMP_PLATFORM -DCONFIG_WIRELESS_EXT +EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS +ifeq ($(CONFIG_USB_HCI), y) +_PLATFORM_FILES += platform/platform_RTK_DMP_usb.o +endif +ARCH:=mips +CROSS_COMPILE:=mipsel-linux- +KVER:= +KSRC ?= /usr/src/DMP_Kernel/jupiter/linux-2.6.12 +endif + +ifeq ($(CONFIG_PLATFORM_MT53XX), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MT53XX +ARCH:= arm +CROSS_COMPILE:= arm11_mtk_le- +KVER:= 2.6.27 +KSRC?= /proj/mtk00802/BD_Compare/BDP/Dev/BDP_V301/BDP_Linux/linux-2.6.27 +endif + +ifeq ($(CONFIG_PLATFORM_ARM_MX51_241H), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_WISTRON_PLATFORM +ARCH := arm +CROSS_COMPILE := /opt/freescale/usr/local/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi- +KVER := 2.6.31 +KSRC ?= /lib/modules/2.6.31-770-g0e46b52/source +endif + +ifeq ($(CONFIG_PLATFORM_FS_MX61), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +ARCH := arm +CROSS_COMPILE := /home/share/CusEnv/FreeScale/arm-eabi-4.4.3/bin/arm-eabi- +KSRC ?= /home/share/CusEnv/FreeScale/FS_kernel_env +endif + + + +ifeq ($(CONFIG_PLATFORM_ACTIONS_ATJ227X), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATJ227X +ARCH := mips +CROSS_COMPILE := /home/cnsd4/project/actions/tools-2.6.27/bin/mipsel-linux-gnu- +KVER := 2.6.27 +KSRC := /home/cnsd4/project/actions/linux-2.6.27.28 +endif + +ifeq ($(CONFIG_PLATFORM_TI_DM365), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_TI_DM365 +EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_RX +EXTRA_CFLAGS += -DCONFIG_SINGLE_XMIT_BUF -DCONFIG_SINGLE_RECV_BUF +ARCH := arm +#CROSS_COMPILE := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/arm/v5t_le/bin/arm_v5t_le- +#KSRC := /home/cnsd4/Appro/mv_pro_5.0/montavista/pro/devkit/lsp/ti-davinci/linux-dm365 +CROSS_COMPILE := /opt/montavista/pro5.0/devkit/arm/v5t_le/bin/arm-linux- +KSRC:= /home/vivotek/lsp/DM365/kernel_platform/kernel/linux-2.6.18 +KERNELOUTPUT := ${PRODUCTDIR}/tmp +KVER := 2.6.18 +endif + +ifeq ($(CONFIG_PLATFORM_MOZART), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MOZART +ARCH := arm +CROSS_COMPILE := /home/vivotek/lsp/mozart3v2/Mozart3e_Toolchain/build_arm_nofpu/usr/bin/arm-linux- +KVER := $(shell uname -r) +KSRC:= /opt/Vivotek/lsp/mozart3v2/kernel_platform/kernel/mozart_kernel-1.17 +KERNELOUTPUT := /home/pink/sample/ODM/IP8136W-VINT/tmp/kernel +endif + +ifeq ($(CONFIG_PLATFORM_TEGRA3_CARDHU), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +# default setting for Android 4.1, 4.2 +EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +ARCH := arm +CROSS_COMPILE := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- +KSRC := /home/android_sdk/nvidia/tegra-16r3-partner-android-4.1_20120723/out/target/product/cardhu/obj/KERNEL +MODULE_NAME := wlan +endif + +ifeq ($(CONFIG_PLATFORM_TEGRA4_DALMORE), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +# default setting for Android 4.1, 4.2 +EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +ARCH := arm +CROSS_COMPILE := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- +KSRC := /home/android_sdk/nvidia/tegra-17r9-partner-android-4.2-dalmore_20130131/out/target/product/dalmore/obj/KERNEL +MODULE_NAME := wlan +endif + +ifeq ($(CONFIG_PLATFORM_ARM_TCC8900), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +ARCH := arm +CROSS_COMPILE := /home/android_sdk/Telechips/SDK_2304_20110613/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- +KSRC := /home/android_sdk/Telechips/SDK_2304_20110613/kernel +MODULE_NAME := wlan +endif + +ifeq ($(CONFIG_PLATFORM_ARM_TCC8920), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +ARCH := arm +CROSS_COMPILE := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- +KSRC := /home/android_sdk/Telechips/v12.06_r1-tcc-android-4.0.4/kernel +MODULE_NAME := wlan +endif + +ifeq ($(CONFIG_PLATFORM_ARM_TCC8920_JB42), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +# default setting for Android 4.1, 4.2 +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +ARCH := arm +CROSS_COMPILE := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- +KSRC := /home/android_sdk/Telechips/v13.03_r1-tcc-android-4.2.2_ds_patched/kernel +MODULE_NAME := wlan +endif + +ifeq ($(CONFIG_PLATFORM_ARM_RK2818), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS +ARCH := arm +CROSS_COMPILE := /usr/src/release_fae_version/toolchain/arm-eabi-4.4.0/bin/arm-eabi- +KSRC := /usr/src/release_fae_version/kernel25_A7_281x +MODULE_NAME := wlan +endif + +ifeq ($(CONFIG_PLATFORM_ARM_RK3188), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS +# default setting for Android 4.1, 4.2, 4.3, 4.4 +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +# default setting for Power control +EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC +EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN +# default setting for Special function +ARCH := arm +CROSS_COMPILE := /home/android_sdk/Rockchip/Rk3188/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- +KSRC := /home/android_sdk/Rockchip/Rk3188/kernel +MODULE_NAME := wlan +endif + +ifeq ($(CONFIG_PLATFORM_ARM_RK3066), y) +EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_RK3066 +EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 +ifeq ($(CONFIG_SDIO_HCI), y) +EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN +endif +EXTRA_CFLAGS += -fno-pic +ARCH := arm +CROSS_COMPILE := /home/android_sdk/Rockchip/rk3066_20130607/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi- +#CROSS_COMPILE := /home/android_sdk/Rockchip/Rk3066sdk/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi- +KSRC := /home/android_sdk/Rockchip/Rk3066sdk/kernel +MODULE_NAME :=wlan +endif + +ifeq ($(CONFIG_PLATFORM_ARM_URBETTER), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE +ARCH := arm +CROSS_COMPILE := /media/DATA-1/urbetter/arm-2009q3/bin/arm-none-linux-gnueabi- +KSRC := /media/DATA-1/urbetter/ics-urbetter/kernel +MODULE_NAME := wlan +endif + +ifeq ($(CONFIG_PLATFORM_ARM_TI_PANDA), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN #-DCONFIG_MINIMAL_MEMORY_USAGE +ARCH := arm +#CROSS_COMPILE := /media/DATA-1/aosp/ics-aosp_20111227/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- +#KSRC := /media/DATA-1/aosp/android-omap-panda-3.0_20120104 +CROSS_COMPILE := /media/DATA-1/android-4.0/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- +KSRC := /media/DATA-1/android-4.0/panda_kernel/omap +MODULE_NAME := wlan +endif + +ifeq ($(CONFIG_PLATFORM_MIPS_JZ4760), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_MINIMAL_MEMORY_USAGE +ARCH ?= mips +CROSS_COMPILE ?= /mnt/sdb5/Ingenic/Umido/mips-4.3/bin/mips-linux-gnu- +KSRC ?= /mnt/sdb5/Ingenic/Umido/kernel +endif + +ifeq ($(CONFIG_PLATFORM_SZEBOOK), y) +EXTRA_CFLAGS += -DCONFIG_BIG_ENDIAN +ARCH:=arm +CROSS_COMPILE:=/opt/crosstool2/bin/armeb-unknown-linux-gnueabi- +KVER:= 2.6.31.6 +KSRC:= ../code/linux-2.6.31.6-2020/ +endif + +#Add setting for MN10300 +ifeq ($(CONFIG_PLATFORM_MN10300), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_MN10300 +ARCH := mn10300 +CROSS_COMPILE := mn10300-linux- +KVER := 2.6.32.2 +KSRC := /home/winuser/work/Plat_sLD2T_V3010/usr/src/linux-2.6.32.2 +INSTALL_PREFIX := +endif + + +ifeq ($(CONFIG_PLATFORM_ARM_SUNxI), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUNxI +# default setting for Android 4.1, 4.2 +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT + +EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS +ifeq ($(CONFIG_USB_HCI), y) +EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX +_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o +endif +ifeq ($(CONFIG_SDIO_HCI), y) +# default setting for A10-EVB mmc0 +#EXTRA_CFLAGS += -DCONFIG_WITS_EVB_V13 +_PLATFORM_FILES += platform/platform_ARM_SUNxI_sdio.o +endif + +ARCH := arm +#CROSS_COMPILE := arm-none-linux-gnueabi- +CROSS_COMPILE=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/buildroot/output/external-toolchain/bin/arm-none-linux-gnueabi- +KVER := 3.0.8 +#KSRC:= ../lichee/linux-3.0/ +KSRC=/home/android_sdk/Allwinner/a10/android-jb42/lichee-jb42/linux-3.0 +endif + +ifeq ($(CONFIG_PLATFORM_ARM_SUN6I), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN6I +EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT +# default setting for Android 4.1, 4.2, 4.3, 4.4 +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION + +EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS +ifeq ($(CONFIG_USB_HCI), y) +EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX +_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o +endif +ifeq ($(CONFIG_SDIO_HCI), y) +# default setting for A31-EVB mmc0 +EXTRA_CFLAGS += -DCONFIG_A31_EVB +_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o +endif + +ARCH := arm +#Android-JB42 +#CROSS_COMPILE := /home/android_sdk/Allwinner/a31/android-jb42/lichee/buildroot/output/external-toolchain/bin/arm-linux-gnueabi- +#KSRC :=/home/android_sdk/Allwinner/a31/android-jb42/lichee/linux-3.3 +#ifeq ($(CONFIG_USB_HCI), y) +#MODULE_NAME := 8188eu_sw +#endif +# ==== Cross compile setting for kitkat-a3x_v4.5 ===== +CROSS_COMPILE := /home/android_sdk/Allwinner/a31/kitkat-a3x_v4.5/lichee/buildroot/output/external-toolchain/bin/arm-linux-gnueabi- +KSRC :=/home/android_sdk/Allwinner/a31/kitkat-a3x_v4.5/lichee/linux-3.3 +endif + +ifeq ($(CONFIG_PLATFORM_ARM_SUN7I), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN7I +EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT +# default setting for Android 4.1, 4.2, 4.3, 4.4 +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION + +EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS +ifeq ($(CONFIG_USB_HCI), y) +EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX +_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o +endif +ifeq ($(CONFIG_SDIO_HCI), y) +_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o +endif + +ARCH := arm +# ===Cross compile setting for Android 4.2 SDK === +#CROSS_COMPILE := /home/android_sdk/Allwinner/a20_evb/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- +#KSRC := /home/android_sdk/Allwinner/a20_evb/lichee/linux-3.3 +# ==== Cross compile setting for Android 4.3 SDK ===== +#CROSS_COMPILE := /home/android_sdk/Allwinner/a20/android-jb43/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- +#KSRC := /home/android_sdk/Allwinner/a20/android-jb43/lichee/linux-3.4 +# ==== Cross compile setting for kitkat-a20_v4.4 ===== +CROSS_COMPILE := /home/android_sdk/Allwinner/a20/kitkat-a20_v4.4/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- +KSRC := /home/android_sdk/Allwinner/a20/kitkat-a20_v4.4/lichee/linux-3.4 +endif + +ifeq ($(CONFIG_PLATFORM_ARM_SUN8I_W3P1), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I +EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I_W3P1 +EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT +# default setting for Android 4.1, 4.2 +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT + +EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS +ifeq ($(CONFIG_USB_HCI), y) +EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX +_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o +endif +ifeq ($(CONFIG_SDIO_HCI), y) +_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o +endif + +ARCH := arm +# ===Cross compile setting for Android 4.2 SDK === +#CROSS_COMPILE := /home/android_sdk/Allwinner/a23/android-jb42/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- +#KSRC :=/home/android_sdk/Allwinner/a23/android-jb42/lichee/linux-3.4 +# ===Cross compile setting for Android 4.4 SDK === +CROSS_COMPILE := /home/android_sdk/Allwinner/a23/android-kk44/lichee/out/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- +KSRC :=/home/android_sdk/Allwinner/a23/android-kk44/lichee/linux-3.4 +endif + +ifeq ($(CONFIG_PLATFORM_ARM_SUN8I_W5P1), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I +EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN8I_W5P1 +EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT +# default setting for Android 4.1, 4.2 +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT + +# Enable this for Android 5.0 +EXTRA_CFLAGS += -DCONFIG_RADIO_WORK + +EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS +ifeq ($(CONFIG_USB_HCI), y) +EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX +_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o +endif +ifeq ($(CONFIG_SDIO_HCI), y) +_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o +endif + +ARCH := arm +# ===Cross compile setting for Android L SDK === +CROSS_COMPILE := /home/android_sdk/Allwinner/a33/android-L/lichee/out/sun8iw5p1/android/common/buildroot/external-toolchain/bin/arm-linux-gnueabi- +KSRC :=/home/android_sdk/Allwinner/a33/android-L/lichee/linux-3.4 +endif + +ifeq ($(CONFIG_PLATFORM_ACTIONS_ATV5201), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ACTIONS_ATV5201 +EXTRA_CFLAGS += -DCONFIG_SDIO_DISABLE_RXFIFO_POLLING_LOOP +ARCH := mips +CROSS_COMPILE := mipsel-linux-gnu- +KVER := $(KERNEL_VER) +KSRC:= $(CFGDIR)/../../kernel/linux-$(KERNEL_VER) +endif + +ifeq ($(CONFIG_PLATFORM_ARM_RTD299X), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DUSB_XMITBUF_ALIGN_SZ=1024 -DUSB_PACKET_OFFSET_SZ=0 +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +ifeq ($(CONFIG_ANDROID), y) +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +# Enable this for Android 5.0 +EXTRA_CFLAGS += -DCONFIG_RADIO_WORK +endif +#ARCH, CROSS_COMPILE, KSRC,and MODDESTDIR are provided by external makefile +INSTALL_PREFIX := +endif + +ifeq ($(CONFIG_PLATFORM_HISILICON), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_HISILICON +ifeq ($(SUPPORT_CONCURRENT),y) +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +endif +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +ARCH := arm +ifeq ($(CROSS_COMPILE),) + CROSS_COMPILE = arm-hisiv200-linux- +endif +MODULE_NAME := rtl8192eu +ifeq ($(KSRC),) + KSRC := ../../../../../../kernel/linux-3.4.y +endif +endif + +# Platform setting +ifeq ($(CONFIG_PLATFORM_ARM_SPREADTRUM_6820), y) +ifeq ($(CONFIG_ANDROID_2X), y) +EXTRA_CFLAGS += -DANDROID_2X +endif +EXTRA_CFLAGS += -DCONFIG_PLATFORM_SPRD +EXTRA_CFLAGS += -DPLATFORM_SPREADTRUM_6820 +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +ifeq ($(RTL871X), rtl8188e) +EXTRA_CFLAGS += -DSOFTAP_PS_DURATION=50 +endif +ifeq ($(CONFIG_SDIO_HCI), y) +EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS +_PLATFORM_FILES += platform/platform_sprd_sdio.o +endif +endif + +ifeq ($(CONFIG_PLATFORM_ARM_SPREADTRUM_8810), y) +ifeq ($(CONFIG_ANDROID_2X), y) +EXTRA_CFLAGS += -DANDROID_2X +endif +EXTRA_CFLAGS += -DCONFIG_PLATFORM_SPRD +EXTRA_CFLAGS += -DPLATFORM_SPREADTRUM_8810 +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +ifeq ($(RTL871X), rtl8188e) +EXTRA_CFLAGS += -DSOFTAP_PS_DURATION=50 +endif +ifeq ($(CONFIG_SDIO_HCI), y) +EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS +_PLATFORM_FILES += platform/platform_sprd_sdio.o +endif +endif + +ifeq ($(CONFIG_PLATFORM_ARM_WMT), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +EXTRA_CFLAGS += -DCONFIG_PLATFORM_OPS +ifeq ($(CONFIG_SDIO_HCI), y) +_PLATFORM_FILES += platform/platform_ARM_WMT_sdio.o +endif +ARCH := arm +CROSS_COMPILE := /home/android_sdk/WonderMedia/wm8880-android4.4/toolchain/arm_201103_gcc4.5.2/mybin/arm_1103_le- +KSRC := /home/android_sdk/WonderMedia/wm8880-android4.4/kernel4.4/ +MODULE_NAME :=8189es_kk +endif + +ifeq ($(CONFIG_PLATFORM_RTK119X), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +#EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_SUN7I +EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT +# default setting for Android 4.1, 4.2 +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IFACE_NUMBER=3 +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +#EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION +EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION + +#EXTRA_CFLAGS += -DCONFIG_#PLATFORM_OPS +ifeq ($(CONFIG_USB_HCI), y) +EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX +#_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o +endif +ifeq ($(CONFIG_SDIO_HCI), y) +_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o +endif + +ARCH := arm + +# ==== Cross compile setting for Android 4.4 SDK ===== +#CROSS_COMPILE := arm-linux-gnueabihf- +KVER := 3.10.24 +#KSRC :=/home/android_sdk/Allwinner/a20/android-kitkat44/lichee/linux-3.4 +CROSS_COMPILE := /home/realtek/software_phoenix/phoenix/toolchain/usr/local/arm-2013.11/bin/arm-linux-gnueabihf- +KSRC := /home/realtek/software_phoenix/linux-kernel +MODULE_NAME := 8192eu + +endif + +ifeq ($(CONFIG_PLATFORM_RTK129X), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DRTK_129X_PLATFORM +EXTRA_CFLAGS += -DCONFIG_TRAFFIC_PROTECT +# default setting for Android 4.1, 4.2 +#EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +#EXTRA_CFLAGS += -DCONFIG_P2P_IPS -DCONFIG_QOS_OPTIMIZATION +EXTRA_CFLAGS += -DCONFIG_QOS_OPTIMIZATION +EXTRA_CFLAGS += -Wno-error=date-time + +# default setting for Android 7.0 +ifeq ($(RTK_ANDROID_VERSION), nougat) +EXTRA_CFLAGS += -DRTW_P2P_GROUP_INTERFACE=1 +endif +#EXTRA_CFLAGS += -DCONFIG_#PLATFORM_OPS +ifeq ($(CONFIG_USB_HCI), y) +EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX +#_PLATFORM_FILES += platform/platform_ARM_SUNxI_usb.o +endif +ifeq ($(CONFIG_SDIO_HCI), y) +_PLATFORM_FILES += platform/platform_ARM_SUNnI_sdio.o +endif + +ARCH := arm64 + +# ==== Cross compile setting for Android 4.4 SDK ===== +#CROSS_COMPILE := arm-linux-gnueabihf- +KVER := 4.1.10 +CROSS_COMPILE := $(CROSS) +KSRC := $(LINUX_KERNEL_PATH) +MODULE_NAME := 8822be +endif + +ifeq ($(CONFIG_PLATFORM_NOVATEK_NT72668), y) +EXTRA_CFLAGS += -DCONFIG_PLATFORM_NOVATEK_NT72668 +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_RX +EXTRA_CFLAGS += -DCONFIG_USE_USB_BUFFER_ALLOC_TX +ARCH ?= arm +CROSS_COMPILE := arm-linux-gnueabihf- +KVER := 3.8.0 +KSRC := /Custom/Novatek/TCL/linux-3.8_header +#KSRC := $(KERNELDIR) +endif + +ifeq ($(CONFIG_PLATFORM_ARM_TCC8930_JB42), y) +EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN +# default setting for Android 4.1, 4.2 +EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE +EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT +ARCH := arm +CROSS_COMPILE := /home/android_sdk/Telechips/v13.05_r1-tcc-android-4.2.2_tcc893x-evm_build/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi- +KSRC := /home/android_sdk/Telechips/v13.05_r1-tcc-android-4.2.2_tcc893x-evm_build/kernel +MODULE_NAME := wlan +endif + +ifeq ($(CONFIG_MULTIDRV), y) + +ifeq ($(CONFIG_SDIO_HCI), y) +MODULE_NAME := rtw_sdio +endif + +ifeq ($(CONFIG_USB_HCI), y) +MODULE_NAME := rtw_usb +endif + +ifeq ($(CONFIG_PCI_HCI), y) +MODULE_NAME := rtw_pci +endif + + +endif + +USER_MODULE_NAME ?= +ifneq ($(USER_MODULE_NAME),) +MODULE_NAME := $(USER_MODULE_NAME) +endif + +ifneq ($(KERNELRELEASE),) + +rtk_core := core/rtw_cmd.o \ + core/rtw_security.o \ + core/rtw_debug.o \ + core/rtw_io.o \ + core/rtw_ioctl_query.o \ + core/rtw_ioctl_set.o \ + core/rtw_ieee80211.o \ + core/rtw_mlme.o \ + core/rtw_mlme_ext.o \ + core/rtw_mi.o \ + core/rtw_wlan_util.o \ + core/rtw_vht.o \ + core/rtw_pwrctrl.o \ + core/rtw_rf.o \ + core/rtw_recv.o \ + core/rtw_sta_mgt.o \ + core/rtw_ap.o \ + core/rtw_xmit.o \ + core/rtw_p2p.o \ + core/rtw_tdls.o \ + core/rtw_br_ext.o \ + core/rtw_iol.o \ + core/rtw_sreset.o \ + core/rtw_btcoex_wifionly.o \ + core/rtw_btcoex.o \ + core/rtw_beamforming.o \ + core/rtw_odm.o \ + core/efuse/rtw_efuse.o + +ifeq ($(CONFIG_SDIO_HCI), y) +rtk_core += core/rtw_sdio.o +endif + +$(MODULE_NAME)-y += $(rtk_core) + +$(MODULE_NAME)-$(CONFIG_INTEL_WIDI) += core/rtw_intel_widi.o + +$(MODULE_NAME)-$(CONFIG_WAPI_SUPPORT) += core/rtw_wapi.o \ + core/rtw_wapi_sms4.o + +$(MODULE_NAME)-y += $(_OS_INTFS_FILES) +$(MODULE_NAME)-y += $(_HAL_INTFS_FILES) +$(MODULE_NAME)-y += $(_OUTSRC_FILES) +$(MODULE_NAME)-y += $(_PLATFORM_FILES) + +$(MODULE_NAME)-$(CONFIG_MP_INCLUDED) += core/rtw_mp.o + +ifeq ($(CONFIG_RTL8723B), y) +$(MODULE_NAME)-$(CONFIG_MP_INCLUDED)+= core/rtw_bt_mp.o +endif + +obj-$(CONFIG_RTL8188EU) := $(MODULE_NAME).o + +else + +export CONFIG_RTL8188EU = m + +all: modules + +modules: + $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KSRC) M=$(shell pwd) modules + +strip: + $(CROSS_COMPILE)strip $(MODULE_NAME).ko --strip-unneeded + +install: + install -p -m 644 $(MODULE_NAME).ko $(MODDESTDIR) + /sbin/depmod -a ${KVER} + +uninstall: + rm -f $(MODDESTDIR)/$(MODULE_NAME).ko + /sbin/depmod -a ${KVER} + +config_r: + @echo "make config" + /bin/bash script/Configure script/config.in + + +.PHONY: modules clean + +clean: + #$(MAKE) -C $(KSRC) M=$(shell pwd) clean + cd hal ; rm -fr */*/*/*.mod.c */*/*/*.mod */*/*/*.o */*/*/.*.cmd */*/*/*.ko + cd hal ; rm -fr */*/*.mod.c */*/*.mod */*/*.o */*/.*.cmd */*/*.ko + cd hal ; rm -fr */*.mod.c */*.mod */*.o */.*.cmd */*.ko + cd hal ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko + cd core/efuse ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko + cd core ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko + cd os_dep/linux ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko + cd os_dep ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko + cd platform ; rm -fr *.mod.c *.mod *.o .*.cmd *.ko + rm -fr Module.symvers ; rm -fr Module.markers ; rm -fr modules.order + rm -fr *.mod.c *.mod *.o .*.cmd *.ko *~ + rm -fr .tmp_versions .cache.mk +endif + diff --git a/linux-bsp/drivers/rtl8188eus/README.md b/linux-bsp/drivers/rtl8188eus/README.md new file mode 100644 index 0000000..8fe81e4 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/README.md @@ -0,0 +1,61 @@ +# Download +Downlink from https://github.com/quickreflex/rtl8188eus.git, 2019.08.19 + +# ChangeLog +1, Remove unused files/scripts +2, Update Makefile remove driver debug information "CONFIG_RTW_DEBUG = n" +3, Update Makefile support SAMA5D4 compile + + +# rtl8188eus +Wifi driver support for rtl8188eu, rtl8188eus and rtl8188etv chips and working under the new linux kernel (5.1.x). +More information about your wifi device can be found here: https://wikidevi.com. + +Compiling & Building +--------- +### Dependencies +To compile the driver, you need to have make and a compiler installed. In addition, +you must have the kernel headers installed. If you do not understand what this means, +consult your distro. if compile a new kernel, you will need to set two parameters +with make: KSRC=path_to_kernel_source and KVER=kernel_version. The same goes for installation. + +### Download +``` +git clone -b v5.2.2.4 https://github.com/quickreflex/rtl8188eus.git +cd rtl8188eu +``` + +### Compiling & Installing +``` +make all +make install +``` + +Or with DKMS +``` +dkms add . +dkms build 8188eu/1.0 +dkms install 8188eu/1.0 +``` + +Switch modes +--------- +### Supported interface modes +``` +* IBSS +* managed +* AP +* monitor +* P2P-client +* P2P-GO +``` +### For setting interface modes +``` +ifconfig wlan0 down +iw dev wlan0 set type managed +ifconfig wlan0 up +``` +### For setting TX power +``` +iw wlan0 set txpower fixed 1300 +``` diff --git a/linux-bsp/drivers/rtl8188eus/core/efuse/rtw_efuse.c b/linux-bsp/drivers/rtl8188eus/core/efuse/rtw_efuse.c new file mode 100644 index 0000000..cef3fea --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/efuse/rtw_efuse.c @@ -0,0 +1,2949 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_EFUSE_C_ + +#include <drv_types.h> +#include <hal_data.h> + +#include "../hal/efuse/efuse_mask.h" + +/*------------------------Define local variable------------------------------*/ +u8 fakeEfuseBank = {0}; +u32 fakeEfuseUsedBytes = {0}; +u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE] = {0}; +u8 fakeEfuseInitMap[EFUSE_MAX_MAP_LEN] = {0}; +u8 fakeEfuseModifiedMap[EFUSE_MAX_MAP_LEN] = {0}; + +u32 BTEfuseUsedBytes = {0}; +u8 BTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; +u8 BTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; +u8 BTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; + +u32 fakeBTEfuseUsedBytes = {0}; +u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE]; +u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN] = {0}; +u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN] = {0}; + +u8 maskfileBuffer[64]; +/*------------------------Define local variable------------------------------*/ +BOOLEAN rtw_file_efuse_IsMasked(PADAPTER pAdapter, u16 Offset) +{ + int r = Offset / 16; + int c = (Offset % 16) / 2; + int result = 0; + + if (pAdapter->registrypriv.boffefusemask) + return FALSE; + + if (c < 4) /* Upper double word */ + result = (maskfileBuffer[r] & (0x10 << c)); + else + result = (maskfileBuffer[r] & (0x01 << (c - 4))); + + return (result > 0) ? 0 : 1; +} + +BOOLEAN efuse_IsMasked(PADAPTER pAdapter, u16 Offset) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); + + if (pAdapter->registrypriv.boffefusemask) + return FALSE; + +#if DEV_BUS_TYPE == RT_USB_INTERFACE +#if defined(CONFIG_RTL8188E) + if (IS_HARDWARE_TYPE_8188E(pAdapter)) + return (IS_MASKED(8188E, _MUSB, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8812A) + if (IS_HARDWARE_TYPE_8812(pAdapter)) + return (IS_MASKED(8812A, _MUSB, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8821A) +#if 0 + if (IS_HARDWARE_TYPE_8811AU(pAdapter)) + return (IS_MASKED(8811A, _MUSB, Offset)) ? TRUE : FALSE; +#endif + if (IS_HARDWARE_TYPE_8821(pAdapter)) + return (IS_MASKED(8821A, _MUSB, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8192E) + if (IS_HARDWARE_TYPE_8192E(pAdapter)) + return (IS_MASKED(8192E, _MUSB, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8723B) + if (IS_HARDWARE_TYPE_8723B(pAdapter)) + return (IS_MASKED(8723B, _MUSB, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8703B) + if (IS_HARDWARE_TYPE_8703B(pAdapter)) + return (IS_MASKED(8703B, _MUSB, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8814A) + if (IS_HARDWARE_TYPE_8814A(pAdapter)) + return (IS_MASKED(8814A, _MUSB, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8188F) + if (IS_HARDWARE_TYPE_8188F(pAdapter)) + return (IS_MASKED(8188F, _MUSB, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8822B) + if (IS_HARDWARE_TYPE_8822B(pAdapter)) + return (IS_MASKED(8822B, _MUSB, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8723D) + if (IS_HARDWARE_TYPE_8723D(pAdapter)) + return (IS_MASKED(8723D, _MUSB, Offset)) ? TRUE : FALSE; +#endif + + /*#if defined(CONFIG_RTL8821C) + if (IS_HARDWARE_TYPE_8821C(pAdapter)) + return (IS_MASKED(8821C,_MUSB,Offset)) ? TRUE : FALSE; + #endif*/ + +#elif DEV_BUS_TYPE == RT_PCI_INTERFACE +#if defined(CONFIG_RTL8188E) + if (IS_HARDWARE_TYPE_8188E(pAdapter)) + return (IS_MASKED(8188E, _MPCIE, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8192E) + if (IS_HARDWARE_TYPE_8192E(pAdapter)) + return (IS_MASKED(8192E, _MPCIE, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8812A) + if (IS_HARDWARE_TYPE_8812(pAdapter)) + return (IS_MASKED(8812A, _MPCIE, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8821A) + if (IS_HARDWARE_TYPE_8821(pAdapter)) + return (IS_MASKED(8821A, _MPCIE, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8723B) + if (IS_HARDWARE_TYPE_8723B(pAdapter)) + return (IS_MASKED(8723B, _MPCIE, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8814A) + if (IS_HARDWARE_TYPE_8814A(pAdapter)) + return (IS_MASKED(8814A, _MPCIE, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8822B) + if (IS_HARDWARE_TYPE_8822B(pAdapter)) + return (IS_MASKED(8822B, _MPCIE, Offset)) ? TRUE : FALSE; +#endif + +#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE +#ifdef CONFIG_RTL8188E_SDIO + if (IS_HARDWARE_TYPE_8188E(pAdapter)) + return (IS_MASKED(8188E, _MSDIO, Offset)) ? TRUE : FALSE; +#endif +#ifdef CONFIG_RTL8188F_SDIO + if (IS_HARDWARE_TYPE_8188F(pAdapter)) + return (IS_MASKED(8188F, _MSDIO, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8821C) + if (IS_HARDWARE_TYPE_8821C(pAdapter)) + return (IS_MASKED(8821C, _MSDIO, Offset)) ? TRUE : FALSE; +#endif +#if defined(CONFIG_RTL8822B) + if (IS_HARDWARE_TYPE_8822B(pAdapter)) + return (IS_MASKED(8822B, _MSDIO, Offset)) ? TRUE : FALSE; +#endif +#endif + + return FALSE; +} + +void rtw_efuse_mask_array(PADAPTER pAdapter, u8 *pArray) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); + +#if DEV_BUS_TYPE == RT_USB_INTERFACE +#if defined(CONFIG_RTL8188E) + if (IS_HARDWARE_TYPE_8188E(pAdapter)) + GET_MASK_ARRAY(8188E, _MUSB, pArray); +#endif +#if defined(CONFIG_RTL8812A) + if (IS_HARDWARE_TYPE_8812(pAdapter)) + GET_MASK_ARRAY(8812A, _MUSB, pArray); +#endif +#if defined(CONFIG_RTL8821A) + if (IS_HARDWARE_TYPE_8821(pAdapter)) + GET_MASK_ARRAY(8821A, _MUSB, pArray); +#endif +#if defined(CONFIG_RTL8192E) + if (IS_HARDWARE_TYPE_8192E(pAdapter)) + GET_MASK_ARRAY(8192E, _MUSB, pArray); +#endif +#if defined(CONFIG_RTL8723B) + if (IS_HARDWARE_TYPE_8723B(pAdapter)) + GET_MASK_ARRAY(8723B, _MUSB, pArray); +#endif +#if defined(CONFIG_RTL8703B) + if (IS_HARDWARE_TYPE_8703B(pAdapter)) + GET_MASK_ARRAY(8703B, _MUSB, pArray); +#endif +#if defined(CONFIG_RTL8188F) + if (IS_HARDWARE_TYPE_8188F(pAdapter)) + GET_MASK_ARRAY(8188F, _MUSB, pArray); +#endif +#if defined(CONFIG_RTL8814A) + if (IS_HARDWARE_TYPE_8814A(pAdapter)) + GET_MASK_ARRAY(8814A, _MUSB, pArray); +#endif +#if defined(CONFIG_RTL8822B) + if (IS_HARDWARE_TYPE_8822B(pAdapter)) + GET_MASK_ARRAY(8822B, _MUSB, pArray); +#endif + /*#if defined(CONFIG_RTL8821C) + if (IS_HARDWARE_TYPE_8821C(pAdapter)) + GET_MASK_ARRAY(8821C,_MUSB,pArray); + #endif*/ +#elif DEV_BUS_TYPE == RT_PCI_INTERFACE +#if defined(CONFIG_RTL8188E) + if (IS_HARDWARE_TYPE_8188E(pAdapter)) + GET_MASK_ARRAY(8188E, _MPCIE, pArray); +#endif +#if defined(CONFIG_RTL8192E) + if (IS_HARDWARE_TYPE_8192E(pAdapter)) + GET_MASK_ARRAY(8192E, _MPCIE, pArray); +#endif +#if defined(CONFIG_RTL8812A) + if (IS_HARDWARE_TYPE_8812(pAdapter)) + GET_MASK_ARRAY(8812A, _MPCIE, pArray); +#endif +#if defined(CONFIG_RTL8821A) + if (IS_HARDWARE_TYPE_8821(pAdapter)) + GET_MASK_ARRAY(8821A, _MPCIE, pArray); +#endif +#if defined(CONFIG_RTL8723B) + if (IS_HARDWARE_TYPE_8723B(pAdapter)) + GET_MASK_ARRAY(8723B, _MPCIE, pArray); +#endif +#if defined(CONFIG_RTL8814A) + if (IS_HARDWARE_TYPE_8814A(pAdapter)) + GET_MASK_ARRAY(8814A, _MPCIE, pArray); +#endif +#if defined(CONFIG_RTL8822B) + if (IS_HARDWARE_TYPE_8822B(pAdapter)) + GET_MASK_ARRAY(8822B, _MPCIE, pArray); +#endif +#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE +#if defined(CONFIG_RTL8188E) + if (IS_HARDWARE_TYPE_8188E(pAdapter)) + GET_MASK_ARRAY(8188E, _MSDIO, pArray); +#endif +#if defined(CONFIG_RTL8188F) + if (IS_HARDWARE_TYPE_8188F(pAdapter)) + GET_MASK_ARRAY(8188F, _MSDIO, pArray); +#endif +#if defined(CONFIG_RTL8821C) + if (IS_HARDWARE_TYPE_8821C(pAdapter)) + GET_MASK_ARRAY(8821C , _MSDIO, pArray); +#endif +#if defined(CONFIG_RTL8822B) + if (IS_HARDWARE_TYPE_8822B(pAdapter)) + GET_MASK_ARRAY(8822B , _MSDIO, pArray); +#endif +#endif /*#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE*/ +} + +u16 rtw_get_efuse_mask_arraylen(PADAPTER pAdapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + +#if DEV_BUS_TYPE == RT_USB_INTERFACE +#if defined(CONFIG_RTL8188E) + if (IS_HARDWARE_TYPE_8188E(pAdapter)) + return GET_MASK_ARRAY_LEN(8188E, _MUSB); +#endif +#if defined(CONFIG_RTL8812A) + if (IS_HARDWARE_TYPE_8812(pAdapter)) + return GET_MASK_ARRAY_LEN(8812A, _MUSB); +#endif +#if defined(CONFIG_RTL8821A) + if (IS_HARDWARE_TYPE_8821(pAdapter)) + return GET_MASK_ARRAY_LEN(8821A, _MUSB); +#endif +#if defined(CONFIG_RTL8192E) + if (IS_HARDWARE_TYPE_8192E(pAdapter)) + return GET_MASK_ARRAY_LEN(8192E, _MUSB); +#endif +#if defined(CONFIG_RTL8723B) + if (IS_HARDWARE_TYPE_8723B(pAdapter)) + return GET_MASK_ARRAY_LEN(8723B, _MUSB); +#endif +#if defined(CONFIG_RTL8703B) + if (IS_HARDWARE_TYPE_8703B(pAdapter)) + return GET_MASK_ARRAY_LEN(8703B, _MUSB); +#endif +#if defined(CONFIG_RTL8188F) + if (IS_HARDWARE_TYPE_8188F(pAdapter)) + return GET_MASK_ARRAY_LEN(8188F, _MUSB); +#endif +#if defined(CONFIG_RTL8814A) + if (IS_HARDWARE_TYPE_8814A(pAdapter)) + return GET_MASK_ARRAY_LEN(8814A, _MUSB); +#endif +#if defined(CONFIG_RTL8822B) + if (IS_HARDWARE_TYPE_8822B(pAdapter)) + return GET_MASK_ARRAY_LEN(8822B, _MUSB); +#endif + /*#if defined(CONFIG_RTL8821C) + if (IS_HARDWARE_TYPE_8821C(pAdapter)) + return GET_MASK_ARRAY_LEN(8821C,_MUSB); + #endif*/ +#elif DEV_BUS_TYPE == RT_PCI_INTERFACE +#if defined(CONFIG_RTL8188E) + if (IS_HARDWARE_TYPE_8188E(pAdapter)) + return GET_MASK_ARRAY_LEN(8188E, _MPCIE); +#endif +#if defined(CONFIG_RTL8192E) + if (IS_HARDWARE_TYPE_8192E(pAdapter)) + return GET_MASK_ARRAY_LEN(8192E, _MPCIE); +#endif +#if defined(CONFIG_RTL8812A) + if (IS_HARDWARE_TYPE_8812(pAdapter)) + return GET_MASK_ARRAY_LEN(8812A, _MPCIE); +#endif +#if defined(CONFIG_RTL8821A) + if (IS_HARDWARE_TYPE_8821(pAdapter)) + return GET_MASK_ARRAY_LEN(8821A, _MPCIE); +#endif +#if defined(CONFIG_RTL8723B) + if (IS_HARDWARE_TYPE_8723B(pAdapter)) + return GET_MASK_ARRAY_LEN(8723B, _MPCIE); +#endif +#if defined(CONFIG_RTL8814A) + if (IS_HARDWARE_TYPE_8814A(pAdapter)) + return GET_MASK_ARRAY_LEN(8814A, _MPCIE); +#endif +#if defined(CONFIG_RTL8822B) + if (IS_HARDWARE_TYPE_8822B(pAdapter)) + return GET_MASK_ARRAY_LEN(8822B, _MPCIE); +#endif +#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE +#if defined(CONFIG_RTL8188E) + if (IS_HARDWARE_TYPE_8188E(pAdapter)) + return GET_MASK_ARRAY_LEN(8188E, _MSDIO); +#endif +#if defined(CONFIG_RTL8188F) + if (IS_HARDWARE_TYPE_8188F(pAdapter)) + return GET_MASK_ARRAY_LEN(8188F, _MSDIO); +#endif +#if defined(CONFIG_RTL8821C) + if (IS_HARDWARE_TYPE_8821C(pAdapter)) + return GET_MASK_ARRAY_LEN(8821C, _MSDIO); +#endif +#if defined(CONFIG_RTL8822B) + if (IS_HARDWARE_TYPE_8822B(pAdapter)) + return GET_MASK_ARRAY_LEN(8822B, _MSDIO); +#endif +#endif + return 0; +} + +u8 rtw_efuse_mask_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) +{ + u8 ret = _SUCCESS; + u16 mapLen = 0, i = 0; + + EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); + + ret = rtw_efuse_map_read(padapter, addr, cnts , data); + + if (padapter->registrypriv.boffefusemask == 0) { + + for (i = 0; i < cnts; i++) { + if (padapter->registrypriv.bFileMaskEfuse == _TRUE) { + if (rtw_file_efuse_IsMasked(padapter, addr + i)) /*use file efuse mask.*/ + data[i] = 0xff; + } else { + /*RTW_INFO(" %s , data[%d] = %x\n", __func__, i, data[i]);*/ + if (efuse_IsMasked(padapter, addr + i)) { + data[i] = 0xff; + /*RTW_INFO(" %s ,mask data[%d] = %x\n", __func__, i, data[i]);*/ + } + } + } + + } + return ret; + +} + + +#ifdef RTW_HALMAC +#include "../../hal/hal_halmac.h" + +void Efuse_PowerSwitch(PADAPTER adapter, u8 write, u8 pwrstate) +{ +} + +void BTEfuse_PowerSwitch(PADAPTER adapter, u8 write, u8 pwrstate) +{ +} + +u8 efuse_GetCurrentSize(PADAPTER adapter, u16 *size) +{ + *size = 0; + + return _FAIL; +} + +u16 efuse_GetMaxSize(PADAPTER adapter) +{ + struct dvobj_priv *d; + u32 size = 0; + int err; + + d = adapter_to_dvobj(adapter); + err = rtw_halmac_get_physical_efuse_size(d, &size); + if (err) + return 0; + + return size; +} + +u16 efuse_GetavailableSize(PADAPTER adapter) +{ + struct dvobj_priv *d; + u32 size = 0; + int err; + + d = adapter_to_dvobj(adapter); + err = rtw_halmac_get_available_efuse_size(d, &size); + if (err) + return 0; + + return size; +} + + +u8 efuse_bt_GetCurrentSize(PADAPTER adapter, u16 *usesize) +{ + u8 *efuse_map; + + *usesize = 0; + efuse_map = rtw_malloc(EFUSE_BT_MAP_LEN); + if (efuse_map == NULL) { + RTW_DBG("%s: malloc FAIL\n", __FUNCTION__); + return _FAIL; + } + + /* for get bt phy efuse last use byte */ + hal_ReadEFuse_BT_logic_map(adapter, 0x00, EFUSE_BT_MAP_LEN, efuse_map); + *usesize = fakeBTEfuseUsedBytes; + + if (efuse_map) + rtw_mfree(efuse_map, EFUSE_BT_MAP_LEN); + + return _SUCCESS; +} + +u16 efuse_bt_GetMaxSize(PADAPTER adapter) +{ + return EFUSE_BT_REAL_CONTENT_LEN; +} + +void EFUSE_GetEfuseDefinition(PADAPTER adapter, u8 efusetype, u8 type, void *out, BOOLEAN test) +{ + struct dvobj_priv *d; + u32 v32 = 0; + + + d = adapter_to_dvobj(adapter); + + if (adapter->hal_func.EFUSEGetEfuseDefinition) { + adapter->hal_func.EFUSEGetEfuseDefinition(adapter, efusetype, type, out, test); + return; + } + + if (EFUSE_WIFI == efusetype) { + switch (type) { + case TYPE_EFUSE_MAP_LEN: + rtw_halmac_get_logical_efuse_size(d, &v32); + *(u16 *)out = (u16)v32; + return; + + case TYPE_EFUSE_REAL_CONTENT_LEN: + rtw_halmac_get_physical_efuse_size(d, &v32); + *(u16 *)out = (u16)v32; + return; + } + } else if (EFUSE_BT == efusetype) { + switch (type) { + case TYPE_EFUSE_MAP_LEN: + *(u16 *)out = EFUSE_BT_MAP_LEN; + return; + + case TYPE_EFUSE_REAL_CONTENT_LEN: + *(u16 *)out = EFUSE_BT_REAL_CONTENT_LEN; + return; + } + } +} + +/* + * read/write raw efuse data + */ +u8 rtw_efuse_access(PADAPTER adapter, u8 write, u16 addr, u16 cnts, u8 *data) +{ + struct dvobj_priv *d; + u8 *efuse = NULL; + u32 size, i; + int err; + + + d = adapter_to_dvobj(adapter); + err = rtw_halmac_get_physical_efuse_size(d, &size); + if (err) + size = EFUSE_MAX_SIZE; + + if ((addr + cnts) > size) + return _FAIL; + + if (_TRUE == write) { + err = rtw_halmac_write_physical_efuse(d, addr, cnts, data); + if (err) + return _FAIL; + } else { + if (cnts > 16) + efuse = rtw_zmalloc(size); + + if (efuse) { + err = rtw_halmac_read_physical_efuse_map(d, efuse, size); + if (err) { + rtw_mfree(efuse, size); + return _FAIL; + } + + _rtw_memcpy(data, efuse + addr, cnts); + rtw_mfree(efuse, size); + } else { + err = rtw_halmac_read_physical_efuse(d, addr, cnts, data); + if (err) + return _FAIL; + } + } + + return _SUCCESS; +} + +static inline void dump_buf(u8 *buf, u32 len) +{ + u32 i; + + RTW_INFO("-----------------Len %d----------------\n", len); + for (i = 0; i < len; i++) + printk("%2.2x-", *(buf + i)); + printk("\n"); +} + +/* + * read/write raw efuse data + */ +u8 rtw_efuse_bt_access(PADAPTER adapter, u8 write, u16 addr, u16 cnts, u8 *data) +{ + struct dvobj_priv *d; + u8 *efuse = NULL; + u32 size, i; + int err = _FAIL; + + + d = adapter_to_dvobj(adapter); + + size = EFUSE_BT_REAL_CONTENT_LEN; + + if ((addr + cnts) > size) + return _FAIL; + + if (_TRUE == write) { + err = rtw_halmac_write_bt_physical_efuse(d, addr, cnts, data); + if (err == -1) { + RTW_ERR("%s: rtw_halmac_write_bt_physical_efuse fail!\n", __FUNCTION__); + return _FAIL; + } + RTW_INFO("%s: rtw_halmac_write_bt_physical_efuse OK! data 0x%x\n", __FUNCTION__, *data); + } else { + efuse = rtw_zmalloc(size); + + if (efuse) { + err = rtw_halmac_read_bt_physical_efuse_map(d, efuse, size); + + if (err == -1) { + RTW_ERR("%s: rtw_halmac_read_bt_physical_efuse_map fail!\n", __FUNCTION__); + rtw_mfree(efuse, size); + return _FAIL; + } + dump_buf(efuse + addr, cnts); + + _rtw_memcpy(data, efuse + addr, cnts); + + RTW_INFO("%s: rtw_halmac_read_bt_physical_efuse_map ok! data 0x%x\n", __FUNCTION__, *data); + rtw_mfree(efuse, size); + } + } + + return _SUCCESS; +} + +u8 rtw_efuse_map_read(PADAPTER adapter, u16 addr, u16 cnts, u8 *data) +{ + struct dvobj_priv *d; + u8 *efuse = NULL; + u32 size, i; + int err; + + + d = adapter_to_dvobj(adapter); + err = rtw_halmac_get_logical_efuse_size(d, &size); + if (err) + return _FAIL; + + /* size error handle */ + if ((addr + cnts) > size) { + if (addr < size) + cnts = size - addr; + else + return _FAIL; + } + + if (cnts > 16) + efuse = rtw_zmalloc(size); + + if (efuse) { + err = rtw_halmac_read_logical_efuse_map(d, efuse, size); + if (err) { + rtw_mfree(efuse, size); + return _FAIL; + } + + _rtw_memcpy(data, efuse + addr, cnts); + rtw_mfree(efuse, size); + } else { + err = rtw_halmac_read_logical_efuse(d, addr, cnts, data); + if (err) + return _FAIL; + } + + return _SUCCESS; +} + +u8 rtw_efuse_map_write(PADAPTER adapter, u16 addr, u16 cnts, u8 *data) +{ + struct dvobj_priv *d; + u8 *efuse = NULL; + u32 size, i; + int err; + u8 mask_buf[64] = ""; + u16 mask_len = sizeof(u8) * rtw_get_efuse_mask_arraylen(adapter); + + d = adapter_to_dvobj(adapter); + err = rtw_halmac_get_logical_efuse_size(d, &size); + if (err) + return _FAIL; + + if ((addr + cnts) > size) + return _FAIL; + + efuse = rtw_zmalloc(size); + if (!efuse) + return _FAIL; + + err = rtw_halmac_read_logical_efuse_map(d, efuse, size); + if (err) { + rtw_mfree(efuse, size); + return _FAIL; + } + + _rtw_memcpy(efuse + addr, data, cnts); + + if (adapter->registrypriv.boffefusemask == 0) { + RTW_INFO("Use mask Array Len: %d\n", mask_len); + + if (mask_len != 0) { + if (adapter->registrypriv.bFileMaskEfuse == _TRUE) + _rtw_memcpy(mask_buf, maskfileBuffer, mask_len); + else + rtw_efuse_mask_array(adapter, mask_buf); + + err = rtw_halmac_write_logical_efuse_map(d, efuse, size, mask_buf, mask_len); + } else + err = rtw_halmac_write_logical_efuse_map(d, efuse, size, NULL, 0); + } else { + _rtw_memset(mask_buf, 0xFF, sizeof(mask_buf)); + RTW_INFO("Efuse mask off\n"); + err = rtw_halmac_write_logical_efuse_map(d, efuse, size, mask_buf, size/16); + } + + if (err) { + rtw_mfree(efuse, size); + return _FAIL; + } + + rtw_mfree(efuse, size); + + return _SUCCESS; +} + +int Efuse_PgPacketRead(PADAPTER adapter, u8 offset, u8 *data, BOOLEAN test) +{ + return _FALSE; +} + +int Efuse_PgPacketWrite(PADAPTER adapter, u8 offset, u8 word_en, u8 *data, BOOLEAN test) +{ + return _FALSE; +} + +u8 rtw_BT_efuse_map_read(PADAPTER adapter, u16 addr, u16 cnts, u8 *data) +{ + hal_ReadEFuse_BT_logic_map(adapter,addr, cnts, data); + + return _SUCCESS; +} + +u8 rtw_BT_efuse_map_write(PADAPTER adapter, u16 addr, u16 cnts, u8 *data) +{ +#define RT_ASSERT_RET(expr) \ + if (!(expr)) { \ + printk("Assertion failed! %s at ......\n", #expr); \ + printk(" ......%s,%s, line=%d\n",__FILE__, __FUNCTION__, __LINE__); \ + return _FAIL; \ + } + + u8 offset, word_en; + u8 *map; + u8 newdata[PGPKT_DATA_SIZE]; + s32 i = 0, j = 0, idx; + u8 ret = _SUCCESS; + u16 mapLen = 1024; + + if ((addr + cnts) > mapLen) + return _FAIL; + + RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); /* have to be 8 byte alignment */ + RT_ASSERT_RET((mapLen & 0x7) == 0); /* have to be PGPKT_DATA_SIZE alignment for memcpy */ + + map = rtw_zmalloc(mapLen); + if (map == NULL) + return _FAIL; + + ret = rtw_BT_efuse_map_read(adapter, 0, mapLen, map); + if (ret == _FAIL) + goto exit; + RTW_INFO("OFFSET\tVALUE(hex)\n"); + for (i = 0; i < mapLen; i += 16) { /* set 512 because the iwpriv's extra size have limit 0x7FF */ + RTW_INFO("0x%03x\t", i); + for (j = 0; j < 8; j++) + RTW_INFO("%02X ", map[i + j]); + RTW_INFO("\t"); + for (; j < 16; j++) + RTW_INFO("%02X ", map[i + j]); + RTW_INFO("\n"); + } + RTW_INFO("\n"); + + idx = 0; + offset = (addr >> 3); + while (idx < cnts) { + word_en = 0xF; + j = (addr + idx) & 0x7; + _rtw_memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE); + for (i = j; i < PGPKT_DATA_SIZE && idx < cnts; i++, idx++) { + if (data[idx] != map[addr + idx]) { + word_en &= ~BIT(i >> 1); + newdata[i] = data[idx]; + } + } + + if (word_en != 0xF) { + ret = EfusePgPacketWrite_BT(adapter, offset, word_en, newdata, _FALSE); + RTW_INFO("offset=%x\n", offset); + RTW_INFO("word_en=%x\n", word_en); + RTW_INFO("%s: data=", __FUNCTION__); + for (i = 0; i < PGPKT_DATA_SIZE; i++) + RTW_INFO("0x%02X ", newdata[i]); + RTW_INFO("\n"); + if (ret == _FAIL) + break; + } + offset++; + } +exit: + rtw_mfree(map, mapLen); + return _SUCCESS; +} + +VOID hal_ReadEFuse_BT_logic_map( + PADAPTER padapter, + u16 _offset, + u16 _size_byte, + u8 *pbuf +) +{ + + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; + + u8 *efuseTbl, *phyefuse; + u8 bank; + u16 eFuse_Addr = 0; + u8 efuseHeader, efuseExtHdr, efuseData; + u8 offset, wden; + u16 i, total, used; + u8 efuse_usage; + + + /* */ + /* Do NOT excess total size of EFuse table. Added by Roger, 2008.11.10. */ + /* */ + if ((_offset + _size_byte) > EFUSE_BT_MAP_LEN) { + RTW_INFO("%s: Invalid offset(%#x) with read bytes(%#x)!!\n", __FUNCTION__, _offset, _size_byte); + return; + } + + efuseTbl = rtw_malloc(EFUSE_BT_MAP_LEN); + phyefuse = rtw_malloc(EFUSE_BT_REAL_CONTENT_LEN); + if (efuseTbl == NULL || phyefuse == NULL) { + RTW_INFO("%s: efuseTbl or phyefuse malloc fail!\n", __FUNCTION__); + goto exit; + } + + /* 0xff will be efuse default value instead of 0x00. */ + _rtw_memset(efuseTbl, 0xFF, EFUSE_BT_MAP_LEN); + _rtw_memset(phyefuse, 0xFF, EFUSE_BT_REAL_CONTENT_LEN); + + if (rtw_efuse_bt_access(padapter, _FALSE, 0, EFUSE_BT_REAL_CONTENT_LEN, phyefuse)) + dump_buf(phyefuse, EFUSE_BT_REAL_BANK_CONTENT_LEN); + + total = BANK_NUM; + for (bank = 1; bank <= total; bank++) { /* 8723d Max bake 0~2 */ + eFuse_Addr = 0; + + while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) { + /* ReadEFuseByte(padapter, eFuse_Addr++, &efuseHeader, bPseudoTest); */ + efuseHeader = phyefuse[eFuse_Addr++]; + + if (efuseHeader == 0xFF) + break; + RTW_INFO("%s: efuse[%#X]=0x%02x (header)\n", __FUNCTION__, (((bank - 1) * EFUSE_BT_REAL_CONTENT_LEN) + eFuse_Addr - 1), efuseHeader); + + /* Check PG header for section num. */ + if (EXT_HEADER(efuseHeader)) { /* extended header */ + offset = GET_HDR_OFFSET_2_0(efuseHeader); + RTW_INFO("%s: extended header offset_2_0=0x%X\n", __FUNCTION__, offset); + + /* ReadEFuseByte(padapter, eFuse_Addr++, &efuseExtHdr, bPseudoTest); */ + efuseExtHdr = phyefuse[eFuse_Addr++]; + + RTW_INFO("%s: efuse[%#X]=0x%02x (ext header)\n", __FUNCTION__, (((bank - 1) * EFUSE_BT_REAL_CONTENT_LEN) + eFuse_Addr - 1), efuseExtHdr); + if (ALL_WORDS_DISABLED(efuseExtHdr)) + continue; + + offset |= ((efuseExtHdr & 0xF0) >> 1); + wden = (efuseExtHdr & 0x0F); + } else { + offset = ((efuseHeader >> 4) & 0x0f); + wden = (efuseHeader & 0x0f); + } + + if (offset < EFUSE_BT_MAX_SECTION) { + u16 addr; + + /* Get word enable value from PG header */ + RTW_INFO("%s: Offset=%d Worden=%#X\n", __FUNCTION__, offset, wden); + + addr = offset * PGPKT_DATA_SIZE; + for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) { + /* Check word enable condition in the section */ + if (!(wden & (0x01 << i))) { + efuseData = 0; + /* ReadEFuseByte(padapter, eFuse_Addr++, &efuseData, bPseudoTest); */ + efuseData = phyefuse[eFuse_Addr++]; + + RTW_INFO("%s: efuse[%#X]=0x%02X\n", __FUNCTION__, eFuse_Addr - 1, efuseData); + efuseTbl[addr] = efuseData; + + efuseData = 0; + /* ReadEFuseByte(padapter, eFuse_Addr++, &efuseData, bPseudoTest); */ + efuseData = phyefuse[eFuse_Addr++]; + + RTW_INFO("%s: efuse[%#X]=0x%02X\n", __FUNCTION__, eFuse_Addr - 1, efuseData); + efuseTbl[addr + 1] = efuseData; + } + addr += 2; + } + } else { + RTW_INFO("%s: offset(%d) is illegal!!\n", __FUNCTION__, offset); + eFuse_Addr += Efuse_CalculateWordCnts(wden) * 2; + } + } + + if ((eFuse_Addr - 1) < total) { + RTW_INFO("%s: bank(%d) data end at %#x\n", __FUNCTION__, bank, eFuse_Addr - 1); + break; + } + } + + /* switch bank back to bank 0 for later BT and wifi use. */ + //hal_EfuseSwitchToBank(padapter, 0, bPseudoTest); + + /* Copy from Efuse map to output pointer memory!!! */ + for (i = 0; i < _size_byte; i++) + pbuf[i] = efuseTbl[_offset + i]; + /* Calculate Efuse utilization */ + total = EFUSE_BT_REAL_BANK_CONTENT_LEN; + + used = eFuse_Addr - 1; + + if (total) + efuse_usage = (u8)((used * 100) / total); + else + efuse_usage = 100; + + fakeBTEfuseUsedBytes = used; + RTW_INFO("%s: BTEfuseUsed last Bytes = %#x\n", __FUNCTION__, fakeBTEfuseUsedBytes); + +exit: + if (efuseTbl) + rtw_mfree(efuseTbl, EFUSE_BT_MAP_LEN); + if (phyefuse) + rtw_mfree(phyefuse, EFUSE_BT_REAL_BANK_CONTENT_LEN); +} + + +static u8 hal_EfusePartialWriteCheck( + PADAPTER padapter, + u8 efuseType, + u16 *pAddr, + PPGPKT_STRUCT pTargetPkt, + u8 bPseudoTest) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; + u8 bRet = _FALSE; + u16 startAddr = 0, efuse_max_available_len = EFUSE_BT_REAL_BANK_CONTENT_LEN, efuse_max = EFUSE_BT_REAL_BANK_CONTENT_LEN; + u8 efuse_data = 0; + + startAddr = (u16)fakeBTEfuseUsedBytes; + + startAddr %= efuse_max; + RTW_INFO("%s: startAddr=%#X\n", __FUNCTION__, startAddr); + + while (1) { + if (startAddr >= efuse_max_available_len) { + bRet = _FALSE; + RTW_INFO("%s: startAddr(%d) >= efuse_max_available_len(%d)\n", + __FUNCTION__, startAddr, efuse_max_available_len); + break; + } + if (rtw_efuse_bt_access(padapter, _FALSE, startAddr, 1, &efuse_data)&& (efuse_data != 0xFF)) { + bRet = _FALSE; + RTW_INFO("%s: Something Wrong! last bytes(%#X=0x%02X) is not 0xFF\n", + __FUNCTION__, startAddr, efuse_data); + break; + } else { + /* not used header, 0xff */ + *pAddr = startAddr; + /* RTW_INFO("%s: Started from unused header offset=%d\n", __FUNCTION__, startAddr)); */ + bRet = _TRUE; + break; + } + } + + return bRet; +} + + +static u8 hal_EfusePgPacketWrite2ByteHeader( + PADAPTER padapter, + u8 efuseType, + u16 *pAddr, + PPGPKT_STRUCT pTargetPkt, + u8 bPseudoTest) +{ + u16 efuse_addr, efuse_max_available_len = EFUSE_BT_REAL_BANK_CONTENT_LEN; + u8 pg_header = 0, tmp_header = 0; + u8 repeatcnt = 0; + + /* RTW_INFO("%s\n", __FUNCTION__); */ + + efuse_addr = *pAddr; + if (efuse_addr >= efuse_max_available_len) { + RTW_INFO("%s: addr(%d) over avaliable(%d)!!\n", __FUNCTION__, efuse_addr, efuse_max_available_len); + return _FALSE; + } + + pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F; + /* RTW_INFO("%s: pg_header=0x%x\n", __FUNCTION__, pg_header); */ + + do { + + rtw_efuse_bt_access(padapter, _TRUE, efuse_addr, 1, &pg_header); + rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &tmp_header); + + if (tmp_header != 0xFF) + break; + if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { + RTW_INFO("%s: Repeat over limit for pg_header!!\n", __FUNCTION__); + return _FALSE; + } + } while (1); + + if (tmp_header != pg_header) { + RTW_ERR("%s: PG Header Fail!!(pg=0x%02X read=0x%02X)\n", __FUNCTION__, pg_header, tmp_header); + return _FALSE; + } + + /* to write ext_header */ + efuse_addr++; + pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en; + + do { + rtw_efuse_bt_access(padapter, _TRUE, efuse_addr, 1, &pg_header); + rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &tmp_header); + + if (tmp_header != 0xFF) + break; + if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { + RTW_INFO("%s: Repeat over limit for ext_header!!\n", __FUNCTION__); + return _FALSE; + } + } while (1); + + if (tmp_header != pg_header) { /* offset PG fail */ + RTW_ERR("%s: PG EXT Header Fail!!(pg=0x%02X read=0x%02X)\n", __FUNCTION__, pg_header, tmp_header); + return _FALSE; + } + + *pAddr = efuse_addr; + + return _TRUE; +} + + +static u8 hal_EfusePgPacketWrite1ByteHeader( + PADAPTER pAdapter, + u8 efuseType, + u16 *pAddr, + PPGPKT_STRUCT pTargetPkt, + u8 bPseudoTest) +{ + u8 bRet = _FALSE; + u8 pg_header = 0, tmp_header = 0; + u16 efuse_addr = *pAddr; + u8 repeatcnt = 0; + + + /* RTW_INFO("%s\n", __FUNCTION__); */ + pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en; + + do { + rtw_efuse_bt_access(pAdapter, _TRUE, efuse_addr, 1, &pg_header); + rtw_efuse_bt_access(pAdapter, _FALSE, efuse_addr, 1, &tmp_header); + + if (tmp_header != 0xFF) + break; + if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) { + RTW_INFO("%s: Repeat over limit for pg_header!!\n", __FUNCTION__); + return _FALSE; + } + } while (1); + + if (tmp_header != pg_header) { + RTW_ERR("%s: PG Header Fail!!(pg=0x%02X read=0x%02X)\n", __FUNCTION__, pg_header, tmp_header); + return _FALSE; + } + + *pAddr = efuse_addr; + + return _TRUE; +} + +static u8 hal_EfusePgPacketWriteHeader( + PADAPTER padapter, + u8 efuseType, + u16 *pAddr, + PPGPKT_STRUCT pTargetPkt, + u8 bPseudoTest) +{ + u8 bRet = _FALSE; + + if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE) + bRet = hal_EfusePgPacketWrite2ByteHeader(padapter, efuseType, pAddr, pTargetPkt, bPseudoTest); + else + bRet = hal_EfusePgPacketWrite1ByteHeader(padapter, efuseType, pAddr, pTargetPkt, bPseudoTest); + + return bRet; +} + + +static u8 +Hal_EfuseWordEnableDataWrite( + PADAPTER padapter, + u16 efuse_addr, + u8 word_en, + u8 *data, + u8 bPseudoTest) +{ + u16 tmpaddr = 0; + u16 start_addr = efuse_addr; + u8 badworden = 0x0F; + u8 tmpdata[PGPKT_DATA_SIZE]; + + + /* RTW_INFO("%s: efuse_addr=%#x word_en=%#x\n", __FUNCTION__, efuse_addr, word_en); */ + _rtw_memset(tmpdata, 0xFF, PGPKT_DATA_SIZE); + + if (!(word_en & BIT(0))) { + tmpaddr = start_addr; + rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[0]); + rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[1]); + rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[0]); + rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[1]); + if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) + badworden &= (~BIT(0)); + } + if (!(word_en & BIT(1))) { + tmpaddr = start_addr; + rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[2]); + rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[3]); + rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[2]); + rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[3]); + if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) + badworden &= (~BIT(1)); + } + if (!(word_en & BIT(2))) { + tmpaddr = start_addr; + rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[4]); + rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[5]); + rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[4]); + rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[5]); + if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) + badworden &= (~BIT(2)); + } + if (!(word_en & BIT(3))) { + tmpaddr = start_addr; + rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[6]); + rtw_efuse_bt_access(padapter, _TRUE, start_addr++, 1, &data[7]); + rtw_efuse_bt_access(padapter, _FALSE, tmpaddr, 1, &tmpdata[6]); + rtw_efuse_bt_access(padapter, _FALSE, tmpaddr + 1, 1, &tmpdata[7]); + + if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) + badworden &= (~BIT(3)); + } + + return badworden; +} + +static void +hal_EfuseConstructPGPkt( + u8 offset, + u8 word_en, + u8 *pData, + PPGPKT_STRUCT pTargetPkt) +{ + _rtw_memset(pTargetPkt->data, 0xFF, PGPKT_DATA_SIZE); + pTargetPkt->offset = offset; + pTargetPkt->word_en = word_en; + efuse_WordEnableDataRead(word_en, pData, pTargetPkt->data); + pTargetPkt->word_cnts = Efuse_CalculateWordCnts(pTargetPkt->word_en); +} + +static u8 +hal_EfusePgPacketWriteData( + PADAPTER pAdapter, + u8 efuseType, + u16 *pAddr, + PPGPKT_STRUCT pTargetPkt, + u8 bPseudoTest) +{ + u16 efuse_addr; + u8 badworden; + + efuse_addr = *pAddr; + badworden = Hal_EfuseWordEnableDataWrite(pAdapter, efuse_addr + 1, pTargetPkt->word_en, pTargetPkt->data, bPseudoTest); + if (badworden != 0x0F) { + RTW_INFO("%s: Fail!!\n", __FUNCTION__); + return _FALSE; + } else + RTW_INFO("%s: OK!!\n", __FUNCTION__); + + return _TRUE; +} + +/* *********************************************************** + * Efuse related code + * *********************************************************** */ +static u8 +hal_EfuseSwitchToBank( + PADAPTER padapter, + u8 bank, + u8 bPseudoTest) +{ + u8 bRet = _FALSE; + u32 value32 = 0; +#ifdef HAL_EFUSE_MEMORY + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; +#endif + + + RTW_INFO("%s: Efuse switch bank to %d\n", __FUNCTION__, bank); + if (bPseudoTest) { +#ifdef HAL_EFUSE_MEMORY + pEfuseHal->fakeEfuseBank = bank; +#else + fakeEfuseBank = bank; +#endif + bRet = _TRUE; + } else { + value32 = rtw_read32(padapter, 0x34); + bRet = _TRUE; + switch (bank) { + case 0: + value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); + break; + case 1: + value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_0); + break; + case 2: + value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_1); + break; + case 3: + value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_BT_SEL_2); + break; + default: + value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0); + bRet = _FALSE; + break; + } + rtw_write32(padapter, 0x34, value32); + } + + return bRet; +} + + +#define EFUSE_CTRL 0x30 /* E-Fuse Control. */ + +/* 11/16/2008 MH Read one byte from real Efuse. */ +u8 +efuse_OneByteRead( + IN PADAPTER pAdapter, + IN u16 addr, + IN u8 *data, + IN BOOLEAN bPseudoTest) +{ + u32 tmpidx = 0; + u8 bResult; + u8 readbyte; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + if (IS_HARDWARE_TYPE_8723B(pAdapter) || + (IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->version_id))) || + (IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->version_id)) + ) { + /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ + /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ + /* phy_set_mac_reg(pAdapter, 0x34, BIT11, 0); */ + rtw_write16(pAdapter, 0x34, rtw_read16(pAdapter, 0x34) & (~BIT11)); + } + + /* -----------------e-fuse reg ctrl --------------------------------- */ + /* address */ + rtw_write8(pAdapter, EFUSE_CTRL + 1, (u8)(addr & 0xff)); + rtw_write8(pAdapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) | + (rtw_read8(pAdapter, EFUSE_CTRL + 2) & 0xFC)); + + /* rtw_write8(pAdapter, EFUSE_CTRL+3, 0x72); */ /* read cmd */ + /* Write bit 32 0 */ + readbyte = rtw_read8(pAdapter, EFUSE_CTRL + 3); + rtw_write8(pAdapter, EFUSE_CTRL + 3, (readbyte & 0x7f)); + + while (!(0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 1000)) { + rtw_mdelay_os(1); + tmpidx++; + } + if (tmpidx < 100) { + *data = rtw_read8(pAdapter, EFUSE_CTRL); + bResult = _TRUE; + } else { + *data = 0xff; + bResult = _FALSE; + RTW_INFO("%s: [ERROR] addr=0x%x bResult=%d time out 1s !!!\n", __FUNCTION__, addr, bResult); + RTW_INFO("%s: [ERROR] EFUSE_CTRL =0x%08x !!!\n", __FUNCTION__, rtw_read32(pAdapter, EFUSE_CTRL)); + } + + return bResult; +} + + +static u16 +hal_EfuseGetCurrentSize_BT( + PADAPTER padapter, + u8 bPseudoTest) +{ +#ifdef HAL_EFUSE_MEMORY + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; +#endif + u16 btusedbytes; + u16 efuse_addr; + u8 bank, startBank; + u8 hoffset = 0, hworden = 0; + u8 efuse_data, word_cnts = 0; + u16 retU2 = 0; + u8 bContinual = _TRUE; + + + btusedbytes = fakeBTEfuseUsedBytes; + + efuse_addr = (u16)((btusedbytes % EFUSE_BT_REAL_BANK_CONTENT_LEN)); + startBank = (u8)(1 + (btusedbytes / EFUSE_BT_REAL_BANK_CONTENT_LEN)); + + RTW_INFO("%s: start from bank=%d addr=0x%X\n", __FUNCTION__, startBank, efuse_addr); + retU2 = EFUSE_BT_REAL_CONTENT_LEN - EFUSE_PROTECT_BYTES_BANK; + + for (bank = startBank; bank < 3; bank++) { + if (hal_EfuseSwitchToBank(padapter, bank, bPseudoTest) == _FALSE) { + RTW_ERR("%s: switch bank(%d) Fail!!\n", __FUNCTION__, bank); + /* bank = EFUSE_MAX_BANK; */ + break; + } + + /* only when bank is switched we have to reset the efuse_addr. */ + if (bank != startBank) + efuse_addr = 0; + + + while (AVAILABLE_EFUSE_ADDR(efuse_addr)) { + if (rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &efuse_data) == _FALSE) { + RTW_ERR("%s: efuse_OneByteRead Fail! addr=0x%X !!\n", __FUNCTION__, efuse_addr); + /* bank = EFUSE_MAX_BANK; */ + break; + } + RTW_INFO("%s: efuse_OneByteRead ! addr=0x%X !efuse_data=0x%X! bank =%d\n", __FUNCTION__, efuse_addr, efuse_data, bank); + + if (efuse_data == 0xFF) + break; + + if (EXT_HEADER(efuse_data)) { + hoffset = GET_HDR_OFFSET_2_0(efuse_data); + efuse_addr++; + rtw_efuse_bt_access(padapter, _FALSE, efuse_addr, 1, &efuse_data); + RTW_INFO("%s: efuse_OneByteRead EXT_HEADER ! addr=0x%X !efuse_data=0x%X! bank =%d\n", __FUNCTION__, efuse_addr, efuse_data, bank); + + if (ALL_WORDS_DISABLED(efuse_data)) { + efuse_addr++; + continue; + } + + /* hoffset = ((hoffset & 0xE0) >> 5) | ((efuse_data & 0xF0) >> 1); */ + hoffset |= ((efuse_data & 0xF0) >> 1); + hworden = efuse_data & 0x0F; + } else { + hoffset = (efuse_data >> 4) & 0x0F; + hworden = efuse_data & 0x0F; + } + + RTW_INFO(FUNC_ADPT_FMT": Offset=%d Worden=%#X\n", + FUNC_ADPT_ARG(padapter), hoffset, hworden); + + word_cnts = Efuse_CalculateWordCnts(hworden); + /* read next header */ + efuse_addr += (word_cnts * 2) + 1; + } + /* Check if we need to check next bank efuse */ + if (efuse_addr < retU2) + break;/* don't need to check next bank. */ + } + retU2 = ((bank - 1) * EFUSE_BT_REAL_BANK_CONTENT_LEN) + efuse_addr; + + fakeBTEfuseUsedBytes = retU2; + RTW_INFO("%s: CurrentSize=%d\n", __FUNCTION__, retU2); + return retU2; +} + + +static u8 +hal_BT_EfusePgCheckAvailableAddr( + PADAPTER pAdapter, + u8 bPseudoTest) +{ + u16 max_available = EFUSE_BT_REAL_CONTENT_LEN - EFUSE_PROTECT_BYTES_BANK; + u16 current_size = 0; + + RTW_INFO("%s: max_available=%d\n", __FUNCTION__, max_available); + current_size = hal_EfuseGetCurrentSize_BT(pAdapter, bPseudoTest); + if (current_size >= max_available) { + RTW_INFO("%s: Error!! current_size(%d)>max_available(%d)\n", __FUNCTION__, current_size, max_available); + return _FALSE; + } + return _TRUE; +} + +u8 EfusePgPacketWrite_BT( + PADAPTER pAdapter, + u8 offset, + u8 word_en, + u8 *pData, + u8 bPseudoTest) +{ + PGPKT_STRUCT targetPkt; + u16 startAddr = 0; + u8 efuseType = EFUSE_BT; + + if (!hal_BT_EfusePgCheckAvailableAddr(pAdapter, bPseudoTest)) + return _FALSE; + + hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt); + + if (!hal_EfusePartialWriteCheck(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) + return _FALSE; + + if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) + return _FALSE; + + if (!hal_EfusePgPacketWriteData(pAdapter, efuseType, &startAddr, &targetPkt, bPseudoTest)) + return _FALSE; + + return _TRUE; +} + + +#else /* !RTW_HALMAC */ +/* ------------------------------------------------------------------------------ */ +#define REG_EFUSE_CTRL 0x0030 +#define EFUSE_CTRL REG_EFUSE_CTRL /* E-Fuse Control. */ +/* ------------------------------------------------------------------------------ */ + +VOID efuse_PreUpdateAction( + PADAPTER pAdapter, + pu4Byte BackupRegs) +{ +#if defined(CONFIG_RTL8812A) + if (IS_HARDWARE_TYPE_8812AU(pAdapter)) { + /* <20131115, Kordan> Turn off Rx to prevent from being busy when writing the EFUSE. (Asked by Chunchu.)*/ + BackupRegs[0] = phy_query_mac_reg(pAdapter, REG_RCR, bMaskDWord); + BackupRegs[1] = phy_query_mac_reg(pAdapter, REG_RXFLTMAP0, bMaskDWord); + BackupRegs[2] = phy_query_mac_reg(pAdapter, REG_RXFLTMAP0+4, bMaskDWord); + BackupRegs[3] = phy_query_mac_reg(pAdapter, REG_AFE_MISC, bMaskDWord); + + PlatformEFIOWrite4Byte(pAdapter, REG_RCR, 0x1); + PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0, 0); + PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+1, 0); + PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+2, 0); + PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+3, 0); + PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+4, 0); + PlatformEFIOWrite1Byte(pAdapter, REG_RXFLTMAP0+5, 0); + + /* <20140410, Kordan> 0x11 = 0x4E, lower down LX_SPS0 voltage. (Asked by Chunchu)*/ + phy_set_mac_reg(pAdapter, REG_AFE_MISC, bMaskByte1, 0x4E); + } +#endif +} + +VOID efuse_PostUpdateAction( + PADAPTER pAdapter, + pu4Byte BackupRegs) +{ +#if defined(CONFIG_RTL8812A) + if (IS_HARDWARE_TYPE_8812AU(pAdapter)) { + /* <20131115, Kordan> Turn on Rx and restore the registers. (Asked by Chunchu.)*/ + phy_set_mac_reg(pAdapter, REG_RCR, bMaskDWord, BackupRegs[0]); + phy_set_mac_reg(pAdapter, REG_RXFLTMAP0, bMaskDWord, BackupRegs[1]); + phy_set_mac_reg(pAdapter, REG_RXFLTMAP0+4, bMaskDWord, BackupRegs[2]); + phy_set_mac_reg(pAdapter, REG_AFE_MISC, bMaskDWord, BackupRegs[3]); + } +#endif +} + + +BOOLEAN +Efuse_Read1ByteFromFakeContent( + IN PADAPTER pAdapter, + IN u16 Offset, + IN OUT u8 *Value); +BOOLEAN +Efuse_Read1ByteFromFakeContent( + IN PADAPTER pAdapter, + IN u16 Offset, + IN OUT u8 *Value) +{ + if (Offset >= EFUSE_MAX_HW_SIZE) + return _FALSE; + /* DbgPrint("Read fake content, offset = %d\n", Offset); */ + if (fakeEfuseBank == 0) + *Value = fakeEfuseContent[Offset]; + else + *Value = fakeBTEfuseContent[fakeEfuseBank - 1][Offset]; + return _TRUE; +} + +BOOLEAN +Efuse_Write1ByteToFakeContent( + IN PADAPTER pAdapter, + IN u16 Offset, + IN u8 Value); +BOOLEAN +Efuse_Write1ByteToFakeContent( + IN PADAPTER pAdapter, + IN u16 Offset, + IN u8 Value) +{ + if (Offset >= EFUSE_MAX_HW_SIZE) + return _FALSE; + if (fakeEfuseBank == 0) + fakeEfuseContent[Offset] = Value; + else + fakeBTEfuseContent[fakeEfuseBank - 1][Offset] = Value; + return _TRUE; +} + +/*----------------------------------------------------------------------------- + * Function: Efuse_PowerSwitch + * + * Overview: When we want to enable write operation, we should change to + * pwr on state. When we stop write, we should switch to 500k mode + * and disable LDO 2.5V. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/17/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +VOID +Efuse_PowerSwitch( + IN PADAPTER pAdapter, + IN u8 bWrite, + IN u8 PwrState) +{ + pAdapter->hal_func.EfusePowerSwitch(pAdapter, bWrite, PwrState); +} + +VOID +BTEfuse_PowerSwitch( + IN PADAPTER pAdapter, + IN u8 bWrite, + IN u8 PwrState) +{ + if (pAdapter->hal_func.BTEfusePowerSwitch) + pAdapter->hal_func.BTEfusePowerSwitch(pAdapter, bWrite, PwrState); +} + +/*----------------------------------------------------------------------------- + * Function: efuse_GetCurrentSize + * + * Overview: Get current efuse size!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +u16 +Efuse_GetCurrentSize( + IN PADAPTER pAdapter, + IN u8 efuseType, + IN BOOLEAN bPseudoTest) +{ + u16 ret = 0; + + ret = pAdapter->hal_func.EfuseGetCurrentSize(pAdapter, efuseType, bPseudoTest); + + return ret; +} + +/* + * Description: + * Execute E-Fuse read byte operation. + * Refered from SD1 Richard. + * + * Assumption: + * 1. Boot from E-Fuse and successfully auto-load. + * 2. PASSIVE_LEVEL (USB interface) + * + * Created by Roger, 2008.10.21. + * */ +VOID +ReadEFuseByte( + PADAPTER Adapter, + u16 _offset, + u8 *pbuf, + IN BOOLEAN bPseudoTest) +{ + u32 value32; + u8 readbyte; + u16 retry; + /* u32 start=rtw_get_current_time(); */ + + if (bPseudoTest) { + Efuse_Read1ByteFromFakeContent(Adapter, _offset, pbuf); + return; + } + if (IS_HARDWARE_TYPE_8723B(Adapter)) { + /* <20130121, Kordan> For SMIC S55 EFUSE specificatoin. */ + /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ + phy_set_mac_reg(Adapter, EFUSE_TEST, BIT11, 0); + } + /* Write Address */ + rtw_write8(Adapter, EFUSE_CTRL + 1, (_offset & 0xff)); + readbyte = rtw_read8(Adapter, EFUSE_CTRL + 2); + rtw_write8(Adapter, EFUSE_CTRL + 2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); + + /* Write bit 32 0 */ + readbyte = rtw_read8(Adapter, EFUSE_CTRL + 3); + rtw_write8(Adapter, EFUSE_CTRL + 3, (readbyte & 0x7f)); + + /* Check bit 32 read-ready */ + retry = 0; + value32 = rtw_read32(Adapter, EFUSE_CTRL); + /* while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10)) */ + while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) { + value32 = rtw_read32(Adapter, EFUSE_CTRL); + retry++; + } + + /* 20100205 Joseph: Add delay suggested by SD1 Victor. */ + /* This fix the problem that Efuse read error in high temperature condition. */ + /* Designer says that there shall be some delay after ready bit is set, or the */ + /* result will always stay on last data we read. */ + rtw_udelay_os(50); + value32 = rtw_read32(Adapter, EFUSE_CTRL); + + *pbuf = (u8)(value32 & 0xff); + /* RTW_INFO("ReadEFuseByte _offset:%08u, in %d ms\n",_offset ,rtw_get_passing_time_ms(start)); */ + +} + +/* + * Description: + * 1. Execute E-Fuse read byte operation according as map offset and + * save to E-Fuse table. + * 2. Refered from SD1 Richard. + * + * Assumption: + * 1. Boot from E-Fuse and successfully auto-load. + * 2. PASSIVE_LEVEL (USB interface) + * + * Created by Roger, 2008.10.21. + * + * 2008/12/12 MH 1. Reorganize code flow and reserve bytes. and add description. + * 2. Add efuse utilization collect. + * 2008/12/22 MH Read Efuse must check if we write section 1 data again!!! Sec1 + * write addr must be after sec5. + * */ + +VOID +efuse_ReadEFuse( + PADAPTER Adapter, + u8 efuseType, + u16 _offset, + u16 _size_byte, + u8 *pbuf, + IN BOOLEAN bPseudoTest +); +VOID +efuse_ReadEFuse( + PADAPTER Adapter, + u8 efuseType, + u16 _offset, + u16 _size_byte, + u8 *pbuf, + IN BOOLEAN bPseudoTest +) +{ + Adapter->hal_func.ReadEFuse(Adapter, efuseType, _offset, _size_byte, pbuf, bPseudoTest); +} + +VOID +EFUSE_GetEfuseDefinition( + IN PADAPTER pAdapter, + IN u8 efuseType, + IN u8 type, + OUT void *pOut, + IN BOOLEAN bPseudoTest +) +{ + pAdapter->hal_func.EFUSEGetEfuseDefinition(pAdapter, efuseType, type, pOut, bPseudoTest); +} + + +/* 11/16/2008 MH Read one byte from real Efuse. */ +u8 +efuse_OneByteRead( + IN PADAPTER pAdapter, + IN u16 addr, + IN u8 *data, + IN BOOLEAN bPseudoTest) +{ + u32 tmpidx = 0; + u8 bResult; + u8 readbyte; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + /* RTW_INFO("===> EFUSE_OneByteRead(), addr = %x\n", addr); */ + /* RTW_INFO("===> EFUSE_OneByteRead() start, 0x34 = 0x%X\n", rtw_read32(pAdapter, EFUSE_TEST)); */ + + if (bPseudoTest) { + bResult = Efuse_Read1ByteFromFakeContent(pAdapter, addr, data); + return bResult; + } + + if (IS_HARDWARE_TYPE_8723B(pAdapter) || + (IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->version_id))) || + (IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->version_id)) + ) { + /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ + /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ + /* phy_set_mac_reg(pAdapter, 0x34, BIT11, 0); */ + rtw_write16(pAdapter, 0x34, rtw_read16(pAdapter, 0x34) & (~BIT11)); + } + + /* -----------------e-fuse reg ctrl --------------------------------- */ + /* address */ + rtw_write8(pAdapter, EFUSE_CTRL + 1, (u8)(addr & 0xff)); + rtw_write8(pAdapter, EFUSE_CTRL + 2, ((u8)((addr >> 8) & 0x03)) | + (rtw_read8(pAdapter, EFUSE_CTRL + 2) & 0xFC)); + + /* rtw_write8(pAdapter, EFUSE_CTRL+3, 0x72); */ /* read cmd */ + /* Write bit 32 0 */ + readbyte = rtw_read8(pAdapter, EFUSE_CTRL + 3); + rtw_write8(pAdapter, EFUSE_CTRL + 3, (readbyte & 0x7f)); + + while (!(0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 1000)) { + rtw_mdelay_os(1); + tmpidx++; + } + if (tmpidx < 100) { + *data = rtw_read8(pAdapter, EFUSE_CTRL); + bResult = _TRUE; + } else { + *data = 0xff; + bResult = _FALSE; + RTW_INFO("%s: [ERROR] addr=0x%x bResult=%d time out 1s !!!\n", __FUNCTION__, addr, bResult); + RTW_INFO("%s: [ERROR] EFUSE_CTRL =0x%08x !!!\n", __FUNCTION__, rtw_read32(pAdapter, EFUSE_CTRL)); + } + + return bResult; +} + +/* 11/16/2008 MH Write one byte to reald Efuse. */ +u8 +efuse_OneByteWrite( + IN PADAPTER pAdapter, + IN u16 addr, + IN u8 data, + IN BOOLEAN bPseudoTest) +{ + u8 tmpidx = 0; + u8 bResult = _FALSE; + u32 efuseValue = 0; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + /* RTW_INFO("===> EFUSE_OneByteWrite(), addr = %x data=%x\n", addr, data); */ + /* RTW_INFO("===> EFUSE_OneByteWrite() start, 0x34 = 0x%X\n", rtw_read32(pAdapter, EFUSE_TEST)); */ + + if (bPseudoTest) { + bResult = Efuse_Write1ByteToFakeContent(pAdapter, addr, data); + return bResult; + } + + Efuse_PowerSwitch(pAdapter, _TRUE, _TRUE); + + /* -----------------e-fuse reg ctrl --------------------------------- */ + /* address */ + + + efuseValue = rtw_read32(pAdapter, EFUSE_CTRL); + efuseValue |= (BIT21 | BIT31); + efuseValue &= ~(0x3FFFF); + efuseValue |= ((addr << 8 | data) & 0x3FFFF); + + /* <20130227, Kordan> 8192E MP chip A-cut had better not set 0x34[11] until B-Cut. */ + if (IS_HARDWARE_TYPE_8723B(pAdapter) || + (IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->version_id))) || + (IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->version_id)) + ) { + /* <20130121, Kordan> For SMIC EFUSE specificatoin. */ + /* 0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) */ + /* phy_set_mac_reg(pAdapter, 0x34, BIT11, 1); */ + rtw_write16(pAdapter, 0x34, rtw_read16(pAdapter, 0x34) | (BIT11)); + rtw_write32(pAdapter, EFUSE_CTRL, 0x90600000 | ((addr << 8 | data))); + } else + rtw_write32(pAdapter, EFUSE_CTRL, efuseValue); + + rtw_mdelay_os(1); + + while ((0x80 & rtw_read8(pAdapter, EFUSE_CTRL + 3)) && (tmpidx < 100)) { + rtw_mdelay_os(1); + tmpidx++; + } + + if (tmpidx < 100) + bResult = _TRUE; + else { + bResult = _FALSE; + RTW_INFO("%s: [ERROR] addr=0x%x ,efuseValue=0x%x ,bResult=%d time out 1s !!!\n", + __FUNCTION__, addr, efuseValue, bResult); + RTW_INFO("%s: [ERROR] EFUSE_CTRL =0x%08x !!!\n", __FUNCTION__, rtw_read32(pAdapter, EFUSE_CTRL)); + } + + /* disable Efuse program enable */ + if (IS_HARDWARE_TYPE_8723B(pAdapter) || + (IS_HARDWARE_TYPE_8192E(pAdapter) && (!IS_A_CUT(pHalData->version_id))) || + (IS_VENDOR_8188E_I_CUT_SERIES(pAdapter)) || (IS_CHIP_VENDOR_SMIC(pHalData->version_id)) + ) + phy_set_mac_reg(pAdapter, EFUSE_TEST, BIT(11), 0); + + Efuse_PowerSwitch(pAdapter, _TRUE, _FALSE); + + return bResult; +} + +int +Efuse_PgPacketRead(IN PADAPTER pAdapter, + IN u8 offset, + IN u8 *data, + IN BOOLEAN bPseudoTest) +{ + int ret = 0; + + ret = pAdapter->hal_func.Efuse_PgPacketRead(pAdapter, offset, data, bPseudoTest); + + return ret; +} + +int +Efuse_PgPacketWrite(IN PADAPTER pAdapter, + IN u8 offset, + IN u8 word_en, + IN u8 *data, + IN BOOLEAN bPseudoTest) +{ + int ret; + + ret = pAdapter->hal_func.Efuse_PgPacketWrite(pAdapter, offset, word_en, data, bPseudoTest); + + return ret; +} + + +int +Efuse_PgPacketWrite_BT(IN PADAPTER pAdapter, + IN u8 offset, + IN u8 word_en, + IN u8 *data, + IN BOOLEAN bPseudoTest) +{ + int ret; + + ret = pAdapter->hal_func.Efuse_PgPacketWrite_BT(pAdapter, offset, word_en, data, bPseudoTest); + + return ret; +} + + +u8 +Efuse_WordEnableDataWrite(IN PADAPTER pAdapter, + IN u16 efuse_addr, + IN u8 word_en, + IN u8 *data, + IN BOOLEAN bPseudoTest) +{ + u8 ret = 0; + + ret = pAdapter->hal_func.Efuse_WordEnableDataWrite(pAdapter, efuse_addr, word_en, data, bPseudoTest); + + return ret; +} + +static u8 efuse_read8(PADAPTER padapter, u16 address, u8 *value) +{ + return efuse_OneByteRead(padapter, address, value, _FALSE); +} + +static u8 efuse_write8(PADAPTER padapter, u16 address, u8 *value) +{ + return efuse_OneByteWrite(padapter, address, *value, _FALSE); +} + +/* + * read/wirte raw efuse data + */ +u8 rtw_efuse_access(PADAPTER padapter, u8 bWrite, u16 start_addr, u16 cnts, u8 *data) +{ + int i = 0; + u16 real_content_len = 0, max_available_size = 0; + u8 res = _FAIL ; + u8(*rw8)(PADAPTER, u16, u8 *); + u32 backupRegs[4] = {0}; + + + EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (PVOID)&real_content_len, _FALSE); + EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE); + + if (start_addr > real_content_len) + return _FAIL; + + if (_TRUE == bWrite) { + if ((start_addr + cnts) > max_available_size) + return _FAIL; + rw8 = &efuse_write8; + } else + rw8 = &efuse_read8; + + efuse_PreUpdateAction(padapter, backupRegs); + + Efuse_PowerSwitch(padapter, bWrite, _TRUE); + + /* e-fuse one byte read / write */ + for (i = 0; i < cnts; i++) { + if (start_addr >= real_content_len) { + res = _FAIL; + break; + } + + res = rw8(padapter, start_addr++, data++); + if (_FAIL == res) + break; + } + + Efuse_PowerSwitch(padapter, bWrite, _FALSE); + + efuse_PostUpdateAction(padapter, backupRegs); + + return res; +} +/* ------------------------------------------------------------------------------ */ +u16 efuse_GetMaxSize(PADAPTER padapter) +{ + u16 max_size; + + max_size = 0; + EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI , TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_size, _FALSE); + return max_size; +} +/* ------------------------------------------------------------------------------ */ +u8 efuse_GetCurrentSize(PADAPTER padapter, u16 *size) +{ + Efuse_PowerSwitch(padapter, _FALSE, _TRUE); + *size = Efuse_GetCurrentSize(padapter, EFUSE_WIFI, _FALSE); + Efuse_PowerSwitch(padapter, _FALSE, _FALSE); + + return _SUCCESS; +} +/* ------------------------------------------------------------------------------ */ +u16 efuse_bt_GetMaxSize(PADAPTER padapter) +{ + u16 max_size; + + max_size = 0; + EFUSE_GetEfuseDefinition(padapter, EFUSE_BT , TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_size, _FALSE); + return max_size; +} + +u8 efuse_bt_GetCurrentSize(PADAPTER padapter, u16 *size) +{ + Efuse_PowerSwitch(padapter, _FALSE, _TRUE); + *size = Efuse_GetCurrentSize(padapter, EFUSE_BT, _FALSE); + Efuse_PowerSwitch(padapter, _FALSE, _FALSE); + + return _SUCCESS; +} + +u8 rtw_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) +{ + u16 mapLen = 0; + + EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); + + if ((addr + cnts) > mapLen) + return _FAIL; + + Efuse_PowerSwitch(padapter, _FALSE, _TRUE); + + efuse_ReadEFuse(padapter, EFUSE_WIFI, addr, cnts, data, _FALSE); + + Efuse_PowerSwitch(padapter, _FALSE, _FALSE); + + return _SUCCESS; +} + +u8 rtw_BT_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) +{ + u16 mapLen = 0; + + EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); + + if ((addr + cnts) > mapLen) + return _FAIL; + + Efuse_PowerSwitch(padapter, _FALSE, _TRUE); + + efuse_ReadEFuse(padapter, EFUSE_BT, addr, cnts, data, _FALSE); + + Efuse_PowerSwitch(padapter, _FALSE, _FALSE); + + return _SUCCESS; +} + +/* ------------------------------------------------------------------------------ */ +u8 rtw_efuse_map_write(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) +{ +#define RT_ASSERT_RET(expr) \ + if (!(expr)) { \ + printk("Assertion failed! %s at ......\n", #expr); \ + printk(" ......%s,%s, line=%d\n",__FILE__, __FUNCTION__, __LINE__); \ + return _FAIL; \ + } + + u8 offset, word_en; + u8 *map; + u8 newdata[PGPKT_DATA_SIZE]; + s32 i, j, idx, chk_total_byte; + u8 ret = _SUCCESS; + u16 mapLen = 0, startAddr = 0, efuse_max_available_len = 0; + u32 backupRegs[4] = {0}; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; + + + EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); + EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &efuse_max_available_len, _FALSE); + + if ((addr + cnts) > mapLen) + return _FAIL; + + RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); /* have to be 8 byte alignment */ + RT_ASSERT_RET((mapLen & 0x7) == 0); /* have to be PGPKT_DATA_SIZE alignment for memcpy */ + + map = rtw_zmalloc(mapLen); + if (map == NULL) + return _FAIL; + + _rtw_memset(map, 0xFF, mapLen); + + ret = rtw_efuse_map_read(padapter, 0, mapLen, map); + if (ret == _FAIL) + goto exit; + + if (padapter->registrypriv.boffefusemask == 0) { + for (i = 0; i < cnts; i++) { + if (padapter->registrypriv.bFileMaskEfuse == _TRUE) { + if (rtw_file_efuse_IsMasked(padapter, addr + i)) /*use file efuse mask. */ + data[i] = map[addr + i]; + } else { + if (efuse_IsMasked(padapter, addr + i)) + data[i] = map[addr + i]; + } + RTW_INFO("%s , data[%d] = %x, map[addr+i]= %x\n", __func__, i, data[i], map[addr + i]); + } + } + /*Efuse_PowerSwitch(padapter, _TRUE, _TRUE);*/ + + chk_total_byte = 0; + idx = 0; + offset = (addr >> 3); + + while (idx < cnts) { + word_en = 0xF; + j = (addr + idx) & 0x7; + for (i = j; i < PGPKT_DATA_SIZE && idx < cnts; i++, idx++) { + if (data[idx] != map[addr + idx]) + word_en &= ~BIT(i >> 1); + } + + if (word_en != 0xF) { + chk_total_byte += Efuse_CalculateWordCnts(word_en) * 2; + + if (offset >= EFUSE_MAX_SECTION_BASE) /* Over EFUSE_MAX_SECTION 16 for 2 ByteHeader */ + chk_total_byte += 2; + else + chk_total_byte += 1; + } + + offset++; + } + + RTW_INFO("Total PG bytes Count = %d\n", chk_total_byte); + rtw_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&startAddr); + + if (startAddr == 0) { + startAddr = Efuse_GetCurrentSize(padapter, EFUSE_WIFI, _FALSE); + RTW_INFO("%s: Efuse_GetCurrentSize startAddr=%#X\n", __func__, startAddr); + } + RTW_DBG("%s: startAddr=%#X\n", __func__, startAddr); + + if ((startAddr + chk_total_byte) >= efuse_max_available_len) { + RTW_INFO("%s: startAddr(0x%X) + PG data len %d >= efuse_max_available_len(0x%X)\n", + __func__, startAddr, chk_total_byte, efuse_max_available_len); + ret = _FAIL; + goto exit; + } + + efuse_PreUpdateAction(padapter, backupRegs); + + idx = 0; + offset = (addr >> 3); + while (idx < cnts) { + word_en = 0xF; + j = (addr + idx) & 0x7; + _rtw_memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE); + for (i = j; i < PGPKT_DATA_SIZE && idx < cnts; i++, idx++) { + if (data[idx] != map[addr + idx]) { + word_en &= ~BIT(i >> 1); + newdata[i] = data[idx]; +#ifdef CONFIG_RTL8723B + if (addr + idx == 0x8) { + if (IS_C_CUT(pHalData->version_id) || IS_B_CUT(pHalData->version_id)) { + if (pHalData->adjuseVoltageVal == 6) { + newdata[i] = map[addr + idx]; + RTW_INFO(" %s ,\n adjuseVoltageVal = %d ,newdata[%d] = %x\n", __func__, pHalData->adjuseVoltageVal, i, newdata[i]); + } + } + } +#endif + } + } + + if (word_en != 0xF) { + ret = Efuse_PgPacketWrite(padapter, offset, word_en, newdata, _FALSE); + RTW_INFO("offset=%x\n", offset); + RTW_INFO("word_en=%x\n", word_en); + + for (i = 0; i < PGPKT_DATA_SIZE; i++) + RTW_INFO("data=%x \t", newdata[i]); + if (ret == _FAIL) + break; + } + + offset++; + } + + /*Efuse_PowerSwitch(padapter, _TRUE, _FALSE);*/ + + efuse_PostUpdateAction(padapter, backupRegs); + +exit: + + rtw_mfree(map, mapLen); + + return ret; +} + + +u8 rtw_BT_efuse_map_write(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) +{ +#define RT_ASSERT_RET(expr) \ + if (!(expr)) { \ + printk("Assertion failed! %s at ......\n", #expr); \ + printk(" ......%s,%s, line=%d\n",__FILE__, __FUNCTION__, __LINE__); \ + return _FAIL; \ + } + + u8 offset, word_en; + u8 *map; + u8 newdata[PGPKT_DATA_SIZE]; + s32 i = 0, j = 0, idx; + u8 ret = _SUCCESS; + u16 mapLen = 0; + + EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); + + if ((addr + cnts) > mapLen) + return _FAIL; + + RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); /* have to be 8 byte alignment */ + RT_ASSERT_RET((mapLen & 0x7) == 0); /* have to be PGPKT_DATA_SIZE alignment for memcpy */ + + map = rtw_zmalloc(mapLen); + if (map == NULL) + return _FAIL; + + ret = rtw_BT_efuse_map_read(padapter, 0, mapLen, map); + if (ret == _FAIL) + goto exit; + RTW_INFO("OFFSET\tVALUE(hex)\n"); + for (i = 0; i < 1024; i += 16) { /* set 512 because the iwpriv's extra size have limit 0x7FF */ + RTW_INFO("0x%03x\t", i); + for (j = 0; j < 8; j++) + RTW_INFO("%02X ", map[i + j]); + RTW_INFO("\t"); + for (; j < 16; j++) + RTW_INFO("%02X ", map[i + j]); + RTW_INFO("\n"); + } + RTW_INFO("\n"); + Efuse_PowerSwitch(padapter, _TRUE, _TRUE); + + idx = 0; + offset = (addr >> 3); + while (idx < cnts) { + word_en = 0xF; + j = (addr + idx) & 0x7; + _rtw_memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE); + for (i = j; i < PGPKT_DATA_SIZE && idx < cnts; i++, idx++) { + if (data[idx] != map[addr + idx]) { + word_en &= ~BIT(i >> 1); + newdata[i] = data[idx]; + } + } + + if (word_en != 0xF) { + RTW_INFO("offset=%x\n", offset); + RTW_INFO("word_en=%x\n", word_en); + RTW_INFO("%s: data=", __FUNCTION__); + for (i = 0; i < PGPKT_DATA_SIZE; i++) + RTW_INFO("0x%02X ", newdata[i]); + RTW_INFO("\n"); + ret = Efuse_PgPacketWrite_BT(padapter, offset, word_en, newdata, _FALSE); + if (ret == _FAIL) + break; + } + + offset++; + } + + Efuse_PowerSwitch(padapter, _TRUE, _FALSE); + +exit: + + rtw_mfree(map, mapLen); + + return ret; +} + +/*----------------------------------------------------------------------------- + * Function: Efuse_ReadAllMap + * + * Overview: Read All Efuse content + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/11/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +VOID +Efuse_ReadAllMap( + IN PADAPTER pAdapter, + IN u8 efuseType, + IN OUT u8 *Efuse, + IN BOOLEAN bPseudoTest); +VOID +Efuse_ReadAllMap( + IN PADAPTER pAdapter, + IN u8 efuseType, + IN OUT u8 *Efuse, + IN BOOLEAN bPseudoTest) +{ + u16 mapLen = 0; + + Efuse_PowerSwitch(pAdapter, _FALSE, _TRUE); + + EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest); + + efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse, bPseudoTest); + + Efuse_PowerSwitch(pAdapter, _FALSE, _FALSE); +} + +/*----------------------------------------------------------------------------- + * Function: efuse_ShadowRead1Byte + * efuse_ShadowRead2Byte + * efuse_ShadowRead4Byte + * + * Overview: Read from efuse init map by one/two/four bytes !!!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/12/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +static VOID +efuse_ShadowRead1Byte( + IN PADAPTER pAdapter, + IN u16 Offset, + IN OUT u8 *Value) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); + + *Value = pHalData->efuse_eeprom_data[Offset]; + +} /* EFUSE_ShadowRead1Byte */ + +/* ---------------Read Two Bytes */ +static VOID +efuse_ShadowRead2Byte( + IN PADAPTER pAdapter, + IN u16 Offset, + IN OUT u16 *Value) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); + + *Value = pHalData->efuse_eeprom_data[Offset]; + *Value |= pHalData->efuse_eeprom_data[Offset + 1] << 8; + +} /* EFUSE_ShadowRead2Byte */ + +/* ---------------Read Four Bytes */ +static VOID +efuse_ShadowRead4Byte( + IN PADAPTER pAdapter, + IN u16 Offset, + IN OUT u32 *Value) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); + + *Value = pHalData->efuse_eeprom_data[Offset]; + *Value |= pHalData->efuse_eeprom_data[Offset + 1] << 8; + *Value |= pHalData->efuse_eeprom_data[Offset + 2] << 16; + *Value |= pHalData->efuse_eeprom_data[Offset + 3] << 24; + +} /* efuse_ShadowRead4Byte */ + + +/*----------------------------------------------------------------------------- + * Function: efuse_ShadowWrite1Byte + * efuse_ShadowWrite2Byte + * efuse_ShadowWrite4Byte + * + * Overview: Write efuse modify map by one/two/four byte. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/12/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +#ifdef PLATFORM +static VOID +efuse_ShadowWrite1Byte( + IN PADAPTER pAdapter, + IN u16 Offset, + IN u8 Value); +#endif /* PLATFORM */ +static VOID +efuse_ShadowWrite1Byte( + IN PADAPTER pAdapter, + IN u16 Offset, + IN u8 Value) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); + + pHalData->efuse_eeprom_data[Offset] = Value; + +} /* efuse_ShadowWrite1Byte */ + +/* ---------------Write Two Bytes */ +static VOID +efuse_ShadowWrite2Byte( + IN PADAPTER pAdapter, + IN u16 Offset, + IN u16 Value) +{ + + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); + + + pHalData->efuse_eeprom_data[Offset] = Value & 0x00FF; + pHalData->efuse_eeprom_data[Offset + 1] = Value >> 8; + +} /* efuse_ShadowWrite1Byte */ + +/* ---------------Write Four Bytes */ +static VOID +efuse_ShadowWrite4Byte( + IN PADAPTER pAdapter, + IN u16 Offset, + IN u32 Value) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); + + pHalData->efuse_eeprom_data[Offset] = (u8)(Value & 0x000000FF); + pHalData->efuse_eeprom_data[Offset + 1] = (u8)((Value >> 8) & 0x0000FF); + pHalData->efuse_eeprom_data[Offset + 2] = (u8)((Value >> 16) & 0x00FF); + pHalData->efuse_eeprom_data[Offset + 3] = (u8)((Value >> 24) & 0xFF); + +} /* efuse_ShadowWrite1Byte */ + + +/*----------------------------------------------------------------------------- + * Function: EFUSE_ShadowRead + * + * Overview: Read from efuse init map !!!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/12/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +void +EFUSE_ShadowRead( + IN PADAPTER pAdapter, + IN u8 Type, + IN u16 Offset, + IN OUT u32 *Value) +{ + if (Type == 1) + efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value); + else if (Type == 2) + efuse_ShadowRead2Byte(pAdapter, Offset, (u16 *)Value); + else if (Type == 4) + efuse_ShadowRead4Byte(pAdapter, Offset, (u32 *)Value); + +} /* EFUSE_ShadowRead */ + +/*----------------------------------------------------------------------------- + * Function: EFUSE_ShadowWrite + * + * Overview: Write efuse modify map for later update operation to use!!!!! + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/12/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +VOID +EFUSE_ShadowWrite( + IN PADAPTER pAdapter, + IN u8 Type, + IN u16 Offset, + IN OUT u32 Value); +VOID +EFUSE_ShadowWrite( + IN PADAPTER pAdapter, + IN u8 Type, + IN u16 Offset, + IN OUT u32 Value) +{ +#if (MP_DRIVER == 0) + return; +#endif + if (pAdapter->registrypriv.mp_mode == 0) + return; + + + if (Type == 1) + efuse_ShadowWrite1Byte(pAdapter, Offset, (u8)Value); + else if (Type == 2) + efuse_ShadowWrite2Byte(pAdapter, Offset, (u16)Value); + else if (Type == 4) + efuse_ShadowWrite4Byte(pAdapter, Offset, (u32)Value); + +} /* EFUSE_ShadowWrite */ + +VOID +Efuse_InitSomeVar( + IN PADAPTER pAdapter +); +VOID +Efuse_InitSomeVar( + IN PADAPTER pAdapter +) +{ + u8 i; + + _rtw_memset((PVOID)&fakeEfuseContent[0], 0xff, EFUSE_MAX_HW_SIZE); + _rtw_memset((PVOID)&fakeEfuseInitMap[0], 0xff, EFUSE_MAX_MAP_LEN); + _rtw_memset((PVOID)&fakeEfuseModifiedMap[0], 0xff, EFUSE_MAX_MAP_LEN); + + for (i = 0; i < EFUSE_MAX_BT_BANK; i++) + _rtw_memset((PVOID)&BTEfuseContent[i][0], EFUSE_MAX_HW_SIZE, 0xff); + _rtw_memset((PVOID)&BTEfuseInitMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN); + _rtw_memset((PVOID)&BTEfuseModifiedMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN); + + for (i = 0; i < EFUSE_MAX_BT_BANK; i++) + _rtw_memset((PVOID)&fakeBTEfuseContent[i][0], 0xff, EFUSE_MAX_HW_SIZE); + _rtw_memset((PVOID)&fakeBTEfuseInitMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN); + _rtw_memset((PVOID)&fakeBTEfuseModifiedMap[0], 0xff, EFUSE_BT_MAX_MAP_LEN); +} +#endif /* !RTW_HALMAC */ +/* 11/16/2008 MH Add description. Get current efuse area enabled word!!. */ +u8 +Efuse_CalculateWordCnts(IN u8 word_en) +{ + u8 word_cnts = 0; + if (!(word_en & BIT(0))) + word_cnts++; /* 0 : write enable */ + if (!(word_en & BIT(1))) + word_cnts++; + if (!(word_en & BIT(2))) + word_cnts++; + if (!(word_en & BIT(3))) + word_cnts++; + return word_cnts; +} + +/*----------------------------------------------------------------------------- + * Function: efuse_WordEnableDataRead + * + * Overview: Read allowed word in current efuse section data. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/16/2008 MHC Create Version 0. + * 11/21/2008 MHC Fix Write bug when we only enable late word. + * + *---------------------------------------------------------------------------*/ +void +efuse_WordEnableDataRead(IN u8 word_en, + IN u8 *sourdata, + IN u8 *targetdata) +{ + if (!(word_en & BIT(0))) { + targetdata[0] = sourdata[0]; + targetdata[1] = sourdata[1]; + } + if (!(word_en & BIT(1))) { + targetdata[2] = sourdata[2]; + targetdata[3] = sourdata[3]; + } + if (!(word_en & BIT(2))) { + targetdata[4] = sourdata[4]; + targetdata[5] = sourdata[5]; + } + if (!(word_en & BIT(3))) { + targetdata[6] = sourdata[6]; + targetdata[7] = sourdata[7]; + } +} + +/*----------------------------------------------------------------------------- + * Function: EFUSE_ShadowMapUpdate + * + * Overview: Transfer current EFUSE content to shadow init and modify map. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/13/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +void EFUSE_ShadowMapUpdate( + IN PADAPTER pAdapter, + IN u8 efuseType, + IN BOOLEAN bPseudoTest) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); + u16 mapLen = 0; +#ifdef RTW_HALMAC + u8 *efuse_map = NULL; + int err; + + + mapLen = EEPROM_MAX_SIZE; + efuse_map = pHalData->efuse_eeprom_data; + /* efuse default content is 0xFF */ + _rtw_memset(efuse_map, 0xFF, EEPROM_MAX_SIZE); + + EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest); + if (!mapLen) { + RTW_WARN("%s: <ERROR> fail to get efuse size!\n", __FUNCTION__); + mapLen = EEPROM_MAX_SIZE; + } + if (mapLen > EEPROM_MAX_SIZE) { + RTW_WARN("%s: <ERROR> size of efuse data(%d) is large than expected(%d)!\n", + __FUNCTION__, mapLen, EEPROM_MAX_SIZE); + mapLen = EEPROM_MAX_SIZE; + } + + if (pHalData->bautoload_fail_flag == _FALSE) { + err = rtw_halmac_read_logical_efuse_map(adapter_to_dvobj(pAdapter), efuse_map, mapLen); + if (err) + RTW_ERR("%s: <ERROR> fail to get efuse map!\n", __FUNCTION__); + } +#else /* !RTW_HALMAC */ + EFUSE_GetEfuseDefinition(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, bPseudoTest); + + if (pHalData->bautoload_fail_flag == _TRUE) + _rtw_memset(pHalData->efuse_eeprom_data, 0xFF, mapLen); + else { +#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE + if (_SUCCESS != retriveAdaptorInfoFile(pAdapter->registrypriv.adaptor_info_caching_file_path, pHalData->efuse_eeprom_data)) { +#endif + + Efuse_ReadAllMap(pAdapter, efuseType, pHalData->efuse_eeprom_data, bPseudoTest); + +#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE + storeAdaptorInfoFile(pAdapter->registrypriv.adaptor_info_caching_file_path, pHalData->efuse_eeprom_data); + } +#endif + } + + /* PlatformMoveMemory((PVOID)&pHalData->EfuseMap[EFUSE_MODIFY_MAP][0], */ + /* (PVOID)&pHalData->EfuseMap[EFUSE_INIT_MAP][0], mapLen); */ +#endif /* !RTW_HALMAC */ + + rtw_dump_cur_efuse(pAdapter); +} /* EFUSE_ShadowMapUpdate */ + +const u8 _mac_hidden_max_bw_to_hal_bw_cap[MAC_HIDDEN_MAX_BW_NUM] = { + 0, + 0, + (BW_CAP_160M | BW_CAP_80M | BW_CAP_40M | BW_CAP_20M | BW_CAP_10M | BW_CAP_5M), + (BW_CAP_5M), + (BW_CAP_10M | BW_CAP_5M), + (BW_CAP_20M | BW_CAP_10M | BW_CAP_5M), + (BW_CAP_40M | BW_CAP_20M | BW_CAP_10M | BW_CAP_5M), + (BW_CAP_80M | BW_CAP_40M | BW_CAP_20M | BW_CAP_10M | BW_CAP_5M), +}; + +const u8 _mac_hidden_proto_to_hal_proto_cap[MAC_HIDDEN_PROTOCOL_NUM] = { + 0, + 0, + (PROTO_CAP_11N | PROTO_CAP_11G | PROTO_CAP_11B), + (PROTO_CAP_11AC | PROTO_CAP_11N | PROTO_CAP_11G | PROTO_CAP_11B), +}; + +u8 mac_hidden_wl_func_to_hal_wl_func(u8 func) +{ + u8 wl_func = 0; + + if (func & BIT0) + wl_func |= WL_FUNC_MIRACAST; + if (func & BIT1) + wl_func |= WL_FUNC_P2P; + if (func & BIT2) + wl_func |= WL_FUNC_TDLS; + if (func & BIT3) + wl_func |= WL_FUNC_FTM; + + return wl_func; +} + +#ifdef PLATFORM_LINUX +#ifdef CONFIG_ADAPTOR_INFO_CACHING_FILE +/* #include <rtw_eeprom.h> */ + +int isAdaptorInfoFileValid(void) +{ + return _TRUE; +} + +int storeAdaptorInfoFile(char *path, u8 *efuse_data) +{ + int ret = _SUCCESS; + + if (path && efuse_data) { + ret = rtw_store_to_file(path, efuse_data, EEPROM_MAX_SIZE_512); + if (ret == EEPROM_MAX_SIZE) + ret = _SUCCESS; + else + ret = _FAIL; + } else { + RTW_INFO("%s NULL pointer\n", __FUNCTION__); + ret = _FAIL; + } + return ret; +} + +int retriveAdaptorInfoFile(char *path, u8 *efuse_data) +{ + int ret = _SUCCESS; + mm_segment_t oldfs; + struct file *fp; + + if (path && efuse_data) { + + ret = rtw_retrieve_from_file(path, efuse_data, EEPROM_MAX_SIZE); + + if (ret == EEPROM_MAX_SIZE) + ret = _SUCCESS; + else + ret = _FAIL; + +#if 0 + if (isAdaptorInfoFileValid()) + return 0; + else + return _FAIL; +#endif + + } else { + RTW_INFO("%s NULL pointer\n", __FUNCTION__); + ret = _FAIL; + } + return ret; +} +#endif /* CONFIG_ADAPTOR_INFO_CACHING_FILE */ + +u8 rtw_efuse_file_read(PADAPTER padapter, u8 *filepatch, u8 *buf, u32 len) +{ + char *ptmpbuf = NULL, *ptr; + u8 val8; + u32 count, i, j; + int err; + u32 bufsize = 4096; + + ptmpbuf = rtw_zmalloc(bufsize); + if (ptmpbuf == NULL) + return _FALSE; + + count = rtw_retrieve_from_file(filepatch, ptmpbuf, bufsize); + if (count <= 100) { + rtw_mfree(ptmpbuf, bufsize); + RTW_ERR("%s, filepatch %s, size=%d, FAIL!!\n", __FUNCTION__, filepatch, count); + return _FALSE; + } + + i = 0; + j = 0; + ptr = ptmpbuf; + while ((j < len) && (i < count)) { + if (ptmpbuf[i] == '\0') + break; + + ptr = strpbrk(&ptmpbuf[i], " \t\n\r"); + if (ptr) { + if (ptr == &ptmpbuf[i]) { + i++; + continue; + } + + /* Add string terminating null */ + *ptr = 0; + } else { + ptr = &ptmpbuf[count-1]; + } + + err = sscanf(&ptmpbuf[i], "%hhx", &val8); + if (err != 1) { + RTW_WARN("Something wrong to parse efuse file, string=%s\n", &ptmpbuf[i]); + } else { + buf[j] = val8; + RTW_DBG("i=%d, j=%d, 0x%02x\n", i, j, buf[j]); + j++; + } + + i = ptr - ptmpbuf + 1; + } + + rtw_mfree(ptmpbuf, bufsize); + RTW_INFO("%s, filepatch %s, size=%d, done\n", __FUNCTION__, filepatch, count); + return _TRUE; +} + +#ifdef CONFIG_EFUSE_CONFIG_FILE +u32 rtw_read_efuse_from_file(const char *path, u8 *buf, int map_size) +{ + u32 i; + u8 c; + u8 temp[3]; + u8 temp_i; + u8 end = _FALSE; + u32 ret = _FAIL; + + u8 *file_data = NULL; + u32 file_size, read_size, pos = 0; + u8 *map = NULL; + + if (rtw_is_file_readable_with_size(path, &file_size) != _TRUE) { + RTW_PRINT("%s %s is not readable\n", __func__, path); + goto exit; + } + + file_data = rtw_vmalloc(file_size); + if (!file_data) { + RTW_ERR("%s rtw_vmalloc(%d) fail\n", __func__, file_size); + goto exit; + } + + read_size = rtw_retrieve_from_file(path, file_data, file_size); + if (read_size == 0) { + RTW_ERR("%s read from %s fail\n", __func__, path); + goto exit; + } + + map = rtw_vmalloc(map_size); + if (!map) { + RTW_ERR("%s rtw_vmalloc(%d) fail\n", __func__, map_size); + goto exit; + } + _rtw_memset(map, 0xff, map_size); + + temp[2] = 0; /* end of string '\0' */ + + for (i = 0 ; i < map_size ; i++) { + temp_i = 0; + + while (1) { + if (pos >= read_size) { + end = _TRUE; + break; + } + c = file_data[pos++]; + + /* bypass spece or eol or null before first hex digit */ + if (temp_i == 0 && (is_eol(c) == _TRUE || is_space(c) == _TRUE || is_null(c) == _TRUE)) + continue; + + if (IsHexDigit(c) == _FALSE) { + RTW_ERR("%s invalid 8-bit hex format for offset:0x%03x\n", __func__, i); + goto exit; + } + + temp[temp_i++] = c; + + if (temp_i == 2) { + /* parse value */ + if (sscanf(temp, "%hhx", &map[i]) != 1) { + RTW_ERR("%s sscanf fail for offset:0x%03x\n", __func__, i); + goto exit; + } + break; + } + } + + if (end == _TRUE) { + if (temp_i != 0) { + RTW_ERR("%s incomplete 8-bit hex format for offset:0x%03x\n", __func__, i); + goto exit; + } + break; + } + } + + RTW_PRINT("efuse file:%s, 0x%03x byte content read\n", path, i); + + _rtw_memcpy(buf, map, map_size); + + ret = _SUCCESS; + +exit: + if (file_data) + rtw_vmfree(file_data, file_size); + if (map) + rtw_vmfree(map, map_size); + + return ret; +} + +u32 rtw_read_macaddr_from_file(const char *path, u8 *buf) +{ + u32 i; + u8 temp[3]; + u32 ret = _FAIL; + + u8 file_data[17]; + u32 read_size, pos = 0; + u8 addr[ETH_ALEN]; + + if (rtw_is_file_readable(path) != _TRUE) { + RTW_PRINT("%s %s is not readable\n", __func__, path); + goto exit; + } + + read_size = rtw_retrieve_from_file(path, file_data, 17); + if (read_size != 17) { + RTW_ERR("%s read from %s fail\n", __func__, path); + goto exit; + } + + temp[2] = 0; /* end of string '\0' */ + + for (i = 0 ; i < ETH_ALEN ; i++) { + if (IsHexDigit(file_data[i * 3]) == _FALSE || IsHexDigit(file_data[i * 3 + 1]) == _FALSE) { + RTW_ERR("%s invalid 8-bit hex format for address offset:%u\n", __func__, i); + goto exit; + } + + if (i < ETH_ALEN - 1 && file_data[i * 3 + 2] != ':') { + RTW_ERR("%s invalid separator after address offset:%u\n", __func__, i); + goto exit; + } + + temp[0] = file_data[i * 3]; + temp[1] = file_data[i * 3 + 1]; + if (sscanf(temp, "%hhx", &addr[i]) != 1) { + RTW_ERR("%s sscanf fail for address offset:0x%03x\n", __func__, i); + goto exit; + } + } + + _rtw_memcpy(buf, addr, ETH_ALEN); + + RTW_PRINT("wifi_mac file: %s\n", path); +#ifdef CONFIG_RTW_DEBUG + RTW_INFO(MAC_FMT"\n", MAC_ARG(buf)); +#endif + + ret = _SUCCESS; + +exit: + return ret; +} +#endif /* CONFIG_EFUSE_CONFIG_FILE */ + +#endif /* PLATFORM_LINUX */ diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_ap.c b/linux-bsp/drivers/rtl8188eus/core/rtw_ap.c new file mode 100644 index 0000000..dc5f8d1 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_ap.c @@ -0,0 +1,4171 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_AP_C_ + +#include <drv_types.h> +#include <hal_data.h> + +#ifdef CONFIG_AP_MODE + +extern unsigned char RTW_WPA_OUI[]; +extern unsigned char WMM_OUI[]; +extern unsigned char WPS_OUI[]; +extern unsigned char P2P_OUI[]; +extern unsigned char WFD_OUI[]; + +void init_mlme_ap_info(_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + + _rtw_spinlock_init(&pmlmepriv->bcn_update_lock); + + /* pmlmeext->bstart_bss = _FALSE; */ + +} + +void free_mlme_ap_info(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + + stop_ap_mode(padapter); + _rtw_spinlock_free(&pmlmepriv->bcn_update_lock); + +} + +static void update_BCNTIM(_adapter *padapter) +{ + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork_mlmeext = &(pmlmeinfo->network); + unsigned char *pie = pnetwork_mlmeext->IEs; + +#if 0 + + + /* update TIM IE */ + /* if(pstapriv->tim_bitmap) */ +#endif + if (_TRUE) { + u8 *p, *dst_ie, *premainder_ie = NULL, *pbackup_remainder_ie = NULL; + u16 tim_bitmap_le; + uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen; + + tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap); + + p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_); + if (p != NULL && tim_ielen > 0) { + tim_ielen += 2; + + premainder_ie = p + tim_ielen; + + tim_ie_offset = (sint)(p - pie); + + remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen; + + /*append TIM IE from dst_ie offset*/ + dst_ie = p; + } else { + tim_ielen = 0; + + /*calculate head_len*/ + offset = _FIXED_IE_LENGTH_; + + /* get ssid_ie len */ + p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SSID_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)); + if (p != NULL) + offset += tmp_len + 2; + + /*get supported rates len*/ + p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_)); + if (p != NULL) + offset += tmp_len + 2; + + /*DS Parameter Set IE, len=3*/ + offset += 3; + + premainder_ie = pie + offset; + + remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen; + + /*append TIM IE from offset*/ + dst_ie = pie + offset; + + } + + if (remainder_ielen > 0) { + pbackup_remainder_ie = rtw_malloc(remainder_ielen); + if (pbackup_remainder_ie && premainder_ie) + _rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); + } + + *dst_ie++ = _TIM_IE_; + + if ((pstapriv->tim_bitmap & 0xff00) && (pstapriv->tim_bitmap & 0x00fe)) + tim_ielen = 5; + else + tim_ielen = 4; + + *dst_ie++ = tim_ielen; + + *dst_ie++ = 0;/*DTIM count*/ + *dst_ie++ = 1;/*DTIM period*/ + + if (pstapriv->tim_bitmap & BIT(0))/*for bc/mc frames*/ + *dst_ie++ = BIT(0);/*bitmap ctrl */ + else + *dst_ie++ = 0; + + if (tim_ielen == 4) { + u8 pvb = 0; + + if (pstapriv->tim_bitmap & 0x00fe) + pvb = (u8)tim_bitmap_le; + else if (pstapriv->tim_bitmap & 0xff00) + pvb = (u8)(tim_bitmap_le >> 8); + else + pvb = (u8)tim_bitmap_le; + + *dst_ie++ = pvb; + + } else if (tim_ielen == 5) { + _rtw_memcpy(dst_ie, &tim_bitmap_le, 2); + dst_ie += 2; + } + + /*copy remainder IE*/ + if (pbackup_remainder_ie) { + _rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); + + rtw_mfree(pbackup_remainder_ie, remainder_ielen); + } + + offset = (uint)(dst_ie - pie); + pnetwork_mlmeext->IELength = offset + remainder_ielen; + + } +} + +void rtw_add_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index, u8 *data, u8 len) +{ + PNDIS_802_11_VARIABLE_IEs pIE; + u8 bmatch = _FALSE; + u8 *pie = pnetwork->IEs; + u8 *p = NULL, *dst_ie = NULL, *premainder_ie = NULL, *pbackup_remainder_ie = NULL; + u32 i, offset, ielen, ie_offset, remainder_ielen = 0; + + for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pnetwork->IELength;) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(pnetwork->IEs + i); + + if (pIE->ElementID > index) + break; + else if (pIE->ElementID == index) { /* already exist the same IE */ + p = (u8 *)pIE; + ielen = pIE->Length; + bmatch = _TRUE; + break; + } + + p = (u8 *)pIE; + ielen = pIE->Length; + i += (pIE->Length + 2); + } + + if (p != NULL && ielen > 0) { + ielen += 2; + + premainder_ie = p + ielen; + + ie_offset = (sint)(p - pie); + + remainder_ielen = pnetwork->IELength - ie_offset - ielen; + + if (bmatch) + dst_ie = p; + else + dst_ie = (p + ielen); + } + + if (dst_ie == NULL) + return; + + if (remainder_ielen > 0) { + pbackup_remainder_ie = rtw_malloc(remainder_ielen); + if (pbackup_remainder_ie && premainder_ie) + _rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); + } + + *dst_ie++ = index; + *dst_ie++ = len; + + _rtw_memcpy(dst_ie, data, len); + dst_ie += len; + + /* copy remainder IE */ + if (pbackup_remainder_ie) { + _rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); + + rtw_mfree(pbackup_remainder_ie, remainder_ielen); + } + + offset = (uint)(dst_ie - pie); + pnetwork->IELength = offset + remainder_ielen; +} + +void rtw_remove_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index) +{ + u8 *p, *dst_ie = NULL, *premainder_ie = NULL, *pbackup_remainder_ie = NULL; + uint offset, ielen, ie_offset, remainder_ielen = 0; + u8 *pie = pnetwork->IEs; + + p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, index, &ielen, pnetwork->IELength - _FIXED_IE_LENGTH_); + if (p != NULL && ielen > 0) { + ielen += 2; + + premainder_ie = p + ielen; + + ie_offset = (sint)(p - pie); + + remainder_ielen = pnetwork->IELength - ie_offset - ielen; + + dst_ie = p; + } else + return; + + if (remainder_ielen > 0) { + pbackup_remainder_ie = rtw_malloc(remainder_ielen); + if (pbackup_remainder_ie && premainder_ie) + _rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); + } + + /* copy remainder IE */ + if (pbackup_remainder_ie) { + _rtw_memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); + + rtw_mfree(pbackup_remainder_ie, remainder_ielen); + } + + offset = (uint)(dst_ie - pie); + pnetwork->IELength = offset + remainder_ielen; +} + + +u8 chk_sta_is_alive(struct sta_info *psta); +u8 chk_sta_is_alive(struct sta_info *psta) +{ + u8 ret = _FALSE; +#ifdef DBG_EXPIRATION_CHK + RTW_INFO("sta:"MAC_FMT", rssi:%d, rx:"STA_PKTS_FMT", expire_to:%u, %s%ssq_len:%u\n" + , MAC_ARG(psta->hwaddr) + , psta->rssi_stat.undecorated_smoothed_pwdb + /* , STA_RX_PKTS_ARG(psta) */ + , STA_RX_PKTS_DIFF_ARG(psta) + , psta->expire_to + , psta->state & WIFI_SLEEP_STATE ? "PS, " : "" + , psta->state & WIFI_STA_ALIVE_CHK_STATE ? "SAC, " : "" + , psta->sleepq_len + ); +#endif + + /* if(sta_last_rx_pkts(psta) == sta_rx_pkts(psta)) */ + if ((psta->sta_stats.last_rx_data_pkts + psta->sta_stats.last_rx_ctrl_pkts) == (psta->sta_stats.rx_data_pkts + psta->sta_stats.rx_ctrl_pkts)) { +#if 0 + if (psta->state & WIFI_SLEEP_STATE) + ret = _TRUE; +#endif + } else + ret = _TRUE; + + sta_update_last_rx_pkts(psta); + + return ret; +} + +void expire_timeout_chk(_adapter *padapter) +{ + _irqL irqL; + _list *phead, *plist; + u8 updated = _FALSE; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 chk_alive_num = 0; + char chk_alive_list[NUM_STA]; + int i; + + +#ifdef CONFIG_MCC_MODE + /* then driver may check fail due to not recv client's frame under sitesurvey, + * don't expire timeout chk under MCC under sitesurvey */ + + if (rtw_hal_mcc_link_status_chk(padapter, __func__) == _FALSE) + return; +#endif + + _enter_critical_bh(&pstapriv->auth_list_lock, &irqL); + + phead = &pstapriv->auth_list; + plist = get_next(phead); + + /* check auth_queue */ +#ifdef DBG_EXPIRATION_CHK + if (rtw_end_of_queue_search(phead, plist) == _FALSE) { + RTW_INFO(FUNC_NDEV_FMT" auth_list, cnt:%u\n" + , FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->auth_list_cnt); + } +#endif + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, auth_list); + + plist = get_next(plist); + + +#ifdef CONFIG_ATMEL_RC_PATCH + if (_TRUE == _rtw_memcmp((void *)(pstapriv->atmel_rc_pattern), (void *)(psta->hwaddr), ETH_ALEN)) + continue; + if (psta->flag_atmel_rc) + continue; +#endif + if (psta->expire_to > 0) { + psta->expire_to--; + if (psta->expire_to == 0) { + rtw_list_delete(&psta->auth_list); + pstapriv->auth_list_cnt--; + + RTW_INFO("auth expire %02X%02X%02X%02X%02X%02X\n", + psta->hwaddr[0], psta->hwaddr[1], psta->hwaddr[2], psta->hwaddr[3], psta->hwaddr[4], psta->hwaddr[5]); + + _exit_critical_bh(&pstapriv->auth_list_lock, &irqL); + + /* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + rtw_free_stainfo(padapter, psta); + /* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + + _enter_critical_bh(&pstapriv->auth_list_lock, &irqL); + } + } + + } + + _exit_critical_bh(&pstapriv->auth_list_lock, &irqL); + psta = NULL; + + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + phead = &pstapriv->asoc_list; + plist = get_next(phead); + + /* check asoc_queue */ +#ifdef DBG_EXPIRATION_CHK + if (rtw_end_of_queue_search(phead, plist) == _FALSE) { + RTW_INFO(FUNC_NDEV_FMT" asoc_list, cnt:%u\n" + , FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->asoc_list_cnt); + } +#endif + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); + plist = get_next(plist); +#ifdef CONFIG_ATMEL_RC_PATCH + RTW_INFO("%s:%d psta=%p, %02x,%02x||%02x,%02x \n\n", __func__, __LINE__, + psta, pstapriv->atmel_rc_pattern[0], pstapriv->atmel_rc_pattern[5], psta->hwaddr[0], psta->hwaddr[5]); + if (_TRUE == _rtw_memcmp((void *)pstapriv->atmel_rc_pattern, (void *)(psta->hwaddr), ETH_ALEN)) + continue; + if (psta->flag_atmel_rc) + continue; + RTW_INFO("%s: debug line:%d\n", __func__, __LINE__); +#endif +#ifdef CONFIG_AUTO_AP_MODE + if (psta->isrc) + continue; +#endif + if (chk_sta_is_alive(psta) || !psta->expire_to) { + psta->expire_to = pstapriv->expire_to; + psta->keep_alive_trycnt = 0; +#ifdef CONFIG_TX_MCAST2UNI + psta->under_exist_checking = 0; +#endif /* CONFIG_TX_MCAST2UNI */ + } else + psta->expire_to--; + +#ifndef CONFIG_ACTIVE_KEEP_ALIVE_CHECK +#ifdef CONFIG_80211N_HT +#ifdef CONFIG_TX_MCAST2UNI + if ((psta->flags & WLAN_STA_HT) && (psta->htpriv.agg_enable_bitmap || psta->under_exist_checking)) { + /* check sta by delba(addba) for 11n STA */ + /* ToDo: use CCX report to check for all STAs */ + /* RTW_INFO("asoc check by DELBA/ADDBA! (pstapriv->expire_to=%d s)(psta->expire_to=%d s), [%02x, %d]\n", pstapriv->expire_to*2, psta->expire_to*2, psta->htpriv.agg_enable_bitmap, psta->under_exist_checking); */ + + if (psta->expire_to <= (pstapriv->expire_to - 50)) { + RTW_INFO("asoc expire by DELBA/ADDBA! (%d s)\n", (pstapriv->expire_to - psta->expire_to) * 2); + psta->under_exist_checking = 0; + psta->expire_to = 0; + } else if (psta->expire_to <= (pstapriv->expire_to - 3) && (psta->under_exist_checking == 0)) { + RTW_INFO("asoc check by DELBA/ADDBA! (%d s)\n", (pstapriv->expire_to - psta->expire_to) * 2); + psta->under_exist_checking = 1; + /* tear down TX AMPDU */ + send_delba(padapter, 1, psta->hwaddr);/* */ /* originator */ + psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ + psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ + } + } +#endif /* CONFIG_TX_MCAST2UNI */ +#endif /* CONFIG_80211N_HT */ +#endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */ + + if (psta->expire_to <= 0) { + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + if (padapter->registrypriv.wifi_spec == 1) { + psta->expire_to = pstapriv->expire_to; + continue; + } + +#ifndef CONFIG_ACTIVE_KEEP_ALIVE_CHECK +#ifdef CONFIG_80211N_HT + +#define KEEP_ALIVE_TRYCNT (3) + + if (psta->keep_alive_trycnt > 0 && psta->keep_alive_trycnt <= KEEP_ALIVE_TRYCNT) { + if (psta->state & WIFI_STA_ALIVE_CHK_STATE) + psta->state ^= WIFI_STA_ALIVE_CHK_STATE; + else + psta->keep_alive_trycnt = 0; + + } else if ((psta->keep_alive_trycnt > KEEP_ALIVE_TRYCNT) && !(psta->state & WIFI_STA_ALIVE_CHK_STATE)) + psta->keep_alive_trycnt = 0; + if ((psta->htpriv.ht_option == _TRUE) && (psta->htpriv.ampdu_enable == _TRUE)) { + uint priority = 1; /* test using BK */ + u8 issued = 0; + + /* issued = (psta->htpriv.agg_enable_bitmap>>priority)&0x1; */ + issued |= (psta->htpriv.candidate_tid_bitmap >> priority) & 0x1; + + if (0 == issued) { + if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) { + psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority); + + if (psta->state & WIFI_SLEEP_STATE) + psta->expire_to = 2; /* 2x2=4 sec */ + else + psta->expire_to = 1; /* 2 sec */ + + psta->state |= WIFI_STA_ALIVE_CHK_STATE; + + /* add_ba_hdl(padapter, (u8*)paddbareq_parm); */ + + RTW_INFO("issue addba_req to check if sta alive, keep_alive_trycnt=%d\n", psta->keep_alive_trycnt); + + issue_addba_req(padapter, psta->hwaddr, (u8)priority); + + _set_timer(&psta->addba_retry_timer, ADDBA_TO); + + psta->keep_alive_trycnt++; + + continue; + } + } + } + if (psta->keep_alive_trycnt > 0 && psta->state & WIFI_STA_ALIVE_CHK_STATE) { + psta->keep_alive_trycnt = 0; + psta->state ^= WIFI_STA_ALIVE_CHK_STATE; + RTW_INFO("change to another methods to check alive if staion is at ps mode\n"); + } + +#endif /* CONFIG_80211N_HT */ +#endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */ + if (psta->state & WIFI_SLEEP_STATE) { + if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) { + /* to check if alive by another methods if staion is at ps mode. */ + psta->expire_to = pstapriv->expire_to; + psta->state |= WIFI_STA_ALIVE_CHK_STATE; + + /* RTW_INFO("alive chk, sta:" MAC_FMT " is at ps mode!\n", MAC_ARG(psta->hwaddr)); */ + + /* to update bcn with tim_bitmap for this station */ + pstapriv->tim_bitmap |= BIT(psta->aid); + update_beacon(padapter, _TIM_IE_, NULL, _TRUE); + + if (!pmlmeext->active_keep_alive_check) + continue; + } + } +#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK + if (pmlmeext->active_keep_alive_check) { + int stainfo_offset; + + stainfo_offset = rtw_stainfo_offset(pstapriv, psta); + if (stainfo_offset_valid(stainfo_offset)) + chk_alive_list[chk_alive_num++] = stainfo_offset; + + continue; + } +#endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */ + rtw_list_delete(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + RTW_INFO("asoc expire "MAC_FMT", state=0x%x\n", MAC_ARG(psta->hwaddr), psta->state); + updated = ap_free_sta(padapter, psta, _FALSE, WLAN_REASON_DEAUTH_LEAVING, _TRUE); + } else { + /* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */ + if (psta->sleepq_len > (NR_XMITFRAME / pstapriv->asoc_list_cnt) + && padapter->xmitpriv.free_xmitframe_cnt < ((NR_XMITFRAME / pstapriv->asoc_list_cnt) / 2) + ) { + RTW_INFO("%s sta:"MAC_FMT", sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__ + , MAC_ARG(psta->hwaddr) + , psta->sleepq_len, padapter->xmitpriv.free_xmitframe_cnt, pstapriv->asoc_list_cnt); + wakeup_sta_to_xmit(padapter, psta); + } + } + } + + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + +#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK + if (chk_alive_num) { + + u8 backup_ch = 0, backup_bw, backup_offset; + u8 union_ch = 0, union_bw, union_offset; + u8 switch_channel = _TRUE; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + if (!rtw_mi_get_ch_setting_union(padapter, &union_ch, &union_bw, &union_offset) + || pmlmeext->cur_channel != union_ch) + goto bypass_active_keep_alive; + +#ifdef CONFIG_MCC_MODE + if (MCC_EN(padapter)) { + /* driver doesn't switch channel under MCC */ + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) + switch_channel = _FALSE; + } +#endif + /* switch to correct channel of current network before issue keep-alive frames */ + if (switch_channel == _TRUE && rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) { + backup_ch = rtw_get_oper_ch(padapter); + backup_bw = rtw_get_oper_bw(padapter); + backup_offset = rtw_get_oper_choffset(padapter); + set_channel_bwmode(padapter, union_ch, union_offset, union_bw); + } + + /* issue null data to check sta alive*/ + for (i = 0; i < chk_alive_num; i++) { + int ret = _FAIL; + + psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); +#ifdef CONFIG_ATMEL_RC_PATCH + if (_TRUE == _rtw_memcmp(pstapriv->atmel_rc_pattern, psta->hwaddr, ETH_ALEN)) + continue; + if (psta->flag_atmel_rc) + continue; +#endif + if (!(psta->state & _FW_LINKED)) + continue; + + if (psta->state & WIFI_SLEEP_STATE) + ret = issue_nulldata(padapter, psta->hwaddr, 0, 1, 50); + else + ret = issue_nulldata(padapter, psta->hwaddr, 0, 3, 50); + + psta->keep_alive_trycnt++; + if (ret == _SUCCESS) { + RTW_INFO("asoc check, sta(" MAC_FMT ") is alive\n", MAC_ARG(psta->hwaddr)); + psta->expire_to = pstapriv->expire_to; + psta->keep_alive_trycnt = 0; + continue; + } else if (psta->keep_alive_trycnt <= 3) { + RTW_INFO("ack check for asoc expire, keep_alive_trycnt=%d\n", psta->keep_alive_trycnt); + psta->expire_to = 1; + continue; + } + + psta->keep_alive_trycnt = 0; + RTW_INFO("asoc expire "MAC_FMT", state=0x%x\n", MAC_ARG(psta->hwaddr), psta->state); + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + if (rtw_is_list_empty(&psta->asoc_list) == _FALSE) { + rtw_list_delete(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + updated = ap_free_sta(padapter, psta, _FALSE, WLAN_REASON_DEAUTH_LEAVING, _TRUE); + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + } + + /* back to the original operation channel */ + if (switch_channel && backup_ch > 0) + set_channel_bwmode(padapter, backup_ch, backup_offset, backup_bw); + +bypass_active_keep_alive: + ; + } +#endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */ + + associated_clients_update(padapter, updated, STA_INFO_UPDATE_ALL); +} + +void add_RATid(_adapter *padapter, struct sta_info *psta, u8 rssi_level, u8 is_update_bw) +{ + int i; + u8 rf_type; + unsigned char sta_band = 0; + u64 tx_ra_bitmap = 0; + struct ht_priv *psta_ht = NULL; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + WLAN_BSSID_EX *pcur_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; + +#ifdef CONFIG_80211N_HT + if (psta) + psta_ht = &psta->htpriv; + else + return; +#endif /* CONFIG_80211N_HT */ + + if (!(psta->state & _FW_LINKED)) + return; + + rtw_hal_update_sta_rate_mask(padapter, psta); + tx_ra_bitmap = psta->ra_mask; + + if (pcur_network->Configuration.DSConfig > 14) { + + if (tx_ra_bitmap & 0xffff000) + sta_band |= WIRELESS_11_5N ; + + if (tx_ra_bitmap & 0xff0) + sta_band |= WIRELESS_11A; + + /* 5G band */ +#ifdef CONFIG_80211AC_VHT + if (psta->vhtpriv.vht_option) + sta_band = WIRELESS_11_5AC; +#endif + + } else { + if (tx_ra_bitmap & 0xffff000) + sta_band |= WIRELESS_11_24N; + + if (tx_ra_bitmap & 0xff0) + sta_band |= WIRELESS_11G; + + if (tx_ra_bitmap & 0x0f) + sta_band |= WIRELESS_11B; + } + + psta->wireless_mode = sta_band; + psta->raid = rtw_hal_networktype_to_raid(padapter, psta); + + if (psta->aid < NUM_STA) { + RTW_INFO("%s=> mac_id:%d , raid:%d, tx_ra_bitmap:0x%016llx, networkType:0x%02x\n", + __FUNCTION__, psta->mac_id, psta->raid, tx_ra_bitmap, psta->wireless_mode); + + rtw_update_ramask(padapter, psta, psta->mac_id, rssi_level, is_update_bw); + } else + RTW_INFO("station aid %d exceed the max number\n", psta->aid); + +} + +void update_bmc_sta(_adapter *padapter) +{ + _irqL irqL; + unsigned char network_type; + int supportRateNum = 0; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + WLAN_BSSID_EX *pcur_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; + struct sta_info *psta = rtw_get_bcmc_stainfo(padapter); + + if (psta) { + psta->aid = 0;/* default set to 0 */ + psta->qos_option = 0; +#ifdef CONFIG_80211N_HT + psta->htpriv.ht_option = _FALSE; +#endif /* CONFIG_80211N_HT */ + + psta->ieee8021x_blocked = 0; + + _rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); + + /* psta->dot118021XPrivacy = _NO_PRIVACY_; */ /* !!! remove it, because it has been set before this. */ + + /* prepare for add_RATid */ + supportRateNum = rtw_get_rateset_len((u8 *)&pcur_network->SupportedRates); + network_type = rtw_check_network_type((u8 *)&pcur_network->SupportedRates, supportRateNum, pcur_network->Configuration.DSConfig); + if (IsSupportedTxCCK(network_type)) + network_type = WIRELESS_11B; + else if (network_type == WIRELESS_INVALID) { /* error handling */ + if (pcur_network->Configuration.DSConfig > 14) + network_type = WIRELESS_11A; + else + network_type = WIRELESS_11B; + } + update_sta_basic_rate(psta, network_type); + psta->wireless_mode = network_type; + + rtw_hal_update_sta_rate_mask(padapter, psta); + + psta->raid = rtw_hal_networktype_to_raid(padapter, psta); + + _enter_critical_bh(&psta->lock, &irqL); + psta->state = _FW_LINKED; + _exit_critical_bh(&psta->lock, &irqL); + + rtw_sta_media_status_rpt(padapter, psta, 1); + rtw_hal_update_ra_mask(psta, psta->rssi_level, _TRUE); + } else + RTW_INFO("add_RATid_bmc_sta error!\n"); + +} + +/* notes: + * AID: 1~MAX for sta and 0 for bc/mc in ap/adhoc mode */ +void update_sta_info_apmode(_adapter *padapter, struct sta_info *psta) +{ + _irqL irqL; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); +#ifdef CONFIG_80211N_HT + struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; + struct ht_priv *phtpriv_sta = &psta->htpriv; +#endif /* CONFIG_80211N_HT */ + u8 cur_ldpc_cap = 0, cur_stbc_cap = 0, cur_beamform_cap = 0; + /* set intf_tag to if1 */ + /* psta->intf_tag = 0; */ + + RTW_INFO("%s\n", __FUNCTION__); + + /*alloc macid when call rtw_alloc_stainfo(),release macid when call rtw_free_stainfo()*/ + + /* ap mode */ + rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, _TRUE); + + if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) + psta->ieee8021x_blocked = _TRUE; + else + psta->ieee8021x_blocked = _FALSE; + + + /* update sta's cap */ + + /* ERP */ + VCS_update(padapter, psta); +#ifdef CONFIG_80211N_HT + /* HT related cap */ + if (phtpriv_sta->ht_option) { + /* check if sta supports rx ampdu */ + phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable; + + phtpriv_sta->rx_ampdu_min_spacing = (phtpriv_sta->ht_cap.ampdu_params_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2; + + /* bwmode */ + if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH)) + psta->bw_mode = CHANNEL_WIDTH_40; + else + psta->bw_mode = CHANNEL_WIDTH_20; + + if (psta->ht_40mhz_intolerant) + psta->bw_mode = CHANNEL_WIDTH_20; + + if (pmlmeext->cur_bwmode < psta->bw_mode) + psta->bw_mode = pmlmeext->cur_bwmode; + + phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset; + + + /* check if sta support s Short GI 20M */ + if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_20)) + phtpriv_sta->sgi_20m = _TRUE; + + /* check if sta support s Short GI 40M */ + if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_40)) { + if (psta->bw_mode == CHANNEL_WIDTH_40) /* according to psta->bw_mode */ + phtpriv_sta->sgi_40m = _TRUE; + else + phtpriv_sta->sgi_40m = _FALSE; + } + + psta->qos_option = _TRUE; + + /* B0 Config LDPC Coding Capability */ + if (TEST_FLAG(phtpriv_ap->ldpc_cap, LDPC_HT_ENABLE_TX) && + GET_HT_CAP_ELE_LDPC_CAP((u8 *)(&phtpriv_sta->ht_cap))) { + SET_FLAG(cur_ldpc_cap, (LDPC_HT_ENABLE_TX | LDPC_HT_CAP_TX)); + RTW_INFO("Enable HT Tx LDPC for STA(%d)\n", psta->aid); + } + + /* B7 B8 B9 Config STBC setting */ + if (TEST_FLAG(phtpriv_ap->stbc_cap, STBC_HT_ENABLE_TX) && + GET_HT_CAP_ELE_RX_STBC((u8 *)(&phtpriv_sta->ht_cap))) { + SET_FLAG(cur_stbc_cap, (STBC_HT_ENABLE_TX | STBC_HT_CAP_TX)); + RTW_INFO("Enable HT Tx STBC for STA(%d)\n", psta->aid); + } + +#ifdef CONFIG_BEAMFORMING + /*Config Tx beamforming setting*/ + if (TEST_FLAG(phtpriv_ap->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE) && + GET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP((u8 *)(&phtpriv_sta->ht_cap))) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE); + /*Shift to BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP*/ + SET_FLAG(cur_beamform_cap, GET_HT_CAP_TXBF_CHNL_ESTIMATION_NUM_ANTENNAS((u8 *)(&phtpriv_sta->ht_cap)) << 6); + } + + if (TEST_FLAG(phtpriv_ap->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE) && + GET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP((u8 *)(&phtpriv_sta->ht_cap))) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE); + /*Shift to BEAMFORMING_HT_BEAMFORMER_STEER_NUM*/ + SET_FLAG(cur_beamform_cap, GET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS((u8 *)(&phtpriv_sta->ht_cap)) << 4); + } + if (cur_beamform_cap) + RTW_INFO("Client STA(%d) HT Beamforming Cap = 0x%02X\n", psta->aid, cur_beamform_cap); +#endif /*CONFIG_BEAMFORMING*/ + } else { + phtpriv_sta->ampdu_enable = _FALSE; + + phtpriv_sta->sgi_20m = _FALSE; + phtpriv_sta->sgi_40m = _FALSE; + psta->bw_mode = CHANNEL_WIDTH_20; + phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + } + + phtpriv_sta->ldpc_cap = cur_ldpc_cap; + phtpriv_sta->stbc_cap = cur_stbc_cap; + phtpriv_sta->beamform_cap = cur_beamform_cap; + + /* Rx AMPDU */ + send_delba(padapter, 0, psta->hwaddr);/* recipient */ + + /* TX AMPDU */ + send_delba(padapter, 1, psta->hwaddr);/* */ /* originator */ + phtpriv_sta->agg_enable_bitmap = 0x0;/* reset */ + phtpriv_sta->candidate_tid_bitmap = 0x0;/* reset */ +#endif /* CONFIG_80211N_HT */ + +#ifdef CONFIG_80211AC_VHT + update_sta_vht_info_apmode(padapter, psta); +#endif + + update_ldpc_stbc_cap(psta); + + /* todo: init other variables */ + + _rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); + + + /* add ratid */ + /* add_RATid(padapter, psta); */ /* move to ap_sta_info_defer_update() */ + + + _enter_critical_bh(&psta->lock, &irqL); + psta->state |= _FW_LINKED; + _exit_critical_bh(&psta->lock, &irqL); + + +} + +static void update_ap_info(_adapter *padapter, struct sta_info *psta) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); +#ifdef CONFIG_80211N_HT + struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; +#endif /* CONFIG_80211N_HT */ + + psta->wireless_mode = pmlmeext->cur_wireless_mode; + + psta->bssratelen = rtw_get_rateset_len(pnetwork->SupportedRates); + _rtw_memcpy(psta->bssrateset, pnetwork->SupportedRates, psta->bssratelen); + +#ifdef CONFIG_80211N_HT + /* HT related cap */ + if (phtpriv_ap->ht_option) { + /* check if sta supports rx ampdu */ + /* phtpriv_ap->ampdu_enable = phtpriv_ap->ampdu_enable; */ + + /* check if sta support s Short GI 20M */ + if ((phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_20)) + phtpriv_ap->sgi_20m = _TRUE; + /* check if sta support s Short GI 40M */ + if ((phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_40)) + phtpriv_ap->sgi_40m = _TRUE; + + psta->qos_option = _TRUE; + } else { + phtpriv_ap->ampdu_enable = _FALSE; + + phtpriv_ap->sgi_20m = _FALSE; + phtpriv_ap->sgi_40m = _FALSE; + } + + psta->bw_mode = pmlmeext->cur_bwmode; + phtpriv_ap->ch_offset = pmlmeext->cur_ch_offset; + + phtpriv_ap->agg_enable_bitmap = 0x0;/* reset */ + phtpriv_ap->candidate_tid_bitmap = 0x0;/* reset */ + + _rtw_memcpy(&psta->htpriv, &pmlmepriv->htpriv, sizeof(struct ht_priv)); + +#ifdef CONFIG_80211AC_VHT + _rtw_memcpy(&psta->vhtpriv, &pmlmepriv->vhtpriv, sizeof(struct vht_priv)); +#endif /* CONFIG_80211AC_VHT */ + +#endif /* CONFIG_80211N_HT */ + + psta->state |= WIFI_AP_STATE; /* Aries, add,fix bug of flush_cam_entry at STOP AP mode , 0724 */ +} + +static void rtw_set_hw_wmm_param(_adapter *padapter) +{ + u8 ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime; + u8 acm_mask; + u16 TXOP; + u32 acParm, i; + u32 edca[4], inx[4]; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct registry_priv *pregpriv = &padapter->registrypriv; + + acm_mask = 0; + + if (is_supported_5g(pmlmeext->cur_wireless_mode) || + (pmlmeext->cur_wireless_mode & WIRELESS_11_24N)) + aSifsTime = 16; + else + aSifsTime = 10; + + if (pmlmeinfo->WMM_enable == 0) { + padapter->mlmepriv.acm_mask = 0; + + AIFS = aSifsTime + (2 * pmlmeinfo->slotTime); + + if (pmlmeext->cur_wireless_mode & (WIRELESS_11G | WIRELESS_11A)) { + ECWMin = 4; + ECWMax = 10; + } else if (pmlmeext->cur_wireless_mode & WIRELESS_11B) { + ECWMin = 5; + ECWMax = 10; + } else { + ECWMin = 4; + ECWMax = 10; + } + + TXOP = 0; + acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm)); + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm)); + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm)); + + ECWMin = 2; + ECWMax = 3; + TXOP = 0x2f; + acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm)); + + } else { + edca[0] = edca[1] = edca[2] = edca[3] = 0; + + /*TODO:*/ + acm_mask = 0; + padapter->mlmepriv.acm_mask = acm_mask; + +#if 0 + /* BK */ + /* AIFS = AIFSN * slot time + SIFS - r2t phy delay */ +#endif + AIFS = (7 * pmlmeinfo->slotTime) + aSifsTime; + ECWMin = 4; + ECWMax = 10; + TXOP = 0; + acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm)); + edca[XMIT_BK_QUEUE] = acParm; + RTW_INFO("WMM(BK): %x\n", acParm); + + /* BE */ + AIFS = (3 * pmlmeinfo->slotTime) + aSifsTime; + ECWMin = 4; + ECWMax = 6; + TXOP = 0; + acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm)); + edca[XMIT_BE_QUEUE] = acParm; + RTW_INFO("WMM(BE): %x\n", acParm); + + /* VI */ + AIFS = (1 * pmlmeinfo->slotTime) + aSifsTime; + ECWMin = 3; + ECWMax = 4; + TXOP = 94; + acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm)); + edca[XMIT_VI_QUEUE] = acParm; + RTW_INFO("WMM(VI): %x\n", acParm); + + /* VO */ + AIFS = (1 * pmlmeinfo->slotTime) + aSifsTime; + ECWMin = 2; + ECWMax = 3; + TXOP = 47; + acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm)); + edca[XMIT_VO_QUEUE] = acParm; + RTW_INFO("WMM(VO): %x\n", acParm); + + + if (padapter->registrypriv.acm_method == 1) + rtw_hal_set_hwreg(padapter, HW_VAR_ACM_CTRL, (u8 *)(&acm_mask)); + else + padapter->mlmepriv.acm_mask = acm_mask; + + inx[0] = 0; + inx[1] = 1; + inx[2] = 2; + inx[3] = 3; + + if (pregpriv->wifi_spec == 1) { + u32 j, tmp, change_inx = _FALSE; + + /* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */ + for (i = 0 ; i < 4 ; i++) { + for (j = i + 1 ; j < 4 ; j++) { + /* compare CW and AIFS */ + if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) + change_inx = _TRUE; + else if ((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) { + /* compare TXOP */ + if ((edca[j] >> 16) > (edca[i] >> 16)) + change_inx = _TRUE; + } + + if (change_inx) { + tmp = edca[i]; + edca[i] = edca[j]; + edca[j] = tmp; + + tmp = inx[i]; + inx[i] = inx[j]; + inx[j] = tmp; + + change_inx = _FALSE; + } + } + } + } + + for (i = 0 ; i < 4 ; i++) { + pxmitpriv->wmm_para_seq[i] = inx[i]; + RTW_INFO("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]); + } + + } + +} + +static void update_hw_ht_param(_adapter *padapter) +{ + unsigned char max_AMPDU_len; + unsigned char min_MPDU_spacing; + struct registry_priv *pregpriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + RTW_INFO("%s\n", __FUNCTION__); + + + /* handle A-MPDU parameter field */ + /* + AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k + AMPDU_para [4:2]:Min MPDU Start Spacing + */ + max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; + + min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; + + rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); + + rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); + + /* */ + /* Config SM Power Save setting */ + /* */ + pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2; + if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) { +#if 0 + u8 i; + /* update the MCS rates */ + for (i = 0; i < 16; i++) + pmlmeinfo->HT_caps.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; +#endif + RTW_INFO("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __FUNCTION__); + } + + /* */ + /* Config current HT Protection mode. */ + /* */ + /* pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; */ + +} + +static void rtw_ap_check_scan(_adapter *padapter) +{ + _irqL irqL; + _list *plist, *phead; + u32 delta_time, lifetime; + struct wlan_network *pnetwork = NULL; + WLAN_BSSID_EX *pbss = NULL; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + _queue *queue = &(pmlmepriv->scanned_queue); + u8 do_scan = _FALSE; + u8 reason = RTW_AUTO_SCAN_REASON_UNSPECIFIED; + + lifetime = SCANQUEUE_LIFETIME; /* 20 sec */ + + _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + phead = get_list_head(queue); + if (rtw_end_of_queue_search(phead, get_next(phead)) == _TRUE) + if (padapter->registrypriv.wifi_spec) { + do_scan = _TRUE; + reason |= RTW_AUTO_SCAN_REASON_2040_BSS; + } + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + +#ifdef CONFIG_AUTO_CHNL_SEL_NHM + if (padapter->registrypriv.acs_auto_scan) { + do_scan = _TRUE; + reason |= RTW_AUTO_SCAN_REASON_ACS; + rtw_acs_start(padapter, _TRUE); + } +#endif + + if (_TRUE == do_scan) { + RTW_INFO("%s : drv scans by itself and wait_completed\n", __func__); + rtw_drv_scan_by_self(padapter, reason); + rtw_scan_wait_completed(padapter); + } + +#ifdef CONFIG_AUTO_CHNL_SEL_NHM + if (padapter->registrypriv.acs_auto_scan) + rtw_acs_start(padapter, _FALSE); +#endif + _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + + phead = get_list_head(queue); + plist = get_next(phead); + + while (1) { + + if (rtw_end_of_queue_search(phead, plist) == _TRUE) + break; + + pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); + + if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.Configuration.DSConfig) >= 0 + && rtw_mlme_band_check(padapter, pnetwork->network.Configuration.DSConfig) == _TRUE + && _TRUE == rtw_validate_ssid(&(pnetwork->network.Ssid))) { + delta_time = (u32) rtw_get_passing_time_ms(pnetwork->last_scanned); + + if (delta_time < lifetime) { + + uint ie_len = 0; + u8 *pbuf = NULL; + u8 *ie = NULL; + + pbss = &pnetwork->network; + ie = pbss->IEs; + + /*check if HT CAP INFO IE exists or not*/ + pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pbss->IELength - _BEACON_IE_OFFSET_)); + if (pbuf == NULL) { + /* HT CAP INFO IE don't exist, it is b/g mode bss.*/ + + if (_FALSE == ATOMIC_READ(&pmlmepriv->olbc)) + ATOMIC_SET(&pmlmepriv->olbc, _TRUE); + + if (_FALSE == ATOMIC_READ(&pmlmepriv->olbc_ht)) + ATOMIC_SET(&pmlmepriv->olbc_ht, _TRUE); + + if (padapter->registrypriv.wifi_spec) + RTW_INFO("%s: %s is a/b/g ap\n", __func__, pnetwork->network.Ssid.Ssid); + } + } + } + + plist = get_next(plist); + + } + + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + + pmlmepriv->num_sta_no_ht = 0; /* reset to 0 after ap do scanning*/ + +} + +void rtw_start_bss_hdl_after_chbw_decided(_adapter *adapter) +{ + WLAN_BSSID_EX *pnetwork = &(adapter->mlmepriv.cur_network.network); + struct sta_info *sta = NULL; + + /* update cur_wireless_mode */ + update_wireless_mode(adapter); + + /* update RRSR and RTS_INIT_RATE register after set channel and bandwidth */ + UpdateBrateTbl(adapter, pnetwork->SupportedRates); + rtw_hal_set_hwreg(adapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates); + + /* update capability after cur_wireless_mode updated */ + update_capinfo(adapter, rtw_get_capability(pnetwork)); + + /* update bc/mc sta_info */ + update_bmc_sta(adapter); + + /* update AP's sta info */ + sta = rtw_get_stainfo(&adapter->stapriv, pnetwork->MacAddress); + if (!sta) { + RTW_INFO(FUNC_ADPT_FMT" !sta for macaddr="MAC_FMT"\n", FUNC_ADPT_ARG(adapter), MAC_ARG(pnetwork->MacAddress)); + rtw_warn_on(1); + return; + } + + update_ap_info(adapter, sta); +} + +void start_bss_network(_adapter *padapter, struct createbss_parm *parm) +{ +#define DUMP_ADAPTERS_STATUS 0 + + u8 val8; + u16 bcn_interval; + u32 acparm; + struct registry_priv *pregpriv = &padapter->registrypriv; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct security_priv *psecuritypriv = &(padapter->securitypriv); + WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; /* used as input */ + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork_mlmeext = &(pmlmeinfo->network); + struct dvobj_priv *pdvobj = padapter->dvobj; + s16 req_ch = -1, req_bw = -1, req_offset = -1; + bool ch_setting_changed = _FALSE; + u8 ch_to_set = 0, bw_to_set, offset_to_set; + u8 doiqk = _FALSE; + /* use for check ch bw offset can be allowed or not */ + u8 chbw_allow = _TRUE; + + if (parm->req_ch != 0) { + /* bypass other setting, go checking ch, bw, offset */ + req_ch = parm->req_ch; + req_bw = parm->req_bw; + req_offset = parm->req_offset; + goto chbw_decision; + } else { + /* inform this request comes from upper layer */ + req_ch = 0; + } + + bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod; + + /* check if there is wps ie, */ + /* if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd, */ + /* and at first time the security ie ( RSN/WPA IE) will not include in beacon. */ + if (NULL == rtw_get_wps_ie(pnetwork->IEs + _FIXED_IE_LENGTH_, pnetwork->IELength - _FIXED_IE_LENGTH_, NULL, NULL)) + pmlmeext->bstart_bss = _TRUE; + + /* todo: update wmm, ht cap */ + /* pmlmeinfo->WMM_enable; */ + /* pmlmeinfo->HT_enable; */ + if (pmlmepriv->qospriv.qos_option) + pmlmeinfo->WMM_enable = _TRUE; +#ifdef CONFIG_80211N_HT + if (pmlmepriv->htpriv.ht_option) { + pmlmeinfo->WMM_enable = _TRUE; + pmlmeinfo->HT_enable = _TRUE; + /* pmlmeinfo->HT_info_enable = _TRUE; */ + /* pmlmeinfo->HT_caps_enable = _TRUE; */ + + update_hw_ht_param(padapter); + } +#endif /* #CONFIG_80211N_HT */ + +#ifdef CONFIG_80211AC_VHT + if (pmlmepriv->vhtpriv.vht_option) { + pmlmeinfo->VHT_enable = _TRUE; + update_hw_vht_param(padapter); + } +#endif /* CONFIG_80211AC_VHT */ + + if (pmlmepriv->cur_network.join_res != _TRUE) { /* setting only at first time */ + /* WEP Key will be set before this function, do not clear CAM. */ + if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) && (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_)) + flush_all_cam_entry(padapter); /* clear CAM */ + } + + /* set MSR to AP_Mode */ + Set_MSR(padapter, _HW_STATE_AP_); + + /* Set BSSID REG */ + rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pnetwork->MacAddress); + + /* Set EDCA param reg */ +#ifdef CONFIG_CONCURRENT_MODE + acparm = 0x005ea42b; +#else + acparm = 0x002F3217; /* VO */ +#endif + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm)); + acparm = 0x005E4317; /* VI */ + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm)); + /* acparm = 0x00105320; */ /* BE */ + acparm = 0x005ea42b; + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm)); + acparm = 0x0000A444; /* BK */ + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm)); + + /* Set Security */ + val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf; + rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + + /* Beacon Control related register */ + rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval)); + +chbw_decision: + ch_setting_changed = rtw_ap_chbw_decision(padapter, req_ch, req_bw, req_offset + , &ch_to_set, &bw_to_set, &offset_to_set, &chbw_allow); + + /* let pnetwork_mlmeext == pnetwork_mlme. */ + _rtw_memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length); + + rtw_start_bss_hdl_after_chbw_decided(padapter); + +#if defined(CONFIG_DFS_MASTER) + rtw_dfs_master_status_apply(padapter, MLME_AP_STARTED); +#endif + +#ifdef CONFIG_MCC_MODE + if (MCC_EN(padapter)) { + /* + * due to check under rtw_ap_chbw_decision + * if under MCC mode, means req channel setting is the same as current channel setting + * if not under MCC mode, mean req channel setting is not the same as current channel setting + */ + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) { + RTW_INFO(FUNC_ADPT_FMT": req channel setting is the same as current channel setting, go to update BCN\n" + , FUNC_ADPT_ARG(padapter)); + + goto update_beacon; + + } + } + + /* issue null data to AP for all interface connecting to AP before switch channel setting for softap */ + rtw_hal_mcc_issue_null_data(padapter, chbw_allow, 1); +#endif /* CONFIG_MCC_MODE */ + + doiqk = _TRUE; + rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk); + + if (ch_to_set != 0) { + set_channel_bwmode(padapter, ch_to_set, offset_to_set, bw_to_set); + rtw_mi_update_union_chan_inf(padapter, ch_to_set, offset_to_set, bw_to_set); + } + + doiqk = _FALSE; + rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk); + +#ifdef CONFIG_MCC_MODE + /* after set_channel_bwmode for backup IQK */ + rtw_hal_set_mcc_setting_start_bss_network(padapter, chbw_allow); +#endif + + if (DUMP_ADAPTERS_STATUS) { + RTW_INFO(FUNC_ADPT_FMT" done\n", FUNC_ADPT_ARG(padapter)); + dump_adapters_status(RTW_DBGDUMP , adapter_to_dvobj(padapter)); + } + +update_beacon: + /* update beacon content only if bstart_bss is _TRUE */ + if (_TRUE == pmlmeext->bstart_bss) { + + _irqL irqL; + + if ((ATOMIC_READ(&pmlmepriv->olbc) == _TRUE) || (ATOMIC_READ(&pmlmepriv->olbc_ht) == _TRUE)) { + /* AP is not starting a 40 MHz BSS in presence of an 802.11g BSS. */ + + pmlmepriv->ht_op_mode &= (~HT_INFO_OPERATION_MODE_OP_MODE_MASK); + pmlmepriv->ht_op_mode |= OP_MODE_MAY_BE_LEGACY_STAS; + update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _FALSE); + } + + update_beacon(padapter, _TIM_IE_, NULL, _FALSE); + +#ifdef CONFIG_SWTIMER_BASED_TXBCN + _enter_critical_bh(&pdvobj->ap_if_q.lock, &irqL); + if (rtw_is_list_empty(&padapter->list)) { + rtw_list_insert_tail(&padapter->list, get_list_head(&pdvobj->ap_if_q)); + pdvobj->nr_ap_if++; + pdvobj->inter_bcn_space = DEFAULT_BCN_INTERVAL / pdvobj->nr_ap_if; + } + _exit_critical_bh(&pdvobj->ap_if_q.lock, &irqL); + + rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pdvobj->inter_bcn_space)); + +#endif /*CONFIG_SWTIMER_BASED_TXBCN*/ + + } + + rtw_scan_wait_completed(padapter); + + /* send beacon */ + if ((0 == rtw_mi_check_fwstate(padapter, _FW_UNDER_SURVEY)) + && (0 == rtw_mi_check_fwstate(padapter, WIFI_OP_CH_SWITCHING)) + ) { + + /*update_beacon(padapter, _TIM_IE_, NULL, _TRUE);*/ + +#if !defined(CONFIG_INTERRUPT_BASED_TXBCN) +#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) +#ifdef CONFIG_SWTIMER_BASED_TXBCN + if (pdvobj->nr_ap_if == 1) { + RTW_INFO("start SW BCN TIMER!\n"); + _set_timer(&pdvobj->txbcn_timer, bcn_interval); + } +#else + /* other case will tx beacon when bcn interrupt coming in. */ + if (send_beacon(padapter) == _FAIL) + RTW_INFO("issue_beacon, fail!\n"); +#endif +#endif +#endif /* !defined(CONFIG_INTERRUPT_BASED_TXBCN) */ + } + + /*Set EDCA param reg after update cur_wireless_mode & update_capinfo*/ + if (pregpriv->wifi_spec == 1) + rtw_set_hw_wmm_param(padapter); + + /*pmlmeext->bstart_bss = _TRUE;*/ +} + +int rtw_check_beacon_data(_adapter *padapter, u8 *pbuf, int len) +{ + int ret = _SUCCESS; + u8 *p; + u8 *pHT_caps_ie = NULL; + u8 *pHT_info_ie = NULL; + u16 cap, ht_cap = _FALSE; + uint ie_len = 0; + int group_cipher, pairwise_cipher; + u8 channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX]; + int supportRateNum = 0; + u8 OUI1[] = {0x00, 0x50, 0xf2, 0x01}; + u8 wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; + u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + WLAN_BSSID_EX *pbss_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *ie = pbss_network->IEs; + u8 vht_cap = _FALSE; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 rf_num = 0; + + /* SSID */ + /* Supported rates */ + /* DS Params */ + /* WLAN_EID_COUNTRY */ + /* ERP Information element */ + /* Extended supported rates */ + /* WPA/WPA2 */ + /* Wi-Fi Wireless Multimedia Extensions */ + /* ht_capab, ht_oper */ + /* WPS IE */ + + RTW_INFO("%s, len=%d\n", __FUNCTION__, len); + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE) + return _FAIL; + + + if (len > MAX_IE_SZ) + return _FAIL; + + pbss_network->IELength = len; + + _rtw_memset(ie, 0, MAX_IE_SZ); + + _rtw_memcpy(ie, pbuf, pbss_network->IELength); + + + if (pbss_network->InfrastructureMode != Ndis802_11APMode) + return _FAIL; + + + rtw_ap_check_scan(padapter); + + + pbss_network->Rssi = 0; + + _rtw_memcpy(pbss_network->MacAddress, adapter_mac_addr(padapter), ETH_ALEN); + + /* beacon interval */ + p = rtw_get_beacon_interval_from_ie(ie);/* ie + 8; */ /* 8: TimeStamp, 2: Beacon Interval 2:Capability */ + /* pbss_network->Configuration.BeaconPeriod = le16_to_cpu(*(unsigned short*)p); */ + pbss_network->Configuration.BeaconPeriod = RTW_GET_LE16(p); + + /* capability */ + /* cap = *(unsigned short *)rtw_get_capability_from_ie(ie); */ + /* cap = le16_to_cpu(cap); */ + cap = RTW_GET_LE16(ie); + + /* SSID */ + p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) { + _rtw_memset(&pbss_network->Ssid, 0, sizeof(NDIS_802_11_SSID)); + _rtw_memcpy(pbss_network->Ssid.Ssid, (p + 2), ie_len); + pbss_network->Ssid.SsidLength = ie_len; +#ifdef CONFIG_P2P + _rtw_memcpy(padapter->wdinfo.p2p_group_ssid, pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength); + padapter->wdinfo.p2p_group_ssid_len = pbss_network->Ssid.SsidLength; +#endif + } + + /* chnnel */ + channel = 0; + pbss_network->Configuration.Length = 0; + p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) + channel = *(p + 2); + + pbss_network->Configuration.DSConfig = channel; + + + _rtw_memset(supportRate, 0, NDIS_802_11_LENGTH_RATES_EX); + /* get supported rates */ + p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p != NULL) { + _rtw_memcpy(supportRate, p + 2, ie_len); + supportRateNum = ie_len; + } + + /* get ext_supported rates */ + p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_); + if (p != NULL) { + _rtw_memcpy(supportRate + supportRateNum, p + 2, ie_len); + supportRateNum += ie_len; + + } + + network_type = rtw_check_network_type(supportRate, supportRateNum, channel); + + rtw_set_supported_rate(pbss_network->SupportedRates, network_type); + + + /* parsing ERP_IE */ + p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) + ERP_IE_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)p); + + /* update privacy/security */ + if (cap & BIT(4)) + pbss_network->Privacy = 1; + else + pbss_network->Privacy = 0; + + psecuritypriv->wpa_psk = 0; + + /* wpa2 */ + group_cipher = 0; + pairwise_cipher = 0; + psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_; + psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_; + p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) { + if (rtw_parse_wpa2_ie(p, ie_len + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; + + psecuritypriv->dot8021xalg = 1;/* psk, todo:802.1x */ + psecuritypriv->wpa_psk |= BIT(1); + + psecuritypriv->wpa2_group_cipher = group_cipher; + psecuritypriv->wpa2_pairwise_cipher = pairwise_cipher; +#if 0 + switch (group_cipher) { + case WPA_CIPHER_NONE: + psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_; + break; + case WPA_CIPHER_WEP40: + psecuritypriv->wpa2_group_cipher = _WEP40_; + break; + case WPA_CIPHER_TKIP: + psecuritypriv->wpa2_group_cipher = _TKIP_; + break; + case WPA_CIPHER_CCMP: + psecuritypriv->wpa2_group_cipher = _AES_; + break; + case WPA_CIPHER_WEP104: + psecuritypriv->wpa2_group_cipher = _WEP104_; + break; + } + + switch (pairwise_cipher) { + case WPA_CIPHER_NONE: + psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_; + break; + case WPA_CIPHER_WEP40: + psecuritypriv->wpa2_pairwise_cipher = _WEP40_; + break; + case WPA_CIPHER_TKIP: + psecuritypriv->wpa2_pairwise_cipher = _TKIP_; + break; + case WPA_CIPHER_CCMP: + psecuritypriv->wpa2_pairwise_cipher = _AES_; + break; + case WPA_CIPHER_WEP104: + psecuritypriv->wpa2_pairwise_cipher = _WEP104_; + break; + } +#endif + } + + } + + /* wpa */ + ie_len = 0; + group_cipher = 0; + pairwise_cipher = 0; + psecuritypriv->wpa_group_cipher = _NO_PRIVACY_; + psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_; + for (p = ie + _BEACON_IE_OFFSET_; ; p += (ie_len + 2)) { + p = rtw_get_ie(p, _SSN_IE_1_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); + if ((p) && (_rtw_memcmp(p + 2, OUI1, 4))) { + if (rtw_parse_wpa_ie(p, ie_len + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; + + psecuritypriv->dot8021xalg = 1;/* psk, todo:802.1x */ + + psecuritypriv->wpa_psk |= BIT(0); + + psecuritypriv->wpa_group_cipher = group_cipher; + psecuritypriv->wpa_pairwise_cipher = pairwise_cipher; + +#if 0 + switch (group_cipher) { + case WPA_CIPHER_NONE: + psecuritypriv->wpa_group_cipher = _NO_PRIVACY_; + break; + case WPA_CIPHER_WEP40: + psecuritypriv->wpa_group_cipher = _WEP40_; + break; + case WPA_CIPHER_TKIP: + psecuritypriv->wpa_group_cipher = _TKIP_; + break; + case WPA_CIPHER_CCMP: + psecuritypriv->wpa_group_cipher = _AES_; + break; + case WPA_CIPHER_WEP104: + psecuritypriv->wpa_group_cipher = _WEP104_; + break; + } + + switch (pairwise_cipher) { + case WPA_CIPHER_NONE: + psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_; + break; + case WPA_CIPHER_WEP40: + psecuritypriv->wpa_pairwise_cipher = _WEP40_; + break; + case WPA_CIPHER_TKIP: + psecuritypriv->wpa_pairwise_cipher = _TKIP_; + break; + case WPA_CIPHER_CCMP: + psecuritypriv->wpa_pairwise_cipher = _AES_; + break; + case WPA_CIPHER_WEP104: + psecuritypriv->wpa_pairwise_cipher = _WEP104_; + break; + } +#endif + } + + break; + + } + + if ((p == NULL) || (ie_len == 0)) + break; + + } + + /* wmm */ + ie_len = 0; + pmlmepriv->qospriv.qos_option = 0; + if (pregistrypriv->wmm_enable) { + for (p = ie + _BEACON_IE_OFFSET_; ; p += (ie_len + 2)) { + p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); + if ((p) && _rtw_memcmp(p + 2, WMM_PARA_IE, 6)) { + pmlmepriv->qospriv.qos_option = 1; + + *(p + 8) |= BIT(7); /* QoS Info, support U-APSD */ + + /* disable all ACM bits since the WMM admission control is not supported */ + *(p + 10) &= ~BIT(4); /* BE */ + *(p + 14) &= ~BIT(4); /* BK */ + *(p + 18) &= ~BIT(4); /* VI */ + *(p + 22) &= ~BIT(4); /* VO */ + + break; + } + + if ((p == NULL) || (ie_len == 0)) + break; + } + } +#ifdef CONFIG_80211N_HT + /* parsing HT_CAP_IE */ + p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) { + u8 rf_type = 0; + HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor = MAX_AMPDU_FACTOR_64K; + struct rtw_ieee80211_ht_cap *pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2); + + if (0) { + RTW_INFO(FUNC_ADPT_FMT" HT_CAP_IE from upper layer:\n", FUNC_ADPT_ARG(padapter)); + dump_ht_cap_ie_content(RTW_DBGDUMP, p + 2, ie_len); + } + + pHT_caps_ie = p; + + ht_cap = _TRUE; + network_type |= WIRELESS_11_24N; + + rtw_ht_use_default_setting(padapter); + + /* Update HT Capabilities Info field */ + if (pmlmepriv->htpriv.sgi_20m == _FALSE) + pht_cap->cap_info &= ~(IEEE80211_HT_CAP_SGI_20); + + if (pmlmepriv->htpriv.sgi_40m == _FALSE) + pht_cap->cap_info &= ~(IEEE80211_HT_CAP_SGI_40); + + if (!TEST_FLAG(pmlmepriv->htpriv.ldpc_cap, LDPC_HT_ENABLE_RX)) + pht_cap->cap_info &= ~(IEEE80211_HT_CAP_LDPC_CODING); + + if (!TEST_FLAG(pmlmepriv->htpriv.stbc_cap, STBC_HT_ENABLE_TX)) + pht_cap->cap_info &= ~(IEEE80211_HT_CAP_TX_STBC); + + if (!TEST_FLAG(pmlmepriv->htpriv.stbc_cap, STBC_HT_ENABLE_RX)) + pht_cap->cap_info &= ~(IEEE80211_HT_CAP_RX_STBC_3R); + + /* Update A-MPDU Parameters field */ + pht_cap->ampdu_params_info &= ~(IEEE80211_HT_CAP_AMPDU_FACTOR | IEEE80211_HT_CAP_AMPDU_DENSITY); + + if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) || + (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP)) + pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & (0x07 << 2)); + else + pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & 0x00); + + rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); + pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_FACTOR & max_rx_ampdu_factor); /* set Max Rx AMPDU size to 64K */ + + _rtw_memcpy(&(pmlmeinfo->HT_caps), pht_cap, sizeof(struct HT_caps_element)); + + /* Update Supported MCS Set field */ + { + struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); + u8 rx_nss = 0; + int i; + + rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + rx_nss = rtw_min(rf_type_to_rf_rx_cnt(rf_type), hal_spec->rx_nss_num); + + /* RX MCS Bitmask */ + switch (rx_nss) { + case 1: + set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_1R); + break; + case 2: + set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_2R); + break; + case 3: + set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_3R); + break; + case 4: + set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_4R); + break; + default: + RTW_WARN("rf_type:%d or rx_nss:%u is not expected\n", rf_type, hal_spec->rx_nss_num); + } + for (i = 0; i < 10; i++) + *(HT_CAP_ELE_RX_MCS_MAP(pht_cap) + i) &= padapter->mlmeextpriv.default_supported_mcs_set[i]; + } + +#ifdef CONFIG_BEAMFORMING + /* Use registry value to enable HT Beamforming. */ + /* ToDo: use configure file to set these capability. */ + pht_cap->tx_BF_cap_info = 0; + + /* HT Beamformer */ + if (TEST_FLAG(pmlmepriv->htpriv.beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) { + /* Transmit NDP Capable */ + SET_HT_CAP_TXBF_TRANSMIT_NDP_CAP(pht_cap, 1); + /* Explicit Compressed Steering Capable */ + SET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP(pht_cap, 1); + /* Compressed Steering Number Antennas */ + SET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(pht_cap, 1); + rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMER_CAP, (u8 *)&rf_num); + SET_HT_CAP_TXBF_CHNL_ESTIMATION_NUM_ANTENNAS(pht_cap, rf_num); + } + + /* HT Beamformee */ + if (TEST_FLAG(pmlmepriv->htpriv.beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) { + /* Receive NDP Capable */ + SET_HT_CAP_TXBF_RECEIVE_NDP_CAP(pht_cap, 1); + /* Explicit Compressed Beamforming Feedback Capable */ + SET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP(pht_cap, 2); + rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMEE_CAP, (u8 *)&rf_num); + SET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(pht_cap, rf_num); + } +#endif /* CONFIG_BEAMFORMING */ + + _rtw_memcpy(&pmlmepriv->htpriv.ht_cap, p + 2, ie_len); + + if (0) { + RTW_INFO(FUNC_ADPT_FMT" HT_CAP_IE driver masked:\n", FUNC_ADPT_ARG(padapter)); + dump_ht_cap_ie_content(RTW_DBGDUMP, p + 2, ie_len); + } + } + + /* parsing HT_INFO_IE */ + p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) + pHT_info_ie = p; +#endif /* CONFIG_80211N_HT */ + switch (network_type) { + case WIRELESS_11B: + pbss_network->NetworkTypeInUse = Ndis802_11DS; + break; + case WIRELESS_11G: + case WIRELESS_11BG: + case WIRELESS_11G_24N: + case WIRELESS_11BG_24N: + pbss_network->NetworkTypeInUse = Ndis802_11OFDM24; + break; + case WIRELESS_11A: + pbss_network->NetworkTypeInUse = Ndis802_11OFDM5; + break; + default: + pbss_network->NetworkTypeInUse = Ndis802_11OFDM24; + break; + } + + pmlmepriv->cur_network.network_type = network_type; + +#ifdef CONFIG_80211N_HT + pmlmepriv->htpriv.ht_option = _FALSE; + + if ((psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) || + (psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_TKIP)) { + /* todo: */ + /* ht_cap = _FALSE; */ + } + + /* ht_cap */ + if (pregistrypriv->ht_enable && ht_cap == _TRUE) { + pmlmepriv->htpriv.ht_option = _TRUE; + pmlmepriv->qospriv.qos_option = 1; + + pmlmepriv->htpriv.ampdu_enable = pregistrypriv->ampdu_enable ? _TRUE : _FALSE; + + HT_caps_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)pHT_caps_ie); + + HT_info_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)pHT_info_ie); + } +#endif + +#ifdef CONFIG_80211AC_VHT + + /* Parsing VHT CAP IE */ + p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_VHTCapability, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) + vht_cap = _TRUE; + /* Parsing VHT OPERATION IE */ + + + pmlmepriv->vhtpriv.vht_option = _FALSE; + /* if channel in 5G band, then add vht ie . */ + if ((pbss_network->Configuration.DSConfig > 14) + && (pmlmepriv->htpriv.ht_option == _TRUE) + && REGSTY_IS_11AC_ENABLE(pregistrypriv) + && hal_chk_proto_cap(padapter, PROTO_CAP_11AC) + && (!pmlmepriv->country_ent || COUNTRY_CHPLAN_EN_11AC(pmlmepriv->country_ent)) + ) { + if (vht_cap == _TRUE) + pmlmepriv->vhtpriv.vht_option = _TRUE; + else if (REGSTY_IS_11AC_AUTO(pregistrypriv)) { + u8 cap_len, operation_len; + + rtw_vht_use_default_setting(padapter); + + { + /* VHT Operation mode notifiy bit in Extended IE (127) */ + uint len = 0; + + SET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(pmlmepriv->ext_capab_ie_data, 1); + pmlmepriv->ext_capab_ie_len = 10; + rtw_set_ie(pbss_network->IEs + pbss_network->IELength, EID_EXTCapability, 8, pmlmepriv->ext_capab_ie_data, &len); + pbss_network->IELength += pmlmepriv->ext_capab_ie_len; + } + + /* VHT Capabilities element */ + cap_len = rtw_build_vht_cap_ie(padapter, pbss_network->IEs + pbss_network->IELength); + pbss_network->IELength += cap_len; + + /* VHT Operation element */ + operation_len = rtw_build_vht_operation_ie(padapter, pbss_network->IEs + pbss_network->IELength, pbss_network->Configuration.DSConfig); + pbss_network->IELength += operation_len; + + pmlmepriv->vhtpriv.vht_option = _TRUE; + } + } +#endif /* CONFIG_80211AC_VHT */ + + if(pbss_network->Configuration.DSConfig <= 14 && padapter->registrypriv.wifi_spec == 1) { + uint len = 0; + + SET_EXT_CAPABILITY_ELE_BSS_COEXIST(pmlmepriv->ext_capab_ie_data, 1); + pmlmepriv->ext_capab_ie_len = 10; + rtw_set_ie(pbss_network->IEs + pbss_network->IELength, EID_EXTCapability, 8, pmlmepriv->ext_capab_ie_data, &len); + pbss_network->IELength += pmlmepriv->ext_capab_ie_len; + } + + pbss_network->Length = get_WLAN_BSSID_EX_sz((WLAN_BSSID_EX *)pbss_network); + + rtw_ies_get_chbw(pbss_network->IEs + _BEACON_IE_OFFSET_, pbss_network->IELength - _BEACON_IE_OFFSET_ + , &pmlmepriv->ori_ch, &pmlmepriv->ori_bw, &pmlmepriv->ori_offset); + rtw_warn_on(pmlmepriv->ori_ch == 0); + + { + /* alloc sta_info for ap itself */ + + struct sta_info *sta; + + sta = rtw_get_stainfo(&padapter->stapriv, pbss_network->MacAddress); + if (!sta) { + sta = rtw_alloc_stainfo(&padapter->stapriv, pbss_network->MacAddress); + if (sta == NULL) + return _FAIL; + } + } + + rtw_startbss_cmd(padapter, RTW_CMDF_WAIT_ACK); + { + int sk_band = RTW_GET_SCAN_BAND_SKIP(padapter); + + if (sk_band) + RTW_CLR_SCAN_BAND_SKIP(padapter, sk_band); + } + + rtw_indicate_connect(padapter); + + pmlmepriv->cur_network.join_res = _TRUE;/* for check if already set beacon */ + + /* update bc/mc sta_info */ + /* update_bmc_sta(padapter); */ + + return ret; + +} + +#if CONFIG_RTW_MACADDR_ACL +void rtw_macaddr_acl_init(_adapter *adapter) +{ + struct sta_priv *stapriv = &adapter->stapriv; + struct wlan_acl_pool *acl = &stapriv->acl_list; + _queue *acl_node_q = &acl->acl_node_q; + int i; + _irqL irqL; + + _enter_critical_bh(&(acl_node_q->lock), &irqL); + _rtw_init_listhead(&(acl_node_q->queue)); + acl->num = 0; + acl->mode = RTW_ACL_MODE_DISABLED; + for (i = 0; i < NUM_ACL; i++) { + _rtw_init_listhead(&acl->aclnode[i].list); + acl->aclnode[i].valid = _FALSE; + } + _exit_critical_bh(&(acl_node_q->lock), &irqL); +} + +void rtw_macaddr_acl_deinit(_adapter *adapter) +{ + struct sta_priv *stapriv = &adapter->stapriv; + struct wlan_acl_pool *acl = &stapriv->acl_list; + _queue *acl_node_q = &acl->acl_node_q; + _irqL irqL; + _list *head, *list; + struct rtw_wlan_acl_node *acl_node; + + _enter_critical_bh(&(acl_node_q->lock), &irqL); + head = get_list_head(acl_node_q); + list = get_next(head); + while (rtw_end_of_queue_search(head, list) == _FALSE) { + acl_node = LIST_CONTAINOR(list, struct rtw_wlan_acl_node, list); + list = get_next(list); + + if (acl_node->valid == _TRUE) { + acl_node->valid = _FALSE; + rtw_list_delete(&acl_node->list); + acl->num--; + } + } + _exit_critical_bh(&(acl_node_q->lock), &irqL); + + rtw_warn_on(acl->num); + acl->mode = RTW_ACL_MODE_DISABLED; +} + +void rtw_set_macaddr_acl(_adapter *adapter, int mode) +{ + struct sta_priv *stapriv = &adapter->stapriv; + struct wlan_acl_pool *acl = &stapriv->acl_list; + + RTW_INFO(FUNC_ADPT_FMT" mode=%d\n", FUNC_ADPT_ARG(adapter), mode); + + acl->mode = mode; + + if (mode == RTW_ACL_MODE_DISABLED) + rtw_macaddr_acl_deinit(adapter); +} + +int rtw_acl_add_sta(_adapter *adapter, const u8 *addr) +{ + _irqL irqL; + _list *list, *head; + u8 existed = 0; + int i = -1, ret = 0; + struct rtw_wlan_acl_node *acl_node; + struct sta_priv *stapriv = &adapter->stapriv; + struct wlan_acl_pool *acl = &stapriv->acl_list; + _queue *acl_node_q = &acl->acl_node_q; + + _enter_critical_bh(&(acl_node_q->lock), &irqL); + + head = get_list_head(acl_node_q); + list = get_next(head); + + /* search for existed entry */ + while (rtw_end_of_queue_search(head, list) == _FALSE) { + acl_node = LIST_CONTAINOR(list, struct rtw_wlan_acl_node, list); + list = get_next(list); + + if (_rtw_memcmp(acl_node->addr, addr, ETH_ALEN)) { + if (acl_node->valid == _TRUE) { + existed = 1; + break; + } + } + } + if (existed) + goto release_lock; + + if (acl->num >= NUM_ACL) + goto release_lock; + + /* find empty one and use */ + for (i = 0; i < NUM_ACL; i++) { + + acl_node = &acl->aclnode[i]; + if (acl_node->valid == _FALSE) { + + _rtw_init_listhead(&acl_node->list); + _rtw_memcpy(acl_node->addr, addr, ETH_ALEN); + acl_node->valid = _TRUE; + + rtw_list_insert_tail(&acl_node->list, get_list_head(acl_node_q)); + acl->num++; + break; + } + } + +release_lock: + _exit_critical_bh(&(acl_node_q->lock), &irqL); + + if (!existed && (i < 0 || i >= NUM_ACL)) + ret = -1; + + RTW_INFO(FUNC_ADPT_FMT" "MAC_FMT" %s (acl_num=%d)\n" + , FUNC_ADPT_ARG(adapter), MAC_ARG(addr) + , (existed ? "existed" : ((i < 0 || i >= NUM_ACL) ? "no room" : "added")) + , acl->num); + + return ret; +} + +int rtw_acl_remove_sta(_adapter *adapter, const u8 *addr) +{ + _irqL irqL; + _list *list, *head; + int ret = 0; + struct rtw_wlan_acl_node *acl_node; + struct sta_priv *stapriv = &adapter->stapriv; + struct wlan_acl_pool *acl = &stapriv->acl_list; + _queue *acl_node_q = &acl->acl_node_q; + u8 is_baddr = is_broadcast_mac_addr(addr); + u8 match = 0; + + _enter_critical_bh(&(acl_node_q->lock), &irqL); + + head = get_list_head(acl_node_q); + list = get_next(head); + + while (rtw_end_of_queue_search(head, list) == _FALSE) { + acl_node = LIST_CONTAINOR(list, struct rtw_wlan_acl_node, list); + list = get_next(list); + + if (is_baddr || _rtw_memcmp(acl_node->addr, addr, ETH_ALEN)) { + if (acl_node->valid == _TRUE) { + acl_node->valid = _FALSE; + rtw_list_delete(&acl_node->list); + acl->num--; + match = 1; + } + } + } + + _exit_critical_bh(&(acl_node_q->lock), &irqL); + + RTW_INFO(FUNC_ADPT_FMT" "MAC_FMT" %s (acl_num=%d)\n" + , FUNC_ADPT_ARG(adapter), MAC_ARG(addr) + , is_baddr ? "clear all" : (match ? "match" : "no found") + , acl->num); + + return ret; +} +#endif /* CONFIG_RTW_MACADDR_ACL */ + +u8 rtw_ap_set_pairwise_key(_adapter *padapter, struct sta_info *psta) +{ + struct cmd_obj *ph2c; + struct set_stakey_parm *psetstakey_para; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + psetstakey_para = (struct set_stakey_parm *)rtw_zmalloc(sizeof(struct set_stakey_parm)); + if (psetstakey_para == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); + + + psetstakey_para->algorithm = (u8)psta->dot118021XPrivacy; + + _rtw_memcpy(psetstakey_para->addr, psta->hwaddr, ETH_ALEN); + + _rtw_memcpy(psetstakey_para->key, &psta->dot118021x_UncstKey, 16); + + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + return res; + +} + +static int rtw_ap_set_key(_adapter *padapter, u8 *key, u8 alg, int keyid, u8 set_tx) +{ + u8 keylen; + struct cmd_obj *pcmd; + struct setkey_parm *psetkeyparm; + struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); + int res = _SUCCESS; + + /* RTW_INFO("%s\n", __FUNCTION__); */ + + pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmd == NULL) { + res = _FAIL; + goto exit; + } + psetkeyparm = (struct setkey_parm *)rtw_zmalloc(sizeof(struct setkey_parm)); + if (psetkeyparm == NULL) { + rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + _rtw_memset(psetkeyparm, 0, sizeof(struct setkey_parm)); + + psetkeyparm->keyid = (u8)keyid; + if (is_wep_enc(alg)) + padapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid); + + psetkeyparm->algorithm = alg; + + psetkeyparm->set_tx = set_tx; + + switch (alg) { + case _WEP40_: + keylen = 5; + break; + case _WEP104_: + keylen = 13; + break; + case _TKIP_: + case _TKIP_WTMIC_: + case _AES_: + default: + keylen = 16; + } + + _rtw_memcpy(&(psetkeyparm->key[0]), key, keylen); + + pcmd->cmdcode = _SetKey_CMD_; + pcmd->parmbuf = (u8 *)psetkeyparm; + pcmd->cmdsz = (sizeof(struct setkey_parm)); + pcmd->rsp = NULL; + pcmd->rspsz = 0; + + + _rtw_init_listhead(&pcmd->list); + + res = rtw_enqueue_cmd(pcmdpriv, pcmd); + +exit: + + return res; +} + +int rtw_ap_set_group_key(_adapter *padapter, u8 *key, u8 alg, int keyid) +{ + RTW_INFO("%s\n", __FUNCTION__); + + return rtw_ap_set_key(padapter, key, alg, keyid, 1); +} + +int rtw_ap_set_wep_key(_adapter *padapter, u8 *key, u8 keylen, int keyid, u8 set_tx) +{ + u8 alg; + + switch (keylen) { + case 5: + alg = _WEP40_; + break; + case 13: + alg = _WEP104_; + break; + default: + alg = _NO_PRIVACY_; + } + + RTW_INFO("%s\n", __FUNCTION__); + + return rtw_ap_set_key(padapter, key, alg, keyid, set_tx); +} + +u8 rtw_ap_bmc_frames_hdl(_adapter *padapter) +{ +#define HIQ_XMIT_COUNTS (6) + _irqL irqL; + struct sta_info *psta_bmc; + _list *xmitframe_plist, *xmitframe_phead; + struct xmit_frame *pxmitframe = NULL; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct sta_priv *pstapriv = &padapter->stapriv; + bool update_tim = _FALSE; + + + if (padapter->registrypriv.wifi_spec != 1) + return H2C_SUCCESS; + + + psta_bmc = rtw_get_bcmc_stainfo(padapter); + if (!psta_bmc) + return H2C_SUCCESS; + + + _enter_critical_bh(&pxmitpriv->lock, &irqL); + + if ((pstapriv->tim_bitmap & BIT(0)) && (psta_bmc->sleepq_len > 0)) { + int tx_counts = 0; + + _update_beacon(padapter, _TIM_IE_, NULL, _FALSE, "update TIM with TIB=1"); + + RTW_INFO("sleepq_len of bmc_sta = %d\n", psta_bmc->sleepq_len); + + xmitframe_phead = get_list_head(&psta_bmc->sleep_q); + xmitframe_plist = get_next(xmitframe_phead); + + while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) { + pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); + + xmitframe_plist = get_next(xmitframe_plist); + + rtw_list_delete(&pxmitframe->list); + + psta_bmc->sleepq_len--; + tx_counts++; + + if (psta_bmc->sleepq_len > 0) + pxmitframe->attrib.mdata = 1; + else + pxmitframe->attrib.mdata = 0; + + if (tx_counts == HIQ_XMIT_COUNTS) + pxmitframe->attrib.mdata = 0; + + pxmitframe->attrib.triggered = 1; + + if (xmitframe_hiq_filter(pxmitframe) == _TRUE) + pxmitframe->attrib.qsel = QSLT_HIGH;/*HIQ*/ + + rtw_hal_xmitframe_enqueue(padapter, pxmitframe); + + if (tx_counts == HIQ_XMIT_COUNTS) + break; + + } + + } else { + if (psta_bmc->sleepq_len == 0) { + + /*RTW_INFO("sleepq_len of bmc_sta = %d\n", psta_bmc->sleepq_len);*/ + + if (pstapriv->tim_bitmap & BIT(0)) + update_tim = _TRUE; + + pstapriv->tim_bitmap &= ~BIT(0); + pstapriv->sta_dz_bitmap &= ~BIT(0); + + if (update_tim == _TRUE) { + RTW_INFO("clear TIB\n"); + _update_beacon(padapter, _TIM_IE_, NULL, _TRUE, "bmc sleepq and HIQ empty"); + } + } + } + + _exit_critical_bh(&pxmitpriv->lock, &irqL); + +#if 0 + /* HIQ Check */ + rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty); + + while (_FALSE == empty && rtw_get_passing_time_ms(start) < 3000) { + rtw_msleep_os(100); + rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty); + } + + + printk("check if hiq empty=%d\n", empty); +#endif + + return H2C_SUCCESS; +} + +#ifdef CONFIG_NATIVEAP_MLME + +static void associated_stainfo_update(_adapter *padapter, struct sta_info *psta, u32 sta_info_type) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + + RTW_INFO("%s: "MAC_FMT", updated_type=0x%x\n", __func__, MAC_ARG(psta->hwaddr), sta_info_type); + + if (sta_info_type & STA_INFO_UPDATE_BW) { + + if ((psta->flags & WLAN_STA_HT) && !psta->ht_20mhz_set) { + if (pmlmepriv->sw_to_20mhz) { + psta->bw_mode = CHANNEL_WIDTH_20; + /*psta->htpriv.ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;*/ + psta->htpriv.sgi_40m = _FALSE; + } else { + /*TODO: Switch back to 40MHZ?80MHZ*/ + } + } + } + + /* + if (sta_info_type & STA_INFO_UPDATE_RATE) { + + } + */ + + if (sta_info_type & STA_INFO_UPDATE_PROTECTION_MODE) + VCS_update(padapter, psta); + + /* + if (sta_info_type & STA_INFO_UPDATE_CAP) { + + } + + if (sta_info_type & STA_INFO_UPDATE_HT_CAP) { + + } + + if (sta_info_type & STA_INFO_UPDATE_VHT_CAP) { + + } + */ + +} + +static void update_bcn_ext_capab_ie(_adapter *padapter) +{ + sint ie_len = 0; + unsigned char *pbuf; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network); + u8 *ie = pnetwork->IEs; + u8 null_extcap_data[8] = {0}; + + pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_CAP_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); + if (pbuf && ie_len > 0) + rtw_remove_bcn_ie(padapter, pnetwork, _EXT_CAP_IE_); + + if ((pmlmepriv->ext_capab_ie_len > 0) && + (_rtw_memcmp(pmlmepriv->ext_capab_ie_data, null_extcap_data, sizeof(null_extcap_data)) == _FALSE)) + rtw_add_bcn_ie(padapter, pnetwork, _EXT_CAP_IE_, pmlmepriv->ext_capab_ie_data, pmlmepriv->ext_capab_ie_len); + +} + +static void update_bcn_fixed_ie(_adapter *padapter) +{ + RTW_INFO("%s\n", __FUNCTION__); + +} + +static void update_bcn_erpinfo_ie(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network); + unsigned char *p, *ie = pnetwork->IEs; + u32 len = 0; + + RTW_INFO("%s, ERP_enable=%d\n", __FUNCTION__, pmlmeinfo->ERP_enable); + + if (!pmlmeinfo->ERP_enable) + return; + + /* parsing ERP_IE */ + p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); + if (p && len > 0) { + PNDIS_802_11_VARIABLE_IEs pIE = (PNDIS_802_11_VARIABLE_IEs)p; + + if (pmlmepriv->num_sta_non_erp == 1) + pIE->data[0] |= RTW_ERP_INFO_NON_ERP_PRESENT | RTW_ERP_INFO_USE_PROTECTION; + else + pIE->data[0] &= ~(RTW_ERP_INFO_NON_ERP_PRESENT | RTW_ERP_INFO_USE_PROTECTION); + + if (pmlmepriv->num_sta_no_short_preamble > 0) + pIE->data[0] |= RTW_ERP_INFO_BARKER_PREAMBLE_MODE; + else + pIE->data[0] &= ~(RTW_ERP_INFO_BARKER_PREAMBLE_MODE); + + ERP_IE_handler(padapter, pIE); + } + +} + +static void update_bcn_htcap_ie(_adapter *padapter) +{ + RTW_INFO("%s\n", __FUNCTION__); + +} + +static void update_bcn_htinfo_ie(_adapter *padapter) +{ + /* + u8 beacon_updated = _FALSE; + u32 sta_info_update_type = STA_INFO_UPDATE_NONE; + */ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network); + unsigned char *p, *ie = pnetwork->IEs; + u32 len = 0; + + if (pmlmepriv->htpriv.ht_option == _FALSE) + return; + + if (pmlmeinfo->HT_info_enable != 1) + return; + + + RTW_INFO("%s current operation mode=0x%X\n", + __FUNCTION__, pmlmepriv->ht_op_mode); + + RTW_INFO("num_sta_40mhz_intolerant(%d), 20mhz_width_req(%d), intolerant_ch_rpt(%d), olbc(%d)\n", + pmlmepriv->num_sta_40mhz_intolerant, pmlmepriv->ht_20mhz_width_req, pmlmepriv->ht_intolerant_ch_reported, ATOMIC_READ(&pmlmepriv->olbc)); + + /*parsing HT_INFO_IE, currently only update ht_op_mode - pht_info->infos[1] & pht_info->infos[2] for wifi logo test*/ + p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); + if (p && len > 0) { + struct HT_info_element *pht_info = NULL; + + pht_info = (struct HT_info_element *)(p + 2); + + /* for STA Channel Width/Secondary Channel Offset*/ + if ((pmlmepriv->sw_to_20mhz == 0) && (pmlmeext->cur_channel <= 14)) { + if ((pmlmepriv->num_sta_40mhz_intolerant > 0) || (pmlmepriv->ht_20mhz_width_req == _TRUE) + || (pmlmepriv->ht_intolerant_ch_reported == _TRUE) || (ATOMIC_READ(&pmlmepriv->olbc) == _TRUE)) { + SET_HT_OP_ELE_2ND_CHL_OFFSET(pht_info, 0); + SET_HT_OP_ELE_STA_CHL_WIDTH(pht_info, 0); + + pmlmepriv->sw_to_20mhz = 1; + /* + sta_info_update_type |= STA_INFO_UPDATE_BW; + beacon_updated = _TRUE; + */ + + RTW_INFO("%s:switching to 20Mhz\n", __FUNCTION__); + + /*TODO : cur_bwmode/cur_ch_offset switches to 20Mhz*/ + } + } else { + + if ((pmlmepriv->num_sta_40mhz_intolerant == 0) && (pmlmepriv->ht_20mhz_width_req == _FALSE) + && (pmlmepriv->ht_intolerant_ch_reported == _FALSE) && (ATOMIC_READ(&pmlmepriv->olbc) == _FALSE)) { + + if (pmlmeext->cur_bwmode >= CHANNEL_WIDTH_40) { + + SET_HT_OP_ELE_STA_CHL_WIDTH(pht_info, 1); + + SET_HT_OP_ELE_2ND_CHL_OFFSET(pht_info, + (pmlmeext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) ? + HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE : HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW); + + pmlmepriv->sw_to_20mhz = 0; + /* + sta_info_update_type |= STA_INFO_UPDATE_BW; + beacon_updated = _TRUE; + */ + + RTW_INFO("%s:switching back to 40Mhz\n", __FUNCTION__); + } + } + } + + /* to update ht_op_mode*/ + *(u16 *)(pht_info->infos + 1) = cpu_to_le16(pmlmepriv->ht_op_mode); + + } + + /*associated_clients_update(padapter, beacon_updated, sta_info_update_type);*/ + +} + +static void update_bcn_rsn_ie(_adapter *padapter) +{ + RTW_INFO("%s\n", __FUNCTION__); + +} + +static void update_bcn_wpa_ie(_adapter *padapter) +{ + RTW_INFO("%s\n", __FUNCTION__); + +} + +static void update_bcn_wmm_ie(_adapter *padapter) +{ + RTW_INFO("%s\n", __FUNCTION__); + +} + +static void update_bcn_wps_ie(_adapter *padapter) +{ + u8 *pwps_ie = NULL, *pwps_ie_src, *premainder_ie, *pbackup_remainder_ie = NULL; + uint wps_ielen = 0, wps_offset, remainder_ielen; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network); + unsigned char *ie = pnetwork->IEs; + u32 ielen = pnetwork->IELength; + + + RTW_INFO("%s\n", __FUNCTION__); + + pwps_ie = rtw_get_wps_ie(ie + _FIXED_IE_LENGTH_, ielen - _FIXED_IE_LENGTH_, NULL, &wps_ielen); + + if (pwps_ie == NULL || wps_ielen == 0) + return; + + pwps_ie_src = pmlmepriv->wps_beacon_ie; + if (pwps_ie_src == NULL) + return; + + wps_offset = (uint)(pwps_ie - ie); + + premainder_ie = pwps_ie + wps_ielen; + + remainder_ielen = ielen - wps_offset - wps_ielen; + + if (remainder_ielen > 0) { + pbackup_remainder_ie = rtw_malloc(remainder_ielen); + if (pbackup_remainder_ie) + _rtw_memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); + } + + wps_ielen = (uint)pwps_ie_src[1];/* to get ie data len */ + if ((wps_offset + wps_ielen + 2 + remainder_ielen) <= MAX_IE_SZ) { + _rtw_memcpy(pwps_ie, pwps_ie_src, wps_ielen + 2); + pwps_ie += (wps_ielen + 2); + + if (pbackup_remainder_ie) + _rtw_memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen); + + /* update IELength */ + pnetwork->IELength = wps_offset + (wps_ielen + 2) + remainder_ielen; + } + + if (pbackup_remainder_ie) + rtw_mfree(pbackup_remainder_ie, remainder_ielen); + + /* deal with the case without set_tx_beacon_cmd() in update_beacon() */ +#if defined(CONFIG_INTERRUPT_BASED_TXBCN) || defined(CONFIG_PCI_HCI) + if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { + u8 sr = 0; + rtw_get_wps_attr_content(pwps_ie_src, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL); + + if (sr) { + set_fwstate(pmlmepriv, WIFI_UNDER_WPS); + RTW_INFO("%s, set WIFI_UNDER_WPS\n", __func__); + } else { + clr_fwstate(pmlmepriv, WIFI_UNDER_WPS); + RTW_INFO("%s, clr WIFI_UNDER_WPS\n", __func__); + } + } +#endif +} + +static void update_bcn_p2p_ie(_adapter *padapter) +{ + +} + +static void update_bcn_vendor_spec_ie(_adapter *padapter, u8 *oui) +{ + RTW_INFO("%s\n", __FUNCTION__); + + if (_rtw_memcmp(RTW_WPA_OUI, oui, 4)) + update_bcn_wpa_ie(padapter); + else if (_rtw_memcmp(WMM_OUI, oui, 4)) + update_bcn_wmm_ie(padapter); + else if (_rtw_memcmp(WPS_OUI, oui, 4)) + update_bcn_wps_ie(padapter); + else if (_rtw_memcmp(P2P_OUI, oui, 4)) + update_bcn_p2p_ie(padapter); + else + RTW_INFO("unknown OUI type!\n"); + + +} + +void _update_beacon(_adapter *padapter, u8 ie_id, u8 *oui, u8 tx, const char *tag) +{ + _irqL irqL; + struct mlme_priv *pmlmepriv; + struct mlme_ext_priv *pmlmeext; + /* struct mlme_ext_info *pmlmeinfo; */ + + /* RTW_INFO("%s\n", __FUNCTION__); */ + + if (!padapter) + return; + + pmlmepriv = &(padapter->mlmepriv); + pmlmeext = &(padapter->mlmeextpriv); + /* pmlmeinfo = &(pmlmeext->mlmext_info); */ + + if (_FALSE == pmlmeext->bstart_bss) + return; + + _enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); + + switch (ie_id) { + case 0xFF: + + update_bcn_fixed_ie(padapter);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */ + + break; + + case _TIM_IE_: + + update_BCNTIM(padapter); + + break; + + case _ERPINFO_IE_: + + update_bcn_erpinfo_ie(padapter); + + break; + + case _HT_CAPABILITY_IE_: + + update_bcn_htcap_ie(padapter); + + break; + + case _RSN_IE_2_: + + update_bcn_rsn_ie(padapter); + + break; + + case _HT_ADD_INFO_IE_: + + update_bcn_htinfo_ie(padapter); + + break; + + case _EXT_CAP_IE_: + + update_bcn_ext_capab_ie(padapter); + + break; + + case _VENDOR_SPECIFIC_IE_: + + update_bcn_vendor_spec_ie(padapter, oui); + + break; + + default: + break; + } + + pmlmepriv->update_bcn = _TRUE; + + _exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); + +#ifndef CONFIG_INTERRUPT_BASED_TXBCN +#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + if (tx) { + /* send_beacon(padapter); */ /* send_beacon must execute on TSR level */ + if (0) + RTW_INFO(FUNC_ADPT_FMT" ie_id:%u - %s\n", FUNC_ADPT_ARG(padapter), ie_id, tag); + set_tx_beacon_cmd(padapter); + } +#else + { + /* PCI will issue beacon when BCN interrupt occurs. */ + } +#endif +#endif /* !CONFIG_INTERRUPT_BASED_TXBCN */ + +} + +#ifdef CONFIG_80211N_HT + +void rtw_process_public_act_bsscoex(_adapter *padapter, u8 *pframe, uint frame_len) +{ + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 beacon_updated = _FALSE; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + uint frame_body_len = frame_len - sizeof(struct rtw_ieee80211_hdr_3addr); + u8 category, action; + + psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe)); + if (psta == NULL) + return; + + + category = frame_body[0]; + action = frame_body[1]; + + if (frame_body_len > 0) { + if ((frame_body[2] == EID_BSSCoexistence) && (frame_body[3] > 0)) { + u8 ie_data = frame_body[4]; + + if (ie_data & RTW_WLAN_20_40_BSS_COEX_40MHZ_INTOL) { + if (psta->ht_40mhz_intolerant == 0) { + psta->ht_40mhz_intolerant = 1; + pmlmepriv->num_sta_40mhz_intolerant++; + beacon_updated = _TRUE; + } + } else if (ie_data & RTW_WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) { + if (pmlmepriv->ht_20mhz_width_req == _FALSE) { + pmlmepriv->ht_20mhz_width_req = _TRUE; + beacon_updated = _TRUE; + } + } else + beacon_updated = _FALSE; + } + } + + if (frame_body_len > 8) { + /* if EID_BSSIntolerantChlReport ie exists */ + if ((frame_body[5] == EID_BSSIntolerantChlReport) && (frame_body[6] > 0)) { + /*todo:*/ + if (pmlmepriv->ht_intolerant_ch_reported == _FALSE) { + pmlmepriv->ht_intolerant_ch_reported = _TRUE; + beacon_updated = _TRUE; + } + } + } + + if (beacon_updated) { + + update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _TRUE); + + associated_stainfo_update(padapter, psta, STA_INFO_UPDATE_BW); + } + + + +} + +void rtw_process_ht_action_smps(_adapter *padapter, u8 *ta, u8 ctrl_field) +{ + u8 e_field, m_field; + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + + psta = rtw_get_stainfo(pstapriv, ta); + if (psta == NULL) + return; + + e_field = (ctrl_field & BIT(0)) ? 1 : 0; + m_field = (ctrl_field & BIT(1)) ? 1 : 0; + + if (e_field) { + + /* enable */ + /* 0:static SMPS, 1:dynamic SMPS, 3:SMPS disabled, 2:reserved*/ + + if (m_field) /*mode*/ + psta->htpriv.smps_cap = 1; + else + psta->htpriv.smps_cap = 0; + } else { + /*disable*/ + psta->htpriv.smps_cap = 3; + } + + rtw_dm_ra_mask_wk_cmd(padapter, (u8 *)psta); + +} + +/* +op_mode +Set to 0 (HT pure) under the followign conditions + - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or + - all STAs in the BSS are 20 MHz HT in 20 MHz BSS +Set to 1 (HT non-member protection) if there may be non-HT STAs + in both the primary and the secondary channel +Set to 2 if only HT STAs are associated in BSS, + however and at least one 20 MHz HT STA is associated +Set to 3 (HT mixed mode) when one or more non-HT STAs are associated + (currently non-GF HT station is considered as non-HT STA also) +*/ +int rtw_ht_operation_update(_adapter *padapter) +{ + u16 cur_op_mode, new_op_mode; + int op_mode_changes = 0; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; + + if (pmlmepriv->htpriv.ht_option == _FALSE) + return 0; + + /*if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed) + return 0;*/ + + RTW_INFO("%s current operation mode=0x%X\n", + __FUNCTION__, pmlmepriv->ht_op_mode); + + if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) + && pmlmepriv->num_sta_ht_no_gf) { + pmlmepriv->ht_op_mode |= + HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; + op_mode_changes++; + } else if ((pmlmepriv->ht_op_mode & + HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) && + pmlmepriv->num_sta_ht_no_gf == 0) { + pmlmepriv->ht_op_mode &= + ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT; + op_mode_changes++; + } + + if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && + (pmlmepriv->num_sta_no_ht || ATOMIC_READ(&pmlmepriv->olbc_ht))) { + pmlmepriv->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; + op_mode_changes++; + } else if ((pmlmepriv->ht_op_mode & + HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) && + (pmlmepriv->num_sta_no_ht == 0 && !ATOMIC_READ(&pmlmepriv->olbc_ht))) { + pmlmepriv->ht_op_mode &= + ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT; + op_mode_changes++; + } + + /* Note: currently we switch to the MIXED op mode if HT non-greenfield + * station is associated. Probably it's a theoretical case, since + * it looks like all known HT STAs support greenfield. + */ + new_op_mode = 0; + if (pmlmepriv->num_sta_no_ht /*|| + (pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)*/) + new_op_mode = OP_MODE_MIXED; + else if ((phtpriv_ap->ht_cap.cap_info & IEEE80211_HT_CAP_SUP_WIDTH) + && pmlmepriv->num_sta_ht_20mhz) + new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED; + else if (ATOMIC_READ(&pmlmepriv->olbc_ht)) + new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS; + else + new_op_mode = OP_MODE_PURE; + + cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK; + if (cur_op_mode != new_op_mode) { + pmlmepriv->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK; + pmlmepriv->ht_op_mode |= new_op_mode; + op_mode_changes++; + } + + RTW_INFO("%s new operation mode=0x%X changes=%d\n", + __FUNCTION__, pmlmepriv->ht_op_mode, op_mode_changes); + + return op_mode_changes; + +} + +#endif /* CONFIG_80211N_HT */ + +void associated_clients_update(_adapter *padapter, u8 updated, u32 sta_info_type) +{ + /* update associcated stations cap. */ + if (updated == _TRUE) { + _irqL irqL; + _list *phead, *plist; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + phead = &pstapriv->asoc_list; + plist = get_next(phead); + + /* check asoc_queue */ + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); + + plist = get_next(plist); + + associated_stainfo_update(padapter, psta, sta_info_type); + } + + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + } + +} + +/* called > TSR LEVEL for USB or SDIO Interface*/ +void bss_cap_update_on_sta_join(_adapter *padapter, struct sta_info *psta) +{ + u8 beacon_updated = _FALSE; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + + +#if 0 + if (!(psta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && + !psta->no_short_preamble_set) { + psta->no_short_preamble_set = 1; + pmlmepriv->num_sta_no_short_preamble++; + if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && + (pmlmepriv->num_sta_no_short_preamble == 1)) + ieee802_11_set_beacons(hapd->iface); + } +#endif + + + if (!(psta->flags & WLAN_STA_SHORT_PREAMBLE)) { + if (!psta->no_short_preamble_set) { + psta->no_short_preamble_set = 1; + + pmlmepriv->num_sta_no_short_preamble++; + + if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && + (pmlmepriv->num_sta_no_short_preamble == 1)) { + beacon_updated = _TRUE; + update_beacon(padapter, 0xFF, NULL, _TRUE); + } + + } + } else { + if (psta->no_short_preamble_set) { + psta->no_short_preamble_set = 0; + + pmlmepriv->num_sta_no_short_preamble--; + + if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && + (pmlmepriv->num_sta_no_short_preamble == 0)) { + beacon_updated = _TRUE; + update_beacon(padapter, 0xFF, NULL, _TRUE); + } + + } + } + +#if 0 + if (psta->flags & WLAN_STA_NONERP && !psta->nonerp_set) { + psta->nonerp_set = 1; + pmlmepriv->num_sta_non_erp++; + if (pmlmepriv->num_sta_non_erp == 1) + ieee802_11_set_beacons(hapd->iface); + } +#endif + + if (psta->flags & WLAN_STA_NONERP) { + if (!psta->nonerp_set) { + psta->nonerp_set = 1; + + pmlmepriv->num_sta_non_erp++; + + if (pmlmepriv->num_sta_non_erp == 1) { + beacon_updated = _TRUE; + update_beacon(padapter, _ERPINFO_IE_, NULL, _TRUE); + } + } + + } else { + if (psta->nonerp_set) { + psta->nonerp_set = 0; + + pmlmepriv->num_sta_non_erp--; + + if (pmlmepriv->num_sta_non_erp == 0) { + beacon_updated = _TRUE; + update_beacon(padapter, _ERPINFO_IE_, NULL, _TRUE); + } + } + + } + + +#if 0 + if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT) && + !psta->no_short_slot_time_set) { + psta->no_short_slot_time_set = 1; + pmlmepriv->num_sta_no_short_slot_time++; + if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && + (pmlmepriv->num_sta_no_short_slot_time == 1)) + ieee802_11_set_beacons(hapd->iface); + } +#endif + + if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT)) { + if (!psta->no_short_slot_time_set) { + psta->no_short_slot_time_set = 1; + + pmlmepriv->num_sta_no_short_slot_time++; + + if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && + (pmlmepriv->num_sta_no_short_slot_time == 1)) { + beacon_updated = _TRUE; + update_beacon(padapter, 0xFF, NULL, _TRUE); + } + + } + } else { + if (psta->no_short_slot_time_set) { + psta->no_short_slot_time_set = 0; + + pmlmepriv->num_sta_no_short_slot_time--; + + if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) && + (pmlmepriv->num_sta_no_short_slot_time == 0)) { + beacon_updated = _TRUE; + update_beacon(padapter, 0xFF, NULL, _TRUE); + } + } + } + +#ifdef CONFIG_80211N_HT + + if (psta->flags & WLAN_STA_HT) { + u16 ht_capab = le16_to_cpu(psta->htpriv.ht_cap.cap_info); + + RTW_INFO("HT: STA " MAC_FMT " HT Capabilities " + "Info: 0x%04x\n", MAC_ARG(psta->hwaddr), ht_capab); + + if (psta->no_ht_set) { + psta->no_ht_set = 0; + pmlmepriv->num_sta_no_ht--; + } + + if ((ht_capab & IEEE80211_HT_CAP_GRN_FLD) == 0) { + if (!psta->no_ht_gf_set) { + psta->no_ht_gf_set = 1; + pmlmepriv->num_sta_ht_no_gf++; + } + RTW_INFO("%s STA " MAC_FMT " - no " + "greenfield, num of non-gf stations %d\n", + __FUNCTION__, MAC_ARG(psta->hwaddr), + pmlmepriv->num_sta_ht_no_gf); + } + + if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH) == 0) { + if (!psta->ht_20mhz_set) { + psta->ht_20mhz_set = 1; + pmlmepriv->num_sta_ht_20mhz++; + } + RTW_INFO("%s STA " MAC_FMT " - 20 MHz HT, " + "num of 20MHz HT STAs %d\n", + __FUNCTION__, MAC_ARG(psta->hwaddr), + pmlmepriv->num_sta_ht_20mhz); + } + + } else { + if (!psta->no_ht_set) { + psta->no_ht_set = 1; + pmlmepriv->num_sta_no_ht++; + } + if (pmlmepriv->htpriv.ht_option == _TRUE) { + RTW_INFO("%s STA " MAC_FMT + " - no HT, num of non-HT stations %d\n", + __FUNCTION__, MAC_ARG(psta->hwaddr), + pmlmepriv->num_sta_no_ht); + } + } + + if (rtw_ht_operation_update(padapter) > 0) { + update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, _FALSE); + update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _TRUE); + /*beacon_updated = _TRUE;*/ + } + +#endif /* CONFIG_80211N_HT */ + + /* update associcated stations cap. */ + associated_clients_update(padapter, beacon_updated, STA_INFO_UPDATE_ALL); + + RTW_INFO("%s, updated=%d\n", __func__, beacon_updated); + +} + +u8 bss_cap_update_on_sta_leave(_adapter *padapter, struct sta_info *psta) +{ + u8 beacon_updated = _FALSE; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + + if (!psta) + return beacon_updated; + + if (psta->no_short_preamble_set) { + psta->no_short_preamble_set = 0; + pmlmepriv->num_sta_no_short_preamble--; + if (pmlmeext->cur_wireless_mode > WIRELESS_11B + && pmlmepriv->num_sta_no_short_preamble == 0) { + beacon_updated = _TRUE; + update_beacon(padapter, 0xFF, NULL, _TRUE); + } + } + + if (psta->nonerp_set) { + psta->nonerp_set = 0; + pmlmepriv->num_sta_non_erp--; + if (pmlmepriv->num_sta_non_erp == 0) { + beacon_updated = _TRUE; + update_beacon(padapter, _ERPINFO_IE_, NULL, _TRUE); + } + } + + if (psta->no_short_slot_time_set) { + psta->no_short_slot_time_set = 0; + pmlmepriv->num_sta_no_short_slot_time--; + if (pmlmeext->cur_wireless_mode > WIRELESS_11B + && pmlmepriv->num_sta_no_short_slot_time == 0) { + beacon_updated = _TRUE; + update_beacon(padapter, 0xFF, NULL, _TRUE); + } + } + +#ifdef CONFIG_80211N_HT + + if (psta->no_ht_gf_set) { + psta->no_ht_gf_set = 0; + pmlmepriv->num_sta_ht_no_gf--; + } + + if (psta->no_ht_set) { + psta->no_ht_set = 0; + pmlmepriv->num_sta_no_ht--; + } + + if (psta->ht_20mhz_set) { + psta->ht_20mhz_set = 0; + pmlmepriv->num_sta_ht_20mhz--; + } + + + + if (rtw_ht_operation_update(padapter) > 0) { + update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, _FALSE); + update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _TRUE); + } + +#endif /* CONFIG_80211N_HT */ + +#if 0 + /* update associated stations cap. */ + associated_clients_update(padapter, beacon_updated, STA_INFO_UPDATE_ALL); /* move it to avoid deadlock */ +#endif + + RTW_INFO("%s, updated=%d\n", __func__, beacon_updated); + + return beacon_updated; + +} + +u8 ap_free_sta(_adapter *padapter, struct sta_info *psta, bool active, u16 reason, bool enqueue) +{ + _irqL irqL; + u8 beacon_updated = _FALSE; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct sta_priv *pstapriv = &padapter->stapriv; + + if (!psta) + return beacon_updated; + + if (active == _TRUE) { +#ifdef CONFIG_80211N_HT + /* tear down Rx AMPDU */ + send_delba(padapter, 0, psta->hwaddr);/* recipient */ + + /* tear down TX AMPDU */ + send_delba(padapter, 1, psta->hwaddr);/* */ /* originator */ + +#endif /* CONFIG_80211N_HT */ + + issue_deauth(padapter, psta->hwaddr, reason); + } + +#ifdef CONFIG_BEAMFORMING + beamforming_wk_cmd(padapter, BEAMFORMING_CTRL_LEAVE, psta->hwaddr, ETH_ALEN, 1); +#endif + + psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ + psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ + + /* clear cam entry / key */ + rtw_clearstakey_cmd(padapter, psta, enqueue); + + + _enter_critical_bh(&psta->lock, &irqL); + psta->state &= ~_FW_LINKED; + _exit_critical_bh(&psta->lock, &irqL); + +#ifdef CONFIG_IOCTL_CFG80211 + if (1) { +#ifdef COMPAT_KERNEL_RELEASE + rtw_cfg80211_indicate_sta_disassoc(padapter, psta->hwaddr, reason); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) + rtw_cfg80211_indicate_sta_disassoc(padapter, psta->hwaddr, reason); +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) */ + /* will call rtw_cfg80211_indicate_sta_disassoc() in cmd_thread for old API context */ +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) && !defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) */ + } else +#endif /* CONFIG_IOCTL_CFG80211 */ + { + rtw_indicate_sta_disassoc_event(padapter, psta); + } + + report_del_sta_event(padapter, psta->hwaddr, reason, enqueue, _FALSE); + + beacon_updated = bss_cap_update_on_sta_leave(padapter, psta); + + /* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + rtw_free_stainfo(padapter, psta); + /* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + + + return beacon_updated; + +} + +int rtw_ap_inform_ch_switch(_adapter *padapter, u8 new_ch, u8 ch_offset) +{ + _irqL irqL; + _list *phead, *plist; + int ret = 0; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) + return ret; + + RTW_INFO(FUNC_NDEV_FMT" with ch:%u, offset:%u\n", + FUNC_NDEV_ARG(padapter->pnetdev), new_ch, ch_offset); + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + phead = &pstapriv->asoc_list; + plist = get_next(phead); + + /* for each sta in asoc_queue */ + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); + plist = get_next(plist); + + issue_action_spct_ch_switch(padapter, psta->hwaddr, new_ch, ch_offset); + psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2); + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + issue_action_spct_ch_switch(padapter, bc_addr, new_ch, ch_offset); + + return ret; +} + +int rtw_sta_flush(_adapter *padapter, bool enqueue) +{ + _irqL irqL; + _list *phead, *plist; + int ret = 0; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 flush_num = 0; + char flush_list[NUM_STA]; + int i; + + if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) + return ret; + + RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); + + /* pick sta from sta asoc_queue */ + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + phead = &pstapriv->asoc_list; + plist = get_next(phead); + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + int stainfo_offset; + + psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); + plist = get_next(plist); + + rtw_list_delete(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + + stainfo_offset = rtw_stainfo_offset(pstapriv, psta); + if (stainfo_offset_valid(stainfo_offset)) + flush_list[flush_num++] = stainfo_offset; + else + rtw_warn_on(1); + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + /* call ap_free_sta() for each sta picked */ + for (i = 0; i < flush_num; i++) { + psta = rtw_get_stainfo_by_offset(pstapriv, flush_list[i]); + ap_free_sta(padapter, psta, _TRUE, WLAN_REASON_DEAUTH_LEAVING, enqueue); + } + + issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING); + + associated_clients_update(padapter, _TRUE, STA_INFO_UPDATE_ALL); + + return ret; +} + +/* called > TSR LEVEL for USB or SDIO Interface*/ +void sta_info_update(_adapter *padapter, struct sta_info *psta) +{ + int flags = psta->flags; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + + + /* update wmm cap. */ + if (WLAN_STA_WME & flags) + psta->qos_option = 1; + else + psta->qos_option = 0; + + if (pmlmepriv->qospriv.qos_option == 0) + psta->qos_option = 0; + + +#ifdef CONFIG_80211N_HT + /* update 802.11n ht cap. */ + if (WLAN_STA_HT & flags) { + psta->htpriv.ht_option = _TRUE; + psta->qos_option = 1; + + psta->htpriv.smps_cap = (psta->htpriv.ht_cap.cap_info & IEEE80211_HT_CAP_SM_PS) >> 2; + } else + psta->htpriv.ht_option = _FALSE; + + if (pmlmepriv->htpriv.ht_option == _FALSE) + psta->htpriv.ht_option = _FALSE; +#endif + +#ifdef CONFIG_80211AC_VHT + /* update 802.11AC vht cap. */ + if (WLAN_STA_VHT & flags) + psta->vhtpriv.vht_option = _TRUE; + else + psta->vhtpriv.vht_option = _FALSE; + + if (pmlmepriv->vhtpriv.vht_option == _FALSE) + psta->vhtpriv.vht_option = _FALSE; +#endif + + update_sta_info_apmode(padapter, psta); +} + +/* called >= TSR LEVEL for USB or SDIO Interface*/ +void ap_sta_info_defer_update(_adapter *padapter, struct sta_info *psta) +{ + if (psta->state & _FW_LINKED) + rtw_hal_update_ra_mask(psta, psta->rssi_level, _TRUE); /* DM_RATR_STA_INIT */ +} +/* restore hw setting from sw data structures */ +void rtw_ap_restore_network(_adapter *padapter) +{ + struct mlme_priv *mlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta; + struct security_priv *psecuritypriv = &(padapter->securitypriv); + _irqL irqL; + _list *phead, *plist; + u8 chk_alive_num = 0; + char chk_alive_list[NUM_STA]; + int i; + + rtw_setopmode_cmd(padapter, Ndis802_11APMode, _FALSE); + + set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + + rtw_startbss_cmd(padapter, RTW_CMDF_DIRECTLY); + + if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) || + (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) { + /* restore group key, WEP keys is restored in ips_leave() */ + rtw_set_key(padapter, psecuritypriv, psecuritypriv->dot118021XGrpKeyid, 0, _FALSE); + } + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + phead = &pstapriv->asoc_list; + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + int stainfo_offset; + + psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); + plist = get_next(plist); + + stainfo_offset = rtw_stainfo_offset(pstapriv, psta); + if (stainfo_offset_valid(stainfo_offset)) + chk_alive_list[chk_alive_num++] = stainfo_offset; + } + + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + for (i = 0; i < chk_alive_num; i++) { + psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); + + if (psta == NULL) + RTW_INFO(FUNC_ADPT_FMT" sta_info is null\n", FUNC_ADPT_ARG(padapter)); + else if (psta->state & _FW_LINKED) { + rtw_sta_media_status_rpt(padapter, psta, 1); + Update_RA_Entry(padapter, psta); + /* pairwise key */ + /* per sta pairwise key and settings */ + if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) || + (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) + rtw_setstakey_cmd(padapter, psta, UNICAST_KEY, _FALSE); + } + } + +} + +void start_ap_mode(_adapter *padapter) +{ + int i; + struct sta_info *psta = NULL; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct security_priv *psecuritypriv = &padapter->securitypriv; + + pmlmepriv->update_bcn = _FALSE; + + /*init_mlme_ap_info(padapter);*/ + + pmlmeext->bstart_bss = _FALSE; + + pmlmepriv->num_sta_non_erp = 0; + + pmlmepriv->num_sta_no_short_slot_time = 0; + + pmlmepriv->num_sta_no_short_preamble = 0; + + pmlmepriv->num_sta_ht_no_gf = 0; +#ifdef CONFIG_80211N_HT + pmlmepriv->num_sta_no_ht = 0; +#endif /* CONFIG_80211N_HT */ + pmlmeinfo->HT_info_enable = 0; + pmlmeinfo->HT_caps_enable = 0; + pmlmeinfo->HT_enable = 0; + + pmlmepriv->num_sta_ht_20mhz = 0; + pmlmepriv->num_sta_40mhz_intolerant = 0; + ATOMIC_SET(&pmlmepriv->olbc, _FALSE); + ATOMIC_SET(&pmlmepriv->olbc_ht, _FALSE); + +#ifdef CONFIG_80211N_HT + pmlmepriv->ht_20mhz_width_req = _FALSE; + pmlmepriv->ht_intolerant_ch_reported = _FALSE; + pmlmepriv->ht_op_mode = 0; + pmlmepriv->sw_to_20mhz = 0; +#endif + + _rtw_memset(pmlmepriv->ext_capab_ie_data, 0, sizeof(pmlmepriv->ext_capab_ie_data)); + pmlmepriv->ext_capab_ie_len = 0; + +#ifdef CONFIG_CONCURRENT_MODE + psecuritypriv->dot118021x_bmc_cam_id = INVALID_SEC_MAC_CAM_ID; +#endif + + for (i = 0 ; i < NUM_STA ; i++) + pstapriv->sta_aid[i] = NULL; + +#if CONFIG_RTW_MACADDR_ACL + rtw_macaddr_acl_init(padapter); +#endif + + psta = rtw_get_bcmc_stainfo(padapter); + /*_enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL);*/ + if (psta) + rtw_free_stainfo(padapter, psta); + /*_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);*/ + + rtw_init_bcmc_stainfo(padapter); + + if (rtw_mi_get_ap_num(padapter)) + RTW_SET_SCAN_BAND_SKIP(padapter, BAND_5G); + +} + +void stop_ap_mode(_adapter *padapter) +{ + _irqL irqL; + struct sta_info *psta = NULL; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct dvobj_priv *pdvobj = padapter->dvobj; + + RTW_INFO("%s -"ADPT_FMT"\n", __func__, ADPT_ARG(padapter)); + + pmlmepriv->update_bcn = _FALSE; + /*pmlmeext->bstart_bss = _FALSE;*/ + padapter->netif_up = _FALSE; + /* _rtw_spinlock_free(&pmlmepriv->bcn_update_lock); */ + + /* reset and init security priv , this can refine with rtw_reset_securitypriv */ + _rtw_memset((unsigned char *)&padapter->securitypriv, 0, sizeof(struct security_priv)); + padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen; + padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; + +#ifdef CONFIG_DFS_MASTER + rtw_dfs_master_status_apply(padapter, MLME_AP_STOPPED); +#endif + + /* free scan queue */ + rtw_free_network_queue(padapter, _TRUE); + +#if CONFIG_RTW_MACADDR_ACL + rtw_macaddr_acl_deinit(padapter); +#endif + + rtw_sta_flush(padapter, _TRUE); + + /* free_assoc_sta_resources */ + rtw_free_all_stainfo(padapter); + + psta = rtw_get_bcmc_stainfo(padapter); + /* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + rtw_free_stainfo(padapter, psta); + /*_exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL);*/ + + rtw_free_mlme_priv_ie_data(pmlmepriv); + +#ifdef CONFIG_SWTIMER_BASED_TXBCN + if (pmlmeext->bstart_bss == _TRUE) { + _enter_critical_bh(&pdvobj->ap_if_q.lock, &irqL); + pdvobj->nr_ap_if--; + if (pdvobj->nr_ap_if > 0) + pdvobj->inter_bcn_space = DEFAULT_BCN_INTERVAL / pdvobj->nr_ap_if; + else + pdvobj->inter_bcn_space = DEFAULT_BCN_INTERVAL; + + rtw_list_delete(&padapter->list); + _exit_critical_bh(&pdvobj->ap_if_q.lock, &irqL); + + rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pdvobj->inter_bcn_space)); + + if (pdvobj->nr_ap_if == 0) + _cancel_timer_ex(&pdvobj->txbcn_timer); + } +#endif + + pmlmeext->bstart_bss = _FALSE; + +#ifdef CONFIG_BT_COEXIST + rtw_btcoex_MediaStatusNotify(padapter, 0); /* disconnect */ +#endif + +} + +#endif /* CONFIG_NATIVEAP_MLME */ + +void rtw_ap_update_bss_chbw(_adapter *adapter, WLAN_BSSID_EX *bss, u8 ch, u8 bw, u8 offset) +{ +#define UPDATE_VHT_CAP 1 +#define UPDATE_HT_CAP 1 + +#ifdef CONFIG_80211AC_VHT + { + struct vht_priv *vhtpriv = &adapter->mlmepriv.vhtpriv; + u8 *vht_cap_ie, *vht_op_ie; + int vht_cap_ielen, vht_op_ielen; + u8 center_freq; + + vht_cap_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_VHTCapability, &vht_cap_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs))); + vht_op_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_VHTOperation, &vht_op_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs))); + center_freq = rtw_get_center_ch(ch, bw, offset); + + /* update vht cap ie */ + if (vht_cap_ie && vht_cap_ielen) { + #if UPDATE_VHT_CAP + /* if ((bw == CHANNEL_WIDTH_160 || bw == CHANNEL_WIDTH_80_80) && pvhtpriv->sgi_160m) + SET_VHT_CAPABILITY_ELE_SHORT_GI160M(pvht_cap_ie + 2, 1); + else */ + SET_VHT_CAPABILITY_ELE_SHORT_GI160M(vht_cap_ie + 2, 0); + + if (bw >= CHANNEL_WIDTH_80 && vhtpriv->sgi_80m) + SET_VHT_CAPABILITY_ELE_SHORT_GI80M(vht_cap_ie + 2, 1); + else + SET_VHT_CAPABILITY_ELE_SHORT_GI80M(vht_cap_ie + 2, 0); + #endif + } + + /* update vht op ie */ + if (vht_op_ie && vht_op_ielen) { + if (bw < CHANNEL_WIDTH_80) { + SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 0); + SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, 0); + SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0); + } else if (bw == CHANNEL_WIDTH_80) { + SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 1); + SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, center_freq); + SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0); + } else { + RTW_ERR(FUNC_ADPT_FMT" unsupported BW:%u\n", FUNC_ADPT_ARG(adapter), bw); + rtw_warn_on(1); + } + } + } +#endif /* CONFIG_80211AC_VHT */ +#ifdef CONFIG_80211N_HT + { + struct ht_priv *htpriv = &adapter->mlmepriv.htpriv; + u8 *ht_cap_ie, *ht_op_ie; + int ht_cap_ielen, ht_op_ielen; + + ht_cap_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_HTCapability, &ht_cap_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs))); + ht_op_ie = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), EID_HTInfo, &ht_op_ielen, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs))); + + /* update ht cap ie */ + if (ht_cap_ie && ht_cap_ielen) { + #if UPDATE_HT_CAP + if (bw >= CHANNEL_WIDTH_40) + SET_HT_CAP_ELE_CHL_WIDTH(ht_cap_ie + 2, 1); + else + SET_HT_CAP_ELE_CHL_WIDTH(ht_cap_ie + 2, 0); + + if (bw >= CHANNEL_WIDTH_40 && htpriv->sgi_40m) + SET_HT_CAP_ELE_SHORT_GI40M(ht_cap_ie + 2, 1); + else + SET_HT_CAP_ELE_SHORT_GI40M(ht_cap_ie + 2, 0); + + if (htpriv->sgi_20m) + SET_HT_CAP_ELE_SHORT_GI20M(ht_cap_ie + 2, 1); + else + SET_HT_CAP_ELE_SHORT_GI20M(ht_cap_ie + 2, 0); + #endif + } + + /* update ht op ie */ + if (ht_op_ie && ht_op_ielen) { + SET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2, ch); + switch (offset) { + case HAL_PRIME_CHNL_OFFSET_LOWER: + SET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2, SCA); + break; + case HAL_PRIME_CHNL_OFFSET_UPPER: + SET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2, SCB); + break; + case HAL_PRIME_CHNL_OFFSET_DONT_CARE: + default: + SET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2, SCN); + break; + } + + if (bw >= CHANNEL_WIDTH_40) + SET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2, 1); + else + SET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2, 0); + } + } +#endif /* CONFIG_80211N_HT */ + + { + u8 *p; + int ie_len; + u8 old_ch = bss->Configuration.DSConfig; + bool change_band = _FALSE; + + if ((ch <= 14 && old_ch >= 36) || (ch >= 36 && old_ch <= 14)) + change_band = _TRUE; + + /* update channel in IE */ + p = rtw_get_ie((bss->IEs + sizeof(NDIS_802_11_FIXED_IEs)), _DSSET_IE_, &ie_len, (bss->IELength - sizeof(NDIS_802_11_FIXED_IEs))); + if (p && ie_len > 0) + *(p + 2) = ch; + + bss->Configuration.DSConfig = ch; + + /* band is changed, update ERP, support rate, ext support rate IE */ + if (change_band == _TRUE) + change_band_update_ie(adapter, bss, ch); + } + +} + +bool rtw_ap_chbw_decision(_adapter *adapter, s16 req_ch, s8 req_bw, s8 req_offset + , u8 *ch, u8 *bw, u8 *offset, u8 *chbw_allow) +{ + u8 cur_ie_ch, cur_ie_bw, cur_ie_offset; + u8 dec_ch, dec_bw, dec_offset; + u8 u_ch = 0, u_offset, u_bw; + bool changed = _FALSE; + struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv); + WLAN_BSSID_EX *network = &(adapter->mlmepriv.cur_network.network); + struct mi_state mstate; + bool set_u_ch = _FALSE, set_dec_ch = _FALSE; + + rtw_ies_get_chbw(network->IEs + sizeof(NDIS_802_11_FIXED_IEs) + , network->IELength - sizeof(NDIS_802_11_FIXED_IEs) + , &cur_ie_ch, &cur_ie_bw, &cur_ie_offset); + +#ifdef CONFIG_MCC_MODE + if (MCC_EN(adapter)) { + if (rtw_hal_check_mcc_status(adapter, MCC_STATUS_DOING_MCC)) { + /* check channel settings are the same */ + if (cur_ie_ch == mlmeext->cur_channel + && cur_ie_bw == mlmeext->cur_bwmode + && cur_ie_offset == mlmeext->cur_ch_offset) { + + + RTW_INFO(FUNC_ADPT_FMT"req ch settings are the same as current ch setting, go to exit\n" + , FUNC_ADPT_ARG(adapter)); + + *chbw_allow = _FALSE; + goto exit; + } else { + RTW_INFO(FUNC_ADPT_FMT"request channel settings are not the same as current channel setting(%d,%d,%d,%d,%d,%d), restart MCC\n" + , FUNC_ADPT_ARG(adapter) + , cur_ie_ch, cur_ie_bw, cur_ie_bw + , mlmeext->cur_channel, mlmeext->cur_bwmode, mlmeext->cur_ch_offset); + + rtw_hal_set_mcc_setting_disconnect(adapter); + } + } + } +#endif /* CONFIG_MCC_MODE */ + + /* use chbw of cur_ie updated with specifying req as temporary decision */ + dec_ch = (req_ch <= 0) ? cur_ie_ch : req_ch; + dec_bw = (req_bw < 0) ? cur_ie_bw : req_bw; + dec_offset = (req_offset < 0) ? cur_ie_offset : req_offset; + + rtw_mi_status_no_self(adapter, &mstate); + RTW_INFO(FUNC_ADPT_FMT" ld_sta_num:%u, lg_sta_num%u, ap_num:%u\n" + , FUNC_ADPT_ARG(adapter), MSTATE_STA_LD_NUM(&mstate), MSTATE_STA_LG_NUM(&mstate), MSTATE_AP_NUM(&mstate)); + + if (MSTATE_STA_LD_NUM(&mstate) || MSTATE_AP_NUM(&mstate)) { + /* has linked STA or AP mode, follow */ + + rtw_warn_on(!rtw_mi_get_ch_setting_union_no_self(adapter, &u_ch, &u_bw, &u_offset)); + + RTW_INFO(FUNC_ADPT_FMT" union no self: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset); + RTW_INFO(FUNC_ADPT_FMT" req: %d,%d,%d\n", FUNC_ADPT_ARG(adapter), req_ch, req_bw, req_offset); + + rtw_adjust_chbw(adapter, u_ch, &dec_bw, &dec_offset); +#ifdef CONFIG_MCC_MODE + if (MCC_EN(adapter)) { + if (!rtw_is_chbw_grouped(u_ch, u_bw, u_offset, dec_ch, dec_bw, dec_offset)) { + mlmeext->cur_channel = *ch = dec_ch; + mlmeext->cur_bwmode = *bw = dec_bw; + mlmeext->cur_ch_offset = *offset = dec_offset; + /* channel bw offset can not be allowed, need MCC */ + *chbw_allow = _FALSE; + RTW_INFO(FUNC_ADPT_FMT" enable mcc: %u,%u,%u\n", FUNC_ADPT_ARG(adapter) + , *ch, *bw, *offset); + goto exit; + } else + /* channel bw offset can be allowed, not need MCC */ + *chbw_allow = _TRUE; + } +#endif /* CONFIG_MCC_MODE */ + rtw_sync_chbw(&dec_ch, &dec_bw, &dec_offset + , &u_ch, &u_bw, &u_offset); + + rtw_ap_update_bss_chbw(adapter, &(adapter->mlmepriv.cur_network.network) + , dec_ch, dec_bw, dec_offset); + + set_u_ch = _TRUE; + } else if (MSTATE_STA_LG_NUM(&mstate)) { + /* has linking STA */ + + rtw_warn_on(!rtw_mi_get_ch_setting_union_no_self(adapter, &u_ch, &u_bw, &u_offset)); + + RTW_INFO(FUNC_ADPT_FMT" union no self: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset); + RTW_INFO(FUNC_ADPT_FMT" req: %d,%d,%d\n", FUNC_ADPT_ARG(adapter), req_ch, req_bw, req_offset); + + rtw_adjust_chbw(adapter, dec_ch, &dec_bw, &dec_offset); + + if (rtw_is_chbw_grouped(u_ch, u_bw, u_offset, dec_ch, dec_bw, dec_offset)) { + + rtw_sync_chbw(&dec_ch, &dec_bw, &dec_offset + , &u_ch, &u_bw, &u_offset); + + rtw_ap_update_bss_chbw(adapter, &(adapter->mlmepriv.cur_network.network) + , dec_ch, dec_bw, dec_offset); + + set_u_ch = _TRUE; + + /* channel bw offset can be allowed, not need MCC */ + *chbw_allow = _TRUE; + } else { +#ifdef CONFIG_MCC_MODE + if (MCC_EN(adapter)) { + mlmeext->cur_channel = *ch = dec_ch; + mlmeext->cur_bwmode = *bw = dec_bw; + mlmeext->cur_ch_offset = *offset = dec_offset; + + /* channel bw offset can not be allowed, need MCC */ + *chbw_allow = _FALSE; + RTW_INFO(FUNC_ADPT_FMT" enable mcc: %u,%u,%u\n", FUNC_ADPT_ARG(adapter) + , *ch, *bw, *offset); + goto exit; + } +#endif /* CONFIG_MCC_MODE */ + /* set this for possible ch change when join down*/ + set_fwstate(&adapter->mlmepriv, WIFI_OP_CH_SWITCHING); + } + } else { + /* single AP mode */ + + RTW_INFO(FUNC_ADPT_FMT" req: %d,%d,%d\n", FUNC_ADPT_ARG(adapter), req_ch, req_bw, req_offset); + + /* check temporary decision first */ + rtw_adjust_chbw(adapter, dec_ch, &dec_bw, &dec_offset); + if (!rtw_get_offset_by_chbw(dec_ch, dec_bw, &dec_offset)) { + if (req_ch == -1 || req_bw == -1) + goto choose_chbw; + RTW_WARN(FUNC_ADPT_FMT" req: %u,%u has no valid offset\n", FUNC_ADPT_ARG(adapter), dec_ch, dec_bw); + *chbw_allow = _FALSE; + goto exit; + } + + if (!rtw_chset_is_chbw_valid(mlmeext->channel_set, dec_ch, dec_bw, dec_offset)) { + if (req_ch == -1 || req_bw == -1) + goto choose_chbw; + RTW_WARN(FUNC_ADPT_FMT" req: %u,%u,%u doesn't fit in chplan\n", FUNC_ADPT_ARG(adapter), dec_ch, dec_bw, dec_offset); + *chbw_allow = _FALSE; + goto exit; + } + + if (rtw_odm_dfs_domain_unknown(adapter) && rtw_is_dfs_ch(dec_ch, dec_bw, dec_offset)) { + if (req_ch >= 0) + RTW_WARN(FUNC_ADPT_FMT" DFS channel %u,%u,%u can't be used\n", FUNC_ADPT_ARG(adapter), dec_ch, dec_bw, dec_offset); + if (req_ch > 0) { + /* specific channel and not from IE => don't change channel setting */ + *chbw_allow = _FALSE; + goto exit; + } + goto choose_chbw; + } + + if (rtw_chset_is_ch_non_ocp(mlmeext->channel_set, dec_ch, dec_bw, dec_offset) == _FALSE) + goto update_bss_chbw; + +choose_chbw: + if (req_bw < 0) + req_bw = cur_ie_bw; + +#if defined(CONFIG_DFS_MASTER) + if (!rtw_odm_dfs_domain_unknown(adapter)) { + /* choose 5G DFS channel for debug */ + if (adapter_to_rfctl(adapter)->dbg_dfs_master_choose_dfs_ch_first + && rtw_choose_shortest_waiting_ch(adapter, req_bw, &dec_ch, &dec_bw, &dec_offset, RTW_CHF_2G | RTW_CHF_NON_DFS) == _TRUE) + RTW_INFO(FUNC_ADPT_FMT" choose 5G DFS channel for debug\n", FUNC_ADPT_ARG(adapter)); + else if (adapter_to_rfctl(adapter)->dfs_ch_sel_d_flags + && rtw_choose_shortest_waiting_ch(adapter, req_bw, &dec_ch, &dec_bw, &dec_offset, adapter_to_rfctl(adapter)->dfs_ch_sel_d_flags) == _TRUE) + RTW_INFO(FUNC_ADPT_FMT" choose with dfs_ch_sel_d_flags:0x%02x for debug\n", FUNC_ADPT_ARG(adapter), adapter_to_rfctl(adapter)->dfs_ch_sel_d_flags); + else if (rtw_choose_shortest_waiting_ch(adapter, req_bw, &dec_ch, &dec_bw, &dec_offset, 0) == _FALSE) { + RTW_WARN(FUNC_ADPT_FMT" no available channel\n", FUNC_ADPT_ARG(adapter)); + *chbw_allow = _FALSE; + goto exit; + } + } else +#endif /* defined(CONFIG_DFS_MASTER) */ + if (rtw_choose_shortest_waiting_ch(adapter, req_bw, &dec_ch, &dec_bw, &dec_offset, RTW_CHF_DFS) == _FALSE) { + RTW_WARN(FUNC_ADPT_FMT" no available channel\n", FUNC_ADPT_ARG(adapter)); + *chbw_allow = _FALSE; + goto exit; + } + +update_bss_chbw: + rtw_ap_update_bss_chbw(adapter, &(adapter->mlmepriv.cur_network.network) + , dec_ch, dec_bw, dec_offset); + + /* channel bw offset can be allowed for single AP, not need MCC */ + *chbw_allow = _TRUE; + set_dec_ch = _TRUE; + } + + if (rtw_mi_check_fwstate(adapter, _FW_UNDER_SURVEY)) { + /* scanning, leave ch setting to scan state machine */ + set_u_ch = set_dec_ch = _FALSE; + } + + if (mlmeext->cur_channel != dec_ch + || mlmeext->cur_bwmode != dec_bw + || mlmeext->cur_ch_offset != dec_offset) + changed = _TRUE; + + if (changed == _TRUE && rtw_linked_check(adapter) == _TRUE) { +#ifdef CONFIG_SPCT_CH_SWITCH + if (1) + rtw_ap_inform_ch_switch(adapter, dec_ch, dec_offset); + else +#endif + rtw_sta_flush(adapter, _FALSE); + } + + mlmeext->cur_channel = dec_ch; + mlmeext->cur_bwmode = dec_bw; + mlmeext->cur_ch_offset = dec_offset; + + if (u_ch != 0) + RTW_INFO(FUNC_ADPT_FMT" union: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset); + + RTW_INFO(FUNC_ADPT_FMT" dec: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), dec_ch, dec_bw, dec_offset); + + if (set_u_ch == _TRUE) { + *ch = u_ch; + *bw = u_bw; + *offset = u_offset; + } else if (set_dec_ch == _TRUE) { + *ch = dec_ch; + *bw = dec_bw; + *offset = dec_offset; + } +exit: + return changed; +} + +/*#define DBG_SWTIMER_BASED_TXBCN*/ + +#ifdef CONFIG_SWTIMER_BASED_TXBCN +void tx_beacon_handlder(struct dvobj_priv *pdvobj) +{ +#define BEACON_EARLY_TIME 20 /* unit:TU*/ + _irqL irqL; + _list *plist, *phead; + u32 timestamp[2]; + u32 bcn_interval_us; /* unit : usec */ + u64 time; + u32 cur_tick, time_offset; /* unit : usec */ + u32 inter_bcn_space_us; /* unit : usec */ + int nr_vap, idx, bcn_idx; + int i; + u8 val8, late = 0; + _adapter *padapter = NULL; + + i = 0; + + /* get first ap mode interface */ + _enter_critical_bh(&pdvobj->ap_if_q.lock, &irqL); + if (rtw_is_list_empty(&pdvobj->ap_if_q.queue) || (pdvobj->nr_ap_if == 0)) { + RTW_INFO("[%s] ERROR: ap_if_q is empty!or nr_ap = %d\n", __func__, pdvobj->nr_ap_if); + _exit_critical_bh(&pdvobj->ap_if_q.lock, &irqL); + return; + } else + padapter = LIST_CONTAINOR(get_next(&(pdvobj->ap_if_q.queue)), struct _ADAPTER, list); + _exit_critical_bh(&pdvobj->ap_if_q.lock, &irqL); + + if (NULL == padapter) { + RTW_INFO("[%s] ERROR: no any ap interface!\n", __func__); + return; + } + + + bcn_interval_us = DEFAULT_BCN_INTERVAL * NET80211_TU_TO_US; + if (0 == bcn_interval_us) { + RTW_INFO("[%s] ERROR: beacon interval = 0\n", __func__); + return; + } + + /* read TSF */ + timestamp[1] = rtw_read32(padapter, 0x560 + 4); + timestamp[0] = rtw_read32(padapter, 0x560); + while (timestamp[1]) { + time = (0xFFFFFFFF % bcn_interval_us + 1) * timestamp[1] + timestamp[0]; + timestamp[0] = (u32)time; + timestamp[1] = (u32)(time >> 32); + } + cur_tick = timestamp[0] % bcn_interval_us; + + + _enter_critical_bh(&pdvobj->ap_if_q.lock, &irqL); + + nr_vap = (pdvobj->nr_ap_if - 1); + if (nr_vap > 0) { + inter_bcn_space_us = pdvobj->inter_bcn_space * NET80211_TU_TO_US; /* beacon_interval / (nr_vap+1); */ + idx = cur_tick / inter_bcn_space_us; + if (idx < nr_vap) /* if (idx < (nr_vap+1))*/ + bcn_idx = idx + 1; /* bcn_idx = (idx + 1) % (nr_vap+1);*/ + else + bcn_idx = 0; + + /* to get padapter based on bcn_idx */ + padapter = NULL; + phead = get_list_head(&pdvobj->ap_if_q); + plist = get_next(phead); + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + padapter = LIST_CONTAINOR(plist, struct _ADAPTER, list); + + plist = get_next(plist); + + if (i == bcn_idx) + break; + + i++; + } + if ((NULL == padapter) || (i > pdvobj->nr_ap_if)) { + RTW_INFO("[%s] ERROR: nr_ap_if = %d, padapter=%p, bcn_idx=%d, index=%d\n", + __func__, pdvobj->nr_ap_if, padapter, bcn_idx, i); + _exit_critical_bh(&pdvobj->ap_if_q.lock, &irqL); + return; + } +#ifdef DBG_SWTIMER_BASED_TXBCN + RTW_INFO("BCN_IDX=%d, cur_tick=%d, padapter=%p\n", bcn_idx, cur_tick, padapter); +#endif + if (((idx + 2 == nr_vap + 1) && (idx < nr_vap + 1)) || (0 == bcn_idx)) { + time_offset = bcn_interval_us - cur_tick - BEACON_EARLY_TIME * NET80211_TU_TO_US; + if ((s32)time_offset < 0) + time_offset += inter_bcn_space_us; + + } else { + time_offset = (idx + 2) * inter_bcn_space_us - cur_tick - BEACON_EARLY_TIME * NET80211_TU_TO_US; + if (time_offset > (inter_bcn_space_us + (inter_bcn_space_us >> 1))) { + time_offset -= inter_bcn_space_us; + late = 1; + } + } + } else + /*#endif*/ { /* MBSSID */ + time_offset = 2 * bcn_interval_us - cur_tick - BEACON_EARLY_TIME * NET80211_TU_TO_US; + if (time_offset > (bcn_interval_us + (bcn_interval_us >> 1))) { + time_offset -= bcn_interval_us; + late = 1; + } + } + _exit_critical_bh(&pdvobj->ap_if_q.lock, &irqL); + +#ifdef DBG_SWTIMER_BASED_TXBCN + RTW_INFO("set sw bcn timer %d us\n", time_offset); +#endif + _set_timer(&pdvobj->txbcn_timer, time_offset / NET80211_TU_TO_US); + + if (padapter) { +#ifdef DBG_SWTIMER_BASED_TXBCN + RTW_INFO("padapter=%p, PORT=%d\n", padapter, padapter->hw_port); +#endif + /*update_beacon(padapter, _TIM_IE_, NULL, _FALSE);*/ + issue_beacon(padapter, 0); + } + +#if 0 + /* handle any buffered BC/MC frames*/ + /* Don't dynamically change DIS_ATIM due to HW will auto send ACQ after HIQ empty.*/ + val8 = *((unsigned char *)priv->beaconbuf + priv->timoffset + 4); + if (val8 & 0x01) { + process_mcast_dzqueue(priv); + priv->pkt_in_dtimQ = 0; + } +#endif + +} + +void tx_beacon_timer_handlder(struct dvobj_priv *pdvobj) +{ + _adapter *padapter = pdvobj->padapters[0]; + + if (padapter) + set_tx_beacon_cmd(padapter); +} +#endif + +#endif /* CONFIG_AP_MODE */ diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_beamforming.c b/linux-bsp/drivers/rtl8188eus/core/rtw_beamforming.c new file mode 100644 index 0000000..28a7899 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_beamforming.c @@ -0,0 +1,3157 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2016 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_BEAMFORMING_C_ + +#include <drv_types.h> +#include <hal_data.h> + +#ifdef CONFIG_BEAMFORMING + +#ifdef RTW_BEAMFORMING_VERSION_2 + +struct ndpa_sta_info { + u16 aid:12; + u16 feedback_type:1; + u16 nc_index:3; +}; + +static void _get_txvector_parameter(PADAPTER adapter, struct sta_info *sta, u8 *g_id, u16 *p_aid) +{ + struct mlme_priv *mlme; + u16 aid; + u8 *bssid; + u16 val16; + u8 i; + + + mlme = &adapter->mlmepriv; + + if (check_fwstate(mlme, WIFI_AP_STATE)) { + /* + * Sent by an AP and addressed to a STA associated with that AP + * or sent by a DLS or TDLS STA in a direct path to + * a DLS or TDLS peer STA + */ + + aid = sta->aid; + bssid = adapter_mac_addr(adapter); + RTW_INFO("%s: AID=0x%x BSSID=" MAC_FMT "\n", + __FUNCTION__, sta->aid, MAC_ARG(bssid)); + + /* AID[0:8] */ + aid &= 0x1FF; + /* BSSID[44:47] xor BSSID[40:43] */ + val16 = ((bssid[5] & 0xF0) >> 4) ^ (bssid[5] & 0xF); + /* (dec(AID[0:8]) + dec(BSSID)*2^5) mod 2^9 */ + *p_aid = (aid + (val16 << 5)) & 0x1FF; + *g_id = 63; + } else if ((check_fwstate(mlme, WIFI_ADHOC_STATE) == _TRUE) + || (check_fwstate(mlme, WIFI_ADHOC_MASTER_STATE) == _TRUE)) { + /* + * Otherwise, includes + * 1. Sent to an IBSS STA + * 2. Sent by an AP to a non associated STA + * 3. Sent to a STA for which it is not known + * which condition is applicable + */ + *p_aid = 0; + *g_id = 63; + } else { + /* Addressed to AP */ + bssid = sta->hwaddr; + RTW_INFO("%s: BSSID=" MAC_FMT "\n", __FUNCTION__, MAC_ARG(bssid)); + + /* BSSID[39:47] */ + *p_aid = (bssid[5] << 1) | (bssid[4] >> 7); + *g_id = 0; + } + + RTW_INFO("%s: GROUP_ID=0x%02x PARTIAL_AID=0x%04x\n", + __FUNCTION__, *g_id, *p_aid); +} + +/* + * Parameters + * adapter struct _adapter* + * sta struct sta_info* + * sta_bf_cap beamforming capabe of sta + * sounding_dim Number of Sounding Dimensions + * comp_steering Compressed Steering Number of Beamformer Antennas Supported + */ +static void _get_sta_beamform_cap(PADAPTER adapter, struct sta_info *sta, + u8 *sta_bf_cap, u8 *sounding_dim, u8 *comp_steering) +{ + struct beamforming_info *info; + struct ht_priv *ht; +#ifdef CONFIG_80211AC_VHT + struct vht_priv *vht; +#endif /* CONFIG_80211AC_VHT */ + u16 bf_cap; + + + *sta_bf_cap = 0; + *sounding_dim = 0; + *comp_steering = 0; + + info = GET_BEAMFORM_INFO(adapter); + ht = &adapter->mlmepriv.htpriv; +#ifdef CONFIG_80211AC_VHT + vht = &adapter->mlmepriv.vhtpriv; +#endif /* CONFIG_80211AC_VHT */ + + if (is_supported_ht(sta->wireless_mode) == _TRUE) { + /* HT */ + bf_cap = ht->beamform_cap; + + if (TEST_FLAG(bf_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) { + info->beamforming_cap |= BEAMFORMEE_CAP_HT_EXPLICIT; + *sta_bf_cap |= BEAMFORMER_CAP_HT_EXPLICIT; + *sounding_dim = (bf_cap & BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP) >> 6; + } + if (TEST_FLAG(bf_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) { + info->beamforming_cap |= BEAMFORMER_CAP_HT_EXPLICIT; + *sta_bf_cap |= BEAMFORMEE_CAP_HT_EXPLICIT; + *comp_steering = (bf_cap & BEAMFORMING_HT_BEAMFORMER_STEER_NUM) >> 4; + } + } + +#ifdef CONFIG_80211AC_VHT + if (is_supported_vht(sta->wireless_mode) == _TRUE) { + /* VHT */ + bf_cap = vht->beamform_cap; + + /* We are SU Beamformee because the STA is SU Beamformer */ + if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) { + info->beamforming_cap |= BEAMFORMEE_CAP_VHT_SU; + *sta_bf_cap |= BEAMFORMER_CAP_VHT_SU; + + /* We are MU Beamformee because the STA is MU Beamformer */ + if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE)) { + info->beamforming_cap |= BEAMFORMEE_CAP_VHT_MU; + *sta_bf_cap |= BEAMFORMER_CAP_VHT_MU; + } + + *sounding_dim = (bf_cap & BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM) >> 12; + } + /* We are SU Beamformer because the STA is SU Beamformee */ + if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) { + info->beamforming_cap |= BEAMFORMER_CAP_VHT_SU; + *sta_bf_cap |= BEAMFORMEE_CAP_VHT_SU; + + /* We are MU Beamformer because the STA is MU Beamformee */ + if (TEST_FLAG(bf_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) { + info->beamforming_cap |= BEAMFORMER_CAP_VHT_MU; + *sta_bf_cap |= BEAMFORMEE_CAP_VHT_MU; + } + + *comp_steering = (bf_cap & BEAMFORMING_VHT_BEAMFORMER_STS_CAP) >> 8; + } + } +#endif /* CONFIG_80211AC_VHT */ +} + +static u8 _send_ht_ndpa_packet(PADAPTER adapter, u8 *ra, CHANNEL_WIDTH bw) +{ + /* General */ + struct xmit_priv *pxmitpriv; + struct mlme_ext_priv *pmlmeext; + struct mlme_ext_info *pmlmeinfo; + struct xmit_frame *pmgntframe; + /* Beamforming */ + struct beamforming_info *info; + struct beamformee_entry *bfee; + struct ndpa_sta_info sta_info; + u8 ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xE0, 0x4C}; + /* MISC */ + struct pkt_attrib *attrib; + struct rtw_ieee80211_hdr *pwlanhdr; + enum MGN_RATE txrate; + u8 *pframe; + u16 duration = 0; + u8 aSifsTime = 0; + + + RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra)); + + pxmitpriv = &adapter->xmitpriv; + pmlmeext = &adapter->mlmeextpriv; + pmlmeinfo = &pmlmeext->mlmext_info; + bfee = rtw_bf_bfee_get_entry_by_addr(adapter, ra); + if (!bfee) { + RTW_ERR("%s: Cann't find beamformee entry!\n", __FUNCTION__); + return _FALSE; + } + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (!pmgntframe) { + RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__); + return _FALSE; + } + + txrate = beamforming_get_htndp_tx_rate(GET_PDM_ODM(adapter), bfee->comp_steering_num_of_bfer); + + /* update attribute */ + attrib = &pmgntframe->attrib; + update_mgntframe_attrib(adapter, attrib); + /*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */ + attrib->subtype = WIFI_ACTION_NOACK; + attrib->bwmode = bw; + /*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */ + attrib->order = 1; + attrib->rate = (u8)txrate; + attrib->bf_pkt_type = 0; + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + /* Frame control */ + pwlanhdr->frame_ctl = 0; + set_frame_sub_type(pframe, attrib->subtype); + set_order_bit(pframe); + + /* Duration */ + if (pmlmeext->cur_wireless_mode == WIRELESS_11B) + aSifsTime = 10; + else + aSifsTime = 16; + duration = 2 * aSifsTime + 40; + if (bw == CHANNEL_WIDTH_40) + duration += 87; + else + duration += 180; + set_duration(pframe, duration); + + /* DA */ + _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); + /* SA */ + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN); + /* BSSID */ + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); + + /* HT control field */ + SET_HT_CTRL_CSI_STEERING(pframe + 24, 3); + SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe + 24, 1); + + /* + * Frame Body + * Category field: vender-specific value, 0x7F + * OUI: 0x00E04C + */ + _rtw_memcpy(pframe + 28, ActionHdr, 4); + + attrib->pktlen = 32; + attrib->last_txcmdsz = attrib->pktlen; + + dump_mgntframe(adapter, pmgntframe); + + return _TRUE; +} + +static u8 _send_vht_ndpa_packet(PADAPTER adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw) +{ + /* General */ + struct xmit_priv *pxmitpriv; + struct mlme_ext_priv *pmlmeext; + struct xmit_frame *pmgntframe; + /* Beamforming */ + struct beamforming_info *info; + struct beamformee_entry *bfee; + struct ndpa_sta_info sta_info; + /* MISC */ + struct pkt_attrib *attrib; + struct rtw_ieee80211_hdr *pwlanhdr; + u8 *pframe; + enum MGN_RATE txrate; + u16 duration = 0; + u8 sequence = 0, aSifsTime = 0; + + + RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra)); + + pxmitpriv = &adapter->xmitpriv; + pmlmeext = &adapter->mlmeextpriv; + info = GET_BEAMFORM_INFO(adapter); + bfee = rtw_bf_bfee_get_entry_by_addr(adapter, ra); + if (!bfee) { + RTW_ERR("%s: Cann't find beamformee entry!\n", __FUNCTION__); + return _FALSE; + } + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (!pmgntframe) { + RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__); + return _FALSE; + } + + txrate = beamforming_get_vht_ndp_tx_rate(GET_PDM_ODM(adapter), bfee->comp_steering_num_of_bfer); + + /* update attribute */ + attrib = &pmgntframe->attrib; + update_mgntframe_attrib(adapter, attrib); + /*pattrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */ + attrib->subtype = WIFI_NDPA; + attrib->bwmode = bw; + /*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */ + attrib->rate = (u8)txrate; + attrib->bf_pkt_type = 0; + + _rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET); + pframe = pmgntframe->buf_addr + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + /* Frame control */ + pwlanhdr->frame_ctl = 0; + set_frame_sub_type(pframe, attrib->subtype); + + /* Duration */ + if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode)) + aSifsTime = 16; + else + aSifsTime = 10; + duration = 2 * aSifsTime + 44; + if (bw == CHANNEL_WIDTH_80) + duration += 40; + else if (bw == CHANNEL_WIDTH_40) + duration += 87; + else + duration += 180; + set_duration(pframe, duration); + + /* RA */ + _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); + + /* TA */ + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN); + + /* Sounding Sequence, bit0~1 is reserved */ + sequence = info->sounding_sequence << 2; + if (info->sounding_sequence >= 0x3f) + info->sounding_sequence = 0; + else + info->sounding_sequence++; + _rtw_memcpy(pframe + 16, &sequence, 1); + + /* STA Info */ + /* + * "AID12" Equal to 0 if the STA is an AP, mesh STA or + * STA that is a member of an IBSS + */ + if (check_fwstate(&adapter->mlmepriv, WIFI_AP_STATE) == _FALSE) + aid = 0; + sta_info.aid = aid; + /* "Feedback Type" set to 0 for SU */ + sta_info.feedback_type = 0; + /* "Nc Index" reserved if the Feedback Type field indicates SU */ + sta_info.nc_index = 0; + _rtw_memcpy(pframe + 17, (u8 *)&sta_info, 2); + + attrib->pktlen = 19; + attrib->last_txcmdsz = attrib->pktlen; + + dump_mgntframe(adapter, pmgntframe); + + return _TRUE; +} + +static u8 _send_vht_mu_ndpa_packet(PADAPTER adapter, CHANNEL_WIDTH bw) +{ + /* General */ + struct xmit_priv *pxmitpriv; + struct mlme_ext_priv *pmlmeext; + struct xmit_frame *pmgntframe; + /* Beamforming */ + struct beamforming_info *info; + struct sounding_info *sounding; + struct beamformee_entry *bfee; + struct ndpa_sta_info sta_info; + /* MISC */ + struct pkt_attrib *attrib; + struct rtw_ieee80211_hdr *pwlanhdr; + enum MGN_RATE txrate; + u8 *pframe; + u8 *ra = NULL; + u16 duration = 0; + u8 sequence = 0, aSifsTime = 0; + u8 i; + + + RTW_INFO("+%s\n", __FUNCTION__); + + pxmitpriv = &adapter->xmitpriv; + pmlmeext = &adapter->mlmeextpriv; + info = GET_BEAMFORM_INFO(adapter); + sounding = &info->sounding_info; + + txrate = MGN_VHT2SS_MCS0; + + /* + * Fill the first MU BFee entry (STA1) MAC addr to destination address then + * HW will change A1 to broadcast addr. + * 2015.05.28. Suggested by SD1 Chunchu. + */ + bfee = &info->bfee_entry[sounding->mu_sounding_list[0]]; + ra = bfee->mac_addr; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (!pmgntframe) { + RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__); + return _FALSE; + } + + /* update attribute */ + attrib = &pmgntframe->attrib; + update_mgntframe_attrib(adapter, attrib); + /*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */ + attrib->subtype = WIFI_NDPA; + attrib->bwmode = bw; + /*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */ + attrib->rate = (u8)txrate; + /* Set TxBFPktType of Tx desc to unicast type if there is only one MU STA for HW design */ + if (info->sounding_info.candidate_mu_bfee_cnt > 1) + attrib->bf_pkt_type = 1; + else + attrib->bf_pkt_type = 0; + + _rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET); + pframe = pmgntframe->buf_addr + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + /* Frame control */ + pwlanhdr->frame_ctl = 0; + set_frame_sub_type(pframe, attrib->subtype); + + /* Duration */ + if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode)) + aSifsTime = 16; + else + aSifsTime = 10; + duration = 2 * aSifsTime + 44; + if (bw == CHANNEL_WIDTH_80) + duration += 40; + else if (bw == CHANNEL_WIDTH_40) + duration += 87; + else + duration += 180; + set_duration(pframe, duration); + + /* RA */ + _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); + + /* TA */ + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN); + + /* Sounding Sequence, bit0~1 is reserved */ + sequence = info->sounding_sequence << 2; + if (info->sounding_sequence >= 0x3f) + info->sounding_sequence = 0; + else + info->sounding_sequence++; + _rtw_memcpy(pframe + 16, &sequence, 1); + + attrib->pktlen = 17; + + /* + * Construct STA info. for multiple STAs + * STA Info1, ..., STA Info n + */ + for (i = 0; i < sounding->candidate_mu_bfee_cnt; i++) { + bfee = &info->bfee_entry[sounding->mu_sounding_list[i]]; + sta_info.aid = bfee->aid; + sta_info.feedback_type = 1; /* 1'b1: MU */ + sta_info.nc_index = 0; + _rtw_memcpy(pframe + attrib->pktlen, (u8 *)&sta_info, 2); + attrib->pktlen += 2; + } + + attrib->last_txcmdsz = attrib->pktlen; + + dump_mgntframe(adapter, pmgntframe); + + return _TRUE; +} + +static u8 _send_bf_report_poll(PADAPTER adapter, u8 *ra, u8 bFinalPoll) +{ + /* General */ + struct xmit_priv *pxmitpriv; + struct xmit_frame *pmgntframe; + /* MISC */ + struct pkt_attrib *attrib; + struct rtw_ieee80211_hdr *pwlanhdr; + u8 *pframe; + + + RTW_INFO("+%s: Send to " MAC_FMT "\n", __FUNCTION__, MAC_ARG(ra)); + + pxmitpriv = &adapter->xmitpriv; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (!pmgntframe) { + RTW_ERR("%s: alloc mgnt frame fail!\n", __FUNCTION__); + return _FALSE; + } + + /* update attribute */ + attrib = &pmgntframe->attrib; + update_mgntframe_attrib(adapter, attrib); + /*attrib->type = WIFI_MGT_TYPE;*/ /* set in update_mgntframe_attrib() */ + attrib->subtype = WIFI_BF_REPORT_POLL; + attrib->bwmode = CHANNEL_WIDTH_20; + /*attrib->qsel = QSLT_MGNT;*/ /* set in update_mgntframe_attrib() */ + attrib->rate = MGN_6M; + if (bFinalPoll) + attrib->bf_pkt_type = 3; + else + attrib->bf_pkt_type = 2; + + _rtw_memset(pmgntframe->buf_addr, 0, TXDESC_OFFSET + WLANHDR_OFFSET); + pframe = pmgntframe->buf_addr + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + /* Frame control */ + pwlanhdr->frame_ctl = 0; + set_frame_sub_type(pframe, attrib->subtype); + + /* Duration */ + set_duration(pframe, 100); + + /* RA */ + _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); + + /* TA */ + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN); + + /* Feedback Segment Retransmission Bitmap */ + pframe[16] = 0xFF; + + attrib->pktlen = 17; + attrib->last_txcmdsz = attrib->pktlen; + + dump_mgntframe(adapter, pmgntframe); + + return _TRUE; +} + +static void _sounding_update_min_period(PADAPTER adapter, u16 period, u8 leave) +{ + struct beamforming_info *info; + struct beamformee_entry *bfee; + u8 i = 0; + u16 min_val = 0xFFFF; + + + info = GET_BEAMFORM_INFO(adapter); + + if (_TRUE == leave) { + /* + * When a BFee left, + * we need to find the latest min sounding period + * from the remaining BFees + */ + for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { + bfee = &info->bfee_entry[i]; + if ((bfee->used == _TRUE) + && (bfee->sound_period < min_val)) + min_val = bfee->sound_period; + } + + if (min_val == 0xFFFF) + info->sounding_info.min_sounding_period = 0; + else + info->sounding_info.min_sounding_period = min_val; + } else { + if ((info->sounding_info.min_sounding_period == 0) + || (period < info->sounding_info.min_sounding_period)) + info->sounding_info.min_sounding_period = period; + } +} + +static void _sounding_init(struct sounding_info *sounding) +{ + _rtw_memset(sounding->su_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_SU); + _rtw_memset(sounding->mu_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_MU); + sounding->state = SOUNDING_STATE_NONE; + sounding->su_bfee_curidx = 0xFF; + sounding->candidate_mu_bfee_cnt = 0; + sounding->min_sounding_period = 0; + sounding->sound_remain_cnt_per_period = 0; +} + +static void _sounding_reset_vars(PADAPTER adapter) +{ + struct beamforming_info *info; + struct sounding_info *sounding; + u8 idx; + + + info = GET_BEAMFORM_INFO(adapter); + sounding = &info->sounding_info; + + _rtw_memset(sounding->su_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_SU); + _rtw_memset(sounding->mu_sounding_list, 0xFF, MAX_NUM_BEAMFORMEE_MU); + sounding->su_bfee_curidx = 0xFF; + sounding->candidate_mu_bfee_cnt = 0; + + /* Clear bSound flag for the new period */ + for (idx = 0; idx < MAX_BEAMFORMEE_ENTRY_NUM; idx++) { + if ((info->bfee_entry[idx].used == _TRUE) + && (info->bfee_entry[idx].sounding == _TRUE)) { + info->bfee_entry[idx].sounding = _FALSE; + info->bfee_entry[idx].bCandidateSoundingPeer = _FALSE; + } + } +} + +/* + * Return + * 0 Prepare sounding list OK + * -1 Fail to prepare sounding list, because no beamformee need to souding + * -2 Fail to prepare sounding list, because beamformee state not ready + * + */ +static int _sounding_get_list(PADAPTER adapter) +{ + struct beamforming_info *info; + struct sounding_info *sounding; + struct beamformee_entry *bfee; + u8 i, mu_idx = 0, su_idx = 0, not_ready = 0; + int ret = 0; + + + info = GET_BEAMFORM_INFO(adapter); + sounding = &info->sounding_info; + + /* Add MU BFee list first because MU priority is higher than SU */ + for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { + bfee = &info->bfee_entry[i]; + if (bfee->used == _FALSE) + continue; + + if (bfee->state != BEAMFORM_ENTRY_HW_STATE_ADDED) { + RTW_ERR("%s: Invalid BFee idx(%d) Hw state=%d\n", __FUNCTION__, i, bfee->state); + not_ready++; + continue; + } + + /* + * Decrease BFee's SoundCnt per period + * If the remain count is 0, + * then it can be sounded at this time + */ + if (bfee->SoundCnt) { + bfee->SoundCnt--; + if (bfee->SoundCnt) + continue; + } + + /* + * <tynli_Note> + * If the STA supports MU BFee capability then we add it to MUSoundingList directly + * because we can only sound one STA by unicast NDPA with MU cap enabled to get correct channel info. + * Suggested by BB team Luke Lee. 2015.11.25. + */ + if (bfee->cap & BEAMFORMEE_CAP_VHT_MU) { + /* MU BFee */ + if (mu_idx >= MAX_NUM_BEAMFORMEE_MU) { + RTW_ERR("%s: Too much MU bfee entry(Limit:%d)\n", __FUNCTION__, MAX_NUM_BEAMFORMEE_MU); + continue; + } + + if (bfee->bApplySounding == _TRUE) { + bfee->bCandidateSoundingPeer = _TRUE; + bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, sounding->min_sounding_period); + sounding->mu_sounding_list[mu_idx] = i; + mu_idx++; + } + } else if (bfee->cap & (BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) { + /* SU BFee (HT/VHT) */ + if (su_idx >= MAX_NUM_BEAMFORMEE_SU) { + RTW_ERR("%s: Too much SU bfee entry(Limit:%d)\n", __FUNCTION__, MAX_NUM_BEAMFORMEE_SU); + continue; + } + + if (bfee->bDeleteSounding == _TRUE) { + sounding->su_sounding_list[su_idx] = i; + su_idx++; + } else if ((bfee->bApplySounding == _TRUE) + && (bfee->bSuspendSUCap == _FALSE)) { + bfee->bCandidateSoundingPeer = _TRUE; + bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, sounding->min_sounding_period); + sounding->su_sounding_list[su_idx] = i; + su_idx++; + } + } + } + + sounding->candidate_mu_bfee_cnt = mu_idx; + + if (su_idx + mu_idx == 0) { + ret = -1; + if (not_ready) + ret = -2; + } + + RTW_INFO("-%s: There are %d SU and %d MU BFees in this sounding period\n", __FUNCTION__, su_idx, mu_idx); + + return ret; +} + +static void _sounding_handler(PADAPTER adapter) +{ + struct beamforming_info *info; + struct sounding_info *sounding; + struct beamformee_entry *bfee; + u8 su_idx, i; + u32 timeout_period = 0; + u8 set_timer = _FALSE; + int ret = 0; + static u16 wait_cnt = 0; + + + info = GET_BEAMFORM_INFO(adapter); + sounding = &info->sounding_info; + + RTW_DBG("+%s: state=%d\n", __FUNCTION__, sounding->state); + if ((sounding->state != SOUNDING_STATE_INIT) + && (sounding->state != SOUNDING_STATE_SU_SOUNDDOWN) + && (sounding->state != SOUNDING_STATE_MU_SOUNDDOWN) + && (sounding->state != SOUNDING_STATE_SOUNDING_TIMEOUT)) { + RTW_WARN("%s: Invalid State(%d) and return!\n", __FUNCTION__, sounding->state); + return; + } + + if (sounding->state == SOUNDING_STATE_INIT) { + RTW_INFO("%s: Sounding start\n", __FUNCTION__); + + /* Init Var */ + _sounding_reset_vars(adapter); + + /* Get the sounding list of this sounding period */ + ret = _sounding_get_list(adapter); + if (ret == -1) { + wait_cnt = 0; + sounding->state = SOUNDING_STATE_NONE; + RTW_ERR("%s: No BFees found, set to SOUNDING_STATE_NONE\n", __FUNCTION__); + info->sounding_running--; + return; + } + if (ret == -2) { + RTW_WARN("%s: Temporarily cann't find BFee to sounding\n", __FUNCTION__); + if (wait_cnt < 5) { + wait_cnt++; + } else { + wait_cnt = 0; + sounding->state = SOUNDING_STATE_NONE; + RTW_ERR("%s: Wait changing state timeout!! Set to SOUNDING_STATE_NONE\n", __FUNCTION__); + } + info->sounding_running--; + return; + } + if (ret != 0) { + wait_cnt = 0; + RTW_ERR("%s: Unkown state(%d)!\n", __FUNCTION__, ret); + info->sounding_running--; + return; + + } + + wait_cnt = 0; + + if (check_fwstate(&adapter->mlmepriv, WIFI_SITE_MONITOR) == _TRUE) { + RTW_INFO("%s: Sounding abort! scanning APs...\n", __FUNCTION__); + info->sounding_running--; + return; + } + + rtw_ps_deny(adapter, PS_DENY_BEAMFORMING); + LeaveAllPowerSaveModeDirect(adapter); + } + + /* Get non-sound SU BFee index */ + for (i = 0; i < MAX_NUM_BEAMFORMEE_SU; i++) { + su_idx = sounding->su_sounding_list[i]; + if (su_idx >= MAX_BEAMFORMEE_ENTRY_NUM) + continue; + bfee = &info->bfee_entry[su_idx]; + if (_FALSE == bfee->sounding) + break; + } + if (i < MAX_NUM_BEAMFORMEE_SU) { + sounding->su_bfee_curidx = su_idx; + /* Set to sounding start state */ + sounding->state = SOUNDING_STATE_SU_START; + RTW_DBG("%s: Set to SOUNDING_STATE_SU_START\n", __FUNCTION__); + + bfee->sounding = _TRUE; + /* Reset sounding timeout flag for the new sounding */ + bfee->bSoundingTimeout = _FALSE; + + if (_TRUE == bfee->bDeleteSounding) { + u8 res = _FALSE; + rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 0); + return; + } + + /* Start SU sounding */ + if (bfee->cap & BEAMFORMEE_CAP_VHT_SU) + _send_vht_ndpa_packet(adapter, bfee->mac_addr, bfee->aid, bfee->sound_bw); + else if (bfee->cap & BEAMFORMEE_CAP_HT_EXPLICIT) + _send_ht_ndpa_packet(adapter, bfee->mac_addr, bfee->sound_bw); + + /* Set sounding timeout timer */ + _set_timer(&info->sounding_timeout_timer, SU_SOUNDING_TIMEOUT); + return; + } + + if (sounding->candidate_mu_bfee_cnt > 0) { + /* + * If there is no SU BFee then find MU BFee and perform MU sounding + * + * <tynli_note> Need to check the MU starting condition. 2015.12.15. + */ + sounding->state = SOUNDING_STATE_MU_START; + RTW_DBG("%s: Set to SOUNDING_STATE_MU_START\n", __FUNCTION__); + + /* Update MU BFee info */ + for (i = 0; i < sounding->candidate_mu_bfee_cnt; i++) { + bfee = &info->bfee_entry[sounding->mu_sounding_list[i]]; + bfee->sounding = _TRUE; + } + + /* Send MU NDPA */ + bfee = &info->bfee_entry[sounding->mu_sounding_list[0]]; + _send_vht_mu_ndpa_packet(adapter, bfee->sound_bw); + + /* Send BF report poll if more than 1 MU STA */ + for (i = 1; i < sounding->candidate_mu_bfee_cnt; i++) { + bfee = &info->bfee_entry[sounding->mu_sounding_list[i]]; + + if (i == (sounding->candidate_mu_bfee_cnt - 1))/* The last STA*/ + _send_bf_report_poll(adapter, bfee->mac_addr, _TRUE); + else + _send_bf_report_poll(adapter, bfee->mac_addr, _FALSE); + } + + sounding->candidate_mu_bfee_cnt = 0; + + /* Set sounding timeout timer */ + _set_timer(&info->sounding_timeout_timer, MU_SOUNDING_TIMEOUT); + return; + } + + info->sounding_running--; + sounding->state = SOUNDING_STATE_INIT; + RTW_INFO("%s: Sounding finished!\n", __FUNCTION__); + rtw_ps_deny_cancel(adapter, PS_DENY_BEAMFORMING); +} + +static void _sounding_force_stop(PADAPTER adapter) +{ + struct beamforming_info *info; + struct sounding_info *sounding; + u8 cancelled; + + + info = GET_BEAMFORM_INFO(adapter); + sounding = &info->sounding_info; + + if ((sounding->state == SOUNDING_STATE_SU_START) + || (sounding->state == SOUNDING_STATE_MU_START)) { + u8 res = _FALSE; + _cancel_timer(&info->sounding_timeout_timer, &cancelled); + rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 1); + return; + } + + info->sounding_running--; + sounding->state = SOUNDING_STATE_INIT; + RTW_INFO("%s: Sounding finished!\n", __FUNCTION__); + rtw_ps_deny_cancel(adapter, PS_DENY_BEAMFORMING); +} + +static void _sounding_timer_handler(void *FunctionContext) +{ + PADAPTER adapter; + struct beamforming_info *info; + struct sounding_info *sounding; + static u8 delay = 0; + + + RTW_DBG("+%s\n", __FUNCTION__); + + adapter = (PADAPTER)FunctionContext; + info = GET_BEAMFORM_INFO(adapter); + sounding = &info->sounding_info; + + if (SOUNDING_STATE_NONE == sounding->state) { + RTW_INFO("%s: Stop!\n", __FUNCTION__); + if (info->sounding_running) + RTW_WARN("%s: souding_running=%d when thread stop!\n", + __FUNCTION__, info->sounding_running); + return; + } + + _set_timer(&info->sounding_timer, sounding->min_sounding_period); + + if (!info->sounding_running) { + if (SOUNDING_STATE_INIT != sounding->state) { + RTW_WARN("%s: state(%d) != SOUNDING_STATE_INIT!!\n", __FUNCTION__, sounding->state); + sounding->state = SOUNDING_STATE_INIT; + } + delay = 0; + info->sounding_running++; + rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 1); + } else { + if (delay != 0xFF) + delay++; + RTW_WARN("%s: souding is still processing...(state:%d, running:%d, delay:%d)\n", + __FUNCTION__, sounding->state, info->sounding_running, delay); + if (delay > 3) { + RTW_WARN("%s: Stop sounding!!\n", __FUNCTION__); + _sounding_force_stop(adapter); + } + } +} + +static void _sounding_timeout_timer_handler(void *FunctionContext) +{ + PADAPTER adapter; + struct beamforming_info *info; + struct sounding_info *sounding; + struct beamformee_entry *bfee; + + + RTW_WARN("+%s\n", __FUNCTION__); + + adapter = (PADAPTER)FunctionContext; + info = GET_BEAMFORM_INFO(adapter); + sounding = &info->sounding_info; + + if (SOUNDING_STATE_SU_START == sounding->state) { + sounding->state = SOUNDING_STATE_SOUNDING_TIMEOUT; + RTW_ERR("%s: Set to SU SOUNDING_STATE_SOUNDING_TIMEOUT\n", __FUNCTION__); + /* SU BFee */ + bfee = &info->bfee_entry[sounding->su_bfee_curidx]; + bfee->bSoundingTimeout = _TRUE; + RTW_WARN("%s: The BFee entry[%d] is Sounding Timeout!\n", __FUNCTION__, sounding->su_bfee_curidx); + } else if (SOUNDING_STATE_MU_START == sounding->state) { + sounding->state = SOUNDING_STATE_SOUNDING_TIMEOUT; + RTW_ERR("%s: Set to MU SOUNDING_STATE_SOUNDING_TIMEOUT\n", __FUNCTION__); + } else { + RTW_WARN("%s: unexpected sounding state:0x%02x\n", __FUNCTION__, sounding->state); + return; + } + + rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 1); +} + +static struct beamformer_entry *_bfer_get_free_entry(PADAPTER adapter) +{ + u8 i = 0; + struct beamforming_info *info; + struct beamformer_entry *bfer; + + + info = GET_BEAMFORM_INFO(adapter); + + for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) { + bfer = &info->bfer_entry[i]; + if (bfer->used == _FALSE) + return bfer; + } + + return NULL; +} + +static struct beamformer_entry *_bfer_get_entry_by_addr(PADAPTER adapter, u8 *ra) +{ + u8 i = 0; + struct beamforming_info *info; + struct beamformer_entry *bfer; + + + info = GET_BEAMFORM_INFO(adapter); + + for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) { + bfer = &info->bfer_entry[i]; + if (bfer->used == _FALSE) + continue; + if (_rtw_memcmp(ra, bfer->mac_addr, ETH_ALEN) == _TRUE) + return bfer; + } + + return NULL; +} + +static struct beamformer_entry *_bfer_add_entry(PADAPTER adapter, + struct sta_info *sta, u8 bf_cap, u8 sounding_dim, u8 comp_steering) +{ + struct mlme_priv *mlme; + struct beamforming_info *info; + struct beamformer_entry *bfer; + u8 *bssid; + u16 val16; + u8 i; + + + mlme = &adapter->mlmepriv; + info = GET_BEAMFORM_INFO(adapter); + + bfer = _bfer_get_entry_by_addr(adapter, sta->hwaddr); + if (!bfer) { + bfer = _bfer_get_free_entry(adapter); + if (!bfer) + return NULL; + } + + bfer->used = _TRUE; + _get_txvector_parameter(adapter, sta, &bfer->g_id, &bfer->p_aid); + _rtw_memcpy(bfer->mac_addr, sta->hwaddr, ETH_ALEN); + bfer->cap = bf_cap; + bfer->state = BEAMFORM_ENTRY_HW_STATE_ADD_INIT; + bfer->NumofSoundingDim = sounding_dim; + + if (TEST_FLAG(bf_cap, BEAMFORMER_CAP_VHT_MU)) { + info->beamformer_mu_cnt += 1; + bfer->aid = sta->aid; + } else if (TEST_FLAG(bf_cap, BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT)) { + info->beamformer_su_cnt += 1; + + /* Record HW idx info */ + for (i = 0; i < MAX_NUM_BEAMFORMER_SU; i++) { + if ((info->beamformer_su_reg_maping & BIT(i)) == 0) { + info->beamformer_su_reg_maping |= BIT(i); + bfer->su_reg_index = i; + break; + } + } + RTW_INFO("%s: Add BFer entry beamformer_su_reg_maping=%#x, su_reg_index=%d\n", + __FUNCTION__, info->beamformer_su_reg_maping, bfer->su_reg_index); + } + + return bfer; +} + +static void _bfer_remove_entry(PADAPTER adapter, struct beamformer_entry *entry) +{ + struct beamforming_info *info; + + + info = GET_BEAMFORM_INFO(adapter); + + entry->state = BEAMFORM_ENTRY_HW_STATE_DELETE_INIT; + + if (TEST_FLAG(entry->cap, BEAMFORMER_CAP_VHT_MU)) { + info->beamformer_mu_cnt -= 1; + _rtw_memset(entry->gid_valid, 0, 8); + _rtw_memset(entry->user_position, 0, 16); + } else if (TEST_FLAG(entry->cap, BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT)) { + info->beamformer_su_cnt -= 1; + } + + if (info->beamformer_mu_cnt == 0) + info->beamforming_cap &= ~BEAMFORMEE_CAP_VHT_MU; + if (info->beamformer_su_cnt == 0) + info->beamforming_cap &= ~(BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT); +} + +static u8 _bfer_set_entry_gid(PADAPTER adapter, u8 *addr, u8 *gid, u8 *position) +{ + struct beamformer_entry *bfer = NULL; + + + bfer = _bfer_get_entry_by_addr(adapter, addr); + if (!bfer) { + RTW_INFO("%s: Cannot find BFer entry!!\n", __FUNCTION__); + return _FAIL; + } + + /* Parsing Membership Status Array */ + _rtw_memcpy(bfer->gid_valid, gid, 8); + /* Parsing User Position Array */ + _rtw_memcpy(bfer->user_position, position, 16); + + /* Config HW GID table */ + rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_GID_TABLE, (u8*)&bfer, sizeof(struct beamformer_entry *), 1); + + return _SUCCESS; +} + +static struct beamformee_entry *_bfee_get_free_entry(PADAPTER adapter) +{ + u8 i = 0; + struct beamforming_info *info; + struct beamformee_entry *bfee; + + + info = GET_BEAMFORM_INFO(adapter); + + for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { + bfee = &info->bfee_entry[i]; + if (bfee->used == _FALSE) + return bfee; + } + + return NULL; +} + +static struct beamformee_entry *_bfee_get_entry_by_addr(PADAPTER adapter, u8 *ra) +{ + u8 i = 0; + struct beamforming_info *info; + struct beamformee_entry *bfee; + + + info = GET_BEAMFORM_INFO(adapter); + + for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { + bfee = &info->bfee_entry[i]; + if (bfee->used == _FALSE) + continue; + if (_rtw_memcmp(ra, bfee->mac_addr, ETH_ALEN) == _TRUE) + return bfee; + } + + return NULL; +} + +static u8 _bfee_get_first_su_entry_idx(PADAPTER adapter, struct beamformee_entry *ignore) +{ + struct beamforming_info *info; + struct beamformee_entry *bfee; + u8 i; + + + info = GET_BEAMFORM_INFO(adapter); + + for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { + bfee = &info->bfee_entry[i]; + if (ignore && (bfee == ignore)) + continue; + if (bfee->used == _FALSE) + continue; + if ((!TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_MU)) + && TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) + return i; + } + + return 0xFF; +} + +/* + * Description: + * Get the first entry index of MU Beamformee. + * + * Return Value: + * Index of the first MU sta, or 0xFF for invalid index. + * + * 2015.05.25. Created by tynli. + * + */ +static u8 _bfee_get_first_mu_entry_idx(PADAPTER adapter, struct beamformee_entry *ignore) +{ + struct beamforming_info *info; + struct beamformee_entry *bfee; + u8 i; + + + info = GET_BEAMFORM_INFO(adapter); + + for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { + bfee = &info->bfee_entry[i]; + if (ignore && (bfee == ignore)) + continue; + if (bfee->used == _FALSE) + continue; + if (TEST_FLAG(bfee->cap, BEAMFORMEE_CAP_VHT_MU)) + return i; + } + + return 0xFF; +} + +static struct beamformee_entry *_bfee_add_entry(PADAPTER adapter, + struct sta_info *sta, u8 bf_cap, u8 sounding_dim, u8 comp_steering) +{ + struct mlme_priv *mlme; + struct beamforming_info *info; + struct beamformee_entry *bfee; + u8 *bssid; + u16 val16; + u8 i; + + + mlme = &adapter->mlmepriv; + info = GET_BEAMFORM_INFO(adapter); + + bfee = _bfee_get_entry_by_addr(adapter, sta->hwaddr); + if (!bfee) { + bfee = _bfee_get_free_entry(adapter); + if (!bfee) + return NULL; + } + + bfee->used = _TRUE; + bfee->aid = sta->aid; + bfee->mac_id = sta->mac_id; + bfee->sound_bw = sta->bw_mode; + + _get_txvector_parameter(adapter, sta, &bfee->g_id, &bfee->p_aid); + sta->txbf_gid = bfee->g_id; + sta->txbf_paid = bfee->p_aid; + + _rtw_memcpy(bfee->mac_addr, sta->hwaddr, ETH_ALEN); + bfee->txbf = _FALSE; + bfee->sounding = _FALSE; + bfee->sound_period = 40; + _sounding_update_min_period(adapter, bfee->sound_period, _FALSE); + bfee->SoundCnt = GetInitSoundCnt(bfee->sound_period, info->sounding_info.min_sounding_period); + bfee->cap = bf_cap; + bfee->state = BEAMFORM_ENTRY_HW_STATE_ADD_INIT; + + bfee->bCandidateSoundingPeer = _FALSE; + bfee->bSoundingTimeout = _FALSE; + bfee->bDeleteSounding = _FALSE; + bfee->bApplySounding = _TRUE; + + bfee->tx_timestamp = 0; + bfee->tx_bytes = 0; + + bfee->LogStatusFailCnt = 0; + bfee->NumofSoundingDim = sounding_dim; + bfee->comp_steering_num_of_bfer = comp_steering; + bfee->bSuspendSUCap = _FALSE; + + if (TEST_FLAG(bf_cap, BEAMFORMEE_CAP_VHT_MU)) { + info->beamformee_mu_cnt += 1; + info->first_mu_bfee_index = _bfee_get_first_mu_entry_idx(adapter, NULL); + + if (_TRUE == info->bEnableSUTxBFWorkAround) { + /* When the first MU BFee added, discard SU BFee bfee's capability */ + if ((info->beamformee_mu_cnt == 1) && (info->beamformee_su_cnt > 0)) { + if (info->TargetSUBFee) { + info->TargetSUBFee->bSuspendSUCap = _TRUE; + info->TargetSUBFee->bDeleteSounding = _TRUE; + } else { + RTW_ERR("%s: UNEXPECTED!! info->TargetSUBFee is NULL!", __FUNCTION__); + } + info->TargetSUBFee = NULL; + _rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO)); + rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 0); + } + } + + /* Record HW idx info */ + for (i = 0; i < MAX_NUM_BEAMFORMEE_MU; i++) { + if ((info->beamformee_mu_reg_maping & BIT(i)) == 0) { + info->beamformee_mu_reg_maping |= BIT(i); + bfee->mu_reg_index = i; + break; + } + } + RTW_INFO("%s: Add BFee entry beamformee_mu_reg_maping=%#x, mu_reg_index=%d\n", + __FUNCTION__, info->beamformee_mu_reg_maping, bfee->mu_reg_index); + + } else if (TEST_FLAG(bf_cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) { + info->beamformee_su_cnt += 1; + + if (_TRUE == info->bEnableSUTxBFWorkAround) { + /* Record the first SU BFee index. We only allow the first SU BFee to be sound */ + if ((info->beamformee_su_cnt == 1) && (info->beamformee_mu_cnt == 0)) { + info->TargetSUBFee = bfee; + _rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO)); + bfee->bSuspendSUCap = _FALSE; + } else { + bfee->bSuspendSUCap = _TRUE; + } + } + + /* Record HW idx info */ + for (i = 0; i < MAX_NUM_BEAMFORMEE_SU; i++) { + if ((info->beamformee_su_reg_maping & BIT(i)) == 0) { + info->beamformee_su_reg_maping |= BIT(i); + bfee->su_reg_index = i; + break; + } + } + RTW_INFO("%s: Add BFee entry beamformee_su_reg_maping=%#x, su_reg_index=%d\n", + __FUNCTION__, info->beamformee_su_reg_maping, bfee->su_reg_index); + } + + return bfee; +} + +static void _bfee_remove_entry(PADAPTER adapter, struct beamformee_entry *entry) +{ + struct beamforming_info *info; + u8 idx; + + + info = GET_BEAMFORM_INFO(adapter); + + entry->state = BEAMFORM_ENTRY_HW_STATE_DELETE_INIT; + + if (TEST_FLAG(entry->cap, BEAMFORMEE_CAP_VHT_MU)) { + info->beamformee_mu_cnt -= 1; + info->first_mu_bfee_index = _bfee_get_first_mu_entry_idx(adapter, entry); + + if (_TRUE == info->bEnableSUTxBFWorkAround) { + if ((info->beamformee_mu_cnt == 0) && (info->beamformee_su_cnt > 0)) { + idx = _bfee_get_first_su_entry_idx(adapter, NULL); + info->TargetSUBFee = &info->bfee_entry[idx]; + _rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO)); + info->TargetSUBFee->bSuspendSUCap = _FALSE; + } + } + } else if (TEST_FLAG(entry->cap, BEAMFORMEE_CAP_VHT_SU|BEAMFORMEE_CAP_HT_EXPLICIT)) { + info->beamformee_su_cnt -= 1; + + /* When the target SU BFee leaves, disable workaround */ + if ((_TRUE == info->bEnableSUTxBFWorkAround) + && (entry == info->TargetSUBFee)) { + entry->bSuspendSUCap = _TRUE; + info->TargetSUBFee = NULL; + _rtw_memset(&info->TargetCSIInfo, 0, sizeof(struct _RT_CSI_INFO)); + rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 0); + } + } + + if (info->beamformee_mu_cnt == 0) + info->beamforming_cap &= ~BEAMFORMER_CAP_VHT_MU; + if (info->beamformee_su_cnt == 0) + info->beamforming_cap &= ~(BEAMFORMER_CAP_VHT_SU|BEAMFORMER_CAP_HT_EXPLICIT); + + _sounding_update_min_period(adapter, 0, _TRUE); +} + +static enum beamforming_cap _bfee_get_entry_cap_by_macid(PADAPTER adapter, u8 macid) +{ + struct beamforming_info *info; + struct beamformee_entry *bfee; + u8 i; + + + info = GET_BEAMFORM_INFO(adapter); + + for (i = 0; i < MAX_BEAMFORMER_ENTRY_NUM; i++) { + bfee = &info->bfee_entry[i]; + if (bfee->used == _FALSE) + continue; + if (bfee->mac_id == macid) + return bfee->cap; + } + + return BEAMFORMING_CAP_NONE; +} + +static void _beamforming_enter(PADAPTER adapter, void *p) +{ + struct mlme_priv *mlme; + struct ht_priv *htpriv; +#ifdef CONFIG_80211AC_VHT + struct vht_priv *vhtpriv; +#endif + struct mlme_ext_priv *mlme_ext; + struct sta_info *sta, *sta_copy; + struct beamforming_info *info; + struct beamformer_entry *bfer = NULL; + struct beamformee_entry *bfee = NULL; + u8 wireless_mode; + u8 sta_bf_cap; + u8 sounding_dim = 0; /* number of sounding dimensions */ + u8 comp_steering_num = 0; /* compressed steering number */ + + + mlme = &adapter->mlmepriv; + htpriv = &mlme->htpriv; +#ifdef CONFIG_80211AC_VHT + vhtpriv = &mlme->vhtpriv; +#endif + mlme_ext = &adapter->mlmeextpriv; + info = GET_BEAMFORM_INFO(adapter); + + sta_copy = (struct sta_info *)p; + sta = rtw_get_stainfo(&adapter->stapriv, sta_copy->hwaddr); + if (!sta) { + RTW_ERR("%s: Cann't find STA info for " MAC_FMT "\n", + __FUNCTION__, MAC_ARG(sta_copy->hwaddr)); + return; + } + if (sta != sta_copy) { + RTW_WARN("%s: Origin sta(fake)=%p realsta=%p for " MAC_FMT "\n", + __FUNCTION__, sta_copy, sta, MAC_ARG(sta_copy->hwaddr)); + } + + /* The current setting does not support Beaforming */ + wireless_mode = sta->wireless_mode; + if ((is_supported_ht(wireless_mode) == _FALSE) + && (is_supported_vht(wireless_mode) == _FALSE)) { + RTW_WARN("%s: Not support HT or VHT mode\n", __FUNCTION__); + return; + } + + if ((0 == htpriv->beamform_cap) +#ifdef CONFIG_80211AC_VHT + && (0 == vhtpriv->beamform_cap) +#endif + ) { + RTW_INFO("The configuration disabled Beamforming! Skip...\n"); + return; + } + + _get_sta_beamform_cap(adapter, sta, + &sta_bf_cap, &sounding_dim, &comp_steering_num); + RTW_INFO("STA Beamforming Capability=0x%02X\n", sta_bf_cap); + if (sta_bf_cap == BEAMFORMING_CAP_NONE) + return; + if ((sta_bf_cap & BEAMFORMEE_CAP_HT_EXPLICIT) + || (sta_bf_cap & BEAMFORMEE_CAP_VHT_SU) + || (sta_bf_cap & BEAMFORMEE_CAP_VHT_MU)) + sta_bf_cap |= BEAMFORMEE_CAP; + if ((sta_bf_cap & BEAMFORMER_CAP_HT_EXPLICIT) + || (sta_bf_cap & BEAMFORMER_CAP_VHT_SU) + || (sta_bf_cap & BEAMFORMER_CAP_VHT_MU)) + sta_bf_cap |= BEAMFORMER_CAP; + + if (sta_bf_cap & BEAMFORMER_CAP) { + /* The other side is beamformer */ + bfer = _bfer_add_entry(adapter, sta, sta_bf_cap, sounding_dim, comp_steering_num); + if (!bfer) + RTW_ERR("%s: Fail to allocate bfer entry!\n", __FUNCTION__); + } + if (sta_bf_cap & BEAMFORMEE_CAP) { + /* The other side is beamformee */ + bfee = _bfee_add_entry(adapter, sta, sta_bf_cap, sounding_dim, comp_steering_num); + if (!bfee) + RTW_ERR("%s: Fail to allocate bfee entry!\n", __FUNCTION__); + } + if (!bfer && !bfee) + return; + + rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_ENTER, (u8*)sta); + + /* Perform sounding if there is BFee */ + if ((info->beamformee_su_cnt != 0) + || (info->beamformee_mu_cnt != 0)) { + if (SOUNDING_STATE_NONE == info->sounding_info.state) { + info->sounding_info.state = SOUNDING_STATE_INIT; + /* Start sounding after 2 sec */ + _set_timer(&info->sounding_timer, 2000); + } + } +} + +static void _beamforming_reset(PADAPTER adapter) +{ + RTW_ERR("%s: Not ready!!\n", __FUNCTION__); +} + +static void _beamforming_leave(PADAPTER adapter, u8 *ra) +{ + struct beamforming_info *info; + struct beamformer_entry *bfer = NULL; + struct beamformee_entry *bfee = NULL; + u8 bHwStateAddInit = _FALSE; + + + RTW_INFO("+%s\n", __FUNCTION__); + + info = GET_BEAMFORM_INFO(adapter); + bfer = _bfer_get_entry_by_addr(adapter, ra); + bfee = _bfee_get_entry_by_addr(adapter, ra); + + if (!bfer && !bfee) { + RTW_WARN("%s: " MAC_FMT " is neither beamforming ee or er!!\n", + __FUNCTION__, MAC_ARG(ra)); + return; + } + + if (bfer) + _bfer_remove_entry(adapter, bfer); + + if (bfee) + _bfee_remove_entry(adapter, bfee); + + rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, ra); + + /* Stop sounding if there is no any BFee */ + if ((info->beamformee_su_cnt == 0) + && (info->beamformee_mu_cnt == 0)) { + u8 cancelled; + _cancel_timer(&info->sounding_timer, &cancelled); + _sounding_init(&info->sounding_info); + } + + RTW_INFO("-%s\n", __FUNCTION__); +} + +static void _beamforming_sounding_down(PADAPTER adapter, u8 status) +{ + struct beamforming_info *info; + struct sounding_info *sounding; + struct beamformee_entry *bfee; + + + info = GET_BEAMFORM_INFO(adapter); + sounding = &info->sounding_info; + + RTW_INFO("+%s: sounding=%d, status=0x%02x\n", __FUNCTION__, sounding->state, status); + + if (sounding->state == SOUNDING_STATE_MU_START) { + RTW_INFO("%s: MU sounding done\n", __FUNCTION__); + sounding->state = SOUNDING_STATE_MU_SOUNDDOWN; + RTW_INFO("%s: Set to SOUNDING_STATE_MU_SOUNDDOWN\n", __FUNCTION__); + info->SetHalSoundownOnDemandCnt++; + rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status); + } else if (sounding->state == SOUNDING_STATE_SU_START) { + RTW_INFO("%s: SU entry[%d] sounding down\n", __FUNCTION__, sounding->su_bfee_curidx); + bfee = &info->bfee_entry[sounding->su_bfee_curidx]; + sounding->state = SOUNDING_STATE_SU_SOUNDDOWN; + RTW_INFO("%s: Set to SOUNDING_STATE_SU_SOUNDDOWN\n", __FUNCTION__); + + /* + * <tynli_note> + * bfee->bSoundingTimeout this flag still cannot avoid + * old sound down event happens in the new sounding period. + * 2015.12.10 + */ + if (_TRUE == bfee->bSoundingTimeout) { + RTW_WARN("%s: The entry[%d] is bSoundingTimeout!\n", __FUNCTION__, sounding->su_bfee_curidx); + bfee->bSoundingTimeout = _FALSE; + return; + } + + if (_TRUE == status) { + /* success */ + bfee->LogStatusFailCnt = 0; + info->SetHalSoundownOnDemandCnt++; + rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status); + } else if (_TRUE == bfee->bDeleteSounding) { + RTW_WARN("%s: Delete entry[%d] sounding info!\n", __FUNCTION__, sounding->su_bfee_curidx); + rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_STATUS, &status); + bfee->bDeleteSounding = _FALSE; + } else { + bfee->LogStatusFailCnt++; + RTW_WARN("%s: LogStatusFailCnt=%d\n", __FUNCTION__, bfee->LogStatusFailCnt); + if (bfee->LogStatusFailCnt > 30) { + RTW_ERR("%s: LogStatusFailCnt > 30, Stop SOUNDING!!\n", __FUNCTION__); + rtw_bf_cmd(adapter, BEAMFORMING_CTRL_LEAVE, bfee->mac_addr, ETH_ALEN, 1); + } + } + } else { + RTW_WARN("%s: unexpected sounding state:0x%02x\n", __FUNCTION__, sounding->state); + return; + } + + rtw_bf_cmd(adapter, BEAMFORMING_CTRL_START_PERIOD, NULL, 0, 0); +} + +static void _c2h_snd_txbf(PADAPTER adapter, u8 *buf, u8 buf_len) +{ + struct beamforming_info *info; + u8 cancelled; + u8 res; + + + info = GET_BEAMFORM_INFO(adapter); + + _cancel_timer(&info->sounding_timeout_timer, &cancelled); + + res = C2H_SND_TXBF_GET_SND_RESULT(buf) ? _TRUE : _FALSE; + RTW_INFO("+%s: %s\n", __FUNCTION__, res==_TRUE?"Success":"Fail!"); + + rtw_bf_cmd(adapter, BEAMFORMING_CTRL_END_PERIOD, &res, 1, 1); +} + +/* + * Description: + * This function is for phydm only + */ +enum beamforming_cap rtw_bf_bfee_get_entry_cap_by_macid(void *mlme, u8 macid) +{ + PADAPTER adapter; + enum beamforming_cap cap = BEAMFORMING_CAP_NONE; + + + adapter = mlme_to_adapter((struct mlme_priv *)mlme); + cap = _bfee_get_entry_cap_by_macid(adapter, macid); + + return cap; +} + +struct beamformer_entry *rtw_bf_bfer_get_entry_by_addr(PADAPTER adapter, u8 *ra) +{ + return _bfer_get_entry_by_addr(adapter, ra); +} + +struct beamformee_entry *rtw_bf_bfee_get_entry_by_addr(PADAPTER adapter, u8 *ra) +{ + return _bfee_get_entry_by_addr(adapter, ra); +} + +void rtw_bf_get_ndpa_packet(PADAPTER adapter, union recv_frame *precv_frame) +{ + RTW_DBG("+%s\n", __FUNCTION__); +} + +u32 rtw_bf_get_report_packet(PADAPTER adapter, union recv_frame *precv_frame) +{ + u32 ret = _SUCCESS; + struct beamforming_info *info; + struct beamformee_entry *bfee = NULL; + u8 *pframe; + u32 frame_len; + u8 *ta; + u8 *frame_body; + u8 category, action; + u8 *pMIMOCtrlField, *pCSIMatrix; + u8 Nc = 0, Nr = 0, CH_W = 0, Ng = 0, CodeBook = 0; + u16 CSIMatrixLen = 0; + + + RTW_INFO("+%s\n", __FUNCTION__); + + info = GET_BEAMFORM_INFO(adapter); + pframe = precv_frame->u.hdr.rx_data; + frame_len = precv_frame->u.hdr.len; + + /* Memory comparison to see if CSI report is the same with previous one */ + ta = get_addr2_ptr(pframe); + bfee = _bfee_get_entry_by_addr(adapter, ta); + if (!bfee) + return _FAIL; + + frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + category = frame_body[0]; + action = frame_body[1]; + + if ((category == RTW_WLAN_CATEGORY_VHT) + && (action == RTW_WLAN_ACTION_VHT_COMPRESSED_BEAMFORMING)) { + pMIMOCtrlField = pframe + 26; + Nc = (*pMIMOCtrlField) & 0x7; + Nr = ((*pMIMOCtrlField) & 0x38) >> 3; + CH_W = (((*pMIMOCtrlField) & 0xC0) >> 6); + Ng = (*(pMIMOCtrlField+1)) & 0x3; + CodeBook = ((*(pMIMOCtrlField+1)) & 0x4) >> 2; + /* + * 24+(1+1+3)+2 + * ==> MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2) + */ + pCSIMatrix = pMIMOCtrlField + 3 + Nc; + CSIMatrixLen = frame_len - 26 - 3 - Nc; + info->TargetCSIInfo.bVHT = _TRUE; + } else if ((category == RTW_WLAN_CATEGORY_HT) + && (action == RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING)) { + pMIMOCtrlField = pframe + 26; + Nc = (*pMIMOCtrlField) & 0x3; + Nr = ((*pMIMOCtrlField) & 0xC) >> 2; + CH_W = ((*pMIMOCtrlField) & 0x10) >> 4; + Ng = ((*pMIMOCtrlField) & 0x60) >> 5; + CodeBook = ((*(pMIMOCtrlField+1)) & 0x6) >> 1; + /* + * 24+(1+1+6)+2 + * ==> MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2) + */ + pCSIMatrix = pMIMOCtrlField + 6 + Nr; + CSIMatrixLen = frame_len - 26 - 6 - Nr; + info->TargetCSIInfo.bVHT = _FALSE; + } + + /* Update current CSI report info */ + if ((_TRUE == info->bEnableSUTxBFWorkAround) + && (info->TargetSUBFee == bfee)) { + if ((info->TargetCSIInfo.Nc != Nc) || (info->TargetCSIInfo.Nr != Nr) || + (info->TargetCSIInfo.ChnlWidth != CH_W) || (info->TargetCSIInfo.Ng != Ng) || + (info->TargetCSIInfo.CodeBook != CodeBook)) { + info->TargetCSIInfo.Nc = Nc; + info->TargetCSIInfo.Nr = Nr; + info->TargetCSIInfo.ChnlWidth = CH_W; + info->TargetCSIInfo.Ng = Ng; + info->TargetCSIInfo.CodeBook = CodeBook; + + rtw_bf_cmd(adapter, BEAMFORMING_CTRL_SET_CSI_REPORT, (u8*)&info->TargetCSIInfo, sizeof(struct _RT_CSI_INFO), 1); + } + } + + RTW_INFO("%s: pkt type=%d-%d, Nc=%d, Nr=%d, CH_W=%d, Ng=%d, CodeBook=%d\n", + __FUNCTION__, category, action, Nc, Nr, CH_W, Ng, CodeBook); + + return ret; +} + +u8 rtw_bf_send_vht_gid_mgnt_packet(PADAPTER adapter, u8 *ra, u8 *gid, u8 *position) +{ + /* General */ + struct xmit_priv *xmitpriv; + struct mlme_priv *mlmepriv; + struct xmit_frame *pmgntframe; + /* MISC */ + struct pkt_attrib *attrib; + struct rtw_ieee80211_hdr *wlanhdr; + u8 *pframe, *ptr; + + + xmitpriv = &adapter->xmitpriv; + mlmepriv = &adapter->mlmepriv; + + pmgntframe = alloc_mgtxmitframe(xmitpriv); + if (!pmgntframe) + return _FALSE; + + /* update attribute */ + attrib = &pmgntframe->attrib; + update_mgntframe_attrib(adapter, attrib); + attrib->rate = MGN_6M; + attrib->bwmode = CHANNEL_WIDTH_20; + attrib->subtype = WIFI_ACTION; + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)pmgntframe->buf_addr + TXDESC_OFFSET; + wlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + wlanhdr->frame_ctl = 0; + set_frame_sub_type(pframe, attrib->subtype); + set_duration(pframe, 0); + SetFragNum(pframe, 0); + SetSeqNum(pframe, 0); + + _rtw_memcpy(wlanhdr->addr1, ra, ETH_ALEN); + _rtw_memcpy(wlanhdr->addr2, adapter_mac_addr(adapter), ETH_ALEN); + _rtw_memcpy(wlanhdr->addr3, get_bssid(mlmepriv), ETH_ALEN); + + pframe[24] = RTW_WLAN_CATEGORY_VHT; + pframe[25] = RTW_WLAN_ACTION_VHT_GROUPID_MANAGEMENT; + /* Set Membership Status Array */ + ptr = pframe + 26; + _rtw_memcpy(ptr, gid, 8); + /* Set User Position Array */ + ptr = pframe + 34; + _rtw_memcpy(ptr, position, 16); + + attrib->pktlen = 54; + attrib->last_txcmdsz = attrib->pktlen; + + dump_mgntframe(adapter, pmgntframe); + + return _TRUE; +} + +/* + * Description: + * On VHT GID management frame by an MU beamformee. + */ +void rtw_bf_get_vht_gid_mgnt_packet(PADAPTER adapter, union recv_frame *precv_frame) +{ + u8 *pframe; + u8 *ta, *gid, *position; + + + RTW_DBG("+%s\n", __FUNCTION__); + + pframe = precv_frame->u.hdr.rx_data; + + /* Get address by Addr2 */ + ta = get_addr2_ptr(pframe); + /* Remove signaling TA */ + ta[0] &= 0xFE; + + /* Membership Status Array */ + gid = pframe + 26; + /* User Position Array */ + position= pframe + 34; + + _bfer_set_entry_gid(adapter, ta, gid, position); +} + +void rtw_bf_init(PADAPTER adapter) +{ + struct beamforming_info *info; + + + info = GET_BEAMFORM_INFO(adapter); + info->beamforming_cap = BEAMFORMING_CAP_NONE; + info->beamforming_state = BEAMFORMING_STATE_IDLE; +/* + info->bfee_entry[MAX_BEAMFORMEE_ENTRY_NUM]; + info->bfer_entry[MAX_BEAMFORMER_ENTRY_NUM]; +*/ + info->sounding_sequence = 0; + info->beamformee_su_cnt = 0; + info->beamformer_su_cnt = 0; + info->beamformee_su_reg_maping = 0; + info->beamformer_su_reg_maping = 0; + info->beamformee_mu_cnt = 0; + info->beamformer_mu_cnt = 0; + info->beamformee_mu_reg_maping = 0; + info->first_mu_bfee_index = 0xFF; + info->mu_bfer_curidx = 0xFF; + + _sounding_init(&info->sounding_info); + _init_timer(&info->sounding_timer, adapter->pnetdev, _sounding_timer_handler, adapter); + _init_timer(&info->sounding_timeout_timer, adapter->pnetdev, _sounding_timeout_timer_handler, adapter); + + info->SetHalBFEnterOnDemandCnt = 0; + info->SetHalBFLeaveOnDemandCnt = 0; + info->SetHalSoundownOnDemandCnt = 0; + + info->bEnableSUTxBFWorkAround = _TRUE; + info->TargetSUBFee = NULL; + + info->sounding_running = 0; +} + +void rtw_bf_cmd_hdl(PADAPTER adapter, u8 type, u8 *pbuf) +{ + switch (type) { + case BEAMFORMING_CTRL_ENTER: + _beamforming_enter(adapter, pbuf); + break; + + case BEAMFORMING_CTRL_LEAVE: + if (pbuf == NULL) + _beamforming_reset(adapter); + else + _beamforming_leave(adapter, pbuf); + break; + + case BEAMFORMING_CTRL_START_PERIOD: + _sounding_handler(adapter); + break; + + case BEAMFORMING_CTRL_END_PERIOD: + _beamforming_sounding_down(adapter, *pbuf); + break; + + case BEAMFORMING_CTRL_SET_GID_TABLE: + rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_SET_GID_TABLE, *(void**)pbuf); + break; + + case BEAMFORMING_CTRL_SET_CSI_REPORT: + rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_CSI_REPORT, pbuf); + break; + + default: + break; + } +} + +u8 rtw_bf_cmd(PADAPTER adapter, s32 type, u8 *pbuf, s32 size, u8 enqueue) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + u8 *wk_buf; + u8 res = _SUCCESS; + + + if (!enqueue) { + rtw_bf_cmd_hdl(adapter, type, pbuf); + goto exit; + } + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + if (pbuf != NULL) { + wk_buf = rtw_zmalloc(size); + if (wk_buf == NULL) { + rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); + rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm)); + res = _FAIL; + goto exit; + } + + _rtw_memcpy(wk_buf, pbuf, size); + } else { + wk_buf = NULL; + size = 0; + } + + pdrvextra_cmd_parm->ec_id = BEAMFORMING_WK_CID; + pdrvextra_cmd_parm->type = type; + pdrvextra_cmd_parm->size = size; + pdrvextra_cmd_parm->pbuf = wk_buf; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + return res; +} + +void rtw_bf_update_attrib(PADAPTER adapter, struct pkt_attrib *attrib, struct sta_info *sta) +{ + if (sta) { + attrib->txbf_g_id = sta->txbf_gid; + attrib->txbf_p_aid = sta->txbf_paid; + } +} + +void rtw_bf_c2h_handler(PADAPTER adapter, u8 id, u8 *buf, u8 buf_len) +{ + switch (id) { + case CMD_ID_C2H_SND_TXBF: + _c2h_snd_txbf(adapter, buf, buf_len); + break; + } +} + +#define toMbps(bytes, secs) (rtw_division64(bytes >> 17, secs)) +void rtw_bf_update_traffic(PADAPTER adapter) +{ + struct beamforming_info *info; + struct sounding_info *sounding; + struct beamformee_entry *bfee; + struct sta_info *sta; + u8 bfee_cnt, sounding_idx, i; + u16 tp[MAX_BEAMFORMEE_ENTRY_NUM] = {0}; + u8 tx_rate[MAX_BEAMFORMEE_ENTRY_NUM] = {0}; + u64 tx_bytes, last_bytes; + u32 time, last_timestamp; + u8 set_timer = _FALSE; + + + info = GET_BEAMFORM_INFO(adapter); + sounding = &info->sounding_info; + + /* Check any bfee exist? */ + bfee_cnt = info->beamformee_su_cnt + info->beamformee_mu_cnt; + if (bfee_cnt == 0) + return; + + for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { + bfee = &info->bfee_entry[i]; + if (_FALSE == bfee->used) + continue; + + sta = rtw_get_stainfo(&adapter->stapriv, bfee->mac_addr); + if (!sta) { + RTW_ERR("%s: Cann't find sta_info for " MAC_FMT "!\n", __FUNCTION__, MAC_ARG(bfee->mac_addr)); + continue; + } + + last_timestamp = bfee->tx_timestamp; + last_bytes = bfee->tx_bytes; + bfee->tx_timestamp = rtw_get_current_time(); + bfee->tx_bytes = sta->sta_stats.tx_bytes; + if (last_timestamp) { + if (bfee->tx_bytes >= last_bytes) + tx_bytes = bfee->tx_bytes - last_bytes; + else + tx_bytes = bfee->tx_bytes + (~last_bytes); + time = rtw_get_time_interval_ms(last_timestamp, bfee->tx_timestamp); + time = (time > 1000) ? time/1000 : 1; + tp[i] = toMbps(tx_bytes, time); + tx_rate[i] = rtw_get_current_tx_rate(adapter, bfee->mac_id); + RTW_INFO("%s: BFee idx(%d), MadId(%d), TxTP=%lld bytes (%d Mbps), txrate=%d\n", + __FUNCTION__, i, bfee->mac_id, tx_bytes, tp[i], tx_rate[i]); + } + } + + sounding_idx = phydm_get_beamforming_sounding_info(GET_PDM_ODM(adapter), tp, MAX_BEAMFORMEE_ENTRY_NUM, tx_rate); + + for (i = 0; i < MAX_BEAMFORMEE_ENTRY_NUM; i++) { + bfee = &info->bfee_entry[i]; + if (_FALSE == bfee->used) { + if (sounding_idx & BIT(i)) + RTW_WARN("%s: bfee(%d) not in used but need sounding?!\n", __FUNCTION__, i); + continue; + } + + if (sounding_idx & BIT(i)) { + if (_FALSE == bfee->bApplySounding) { + bfee->bApplySounding = _TRUE; + bfee->SoundCnt = 0; + set_timer = _TRUE; + } + } else { + if (_TRUE == bfee->bApplySounding) { + bfee->bApplySounding = _FALSE; + bfee->bDeleteSounding = _TRUE; + bfee->SoundCnt = 0; + set_timer = _TRUE; + } + } + } + + if (_TRUE == set_timer) { + if (SOUNDING_STATE_NONE == info->sounding_info.state) { + info->sounding_info.state = SOUNDING_STATE_INIT; + _set_timer(&info->sounding_timer, 0); + } + } +} + +#else /* !RTW_BEAMFORMING_VERSION_2 */ + +#if (BEAMFORMING_SUPPORT == 0) /*for diver defined beamforming*/ +struct beamforming_entry *beamforming_get_entry_by_addr(struct mlme_priv *pmlmepriv, u8 *ra, u8 *idx) +{ + u8 i = 0; + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); + + for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) { + if (pBeamInfo->beamforming_entry[i].bUsed && + (_rtw_memcmp(ra, pBeamInfo->beamforming_entry[i].mac_addr, ETH_ALEN))) { + *idx = i; + return &(pBeamInfo->beamforming_entry[i]); + } + } + + return NULL; +} + +BEAMFORMING_CAP beamforming_get_entry_beam_cap_by_mac_id(PVOID pmlmepriv , u8 mac_id) +{ + u8 i = 0; + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO((struct mlme_priv *)pmlmepriv); + BEAMFORMING_CAP BeamformEntryCap = BEAMFORMING_CAP_NONE; + + for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) { + if (pBeamInfo->beamforming_entry[i].bUsed && + (mac_id == pBeamInfo->beamforming_entry[i].mac_id)) { + BeamformEntryCap = pBeamInfo->beamforming_entry[i].beamforming_entry_cap; + i = BEAMFORMING_ENTRY_NUM; + } + } + + return BeamformEntryCap; +} + +struct beamforming_entry *beamforming_get_free_entry(struct mlme_priv *pmlmepriv, u8 *idx) +{ + u8 i = 0; + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); + + for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) { + if (pBeamInfo->beamforming_entry[i].bUsed == _FALSE) { + *idx = i; + return &(pBeamInfo->beamforming_entry[i]); + } + } + return NULL; +} + + +struct beamforming_entry *beamforming_add_entry(PADAPTER adapter, u8 *ra, u16 aid, + u16 mac_id, CHANNEL_WIDTH bw, BEAMFORMING_CAP beamfrom_cap, u8 *idx) +{ + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct beamforming_entry *pEntry = beamforming_get_free_entry(pmlmepriv, idx); + + if (pEntry != NULL) { + pEntry->bUsed = _TRUE; + pEntry->aid = aid; + pEntry->mac_id = mac_id; + pEntry->sound_bw = bw; + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + u16 BSSID = ((*(adapter_mac_addr(adapter) + 5) & 0xf0) >> 4) ^ + (*(adapter_mac_addr(adapter) + 5) & 0xf); /* BSSID[44:47] xor BSSID[40:43] */ + pEntry->p_aid = (aid + BSSID * 32) & 0x1ff; /* (dec(A) + dec(B)*32) mod 512 */ + pEntry->g_id = 63; + } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { + pEntry->p_aid = 0; + pEntry->g_id = 63; + } else { + pEntry->p_aid = ra[5]; /* BSSID[39:47] */ + pEntry->p_aid = (pEntry->p_aid << 1) | (ra[4] >> 7); + pEntry->g_id = 0; + } + _rtw_memcpy(pEntry->mac_addr, ra, ETH_ALEN); + pEntry->bSound = _FALSE; + + /* 3 TODO SW/FW sound period */ + pEntry->sound_period = 200; + pEntry->beamforming_entry_cap = beamfrom_cap; + pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE; + + + pEntry->PreLogSeq = 0; /*Modified by Jeffery @2015-04-13*/ + pEntry->LogSeq = 0; /*Modified by Jeffery @2014-10-29*/ + pEntry->LogRetryCnt = 0; /*Modified by Jeffery @2014-10-29*/ + pEntry->LogSuccess = 0; /*LogSuccess is NOT needed to be accumulated, so LogSuccessCnt->LogSuccess, 2015-04-13, Jeffery*/ + pEntry->ClockResetTimes = 0; /*Modified by Jeffery @2015-04-13*/ + pEntry->LogStatusFailCnt = 0; + + return pEntry; + } else + return NULL; +} + +BOOLEAN beamforming_remove_entry(struct mlme_priv *pmlmepriv, u8 *ra, u8 *idx) +{ + struct beamforming_entry *pEntry = beamforming_get_entry_by_addr(pmlmepriv, ra, idx); + + if (pEntry != NULL) { + pEntry->bUsed = _FALSE; + pEntry->beamforming_entry_cap = BEAMFORMING_CAP_NONE; + pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE; + return _TRUE; + } else + return _FALSE; +} + +/* Used for BeamformingStart_V1 */ +void beamforming_dym_ndpa_rate(PADAPTER adapter) +{ + u16 NDPARate = MGN_6M; + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(adapter); + + if (pHalData->min_undecorated_pwdb_for_dm > 30) /* link RSSI > 30% */ + NDPARate = MGN_24M; + else + NDPARate = MGN_6M; + + /* BW = CHANNEL_WIDTH_20; */ + NDPARate = NDPARate << 8; + rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_RATE, (u8 *)&NDPARate); +} + +void beamforming_dym_period(PADAPTER Adapter) +{ + u8 Idx; + BOOLEAN bChangePeriod = _FALSE; + u16 SoundPeriod_SW, SoundPeriod_FW; + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter); + struct beamforming_entry *pBeamformEntry; + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO((&Adapter->mlmepriv)); + struct sounding_info *pSoundInfo = &(pBeamInfo->sounding_info); + + /* 3 TODO per-client throughput caculation. */ + + if (pdvobjpriv->traffic_stat.cur_tx_tp + pdvobjpriv->traffic_stat.cur_rx_tp > 2) { + SoundPeriod_SW = 32 * 20; + SoundPeriod_FW = 2; + } else { + SoundPeriod_SW = 32 * 2000; + SoundPeriod_FW = 200; + } + + for (Idx = 0; Idx < BEAMFORMING_ENTRY_NUM; Idx++) { + pBeamformEntry = pBeamInfo->beamforming_entry + Idx; + if (pBeamformEntry->bDefaultCSI) { + SoundPeriod_SW = 32 * 2000; + SoundPeriod_FW = 200; + } + + if (pBeamformEntry->beamforming_entry_cap & (BEAMFORMER_CAP_HT_EXPLICIT | BEAMFORMER_CAP_VHT_SU)) { + if (pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER) { + if (pBeamformEntry->sound_period != SoundPeriod_FW) { + pBeamformEntry->sound_period = SoundPeriod_FW; + bChangePeriod = _TRUE; /* Only FW sounding need to send H2C packet to change sound period. */ + } + } else if (pBeamformEntry->sound_period != SoundPeriod_SW) + pBeamformEntry->sound_period = SoundPeriod_SW; + } + } + + if (bChangePeriod) + rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&Idx); +} + +BOOLEAN issue_ht_sw_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct rtw_ieee80211_hdr *pwlanhdr; + struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c}; + u8 *pframe; + u16 *fctrl; + u16 duration = 0; + u8 aSifsTime = 0; + u8 NDPTxRate = 0; + + RTW_INFO("%s: issue_ht_sw_ndpa_packet!\n", __func__); + + NDPTxRate = MGN_MCS8; + RTW_INFO("%s: NDPTxRate =%d\n", __func__, NDPTxRate); + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + + if (pmgntframe == NULL) + return _FALSE; + + /*update attribute*/ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(Adapter, pattrib); + pattrib->qsel = QSLT_MGNT; + pattrib->rate = NDPTxRate; + pattrib->bwmode = bw; + pattrib->order = 1; + pattrib->subtype = WIFI_ACTION_NOACK; + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_ctl; + *(fctrl) = 0; + + set_order_bit(pframe); + set_frame_sub_type(pframe, WIFI_ACTION_NOACK); + + _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + if (pmlmeext->cur_wireless_mode == WIRELESS_11B) + aSifsTime = 10; + else + aSifsTime = 16; + + duration = 2 * aSifsTime + 40; + + if (bw == CHANNEL_WIDTH_40) + duration += 87; + else + duration += 180; + + set_duration(pframe, duration); + + /*HT control field*/ + SET_HT_CTRL_CSI_STEERING(pframe + 24, 3); + SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe + 24, 1); + + _rtw_memcpy(pframe + 28, ActionHdr, 4); + + pattrib->pktlen = 32; + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(Adapter, pmgntframe); + + return _TRUE; + + +} +BOOLEAN issue_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct rtw_ieee80211_hdr *pwlanhdr; + struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 ActionHdr[4] = {ACT_CAT_VENDOR, 0x00, 0xe0, 0x4c}; + u8 *pframe; + u16 *fctrl; + u16 duration = 0; + u8 aSifsTime = 0; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + + if (pmgntframe == NULL) + return _FALSE; + + /*update attribute*/ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(Adapter, pattrib); + + if (qidx == BCN_QUEUE_INX) + pattrib->qsel = QSLT_BEACON; + pattrib->rate = MGN_MCS8; + pattrib->bwmode = bw; + pattrib->order = 1; + pattrib->subtype = WIFI_ACTION_NOACK; + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_ctl; + *(fctrl) = 0; + + set_order_bit(pframe); + set_frame_sub_type(pframe, WIFI_ACTION_NOACK); + + _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + if (pmlmeext->cur_wireless_mode == WIRELESS_11B) + aSifsTime = 10; + else + aSifsTime = 16; + + duration = 2 * aSifsTime + 40; + + if (bw == CHANNEL_WIDTH_40) + duration += 87; + else + duration += 180; + + set_duration(pframe, duration); + + /* HT control field */ + SET_HT_CTRL_CSI_STEERING(pframe + 24, 3); + SET_HT_CTRL_NDP_ANNOUNCEMENT(pframe + 24, 1); + + _rtw_memcpy(pframe + 28, ActionHdr, 4); + + pattrib->pktlen = 32; + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(Adapter, pmgntframe); + + return _TRUE; +} + +BOOLEAN beamforming_send_ht_ndpa_packet(PADAPTER Adapter, u8 *ra, CHANNEL_WIDTH bw, u8 qidx) +{ + return issue_ht_ndpa_packet(Adapter, ra, bw, qidx); +} +BOOLEAN issue_vht_sw_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw, u8 qidx) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct rtw_ieee80211_hdr *pwlanhdr; + struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); + struct rtw_ndpa_sta_info sta_info; + u8 NDPTxRate = 0; + + u8 *pframe; + u16 *fctrl; + u16 duration = 0; + u8 sequence = 0, aSifsTime = 0; + + RTW_INFO("%s: issue_vht_sw_ndpa_packet!\n", __func__); + + + NDPTxRate = MGN_VHT2SS_MCS0; + RTW_INFO("%s: NDPTxRate =%d\n", __func__, NDPTxRate); + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + + if (pmgntframe == NULL) { + RTW_INFO("%s, alloc mgnt frame fail\n", __func__); + return _FALSE; + } + + /*update attribute*/ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(Adapter, pattrib); + pattrib->qsel = QSLT_MGNT; + pattrib->rate = NDPTxRate; + pattrib->bwmode = bw; + pattrib->subtype = WIFI_NDPA; + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_ctl; + *(fctrl) = 0; + + set_frame_sub_type(pframe, WIFI_NDPA); + + _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN); + + if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode)) + aSifsTime = 16; + else + aSifsTime = 10; + + duration = 2 * aSifsTime + 44; + + if (bw == CHANNEL_WIDTH_80) + duration += 40; + else if (bw == CHANNEL_WIDTH_40) + duration += 87; + else + duration += 180; + + set_duration(pframe, duration); + + sequence = pBeamInfo->sounding_sequence << 2; + if (pBeamInfo->sounding_sequence >= 0x3f) + pBeamInfo->sounding_sequence = 0; + else + pBeamInfo->sounding_sequence++; + + _rtw_memcpy(pframe + 16, &sequence, 1); + if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) + aid = 0; + + sta_info.aid = aid; + sta_info.feedback_type = 0; + sta_info.nc_index = 0; + + _rtw_memcpy(pframe + 17, (u8 *)&sta_info, 2); + + pattrib->pktlen = 19; + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(Adapter, pmgntframe); + + + return _TRUE; + +} +BOOLEAN issue_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw, u8 qidx) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct rtw_ieee80211_hdr *pwlanhdr; + struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); + struct rtw_ndpa_sta_info sta_info; + u8 *pframe; + u16 *fctrl; + u16 duration = 0; + u8 sequence = 0, aSifsTime = 0; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return _FALSE; + + /*update attribute*/ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(Adapter, pattrib); + + if (qidx == BCN_QUEUE_INX) + pattrib->qsel = QSLT_BEACON; + pattrib->rate = MGN_VHT2SS_MCS0; + pattrib->bwmode = bw; + pattrib->subtype = WIFI_NDPA; + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_ctl; + *(fctrl) = 0; + + set_frame_sub_type(pframe, WIFI_NDPA); + + _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(Adapter), ETH_ALEN); + + if (is_supported_5g(pmlmeext->cur_wireless_mode) || is_supported_ht(pmlmeext->cur_wireless_mode)) + aSifsTime = 16; + else + aSifsTime = 10; + + duration = 2 * aSifsTime + 44; + + if (bw == CHANNEL_WIDTH_80) + duration += 40; + else if (bw == CHANNEL_WIDTH_40) + duration += 87; + else + duration += 180; + + set_duration(pframe, duration); + + sequence = pBeamInfo->sounding_sequence << 2; + if (pBeamInfo->sounding_sequence >= 0x3f) + pBeamInfo->sounding_sequence = 0; + else + pBeamInfo->sounding_sequence++; + + _rtw_memcpy(pframe + 16, &sequence, 1); + + if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) + aid = 0; + + sta_info.aid = aid; + sta_info.feedback_type = 0; + sta_info.nc_index = 0; + + _rtw_memcpy(pframe + 17, (u8 *)&sta_info, 2); + + pattrib->pktlen = 19; + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(Adapter, pmgntframe); + + return _TRUE; +} + +BOOLEAN beamforming_send_vht_ndpa_packet(PADAPTER Adapter, u8 *ra, u16 aid, CHANNEL_WIDTH bw, u8 qidx) +{ + return issue_vht_ndpa_packet(Adapter, ra, aid, bw, qidx); +} + +BOOLEAN beamfomring_bSounding(struct beamforming_info *pBeamInfo) +{ + BOOLEAN bSounding = _FALSE; + + if ((beamforming_get_beamform_cap(pBeamInfo) & BEAMFORMER_CAP) == 0) + bSounding = _FALSE; + else + bSounding = _TRUE; + + return bSounding; +} + +u8 beamforming_sounding_idx(struct beamforming_info *pBeamInfo) +{ + u8 idx = 0; + u8 i; + + for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) { + if (pBeamInfo->beamforming_entry[i].bUsed && + (_FALSE == pBeamInfo->beamforming_entry[i].bSound)) { + idx = i; + break; + } + } + + return idx; +} + +SOUNDING_MODE beamforming_sounding_mode(struct beamforming_info *pBeamInfo, u8 idx) +{ + struct beamforming_entry BeamEntry = pBeamInfo->beamforming_entry[idx]; + SOUNDING_MODE mode; + + if (BeamEntry.beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU) + mode = SOUNDING_FW_VHT_TIMER; + else if (BeamEntry.beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT) + mode = SOUNDING_FW_HT_TIMER; + else + mode = SOUNDING_STOP_All_TIMER; + + return mode; +} + +u16 beamforming_sounding_time(struct beamforming_info *pBeamInfo, SOUNDING_MODE mode, u8 idx) +{ + u16 sounding_time = 0xffff; + struct beamforming_entry BeamEntry = pBeamInfo->beamforming_entry[idx]; + + sounding_time = BeamEntry.sound_period; + + return sounding_time; +} + +CHANNEL_WIDTH beamforming_sounding_bw(struct beamforming_info *pBeamInfo, SOUNDING_MODE mode, u8 idx) +{ + CHANNEL_WIDTH sounding_bw = CHANNEL_WIDTH_20; + struct beamforming_entry BeamEntry = pBeamInfo->beamforming_entry[idx]; + + sounding_bw = BeamEntry.sound_bw; + + return sounding_bw; +} + +BOOLEAN beamforming_select_beam_entry(struct beamforming_info *pBeamInfo) +{ + struct sounding_info *pSoundInfo = &(pBeamInfo->sounding_info); + + pSoundInfo->sound_idx = beamforming_sounding_idx(pBeamInfo); + + if (pSoundInfo->sound_idx < BEAMFORMING_ENTRY_NUM) + pSoundInfo->sound_mode = beamforming_sounding_mode(pBeamInfo, pSoundInfo->sound_idx); + else + pSoundInfo->sound_mode = SOUNDING_STOP_All_TIMER; + + if (SOUNDING_STOP_All_TIMER == pSoundInfo->sound_mode) + return _FALSE; + else { + pSoundInfo->sound_bw = beamforming_sounding_bw(pBeamInfo, pSoundInfo->sound_mode, pSoundInfo->sound_idx); + pSoundInfo->sound_period = beamforming_sounding_time(pBeamInfo, pSoundInfo->sound_mode, pSoundInfo->sound_idx); + return _TRUE; + } +} + +BOOLEAN beamforming_start_fw(PADAPTER adapter, u8 idx) +{ + u8 *RA = NULL; + struct beamforming_entry *pEntry; + BOOLEAN ret = _TRUE; + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); + + pEntry = &(pBeamInfo->beamforming_entry[idx]); + if (pEntry->bUsed == _FALSE) { + RTW_INFO("Skip Beamforming, no entry for Idx =%d\n", idx); + return _FALSE; + } + + pEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_PROGRESSING; + pEntry->bSound = _TRUE; + rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&idx); + + return _TRUE; +} + +void beamforming_end_fw(PADAPTER adapter) +{ + u8 idx = 0; + + rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&idx); + + RTW_INFO("%s\n", __FUNCTION__); +} + +BOOLEAN beamforming_start_period(PADAPTER adapter) +{ + BOOLEAN ret = _TRUE; + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); + struct sounding_info *pSoundInfo = &(pBeamInfo->sounding_info); + + beamforming_dym_ndpa_rate(adapter); + + beamforming_select_beam_entry(pBeamInfo); + + if (pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER) + ret = beamforming_start_fw(adapter, pSoundInfo->sound_idx); + else + ret = _FALSE; + + RTW_INFO("%s Idx %d Mode %d BW %d Period %d\n", __FUNCTION__, + pSoundInfo->sound_idx, pSoundInfo->sound_mode, pSoundInfo->sound_bw, pSoundInfo->sound_period); + + return ret; +} + +void beamforming_end_period(PADAPTER adapter) +{ + u8 idx = 0; + struct beamforming_entry *pBeamformEntry; + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); + struct sounding_info *pSoundInfo = &(pBeamInfo->sounding_info); + + + if (pSoundInfo->sound_mode == SOUNDING_FW_VHT_TIMER || pSoundInfo->sound_mode == SOUNDING_FW_HT_TIMER) + beamforming_end_fw(adapter); +} + +void beamforming_notify(PADAPTER adapter) +{ + BOOLEAN bSounding = _FALSE; + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(&(adapter->mlmepriv)); + + bSounding = beamfomring_bSounding(pBeamInfo); + + if (pBeamInfo->beamforming_state == BEAMFORMING_STATE_IDLE) { + if (bSounding) { + if (beamforming_start_period(adapter) == _TRUE) + pBeamInfo->beamforming_state = BEAMFORMING_STATE_START; + } + } else if (pBeamInfo->beamforming_state == BEAMFORMING_STATE_START) { + if (bSounding) { + if (beamforming_start_period(adapter) == _FALSE) + pBeamInfo->beamforming_state = BEAMFORMING_STATE_END; + } else { + beamforming_end_period(adapter); + pBeamInfo->beamforming_state = BEAMFORMING_STATE_END; + } + } else if (pBeamInfo->beamforming_state == BEAMFORMING_STATE_END) { + if (bSounding) { + if (beamforming_start_period(adapter) == _TRUE) + pBeamInfo->beamforming_state = BEAMFORMING_STATE_START; + } + } else + RTW_INFO("%s BeamformState %d\n", __FUNCTION__, pBeamInfo->beamforming_state); + + RTW_INFO("%s BeamformState %d bSounding %d\n", __FUNCTION__, pBeamInfo->beamforming_state, bSounding); +} + +BOOLEAN beamforming_init_entry(PADAPTER adapter, struct sta_info *psta, u8 *idx) +{ + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct ht_priv *phtpriv = &(pmlmepriv->htpriv); +#ifdef CONFIG_80211AC_VHT + struct vht_priv *pvhtpriv = &(pmlmepriv->vhtpriv); +#endif + struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct beamforming_entry *pBeamformEntry = NULL; + u8 *ra; + u16 aid, mac_id; + u8 wireless_mode; + CHANNEL_WIDTH bw = CHANNEL_WIDTH_20; + BEAMFORMING_CAP beamform_cap = BEAMFORMING_CAP_NONE; + + /* The current setting does not support Beaforming */ + if (0 == phtpriv->beamform_cap +#ifdef CONFIG_80211AC_VHT + && 0 == pvhtpriv->beamform_cap +#endif + ) { + RTW_INFO("The configuration disabled Beamforming! Skip...\n"); + return _FALSE; + } + + aid = psta->aid; + ra = psta->hwaddr; + mac_id = psta->mac_id; + wireless_mode = psta->wireless_mode; + bw = psta->bw_mode; + + if (is_supported_ht(wireless_mode) || is_supported_vht(wireless_mode)) { + /* 3 */ /* HT */ + u8 cur_beamform; + + cur_beamform = psta->htpriv.beamform_cap; + + /* We are Beamformee because the STA is Beamformer */ + if (TEST_FLAG(cur_beamform, BEAMFORMING_HT_BEAMFORMER_ENABLE)) + beamform_cap = (BEAMFORMING_CAP)(beamform_cap | BEAMFORMEE_CAP_HT_EXPLICIT); + + /* We are Beamformer because the STA is Beamformee */ + if (TEST_FLAG(cur_beamform, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) + beamform_cap = (BEAMFORMING_CAP)(beamform_cap | BEAMFORMER_CAP_HT_EXPLICIT); +#ifdef CONFIG_80211AC_VHT + if (is_supported_vht(wireless_mode)) { + /* 3 */ /* VHT */ + cur_beamform = psta->vhtpriv.beamform_cap; + + /* We are Beamformee because the STA is Beamformer */ + if (TEST_FLAG(cur_beamform, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) + beamform_cap = (BEAMFORMING_CAP)(beamform_cap | BEAMFORMEE_CAP_VHT_SU); + /* We are Beamformer because the STA is Beamformee */ + if (TEST_FLAG(cur_beamform, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) + beamform_cap = (BEAMFORMING_CAP)(beamform_cap | BEAMFORMER_CAP_VHT_SU); + } +#endif /* CONFIG_80211AC_VHT */ + + if (beamform_cap == BEAMFORMING_CAP_NONE) + return _FALSE; + + RTW_INFO("Beamforming Config Capability = 0x%02X\n", beamform_cap); + + pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ra, idx); + if (pBeamformEntry == NULL) { + pBeamformEntry = beamforming_add_entry(adapter, ra, aid, mac_id, bw, beamform_cap, idx); + if (pBeamformEntry == NULL) + return _FALSE; + else + pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING; + } else { + /* Entry has been created. If entry is initialing or progressing then errors occur. */ + if (pBeamformEntry->beamforming_entry_state != BEAMFORMING_ENTRY_STATE_INITIALIZED && + pBeamformEntry->beamforming_entry_state != BEAMFORMING_ENTRY_STATE_PROGRESSED) { + RTW_INFO("Error State of Beamforming"); + return _FALSE; + } else + pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZEING; + } + + pBeamformEntry->beamforming_entry_state = BEAMFORMING_ENTRY_STATE_INITIALIZED; + psta->txbf_paid = pBeamformEntry->p_aid; + psta->txbf_gid = pBeamformEntry->g_id; + + RTW_INFO("%s Idx %d\n", __FUNCTION__, *idx); + } else + return _FALSE; + + return _SUCCESS; +} + +void beamforming_deinit_entry(PADAPTER adapter, u8 *ra) +{ + u8 idx = 0; + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + + if (beamforming_remove_entry(pmlmepriv, ra, &idx) == _TRUE) + rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, (u8 *)&idx); + + RTW_INFO("%s Idx %d\n", __FUNCTION__, idx); +} + +void beamforming_reset(PADAPTER adapter) +{ + u8 idx = 0; + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); + + for (idx = 0; idx < BEAMFORMING_ENTRY_NUM; idx++) { + if (pBeamInfo->beamforming_entry[idx].bUsed == _TRUE) { + pBeamInfo->beamforming_entry[idx].bUsed = _FALSE; + pBeamInfo->beamforming_entry[idx].beamforming_entry_cap = BEAMFORMING_CAP_NONE; + pBeamInfo->beamforming_entry[idx].beamforming_entry_state = BEAMFORMING_ENTRY_STATE_UNINITIALIZE; + rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_LEAVE, (u8 *)&idx); + } + } + + RTW_INFO("%s\n", __FUNCTION__); +} + +void beamforming_sounding_fail(PADAPTER Adapter) +{ + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); + struct beamforming_entry *pEntry = &(pBeamInfo->beamforming_entry[pBeamInfo->beamforming_cur_idx]); + + pEntry->bSound = _FALSE; + rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&pBeamInfo->beamforming_cur_idx); + beamforming_deinit_entry(Adapter, pEntry->mac_addr); +} + +void beamforming_check_sounding_success(PADAPTER Adapter, BOOLEAN status) +{ + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO(pmlmepriv); + struct beamforming_entry *pEntry = &(pBeamInfo->beamforming_entry[pBeamInfo->beamforming_cur_idx]); + + if (status == 1) + pEntry->LogStatusFailCnt = 0; + else { + pEntry->LogStatusFailCnt++; + RTW_INFO("%s LogStatusFailCnt %d\n", __FUNCTION__, pEntry->LogStatusFailCnt); + } + if (pEntry->LogStatusFailCnt > 20) { + RTW_INFO("%s LogStatusFailCnt > 20, Stop SOUNDING\n", __FUNCTION__); + /* pEntry->bSound = _FALSE; */ + /* rtw_hal_set_hwreg(Adapter, HW_VAR_SOUNDING_FW_NDPA, (u8 *)&pBeamInfo->beamforming_cur_idx); */ + /* beamforming_deinit_entry(Adapter, pEntry->mac_addr); */ + beamforming_wk_cmd(Adapter, BEAMFORMING_CTRL_SOUNDING_FAIL, NULL, 0, 1); + } +} + +void beamforming_enter(PADAPTER adapter, PVOID psta) +{ + u8 idx = 0xff; + + if (beamforming_init_entry(adapter, (struct sta_info *)psta, &idx)) + rtw_hal_set_hwreg(adapter, HW_VAR_SOUNDING_ENTER, (u8 *)&idx); + + /* RTW_INFO("%s Idx %d\n", __FUNCTION__, idx); */ +} + +void beamforming_leave(PADAPTER adapter, u8 *ra) +{ + if (ra == NULL) + beamforming_reset(adapter); + else + beamforming_deinit_entry(adapter, ra); + + beamforming_notify(adapter); +} + +BEAMFORMING_CAP beamforming_get_beamform_cap(struct beamforming_info *pBeamInfo) +{ + u8 i; + BOOLEAN bSelfBeamformer = _FALSE; + BOOLEAN bSelfBeamformee = _FALSE; + struct beamforming_entry beamforming_entry; + BEAMFORMING_CAP beamform_cap = BEAMFORMING_CAP_NONE; + + for (i = 0; i < BEAMFORMING_ENTRY_NUM; i++) { + beamforming_entry = pBeamInfo->beamforming_entry[i]; + + if (beamforming_entry.bUsed) { + if ((beamforming_entry.beamforming_entry_cap & BEAMFORMEE_CAP_VHT_SU) || + (beamforming_entry.beamforming_entry_cap & BEAMFORMEE_CAP_HT_EXPLICIT)) + bSelfBeamformee = _TRUE; + if ((beamforming_entry.beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU) || + (beamforming_entry.beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT)) + bSelfBeamformer = _TRUE; + } + + if (bSelfBeamformer && bSelfBeamformee) + i = BEAMFORMING_ENTRY_NUM; + } + + if (bSelfBeamformer) + beamform_cap |= BEAMFORMER_CAP; + if (bSelfBeamformee) + beamform_cap |= BEAMFORMEE_CAP; + + return beamform_cap; +} + +void beamforming_watchdog(PADAPTER Adapter) +{ + struct beamforming_info *pBeamInfo = GET_BEAMFORM_INFO((&(Adapter->mlmepriv))); + + if (pBeamInfo->beamforming_state != BEAMFORMING_STATE_START) + return; + + beamforming_dym_period(Adapter); + beamforming_dym_ndpa_rate(Adapter); +} +#endif/* #if (BEAMFORMING_SUPPORT ==0) - for diver defined beamforming*/ + +u32 rtw_beamforming_get_report_frame(PADAPTER Adapter, union recv_frame *precv_frame) +{ + u32 ret = _SUCCESS; +#if (BEAMFORMING_SUPPORT == 1) + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); + struct PHY_DM_STRUCT *pDM_Odm = &(pHalData->odmpriv); + + ret = beamforming_get_report_frame(pDM_Odm, precv_frame); + +#else /*(BEAMFORMING_SUPPORT == 0)- for drv beamfoming*/ + struct beamforming_entry *pBeamformEntry = NULL; + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + u8 *pframe = precv_frame->u.hdr.rx_data; + u32 frame_len = precv_frame->u.hdr.len; + u8 *ta; + u8 idx, offset; + + /*RTW_INFO("rtw_beamforming_get_report_frame\n");*/ + + /*Memory comparison to see if CSI report is the same with previous one*/ + ta = get_addr2_ptr(pframe); + pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ta, &idx); + if (pBeamformEntry->beamforming_entry_cap & BEAMFORMER_CAP_VHT_SU) + offset = 31; /*24+(1+1+3)+2 MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)*/ + else if (pBeamformEntry->beamforming_entry_cap & BEAMFORMER_CAP_HT_EXPLICIT) + offset = 34; /*24+(1+1+6)+2 MAC header+(Category+ActionCode+MIMOControlField)+SNR(Nc=2)*/ + else + return ret; + + /*RTW_INFO("%s MacId %d offset=%d\n", __FUNCTION__, pBeamformEntry->mac_id, offset);*/ + + if (_rtw_memcmp(pBeamformEntry->PreCsiReport + offset, pframe + offset, frame_len - offset) == _FALSE) + pBeamformEntry->DefaultCsiCnt = 0; + else + pBeamformEntry->DefaultCsiCnt++; + + _rtw_memcpy(&pBeamformEntry->PreCsiReport, pframe, frame_len); + + pBeamformEntry->bDefaultCSI = _FALSE; + + if (pBeamformEntry->DefaultCsiCnt > 20) + pBeamformEntry->bDefaultCSI = _TRUE; + else + pBeamformEntry->bDefaultCSI = _FALSE; +#endif + return ret; +} + +void rtw_beamforming_get_ndpa_frame(PADAPTER Adapter, union recv_frame *precv_frame) +{ +#if (BEAMFORMING_SUPPORT == 1) + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); + struct PHY_DM_STRUCT *pDM_Odm = &(pHalData->odmpriv); + + beamforming_get_ndpa_frame(pDM_Odm, precv_frame); + +#else /*(BEAMFORMING_SUPPORT == 0)- for drv beamfoming*/ + u8 *ta; + u8 idx, Sequence; + u8 *pframe = precv_frame->u.hdr.rx_data; + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + struct beamforming_entry *pBeamformEntry = NULL; + + /*RTW_INFO("rtw_beamforming_get_ndpa_frame\n");*/ + + if (IS_HARDWARE_TYPE_8812(Adapter) == _FALSE) + return; + else if (get_frame_sub_type(pframe) != WIFI_NDPA) + return; + + ta = get_addr2_ptr(pframe); + /*Remove signaling TA. */ + ta[0] = ta[0] & 0xFE; + + pBeamformEntry = beamforming_get_entry_by_addr(pmlmepriv, ta, &idx); + + if (pBeamformEntry == NULL) + return; + else if (!(pBeamformEntry->beamforming_entry_cap & BEAMFORMEE_CAP_VHT_SU)) + return; + /*LogSuccess: As long as 8812A receive NDPA and feedback CSI succeed once, clock reset is NO LONGER needed !2015-04-10, Jeffery*/ + /*ClockResetTimes: While BFer entry always doesn't receive our CSI, clock will reset again and again.So ClockResetTimes is limited to 5 times.2015-04-13, Jeffery*/ + else if ((pBeamformEntry->LogSuccess == 1) || (pBeamformEntry->ClockResetTimes == 5)) { + RTW_INFO("[%s] LogSeq=%d, PreLogSeq=%d\n", __func__, pBeamformEntry->LogSeq, pBeamformEntry->PreLogSeq); + return; + } + + Sequence = (pframe[16]) >> 2; + RTW_INFO("[%s] Start, Sequence=%d, LogSeq=%d, PreLogSeq=%d, LogRetryCnt=%d, ClockResetTimes=%d, LogSuccess=%d\n", + __func__, Sequence, pBeamformEntry->LogSeq, pBeamformEntry->PreLogSeq, pBeamformEntry->LogRetryCnt, pBeamformEntry->ClockResetTimes, pBeamformEntry->LogSuccess); + + if ((pBeamformEntry->LogSeq != 0) && (pBeamformEntry->PreLogSeq != 0)) { + /*Success condition*/ + if ((pBeamformEntry->LogSeq != Sequence) && (pBeamformEntry->PreLogSeq != pBeamformEntry->LogSeq)) { + /* break option for clcok reset, 2015-03-30, Jeffery */ + pBeamformEntry->LogRetryCnt = 0; + /*As long as 8812A receive NDPA and feedback CSI succeed once, clock reset is no longer needed.*/ + /*That is, LogSuccess is NOT needed to be reset to zero, 2015-04-13, Jeffery*/ + pBeamformEntry->LogSuccess = 1; + + } else {/*Fail condition*/ + + if (pBeamformEntry->LogRetryCnt == 5) { + pBeamformEntry->ClockResetTimes++; + pBeamformEntry->LogRetryCnt = 0; + + RTW_INFO("[%s] Clock Reset!!! ClockResetTimes=%d\n", __func__, pBeamformEntry->ClockResetTimes); + beamforming_wk_cmd(Adapter, BEAMFORMING_CTRL_SOUNDING_CLK, NULL, 0, 1); + + } else + pBeamformEntry->LogRetryCnt++; + } + } + + /*Update LogSeq & PreLogSeq*/ + pBeamformEntry->PreLogSeq = pBeamformEntry->LogSeq; + pBeamformEntry->LogSeq = Sequence; + +#endif + +} + + + + +void beamforming_wk_hdl(_adapter *padapter, u8 type, u8 *pbuf) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + struct PHY_DM_STRUCT *pDM_Odm = &(pHalData->odmpriv); + +#if (BEAMFORMING_SUPPORT == 1) /*(BEAMFORMING_SUPPORT == 1)- for PHYDM beamfoming*/ + switch (type) { + case BEAMFORMING_CTRL_ENTER: { + struct sta_info *psta = (PVOID)pbuf; + u16 staIdx = psta->mac_id; + + beamforming_enter(pDM_Odm, staIdx); + break; + } + case BEAMFORMING_CTRL_LEAVE: + beamforming_leave(pDM_Odm, pbuf); + break; + default: + break; + + } +#else /*(BEAMFORMING_SUPPORT == 0)- for drv beamfoming*/ + switch (type) { + case BEAMFORMING_CTRL_ENTER: + beamforming_enter(padapter, (PVOID)pbuf); + break; + + case BEAMFORMING_CTRL_LEAVE: + beamforming_leave(padapter, pbuf); + break; + + case BEAMFORMING_CTRL_SOUNDING_FAIL: + beamforming_sounding_fail(padapter); + break; + + case BEAMFORMING_CTRL_SOUNDING_CLK: + rtw_hal_set_hwreg(padapter, HW_VAR_SOUNDING_CLK, NULL); + break; + + default: + break; + } +#endif +} + +u8 beamforming_wk_cmd(_adapter *padapter, s32 type, u8 *pbuf, s32 size, u8 enqueue) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + if (enqueue) { + u8 *wk_buf; + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + if (pbuf != NULL) { + wk_buf = rtw_zmalloc(size); + if (wk_buf == NULL) { + rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); + rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm)); + res = _FAIL; + goto exit; + } + + _rtw_memcpy(wk_buf, pbuf, size); + } else { + wk_buf = NULL; + size = 0; + } + + pdrvextra_cmd_parm->ec_id = BEAMFORMING_WK_CID; + pdrvextra_cmd_parm->type = type; + pdrvextra_cmd_parm->size = size; + pdrvextra_cmd_parm->pbuf = wk_buf; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + } else + beamforming_wk_hdl(padapter, type, pbuf); + +exit: + + + return res; +} + +void update_attrib_txbf_info(_adapter *padapter, struct pkt_attrib *pattrib, struct sta_info *psta) +{ + if (psta) { + pattrib->txbf_g_id = psta->txbf_gid; + pattrib->txbf_p_aid = psta->txbf_paid; + } +} +#endif /* !RTW_BEAMFORMING_VERSION_2 */ + +#endif /* CONFIG_BEAMFORMING */ diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_br_ext.c b/linux-bsp/drivers/rtl8188eus/core/rtw_br_ext.c new file mode 100644 index 0000000..b330edf --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_br_ext.c @@ -0,0 +1,1585 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_BR_EXT_C_ + +#ifdef __KERNEL__ + #include <linux/if_arp.h> + #include <net/ip.h> + #include <net/ipx.h> + #include <linux/atalk.h> + #include <linux/udp.h> + #include <linux/if_pppox.h> +#endif + +#if 1 /* rtw_wifi_driver */ + #include <drv_types.h> +#else /* rtw_wifi_driver */ + #include "./8192cd_cfg.h" + + #ifndef __KERNEL__ + #include "./sys-support.h" + #endif + + #include "./8192cd.h" + #include "./8192cd_headers.h" + #include "./8192cd_br_ext.h" + #include "./8192cd_debug.h" +#endif /* rtw_wifi_driver */ + +#ifdef CL_IPV6_PASS + #ifdef __KERNEL__ + #include <linux/ipv6.h> + #include <linux/icmpv6.h> + #include <net/ndisc.h> + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)) + #include <net/ip6_checksum.h> + #else + #include <net/checksum.h> + #endif + #endif +#endif + +#ifdef CONFIG_BR_EXT + +/* #define BR_EXT_DEBUG */ + +#define NAT25_IPV4 01 +#define NAT25_IPV6 02 +#define NAT25_IPX 03 +#define NAT25_APPLE 04 +#define NAT25_PPPOE 05 + +#define RTL_RELAY_TAG_LEN (ETH_ALEN) +#define TAG_HDR_LEN 4 + +#define MAGIC_CODE 0x8186 +#define MAGIC_CODE_LEN 2 +#define WAIT_TIME_PPPOE 5 /* waiting time for pppoe server in sec */ + +/*----------------------------------------------------------------- + How database records network address: + 0 1 2 3 4 5 6 7 8 9 10 + |----|----|----|----|----|----|----|----|----|----|----| + IPv4 |type| | IP addr | + IPX |type| Net addr | Node addr | + IPX |type| Net addr |Sckt addr| + Apple |type| Network |node| + PPPoE |type| SID | AC MAC | +-----------------------------------------------------------------*/ + + +/* Find a tag in pppoe frame and return the pointer */ +static __inline__ unsigned char *__nat25_find_pppoe_tag(struct pppoe_hdr *ph, unsigned short type) +{ + unsigned char *cur_ptr, *start_ptr; + unsigned short tagLen, tagType; + + start_ptr = cur_ptr = (unsigned char *)ph->tag; + while ((cur_ptr - start_ptr) < ntohs(ph->length)) { + /* prevent un-alignment access */ + tagType = (unsigned short)((cur_ptr[0] << 8) + cur_ptr[1]); + tagLen = (unsigned short)((cur_ptr[2] << 8) + cur_ptr[3]); + if (tagType == type) + return cur_ptr; + cur_ptr = cur_ptr + TAG_HDR_LEN + tagLen; + } + return 0; +} + + +static __inline__ int __nat25_add_pppoe_tag(struct sk_buff *skb, struct pppoe_tag *tag) +{ + struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); + int data_len; + + data_len = tag->tag_len + TAG_HDR_LEN; + if (skb_tailroom(skb) < data_len) { + _DEBUG_ERR("skb_tailroom() failed in add SID tag!\n"); + return -1; + } + + skb_put(skb, data_len); + /* have a room for new tag */ + memmove(((unsigned char *)ph->tag + data_len), (unsigned char *)ph->tag, ntohs(ph->length)); + ph->length = htons(ntohs(ph->length) + data_len); + memcpy((unsigned char *)ph->tag, tag, data_len); + return data_len; +} + +static int skb_pull_and_merge(struct sk_buff *skb, unsigned char *src, int len) +{ + int tail_len; + unsigned long end, tail; + + if ((src + len) > skb_tail_pointer(skb) || skb->len < len) + return -1; + + tail = (unsigned long)skb_tail_pointer(skb); + end = (unsigned long)src + len; + if (tail < end) + return -1; + + tail_len = (int)(tail - end); + if (tail_len > 0) + memmove(src, src + len, tail_len); + + skb_trim(skb, skb->len - len); + return 0; +} + +static __inline__ unsigned long __nat25_timeout(_adapter *priv) +{ + unsigned long timeout; + + timeout = jiffies - NAT25_AGEING_TIME * HZ; + + return timeout; +} + + +static __inline__ int __nat25_has_expired(_adapter *priv, + struct nat25_network_db_entry *fdb) +{ + if (time_before_eq(fdb->ageing_timer, __nat25_timeout(priv))) + return 1; + + return 0; +} + + +static __inline__ void __nat25_generate_ipv4_network_addr(unsigned char *networkAddr, + unsigned int *ipAddr) +{ + memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); + + networkAddr[0] = NAT25_IPV4; + memcpy(networkAddr + 7, (unsigned char *)ipAddr, 4); +} + + +static __inline__ void __nat25_generate_ipx_network_addr_with_node(unsigned char *networkAddr, + unsigned int *ipxNetAddr, unsigned char *ipxNodeAddr) +{ + memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); + + networkAddr[0] = NAT25_IPX; + memcpy(networkAddr + 1, (unsigned char *)ipxNetAddr, 4); + memcpy(networkAddr + 5, ipxNodeAddr, 6); +} + + +static __inline__ void __nat25_generate_ipx_network_addr_with_socket(unsigned char *networkAddr, + unsigned int *ipxNetAddr, unsigned short *ipxSocketAddr) +{ + memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); + + networkAddr[0] = NAT25_IPX; + memcpy(networkAddr + 1, (unsigned char *)ipxNetAddr, 4); + memcpy(networkAddr + 5, (unsigned char *)ipxSocketAddr, 2); +} + + +static __inline__ void __nat25_generate_apple_network_addr(unsigned char *networkAddr, + unsigned short *network, unsigned char *node) +{ + memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); + + networkAddr[0] = NAT25_APPLE; + memcpy(networkAddr + 1, (unsigned char *)network, 2); + networkAddr[3] = *node; +} + + +static __inline__ void __nat25_generate_pppoe_network_addr(unsigned char *networkAddr, + unsigned char *ac_mac, unsigned short *sid) +{ + memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); + + networkAddr[0] = NAT25_PPPOE; + memcpy(networkAddr + 1, (unsigned char *)sid, 2); + memcpy(networkAddr + 3, (unsigned char *)ac_mac, 6); +} + + +#ifdef CL_IPV6_PASS +static void __nat25_generate_ipv6_network_addr(unsigned char *networkAddr, + unsigned int *ipAddr) +{ + memset(networkAddr, 0, MAX_NETWORK_ADDR_LEN); + + networkAddr[0] = NAT25_IPV6; + memcpy(networkAddr + 1, (unsigned char *)ipAddr, 16); +} + + +static unsigned char *scan_tlv(unsigned char *data, int len, unsigned char tag, unsigned char len8b) +{ + while (len > 0) { + if (*data == tag && *(data + 1) == len8b && len >= len8b * 8) + return data + 2; + + len -= (*(data + 1)) * 8; + data += (*(data + 1)) * 8; + } + return NULL; +} + + +static int update_nd_link_layer_addr(unsigned char *data, int len, unsigned char *replace_mac) +{ + struct icmp6hdr *icmphdr = (struct icmp6hdr *)data; + unsigned char *mac; + + if (icmphdr->icmp6_type == NDISC_ROUTER_SOLICITATION) { + if (len >= 8) { + mac = scan_tlv(&data[8], len - 8, 1, 1); + if (mac) { + RTW_INFO("Router Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); + memcpy(mac, replace_mac, 6); + return 1; + } + } + } else if (icmphdr->icmp6_type == NDISC_ROUTER_ADVERTISEMENT) { + if (len >= 16) { + mac = scan_tlv(&data[16], len - 16, 1, 1); + if (mac) { + RTW_INFO("Router Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); + memcpy(mac, replace_mac, 6); + return 1; + } + } + } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) { + if (len >= 24) { + mac = scan_tlv(&data[24], len - 24, 1, 1); + if (mac) { + RTW_INFO("Neighbor Solicitation, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); + memcpy(mac, replace_mac, 6); + return 1; + } + } + } else if (icmphdr->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT) { + if (len >= 24) { + mac = scan_tlv(&data[24], len - 24, 2, 1); + if (mac) { + RTW_INFO("Neighbor Advertisement, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); + memcpy(mac, replace_mac, 6); + return 1; + } + } + } else if (icmphdr->icmp6_type == NDISC_REDIRECT) { + if (len >= 40) { + mac = scan_tlv(&data[40], len - 40, 2, 1); + if (mac) { + RTW_INFO("Redirect, replace MAC From: %02x:%02x:%02x:%02x:%02x:%02x, To: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + replace_mac[0], replace_mac[1], replace_mac[2], replace_mac[3], replace_mac[4], replace_mac[5]); + memcpy(mac, replace_mac, 6); + return 1; + } + } + } + return 0; +} + + +static void convert_ipv6_mac_to_mc(struct sk_buff *skb) +{ + struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN); + unsigned char *dst_mac = skb->data; + + /* dst_mac[0] = 0xff; */ + /* dst_mac[1] = 0xff; */ + /*modified by qinjunjie,ipv6 multicast address ix 0x33-33-xx-xx-xx-xx*/ + dst_mac[0] = 0x33; + dst_mac[1] = 0x33; + memcpy(&dst_mac[2], &iph->daddr.s6_addr32[3], 4); +#if defined(__LINUX_2_6__) + /*modified by qinjunjie,warning:should not remove next line*/ + skb->pkt_type = PACKET_MULTICAST; +#endif +} +#endif /* CL_IPV6_PASS */ + + +static __inline__ int __nat25_network_hash(unsigned char *networkAddr) +{ + if (networkAddr[0] == NAT25_IPV4) { + unsigned long x; + + x = networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; + + return x & (NAT25_HASH_SIZE - 1); + } else if (networkAddr[0] == NAT25_IPX) { + unsigned long x; + + x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ + networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10]; + + return x & (NAT25_HASH_SIZE - 1); + } else if (networkAddr[0] == NAT25_APPLE) { + unsigned long x; + + x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3]; + + return x & (NAT25_HASH_SIZE - 1); + } else if (networkAddr[0] == NAT25_PPPOE) { + unsigned long x; + + x = networkAddr[0] ^ networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ networkAddr[6] ^ networkAddr[7] ^ networkAddr[8]; + + return x & (NAT25_HASH_SIZE - 1); + } +#ifdef CL_IPV6_PASS + else if (networkAddr[0] == NAT25_IPV6) { + unsigned long x; + + x = networkAddr[1] ^ networkAddr[2] ^ networkAddr[3] ^ networkAddr[4] ^ networkAddr[5] ^ + networkAddr[6] ^ networkAddr[7] ^ networkAddr[8] ^ networkAddr[9] ^ networkAddr[10] ^ + networkAddr[11] ^ networkAddr[12] ^ networkAddr[13] ^ networkAddr[14] ^ networkAddr[15] ^ + networkAddr[16]; + + return x & (NAT25_HASH_SIZE - 1); + } +#endif + else { + unsigned long x = 0; + int i; + + for (i = 0; i < MAX_NETWORK_ADDR_LEN; i++) + x ^= networkAddr[i]; + + return x & (NAT25_HASH_SIZE - 1); + } +} + + +static __inline__ void __network_hash_link(_adapter *priv, + struct nat25_network_db_entry *ent, int hash) +{ + /* Caller must _enter_critical_bh already! */ + /* _irqL irqL; */ + /* _enter_critical_bh(&priv->br_ext_lock, &irqL); */ + + ent->next_hash = priv->nethash[hash]; + if (ent->next_hash != NULL) + ent->next_hash->pprev_hash = &ent->next_hash; + priv->nethash[hash] = ent; + ent->pprev_hash = &priv->nethash[hash]; + + /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ +} + + +static __inline__ void __network_hash_unlink(struct nat25_network_db_entry *ent) +{ + /* Caller must _enter_critical_bh already! */ + /* _irqL irqL; */ + /* _enter_critical_bh(&priv->br_ext_lock, &irqL); */ + + *(ent->pprev_hash) = ent->next_hash; + if (ent->next_hash != NULL) + ent->next_hash->pprev_hash = ent->pprev_hash; + ent->next_hash = NULL; + ent->pprev_hash = NULL; + + /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ +} + + +static int __nat25_db_network_lookup_and_replace(_adapter *priv, + struct sk_buff *skb, unsigned char *networkAddr) +{ + struct nat25_network_db_entry *db; + _irqL irqL; + _enter_critical_bh(&priv->br_ext_lock, &irqL); + + db = priv->nethash[__nat25_network_hash(networkAddr)]; + while (db != NULL) { + if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { + if (!__nat25_has_expired(priv, db)) { + /* replace the destination mac address */ + memcpy(skb->data, db->macAddr, ETH_ALEN); + atomic_inc(&db->use_count); + +#ifdef CL_IPV6_PASS + RTW_INFO("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x\n", + db->macAddr[0], + db->macAddr[1], + db->macAddr[2], + db->macAddr[3], + db->macAddr[4], + db->macAddr[5], + db->networkAddr[0], + db->networkAddr[1], + db->networkAddr[2], + db->networkAddr[3], + db->networkAddr[4], + db->networkAddr[5], + db->networkAddr[6], + db->networkAddr[7], + db->networkAddr[8], + db->networkAddr[9], + db->networkAddr[10], + db->networkAddr[11], + db->networkAddr[12], + db->networkAddr[13], + db->networkAddr[14], + db->networkAddr[15], + db->networkAddr[16]); +#else + RTW_INFO("NAT25: Lookup M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + db->macAddr[0], + db->macAddr[1], + db->macAddr[2], + db->macAddr[3], + db->macAddr[4], + db->macAddr[5], + db->networkAddr[0], + db->networkAddr[1], + db->networkAddr[2], + db->networkAddr[3], + db->networkAddr[4], + db->networkAddr[5], + db->networkAddr[6], + db->networkAddr[7], + db->networkAddr[8], + db->networkAddr[9], + db->networkAddr[10]); +#endif + } + _exit_critical_bh(&priv->br_ext_lock, &irqL); + return 1; + } + + db = db->next_hash; + } + + _exit_critical_bh(&priv->br_ext_lock, &irqL); + return 0; +} + + +static void __nat25_db_network_insert(_adapter *priv, + unsigned char *macAddr, unsigned char *networkAddr) +{ + struct nat25_network_db_entry *db; + int hash; + _irqL irqL; + _enter_critical_bh(&priv->br_ext_lock, &irqL); + + hash = __nat25_network_hash(networkAddr); + db = priv->nethash[hash]; + while (db != NULL) { + if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { + memcpy(db->macAddr, macAddr, ETH_ALEN); + db->ageing_timer = jiffies; + _exit_critical_bh(&priv->br_ext_lock, &irqL); + return; + } + + db = db->next_hash; + } + + db = (struct nat25_network_db_entry *) rtw_malloc(sizeof(*db)); + if (db == NULL) { + _exit_critical_bh(&priv->br_ext_lock, &irqL); + return; + } + + memcpy(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN); + memcpy(db->macAddr, macAddr, ETH_ALEN); + atomic_set(&db->use_count, 1); + db->ageing_timer = jiffies; + + __network_hash_link(priv, db, hash); + + _exit_critical_bh(&priv->br_ext_lock, &irqL); +} + + +static void __nat25_db_print(_adapter *priv) +{ + _irqL irqL; + _enter_critical_bh(&priv->br_ext_lock, &irqL); + +#ifdef BR_EXT_DEBUG + static int counter = 0; + int i, j; + struct nat25_network_db_entry *db; + + counter++; + if ((counter % 16) != 0) + return; + + for (i = 0, j = 0; i < NAT25_HASH_SIZE; i++) { + db = priv->nethash[i]; + + while (db != NULL) { +#ifdef CL_IPV6_PASS + panic_printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x\n", + j, + i, + atomic_read(&db->use_count), + db->macAddr[0], + db->macAddr[1], + db->macAddr[2], + db->macAddr[3], + db->macAddr[4], + db->macAddr[5], + db->networkAddr[0], + db->networkAddr[1], + db->networkAddr[2], + db->networkAddr[3], + db->networkAddr[4], + db->networkAddr[5], + db->networkAddr[6], + db->networkAddr[7], + db->networkAddr[8], + db->networkAddr[9], + db->networkAddr[10], + db->networkAddr[11], + db->networkAddr[12], + db->networkAddr[13], + db->networkAddr[14], + db->networkAddr[15], + db->networkAddr[16]); +#else + panic_printk("NAT25: DB(%d) H(%02d) C(%d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + j, + i, + atomic_read(&db->use_count), + db->macAddr[0], + db->macAddr[1], + db->macAddr[2], + db->macAddr[3], + db->macAddr[4], + db->macAddr[5], + db->networkAddr[0], + db->networkAddr[1], + db->networkAddr[2], + db->networkAddr[3], + db->networkAddr[4], + db->networkAddr[5], + db->networkAddr[6], + db->networkAddr[7], + db->networkAddr[8], + db->networkAddr[9], + db->networkAddr[10]); +#endif + j++; + + db = db->next_hash; + } + } +#endif + + _exit_critical_bh(&priv->br_ext_lock, &irqL); +} + + + + +/* + * NAT2.5 interface + */ + +void nat25_db_cleanup(_adapter *priv) +{ + int i; + _irqL irqL; + _enter_critical_bh(&priv->br_ext_lock, &irqL); + + for (i = 0; i < NAT25_HASH_SIZE; i++) { + struct nat25_network_db_entry *f; + f = priv->nethash[i]; + while (f != NULL) { + struct nat25_network_db_entry *g; + + g = f->next_hash; + if (priv->scdb_entry == f) { + memset(priv->scdb_mac, 0, ETH_ALEN); + memset(priv->scdb_ip, 0, 4); + priv->scdb_entry = NULL; + } + __network_hash_unlink(f); + rtw_mfree((u8 *) f, sizeof(struct nat25_network_db_entry)); + + f = g; + } + } + + _exit_critical_bh(&priv->br_ext_lock, &irqL); +} + + +void nat25_db_expire(_adapter *priv) +{ + int i; + _irqL irqL; + _enter_critical_bh(&priv->br_ext_lock, &irqL); + + /* if(!priv->ethBrExtInfo.nat25_disable) */ + { + for (i = 0; i < NAT25_HASH_SIZE; i++) { + struct nat25_network_db_entry *f; + f = priv->nethash[i]; + + while (f != NULL) { + struct nat25_network_db_entry *g; + g = f->next_hash; + + if (__nat25_has_expired(priv, f)) { + if (atomic_dec_and_test(&f->use_count)) { +#ifdef BR_EXT_DEBUG +#ifdef CL_IPV6_PASS + panic_printk("NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x\n", + i, + f->macAddr[0], + f->macAddr[1], + f->macAddr[2], + f->macAddr[3], + f->macAddr[4], + f->macAddr[5], + f->networkAddr[0], + f->networkAddr[1], + f->networkAddr[2], + f->networkAddr[3], + f->networkAddr[4], + f->networkAddr[5], + f->networkAddr[6], + f->networkAddr[7], + f->networkAddr[8], + f->networkAddr[9], + f->networkAddr[10], + f->networkAddr[11], + f->networkAddr[12], + f->networkAddr[13], + f->networkAddr[14], + f->networkAddr[15], + f->networkAddr[16]); +#else + + panic_printk("NAT25 Expire H(%02d) M:%02x%02x%02x%02x%02x%02x N:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + i, + f->macAddr[0], + f->macAddr[1], + f->macAddr[2], + f->macAddr[3], + f->macAddr[4], + f->macAddr[5], + f->networkAddr[0], + f->networkAddr[1], + f->networkAddr[2], + f->networkAddr[3], + f->networkAddr[4], + f->networkAddr[5], + f->networkAddr[6], + f->networkAddr[7], + f->networkAddr[8], + f->networkAddr[9], + f->networkAddr[10]); +#endif +#endif + if (priv->scdb_entry == f) { + memset(priv->scdb_mac, 0, ETH_ALEN); + memset(priv->scdb_ip, 0, 4); + priv->scdb_entry = NULL; + } + __network_hash_unlink(f); + rtw_mfree((u8 *) f, sizeof(struct nat25_network_db_entry)); + } + } + + f = g; + } + } + } + + _exit_critical_bh(&priv->br_ext_lock, &irqL); +} + + +#ifdef SUPPORT_TX_MCAST2UNI +static int checkIPMcAndReplace(_adapter *priv, struct sk_buff *skb, unsigned int *dst_ip) +{ + struct stat_info *pstat; + struct list_head *phead, *plist; + int i; + + phead = &priv->asoc_list; + plist = phead->next; + + while (plist != phead) { + pstat = list_entry(plist, struct stat_info, asoc_list); + plist = plist->next; + + if (pstat->ipmc_num == 0) + continue; + + for (i = 0; i < MAX_IP_MC_ENTRY; i++) { + if (pstat->ipmc[i].used && !memcmp(&pstat->ipmc[i].mcmac[3], ((unsigned char *)dst_ip) + 1, 3)) { + memcpy(skb->data, pstat->ipmc[i].mcmac, ETH_ALEN); + return 1; + } + } + } + return 0; +} +#endif + +int nat25_db_handle(_adapter *priv, struct sk_buff *skb, int method) +{ + unsigned short protocol; + unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; + + if (skb == NULL) + return -1; + + if ((method <= NAT25_MIN) || (method >= NAT25_MAX)) + return -1; + + protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN)); + + /*---------------------------------------------------*/ + /* Handle IP frame */ + /*---------------------------------------------------*/ + if (protocol == __constant_htons(ETH_P_IP)) { + struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN); + + if (((unsigned char *)(iph) + (iph->ihl << 2)) >= (skb->data + ETH_HLEN + skb->len)) { + DEBUG_WARN("NAT25: malformed IP packet !\n"); + return -1; + } + + switch (method) { + case NAT25_CHECK: + return -1; + + case NAT25_INSERT: { + /* some muticast with source IP is all zero, maybe other case is illegal */ + /* in class A, B, C, host address is all zero or all one is illegal */ + if (iph->saddr == 0) + return 0; + RTW_INFO("NAT25: Insert IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr); + __nat25_generate_ipv4_network_addr(networkAddr, &iph->saddr); + /* record source IP address and , source mac address into db */ + __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); + + __nat25_db_print(priv); + } + return 0; + + case NAT25_LOOKUP: { + RTW_INFO("NAT25: Lookup IP, SA=%08x, DA=%08x\n", iph->saddr, iph->daddr); +#ifdef SUPPORT_TX_MCAST2UNI + if (priv->pshare->rf_ft_var.mc2u_disable || + ((((OPMODE & (WIFI_STATION_STATE | WIFI_ASOC_STATE)) + == (WIFI_STATION_STATE | WIFI_ASOC_STATE)) && + !checkIPMcAndReplace(priv, skb, &iph->daddr)) || + (OPMODE & WIFI_ADHOC_STATE))) +#endif + { + __nat25_generate_ipv4_network_addr(networkAddr, &iph->daddr); + + if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) { + if (*((unsigned char *)&iph->daddr + 3) == 0xff) { + /* L2 is unicast but L3 is broadcast, make L2 bacome broadcast */ + RTW_INFO("NAT25: Set DA as boardcast\n"); + memset(skb->data, 0xff, ETH_ALEN); + } else { + /* forward unknow IP packet to upper TCP/IP */ + RTW_INFO("NAT25: Replace DA with BR's MAC\n"); + if ((*(u32 *)priv->br_mac) == 0 && (*(u16 *)(priv->br_mac + 4)) == 0) { + void netdev_br_init(struct net_device *netdev); + printk("Re-init netdev_br_init() due to br_mac==0!\n"); + netdev_br_init(priv->pnetdev); + } + memcpy(skb->data, priv->br_mac, ETH_ALEN); + } + } + } + } + return 0; + + default: + return -1; + } + } + + /*---------------------------------------------------*/ + /* Handle ARP frame */ + /*---------------------------------------------------*/ + else if (protocol == __constant_htons(ETH_P_ARP)) { + struct arphdr *arp = (struct arphdr *)(skb->data + ETH_HLEN); + unsigned char *arp_ptr = (unsigned char *)(arp + 1); + unsigned int *sender, *target; + + if (arp->ar_pro != __constant_htons(ETH_P_IP)) { + DEBUG_WARN("NAT25: arp protocol unknown (%4x)!\n", htons(arp->ar_pro)); + return -1; + } + + switch (method) { + case NAT25_CHECK: + return 0; /* skb_copy for all ARP frame */ + + case NAT25_INSERT: { + RTW_INFO("NAT25: Insert ARP, MAC=%02x%02x%02x%02x%02x%02x\n", arp_ptr[0], + arp_ptr[1], arp_ptr[2], arp_ptr[3], arp_ptr[4], arp_ptr[5]); + + /* change to ARP sender mac address to wlan STA address */ + memcpy(arp_ptr, GET_MY_HWADDR(priv), ETH_ALEN); + + arp_ptr += arp->ar_hln; + sender = (unsigned int *)arp_ptr; + + __nat25_generate_ipv4_network_addr(networkAddr, sender); + + __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); + + __nat25_db_print(priv); + } + return 0; + + case NAT25_LOOKUP: { + RTW_INFO("NAT25: Lookup ARP\n"); + + arp_ptr += arp->ar_hln; + sender = (unsigned int *)arp_ptr; + arp_ptr += (arp->ar_hln + arp->ar_pln); + target = (unsigned int *)arp_ptr; + + __nat25_generate_ipv4_network_addr(networkAddr, target); + + __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); + + /* change to ARP target mac address to Lookup result */ + arp_ptr = (unsigned char *)(arp + 1); + arp_ptr += (arp->ar_hln + arp->ar_pln); + memcpy(arp_ptr, skb->data, ETH_ALEN); + } + return 0; + + default: + return -1; + } + } + + /*---------------------------------------------------*/ + /* Handle IPX and Apple Talk frame */ + /*---------------------------------------------------*/ + else if ((protocol == __constant_htons(ETH_P_IPX)) || + (protocol == __constant_htons(ETH_P_ATALK)) || + (protocol == __constant_htons(ETH_P_AARP))) { + unsigned char ipx_header[2] = {0xFF, 0xFF}; + struct ipxhdr *ipx = NULL; + struct elapaarp *ea = NULL; + struct ddpehdr *ddp = NULL; + unsigned char *framePtr = skb->data + ETH_HLEN; + + if (protocol == __constant_htons(ETH_P_IPX)) { + RTW_INFO("NAT25: Protocol=IPX (Ethernet II)\n"); + ipx = (struct ipxhdr *)framePtr; + } else { /* if(protocol <= __constant_htons(ETH_FRAME_LEN)) */ + if (!memcmp(ipx_header, framePtr, 2)) { + RTW_INFO("NAT25: Protocol=IPX (Ethernet 802.3)\n"); + ipx = (struct ipxhdr *)framePtr; + } else { + unsigned char ipx_8022_type = 0xE0; + unsigned char snap_8022_type = 0xAA; + + if (*framePtr == snap_8022_type) { + unsigned char ipx_snap_id[5] = {0x0, 0x0, 0x0, 0x81, 0x37}; /* IPX SNAP ID */ + unsigned char aarp_snap_id[5] = {0x00, 0x00, 0x00, 0x80, 0xF3}; /* Apple Talk AARP SNAP ID */ + unsigned char ddp_snap_id[5] = {0x08, 0x00, 0x07, 0x80, 0x9B}; /* Apple Talk DDP SNAP ID */ + + framePtr += 3; /* eliminate the 802.2 header */ + + if (!memcmp(ipx_snap_id, framePtr, 5)) { + framePtr += 5; /* eliminate the SNAP header */ + + RTW_INFO("NAT25: Protocol=IPX (Ethernet SNAP)\n"); + ipx = (struct ipxhdr *)framePtr; + } else if (!memcmp(aarp_snap_id, framePtr, 5)) { + framePtr += 5; /* eliminate the SNAP header */ + + ea = (struct elapaarp *)framePtr; + } else if (!memcmp(ddp_snap_id, framePtr, 5)) { + framePtr += 5; /* eliminate the SNAP header */ + + ddp = (struct ddpehdr *)framePtr; + } else { + DEBUG_WARN("NAT25: Protocol=Ethernet SNAP %02x%02x%02x%02x%02x\n", framePtr[0], + framePtr[1], framePtr[2], framePtr[3], framePtr[4]); + return -1; + } + } else if (*framePtr == ipx_8022_type) { + framePtr += 3; /* eliminate the 802.2 header */ + + if (!memcmp(ipx_header, framePtr, 2)) { + RTW_INFO("NAT25: Protocol=IPX (Ethernet 802.2)\n"); + ipx = (struct ipxhdr *)framePtr; + } else + return -1; + } + } + } + + /* IPX */ + if (ipx != NULL) { + switch (method) { + case NAT25_CHECK: + if (!memcmp(skb->data + ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) { + RTW_INFO("NAT25: Check IPX skb_copy\n"); + return 0; + } + return -1; + + case NAT25_INSERT: { + RTW_INFO("NAT25: Insert IPX, Dest=%08x,%02x%02x%02x%02x%02x%02x,%04x Source=%08x,%02x%02x%02x%02x%02x%02x,%04x\n", + ipx->ipx_dest.net, + ipx->ipx_dest.node[0], + ipx->ipx_dest.node[1], + ipx->ipx_dest.node[2], + ipx->ipx_dest.node[3], + ipx->ipx_dest.node[4], + ipx->ipx_dest.node[5], + ipx->ipx_dest.sock, + ipx->ipx_source.net, + ipx->ipx_source.node[0], + ipx->ipx_source.node[1], + ipx->ipx_source.node[2], + ipx->ipx_source.node[3], + ipx->ipx_source.node[4], + ipx->ipx_source.node[5], + ipx->ipx_source.sock); + + if (!memcmp(skb->data + ETH_ALEN, ipx->ipx_source.node, ETH_ALEN)) { + RTW_INFO("NAT25: Use IPX Net, and Socket as network addr\n"); + + __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_source.net, &ipx->ipx_source.sock); + + /* change IPX source node addr to wlan STA address */ + memcpy(ipx->ipx_source.node, GET_MY_HWADDR(priv), ETH_ALEN); + } else + __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_source.net, ipx->ipx_source.node); + + __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); + + __nat25_db_print(priv); + } + return 0; + + case NAT25_LOOKUP: { + if (!memcmp(GET_MY_HWADDR(priv), ipx->ipx_dest.node, ETH_ALEN)) { + RTW_INFO("NAT25: Lookup IPX, Modify Destination IPX Node addr\n"); + + __nat25_generate_ipx_network_addr_with_socket(networkAddr, &ipx->ipx_dest.net, &ipx->ipx_dest.sock); + + __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); + + /* replace IPX destination node addr with Lookup destination MAC addr */ + memcpy(ipx->ipx_dest.node, skb->data, ETH_ALEN); + } else { + __nat25_generate_ipx_network_addr_with_node(networkAddr, &ipx->ipx_dest.net, ipx->ipx_dest.node); + + __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); + } + } + return 0; + + default: + return -1; + } + } + + /* AARP */ + else if (ea != NULL) { + /* Sanity check fields. */ + if (ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN) { + DEBUG_WARN("NAT25: Appletalk AARP Sanity check fail!\n"); + return -1; + } + + switch (method) { + case NAT25_CHECK: + return 0; + + case NAT25_INSERT: { + /* change to AARP source mac address to wlan STA address */ + memcpy(ea->hw_src, GET_MY_HWADDR(priv), ETH_ALEN); + + RTW_INFO("NAT25: Insert AARP, Source=%d,%d Destination=%d,%d\n", + ea->pa_src_net, + ea->pa_src_node, + ea->pa_dst_net, + ea->pa_dst_node); + + __nat25_generate_apple_network_addr(networkAddr, &ea->pa_src_net, &ea->pa_src_node); + + __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); + + __nat25_db_print(priv); + } + return 0; + + case NAT25_LOOKUP: { + RTW_INFO("NAT25: Lookup AARP, Source=%d,%d Destination=%d,%d\n", + ea->pa_src_net, + ea->pa_src_node, + ea->pa_dst_net, + ea->pa_dst_node); + + __nat25_generate_apple_network_addr(networkAddr, &ea->pa_dst_net, &ea->pa_dst_node); + + __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); + + /* change to AARP destination mac address to Lookup result */ + memcpy(ea->hw_dst, skb->data, ETH_ALEN); + } + return 0; + + default: + return -1; + } + } + + /* DDP */ + else if (ddp != NULL) { + switch (method) { + case NAT25_CHECK: + return -1; + + case NAT25_INSERT: { + RTW_INFO("NAT25: Insert DDP, Source=%d,%d Destination=%d,%d\n", + ddp->deh_snet, + ddp->deh_snode, + ddp->deh_dnet, + ddp->deh_dnode); + + __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_snet, &ddp->deh_snode); + + __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); + + __nat25_db_print(priv); + } + return 0; + + case NAT25_LOOKUP: { + RTW_INFO("NAT25: Lookup DDP, Source=%d,%d Destination=%d,%d\n", + ddp->deh_snet, + ddp->deh_snode, + ddp->deh_dnet, + ddp->deh_dnode); + + __nat25_generate_apple_network_addr(networkAddr, &ddp->deh_dnet, &ddp->deh_dnode); + + __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); + } + return 0; + + default: + return -1; + } + } + + return -1; + } + + /*---------------------------------------------------*/ + /* Handle PPPoE frame */ + /*---------------------------------------------------*/ + else if ((protocol == __constant_htons(ETH_P_PPP_DISC)) || + (protocol == __constant_htons(ETH_P_PPP_SES))) { + struct pppoe_hdr *ph = (struct pppoe_hdr *)(skb->data + ETH_HLEN); + unsigned short *pMagic; + + switch (method) { + case NAT25_CHECK: + if (ph->sid == 0) + return 0; + return 1; + + case NAT25_INSERT: + if (ph->sid == 0) { /* Discovery phase according to tag */ + if (ph->code == PADI_CODE || ph->code == PADR_CODE) { + if (priv->ethBrExtInfo.addPPPoETag) { + struct pppoe_tag *tag, *pOldTag; + unsigned char tag_buf[40]; + int old_tag_len = 0; + + tag = (struct pppoe_tag *)tag_buf; + pOldTag = (struct pppoe_tag *)__nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID)); + if (pOldTag) { /* if SID existed, copy old value and delete it */ + old_tag_len = ntohs(pOldTag->tag_len); + if (old_tag_len + TAG_HDR_LEN + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN > sizeof(tag_buf)) { + DEBUG_ERR("SID tag length too long!\n"); + return -1; + } + + memcpy(tag->tag_data + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN, + pOldTag->tag_data, old_tag_len); + + if (skb_pull_and_merge(skb, (unsigned char *)pOldTag, TAG_HDR_LEN + old_tag_len) < 0) { + DEBUG_ERR("call skb_pull_and_merge() failed in PADI/R packet!\n"); + return -1; + } + ph->length = htons(ntohs(ph->length) - TAG_HDR_LEN - old_tag_len); + } + + tag->tag_type = PTT_RELAY_SID; + tag->tag_len = htons(MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN + old_tag_len); + + /* insert the magic_code+client mac in relay tag */ + pMagic = (unsigned short *)tag->tag_data; + *pMagic = htons(MAGIC_CODE); + memcpy(tag->tag_data + MAGIC_CODE_LEN, skb->data + ETH_ALEN, ETH_ALEN); + + /* Add relay tag */ + if (__nat25_add_pppoe_tag(skb, tag) < 0) + return -1; + + RTW_INFO("NAT25: Insert PPPoE, forward %s packet\n", + (ph->code == PADI_CODE ? "PADI" : "PADR")); + } else { /* not add relay tag */ + if (priv->pppoe_connection_in_progress && + memcmp(skb->data + ETH_ALEN, priv->pppoe_addr, ETH_ALEN)) { + DEBUG_ERR("Discard PPPoE packet due to another PPPoE connection is in progress!\n"); + return -2; + } + + if (priv->pppoe_connection_in_progress == 0) + memcpy(priv->pppoe_addr, skb->data + ETH_ALEN, ETH_ALEN); + + priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE; + } + } else + return -1; + } else { /* session phase */ + RTW_INFO("NAT25: Insert PPPoE, insert session packet to %s\n", skb->dev->name); + + __nat25_generate_pppoe_network_addr(networkAddr, skb->data, &(ph->sid)); + + __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); + + __nat25_db_print(priv); + + if (!priv->ethBrExtInfo.addPPPoETag && + priv->pppoe_connection_in_progress && + !memcmp(skb->data + ETH_ALEN, priv->pppoe_addr, ETH_ALEN)) + priv->pppoe_connection_in_progress = 0; + } + return 0; + + case NAT25_LOOKUP: + if (ph->code == PADO_CODE || ph->code == PADS_CODE) { + if (priv->ethBrExtInfo.addPPPoETag) { + struct pppoe_tag *tag; + unsigned char *ptr; + unsigned short tagType, tagLen; + int offset = 0; + + ptr = __nat25_find_pppoe_tag(ph, ntohs(PTT_RELAY_SID)); + if (ptr == 0) { + DEBUG_ERR("Fail to find PTT_RELAY_SID in FADO!\n"); + return -1; + } + + tag = (struct pppoe_tag *)ptr; + tagType = (unsigned short)((ptr[0] << 8) + ptr[1]); + tagLen = (unsigned short)((ptr[2] << 8) + ptr[3]); + + if ((tagType != ntohs(PTT_RELAY_SID)) || (tagLen < (MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN))) { + DEBUG_ERR("Invalid PTT_RELAY_SID tag length [%d]!\n", tagLen); + return -1; + } + + pMagic = (unsigned short *)tag->tag_data; + if (ntohs(*pMagic) != MAGIC_CODE) { + DEBUG_ERR("Can't find MAGIC_CODE in %s packet!\n", + (ph->code == PADO_CODE ? "PADO" : "PADS")); + return -1; + } + + memcpy(skb->data, tag->tag_data + MAGIC_CODE_LEN, ETH_ALEN); + + if (tagLen > MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN) + offset = TAG_HDR_LEN; + + if (skb_pull_and_merge(skb, ptr + offset, TAG_HDR_LEN + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN - offset) < 0) { + DEBUG_ERR("call skb_pull_and_merge() failed in PADO packet!\n"); + return -1; + } + ph->length = htons(ntohs(ph->length) - (TAG_HDR_LEN + MAGIC_CODE_LEN + RTL_RELAY_TAG_LEN - offset)); + if (offset > 0) + tag->tag_len = htons(tagLen - MAGIC_CODE_LEN - RTL_RELAY_TAG_LEN); + + RTW_INFO("NAT25: Lookup PPPoE, forward %s Packet from %s\n", + (ph->code == PADO_CODE ? "PADO" : "PADS"), skb->dev->name); + } else { /* not add relay tag */ + if (!priv->pppoe_connection_in_progress) { + DEBUG_ERR("Discard PPPoE packet due to no connection in progresss!\n"); + return -1; + } + memcpy(skb->data, priv->pppoe_addr, ETH_ALEN); + priv->pppoe_connection_in_progress = WAIT_TIME_PPPOE; + } + } else { + if (ph->sid != 0) { + RTW_INFO("NAT25: Lookup PPPoE, lookup session packet from %s\n", skb->dev->name); + __nat25_generate_pppoe_network_addr(networkAddr, skb->data + ETH_ALEN, &(ph->sid)); + + __nat25_db_network_lookup_and_replace(priv, skb, networkAddr); + + __nat25_db_print(priv); + } else + return -1; + + } + return 0; + + default: + return -1; + } + } + + /*---------------------------------------------------*/ + /* Handle EAP frame */ + /*---------------------------------------------------*/ + else if (protocol == __constant_htons(0x888e)) { + switch (method) { + case NAT25_CHECK: + return -1; + + case NAT25_INSERT: + return 0; + + case NAT25_LOOKUP: + return 0; + + default: + return -1; + } + } + + /*---------------------------------------------------*/ + /* Handle C-Media proprietary frame */ + /*---------------------------------------------------*/ + else if ((protocol == __constant_htons(0xe2ae)) || + (protocol == __constant_htons(0xe2af))) { + switch (method) { + case NAT25_CHECK: + return -1; + + case NAT25_INSERT: + return 0; + + case NAT25_LOOKUP: + return 0; + + default: + return -1; + } + } + + /*---------------------------------------------------*/ + /* Handle IPV6 frame */ + /*---------------------------------------------------*/ +#ifdef CL_IPV6_PASS + else if (protocol == __constant_htons(ETH_P_IPV6)) { + struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + ETH_HLEN); + + if (sizeof(*iph) >= (skb->len - ETH_HLEN)) { + DEBUG_WARN("NAT25: malformed IPv6 packet !\n"); + return -1; + } + + switch (method) { + case NAT25_CHECK: + if (skb->data[0] & 1) + return 0; + return -1; + + case NAT25_INSERT: { + RTW_INFO("NAT25: Insert IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x," + " DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", + iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3], + iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7], + iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3], + iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]); + + if (memcmp(&iph->saddr, "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16)) { + __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->saddr); + __nat25_db_network_insert(priv, skb->data + ETH_ALEN, networkAddr); + __nat25_db_print(priv); + + if (iph->nexthdr == IPPROTO_ICMPV6 && + skb->len > (ETH_HLEN + sizeof(*iph) + 4)) { + if (update_nd_link_layer_addr(skb->data + ETH_HLEN + sizeof(*iph), + skb->len - ETH_HLEN - sizeof(*iph), GET_MY_HWADDR(priv))) { + struct icmp6hdr *hdr = (struct icmp6hdr *)(skb->data + ETH_HLEN + sizeof(*iph)); + hdr->icmp6_cksum = 0; + hdr->icmp6_cksum = csum_ipv6_magic(&iph->saddr, &iph->daddr, + iph->payload_len, + IPPROTO_ICMPV6, + csum_partial((__u8 *)hdr, iph->payload_len, 0)); + } + } + } + } + return 0; + + case NAT25_LOOKUP: + RTW_INFO("NAT25: Lookup IP, SA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x," + " DA=%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x\n", + iph->saddr.s6_addr16[0], iph->saddr.s6_addr16[1], iph->saddr.s6_addr16[2], iph->saddr.s6_addr16[3], + iph->saddr.s6_addr16[4], iph->saddr.s6_addr16[5], iph->saddr.s6_addr16[6], iph->saddr.s6_addr16[7], + iph->daddr.s6_addr16[0], iph->daddr.s6_addr16[1], iph->daddr.s6_addr16[2], iph->daddr.s6_addr16[3], + iph->daddr.s6_addr16[4], iph->daddr.s6_addr16[5], iph->daddr.s6_addr16[6], iph->daddr.s6_addr16[7]); + + + __nat25_generate_ipv6_network_addr(networkAddr, (unsigned int *)&iph->daddr); + if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) { +#ifdef SUPPORT_RX_UNI2MCAST + if (iph->daddr.s6_addr[0] == 0xff) + convert_ipv6_mac_to_mc(skb); +#endif + } + return 0; + + default: + return -1; + } + } +#endif /* CL_IPV6_PASS */ + + return -1; +} + + +int nat25_handle_frame(_adapter *priv, struct sk_buff *skb) +{ +#ifdef BR_EXT_DEBUG + if ((!priv->ethBrExtInfo.nat25_disable) && (!(skb->data[0] & 1))) { + panic_printk("NAT25: Input Frame: DA=%02x%02x%02x%02x%02x%02x SA=%02x%02x%02x%02x%02x%02x\n", + skb->data[0], + skb->data[1], + skb->data[2], + skb->data[3], + skb->data[4], + skb->data[5], + skb->data[6], + skb->data[7], + skb->data[8], + skb->data[9], + skb->data[10], + skb->data[11]); + } +#endif + + if (!(skb->data[0] & 1)) { + int is_vlan_tag = 0, i, retval = 0; + unsigned short vlan_hdr = 0; + + if (*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_8021Q)) { + is_vlan_tag = 1; + vlan_hdr = *((unsigned short *)(skb->data + ETH_ALEN * 2 + 2)); + for (i = 0; i < 6; i++) + *((unsigned short *)(skb->data + ETH_ALEN * 2 + 2 - i * 2)) = *((unsigned short *)(skb->data + ETH_ALEN * 2 - 2 - i * 2)); + skb_pull(skb, 4); + } + + if (!priv->ethBrExtInfo.nat25_disable) { + _irqL irqL; + _enter_critical_bh(&priv->br_ext_lock, &irqL); + /* + * This function look up the destination network address from + * the NAT2.5 database. Return value = -1 means that the + * corresponding network protocol is NOT support. + */ + if (!priv->ethBrExtInfo.nat25sc_disable && + (*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_IP)) && + !memcmp(priv->scdb_ip, skb->data + ETH_HLEN + 16, 4)) { + memcpy(skb->data, priv->scdb_mac, ETH_ALEN); + + _exit_critical_bh(&priv->br_ext_lock, &irqL); + } else { + _exit_critical_bh(&priv->br_ext_lock, &irqL); + + retval = nat25_db_handle(priv, skb, NAT25_LOOKUP); + } + } else { + if (((*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_IP)) && + !memcmp(priv->br_ip, skb->data + ETH_HLEN + 16, 4)) || + ((*((unsigned short *)(skb->data + ETH_ALEN * 2)) == __constant_htons(ETH_P_ARP)) && + !memcmp(priv->br_ip, skb->data + ETH_HLEN + 24, 4))) { + /* for traffic to upper TCP/IP */ + retval = nat25_db_handle(priv, skb, NAT25_LOOKUP); + } + } + + if (is_vlan_tag) { + skb_push(skb, 4); + for (i = 0; i < 6; i++) + *((unsigned short *)(skb->data + i * 2)) = *((unsigned short *)(skb->data + 4 + i * 2)); + *((unsigned short *)(skb->data + ETH_ALEN * 2)) = __constant_htons(ETH_P_8021Q); + *((unsigned short *)(skb->data + ETH_ALEN * 2 + 2)) = vlan_hdr; + } + + if (retval == -1) { + /* DEBUG_ERR("NAT25: Lookup fail!\n"); */ + return -1; + } + } + + return 0; +} + +#if 0 +void mac_clone(_adapter *priv, unsigned char *addr) +{ + struct sockaddr sa; + + memcpy(sa.sa_data, addr, ETH_ALEN); + RTW_INFO("MAC Clone: Addr=%02x%02x%02x%02x%02x%02x\n", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + rtl8192cd_set_hwaddr(priv->dev, &sa); +} + + +int mac_clone_handle_frame(_adapter *priv, struct sk_buff *skb) +{ + if (priv->ethBrExtInfo.macclone_enable && !priv->macclone_completed) { + if (!(skb->data[ETH_ALEN] & 1)) { /* check any other particular MAC add */ + if (memcmp(skb->data + ETH_ALEN, GET_MY_HWADDR(priv), ETH_ALEN) && + ((priv->dev->br_port) && + memcmp(skb->data + ETH_ALEN, priv->br_mac, ETH_ALEN))) { + mac_clone(priv, skb->data + ETH_ALEN); + priv->macclone_completed = 1; + } + } + } + + return 0; +} +#endif /* 0 */ + +#define SERVER_PORT 67 +#define CLIENT_PORT 68 +#define DHCP_MAGIC 0x63825363 +#define BROADCAST_FLAG 0x8000 + +struct dhcpMessage { + u_int8_t op; + u_int8_t htype; + u_int8_t hlen; + u_int8_t hops; + u_int32_t xid; + u_int16_t secs; + u_int16_t flags; + u_int32_t ciaddr; + u_int32_t yiaddr; + u_int32_t siaddr; + u_int32_t giaddr; + u_int8_t chaddr[16]; + u_int8_t sname[64]; + u_int8_t file[128]; + u_int32_t cookie; + u_int8_t options[308]; /* 312 - cookie */ +}; + +void dhcp_flag_bcast(_adapter *priv, struct sk_buff *skb) +{ + if (skb == NULL) + return; + + if (!priv->ethBrExtInfo.dhcp_bcst_disable) { + unsigned short protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN)); + + if (protocol == __constant_htons(ETH_P_IP)) { /* IP */ + struct iphdr *iph = (struct iphdr *)(skb->data + ETH_HLEN); + + if (iph->protocol == IPPROTO_UDP) { /* UDP */ + struct udphdr *udph = (struct udphdr *)((SIZE_PTR)iph + (iph->ihl << 2)); + + if ((udph->source == __constant_htons(CLIENT_PORT)) + && (udph->dest == __constant_htons(SERVER_PORT))) { /* DHCP request */ + struct dhcpMessage *dhcph = + (struct dhcpMessage *)((SIZE_PTR)udph + sizeof(struct udphdr)); + + if (dhcph->cookie == __constant_htonl(DHCP_MAGIC)) { /* match magic word */ + if (!(dhcph->flags & htons(BROADCAST_FLAG))) { /* if not broadcast */ + register int sum = 0; + + RTW_INFO("DHCP: change flag of DHCP request to broadcast.\n"); + /* or BROADCAST flag */ + dhcph->flags |= htons(BROADCAST_FLAG); + /* recalculate checksum */ + sum = ~(udph->check) & 0xffff; + sum += dhcph->flags; + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + udph->check = ~sum; + } + } + } + } + } + } +} + + +void *scdb_findEntry(_adapter *priv, unsigned char *macAddr, + unsigned char *ipAddr) +{ + unsigned char networkAddr[MAX_NETWORK_ADDR_LEN]; + struct nat25_network_db_entry *db; + int hash; + /* _irqL irqL; */ + /* _enter_critical_bh(&priv->br_ext_lock, &irqL); */ + + __nat25_generate_ipv4_network_addr(networkAddr, (unsigned int *)ipAddr); + hash = __nat25_network_hash(networkAddr); + db = priv->nethash[hash]; + while (db != NULL) { + if (!memcmp(db->networkAddr, networkAddr, MAX_NETWORK_ADDR_LEN)) { + /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ + return (void *)db; + } + + db = db->next_hash; + } + + /* _exit_critical_bh(&priv->br_ext_lock, &irqL); */ + return NULL; +} + +#endif /* CONFIG_BR_EXT */ diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_bt_mp.c b/linux-bsp/drivers/rtl8188eus/core/rtw_bt_mp.c new file mode 100644 index 0000000..a0597d8 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_bt_mp.c @@ -0,0 +1,1580 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + + +#include <drv_types.h> +#include <rtw_bt_mp.h> + +#if defined(CONFIG_RTL8723B) + #include <rtl8723b_hal.h> +#endif + +#if defined(CONFIG_RTL8723B) || defined(CONFIG_RTL8821A) +void MPh2c_timeout_handle(void *FunctionContext) +{ + PADAPTER pAdapter; + PMPT_CONTEXT pMptCtx; + + + RTW_INFO("[MPT], MPh2c_timeout_handle\n"); + + pAdapter = (PADAPTER)FunctionContext; + pMptCtx = &pAdapter->mppriv.mpt_ctx; + + pMptCtx->bMPh2c_timeout = _TRUE; + + if ((_FALSE == pMptCtx->MptH2cRspEvent) + || ((_TRUE == pMptCtx->MptH2cRspEvent) + && (_FALSE == pMptCtx->MptBtC2hEvent))) + _rtw_up_sema(&pMptCtx->MPh2c_Sema); +} + +u32 WaitC2Hevent(PADAPTER pAdapter, u8 *C2H_event, u32 delay_time) +{ + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + pMptCtx->bMPh2c_timeout = _FALSE; + + if (pAdapter->registrypriv.mp_mode == 0) { + RTW_INFO("[MPT], Error!! WaitC2Hevent mp_mode == 0!!\n"); + return _FALSE; + } + + _set_timer(&pMptCtx->MPh2c_timeout_timer, delay_time); + + _rtw_down_sema(&pMptCtx->MPh2c_Sema); + + if (pMptCtx->bMPh2c_timeout == _TRUE) { + *C2H_event = _FALSE; + + return _FALSE; + } + + /* for safty, cancel timer here again */ + _cancel_timer_ex(&pMptCtx->MPh2c_timeout_timer); + + return _TRUE; +} + +BT_CTRL_STATUS +mptbt_CheckC2hFrame( + PADAPTER Adapter, + PBT_H2C pH2c, + PBT_EXT_C2H pExtC2h +) +{ + BT_CTRL_STATUS c2hStatus = BT_STATUS_C2H_SUCCESS; + + /* RTW_INFO("[MPT], MPT rsp C2H hex: %x %x %x %x %x %x\n"), pExtC2h , pExtC2h+1 ,pExtC2h+2 ,pExtC2h+3 ,pExtC2h+4 ,pExtC2h+5); */ + + RTW_INFO("[MPT], statusCode = 0x%x\n", pExtC2h->statusCode); + RTW_INFO("[MPT], retLen = %d\n", pExtC2h->retLen); + RTW_INFO("[MPT], opCodeVer : req/rsp=%d/%d\n", pH2c->opCodeVer, pExtC2h->opCodeVer); + RTW_INFO("[MPT], reqNum : req/rsp=%d/%d\n", pH2c->reqNum, pExtC2h->reqNum); + if (pExtC2h->reqNum != pH2c->reqNum) { + c2hStatus = BT_STATUS_C2H_REQNUM_MISMATCH; + RTW_INFO("[MPT], Error!! C2H reqNum Mismatch!!\n"); + } else if (pExtC2h->opCodeVer != pH2c->opCodeVer) { + c2hStatus = BT_STATUS_OPCODE_L_VERSION_MISMATCH; + RTW_INFO("[MPT], Error!! OPCode version L mismatch!!\n"); + } + + return c2hStatus; +} + +BT_CTRL_STATUS +mptbt_SendH2c( + PADAPTER Adapter, + PBT_H2C pH2c, + u2Byte h2cCmdLen +) +{ + /* KIRQL OldIrql = KeGetCurrentIrql(); */ + BT_CTRL_STATUS h2cStatus = BT_STATUS_H2C_SUCCESS; + PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); + u1Byte i; + + RTW_INFO("[MPT], mptbt_SendH2c()=========>\n"); + + /* PlatformResetEvent(&pMptCtx->MptH2cRspEvent); */ + /* PlatformResetEvent(&pMptCtx->MptBtC2hEvent); */ + + /* if(OldIrql == PASSIVE_LEVEL) + * { */ + /* RTPRINT_DATA(FMPBT, FMPBT_H2C_CONTENT, ("[MPT], MPT H2C hex:\n"), pH2c, h2cCmdLen); */ + + for (i = 0; i < BT_H2C_MAX_RETRY; i++) { + RTW_INFO("[MPT], Send H2C command to wifi!!!\n"); + + pMptCtx->MptH2cRspEvent = _FALSE; + pMptCtx->MptBtC2hEvent = _FALSE; + +#if defined(CONFIG_RTL8723B) + rtl8723b_set_FwBtMpOper_cmd(Adapter, pH2c->opCode, pH2c->opCodeVer, pH2c->reqNum, pH2c->buf); +#endif + pMptCtx->h2cReqNum++; + pMptCtx->h2cReqNum %= 16; + + if (WaitC2Hevent(Adapter, &pMptCtx->MptH2cRspEvent, 100)) { + RTW_INFO("[MPT], Received WiFi MptH2cRspEvent!!!\n"); + if (WaitC2Hevent(Adapter, &pMptCtx->MptBtC2hEvent, 400)) { + RTW_INFO("[MPT], Received MptBtC2hEvent!!!\n"); + break; + } else { + RTW_INFO("[MPT], Error!!BT MptBtC2hEvent timeout!!\n"); + h2cStatus = BT_STATUS_H2C_BT_NO_RSP; + } + } else { + RTW_INFO("[MPT], Error!!WiFi MptH2cRspEvent timeout!!\n"); + h2cStatus = BT_STATUS_H2C_TIMTOUT; + } + } + /* } + * else + * { + * RT_ASSERT(FALSE, ("[MPT], mptbt_SendH2c() can only run under PASSIVE_LEVEL!!\n")); + * h2cStatus = BT_STATUS_WRONG_LEVEL; + * } */ + + RTW_INFO("[MPT], mptbt_SendH2c()<=========\n"); + return h2cStatus; +} + + + +BT_CTRL_STATUS +mptbt_CheckBtRspStatus( + PADAPTER Adapter, + PBT_EXT_C2H pExtC2h +) +{ + BT_CTRL_STATUS retStatus = BT_OP_STATUS_SUCCESS; + + switch (pExtC2h->statusCode) { + case BT_OP_STATUS_SUCCESS: + retStatus = BT_STATUS_BT_OP_SUCCESS; + RTW_INFO("[MPT], BT status : BT_STATUS_SUCCESS\n"); + break; + case BT_OP_STATUS_VERSION_MISMATCH: + retStatus = BT_STATUS_OPCODE_L_VERSION_MISMATCH; + RTW_INFO("[MPT], BT status : BT_STATUS_OPCODE_L_VERSION_MISMATCH\n"); + break; + case BT_OP_STATUS_UNKNOWN_OPCODE: + retStatus = BT_STATUS_UNKNOWN_OPCODE_L; + RTW_INFO("[MPT], BT status : BT_STATUS_UNKNOWN_OPCODE_L\n"); + break; + case BT_OP_STATUS_ERROR_PARAMETER: + retStatus = BT_STATUS_PARAMETER_FORMAT_ERROR_L; + RTW_INFO("[MPT], BT status : BT_STATUS_PARAMETER_FORMAT_ERROR_L\n"); + break; + default: + retStatus = BT_STATUS_UNKNOWN_STATUS_L; + RTW_INFO("[MPT], BT status : BT_STATUS_UNKNOWN_STATUS_L\n"); + break; + } + + return retStatus; +} + + + +BT_CTRL_STATUS +mptbt_BtFwOpCodeProcess( + PADAPTER Adapter, + u1Byte btFwOpCode, + u1Byte opCodeVer, + pu1Byte pH2cPar, + u1Byte h2cParaLen +) +{ + u1Byte H2C_Parameter[6] = {0}; + PBT_H2C pH2c = (PBT_H2C)&H2C_Parameter[0]; + PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); + PBT_EXT_C2H pExtC2h = (PBT_EXT_C2H)&pMptCtx->c2hBuf[0]; + u2Byte paraLen = 0, i; + BT_CTRL_STATUS h2cStatus = BT_STATUS_H2C_SUCCESS, c2hStatus = BT_STATUS_C2H_SUCCESS; + BT_CTRL_STATUS retStatus = BT_STATUS_H2C_BT_NO_RSP; + + if (Adapter->registrypriv.mp_mode == 0) { + RTW_INFO("[MPT], Error!! mptbt_BtFwOpCodeProces mp_mode == 0!!\n"); + return _FALSE; + } + + pH2c->opCode = btFwOpCode; + pH2c->opCodeVer = opCodeVer; + pH2c->reqNum = pMptCtx->h2cReqNum; + /* PlatformMoveMemory(&pH2c->buf[0], pH2cPar, h2cParaLen); */ + /* _rtw_memcpy(&pH2c->buf[0], pH2cPar, h2cParaLen); */ + _rtw_memcpy(pH2c->buf, pH2cPar, h2cParaLen); + + RTW_INFO("[MPT], pH2c->opCode=%d\n", pH2c->opCode); + RTW_INFO("[MPT], pH2c->opCodeVer=%d\n", pH2c->opCodeVer); + RTW_INFO("[MPT], pH2c->reqNum=%d\n", pH2c->reqNum); + RTW_INFO("[MPT], h2c parameter length=%d\n", h2cParaLen); + for (i = 0; i < h2cParaLen; i++) + RTW_INFO("[MPT], parameter[%d]=0x%02x\n", i, pH2c->buf[i]); + + h2cStatus = mptbt_SendH2c(Adapter, pH2c, h2cParaLen + 2); + if (BT_STATUS_H2C_SUCCESS == h2cStatus) { + /* if reach here, it means H2C get the correct c2h response, */ + c2hStatus = mptbt_CheckC2hFrame(Adapter, pH2c, pExtC2h); + if (BT_STATUS_C2H_SUCCESS == c2hStatus) + retStatus = mptbt_CheckBtRspStatus(Adapter, pExtC2h); + else { + RTW_INFO("[MPT], Error!! C2H failed for pH2c->opCode=%d\n", pH2c->opCode); + /* check c2h status error, return error status code to upper layer. */ + retStatus = c2hStatus; + } + } else { + RTW_INFO("[MPT], Error!! H2C failed for pH2c->opCode=%d\n", pH2c->opCode); + /* check h2c status error, return error status code to upper layer. */ + retStatus = h2cStatus; + } + + return retStatus; +} + + + + +u2Byte +mptbt_BtReady( + PADAPTER Adapter, + PBT_REQ_CMD pBtReq, + PBT_RSP_CMD pBtRsp +) +{ + u1Byte h2cParaBuf[6] = {0}; + u1Byte h2cParaLen = 0; + u2Byte paraLen = 0; + u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; + u1Byte btOpcode; + u1Byte btOpcodeVer = 0; + PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); + PBT_EXT_C2H pExtC2h = (PBT_EXT_C2H)&pMptCtx->c2hBuf[0]; + u1Byte i; + u1Byte btFwVer = 0, bdAddr[6] = {0}; + u2Byte btRealFwVer = 0; + pu2Byte pu2Tmp = NULL; + + /* */ + /* check upper layer parameters */ + /* */ + + /* 1. check upper layer opcode version */ + if (pBtReq->opCodeVer != 1) { + RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n"); + pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; + return paraLen; + } + + pBtRsp->pParamStart[0] = MP_BT_NOT_READY; + paraLen = 10; + /* */ + /* execute lower layer opcodes */ + /* */ + + /* Get BT FW version */ + /* fill h2c parameters */ + btOpcode = BT_LO_OP_GET_BT_VERSION; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } else { + pu2Tmp = (pu2Byte)&pExtC2h->buf[0]; + btRealFwVer = *pu2Tmp; + btFwVer = pExtC2h->buf[1]; + RTW_INFO("[MPT], btRealFwVer=0x%x, btFwVer=0x%x\n", btRealFwVer, btFwVer); + } + + /* Get BD Address */ + /* fill h2c parameters */ + btOpcode = BT_LO_OP_GET_BD_ADDR_L; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } else { + bdAddr[5] = pExtC2h->buf[0]; + bdAddr[4] = pExtC2h->buf[1]; + bdAddr[3] = pExtC2h->buf[2]; + } + + /* fill h2c parameters */ + btOpcode = BT_LO_OP_GET_BD_ADDR_H; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } else { + bdAddr[2] = pExtC2h->buf[0]; + bdAddr[1] = pExtC2h->buf[1]; + bdAddr[0] = pExtC2h->buf[2]; + } + RTW_INFO("[MPT], Local BDAddr:"); + for (i = 0; i < 6; i++) + RTW_INFO(" 0x%x ", bdAddr[i]); + pBtRsp->status = BT_STATUS_SUCCESS; + pBtRsp->pParamStart[0] = MP_BT_READY; + pu2Tmp = (pu2Byte)&pBtRsp->pParamStart[1]; + *pu2Tmp = btRealFwVer; + pBtRsp->pParamStart[3] = btFwVer; + for (i = 0; i < 6; i++) + pBtRsp->pParamStart[4 + i] = bdAddr[5 - i]; + + return paraLen; +} + +void mptbt_close_WiFiRF(PADAPTER Adapter) +{ + phy_set_bb_reg(Adapter, 0x824, 0xF, 0x0); + phy_set_bb_reg(Adapter, 0x824, 0x700000, 0x0); + phy_set_rf_reg(Adapter, RF_PATH_A, 0x0, 0xF0000, 0x0); +} + +void mptbt_open_WiFiRF(PADAPTER Adapter) +{ + phy_set_bb_reg(Adapter, 0x824, 0x700000, 0x3); + phy_set_bb_reg(Adapter, 0x824, 0xF, 0x2); + phy_set_rf_reg(Adapter, RF_PATH_A, 0x0, 0xF0000, 0x3); +} + +u4Byte mptbt_switch_RF(PADAPTER Adapter, u1Byte Enter) +{ + u2Byte tmp_2byte = 0; + + /* Enter test mode */ + if (Enter) { + /* 1>. close WiFi RF */ + mptbt_close_WiFiRF(Adapter); + + /* 2>. change ant switch to BT */ + tmp_2byte = rtw_read16(Adapter, 0x860); + tmp_2byte = tmp_2byte | BIT(9); + tmp_2byte = tmp_2byte & (~BIT(8)); + rtw_write16(Adapter, 0x860, tmp_2byte); + rtw_write16(Adapter, 0x870, 0x300); + } else { + /* 1>. Open WiFi RF */ + mptbt_open_WiFiRF(Adapter); + + /* 2>. change ant switch back */ + tmp_2byte = rtw_read16(Adapter, 0x860); + tmp_2byte = tmp_2byte | BIT(8); + tmp_2byte = tmp_2byte & (~BIT(9)); + rtw_write16(Adapter, 0x860, tmp_2byte); + rtw_write16(Adapter, 0x870, 0x300); + } + + return 0; +} + +u2Byte +mptbt_BtSetMode( + PADAPTER Adapter, + PBT_REQ_CMD pBtReq, + PBT_RSP_CMD pBtRsp +) +{ + u1Byte h2cParaBuf[6] = {0}; + u1Byte h2cParaLen = 0; + u2Byte paraLen = 0; + u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; + u1Byte btOpcode; + u1Byte btOpcodeVer = 0; + u1Byte btModeToSet = 0; + + /* */ + /* check upper layer parameters */ + /* */ + /* 1. check upper layer opcode version */ + if (pBtReq->opCodeVer != 1) { + RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n"); + pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; + return paraLen; + } + /* 2. check upper layer parameter length */ + if (1 == pBtReq->paraLength) { + btModeToSet = pBtReq->pParamStart[0]; + RTW_INFO("[MPT], BtTestMode=%d\n", btModeToSet); + } else { + RTW_INFO("[MPT], Error!! wrong parameter length=%d (should be 1)\n", pBtReq->paraLength); + pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; + return paraLen; + } + + /* */ + /* execute lower layer opcodes */ + /* */ + + /* 1. fill h2c parameters */ + /* check bt mode */ + btOpcode = BT_LO_OP_SET_BT_MODE; + if (btModeToSet >= MP_BT_MODE_MAX) { + pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } else { + mptbt_switch_RF(Adapter, 1); + + h2cParaBuf[0] = btModeToSet; + h2cParaLen = 1; + /* 2. execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + } + + /* 3. construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS == retStatus) + pBtRsp->status = BT_STATUS_SUCCESS; + else { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + } + + return paraLen; +} + + +VOID +MPTBT_FwC2hBtMpCtrl( + PADAPTER Adapter, + pu1Byte tmpBuf, + u1Byte length +) +{ + u32 i; + PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); + PBT_EXT_C2H pExtC2h = (PBT_EXT_C2H)tmpBuf; + + if (Adapter->bBTFWReady == _FALSE || Adapter->registrypriv.mp_mode == 0) { + /* RTW_INFO("Ignore C2H BT MP Info since not in MP mode\n"); */ + return; + } + if (length > 32 || length < 3) { + RTW_INFO("\n [MPT], pExtC2h->buf hex: length=%d > 32 || < 3\n", length); + return; + } + + /* cancel_timeout for h2c handle */ + _cancel_timer_ex(&pMptCtx->MPh2c_timeout_timer); + + for (i = 0; i < length; i++) + RTW_INFO("[MPT], %s, buf[%d]=0x%02x ", __FUNCTION__, i, tmpBuf[i]); + RTW_INFO("[MPT], pExtC2h->extendId=0x%x\n", pExtC2h->extendId); + + switch (pExtC2h->extendId) { + case EXT_C2H_WIFI_FW_ACTIVE_RSP: + RTW_INFO("[MPT], EXT_C2H_WIFI_FW_ACTIVE_RSP\n"); +#if 0 + RTW_INFO("[MPT], pExtC2h->buf hex:\n"); + for (i = 0; i < (length - 3); i++) + RTW_INFO(" 0x%x ", pExtC2h->buf[i]); +#endif + if ((_FALSE == pMptCtx->bMPh2c_timeout) + && (_FALSE == pMptCtx->MptH2cRspEvent)) { + pMptCtx->MptH2cRspEvent = _TRUE; + _rtw_up_sema(&pMptCtx->MPh2c_Sema); + } + break; + + case EXT_C2H_TRIG_BY_BT_FW: + RTW_INFO("[MPT], EXT_C2H_TRIG_BY_BT_FW\n"); + _rtw_memcpy(&pMptCtx->c2hBuf[0], tmpBuf, length); + RTW_INFO("[MPT], pExtC2h->statusCode=0x%x\n", pExtC2h->statusCode); + RTW_INFO("[MPT], pExtC2h->retLen=0x%x\n", pExtC2h->retLen); + RTW_INFO("[MPT], pExtC2h->opCodeVer=0x%x\n", pExtC2h->opCodeVer); + RTW_INFO("[MPT], pExtC2h->reqNum=0x%x\n", pExtC2h->reqNum); + for (i = 0; i < (length - 3); i++) + RTW_INFO("[MPT], pExtC2h->buf[%d]=0x%02x\n", i, pExtC2h->buf[i]); + + if ((_FALSE == pMptCtx->bMPh2c_timeout) + && (_TRUE == pMptCtx->MptH2cRspEvent) + && (_FALSE == pMptCtx->MptBtC2hEvent)) { + pMptCtx->MptBtC2hEvent = _TRUE; + _rtw_up_sema(&pMptCtx->MPh2c_Sema); + } + break; + + default: + RTW_INFO("[MPT], EXT_C2H Target not found,pExtC2h->extendId =%d ,pExtC2h->reqNum=%d\n", pExtC2h->extendId, pExtC2h->reqNum); + break; + } + + + +} + + +u2Byte +mptbt_BtGetGeneral( + IN PADAPTER Adapter, + IN PBT_REQ_CMD pBtReq, + IN PBT_RSP_CMD pBtRsp +) +{ + PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); + PBT_EXT_C2H pExtC2h = (PBT_EXT_C2H)&pMptCtx->c2hBuf[0]; + u1Byte h2cParaBuf[6] = {0}; + u1Byte h2cParaLen = 0; + u2Byte paraLen = 0; + u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; + u1Byte btOpcode, bdAddr[6] = {0}; + u1Byte btOpcodeVer = 0; + u1Byte getType = 0, i; + u2Byte getParaLen = 0, validParaLen = 0; + u1Byte regType = 0, reportType = 0; + u4Byte regAddr = 0, regValue = 0; + pu4Byte pu4Tmp; + pu2Byte pu2Tmp; + pu1Byte pu1Tmp; + + /* */ + /* check upper layer parameters */ + /* */ + + /* check upper layer opcode version */ + if (pBtReq->opCodeVer != 1) { + RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n"); + pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; + return paraLen; + } + /* check upper layer parameter length */ + if (pBtReq->paraLength < 1) { + RTW_INFO("[MPT], Error!! wrong parameter length=%d (should larger than 1)\n", pBtReq->paraLength); + pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; + return paraLen; + } + getParaLen = pBtReq->paraLength - 1; + getType = pBtReq->pParamStart[0]; + + RTW_INFO("[MPT], getType=%d, getParaLen=%d\n", getType, getParaLen); + + /* check parameter first */ + switch (getType) { + case BT_GGET_REG: + RTW_INFO("[MPT], [BT_GGET_REG]\n"); + validParaLen = 5; + if (getParaLen == validParaLen) { + btOpcode = BT_LO_OP_READ_REG; + regType = pBtReq->pParamStart[1]; + pu4Tmp = (pu4Byte)&pBtReq->pParamStart[2]; + regAddr = *pu4Tmp; + RTW_INFO("[MPT], BT_GGET_REG regType=0x%02x, regAddr=0x%08x!!\n", + regType, regAddr); + if (regType >= BT_REG_MAX) { + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } else { + if (((BT_REG_RF == regType) && (regAddr > 0x7f)) || + ((BT_REG_MODEM == regType) && (regAddr > 0x1ff)) || + ((BT_REG_BLUEWIZE == regType) && (regAddr > 0xfff)) || + ((BT_REG_VENDOR == regType) && (regAddr > 0xfff)) || + ((BT_REG_LE == regType) && (regAddr > 0xfff))) { + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } + } + } + break; + case BT_GGET_STATUS: + RTW_INFO("[MPT], [BT_GGET_STATUS]\n"); + validParaLen = 0; + break; + case BT_GGET_REPORT: + RTW_INFO("[MPT], [BT_GGET_REPORT]\n"); + validParaLen = 1; + if (getParaLen == validParaLen) { + reportType = pBtReq->pParamStart[1]; + RTW_INFO("[MPT], BT_GGET_REPORT reportType=0x%x!!\n", reportType); + if (reportType >= BT_REPORT_MAX) { + pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } + } + break; + default: { + RTW_INFO("[MPT], Error!! getType=%d, out of range\n", getType); + pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } + break; + } + if (getParaLen != validParaLen) { + RTW_INFO("[MPT], Error!! wrong parameter length=%d for BT_GET_GEN_CMD cmd id=0x%x, paraLen should=0x%x\n", + getParaLen, getType, validParaLen); + pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; + return paraLen; + } + + /* */ + /* execute lower layer opcodes */ + /* */ + if (BT_GGET_REG == getType) { + /* fill h2c parameters */ + /* here we should write reg value first then write the address, adviced by Austin */ + btOpcode = BT_LO_OP_READ_REG; + h2cParaBuf[0] = regType; + h2cParaBuf[1] = pBtReq->pParamStart[2]; + h2cParaBuf[2] = pBtReq->pParamStart[3]; + h2cParaLen = 3; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + pu2Tmp = (pu2Byte)&pExtC2h->buf[0]; + regValue = *pu2Tmp; + RTW_INFO("[MPT], read reg regType=0x%02x, regAddr=0x%08x, regValue=0x%04x\n", + regType, regAddr, regValue); + + pu4Tmp = (pu4Byte)&pBtRsp->pParamStart[0]; + *pu4Tmp = regValue; + paraLen = 4; + } else if (BT_GGET_STATUS == getType) { + btOpcode = BT_LO_OP_GET_BT_STATUS; + h2cParaLen = 0; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + pBtRsp->pParamStart[0] = pExtC2h->buf[0]; + pBtRsp->pParamStart[1] = pExtC2h->buf[1]; + RTW_INFO("[MPT], read bt status, testMode=0x%x, testStatus=0x%x\n", + pBtRsp->pParamStart[0], pBtRsp->pParamStart[1]); + paraLen = 2; + } else if (BT_GGET_REPORT == getType) { + switch (reportType) { + case BT_REPORT_RX_PACKET_CNT: { + RTW_INFO("[MPT], [Rx Packet Counts]\n"); + btOpcode = BT_LO_OP_GET_RX_PKT_CNT_L; + h2cParaLen = 0; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + pBtRsp->pParamStart[0] = pExtC2h->buf[0]; + pBtRsp->pParamStart[1] = pExtC2h->buf[1]; + + btOpcode = BT_LO_OP_GET_RX_PKT_CNT_H; + h2cParaLen = 0; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + pBtRsp->pParamStart[2] = pExtC2h->buf[0]; + pBtRsp->pParamStart[3] = pExtC2h->buf[1]; + paraLen = 4; + } + break; + case BT_REPORT_RX_ERROR_BITS: { + RTW_INFO("[MPT], [Rx Error Bits]\n"); + btOpcode = BT_LO_OP_GET_RX_ERROR_BITS_L; + h2cParaLen = 0; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + pBtRsp->pParamStart[0] = pExtC2h->buf[0]; + pBtRsp->pParamStart[1] = pExtC2h->buf[1]; + + btOpcode = BT_LO_OP_GET_RX_ERROR_BITS_H; + h2cParaLen = 0; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + pBtRsp->pParamStart[2] = pExtC2h->buf[0]; + pBtRsp->pParamStart[3] = pExtC2h->buf[1]; + paraLen = 4; + } + break; + case BT_REPORT_RSSI: { + RTW_INFO("[MPT], [RSSI]\n"); + btOpcode = BT_LO_OP_GET_RSSI; + h2cParaLen = 0; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + pBtRsp->pParamStart[0] = pExtC2h->buf[0]; + pBtRsp->pParamStart[1] = pExtC2h->buf[1]; + paraLen = 2; + } + break; + case BT_REPORT_CFO_HDR_QUALITY: { + RTW_INFO("[MPT], [CFO & Header Quality]\n"); + btOpcode = BT_LO_OP_GET_CFO_HDR_QUALITY_L; + h2cParaLen = 0; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + pBtRsp->pParamStart[0] = pExtC2h->buf[0]; + pBtRsp->pParamStart[1] = pExtC2h->buf[1]; + + btOpcode = BT_LO_OP_GET_CFO_HDR_QUALITY_H; + h2cParaLen = 0; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + pBtRsp->pParamStart[2] = pExtC2h->buf[0]; + pBtRsp->pParamStart[3] = pExtC2h->buf[1]; + paraLen = 4; + } + break; + case BT_REPORT_CONNECT_TARGET_BD_ADDR: { + RTW_INFO("[MPT], [Connected Target BD ADDR]\n"); + btOpcode = BT_LO_OP_GET_TARGET_BD_ADDR_L; + h2cParaLen = 0; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + bdAddr[5] = pExtC2h->buf[0]; + bdAddr[4] = pExtC2h->buf[1]; + bdAddr[3] = pExtC2h->buf[2]; + + btOpcode = BT_LO_OP_GET_TARGET_BD_ADDR_H; + h2cParaLen = 0; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + bdAddr[2] = pExtC2h->buf[0]; + bdAddr[1] = pExtC2h->buf[1]; + bdAddr[0] = pExtC2h->buf[2]; + + RTW_INFO("[MPT], Connected Target BDAddr:%s", bdAddr); + for (i = 0; i < 6; i++) + pBtRsp->pParamStart[i] = bdAddr[5 - i]; + paraLen = 6; + } + break; + default: + pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + break; + } + } + + pBtRsp->status = BT_STATUS_SUCCESS; + return paraLen; +} + + + +u2Byte +mptbt_BtSetGeneral( + IN PADAPTER Adapter, + IN PBT_REQ_CMD pBtReq, + IN PBT_RSP_CMD pBtRsp +) +{ + u1Byte h2cParaBuf[6] = {0}; + u1Byte h2cParaLen = 0; + u2Byte paraLen = 0; + u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; + u1Byte btOpcode; + u1Byte btOpcodeVer = 0; + u1Byte setType = 0; + u2Byte setParaLen = 0, validParaLen = 0; + u1Byte regType = 0, bdAddr[6] = {0}, calVal = 0; + u4Byte regAddr = 0, regValue = 0; + pu4Byte pu4Tmp; + pu2Byte pu2Tmp; + pu1Byte pu1Tmp; + + /* */ + /* check upper layer parameters */ + /* */ + + /* check upper layer opcode version */ + if (pBtReq->opCodeVer != 1) { + RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n"); + pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; + return paraLen; + } + /* check upper layer parameter length */ + if (pBtReq->paraLength < 1) { + RTW_INFO("[MPT], Error!! wrong parameter length=%d (should larger than 1)\n", pBtReq->paraLength); + pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; + return paraLen; + } + setParaLen = pBtReq->paraLength - 1; + setType = pBtReq->pParamStart[0]; + + RTW_INFO("[MPT], setType=%d, setParaLen=%d\n", setType, setParaLen); + + /* check parameter first */ + switch (setType) { + case BT_GSET_REG: + RTW_INFO("[MPT], [BT_GSET_REG]\n"); + validParaLen = 9; + if (setParaLen == validParaLen) { + btOpcode = BT_LO_OP_WRITE_REG_VALUE; + regType = pBtReq->pParamStart[1]; + pu4Tmp = (pu4Byte)&pBtReq->pParamStart[2]; + regAddr = *pu4Tmp; + pu4Tmp = (pu4Byte)&pBtReq->pParamStart[6]; + regValue = *pu4Tmp; + RTW_INFO("[MPT], BT_GSET_REG regType=0x%x, regAddr=0x%x, regValue=0x%x!!\n", + regType, regAddr, regValue); + if (regType >= BT_REG_MAX) { + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } else { + if (((BT_REG_RF == regType) && (regAddr > 0x7f)) || + ((BT_REG_MODEM == regType) && (regAddr > 0x1ff)) || + ((BT_REG_BLUEWIZE == regType) && (regAddr > 0xfff)) || + ((BT_REG_VENDOR == regType) && (regAddr > 0xfff)) || + ((BT_REG_LE == regType) && (regAddr > 0xfff))) { + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } + } + } + break; + case BT_GSET_RESET: + RTW_INFO("[MPT], [BT_GSET_RESET]\n"); + validParaLen = 0; + break; + case BT_GSET_TARGET_BD_ADDR: + RTW_INFO("[MPT], [BT_GSET_TARGET_BD_ADDR]\n"); + validParaLen = 6; + if (setParaLen == validParaLen) { + btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_H; + if ((pBtReq->pParamStart[1] == 0) && + (pBtReq->pParamStart[2] == 0) && + (pBtReq->pParamStart[3] == 0) && + (pBtReq->pParamStart[4] == 0) && + (pBtReq->pParamStart[5] == 0) && + (pBtReq->pParamStart[6] == 0)) { + RTW_INFO("[MPT], Error!! targetBDAddr=all zero\n"); + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } + if ((pBtReq->pParamStart[1] == 0xff) && + (pBtReq->pParamStart[2] == 0xff) && + (pBtReq->pParamStart[3] == 0xff) && + (pBtReq->pParamStart[4] == 0xff) && + (pBtReq->pParamStart[5] == 0xff) && + (pBtReq->pParamStart[6] == 0xff)) { + RTW_INFO("[MPT], Error!! targetBDAddr=all 0xf\n"); + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } + bdAddr[0] = pBtReq->pParamStart[6]; + bdAddr[1] = pBtReq->pParamStart[5]; + bdAddr[2] = pBtReq->pParamStart[4]; + bdAddr[3] = pBtReq->pParamStart[3]; + bdAddr[4] = pBtReq->pParamStart[2]; + bdAddr[5] = pBtReq->pParamStart[1]; + RTW_INFO("[MPT], target BDAddr:%x,%x,%x,%x,%x,%x\n", + bdAddr[0], bdAddr[1], bdAddr[2], bdAddr[3], bdAddr[4], bdAddr[5]); + } + break; + case BT_GSET_TX_PWR_FINETUNE: + RTW_INFO("[MPT], [BT_GSET_TX_PWR_FINETUNE]\n"); + validParaLen = 1; + if (setParaLen == validParaLen) { + btOpcode = BT_LO_OP_SET_TX_POWER_CALIBRATION; + calVal = pBtReq->pParamStart[1]; + if ((calVal < 1) || (calVal > 9)) { + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } + RTW_INFO("[MPT], calVal=%d\n", calVal); + } + break; + case BT_SET_TRACKING_INTERVAL: + RTW_INFO("[MPT], [BT_SET_TRACKING_INTERVAL] setParaLen =%d\n", setParaLen); + + validParaLen = 1; + if (setParaLen == validParaLen) + calVal = pBtReq->pParamStart[1]; + break; + case BT_SET_THERMAL_METER: + RTW_INFO("[MPT], [BT_SET_THERMAL_METER] setParaLen =%d\n", setParaLen); + validParaLen = 1; + if (setParaLen == validParaLen) + calVal = pBtReq->pParamStart[1]; + break; + case BT_ENABLE_CFO_TRACKING: + RTW_INFO("[MPT], [BT_ENABLE_CFO_TRACKING] setParaLen =%d\n", setParaLen); + validParaLen = 1; + if (setParaLen == validParaLen) + calVal = pBtReq->pParamStart[1]; + break; + case BT_GSET_UPDATE_BT_PATCH: + + break; + default: { + RTW_INFO("[MPT], Error!! setType=%d, out of range\n", setType); + pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } + break; + } + if (setParaLen != validParaLen) { + RTW_INFO("[MPT], Error!! wrong parameter length=%d for BT_SET_GEN_CMD cmd id=0x%x, paraLen should=0x%x\n", + setParaLen, setType, validParaLen); + pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; + return paraLen; + } + + /* */ + /* execute lower layer opcodes */ + /* */ + if (BT_GSET_REG == setType) { + /* fill h2c parameters */ + /* here we should write reg value first then write the address, adviced by Austin */ + btOpcode = BT_LO_OP_WRITE_REG_VALUE; + h2cParaBuf[0] = pBtReq->pParamStart[6]; + h2cParaBuf[1] = pBtReq->pParamStart[7]; + h2cParaBuf[2] = pBtReq->pParamStart[8]; + h2cParaLen = 3; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + /* write reg address */ + btOpcode = BT_LO_OP_WRITE_REG_ADDR; + h2cParaBuf[0] = regType; + h2cParaBuf[1] = pBtReq->pParamStart[2]; + h2cParaBuf[2] = pBtReq->pParamStart[3]; + h2cParaLen = 3; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + } else if (BT_GSET_RESET == setType) { + btOpcode = BT_LO_OP_RESET; + h2cParaLen = 0; + /* execute h2c and check respond c2h from bt fw is correct or not */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + } else if (BT_GSET_TARGET_BD_ADDR == setType) { + /* fill h2c parameters */ + btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_L; + h2cParaBuf[0] = pBtReq->pParamStart[1]; + h2cParaBuf[1] = pBtReq->pParamStart[2]; + h2cParaBuf[2] = pBtReq->pParamStart[3]; + h2cParaLen = 3; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + btOpcode = BT_LO_OP_SET_TARGET_BD_ADDR_H; + h2cParaBuf[0] = pBtReq->pParamStart[4]; + h2cParaBuf[1] = pBtReq->pParamStart[5]; + h2cParaBuf[2] = pBtReq->pParamStart[6]; + h2cParaLen = 3; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + } else if (BT_GSET_TX_PWR_FINETUNE == setType) { + /* fill h2c parameters */ + btOpcode = BT_LO_OP_SET_TX_POWER_CALIBRATION; + h2cParaBuf[0] = calVal; + h2cParaLen = 1; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + } else if (BT_SET_TRACKING_INTERVAL == setType) { + /* BT_LO_OP_SET_TRACKING_INTERVAL = 0x22, */ + /* BT_LO_OP_SET_THERMAL_METER = 0x23, */ + /* BT_LO_OP_ENABLE_CFO_TRACKING = 0x24, */ + btOpcode = BT_LO_OP_SET_TRACKING_INTERVAL; + h2cParaBuf[0] = calVal; + h2cParaLen = 1; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + } else if (BT_SET_THERMAL_METER == setType) { + btOpcode = BT_LO_OP_SET_THERMAL_METER; + h2cParaBuf[0] = calVal; + h2cParaLen = 1; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + } else if (BT_ENABLE_CFO_TRACKING == setType) { + btOpcode = BT_LO_OP_ENABLE_CFO_TRACKING; + h2cParaBuf[0] = calVal; + h2cParaLen = 1; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + } + + pBtRsp->status = BT_STATUS_SUCCESS; + return paraLen; +} + + + +u2Byte +mptbt_BtSetTxRxPars( + IN PADAPTER Adapter, + IN PBT_REQ_CMD pBtReq, + IN PBT_RSP_CMD pBtRsp +) +{ + u1Byte h2cParaBuf[6] = {0}; + u1Byte h2cParaLen = 0; + u2Byte paraLen = 0; + u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; + u1Byte btOpcode; + u1Byte btOpcodeVer = 0; + PBT_TXRX_PARAMETERS pTxRxPars = (PBT_TXRX_PARAMETERS)&pBtReq->pParamStart[0]; + u2Byte lenTxRx = sizeof(BT_TXRX_PARAMETERS); + u1Byte i; + u1Byte bdAddr[6] = {0}; + + /* */ + /* check upper layer parameters */ + /* */ + + /* 1. check upper layer opcode version */ + if (pBtReq->opCodeVer != 1) { + RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n"); + pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; + return paraLen; + } + /* 2. check upper layer parameter length */ + if (pBtReq->paraLength == sizeof(BT_TXRX_PARAMETERS)) { + RTW_INFO("[MPT], pTxRxPars->txrxChannel=0x%x\n", pTxRxPars->txrxChannel); + RTW_INFO("[MPT], pTxRxPars->txrxTxPktCnt=0x%8x\n", pTxRxPars->txrxTxPktCnt); + RTW_INFO("[MPT], pTxRxPars->txrxTxPktInterval=0x%x\n", pTxRxPars->txrxTxPktInterval); + RTW_INFO("[MPT], pTxRxPars->txrxPayloadType=0x%x\n", pTxRxPars->txrxPayloadType); + RTW_INFO("[MPT], pTxRxPars->txrxPktType=0x%x\n", pTxRxPars->txrxPktType); + RTW_INFO("[MPT], pTxRxPars->txrxPayloadLen=0x%x\n", pTxRxPars->txrxPayloadLen); + RTW_INFO("[MPT], pTxRxPars->txrxPktHeader=0x%x\n", pTxRxPars->txrxPktHeader); + RTW_INFO("[MPT], pTxRxPars->txrxWhitenCoeff=0x%x\n", pTxRxPars->txrxWhitenCoeff); + bdAddr[0] = pTxRxPars->txrxBdaddr[5]; + bdAddr[1] = pTxRxPars->txrxBdaddr[4]; + bdAddr[2] = pTxRxPars->txrxBdaddr[3]; + bdAddr[3] = pTxRxPars->txrxBdaddr[2]; + bdAddr[4] = pTxRxPars->txrxBdaddr[1]; + bdAddr[5] = pTxRxPars->txrxBdaddr[0]; + RTW_INFO("[MPT], pTxRxPars->txrxBdaddr: %s", &bdAddr[0]); + RTW_INFO("[MPT], pTxRxPars->txrxTxGainIndex=0x%x\n", pTxRxPars->txrxTxGainIndex); + } else { + RTW_INFO("[MPT], Error!! pBtReq->paraLength=%d, correct Len=%d\n", pBtReq->paraLength, lenTxRx); + pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; + return paraLen; + } + + /* */ + /* execute lower layer opcodes */ + /* */ + + /* fill h2c parameters */ + btOpcode = BT_LO_OP_SET_PKT_HEADER; + if (pTxRxPars->txrxPktHeader > 0x3ffff) { + RTW_INFO("[MPT], Error!! pTxRxPars->txrxPktHeader=0x%x is out of range, (should be between 0x0~0x3ffff)\n", pTxRxPars->txrxPktHeader); + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } else { + h2cParaBuf[0] = (u1Byte)(pTxRxPars->txrxPktHeader & 0xff); + h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxPktHeader & 0xff00) >> 8); + h2cParaBuf[2] = (u1Byte)((pTxRxPars->txrxPktHeader & 0xff0000) >> 16); + h2cParaLen = 3; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + } + + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + /* fill h2c parameters */ + btOpcode = BT_LO_OP_SET_PKT_TYPE_LEN; + { + u2Byte payloadLenLimit = 0; + switch (pTxRxPars->txrxPktType) { + case MP_BT_PKT_DH1: + payloadLenLimit = 27 * 8; + break; + case MP_BT_PKT_DH3: + payloadLenLimit = 183 * 8; + break; + case MP_BT_PKT_DH5: + payloadLenLimit = 339 * 8; + break; + case MP_BT_PKT_2DH1: + payloadLenLimit = 54 * 8; + break; + case MP_BT_PKT_2DH3: + payloadLenLimit = 367 * 8; + break; + case MP_BT_PKT_2DH5: + payloadLenLimit = 679 * 8; + break; + case MP_BT_PKT_3DH1: + payloadLenLimit = 83 * 8; + break; + case MP_BT_PKT_3DH3: + payloadLenLimit = 552 * 8; + break; + case MP_BT_PKT_3DH5: + payloadLenLimit = 1021 * 8; + break; + case MP_BT_PKT_LE: + payloadLenLimit = 39 * 8; + break; + default: { + RTW_INFO("[MPT], Error!! Unknown pTxRxPars->txrxPktType=0x%x\n", pTxRxPars->txrxPktType); + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } + break; + } + + if (pTxRxPars->txrxPayloadLen > payloadLenLimit) { + RTW_INFO("[MPT], Error!! pTxRxPars->txrxPayloadLen=0x%x, (should smaller than %d)\n", + pTxRxPars->txrxPayloadLen, payloadLenLimit); + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } + + h2cParaBuf[0] = pTxRxPars->txrxPktType; + h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxPayloadLen & 0xff)); + h2cParaBuf[2] = (u1Byte)((pTxRxPars->txrxPayloadLen & 0xff00) >> 8); + h2cParaLen = 3; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + } + + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + /* fill h2c parameters */ + btOpcode = BT_LO_OP_SET_PKT_CNT_L_PL_TYPE; + if (pTxRxPars->txrxPayloadType > MP_BT_PAYLOAD_MAX) { + RTW_INFO("[MPT], Error!! pTxRxPars->txrxPayloadType=0x%x, (should be between 0~4)\n", pTxRxPars->txrxPayloadType); + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } else { + h2cParaBuf[0] = (u1Byte)((pTxRxPars->txrxTxPktCnt & 0xff)); + h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxTxPktCnt & 0xff00) >> 8); + h2cParaBuf[2] = pTxRxPars->txrxPayloadType; + h2cParaLen = 3; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + } + + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + /* fill h2c parameters */ + btOpcode = BT_LO_OP_SET_PKT_CNT_H_PKT_INTV; + if (pTxRxPars->txrxTxPktInterval > 15) { + RTW_INFO("[MPT], Error!! pTxRxPars->txrxTxPktInterval=0x%x, (should be between 0~15)\n", pTxRxPars->txrxTxPktInterval); + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } else { + h2cParaBuf[0] = (u1Byte)((pTxRxPars->txrxTxPktCnt & 0xff0000) >> 16); + h2cParaBuf[1] = (u1Byte)((pTxRxPars->txrxTxPktCnt & 0xff000000) >> 24); + h2cParaBuf[2] = pTxRxPars->txrxTxPktInterval; + h2cParaLen = 3; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + } + + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + /* fill h2c parameters */ + btOpcode = BT_LO_OP_SET_WHITENCOEFF; + { + h2cParaBuf[0] = pTxRxPars->txrxWhitenCoeff; + h2cParaLen = 1; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + } + + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + + /* fill h2c parameters */ + btOpcode = BT_LO_OP_SET_CHNL_TX_GAIN; + if ((pTxRxPars->txrxChannel > 78) || + (pTxRxPars->txrxTxGainIndex > 7)) { + RTW_INFO("[MPT], Error!! pTxRxPars->txrxChannel=0x%x, (should be between 0~78)\n", pTxRxPars->txrxChannel); + RTW_INFO("[MPT], Error!! pTxRxPars->txrxTxGainIndex=0x%x, (should be between 0~7)\n", pTxRxPars->txrxTxGainIndex); + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } else { + h2cParaBuf[0] = pTxRxPars->txrxChannel; + h2cParaBuf[1] = pTxRxPars->txrxTxGainIndex; + h2cParaLen = 2; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + } + + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + /* fill h2c parameters */ + btOpcode = BT_LO_OP_SET_BD_ADDR_L; + if ((pTxRxPars->txrxBdaddr[0] == 0) && + (pTxRxPars->txrxBdaddr[1] == 0) && + (pTxRxPars->txrxBdaddr[2] == 0) && + (pTxRxPars->txrxBdaddr[3] == 0) && + (pTxRxPars->txrxBdaddr[4] == 0) && + (pTxRxPars->txrxBdaddr[5] == 0)) { + RTW_INFO("[MPT], Error!! pTxRxPars->txrxBdaddr=all zero\n"); + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } + if ((pTxRxPars->txrxBdaddr[0] == 0xff) && + (pTxRxPars->txrxBdaddr[1] == 0xff) && + (pTxRxPars->txrxBdaddr[2] == 0xff) && + (pTxRxPars->txrxBdaddr[3] == 0xff) && + (pTxRxPars->txrxBdaddr[4] == 0xff) && + (pTxRxPars->txrxBdaddr[5] == 0xff)) { + RTW_INFO("[MPT], Error!! pTxRxPars->txrxBdaddr=all 0xf\n"); + pBtRsp->status = (btOpcode << 8) | BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } + + { + h2cParaBuf[0] = pTxRxPars->txrxBdaddr[0]; + h2cParaBuf[1] = pTxRxPars->txrxBdaddr[1]; + h2cParaBuf[2] = pTxRxPars->txrxBdaddr[2]; + h2cParaLen = 3; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + } + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + btOpcode = BT_LO_OP_SET_BD_ADDR_H; + { + h2cParaBuf[0] = pTxRxPars->txrxBdaddr[3]; + h2cParaBuf[1] = pTxRxPars->txrxBdaddr[4]; + h2cParaBuf[2] = pTxRxPars->txrxBdaddr[5]; + h2cParaLen = 3; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + } + /* ckeck bt return status. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + pBtRsp->status = BT_STATUS_SUCCESS; + return paraLen; +} + + + +u2Byte +mptbt_BtTestCtrl( + IN PADAPTER Adapter, + IN PBT_REQ_CMD pBtReq, + IN PBT_RSP_CMD pBtRsp +) +{ + u1Byte h2cParaBuf[6] = {0}; + u1Byte h2cParaLen = 0; + u2Byte paraLen = 0; + u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; + u1Byte btOpcode; + u1Byte btOpcodeVer = 0; + u1Byte testCtrl = 0; + + /* */ + /* check upper layer parameters */ + /* */ + + /* 1. check upper layer opcode version */ + if (pBtReq->opCodeVer != 1) { + RTW_INFO("[MPT], Error!! Upper OP code version not match!!!\n"); + pBtRsp->status = BT_STATUS_OPCODE_U_VERSION_MISMATCH; + return paraLen; + } + /* 2. check upper layer parameter length */ + if (1 == pBtReq->paraLength) { + testCtrl = pBtReq->pParamStart[0]; + RTW_INFO("[MPT], testCtrl=%d\n", testCtrl); + } else { + RTW_INFO("[MPT], Error!! wrong parameter length=%d (should be 1)\n", pBtReq->paraLength); + pBtRsp->status = BT_STATUS_PARAMETER_FORMAT_ERROR_U; + return paraLen; + } + + /* */ + /* execute lower layer opcodes */ + /* */ + + /* 1. fill h2c parameters */ + /* check bt mode */ + btOpcode = BT_LO_OP_TEST_CTRL; + if (testCtrl >= MP_BT_TEST_MAX) { + RTW_INFO("[MPT], Error!! testCtrl=0x%x, (should be between smaller or equal to 0x%x)\n", + testCtrl, MP_BT_TEST_MAX - 1); + pBtRsp->status = BT_STATUS_PARAMETER_OUT_OF_RANGE_U; + return paraLen; + } else { + h2cParaBuf[0] = testCtrl; + h2cParaLen = 1; + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); + } + + /* 3. construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + pBtRsp->status = BT_STATUS_SUCCESS; + return paraLen; +} + + +u2Byte +mptbt_TestBT( + IN PADAPTER Adapter, + IN PBT_REQ_CMD pBtReq, + IN PBT_RSP_CMD pBtRsp +) +{ + + u1Byte h2cParaBuf[6] = {0}; + u1Byte h2cParaLen = 0; + u2Byte paraLen = 0; + u1Byte retStatus = BT_STATUS_BT_OP_SUCCESS; + u1Byte btOpcode; + u1Byte btOpcodeVer = 0; + u1Byte testCtrl = 0; + + /* 1. fill h2c parameters */ + btOpcode = 0x11; + h2cParaBuf[0] = 0x11; + h2cParaBuf[1] = 0x0; + h2cParaBuf[2] = 0x0; + h2cParaBuf[3] = 0x0; + h2cParaBuf[4] = 0x0; + h2cParaLen = 1; + /* retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, &h2cParaBuf[0], h2cParaLen); */ + retStatus = mptbt_BtFwOpCodeProcess(Adapter, btOpcode, btOpcodeVer, h2cParaBuf, h2cParaLen); + + + /* 3. construct respond status code and data. */ + if (BT_STATUS_BT_OP_SUCCESS != retStatus) { + pBtRsp->status = ((btOpcode << 8) | retStatus); + RTW_INFO("[MPT], Error!! status code=0x%x\n", pBtRsp->status); + return paraLen; + } + + pBtRsp->status = BT_STATUS_SUCCESS; + return paraLen; +} + +VOID +mptbt_BtControlProcess( + PADAPTER Adapter, + PVOID pInBuf +) +{ + u1Byte H2C_Parameter[6] = {0}; + PBT_H2C pH2c = (PBT_H2C)&H2C_Parameter[0]; + PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); + PBT_REQ_CMD pBtReq = (PBT_REQ_CMD)pInBuf; + PBT_RSP_CMD pBtRsp; + u1Byte i; + + + RTW_INFO("[MPT], mptbt_BtControlProcess()=========>\n"); + + RTW_INFO("[MPT], input opCodeVer=%d\n", pBtReq->opCodeVer); + RTW_INFO("[MPT], input OpCode=%d\n", pBtReq->OpCode); + RTW_INFO("[MPT], paraLength=%d\n", pBtReq->paraLength); + if (pBtReq->paraLength) { + /* RTW_INFO("[MPT], parameters(hex):0x%x %d\n",&pBtReq->pParamStart[0], pBtReq->paraLength); */ + } + + _rtw_memset((void *)pMptCtx->mptOutBuf, 0, 100); + pMptCtx->mptOutLen = 4; /* length of (BT_RSP_CMD.status+BT_RSP_CMD.paraLength) */ + + pBtRsp = (PBT_RSP_CMD)pMptCtx->mptOutBuf; + pBtRsp->status = BT_STATUS_SUCCESS; + pBtRsp->paraLength = 0x0; + + /* The following we should maintain the User OP codes sent by upper layer */ + switch (pBtReq->OpCode) { + case BT_UP_OP_BT_READY: + RTW_INFO("[MPT], OPcode : [BT_READY]\n"); + pBtRsp->paraLength = mptbt_BtReady(Adapter, pBtReq, pBtRsp); + break; + case BT_UP_OP_BT_SET_MODE: + RTW_INFO("[MPT], OPcode : [BT_SET_MODE]\n"); + pBtRsp->paraLength = mptbt_BtSetMode(Adapter, pBtReq, pBtRsp); + break; + case BT_UP_OP_BT_SET_TX_RX_PARAMETER: + RTW_INFO("[MPT], OPcode : [BT_SET_TXRX_PARAMETER]\n"); + pBtRsp->paraLength = mptbt_BtSetTxRxPars(Adapter, pBtReq, pBtRsp); + break; + case BT_UP_OP_BT_SET_GENERAL: + RTW_INFO("[MPT], OPcode : [BT_SET_GENERAL]\n"); + pBtRsp->paraLength = mptbt_BtSetGeneral(Adapter, pBtReq, pBtRsp); + break; + case BT_UP_OP_BT_GET_GENERAL: + RTW_INFO("[MPT], OPcode : [BT_GET_GENERAL]\n"); + pBtRsp->paraLength = mptbt_BtGetGeneral(Adapter, pBtReq, pBtRsp); + break; + case BT_UP_OP_BT_TEST_CTRL: + RTW_INFO("[MPT], OPcode : [BT_TEST_CTRL]\n"); + pBtRsp->paraLength = mptbt_BtTestCtrl(Adapter, pBtReq, pBtRsp); + break; + case BT_UP_OP_TEST_BT: + RTW_INFO("[MPT], OPcode : [TEST_BT]\n"); + pBtRsp->paraLength = mptbt_TestBT(Adapter, pBtReq, pBtRsp); + break; + default: + RTW_INFO("[MPT], Error!! OPcode : UNDEFINED!!!!\n"); + pBtRsp->status = BT_STATUS_UNKNOWN_OPCODE_U; + pBtRsp->paraLength = 0x0; + break; + } + + pMptCtx->mptOutLen += pBtRsp->paraLength; + + RTW_INFO("[MPT], pMptCtx->mptOutLen=%d, pBtRsp->paraLength=%d\n", pMptCtx->mptOutLen, pBtRsp->paraLength); + RTW_INFO("[MPT], mptbt_BtControlProcess()<=========\n"); +} + +#endif diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_btcoex.c b/linux-bsp/drivers/rtl8188eus/core/rtw_btcoex.c new file mode 100644 index 0000000..7f37ff1 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_btcoex.c @@ -0,0 +1,1717 @@ +/****************************************************************************** + * + * Copyright(c) 2013 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifdef CONFIG_BT_COEXIST + +#include <drv_types.h> +#include <hal_btcoex.h> +#include <hal_data.h> + + +void rtw_btcoex_Initialize(PADAPTER padapter) +{ + hal_btcoex_Initialize(padapter); +} + +void rtw_btcoex_PowerOnSetting(PADAPTER padapter) +{ + hal_btcoex_PowerOnSetting(padapter); +} + +void rtw_btcoex_PreLoadFirmware(PADAPTER padapter) +{ + hal_btcoex_PreLoadFirmware(padapter); +} + +void rtw_btcoex_HAL_Initialize(PADAPTER padapter, u8 bWifiOnly) +{ + hal_btcoex_InitHwConfig(padapter, bWifiOnly); +} + +void rtw_btcoex_IpsNotify(PADAPTER padapter, u8 type) +{ + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + if (_FALSE == pHalData->EEPROMBluetoothCoexist) + return; + + hal_btcoex_IpsNotify(padapter, type); +} + +void rtw_btcoex_LpsNotify(PADAPTER padapter, u8 type) +{ + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + if (_FALSE == pHalData->EEPROMBluetoothCoexist) + return; + + hal_btcoex_LpsNotify(padapter, type); +} + +void rtw_btcoex_ScanNotify(PADAPTER padapter, u8 type) +{ + PHAL_DATA_TYPE pHalData; +#ifdef CONFIG_BT_COEXIST_SOCKET_TRX + struct bt_coex_info *pcoex_info = &padapter->coex_info; + PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; +#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ + + pHalData = GET_HAL_DATA(padapter); + if (_FALSE == pHalData->EEPROMBluetoothCoexist) + return; + + if (_FALSE == type) { + #ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_buddy_check_fwstate(padapter, WIFI_SITE_MONITOR)) + return; + #endif + + if (DEV_MGMT_TX_NUM(adapter_to_dvobj(padapter)) + || DEV_ROCH_NUM(adapter_to_dvobj(padapter))) + return; + } + +#ifdef CONFIG_BT_COEXIST_SOCKET_TRX + if (pBtMgnt->ExtConfig.bEnableWifiScanNotify) + rtw_btcoex_SendScanNotify(padapter, type); +#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ + + hal_btcoex_ScanNotify(padapter, type); +} + +void rtw_btcoex_ConnectNotify(PADAPTER padapter, u8 action) +{ + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + if (_FALSE == pHalData->EEPROMBluetoothCoexist) + return; + +#ifdef DBG_CONFIG_ERROR_RESET + if (_TRUE == rtw_hal_sreset_inprogress(padapter)) { + RTW_INFO(FUNC_ADPT_FMT ": [BTCoex] under reset, skip notify!\n", + FUNC_ADPT_ARG(padapter)); + return; + } +#endif /* DBG_CONFIG_ERROR_RESET */ + +#ifdef CONFIG_CONCURRENT_MODE + if (_FALSE == action) { + if (rtw_mi_buddy_check_fwstate(padapter, WIFI_UNDER_LINKING)) + return; + } +#endif + + hal_btcoex_ConnectNotify(padapter, action); +} + +void rtw_btcoex_MediaStatusNotify(PADAPTER padapter, u8 mediaStatus) +{ + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + if (_FALSE == pHalData->EEPROMBluetoothCoexist) + return; + +#ifdef DBG_CONFIG_ERROR_RESET + if (_TRUE == rtw_hal_sreset_inprogress(padapter)) { + RTW_INFO(FUNC_ADPT_FMT ": [BTCoex] under reset, skip notify!\n", + FUNC_ADPT_ARG(padapter)); + return; + } +#endif /* DBG_CONFIG_ERROR_RESET */ + +#ifdef CONFIG_CONCURRENT_MODE + if (RT_MEDIA_DISCONNECT == mediaStatus) { + if (rtw_mi_buddy_check_fwstate(padapter, WIFI_ASOC_STATE)) + return; + } +#endif /* CONFIG_CONCURRENT_MODE */ + + if ((RT_MEDIA_CONNECT == mediaStatus) + && (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE)) + rtw_hal_set_hwreg(padapter, HW_VAR_DL_RSVD_PAGE, NULL); + + hal_btcoex_MediaStatusNotify(padapter, mediaStatus); +} + +void rtw_btcoex_SpecialPacketNotify(PADAPTER padapter, u8 pktType) +{ + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + if (_FALSE == pHalData->EEPROMBluetoothCoexist) + return; + + hal_btcoex_SpecialPacketNotify(padapter, pktType); +} + +void rtw_btcoex_IQKNotify(PADAPTER padapter, u8 state) +{ + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + if (_FALSE == pHalData->EEPROMBluetoothCoexist) + return; + + hal_btcoex_IQKNotify(padapter, state); +} + +void rtw_btcoex_BtInfoNotify(PADAPTER padapter, u8 length, u8 *tmpBuf) +{ + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + if (_FALSE == pHalData->EEPROMBluetoothCoexist) + return; + + hal_btcoex_BtInfoNotify(padapter, length, tmpBuf); +} + +void rtw_btcoex_BtMpRptNotify(PADAPTER padapter, u8 length, u8 *tmpBuf) +{ + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + if (_FALSE == pHalData->EEPROMBluetoothCoexist) + return; + + if (padapter->registrypriv.mp_mode == 1) + return; + + hal_btcoex_BtMpRptNotify(padapter, length, tmpBuf); +} + +void rtw_btcoex_SuspendNotify(PADAPTER padapter, u8 state) +{ + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + if (_FALSE == pHalData->EEPROMBluetoothCoexist) + return; + + hal_btcoex_SuspendNotify(padapter, state); +} + +void rtw_btcoex_HaltNotify(PADAPTER padapter) +{ + PHAL_DATA_TYPE pHalData; + u8 do_halt = 1; + + pHalData = GET_HAL_DATA(padapter); + if (_FALSE == pHalData->EEPROMBluetoothCoexist) + do_halt = 0; + + if (_FALSE == padapter->bup) { + RTW_INFO(FUNC_ADPT_FMT ": bup=%d Skip!\n", + FUNC_ADPT_ARG(padapter), padapter->bup); + do_halt = 0; + } + + if (rtw_is_surprise_removed(padapter)) { + RTW_INFO(FUNC_ADPT_FMT ": bSurpriseRemoved=%s Skip!\n", + FUNC_ADPT_ARG(padapter), rtw_is_surprise_removed(padapter) ? "True" : "False"); + do_halt = 0; + } + + hal_btcoex_HaltNotify(padapter, do_halt); +} + +void rtw_btcoex_switchband_notify(u8 under_scan, u8 band_type) +{ + hal_btcoex_switchband_notify(under_scan, band_type); +} + +void rtw_btcoex_SwitchBtTRxMask(PADAPTER padapter) +{ + hal_btcoex_SwitchBtTRxMask(padapter); +} + +void rtw_btcoex_Switch(PADAPTER padapter, u8 enable) +{ + hal_btcoex_SetBTCoexist(padapter, enable); +} + +u8 rtw_btcoex_IsBtDisabled(PADAPTER padapter) +{ + return hal_btcoex_IsBtDisabled(padapter); +} + +void rtw_btcoex_Handler(PADAPTER padapter) +{ + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + + if (_FALSE == pHalData->EEPROMBluetoothCoexist) + return; + + hal_btcoex_Hanlder(padapter); +} + +s32 rtw_btcoex_IsBTCoexRejectAMPDU(PADAPTER padapter) +{ + s32 coexctrl; + + coexctrl = hal_btcoex_IsBTCoexRejectAMPDU(padapter); + + return coexctrl; +} + +s32 rtw_btcoex_IsBTCoexCtrlAMPDUSize(PADAPTER padapter) +{ + s32 coexctrl; + + coexctrl = hal_btcoex_IsBTCoexCtrlAMPDUSize(padapter); + + return coexctrl; +} + +u32 rtw_btcoex_GetAMPDUSize(PADAPTER padapter) +{ + u32 size; + + size = hal_btcoex_GetAMPDUSize(padapter); + + return size; +} + +void rtw_btcoex_SetManualControl(PADAPTER padapter, u8 manual) +{ + if (_TRUE == manual) + hal_btcoex_SetManualControl(padapter, _TRUE); + else + hal_btcoex_SetManualControl(padapter, _FALSE); +} + +u8 rtw_btcoex_1Ant(PADAPTER padapter) +{ + return hal_btcoex_1Ant(padapter); +} + +u8 rtw_btcoex_IsBtControlLps(PADAPTER padapter) +{ + return hal_btcoex_IsBtControlLps(padapter); +} + +u8 rtw_btcoex_IsLpsOn(PADAPTER padapter) +{ + return hal_btcoex_IsLpsOn(padapter); +} + +u8 rtw_btcoex_RpwmVal(PADAPTER padapter) +{ + return hal_btcoex_RpwmVal(padapter); +} + +u8 rtw_btcoex_LpsVal(PADAPTER padapter) +{ + return hal_btcoex_LpsVal(padapter); +} + +u32 rtw_btcoex_GetRaMask(PADAPTER padapter) +{ + return hal_btcoex_GetRaMask(padapter); +} + +void rtw_btcoex_RecordPwrMode(PADAPTER padapter, u8 *pCmdBuf, u8 cmdLen) +{ + hal_btcoex_RecordPwrMode(padapter, pCmdBuf, cmdLen); +} + +void rtw_btcoex_DisplayBtCoexInfo(PADAPTER padapter, u8 *pbuf, u32 bufsize) +{ + hal_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize); +} + +void rtw_btcoex_SetDBG(PADAPTER padapter, u32 *pDbgModule) +{ + hal_btcoex_SetDBG(padapter, pDbgModule); +} + +u32 rtw_btcoex_GetDBG(PADAPTER padapter, u8 *pStrBuf, u32 bufSize) +{ + return hal_btcoex_GetDBG(padapter, pStrBuf, bufSize); +} + +u8 rtw_btcoex_IncreaseScanDeviceNum(PADAPTER padapter) +{ + return hal_btcoex_IncreaseScanDeviceNum(padapter); +} + +u8 rtw_btcoex_IsBtLinkExist(PADAPTER padapter) +{ + return hal_btcoex_IsBtLinkExist(padapter); +} + +void rtw_btcoex_SetBtPatchVersion(PADAPTER padapter, u16 btHciVer, u16 btPatchVer) +{ + hal_btcoex_SetBtPatchVersion(padapter, btHciVer, btPatchVer); +} + +void rtw_btcoex_SetHciVersion(PADAPTER padapter, u16 hciVersion) +{ + hal_btcoex_SetHciVersion(padapter, hciVersion); +} + +void rtw_btcoex_StackUpdateProfileInfo(void) +{ + hal_btcoex_StackUpdateProfileInfo(); +} + +void rtw_btcoex_pta_off_on_notify(PADAPTER padapter, u8 bBTON) +{ + hal_btcoex_pta_off_on_notify(padapter, bBTON); +} + +/* ================================================== + * Below Functions are called by BT-Coex + * ================================================== */ +void rtw_btcoex_rx_ampdu_apply(PADAPTER padapter) +{ + rtw_rx_ampdu_apply(padapter); +} + +void rtw_btcoex_LPS_Enter(PADAPTER padapter) +{ + struct pwrctrl_priv *pwrpriv; + u8 lpsVal; + + + pwrpriv = adapter_to_pwrctl(padapter); + + pwrpriv->bpower_saving = _TRUE; + lpsVal = rtw_btcoex_LpsVal(padapter); + rtw_set_ps_mode(padapter, PS_MODE_MIN, 0, lpsVal, "BTCOEX"); +} + +void rtw_btcoex_LPS_Leave(PADAPTER padapter) +{ + struct pwrctrl_priv *pwrpriv; + + + pwrpriv = adapter_to_pwrctl(padapter); + + if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { + rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "BTCOEX"); + LPS_RF_ON_check(padapter, 100); + pwrpriv->bpower_saving = _FALSE; + } +} + +u16 rtw_btcoex_btreg_read(PADAPTER padapter, u8 type, u16 addr, u32 *data) +{ + return hal_btcoex_btreg_read(padapter, type, addr, data); +} + +u16 rtw_btcoex_btreg_write(PADAPTER padapter, u8 type, u16 addr, u16 val) +{ + return hal_btcoex_btreg_write(padapter, type, addr, val); +} + +u8 rtw_btcoex_get_bt_coexist(PADAPTER padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + return pHalData->EEPROMBluetoothCoexist; +} + +u8 rtw_btcoex_get_chip_type(PADAPTER padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + return pHalData->EEPROMBluetoothType; +} + +u8 rtw_btcoex_get_pg_ant_num(PADAPTER padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + return pHalData->EEPROMBluetoothAntNum == Ant_x2 ? 2 : 1; +} + +u8 rtw_btcoex_get_pg_single_ant_path(PADAPTER padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + return pHalData->ant_path; +} + +u8 rtw_btcoex_get_pg_rfe_type(PADAPTER padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + return pHalData->rfe_type; +} + +u8 rtw_btcoex_is_tfbga_package_type(PADAPTER padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + +#ifdef CONFIG_RTL8723B + if ((pHalData->PackageType == PACKAGE_TFBGA79) || (pHalData->PackageType == PACKAGE_TFBGA80) + || (pHalData->PackageType == PACKAGE_TFBGA90)) + return _TRUE; +#endif + + return _FALSE; +} + +u8 rtw_btcoex_get_ant_div_cfg(PADAPTER padapter) +{ + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + + return (pHalData->AntDivCfg == 0) ? _FALSE : _TRUE; +} + +/* ================================================== + * Below Functions are BT-Coex socket related function + * ================================================== */ + +#ifdef CONFIG_BT_COEXIST_SOCKET_TRX +_adapter *pbtcoexadapter; /* = NULL; */ /* do not initialise globals to 0 or NULL */ +u8 rtw_btcoex_btinfo_cmd(_adapter *adapter, u8 *buf, u16 len) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + u8 *btinfo; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + u8 res = _SUCCESS; + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + btinfo = rtw_zmalloc(len); + if (btinfo == NULL) { + rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); + rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = BTINFO_WK_CID; + pdrvextra_cmd_parm->type = 0; + pdrvextra_cmd_parm->size = len; + pdrvextra_cmd_parm->pbuf = btinfo; + + _rtw_memcpy(btinfo, buf, len); + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + return res; +} + +u8 rtw_btcoex_send_event_to_BT(_adapter *padapter, u8 status, u8 event_code, u8 opcode_low, u8 opcode_high, u8 *dbg_msg) +{ + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0, tx_event_length = 0; + rtw_HCI_event *pEvent; + + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + pEvent->EventCode = event_code; + pEvent->Data[0] = 0x1; /* packet # */ + pEvent->Data[1] = opcode_low; + pEvent->Data[2] = opcode_high; + len = len + 3; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len++; + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; +#if 0 + rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, dbg_msg); +#endif + status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + + return status; +} + +/* +Ref: +Realtek Wi-Fi Driver +Host Controller Interface for +Bluetooth 3.0 + HS V1.4 2013/02/07 + +Window team code & BT team code + */ + + +u8 rtw_btcoex_parse_BT_info_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) +{ +#define BT_INFO_LENGTH 8 + + u8 curPollEnable = pcmd[0]; + u8 curPollTime = pcmd[1]; + u8 btInfoReason = pcmd[2]; + u8 btInfoLen = pcmd[3]; + u8 btinfo[BT_INFO_LENGTH]; + + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0, tx_event_length = 0; + RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; + rtw_HCI_event *pEvent; + + /* RTW_INFO("%s\n",__func__); + RTW_INFO("current Poll Enable: %d, currrent Poll Time: %d\n",curPollEnable,curPollTime); + RTW_INFO("BT Info reason: %d, BT Info length: %d\n",btInfoReason,btInfoLen); + RTW_INFO("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n" + ,pcmd[4],pcmd[5],pcmd[6],pcmd[7],pcmd[8],pcmd[9],pcmd[10],pcmd[11]);*/ + + _rtw_memset(btinfo, 0, BT_INFO_LENGTH); + +#if 1 + if (BT_INFO_LENGTH != btInfoLen) { + status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE; + RTW_INFO("Error BT Info Length: %d\n", btInfoLen); + /* return _FAIL; */ + } else +#endif + { + if (0x1 == btInfoReason || 0x2 == btInfoReason) { + _rtw_memcpy(btinfo, &pcmd[4], btInfoLen); + btinfo[0] = btInfoReason; + rtw_btcoex_btinfo_cmd(padapter, btinfo, btInfoLen); + } else + RTW_INFO("Other BT info reason\n"); + } + + /* send complete event to BT */ + { + + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; + pEvent->Data[0] = 0x1; /* packet # */ + pEvent->Data[1] = HCIOPCODELOW(HCI_BT_INFO_NOTIFY, OGF_EXTENSION); + pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_INFO_NOTIFY, OGF_EXTENSION); + len = len + 3; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len++; + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; +#if 0 + rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT_info_event"); +#endif + status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + + return status; + /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ + } +} + +u8 rtw_btcoex_parse_BT_patch_ver_info_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) +{ + RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; + u16 btPatchVer = 0x0, btHciVer = 0x0; + /* u16 *pU2tmp; */ + + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0, tx_event_length = 0; + rtw_HCI_event *pEvent; + + btHciVer = pcmd[0] | pcmd[1] << 8; + btPatchVer = pcmd[2] | pcmd[3] << 8; + + + RTW_INFO("%s, cmd:%02x %02x %02x %02x\n", __func__, pcmd[0] , pcmd[1] , pcmd[2] , pcmd[3]); + RTW_INFO("%s, HCI Ver:%d, Patch Ver:%d\n", __func__, btHciVer, btPatchVer); + + rtw_btcoex_SetBtPatchVersion(padapter, btHciVer, btPatchVer); + + + /* send complete event to BT */ + { + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + + pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; + pEvent->Data[0] = 0x1; /* packet # */ + pEvent->Data[1] = HCIOPCODELOW(HCI_BT_PATCH_VERSION_NOTIFY, OGF_EXTENSION); + pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_PATCH_VERSION_NOTIFY, OGF_EXTENSION); + len = len + 3; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len++; + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; +#if 0 + rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT_patch_event"); +#endif + status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + return status; + /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ + } +} + +u8 rtw_btcoex_parse_HCI_Ver_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) +{ + RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; + u16 hciver = pcmd[0] | pcmd[1] << 8; + + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0, tx_event_length = 0; + rtw_HCI_event *pEvent; + + struct bt_coex_info *pcoex_info = &padapter->coex_info; + PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; + pBtMgnt->ExtConfig.HCIExtensionVer = hciver; + RTW_INFO("%s, HCI Version: %d\n", __func__, pBtMgnt->ExtConfig.HCIExtensionVer); + if (pBtMgnt->ExtConfig.HCIExtensionVer < 4) { + status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE; + RTW_INFO("%s, Version = %d, HCI Version < 4\n", __func__, pBtMgnt->ExtConfig.HCIExtensionVer); + } else + rtw_btcoex_SetHciVersion(padapter, hciver); + /* send complete event to BT */ + { + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + + pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; + pEvent->Data[0] = 0x1; /* packet # */ + pEvent->Data[1] = HCIOPCODELOW(HCI_EXTENSION_VERSION_NOTIFY, OGF_EXTENSION); + pEvent->Data[2] = HCIOPCODEHIGHT(HCI_EXTENSION_VERSION_NOTIFY, OGF_EXTENSION); + len = len + 3; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len++; + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; + + status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + return status; + /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ + } + +} + +u8 rtw_btcoex_parse_WIFI_scan_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) +{ + RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; + + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0, tx_event_length = 0; + rtw_HCI_event *pEvent; + + struct bt_coex_info *pcoex_info = &padapter->coex_info; + PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; + pBtMgnt->ExtConfig.bEnableWifiScanNotify = pcmd[0]; + RTW_INFO("%s, bEnableWifiScanNotify: %d\n", __func__, pBtMgnt->ExtConfig.bEnableWifiScanNotify); + + /* send complete event to BT */ + { + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + + pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; + pEvent->Data[0] = 0x1; /* packet # */ + pEvent->Data[1] = HCIOPCODELOW(HCI_ENABLE_WIFI_SCAN_NOTIFY, OGF_EXTENSION); + pEvent->Data[2] = HCIOPCODEHIGHT(HCI_ENABLE_WIFI_SCAN_NOTIFY, OGF_EXTENSION); + len = len + 3; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len++; + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; + + status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + return status; + /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ + } +} + +u8 rtw_btcoex_parse_HCI_link_status_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) +{ + RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; + struct bt_coex_info *pcoex_info = &padapter->coex_info; + PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; + /* PBT_DBG pBtDbg=&padapter->MgntInfo.BtInfo.BtDbg; */ + u8 i, numOfHandle = 0, numOfAcl = 0; + u16 conHandle; + u8 btProfile, btCoreSpec, linkRole; + u8 *pTriple; + + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0, tx_event_length = 0; + rtw_HCI_event *pEvent; + + /* pBtDbg->dbgHciInfo.hciCmdCntLinkStatusNotify++; */ + /* RT_DISP_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "LinkStatusNotify, Hex Data :\n", */ + /* &pHciCmd->Data[0], pHciCmd->Length); */ + + RTW_INFO("BTLinkStatusNotify\n"); + + /* Current only RTL8723 support this command. */ + /* pBtMgnt->bSupportProfile = TRUE; */ + pBtMgnt->bSupportProfile = _FALSE; + + pBtMgnt->ExtConfig.NumberOfACL = 0; + pBtMgnt->ExtConfig.NumberOfSCO = 0; + + numOfHandle = pcmd[0]; + /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, ("numOfHandle = 0x%x\n", numOfHandle)); */ + /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCIExtensionVer = %d\n", pBtMgnt->ExtConfig.HCIExtensionVer)); */ + RTW_INFO("numOfHandle = 0x%x\n", numOfHandle); + RTW_INFO("HCIExtensionVer = %d\n", pBtMgnt->ExtConfig.HCIExtensionVer); + + pTriple = &pcmd[1]; + for (i = 0; i < numOfHandle; i++) { + if (pBtMgnt->ExtConfig.HCIExtensionVer < 1) { + conHandle = *((u8 *)&pTriple[0]); + btProfile = pTriple[2]; + btCoreSpec = pTriple[3]; + if (BT_PROFILE_SCO == btProfile) + pBtMgnt->ExtConfig.NumberOfSCO++; + else { + pBtMgnt->ExtConfig.NumberOfACL++; + pBtMgnt->ExtConfig.aclLink[i].ConnectHandle = conHandle; + pBtMgnt->ExtConfig.aclLink[i].BTProfile = btProfile; + pBtMgnt->ExtConfig.aclLink[i].BTCoreSpec = btCoreSpec; + } + /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, */ + /* ("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d\n", */ + /* conHandle, btProfile, btCoreSpec)); */ + RTW_INFO("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d\n", conHandle, btProfile, btCoreSpec); + pTriple += 4; + } else if (pBtMgnt->ExtConfig.HCIExtensionVer >= 1) { + conHandle = *((pu2Byte)&pTriple[0]); + btProfile = pTriple[2]; + btCoreSpec = pTriple[3]; + linkRole = pTriple[4]; + if (BT_PROFILE_SCO == btProfile) + pBtMgnt->ExtConfig.NumberOfSCO++; + else { + pBtMgnt->ExtConfig.NumberOfACL++; + pBtMgnt->ExtConfig.aclLink[i].ConnectHandle = conHandle; + pBtMgnt->ExtConfig.aclLink[i].BTProfile = btProfile; + pBtMgnt->ExtConfig.aclLink[i].BTCoreSpec = btCoreSpec; + pBtMgnt->ExtConfig.aclLink[i].linkRole = linkRole; + } + /* RT_DISP(FIOCTL, IOCTL_BT_HCICMD_EXT, */ + RTW_INFO("Connection_Handle=0x%x, BTProfile=%d, BTSpec=%d, LinkRole=%d\n", + conHandle, btProfile, btCoreSpec, linkRole); + pTriple += 5; + } + } + rtw_btcoex_StackUpdateProfileInfo(); + + /* send complete event to BT */ + { + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + + pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; + pEvent->Data[0] = 0x1; /* packet # */ + pEvent->Data[1] = HCIOPCODELOW(HCI_LINK_STATUS_NOTIFY, OGF_EXTENSION); + pEvent->Data[2] = HCIOPCODEHIGHT(HCI_LINK_STATUS_NOTIFY, OGF_EXTENSION); + len = len + 3; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len++; + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; + + status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + return status; + /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ + } + + +} + +u8 rtw_btcoex_parse_HCI_BT_coex_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) +{ + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0, tx_event_length = 0; + rtw_HCI_event *pEvent; + RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; + + { + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + + pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; + pEvent->Data[0] = 0x1; /* packet # */ + pEvent->Data[1] = HCIOPCODELOW(HCI_BT_COEX_NOTIFY, OGF_EXTENSION); + pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_COEX_NOTIFY, OGF_EXTENSION); + len = len + 3; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len++; + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; + + status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + return status; + /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ + } +} + +u8 rtw_btcoex_parse_HCI_BT_operation_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) +{ + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0, tx_event_length = 0; + rtw_HCI_event *pEvent; + RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; + + RTW_INFO("%s, OP code: %d\n", __func__, pcmd[0]); + + switch (pcmd[0]) { + case HCI_BT_OP_NONE: + RTW_INFO("[bt operation] : Operation None!!\n"); + break; + case HCI_BT_OP_INQUIRY_START: + RTW_INFO("[bt operation] : Inquiry start!!\n"); + break; + case HCI_BT_OP_INQUIRY_FINISH: + RTW_INFO("[bt operation] : Inquiry finished!!\n"); + break; + case HCI_BT_OP_PAGING_START: + RTW_INFO("[bt operation] : Paging is started!!\n"); + break; + case HCI_BT_OP_PAGING_SUCCESS: + RTW_INFO("[bt operation] : Paging complete successfully!!\n"); + break; + case HCI_BT_OP_PAGING_UNSUCCESS: + RTW_INFO("[bt operation] : Paging complete unsuccessfully!!\n"); + break; + case HCI_BT_OP_PAIRING_START: + RTW_INFO("[bt operation] : Pairing start!!\n"); + break; + case HCI_BT_OP_PAIRING_FINISH: + RTW_INFO("[bt operation] : Pairing finished!!\n"); + break; + case HCI_BT_OP_BT_DEV_ENABLE: + RTW_INFO("[bt operation] : BT Device is enabled!!\n"); + break; + case HCI_BT_OP_BT_DEV_DISABLE: + RTW_INFO("[bt operation] : BT Device is disabled!!\n"); + break; + default: + RTW_INFO("[bt operation] : Unknown, error!!\n"); + break; + } + + /* send complete event to BT */ + { + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + + pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; + pEvent->Data[0] = 0x1; /* packet # */ + pEvent->Data[1] = HCIOPCODELOW(HCI_BT_OPERATION_NOTIFY, OGF_EXTENSION); + pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_OPERATION_NOTIFY, OGF_EXTENSION); + len = len + 3; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len++; + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; + + status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + return status; + /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ + } +} + +u8 rtw_btcoex_parse_BT_AFH_MAP_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) +{ + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0, tx_event_length = 0; + rtw_HCI_event *pEvent; + RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; + + { + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + + pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; + pEvent->Data[0] = 0x1; /* packet # */ + pEvent->Data[1] = HCIOPCODELOW(HCI_BT_AFH_MAP_NOTIFY, OGF_EXTENSION); + pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_AFH_MAP_NOTIFY, OGF_EXTENSION); + len = len + 3; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len++; + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; + + status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + return status; + /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ + } +} + +u8 rtw_btcoex_parse_BT_register_val_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) +{ + + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0, tx_event_length = 0; + rtw_HCI_event *pEvent; + RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; + + { + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + + pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; + pEvent->Data[0] = 0x1; /* packet # */ + pEvent->Data[1] = HCIOPCODELOW(HCI_BT_REGISTER_VALUE_NOTIFY, OGF_EXTENSION); + pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_REGISTER_VALUE_NOTIFY, OGF_EXTENSION); + len = len + 3; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len++; + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; + + status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + return status; + /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ + } +} + +u8 rtw_btcoex_parse_HCI_BT_abnormal_notify_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) +{ + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0, tx_event_length = 0; + rtw_HCI_event *pEvent; + RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; + + { + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + + pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; + pEvent->Data[0] = 0x1; /* packet # */ + pEvent->Data[1] = HCIOPCODELOW(HCI_BT_ABNORMAL_NOTIFY, OGF_EXTENSION); + pEvent->Data[2] = HCIOPCODEHIGHT(HCI_BT_ABNORMAL_NOTIFY, OGF_EXTENSION); + len = len + 3; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len++; + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; + + status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + return status; + /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ + } +} + +u8 rtw_btcoex_parse_HCI_query_RF_status_cmd(_adapter *padapter, u8 *pcmd, u16 cmdlen) +{ + u8 localBuf[6] = ""; + u8 *pRetPar; + u8 len = 0, tx_event_length = 0; + rtw_HCI_event *pEvent; + RTW_HCI_STATUS status = HCI_STATUS_SUCCESS; + + { + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + + pEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE; + pEvent->Data[0] = 0x1; /* packet # */ + pEvent->Data[1] = HCIOPCODELOW(HCI_QUERY_RF_STATUS, OGF_EXTENSION); + pEvent->Data[2] = HCIOPCODEHIGHT(HCI_QUERY_RF_STATUS, OGF_EXTENSION); + len = len + 3; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + pRetPar[0] = status; /* status */ + + len++; + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; + + status = rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + return status; + /* bthci_IndicateEvent(Adapter, PPacketIrpEvent, len+2); */ + } +} + +/***************************************** +* HCI cmd format : +*| 15 - 0 | +*| OPcode (OCF|OGF<<10) | +*| 15 - 8 |7 - 0 | +*|Cmd para |Cmd para Length | +*|Cmd para...... | +******************************************/ + +/* bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + * | OCF | OGF | */ +void rtw_btcoex_parse_hci_extend_cmd(_adapter *padapter, u8 *pcmd, u16 len, const u16 hci_OCF) +{ + + RTW_INFO("%s: OCF: %x\n", __func__, hci_OCF); + switch (hci_OCF) { + case HCI_EXTENSION_VERSION_NOTIFY: + RTW_INFO("HCI_EXTENSION_VERSION_NOTIFY\n"); + rtw_btcoex_parse_HCI_Ver_notify_cmd(padapter, pcmd, len); + break; + case HCI_LINK_STATUS_NOTIFY: + RTW_INFO("HCI_LINK_STATUS_NOTIFY\n"); + rtw_btcoex_parse_HCI_link_status_notify_cmd(padapter, pcmd, len); + break; + case HCI_BT_OPERATION_NOTIFY: + /* only for 8723a 2ant */ + RTW_INFO("HCI_BT_OPERATION_NOTIFY\n"); + rtw_btcoex_parse_HCI_BT_operation_notify_cmd(padapter, pcmd, len); + /* */ + break; + case HCI_ENABLE_WIFI_SCAN_NOTIFY: + RTW_INFO("HCI_ENABLE_WIFI_SCAN_NOTIFY\n"); + rtw_btcoex_parse_WIFI_scan_notify_cmd(padapter, pcmd, len); + break; + case HCI_QUERY_RF_STATUS: + /* only for 8723b 2ant */ + RTW_INFO("HCI_QUERY_RF_STATUS\n"); + rtw_btcoex_parse_HCI_query_RF_status_cmd(padapter, pcmd, len); + break; + case HCI_BT_ABNORMAL_NOTIFY: + RTW_INFO("HCI_BT_ABNORMAL_NOTIFY\n"); + rtw_btcoex_parse_HCI_BT_abnormal_notify_cmd(padapter, pcmd, len); + break; + case HCI_BT_INFO_NOTIFY: + RTW_INFO("HCI_BT_INFO_NOTIFY\n"); + rtw_btcoex_parse_BT_info_notify_cmd(padapter, pcmd, len); + break; + case HCI_BT_COEX_NOTIFY: + RTW_INFO("HCI_BT_COEX_NOTIFY\n"); + rtw_btcoex_parse_HCI_BT_coex_notify_cmd(padapter, pcmd, len); + break; + case HCI_BT_PATCH_VERSION_NOTIFY: + RTW_INFO("HCI_BT_PATCH_VERSION_NOTIFY\n"); + rtw_btcoex_parse_BT_patch_ver_info_cmd(padapter, pcmd, len); + break; + case HCI_BT_AFH_MAP_NOTIFY: + RTW_INFO("HCI_BT_AFH_MAP_NOTIFY\n"); + rtw_btcoex_parse_BT_AFH_MAP_notify_cmd(padapter, pcmd, len); + break; + case HCI_BT_REGISTER_VALUE_NOTIFY: + RTW_INFO("HCI_BT_REGISTER_VALUE_NOTIFY\n"); + rtw_btcoex_parse_BT_register_val_notify_cmd(padapter, pcmd, len); + break; + default: + RTW_INFO("ERROR!!! Unknown OCF: %x\n", hci_OCF); + break; + + } +} + +void rtw_btcoex_parse_hci_cmd(_adapter *padapter, u8 *pcmd, u16 len) +{ + u16 opcode = pcmd[0] | pcmd[1] << 8; + u16 hci_OGF = HCI_OGF(opcode); + u16 hci_OCF = HCI_OCF(opcode); + u8 cmdlen = len - 3; + u8 pare_len = pcmd[2]; + + RTW_INFO("%s OGF: %x,OCF: %x\n", __func__, hci_OGF, hci_OCF); + switch (hci_OGF) { + case OGF_EXTENSION: + RTW_INFO("HCI_EXTENSION_CMD_OGF\n"); + rtw_btcoex_parse_hci_extend_cmd(padapter, &pcmd[3], cmdlen, hci_OCF); + break; + default: + RTW_INFO("Other OGF: %x\n", hci_OGF); + break; + } +} + +u16 rtw_btcoex_parse_recv_data(u8 *msg, u8 msg_size) +{ + u8 cmp_msg1[32] = attend_ack; + u8 cmp_msg2[32] = leave_ack; + u8 cmp_msg3[32] = bt_leave; + u8 cmp_msg4[32] = invite_req; + u8 cmp_msg5[32] = attend_req; + u8 cmp_msg6[32] = invite_rsp; + u8 res = OTHER; + + if (_rtw_memcmp(cmp_msg1, msg, msg_size) == _TRUE) { + /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ + res = RX_ATTEND_ACK; + } else if (_rtw_memcmp(cmp_msg2, msg, msg_size) == _TRUE) { + /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ + res = RX_LEAVE_ACK; + } else if (_rtw_memcmp(cmp_msg3, msg, msg_size) == _TRUE) { + /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ + res = RX_BT_LEAVE; + } else if (_rtw_memcmp(cmp_msg4, msg, msg_size) == _TRUE) { + /*RTW_INFO("%s, msg:%s\n",__func__,msg);*/ + res = RX_INVITE_REQ; + } else if (_rtw_memcmp(cmp_msg5, msg, msg_size) == _TRUE) + res = RX_ATTEND_REQ; + else if (_rtw_memcmp(cmp_msg6, msg, msg_size) == _TRUE) + res = RX_INVITE_RSP; + else { + /*RTW_INFO("%s, %s\n", __func__, msg);*/ + res = OTHER; + } + + /*RTW_INFO("%s, res:%d\n", __func__, res);*/ + + return res; +} + +void rtw_btcoex_recvmsgbysocket(void *data) +{ + u8 recv_data[255]; + u8 tx_msg[255] = leave_ack; + u32 len = 0; + u16 recv_length = 0; + u16 parse_res = 0; +#if 0 + u8 para_len = 0, polling_enable = 0, poling_interval = 0, reason = 0, btinfo_len = 0; + u8 btinfo[BT_INFO_LEN] = {0}; +#endif + + struct bt_coex_info *pcoex_info = NULL; + struct sock *sk = NULL; + struct sk_buff *skb = NULL; + + /*RTW_INFO("%s\n",__func__);*/ + + if (pbtcoexadapter == NULL) { + RTW_INFO("%s: btcoexadapter NULL!\n", __func__); + return; + } + + pcoex_info = &pbtcoexadapter->coex_info; + sk = pcoex_info->sk_store; + + if (sk == NULL) { + RTW_INFO("%s: critical error when receive socket data!\n", __func__); + return; + } + + len = skb_queue_len(&sk->sk_receive_queue); + while (len > 0) { + skb = skb_dequeue(&sk->sk_receive_queue); + + /*important: cut the udp header from skb->data! header length is 8 byte*/ + recv_length = skb->len - 8; + _rtw_memset(recv_data, 0, sizeof(recv_data)); + _rtw_memcpy(recv_data, skb->data + 8, recv_length); + + parse_res = rtw_btcoex_parse_recv_data(recv_data, recv_length); +#if 0 + if (RX_ATTEND_ACK == parse_res) { + /* attend ack */ + pcoex_info->BT_attend = _TRUE; + RTW_INFO("RX_ATTEND_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); + } else if (RX_ATTEND_REQ == parse_res) { + /* attend req from BT */ + pcoex_info->BT_attend = _TRUE; + RTW_INFO("RX_BT_ATTEND_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); + rtw_btcoex_sendmsgbysocket(pbtcoexadapter, attend_ack, sizeof(attend_ack), _FALSE); + } else if (RX_INVITE_REQ == parse_res) { + /* invite req from BT */ + pcoex_info->BT_attend = _TRUE; + RTW_INFO("RX_INVITE_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); + rtw_btcoex_sendmsgbysocket(pbtcoexadapter, invite_rsp, sizeof(invite_rsp), _FALSE); + } else if (RX_INVITE_RSP == parse_res) { + /* invite rsp */ + pcoex_info->BT_attend = _TRUE; + RTW_INFO("RX_INVITE_RSP!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); + } else if (RX_LEAVE_ACK == parse_res) { + /* mean BT know wifi will leave */ + pcoex_info->BT_attend = _FALSE; + RTW_INFO("RX_LEAVE_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); + } else if (RX_BT_LEAVE == parse_res) { + /* BT leave */ + rtw_btcoex_sendmsgbysocket(pbtcoexadapter, leave_ack, sizeof(leave_ack), _FALSE); /* no ack */ + pcoex_info->BT_attend = _FALSE; + RTW_INFO("RX_BT_LEAVE!sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); + } else { + /* todo: check if recv data are really hci cmds */ + if (_TRUE == pcoex_info->BT_attend) + rtw_btcoex_parse_hci_cmd(pbtcoexadapter, recv_data, recv_length); + } +#endif + switch (parse_res) { + case RX_ATTEND_ACK: + /* attend ack */ + pcoex_info->BT_attend = _TRUE; + RTW_INFO("RX_ATTEND_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); + rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); + break; + + case RX_ATTEND_REQ: + pcoex_info->BT_attend = _TRUE; + RTW_INFO("RX_BT_ATTEND_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); + rtw_btcoex_sendmsgbysocket(pbtcoexadapter, attend_ack, sizeof(attend_ack), _FALSE); + rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); + break; + + case RX_INVITE_REQ: + /* invite req from BT */ + pcoex_info->BT_attend = _TRUE; + RTW_INFO("RX_INVITE_REQ!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); + rtw_btcoex_sendmsgbysocket(pbtcoexadapter, invite_rsp, sizeof(invite_rsp), _FALSE); + rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); + break; + + case RX_INVITE_RSP: + /*invite rsp*/ + pcoex_info->BT_attend = _TRUE; + RTW_INFO("RX_INVITE_RSP!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); + rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); + break; + + case RX_LEAVE_ACK: + /* mean BT know wifi will leave */ + pcoex_info->BT_attend = _FALSE; + RTW_INFO("RX_LEAVE_ACK!,sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); + rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); + break; + + case RX_BT_LEAVE: + /* BT leave */ + rtw_btcoex_sendmsgbysocket(pbtcoexadapter, leave_ack, sizeof(leave_ack), _FALSE); /* no ack */ + pcoex_info->BT_attend = _FALSE; + RTW_INFO("RX_BT_LEAVE!sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); + rtw_btcoex_pta_off_on_notify(pbtcoexadapter, pcoex_info->BT_attend); + break; + + default: + if (_TRUE == pcoex_info->BT_attend) + rtw_btcoex_parse_hci_cmd(pbtcoexadapter, recv_data, recv_length); + else + RTW_INFO("ERROR!! BT is UP\n"); + break; + + } + + len--; + kfree_skb(skb); + } +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) + void rtw_btcoex_recvmsg_init(struct sock *sk_in, s32 bytes) +#else + void rtw_btcoex_recvmsg_init(struct sock *sk_in) +#endif +{ + struct bt_coex_info *pcoex_info = NULL; + + if (pbtcoexadapter == NULL) { + RTW_INFO("%s: btcoexadapter NULL\n", __func__); + return; + } + pcoex_info = &pbtcoexadapter->coex_info; + pcoex_info->sk_store = sk_in; + if (pcoex_info->btcoex_wq != NULL) + queue_delayed_work(pcoex_info->btcoex_wq, &pcoex_info->recvmsg_work, 0); + else + RTW_INFO("%s: BTCOEX workqueue NULL\n", __func__); +} + +u8 rtw_btcoex_sendmsgbysocket(_adapter *padapter, u8 *msg, u8 msg_size, bool force) +{ + u8 error; + struct msghdr udpmsg; + mm_segment_t oldfs; + struct iovec iov; + struct bt_coex_info *pcoex_info = &padapter->coex_info; + + /* RTW_INFO("%s: msg:%s, force:%s\n", __func__, msg, force == _TRUE?"TRUE":"FALSE"); */ + if (_FALSE == force) { + if (_FALSE == pcoex_info->BT_attend) { + RTW_INFO("TX Blocked: WiFi-BT disconnected\n"); + return _FAIL; + } + } + + iov.iov_base = (void *)msg; + iov.iov_len = msg_size; + udpmsg.msg_name = &pcoex_info->bt_sockaddr; + udpmsg.msg_namelen = sizeof(struct sockaddr_in); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) + /* referece:sock_xmit in kernel code + * WRITE for sock_sendmsg, READ for sock_recvmsg + * third parameter for msg_iovlen + * last parameter for iov_len + */ + iov_iter_init(&udpmsg.msg_iter, WRITE, &iov, 1, msg_size); +#else + udpmsg.msg_iov = &iov; + udpmsg.msg_iovlen = 1; +#endif + udpmsg.msg_control = NULL; + udpmsg.msg_controllen = 0; + udpmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; + oldfs = get_fs(); + set_fs(KERNEL_DS); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) + error = sock_sendmsg(pcoex_info->udpsock, &udpmsg); +#else + error = sock_sendmsg(pcoex_info->udpsock, &udpmsg, msg_size); +#endif + set_fs(oldfs); + if (error < 0) { + RTW_INFO("Error when sendimg msg, error:%d\n", error); + return _FAIL; + } else + return _SUCCESS; +} + +u8 rtw_btcoex_create_kernel_socket(_adapter *padapter) +{ + s8 kernel_socket_err; + u8 tx_msg[255] = attend_req; + struct bt_coex_info *pcoex_info = &padapter->coex_info; + s32 sock_reuse = 1; + u8 status = _FAIL; + + RTW_INFO("%s CONNECT_PORT %d\n", __func__, CONNECT_PORT); + + if (NULL == pcoex_info) { + RTW_INFO("coex_info: NULL\n"); + status = _FAIL; + } + + kernel_socket_err = sock_create(PF_INET, SOCK_DGRAM, 0, &pcoex_info->udpsock); + + if (kernel_socket_err < 0) { + RTW_INFO("Error during creation of socket error:%d\n", kernel_socket_err); + status = _FAIL; + } else { + _rtw_memset(&(pcoex_info->wifi_sockaddr), 0, sizeof(pcoex_info->wifi_sockaddr)); + pcoex_info->wifi_sockaddr.sin_family = AF_INET; + pcoex_info->wifi_sockaddr.sin_port = htons(CONNECT_PORT); + pcoex_info->wifi_sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + _rtw_memset(&(pcoex_info->bt_sockaddr), 0, sizeof(pcoex_info->bt_sockaddr)); + pcoex_info->bt_sockaddr.sin_family = AF_INET; + pcoex_info->bt_sockaddr.sin_port = htons(CONNECT_PORT_BT); + pcoex_info->bt_sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + pcoex_info->sk_store = NULL; + kernel_socket_err = pcoex_info->udpsock->ops->bind(pcoex_info->udpsock, (struct sockaddr *)&pcoex_info->wifi_sockaddr, + sizeof(pcoex_info->wifi_sockaddr)); + if (kernel_socket_err == 0) { + RTW_INFO("binding socket success\n"); + pcoex_info->udpsock->sk->sk_data_ready = rtw_btcoex_recvmsg_init; + pcoex_info->sock_open |= KERNEL_SOCKET_OK; + pcoex_info->BT_attend = _FALSE; + RTW_INFO("WIFI sending attend_req\n"); + rtw_btcoex_sendmsgbysocket(padapter, attend_req, sizeof(attend_req), _TRUE); + status = _SUCCESS; + } else { + pcoex_info->BT_attend = _FALSE; + sock_release(pcoex_info->udpsock); /* bind fail release socket */ + RTW_INFO("Error binding socket: %d\n", kernel_socket_err); + status = _FAIL; + } + + } + + return status; +} + +void rtw_btcoex_close_kernel_socket(_adapter *padapter) +{ + struct bt_coex_info *pcoex_info = &padapter->coex_info; + if (pcoex_info->sock_open & KERNEL_SOCKET_OK) { + RTW_INFO("release kernel socket\n"); + sock_release(pcoex_info->udpsock); + pcoex_info->sock_open &= ~(KERNEL_SOCKET_OK); + if (_TRUE == pcoex_info->BT_attend) + pcoex_info->BT_attend = _FALSE; + + RTW_INFO("sock_open:%d, BT_attend:%d\n", pcoex_info->sock_open, pcoex_info->BT_attend); + } +} + +void rtw_btcoex_init_socket(_adapter *padapter) +{ + + u8 is_invite = _FALSE; + struct bt_coex_info *pcoex_info = &padapter->coex_info; + RTW_INFO("%s\n", __func__); + if (_FALSE == pcoex_info->is_exist) { + _rtw_memset(pcoex_info, 0, sizeof(struct bt_coex_info)); + pcoex_info->btcoex_wq = create_workqueue("BTCOEX"); + INIT_DELAYED_WORK(&pcoex_info->recvmsg_work, + (void *)rtw_btcoex_recvmsgbysocket); + pbtcoexadapter = padapter; + /* We expect BT is off if BT don't send ack to wifi */ + RTW_INFO("We expect BT is off if BT send ack to wifi\n"); + rtw_btcoex_pta_off_on_notify(pbtcoexadapter, _FALSE); + if (rtw_btcoex_create_kernel_socket(padapter) == _SUCCESS) + pcoex_info->is_exist = _TRUE; + else { + pcoex_info->is_exist = _FALSE; + pbtcoexadapter = NULL; + } + + RTW_INFO("%s: pbtcoexadapter:%p, coex_info->is_exist: %s\n" + , __func__, pbtcoexadapter, pcoex_info->is_exist == _TRUE ? "TRUE" : "FALSE"); + } +} + +void rtw_btcoex_close_socket(_adapter *padapter) +{ + struct bt_coex_info *pcoex_info = &padapter->coex_info; + + RTW_INFO("%s--coex_info->is_exist: %s, pcoex_info->BT_attend:%s\n" + , __func__, pcoex_info->is_exist == _TRUE ? "TRUE" : "FALSE", pcoex_info->BT_attend == _TRUE ? "TRUE" : "FALSE"); + + if (_TRUE == pcoex_info->is_exist) { + if (_TRUE == pcoex_info->BT_attend) { + /*inform BT wifi leave*/ + rtw_btcoex_sendmsgbysocket(padapter, wifi_leave, sizeof(wifi_leave), _FALSE); + msleep(50); + } + + if (pcoex_info->btcoex_wq != NULL) { + flush_workqueue(pcoex_info->btcoex_wq); + destroy_workqueue(pcoex_info->btcoex_wq); + } + + rtw_btcoex_close_kernel_socket(padapter); + pbtcoexadapter = NULL; + pcoex_info->is_exist = _FALSE; + } +} + +void rtw_btcoex_dump_tx_msg(u8 *tx_msg, u8 len, u8 *msg_name) +{ + u8 i = 0; + RTW_INFO("======> Msg name: %s\n", msg_name); + for (i = 0; i < len; i++) + printk("%02x ", tx_msg[i]); + printk("\n"); + RTW_INFO("Msg name: %s <======\n", msg_name); +} + +/* Porting from Windows team */ +void rtw_btcoex_SendEventExtBtCoexControl(PADAPTER padapter, u8 bNeedDbgRsp, u8 dataLen, void *pData) +{ + u8 len = 0, tx_event_length = 0; + u8 localBuf[32] = ""; + u8 *pRetPar; + u8 opCode = 0; + u8 *pInBuf = (pu1Byte)pData; + u8 *pOpCodeContent; + rtw_HCI_event *pEvent; + + opCode = pInBuf[0]; + + RTW_INFO("%s, OPCode:%02x\n", __func__, opCode); + + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + /* len += bthci_ExtensionEventHeaderRtk(&localBuf[0], */ + /* HCI_EVENT_EXT_BT_COEX_CONTROL); */ + pEvent->EventCode = HCI_EVENT_EXTENSION_RTK; + pEvent->Data[0] = HCI_EVENT_EXT_BT_COEX_CONTROL; /* extension event code */ + len++; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + _rtw_memcpy(&pRetPar[0], pData, dataLen); + + len += dataLen; + + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; +#if 0 + rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT COEX CONTROL", _FALSE); +#endif + rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + +} + +/* Porting from Windows team */ +void rtw_btcoex_SendEventExtBtInfoControl(PADAPTER padapter, u8 dataLen, void *pData) +{ + rtw_HCI_event *pEvent; + u8 *pRetPar; + u8 len = 0, tx_event_length = 0; + u8 localBuf[32] = ""; + + struct bt_coex_info *pcoex_info = &padapter->coex_info; + PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; + + /* RTW_INFO("%s\n",__func__);*/ + if (pBtMgnt->ExtConfig.HCIExtensionVer < 4) { /* not support */ + RTW_INFO("ERROR: HCIExtensionVer = %d, HCIExtensionVer<4 !!!!\n", pBtMgnt->ExtConfig.HCIExtensionVer); + return; + } + + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + /* len += bthci_ExtensionEventHeaderRtk(&localBuf[0], */ + /* HCI_EVENT_EXT_BT_INFO_CONTROL); */ + pEvent->EventCode = HCI_EVENT_EXTENSION_RTK; + pEvent->Data[0] = HCI_EVENT_EXT_BT_INFO_CONTROL; /* extension event code */ + len++; + + /* Return parameters starts from here */ + pRetPar = &pEvent->Data[len]; + _rtw_memcpy(&pRetPar[0], pData, dataLen); + + len += dataLen; + + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; +#if 0 + rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "BT INFO CONTROL"); +#endif + rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); + +} + +void rtw_btcoex_SendScanNotify(PADAPTER padapter, u8 scanType) +{ + u8 len = 0, tx_event_length = 0; + u8 localBuf[7] = ""; + u8 *pRetPar; + u8 *pu1Temp; + rtw_HCI_event *pEvent; + struct bt_coex_info *pcoex_info = &padapter->coex_info; + PBT_MGNT pBtMgnt = &pcoex_info->BtMgnt; + + /* if(!pBtMgnt->BtOperationOn) + * return; */ + + pEvent = (rtw_HCI_event *)(&localBuf[0]); + + /* len += bthci_ExtensionEventHeaderRtk(&localBuf[0], + * HCI_EVENT_EXT_WIFI_SCAN_NOTIFY); */ + + pEvent->EventCode = HCI_EVENT_EXTENSION_RTK; + pEvent->Data[0] = HCI_EVENT_EXT_WIFI_SCAN_NOTIFY; /* extension event code */ + len++; + + /* Return parameters starts from here */ + /* pRetPar = &PPacketIrpEvent->Data[len]; */ + /* pu1Temp = (u8 *)&pRetPar[0]; */ + /* *pu1Temp = scanType; */ + pEvent->Data[len] = scanType; + len += 1; + + pEvent->Length = len; + + /* total tx event length + EventCode length + sizeof(length) */ + tx_event_length = pEvent->Length + 2; +#if 0 + rtw_btcoex_dump_tx_msg((u8 *)pEvent, tx_event_length, "WIFI SCAN OPERATION"); +#endif + rtw_btcoex_sendmsgbysocket(padapter, (u8 *)pEvent, tx_event_length, _FALSE); +} +#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ +#endif /* CONFIG_BT_COEXIST */ diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_btcoex_wifionly.c b/linux-bsp/drivers/rtl8188eus/core/rtw_btcoex_wifionly.c new file mode 100644 index 0000000..f61ad2b --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_btcoex_wifionly.c @@ -0,0 +1,42 @@ +/****************************************************************************** + * + * Copyright(c) 2013 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#include <drv_types.h> +#include <hal_btcoex_wifionly.h> +#include <hal_data.h> + +void rtw_btcoex_wifionly_switchband_notify(PADAPTER padapter) +{ + hal_btcoex_wifionly_switchband_notify(padapter); +} + +void rtw_btcoex_wifionly_scan_notify(PADAPTER padapter) +{ + hal_btcoex_wifionly_scan_notify(padapter); +} + +void rtw_btcoex_wifionly_hw_config(PADAPTER padapter) +{ + hal_btcoex_wifionly_hw_config(padapter); +} + +void rtw_btcoex_wifionly_initialize(PADAPTER padapter) +{ + hal_btcoex_wifionly_initlizevariables(padapter); +} diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_cmd.c b/linux-bsp/drivers/rtl8188eus/core/rtw_cmd.c new file mode 100644 index 0000000..bb2bcf8 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_cmd.c @@ -0,0 +1,4803 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_CMD_C_ + +#include <drv_types.h> +#include <hal_data.h> + +#ifndef DBG_CMD_EXECUTE + #define DBG_CMD_EXECUTE 0 +#endif + +/* +Caller and the rtw_cmd_thread can protect cmd_q by spin_lock. +No irqsave is necessary. +*/ + +sint _rtw_init_cmd_priv(struct cmd_priv *pcmdpriv) +{ + sint res = _SUCCESS; + + + _rtw_init_sema(&(pcmdpriv->cmd_queue_sema), 0); + /* _rtw_init_sema(&(pcmdpriv->cmd_done_sema), 0); */ + _rtw_init_sema(&(pcmdpriv->terminate_cmdthread_sema), 0); + + + _rtw_init_queue(&(pcmdpriv->cmd_queue)); + + /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ + + pcmdpriv->cmd_seq = 1; + + pcmdpriv->cmd_allocated_buf = rtw_zmalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ); + + if (pcmdpriv->cmd_allocated_buf == NULL) { + res = _FAIL; + goto exit; + } + + pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ - ((SIZE_PTR)(pcmdpriv->cmd_allocated_buf) & (CMDBUFF_ALIGN_SZ - 1)); + + pcmdpriv->rsp_allocated_buf = rtw_zmalloc(MAX_RSPSZ + 4); + + if (pcmdpriv->rsp_allocated_buf == NULL) { + res = _FAIL; + goto exit; + } + + pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 - ((SIZE_PTR)(pcmdpriv->rsp_allocated_buf) & 3); + + pcmdpriv->cmd_issued_cnt = pcmdpriv->cmd_done_cnt = pcmdpriv->rsp_cnt = 0; + + _rtw_mutex_init(&pcmdpriv->sctx_mutex); +exit: + + + return res; + +} + +#ifdef CONFIG_C2H_WK +static void c2h_wk_callback(_workitem *work) +{ + struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk); + _adapter *adapter = container_of(evtpriv, _adapter, evtpriv); + u8 *c2h_evt; + c2h_id_filter direct_hdl_filter = rtw_hal_c2h_id_handle_directly; + u8 id, seq, plen; + u8 *payload; + + evtpriv->c2h_wk_alive = _TRUE; + + while (!rtw_cbuf_empty(evtpriv->c2h_queue)) { + c2h_evt = (u8 *)rtw_cbuf_pop(evtpriv->c2h_queue); + if (c2h_evt != NULL) { + /* This C2H event is read, clear it */ + c2h_evt_clear(adapter); + } else { + c2h_evt = (u8 *)rtw_malloc(C2H_REG_LEN); + if (c2h_evt == NULL) { + rtw_warn_on(1); + continue; + } + + /* This C2H event is not read, read & clear now */ + if (rtw_hal_c2h_evt_read(adapter, c2h_evt) != _SUCCESS) { + rtw_mfree(c2h_evt, C2H_REG_LEN); + continue; + } + } + + /* Special pointer to trigger c2h_evt_clear only */ + if ((void *)c2h_evt == (void *)evtpriv) + continue; + + if (!rtw_hal_c2h_valid(adapter, c2h_evt) + || rtw_hal_c2h_reg_hdr_parse(adapter, c2h_evt, &id, &seq, &plen, &payload) != _SUCCESS + ) { + rtw_mfree(c2h_evt, C2H_REG_LEN); + continue; + } + + if (direct_hdl_filter(adapter, id, seq, plen, payload) == _TRUE) { + /* Handle directly */ + rtw_hal_c2h_handler(adapter, id, seq, plen, payload); + rtw_mfree(c2h_evt, C2H_REG_LEN); + } else { + /* Enqueue into cmd_thread for others */ + rtw_c2h_reg_wk_cmd(adapter, c2h_evt); + rtw_mfree(c2h_evt, C2H_REG_LEN); + } + } + + evtpriv->c2h_wk_alive = _FALSE; +} +#endif /* CONFIG_C2H_WK */ + +sint _rtw_init_evt_priv(struct evt_priv *pevtpriv) +{ + sint res = _SUCCESS; + + +#ifdef CONFIG_H2CLBK + _rtw_init_sema(&(pevtpriv->lbkevt_done), 0); + pevtpriv->lbkevt_limit = 0; + pevtpriv->lbkevt_num = 0; + pevtpriv->cmdevt_parm = NULL; +#endif + + /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ + ATOMIC_SET(&pevtpriv->event_seq, 0); + pevtpriv->evt_done_cnt = 0; + +#ifdef CONFIG_EVENT_THREAD_MODE + + _rtw_init_sema(&(pevtpriv->evt_notify), 0); + _rtw_init_sema(&(pevtpriv->terminate_evtthread_sema), 0); + + pevtpriv->evt_allocated_buf = rtw_zmalloc(MAX_EVTSZ + 4); + if (pevtpriv->evt_allocated_buf == NULL) { + res = _FAIL; + goto exit; + } + pevtpriv->evt_buf = pevtpriv->evt_allocated_buf + 4 - ((unsigned int)(pevtpriv->evt_allocated_buf) & 3); + + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + pevtpriv->allocated_c2h_mem = rtw_zmalloc(C2H_MEM_SZ + 4); + + if (pevtpriv->allocated_c2h_mem == NULL) { + res = _FAIL; + goto exit; + } + + pevtpriv->c2h_mem = pevtpriv->allocated_c2h_mem + 4\ + - ((u32)(pevtpriv->allocated_c2h_mem) & 3); +#ifdef PLATFORM_OS_XP + pevtpriv->pc2h_mdl = IoAllocateMdl((u8 *)pevtpriv->c2h_mem, C2H_MEM_SZ , FALSE, FALSE, NULL); + + if (pevtpriv->pc2h_mdl == NULL) { + res = _FAIL; + goto exit; + } + MmBuildMdlForNonPagedPool(pevtpriv->pc2h_mdl); +#endif +#endif /* end of CONFIG_SDIO_HCI */ + + _rtw_init_queue(&(pevtpriv->evt_queue)); + +exit: + +#endif /* end of CONFIG_EVENT_THREAD_MODE */ + +#ifdef CONFIG_C2H_WK + _init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL); + pevtpriv->c2h_wk_alive = _FALSE; + pevtpriv->c2h_queue = rtw_cbuf_alloc(C2H_QUEUE_MAX_LEN + 1); +#endif + + + return res; +} + +void _rtw_free_evt_priv(struct evt_priv *pevtpriv) +{ + + +#ifdef CONFIG_EVENT_THREAD_MODE + _rtw_free_sema(&(pevtpriv->evt_notify)); + _rtw_free_sema(&(pevtpriv->terminate_evtthread_sema)); + + + if (pevtpriv->evt_allocated_buf) + rtw_mfree(pevtpriv->evt_allocated_buf, MAX_EVTSZ + 4); +#endif + +#ifdef CONFIG_C2H_WK + _cancel_workitem_sync(&pevtpriv->c2h_wk); + while (pevtpriv->c2h_wk_alive) + rtw_msleep_os(10); + + while (!rtw_cbuf_empty(pevtpriv->c2h_queue)) { + void *c2h; + c2h = rtw_cbuf_pop(pevtpriv->c2h_queue); + if (c2h != NULL && c2h != (void *)pevtpriv) + rtw_mfree(c2h, 16); + } + rtw_cbuf_free(pevtpriv->c2h_queue); +#endif + + + +} + +void _rtw_free_cmd_priv(struct cmd_priv *pcmdpriv) +{ + + if (pcmdpriv) { + _rtw_spinlock_free(&(pcmdpriv->cmd_queue.lock)); + _rtw_free_sema(&(pcmdpriv->cmd_queue_sema)); + /* _rtw_free_sema(&(pcmdpriv->cmd_done_sema)); */ + _rtw_free_sema(&(pcmdpriv->terminate_cmdthread_sema)); + + if (pcmdpriv->cmd_allocated_buf) + rtw_mfree(pcmdpriv->cmd_allocated_buf, MAX_CMDSZ + CMDBUFF_ALIGN_SZ); + + if (pcmdpriv->rsp_allocated_buf) + rtw_mfree(pcmdpriv->rsp_allocated_buf, MAX_RSPSZ + 4); + + _rtw_mutex_free(&pcmdpriv->sctx_mutex); + } +} + +/* +Calling Context: + +rtw_enqueue_cmd can only be called between kernel thread, +since only spin_lock is used. + +ISR/Call-Back functions can't call this sub-function. + +*/ +#ifdef DBG_CMD_QUEUE +extern u8 dump_cmd_id; +#endif + +sint _rtw_enqueue_cmd(_queue *queue, struct cmd_obj *obj, bool to_head) +{ + _irqL irqL; + + + if (obj == NULL) + goto exit; + + /* _enter_critical_bh(&queue->lock, &irqL); */ + _enter_critical(&queue->lock, &irqL); + + if (to_head) + rtw_list_insert_head(&obj->list, &queue->queue); + else + rtw_list_insert_tail(&obj->list, &queue->queue); + +#ifdef DBG_CMD_QUEUE + if (dump_cmd_id) { + printk("%s===> cmdcode:0x%02x\n", __FUNCTION__, obj->cmdcode); + if (obj->cmdcode == GEN_CMD_CODE(_Set_MLME_EVT)) { + if (obj->parmbuf) { + struct C2HEvent_Header *pc2h_evt_hdr = (struct C2HEvent_Header *)(obj->parmbuf); + printk("pc2h_evt_hdr->ID:0x%02x(%d)\n", pc2h_evt_hdr->ID, pc2h_evt_hdr->ID); + } + } + if (obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { + if (obj->parmbuf) { + struct drvextra_cmd_parm *pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)(obj->parmbuf); + printk("pdrvextra_cmd_parm->ec_id:0x%02x\n", pdrvextra_cmd_parm->ec_id); + } + } + } + + if (queue->queue.prev->next != &queue->queue) { + RTW_INFO("[%d] head %p, tail %p, tail->prev->next %p[tail], tail->next %p[head]\n", __LINE__, + &queue->queue, queue->queue.prev, queue->queue.prev->prev->next, queue->queue.prev->next); + + RTW_INFO("==========%s============\n", __FUNCTION__); + RTW_INFO("head:%p,obj_addr:%p\n", &queue->queue, obj); + RTW_INFO("padapter: %p\n", obj->padapter); + RTW_INFO("cmdcode: 0x%02x\n", obj->cmdcode); + RTW_INFO("res: %d\n", obj->res); + RTW_INFO("parmbuf: %p\n", obj->parmbuf); + RTW_INFO("cmdsz: %d\n", obj->cmdsz); + RTW_INFO("rsp: %p\n", obj->rsp); + RTW_INFO("rspsz: %d\n", obj->rspsz); + RTW_INFO("sctx: %p\n", obj->sctx); + RTW_INFO("list->next: %p\n", obj->list.next); + RTW_INFO("list->prev: %p\n", obj->list.prev); + } +#endif /* DBG_CMD_QUEUE */ + + /* _exit_critical_bh(&queue->lock, &irqL); */ + _exit_critical(&queue->lock, &irqL); + +exit: + + + return _SUCCESS; +} + +struct cmd_obj *_rtw_dequeue_cmd(_queue *queue) +{ + _irqL irqL; + struct cmd_obj *obj; + + + /* _enter_critical_bh(&(queue->lock), &irqL); */ + _enter_critical(&queue->lock, &irqL); + +#ifdef DBG_CMD_QUEUE + if (queue->queue.prev->next != &queue->queue) { + RTW_INFO("[%d] head %p, tail %p, tail->prev->next %p[tail], tail->next %p[head]\n", __LINE__, + &queue->queue, queue->queue.prev, queue->queue.prev->prev->next, queue->queue.prev->next); + } +#endif /* DBG_CMD_QUEUE */ + + + if (rtw_is_list_empty(&(queue->queue))) + obj = NULL; + else { + obj = LIST_CONTAINOR(get_next(&(queue->queue)), struct cmd_obj, list); + +#ifdef DBG_CMD_QUEUE + if (queue->queue.prev->next != &queue->queue) { + RTW_INFO("==========%s============\n", __FUNCTION__); + RTW_INFO("head:%p,obj_addr:%p\n", &queue->queue, obj); + RTW_INFO("padapter: %p\n", obj->padapter); + RTW_INFO("cmdcode: 0x%02x\n", obj->cmdcode); + RTW_INFO("res: %d\n", obj->res); + RTW_INFO("parmbuf: %p\n", obj->parmbuf); + RTW_INFO("cmdsz: %d\n", obj->cmdsz); + RTW_INFO("rsp: %p\n", obj->rsp); + RTW_INFO("rspsz: %d\n", obj->rspsz); + RTW_INFO("sctx: %p\n", obj->sctx); + RTW_INFO("list->next: %p\n", obj->list.next); + RTW_INFO("list->prev: %p\n", obj->list.prev); + } + + if (dump_cmd_id) { + RTW_INFO("%s===> cmdcode:0x%02x\n", __FUNCTION__, obj->cmdcode); + if (obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { + if (obj->parmbuf) { + struct drvextra_cmd_parm *pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)(obj->parmbuf); + printk("pdrvextra_cmd_parm->ec_id:0x%02x\n", pdrvextra_cmd_parm->ec_id); + } + } + + } +#endif /* DBG_CMD_QUEUE */ + + rtw_list_delete(&obj->list); + } + + /* _exit_critical_bh(&(queue->lock), &irqL); */ + _exit_critical(&queue->lock, &irqL); + + + return obj; +} + +u32 rtw_init_cmd_priv(struct cmd_priv *pcmdpriv) +{ + u32 res; + res = _rtw_init_cmd_priv(pcmdpriv); + return res; +} + +u32 rtw_init_evt_priv(struct evt_priv *pevtpriv) +{ + int res; + res = _rtw_init_evt_priv(pevtpriv); + return res; +} + +void rtw_free_evt_priv(struct evt_priv *pevtpriv) +{ + _rtw_free_evt_priv(pevtpriv); +} + +void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv) +{ + _rtw_free_cmd_priv(pcmdpriv); +} + +int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj); +int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) +{ + u8 bAllow = _FALSE; /* set to _TRUE to allow enqueuing cmd when hw_init_completed is _FALSE */ + +#ifdef SUPPORT_HW_RFOFF_DETECTED + /* To decide allow or not */ + if ((adapter_to_pwrctl(pcmdpriv->padapter)->bHWPwrPindetect) + && (!pcmdpriv->padapter->registrypriv.usbss_enable) + ) { + if (cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { + struct drvextra_cmd_parm *pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)cmd_obj->parmbuf; + if (pdrvextra_cmd_parm->ec_id == POWER_SAVING_CTRL_WK_CID) { + /* RTW_INFO("==>enqueue POWER_SAVING_CTRL_WK_CID\n"); */ + bAllow = _TRUE; + } + } + } +#endif + + if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan)) + bAllow = _TRUE; + + if (cmd_obj->no_io) + bAllow = _TRUE; + + if ((!rtw_is_hw_init_completed(pcmdpriv->padapter) && (bAllow == _FALSE)) + || ATOMIC_READ(&(pcmdpriv->cmdthd_running)) == _FALSE /* com_thread not running */ + ) { + if (DBG_CMD_EXECUTE) + RTW_INFO(ADPT_FMT" drop "CMD_FMT" hw_init_completed:%u, cmdthd_running:%u\n", ADPT_ARG(cmd_obj->padapter) + , CMD_ARG(cmd_obj), rtw_get_hw_init_completed(cmd_obj->padapter), ATOMIC_READ(&pcmdpriv->cmdthd_running)); + if (0) + rtw_warn_on(1); + + return _FAIL; + } + return _SUCCESS; +} + + + +u32 rtw_enqueue_cmd(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj) +{ + int res = _FAIL; + PADAPTER padapter = pcmdpriv->padapter; + + + if (cmd_obj == NULL) + goto exit; + + cmd_obj->padapter = padapter; + +#ifdef CONFIG_CONCURRENT_MODE + /* change pcmdpriv to primary's pcmdpriv */ + if (padapter->adapter_type != PRIMARY_ADAPTER) + pcmdpriv = &(GET_PRIMARY_ADAPTER(padapter)->cmdpriv); +#endif + + res = rtw_cmd_filter(pcmdpriv, cmd_obj); + if ((_FAIL == res) || (cmd_obj->cmdsz > MAX_CMDSZ)) { + if (cmd_obj->cmdsz > MAX_CMDSZ) { + RTW_INFO("%s failed due to obj->cmdsz(%d) > MAX_CMDSZ(%d)\n", __func__, cmd_obj->cmdsz, MAX_CMDSZ); + rtw_warn_on(1); + } + + if (cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { + struct drvextra_cmd_parm *extra_parm = (struct drvextra_cmd_parm *)cmd_obj->parmbuf; + + if (extra_parm->pbuf && extra_parm->size > 0) + rtw_mfree(extra_parm->pbuf, extra_parm->size); + } + rtw_free_cmd_obj(cmd_obj); + goto exit; + } + + res = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, cmd_obj, 0); + + if (res == _SUCCESS) + _rtw_up_sema(&pcmdpriv->cmd_queue_sema); + +exit: + + + return res; +} + +struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv) +{ + struct cmd_obj *cmd_obj; + + + cmd_obj = _rtw_dequeue_cmd(&pcmdpriv->cmd_queue); + + return cmd_obj; +} + +void rtw_cmd_clr_isr(struct cmd_priv *pcmdpriv) +{ + pcmdpriv->cmd_done_cnt++; + /* _rtw_up_sema(&(pcmdpriv->cmd_done_sema)); */ +} + +void rtw_free_cmd_obj(struct cmd_obj *pcmd) +{ + struct drvextra_cmd_parm *extra_parm = NULL; + + if (pcmd->parmbuf != NULL) { + /* free parmbuf in cmd_obj */ + rtw_mfree((unsigned char *)pcmd->parmbuf, pcmd->cmdsz); + } + if (pcmd->rsp != NULL) { + if (pcmd->rspsz != 0) { + /* free rsp in cmd_obj */ + rtw_mfree((unsigned char *)pcmd->rsp, pcmd->rspsz); + } + } + + /* free cmd_obj */ + rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj)); + +} + + +void rtw_stop_cmd_thread(_adapter *adapter) +{ + if (adapter->cmdThread && + ATOMIC_READ(&(adapter->cmdpriv.cmdthd_running)) == _TRUE && + adapter->cmdpriv.stop_req == 0) { + adapter->cmdpriv.stop_req = 1; + _rtw_up_sema(&adapter->cmdpriv.cmd_queue_sema); + _rtw_down_sema(&adapter->cmdpriv.terminate_cmdthread_sema); + } +} + +thread_return rtw_cmd_thread(thread_context context) +{ + u8 ret; + struct cmd_obj *pcmd; + u8 *pcmdbuf, *prspbuf; + u32 cmd_start_time; + u32 cmd_process_time; + u8(*cmd_hdl)(_adapter *padapter, u8 *pbuf); + void (*pcmd_callback)(_adapter *dev, struct cmd_obj *pcmd); + PADAPTER padapter = (PADAPTER)context; + struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); + struct drvextra_cmd_parm *extra_parm = NULL; + _irqL irqL; + + thread_enter("RTW_CMD_THREAD"); + + pcmdbuf = pcmdpriv->cmd_buf; + prspbuf = pcmdpriv->rsp_buf; + + pcmdpriv->stop_req = 0; + ATOMIC_SET(&(pcmdpriv->cmdthd_running), _TRUE); + _rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema); + + + while (1) { + if (_rtw_down_sema(&pcmdpriv->cmd_queue_sema) == _FAIL) { + RTW_PRINT(FUNC_ADPT_FMT" _rtw_down_sema(&pcmdpriv->cmd_queue_sema) return _FAIL, break\n", FUNC_ADPT_ARG(padapter)); + break; + } + + if (RTW_CANNOT_RUN(padapter)) { + RTW_PRINT("%s: DriverStopped(%s) SurpriseRemoved(%s) break at line %d\n", + __func__ + , rtw_is_drv_stopped(padapter) ? "True" : "False" + , rtw_is_surprise_removed(padapter) ? "True" : "False" + , __LINE__); + break; + } + + if (pcmdpriv->stop_req) { + RTW_PRINT(FUNC_ADPT_FMT" stop_req:%u, break\n", FUNC_ADPT_ARG(padapter), pcmdpriv->stop_req); + break; + } + + _enter_critical(&pcmdpriv->cmd_queue.lock, &irqL); + if (rtw_is_list_empty(&(pcmdpriv->cmd_queue.queue))) { + /* RTW_INFO("%s: cmd queue is empty!\n", __func__); */ + _exit_critical(&pcmdpriv->cmd_queue.lock, &irqL); + continue; + } + _exit_critical(&pcmdpriv->cmd_queue.lock, &irqL); + +_next: + if (RTW_CANNOT_RUN(padapter)) { + RTW_PRINT("%s: DriverStopped(%s) SurpriseRemoved(%s) break at line %d\n", + __func__ + , rtw_is_drv_stopped(padapter) ? "True" : "False" + , rtw_is_surprise_removed(padapter) ? "True" : "False" + , __LINE__); + break; + } + + pcmd = rtw_dequeue_cmd(pcmdpriv); + if (!pcmd) { +#ifdef CONFIG_LPS_LCLK + rtw_unregister_cmd_alive(padapter); +#endif + continue; + } + + cmd_start_time = rtw_get_current_time(); + pcmdpriv->cmd_issued_cnt++; + + if (pcmd->cmdsz > MAX_CMDSZ) { + RTW_ERR("%s cmdsz:%d > MAX_CMDSZ:%d\n", __func__, pcmd->cmdsz, MAX_CMDSZ); + pcmd->res = H2C_PARAMETERS_ERROR; + goto post_process; + } + + if (pcmd->cmdcode >= (sizeof(wlancmds) / sizeof(struct cmd_hdl))) { + RTW_ERR("%s undefined cmdcode:%d\n", __func__, pcmd->cmdcode); + pcmd->res = H2C_PARAMETERS_ERROR; + goto post_process; + } + + cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns; + if (!cmd_hdl) { + RTW_ERR("%s no cmd_hdl for cmdcode:%d\n", __func__, pcmd->cmdcode); + pcmd->res = H2C_PARAMETERS_ERROR; + goto post_process; + } + + if (_FAIL == rtw_cmd_filter(pcmdpriv, pcmd)) { + pcmd->res = H2C_DROPPED; + if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { + extra_parm = (struct drvextra_cmd_parm *)pcmd->parmbuf; + if (extra_parm && extra_parm->pbuf && extra_parm->size > 0) + rtw_mfree(extra_parm->pbuf, extra_parm->size); + } + goto post_process; + } + +#ifdef CONFIG_LPS_LCLK + if (pcmd->no_io) + rtw_unregister_cmd_alive(padapter); + else { + if (rtw_register_cmd_alive(padapter) != _SUCCESS) { + if (DBG_CMD_EXECUTE) + RTW_PRINT("%s: wait to leave LPS_LCLK\n", __func__); + + pcmd->res = H2C_ENQ_HEAD; + ret = _rtw_enqueue_cmd(&pcmdpriv->cmd_queue, pcmd, 1); + if (ret == _SUCCESS) { + if (DBG_CMD_EXECUTE) + RTW_INFO(ADPT_FMT" "CMD_FMT" ENQ_HEAD\n", ADPT_ARG(pcmd->padapter), CMD_ARG(pcmd)); + continue; + } + + RTW_INFO(ADPT_FMT" "CMD_FMT" ENQ_HEAD_FAIL\n", ADPT_ARG(pcmd->padapter), CMD_ARG(pcmd)); + pcmd->res = H2C_ENQ_HEAD_FAIL; + rtw_warn_on(1); + } + } +#endif /* CONFIG_LPS_LCLK */ + + if (DBG_CMD_EXECUTE) + RTW_INFO(ADPT_FMT" "CMD_FMT" %sexecute\n", ADPT_ARG(pcmd->padapter), CMD_ARG(pcmd) + , pcmd->res == H2C_ENQ_HEAD ? "ENQ_HEAD " : (pcmd->res == H2C_ENQ_HEAD_FAIL ? "ENQ_HEAD_FAIL " : "")); + + _rtw_memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); + ret = cmd_hdl(pcmd->padapter, pcmdbuf); + pcmd->res = ret; + + pcmdpriv->cmd_seq++; + +post_process: + + _enter_critical_mutex(&(pcmd->padapter->cmdpriv.sctx_mutex), NULL); + if (pcmd->sctx) { + if (0) + RTW_PRINT(FUNC_ADPT_FMT" pcmd->sctx\n", + FUNC_ADPT_ARG(pcmd->padapter)); + if (pcmd->res == H2C_SUCCESS) + rtw_sctx_done(&pcmd->sctx); + else + rtw_sctx_done_err(&pcmd->sctx, RTW_SCTX_DONE_CMD_ERROR); + } + _exit_critical_mutex(&(pcmd->padapter->cmdpriv.sctx_mutex), NULL); + + cmd_process_time = rtw_get_passing_time_ms(cmd_start_time); + if (cmd_process_time > 1000) { + RTW_INFO(ADPT_FMT" "CMD_FMT" process_time=%d\n", ADPT_ARG(pcmd->padapter), CMD_ARG(pcmd), cmd_process_time); + if (0) + rtw_warn_on(1); + } + + /* call callback function for post-processed */ + if (pcmd->cmdcode < (sizeof(rtw_cmd_callback) / sizeof(struct _cmd_callback))) { + pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback; + if (pcmd_callback == NULL) { + rtw_free_cmd_obj(pcmd); + } else { + /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!=NULL) */ + pcmd_callback(pcmd->padapter, pcmd);/* need conider that free cmd_obj in rtw_cmd_callback */ + } + } else { + rtw_free_cmd_obj(pcmd); + } + + flush_signals_thread(); + + goto _next; + + } + +#ifdef CONFIG_LPS_LCLK + rtw_unregister_cmd_alive(padapter); +#endif + + /* to avoid enqueue cmd after free all cmd_obj */ + ATOMIC_SET(&(pcmdpriv->cmdthd_running), _FALSE); + + /* free all cmd_obj resources */ + do { + pcmd = rtw_dequeue_cmd(pcmdpriv); + if (pcmd == NULL) + break; + + if (0) + RTW_INFO("%s: leaving... drop "CMD_FMT"\n", __func__, CMD_ARG(pcmd)); + + if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { + extra_parm = (struct drvextra_cmd_parm *)pcmd->parmbuf; + if (extra_parm->pbuf && extra_parm->size > 0) + rtw_mfree(extra_parm->pbuf, extra_parm->size); + } + + rtw_free_cmd_obj(pcmd); + } while (1); + + _rtw_up_sema(&pcmdpriv->terminate_cmdthread_sema); + + + thread_exit(); + +} + + +#ifdef CONFIG_EVENT_THREAD_MODE +u32 rtw_enqueue_evt(struct evt_priv *pevtpriv, struct evt_obj *obj) +{ + _irqL irqL; + int res; + _queue *queue = &pevtpriv->evt_queue; + + + res = _SUCCESS; + + if (obj == NULL) { + res = _FAIL; + goto exit; + } + + _enter_critical_bh(&queue->lock, &irqL); + + rtw_list_insert_tail(&obj->list, &queue->queue); + + _exit_critical_bh(&queue->lock, &irqL); + + /* rtw_evt_notify_isr(pevtpriv); */ + +exit: + + + return res; +} + +struct evt_obj *rtw_dequeue_evt(_queue *queue) +{ + _irqL irqL; + struct evt_obj *pevtobj; + + + _enter_critical_bh(&queue->lock, &irqL); + + if (rtw_is_list_empty(&(queue->queue))) + pevtobj = NULL; + else { + pevtobj = LIST_CONTAINOR(get_next(&(queue->queue)), struct evt_obj, list); + rtw_list_delete(&pevtobj->list); + } + + _exit_critical_bh(&queue->lock, &irqL); + + + return pevtobj; +} + +void rtw_free_evt_obj(struct evt_obj *pevtobj) +{ + + if (pevtobj->parmbuf) + rtw_mfree((unsigned char *)pevtobj->parmbuf, pevtobj->evtsz); + + rtw_mfree((unsigned char *)pevtobj, sizeof(struct evt_obj)); + +} + +void rtw_evt_notify_isr(struct evt_priv *pevtpriv) +{ + pevtpriv->evt_done_cnt++; + _rtw_up_sema(&(pevtpriv->evt_notify)); +} +#endif + + +/* +u8 rtw_setstandby_cmd(unsigned char *adapter) +*/ +u8 rtw_setstandby_cmd(_adapter *padapter, uint action) +{ + struct cmd_obj *ph2c; + struct usb_suspend_parm *psetusbsuspend; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + u8 ret = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + ret = _FAIL; + goto exit; + } + + psetusbsuspend = (struct usb_suspend_parm *)rtw_zmalloc(sizeof(struct usb_suspend_parm)); + if (psetusbsuspend == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + ret = _FAIL; + goto exit; + } + + psetusbsuspend->action = action; + + init_h2fwcmd_w_parm_no_rsp(ph2c, psetusbsuspend, GEN_CMD_CODE(_SetUsbSuspend)); + + ret = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + + return ret; +} + +/* +rtw_sitesurvey_cmd(~) + ### NOTE:#### (!!!!) + MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock +*/ +u8 rtw_sitesurvey_cmd(_adapter *padapter, NDIS_802_11_SSID *ssid, int ssid_num, + struct rtw_ieee80211_channel *ch, int ch_num) +{ + u8 res = _FAIL; + struct cmd_obj *ph2c; + struct sitesurvey_parm *psurveyPara; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#endif /* CONFIG_P2P */ + + +#ifdef CONFIG_LPS + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1); +#endif + +#ifdef CONFIG_P2P_PS + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + p2p_ps_wk_cmd(padapter, P2P_PS_SCAN, 1); +#endif /* CONFIG_P2P_PS */ + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) + return _FAIL; + + psurveyPara = (struct sitesurvey_parm *)rtw_zmalloc(sizeof(struct sitesurvey_parm)); + if (psurveyPara == NULL) { + rtw_mfree((unsigned char *) ph2c, sizeof(struct cmd_obj)); + return _FAIL; + } + + rtw_free_network_queue(padapter, _FALSE); + + + init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); + + /* psurveyPara->bsslimit = 48; */ + psurveyPara->scan_mode = pmlmepriv->scan_mode; + + /* prepare ssid list */ + if (ssid) { + int i; + for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) { + if (ssid[i].SsidLength) { + _rtw_memcpy(&psurveyPara->ssid[i], &ssid[i], sizeof(NDIS_802_11_SSID)); + psurveyPara->ssid_num++; + if (0) + RTW_INFO(FUNC_ADPT_FMT" ssid:(%s, %d)\n", FUNC_ADPT_ARG(padapter), + psurveyPara->ssid[i].Ssid, psurveyPara->ssid[i].SsidLength); + } + } + } + + /* prepare channel list */ + if (ch) { + int i; + for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) { + if (ch[i].hw_value && !(ch[i].flags & RTW_IEEE80211_CHAN_DISABLED)) { + _rtw_memcpy(&psurveyPara->ch[i], &ch[i], sizeof(struct rtw_ieee80211_channel)); + psurveyPara->ch_num++; + if (0) + RTW_INFO(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter), + psurveyPara->ch[i].hw_value); + } + } + } + + set_fwstate(pmlmepriv, _FW_UNDER_SURVEY); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + + if (res == _SUCCESS) { + + pmlmepriv->scan_start_time = rtw_get_current_time(); + +#ifdef CONFIG_SCAN_BACKOP + if (rtw_mi_buddy_check_mlmeinfo_state(padapter, WIFI_FW_AP_STATE)) { + if (is_supported_5g(padapter->registrypriv.wireless_mode) + && IsSupported24G(padapter->registrypriv.wireless_mode)) /* dual band */ + mlme_set_scan_to_timer(pmlmepriv, CONC_SCANNING_TIMEOUT_DUAL_BAND); + else /* single band */ + mlme_set_scan_to_timer(pmlmepriv, CONC_SCANNING_TIMEOUT_SINGLE_BAND); + } else +#endif /* CONFIG_SCAN_BACKOP */ + mlme_set_scan_to_timer(pmlmepriv, SCANNING_TIMEOUT); + + rtw_led_control(padapter, LED_CTL_SITE_SURVEY); + } else + _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); + + + return res; +} + +u8 rtw_setdatarate_cmd(_adapter *padapter, u8 *rateset) +{ + struct cmd_obj *ph2c; + struct setdatarate_parm *pbsetdataratepara; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pbsetdataratepara = (struct setdatarate_parm *)rtw_zmalloc(sizeof(struct setdatarate_parm)); + if (pbsetdataratepara == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, pbsetdataratepara, GEN_CMD_CODE(_SetDataRate)); +#ifdef MP_FIRMWARE_OFFLOAD + pbsetdataratepara->curr_rateidx = *(u32 *)rateset; + /* _rtw_memcpy(pbsetdataratepara, rateset, sizeof(u32)); */ +#else + pbsetdataratepara->mac_id = 5; + _rtw_memcpy(pbsetdataratepara->datarates, rateset, NumRates); +#endif + res = rtw_enqueue_cmd(pcmdpriv, ph2c); +exit: + + + return res; +} + +u8 rtw_setbasicrate_cmd(_adapter *padapter, u8 *rateset) +{ + struct cmd_obj *ph2c; + struct setbasicrate_parm *pssetbasicratepara; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + pssetbasicratepara = (struct setbasicrate_parm *)rtw_zmalloc(sizeof(struct setbasicrate_parm)); + + if (pssetbasicratepara == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara, _SetBasicRate_CMD_); + + _rtw_memcpy(pssetbasicratepara->basicrates, rateset, NumRates); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); +exit: + + + return res; +} + + +/* +unsigned char rtw_setphy_cmd(unsigned char *adapter) + +1. be called only after rtw_update_registrypriv_dev_network( ~) or mp testing program +2. for AdHoc/Ap mode or mp mode? + +*/ +u8 rtw_setphy_cmd(_adapter *padapter, u8 modem, u8 ch) +{ + struct cmd_obj *ph2c; + struct setphy_parm *psetphypara; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + /* struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + * struct registry_priv* pregistry_priv = &padapter->registrypriv; */ + u8 res = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + psetphypara = (struct setphy_parm *)rtw_zmalloc(sizeof(struct setphy_parm)); + + if (psetphypara == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, psetphypara, _SetPhy_CMD_); + + + psetphypara->modem = modem; + psetphypara->rfchannel = ch; + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); +exit: + return res; +} + +u8 rtw_getmacreg_cmd(_adapter *padapter, u8 len, u32 addr) +{ + struct cmd_obj *ph2c; + struct readMAC_parm *preadmacparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + preadmacparm = (struct readMAC_parm *)rtw_zmalloc(sizeof(struct readMAC_parm)); + + if (preadmacparm == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, preadmacparm, GEN_CMD_CODE(_GetMACReg)); + + preadmacparm->len = len; + preadmacparm->addr = addr; + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + return res; +} + +void rtw_usb_catc_trigger_cmd(_adapter *padapter, const char *caller) +{ + RTW_INFO("%s caller:%s\n", __func__, caller); + rtw_getmacreg_cmd(padapter, 1, 0x1c4); +} + +u8 rtw_setbbreg_cmd(_adapter *padapter, u8 offset, u8 val) +{ + struct cmd_obj *ph2c; + struct writeBB_parm *pwritebbparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + pwritebbparm = (struct writeBB_parm *)rtw_zmalloc(sizeof(struct writeBB_parm)); + + if (pwritebbparm == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, pwritebbparm, GEN_CMD_CODE(_SetBBReg)); + + pwritebbparm->offset = offset; + pwritebbparm->value = val; + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); +exit: + return res; +} + +u8 rtw_getbbreg_cmd(_adapter *padapter, u8 offset, u8 *pval) +{ + struct cmd_obj *ph2c; + struct readBB_parm *prdbbparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + prdbbparm = (struct readBB_parm *)rtw_zmalloc(sizeof(struct readBB_parm)); + + if (prdbbparm == NULL) { + rtw_mfree((unsigned char *) ph2c, sizeof(struct cmd_obj)); + return _FAIL; + } + + _rtw_init_listhead(&ph2c->list); + ph2c->cmdcode = GEN_CMD_CODE(_GetBBReg); + ph2c->parmbuf = (unsigned char *)prdbbparm; + ph2c->cmdsz = sizeof(struct readBB_parm); + ph2c->rsp = pval; + ph2c->rspsz = sizeof(struct readBB_rsp); + + prdbbparm->offset = offset; + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); +exit: + return res; +} + +u8 rtw_setrfreg_cmd(_adapter *padapter, u8 offset, u32 val) +{ + struct cmd_obj *ph2c; + struct writeRF_parm *pwriterfparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + pwriterfparm = (struct writeRF_parm *)rtw_zmalloc(sizeof(struct writeRF_parm)); + + if (pwriterfparm == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg)); + + pwriterfparm->offset = offset; + pwriterfparm->value = val; + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); +exit: + return res; +} + +u8 rtw_getrfreg_cmd(_adapter *padapter, u8 offset, u8 *pval) +{ + struct cmd_obj *ph2c; + struct readRF_parm *prdrfparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + prdrfparm = (struct readRF_parm *)rtw_zmalloc(sizeof(struct readRF_parm)); + if (prdrfparm == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + _rtw_init_listhead(&ph2c->list); + ph2c->cmdcode = GEN_CMD_CODE(_GetRFReg); + ph2c->parmbuf = (unsigned char *)prdrfparm; + ph2c->cmdsz = sizeof(struct readRF_parm); + ph2c->rsp = pval; + ph2c->rspsz = sizeof(struct readRF_rsp); + + prdrfparm->offset = offset; + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + + return res; +} + +void rtw_getbbrfreg_cmdrsp_callback(_adapter *padapter, struct cmd_obj *pcmd) +{ + + /* rtw_free_cmd_obj(pcmd); */ + rtw_mfree((unsigned char *) pcmd->parmbuf, pcmd->cmdsz); + rtw_mfree((unsigned char *) pcmd, sizeof(struct cmd_obj)); + +#ifdef CONFIG_MP_INCLUDED + if (padapter->registrypriv.mp_mode == 1) + padapter->mppriv.workparam.bcompleted = _TRUE; +#endif +} + +void rtw_readtssi_cmdrsp_callback(_adapter *padapter, struct cmd_obj *pcmd) +{ + + rtw_mfree((unsigned char *) pcmd->parmbuf, pcmd->cmdsz); + rtw_mfree((unsigned char *) pcmd, sizeof(struct cmd_obj)); + +#ifdef CONFIG_MP_INCLUDED + if (padapter->registrypriv.mp_mode == 1) + padapter->mppriv.workparam.bcompleted = _TRUE; +#endif + +} + +static u8 rtw_createbss_cmd(_adapter *adapter, int flags, bool adhoc + , s16 req_ch, s8 req_bw, s8 req_offset) +{ + struct cmd_obj *cmdobj; + struct createbss_parm *parm; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct submit_ctx sctx; + u8 res = _SUCCESS; + + if (req_ch > 0 && req_bw >= 0 && req_offset >= 0) { + if (!rtw_chset_is_chbw_valid(adapter->mlmeextpriv.channel_set, req_ch, req_bw, req_offset)) { + res = _FAIL; + goto exit; + } + } + + /* prepare cmd parameter */ + parm = (struct createbss_parm *)rtw_zmalloc(sizeof(*parm)); + if (parm == NULL) { + res = _FAIL; + goto exit; + } + + if (adhoc) { + /* for now, adhoc doesn't support ch,bw,offset request */ + parm->adhoc = 1; + } else { + parm->adhoc = 0; + parm->req_ch = req_ch; + parm->req_bw = req_bw; + parm->req_offset = req_offset; + } + + if (flags & RTW_CMDF_DIRECTLY) { + /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ + if (H2C_SUCCESS != createbss_hdl(adapter, (u8 *)parm)) + res = _FAIL; + rtw_mfree((u8 *)parm, sizeof(*parm)); + } else { + /* need enqueue, prepare cmd_obj and enqueue */ + cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj)); + if (cmdobj == NULL) { + res = _FAIL; + rtw_mfree((u8 *)parm, sizeof(*parm)); + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(cmdobj, parm, GEN_CMD_CODE(_CreateBss)); + + if (flags & RTW_CMDF_WAIT_ACK) { + cmdobj->sctx = &sctx; + rtw_sctx_init(&sctx, 2000); + } + + res = rtw_enqueue_cmd(pcmdpriv, cmdobj); + + if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) { + rtw_sctx_wait(&sctx, __func__); + _enter_critical_mutex(&pcmdpriv->sctx_mutex, NULL); + if (sctx.status == RTW_SCTX_SUBMITTED) + cmdobj->sctx = NULL; + _exit_critical_mutex(&pcmdpriv->sctx_mutex, NULL); + } + } + +exit: + return res; +} + +inline u8 rtw_create_ibss_cmd(_adapter *adapter, int flags) +{ + return rtw_createbss_cmd(adapter, flags + , 1 + , 0, -1, -1 /* for now, adhoc doesn't support ch,bw,offset request */ + ); +} + +inline u8 rtw_startbss_cmd(_adapter *adapter, int flags) +{ + return rtw_createbss_cmd(adapter, flags + , 0 + , 0, -1, -1 /* excute entire AP setup cmd */ + ); +} + +inline u8 rtw_change_bss_chbw_cmd(_adapter *adapter, int flags, s16 req_ch, s8 req_bw, s8 req_offset) +{ + return rtw_createbss_cmd(adapter, flags + , 0 + , req_ch, req_bw, req_offset + ); +} + +u8 rtw_joinbss_cmd(_adapter *padapter, struct wlan_network *pnetwork) +{ + u8 *auth, res = _SUCCESS; + uint t_len = 0; + WLAN_BSSID_EX *psecnetwork; + struct cmd_obj *pcmd; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct registry_priv *pregistrypriv = &padapter->registrypriv; +#ifdef CONFIG_80211N_HT + struct ht_priv *phtpriv = &pmlmepriv->htpriv; +#endif /* CONFIG_80211N_HT */ +#ifdef CONFIG_80211AC_VHT + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; +#endif /* CONFIG_80211AC_VHT */ + NDIS_802_11_NETWORK_INFRASTRUCTURE ndis_network_mode = pnetwork->network.InfrastructureMode; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u32 tmp_len; + u8 *ptmp = NULL; +#ifdef CONFIG_RTW_80211R + struct _ft_priv *pftpriv = &pmlmepriv->ftpriv; +#endif + + rtw_led_control(padapter, LED_CTL_START_TO_LINK); + + pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmd == NULL) { + res = _FAIL; + goto exit; + } +#if 0 + /* for IEs is pointer */ + t_len = sizeof(ULONG) + sizeof(NDIS_802_11_MAC_ADDRESS) + 2 + + sizeof(NDIS_802_11_SSID) + sizeof(ULONG) + + sizeof(NDIS_802_11_RSSI) + sizeof(NDIS_802_11_NETWORK_TYPE) + + sizeof(NDIS_802_11_CONFIGURATION) + + sizeof(NDIS_802_11_NETWORK_INFRASTRUCTURE) + + sizeof(NDIS_802_11_RATES_EX) + sizeof(WLAN_PHY_INFO) + sizeof(ULONG) + MAX_IE_SZ; +#endif + /* for IEs is fix buf size */ + t_len = sizeof(WLAN_BSSID_EX); + + + /* for hidden ap to set fw_state here */ + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) != _TRUE) { + switch (ndis_network_mode) { + case Ndis802_11IBSS: + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + break; + + case Ndis802_11Infrastructure: + set_fwstate(pmlmepriv, WIFI_STATION_STATE); + break; + + case Ndis802_11APMode: + case Ndis802_11AutoUnknown: + case Ndis802_11InfrastructureMax: + case Ndis802_11Monitor: + break; + + } + } + + pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->network.IEs, pnetwork->network.IELength); + + /* + Modified by Arvin 2015/05/13 + Solution for allocating a new WLAN_BSSID_EX to avoid race condition issue between disconnect and joinbss + */ + psecnetwork = (WLAN_BSSID_EX *)rtw_zmalloc(sizeof(WLAN_BSSID_EX)); + if (psecnetwork == NULL) { + if (pcmd != NULL) + rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj)); + + res = _FAIL; + + + goto exit; + } + + _rtw_memset(psecnetwork, 0, t_len); + + _rtw_memcpy(psecnetwork, &pnetwork->network, get_WLAN_BSSID_EX_sz(&pnetwork->network)); + + auth = &psecuritypriv->authenticator_ie[0]; + psecuritypriv->authenticator_ie[0] = (unsigned char)psecnetwork->IELength; + + if ((psecnetwork->IELength - 12) < (256 - 1)) + _rtw_memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], psecnetwork->IELength - 12); + else + _rtw_memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256 - 1)); + + psecnetwork->IELength = 0; + /* Added by Albert 2009/02/18 */ + /* If the the driver wants to use the bssid to create the connection. */ + /* If not, we have to copy the connecting AP's MAC address to it so that */ + /* the driver just has the bssid information for PMKIDList searching. */ + + if (pmlmepriv->assoc_by_bssid == _FALSE) + _rtw_memcpy(&pmlmepriv->assoc_bssid[0], &pnetwork->network.MacAddress[0], ETH_ALEN); + + psecnetwork->IELength = rtw_restruct_sec_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength); + + + pqospriv->qos_option = 0; + + if (pregistrypriv->wmm_enable) { + tmp_len = rtw_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], pnetwork->network.IELength, psecnetwork->IELength); + + if (psecnetwork->IELength != tmp_len) { + psecnetwork->IELength = tmp_len; + pqospriv->qos_option = 1; /* There is WMM IE in this corresp. beacon */ + } else { + pqospriv->qos_option = 0;/* There is no WMM IE in this corresp. beacon */ + } + } + +#ifdef CONFIG_80211N_HT + phtpriv->ht_option = _FALSE; + ptmp = rtw_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, &tmp_len, pnetwork->network.IELength - 12); + if (pregistrypriv->ht_enable && ptmp && tmp_len > 0) { + /* Added by Albert 2010/06/23 */ + /* For the WEP mode, we will use the bg mode to do the connection to avoid some IOT issue. */ + /* Especially for Realtek 8192u SoftAP. */ + if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) && + (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) && + (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) { + rtw_ht_use_default_setting(padapter); + + rtw_build_wmm_ie_ht(padapter, &psecnetwork->IEs[0], &psecnetwork->IELength); + + /* rtw_restructure_ht_ie */ + rtw_restructure_ht_ie(padapter, &pnetwork->network.IEs[12], &psecnetwork->IEs[0], + pnetwork->network.IELength - 12, &psecnetwork->IELength, + pnetwork->network.Configuration.DSConfig); + } + } + +#ifdef CONFIG_80211AC_VHT + pvhtpriv->vht_option = _FALSE; + if (phtpriv->ht_option + && REGSTY_IS_11AC_ENABLE(pregistrypriv) + && hal_chk_proto_cap(padapter, PROTO_CAP_11AC) + && (!pmlmepriv->country_ent || COUNTRY_CHPLAN_EN_11AC(pmlmepriv->country_ent)) + ) { + rtw_restructure_vht_ie(padapter, &pnetwork->network.IEs[0], &psecnetwork->IEs[0], + pnetwork->network.IELength, &psecnetwork->IELength); + } +#endif + + rtw_append_exented_cap(padapter, &psecnetwork->IEs[0], &psecnetwork->IELength); + +#endif /* CONFIG_80211N_HT */ + +#ifdef CONFIG_RTW_80211R + /*IEEE802.11-2012 Std. Table 8-101�XAKM suite selectors*/ + if ((rtw_chk_ft_flags(padapter, RTW_FT_STA_SUPPORTED)) && + ((psecuritypriv->rsn_akm_suite_type == 3) || (psecuritypriv->rsn_akm_suite_type == 4)) + ) { + ptmp = rtw_get_ie(&pnetwork->network.IEs[12], _MDIE_, &tmp_len, pnetwork->network.IELength-12); + if (ptmp) { + _rtw_memcpy(&pftpriv->mdid, ptmp+2, 2); + pftpriv->ft_cap = *(ptmp+4); + + RTW_INFO("FT: Target AP "MAC_FMT" MDID=(0x%2x), capacity=(0x%2x)\n", MAC_ARG(pnetwork->network.MacAddress), pftpriv->mdid, pftpriv->ft_cap); + rtw_set_ft_flags(padapter, RTW_FT_SUPPORTED); + if ((rtw_chk_ft_flags(padapter, RTW_FT_STA_OVER_DS_SUPPORTED)) && (pftpriv->ft_roam_on_expired == _FALSE) && (pftpriv->ft_cap & 0x01)) + rtw_set_ft_flags(padapter, RTW_FT_OVER_DS_SUPPORTED); + } else { + /*Don't use FT roaming if Target AP cannot support FT*/ + RTW_INFO("FT: Target AP "MAC_FMT" could not support FT\n", MAC_ARG(pnetwork->network.MacAddress)); + rtw_clr_ft_flags(padapter, RTW_FT_SUPPORTED|RTW_FT_OVER_DS_SUPPORTED); + rtw_reset_ft_status(padapter); + } + } else { + /*It could be a non-FT connection*/ + RTW_INFO("FT: non-FT rtw_joinbss_cmd\n"); + rtw_clr_ft_flags(padapter, RTW_FT_SUPPORTED|RTW_FT_OVER_DS_SUPPORTED); + rtw_reset_ft_status(padapter); + } +#endif + +#if 0 + psecuritypriv->supplicant_ie[0] = (u8)psecnetwork->IELength; + + if (psecnetwork->IELength < (256 - 1)) + _rtw_memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0], psecnetwork->IELength); + else + _rtw_memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0], (256 - 1)); +#endif + + pcmd->cmdsz = sizeof(WLAN_BSSID_EX); + +#ifdef CONFIG_RTL8712 + /* wlan_network endian conversion */ + psecnetwork->Length = cpu_to_le32(psecnetwork->Length); + psecnetwork->Ssid.SsidLength = cpu_to_le32(psecnetwork->Ssid.SsidLength); + psecnetwork->Privacy = cpu_to_le32(psecnetwork->Privacy); + psecnetwork->Rssi = cpu_to_le32(psecnetwork->Rssi); + psecnetwork->NetworkTypeInUse = cpu_to_le32(psecnetwork->NetworkTypeInUse); + psecnetwork->Configuration.ATIMWindow = cpu_to_le32(psecnetwork->Configuration.ATIMWindow); + psecnetwork->Configuration.BeaconPeriod = cpu_to_le32(psecnetwork->Configuration.BeaconPeriod); + psecnetwork->Configuration.DSConfig = cpu_to_le32(psecnetwork->Configuration.DSConfig); + psecnetwork->Configuration.FHConfig.DwellTime = cpu_to_le32(psecnetwork->Configuration.FHConfig.DwellTime); + psecnetwork->Configuration.FHConfig.HopPattern = cpu_to_le32(psecnetwork->Configuration.FHConfig.HopPattern); + psecnetwork->Configuration.FHConfig.HopSet = cpu_to_le32(psecnetwork->Configuration.FHConfig.HopSet); + psecnetwork->Configuration.FHConfig.Length = cpu_to_le32(psecnetwork->Configuration.FHConfig.Length); + psecnetwork->Configuration.Length = cpu_to_le32(psecnetwork->Configuration.Length); + psecnetwork->InfrastructureMode = cpu_to_le32(psecnetwork->InfrastructureMode); + psecnetwork->IELength = cpu_to_le32(psecnetwork->IELength); +#endif + + _rtw_init_listhead(&pcmd->list); + pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */ + pcmd->parmbuf = (unsigned char *)psecnetwork; + pcmd->rsp = NULL; + pcmd->rspsz = 0; + + res = rtw_enqueue_cmd(pcmdpriv, pcmd); + +exit: + + + return res; +} + +u8 rtw_disassoc_cmd(_adapter *padapter, u32 deauth_timeout_ms, bool enqueue) /* for sta_mode */ +{ + struct cmd_obj *cmdobj = NULL; + struct disconnect_parm *param = NULL; + struct cmd_priv *cmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + + /* prepare cmd parameter */ + param = (struct disconnect_parm *)rtw_zmalloc(sizeof(*param)); + if (param == NULL) { + res = _FAIL; + goto exit; + } + param->deauth_timeout_ms = deauth_timeout_ms; + + if (enqueue) { + /* need enqueue, prepare cmd_obj and enqueue */ + cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj)); + if (cmdobj == NULL) { + res = _FAIL; + rtw_mfree((u8 *)param, sizeof(*param)); + goto exit; + } + init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_); + res = rtw_enqueue_cmd(cmdpriv, cmdobj); + } else { + /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ + if (H2C_SUCCESS != disconnect_hdl(padapter, (u8 *)param)) + res = _FAIL; + rtw_mfree((u8 *)param, sizeof(*param)); + } + +exit: + + + return res; +} + +u8 rtw_setopmode_cmd(_adapter *padapter, NDIS_802_11_NETWORK_INFRASTRUCTURE networktype, bool enqueue) +{ + struct cmd_obj *ph2c; + struct setopmode_parm *psetop; + + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + psetop = (struct setopmode_parm *)rtw_zmalloc(sizeof(struct setopmode_parm)); + + if (psetop == NULL) { + res = _FAIL; + goto exit; + } + psetop->mode = (u8)networktype; + + if (enqueue) { + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + rtw_mfree((u8 *)psetop, sizeof(*psetop)); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_); + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + } else { + setopmode_hdl(padapter, (u8 *)psetop); + rtw_mfree((u8 *)psetop, sizeof(*psetop)); + } +exit: + + + return res; +} + +u8 rtw_setstakey_cmd(_adapter *padapter, struct sta_info *sta, u8 key_type, bool enqueue) +{ + struct cmd_obj *ph2c; + struct set_stakey_parm *psetstakey_para; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct set_stakey_rsp *psetstakey_rsp = NULL; + + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + u8 res = _SUCCESS; + + + psetstakey_para = (struct set_stakey_parm *)rtw_zmalloc(sizeof(struct set_stakey_parm)); + if (psetstakey_para == NULL) { + res = _FAIL; + goto exit; + } + + _rtw_memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN); + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) + psetstakey_para->algorithm = (unsigned char) psecuritypriv->dot11PrivacyAlgrthm; + else + GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, _FALSE); + + if (key_type == GROUP_KEY) + _rtw_memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16); + else if (key_type == UNICAST_KEY) + _rtw_memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16); +#ifdef CONFIG_TDLS + else if (key_type == TDLS_KEY) { + _rtw_memcpy(&psetstakey_para->key, sta->tpk.tk, 16); + psetstakey_para->algorithm = (u8)sta->dot118021XPrivacy; + } +#endif /* CONFIG_TDLS */ + + /* jeff: set this becasue at least sw key is ready */ + padapter->securitypriv.busetkipkey = _TRUE; + + if (enqueue) { + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm)); + res = _FAIL; + goto exit; + } + + psetstakey_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_stakey_rsp)); + if (psetstakey_rsp == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm)); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); + ph2c->rsp = (u8 *) psetstakey_rsp; + ph2c->rspsz = sizeof(struct set_stakey_rsp); + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + } else { + set_stakey_hdl(padapter, (u8 *)psetstakey_para); + rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm)); + } +exit: + + + return res; +} + +u8 rtw_clearstakey_cmd(_adapter *padapter, struct sta_info *sta, u8 enqueue) +{ + struct cmd_obj *ph2c; + struct set_stakey_parm *psetstakey_para; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct set_stakey_rsp *psetstakey_rsp = NULL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + s16 cam_id = 0; + u8 res = _SUCCESS; + + + if (!enqueue) { + while ((cam_id = rtw_camid_search(padapter, sta->hwaddr, -1, -1)) >= 0) { + RTW_PRINT("clear key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(sta->hwaddr), cam_id); + clear_cam_entry(padapter, cam_id); + rtw_camid_free(padapter, cam_id); + } + } else { + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + psetstakey_para = (struct set_stakey_parm *)rtw_zmalloc(sizeof(struct set_stakey_parm)); + if (psetstakey_para == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + psetstakey_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_stakey_rsp)); + if (psetstakey_rsp == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm)); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_); + ph2c->rsp = (u8 *) psetstakey_rsp; + ph2c->rspsz = sizeof(struct set_stakey_rsp); + + _rtw_memcpy(psetstakey_para->addr, sta->hwaddr, ETH_ALEN); + + psetstakey_para->algorithm = _NO_PRIVACY_; + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + + } + +exit: + + + return res; +} + +u8 rtw_setrttbl_cmd(_adapter *padapter, struct setratable_parm *prate_table) +{ + struct cmd_obj *ph2c; + struct setratable_parm *psetrttblparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + psetrttblparm = (struct setratable_parm *)rtw_zmalloc(sizeof(struct setratable_parm)); + + if (psetrttblparm == NULL) { + rtw_mfree((unsigned char *) ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); + + _rtw_memcpy(psetrttblparm, prate_table, sizeof(struct setratable_parm)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); +exit: + return res; + +} + +u8 rtw_getrttbl_cmd(_adapter *padapter, struct getratable_rsp *pval) +{ + struct cmd_obj *ph2c; + struct getratable_parm *pgetrttblparm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + pgetrttblparm = (struct getratable_parm *)rtw_zmalloc(sizeof(struct getratable_parm)); + + if (pgetrttblparm == NULL) { + rtw_mfree((unsigned char *) ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + /* init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); */ + + _rtw_init_listhead(&ph2c->list); + ph2c->cmdcode = GEN_CMD_CODE(_GetRaTable); + ph2c->parmbuf = (unsigned char *)pgetrttblparm; + ph2c->cmdsz = sizeof(struct getratable_parm); + ph2c->rsp = (u8 *)pval; + ph2c->rspsz = sizeof(struct getratable_rsp); + + pgetrttblparm->rsvd = 0x0; + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); +exit: + return res; + +} + +u8 rtw_setassocsta_cmd(_adapter *padapter, u8 *mac_addr) +{ + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct cmd_obj *ph2c; + struct set_assocsta_parm *psetassocsta_para; + struct set_stakey_rsp *psetassocsta_rsp = NULL; + + u8 res = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + psetassocsta_para = (struct set_assocsta_parm *)rtw_zmalloc(sizeof(struct set_assocsta_parm)); + if (psetassocsta_para == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + psetassocsta_rsp = (struct set_stakey_rsp *)rtw_zmalloc(sizeof(struct set_assocsta_rsp)); + if (psetassocsta_rsp == NULL) { + rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); + rtw_mfree((u8 *) psetassocsta_para, sizeof(struct set_assocsta_parm)); + return _FAIL; + } + + init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_); + ph2c->rsp = (u8 *) psetassocsta_rsp; + ph2c->rspsz = sizeof(struct set_assocsta_rsp); + + _rtw_memcpy(psetassocsta_para->addr, mac_addr, ETH_ALEN); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + + return res; +} + +u8 rtw_addbareq_cmd(_adapter *padapter, u8 tid, u8 *addr) +{ + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct cmd_obj *ph2c; + struct addBaReq_parm *paddbareq_parm; + + u8 res = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + paddbareq_parm = (struct addBaReq_parm *)rtw_zmalloc(sizeof(struct addBaReq_parm)); + if (paddbareq_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + paddbareq_parm->tid = tid; + _rtw_memcpy(paddbareq_parm->addr, addr, ETH_ALEN); + + init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq)); + + /* RTW_INFO("rtw_addbareq_cmd, tid=%d\n", tid); */ + + /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + + return res; +} + +u8 rtw_addbarsp_cmd(_adapter *padapter, u8 *addr, u16 tid, u8 status, u8 size, u16 start_seq) +{ + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct cmd_obj *ph2c; + struct addBaRsp_parm *paddBaRsp_parm; + u8 res = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + paddBaRsp_parm = (struct addBaRsp_parm *)rtw_zmalloc(sizeof(struct addBaRsp_parm)); + + if (paddBaRsp_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + _rtw_memcpy(paddBaRsp_parm->addr, addr, ETH_ALEN); + paddBaRsp_parm->tid = tid; + paddBaRsp_parm->status = status; + paddBaRsp_parm->size = size; + paddBaRsp_parm->start_seq = start_seq; + + init_h2fwcmd_w_parm_no_rsp(ph2c, paddBaRsp_parm, GEN_CMD_CODE(_AddBARsp)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + + return res; +} +/* add for CONFIG_IEEE80211W, none 11w can use it */ +u8 rtw_reset_securitypriv_cmd(_adapter *padapter) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = RESET_SECURITYPRIV; + pdrvextra_cmd_parm->type = 0; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + + /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + + return res; + +} + +u8 rtw_free_assoc_resources_cmd(_adapter *padapter) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = FREE_ASSOC_RESOURCES; + pdrvextra_cmd_parm->type = 0; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + + /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + + return res; + +} + +u8 rtw_dynamic_chk_wk_cmd(_adapter *padapter) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + /* only primary padapter does this cmd */ + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID; + pdrvextra_cmd_parm->type = 0; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + + /* rtw_enqueue_cmd(pcmdpriv, ph2c); */ + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + + return res; + +} + +u8 rtw_set_ch_cmd(_adapter *padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue) +{ + struct cmd_obj *pcmdobj; + struct set_ch_parm *set_ch_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + u8 res = _SUCCESS; + + + RTW_INFO(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n", + FUNC_NDEV_ARG(padapter->pnetdev), ch, bw, ch_offset); + + /* check input parameter */ + + /* prepare cmd parameter */ + set_ch_parm = (struct set_ch_parm *)rtw_zmalloc(sizeof(*set_ch_parm)); + if (set_ch_parm == NULL) { + res = _FAIL; + goto exit; + } + set_ch_parm->ch = ch; + set_ch_parm->bw = bw; + set_ch_parm->ch_offset = ch_offset; + + if (enqueue) { + /* need enqueue, prepare cmd_obj and enqueue */ + pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmdobj == NULL) { + rtw_mfree((u8 *)set_ch_parm, sizeof(*set_ch_parm)); + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm, GEN_CMD_CODE(_SetChannel)); + res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); + } else { + /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ + if (H2C_SUCCESS != set_ch_hdl(padapter, (u8 *)set_ch_parm)) + res = _FAIL; + + rtw_mfree((u8 *)set_ch_parm, sizeof(*set_ch_parm)); + } + + /* do something based on res... */ + +exit: + + RTW_INFO(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev), res); + + + return res; +} + +u8 _rtw_set_chplan_cmd(_adapter *adapter, int flags, u8 chplan, const struct country_chplan *country_ent, u8 swconfig) +{ + struct cmd_obj *cmdobj; + struct SetChannelPlan_param *parm; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct submit_ctx sctx; + u8 res = _SUCCESS; + + + /* check if allow software config */ + if (swconfig && rtw_hal_is_disable_sw_channel_plan(adapter) == _TRUE) { + res = _FAIL; + goto exit; + } + + /* if country_entry is provided, replace chplan */ + if (country_ent) + chplan = country_ent->chplan; + + /* check input parameter */ + if (!rtw_is_channel_plan_valid(chplan)) { + res = _FAIL; + goto exit; + } + + /* prepare cmd parameter */ + parm = (struct SetChannelPlan_param *)rtw_zmalloc(sizeof(*parm)); + if (parm == NULL) { + res = _FAIL; + goto exit; + } + parm->country_ent = country_ent; + parm->channel_plan = chplan; + + if (flags & RTW_CMDF_DIRECTLY) { + /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ + if (H2C_SUCCESS != set_chplan_hdl(adapter, (u8 *)parm)) + res = _FAIL; + rtw_mfree((u8 *)parm, sizeof(*parm)); + } else { + /* need enqueue, prepare cmd_obj and enqueue */ + cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj)); + if (cmdobj == NULL) { + res = _FAIL; + rtw_mfree((u8 *)parm, sizeof(*parm)); + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(cmdobj, parm, GEN_CMD_CODE(_SetChannelPlan)); + + if (flags & RTW_CMDF_WAIT_ACK) { + cmdobj->sctx = &sctx; + rtw_sctx_init(&sctx, 2000); + } + + res = rtw_enqueue_cmd(pcmdpriv, cmdobj); + + if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) { + rtw_sctx_wait(&sctx, __func__); + _enter_critical_mutex(&pcmdpriv->sctx_mutex, NULL); + if (sctx.status == RTW_SCTX_SUBMITTED) + cmdobj->sctx = NULL; + _exit_critical_mutex(&pcmdpriv->sctx_mutex, NULL); + } + } + +exit: + + + return res; +} + +inline u8 rtw_set_chplan_cmd(_adapter *adapter, int flags, u8 chplan, u8 swconfig) +{ + return _rtw_set_chplan_cmd(adapter, flags, chplan, NULL, swconfig); +} + +inline u8 rtw_set_country_cmd(_adapter *adapter, int flags, const char *country_code, u8 swconfig) +{ + const struct country_chplan *ent; + + if (is_alpha(country_code[0]) == _FALSE + || is_alpha(country_code[1]) == _FALSE + ) { + RTW_PRINT("%s input country_code is not alpha2\n", __func__); + return _FAIL; + } + + ent = rtw_get_chplan_from_country(country_code); + + if (ent == NULL) { + RTW_PRINT("%s unsupported country_code:\"%c%c\"\n", __func__, country_code[0], country_code[1]); + return _FAIL; + } + + RTW_PRINT("%s country_code:\"%c%c\" mapping to chplan:0x%02x\n", __func__, country_code[0], country_code[1], ent->chplan); + + return _rtw_set_chplan_cmd(adapter, flags, RTW_CHPLAN_MAX, ent, swconfig); +} + +u8 rtw_led_blink_cmd(_adapter *padapter, PVOID pLed) +{ + struct cmd_obj *pcmdobj; + struct LedBlink_param *ledBlink_param; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + u8 res = _SUCCESS; + + + + pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmdobj == NULL) { + res = _FAIL; + goto exit; + } + + ledBlink_param = (struct LedBlink_param *)rtw_zmalloc(sizeof(struct LedBlink_param)); + if (ledBlink_param == NULL) { + rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + ledBlink_param->pLed = pLed; + + init_h2fwcmd_w_parm_no_rsp(pcmdobj, ledBlink_param, GEN_CMD_CODE(_LedBlink)); + res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); + +exit: + + + return res; +} + +u8 rtw_set_csa_cmd(_adapter *padapter, u8 new_ch_no) +{ + struct cmd_obj *pcmdobj; + struct SetChannelSwitch_param *setChannelSwitch_param; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + u8 res = _SUCCESS; + + + + pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmdobj == NULL) { + res = _FAIL; + goto exit; + } + + setChannelSwitch_param = (struct SetChannelSwitch_param *)rtw_zmalloc(sizeof(struct SetChannelSwitch_param)); + if (setChannelSwitch_param == NULL) { + rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + setChannelSwitch_param->new_ch_no = new_ch_no; + + init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelSwitch_param, GEN_CMD_CODE(_SetChannelSwitch)); + res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); + +exit: + + + return res; +} + +u8 rtw_tdls_cmd(_adapter *padapter, u8 *addr, u8 option) +{ + struct cmd_obj *pcmdobj; + struct TDLSoption_param *TDLSoption; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + u8 res = _SUCCESS; + + +#ifdef CONFIG_TDLS + + + pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmdobj == NULL) { + res = _FAIL; + goto exit; + } + + TDLSoption = (struct TDLSoption_param *)rtw_zmalloc(sizeof(struct TDLSoption_param)); + if (TDLSoption == NULL) { + rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + _rtw_spinlock(&(padapter->tdlsinfo.cmd_lock)); + if (addr != NULL) + _rtw_memcpy(TDLSoption->addr, addr, 6); + TDLSoption->option = option; + _rtw_spinunlock(&(padapter->tdlsinfo.cmd_lock)); + init_h2fwcmd_w_parm_no_rsp(pcmdobj, TDLSoption, GEN_CMD_CODE(_TDLS)); + res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); + +#endif /* CONFIG_TDLS */ + +exit: + + + + return res; +} + +u8 rtw_enable_hw_update_tsf_cmd(_adapter *padapter) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = EN_HW_UPDATE_TSF_WK_CID; + pdrvextra_cmd_parm->type = 0; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + return res; +} + +/* from_timer == 1 means driver is in LPS */ +u8 traffic_status_watchdog(_adapter *padapter, u8 from_timer) +{ + u8 bEnterPS = _FALSE; + u16 BusyThresholdHigh; + u16 BusyThresholdLow; + u16 BusyThreshold; + u8 bBusyTraffic = _FALSE, bTxBusyTraffic = _FALSE, bRxBusyTraffic = _FALSE; + u8 bHigherBusyTraffic = _FALSE, bHigherBusyRxTraffic = _FALSE, bHigherBusyTxTraffic = _FALSE; + + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); +#ifdef CONFIG_TDLS + struct tdls_info *ptdlsinfo = &(padapter->tdlsinfo); + struct tdls_txmgmt txmgmt; + u8 baddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +#endif /* CONFIG_TDLS */ + + RT_LINK_DETECT_T *link_detect = &pmlmepriv->LinkDetectInfo; + +#ifdef CONFIG_BT_COEXIST + if (padapter->registrypriv.wifi_spec != 1) { + BusyThresholdHigh = 25; + BusyThresholdLow = 10; + } else +#endif /* CONFIG_BT_COEXIST */ + { + BusyThresholdHigh = 100; + BusyThresholdLow = 75; + } + BusyThreshold = BusyThresholdHigh; + + + /* */ + /* Determine if our traffic is busy now */ + /* */ + if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + /*&& !MgntInitAdapterInProgress(pMgntInfo)*/) { + /* if we raise bBusyTraffic in last watchdog, using lower threshold. */ + if (pmlmepriv->LinkDetectInfo.bBusyTraffic) + BusyThreshold = BusyThresholdLow; + + if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > BusyThreshold || + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > BusyThreshold) { + bBusyTraffic = _TRUE; + + if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) + bRxBusyTraffic = _TRUE; + else + bTxBusyTraffic = _TRUE; + } + + /* Higher Tx/Rx data. */ + if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 || + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) { + bHigherBusyTraffic = _TRUE; + + if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) + bHigherBusyRxTraffic = _TRUE; + else + bHigherBusyTxTraffic = _TRUE; + } + +#ifdef CONFIG_TRAFFIC_PROTECT +#define TX_ACTIVE_TH 10 +#define RX_ACTIVE_TH 20 +#define TRAFFIC_PROTECT_PERIOD_MS 4500 + + if (link_detect->NumTxOkInPeriod > TX_ACTIVE_TH + || link_detect->NumRxUnicastOkInPeriod > RX_ACTIVE_TH) { + + RTW_INFO(FUNC_ADPT_FMT" acqiure wake_lock for %u ms(tx:%d,rx_unicast:%d)\n", + FUNC_ADPT_ARG(padapter), + TRAFFIC_PROTECT_PERIOD_MS, + link_detect->NumTxOkInPeriod, + link_detect->NumRxUnicastOkInPeriod); + + rtw_lock_traffic_suspend_timeout(TRAFFIC_PROTECT_PERIOD_MS); + } +#endif + +#ifdef CONFIG_TDLS +#ifdef CONFIG_TDLS_AUTOSETUP + /* TDLS_WATCHDOG_PERIOD * 2sec, periodically send */ + if (hal_chk_wl_func(padapter, WL_FUNC_TDLS) == _TRUE) { + if ((ptdlsinfo->watchdog_count % TDLS_WATCHDOG_PERIOD) == 0) { + _rtw_memcpy(txmgmt.peer, baddr, ETH_ALEN); + issue_tdls_dis_req(padapter, &txmgmt); + } + ptdlsinfo->watchdog_count++; + } +#endif /* CONFIG_TDLS_AUTOSETUP */ +#endif /* CONFIG_TDLS */ + +#ifdef CONFIG_LPS + /* check traffic for powersaving. */ + if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) || +#ifdef CONFIG_LPS_SLOW_TRANSITION + (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2) +#else /* CONFIG_LPS_SLOW_TRANSITION */ + (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 4) +#endif /* CONFIG_LPS_SLOW_TRANSITION */ + ) { +#ifdef DBG_RX_COUNTER_DUMP + if (padapter->dump_rx_cnt_mode & DUMP_DRV_TRX_COUNTER_DATA) + RTW_INFO("(-)Tx = %d, Rx = %d\n", pmlmepriv->LinkDetectInfo.NumTxOkInPeriod, pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod); +#endif + bEnterPS = _FALSE; +#ifdef CONFIG_LPS_SLOW_TRANSITION + if (bBusyTraffic == _TRUE) { + if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount <= 4) + pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 4; + + pmlmepriv->LinkDetectInfo.TrafficTransitionCount++; + + /* RTW_INFO("Set TrafficTransitionCount to %d\n", pmlmepriv->LinkDetectInfo.TrafficTransitionCount); */ + + if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount > 30/*TrafficTransitionLevel*/) + pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 30; + } +#endif /* CONFIG_LPS_SLOW_TRANSITION */ + + } else { +#ifdef DBG_RX_COUNTER_DUMP + if (padapter->dump_rx_cnt_mode & DUMP_DRV_TRX_COUNTER_DATA) + RTW_INFO("(+)Tx = %d, Rx = %d\n", pmlmepriv->LinkDetectInfo.NumTxOkInPeriod, pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod); +#endif +#ifdef CONFIG_LPS_SLOW_TRANSITION + if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount >= 2) + pmlmepriv->LinkDetectInfo.TrafficTransitionCount -= 2; + else + pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0; + + if (pmlmepriv->LinkDetectInfo.TrafficTransitionCount == 0) + bEnterPS = _TRUE; +#else /* CONFIG_LPS_SLOW_TRANSITION */ + bEnterPS = _TRUE; +#endif /* CONFIG_LPS_SLOW_TRANSITION */ + } + +#ifdef CONFIG_DYNAMIC_DTIM + if (pmlmepriv->LinkDetectInfo.LowPowerTransitionCount == 8) + bEnterPS = _FALSE; + + RTW_INFO("LowPowerTransitionCount=%d\n", pmlmepriv->LinkDetectInfo.LowPowerTransitionCount); +#endif /* CONFIG_DYNAMIC_DTIM */ + + /* LeisurePS only work in infra mode. */ + if (bEnterPS) { + if (!from_timer) { +#ifdef CONFIG_DYNAMIC_DTIM + if (pmlmepriv->LinkDetectInfo.LowPowerTransitionCount < 8) + adapter_to_pwrctl(padapter)->dtim = 1; + else + adapter_to_pwrctl(padapter)->dtim = 3; +#endif /* CONFIG_DYNAMIC_DTIM */ + LPS_Enter(padapter, "TRAFFIC_IDLE"); + } else { + /* do this at caller */ + /* rtw_lps_ctrl_wk_cmd(adapter, LPS_CTRL_ENTER, 1); */ + /* rtw_hal_dm_watchdog_in_lps(padapter); */ + } +#ifdef CONFIG_DYNAMIC_DTIM + if (adapter_to_pwrctl(padapter)->bFwCurrentInPSMode == _TRUE) + pmlmepriv->LinkDetectInfo.LowPowerTransitionCount++; +#endif /* CONFIG_DYNAMIC_DTIM */ + } else { +#ifdef CONFIG_DYNAMIC_DTIM + if (pmlmepriv->LinkDetectInfo.LowPowerTransitionCount != 8) + pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0; + else + pmlmepriv->LinkDetectInfo.LowPowerTransitionCount++; +#endif /* CONFIG_DYNAMIC_DTIM */ + if (!from_timer) + LPS_Leave(padapter, "TRAFFIC_BUSY"); + else { +#ifdef CONFIG_CONCURRENT_MODE + #ifndef CONFIG_FW_MULTI_PORT_SUPPORT + if (padapter->hw_port == HW_PORT0) + #endif +#endif + rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_TRAFFIC_BUSY, 1); + } + } + +#endif /* CONFIG_LPS */ + } else { +#ifdef CONFIG_LPS + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + int n_assoc_iface = 0; + int i; + + for (i = 0; i < dvobj->iface_nums; i++) { + if (check_fwstate(&(dvobj->padapters[i]->mlmepriv), WIFI_ASOC_STATE)) + n_assoc_iface++; + } + + if (!from_timer && n_assoc_iface == 0) + LPS_Leave(padapter, "NON_LINKED"); +#endif + } + + session_tracker_chk_cmd(padapter, NULL); + +#ifdef CONFIG_BEAMFORMING +#ifdef RTW_BEAMFORMING_VERSION_2 + rtw_bf_update_traffic(padapter); +#endif /* RTW_BEAMFORMING_VERSION_2 */ +#endif /* CONFIG_BEAMFORMING */ + + pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0; + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0; + pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0; + pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic; + pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic; + pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic; + pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic; + pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic; + pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic; + + return bEnterPS; + +} + + +/* for 11n Logo 4.2.31/4.2.32 */ +static void dynamic_update_bcn_check(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + if (!padapter->registrypriv.wifi_spec) + return; + + if (!MLME_IS_AP(padapter)) + return; + + if (pmlmeext->bstart_bss) { + /* In 10 * 2 = 20s, there are no legacy AP, update HT info */ + static u8 count = 1; + + if (count % 10 == 0) { + count = 1; + + if (_FALSE == ATOMIC_READ(&pmlmepriv->olbc) + && _FALSE == ATOMIC_READ(&pmlmepriv->olbc_ht)) { + + if (rtw_ht_operation_update(padapter) > 0) { + update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, _FALSE); + update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _TRUE); + } + } + } + + /* In 2s, there are any legacy AP, update HT info, and then reset count */ + + if (_FALSE != ATOMIC_READ(&pmlmepriv->olbc) + && _FALSE != ATOMIC_READ(&pmlmepriv->olbc_ht)) { + + if (rtw_ht_operation_update(padapter) > 0) { + update_beacon(padapter, _HT_CAPABILITY_IE_, NULL, _FALSE); + update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, _TRUE); + + } + ATOMIC_SET(&pmlmepriv->olbc, _FALSE); + ATOMIC_SET(&pmlmepriv->olbc_ht, _FALSE); + count = 0; + } + + count ++; + } +} +void rtw_iface_dynamic_chk_wk_hdl(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + + #ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK + #ifdef CONFIG_AP_MODE + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) + expire_timeout_chk(padapter); + #endif + #endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */ + dynamic_update_bcn_check(padapter); + + linked_status_chk(padapter, 0); + traffic_status_watchdog(padapter, 0); + + /* for debug purpose */ + _linked_info_dump(padapter); + + #ifdef CONFIG_BEAMFORMING + #ifndef RTW_BEAMFORMING_VERSION_2 + #if (BEAMFORMING_SUPPORT == 0) /*for diver defined beamforming*/ + beamforming_watchdog(padapter); + #endif + #endif /* !RTW_BEAMFORMING_VERSION_2 */ + #endif + +} +void rtw_dynamic_chk_wk_hdl(_adapter *padapter) +{ + rtw_mi_dynamic_chk_wk_hdl(padapter); + +#ifdef DBG_CONFIG_ERROR_DETECT + rtw_hal_sreset_xmit_status_check(padapter); + rtw_hal_sreset_linked_status_check(padapter); +#endif + + /* if(check_fwstate(pmlmepriv, _FW_UNDER_LINKING|_FW_UNDER_SURVEY)==_FALSE) */ + { +#ifdef DBG_RX_COUNTER_DUMP + rtw_dump_rx_counters(padapter); +#endif + dm_DynamicUsbTxAgg(padapter, 0); + } + rtw_hal_dm_watchdog(padapter); + + /* check_hw_pbc(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->type); */ + +#ifdef CONFIG_BT_COEXIST + /* BT-Coexist */ + rtw_btcoex_Handler(padapter); +#endif + +#ifdef CONFIG_IPS_CHECK_IN_WD + /* always call rtw_ps_processor() at last one. */ + rtw_ps_processor(padapter); +#endif + +#ifdef CONFIG_MCC_MODE + rtw_hal_mcc_sw_status_check(padapter); +#endif /* CONFIG_MCC_MODE */ + +} + +#ifdef CONFIG_LPS + +void lps_ctrl_wk_hdl(_adapter *padapter, u8 lps_ctrl_type); +void lps_ctrl_wk_hdl(_adapter *padapter, u8 lps_ctrl_type) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u8 mstatus; + + + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) + || (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)) + return; + + switch (lps_ctrl_type) { + case LPS_CTRL_SCAN: + /* RTW_INFO("LPS_CTRL_SCAN\n"); */ +#ifdef CONFIG_BT_COEXIST + rtw_btcoex_ScanNotify(padapter, _TRUE); +#endif /* CONFIG_BT_COEXIST */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + /* connect */ + LPS_Leave(padapter, "LPS_CTRL_SCAN"); + } + break; + case LPS_CTRL_JOINBSS: + /* RTW_INFO("LPS_CTRL_JOINBSS\n"); */ + LPS_Leave(padapter, "LPS_CTRL_JOINBSS"); + break; + case LPS_CTRL_CONNECT: + /* RTW_INFO("LPS_CTRL_CONNECT\n"); */ + mstatus = 1;/* connect */ + /* Reset LPS Setting */ + pwrpriv->LpsIdleCount = 0; + rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); +#ifdef CONFIG_BT_COEXIST + rtw_btcoex_MediaStatusNotify(padapter, mstatus); +#endif /* CONFIG_BT_COEXIST */ + break; + case LPS_CTRL_DISCONNECT: + /* RTW_INFO("LPS_CTRL_DISCONNECT\n"); */ + mstatus = 0;/* disconnect */ +#ifdef CONFIG_BT_COEXIST + rtw_btcoex_MediaStatusNotify(padapter, mstatus); +#endif /* CONFIG_BT_COEXIST */ + LPS_Leave(padapter, "LPS_CTRL_DISCONNECT"); + rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); + break; + case LPS_CTRL_SPECIAL_PACKET: + /* RTW_INFO("LPS_CTRL_SPECIAL_PACKET\n"); */ + pwrpriv->DelayLPSLastTimeStamp = rtw_get_current_time(); +#ifdef CONFIG_BT_COEXIST + rtw_btcoex_SpecialPacketNotify(padapter, PACKET_DHCP); +#endif /* CONFIG_BT_COEXIST */ + LPS_Leave(padapter, "LPS_CTRL_SPECIAL_PACKET"); + break; + case LPS_CTRL_LEAVE: + LPS_Leave(padapter, "LPS_CTRL_LEAVE"); + break; + case LPS_CTRL_LEAVE_CFG80211_PWRMGMT: + LPS_Leave(padapter, "CFG80211_PWRMGMT"); + break; + case LPS_CTRL_TRAFFIC_BUSY: + LPS_Leave(padapter, "LPS_CTRL_TRAFFIC_BUSY"); + break; + case LPS_CTRL_TX_TRAFFIC_LEAVE: + LPS_Leave(padapter, "LPS_CTRL_TX_TRAFFIC_LEAVE"); + break; + case LPS_CTRL_RX_TRAFFIC_LEAVE: + LPS_Leave(padapter, "LPS_CTRL_RX_TRAFFIC_LEAVE"); + break; + case LPS_CTRL_ENTER: + LPS_Enter(padapter, "TRAFFIC_IDLE_1"); + break; + default: + break; + } + +} + +u8 rtw_lps_ctrl_wk_cmd(_adapter *padapter, u8 lps_ctrl_type, u8 enqueue) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + /* struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); */ + u8 res = _SUCCESS; + + + /* if(!pwrctrlpriv->bLeisurePs) */ + /* return res; */ + + if (enqueue) { + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID; + pdrvextra_cmd_parm->type = lps_ctrl_type; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + } else + lps_ctrl_wk_hdl(padapter, lps_ctrl_type); + +exit: + + + return res; + +} + +void rtw_dm_in_lps_hdl(_adapter *padapter) +{ + rtw_hal_set_hwreg(padapter, HW_VAR_DM_IN_LPS, NULL); +} + +u8 rtw_dm_in_lps_wk_cmd(_adapter *padapter) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = DM_IN_LPS_WK_CID; + pdrvextra_cmd_parm->type = 0; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + return res; + +} + +void rtw_lps_change_dtim_hdl(_adapter *padapter, u8 dtim) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + + if (dtim <= 0 || dtim > 16) + return; + +#ifdef CONFIG_BT_COEXIST + if (rtw_btcoex_IsBtControlLps(padapter) == _TRUE) + return; +#endif + +#ifdef CONFIG_LPS_LCLK + _enter_pwrlock(&pwrpriv->lock); +#endif + + if (pwrpriv->dtim != dtim) { + RTW_INFO("change DTIM from %d to %d, bFwCurrentInPSMode=%d, ps_mode=%d\n", pwrpriv->dtim, dtim, + pwrpriv->bFwCurrentInPSMode, pwrpriv->pwr_mode); + + pwrpriv->dtim = dtim; + } + + if ((pwrpriv->bFwCurrentInPSMode == _TRUE) && (pwrpriv->pwr_mode > PS_MODE_ACTIVE)) { + u8 ps_mode = pwrpriv->pwr_mode; + + /* RTW_INFO("change DTIM from %d to %d, ps_mode=%d\n", pwrpriv->dtim, dtim, ps_mode); */ + + rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); + } + +#ifdef CONFIG_LPS_LCLK + _exit_pwrlock(&pwrpriv->lock); +#endif + +} + +#endif + +u8 rtw_lps_change_dtim_cmd(_adapter *padapter, u8 dtim) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + /* + #ifdef CONFIG_CONCURRENT_MODE + if (padapter->hw_port != HW_PORT0) + return res; + #endif + */ + { + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = LPS_CHANGE_DTIM_CID; + pdrvextra_cmd_parm->type = dtim; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + } + +exit: + + return res; + +} + +#if (RATE_ADAPTIVE_SUPPORT == 1) +void rpt_timer_setting_wk_hdl(_adapter *padapter, u16 minRptTime) +{ + rtw_hal_set_hwreg(padapter, HW_VAR_RPT_TIMER_SETTING, (u8 *)(&minRptTime)); +} + +u8 rtw_rpt_timer_cfg_cmd(_adapter *padapter, u16 minRptTime) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + u8 res = _SUCCESS; + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = RTP_TIMER_CFG_WK_CID; + pdrvextra_cmd_parm->type = minRptTime; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + res = rtw_enqueue_cmd(pcmdpriv, ph2c); +exit: + + + return res; + +} + +#endif + +#ifdef CONFIG_ANTENNA_DIVERSITY +void antenna_select_wk_hdl(_adapter *padapter, u8 antenna) +{ + rtw_hal_set_odm_var(padapter, HAL_ODM_ANTDIV_SELECT, &antenna, _TRUE); +} + +u8 rtw_antenna_select_cmd(_adapter *padapter, u8 antenna, u8 enqueue) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + u8 bSupportAntDiv = _FALSE; + u8 res = _SUCCESS; + int i; + + rtw_hal_get_def_var(padapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &(bSupportAntDiv)); + if (_FALSE == bSupportAntDiv) + return _FAIL; + + for (i = 0; i < dvobj->iface_nums; i++) { + if (rtw_linked_check(dvobj->padapters[i])) + return _FAIL; + } + + if (_TRUE == enqueue) { + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = ANT_SELECT_WK_CID; + pdrvextra_cmd_parm->type = antenna; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + } else + antenna_select_wk_hdl(padapter, antenna); +exit: + + + return res; + +} +#endif + +void rtw_dm_ra_mask_hdl(_adapter *padapter, struct sta_info *psta) +{ + if (psta) + set_sta_rate(padapter, psta); +} + +u8 rtw_dm_ra_mask_wk_cmd(_adapter *padapter, u8 *psta) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = DM_RA_MSK_WK_CID; + pdrvextra_cmd_parm->type = 0; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = psta; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + return res; + +} + +void power_saving_wk_hdl(_adapter *padapter) +{ + rtw_ps_processor(padapter); +} + +/* add for CONFIG_IEEE80211W, none 11w can use it */ +void reset_securitypriv_hdl(_adapter *padapter) +{ + rtw_reset_securitypriv(padapter); +} + +void free_assoc_resources_hdl(_adapter *padapter) +{ + rtw_free_assoc_resources(padapter, 1); +} + +#ifdef CONFIG_P2P +u8 p2p_protocol_wk_cmd(_adapter *padapter, int intCmdType) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return res; + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID; + pdrvextra_cmd_parm->type = intCmdType; /* As the command tppe. */ + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; /* Must be NULL here */ + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + + return res; + +} + +#ifdef CONFIG_IOCTL_CFG80211 +static u8 _p2p_roch_cmd(_adapter *adapter + , u64 cookie, struct wireless_dev *wdev + , struct ieee80211_channel *ch, enum nl80211_channel_type ch_type + , unsigned int duration + , u8 flags +) +{ + struct cmd_obj *cmdobj; + struct drvextra_cmd_parm *parm; + struct p2p_roch_parm *roch_parm; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + struct submit_ctx sctx; + u8 cancel = duration ? 0 : 1; + u8 res = _SUCCESS; + + roch_parm = (struct p2p_roch_parm *)rtw_zmalloc(sizeof(struct p2p_roch_parm)); + if (roch_parm == NULL) { + res = _FAIL; + goto exit; + } + + roch_parm->cookie = cookie; + roch_parm->wdev = wdev; + if (!cancel) { + _rtw_memcpy(&roch_parm->ch, ch, sizeof(struct ieee80211_channel)); + roch_parm->ch_type = ch_type; + roch_parm->duration = duration; + } + + if (flags & RTW_CMDF_DIRECTLY) { + /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ + if (H2C_SUCCESS != p2p_protocol_wk_hdl(adapter, cancel ? P2P_CANCEL_RO_CH_WK : P2P_RO_CH_WK, (u8 *)roch_parm)) + res = _FAIL; + rtw_mfree((u8 *)roch_parm, sizeof(*roch_parm)); + } else { + /* need enqueue, prepare cmd_obj and enqueue */ + parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (parm == NULL) { + rtw_mfree((u8 *)roch_parm, sizeof(*roch_parm)); + res = _FAIL; + goto exit; + } + + parm->ec_id = P2P_PROTO_WK_CID; + parm->type = cancel ? P2P_CANCEL_RO_CH_WK : P2P_RO_CH_WK; + parm->size = sizeof(*roch_parm); + parm->pbuf = (u8 *)roch_parm; + + cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj)); + if (cmdobj == NULL) { + res = _FAIL; + rtw_mfree((u8 *)roch_parm, sizeof(*roch_parm)); + rtw_mfree((u8 *)parm, sizeof(*parm)); + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(cmdobj, parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + if (flags & RTW_CMDF_WAIT_ACK) { + cmdobj->sctx = &sctx; + rtw_sctx_init(&sctx, 10 * 1000); + } + + res = rtw_enqueue_cmd(pcmdpriv, cmdobj); + + if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) { + rtw_sctx_wait(&sctx, __func__); + _enter_critical_mutex(&pcmdpriv->sctx_mutex, NULL); + if (sctx.status == RTW_SCTX_SUBMITTED) + cmdobj->sctx = NULL; + _exit_critical_mutex(&pcmdpriv->sctx_mutex, NULL); + if (sctx.status != RTW_SCTX_DONE_SUCCESS) + res = _FAIL; + } + } + +exit: + return res; +} + +inline u8 p2p_roch_cmd(_adapter *adapter + , u64 cookie, struct wireless_dev *wdev + , struct ieee80211_channel *ch, enum nl80211_channel_type ch_type + , unsigned int duration + , u8 flags +) +{ + return _p2p_roch_cmd(adapter, cookie, wdev, ch, ch_type, duration, flags); +} + +inline u8 p2p_cancel_roch_cmd(_adapter *adapter, u64 cookie, struct wireless_dev *wdev, u8 flags) +{ + return _p2p_roch_cmd(adapter, cookie, wdev, NULL, 0, 0, flags); +} +#endif /* CONFIG_IOCTL_CFG80211 */ +#endif /* CONFIG_P2P */ + +u8 rtw_ps_cmd(_adapter *padapter) +{ + struct cmd_obj *ppscmd; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + u8 res = _SUCCESS; + +#ifdef CONFIG_CONCURRENT_MODE + if (padapter->adapter_type != PRIMARY_ADAPTER) + goto exit; +#endif + + ppscmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ppscmd == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ppscmd, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID; + pdrvextra_cmd_parm->type = 0; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ppscmd); + +exit: + + + return res; + +} + +#ifdef CONFIG_AP_MODE + +static void rtw_chk_hi_queue_hdl(_adapter *padapter) +{ + struct sta_info *psta_bmc; + struct sta_priv *pstapriv = &padapter->stapriv; + u32 start = rtw_get_current_time(); + u8 empty = _FALSE; + + psta_bmc = rtw_get_bcmc_stainfo(padapter); + if (!psta_bmc) + return; + + rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty); + + while (_FALSE == empty && rtw_get_passing_time_ms(start) < rtw_get_wait_hiq_empty_ms()) { + rtw_msleep_os(100); + rtw_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &empty); + } + + if (psta_bmc->sleepq_len == 0) { + if (empty == _SUCCESS) { + bool update_tim = _FALSE; + + if (pstapriv->tim_bitmap & BIT(0)) + update_tim = _TRUE; + + pstapriv->tim_bitmap &= ~BIT(0); + pstapriv->sta_dz_bitmap &= ~BIT(0); + + if (update_tim == _TRUE) + _update_beacon(padapter, _TIM_IE_, NULL, _TRUE, "bmc sleepq and HIQ empty"); + } else /* re check again */ + rtw_chk_hi_queue_cmd(padapter); + + } + +} + +u8 rtw_chk_hi_queue_cmd(_adapter *padapter) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID; + pdrvextra_cmd_parm->type = 0; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + return res; + +} + +#ifdef CONFIG_DFS_MASTER +u8 rtw_dfs_master_hdl(_adapter *adapter) +{ + struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); + struct mlme_priv *mlme = &adapter->mlmepriv; + + if (!rfctl->dfs_master_enabled) + goto exit; + + if (rtw_get_on_cur_ch_time(adapter) == 0 + || rtw_get_passing_time_ms(rtw_get_on_cur_ch_time(adapter)) < 300 + ) { + /* offchannel , bypass radar detect */ + goto cac_status_chk; + } + + if (IS_CH_WAITING(rfctl) && !IS_UNDER_CAC(rfctl)) { + /* non_ocp, bypass radar detect */ + goto cac_status_chk; + } + + if (!rfctl->dbg_dfs_master_fake_radar_detect_cnt + && rtw_odm_radar_detect(adapter) != _TRUE) + goto cac_status_chk; + + if (rfctl->dbg_dfs_master_fake_radar_detect_cnt != 0) { + RTW_INFO(FUNC_ADPT_FMT" fake radar detect, cnt:%d\n", FUNC_ADPT_ARG(adapter) + , rfctl->dbg_dfs_master_fake_radar_detect_cnt); + rfctl->dbg_dfs_master_fake_radar_detect_cnt--; + } + + if (rfctl->dbg_dfs_master_radar_detect_trigger_non) { + /* radar detect debug mode, trigger no mlme flow */ + if (0) + RTW_INFO(FUNC_ADPT_FMT" radar detected, trigger no mlme flow for debug\n", FUNC_ADPT_ARG(adapter)); + } else { + /* TODO: move timer to rfctl */ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + int i; + + for (i = 0; i < dvobj->iface_nums; i++) { + if (!dvobj->padapters[i]) + continue; + if (check_fwstate(&dvobj->padapters[i]->mlmepriv, WIFI_AP_STATE) + && check_fwstate(&dvobj->padapters[i]->mlmepriv, WIFI_ASOC_STATE)) + break; + } + + if (i >= dvobj->iface_nums) { + /* what? */ + rtw_warn_on(1); + } else { + rtw_chset_update_non_ocp(dvobj->padapters[i]->mlmeextpriv.channel_set + , rfctl->radar_detect_ch, rfctl->radar_detect_bw, rfctl->radar_detect_offset); + rfctl->radar_detected = 1; + + /* trigger channel selection */ + rtw_change_bss_chbw_cmd(dvobj->padapters[i], RTW_CMDF_DIRECTLY, -1, dvobj->padapters[i]->mlmepriv.ori_bw, -1); + } + + if (rfctl->dfs_master_enabled) + goto set_timer; + goto exit; + } + +cac_status_chk: + + if (!IS_CH_WAITING(rfctl) && !IS_CAC_STOPPED(rfctl)) { + u8 pause = 0x00; + + rtw_hal_set_hwreg(adapter, HW_VAR_TXPAUSE, &pause); + rfctl->cac_start_time = rfctl->cac_end_time = RTW_CAC_STOPPED; + } + +set_timer: + _set_timer(&mlme->dfs_master_timer, DFS_MASTER_TIMER_MS); + +exit: + return H2C_SUCCESS; +} + +u8 rtw_dfs_master_cmd(_adapter *adapter, bool enqueue) +{ + struct cmd_obj *cmdobj; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + u8 res = _FAIL; + + if (enqueue) { + cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (cmdobj == NULL) + goto exit; + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((u8 *)cmdobj, sizeof(struct cmd_obj)); + goto exit; + } + + pdrvextra_cmd_parm->ec_id = DFS_MASTER_WK_CID; + pdrvextra_cmd_parm->type = 0; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + + init_h2fwcmd_w_parm_no_rsp(cmdobj, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + res = rtw_enqueue_cmd(pcmdpriv, cmdobj); + } else { + rtw_dfs_master_hdl(adapter); + res = _SUCCESS; + } + +exit: + return res; +} + +void rtw_dfs_master_timer_hdl(RTW_TIMER_HDL_ARGS) +{ + _adapter *adapter = (_adapter *)FunctionContext; + + rtw_dfs_master_cmd(adapter, _TRUE); +} + +void rtw_dfs_master_enable(_adapter *adapter, u8 ch, u8 bw, u8 offset) +{ + struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); + + /* TODO: move timer to rfctl */ + adapter = GET_PRIMARY_ADAPTER(adapter); + + RTW_INFO(FUNC_ADPT_FMT" on %u,%u,%u\n", FUNC_ADPT_ARG(adapter), ch, bw, offset); + + if (rtw_is_cac_reset_needed(adapter, ch, bw, offset) == _TRUE) + rtw_reset_cac(adapter, ch, bw, offset); + + rfctl->radar_detect_by_others = _FALSE; + rfctl->radar_detect_ch = ch; + rfctl->radar_detect_bw = bw; + rfctl->radar_detect_offset = offset; + + rfctl->radar_detected = 0; + + if (!rfctl->dfs_master_enabled) { + RTW_INFO(FUNC_ADPT_FMT" set dfs_master_enabled\n", FUNC_ADPT_ARG(adapter)); + rfctl->dfs_master_enabled = 1; + _set_timer(&adapter->mlmepriv.dfs_master_timer, DFS_MASTER_TIMER_MS); + + if (rtw_rfctl_overlap_radar_detect_ch(rfctl)) { + if (IS_CH_WAITING(rfctl)) { + u8 pause = 0xFF; + + rtw_hal_set_hwreg(adapter, HW_VAR_TXPAUSE, &pause); + } + rtw_odm_radar_detect_enable(adapter); + } + } +} + +void rtw_dfs_master_disable(_adapter *adapter, u8 ch, u8 bw, u8 offset, bool by_others) +{ + struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); + + /* TODO: move timer to rfctl */ + adapter = GET_PRIMARY_ADAPTER(adapter); + + rfctl->radar_detect_by_others = by_others; + + if (rfctl->dfs_master_enabled) { + bool overlap_radar_detect_ch = rtw_rfctl_overlap_radar_detect_ch(rfctl); + + RTW_INFO(FUNC_ADPT_FMT" clear dfs_master_enabled\n", FUNC_ADPT_ARG(adapter)); + + rfctl->dfs_master_enabled = 0; + rfctl->radar_detected = 0; + rfctl->radar_detect_ch = 0; + rfctl->radar_detect_bw = 0; + rfctl->radar_detect_offset = 0; + rfctl->cac_start_time = rfctl->cac_end_time = RTW_CAC_STOPPED; + _cancel_timer_ex(&adapter->mlmepriv.dfs_master_timer); + + if (overlap_radar_detect_ch) { + u8 pause = 0x00; + + rtw_hal_set_hwreg(adapter, HW_VAR_TXPAUSE, &pause); + rtw_odm_radar_detect_disable(adapter); + } + } + + if (by_others) { + rfctl->radar_detect_ch = ch; + rfctl->radar_detect_bw = bw; + rfctl->radar_detect_offset = offset; + } +} + +void rtw_dfs_master_status_apply(_adapter *adapter, u8 self_action) +{ + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + struct mi_state mstate; + u8 u_ch, u_bw, u_offset; + bool ld_sta_in_dfs = _FALSE; + bool sync_ch = _FALSE; /* _FALSE: asign channel directly */ + bool needed = _FALSE; + + rtw_mi_status_no_self(adapter, &mstate); + rtw_mi_get_ch_setting_union_no_self(adapter, &u_ch, &u_bw, &u_offset); + if (u_ch != 0) + sync_ch = _TRUE; + + switch (self_action) { + case MLME_STA_CONNECTING: + MSTATE_STA_LG_NUM(&mstate)++; + break; + case MLME_STA_CONNECTED: + MSTATE_STA_LD_NUM(&mstate)++; + break; + case MLME_AP_STARTED: + MSTATE_AP_NUM(&mstate)++; + break; + case MLME_AP_STOPPED: + case MLME_STA_DISCONNECTED: + default: + break; + } + + if (sync_ch == _TRUE) { + if (!rtw_is_chbw_grouped(mlmeext->cur_channel, mlmeext->cur_bwmode, mlmeext->cur_ch_offset, u_ch, u_bw, u_offset)) { + RTW_INFO(FUNC_ADPT_FMT" can't sync %u,%u,%u with %u,%u,%u\n", FUNC_ADPT_ARG(adapter) + , mlmeext->cur_channel, mlmeext->cur_bwmode, mlmeext->cur_ch_offset, u_ch, u_bw, u_offset); + goto apply; + } + + rtw_sync_chbw(&mlmeext->cur_channel, &mlmeext->cur_bwmode, &mlmeext->cur_ch_offset + , &u_ch, &u_bw, &u_offset); + } else { + u_ch = mlmeext->cur_channel; + u_bw = mlmeext->cur_bwmode; + u_offset = mlmeext->cur_ch_offset; + } + + if (MSTATE_STA_LD_NUM(&mstate) > 0) { + /* rely on AP on which STA mode connects */ + if (rtw_is_dfs_ch(u_ch, u_bw, u_offset)) + ld_sta_in_dfs = _TRUE; + goto apply; + } + + if (MSTATE_STA_LG_NUM(&mstate) > 0) { + /* STA mode is linking */ + goto apply; + } + + if (MSTATE_AP_NUM(&mstate) == 0) { + /* No working AP mode */ + goto apply; + } + + if (rtw_is_dfs_ch(u_ch, u_bw, u_offset)) + needed = _TRUE; + +apply: + + RTW_INFO(FUNC_ADPT_FMT" needed:%d, self_action:%u\n" + , FUNC_ADPT_ARG(adapter), needed, self_action); + RTW_INFO(FUNC_ADPT_FMT" ld_sta_num:%u, lg_sta_num:%u, ap_num:%u, %u,%u,%u\n" + , FUNC_ADPT_ARG(adapter), MSTATE_STA_LD_NUM(&mstate), MSTATE_STA_LG_NUM(&mstate), MSTATE_AP_NUM(&mstate) + , u_ch, u_bw, u_offset); + + if (needed == _TRUE) + rtw_dfs_master_enable(adapter, u_ch, u_bw, u_offset); + else + rtw_dfs_master_disable(adapter, u_ch, u_bw, u_offset, ld_sta_in_dfs); +} +#endif /* CONFIG_DFS_MASTER */ + +#endif /* CONFIG_AP_MODE */ + +#ifdef CONFIG_BT_COEXIST +struct btinfo { + u8 cid; + u8 len; + + u8 bConnection:1; + u8 bSCOeSCO:1; + u8 bInQPage:1; + u8 bACLBusy:1; + u8 bSCOBusy:1; + u8 bHID:1; + u8 bA2DP:1; + u8 bFTP:1; + + u8 retry_cnt:4; + u8 rsvd_34:1; + u8 rsvd_35:1; + u8 rsvd_36:1; + u8 rsvd_37:1; + + u8 rssi; + + u8 rsvd_50:1; + u8 rsvd_51:1; + u8 rsvd_52:1; + u8 rsvd_53:1; + u8 rsvd_54:1; + u8 rsvd_55:1; + u8 eSCO_SCO:1; + u8 Master_Slave:1; + + u8 rsvd_6; + u8 rsvd_7; +}; + +void btinfo_evt_dump(void *sel, void *buf) +{ + struct btinfo *info = (struct btinfo *)buf; + + RTW_PRINT_SEL(sel, "cid:0x%02x, len:%u\n", info->cid, info->len); + + if (info->len > 2) + RTW_PRINT_SEL(sel, "byte2:%s%s%s%s%s%s%s%s\n" + , info->bConnection ? "bConnection " : "" + , info->bSCOeSCO ? "bSCOeSCO " : "" + , info->bInQPage ? "bInQPage " : "" + , info->bACLBusy ? "bACLBusy " : "" + , info->bSCOBusy ? "bSCOBusy " : "" + , info->bHID ? "bHID " : "" + , info->bA2DP ? "bA2DP " : "" + , info->bFTP ? "bFTP" : "" + ); + + if (info->len > 3) + RTW_PRINT_SEL(sel, "retry_cnt:%u\n", info->retry_cnt); + + if (info->len > 4) + RTW_PRINT_SEL(sel, "rssi:%u\n", info->rssi); + + if (info->len > 5) + RTW_PRINT_SEL(sel, "byte5:%s%s\n" + , info->eSCO_SCO ? "eSCO_SCO " : "" + , info->Master_Slave ? "Master_Slave " : "" + ); +} + +static void rtw_btinfo_hdl(_adapter *adapter, u8 *buf, u16 buf_len) +{ +#define BTINFO_WIFI_FETCH 0x23 +#define BTINFO_BT_AUTO_RPT 0x27 +#ifdef CONFIG_BT_COEXIST_SOCKET_TRX + struct btinfo_8761ATV *info = (struct btinfo_8761ATV *)buf; +#else /* !CONFIG_BT_COEXIST_SOCKET_TRX */ + struct btinfo *info = (struct btinfo *)buf; +#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ + u8 cmd_idx; + u8 len; + + cmd_idx = info->cid; + + if (info->len > buf_len - 2) { + rtw_warn_on(1); + len = buf_len - 2; + } else + len = info->len; + + /* #define DBG_PROC_SET_BTINFO_EVT */ +#ifdef DBG_PROC_SET_BTINFO_EVT +#ifdef CONFIG_BT_COEXIST_SOCKET_TRX + RTW_INFO("%s: btinfo[0]=%x,btinfo[1]=%x,btinfo[2]=%x,btinfo[3]=%x btinfo[4]=%x,btinfo[5]=%x,btinfo[6]=%x,btinfo[7]=%x\n" + , __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); +#else/* !CONFIG_BT_COEXIST_SOCKET_TRX */ + btinfo_evt_dump(RTW_DBGDUMP, info); +#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ +#endif /* DBG_PROC_SET_BTINFO_EVT */ + + /* transform BT-FW btinfo to WiFI-FW C2H format and notify */ + if (cmd_idx == BTINFO_WIFI_FETCH) + buf[1] = 0; + else if (cmd_idx == BTINFO_BT_AUTO_RPT) + buf[1] = 2; +#ifdef CONFIG_BT_COEXIST_SOCKET_TRX + else if (0x01 == cmd_idx || 0x02 == cmd_idx) + buf[1] = buf[0]; +#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ + rtw_btcoex_BtInfoNotify(adapter , len + 1, &buf[1]); +} + +u8 rtw_btinfo_cmd(_adapter *adapter, u8 *buf, u16 len) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + u8 *btinfo; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + u8 res = _SUCCESS; + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + btinfo = rtw_zmalloc(len); + if (btinfo == NULL) { + rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); + rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = BTINFO_WK_CID; + pdrvextra_cmd_parm->type = 0; + pdrvextra_cmd_parm->size = len; + pdrvextra_cmd_parm->pbuf = btinfo; + + _rtw_memcpy(btinfo, buf, len); + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + return res; +} +#endif /* CONFIG_BT_COEXIST */ + +u8 rtw_test_h2c_cmd(_adapter *adapter, u8 *buf, u8 len) +{ + struct cmd_obj *pcmdobj; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + u8 *ph2c_content; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + u8 res = _SUCCESS; + + pcmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmdobj == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + ph2c_content = rtw_zmalloc(len); + if (ph2c_content == NULL) { + rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj)); + rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = TEST_H2C_CID; + pdrvextra_cmd_parm->type = 0; + pdrvextra_cmd_parm->size = len; + pdrvextra_cmd_parm->pbuf = ph2c_content; + + _rtw_memcpy(ph2c_content, buf, len); + + init_h2fwcmd_w_parm_no_rsp(pcmdobj, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); + +exit: + return res; +} + +static s32 rtw_mp_cmd_hdl(_adapter *padapter, u8 mp_cmd_id) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + int ret = H2C_SUCCESS; + u8 rfreg0; + + if (mp_cmd_id == MP_START) { + if (padapter->registrypriv.mp_mode == 0) { + rtw_hal_deinit(padapter); + padapter->registrypriv.mp_mode = 1; +#ifdef CONFIG_RF_POWER_TRIM + if (!IS_HARDWARE_TYPE_8814A(padapter) && !IS_HARDWARE_TYPE_8822B(padapter)) { + padapter->registrypriv.RegPwrTrimEnable = 1; + rtw_hal_read_chip_info(padapter); + } +#endif /*CONFIG_RF_POWER_TRIM*/ + rtw_hal_init(padapter); +#ifdef RTW_HALMAC /*for New IC*/ + MPT_InitializeAdapter(padapter, 1); +#endif /* CONFIG_MP_INCLUDED */ + } + + if (padapter->registrypriv.mp_mode == 0) { + ret = H2C_REJECTED; + goto exit; + } + + if (padapter->mppriv.mode == MP_OFF) { + if (mp_start_test(padapter) == _FAIL) { + ret = H2C_REJECTED; + goto exit; + } + padapter->mppriv.mode = MP_ON; + MPT_PwrCtlDM(padapter, 0); + } + padapter->mppriv.bmac_filter = _FALSE; +#ifdef CONFIG_RTL8723B +#ifdef CONFIG_USB_HCI + rtw_write32(padapter, 0x765, 0x0000); + rtw_write32(padapter, 0x948, 0x0280); +#else + rtw_write32(padapter, 0x765, 0x0000); + rtw_write32(padapter, 0x948, 0x0000); +#endif +#ifdef CONFIG_FOR_RTL8723BS_VQ0 + rtw_write32(padapter, 0x765, 0x0000); + rtw_write32(padapter, 0x948, 0x0280); +#endif + rtw_write8(padapter, 0x66, 0x27); /*Open BT uart Log*/ + rtw_write8(padapter, 0xc50, 0x20); /*for RX init Gain*/ +#endif +#ifdef CONFIG_RTL8188F + RTW_INFO("Set reg 0x88c, 0x58, 0x00\n"); + rfreg0 = phy_query_rf_reg(padapter, RF_PATH_A, 0x0, 0x1f); + phy_set_bb_reg(padapter, 0x88c, BIT21|BIT20, 0x3); + phy_set_rf_reg(padapter, RF_PATH_A, 0x58, BIT1, 0x1); + phy_set_rf_reg(padapter, RF_PATH_A, 0x0, 0xF001f, 0x2001f); + rtw_msleep_os(200); + phy_set_rf_reg(padapter, RF_PATH_A, 0x0, 0xF001f, 0x30000 | rfreg0); + phy_set_rf_reg(padapter, RF_PATH_A, 0x58, BIT1, 0x0); + phy_set_bb_reg(padapter, 0x88c, BIT21|BIT20, 0x0); + rtw_msleep_os(1000); +#endif + + odm_write_dig(&pHalData->odmpriv, 0x20); + + } else if (mp_cmd_id == MP_STOP) { + if (padapter->registrypriv.mp_mode == 1) { + MPT_DeInitAdapter(padapter); + rtw_hal_deinit(padapter); + padapter->registrypriv.mp_mode = 0; + rtw_hal_init(padapter); + } + + if (padapter->mppriv.mode != MP_OFF) { + mp_stop_test(padapter); + padapter->mppriv.mode = MP_OFF; + } + + } else { + RTW_INFO(FUNC_ADPT_FMT"invalid id:%d\n", FUNC_ADPT_ARG(padapter), mp_cmd_id); + ret = H2C_PARAMETERS_ERROR; + rtw_warn_on(1); + } + +exit: + return ret; +} + +u8 rtw_mp_cmd(_adapter *adapter, u8 mp_cmd_id, u8 flags) +{ + struct cmd_obj *cmdobj; + struct drvextra_cmd_parm *parm; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + struct submit_ctx sctx; + u8 res = _SUCCESS; + + parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (parm == NULL) { + res = _FAIL; + goto exit; + } + + parm->ec_id = MP_CMD_WK_CID; + parm->type = mp_cmd_id; + parm->size = 0; + parm->pbuf = NULL; + + if (flags & RTW_CMDF_DIRECTLY) { + /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ + if (H2C_SUCCESS != rtw_mp_cmd_hdl(adapter, mp_cmd_id)) + res = _FAIL; + rtw_mfree((u8 *)parm, sizeof(*parm)); + } else { + /* need enqueue, prepare cmd_obj and enqueue */ + cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj)); + if (cmdobj == NULL) { + res = _FAIL; + rtw_mfree((u8 *)parm, sizeof(*parm)); + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(cmdobj, parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + if (flags & RTW_CMDF_WAIT_ACK) { + cmdobj->sctx = &sctx; + rtw_sctx_init(&sctx, 10 * 1000); + } + + res = rtw_enqueue_cmd(pcmdpriv, cmdobj); + + if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) { + rtw_sctx_wait(&sctx, __func__); + _enter_critical_mutex(&pcmdpriv->sctx_mutex, NULL); + if (sctx.status == RTW_SCTX_SUBMITTED) + cmdobj->sctx = NULL; + _exit_critical_mutex(&pcmdpriv->sctx_mutex, NULL); + if (sctx.status != RTW_SCTX_DONE_SUCCESS) + res = _FAIL; + } + } + +exit: + return res; +} + +#ifdef CONFIG_RTW_CUSTOMER_STR +static s32 rtw_customer_str_cmd_hdl(_adapter *adapter, u8 write, const u8 *cstr) +{ + int ret = H2C_SUCCESS; + + if (write) + ret = rtw_hal_h2c_customer_str_write(adapter, cstr); + else + ret = rtw_hal_h2c_customer_str_req(adapter); + + return ret == _SUCCESS ? H2C_SUCCESS : H2C_REJECTED; +} + +static u8 rtw_customer_str_cmd(_adapter *adapter, u8 write, const u8 *cstr) +{ + struct cmd_obj *cmdobj; + struct drvextra_cmd_parm *parm; + u8 *str = NULL; + struct cmd_priv *pcmdpriv = &adapter->cmdpriv; + struct submit_ctx sctx; + u8 res = _SUCCESS; + + parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (parm == NULL) { + res = _FAIL; + goto exit; + } + + if (write) { + str = rtw_zmalloc(RTW_CUSTOMER_STR_LEN); + if (str == NULL) { + rtw_mfree((u8 *)parm, sizeof(struct drvextra_cmd_parm)); + res = _FAIL; + goto exit; + } + } + + parm->ec_id = CUSTOMER_STR_WK_CID; + parm->type = write; + parm->size = write ? RTW_CUSTOMER_STR_LEN : 0; + parm->pbuf = write ? str : NULL; + + if (write) + _rtw_memcpy(str, cstr, RTW_CUSTOMER_STR_LEN); + + /* need enqueue, prepare cmd_obj and enqueue */ + cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj)); + if (cmdobj == NULL) { + res = _FAIL; + rtw_mfree((u8 *)parm, sizeof(*parm)); + if (write) + rtw_mfree(str, RTW_CUSTOMER_STR_LEN); + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(cmdobj, parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + cmdobj->sctx = &sctx; + rtw_sctx_init(&sctx, 2 * 1000); + + res = rtw_enqueue_cmd(pcmdpriv, cmdobj); + + if (res == _SUCCESS) { + rtw_sctx_wait(&sctx, __func__); + _enter_critical_mutex(&pcmdpriv->sctx_mutex, NULL); + if (sctx.status == RTW_SCTX_SUBMITTED) + cmdobj->sctx = NULL; + _exit_critical_mutex(&pcmdpriv->sctx_mutex, NULL); + if (sctx.status != RTW_SCTX_DONE_SUCCESS) + res = _FAIL; + } + +exit: + return res; +} + +inline u8 rtw_customer_str_req_cmd(_adapter *adapter) +{ + return rtw_customer_str_cmd(adapter, 0, NULL); +} + +inline u8 rtw_customer_str_write_cmd(_adapter *adapter, const u8 *cstr) +{ + return rtw_customer_str_cmd(adapter, 1, cstr); +} +#endif /* CONFIG_RTW_CUSTOMER_STR */ + +u8 rtw_c2h_wk_cmd(PADAPTER padapter, u8 *pbuf, u16 length, u8 type) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 *extra_cmd_buf; + u8 res = _SUCCESS; + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + extra_cmd_buf = rtw_zmalloc(length); + if (extra_cmd_buf == NULL) { + rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); + rtw_mfree((u8 *)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm)); + res = _FAIL; + goto exit; + } + + _rtw_memcpy(extra_cmd_buf, pbuf, length); + pdrvextra_cmd_parm->ec_id = C2H_WK_CID; + pdrvextra_cmd_parm->type = type; + pdrvextra_cmd_parm->size = length; + pdrvextra_cmd_parm->pbuf = extra_cmd_buf; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + return res; +} + +#ifdef CONFIG_FW_C2H_REG +inline u8 rtw_c2h_reg_wk_cmd(_adapter *adapter, u8 *c2h_evt) +{ + return rtw_c2h_wk_cmd(adapter, c2h_evt, c2h_evt ? C2H_REG_LEN : 0, C2H_TYPE_REG); +} +#endif + +#ifdef CONFIG_FW_C2H_PKT +inline u8 rtw_c2h_packet_wk_cmd(_adapter *adapter, u8 *c2h_evt, u16 length) +{ + return rtw_c2h_wk_cmd(adapter, c2h_evt, length, C2H_TYPE_PKT); +} +#endif + +u8 rtw_run_in_thread_cmd(PADAPTER padapter, void (*func)(void *), void *context) +{ + struct cmd_priv *pcmdpriv; + struct cmd_obj *ph2c; + struct RunInThread_param *parm; + s32 res = _SUCCESS; + + + pcmdpriv = &padapter->cmdpriv; + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (NULL == ph2c) { + res = _FAIL; + goto exit; + } + + parm = (struct RunInThread_param *)rtw_zmalloc(sizeof(struct RunInThread_param)); + if (NULL == parm) { + rtw_mfree((u8 *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + parm->func = func; + parm->context = context; + init_h2fwcmd_w_parm_no_rsp(ph2c, parm, GEN_CMD_CODE(_RunInThreadCMD)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); +exit: + + + return res; +} + +#ifdef CONFIG_FW_C2H_REG +s32 c2h_evt_hdl(_adapter *adapter, u8 *c2h_evt, c2h_id_filter filter) +{ + s32 ret = _FAIL; + u8 buf[C2H_REG_LEN] = {0}; + u8 id, seq, plen; + u8 *payload; + + if (!c2h_evt) { + /* No c2h event in cmd_obj, read c2h event before handling*/ + if (rtw_hal_c2h_evt_read(adapter, buf) != _SUCCESS) + goto exit; + c2h_evt = buf; + } + + rtw_hal_c2h_reg_hdr_parse(adapter, c2h_evt, &id, &seq, &plen, &payload); + + if (filter && filter(adapter, id, seq, plen, payload) == _FALSE) + goto exit; + + ret = rtw_hal_c2h_handler(adapter, id, seq, plen, payload); + +exit: + return ret; +} +#endif /* CONFIG_FW_C2H_REG */ + +u8 session_tracker_cmd(_adapter *adapter, u8 cmd, struct sta_info *sta, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port) +{ + struct cmd_priv *cmdpriv = &adapter->cmdpriv; + struct cmd_obj *cmdobj; + struct drvextra_cmd_parm *cmd_parm; + struct st_cmd_parm *st_parm; + u8 res = _SUCCESS; + + cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (cmdobj == NULL) { + res = _FAIL; + goto exit; + } + + cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (cmd_parm == NULL) { + rtw_mfree((u8 *)cmdobj, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + st_parm = (struct st_cmd_parm *)rtw_zmalloc(sizeof(struct st_cmd_parm)); + if (st_parm == NULL) { + rtw_mfree((u8 *)cmdobj, sizeof(struct cmd_obj)); + rtw_mfree((u8 *)cmd_parm, sizeof(struct drvextra_cmd_parm)); + res = _FAIL; + goto exit; + } + + st_parm->cmd = cmd; + st_parm->sta = sta; + if (cmd != ST_CMD_CHK) { + _rtw_memcpy(&st_parm->local_naddr, local_naddr, 4); + _rtw_memcpy(&st_parm->local_port, local_port, 2); + _rtw_memcpy(&st_parm->remote_naddr, remote_naddr, 4); + _rtw_memcpy(&st_parm->remote_port, remote_port, 2); + } + + cmd_parm->ec_id = SESSION_TRACKER_WK_CID; + cmd_parm->type = 0; + cmd_parm->size = sizeof(struct st_cmd_parm); + cmd_parm->pbuf = (u8 *)st_parm; + init_h2fwcmd_w_parm_no_rsp(cmdobj, cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + cmdobj->no_io = 1; + + res = rtw_enqueue_cmd(cmdpriv, cmdobj); + +exit: + return res; +} + +inline u8 session_tracker_chk_cmd(_adapter *adapter, struct sta_info *sta) +{ + return session_tracker_cmd(adapter, ST_CMD_CHK, sta, NULL, NULL, NULL, NULL); +} + +inline u8 session_tracker_add_cmd(_adapter *adapter, struct sta_info *sta, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port) +{ + return session_tracker_cmd(adapter, ST_CMD_ADD, sta, local_naddr, local_port, remote_naddr, remote_port); +} + +inline u8 session_tracker_del_cmd(_adapter *adapter, struct sta_info *sta, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port) +{ + return session_tracker_cmd(adapter, ST_CMD_DEL, sta, local_naddr, local_port, remote_naddr, remote_port); +} + +void session_tracker_chk_for_sta(_adapter *adapter, struct sta_info *sta) +{ + struct st_ctl_t *st_ctl = &sta->st_ctl; + int i; + _irqL irqL; + _list *plist, *phead, *pnext; + _list dlist; + struct session_tracker *st = NULL; + u8 op_wfd_mode = MIRACAST_DISABLED; + + if (DBG_SESSION_TRACKER) + RTW_INFO(FUNC_ADPT_FMT" sta:%p\n", FUNC_ADPT_ARG(adapter), sta); + + if (!(sta->state & _FW_LINKED)) + goto exit; + + for (i = 0; i < SESSION_TRACKER_REG_ID_NUM; i++) { + if (st_ctl->reg[i].s_proto != 0) + break; + } + if (i >= SESSION_TRACKER_REG_ID_NUM) + goto chk_sta; + + _rtw_init_listhead(&dlist); + + _enter_critical_bh(&st_ctl->tracker_q.lock, &irqL); + + phead = &st_ctl->tracker_q.queue; + plist = get_next(phead); + pnext = get_next(plist); + while (rtw_end_of_queue_search(phead, plist) == _FALSE) { + st = LIST_CONTAINOR(plist, struct session_tracker, list); + plist = pnext; + pnext = get_next(pnext); + + if (st->status != ST_STATUS_ESTABLISH + && rtw_get_passing_time_ms(st->set_time) > ST_EXPIRE_MS + ) { + rtw_list_delete(&st->list); + rtw_list_insert_tail(&st->list, &dlist); + } + + /* TODO: check OS for status update */ + if (st->status == ST_STATUS_CHECK) + st->status = ST_STATUS_ESTABLISH; + + if (st->status != ST_STATUS_ESTABLISH) + continue; + + #ifdef CONFIG_WFD + if (0) + RTW_INFO(FUNC_ADPT_FMT" local:%u, remote:%u, rtsp:%u, %u, %u\n", FUNC_ADPT_ARG(adapter) + , ntohs(st->local_port), ntohs(st->remote_port), adapter->wfd_info.rtsp_ctrlport, adapter->wfd_info.tdls_rtsp_ctrlport + , adapter->wfd_info.peer_rtsp_ctrlport); + if (ntohs(st->local_port) == adapter->wfd_info.rtsp_ctrlport) + op_wfd_mode |= MIRACAST_SINK; + if (ntohs(st->local_port) == adapter->wfd_info.tdls_rtsp_ctrlport) + op_wfd_mode |= MIRACAST_SINK; + if (ntohs(st->remote_port) == adapter->wfd_info.peer_rtsp_ctrlport) + op_wfd_mode |= MIRACAST_SOURCE; + #endif + } + + _exit_critical_bh(&st_ctl->tracker_q.lock, &irqL); + + plist = get_next(&dlist); + while (rtw_end_of_queue_search(&dlist, plist) == _FALSE) { + st = LIST_CONTAINOR(plist, struct session_tracker, list); + plist = get_next(plist); + rtw_mfree((u8 *)st, sizeof(struct session_tracker)); + } + +chk_sta: + if (STA_OP_WFD_MODE(sta) != op_wfd_mode) { + STA_SET_OP_WFD_MODE(sta, op_wfd_mode); + rtw_sta_media_status_rpt_cmd(adapter, sta, 1); + } + +exit: + return; +} + +void session_tracker_chk_for_adapter(_adapter *adapter) +{ + struct sta_priv *stapriv = &adapter->stapriv; + struct sta_info *sta; + int i; + _irqL irqL; + _list *plist, *phead; + u8 op_wfd_mode = MIRACAST_DISABLED; + + _enter_critical_bh(&stapriv->sta_hash_lock, &irqL); + + for (i = 0; i < NUM_STA; i++) { + phead = &(stapriv->sta_hash[i]); + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + sta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + plist = get_next(plist); + + session_tracker_chk_for_sta(adapter, sta); + + op_wfd_mode |= STA_OP_WFD_MODE(sta); + } + } + + _exit_critical_bh(&stapriv->sta_hash_lock, &irqL); + +#ifdef CONFIG_WFD + adapter->wfd_info.op_wfd_mode = MIRACAST_MODE_REVERSE(op_wfd_mode); +#endif +} + +void session_tracker_cmd_hdl(_adapter *adapter, struct st_cmd_parm *parm) +{ + u8 cmd = parm->cmd; + struct sta_info *sta = parm->sta; + + if (cmd == ST_CMD_CHK) { + if (sta) + session_tracker_chk_for_sta(adapter, sta); + else + session_tracker_chk_for_adapter(adapter); + + goto exit; + + } else if (cmd == ST_CMD_ADD || cmd == ST_CMD_DEL) { + struct st_ctl_t *st_ctl; + u32 local_naddr = parm->local_naddr; + u16 local_port = parm->local_port; + u32 remote_naddr = parm->remote_naddr; + u16 remote_port = parm->remote_port; + struct session_tracker *st = NULL; + _irqL irqL; + _list *plist, *phead; + u8 free_st = 0; + u8 alloc_st = 0; + + if (DBG_SESSION_TRACKER) + RTW_INFO(FUNC_ADPT_FMT" cmd:%u, sta:%p, local:"IP_FMT":"PORT_FMT", remote:"IP_FMT":"PORT_FMT"\n" + , FUNC_ADPT_ARG(adapter), cmd, sta + , IP_ARG(&local_naddr), PORT_ARG(&local_port) + , IP_ARG(&remote_naddr), PORT_ARG(&remote_port) + ); + + if (!(sta->state & _FW_LINKED)) + goto exit; + + st_ctl = &sta->st_ctl; + + _enter_critical_bh(&st_ctl->tracker_q.lock, &irqL); + + phead = &st_ctl->tracker_q.queue; + plist = get_next(phead); + while (rtw_end_of_queue_search(phead, plist) == _FALSE) { + st = LIST_CONTAINOR(plist, struct session_tracker, list); + + if (st->local_naddr == local_naddr + && st->local_port == local_port + && st->remote_naddr == remote_naddr + && st->remote_port == remote_port) + break; + + plist = get_next(plist); + } + + if (rtw_end_of_queue_search(phead, plist) == _TRUE) + st = NULL; + + switch (cmd) { + case ST_CMD_DEL: + if (st) { + rtw_list_delete(plist); + free_st = 1; + } + goto unlock; + case ST_CMD_ADD: + if (!st) + alloc_st = 1; + } + +unlock: + _exit_critical_bh(&st_ctl->tracker_q.lock, &irqL); + + if (free_st) { + rtw_mfree((u8 *)st, sizeof(struct session_tracker)); + goto exit; + } + + if (alloc_st) { + st = (struct session_tracker *)rtw_zmalloc(sizeof(struct session_tracker)); + if (!st) + goto exit; + + st->local_naddr = local_naddr; + st->local_port = local_port; + st->remote_naddr = remote_naddr; + st->remote_port = remote_port; + st->set_time = rtw_get_current_time(); + st->status = ST_STATUS_CHECK; + + _enter_critical_bh(&st_ctl->tracker_q.lock, &irqL); + rtw_list_insert_tail(&st->list, phead); + _exit_critical_bh(&st_ctl->tracker_q.lock, &irqL); + } + } + +exit: + return; +} + +u8 rtw_drvextra_cmd_hdl(_adapter *padapter, unsigned char *pbuf) +{ + int ret = H2C_SUCCESS; + struct drvextra_cmd_parm *pdrvextra_cmd; + + if (!pbuf) + return H2C_PARAMETERS_ERROR; + + pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf; + + switch (pdrvextra_cmd->ec_id) { + case STA_MSTATUS_RPT_WK_CID: + rtw_sta_media_status_rpt_cmd_hdl(padapter, (struct sta_media_status_rpt_cmd_parm *)pdrvextra_cmd->pbuf); + break; + + case DYNAMIC_CHK_WK_CID:/*only primary padapter go to this cmd, but execute dynamic_chk_wk_hdl() for two interfaces */ + rtw_dynamic_chk_wk_hdl(padapter); + break; + case POWER_SAVING_CTRL_WK_CID: + power_saving_wk_hdl(padapter); + break; +#ifdef CONFIG_LPS + case LPS_CTRL_WK_CID: + lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type); + break; + case DM_IN_LPS_WK_CID: + rtw_dm_in_lps_hdl(padapter); + break; + case LPS_CHANGE_DTIM_CID: + rtw_lps_change_dtim_hdl(padapter, (u8)pdrvextra_cmd->type); + break; +#endif +#if (RATE_ADAPTIVE_SUPPORT == 1) + case RTP_TIMER_CFG_WK_CID: + rpt_timer_setting_wk_hdl(padapter, pdrvextra_cmd->type); + break; +#endif +#ifdef CONFIG_ANTENNA_DIVERSITY + case ANT_SELECT_WK_CID: + antenna_select_wk_hdl(padapter, pdrvextra_cmd->type); + break; +#endif +#ifdef CONFIG_P2P_PS + case P2P_PS_WK_CID: + p2p_ps_wk_hdl(padapter, pdrvextra_cmd->type); + break; +#endif +#ifdef CONFIG_P2P + case P2P_PROTO_WK_CID: + /* + * Commented by Albert 2011/07/01 + * I used the type_size as the type command + */ + ret = p2p_protocol_wk_hdl(padapter, pdrvextra_cmd->type, pdrvextra_cmd->pbuf); + break; +#endif +#ifdef CONFIG_AP_MODE + case CHECK_HIQ_WK_CID: + rtw_chk_hi_queue_hdl(padapter); + break; +#endif +#ifdef CONFIG_INTEL_WIDI + case INTEl_WIDI_WK_CID: + intel_widi_wk_hdl(padapter, pdrvextra_cmd->type, pdrvextra_cmd->pbuf); + break; +#endif + /* add for CONFIG_IEEE80211W, none 11w can use it */ + case RESET_SECURITYPRIV: + reset_securitypriv_hdl(padapter); + break; + case FREE_ASSOC_RESOURCES: + free_assoc_resources_hdl(padapter); + break; + case C2H_WK_CID: + switch (pdrvextra_cmd->type) { + #ifdef CONFIG_FW_C2H_REG + case C2H_TYPE_REG: + c2h_evt_hdl(padapter, pdrvextra_cmd->pbuf, NULL); + break; + #endif + #ifdef CONFIG_FW_C2H_PKT + case C2H_TYPE_PKT: + rtw_hal_c2h_pkt_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->size); + break; + #endif + default: + RTW_ERR("unknown C2H type:%d\n", pdrvextra_cmd->type); + rtw_warn_on(1); + break; + } + break; +#ifdef CONFIG_BEAMFORMING + case BEAMFORMING_WK_CID: + beamforming_wk_hdl(padapter, pdrvextra_cmd->type, pdrvextra_cmd->pbuf); + break; +#endif + case DM_RA_MSK_WK_CID: + rtw_dm_ra_mask_hdl(padapter, (struct sta_info *)pdrvextra_cmd->pbuf); + break; +#ifdef CONFIG_BT_COEXIST + case BTINFO_WK_CID: + rtw_btinfo_hdl(padapter, pdrvextra_cmd->pbuf, pdrvextra_cmd->size); + break; +#endif +#ifdef CONFIG_DFS_MASTER + case DFS_MASTER_WK_CID: + rtw_dfs_master_hdl(padapter); + break; +#endif + case SESSION_TRACKER_WK_CID: + session_tracker_cmd_hdl(padapter, (struct st_cmd_parm *)pdrvextra_cmd->pbuf); + break; + case EN_HW_UPDATE_TSF_WK_CID: + rtw_hal_set_hwreg(padapter, HW_VAR_EN_HW_UPDATE_TSF, NULL); + break; + case TEST_H2C_CID: + rtw_hal_fill_h2c_cmd(padapter, pdrvextra_cmd->pbuf[0], pdrvextra_cmd->size - 1, &pdrvextra_cmd->pbuf[1]); + break; + case MP_CMD_WK_CID: + ret = rtw_mp_cmd_hdl(padapter, pdrvextra_cmd->type); + break; +#ifdef CONFIG_RTW_CUSTOMER_STR + case CUSTOMER_STR_WK_CID: + ret = rtw_customer_str_cmd_hdl(padapter, pdrvextra_cmd->type, pdrvextra_cmd->pbuf); + break; +#endif + default: + break; + } + + if (pdrvextra_cmd->pbuf && pdrvextra_cmd->size > 0) + rtw_mfree(pdrvextra_cmd->pbuf, pdrvextra_cmd->size); + + return ret; +} + +void rtw_survey_cmd_callback(_adapter *padapter , struct cmd_obj *pcmd) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + + if (pcmd->res == H2C_DROPPED) { + /* TODO: cancel timer and do timeout handler directly... */ + /* need to make timeout handlerOS independent */ + mlme_set_scan_to_timer(pmlmepriv, 1); + } else if (pcmd->res != H2C_SUCCESS) { + mlme_set_scan_to_timer(pmlmepriv, 1); + } + + /* free cmd */ + rtw_free_cmd_obj(pcmd); + +} +void rtw_disassoc_cmd_callback(_adapter *padapter, struct cmd_obj *pcmd) +{ + _irqL irqL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + + if (pcmd->res != H2C_SUCCESS) { + _enter_critical_bh(&pmlmepriv->lock, &irqL); + set_fwstate(pmlmepriv, _FW_LINKED); + _exit_critical_bh(&pmlmepriv->lock, &irqL); + goto exit; + } +#ifdef CONFIG_BR_EXT + else /* clear bridge database */ + nat25_db_cleanup(padapter); +#endif /* CONFIG_BR_EXT */ + + /* free cmd */ + rtw_free_cmd_obj(pcmd); + +exit: + return; +} + + +void rtw_getmacreg_cmdrsp_callback(_adapter *padapter, struct cmd_obj *pcmd) +{ + + + rtw_free_cmd_obj(pcmd); + +} + +void rtw_joinbss_cmd_callback(_adapter *padapter, struct cmd_obj *pcmd) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + + if (pcmd->res == H2C_DROPPED) { + /* TODO: cancel timer and do timeout handler directly... */ + /* need to make timeout handlerOS independent */ + _set_timer(&pmlmepriv->assoc_timer, 1); + } else if (pcmd->res != H2C_SUCCESS) + _set_timer(&pmlmepriv->assoc_timer, 1); + + rtw_free_cmd_obj(pcmd); + +} + +void rtw_create_ibss_post_hdl(_adapter *padapter, int status) +{ + _irqL irqL; + u8 timer_cancelled; + struct sta_info *psta = NULL; + struct wlan_network *pwlan = NULL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + WLAN_BSSID_EX *pdev_network = &padapter->registrypriv.dev_network; + struct wlan_network *mlme_cur_network = &(pmlmepriv->cur_network); + + if (status != H2C_SUCCESS) + _set_timer(&pmlmepriv->assoc_timer, 1); + + _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled); + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + { + _irqL irqL; + + pwlan = _rtw_alloc_network(pmlmepriv); + _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + if (pwlan == NULL) { + pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue); + if (pwlan == NULL) { + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + goto createbss_cmd_fail; + } + pwlan->last_scanned = rtw_get_current_time(); + } else + rtw_list_insert_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); + + pdev_network->Length = get_WLAN_BSSID_EX_sz(pdev_network); + _rtw_memcpy(&(pwlan->network), pdev_network, pdev_network->Length); + /* pwlan->fixed = _TRUE; */ + + /* copy pdev_network information to pmlmepriv->cur_network */ + _rtw_memcpy(&mlme_cur_network->network, pdev_network, (get_WLAN_BSSID_EX_sz(pdev_network))); + +#if 0 + /* reset DSConfig */ + mlme_cur_network->network.Configuration.DSConfig = (u32)rtw_ch2freq(pdev_network->Configuration.DSConfig); +#endif + + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + /* we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) */ + } + +createbss_cmd_fail: + _exit_critical_bh(&pmlmepriv->lock, &irqL); +exit: + return; +} + + + +void rtw_setstaKey_cmdrsp_callback(_adapter *padapter , struct cmd_obj *pcmd) +{ + + struct sta_priv *pstapriv = &padapter->stapriv; + struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)(pcmd->rsp); + struct sta_info *psta = rtw_get_stainfo(pstapriv, psetstakey_rsp->addr); + + + if (psta == NULL) { + goto exit; + } + + /* psta->aid = psta->mac_id = psetstakey_rsp->keyid; */ /* CAM_ID(CAM_ENTRY) */ + +exit: + + rtw_free_cmd_obj(pcmd); + + +} +void rtw_setassocsta_cmdrsp_callback(_adapter *padapter, struct cmd_obj *pcmd) +{ + _irqL irqL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf); + struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *)(pcmd->rsp); + struct sta_info *psta = rtw_get_stainfo(pstapriv, passocsta_parm->addr); + + + if (psta == NULL) { + goto exit; + } + + psta->aid = psta->mac_id = passocsta_rsp->cam_id; + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) && (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE)) + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + + set_fwstate(pmlmepriv, _FW_LINKED); + _exit_critical_bh(&pmlmepriv->lock, &irqL); + +exit: + rtw_free_cmd_obj(pcmd); + +} + +void rtw_getrttbl_cmd_cmdrsp_callback(_adapter *padapter, struct cmd_obj *pcmd); +void rtw_getrttbl_cmd_cmdrsp_callback(_adapter *padapter, struct cmd_obj *pcmd) +{ + + rtw_free_cmd_obj(pcmd); +#ifdef CONFIG_MP_INCLUDED + if (padapter->registrypriv.mp_mode == 1) + padapter->mppriv.workparam.bcompleted = _TRUE; +#endif + + +} diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_debug.c b/linux-bsp/drivers/rtl8188eus/core/rtw_debug.c new file mode 100644 index 0000000..0809d82 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_debug.c @@ -0,0 +1,5215 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_DEBUG_C_ + +#include <drv_types.h> +#include <hal_data.h> + +#ifdef CONFIG_RTW_DEBUG +const char *rtw_log_level_str[] = { + "_DRV_NONE_ = 0", + "_DRV_ALWAYS_ = 1", + "_DRV_ERR_ = 2", + "_DRV_WARNING_ = 3", + "_DRV_INFO_ = 4", + "_DRV_DEBUG_ = 5", + "_DRV_MAX_ = 6", +}; +#endif + +#ifdef CONFIG_DEBUG_RTL871X + u64 GlobalDebugComponents = 0; +#endif /* CONFIG_DEBUG_RTL871X */ + +#include <rtw_version.h> + +#ifdef CONFIG_TDLS + #define TDLS_DBG_INFO_SPACE_BTWN_ITEM_AND_VALUE 41 +#endif + +void dump_drv_version(void *sel) +{ + RTW_PRINT_SEL(sel, "%s %s\n", DRV_NAME, DRIVERVERSION); +} + +void dump_drv_cfg(void *sel) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)) + char *kernel_version = utsname()->release; + + RTW_PRINT_SEL(sel, "\nKernel Version: %s\n", kernel_version); +#endif + + RTW_PRINT_SEL(sel, "Driver Version: %s\n", DRIVERVERSION); + RTW_PRINT_SEL(sel, "------------------------------------------------\n"); +#ifdef CONFIG_IOCTL_CFG80211 + RTW_PRINT_SEL(sel, "CFG80211\n"); +#ifdef RTW_USE_CFG80211_STA_EVENT + RTW_PRINT_SEL(sel, "RTW_USE_CFG80211_STA_EVENT\n"); +#endif + #ifdef CONFIG_RADIO_WORK + RTW_PRINT_SEL(sel, "CONFIG_RADIO_WORK\n"); + #endif +#else + RTW_PRINT_SEL(sel, "WEXT\n"); +#endif + + RTW_PRINT_SEL(sel, "DBG:%d\n", DBG); +#ifdef CONFIG_RTW_DEBUG + RTW_PRINT_SEL(sel, "CONFIG_RTW_DEBUG\n"); +#endif + +#ifdef CONFIG_CONCURRENT_MODE + RTW_PRINT_SEL(sel, "CONFIG_CONCURRENT_MODE\n"); +#endif + +#ifdef CONFIG_POWER_SAVING + RTW_PRINT_SEL(sel, "CONFIG_POWER_SAVING\n"); +#endif + +#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE + RTW_PRINT_SEL(sel, "LOAD_PHY_PARA_FROM_FILE - REALTEK_CONFIG_PATH=%s\n", REALTEK_CONFIG_PATH); + #if defined(CONFIG_MULTIDRV) || defined(REALTEK_CONFIG_PATH_WITH_IC_NAME_FOLDER) + RTW_PRINT_SEL(sel, "LOAD_PHY_PARA_FROM_FILE - REALTEK_CONFIG_PATH_WITH_IC_NAME_FOLDER\n"); + #endif + +/* configurations about TX power */ +#ifdef CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY + RTW_PRINT_SEL(sel, "CONFIG_CALIBRATE_TX_POWER_BY_REGULATORY\n"); +#endif +#ifdef CONFIG_CALIBRATE_TX_POWER_TO_MAX + RTW_PRINT_SEL(sel, "CONFIG_CALIBRATE_TX_POWER_TO_MAX\n"); +#endif +#endif + RTW_PRINT_SEL(sel, "RTW_DEF_MODULE_REGULATORY_CERT=0x%02x\n", RTW_DEF_MODULE_REGULATORY_CERT); + + RTW_PRINT_SEL(sel, "CONFIG_TXPWR_BY_RATE_EN=%d\n", CONFIG_TXPWR_BY_RATE_EN); + RTW_PRINT_SEL(sel, "CONFIG_TXPWR_LIMIT_EN=%d\n", CONFIG_TXPWR_LIMIT_EN); + + +#ifdef CONFIG_DISABLE_ODM + RTW_PRINT_SEL(sel, "CONFIG_DISABLE_ODM\n"); +#endif + +#ifdef CONFIG_MINIMAL_MEMORY_USAGE + RTW_PRINT_SEL(sel, "CONFIG_MINIMAL_MEMORY_USAGE\n"); +#endif + + RTW_PRINT_SEL(sel, "CONFIG_RTW_ADAPTIVITY_EN = %d\n", CONFIG_RTW_ADAPTIVITY_EN); +#if (CONFIG_RTW_ADAPTIVITY_EN) + RTW_PRINT_SEL(sel, "ADAPTIVITY_MODE = %s\n", (CONFIG_RTW_ADAPTIVITY_MODE) ? "carrier_sense" : "normal"); +#endif + +#ifdef CONFIG_WOWLAN + RTW_PRINT_SEL(sel, "CONFIG_WOWLAN - "); + +#ifdef CONFIG_GPIO_WAKEUP + RTW_PRINT_SEL(sel, "CONFIG_GPIO_WAKEUP - WAKEUP_GPIO_IDX:%d\n", WAKEUP_GPIO_IDX); +#endif +#endif + +#ifdef CONFIG_TDLS + RTW_PRINT_SEL(sel, "CONFIG_TDLS\n"); +#endif + +#ifdef CONFIG_RTW_80211R + RTW_PRINT_SEL(sel, "CONFIG_RTW_80211R\n"); +#endif + +#ifdef CONFIG_USB_HCI +#ifdef CONFIG_SUPPORT_USB_INT + RTW_PRINT_SEL(sel, "CONFIG_SUPPORT_USB_INT\n"); +#endif +#ifdef CONFIG_USB_INTERRUPT_IN_PIPE + RTW_PRINT_SEL(sel, "CONFIG_USB_INTERRUPT_IN_PIPE\n"); +#endif +#ifdef CONFIG_USB_TX_AGGREGATION + RTW_PRINT_SEL(sel, "CONFIG_USB_TX_AGGREGATION\n"); +#endif +#ifdef CONFIG_USB_RX_AGGREGATION + RTW_PRINT_SEL(sel, "CONFIG_USB_RX_AGGREGATION\n"); +#endif +#ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX + RTW_PRINT_SEL(sel, "CONFIG_USE_USB_BUFFER_ALLOC_TX\n"); +#endif +#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX + RTW_PRINT_SEL(sel, "CONFIG_USE_USB_BUFFER_ALLOC_RX\n"); +#endif +#ifdef CONFIG_PREALLOC_RECV_SKB + RTW_PRINT_SEL(sel, "CONFIG_PREALLOC_RECV_SKB\n"); +#endif +#ifdef CONFIG_FIX_NR_BULKIN_BUFFER + RTW_PRINT_SEL(sel, "CONFIG_FIX_NR_BULKIN_BUFFER\n"); +#endif +#endif /*CONFIG_USB_HCI*/ + +#ifdef CONFIG_SDIO_HCI +#ifdef CONFIG_TX_AGGREGATION + RTW_PRINT_SEL(sel, "CONFIG_TX_AGGREGATION\n"); +#endif +#ifdef CONFIG_RX_AGGREGATION + RTW_PRINT_SEL(sel, "CONFIG_RX_AGGREGATION\n"); +#endif +#endif /*CONFIG_SDIO_HCI*/ + +#ifdef CONFIG_PCI_HCI +#endif + + RTW_PRINT_SEL(sel, "MAX_XMITBUF_SZ = %d\n", MAX_XMITBUF_SZ); + RTW_PRINT_SEL(sel, "MAX_RECVBUF_SZ = %d\n", MAX_RECVBUF_SZ); + +} + +void dump_log_level(void *sel) +{ +#ifdef CONFIG_RTW_DEBUG + int i; + + RTW_PRINT_SEL(sel, "drv_log_level:%d\n", rtw_drv_log_level); + for (i = 0; i <= _DRV_MAX_; i++) { + if (rtw_log_level_str[i]) + RTW_PRINT_SEL(sel, "%c %s = %d\n", + (rtw_drv_log_level == i) ? '+' : ' ', rtw_log_level_str[i], i); + } +#else + RTW_PRINT_SEL(sel, "CONFIG_RTW_DEBUG is disabled\n"); +#endif +} + +#ifdef CONFIG_SDIO_HCI +void sd_f0_reg_dump(void *sel, _adapter *adapter) +{ + int i; + + for (i = 0x0; i <= 0xff; i++) { + if (i % 16 == 0) + RTW_PRINT_SEL(sel, "0x%02x ", i); + + _RTW_PRINT_SEL(sel, "%02x ", rtw_sd_f0_read8(adapter, i)); + + if (i % 16 == 15) + _RTW_PRINT_SEL(sel, "\n"); + else if (i % 8 == 7) + _RTW_PRINT_SEL(sel, "\t"); + } +} + +void sdio_local_reg_dump(void *sel, _adapter *adapter) +{ + int i, j = 1; + + for (i = 0x0; i < 0x100; i += 4) { + if (j % 4 == 1) + RTW_PRINT_SEL(sel, "0x%02x", i); + _RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, (0x1025 << 16) | i)); + if ((j++) % 4 == 0) + _RTW_PRINT_SEL(sel, "\n"); + } +} +#endif /* CONFIG_SDIO_HCI */ + +void mac_reg_dump(void *sel, _adapter *adapter) +{ + int i, j = 1; + + RTW_PRINT_SEL(sel, "======= MAC REG =======\n"); + + for (i = 0x0; i < 0x800; i += 4) { + if (j % 4 == 1) + RTW_PRINT_SEL(sel, "0x%04x", i); + _RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, i)); + if ((j++) % 4 == 0) + _RTW_PRINT_SEL(sel, "\n"); + } + +#ifdef CONFIG_RTL8814A + { + for (i = 0x1000; i < 0x1650; i += 4) { + if (j % 4 == 1) + RTW_PRINT_SEL(sel, "0x%04x", i); + _RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, i)); + if ((j++) % 4 == 0) + _RTW_PRINT_SEL(sel, "\n"); + } + } +#endif /* CONFIG_RTL8814A */ + + +#if defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) + for (i = 0x1000; i < 0x1800; i += 4) { + if (j % 4 == 1) + RTW_PRINT_SEL(sel, "0x%04x", i); + _RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, i)); + if ((j++) % 4 == 0) + _RTW_PRINT_SEL(sel, "\n"); + } +#endif /* CONFIG_RTL8822B */ +} + +void bb_reg_dump(void *sel, _adapter *adapter) +{ + int i, j = 1; + + RTW_PRINT_SEL(sel, "======= BB REG =======\n"); + for (i = 0x800; i < 0x1000; i += 4) { + if (j % 4 == 1) + RTW_PRINT_SEL(sel, "0x%04x", i); + _RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, i)); + if ((j++) % 4 == 0) + _RTW_PRINT_SEL(sel, "\n"); + } + +#if defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) + for (i = 0x1800; i < 0x2000; i += 4) { + if (j % 4 == 1) + RTW_PRINT_SEL(sel, "0x%04x", i); + _RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, i)); + if ((j++) % 4 == 0) + _RTW_PRINT_SEL(sel, "\n"); + } +#endif /* CONFIG_RTL8822B */ +} + +void bb_reg_dump_ex(void *sel, _adapter *adapter) +{ + int i, j = 1; + + RTW_PRINT_SEL(sel, "======= BB REG =======\n"); + for (i = 0x800; i < 0x1000; i += 4) { + RTW_PRINT_SEL(sel, "0x%04x", i); + _RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, i)); + _RTW_PRINT_SEL(sel, "\n"); + } + +#if defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) + for (i = 0x1800; i < 0x2000; i += 4) { + RTW_PRINT_SEL(sel, "0x%04x", i); + _RTW_PRINT_SEL(sel, " 0x%08x ", rtw_read32(adapter, i)); + _RTW_PRINT_SEL(sel, "\n"); + } +#endif /* CONFIG_RTL8822B */ +} + +void rf_reg_dump(void *sel, _adapter *adapter) +{ + int i, j = 1, path; + u32 value; + u8 rf_type = 0; + u8 path_nums = 0; + + rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + if ((RF_1T2R == rf_type) || (RF_1T1R == rf_type)) + path_nums = 1; + else + path_nums = 2; + + RTW_PRINT_SEL(sel, "======= RF REG =======\n"); + + for (path = 0; path < path_nums; path++) { + RTW_PRINT_SEL(sel, "RF_Path(%x)\n", path); + for (i = 0; i < 0x100; i++) { + value = rtw_hal_read_rfreg(adapter, path, i, 0xffffffff); + if (j % 4 == 1) + RTW_PRINT_SEL(sel, "0x%02x ", i); + _RTW_PRINT_SEL(sel, " 0x%08x ", value); + if ((j++) % 4 == 0) + _RTW_PRINT_SEL(sel, "\n"); + } + } +} + +static u8 fwdl_test_chksum_fail = 0; +static u8 fwdl_test_wintint_rdy_fail = 0; + +bool rtw_fwdl_test_trigger_chksum_fail(void) +{ + if (fwdl_test_chksum_fail) { + RTW_PRINT("fwdl test case: trigger chksum_fail\n"); + fwdl_test_chksum_fail--; + return _TRUE; + } + return _FALSE; +} + +bool rtw_fwdl_test_trigger_wintint_rdy_fail(void) +{ + if (fwdl_test_wintint_rdy_fail) { + RTW_PRINT("fwdl test case: trigger wintint_rdy_fail\n"); + fwdl_test_wintint_rdy_fail--; + return _TRUE; + } + return _FALSE; +} + +static u32 g_wait_hiq_empty_ms = 0; + +u32 rtw_get_wait_hiq_empty_ms(void) +{ + return g_wait_hiq_empty_ms; +} + +static u8 del_rx_ampdu_test_no_tx_fail = 0; + +bool rtw_del_rx_ampdu_test_trigger_no_tx_fail(void) +{ + if (del_rx_ampdu_test_no_tx_fail) { + RTW_PRINT("del_rx_ampdu test case: trigger no_tx_fail\n"); + del_rx_ampdu_test_no_tx_fail--; + return _TRUE; + } + return _FALSE; +} + +void rtw_sink_rtp_seq_dbg(_adapter *adapter, _pkt *pkt) +{ + struct recv_priv *precvpriv = &(adapter->recvpriv); + if (precvpriv->sink_udpport > 0) { + if (*((u16 *)((pkt->data) + 0x24)) == cpu_to_be16(precvpriv->sink_udpport)) { + precvpriv->pre_rtp_rxseq = precvpriv->cur_rtp_rxseq; + precvpriv->cur_rtp_rxseq = be16_to_cpu(*((u16 *)((pkt->data) + 0x2C))); + if (precvpriv->pre_rtp_rxseq + 1 != precvpriv->cur_rtp_rxseq) + RTW_INFO("%s : RTP Seq num from %d to %d\n", __FUNCTION__, precvpriv->pre_rtp_rxseq, precvpriv->cur_rtp_rxseq); + } + } +} + +void sta_rx_reorder_ctl_dump(void *sel, struct sta_info *sta) +{ + struct recv_reorder_ctrl *reorder_ctl; + int i; + + for (i = 0; i < 16; i++) { + reorder_ctl = &sta->recvreorder_ctrl[i]; + if (reorder_ctl->ampdu_size != RX_AMPDU_SIZE_INVALID || reorder_ctl->indicate_seq != 0xFFFF) { + RTW_PRINT_SEL(sel, "tid=%d, enable=%d, ampdu_size=%u, indicate_seq=%u\n" + , i, reorder_ctl->enable, reorder_ctl->ampdu_size, reorder_ctl->indicate_seq + ); + } + } +} + +void dump_tx_rate_bmp(void *sel, struct dvobj_priv *dvobj) +{ + _adapter *adapter = dvobj_get_primary_adapter(dvobj); + struct rf_ctl_t *rfctl = dvobj_to_rfctl(dvobj); + u8 bw; + + RTW_PRINT_SEL(sel, "%-6s", "bw"); + if (hal_chk_proto_cap(adapter, PROTO_CAP_11AC)) + _RTW_PRINT_SEL(sel, " %-11s", "vht"); + + _RTW_PRINT_SEL(sel, " %-11s %-4s %-3s\n", "ht", "ofdm", "cck"); + + for (bw = CHANNEL_WIDTH_20; bw <= CHANNEL_WIDTH_160; bw++) { + if (!hal_is_bw_support(adapter, bw)) + continue; + + RTW_PRINT_SEL(sel, "%6s", ch_width_str(bw)); + if (hal_chk_proto_cap(adapter, PROTO_CAP_11AC)) { + _RTW_PRINT_SEL(sel, " %03x %03x %03x" + , RATE_BMP_GET_VHT_3SS(rfctl->rate_bmp_vht_by_bw[bw]) + , RATE_BMP_GET_VHT_2SS(rfctl->rate_bmp_vht_by_bw[bw]) + , RATE_BMP_GET_VHT_1SS(rfctl->rate_bmp_vht_by_bw[bw]) + ); + } + + _RTW_PRINT_SEL(sel, " %02x %02x %02x %02x" + , bw <= CHANNEL_WIDTH_40 ? RATE_BMP_GET_HT_4SS(rfctl->rate_bmp_ht_by_bw[bw]) : 0 + , bw <= CHANNEL_WIDTH_40 ? RATE_BMP_GET_HT_3SS(rfctl->rate_bmp_ht_by_bw[bw]) : 0 + , bw <= CHANNEL_WIDTH_40 ? RATE_BMP_GET_HT_2SS(rfctl->rate_bmp_ht_by_bw[bw]) : 0 + , bw <= CHANNEL_WIDTH_40 ? RATE_BMP_GET_HT_1SS(rfctl->rate_bmp_ht_by_bw[bw]) : 0 + ); + + _RTW_PRINT_SEL(sel, " %03x %01x\n" + , bw <= CHANNEL_WIDTH_20 ? RATE_BMP_GET_OFDM(rfctl->rate_bmp_cck_ofdm) : 0 + , bw <= CHANNEL_WIDTH_20 ? RATE_BMP_GET_CCK(rfctl->rate_bmp_cck_ofdm) : 0 + ); + } +} + +void dump_adapters_status(void *sel, struct dvobj_priv *dvobj) +{ + struct rf_ctl_t *rfctl = dvobj_to_rfctl(dvobj); + int i; + _adapter *iface; + u8 u_ch, u_bw, u_offset; + + dump_mi_status(sel, dvobj); + +#ifdef CONFIG_FW_MULTI_PORT_SUPPORT + RTW_PRINT_SEL(sel, "default port id:%d\n\n", dvobj->default_port_id); +#endif /* CONFIG_FW_MULTI_PORT_SUPPORT */ + + RTW_PRINT_SEL(sel, "dev status:%s%s\n\n" + , dev_is_surprise_removed(dvobj) ? " SR" : "" + , dev_is_drv_stopped(dvobj) ? " DS" : "" + ); + +#ifdef CONFIG_P2P +#define P2P_INFO_TITLE_FMT " %-3s %-4s" +#define P2P_INFO_TITLE_ARG , "lch", "p2ps" +#ifdef CONFIG_IOCTL_CFG80211 +#define P2P_INFO_VALUE_FMT " %3u %c%3u" +#define P2P_INFO_VALUE_ARG , iface->wdinfo.listen_channel, iface->wdev_data.p2p_enabled ? 'e' : ' ', rtw_p2p_state(&iface->wdinfo) +#else +#define P2P_INFO_VALUE_FMT " %3u %4u" +#define P2P_INFO_VALUE_ARG , iface->wdinfo.listen_channel, rtw_p2p_state(&iface->wdinfo) +#endif +#define P2P_INFO_DASH "---------" +#else +#define P2P_INFO_TITLE_FMT "" +#define P2P_INFO_TITLE_ARG +#define P2P_INFO_VALUE_FMT "" +#define P2P_INFO_VALUE_ARG +#define P2P_INFO_DASH +#endif + + RTW_PRINT_SEL(sel, "%-2s %-15s %c %-3s %-3s %-3s %-17s %-4s %-7s" + P2P_INFO_TITLE_FMT + " %s\n" + , "id", "ifname", ' ', "bup", "nup", "ncd", "macaddr", "port", "ch" + P2P_INFO_TITLE_ARG + , "status"); + + RTW_PRINT_SEL(sel, "---------------------------------------------------------------" + P2P_INFO_DASH + "-------\n"); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (iface) { + RTW_PRINT_SEL(sel, "%2d %-15s %c %3u %3u %3u "MAC_FMT" %4hhu %3u,%u,%u" + P2P_INFO_VALUE_FMT + " "MLME_STATE_FMT"\n" + , i, iface->registered ? ADPT_ARG(iface) : NULL + , iface->registered ? 'R' : ' ' + , iface->bup + , iface->netif_up + , iface->net_closed + , MAC_ARG(adapter_mac_addr(iface)) + , get_hw_port(iface) + , iface->mlmeextpriv.cur_channel + , iface->mlmeextpriv.cur_bwmode + , iface->mlmeextpriv.cur_ch_offset + P2P_INFO_VALUE_ARG + , MLME_STATE_ARG(iface) + ); + } + } + + RTW_PRINT_SEL(sel, "---------------------------------------------------------------" + P2P_INFO_DASH + "-------\n"); + + rtw_mi_get_ch_setting_union(dvobj_get_primary_adapter(dvobj), &u_ch, &u_bw, &u_offset); + RTW_PRINT_SEL(sel, "%55s %3u,%u,%u\n" + , "union:" + , u_ch, u_bw, u_offset + ); + + RTW_PRINT_SEL(sel, "%55s %3u,%u,%u\n" + , "oper:" + , dvobj->oper_channel + , dvobj->oper_bwmode + , dvobj->oper_ch_offset + ); + +#ifdef CONFIG_DFS_MASTER + if (rfctl->radar_detect_ch != 0) { + u32 non_ocp_ms; + u32 cac_ms; + + for (i = 0; i < dvobj->iface_nums; i++) { + if (!dvobj->padapters[i]) + continue; + if (check_fwstate(&dvobj->padapters[i]->mlmepriv, WIFI_AP_STATE) + && check_fwstate(&dvobj->padapters[i]->mlmepriv, WIFI_ASOC_STATE)) + break; + } + + if (i >= dvobj->iface_nums) { + RTW_PRINT_SEL(sel, "DFS master enable without AP mode???"); + goto end_dfs_master; + } + + RTW_PRINT_SEL(sel, "%55s %3u,%u,%u" + , "radar_detect:" + , rfctl->radar_detect_ch + , rfctl->radar_detect_bw + , rfctl->radar_detect_offset + ); + + _RTW_PRINT_SEL(sel, ", domain:%u", rtw_odm_get_dfs_domain(dvobj->padapters[IFACE_ID0])); + + rtw_get_ch_waiting_ms(dvobj->padapters[i] + , rfctl->radar_detect_ch + , rfctl->radar_detect_bw + , rfctl->radar_detect_offset + , &non_ocp_ms + , &cac_ms + ); + + if (non_ocp_ms) + _RTW_PRINT_SEL(sel, ", non_ocp:%d", non_ocp_ms); + if (cac_ms) + _RTW_PRINT_SEL(sel, ", cac:%d", cac_ms); +end_dfs_master: + _RTW_PRINT_SEL(sel, "\n"); + } +#endif /* CONFIG_DFS_MASTER */ +} + +#define SEC_CAM_ENT_ID_TITLE_FMT "%-2s" +#define SEC_CAM_ENT_ID_TITLE_ARG "id" +#define SEC_CAM_ENT_ID_VALUE_FMT "%2u" +#define SEC_CAM_ENT_ID_VALUE_ARG(id) (id) + +#define SEC_CAM_ENT_TITLE_FMT "%-6s %-17s %-32s %-3s %-7s %-2s %-2s %-5s" +#define SEC_CAM_ENT_TITLE_ARG "ctrl", "addr", "key", "kid", "type", "MK", "GK", "valid" +#define SEC_CAM_ENT_VALUE_FMT "0x%04x "MAC_FMT" "KEY_FMT" %3u %-7s %2u %2u %5u" +#define SEC_CAM_ENT_VALUE_ARG(ent) \ + (ent)->ctrl \ + , MAC_ARG((ent)->mac) \ + , KEY_ARG((ent)->key) \ + , ((ent)->ctrl) & 0x03 \ + , security_type_str((((ent)->ctrl) >> 2) & 0x07) \ + , (((ent)->ctrl) >> 5) & 0x01 \ + , (((ent)->ctrl) >> 6) & 0x01 \ + , (((ent)->ctrl) >> 15) & 0x01 + +void dump_sec_cam_ent(void *sel, struct sec_cam_ent *ent, int id) +{ + if (id >= 0) { + RTW_PRINT_SEL(sel, SEC_CAM_ENT_ID_VALUE_FMT " " SEC_CAM_ENT_VALUE_FMT"\n" + , SEC_CAM_ENT_ID_VALUE_ARG(id), SEC_CAM_ENT_VALUE_ARG(ent)); + } else + RTW_PRINT_SEL(sel, SEC_CAM_ENT_VALUE_FMT"\n", SEC_CAM_ENT_VALUE_ARG(ent)); +} + +void dump_sec_cam_ent_title(void *sel, u8 has_id) +{ + if (has_id) { + RTW_PRINT_SEL(sel, SEC_CAM_ENT_ID_TITLE_FMT " " SEC_CAM_ENT_TITLE_FMT"\n" + , SEC_CAM_ENT_ID_TITLE_ARG, SEC_CAM_ENT_TITLE_ARG); + } else + RTW_PRINT_SEL(sel, SEC_CAM_ENT_TITLE_FMT"\n", SEC_CAM_ENT_TITLE_ARG); +} + +void dump_sec_cam(void *sel, _adapter *adapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + struct sec_cam_ent ent; + int i; + + RTW_PRINT_SEL(sel, "HW sec cam:\n"); + dump_sec_cam_ent_title(sel, 1); + for (i = 0; i < cam_ctl->num; i++) { + rtw_sec_read_cam_ent(adapter, i, (u8 *)(&ent.ctrl), ent.mac, ent.key); + dump_sec_cam_ent(sel , &ent, i); + } +} + +void dump_sec_cam_cache(void *sel, _adapter *adapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + int i; + + RTW_PRINT_SEL(sel, "SW sec cam cache:\n"); + dump_sec_cam_ent_title(sel, 1); + for (i = 0; i < cam_ctl->num; i++) { + if (dvobj->cam_cache[i].ctrl != 0) + dump_sec_cam_ent(sel, &dvobj->cam_cache[i], i); + } + +} + +#ifdef CONFIG_PROC_DEBUG +ssize_t proc_set_write_reg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + u32 addr, val, len; + + if (count < 3) { + RTW_INFO("argument size is less than 3\n"); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%x %x %x", &addr, &val, &len); + + if (num != 3) { + RTW_INFO("invalid write_reg parameter!\n"); + return count; + } + + switch (len) { + case 1: + rtw_write8(padapter, addr, (u8)val); + break; + case 2: + rtw_write16(padapter, addr, (u16)val); + break; + case 4: + rtw_write32(padapter, addr, val); + break; + default: + RTW_INFO("error write length=%d", len); + break; + } + + } + + return count; + +} + +static u32 proc_get_read_addr = 0xeeeeeeee; +static u32 proc_get_read_len = 0x4; + +int proc_get_read_reg(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + + if (proc_get_read_addr == 0xeeeeeeee) { + RTW_PRINT_SEL(m, "address not initialized\n"); + return 0; + } + + switch (proc_get_read_len) { + case 1: + RTW_PRINT_SEL(m, "rtw_read8(0x%x)=0x%x\n", proc_get_read_addr, rtw_read8(padapter, proc_get_read_addr)); + break; + case 2: + RTW_PRINT_SEL(m, "rtw_read16(0x%x)=0x%x\n", proc_get_read_addr, rtw_read16(padapter, proc_get_read_addr)); + break; + case 4: + RTW_PRINT_SEL(m, "rtw_read32(0x%x)=0x%x\n", proc_get_read_addr, rtw_read32(padapter, proc_get_read_addr)); + break; + default: + RTW_PRINT_SEL(m, "error read length=%d\n", proc_get_read_len); + break; + } + + return 0; +} + +ssize_t proc_set_read_reg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + char tmp[16]; + u32 addr, len; + + if (count < 2) { + RTW_INFO("argument size is less than 2\n"); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%x %x", &addr, &len); + + if (num != 2) { + RTW_INFO("invalid read_reg parameter!\n"); + return count; + } + + proc_get_read_addr = addr; + + proc_get_read_len = len; + } + + return count; + +} + +int proc_get_rx_stat(struct seq_file *m, void *v) +{ + _irqL irqL; + _list *plist, *phead; + struct net_device *dev = m->private; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + struct sta_info *psta = NULL; + struct stainfo_stats *pstats = NULL; + struct sta_priv *pstapriv = &(adapter->stapriv); + u32 i, j; + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 null_addr[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + for (i = 0; i < NUM_STA; i++) { + phead = &(pstapriv->sta_hash[i]); + plist = get_next(phead); + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + plist = get_next(plist); + pstats = &psta->sta_stats; + + if (pstats == NULL) + continue; + if ((_rtw_memcmp(psta->hwaddr, bc_addr, 6) != _TRUE) + && (_rtw_memcmp(psta->hwaddr, null_addr, 6) != _TRUE) + && (_rtw_memcmp(psta->hwaddr, adapter_mac_addr(adapter), 6) != _TRUE)) { + RTW_PRINT_SEL(m, "MAC :\t\t"MAC_FMT "\n", MAC_ARG(psta->hwaddr)); + RTW_PRINT_SEL(m, "data_rx_cnt :\t%llu\n", pstats->rx_data_pkts - pstats->rx_data_last_pkts); + pstats->rx_data_last_pkts = pstats->rx_data_pkts; + RTW_PRINT_SEL(m, "duplicate_cnt :\t%u\n", pstats->duplicate_cnt); + pstats->duplicate_cnt = 0; + RTW_PRINT_SEL(m, "rx_per_rate_cnt :\n"); + + for (j = 0; j < 0x60; j++) { + RTW_PRINT_SEL(m, "%08u ", pstats->rxratecnt[j]); + pstats->rxratecnt[j] = 0; + if ((j%8) == 7) + RTW_PRINT_SEL(m, "\n"); + } + RTW_PRINT_SEL(m, "\n"); + } + } + } + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + return 0; +} + +int proc_get_tx_stat(struct seq_file *m, void *v) +{ + _irqL irqL; + _list *plist, *phead; + struct net_device *dev = m->private; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + struct sta_info *psta = NULL, *sta_rec[NUM_STA]; + struct stainfo_stats *pstats = NULL; + struct sta_priv *pstapriv = &(adapter->stapriv); + u32 i, macid_rec_idx = 0; + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 null_addr[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + struct submit_ctx gotc2h; + + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + for (i = 0; i < NUM_STA; i++) { + sta_rec[i] = NULL; + phead = &(pstapriv->sta_hash[i]); + plist = get_next(phead); + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + plist = get_next(plist); + if ((_rtw_memcmp(psta->hwaddr, bc_addr, 6) != _TRUE) + && (_rtw_memcmp(psta->hwaddr, null_addr, 6) != _TRUE) + && (_rtw_memcmp(psta->hwaddr, adapter_mac_addr(adapter), 6) != _TRUE)) { + sta_rec[macid_rec_idx++] = psta; + } + } + } + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + for (i = 0; i < macid_rec_idx; i++) { + pstats = &(sta_rec[i]->sta_stats); + if (pstats == NULL) + continue; + pstapriv->c2h_sta = sta_rec[i]; + rtw_hal_reqtxrpt(adapter, sta_rec[i]->mac_id); + rtw_sctx_init(&gotc2h, 60); + pstapriv->gotc2h = &gotc2h; + if (rtw_sctx_wait(&gotc2h, __func__)) { + RTW_PRINT_SEL(m, "MAC :\t\t"MAC_FMT "\n", MAC_ARG(sta_rec[i]->hwaddr)); + RTW_PRINT_SEL(m, "data_sent_cnt :\t%u\n", pstats->tx_ok_cnt + pstats->tx_fail_cnt); + RTW_PRINT_SEL(m, "success_cnt :\t%u\n", pstats->tx_ok_cnt); + RTW_PRINT_SEL(m, "failure_cnt :\t%u\n", pstats->tx_fail_cnt); + RTW_PRINT_SEL(m, "retry_cnt :\t%u\n\n", pstats->tx_retry_cnt); + } else { + RTW_PRINT_SEL(m, "Warming : Query timeout, operation abort!!\n"); + RTW_PRINT_SEL(m, "\n"); + break; + } + } + return 0; +} + +int proc_get_fwstate(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + + RTW_PRINT_SEL(m, "fwstate=0x%x\n", get_fwstate(pmlmepriv)); + + return 0; +} + +int proc_get_sec_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct security_priv *sec = &padapter->securitypriv; + + RTW_PRINT_SEL(m, "auth_alg=0x%x, enc_alg=0x%x, auth_type=0x%x, enc_type=0x%x\n", + sec->dot11AuthAlgrthm, sec->dot11PrivacyAlgrthm, + sec->ndisauthtype, sec->ndisencryptstatus); + + RTW_PRINT_SEL(m, "hw_decrypted=%d\n", sec->hw_decrypted); + +#ifdef DBG_SW_SEC_CNT + RTW_PRINT_SEL(m, "wep_sw_enc_cnt=%llu, %llu, %llu\n" + , sec->wep_sw_enc_cnt_bc , sec->wep_sw_enc_cnt_mc, sec->wep_sw_enc_cnt_uc); + RTW_PRINT_SEL(m, "wep_sw_dec_cnt=%llu, %llu, %llu\n" + , sec->wep_sw_dec_cnt_bc , sec->wep_sw_dec_cnt_mc, sec->wep_sw_dec_cnt_uc); + + RTW_PRINT_SEL(m, "tkip_sw_enc_cnt=%llu, %llu, %llu\n" + , sec->tkip_sw_enc_cnt_bc , sec->tkip_sw_enc_cnt_mc, sec->tkip_sw_enc_cnt_uc); + RTW_PRINT_SEL(m, "tkip_sw_dec_cnt=%llu, %llu, %llu\n" + , sec->tkip_sw_dec_cnt_bc , sec->tkip_sw_dec_cnt_mc, sec->tkip_sw_dec_cnt_uc); + + RTW_PRINT_SEL(m, "aes_sw_enc_cnt=%llu, %llu, %llu\n" + , sec->aes_sw_enc_cnt_bc , sec->aes_sw_enc_cnt_mc, sec->aes_sw_enc_cnt_uc); + RTW_PRINT_SEL(m, "aes_sw_dec_cnt=%llu, %llu, %llu\n" + , sec->aes_sw_dec_cnt_bc , sec->aes_sw_dec_cnt_mc, sec->aes_sw_dec_cnt_uc); +#endif /* DBG_SW_SEC_CNT */ + + return 0; +} + +int proc_get_mlmext_state(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + RTW_PRINT_SEL(m, "pmlmeinfo->state=0x%x\n", pmlmeinfo->state); + + return 0; +} + +#ifdef CONFIG_LAYER2_ROAMING +int proc_get_roam_flags(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + + RTW_PRINT_SEL(m, "0x%02x\n", rtw_roam_flags(adapter)); + + return 0; +} + +ssize_t proc_set_roam_flags(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + + char tmp[32]; + u8 flags; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%hhx", &flags); + + if (num == 1) + rtw_assign_roam_flags(adapter, flags); + } + + return count; + +} + +int proc_get_roam_param(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *mlme = &adapter->mlmepriv; + + RTW_PRINT_SEL(m, "%12s %12s %11s %14s\n", "rssi_diff_th", "scanr_exp_ms", "scan_int_ms", "rssi_threshold"); + RTW_PRINT_SEL(m, "%-12u %-12u %-11u %-14u\n" + , mlme->roam_rssi_diff_th + , mlme->roam_scanr_exp_ms + , mlme->roam_scan_int_ms + , mlme->roam_rssi_threshold + ); + + return 0; +} + +ssize_t proc_set_roam_param(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *mlme = &adapter->mlmepriv; + + char tmp[32]; + u8 rssi_diff_th; + u32 scanr_exp_ms; + u32 scan_int_ms; + u8 rssi_threshold; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%hhu %u %u %hhu", &rssi_diff_th, &scanr_exp_ms, &scan_int_ms, &rssi_threshold); + + if (num >= 1) + mlme->roam_rssi_diff_th = rssi_diff_th; + if (num >= 2) + mlme->roam_scanr_exp_ms = scanr_exp_ms; + if (num >= 3) + mlme->roam_scan_int_ms = scan_int_ms; + if (num >= 4) + mlme->roam_rssi_threshold = rssi_threshold; + } + + return count; + +} + +ssize_t proc_set_roam_tgt_addr(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + + char tmp[32]; + u8 addr[ETH_ALEN]; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", addr, addr + 1, addr + 2, addr + 3, addr + 4, addr + 5); + if (num == 6) + _rtw_memcpy(adapter->mlmepriv.roam_tgt_addr, addr, ETH_ALEN); + + RTW_INFO("set roam_tgt_addr to "MAC_FMT"\n", MAC_ARG(adapter->mlmepriv.roam_tgt_addr)); + } + + return count; +} +#endif /* CONFIG_LAYER2_ROAMING */ + +#ifdef CONFIG_RTW_80211R +ssize_t proc_set_ft_flags(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + + char tmp[32]; + u8 flags; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + int num = sscanf(tmp, "%hhx", &flags); + + if (num == 1) + adapter->mlmepriv.ftpriv.ft_flags = flags; + } + + return count; + +} + +int proc_get_ft_flags(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + + RTW_PRINT_SEL(m, "0x%02x\n", adapter->mlmepriv.ftpriv.ft_flags); + + return 0; +} +#endif + +int proc_get_qos_option(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + + RTW_PRINT_SEL(m, "qos_option=%d\n", pmlmepriv->qospriv.qos_option); + + return 0; +} + +int proc_get_ht_option(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + +#ifdef CONFIG_80211N_HT + RTW_PRINT_SEL(m, "ht_option=%d\n", pmlmepriv->htpriv.ht_option); +#endif /* CONFIG_80211N_HT */ + + return 0; +} + +int proc_get_rf_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + RTW_PRINT_SEL(m, "cur_ch=%d, cur_bw=%d, cur_ch_offet=%d\n", + pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); + + RTW_PRINT_SEL(m, "oper_ch=%d, oper_bw=%d, oper_ch_offet=%d\n", + rtw_get_oper_ch(padapter), rtw_get_oper_bw(padapter), rtw_get_oper_choffset(padapter)); + + return 0; +} + +int proc_get_scan_param(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + struct ss_res *ss = &mlmeext->sitesurvey_res; + +#define SCAN_PARAM_TITLE_FMT "%10s" +#define SCAN_PARAM_VALUE_FMT "%-10u" +#define SCAN_PARAM_TITLE_ARG , "scan_ch_ms" +#define SCAN_PARAM_VALUE_ARG , ss->scan_ch_ms +#ifdef CONFIG_80211N_HT +#define SCAN_PARAM_TITLE_FMT_HT " %15s %13s" +#define SCAN_PARAM_VALUE_FMT_HT " %-15u %-13u" +#define SCAN_PARAM_TITLE_ARG_HT , "rx_ampdu_accept", "rx_ampdu_size" +#define SCAN_PARAM_VALUE_ARG_HT , ss->rx_ampdu_accept, ss->rx_ampdu_size +#else +#define SCAN_PARAM_TITLE_FMT_HT "" +#define SCAN_PARAM_VALUE_FMT_HT "" +#define SCAN_PARAM_TITLE_ARG_HT +#define SCAN_PARAM_VALUE_ARG_HT +#endif +#ifdef CONFIG_SCAN_BACKOP +#define SCAN_PARAM_TITLE_FMT_BACKOP " %9s %12s" +#define SCAN_PARAM_VALUE_FMT_BACKOP " %-9u %-12u" +#define SCAN_PARAM_TITLE_ARG_BACKOP , "backop_ms", "scan_cnt_max" +#define SCAN_PARAM_VALUE_ARG_BACKOP , ss->backop_ms, ss->scan_cnt_max +#else +#define SCAN_PARAM_TITLE_FMT_BACKOP "" +#define SCAN_PARAM_VALUE_FMT_BACKOP "" +#define SCAN_PARAM_TITLE_ARG_BACKOP +#define SCAN_PARAM_VALUE_ARG_BACKOP +#endif + + RTW_PRINT_SEL(m, + SCAN_PARAM_TITLE_FMT + SCAN_PARAM_TITLE_FMT_HT + SCAN_PARAM_TITLE_FMT_BACKOP + "\n" + SCAN_PARAM_TITLE_ARG + SCAN_PARAM_TITLE_ARG_HT + SCAN_PARAM_TITLE_ARG_BACKOP + ); + + RTW_PRINT_SEL(m, + SCAN_PARAM_VALUE_FMT + SCAN_PARAM_VALUE_FMT_HT + SCAN_PARAM_VALUE_FMT_BACKOP + "\n" + SCAN_PARAM_VALUE_ARG + SCAN_PARAM_VALUE_ARG_HT + SCAN_PARAM_VALUE_ARG_BACKOP + ); + + return 0; +} + +ssize_t proc_set_scan_param(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + struct ss_res *ss = &mlmeext->sitesurvey_res; + + char tmp[32] = {0}; + + u16 scan_ch_ms; +#define SCAN_PARAM_INPUT_FMT "%hu" +#define SCAN_PARAM_INPUT_ARG , &scan_ch_ms +#ifdef CONFIG_80211N_HT + u8 rx_ampdu_accept; + u8 rx_ampdu_size; +#define SCAN_PARAM_INPUT_FMT_HT " %hhu %hhu" +#define SCAN_PARAM_INPUT_ARG_HT , &rx_ampdu_accept, &rx_ampdu_size +#else +#define SCAN_PARAM_INPUT_FMT_HT "" +#define SCAN_PARAM_INPUT_ARG_HT +#endif +#ifdef CONFIG_SCAN_BACKOP + u16 backop_ms; + u8 scan_cnt_max; +#define SCAN_PARAM_INPUT_FMT_BACKOP " %hu %hhu" +#define SCAN_PARAM_INPUT_ARG_BACKOP , &backop_ms, &scan_cnt_max +#else +#define SCAN_PARAM_INPUT_FMT_BACKOP "" +#define SCAN_PARAM_INPUT_ARG_BACKOP +#endif + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, + SCAN_PARAM_INPUT_FMT + SCAN_PARAM_INPUT_FMT_HT + SCAN_PARAM_INPUT_FMT_BACKOP + SCAN_PARAM_INPUT_ARG + SCAN_PARAM_INPUT_ARG_HT + SCAN_PARAM_INPUT_ARG_BACKOP + ); + + if (num-- > 0) + ss->scan_ch_ms = scan_ch_ms; +#ifdef CONFIG_80211N_HT + if (num-- > 0) + ss->rx_ampdu_accept = rx_ampdu_accept; + if (num-- > 0) + ss->rx_ampdu_size = rx_ampdu_size; +#endif +#ifdef CONFIG_SCAN_BACKOP + if (num-- > 0) + ss->backop_ms = backop_ms; + if (num-- > 0) + ss->scan_cnt_max = scan_cnt_max; +#endif + } + + return count; +} + +int proc_get_scan_abort(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + u32 pass_ms; + + pass_ms = rtw_scan_abort_timeout(adapter, 10000); + + RTW_PRINT_SEL(m, "%u\n", pass_ms); + + return 0; +} + +#ifdef CONFIG_SCAN_BACKOP +int proc_get_backop_flags_sta(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + + RTW_PRINT_SEL(m, "0x%02x\n", mlmeext_scan_backop_flags_sta(mlmeext)); + + return 0; +} + +ssize_t proc_set_backop_flags_sta(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + + char tmp[32]; + u8 flags; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%hhx", &flags); + + if (num == 1) + mlmeext_assign_scan_backop_flags_sta(mlmeext, flags); + } + + return count; +} + +int proc_get_backop_flags_ap(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + + RTW_PRINT_SEL(m, "0x%02x\n", mlmeext_scan_backop_flags_ap(mlmeext)); + + return 0; +} + +ssize_t proc_set_backop_flags_ap(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + + char tmp[32]; + u8 flags; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%hhx", &flags); + + if (num == 1) + mlmeext_assign_scan_backop_flags_ap(mlmeext, flags); + } + + return count; +} + +#endif /* CONFIG_SCAN_BACKOP */ + +int proc_get_survey_info(struct seq_file *m, void *v) +{ + _irqL irqL; + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + _queue *queue = &(pmlmepriv->scanned_queue); + struct wlan_network *pnetwork = NULL; + _list *plist, *phead; + s32 notify_signal; + s16 notify_noise = 0; + u16 index = 0, ie_cap = 0; + unsigned char *ie_wpa = NULL, *ie_wpa2 = NULL, *ie_wps = NULL; + unsigned char *ie_p2p = NULL, *ssid = NULL; + char flag_str[64]; + int ielen = 0; + u32 wpsielen = 0; + + _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + phead = get_list_head(queue); + if (!phead) + return 0; + plist = get_next(phead); + if (!plist) + return 0; + + RTW_PRINT_SEL(m, "%5s %-17s %3s %-3s %-4s %-4s %5s %32s %32s\n", "index", "bssid", "ch", "RSSI", "SdBm", "Noise", "age", "flag", "ssid"); + while (1) { + if (rtw_end_of_queue_search(phead, plist) == _TRUE) + break; + + pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); + if (!pnetwork) + break; + + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE && + is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network, 0)) { + notify_signal = translate_percentage_to_dbm(padapter->recvpriv.signal_strength);/* dbm */ + } else { + notify_signal = translate_percentage_to_dbm(pnetwork->network.PhyInfo.SignalStrength);/* dbm */ + } + +#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) + rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR, &(pnetwork->network.Configuration.DSConfig), &(notify_noise)); +#endif + + ie_wpa = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &ielen, pnetwork->network.IELength - 12); + ie_wpa2 = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &ielen, pnetwork->network.IELength - 12); + ie_cap = rtw_get_capability(&pnetwork->network); + ie_wps = rtw_get_wps_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &wpsielen); + ie_p2p = rtw_get_p2p_ie(&pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &ielen); + ssid = pnetwork->network.Ssid.Ssid; + sprintf(flag_str, "%s%s%s%s%s%s%s", + (ie_wpa) ? "[WPA]" : "", + (ie_wpa2) ? "[WPA2]" : "", + (!ie_wpa && !ie_wpa && ie_cap & BIT(4)) ? "[WEP]" : "", + (ie_wps) ? "[WPS]" : "", + (pnetwork->network.InfrastructureMode == Ndis802_11IBSS) ? "[IBSS]" : "", + (ie_cap & BIT(0)) ? "[ESS]" : "", + (ie_p2p) ? "[P2P]" : ""); + RTW_PRINT_SEL(m, "%5d "MAC_FMT" %3d %3d %4d %4d %5d %32s %32s\n", + ++index, + MAC_ARG(pnetwork->network.MacAddress), + pnetwork->network.Configuration.DSConfig, + (int)pnetwork->network.Rssi, + notify_signal, + notify_noise, + rtw_get_passing_time_ms((u32)pnetwork->last_scanned), + flag_str, + pnetwork->network.Ssid.Ssid); + plist = get_next(plist); + } + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + + return 0; +} + +ssize_t proc_set_survey_info(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + _irqL irqL; + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + bool need_indicate_scan_done = _FALSE; + u8 _status = _FALSE; + NDIS_802_11_SSID ssid[RTW_SSID_SCAN_AMOUNT]; + + if (count < 1) + return -EFAULT; + +#ifdef CONFIG_MP_INCLUDED + if (rtw_mi_mp_mode_check(padapter)) { + RTW_INFO("MP mode block Scan request\n"); + goto exit; + } +#endif + if (rtw_is_scan_deny(padapter)) { + RTW_INFO(FUNC_ADPT_FMT ": scan deny\n", FUNC_ADPT_ARG(padapter)); + goto exit; + } + + rtw_ps_deny(padapter, PS_DENY_SCAN); + if (_FAIL == rtw_pwr_wakeup(padapter)) + goto cancel_ps_deny; + + if (!rtw_is_adapter_up(padapter)) { + RTW_INFO("scan abort!! adapter cannot use\n"); + goto cancel_ps_deny; + } + + if (rtw_mi_busy_traffic_check(padapter, _FALSE)) { + RTW_INFO("scan abort!! BusyTraffic == _TRUE\n"); + goto cancel_ps_deny; + } + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) && check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) { + RTW_INFO("scan abort!! AP mode process WPS\n"); + goto cancel_ps_deny; + } + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) == _TRUE) { + RTW_INFO("scan abort!! fwstate=0x%x\n", pmlmepriv->fw_state); + goto cancel_ps_deny; + } + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_buddy_check_fwstate(padapter, + _FW_UNDER_SURVEY | _FW_UNDER_LINKING | WIFI_UNDER_WPS)) { + RTW_INFO("scan abort!! buddy_fwstate check failed\n"); + goto cancel_ps_deny; + } +#endif + _status = rtw_set_802_11_bssid_list_scan(padapter, NULL, 0, NULL, 0); + +cancel_ps_deny: + rtw_ps_deny_cancel(padapter, PS_DENY_SCAN); +exit: + return count; +} + +int proc_get_ap_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + struct sta_info *psta; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct wlan_network *cur_network = &(pmlmepriv->cur_network); + struct sta_priv *pstapriv = &padapter->stapriv; + + psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); + if (psta) { + int i; + struct recv_reorder_ctrl *preorder_ctrl; + + RTW_PRINT_SEL(m, "SSID=%s\n", cur_network->network.Ssid.Ssid); + RTW_PRINT_SEL(m, "sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr)); + RTW_PRINT_SEL(m, "cur_channel=%d, cur_bwmode=%d, cur_ch_offset=%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); + RTW_PRINT_SEL(m, "wireless_mode=0x%x, rtsen=%d, cts2slef=%d\n", psta->wireless_mode, psta->rtsen, psta->cts2self); + RTW_PRINT_SEL(m, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); +#ifdef CONFIG_80211N_HT + RTW_PRINT_SEL(m, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); + RTW_PRINT_SEL(m, "bwmode=%d, ch_offset=%d, sgi_20m=%d,sgi_40m=%d\n", psta->bw_mode, psta->htpriv.ch_offset, psta->htpriv.sgi_20m, psta->htpriv.sgi_40m); + RTW_PRINT_SEL(m, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable); + RTW_PRINT_SEL(m, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); + RTW_PRINT_SEL(m, "ldpc_cap=0x%x, stbc_cap=0x%x, beamform_cap=0x%x\n", psta->htpriv.ldpc_cap, psta->htpriv.stbc_cap, psta->htpriv.beamform_cap); +#endif /* CONFIG_80211N_HT */ +#ifdef CONFIG_80211AC_VHT + RTW_PRINT_SEL(m, "vht_en=%d, vht_sgi_80m=%d\n", psta->vhtpriv.vht_option, psta->vhtpriv.sgi_80m); + RTW_PRINT_SEL(m, "vht_ldpc_cap=0x%x, vht_stbc_cap=0x%x, vht_beamform_cap=0x%x\n", psta->vhtpriv.ldpc_cap, psta->vhtpriv.stbc_cap, psta->vhtpriv.beamform_cap); + RTW_PRINT_SEL(m, "vht_mcs_map=0x%x, vht_highest_rate=0x%x, vht_ampdu_len=%d\n", *(u16 *)psta->vhtpriv.vht_mcs_map, psta->vhtpriv.vht_highest_rate, psta->vhtpriv.ampdu_len); +#endif + + sta_rx_reorder_ctl_dump(m, psta); + } else + RTW_PRINT_SEL(m, "can't get sta's macaddr, cur_network's macaddr:" MAC_FMT "\n", MAC_ARG(cur_network->network.MacAddress)); + + return 0; +} + +ssize_t proc_reset_trx_info(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; + char cmd[32] = {0}; + u8 cnt = 0; + + if (count > sizeof(cmd)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(cmd, buffer, count)) { + int num = sscanf(cmd, "%hhx", &cnt); + + if (0 == cnt) { + pdbgpriv->dbg_rx_ampdu_drop_count = 0; + pdbgpriv->dbg_rx_ampdu_forced_indicate_count = 0; + pdbgpriv->dbg_rx_ampdu_loss_count = 0; + pdbgpriv->dbg_rx_dup_mgt_frame_drop_count = 0; + pdbgpriv->dbg_rx_ampdu_window_shift_cnt = 0; + pdbgpriv->dbg_rx_conflic_mac_addr_cnt = 0; + } + } + + return count; +} + +int proc_get_trx_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + int i; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct recv_priv *precvpriv = &padapter->recvpriv; + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; + struct hw_xmit *phwxmit; + + dump_os_queue(m, padapter); + + RTW_PRINT_SEL(m, "free_xmitbuf_cnt=%d, free_xmitframe_cnt=%d\n" + , pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt); + RTW_PRINT_SEL(m, "free_ext_xmitbuf_cnt=%d, free_xframe_ext_cnt=%d\n" + , pxmitpriv->free_xmit_extbuf_cnt, pxmitpriv->free_xframe_ext_cnt); + RTW_PRINT_SEL(m, "free_recvframe_cnt=%d\n" + , precvpriv->free_recvframe_cnt); + + for (i = 0; i < 4; i++) { + phwxmit = pxmitpriv->hwxmits + i; + RTW_PRINT_SEL(m, "%d, hwq.accnt=%d\n", i, phwxmit->accnt); + } + +#ifdef CONFIG_USB_HCI + RTW_PRINT_SEL(m, "rx_urb_pending_cn=%d\n", ATOMIC_READ(&(precvpriv->rx_pending_cnt))); +#endif + + /* Folowing are RX info */ + /* Counts of packets whose seq_num is less than preorder_ctrl->indicate_seq, Ex delay, retransmission, redundant packets and so on */ + RTW_PRINT_SEL(m, "Rx: Counts of Packets Whose Seq_Num Less Than Reorder Control Seq_Num: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_drop_count); + /* How many times the Rx Reorder Timer is triggered. */ + RTW_PRINT_SEL(m, "Rx: Reorder Time-out Trigger Counts: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_forced_indicate_count); + /* Total counts of packets loss */ + RTW_PRINT_SEL(m, "Rx: Packet Loss Counts: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_loss_count); + RTW_PRINT_SEL(m, "Rx: Duplicate Management Frame Drop Count: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_dup_mgt_frame_drop_count); + RTW_PRINT_SEL(m, "Rx: AMPDU BA window shift Count: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_window_shift_cnt); + /*The same mac addr counts*/ + RTW_PRINT_SEL(m, "Rx: Conflict MAC Address Frames Count: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_conflic_mac_addr_cnt); + return 0; +} + +int proc_get_dis_pwt(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + u8 dis_pwt = 0; + rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DIS_PWT, &(dis_pwt)); + RTW_PRINT_SEL(m, " Tx Power training mode:%s\n", (dis_pwt == _TRUE) ? "Disable" : "Enable"); + return 0; +} +ssize_t proc_set_dis_pwt(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[4] = {0}; + u8 dis_pwt = 0; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%hhx", &dis_pwt); + RTW_INFO("Set Tx Power training mode:%s\n", (dis_pwt == _TRUE) ? "Disable" : "Enable"); + + if (num >= 1) + rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DIS_PWT, &(dis_pwt)); + } + + return count; + +} + +int proc_get_rate_ctl(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + int i; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + u8 data_rate = 0, sgi = 0, data_fb = 0; + + if (adapter->fix_rate != 0xff) { + data_rate = adapter->fix_rate & 0x7F; + sgi = adapter->fix_rate >> 7; + data_fb = adapter->data_fb ? 1 : 0; + RTW_PRINT_SEL(m, "FIXED %s%s%s\n" + , HDATA_RATE(data_rate) + , data_rate > DESC_RATE54M ? (sgi ? " SGI" : " LGI") : "" + , data_fb ? " FB" : "" + ); + RTW_PRINT_SEL(m, "0x%02x %u\n", adapter->fix_rate, adapter->data_fb); + } else + RTW_PRINT_SEL(m, "RA\n"); + + return 0; +} + +ssize_t proc_set_rate_ctl(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + u8 fix_rate; + u8 data_fb; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%hhx %hhu", &fix_rate, &data_fb); + + if (num >= 1) { + u8 fix_rate_ori = adapter->fix_rate; + + adapter->fix_rate = fix_rate; + if (adapter->fix_bw != 0xFF && fix_rate_ori != fix_rate) + rtw_update_tx_rate_bmp(adapter_to_dvobj(adapter)); + } + if (num >= 2) + adapter->data_fb = data_fb ? 1 : 0; + } + + return count; +} + +int proc_get_tx_power_offset(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + int i; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + + RTW_PRINT_SEL(m, "Tx power offset - %u\n", adapter->power_offset); + return 0; +} + +ssize_t proc_set_tx_power_offset(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + u8 power_offset = 0; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%hhu", &power_offset); + + if (num >= 1) { + if (power_offset > 5) + power_offset = 0; + + adapter->power_offset = power_offset; + } + } + + return count; +} + +int proc_get_bw_ctl(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + u8 data_bw = 0; + + if (adapter->fix_bw != 0xff) { + data_bw = adapter->fix_bw; + RTW_PRINT_SEL(m, "FIXED %s\n", ch_width_str(data_bw)); + } else + RTW_PRINT_SEL(m, "Auto\n"); + + return 0; +} + +ssize_t proc_set_bw_ctl(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + u8 fix_bw; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + int num = sscanf(tmp, "%hhu", &fix_bw); + + if (num >= 1) { + u8 fix_bw_ori = adapter->fix_bw; + + adapter->fix_bw = fix_bw; + + if (adapter->fix_rate != 0xFF && fix_bw_ori != fix_bw) + rtw_update_tx_rate_bmp(adapter_to_dvobj(adapter)); + } + } + + return count; +} + +#ifdef DBG_RX_COUNTER_DUMP +int proc_get_rx_cnt_dump(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + int i; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + + RTW_PRINT_SEL(m, "BIT0- Dump RX counters of DRV\n"); + RTW_PRINT_SEL(m, "BIT1- Dump RX counters of MAC\n"); + RTW_PRINT_SEL(m, "BIT2- Dump RX counters of PHY\n"); + RTW_PRINT_SEL(m, "BIT3- Dump TRX data frame of DRV\n"); + RTW_PRINT_SEL(m, "dump_rx_cnt_mode = 0x%02x\n", adapter->dump_rx_cnt_mode); + + return 0; +} +ssize_t proc_set_rx_cnt_dump(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + u8 dump_rx_cnt_mode; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%hhx", &dump_rx_cnt_mode); + + rtw_dump_phy_rxcnts_preprocess(adapter, dump_rx_cnt_mode); + adapter->dump_rx_cnt_mode = dump_rx_cnt_mode; + + } + + return count; +} +#endif +ssize_t proc_set_fwdl_test_case(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + int num; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) + num = sscanf(tmp, "%hhu %hhu", &fwdl_test_chksum_fail, &fwdl_test_wintint_rdy_fail); + + return count; +} + +ssize_t proc_set_del_rx_ampdu_test_case(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + int num; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) + num = sscanf(tmp, "%hhu", &del_rx_ampdu_test_no_tx_fail); + + return count; +} + +#ifdef CONFIG_DFS_MASTER +int proc_get_dfs_master_test_case(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); + + RTW_PRINT_SEL(m, "%-24s %-19s\n", "radar_detect_trigger_non", "choose_dfs_ch_first"); + RTW_PRINT_SEL(m, "%24hhu %19hhu\n" + , rfctl->dbg_dfs_master_radar_detect_trigger_non + , rfctl->dbg_dfs_master_choose_dfs_ch_first + ); + + return 0; +} + +ssize_t proc_set_dfs_master_test_case(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); + char tmp[32]; + u8 radar_detect_trigger_non; + u8 choose_dfs_ch_first; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + int num = sscanf(tmp, "%hhu %hhu", &radar_detect_trigger_non, &choose_dfs_ch_first); + + if (num >= 1) + rfctl->dbg_dfs_master_radar_detect_trigger_non = radar_detect_trigger_non; + if (num >= 2) + rfctl->dbg_dfs_master_choose_dfs_ch_first = choose_dfs_ch_first; + } + + return count; +} +#endif /* CONFIG_DFS_MASTER */ + +ssize_t proc_set_wait_hiq_empty(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + int num; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) + num = sscanf(tmp, "%u", &g_wait_hiq_empty_ms); + + return count; +} + +int proc_get_suspend_resume_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct dvobj_priv *dvobj = padapter->dvobj; + struct debug_priv *pdbgpriv = &dvobj->drv_dbg; + + RTW_PRINT_SEL(m, "dbg_sdio_alloc_irq_cnt=%d\n", pdbgpriv->dbg_sdio_alloc_irq_cnt); + RTW_PRINT_SEL(m, "dbg_sdio_free_irq_cnt=%d\n", pdbgpriv->dbg_sdio_free_irq_cnt); + RTW_PRINT_SEL(m, "dbg_sdio_alloc_irq_error_cnt=%d\n", pdbgpriv->dbg_sdio_alloc_irq_error_cnt); + RTW_PRINT_SEL(m, "dbg_sdio_free_irq_error_cnt=%d\n", pdbgpriv->dbg_sdio_free_irq_error_cnt); + RTW_PRINT_SEL(m, "dbg_sdio_init_error_cnt=%d\n", pdbgpriv->dbg_sdio_init_error_cnt); + RTW_PRINT_SEL(m, "dbg_sdio_deinit_error_cnt=%d\n", pdbgpriv->dbg_sdio_deinit_error_cnt); + RTW_PRINT_SEL(m, "dbg_suspend_error_cnt=%d\n", pdbgpriv->dbg_suspend_error_cnt); + RTW_PRINT_SEL(m, "dbg_suspend_cnt=%d\n", pdbgpriv->dbg_suspend_cnt); + RTW_PRINT_SEL(m, "dbg_resume_cnt=%d\n", pdbgpriv->dbg_resume_cnt); + RTW_PRINT_SEL(m, "dbg_resume_error_cnt=%d\n", pdbgpriv->dbg_resume_error_cnt); + RTW_PRINT_SEL(m, "dbg_deinit_fail_cnt=%d\n", pdbgpriv->dbg_deinit_fail_cnt); + RTW_PRINT_SEL(m, "dbg_carddisable_cnt=%d\n", pdbgpriv->dbg_carddisable_cnt); + RTW_PRINT_SEL(m, "dbg_ps_insuspend_cnt=%d\n", pdbgpriv->dbg_ps_insuspend_cnt); + RTW_PRINT_SEL(m, "dbg_dev_unload_inIPS_cnt=%d\n", pdbgpriv->dbg_dev_unload_inIPS_cnt); + RTW_PRINT_SEL(m, "dbg_scan_pwr_state_cnt=%d\n", pdbgpriv->dbg_scan_pwr_state_cnt); + RTW_PRINT_SEL(m, "dbg_downloadfw_pwr_state_cnt=%d\n", pdbgpriv->dbg_downloadfw_pwr_state_cnt); + RTW_PRINT_SEL(m, "dbg_carddisable_error_cnt=%d\n", pdbgpriv->dbg_carddisable_error_cnt); + RTW_PRINT_SEL(m, "dbg_fw_read_ps_state_fail_cnt=%d\n", pdbgpriv->dbg_fw_read_ps_state_fail_cnt); + RTW_PRINT_SEL(m, "dbg_leave_ips_fail_cnt=%d\n", pdbgpriv->dbg_leave_ips_fail_cnt); + RTW_PRINT_SEL(m, "dbg_leave_lps_fail_cnt=%d\n", pdbgpriv->dbg_leave_lps_fail_cnt); + RTW_PRINT_SEL(m, "dbg_h2c_leave32k_fail_cnt=%d\n", pdbgpriv->dbg_h2c_leave32k_fail_cnt); + RTW_PRINT_SEL(m, "dbg_diswow_dload_fw_fail_cnt=%d\n", pdbgpriv->dbg_diswow_dload_fw_fail_cnt); + RTW_PRINT_SEL(m, "dbg_enwow_dload_fw_fail_cnt=%d\n", pdbgpriv->dbg_enwow_dload_fw_fail_cnt); + RTW_PRINT_SEL(m, "dbg_ips_drvopen_fail_cnt=%d\n", pdbgpriv->dbg_ips_drvopen_fail_cnt); + RTW_PRINT_SEL(m, "dbg_poll_fail_cnt=%d\n", pdbgpriv->dbg_poll_fail_cnt); + RTW_PRINT_SEL(m, "dbg_rpwm_toogle_cnt=%d\n", pdbgpriv->dbg_rpwm_toogle_cnt); + RTW_PRINT_SEL(m, "dbg_rpwm_timeout_fail_cnt=%d\n", pdbgpriv->dbg_rpwm_timeout_fail_cnt); + RTW_PRINT_SEL(m, "dbg_sreset_cnt=%d\n", pdbgpriv->dbg_sreset_cnt); + + return 0; +} + +#ifdef CONFIG_DBG_COUNTER + +int proc_get_rx_logs(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct rx_logs *rx_logs = &padapter->rx_logs; + + RTW_PRINT_SEL(m, + "intf_rx=%d\n" + "intf_rx_err_recvframe=%d\n" + "intf_rx_err_skb=%d\n" + "intf_rx_report=%d\n" + "core_rx=%d\n" + "core_rx_pre=%d\n" + "core_rx_pre_ver_err=%d\n" + "core_rx_pre_mgmt=%d\n" + "core_rx_pre_mgmt_err_80211w=%d\n" + "core_rx_pre_mgmt_err=%d\n" + "core_rx_pre_ctrl=%d\n" + "core_rx_pre_ctrl_err=%d\n" + "core_rx_pre_data=%d\n" + "core_rx_pre_data_wapi_seq_err=%d\n" + "core_rx_pre_data_wapi_key_err=%d\n" + "core_rx_pre_data_handled=%d\n" + "core_rx_pre_data_err=%d\n" + "core_rx_pre_data_unknown=%d\n" + "core_rx_pre_unknown=%d\n" + "core_rx_enqueue=%d\n" + "core_rx_dequeue=%d\n" + "core_rx_post=%d\n" + "core_rx_post_decrypt=%d\n" + "core_rx_post_decrypt_wep=%d\n" + "core_rx_post_decrypt_tkip=%d\n" + "core_rx_post_decrypt_aes=%d\n" + "core_rx_post_decrypt_wapi=%d\n" + "core_rx_post_decrypt_hw=%d\n" + "core_rx_post_decrypt_unknown=%d\n" + "core_rx_post_decrypt_err=%d\n" + "core_rx_post_defrag_err=%d\n" + "core_rx_post_portctrl_err=%d\n" + "core_rx_post_indicate=%d\n" + "core_rx_post_indicate_in_oder=%d\n" + "core_rx_post_indicate_reoder=%d\n" + "core_rx_post_indicate_err=%d\n" + "os_indicate=%d\n" + "os_indicate_ap_mcast=%d\n" + "os_indicate_ap_forward=%d\n" + "os_indicate_ap_self=%d\n" + "os_indicate_err=%d\n" + "os_netif_ok=%d\n" + "os_netif_err=%d\n", + rx_logs->intf_rx, + rx_logs->intf_rx_err_recvframe, + rx_logs->intf_rx_err_skb, + rx_logs->intf_rx_report, + rx_logs->core_rx, + rx_logs->core_rx_pre, + rx_logs->core_rx_pre_ver_err, + rx_logs->core_rx_pre_mgmt, + rx_logs->core_rx_pre_mgmt_err_80211w, + rx_logs->core_rx_pre_mgmt_err, + rx_logs->core_rx_pre_ctrl, + rx_logs->core_rx_pre_ctrl_err, + rx_logs->core_rx_pre_data, + rx_logs->core_rx_pre_data_wapi_seq_err, + rx_logs->core_rx_pre_data_wapi_key_err, + rx_logs->core_rx_pre_data_handled, + rx_logs->core_rx_pre_data_err, + rx_logs->core_rx_pre_data_unknown, + rx_logs->core_rx_pre_unknown, + rx_logs->core_rx_enqueue, + rx_logs->core_rx_dequeue, + rx_logs->core_rx_post, + rx_logs->core_rx_post_decrypt, + rx_logs->core_rx_post_decrypt_wep, + rx_logs->core_rx_post_decrypt_tkip, + rx_logs->core_rx_post_decrypt_aes, + rx_logs->core_rx_post_decrypt_wapi, + rx_logs->core_rx_post_decrypt_hw, + rx_logs->core_rx_post_decrypt_unknown, + rx_logs->core_rx_post_decrypt_err, + rx_logs->core_rx_post_defrag_err, + rx_logs->core_rx_post_portctrl_err, + rx_logs->core_rx_post_indicate, + rx_logs->core_rx_post_indicate_in_oder, + rx_logs->core_rx_post_indicate_reoder, + rx_logs->core_rx_post_indicate_err, + rx_logs->os_indicate, + rx_logs->os_indicate_ap_mcast, + rx_logs->os_indicate_ap_forward, + rx_logs->os_indicate_ap_self, + rx_logs->os_indicate_err, + rx_logs->os_netif_ok, + rx_logs->os_netif_err + ); + + return 0; +} + +int proc_get_tx_logs(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct tx_logs *tx_logs = &padapter->tx_logs; + + RTW_PRINT_SEL(m, + "os_tx=%d\n" + "os_tx_err_up=%d\n" + "os_tx_err_xmit=%d\n" + "os_tx_m2u=%d\n" + "os_tx_m2u_ignore_fw_linked=%d\n" + "os_tx_m2u_ignore_self=%d\n" + "os_tx_m2u_entry=%d\n" + "os_tx_m2u_entry_err_xmit=%d\n" + "os_tx_m2u_entry_err_skb=%d\n" + "os_tx_m2u_stop=%d\n" + "core_tx=%d\n" + "core_tx_err_pxmitframe=%d\n" + "core_tx_err_brtx=%d\n" + "core_tx_upd_attrib=%d\n" + "core_tx_upd_attrib_adhoc=%d\n" + "core_tx_upd_attrib_sta=%d\n" + "core_tx_upd_attrib_ap=%d\n" + "core_tx_upd_attrib_unknown=%d\n" + "core_tx_upd_attrib_dhcp=%d\n" + "core_tx_upd_attrib_icmp=%d\n" + "core_tx_upd_attrib_active=%d\n" + "core_tx_upd_attrib_err_ucast_sta=%d\n" + "core_tx_upd_attrib_err_ucast_ap_link=%d\n" + "core_tx_upd_attrib_err_sta=%d\n" + "core_tx_upd_attrib_err_link=%d\n" + "core_tx_upd_attrib_err_sec=%d\n" + "core_tx_ap_enqueue_warn_fwstate=%d\n" + "core_tx_ap_enqueue_warn_sta=%d\n" + "core_tx_ap_enqueue_warn_nosta=%d\n" + "core_tx_ap_enqueue_warn_link=%d\n" + "core_tx_ap_enqueue_warn_trigger=%d\n" + "core_tx_ap_enqueue_mcast=%d\n" + "core_tx_ap_enqueue_ucast=%d\n" + "core_tx_ap_enqueue=%d\n" + "intf_tx=%d\n" + "intf_tx_pending_ac=%d\n" + "intf_tx_pending_fw_under_survey=%d\n" + "intf_tx_pending_fw_under_linking=%d\n" + "intf_tx_pending_xmitbuf=%d\n" + "intf_tx_enqueue=%d\n" + "core_tx_enqueue=%d\n" + "core_tx_enqueue_class=%d\n" + "core_tx_enqueue_class_err_sta=%d\n" + "core_tx_enqueue_class_err_nosta=%d\n" + "core_tx_enqueue_class_err_fwlink=%d\n" + "intf_tx_direct=%d\n" + "intf_tx_direct_err_coalesce=%d\n" + "intf_tx_dequeue=%d\n" + "intf_tx_dequeue_err_coalesce=%d\n" + "intf_tx_dump_xframe=%d\n" + "intf_tx_dump_xframe_err_txdesc=%d\n" + "intf_tx_dump_xframe_err_port=%d\n", + tx_logs->os_tx, + tx_logs->os_tx_err_up, + tx_logs->os_tx_err_xmit, + tx_logs->os_tx_m2u, + tx_logs->os_tx_m2u_ignore_fw_linked, + tx_logs->os_tx_m2u_ignore_self, + tx_logs->os_tx_m2u_entry, + tx_logs->os_tx_m2u_entry_err_xmit, + tx_logs->os_tx_m2u_entry_err_skb, + tx_logs->os_tx_m2u_stop, + tx_logs->core_tx, + tx_logs->core_tx_err_pxmitframe, + tx_logs->core_tx_err_brtx, + tx_logs->core_tx_upd_attrib, + tx_logs->core_tx_upd_attrib_adhoc, + tx_logs->core_tx_upd_attrib_sta, + tx_logs->core_tx_upd_attrib_ap, + tx_logs->core_tx_upd_attrib_unknown, + tx_logs->core_tx_upd_attrib_dhcp, + tx_logs->core_tx_upd_attrib_icmp, + tx_logs->core_tx_upd_attrib_active, + tx_logs->core_tx_upd_attrib_err_ucast_sta, + tx_logs->core_tx_upd_attrib_err_ucast_ap_link, + tx_logs->core_tx_upd_attrib_err_sta, + tx_logs->core_tx_upd_attrib_err_link, + tx_logs->core_tx_upd_attrib_err_sec, + tx_logs->core_tx_ap_enqueue_warn_fwstate, + tx_logs->core_tx_ap_enqueue_warn_sta, + tx_logs->core_tx_ap_enqueue_warn_nosta, + tx_logs->core_tx_ap_enqueue_warn_link, + tx_logs->core_tx_ap_enqueue_warn_trigger, + tx_logs->core_tx_ap_enqueue_mcast, + tx_logs->core_tx_ap_enqueue_ucast, + tx_logs->core_tx_ap_enqueue, + tx_logs->intf_tx, + tx_logs->intf_tx_pending_ac, + tx_logs->intf_tx_pending_fw_under_survey, + tx_logs->intf_tx_pending_fw_under_linking, + tx_logs->intf_tx_pending_xmitbuf, + tx_logs->intf_tx_enqueue, + tx_logs->core_tx_enqueue, + tx_logs->core_tx_enqueue_class, + tx_logs->core_tx_enqueue_class_err_sta, + tx_logs->core_tx_enqueue_class_err_nosta, + tx_logs->core_tx_enqueue_class_err_fwlink, + tx_logs->intf_tx_direct, + tx_logs->intf_tx_direct_err_coalesce, + tx_logs->intf_tx_dequeue, + tx_logs->intf_tx_dequeue_err_coalesce, + tx_logs->intf_tx_dump_xframe, + tx_logs->intf_tx_dump_xframe_err_txdesc, + tx_logs->intf_tx_dump_xframe_err_port + ); + + return 0; +} + +int proc_get_int_logs(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + + RTW_PRINT_SEL(m, + "all=%d\n" + "err=%d\n" + "tbdok=%d\n" + "tbder=%d\n" + "bcnderr=%d\n" + "bcndma=%d\n" + "bcndma_e=%d\n" + "rx=%d\n" + "rx_rdu=%d\n" + "rx_fovw=%d\n" + "txfovw=%d\n" + "mgntok=%d\n" + "highdok=%d\n" + "bkdok=%d\n" + "bedok=%d\n" + "vidok=%d\n" + "vodok=%d\n", + padapter->int_logs.all, + padapter->int_logs.err, + padapter->int_logs.tbdok, + padapter->int_logs.tbder, + padapter->int_logs.bcnderr, + padapter->int_logs.bcndma, + padapter->int_logs.bcndma_e, + padapter->int_logs.rx, + padapter->int_logs.rx_rdu, + padapter->int_logs.rx_fovw, + padapter->int_logs.txfovw, + padapter->int_logs.mgntok, + padapter->int_logs.highdok, + padapter->int_logs.bkdok, + padapter->int_logs.bedok, + padapter->int_logs.vidok, + padapter->int_logs.vodok + ); + + return 0; +} + +#endif /* CONFIG_DBG_COUNTER */ + +int proc_get_hw_status(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct dvobj_priv *dvobj = padapter->dvobj; + struct debug_priv *pdbgpriv = &dvobj->drv_dbg; + struct registry_priv *regsty = dvobj_to_regsty(dvobj); + + if (regsty->check_hw_status == 0) + RTW_PRINT_SEL(m, "RX FIFO full count: not check in watch dog\n"); + else if (pdbgpriv->dbg_rx_fifo_last_overflow == 1 + && pdbgpriv->dbg_rx_fifo_curr_overflow == 1 + && pdbgpriv->dbg_rx_fifo_diff_overflow == 1 + ) + RTW_PRINT_SEL(m, "RX FIFO full count: no implementation\n"); + else { + RTW_PRINT_SEL(m, "RX FIFO full count: last_time=%llu, current_time=%llu, differential=%llu\n" + , pdbgpriv->dbg_rx_fifo_last_overflow, pdbgpriv->dbg_rx_fifo_curr_overflow, pdbgpriv->dbg_rx_fifo_diff_overflow); + } + + return 0; +} + +ssize_t proc_set_hw_status(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct dvobj_priv *dvobj = padapter->dvobj; + struct registry_priv *regsty = dvobj_to_regsty(dvobj); + char tmp[32]; + u32 enable; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d ", &enable); + + if (regsty && enable <= 1) { + regsty->check_hw_status = enable; + RTW_INFO("check_hw_status=%d\n", regsty->check_hw_status); + } + } + + return count; +} + +int proc_get_trx_info_debug(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + int i; + + + /*============ tx info ============ */ + rtw_hal_get_def_var(padapter, HW_DEF_RA_INFO_DUMP, m); + + /*============ rx info ============ */ + rtw_hal_set_odm_var(padapter, HAL_ODM_RX_INFO_DUMP, m, _FALSE); + + + return 0; +} + +int proc_get_rx_signal(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + + RTW_PRINT_SEL(m, "rssi:%d\n", padapter->recvpriv.rssi); + /* RTW_PRINT_SEL(m, "rxpwdb:%d\n", padapter->recvpriv.rxpwdb); */ + RTW_PRINT_SEL(m, "signal_strength:%u\n", padapter->recvpriv.signal_strength); + RTW_PRINT_SEL(m, "signal_qual:%u\n", padapter->recvpriv.signal_qual); + if (padapter->registrypriv.mp_mode == 1) { + if (padapter->mppriv.antenna_rx == ANTENNA_A) + RTW_PRINT_SEL(m, "Antenna: A\n"); + else if (padapter->mppriv.antenna_rx == ANTENNA_B) + RTW_PRINT_SEL(m, "Antenna: B\n"); + else if (padapter->mppriv.antenna_rx == ANTENNA_C) + RTW_PRINT_SEL(m, "Antenna: C\n"); + else if (padapter->mppriv.antenna_rx == ANTENNA_D) + RTW_PRINT_SEL(m, "Antenna: D\n"); + else if (padapter->mppriv.antenna_rx == ANTENNA_AB) + RTW_PRINT_SEL(m, "Antenna: AB\n"); + else if (padapter->mppriv.antenna_rx == ANTENNA_BC) + RTW_PRINT_SEL(m, "Antenna: BC\n"); + else if (padapter->mppriv.antenna_rx == ANTENNA_CD) + RTW_PRINT_SEL(m, "Antenna: CD\n"); + else + RTW_PRINT_SEL(m, "Antenna: __\n"); + return 0; + } + + rtw_get_noise(padapter); + RTW_PRINT_SEL(m, "noise:%d\n", padapter->recvpriv.noise); +#ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA + rtw_odm_get_perpkt_rssi(m, padapter); + rtw_get_raw_rssi_info(m, padapter); +#endif + return 0; +} + +ssize_t proc_set_rx_signal(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + u32 is_signal_dbg, signal_strength; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%u %u", &is_signal_dbg, &signal_strength); + + is_signal_dbg = is_signal_dbg == 0 ? 0 : 1; + + if (is_signal_dbg && num != 2) + return count; + + signal_strength = signal_strength > 100 ? 100 : signal_strength; + + padapter->recvpriv.is_signal_dbg = is_signal_dbg; + padapter->recvpriv.signal_strength_dbg = signal_strength; + + if (is_signal_dbg) + RTW_INFO("set %s %u\n", "DBG_SIGNAL_STRENGTH", signal_strength); + else + RTW_INFO("set %s\n", "HW_SIGNAL_STRENGTH"); + + } + + return count; + +} +#ifdef CONFIG_80211N_HT + +int proc_get_ht_enable(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + + if (pregpriv) + RTW_PRINT_SEL(m, "%d\n", pregpriv->ht_enable); + + return 0; +} + +ssize_t proc_set_ht_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + char tmp[32]; + u32 mode; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d ", &mode); + + if (pregpriv && mode < 2) { + pregpriv->ht_enable = mode; + RTW_INFO("ht_enable=%d\n", pregpriv->ht_enable); + } + } + + return count; + +} + +int proc_get_bw_mode(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + + if (pregpriv) + RTW_PRINT_SEL(m, "0x%02x\n", pregpriv->bw_mode); + + return 0; +} + +ssize_t proc_set_bw_mode(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + char tmp[32]; + u32 mode; + u8 bw_2g; + u8 bw_5g; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%x ", &mode); + bw_5g = mode >> 4; + bw_2g = mode & 0x0f; + + if (pregpriv && bw_2g <= 4 && bw_5g <= 4) { + + pregpriv->bw_mode = mode; + printk("bw_mode=0x%x\n", mode); + + } + } + + return count; + +} + +int proc_get_ampdu_enable(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + + if (pregpriv) + RTW_PRINT_SEL(m, "%d\n", pregpriv->ampdu_enable); + + return 0; +} + +ssize_t proc_set_ampdu_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + char tmp[32]; + u32 mode; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d ", &mode); + + if (pregpriv && mode < 2) { + pregpriv->ampdu_enable = mode; + printk("ampdu_enable=%d\n", mode); + } + + } + + return count; + +} + +int proc_get_mac_rptbuf(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + u16 i; + u16 mac_id; + u32 shcut_addr = 0; + u32 read_addr = 0; +#ifdef CONFIG_RTL8814A + RTW_PRINT_SEL(m, "TX ShortCut:\n"); + for (mac_id = 0; mac_id < 64; mac_id++) { + rtw_write16(padapter, 0x140, 0x662 | ((mac_id & BIT5) >> 5)); + shcut_addr = 0x8000; + shcut_addr = shcut_addr | ((mac_id & 0x1f) << 7); + RTW_PRINT_SEL(m, "mac_id=%d, 0x140=%x =>\n", mac_id, 0x662 | ((mac_id & BIT5) >> 5)); + for (i = 0; i < 30; i++) { + read_addr = 0; + read_addr = shcut_addr | (i << 2); + RTW_PRINT_SEL(m, "i=%02d: MAC_%04x= %08x ", i, read_addr, rtw_read32(padapter, read_addr)); + if (!((i + 1) % 4)) + RTW_PRINT_SEL(m, "\n"); + if (i == 29) + RTW_PRINT_SEL(m, "\n"); + } + } +#endif /* CONFIG_RTL8814A */ + return 0; +} + + +int proc_get_rx_ampdu(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + + _RTW_PRINT_SEL(m, "accept: "); + if (padapter->fix_rx_ampdu_accept == RX_AMPDU_ACCEPT_INVALID) + RTW_PRINT_SEL(m, "%u%s\n", rtw_rx_ampdu_is_accept(padapter), "(auto)"); + else + RTW_PRINT_SEL(m, "%u%s\n", padapter->fix_rx_ampdu_accept, "(fixed)"); + + _RTW_PRINT_SEL(m, "size: "); + if (padapter->fix_rx_ampdu_size == RX_AMPDU_SIZE_INVALID) + RTW_PRINT_SEL(m, "%u%s\n", rtw_rx_ampdu_size(padapter), "(auto)"); + else + RTW_PRINT_SEL(m, "%u%s\n", padapter->fix_rx_ampdu_size, "(fixed)"); + + RTW_PRINT_SEL(m, "%19s %17s\n", "fix_rx_ampdu_accept", "fix_rx_ampdu_size"); + + _RTW_PRINT_SEL(m, "%-19d %-17u\n" + , padapter->fix_rx_ampdu_accept + , padapter->fix_rx_ampdu_size); + + return 0; +} + +ssize_t proc_set_rx_ampdu(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + char tmp[32]; + u8 accept; + u8 size; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%hhu %hhu", &accept, &size); + + if (num >= 1) + rtw_rx_ampdu_set_accept(padapter, accept, RX_AMPDU_DRV_FIXED); + if (num >= 2) + rtw_rx_ampdu_set_size(padapter, size, RX_AMPDU_DRV_FIXED); + + rtw_rx_ampdu_apply(padapter); + } + +exit: + return count; +} +int proc_get_rx_ampdu_factor(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + + + if (padapter) + RTW_PRINT_SEL(m, "rx ampdu factor = %x\n", padapter->driver_rx_ampdu_factor); + + return 0; +} + +ssize_t proc_set_rx_ampdu_factor(struct file *file, const char __user *buffer + , size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + u32 factor; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d ", &factor); + + if (padapter && (num == 1)) { + RTW_INFO("padapter->driver_rx_ampdu_factor = %x\n", factor); + + if (factor > 0x03) + padapter->driver_rx_ampdu_factor = 0xFF; + else + padapter->driver_rx_ampdu_factor = factor; + } + } + + return count; +} + +int proc_get_rx_ampdu_density(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + + + if (padapter) + RTW_PRINT_SEL(m, "rx ampdu densityg = %x\n", padapter->driver_rx_ampdu_spacing); + + return 0; +} + +ssize_t proc_set_rx_ampdu_density(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + u32 density; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d ", &density); + + if (padapter && (num == 1)) { + RTW_INFO("padapter->driver_rx_ampdu_spacing = %x\n", density); + + if (density > 0x07) + padapter->driver_rx_ampdu_spacing = 0xFF; + else + padapter->driver_rx_ampdu_spacing = density; + } + } + + return count; +} + +int proc_get_tx_ampdu_density(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + + + if (padapter) + RTW_PRINT_SEL(m, "tx ampdu density = %x\n", padapter->driver_ampdu_spacing); + + return 0; +} + +ssize_t proc_set_tx_ampdu_density(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + u32 density; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d ", &density); + + if (padapter && (num == 1)) { + RTW_INFO("padapter->driver_ampdu_spacing = %x\n", density); + + if (density > 0x07) + padapter->driver_ampdu_spacing = 0xFF; + else + padapter->driver_ampdu_spacing = density; + } + } + + return count; +} + +#ifdef CONFIG_TX_AMSDU +int proc_get_tx_amsdu(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + if (padapter) + { + RTW_PRINT_SEL(m, "tx amsdu = %d\n", padapter->tx_amsdu); + RTW_PRINT_SEL(m, "amsdu set timer conut = %u\n", pxmitpriv->amsdu_debug_set_timer); + RTW_PRINT_SEL(m, "amsdu time out count = %u\n", pxmitpriv->amsdu_debug_timeout); + RTW_PRINT_SEL(m, "amsdu coalesce one count = %u\n", pxmitpriv->amsdu_debug_coalesce_one); + RTW_PRINT_SEL(m, "amsdu coalesce two count = %u\n", pxmitpriv->amsdu_debug_coalesce_two); + } + + return 0; +} + +ssize_t proc_set_tx_amsdu(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + char tmp[32]; + u32 amsdu; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d ", &amsdu); + + if (padapter && (num == 1)) { + RTW_INFO("padapter->tx_amsdu = %x\n", amsdu); + + if (amsdu > 3) + padapter->tx_amsdu = 0; + else if(amsdu == 3) + { + pxmitpriv->amsdu_debug_set_timer = 0; + pxmitpriv->amsdu_debug_timeout = 0; + pxmitpriv->amsdu_debug_coalesce_one = 0; + pxmitpriv->amsdu_debug_coalesce_two = 0; + } + else + padapter->tx_amsdu = amsdu; + } + } + + return count; +} + +int proc_get_tx_amsdu_rate(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + + if (padapter) + RTW_PRINT_SEL(m, "tx amsdu rate = %d Mbps\n", padapter->tx_amsdu_rate); + + return 0; +} + +ssize_t proc_set_tx_amsdu_rate(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + u32 amsdu_rate; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d ", &amsdu_rate); + + if (padapter && (num == 1)) { + RTW_INFO("padapter->tx_amsdu_rate = %x\n", amsdu_rate); + padapter->tx_amsdu_rate = amsdu_rate; + } + } + + return count; +} +#endif /* CONFIG_TX_AMSDU */ +#endif /* CONFIG_80211N_HT */ + +int proc_get_en_fwps(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if (pregpriv) + RTW_PRINT_SEL(m, "check_fw_ps = %d , 1:enable get FW PS state , 0: disable get FW PS state\n" + , pregpriv->check_fw_ps); + + return 0; +} + +ssize_t proc_set_en_fwps(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + char tmp[32]; + u32 mode; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d ", &mode); + + if (pregpriv && mode < 2) { + pregpriv->check_fw_ps = mode; + RTW_INFO("pregpriv->check_fw_ps=%d\n", pregpriv->check_fw_ps); + } + + } + + return count; +} + +/* +int proc_get_two_path_rssi(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + + if(padapter) + RTW_PRINT_SEL(m, "%d %d\n", + padapter->recvpriv.RxRssi[0], padapter->recvpriv.RxRssi[1]); + + return 0; +} +*/ +#ifdef CONFIG_80211N_HT +void rtw_dump_dft_phy_cap(void *sel, _adapter *adapter) +{ + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + #ifdef CONFIG_80211AC_VHT + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; + #endif + + #ifdef CONFIG_80211AC_VHT + RTW_PRINT_SEL(sel, "[DFT CAP] VHT STBC Tx : %s\n", (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX)) ? "V" : "X"); + RTW_PRINT_SEL(sel, "[DFT CAP] VHT STBC Rx : %s\n", (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_RX)) ? "V" : "X"); + #endif + RTW_PRINT_SEL(sel, "[DFT CAP] HT STBC Tx : %s\n", (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX)) ? "V" : "X"); + RTW_PRINT_SEL(sel, "[DFT CAP] HT STBC Rx : %s\n\n", (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_RX)) ? "V" : "X"); + + #ifdef CONFIG_80211AC_VHT + RTW_PRINT_SEL(sel, "[DFT CAP] VHT LDPC Tx : %s\n", (TEST_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_TX)) ? "V" : "X"); + RTW_PRINT_SEL(sel, "[DFT CAP] VHT LDPC Rx : %s\n", (TEST_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_RX)) ? "V" : "X"); + #endif + RTW_PRINT_SEL(sel, "[DFT CAP] HT LDPC Tx : %s\n", (TEST_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_TX)) ? "V" : "X"); + RTW_PRINT_SEL(sel, "[DFT CAP] HT LDPC Rx : %s\n\n", (TEST_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_RX)) ? "V" : "X"); + + #ifdef CONFIG_BEAMFORMING + #ifdef CONFIG_80211AC_VHT + RTW_PRINT_SEL(sel, "[DFT CAP] VHT MU Bfer : %s\n", (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) ? "V" : "X"); + RTW_PRINT_SEL(sel, "[DFT CAP] VHT MU Bfee : %s\n", (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE)) ? "V" : "X"); + RTW_PRINT_SEL(sel, "[DFT CAP] VHT SU Bfer : %s\n", (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) ? "V" : "X"); + RTW_PRINT_SEL(sel, "[DFT CAP] VHT SU Bfee : %s\n", (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) ? "V" : "X"); + #endif + RTW_PRINT_SEL(sel, "[DFT CAP] HT Bfer : %s\n", (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) ? "V" : "X"); + RTW_PRINT_SEL(sel, "[DFT CAP] HT Bfee : %s\n", (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) ? "V" : "X"); + #endif +} + +void rtw_get_dft_phy_cap(void *sel, _adapter *adapter) +{ + RTW_PRINT_SEL(sel, "\n ======== PHY CAP protocol ========\n"); + rtw_ht_use_default_setting(adapter); + #ifdef CONFIG_80211AC_VHT + rtw_vht_use_default_setting(adapter); + #endif + rtw_dump_dft_phy_cap(sel, adapter); +} + +void rtw_dump_drv_phy_cap(void *sel, _adapter *adapter) +{ + struct registry_priv *pregistry_priv = &adapter->registrypriv; + + RTW_PRINT_SEL(sel, "\n ======== DRV's configuration ========\n"); + #if 0 + RTW_PRINT_SEL(sel, "[DRV CAP] TRx Capability : 0x%08x\n", phy_spec->trx_cap); + RTW_PRINT_SEL(sel, "[DRV CAP] Tx Stream Num Index : %d\n", (phy_spec->trx_cap >> 24) & 0xFF); /*Tx Stream Num Index [31:24]*/ + RTW_PRINT_SEL(sel, "[DRV CAP] Rx Stream Num Index : %d\n", (phy_spec->trx_cap >> 16) & 0xFF); /*Rx Stream Num Index [23:16]*/ + RTW_PRINT_SEL(sel, "[DRV CAP] Tx Path Num Index : %d\n", (phy_spec->trx_cap >> 8) & 0xFF);/*Tx Path Num Index [15:8]*/ + RTW_PRINT_SEL(sel, "[DRV CAP] Rx Path Num Index : %d\n", (phy_spec->trx_cap & 0xFF));/*Rx Path Num Index [7:0]*/ + #endif + + RTW_PRINT_SEL(sel, "[DRV CAP] STBC Capability : 0x%02x\n", pregistry_priv->stbc_cap); + RTW_PRINT_SEL(sel, "[DRV CAP] VHT STBC Tx : %s\n", (TEST_FLAG(pregistry_priv->stbc_cap, BIT1)) ? "V" : "X"); /*BIT1: Enable VHT STBC Tx*/ + RTW_PRINT_SEL(sel, "[DRV CAP] VHT STBC Rx : %s\n", (TEST_FLAG(pregistry_priv->stbc_cap, BIT0)) ? "V" : "X"); /*BIT0: Enable VHT STBC Rx*/ + RTW_PRINT_SEL(sel, "[DRV CAP] HT STBC Tx : %s\n", (TEST_FLAG(pregistry_priv->stbc_cap, BIT5)) ? "V" : "X"); /*BIT5: Enable HT STBC Tx*/ + RTW_PRINT_SEL(sel, "[DRV CAP] HT STBC Rx : %s\n\n", (TEST_FLAG(pregistry_priv->stbc_cap, BIT4)) ? "V" : "X"); /*BIT4: Enable HT STBC Rx*/ + + RTW_PRINT_SEL(sel, "[DRV CAP] LDPC Capability : 0x%02x\n", pregistry_priv->ldpc_cap); + RTW_PRINT_SEL(sel, "[DRV CAP] VHT LDPC Tx : %s\n", (TEST_FLAG(pregistry_priv->ldpc_cap, BIT1)) ? "V" : "X"); /*BIT1: Enable VHT LDPC Tx*/ + RTW_PRINT_SEL(sel, "[DRV CAP] VHT LDPC Rx : %s\n", (TEST_FLAG(pregistry_priv->ldpc_cap, BIT0)) ? "V" : "X"); /*BIT0: Enable VHT LDPC Rx*/ + RTW_PRINT_SEL(sel, "[DRV CAP] HT LDPC Tx : %s\n", (TEST_FLAG(pregistry_priv->ldpc_cap, BIT5)) ? "V" : "X"); /*BIT5: Enable HT LDPC Tx*/ + RTW_PRINT_SEL(sel, "[DRV CAP] HT LDPC Rx : %s\n\n", (TEST_FLAG(pregistry_priv->ldpc_cap, BIT4)) ? "V" : "X"); /*BIT4: Enable HT LDPC Rx*/ + #ifdef CONFIG_BEAMFORMING + #if 0 + RTW_PRINT_SEL(sel, "[DRV CAP] TxBF parameter : 0x%08x\n", phy_spec->txbf_param); + RTW_PRINT_SEL(sel, "[DRV CAP] VHT Sounding Dim : %d\n", (phy_spec->txbf_param >> 24) & 0xFF); /*VHT Sounding Dim [31:24]*/ + RTW_PRINT_SEL(sel, "[DRV CAP] VHT Steering Ant : %d\n", (phy_spec->txbf_param >> 16) & 0xFF); /*VHT Steering Ant [23:16]*/ + RTW_PRINT_SEL(sel, "[DRV CAP] HT Sounding Dim : %d\n", (phy_spec->txbf_param >> 8) & 0xFF); /*HT Sounding Dim [15:8]*/ + RTW_PRINT_SEL(sel, "[DRV CAP] HT Steering Ant : %d\n", phy_spec->txbf_param & 0xFF); /*HT Steering Ant [7:0]*/ + #endif + + /* + * BIT0: Enable VHT SU Beamformer + * BIT1: Enable VHT SU Beamformee + * BIT2: Enable VHT MU Beamformer, depend on VHT SU Beamformer + * BIT3: Enable VHT MU Beamformee, depend on VHT SU Beamformee + * BIT4: Enable HT Beamformer + * BIT5: Enable HT Beamformee + */ + RTW_PRINT_SEL(sel, "[DRV CAP] TxBF Capability : 0x%02x\n", pregistry_priv->beamform_cap); + RTW_PRINT_SEL(sel, "[DRV CAP] VHT MU Bfer : %s\n", (TEST_FLAG(pregistry_priv->beamform_cap, BIT2)) ? "V" : "X"); + RTW_PRINT_SEL(sel, "[DRV CAP] VHT MU Bfee : %s\n", (TEST_FLAG(pregistry_priv->beamform_cap, BIT3)) ? "V" : "X"); + RTW_PRINT_SEL(sel, "[DRV CAP] VHT SU Bfer : %s\n", (TEST_FLAG(pregistry_priv->beamform_cap, BIT0)) ? "V" : "X"); + RTW_PRINT_SEL(sel, "[DRV CAP] VHT SU Bfee : %s\n", (TEST_FLAG(pregistry_priv->beamform_cap, BIT1)) ? "V" : "X"); + RTW_PRINT_SEL(sel, "[DRV CAP] HT Bfer : %s\n", (TEST_FLAG(pregistry_priv->beamform_cap, BIT4)) ? "V" : "X"); + RTW_PRINT_SEL(sel, "[DRV CAP] HT Bfee : %s\n", (TEST_FLAG(pregistry_priv->beamform_cap, BIT5)) ? "V" : "X"); + + RTW_PRINT_SEL(sel, "[DRV CAP] Tx Bfer rf_num : %d\n", pregistry_priv->beamformer_rf_num); + RTW_PRINT_SEL(sel, "[DRV CAP] Tx Bfee rf_num : %d\n", pregistry_priv->beamformee_rf_num); + #endif +} + +int proc_get_stbc_cap(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + + if (pregpriv) + RTW_PRINT_SEL(m, "0x%02x\n", pregpriv->stbc_cap); + + return 0; +} + +ssize_t proc_set_stbc_cap(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + char tmp[32]; + u32 mode; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d ", &mode); + + if (pregpriv) { + pregpriv->stbc_cap = mode; + RTW_INFO("stbc_cap = 0x%02x\n", mode); + } + } + + return count; +} +int proc_get_rx_stbc(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + + if (pregpriv) + RTW_PRINT_SEL(m, "%d\n", pregpriv->rx_stbc); + + return 0; +} + +ssize_t proc_set_rx_stbc(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + char tmp[32]; + u32 mode; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d ", &mode); + + if (pregpriv && (mode == 0 || mode == 1 || mode == 2 || mode == 3)) { + pregpriv->rx_stbc = mode; + printk("rx_stbc=%d\n", mode); + } + } + + return count; + +} +int proc_get_ldpc_cap(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + + if (pregpriv) + RTW_PRINT_SEL(m, "0x%02x\n", pregpriv->ldpc_cap); + + return 0; +} + +ssize_t proc_set_ldpc_cap(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + char tmp[32]; + u32 mode; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d ", &mode); + + if (pregpriv) { + pregpriv->ldpc_cap = mode; + RTW_INFO("ldpc_cap = 0x%02x\n", mode); + } + } + + return count; +} +#ifdef CONFIG_BEAMFORMING +int proc_get_txbf_cap(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + + if (pregpriv) + RTW_PRINT_SEL(m, "0x%02x\n", pregpriv->beamform_cap); + + return 0; +} + +ssize_t proc_set_txbf_cap(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct registry_priv *pregpriv = &padapter->registrypriv; + char tmp[32]; + u32 mode; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d ", &mode); + + if (pregpriv) { + pregpriv->beamform_cap = mode; + RTW_INFO("beamform_cap = 0x%02x\n", mode); + } + } + + return count; +} +#endif +#endif /* CONFIG_80211N_HT */ + +/*int proc_get_rssi_disp(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + return 0; +} +*/ + +/*ssize_t proc_set_rssi_disp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + u32 enable=0; + + if (count < 1) + { + RTW_INFO("argument size is less than 1\n"); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%x", &enable); + + if (num != 1) { + RTW_INFO("invalid set_rssi_disp parameter!\n"); + return count; + } + + if(enable) + { + RTW_INFO("Linked info Function Enable\n"); + padapter->bLinkInfoDump = enable ; + } + else + { + RTW_INFO("Linked info Function Disable\n"); + padapter->bLinkInfoDump = 0 ; + } + + } + + return count; + +} + +*/ +#ifdef CONFIG_AP_MODE + +int proc_get_all_sta_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _irqL irqL; + struct sta_info *psta; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct sta_priv *pstapriv = &padapter->stapriv; + int i; + _list *plist, *phead; + + RTW_PRINT_SEL(m, "sta_dz_bitmap=0x%x, tim_bitmap=0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap); + + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + for (i = 0; i < NUM_STA; i++) { + phead = &(pstapriv->sta_hash[i]); + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + + plist = get_next(plist); + + /* if(extra_arg == psta->aid) */ + { + RTW_PRINT_SEL(m, "==============================\n"); + RTW_PRINT_SEL(m, "sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr)); + RTW_PRINT_SEL(m, "rtsen=%d, cts2slef=%d\n", psta->rtsen, psta->cts2self); + RTW_PRINT_SEL(m, "state=0x%x, aid=%d, macid=%d, raid=%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); +#ifdef CONFIG_80211N_HT + RTW_PRINT_SEL(m, "qos_en=%d, ht_en=%d, init_rate=%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); + RTW_PRINT_SEL(m, "bwmode=%d, ch_offset=%d, sgi_20m=%d,sgi_40m=%d\n", psta->bw_mode, psta->htpriv.ch_offset, psta->htpriv.sgi_20m, psta->htpriv.sgi_40m); + RTW_PRINT_SEL(m, "ampdu_enable = %d\n", psta->htpriv.ampdu_enable); + RTW_PRINT_SEL(m, "tx_amsdu_enable = %d\n", psta->htpriv.tx_amsdu_enable); + RTW_PRINT_SEL(m, "agg_enable_bitmap=%x, candidate_tid_bitmap=%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap); +#endif /* CONFIG_80211N_HT */ + RTW_PRINT_SEL(m, "sleepq_len=%d\n", psta->sleepq_len); + RTW_PRINT_SEL(m, "sta_xmitpriv.vo_q_qcnt=%d\n", psta->sta_xmitpriv.vo_q.qcnt); + RTW_PRINT_SEL(m, "sta_xmitpriv.vi_q_qcnt=%d\n", psta->sta_xmitpriv.vi_q.qcnt); + RTW_PRINT_SEL(m, "sta_xmitpriv.be_q_qcnt=%d\n", psta->sta_xmitpriv.be_q.qcnt); + RTW_PRINT_SEL(m, "sta_xmitpriv.bk_q_qcnt=%d\n", psta->sta_xmitpriv.bk_q.qcnt); + + RTW_PRINT_SEL(m, "capability=0x%x\n", psta->capability); + RTW_PRINT_SEL(m, "flags=0x%x\n", psta->flags); + RTW_PRINT_SEL(m, "wpa_psk=0x%x\n", psta->wpa_psk); + RTW_PRINT_SEL(m, "wpa2_group_cipher=0x%x\n", psta->wpa2_group_cipher); + RTW_PRINT_SEL(m, "wpa2_pairwise_cipher=0x%x\n", psta->wpa2_pairwise_cipher); + RTW_PRINT_SEL(m, "qos_info=0x%x\n", psta->qos_info); + RTW_PRINT_SEL(m, "dot118021XPrivacy=0x%x\n", psta->dot118021XPrivacy); + + sta_rx_reorder_ctl_dump(m, psta); + +#ifdef CONFIG_TDLS + RTW_PRINT_SEL(m, "tdls_sta_state=0x%08x\n", psta->tdls_sta_state); + RTW_PRINT_SEL(m, "PeerKey_Lifetime=%d\n", psta->TDLS_PeerKey_Lifetime); + RTW_PRINT_SEL(m, "rx_data_pkts=%llu\n", psta->sta_stats.rx_data_pkts); + RTW_PRINT_SEL(m, "rx_bytes=%llu\n", psta->sta_stats.rx_bytes); + RTW_PRINT_SEL(m, "tx_data_pkts=%llu\n", psta->sta_stats.tx_pkts); + RTW_PRINT_SEL(m, "tx_bytes=%llu\n", psta->sta_stats.tx_bytes); +#endif /* CONFIG_TDLS */ + + dump_st_ctl(m, &psta->st_ctl); + + if (STA_OP_WFD_MODE(psta)) + RTW_PRINT_SEL(m, "op_wfd_mode:0x%02x\n", STA_OP_WFD_MODE(psta)); + + RTW_PRINT_SEL(m, "==============================\n"); + } + + } + + } + + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + return 0; +} + +#endif + +#ifdef CONFIG_PREALLOC_RX_SKB_BUFFER +int proc_get_rtkm_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct recv_priv *precvpriv = &padapter->recvpriv; + struct recv_buf *precvbuf; + + precvbuf = (struct recv_buf *)precvpriv->precv_buf; + + RTW_PRINT_SEL(m, "============[RTKM Info]============\n"); + RTW_PRINT_SEL(m, "MAX_RTKM_NR_PREALLOC_RECV_SKB: %d\n", rtw_rtkm_get_nr_recv_skb()); + RTW_PRINT_SEL(m, "MAX_RTKM_RECVBUF_SZ: %d\n", rtw_rtkm_get_buff_size()); + + RTW_PRINT_SEL(m, "============[Driver Info]============\n"); + RTW_PRINT_SEL(m, "NR_PREALLOC_RECV_SKB: %d\n", NR_PREALLOC_RECV_SKB); + RTW_PRINT_SEL(m, "MAX_RECVBUF_SZ: %d\n", precvbuf->alloc_sz); + + return 0; +} +#endif /* CONFIG_PREALLOC_RX_SKB_BUFFER */ + +#ifdef DBG_MEMORY_LEAK +#include <asm/atomic.h> +extern atomic_t _malloc_cnt;; +extern atomic_t _malloc_size;; + +int proc_get_malloc_cnt(struct seq_file *m, void *v) +{ + RTW_PRINT_SEL(m, "_malloc_cnt=%d\n", atomic_read(&_malloc_cnt)); + RTW_PRINT_SEL(m, "_malloc_size=%d\n", atomic_read(&_malloc_size)); + + return 0; +} +#endif /* DBG_MEMORY_LEAK */ + +#ifdef CONFIG_FIND_BEST_CHANNEL +int proc_get_best_channel(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + u32 i, best_channel_24G = 1, best_channel_5G = 36, index_24G = 0, index_5G = 0; + + for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) { + if (pmlmeext->channel_set[i].ChannelNum == 1) + index_24G = i; + if (pmlmeext->channel_set[i].ChannelNum == 36) + index_5G = i; + } + + for (i = 0; (i < MAX_CHANNEL_NUM) && (pmlmeext->channel_set[i].ChannelNum != 0) ; i++) { + /* 2.4G */ + if (pmlmeext->channel_set[i].ChannelNum == 6) { + if (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_24G].rx_count) { + index_24G = i; + best_channel_24G = pmlmeext->channel_set[i].ChannelNum; + } + } + + /* 5G */ + if (pmlmeext->channel_set[i].ChannelNum >= 36 + && pmlmeext->channel_set[i].ChannelNum < 140) { + /* Find primary channel */ + if (((pmlmeext->channel_set[i].ChannelNum - 36) % 8 == 0) + && (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) { + index_5G = i; + best_channel_5G = pmlmeext->channel_set[i].ChannelNum; + } + } + + if (pmlmeext->channel_set[i].ChannelNum >= 149 + && pmlmeext->channel_set[i].ChannelNum < 165) { + /* find primary channel */ + if (((pmlmeext->channel_set[i].ChannelNum - 149) % 8 == 0) + && (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) { + index_5G = i; + best_channel_5G = pmlmeext->channel_set[i].ChannelNum; + } + } +#if 1 /* debug */ + RTW_PRINT_SEL(m, "The rx cnt of channel %3d = %d\n", + pmlmeext->channel_set[i].ChannelNum, pmlmeext->channel_set[i].rx_count); +#endif + } + + RTW_PRINT_SEL(m, "best_channel_5G = %d\n", best_channel_5G); + RTW_PRINT_SEL(m, "best_channel_24G = %d\n", best_channel_24G); + + return 0; +} + +ssize_t proc_set_best_channel(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + char tmp[32]; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + int i; + for (i = 0; pmlmeext->channel_set[i].ChannelNum != 0; i++) + pmlmeext->channel_set[i].rx_count = 0; + + RTW_INFO("set %s\n", "Clean Best Channel Count"); + } + + return count; +} +#endif /* CONFIG_FIND_BEST_CHANNEL */ + +#ifdef CONFIG_BT_COEXIST +int proc_get_btcoex_dbg(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + PADAPTER padapter; + char buf[512] = {0}; + padapter = (PADAPTER)rtw_netdev_priv(dev); + + rtw_btcoex_GetDBG(padapter, buf, 512); + + _RTW_PRINT_SEL(m, "%s", buf); + + return 0; +} + +ssize_t proc_set_btcoex_dbg(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + PADAPTER padapter; + u8 tmp[80] = {0}; + u32 module[2] = {0}; + u32 num; + + padapter = (PADAPTER)rtw_netdev_priv(dev); + + /* RTW_INFO("+" FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter)); */ + + if (NULL == buffer) { + RTW_INFO(FUNC_ADPT_FMT ": input buffer is NULL!\n", + FUNC_ADPT_ARG(padapter)); + + return -EFAULT; + } + + if (count < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input length is 0!\n", + FUNC_ADPT_ARG(padapter)); + + return -EFAULT; + } + + num = count; + if (num > (sizeof(tmp) - 1)) + num = (sizeof(tmp) - 1); + + if (copy_from_user(tmp, buffer, num)) { + RTW_INFO(FUNC_ADPT_FMT ": copy buffer from user space FAIL!\n", + FUNC_ADPT_ARG(padapter)); + + return -EFAULT; + } + + num = sscanf(tmp, "%x %x", module, module + 1); + if (1 == num) { + if (0 == module[0]) + _rtw_memset(module, 0, sizeof(module)); + else + _rtw_memset(module, 0xFF, sizeof(module)); + } else if (2 != num) { + RTW_INFO(FUNC_ADPT_FMT ": input(\"%s\") format incorrect!\n", + FUNC_ADPT_ARG(padapter), tmp); + + if (0 == num) + return -EFAULT; + } + + RTW_INFO(FUNC_ADPT_FMT ": input 0x%08X 0x%08X\n", + FUNC_ADPT_ARG(padapter), module[0], module[1]); + rtw_btcoex_SetDBG(padapter, module); + + return count; +} + +int proc_get_btcoex_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + PADAPTER padapter; + const u32 bufsize = 30 * 100; + u8 *pbuf = NULL; + + padapter = (PADAPTER)rtw_netdev_priv(dev); + + pbuf = rtw_zmalloc(bufsize); + if (NULL == pbuf) + return -ENOMEM; + + rtw_btcoex_DisplayBtCoexInfo(padapter, pbuf, bufsize); + + _RTW_PRINT_SEL(m, "%s\n", pbuf); + + rtw_mfree(pbuf, bufsize); + + return 0; +} +#endif /* CONFIG_BT_COEXIST */ + +#if defined(DBG_CONFIG_ERROR_DETECT) +int proc_get_sreset(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + + return 0; +} + +ssize_t proc_set_sreset(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + s32 trigger_point; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%d", &trigger_point); + + if (trigger_point == SRESET_TGP_NULL) + rtw_hal_sreset_reset(padapter); + else + sreset_set_trigger_point(padapter, trigger_point); + } + + return count; + +} +#endif /* DBG_CONFIG_ERROR_DETECT */ + +#ifdef CONFIG_PCI_HCI + +int proc_get_rx_ring(struct seq_file *m, void *v) +{ + _irqL irqL; + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *) rtw_netdev_priv(dev); + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); + struct recv_priv *precvpriv = &padapter->recvpriv; + struct rtw_rx_ring *rx_ring = &precvpriv->rx_ring[RX_MPDU_QUEUE]; + int i, j; + + RTW_PRINT_SEL(m, "rx ring (%p)\n", rx_ring); + RTW_PRINT_SEL(m, " dma: 0x%08x\n", (int) rx_ring->dma); + RTW_PRINT_SEL(m, " idx: %d\n", rx_ring->idx); + + _enter_critical(&pdvobjpriv->irq_th_lock, &irqL); + for (i = 0; i < precvpriv->rxringcount; i++) { +#ifdef CONFIG_TRX_BD_ARCH + struct rx_buf_desc *entry = &rx_ring->buf_desc[i]; +#else + struct recv_stat *entry = &rx_ring->desc[i]; +#endif + struct sk_buff *skb = rx_ring->rx_buf[i]; + + RTW_PRINT_SEL(m, " desc[%03d]: %p, rx_buf[%03d]: 0x%08x\n", + i, entry, i, cpu_to_le32(*((dma_addr_t *)skb->cb))); + + for (j = 0; j < sizeof(*entry) / 4; j++) { + if ((j % 4) == 0) + RTW_PRINT_SEL(m, " 0x%03x", j); + + RTW_PRINT_SEL(m, " 0x%08x ", ((int *) entry)[j]); + + if ((j % 4) == 3) + RTW_PRINT_SEL(m, "\n"); + } + } + _exit_critical(&pdvobjpriv->irq_th_lock, &irqL); + + return 0; +} + +int proc_get_tx_ring(struct seq_file *m, void *v) +{ + _irqL irqL; + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *) rtw_netdev_priv(dev); + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + int i, j, k; + + _enter_critical(&pdvobjpriv->irq_th_lock, &irqL); + for (i = 0; i < PCI_MAX_TX_QUEUE_COUNT; i++) { + struct rtw_tx_ring *tx_ring = &pxmitpriv->tx_ring[i]; + + RTW_PRINT_SEL(m, "tx ring[%d] (%p)\n", i, tx_ring); + RTW_PRINT_SEL(m, " dma: 0x%08x\n", (int) tx_ring->dma); + RTW_PRINT_SEL(m, " idx: %d\n", tx_ring->idx); + RTW_PRINT_SEL(m, " entries: %d\n", tx_ring->entries); + /* RTW_PRINT_SEL(m, " queue: %d\n", tx_ring->queue); */ + RTW_PRINT_SEL(m, " qlen: %d\n", tx_ring->qlen); + + for (j = 0; j < pxmitpriv->txringcount[i]; j++) { +#ifdef CONFIG_TRX_BD_ARCH + struct tx_buf_desc *entry = &tx_ring->buf_desc[j]; +#else + struct tx_desc *entry = &tx_ring->desc[j]; +#endif + + RTW_PRINT_SEL(m, " desc[%03d]: %p\n", j, entry); + for (k = 0; k < sizeof(*entry) / 4; k++) { + if ((k % 4) == 0) + RTW_PRINT_SEL(m, " 0x%03x", k); + + RTW_PRINT_SEL(m, " 0x%08x ", ((int *) entry)[k]); + + if ((k % 4) == 3) + RTW_PRINT_SEL(m, "\n"); + } + } + } + _exit_critical(&pdvobjpriv->irq_th_lock, &irqL); + + return 0; +} +#endif + +#ifdef CONFIG_WOWLAN +int proc_get_pattern_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + struct registry_priv *pregistrypriv = &padapter->registrypriv; + u8 pattern_num = 0, val8; + char str_1[128]; + char *p_str; + int i = 0 , j = 0, k = 0; + int len = 0, max_len = 0, total = 0; + + p_str = str_1; + max_len = sizeof(str_1); + + total = pwrpriv->wowlan_pattern_idx; + + rtw_set_default_pattern(padapter); + + /*show pattern*/ + RTW_PRINT_SEL(m, "\n======[Pattern Info.]======\n"); + RTW_PRINT_SEL(m, "pattern number: %d\n", total); + RTW_PRINT_SEL(m, "support default patterns: %c\n", + (pregistrypriv->default_patterns_en) ? 'Y' : 'N'); + + for (k = 0; k < total ; k++) { + RTW_PRINT_SEL(m, "\npattern idx: %d\n", k); + RTW_PRINT_SEL(m, "pattern content:\n"); + + p_str = str_1; + max_len = sizeof(str_1); + for (i = 0 ; i < MAX_WKFM_PATTERN_SIZE / 8 ; i++) { + _rtw_memset(p_str, 0, max_len); + len = 0; + for (j = 0 ; j < 8 ; j++) { + val8 = pwrpriv->patterns[k].content[i * 8 + j]; + len += snprintf(p_str + len, max_len - len, + "%02x ", val8); + } + RTW_PRINT_SEL(m, "%s\n", p_str); + } + RTW_PRINT_SEL(m, "\npattern mask:\n"); + for (i = 0 ; i < MAX_WKFM_SIZE / 8 ; i++) { + _rtw_memset(p_str, 0, max_len); + len = 0; + for (j = 0 ; j < 8 ; j++) { + val8 = pwrpriv->patterns[k].mask[i * 8 + j]; + len += snprintf(p_str + len, max_len - len, + "%02x ", val8); + } + RTW_PRINT_SEL(m, "%s\n", p_str); + } + + RTW_PRINT_SEL(m, "\npriv_pattern_len:\n"); + RTW_PRINT_SEL(m, "pattern_len: %d\n", pwrpriv->patterns[k].len); + RTW_PRINT_SEL(m, "*****************\n"); + } + + return 0; +} +ssize_t proc_set_pattern_info(struct file *file, const char __user *buffer, + size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + struct wowlan_ioctl_param poidparam; + u8 tmp[MAX_WKFM_PATTERN_SIZE] = {0}; + int ret = 0, num = 0; + u8 index = 0; + + poidparam.subcode = 0; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (pwrpriv->wowlan_pattern_idx >= MAX_WKFM_CAM_NUM) { + RTW_INFO("WARNING: priv-pattern is full(idx: %d)\n", + pwrpriv->wowlan_pattern_idx); + RTW_INFO("WARNING: please clean priv-pattern first\n"); + return -ENOMEM; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + if (strncmp(tmp, "clean", 5) == 0) { + poidparam.subcode = WOWLAN_PATTERN_CLEAN; + rtw_hal_set_hwreg(padapter, + HW_VAR_WOWLAN, (u8 *)&poidparam); + } else { + index = pwrpriv->wowlan_pattern_idx; + ret = rtw_wowlan_parser_pattern_cmd(tmp, + pwrpriv->patterns[index].content, + &pwrpriv->patterns[index].len, + pwrpriv->patterns[index].mask); + if (ret == _TRUE) + pwrpriv->wowlan_pattern_idx++; + } + } + + return count; +} + +int proc_get_wakeup_reason(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + u8 val = pwrpriv->wowlan_last_wake_reason; + + RTW_PRINT_SEL(m, "last wake reason: %#02x\n", val); + return 0; +} +#endif /*CONFIG_WOWLAN*/ + +#ifdef CONFIG_GPIO_WAKEUP +int proc_get_wowlan_gpio_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + u8 val = pwrpriv->is_high_active; + + RTW_PRINT_SEL(m, "wakeup_gpio_idx: %d\n", WAKEUP_GPIO_IDX); + RTW_PRINT_SEL(m, "high_active: %d\n", val); + + return 0; +} + +ssize_t proc_set_wowlan_gpio_info(struct file *file, const char __user *buffer, + size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + char tmp[32] = {0}; + int num = 0; + u32 is_high_active = 0; + u8 val8 = 0; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + num = sscanf(tmp, "%u", &is_high_active); + + is_high_active = is_high_active == 0 ? 0 : 1; + + pwrpriv->is_high_active = is_high_active; + + rtw_ps_deny(padapter, PS_DENY_IOCTL); + LeaveAllPowerSaveModeDirect(padapter); + val8 = (pwrpriv->is_high_active == 0) ? 1 : 0; + rtw_hal_set_output_gpio(padapter, WAKEUP_GPIO_IDX, val8); + rtw_ps_deny_cancel(padapter, PS_DENY_IOCTL); + + RTW_INFO("set %s %d\n", "gpio_high_active", + pwrpriv->is_high_active); + RTW_INFO("%s: set GPIO_%d %d as default.\n", + __func__, WAKEUP_GPIO_IDX, val8); + } + + return count; +} +#endif /* CONFIG_GPIO_WAKEUP */ + +#ifdef CONFIG_P2P_WOWLAN +int proc_get_p2p_wowlan_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + struct p2p_wowlan_info peerinfo = pwdinfo->p2p_wow_info; + if (_TRUE == peerinfo.is_trigger) { + RTW_PRINT_SEL(m, "is_trigger: TRUE\n"); + switch (peerinfo.wowlan_recv_frame_type) { + case P2P_WOWLAN_RECV_NEGO_REQ: + RTW_PRINT_SEL(m, "Frame Type: Nego Request\n"); + break; + case P2P_WOWLAN_RECV_INVITE_REQ: + RTW_PRINT_SEL(m, "Frame Type: Invitation Request\n"); + break; + case P2P_WOWLAN_RECV_PROVISION_REQ: + RTW_PRINT_SEL(m, "Frame Type: Provision Request\n"); + break; + default: + break; + } + RTW_PRINT_SEL(m, "Peer Addr: "MAC_FMT"\n", MAC_ARG(peerinfo.wowlan_peer_addr)); + RTW_PRINT_SEL(m, "Peer WPS Config: %x\n", peerinfo.wowlan_peer_wpsconfig); + RTW_PRINT_SEL(m, "Persistent Group: %d\n", peerinfo.wowlan_peer_is_persistent); + RTW_PRINT_SEL(m, "Intivation Type: %d\n", peerinfo.wowlan_peer_invitation_type); + } else + RTW_PRINT_SEL(m, "is_trigger: False\n"); + return 0; +} +#endif /* CONFIG_P2P_WOWLAN */ + +int proc_get_new_bcn_max(struct seq_file *m, void *v) +{ + extern int new_bcn_max; + + RTW_PRINT_SEL(m, "%d", new_bcn_max); + return 0; +} + +ssize_t proc_set_new_bcn_max(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + char tmp[32]; + extern int new_bcn_max; + + if (count < 1) + return -EFAULT; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) + sscanf(tmp, "%d ", &new_bcn_max); + + return count; +} + +#ifdef CONFIG_POWER_SAVING +int proc_get_ps_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + u8 ips_mode = pwrpriv->ips_mode; + u8 lps_mode = pwrpriv->power_mgnt; + char *str = ""; + + RTW_PRINT_SEL(m, "======Power Saving Info:======\n"); + RTW_PRINT_SEL(m, "*IPS:\n"); + + if (ips_mode == IPS_NORMAL) { +#ifdef CONFIG_FWLPS_IN_IPS + str = "FW_LPS_IN_IPS"; +#else + str = "Card Disable"; +#endif + } else if (ips_mode == IPS_NONE) + str = "NO IPS"; + else if (ips_mode == IPS_LEVEL_2) + str = "IPS_LEVEL_2"; + else + str = "invalid ips_mode"; + + RTW_PRINT_SEL(m, " IPS mode: %s\n", str); + RTW_PRINT_SEL(m, " IPS enter count:%d, IPS leave count:%d\n", + pwrpriv->ips_enter_cnts, pwrpriv->ips_leave_cnts); + RTW_PRINT_SEL(m, "------------------------------\n"); + RTW_PRINT_SEL(m, "*LPS:\n"); + + if (lps_mode == PS_MODE_ACTIVE) + str = "NO LPS"; + else if (lps_mode == PS_MODE_MIN) + str = "MIN"; + else if (lps_mode == PS_MODE_MAX) + str = "MAX"; + else if (lps_mode == PS_MODE_DTIM) + str = "DTIM"; + else + sprintf(str, "%d", lps_mode); + + RTW_PRINT_SEL(m, " LPS mode: %s\n", str); + + if (pwrpriv->dtim != 0) + RTW_PRINT_SEL(m, " DTIM: %d\n", pwrpriv->dtim); + RTW_PRINT_SEL(m, " LPS enter count:%d, LPS leave count:%d\n", + pwrpriv->lps_enter_cnts, pwrpriv->lps_leave_cnts); + RTW_PRINT_SEL(m, "=============================\n"); + return 0; +} +#endif /* CONFIG_POWER_SAVING */ + +#ifdef CONFIG_TDLS +static int proc_tdls_display_tdls_function_info(struct seq_file *m) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + u8 SpaceBtwnItemAndValue = TDLS_DBG_INFO_SPACE_BTWN_ITEM_AND_VALUE; + u8 SpaceBtwnItemAndValueTmp = 0; + BOOLEAN FirstMatchFound = _FALSE; + int j = 0; + + RTW_PRINT_SEL(m, "============[TDLS Function Info]============\n"); + RTW_PRINT_SEL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Prohibited", (ptdlsinfo->ap_prohibited == _TRUE) ? "_TRUE" : "_FALSE"); + RTW_PRINT_SEL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Channel Switch Prohibited", (ptdlsinfo->ch_switch_prohibited == _TRUE) ? "_TRUE" : "_FALSE"); + RTW_PRINT_SEL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Link Established", (ptdlsinfo->link_established == _TRUE) ? "_TRUE" : "_FALSE"); + RTW_PRINT_SEL(m, "%-*s = %d/%d\n", SpaceBtwnItemAndValue, "TDLS STA Num (Linked/Allowed)", ptdlsinfo->sta_cnt, MAX_ALLOWED_TDLS_STA_NUM); + RTW_PRINT_SEL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Allowed STA Num Reached", (ptdlsinfo->sta_maximum == _TRUE) ? "_TRUE" : "_FALSE"); + +#ifdef CONFIG_TDLS_CH_SW + RTW_PRINT_SEL(m, "%-*s =", SpaceBtwnItemAndValue, "TDLS CH SW State"); + if (ptdlsinfo->chsw_info.ch_sw_state == TDLS_STATE_NONE) + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_STATE_NONE"); + else { + for (j = 0; j < 32; j++) { + if (ptdlsinfo->chsw_info.ch_sw_state & BIT(j)) { + if (FirstMatchFound == _FALSE) { + SpaceBtwnItemAndValueTmp = 1; + FirstMatchFound = _TRUE; + } else + SpaceBtwnItemAndValueTmp = SpaceBtwnItemAndValue + 3; + switch (BIT(j)) { + case TDLS_INITIATOR_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_INITIATOR_STATE"); + break; + case TDLS_RESPONDER_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_RESPONDER_STATE"); + break; + case TDLS_LINKED_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_LINKED_STATE"); + break; + case TDLS_WAIT_PTR_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_WAIT_PTR_STATE"); + break; + case TDLS_ALIVE_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_ALIVE_STATE"); + break; + case TDLS_CH_SWITCH_ON_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_CH_SWITCH_ON_STATE"); + break; + case TDLS_PEER_AT_OFF_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_PEER_AT_OFF_STATE"); + break; + case TDLS_CH_SW_INITIATOR_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_CH_SW_INITIATOR_STATE"); + break; + case TDLS_WAIT_CH_RSP_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValue, " ", "TDLS_WAIT_CH_RSP_STATE"); + break; + default: + RTW_PRINT_SEL(m, "%-*sBIT(%d)\n", SpaceBtwnItemAndValueTmp, " ", j); + break; + } + } + } + } + + RTW_PRINT_SEL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS CH SW On", (ATOMIC_READ(&ptdlsinfo->chsw_info.chsw_on) == _TRUE) ? "_TRUE" : "_FALSE"); + RTW_PRINT_SEL(m, "%-*s = %d\n", SpaceBtwnItemAndValue, "TDLS CH SW Off-Channel Num", ptdlsinfo->chsw_info.off_ch_num); + RTW_PRINT_SEL(m, "%-*s = %d\n", SpaceBtwnItemAndValue, "TDLS CH SW Channel Offset", ptdlsinfo->chsw_info.ch_offset); + RTW_PRINT_SEL(m, "%-*s = %d\n", SpaceBtwnItemAndValue, "TDLS CH SW Current Time", ptdlsinfo->chsw_info.cur_time); + RTW_PRINT_SEL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS CH SW Delay Switch Back", (ptdlsinfo->chsw_info.delay_switch_back == _TRUE) ? "_TRUE" : "_FALSE"); + RTW_PRINT_SEL(m, "%-*s = %d\n", SpaceBtwnItemAndValue, "TDLS CH SW Dump Back", ptdlsinfo->chsw_info.dump_stack); +#endif + + RTW_PRINT_SEL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Device Discovered", (ptdlsinfo->dev_discovered == _TRUE) ? "_TRUE" : "_FALSE"); + RTW_PRINT_SEL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Enable", (ptdlsinfo->tdls_enable == _TRUE) ? "_TRUE" : "_FALSE"); + RTW_PRINT_SEL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "TDLS Driver Setup", (ptdlsinfo->driver_setup == _TRUE) ? "_TRUE" : "_FALSE"); + + return 0; +} + +static int proc_tdls_display_network_info(struct seq_file *m) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct wlan_network *cur_network = &(pmlmepriv->cur_network); + int i = 0; + u8 SpaceBtwnItemAndValue = TDLS_DBG_INFO_SPACE_BTWN_ITEM_AND_VALUE; + + /* Display the linked AP/GO info */ + RTW_PRINT_SEL(m, "============[Associated AP/GO Info]============\n"); + + if ((pmlmepriv->fw_state & WIFI_STATION_STATE) && (pmlmepriv->fw_state & _FW_LINKED)) { + RTW_PRINT_SEL(m, "%-*s = %s\n", SpaceBtwnItemAndValue, "BSSID", cur_network->network.Ssid.Ssid); + RTW_PRINT_SEL(m, "%-*s = "MAC_FMT"\n", SpaceBtwnItemAndValue, "Mac Address", MAC_ARG(cur_network->network.MacAddress)); + + RTW_PRINT_SEL(m, "%-*s = ", SpaceBtwnItemAndValue, "Wireless Mode"); + for (i = 0; i < 8; i++) { + if (pmlmeext->cur_wireless_mode & BIT(i)) { + switch (BIT(i)) { + case WIRELESS_11B: + RTW_PRINT_SEL(m, "%4s", "11B "); + break; + case WIRELESS_11G: + RTW_PRINT_SEL(m, "%4s", "11G "); + break; + case WIRELESS_11A: + RTW_PRINT_SEL(m, "%4s", "11A "); + break; + case WIRELESS_11_24N: + RTW_PRINT_SEL(m, "%7s", "11_24N "); + break; + case WIRELESS_11_5N: + RTW_PRINT_SEL(m, "%6s", "11_5N "); + break; + case WIRELESS_AUTO: + RTW_PRINT_SEL(m, "%5s", "AUTO "); + break; + case WIRELESS_11AC: + RTW_PRINT_SEL(m, "%5s", "11AC "); + break; + } + } + } + RTW_PRINT_SEL(m, "\n"); + + RTW_PRINT_SEL(m, "%-*s = ", SpaceBtwnItemAndValue, "Privacy"); + switch (padapter->securitypriv.dot11PrivacyAlgrthm) { + case _NO_PRIVACY_: + RTW_PRINT_SEL(m, "%s\n", "NO PRIVACY"); + break; + case _WEP40_: + RTW_PRINT_SEL(m, "%s\n", "WEP 40"); + break; + case _TKIP_: + RTW_PRINT_SEL(m, "%s\n", "TKIP"); + break; + case _TKIP_WTMIC_: + RTW_PRINT_SEL(m, "%s\n", "TKIP WTMIC"); + break; + case _AES_: + RTW_PRINT_SEL(m, "%s\n", "AES"); + break; + case _WEP104_: + RTW_PRINT_SEL(m, "%s\n", "WEP 104"); + break; + case _WEP_WPA_MIXED_: + RTW_PRINT_SEL(m, "%s\n", "WEP/WPA Mixed"); + break; + case _SMS4_: + RTW_PRINT_SEL(m, "%s\n", "SMS4"); + break; +#ifdef CONFIG_IEEE80211W + case _BIP_: + RTW_PRINT_SEL(m, "%s\n", "BIP"); + break; +#endif /* CONFIG_IEEE80211W */ + } + + RTW_PRINT_SEL(m, "%-*s = %d\n", SpaceBtwnItemAndValue, "Channel", pmlmeext->cur_channel); + RTW_PRINT_SEL(m, "%-*s = ", SpaceBtwnItemAndValue, "Channel Offset"); + switch (pmlmeext->cur_ch_offset) { + case HAL_PRIME_CHNL_OFFSET_DONT_CARE: + RTW_PRINT_SEL(m, "%s\n", "N/A"); + break; + case HAL_PRIME_CHNL_OFFSET_LOWER: + RTW_PRINT_SEL(m, "%s\n", "Lower"); + break; + case HAL_PRIME_CHNL_OFFSET_UPPER: + RTW_PRINT_SEL(m, "%s\n", "Upper"); + break; + } + + RTW_PRINT_SEL(m, "%-*s = ", SpaceBtwnItemAndValue, "Bandwidth Mode"); + switch (pmlmeext->cur_bwmode) { + case CHANNEL_WIDTH_20: + RTW_PRINT_SEL(m, "%s\n", "20MHz"); + break; + case CHANNEL_WIDTH_40: + RTW_PRINT_SEL(m, "%s\n", "40MHz"); + break; + case CHANNEL_WIDTH_80: + RTW_PRINT_SEL(m, "%s\n", "80MHz"); + break; + case CHANNEL_WIDTH_160: + RTW_PRINT_SEL(m, "%s\n", "160MHz"); + break; + case CHANNEL_WIDTH_80_80: + RTW_PRINT_SEL(m, "%s\n", "80MHz + 80MHz"); + break; + } + } else + RTW_PRINT_SEL(m, "No association with AP/GO exists!\n"); + + return 0; +} + +static int proc_tdls_display_tdls_sta_info(struct seq_file *m) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct sta_priv *pstapriv = &padapter->stapriv; + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + struct sta_info *psta; + int i = 0, j = 0; + _irqL irqL; + _list *plist, *phead; + u8 SpaceBtwnItemAndValue = TDLS_DBG_INFO_SPACE_BTWN_ITEM_AND_VALUE; + u8 SpaceBtwnItemAndValueTmp = 0; + u8 NumOfTdlsStaToShow = 0; + BOOLEAN FirstMatchFound = _FALSE; + + /* Search for TDLS sta info to display */ + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + for (i = 0; i < NUM_STA; i++) { + phead = &(pstapriv->sta_hash[i]); + plist = get_next(phead); + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + plist = get_next(plist); + if (psta->tdls_sta_state != TDLS_STATE_NONE) { + /* We got one TDLS sta info to show */ + RTW_PRINT_SEL(m, "============[TDLS Peer STA Info: STA %d]============\n", ++NumOfTdlsStaToShow); + RTW_PRINT_SEL(m, "%-*s = "MAC_FMT"\n", SpaceBtwnItemAndValue, "Mac Address", MAC_ARG(psta->hwaddr)); + RTW_PRINT_SEL(m, "%-*s =", SpaceBtwnItemAndValue, "TDLS STA State"); + SpaceBtwnItemAndValueTmp = 0; + FirstMatchFound = _FALSE; + for (j = 0; j < 32; j++) { + if (psta->tdls_sta_state & BIT(j)) { + if (FirstMatchFound == _FALSE) { + SpaceBtwnItemAndValueTmp = 1; + FirstMatchFound = _TRUE; + } else + SpaceBtwnItemAndValueTmp = SpaceBtwnItemAndValue + 3; + switch (BIT(j)) { + case TDLS_INITIATOR_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_INITIATOR_STATE"); + break; + case TDLS_RESPONDER_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_RESPONDER_STATE"); + break; + case TDLS_LINKED_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_LINKED_STATE"); + break; + case TDLS_WAIT_PTR_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_WAIT_PTR_STATE"); + break; + case TDLS_ALIVE_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_ALIVE_STATE"); + break; + case TDLS_CH_SWITCH_ON_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_CH_SWITCH_ON_STATE"); + break; + case TDLS_PEER_AT_OFF_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_PEER_AT_OFF_STATE"); + break; + case TDLS_CH_SW_INITIATOR_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValueTmp, " ", "TDLS_CH_SW_INITIATOR_STATE"); + break; + case TDLS_WAIT_CH_RSP_STATE: + RTW_PRINT_SEL(m, "%-*s%s\n", SpaceBtwnItemAndValue, " ", "TDLS_WAIT_CH_RSP_STATE"); + break; + default: + RTW_PRINT_SEL(m, "%-*sBIT(%d)\n", SpaceBtwnItemAndValueTmp, " ", j); + break; + } + } + } + + RTW_PRINT_SEL(m, "%-*s = ", SpaceBtwnItemAndValue, "Wireless Mode"); + for (j = 0; j < 8; j++) { + if (psta->wireless_mode & BIT(j)) { + switch (BIT(j)) { + case WIRELESS_11B: + RTW_PRINT_SEL(m, "%4s", "11B "); + break; + case WIRELESS_11G: + RTW_PRINT_SEL(m, "%4s", "11G "); + break; + case WIRELESS_11A: + RTW_PRINT_SEL(m, "%4s", "11A "); + break; + case WIRELESS_11_24N: + RTW_PRINT_SEL(m, "%7s", "11_24N "); + break; + case WIRELESS_11_5N: + RTW_PRINT_SEL(m, "%6s", "11_5N "); + break; + case WIRELESS_AUTO: + RTW_PRINT_SEL(m, "%5s", "AUTO "); + break; + case WIRELESS_11AC: + RTW_PRINT_SEL(m, "%5s", "11AC "); + break; + } + } + } + RTW_PRINT_SEL(m, "\n"); + + RTW_PRINT_SEL(m, "%-*s = ", SpaceBtwnItemAndValue, "Bandwidth Mode"); + switch (psta->bw_mode) { + case CHANNEL_WIDTH_20: + RTW_PRINT_SEL(m, "%s\n", "20MHz"); + break; + case CHANNEL_WIDTH_40: + RTW_PRINT_SEL(m, "%s\n", "40MHz"); + break; + case CHANNEL_WIDTH_80: + RTW_PRINT_SEL(m, "%s\n", "80MHz"); + break; + case CHANNEL_WIDTH_160: + RTW_PRINT_SEL(m, "%s\n", "160MHz"); + break; + case CHANNEL_WIDTH_80_80: + RTW_PRINT_SEL(m, "%s\n", "80MHz + 80MHz"); + break; + } + + RTW_PRINT_SEL(m, "%-*s = ", SpaceBtwnItemAndValue, "Privacy"); + switch (psta->dot118021XPrivacy) { + case _NO_PRIVACY_: + RTW_PRINT_SEL(m, "%s\n", "NO PRIVACY"); + break; + case _WEP40_: + RTW_PRINT_SEL(m, "%s\n", "WEP 40"); + break; + case _TKIP_: + RTW_PRINT_SEL(m, "%s\n", "TKIP"); + break; + case _TKIP_WTMIC_: + RTW_PRINT_SEL(m, "%s\n", "TKIP WTMIC"); + break; + case _AES_: + RTW_PRINT_SEL(m, "%s\n", "AES"); + break; + case _WEP104_: + RTW_PRINT_SEL(m, "%s\n", "WEP 104"); + break; + case _WEP_WPA_MIXED_: + RTW_PRINT_SEL(m, "%s\n", "WEP/WPA Mixed"); + break; + case _SMS4_: + RTW_PRINT_SEL(m, "%s\n", "SMS4"); + break; +#ifdef CONFIG_IEEE80211W + case _BIP_: + RTW_PRINT_SEL(m, "%s\n", "BIP"); + break; +#endif /* CONFIG_IEEE80211W */ + } + + RTW_PRINT_SEL(m, "%-*s = %d sec/%d sec\n", SpaceBtwnItemAndValue, "TPK Lifetime (Current/Expire)", psta->TPK_count, psta->TDLS_PeerKey_Lifetime); + RTW_PRINT_SEL(m, "%-*s = %llu\n", SpaceBtwnItemAndValue, "Tx Packets Over Direct Link", psta->sta_stats.tx_pkts); + RTW_PRINT_SEL(m, "%-*s = %llu\n", SpaceBtwnItemAndValue, "Rx Packets Over Direct Link", psta->sta_stats.rx_data_pkts); + } + } + } + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + if (NumOfTdlsStaToShow == 0) { + RTW_PRINT_SEL(m, "============[TDLS Peer STA Info]============\n"); + RTW_PRINT_SEL(m, "No TDLS direct link exists!\n"); + } + + return 0; +} + +int proc_get_tdls_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct wlan_network *cur_network = &(pmlmepriv->cur_network); + struct sta_priv *pstapriv = &padapter->stapriv; + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + struct sta_info *psta; + int i = 0, j = 0; + _irqL irqL; + _list *plist, *phead; + u8 SpaceBtwnItemAndValue = 41; + u8 SpaceBtwnItemAndValueTmp = 0; + u8 NumOfTdlsStaToShow = 0; + BOOLEAN FirstMatchFound = _FALSE; + + if (hal_chk_wl_func(padapter, WL_FUNC_TDLS) == _FALSE) { + RTW_PRINT_SEL(m, "No tdls info can be shown since hal doesn't support tdls\n"); + return 0; + } + + proc_tdls_display_tdls_function_info(m); + proc_tdls_display_network_info(m); + proc_tdls_display_tdls_sta_info(m); + + return 0; +} +#endif + +int proc_get_monitor(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + if (WIFI_MONITOR_STATE == get_fwstate(pmlmepriv)) { + RTW_PRINT_SEL(m, "Monitor mode : Enable\n"); + + RTW_PRINT_SEL(m, "ch=%d, ch_offset=%d, bw=%d\n", + rtw_get_oper_ch(padapter), rtw_get_oper_choffset(padapter), rtw_get_oper_bw(padapter)); + } else + RTW_PRINT_SEL(m, "Monitor mode : Disable\n"); + + return 0; +} + +ssize_t proc_set_monitor(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + char tmp[32]; + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + u8 target_chan, target_offset, target_bw; + + if (count < 3) { + RTW_INFO("argument size is less than 3\n"); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + int num = sscanf(tmp, "%hhu %hhu %hhu", &target_chan, &target_offset, &target_bw); + + if (num != 3) { + RTW_INFO("invalid write_reg parameter!\n"); + return count; + } + + padapter->mlmeextpriv.cur_channel = target_chan; + set_channel_bwmode(padapter, target_chan, target_offset, target_bw); + } + + return count; +} + +#include <hal_data.h> +int proc_get_efuse_map(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); + PEFUSE_HAL pEfuseHal = &pHalData->EfuseHal; + int i, j; + u8 ips_mode = IPS_NUM; + u16 mapLen; + + EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, _FALSE); + if (mapLen > EFUSE_MAX_MAP_LEN) + mapLen = EFUSE_MAX_MAP_LEN; + + ips_mode = pwrctrlpriv->ips_mode; + rtw_pm_set_ips(padapter, IPS_NONE); + + if (pHalData->efuse_file_status == EFUSE_FILE_LOADED) { + RTW_PRINT_SEL(m, "File eFuse Map loaded! file path:%s\nDriver eFuse Map From File\n", EFUSE_MAP_PATH); + if (pHalData->bautoload_fail_flag) + RTW_PRINT_SEL(m, "File Autoload fail!!!\n"); + } else if (pHalData->efuse_file_status == EFUSE_FILE_FAILED) { + RTW_PRINT_SEL(m, "Open File eFuse Map Fail ! file path:%s\nDriver eFuse Map From Default\n", EFUSE_MAP_PATH); + if (pHalData->bautoload_fail_flag) + RTW_PRINT_SEL(m, "HW Autoload fail!!!\n"); + } else { + RTW_PRINT_SEL(m, "Driver eFuse Map From HW\n"); + if (pHalData->bautoload_fail_flag) + RTW_PRINT_SEL(m, "HW Autoload fail!!!\n"); + } + for (i = 0; i < mapLen; i += 16) { + RTW_PRINT_SEL(m, "0x%02x\t", i); + for (j = 0; j < 8; j++) + RTW_PRINT_SEL(m, "%02X ", pHalData->efuse_eeprom_data[i + j]); + RTW_PRINT_SEL(m, "\t"); + for (; j < 16; j++) + RTW_PRINT_SEL(m, "%02X ", pHalData->efuse_eeprom_data[i + j]); + RTW_PRINT_SEL(m, "\n"); + } + + if (rtw_efuse_map_read(padapter, 0, mapLen, pEfuseHal->fakeEfuseInitMap) == _FAIL) { + RTW_PRINT_SEL(m, "WARN - Read Realmap Failed\n"); + return 0; + } + + RTW_PRINT_SEL(m, "\n"); + RTW_PRINT_SEL(m, "HW eFuse Map\n"); + for (i = 0; i < mapLen; i += 16) { + RTW_PRINT_SEL(m, "0x%02x\t", i); + for (j = 0; j < 8; j++) + RTW_PRINT_SEL(m, "%02X ", pEfuseHal->fakeEfuseInitMap[i + j]); + RTW_PRINT_SEL(m, "\t"); + for (; j < 16; j++) + RTW_PRINT_SEL(m, "%02X ", pEfuseHal->fakeEfuseInitMap[i + j]); + RTW_PRINT_SEL(m, "\n"); + } + + rtw_pm_set_ips(padapter, ips_mode); + + return 0; +} + +ssize_t proc_set_efuse_map(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ +#if 0 + char tmp[256] = {0}; + u32 addr, cnts; + u8 efuse_data; + + int jj, kk; + + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); + u8 ips_mode = IPS_NUM; + + if (count < 3) { + RTW_INFO("argument size is less than 3\n"); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + + int num = sscanf(tmp, "%x %d %x", &addr, &cnts, &efuse_data); + + if (num != 3) { + RTW_INFO("invalid write_reg parameter!\n"); + return count; + } + } + ips_mode = pwrctrlpriv->ips_mode; + rtw_pm_set_ips(padapter, IPS_NONE); + if (rtw_efuse_map_write(padapter, addr, cnts, &efuse_data) == _FAIL) + RTW_INFO("WARN - rtw_efuse_map_write error!!\n"); + rtw_pm_set_ips(padapter, ips_mode); +#endif + return count; +} + +#ifdef CONFIG_IEEE80211W +ssize_t proc_set_tx_sa_query(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct sta_priv *pstapriv = &padapter->stapriv; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + struct sta_info *psta; + _list *plist, *phead; + _irqL irqL; + char tmp[16]; + u8 mac_addr[NUM_STA][ETH_ALEN]; + u32 key_type; + u8 index; + + if (count > 2) { + RTW_INFO("argument size is more than 2\n"); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { + + int num = sscanf(tmp, "%x", &key_type); + + if (num != 1) { + RTW_INFO("invalid read_reg parameter!\n"); + return count; + } + RTW_INFO("0: set sa query request , key_type=%d\n", key_type); + } + + if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) + && (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) && padapter->securitypriv.binstallBIPkey == _TRUE) { + RTW_INFO("STA:"MAC_FMT"\n", MAC_ARG(get_my_bssid(&(pmlmeinfo->network)))); + /* TX unicast sa_query to AP */ + issue_action_SA_Query(padapter, get_my_bssid(&(pmlmeinfo->network)), 0, 0, (u8)key_type); + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE && padapter->securitypriv.binstallBIPkey == _TRUE) { + /* TX unicast sa_query to every client STA */ + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + for (index = 0; index < NUM_STA; index++) { + psta = NULL; + + phead = &(pstapriv->sta_hash[index]); + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + plist = get_next(plist); + _rtw_memcpy(&mac_addr[psta->mac_id][0], psta->hwaddr, ETH_ALEN); + } + } + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + for (index = 0; index < macid_ctl->num && index < NUM_STA; index++) { + if (rtw_macid_is_used(macid_ctl, index) && !rtw_macid_is_bmc(macid_ctl, index)) { + if (!_rtw_memcmp(get_my_bssid(&(pmlmeinfo->network)), &mac_addr[index][0], ETH_ALEN) + && !IS_MCAST(&mac_addr[index][0])) { + issue_action_SA_Query(padapter, &mac_addr[index][0], 0, 0, (u8)key_type); + RTW_INFO("STA[%u]:"MAC_FMT"\n", index , MAC_ARG(&mac_addr[index][0])); + } + } + } + } + + return count; +} + +int proc_get_tx_sa_query(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + + RTW_PRINT_SEL(m, "%s\n", __func__); + return 0; +} + +ssize_t proc_set_tx_deauth(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct sta_priv *pstapriv = &padapter->stapriv; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + struct sta_info *psta; + _list *plist, *phead; + _irqL irqL; + char tmp[16]; + u8 mac_addr[NUM_STA][ETH_ALEN]; + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u32 key_type; + u8 index; + + + if (count > 2) { + RTW_INFO("argument size is more than 2\n"); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { + + int num = sscanf(tmp, "%x", &key_type); + + if (num != 1) { + RTW_INFO("invalid read_reg parameter!\n"); + return count; + } + RTW_INFO("key_type=%d\n", key_type); + } + if (key_type < 0 || key_type > 4) + return count; + + if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) + && (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) { + if (key_type == 3) /* key_type 3 only for AP mode */ + return count; + /* TX unicast deauth to AP */ + issue_deauth_11w(padapter, get_my_bssid(&(pmlmeinfo->network)), 0, (u8)key_type); + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { + + if (key_type == 3) + issue_deauth_11w(padapter, bc_addr, 0, IEEE80211W_RIGHT_KEY); + + /* TX unicast deauth to every client STA */ + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + for (index = 0; index < NUM_STA; index++) { + psta = NULL; + + phead = &(pstapriv->sta_hash[index]); + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + plist = get_next(plist); + _rtw_memcpy(&mac_addr[psta->mac_id][0], psta->hwaddr, ETH_ALEN); + } + } + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + for (index = 0; index < macid_ctl->num && index < NUM_STA; index++) { + if (rtw_macid_is_used(macid_ctl, index) && !rtw_macid_is_bmc(macid_ctl, index)) { + if (!_rtw_memcmp(get_my_bssid(&(pmlmeinfo->network)), &mac_addr[index][0], ETH_ALEN)) { + if (key_type != 3) + issue_deauth_11w(padapter, &mac_addr[index][0], 0, (u8)key_type); + + psta = rtw_get_stainfo(pstapriv, &mac_addr[index][0]); + if (psta && key_type != IEEE80211W_WRONG_KEY && key_type != IEEE80211W_NO_KEY) { + u8 updated = _FALSE; + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + if (rtw_is_list_empty(&psta->asoc_list) == _FALSE) { + rtw_list_delete(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + updated = ap_free_sta(padapter, psta, _FALSE, WLAN_REASON_PREV_AUTH_NOT_VALID, _TRUE); + + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + associated_clients_update(padapter, updated, STA_INFO_UPDATE_ALL); + } + + RTW_INFO("STA[%u]:"MAC_FMT"\n", index , MAC_ARG(&mac_addr[index][0])); + } + } + } + } + + return count; +} + +int proc_get_tx_deauth(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + + RTW_PRINT_SEL(m, "%s\n", __func__); + return 0; +} + +ssize_t proc_set_tx_auth(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct sta_priv *pstapriv = &padapter->stapriv; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + struct sta_info *psta; + _list *plist, *phead; + _irqL irqL; + char tmp[16]; + u8 mac_addr[NUM_STA][ETH_ALEN]; + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u32 tx_auth; + u8 index; + + + if (count > 2) { + RTW_INFO("argument size is more than 2\n"); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { + + int num = sscanf(tmp, "%x", &tx_auth); + + if (num != 1) { + RTW_INFO("invalid read_reg parameter!\n"); + return count; + } + RTW_INFO("1: setnd auth, 2: send assoc request. tx_auth=%d\n", tx_auth); + } + + if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) + && (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) { + if (tx_auth == 1) { + /* TX unicast auth to AP */ + issue_auth(padapter, NULL, 0); + } else if (tx_auth == 2) { + /* TX unicast auth to AP */ + issue_assocreq(padapter); + } + } + + return count; +} + +int proc_get_tx_auth(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + + RTW_PRINT_SEL(m, "%s\n", __func__); + return 0; +} +#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_MCC_MODE +int proc_get_mcc_info(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + + dump_adapters_status(m, adapter_to_dvobj(adapter)); + rtw_hal_dump_mcc_info(m, adapter_to_dvobj(adapter)); + return 0; +} + +int proc_get_mcc_policy_table(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *adapter = (_adapter *)rtw_netdev_priv(dev); + + rtw_hal_dump_mcc_policy_table(m); + return 0; +} + +ssize_t proc_set_mcc_policy_table(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[255]; + s32 mcc_policy_table_idx; + u32 mcc_duration; + u32 mcc_tsf_sync_offset; + u32 mcc_start_time_offset; + u32 mcc_interval; + s32 mcc_guard_offset0; + s32 mcc_guard_offset1; + + if (NULL == buffer) { + RTW_INFO(FUNC_ADPT_FMT ": input buffer is NULL!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input length is 0!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + RTW_INFO(FUNC_ADPT_FMT ": input length is too large\n", FUNC_ADPT_ARG(padapter)); + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + #if 1 + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + _adapter *iface = NULL; + u8 i = 0; + int num = sscanf(tmp, "%d %u %u %u %u %d %d" + , &mcc_policy_table_idx, &mcc_duration, &mcc_tsf_sync_offset, &mcc_start_time_offset + , &mcc_interval, &mcc_guard_offset0, &mcc_guard_offset1); + + if (num < 7) { + RTW_INFO(FUNC_ADPT_FMT ": input parameters < 7\n", FUNC_ADPT_ARG(padapter)); + return -EINVAL; + } +#if 0 + RTW_INFO("mcc_policy_table_idx:%d\n", mcc_policy_table_idx); + RTW_INFO("mcc_duration:%d\n", mcc_duration); + RTW_INFO("mcc_tsf_sync_offset:%d\n", mcc_tsf_sync_offset); + RTW_INFO("mcc_start_time_offset:%d\n", mcc_start_time_offset); + RTW_INFO("mcc_interval:%d\n", mcc_interval); + RTW_INFO("mcc_guard_offset0:%d\n", mcc_guard_offset0); + RTW_INFO("mcc_guard_offset1:%d\n", mcc_guard_offset1); +#endif + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (!iface) + continue; + iface->registrypriv.rtw_mcc_policy_table_idx = mcc_policy_table_idx; + iface->registrypriv.rtw_mcc_duration = mcc_duration; + iface->registrypriv.rtw_mcc_tsf_sync_offset = mcc_tsf_sync_offset; + iface->registrypriv.rtw_mcc_start_time_offset = mcc_start_time_offset; + iface->registrypriv.rtw_mcc_interval = mcc_interval; + iface->registrypriv.rtw_mcc_guard_offset0 = mcc_guard_offset0; + iface->registrypriv.rtw_mcc_guard_offset1 = mcc_guard_offset1; + } + + rtw_hal_mcc_update_switch_channel_policy_table(padapter); + #endif + } + + return count; +} + +ssize_t proc_set_mcc_enable(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[255]; + u32 en_mcc = 0; + + if (NULL == buffer) { + RTW_INFO(FUNC_ADPT_FMT ": input buffer is NULL!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input length is 0!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + RTW_INFO(FUNC_ADPT_FMT ": input length is too large\n", FUNC_ADPT_ARG(padapter)); + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + _adapter *iface = NULL; + u8 i = 0; + int num = sscanf(tmp, "%u", &en_mcc); + + if (num < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input parameters < 1\n", FUNC_ADPT_ARG(padapter)); + return -EINVAL; + } + + RTW_INFO("%s: en_mcc = %d\n", __func__, en_mcc); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (!iface) + continue; + iface->registrypriv.en_mcc = en_mcc; + } + } + + return count; +} + +ssize_t proc_set_mcc_single_tx_criteria(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[255]; + u32 mcc_single_tx_criteria = 0; + + if (NULL == buffer) { + RTW_INFO(FUNC_ADPT_FMT ": input buffer is NULL!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input length is 0!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + RTW_INFO(FUNC_ADPT_FMT ": input length is too large\n", FUNC_ADPT_ARG(padapter)); + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + _adapter *iface = NULL; + u8 i = 0; + int num = sscanf(tmp, "%u", &mcc_single_tx_criteria); + + if (num < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input parameters < 1\n", FUNC_ADPT_ARG(padapter)); + return -EINVAL; + } + + RTW_INFO("%s: mcc_single_tx_criteria = %d\n", __func__, mcc_single_tx_criteria); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (!iface) + continue; + iface->registrypriv.rtw_mcc_single_tx_cri = mcc_single_tx_criteria; + } + + + } + + return count; +} + + +ssize_t proc_set_mcc_ap_bw20_target_tp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[255]; + u32 mcc_ap_bw20_target_tp = 0; + + if (NULL == buffer) { + RTW_INFO(FUNC_ADPT_FMT ": input buffer is NULL!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input length is 0!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + RTW_INFO(FUNC_ADPT_FMT ": input length is too large\n", FUNC_ADPT_ARG(padapter)); + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + int num = sscanf(tmp, "%u", &mcc_ap_bw20_target_tp); + + if (num < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input parameters < 1\n", FUNC_ADPT_ARG(padapter)); + return -EINVAL; + } + + RTW_INFO("%s: mcc_ap_bw20_target_tp = %d\n", __func__, mcc_ap_bw20_target_tp); + + padapter->registrypriv.rtw_mcc_ap_bw20_target_tx_tp = mcc_ap_bw20_target_tp; + + + } + + return count; +} + +ssize_t proc_set_mcc_ap_bw40_target_tp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[255]; + u32 mcc_ap_bw40_target_tp = 0; + + if (NULL == buffer) { + RTW_INFO(FUNC_ADPT_FMT ": input buffer is NULL!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input length is 0!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + RTW_INFO(FUNC_ADPT_FMT ": input length is too large\n", FUNC_ADPT_ARG(padapter)); + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + int num = sscanf(tmp, "%u", &mcc_ap_bw40_target_tp); + + if (num < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input parameters < 1\n", FUNC_ADPT_ARG(padapter)); + return -EINVAL; + } + + RTW_INFO("%s: mcc_ap_bw40_target_tp = %d\n", __func__, mcc_ap_bw40_target_tp); + + padapter->registrypriv.rtw_mcc_ap_bw40_target_tx_tp = mcc_ap_bw40_target_tp; + + + } + + return count; +} + +ssize_t proc_set_mcc_ap_bw80_target_tp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[255]; + u32 mcc_ap_bw80_target_tp = 0; + + if (NULL == buffer) { + RTW_INFO(FUNC_ADPT_FMT ": input buffer is NULL!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input length is 0!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + RTW_INFO(FUNC_ADPT_FMT ": input length is too large\n", FUNC_ADPT_ARG(padapter)); + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + int num = sscanf(tmp, "%u", &mcc_ap_bw80_target_tp); + + if (num < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input parameters < 1\n", FUNC_ADPT_ARG(padapter)); + return -EINVAL; + } + + RTW_INFO("%s: mcc_ap_bw80_target_tp = %d\n", __func__, mcc_ap_bw80_target_tp); + + padapter->registrypriv.rtw_mcc_ap_bw80_target_tx_tp = mcc_ap_bw80_target_tp; + + + } + + return count; +} + +ssize_t proc_set_mcc_sta_bw20_target_tp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[255]; + u32 mcc_sta_bw20_target_tp = 0; + + if (NULL == buffer) { + RTW_INFO(FUNC_ADPT_FMT ": input buffer is NULL!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input length is 0!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + RTW_INFO(FUNC_ADPT_FMT ": input length is too large\n", FUNC_ADPT_ARG(padapter)); + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + int num = sscanf(tmp, "%u", &mcc_sta_bw20_target_tp); + + if (num < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input parameters < 1\n", FUNC_ADPT_ARG(padapter)); + return -EINVAL; + } + + RTW_INFO("%s: mcc_sta_bw20_target_tp = %d\n", __func__, mcc_sta_bw20_target_tp); + + padapter->registrypriv.rtw_mcc_sta_bw20_target_tx_tp = mcc_sta_bw20_target_tp; + + + } + + return count; +} + +ssize_t proc_set_mcc_sta_bw40_target_tp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[255]; + u32 mcc_sta_bw40_target_tp = 0; + + if (NULL == buffer) { + RTW_INFO(FUNC_ADPT_FMT ": input buffer is NULL!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input length is 0!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + RTW_INFO(FUNC_ADPT_FMT ": input length is too large\n", FUNC_ADPT_ARG(padapter)); + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + int num = sscanf(tmp, "%u", &mcc_sta_bw40_target_tp); + + if (num < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input parameters < 1\n", FUNC_ADPT_ARG(padapter)); + return -EINVAL; + } + + RTW_INFO("%s: mcc_sta_bw40_target_tp = %d\n", __func__, mcc_sta_bw40_target_tp); + + padapter->registrypriv.rtw_mcc_sta_bw40_target_tx_tp = mcc_sta_bw40_target_tp; + + + } + + return count; +} + +ssize_t proc_set_mcc_sta_bw80_target_tp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[255]; + u32 mcc_sta_bw80_target_tp = 0; + + if (NULL == buffer) { + RTW_INFO(FUNC_ADPT_FMT ": input buffer is NULL!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input length is 0!\n", FUNC_ADPT_ARG(padapter)); + return -EFAULT; + } + + if (count > sizeof(tmp)) { + RTW_INFO(FUNC_ADPT_FMT ": input length is too large\n", FUNC_ADPT_ARG(padapter)); + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + int num = sscanf(tmp, "%u", &mcc_sta_bw80_target_tp); + + if (num < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input parameters < 1\n", FUNC_ADPT_ARG(padapter)); + return -EINVAL; + } + + RTW_INFO("%s: mcc_sta_bw80_target_tp = %d\n", __func__, mcc_sta_bw80_target_tp); + + padapter->registrypriv.rtw_mcc_sta_bw80_target_tx_tp = mcc_sta_bw80_target_tp; + + + } + + return count; +} +#endif /* CONFIG_MCC_MODE */ + +int proc_get_ack_timeout(struct seq_file *m, void *v) +{ + struct net_device *dev = m->private; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + u8 ack_timeout_val, ack_timeout_val_cck; + + ack_timeout_val = rtw_read8(padapter, REG_ACKTO); + +#ifdef CONFIG_RTL8821C + ack_timeout_val_cck = rtw_read8(padapter, REG_ACKTO_CCK_8821C); + RTW_PRINT_SEL(m, "Current CCK packet ACK Timeout = %d us (0x%x).\n", ack_timeout_val_cck, ack_timeout_val_cck); + RTW_PRINT_SEL(m, "Current non-CCK packet ACK Timeout = %d us (0x%x).\n", ack_timeout_val, ack_timeout_val); +#else + RTW_PRINT_SEL(m, "Current ACK Timeout = %d us (0x%x).\n", ack_timeout_val, ack_timeout_val); +#endif + + return 0; +} + +ssize_t proc_set_ack_timeout(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data) +{ + struct net_device *dev = data; + _adapter *padapter = (_adapter *)rtw_netdev_priv(dev); + char tmp[32]; + u32 ack_timeout_ms, ack_timeout_ms_cck; + + if (count > sizeof(tmp)) { + rtw_warn_on(1); + return -EFAULT; + } + + if (buffer && !copy_from_user(tmp, buffer, count)) { + int num = sscanf(tmp, "%u %u", &ack_timeout_ms, &ack_timeout_ms_cck); + +#ifdef CONFIG_RTL8821C + if (num < 2) { + RTW_INFO(FUNC_ADPT_FMT ": input parameters < 2\n", FUNC_ADPT_ARG(padapter)); + return -EINVAL; + } +#else + if (num < 1) { + RTW_INFO(FUNC_ADPT_FMT ": input parameters < 1\n", FUNC_ADPT_ARG(padapter)); + return -EINVAL; + } +#endif + /* This register sets the Ack time out value after Tx unicast packet. It is in units of us. */ + rtw_write8(padapter, REG_ACKTO, (u8)ack_timeout_ms); + +#ifdef CONFIG_RTL8821C + /* This register sets the Ack time out value after Tx unicast CCK packet. It is in units of us. */ + rtw_write8(padapter, REG_ACKTO_CCK_8821C, (u8)ack_timeout_ms_cck); + RTW_INFO("Set CCK packet ACK Timeout to %d us.\n", ack_timeout_ms_cck); + RTW_INFO("Set non-CCK packet ACK Timeout to %d us.\n", ack_timeout_ms); +#else + RTW_INFO("Set ACK Timeout to %d us.\n", ack_timeout_ms); +#endif + } + + return count; +} + +#endif /* CONFIG_PROC_DEBUG */ diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_eeprom.c b/linux-bsp/drivers/rtl8188eus/core/rtw_eeprom.c new file mode 100644 index 0000000..d7bca03 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_eeprom.c @@ -0,0 +1,374 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_EEPROM_C_ + +#include <drv_conf.h> +#include <osdep_service.h> +#include <drv_types.h> + +void up_clk(_adapter *padapter, u16 *x) +{ + *x = *x | _EESK; + rtw_write8(padapter, EE_9346CR, (u8)*x); + rtw_udelay_os(CLOCK_RATE); + + +} + +void down_clk(_adapter *padapter, u16 *x) +{ + *x = *x & ~_EESK; + rtw_write8(padapter, EE_9346CR, (u8)*x); + rtw_udelay_os(CLOCK_RATE); +} + +void shift_out_bits(_adapter *padapter, u16 data, u16 count) +{ + u16 x, mask; + + if (rtw_is_surprise_removed(padapter)) { + goto out; + } + mask = 0x01 << (count - 1); + x = rtw_read8(padapter, EE_9346CR); + + x &= ~(_EEDO | _EEDI); + + do { + x &= ~_EEDI; + if (data & mask) + x |= _EEDI; + if (rtw_is_surprise_removed(padapter)) { + goto out; + } + rtw_write8(padapter, EE_9346CR, (u8)x); + rtw_udelay_os(CLOCK_RATE); + up_clk(padapter, &x); + down_clk(padapter, &x); + mask = mask >> 1; + } while (mask); + if (rtw_is_surprise_removed(padapter)) { + goto out; + } + x &= ~_EEDI; + rtw_write8(padapter, EE_9346CR, (u8)x); +out: + return; +} + +u16 shift_in_bits(_adapter *padapter) +{ + u16 x, d = 0, i; + if (rtw_is_surprise_removed(padapter)) { + goto out; + } + x = rtw_read8(padapter, EE_9346CR); + + x &= ~(_EEDO | _EEDI); + d = 0; + + for (i = 0; i < 16; i++) { + d = d << 1; + up_clk(padapter, &x); + if (rtw_is_surprise_removed(padapter)) { + goto out; + } + x = rtw_read8(padapter, EE_9346CR); + + x &= ~(_EEDI); + if (x & _EEDO) + d |= 1; + + down_clk(padapter, &x); + } +out: + + return d; +} + +void standby(_adapter *padapter) +{ + u8 x; + x = rtw_read8(padapter, EE_9346CR); + + x &= ~(_EECS | _EESK); + rtw_write8(padapter, EE_9346CR, x); + + rtw_udelay_os(CLOCK_RATE); + x |= _EECS; + rtw_write8(padapter, EE_9346CR, x); + rtw_udelay_os(CLOCK_RATE); +} + +u16 wait_eeprom_cmd_done(_adapter *padapter) +{ + u8 x; + u16 i, res = _FALSE; + standby(padapter); + for (i = 0; i < 200; i++) { + x = rtw_read8(padapter, EE_9346CR); + if (x & _EEDO) { + res = _TRUE; + goto exit; + } + rtw_udelay_os(CLOCK_RATE); + } +exit: + return res; +} + +void eeprom_clean(_adapter *padapter) +{ + u16 x; + if (rtw_is_surprise_removed(padapter)) { + goto out; + } + x = rtw_read8(padapter, EE_9346CR); + if (rtw_is_surprise_removed(padapter)) { + goto out; + } + x &= ~(_EECS | _EEDI); + rtw_write8(padapter, EE_9346CR, (u8)x); + if (rtw_is_surprise_removed(padapter)) { + goto out; + } + up_clk(padapter, &x); + if (rtw_is_surprise_removed(padapter)) { + goto out; + } + down_clk(padapter, &x); +out: + return; +} + +void eeprom_write16(_adapter *padapter, u16 reg, u16 data) +{ + u8 x; +#ifdef CONFIG_RTL8712 + u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new; + tmp8_ori = rtw_read8(padapter, 0x102502f1); + tmp8_new = tmp8_ori & 0xf7; + if (tmp8_ori != tmp8_new) { + rtw_write8(padapter, 0x102502f1, tmp8_new); + } + tmp8_clk_ori = rtw_read8(padapter, 0x10250003); + tmp8_clk_new = tmp8_clk_ori | 0x20; + if (tmp8_clk_new != tmp8_clk_ori) { + rtw_write8(padapter, 0x10250003, tmp8_clk_new); + } +#endif + + x = rtw_read8(padapter, EE_9346CR); + + x &= ~(_EEDI | _EEDO | _EESK | _EEM0); + x |= _EEM1 | _EECS; + rtw_write8(padapter, EE_9346CR, x); + + shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5); + + if (padapter->EepromAddressSize == 8) /* CF+ and SDIO */ + shift_out_bits(padapter, 0, 6); + else /* USB */ + shift_out_bits(padapter, 0, 4); + + standby(padapter); + + /* Commented out by rcnjko, 2004.0 + * Erase this particular word. Write the erase opcode and register + * number in that order. The opcode is 3bits in length; reg is 6 bits long. */ +/* shift_out_bits(Adapter, EEPROM_ERASE_OPCODE, 3); + * shift_out_bits(Adapter, reg, Adapter->EepromAddressSize); + * + * if (wait_eeprom_cmd_done(Adapter ) == FALSE) + * { + * return; + * } */ + + + standby(padapter); + + /* write the new word to the EEPROM */ + + /* send the write opcode the EEPORM */ + shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3); + + /* select which word in the EEPROM that we are writing to. */ + shift_out_bits(padapter, reg, padapter->EepromAddressSize); + + /* write the data to the selected EEPROM word. */ + shift_out_bits(padapter, data, 16); + + if (wait_eeprom_cmd_done(padapter) == _FALSE) + + goto exit; + + standby(padapter); + + shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5); + shift_out_bits(padapter, reg, 4); + + eeprom_clean(padapter); +exit: +#ifdef CONFIG_RTL8712 + if (tmp8_clk_new != tmp8_clk_ori) + rtw_write8(padapter, 0x10250003, tmp8_clk_ori); + if (tmp8_new != tmp8_ori) + rtw_write8(padapter, 0x102502f1, tmp8_ori); + +#endif + return; +} + +u16 eeprom_read16(_adapter *padapter, u16 reg) /* ReadEEprom */ +{ + + u16 x; + u16 data = 0; +#ifdef CONFIG_RTL8712 + u8 tmp8_ori, tmp8_new, tmp8_clk_ori, tmp8_clk_new; + tmp8_ori = rtw_read8(padapter, 0x102502f1); + tmp8_new = tmp8_ori & 0xf7; + if (tmp8_ori != tmp8_new) { + rtw_write8(padapter, 0x102502f1, tmp8_new); + } + tmp8_clk_ori = rtw_read8(padapter, 0x10250003); + tmp8_clk_new = tmp8_clk_ori | 0x20; + if (tmp8_clk_new != tmp8_clk_ori) { + rtw_write8(padapter, 0x10250003, tmp8_clk_new); + } +#endif + + if (rtw_is_surprise_removed(padapter)) { + goto out; + } + /* select EEPROM, reset bits, set _EECS */ + x = rtw_read8(padapter, EE_9346CR); + + if (rtw_is_surprise_removed(padapter)) { + goto out; + } + + x &= ~(_EEDI | _EEDO | _EESK | _EEM0); + x |= _EEM1 | _EECS; + rtw_write8(padapter, EE_9346CR, (unsigned char)x); + + /* write the read opcode and register number in that order */ + /* The opcode is 3bits in length, reg is 6 bits long */ + shift_out_bits(padapter, EEPROM_READ_OPCODE, 3); + shift_out_bits(padapter, reg, padapter->EepromAddressSize); + + /* Now read the data (16 bits) in from the selected EEPROM word */ + data = shift_in_bits(padapter); + + eeprom_clean(padapter); +out: +#ifdef CONFIG_RTL8712 + if (tmp8_clk_new != tmp8_clk_ori) + rtw_write8(padapter, 0x10250003, tmp8_clk_ori); + if (tmp8_new != tmp8_ori) + rtw_write8(padapter, 0x102502f1, tmp8_ori); + +#endif + return data; + + +} + + + + +/* From even offset */ +void eeprom_read_sz(_adapter *padapter, u16 reg, u8 *data, u32 sz) +{ + + u16 x, data16; + u32 i; + if (rtw_is_surprise_removed(padapter)) { + goto out; + } + /* select EEPROM, reset bits, set _EECS */ + x = rtw_read8(padapter, EE_9346CR); + + if (rtw_is_surprise_removed(padapter)) { + goto out; + } + + x &= ~(_EEDI | _EEDO | _EESK | _EEM0); + x |= _EEM1 | _EECS; + rtw_write8(padapter, EE_9346CR, (unsigned char)x); + + /* write the read opcode and register number in that order */ + /* The opcode is 3bits in length, reg is 6 bits long */ + shift_out_bits(padapter, EEPROM_READ_OPCODE, 3); + shift_out_bits(padapter, reg, padapter->EepromAddressSize); + + + for (i = 0; i < sz; i += 2) { + data16 = shift_in_bits(padapter); + data[i] = data16 & 0xff; + data[i + 1] = data16 >> 8; + } + + eeprom_clean(padapter); +out: + return; +} + + +/* addr_off : address offset of the entry in eeprom (not the tuple number of eeprom (reg); that is addr_off !=reg) */ +u8 eeprom_read(_adapter *padapter, u32 addr_off, u8 sz, u8 *rbuf) +{ + u8 quotient, remainder, addr_2align_odd; + u16 reg, stmp , i = 0, idx = 0; + reg = (u16)(addr_off >> 1); + addr_2align_odd = (u8)(addr_off & 0x1); + + if (addr_2align_odd) { /* read that start at high part: e.g 1,3,5,7,9,... */ + stmp = eeprom_read16(padapter, reg); + rbuf[idx++] = (u8)((stmp >> 8) & 0xff); /* return hogh-part of the short */ + reg++; + sz--; + } + + quotient = sz >> 1; + remainder = sz & 0x1; + + for (i = 0 ; i < quotient; i++) { + stmp = eeprom_read16(padapter, reg + i); + rbuf[idx++] = (u8)(stmp & 0xff); + rbuf[idx++] = (u8)((stmp >> 8) & 0xff); + } + + reg = reg + i; + if (remainder) { /* end of read at lower part of short : 0,2,4,6,... */ + stmp = eeprom_read16(padapter, reg); + rbuf[idx] = (u8)(stmp & 0xff); + } + return _TRUE; +} + + + +VOID read_eeprom_content(_adapter *padapter) +{ + + + +} diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_ieee80211.c b/linux-bsp/drivers/rtl8188eus/core/rtw_ieee80211.c new file mode 100644 index 0000000..532b2f6 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_ieee80211.c @@ -0,0 +1,2736 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _IEEE80211_C + +#ifdef CONFIG_PLATFORM_INTEL_BYT + #include <linux/fs.h> +#endif +#include <drv_types.h> + + +u8 RTW_WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 }; +u16 RTW_WPA_VERSION = 1; +u8 WPA_AUTH_KEY_MGMT_NONE[] = { 0x00, 0x50, 0xf2, 0 }; +u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x50, 0xf2, 1 }; +u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 }; +u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 }; +u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 }; +u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 }; +u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 }; +u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 }; +u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 }; + +u16 RSN_VERSION_BSD = 1; +u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[] = { 0x00, 0x0f, 0xac, 1 }; +u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 }; +u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 }; +u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 }; +u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 }; +u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 }; +u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 }; +u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 }; +/* ----------------------------------------------------------- + * for adhoc-master to generate ie and provide supported-rate to fw + * ----------------------------------------------------------- */ + +static u8 WIFI_CCKRATES[] = { + (IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK), + (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK), + (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK), + (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK) +}; + +static u8 WIFI_OFDMRATES[] = { + (IEEE80211_OFDM_RATE_6MB), + (IEEE80211_OFDM_RATE_9MB), + (IEEE80211_OFDM_RATE_12MB), + (IEEE80211_OFDM_RATE_18MB), + (IEEE80211_OFDM_RATE_24MB), + IEEE80211_OFDM_RATE_36MB, + IEEE80211_OFDM_RATE_48MB, + IEEE80211_OFDM_RATE_54MB +}; + +u8 mgn_rates_cck[4] = {MGN_1M, MGN_2M, MGN_5_5M, MGN_11M}; +u8 mgn_rates_ofdm[8] = {MGN_6M, MGN_9M, MGN_12M, MGN_18M, MGN_24M, MGN_36M, MGN_48M, MGN_54M}; +u8 mgn_rates_mcs0_7[8] = {MGN_MCS0, MGN_MCS1, MGN_MCS2, MGN_MCS3, MGN_MCS4, MGN_MCS5, MGN_MCS6, MGN_MCS7}; +u8 mgn_rates_mcs8_15[8] = {MGN_MCS8, MGN_MCS9, MGN_MCS10, MGN_MCS11, MGN_MCS12, MGN_MCS13, MGN_MCS14, MGN_MCS15}; +u8 mgn_rates_mcs16_23[8] = {MGN_MCS16, MGN_MCS17, MGN_MCS18, MGN_MCS19, MGN_MCS20, MGN_MCS21, MGN_MCS22, MGN_MCS23}; +u8 mgn_rates_mcs24_31[8] = {MGN_MCS24, MGN_MCS25, MGN_MCS26, MGN_MCS27, MGN_MCS28, MGN_MCS29, MGN_MCS30, MGN_MCS31}; +u8 mgn_rates_vht1ss[10] = {MGN_VHT1SS_MCS0, MGN_VHT1SS_MCS1, MGN_VHT1SS_MCS2, MGN_VHT1SS_MCS3, MGN_VHT1SS_MCS4 + , MGN_VHT1SS_MCS5, MGN_VHT1SS_MCS6, MGN_VHT1SS_MCS7, MGN_VHT1SS_MCS8, MGN_VHT1SS_MCS9 + }; +u8 mgn_rates_vht2ss[10] = {MGN_VHT2SS_MCS0, MGN_VHT2SS_MCS1, MGN_VHT2SS_MCS2, MGN_VHT2SS_MCS3, MGN_VHT2SS_MCS4 + , MGN_VHT2SS_MCS5, MGN_VHT2SS_MCS6, MGN_VHT2SS_MCS7, MGN_VHT2SS_MCS8, MGN_VHT2SS_MCS9 + }; +u8 mgn_rates_vht3ss[10] = {MGN_VHT3SS_MCS0, MGN_VHT3SS_MCS1, MGN_VHT3SS_MCS2, MGN_VHT3SS_MCS3, MGN_VHT3SS_MCS4 + , MGN_VHT3SS_MCS5, MGN_VHT3SS_MCS6, MGN_VHT3SS_MCS7, MGN_VHT3SS_MCS8, MGN_VHT3SS_MCS9 + }; +u8 mgn_rates_vht4ss[10] = {MGN_VHT4SS_MCS0, MGN_VHT4SS_MCS1, MGN_VHT4SS_MCS2, MGN_VHT4SS_MCS3, MGN_VHT4SS_MCS4 + , MGN_VHT4SS_MCS5, MGN_VHT4SS_MCS6, MGN_VHT4SS_MCS7, MGN_VHT4SS_MCS8, MGN_VHT4SS_MCS9 + }; + +static const char *const _rate_section_str[] = { + "CCK", + "OFDM", + "HT_1SS", + "HT_2SS", + "HT_3SS", + "HT_4SS", + "VHT_1SS", + "VHT_2SS", + "VHT_3SS", + "VHT_4SS", + "RATE_SECTION_UNKNOWN", +}; + +const char *rate_section_str(u8 section) +{ + section = (section >= RATE_SECTION_NUM) ? RATE_SECTION_NUM : section; + return _rate_section_str[section]; +} + +struct rate_section_ent rates_by_sections[RATE_SECTION_NUM] = { + {RF_1TX, 4, mgn_rates_cck}, + {RF_1TX, 8, mgn_rates_ofdm}, + {RF_1TX, 8, mgn_rates_mcs0_7}, + {RF_2TX, 8, mgn_rates_mcs8_15}, + {RF_3TX, 8, mgn_rates_mcs16_23}, + {RF_4TX, 8, mgn_rates_mcs24_31}, + {RF_1TX, 10, mgn_rates_vht1ss}, + {RF_2TX, 10, mgn_rates_vht2ss}, + {RF_3TX, 10, mgn_rates_vht3ss}, + {RF_4TX, 10, mgn_rates_vht4ss}, +}; + +int rtw_get_bit_value_from_ieee_value(u8 val) +{ + unsigned char dot11_rate_table[] = {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 0}; /* last element must be zero!! */ + + int i = 0; + while (dot11_rate_table[i] != 0) { + if (dot11_rate_table[i] == val) + return BIT(i); + i++; + } + return 0; +} + +uint rtw_is_cckrates_included(u8 *rate) +{ + u32 i = 0; + + while (rate[i] != 0) { + if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || + (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) + return _TRUE; + i++; + } + + return _FALSE; +} + +uint rtw_is_cckratesonly_included(u8 *rate) +{ + u32 i = 0; + + + while (rate[i] != 0) { + if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && + (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) + return _FALSE; + + i++; + } + + return _TRUE; + +} + +int rtw_check_network_type(unsigned char *rate, int ratelen, int channel) +{ + if (channel > 14) { + if ((rtw_is_cckrates_included(rate)) == _TRUE) + return WIRELESS_INVALID; + else + return WIRELESS_11A; + } else { /* could be pure B, pure G, or B/G */ + if ((rtw_is_cckratesonly_included(rate)) == _TRUE) + return WIRELESS_11B; + else if ((rtw_is_cckrates_included(rate)) == _TRUE) + return WIRELESS_11BG; + else + return WIRELESS_11G; + } + +} + +u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *source, + unsigned int *frlen) +{ + _rtw_memcpy((void *)pbuf, (void *)source, len); + *frlen = *frlen + len; + return pbuf + len; +} + +/* rtw_set_ie will update frame length */ +u8 *rtw_set_ie +( + u8 *pbuf, + sint index, + uint len, + u8 *source, + uint *frlen /* frame length */ +) +{ + *pbuf = (u8)index; + + *(pbuf + 1) = (u8)len; + + if (len > 0) + _rtw_memcpy((void *)(pbuf + 2), (void *)source, len); + + *frlen = *frlen + (len + 2); + + return pbuf + len + 2; +} + +inline u8 *rtw_set_ie_ch_switch(u8 *buf, u32 *buf_len, u8 ch_switch_mode, + u8 new_ch, u8 ch_switch_cnt) +{ + u8 ie_data[3]; + + ie_data[0] = ch_switch_mode; + ie_data[1] = new_ch; + ie_data[2] = ch_switch_cnt; + return rtw_set_ie(buf, WLAN_EID_CHANNEL_SWITCH, 3, ie_data, buf_len); +} + +inline u8 secondary_ch_offset_to_hal_ch_offset(u8 ch_offset) +{ + if (ch_offset == SCN) + return HAL_PRIME_CHNL_OFFSET_DONT_CARE; + else if (ch_offset == SCA) + return HAL_PRIME_CHNL_OFFSET_UPPER; + else if (ch_offset == SCB) + return HAL_PRIME_CHNL_OFFSET_LOWER; + + return HAL_PRIME_CHNL_OFFSET_DONT_CARE; +} + +inline u8 hal_ch_offset_to_secondary_ch_offset(u8 ch_offset) +{ + if (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) + return SCN; + else if (ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) + return SCB; + else if (ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) + return SCA; + + return SCN; +} + +inline u8 *rtw_set_ie_secondary_ch_offset(u8 *buf, u32 *buf_len, u8 secondary_ch_offset) +{ + return rtw_set_ie(buf, WLAN_EID_SECONDARY_CHANNEL_OFFSET, 1, &secondary_ch_offset, buf_len); +} + +inline u8 *rtw_set_ie_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl, + u8 flags, u16 reason, u16 precedence) +{ + u8 ie_data[6]; + + ie_data[0] = ttl; + ie_data[1] = flags; + RTW_PUT_LE16((u8 *)&ie_data[2], reason); + RTW_PUT_LE16((u8 *)&ie_data[4], precedence); + + return rtw_set_ie(buf, 0x118, 6, ie_data, buf_len); +} + +/*---------------------------------------------------------------------------- +index: the information element id index, limit is the limit for search +-----------------------------------------------------------------------------*/ +u8 *rtw_get_ie(u8 *pbuf, sint index, sint *len, sint limit) +{ + sint tmp, i; + u8 *p; + if (limit < 1) { + return NULL; + } + + p = pbuf; + i = 0; + *len = 0; + while (1) { + if (*p == index) { + *len = *(p + 1); + return p; + } else { + tmp = *(p + 1); + p += (tmp + 2); + i += (tmp + 2); + } + if (i >= limit) + break; + } + return NULL; +} + +/** + * rtw_get_ie_ex - Search specific IE from a series of IEs + * @in_ie: Address of IEs to search + * @in_len: Length limit from in_ie + * @eid: Element ID to match + * @oui: OUI to match + * @oui_len: OUI length + * @ie: If not NULL and the specific IE is found, the IE will be copied to the buf starting from the specific IE + * @ielen: If not NULL and the specific IE is found, will set to the length of the entire IE + * + * Returns: The address of the specific IE found, or NULL + */ +u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen) +{ + uint cnt; + u8 *target_ie = NULL; + + + if (ielen) + *ielen = 0; + + if (!in_ie || in_len <= 0) + return target_ie; + + cnt = 0; + + while (cnt < in_len) { + if (eid == in_ie[cnt] + && (!oui || _rtw_memcmp(&in_ie[cnt + 2], oui, oui_len) == _TRUE)) { + target_ie = &in_ie[cnt]; + + if (ie) + _rtw_memcpy(ie, &in_ie[cnt], in_ie[cnt + 1] + 2); + + if (ielen) + *ielen = in_ie[cnt + 1] + 2; + + break; + } else { + cnt += in_ie[cnt + 1] + 2; /* goto next */ + } + + } + + return target_ie; +} + +/** + * rtw_ies_remove_ie - Find matching IEs and remove + * @ies: Address of IEs to search + * @ies_len: Pointer of length of ies, will update to new length + * @offset: The offset to start scarch + * @eid: Element ID to match + * @oui: OUI to match + * @oui_len: OUI length + * + * Returns: _SUCCESS: ies is updated, _FAIL: not updated + */ +int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len) +{ + int ret = _FAIL; + u8 *target_ie; + u32 target_ielen; + u8 *start; + uint search_len; + + if (!ies || !ies_len || *ies_len <= offset) + goto exit; + + start = ies + offset; + search_len = *ies_len - offset; + + while (1) { + target_ie = rtw_get_ie_ex(start, search_len, eid, oui, oui_len, NULL, &target_ielen); + if (target_ie && target_ielen) { + u8 *remain_ies = target_ie + target_ielen; + uint remain_len = search_len - (remain_ies - start); + + _rtw_memmove(target_ie, remain_ies, remain_len); + *ies_len = *ies_len - target_ielen; + ret = _SUCCESS; + + start = target_ie; + search_len = remain_len; + } else + break; + } +exit: + return ret; +} + +void rtw_set_supported_rate(u8 *SupportedRates, uint mode) +{ + + _rtw_memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); + + switch (mode) { + case WIRELESS_11B: + _rtw_memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); + break; + + case WIRELESS_11G: + case WIRELESS_11A: + case WIRELESS_11_5N: + case WIRELESS_11A_5N: /* Todo: no basic rate for ofdm ? */ + case WIRELESS_11_5AC: + _rtw_memcpy(SupportedRates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN); + break; + + case WIRELESS_11BG: + case WIRELESS_11G_24N: + case WIRELESS_11_24N: + case WIRELESS_11BG_24N: + _rtw_memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); + _rtw_memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN); + break; + + } +} + +uint rtw_get_rateset_len(u8 *rateset) +{ + uint i = 0; + while (1) { + if ((rateset[i]) == 0) + break; + + if (i > 12) + break; + + i++; + } + return i; +} + +int rtw_generate_ie(struct registry_priv *pregistrypriv) +{ + u8 wireless_mode; + int sz = 0, rateLen; + WLAN_BSSID_EX *pdev_network = &pregistrypriv->dev_network; + u8 *ie = pdev_network->IEs; + + + /* timestamp will be inserted by hardware */ + sz += 8; + ie += sz; + + /* beacon interval : 2bytes */ + *(u16 *)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod); /* BCN_INTERVAL; */ + sz += 2; + ie += 2; + + /* capability info */ + *(u16 *)ie = 0; + + *(u16 *)ie |= cpu_to_le16(cap_IBSS); + + if (pregistrypriv->preamble == PREAMBLE_SHORT) + *(u16 *)ie |= cpu_to_le16(cap_ShortPremble); + + if (pdev_network->Privacy) + *(u16 *)ie |= cpu_to_le16(cap_Privacy); + + sz += 2; + ie += 2; + + /* SSID */ + ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz); + + /* supported rates */ + if (pregistrypriv->wireless_mode == WIRELESS_11ABGN) { + if (pdev_network->Configuration.DSConfig > 14) + wireless_mode = WIRELESS_11A_5N; + else + wireless_mode = WIRELESS_11BG_24N; + } else if (pregistrypriv->wireless_mode == WIRELESS_MODE_MAX) { /* WIRELESS_11ABGN | WIRELESS_11AC */ + if (pdev_network->Configuration.DSConfig > 14) + wireless_mode = WIRELESS_11_5AC; + else + wireless_mode = WIRELESS_11BG_24N; + } else + wireless_mode = pregistrypriv->wireless_mode; + + rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode) ; + + rateLen = rtw_get_rateset_len(pdev_network->SupportedRates); + + if (rateLen > 8) { + ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, pdev_network->SupportedRates, &sz); + /* ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); */ + } else + ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, pdev_network->SupportedRates, &sz); + + /* DS parameter set */ + ie = rtw_set_ie(ie, _DSSET_IE_, 1, (u8 *)&(pdev_network->Configuration.DSConfig), &sz); + + + /* IBSS Parameter Set */ + + ie = rtw_set_ie(ie, _IBSS_PARA_IE_, 2, (u8 *)&(pdev_network->Configuration.ATIMWindow), &sz); + + if (rateLen > 8) + ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); + +#ifdef CONFIG_80211N_HT + /* HT Cap. */ + if (((pregistrypriv->wireless_mode & WIRELESS_11_5N) || (pregistrypriv->wireless_mode & WIRELESS_11_24N)) + && (pregistrypriv->ht_enable == _TRUE)) { + /* todo: */ + } +#endif /* CONFIG_80211N_HT */ + + /* pdev_network->IELength = sz; */ /* update IELength */ + + + /* return _SUCCESS; */ + + return sz; + +} + +unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit) +{ + int len; + u16 val16; + unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01}; + u8 *pbuf = pie; + int limit_new = limit; + + while (1) { + pbuf = rtw_get_ie(pbuf, _WPA_IE_ID_, &len, limit_new); + + if (pbuf) { + + /* check if oui matches... */ + if (_rtw_memcmp((pbuf + 2), wpa_oui_type, sizeof(wpa_oui_type)) == _FALSE) + + goto check_next_ie; + + /* check version... */ + _rtw_memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16)); + + val16 = le16_to_cpu(val16); + if (val16 != 0x0001) + goto check_next_ie; + + *wpa_ie_len = *(pbuf + 1); + + return pbuf; + + } else { + + *wpa_ie_len = 0; + return NULL; + } + +check_next_ie: + + limit_new = limit - (pbuf - pie) - 2 - len; + + if (limit_new <= 0) + break; + + pbuf += (2 + len); + + } + + *wpa_ie_len = 0; + + return NULL; + +} + +unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit) +{ + + return rtw_get_ie(pie, _WPA2_IE_ID_, rsn_ie_len, limit); + +} + +int rtw_get_wpa_cipher_suite(u8 *s) +{ + if (_rtw_memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == _TRUE) + return WPA_CIPHER_NONE; + if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == _TRUE) + return WPA_CIPHER_WEP40; + if (_rtw_memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == _TRUE) + return WPA_CIPHER_TKIP; + if (_rtw_memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == _TRUE) + return WPA_CIPHER_CCMP; + if (_rtw_memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == _TRUE) + return WPA_CIPHER_WEP104; + + return 0; +} + +int rtw_get_wpa2_cipher_suite(u8 *s) +{ + if (_rtw_memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == _TRUE) + return WPA_CIPHER_NONE; + if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == _TRUE) + return WPA_CIPHER_WEP40; + if (_rtw_memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == _TRUE) + return WPA_CIPHER_TKIP; + if (_rtw_memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == _TRUE) + return WPA_CIPHER_CCMP; + if (_rtw_memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == _TRUE) + return WPA_CIPHER_WEP104; + + return 0; +} + + +int rtw_parse_wpa_ie(u8 *wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) +{ + int i, ret = _SUCCESS; + int left, count; + u8 *pos; + u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1}; + + if (wpa_ie_len <= 0) { + /* No WPA IE - fail silently */ + return _FAIL; + } + + + if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie + 1) != (u8)(wpa_ie_len - 2)) || + (_rtw_memcmp(wpa_ie + 2, RTW_WPA_OUI_TYPE, WPA_SELECTOR_LEN) != _TRUE)) + return _FAIL; + + pos = wpa_ie; + + pos += 8; + left = wpa_ie_len - 8; + + + /* group_cipher */ + if (left >= WPA_SELECTOR_LEN) { + + *group_cipher = rtw_get_wpa_cipher_suite(pos); + + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + + } else if (left > 0) { + + return _FAIL; + } + + + /* pairwise_cipher */ + if (left >= 2) { + /* count = le16_to_cpu(*(u16*)pos); */ + count = RTW_GET_LE16(pos); + pos += 2; + left -= 2; + + if (count == 0 || left < count * WPA_SELECTOR_LEN) { + return _FAIL; + } + + for (i = 0; i < count; i++) { + *pairwise_cipher |= rtw_get_wpa_cipher_suite(pos); + + pos += WPA_SELECTOR_LEN; + left -= WPA_SELECTOR_LEN; + } + + } else if (left == 1) { + return _FAIL; + } + + if (is_8021x) { + if (left >= 6) { + pos += 2; + if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) { + *is_8021x = 1; + } + } + } + + return ret; + +} + +int rtw_parse_wpa2_ie(u8 *rsn_ie, int rsn_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x) +{ + int i, ret = _SUCCESS; + int left, count; + u8 *pos; + u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01}; + + if (rsn_ie_len <= 0) { + /* No RSN IE - fail silently */ + return _FAIL; + } + + + if ((*rsn_ie != _WPA2_IE_ID_) || (*(rsn_ie + 1) != (u8)(rsn_ie_len - 2))) + return _FAIL; + + pos = rsn_ie; + pos += 4; + left = rsn_ie_len - 4; + + /* group_cipher */ + if (left >= RSN_SELECTOR_LEN) { + + *group_cipher = rtw_get_wpa2_cipher_suite(pos); + + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + + } else if (left > 0) { + return _FAIL; + } + + /* pairwise_cipher */ + if (left >= 2) { + /* count = le16_to_cpu(*(u16*)pos); */ + count = RTW_GET_LE16(pos); + pos += 2; + left -= 2; + + if (count == 0 || left < count * RSN_SELECTOR_LEN) { + return _FAIL; + } + + for (i = 0; i < count; i++) { + *pairwise_cipher |= rtw_get_wpa2_cipher_suite(pos); + + pos += RSN_SELECTOR_LEN; + left -= RSN_SELECTOR_LEN; + } + + } else if (left == 1) { + + return _FAIL; + } + + if (is_8021x) { + if (left >= 6) { + pos += 2; + if (_rtw_memcmp(pos, SUITE_1X, 4) == 1) { + *is_8021x = 1; + } + } + } + + return ret; + +} + +/* #ifdef CONFIG_WAPI_SUPPORT */ +int rtw_get_wapi_ie(u8 *in_ie, uint in_len, u8 *wapi_ie, u16 *wapi_len) +{ + int len = 0; + u8 authmode, i; + uint cnt; + u8 wapi_oui1[4] = {0x0, 0x14, 0x72, 0x01}; + u8 wapi_oui2[4] = {0x0, 0x14, 0x72, 0x02}; + + + if (wapi_len) + *wapi_len = 0; + + if (!in_ie || in_len <= 0) + return len; + + cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_); + + while (cnt < in_len) { + authmode = in_ie[cnt]; + + /* if(authmode==_WAPI_IE_) */ + if (authmode == _WAPI_IE_ && (_rtw_memcmp(&in_ie[cnt + 6], wapi_oui1, 4) == _TRUE || + _rtw_memcmp(&in_ie[cnt + 6], wapi_oui2, 4) == _TRUE)) { + if (wapi_ie) + _rtw_memcpy(wapi_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); + + if (wapi_len) + *wapi_len = in_ie[cnt + 1] + 2; + + cnt += in_ie[cnt + 1] + 2; /* get next */ + } else { + cnt += in_ie[cnt + 1] + 2; /* get next */ + } + } + + if (wapi_len) + len = *wapi_len; + + + return len; + +} +/* #endif */ + +int rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len) +{ + u8 authmode, sec_idx, i; + u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01}; + uint cnt; + + + /* Search required WPA or WPA2 IE and copy to sec_ie[ ] */ + + cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_); + + sec_idx = 0; + + while (cnt < in_len) { + authmode = in_ie[cnt]; + + if ((authmode == _WPA_IE_ID_) && (_rtw_memcmp(&in_ie[cnt + 2], &wpa_oui[0], 4) == _TRUE)) { + + if (wpa_ie) + _rtw_memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); + + *wpa_len = in_ie[cnt + 1] + 2; + cnt += in_ie[cnt + 1] + 2; /* get next */ + } else { + if (authmode == _WPA2_IE_ID_) { + + if (rsn_ie) + _rtw_memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); + + *rsn_len = in_ie[cnt + 1] + 2; + cnt += in_ie[cnt + 1] + 2; /* get next */ + } else { + cnt += in_ie[cnt + 1] + 2; /* get next */ + } + } + + } + + + return *rsn_len + *wpa_len; + +} + +u8 rtw_is_wps_ie(u8 *ie_ptr, uint *wps_ielen) +{ + u8 match = _FALSE; + u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04}; + + if (ie_ptr == NULL) + return match; + + eid = ie_ptr[0]; + + if ((eid == _WPA_IE_ID_) && (_rtw_memcmp(&ie_ptr[2], wps_oui, 4) == _TRUE)) { + /* RTW_INFO("==> found WPS_IE.....\n"); */ + *wps_ielen = ie_ptr[1] + 2; + match = _TRUE; + } + return match; +} + +u8 *rtw_get_wps_ie_from_scan_queue(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen, u8 frame_type) +{ + u8 *wps = NULL; + + RTW_INFO("[%s] frame_type = %d\n", __FUNCTION__, frame_type); + switch (frame_type) { + case 1: + case 3: { + /* Beacon or Probe Response */ + wps = rtw_get_wps_ie(in_ie + _PROBERSP_IE_OFFSET_, in_len - _PROBERSP_IE_OFFSET_, wps_ie, wps_ielen); + break; + } + case 2: { + /* Probe Request */ + wps = rtw_get_wps_ie(in_ie + _PROBEREQ_IE_OFFSET_ , in_len - _PROBEREQ_IE_OFFSET_ , wps_ie, wps_ielen); + break; + } + } + return wps; +} + +/** + * rtw_get_wps_ie - Search WPS IE from a series of IEs + * @in_ie: Address of IEs to search + * @in_len: Length limit from in_ie + * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the buf starting from wps_ie + * @wps_ielen: If not NULL and WPS IE is found, will set to the length of the entire WPS IE + * + * Returns: The address of the WPS IE found, or NULL + */ +u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen) +{ + uint cnt; + u8 *wpsie_ptr = NULL; + u8 eid, wps_oui[4] = {0x00, 0x50, 0xf2, 0x04}; + + if (wps_ielen) + *wps_ielen = 0; + + if (!in_ie) { + rtw_warn_on(1); + return wpsie_ptr; + } + + if (in_len <= 0) + return wpsie_ptr; + + cnt = 0; + + while (cnt + 1 + 4 < in_len) { + eid = in_ie[cnt]; + + if (cnt + 1 + 4 >= MAX_IE_SZ) { + rtw_warn_on(1); + return NULL; + } + + if (eid == WLAN_EID_VENDOR_SPECIFIC && _rtw_memcmp(&in_ie[cnt + 2], wps_oui, 4) == _TRUE) { + wpsie_ptr = in_ie + cnt; + + if (wps_ie) + _rtw_memcpy(wps_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); + + if (wps_ielen) + *wps_ielen = in_ie[cnt + 1] + 2; + + break; + } else + cnt += in_ie[cnt + 1] + 2; + + } + + return wpsie_ptr; +} + +/** + * rtw_get_wps_attr - Search a specific WPS attribute from a given WPS IE + * @wps_ie: Address of WPS IE to search + * @wps_ielen: Length limit from wps_ie + * @target_attr_id: The attribute ID of WPS attribute to search + * @buf_attr: If not NULL and the WPS attribute is found, WPS attribute will be copied to the buf starting from buf_attr + * @len_attr: If not NULL and the WPS attribute is found, will set to the length of the entire WPS attribute + * + * Returns: the address of the specific WPS attribute found, or NULL + */ +u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id , u8 *buf_attr, u32 *len_attr) +{ + u8 *attr_ptr = NULL; + u8 *target_attr_ptr = NULL; + u8 wps_oui[4] = {0x00, 0x50, 0xF2, 0x04}; + + if (len_attr) + *len_attr = 0; + + if ((wps_ie[0] != _VENDOR_SPECIFIC_IE_) || + (_rtw_memcmp(wps_ie + 2, wps_oui , 4) != _TRUE)) + return attr_ptr; + + /* 6 = 1(Element ID) + 1(Length) + 4(WPS OUI) */ + attr_ptr = wps_ie + 6; /* goto first attr */ + + while (attr_ptr - wps_ie < wps_ielen) { + /* 4 = 2(Attribute ID) + 2(Length) */ + u16 attr_id = RTW_GET_BE16(attr_ptr); + u16 attr_data_len = RTW_GET_BE16(attr_ptr + 2); + u16 attr_len = attr_data_len + 4; + + /* RTW_INFO("%s attr_ptr:%p, id:%u, length:%u\n", __FUNCTION__, attr_ptr, attr_id, attr_data_len); */ + if (attr_id == target_attr_id) { + target_attr_ptr = attr_ptr; + + if (buf_attr) + _rtw_memcpy(buf_attr, attr_ptr, attr_len); + + if (len_attr) + *len_attr = attr_len; + + break; + } else { + attr_ptr += attr_len; /* goto next */ + } + + } + + return target_attr_ptr; +} + +/** + * rtw_get_wps_attr_content - Search a specific WPS attribute content from a given WPS IE + * @wps_ie: Address of WPS IE to search + * @wps_ielen: Length limit from wps_ie + * @target_attr_id: The attribute ID of WPS attribute to search + * @buf_content: If not NULL and the WPS attribute is found, WPS attribute content will be copied to the buf starting from buf_content + * @len_content: If not NULL and the WPS attribute is found, will set to the length of the WPS attribute content + * + * Returns: the address of the specific WPS attribute content found, or NULL + */ +u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id , u8 *buf_content, uint *len_content) +{ + u8 *attr_ptr; + u32 attr_len; + + if (len_content) + *len_content = 0; + + attr_ptr = rtw_get_wps_attr(wps_ie, wps_ielen, target_attr_id, NULL, &attr_len); + + if (attr_ptr && attr_len) { + if (buf_content) + _rtw_memcpy(buf_content, attr_ptr + 4, attr_len - 4); + + if (len_content) + *len_content = attr_len - 4; + + return attr_ptr + 4; + } + + return NULL; +} + +static int rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen, + struct rtw_ieee802_11_elems *elems, + int show_errors) +{ + unsigned int oui; + + /* first 3 bytes in vendor specific information element are the IEEE + * OUI of the vendor. The following byte is used a vendor specific + * sub-type. */ + if (elen < 4) { + if (show_errors) { + RTW_INFO("short vendor specific " + "information element ignored (len=%lu)\n", + (unsigned long) elen); + } + return -1; + } + + oui = RTW_GET_BE24(pos); + switch (oui) { + case OUI_MICROSOFT: + /* Microsoft/Wi-Fi information elements are further typed and + * subtyped */ + switch (pos[3]) { + case 1: + /* Microsoft OUI (00:50:F2) with OUI Type 1: + * real WPA information element */ + elems->wpa_ie = pos; + elems->wpa_ie_len = elen; + break; + case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */ + if (elen < 5) { + RTW_DBG("short WME " + "information element ignored " + "(len=%lu)\n", + (unsigned long) elen); + return -1; + } + switch (pos[4]) { + case WME_OUI_SUBTYPE_INFORMATION_ELEMENT: + case WME_OUI_SUBTYPE_PARAMETER_ELEMENT: + elems->wme = pos; + elems->wme_len = elen; + break; + case WME_OUI_SUBTYPE_TSPEC_ELEMENT: + elems->wme_tspec = pos; + elems->wme_tspec_len = elen; + break; + default: + RTW_DBG("unknown WME " + "information element ignored " + "(subtype=%d len=%lu)\n", + pos[4], (unsigned long) elen); + return -1; + } + break; + case 4: + /* Wi-Fi Protected Setup (WPS) IE */ + elems->wps_ie = pos; + elems->wps_ie_len = elen; + break; + default: + RTW_DBG("Unknown Microsoft " + "information element ignored " + "(type=%d len=%lu)\n", + pos[3], (unsigned long) elen); + return -1; + } + break; + + case OUI_BROADCOM: + switch (pos[3]) { + case VENDOR_HT_CAPAB_OUI_TYPE: + elems->vendor_ht_cap = pos; + elems->vendor_ht_cap_len = elen; + break; + default: + RTW_DBG("Unknown Broadcom " + "information element ignored " + "(type=%d len=%lu)\n", + pos[3], (unsigned long) elen); + return -1; + } + break; + + default: + RTW_DBG("unknown vendor specific information " + "element ignored (vendor OUI %02x:%02x:%02x " + "len=%lu)\n", + pos[0], pos[1], pos[2], (unsigned long) elen); + return -1; + } + + return 0; + +} + +/** + * ieee802_11_parse_elems - Parse information elements in management frames + * @start: Pointer to the start of IEs + * @len: Length of IE buffer in octets + * @elems: Data structure for parsed elements + * @show_errors: Whether to show parsing errors in debug log + * Returns: Parsing result + */ +ParseRes rtw_ieee802_11_parse_elems(u8 *start, uint len, + struct rtw_ieee802_11_elems *elems, + int show_errors) +{ + uint left = len; + u8 *pos = start; + int unknown = 0; + + _rtw_memset(elems, 0, sizeof(*elems)); + + while (left >= 2) { + u8 id, elen; + + id = *pos++; + elen = *pos++; + left -= 2; + + if (elen > left) { + if (show_errors) { + RTW_INFO("IEEE 802.11 element " + "parse failed (id=%d elen=%d " + "left=%lu)\n", + id, elen, (unsigned long) left); + } + return ParseFailed; + } + + switch (id) { + case WLAN_EID_SSID: + elems->ssid = pos; + elems->ssid_len = elen; + break; + case WLAN_EID_SUPP_RATES: + elems->supp_rates = pos; + elems->supp_rates_len = elen; + break; + case WLAN_EID_FH_PARAMS: + elems->fh_params = pos; + elems->fh_params_len = elen; + break; + case WLAN_EID_DS_PARAMS: + elems->ds_params = pos; + elems->ds_params_len = elen; + break; + case WLAN_EID_CF_PARAMS: + elems->cf_params = pos; + elems->cf_params_len = elen; + break; + case WLAN_EID_TIM: + elems->tim = pos; + elems->tim_len = elen; + break; + case WLAN_EID_IBSS_PARAMS: + elems->ibss_params = pos; + elems->ibss_params_len = elen; + break; + case WLAN_EID_CHALLENGE: + elems->challenge = pos; + elems->challenge_len = elen; + break; + case WLAN_EID_ERP_INFO: + elems->erp_info = pos; + elems->erp_info_len = elen; + break; + case WLAN_EID_EXT_SUPP_RATES: + elems->ext_supp_rates = pos; + elems->ext_supp_rates_len = elen; + break; + case WLAN_EID_VENDOR_SPECIFIC: + if (rtw_ieee802_11_parse_vendor_specific(pos, elen, + elems, + show_errors)) + unknown++; + break; + case WLAN_EID_RSN: + elems->rsn_ie = pos; + elems->rsn_ie_len = elen; + break; + case WLAN_EID_PWR_CAPABILITY: + elems->power_cap = pos; + elems->power_cap_len = elen; + break; + case WLAN_EID_SUPPORTED_CHANNELS: + elems->supp_channels = pos; + elems->supp_channels_len = elen; + break; + case WLAN_EID_MOBILITY_DOMAIN: + elems->mdie = pos; + elems->mdie_len = elen; + break; + case WLAN_EID_FAST_BSS_TRANSITION: + elems->ftie = pos; + elems->ftie_len = elen; + break; + case WLAN_EID_TIMEOUT_INTERVAL: + elems->timeout_int = pos; + elems->timeout_int_len = elen; + break; + case WLAN_EID_HT_CAP: + elems->ht_capabilities = pos; + elems->ht_capabilities_len = elen; + break; + case WLAN_EID_HT_OPERATION: + elems->ht_operation = pos; + elems->ht_operation_len = elen; + break; + case WLAN_EID_VHT_CAPABILITY: + elems->vht_capabilities = pos; + elems->vht_capabilities_len = elen; + break; + case WLAN_EID_VHT_OPERATION: + elems->vht_operation = pos; + elems->vht_operation_len = elen; + break; + case WLAN_EID_VHT_OP_MODE_NOTIFY: + elems->vht_op_mode_notify = pos; + elems->vht_op_mode_notify_len = elen; + break; + default: + unknown++; + if (!show_errors) + break; + RTW_DBG("IEEE 802.11 element parse " + "ignored unknown element (id=%d elen=%d)\n", + id, elen); + break; + } + + left -= elen; + pos += elen; + } + + if (left) + return ParseFailed; + + return unknown ? ParseUnknown : ParseOK; + +} + +static u8 key_char2num(u8 ch); +static u8 key_char2num(u8 ch) +{ + if ((ch >= '0') && (ch <= '9')) + return ch - '0'; + else if ((ch >= 'a') && (ch <= 'f')) + return ch - 'a' + 10; + else if ((ch >= 'A') && (ch <= 'F')) + return ch - 'A' + 10; + else + return 0xff; +} + +u8 str_2char2num(u8 hch, u8 lch); +u8 str_2char2num(u8 hch, u8 lch) +{ + return (key_char2num(hch) * 10) + key_char2num(lch); +} + +u8 key_2char2num(u8 hch, u8 lch); +u8 key_2char2num(u8 hch, u8 lch) +{ + return (key_char2num(hch) << 4) | key_char2num(lch); +} + +void macstr2num(u8 *dst, u8 *src); +void macstr2num(u8 *dst, u8 *src) +{ + int jj, kk; + for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) + dst[jj] = key_2char2num(src[kk], src[kk + 1]); +} + +u8 convert_ip_addr(u8 hch, u8 mch, u8 lch) +{ + return (key_char2num(hch) * 100) + (key_char2num(mch) * 10) + key_char2num(lch); +} + +#ifdef CONFIG_PLATFORM_INTEL_BYT +#define MAC_ADDRESS_LEN 12 + +int rtw_get_mac_addr_intel(unsigned char *buf) +{ + int ret = 0; + int i; + struct file *fp = NULL; + mm_segment_t oldfs; + unsigned char c_mac[MAC_ADDRESS_LEN]; + char fname[] = "/config/wifi/mac.txt"; + int jj, kk; + + RTW_INFO("%s Enter\n", __FUNCTION__); + + ret = rtw_retrieve_from_file(fname, c_mac, MAC_ADDRESS_LEN); + if (ret < MAC_ADDRESS_LEN) + return -1; + + for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 2) + buf[jj] = key_2char2num(c_mac[kk], c_mac[kk + 1]); + + RTW_INFO("%s: read from file mac address: "MAC_FMT"\n", + __FUNCTION__, MAC_ARG(buf)); + + return 0; +} +#endif /* CONFIG_PLATFORM_INTEL_BYT */ + +/* + * Description: + * rtw_check_invalid_mac_address: + * This is only used for checking mac address valid or not. + * + * Input: + * adapter: mac_address pointer. + * check_local_bit: check locally bit or not. + * + * Output: + * _TRUE: The mac address is invalid. + * _FALSE: The mac address is valid. + * + * Auther: Isaac.Li + */ +u8 rtw_check_invalid_mac_address(u8 *mac_addr, u8 check_local_bit) +{ + u8 null_mac_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; + u8 multi_mac_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 res = _FALSE; + + if (_rtw_memcmp(mac_addr, null_mac_addr, ETH_ALEN)) { + res = _TRUE; + goto func_exit; + } + + if (_rtw_memcmp(mac_addr, multi_mac_addr, ETH_ALEN)) { + res = _TRUE; + goto func_exit; + } + + if (mac_addr[0] & BIT0) { + res = _TRUE; + goto func_exit; + } + + if (check_local_bit == _TRUE) { + if (mac_addr[0] & BIT1) { + res = _TRUE; + goto func_exit; + } + } + +func_exit: + return res; +} + +extern char *rtw_initmac; +/** + * rtw_macaddr_cfg - Decide the mac address used + * @out: buf to store mac address decided + * @hw_mac_addr: mac address from efuse/epprom + */ +void rtw_macaddr_cfg(u8 *out, const u8 *hw_mac_addr) +{ +#define DEFAULT_RANDOM_MACADDR 1 + u8 mac[ETH_ALEN]; + + if (out == NULL) { + rtw_warn_on(1); + return; + } + + /* Users specify the mac address */ + if (rtw_initmac) { + int jj, kk; + + for (jj = 0, kk = 0; jj < ETH_ALEN; jj++, kk += 3) + mac[jj] = key_2char2num(rtw_initmac[kk], rtw_initmac[kk + 1]); + + goto err_chk; + } + + /* platform specified */ +#ifdef CONFIG_PLATFORM_INTEL_BYT + if (rtw_get_mac_addr_intel(mac) == 0) + goto err_chk; +#endif + + /* Use the mac address stored in the Efuse */ + if (hw_mac_addr) { + _rtw_memcpy(mac, hw_mac_addr, ETH_ALEN); + goto err_chk; + } + +err_chk: + if (rtw_check_invalid_mac_address(mac, _TRUE) == _TRUE) { +#if DEFAULT_RANDOM_MACADDR + RTW_ERR("invalid mac addr:"MAC_FMT", assign random MAC\n", MAC_ARG(mac)); + *((u32 *)(&mac[2])) = rtw_random32(); + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0x4c; +#else + RTW_ERR("invalid mac addr:"MAC_FMT", assign default one\n", MAC_ARG(mac)); + mac[0] = 0x00; + mac[1] = 0xe0; + mac[2] = 0x4c; + mac[3] = 0x87; + mac[4] = 0x00; + mac[5] = 0x00; +#endif + } + + _rtw_memcpy(out, mac, ETH_ALEN); + RTW_INFO("%s mac addr:"MAC_FMT"\n", __func__, MAC_ARG(out)); +} + +#ifdef CONFIG_80211N_HT +void dump_ht_cap_ie_content(void *sel, u8 *buf, u32 buf_len) +{ + if (buf_len != 26) { + RTW_PRINT_SEL(sel, "Invalid HT capability IE len:%d != %d\n", buf_len, 26); + return; + } + + RTW_PRINT_SEL(sel, "HT Capabilities Info:%02x%02x\n", *(buf), *(buf + 1)); + RTW_PRINT_SEL(sel, "A-MPDU Parameters:"HT_AMPDU_PARA_FMT"\n" + , HT_AMPDU_PARA_ARG(HT_CAP_ELE_AMPDU_PARA(buf))); + RTW_PRINT_SEL(sel, "Supported MCS Set:"HT_SUP_MCS_SET_FMT"\n" + , HT_SUP_MCS_SET_ARG(HT_CAP_ELE_SUP_MCS_SET(buf))); +} + +void dump_ht_cap_ie(void *sel, u8 *ie, u32 ie_len) +{ + u8 *pos = (u8 *)ie; + u16 id; + u16 len; + + u8 *ht_cap_ie; + sint ht_cap_ielen; + + ht_cap_ie = rtw_get_ie(ie, _HT_CAPABILITY_IE_, &ht_cap_ielen, ie_len); + if (!ie || ht_cap_ie != ie) + return; + + dump_ht_cap_ie_content(sel, ht_cap_ie + 2, ht_cap_ielen); +} +#endif /* CONFIG_80211N_HT */ + +void dump_ies(void *sel, u8 *buf, u32 buf_len) +{ + u8 *pos = (u8 *)buf; + u8 id, len; + + while (pos - buf + 1 < buf_len) { + id = *pos; + len = *(pos + 1); + + RTW_PRINT_SEL(sel, "%s ID:%u, LEN:%u\n", __FUNCTION__, id, len); +#ifdef CONFIG_80211N_HT + dump_ht_cap_ie(sel, pos, len + 2); +#endif + dump_wps_ie(sel, pos, len + 2); +#ifdef CONFIG_P2P + dump_p2p_ie(sel, pos, len + 2); +#ifdef CONFIG_WFD + dump_wfd_ie(sel, pos, len + 2); +#endif +#endif + + pos += (2 + len); + } +} + +void dump_wps_ie(void *sel, u8 *ie, u32 ie_len) +{ + u8 *pos = (u8 *)ie; + u16 id; + u16 len; + + u8 *wps_ie; + uint wps_ielen; + + wps_ie = rtw_get_wps_ie(ie, ie_len, NULL, &wps_ielen); + if (wps_ie != ie || wps_ielen == 0) + return; + + pos += 6; + while (pos - ie + 4 <= ie_len) { + id = RTW_GET_BE16(pos); + len = RTW_GET_BE16(pos + 2); + + RTW_PRINT_SEL(sel, "%s ID:0x%04x, LEN:%u%s\n", __func__, id, len + , ((pos - ie + 4 + len) <= ie_len) ? "" : "(exceed ie_len)"); + + pos += (4 + len); + } +} + +/** + * rtw_ies_get_chbw - get operation ch, bw, offset from IEs of BSS. + * @ies: pointer of the first tlv IE + * @ies_len: length of @ies + * @ch: pointer of ch, used as output + * @bw: pointer of bw, used as output + * @offset: pointer of offset, used as output + */ +void rtw_ies_get_chbw(u8 *ies, int ies_len, u8 *ch, u8 *bw, u8 *offset) +{ + u8 *p; + int ie_len; + + *ch = 0; + *bw = CHANNEL_WIDTH_20; + *offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + + p = rtw_get_ie(ies, _DSSET_IE_, &ie_len, ies_len); + if (p && ie_len > 0) + *ch = *(p + 2); + +#ifdef CONFIG_80211N_HT + { + u8 *ht_cap_ie, *ht_op_ie; + int ht_cap_ielen, ht_op_ielen; + + ht_cap_ie = rtw_get_ie(ies, EID_HTCapability, &ht_cap_ielen, ies_len); + if (ht_cap_ie && ht_cap_ielen) { + if (GET_HT_CAP_ELE_CHL_WIDTH(ht_cap_ie + 2)) + *bw = CHANNEL_WIDTH_40; + } + + ht_op_ie = rtw_get_ie(ies, EID_HTInfo, &ht_op_ielen, ies_len); + if (ht_op_ie && ht_op_ielen) { + if (*ch == 0) + *ch = GET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2); + else if (*ch != 0 && *ch != GET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2)) { + RTW_INFO("%s ch inconsistent, DSSS:%u, HT primary:%u\n" + , __func__, *ch, GET_HT_OP_ELE_PRI_CHL(ht_op_ie + 2)); + } + + if (!GET_HT_OP_ELE_STA_CHL_WIDTH(ht_op_ie + 2)) + *bw = CHANNEL_WIDTH_20; + + if (*bw == CHANNEL_WIDTH_40) { + switch (GET_HT_OP_ELE_2ND_CHL_OFFSET(ht_op_ie + 2)) { + case SCA: + *offset = HAL_PRIME_CHNL_OFFSET_LOWER; + break; + case SCB: + *offset = HAL_PRIME_CHNL_OFFSET_UPPER; + break; + } + } + } + } +#endif /* CONFIG_80211N_HT */ +#ifdef CONFIG_80211AC_VHT + { + u8 *vht_op_ie; + int vht_op_ielen; + + vht_op_ie = rtw_get_ie(ies, EID_VHTOperation, &vht_op_ielen, ies_len); + if (vht_op_ie && vht_op_ielen) { + /* enable VHT 80 before check enable HT40 or not */ + if (GET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2) >= 1) { + /* for HT40, enable VHT80 */ + if (*bw == CHANNEL_WIDTH_40) + *bw = CHANNEL_WIDTH_80; + /* for HT20, enable VHT20 */ + else if (*bw == CHANNEL_WIDTH_20) { + /* modify VHT OP IE */ + SET_VHT_OPERATION_ELE_CHL_WIDTH(vht_op_ie + 2, 0); + /* reset to 0 for VHT20 */ + SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(vht_op_ie + 2, 0); + SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(vht_op_ie + 2, 0); + } + } else { + /* + VHT OP WIDTH = 0 under HT20/HT40 + if REGSTY_BW_5G(pregistrypriv) < CHANNEL_WIDTH_80 in rtw_build_vht_operation_ie + */ + } + } + } +#endif +} + +void rtw_bss_get_chbw(WLAN_BSSID_EX *bss, u8 *ch, u8 *bw, u8 *offset) +{ + rtw_ies_get_chbw(bss->IEs + sizeof(NDIS_802_11_FIXED_IEs) + , bss->IELength - sizeof(NDIS_802_11_FIXED_IEs) + , ch, bw, offset); + + if (*ch == 0) + *ch = bss->Configuration.DSConfig; + else if (*ch != bss->Configuration.DSConfig) { + RTW_INFO("inconsistent ch - ies:%u bss->Configuration.DSConfig:%u\n" + , *ch, bss->Configuration.DSConfig); + *ch = bss->Configuration.DSConfig; + rtw_warn_on(1); + } +} + +/** + * rtw_is_chbw_grouped - test if the two ch settings can be grouped together + * @ch_a: ch of set a + * @bw_a: bw of set a + * @offset_a: offset of set a + * @ch_b: ch of set b + * @bw_b: bw of set b + * @offset_b: offset of set b + */ +bool rtw_is_chbw_grouped(u8 ch_a, u8 bw_a, u8 offset_a + , u8 ch_b, u8 bw_b, u8 offset_b) +{ + bool is_grouped = _FALSE; + + if (ch_a != ch_b) { + /* ch is different */ + goto exit; + } else if ((bw_a == CHANNEL_WIDTH_40 || bw_a == CHANNEL_WIDTH_80) + && (bw_b == CHANNEL_WIDTH_40 || bw_b == CHANNEL_WIDTH_80) + ) { + if (offset_a != offset_b) + goto exit; + } + + is_grouped = _TRUE; + +exit: + return is_grouped; +} + +/** + * rtw_sync_chbw - obey g_ch, adjust g_bw, g_offset, bw, offset + * @req_ch: pointer of the request ch, may be modified further + * @req_bw: pointer of the request bw, may be modified further + * @req_offset: pointer of the request offset, may be modified further + * @g_ch: pointer of the ongoing group ch + * @g_bw: pointer of the ongoing group bw, may be modified further + * @g_offset: pointer of the ongoing group offset, may be modified further + */ +void rtw_sync_chbw(u8 *req_ch, u8 *req_bw, u8 *req_offset + , u8 *g_ch, u8 *g_bw, u8 *g_offset) +{ + + *req_ch = *g_ch; + + if (*req_bw == CHANNEL_WIDTH_80 && *g_ch <= 14) { + /*2.4G ch, downgrade to 40Mhz */ + *req_bw = CHANNEL_WIDTH_40; + } + + switch (*req_bw) { + case CHANNEL_WIDTH_80: + if (*g_bw == CHANNEL_WIDTH_40 || *g_bw == CHANNEL_WIDTH_80) + *req_offset = *g_offset; + else if (*g_bw == CHANNEL_WIDTH_20) + *req_offset = rtw_get_offset_by_ch(*req_ch); + + if (*req_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) { + RTW_ERR("%s req 80MHz BW without offset, down to 20MHz\n", __func__); + rtw_warn_on(1); + *req_bw = CHANNEL_WIDTH_20; + } + break; + case CHANNEL_WIDTH_40: + if (*g_bw == CHANNEL_WIDTH_40 || *g_bw == CHANNEL_WIDTH_80) + *req_offset = *g_offset; + else if (*g_bw == CHANNEL_WIDTH_20) + *req_offset = rtw_get_offset_by_ch(*req_ch); + + if (*req_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) { + RTW_ERR("%s req 40MHz BW without offset, down to 20MHz\n", __func__); + rtw_warn_on(1); + *req_bw = CHANNEL_WIDTH_20; + } + break; + case CHANNEL_WIDTH_20: + *req_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + break; + default: + RTW_ERR("%s req unsupported BW:%u\n", __func__, *req_bw); + rtw_warn_on(1); + } + + if (*req_bw > *g_bw) { + *g_bw = *req_bw; + *g_offset = *req_offset; + } +} + +/** + * rtw_get_p2p_merged_len - Get merged ie length from muitiple p2p ies. + * @in_ie: Pointer of the first p2p ie + * @in_len: Total len of muiltiple p2p ies + * Returns: Length of merged p2p ie length + */ +u32 rtw_get_p2p_merged_ies_len(u8 *in_ie, u32 in_len) +{ + PNDIS_802_11_VARIABLE_IEs pIE; + u8 OUI[4] = { 0x50, 0x6f, 0x9a, 0x09 }; + int i = 0; + int j = 0, len = 0; + + while (i < in_len) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(in_ie + i); + + if (pIE->ElementID == _VENDOR_SPECIFIC_IE_ && _rtw_memcmp(pIE->data, OUI, 4)) { + len += pIE->Length - 4; /* 4 is P2P OUI length, don't count it in this loop */ + } + + i += (pIE->Length + 2); + } + + return len + 4; /* Append P2P OUI length at last. */ +} + +/** + * rtw_p2p_merge_ies - Merge muitiple p2p ies into one + * @in_ie: Pointer of the first p2p ie + * @in_len: Total len of muiltiple p2p ies + * @merge_ie: Pointer of merged ie + * Returns: Length of merged p2p ie + */ +int rtw_p2p_merge_ies(u8 *in_ie, u32 in_len, u8 *merge_ie) +{ + PNDIS_802_11_VARIABLE_IEs pIE; + u8 len = 0; + u8 OUI[4] = { 0x50, 0x6f, 0x9a, 0x09 }; + u8 ELOUI[6] = { 0xDD, 0x00, 0x50, 0x6f, 0x9a, 0x09 }; /* EID;Len;OUI, Len would copy at the end of function */ + int i = 0; + + if (merge_ie != NULL) { + /* Set first P2P OUI */ + _rtw_memcpy(merge_ie, ELOUI, 6); + merge_ie += 6; + + while (i < in_len) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(in_ie + i); + + /* Take out the rest of P2P OUIs */ + if (pIE->ElementID == _VENDOR_SPECIFIC_IE_ && _rtw_memcmp(pIE->data, OUI, 4)) { + _rtw_memcpy(merge_ie, pIE->data + 4, pIE->Length - 4); + len += pIE->Length - 4; + merge_ie += pIE->Length - 4; + } + + i += (pIE->Length + 2); + } + + return len + 4; /* 4 is for P2P OUI */ + + } + + return 0; +} + +void dump_p2p_ie(void *sel, u8 *ie, u32 ie_len) +{ + u8 *pos = (u8 *)ie; + u8 id; + u16 len; + + u8 *p2p_ie; + uint p2p_ielen; + + p2p_ie = rtw_get_p2p_ie(ie, ie_len, NULL, &p2p_ielen); + if (p2p_ie != ie || p2p_ielen == 0) + return; + + pos += 6; + while (pos - ie + 3 <= ie_len) { + id = *pos; + len = RTW_GET_LE16(pos + 1); + + RTW_PRINT_SEL(sel, "%s ID:%u, LEN:%u%s\n", __func__, id, len + , ((pos - ie + 3 + len) <= ie_len) ? "" : "(exceed ie_len)"); + + pos += (3 + len); + } +} + +/** + * rtw_get_p2p_ie - Search P2P IE from a series of IEs + * @in_ie: Address of IEs to search + * @in_len: Length limit from in_ie + * @p2p_ie: If not NULL and P2P IE is found, P2P IE will be copied to the buf starting from p2p_ie + * @p2p_ielen: If not NULL and P2P IE is found, will set to the length of the entire P2P IE + * + * Returns: The address of the P2P IE found, or NULL + */ +u8 *rtw_get_p2p_ie(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen) +{ + uint cnt; + u8 *p2p_ie_ptr = NULL; + u8 eid, p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09}; + + if (p2p_ielen) + *p2p_ielen = 0; + + if (!in_ie || in_len < 0) { + rtw_warn_on(1); + return p2p_ie_ptr; + } + + if (in_len <= 0) + return p2p_ie_ptr; + + cnt = 0; + + while (cnt + 1 + 4 < in_len) { + eid = in_ie[cnt]; + + if (cnt + 1 + 4 >= MAX_IE_SZ) { + rtw_warn_on(1); + return NULL; + } + + if (eid == WLAN_EID_VENDOR_SPECIFIC && _rtw_memcmp(&in_ie[cnt + 2], p2p_oui, 4) == _TRUE) { + p2p_ie_ptr = in_ie + cnt; + + if (p2p_ie) + _rtw_memcpy(p2p_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); + + if (p2p_ielen) + *p2p_ielen = in_ie[cnt + 1] + 2; + + break; + } else + cnt += in_ie[cnt + 1] + 2; + + } + + return p2p_ie_ptr; +} + +/** + * rtw_get_p2p_attr - Search a specific P2P attribute from a given P2P IE + * @p2p_ie: Address of P2P IE to search + * @p2p_ielen: Length limit from p2p_ie + * @target_attr_id: The attribute ID of P2P attribute to search + * @buf_attr: If not NULL and the P2P attribute is found, P2P attribute will be copied to the buf starting from buf_attr + * @len_attr: If not NULL and the P2P attribute is found, will set to the length of the entire P2P attribute + * + * Returns: the address of the specific WPS attribute found, or NULL + */ +u8 *rtw_get_p2p_attr(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id , u8 *buf_attr, u32 *len_attr) +{ + u8 *attr_ptr = NULL; + u8 *target_attr_ptr = NULL; + u8 p2p_oui[4] = {0x50, 0x6F, 0x9A, 0x09}; + + if (len_attr) + *len_attr = 0; + + if (!p2p_ie + || p2p_ielen <= 6 + || (p2p_ie[0] != WLAN_EID_VENDOR_SPECIFIC) + || (_rtw_memcmp(p2p_ie + 2, p2p_oui, 4) != _TRUE)) + return attr_ptr; + + /* 6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type) */ + attr_ptr = p2p_ie + 6; /* goto first attr */ + + while ((attr_ptr - p2p_ie + 3) <= p2p_ielen) { + /* 3 = 1(Attribute ID) + 2(Length) */ + u8 attr_id = *attr_ptr; + u16 attr_data_len = RTW_GET_LE16(attr_ptr + 1); + u16 attr_len = attr_data_len + 3; + + if (0) + RTW_INFO("%s attr_ptr:%p, id:%u, length:%u\n", __func__, attr_ptr, attr_id, attr_data_len); + + if ((attr_ptr - p2p_ie + attr_len) > p2p_ielen) + break; + + if (attr_id == target_attr_id) { + target_attr_ptr = attr_ptr; + + if (buf_attr) + _rtw_memcpy(buf_attr, attr_ptr, attr_len); + + if (len_attr) + *len_attr = attr_len; + + break; + } else + attr_ptr += attr_len; + } + + return target_attr_ptr; +} + +/** + * rtw_get_p2p_attr_content - Search a specific P2P attribute content from a given P2P IE + * @p2p_ie: Address of P2P IE to search + * @p2p_ielen: Length limit from p2p_ie + * @target_attr_id: The attribute ID of P2P attribute to search + * @buf_content: If not NULL and the P2P attribute is found, P2P attribute content will be copied to the buf starting from buf_content + * @len_content: If not NULL and the P2P attribute is found, will set to the length of the P2P attribute content + * + * Returns: the address of the specific P2P attribute content found, or NULL + */ +u8 *rtw_get_p2p_attr_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id , u8 *buf_content, uint *len_content) +{ + u8 *attr_ptr; + u32 attr_len; + + if (len_content) + *len_content = 0; + + attr_ptr = rtw_get_p2p_attr(p2p_ie, p2p_ielen, target_attr_id, NULL, &attr_len); + + if (attr_ptr && attr_len) { + if (buf_content) + _rtw_memcpy(buf_content, attr_ptr + 3, attr_len - 3); + + if (len_content) + *len_content = attr_len - 3; + + return attr_ptr + 3; + } + + return NULL; +} + +u32 rtw_set_p2p_attr_content(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr) +{ + u32 a_len; + + *pbuf = attr_id; + + /* *(u16*)(pbuf + 1) = cpu_to_le16(attr_len); */ + RTW_PUT_LE16(pbuf + 1, attr_len); + + if (pdata_attr) + _rtw_memcpy(pbuf + 3, pdata_attr, attr_len); + + a_len = attr_len + 3; + + return a_len; +} + +uint rtw_del_p2p_ie(u8 *ies, uint ies_len_ori, const char *msg) +{ +#define DBG_DEL_P2P_IE 0 + + u8 *target_ie; + u32 target_ie_len; + uint ies_len = ies_len_ori; + int index = 0; + + while (1) { + target_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &target_ie_len); + if (target_ie && target_ie_len) { + u8 *next_ie = target_ie + target_ie_len; + uint remain_len = ies_len - (next_ie - ies); + + if (DBG_DEL_P2P_IE && msg) { + RTW_INFO("%s %d before\n", __func__, index); + dump_ies(RTW_DBGDUMP, ies, ies_len); + + RTW_INFO("ies:%p, ies_len:%u\n", ies, ies_len); + RTW_INFO("target_ie:%p, target_ie_len:%u\n", target_ie, target_ie_len); + RTW_INFO("next_ie:%p, remain_len:%u\n", next_ie, remain_len); + } + + _rtw_memmove(target_ie, next_ie, remain_len); + _rtw_memset(target_ie + remain_len, 0, target_ie_len); + ies_len -= target_ie_len; + + if (DBG_DEL_P2P_IE && msg) { + RTW_INFO("%s %d after\n", __func__, index); + dump_ies(RTW_DBGDUMP, ies, ies_len); + } + + index++; + } else + break; + } + + return ies_len; +} + +uint rtw_del_p2p_attr(u8 *ie, uint ielen_ori, u8 attr_id) +{ +#define DBG_DEL_P2P_ATTR 0 + + u8 *target_attr; + u32 target_attr_len; + uint ielen = ielen_ori; + int index = 0; + + while (1) { + target_attr = rtw_get_p2p_attr(ie, ielen, attr_id, NULL, &target_attr_len); + if (target_attr && target_attr_len) { + u8 *next_attr = target_attr + target_attr_len; + uint remain_len = ielen - (next_attr - ie); + + if (DBG_DEL_P2P_ATTR) { + RTW_INFO("%s %d before\n", __func__, index); + dump_ies(RTW_DBGDUMP, ie, ielen); + + RTW_INFO("ie:%p, ielen:%u\n", ie, ielen); + RTW_INFO("target_attr:%p, target_attr_len:%u\n", target_attr, target_attr_len); + RTW_INFO("next_attr:%p, remain_len:%u\n", next_attr, remain_len); + } + + _rtw_memmove(target_attr, next_attr, remain_len); + _rtw_memset(target_attr + remain_len, 0, target_attr_len); + *(ie + 1) -= target_attr_len; + ielen -= target_attr_len; + + if (DBG_DEL_P2P_ATTR) { + RTW_INFO("%s %d after\n", __func__, index); + dump_ies(RTW_DBGDUMP, ie, ielen); + } + + index++; + } else + break; + } + + return ielen; +} + +inline u8 *rtw_bss_ex_get_p2p_ie(WLAN_BSSID_EX *bss_ex, u8 *p2p_ie, uint *p2p_ielen) +{ + return rtw_get_p2p_ie(BSS_EX_TLV_IES(bss_ex), BSS_EX_TLV_IES_LEN(bss_ex), p2p_ie, p2p_ielen); +} + +void rtw_bss_ex_del_p2p_ie(WLAN_BSSID_EX *bss_ex) +{ +#define DBG_BSS_EX_DEL_P2P_IE 0 + + u8 *ies = BSS_EX_TLV_IES(bss_ex); + uint ies_len_ori = BSS_EX_TLV_IES_LEN(bss_ex); + uint ies_len; + + ies_len = rtw_del_p2p_ie(ies, ies_len_ori, DBG_BSS_EX_DEL_P2P_IE ? __func__ : NULL); + bss_ex->IELength -= ies_len_ori - ies_len; +} + +void rtw_bss_ex_del_p2p_attr(WLAN_BSSID_EX *bss_ex, u8 attr_id) +{ +#define DBG_BSS_EX_DEL_P2P_ATTR 0 + + u8 *ies = BSS_EX_TLV_IES(bss_ex); + uint ies_len = BSS_EX_TLV_IES_LEN(bss_ex); + + u8 *ie; + uint ie_len, ie_len_ori; + + int index = 0; + + while (1) { + ie = rtw_get_p2p_ie(ies, ies_len, NULL, &ie_len_ori); + if (ie) { + u8 *next_ie_ori = ie + ie_len_ori; + uint remain_len = bss_ex->IELength - (next_ie_ori - bss_ex->IEs); + u8 has_target_attr = 0; + + if (DBG_BSS_EX_DEL_P2P_ATTR) { + if (rtw_get_p2p_attr(ie, ie_len_ori, attr_id, NULL, NULL)) { + RTW_INFO("%s %d before\n", __func__, index); + dump_ies(RTW_DBGDUMP, BSS_EX_TLV_IES(bss_ex), BSS_EX_TLV_IES_LEN(bss_ex)); + + RTW_INFO("ies:%p, ies_len:%u\n", ies, ies_len); + RTW_INFO("ie:%p, ie_len_ori:%u\n", ie, ie_len_ori); + RTW_INFO("next_ie_ori:%p, remain_len:%u\n", next_ie_ori, remain_len); + has_target_attr = 1; + } + } + + ie_len = rtw_del_p2p_attr(ie, ie_len_ori, attr_id); + if (ie_len != ie_len_ori) { + u8 *next_ie = ie + ie_len; + + _rtw_memmove(next_ie, next_ie_ori, remain_len); + _rtw_memset(next_ie + remain_len, 0, ie_len_ori - ie_len); + bss_ex->IELength -= ie_len_ori - ie_len; + + ies = next_ie; + } else + ies = next_ie_ori; + + if (DBG_BSS_EX_DEL_P2P_ATTR) { + if (has_target_attr) { + RTW_INFO("%s %d after\n", __func__, index); + dump_ies(RTW_DBGDUMP, BSS_EX_TLV_IES(bss_ex), BSS_EX_TLV_IES_LEN(bss_ex)); + } + } + + ies_len = remain_len; + + index++; + } else + break; + } +} + +void dump_wfd_ie(void *sel, u8 *ie, u32 ie_len) +{ + u8 *pos = (u8 *)ie; + u8 id; + u16 len; + + u8 *wfd_ie; + uint wfd_ielen; + + wfd_ie = rtw_get_wfd_ie(ie, ie_len, NULL, &wfd_ielen); + if (wfd_ie != ie || wfd_ielen == 0) + return; + + pos += 6; + while (pos - ie + 3 <= ie_len) { + id = *pos; + len = RTW_GET_BE16(pos + 1); + + RTW_PRINT_SEL(sel, "%s ID:%u, LEN:%u%s\n", __func__, id, len + , ((pos - ie + 3 + len) <= ie_len) ? "" : "(exceed ie_len)"); + + pos += (3 + len); + } +} + +/** + * rtw_get_wfd_ie - Search WFD IE from a series of IEs + * @in_ie: Address of IEs to search + * @in_len: Length limit from in_ie + * @wfd_ie: If not NULL and WFD IE is found, WFD IE will be copied to the buf starting from wfd_ie + * @wfd_ielen: If not NULL and WFD IE is found, will set to the length of the entire WFD IE + * + * Returns: The address of the P2P IE found, or NULL + */ +u8 *rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen) +{ + uint cnt; + u8 *wfd_ie_ptr = NULL; + u8 eid, wfd_oui[4] = {0x50, 0x6F, 0x9A, 0x0A}; + + if (wfd_ielen) + *wfd_ielen = 0; + + if (!in_ie || in_len < 0) { + rtw_warn_on(1); + return wfd_ie_ptr; + } + + if (in_len <= 0) + return wfd_ie_ptr; + + cnt = 0; + + while (cnt + 1 + 4 < in_len) { + eid = in_ie[cnt]; + + if (cnt + 1 + 4 >= MAX_IE_SZ) { + rtw_warn_on(1); + return NULL; + } + + if (eid == WLAN_EID_VENDOR_SPECIFIC && _rtw_memcmp(&in_ie[cnt + 2], wfd_oui, 4) == _TRUE) { + wfd_ie_ptr = in_ie + cnt; + + if (wfd_ie) + _rtw_memcpy(wfd_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); + + if (wfd_ielen) + *wfd_ielen = in_ie[cnt + 1] + 2; + + break; + } else + cnt += in_ie[cnt + 1] + 2; + + } + + return wfd_ie_ptr; +} + +/** + * rtw_get_wfd_attr - Search a specific WFD attribute from a given WFD IE + * @wfd_ie: Address of WFD IE to search + * @wfd_ielen: Length limit from wfd_ie + * @target_attr_id: The attribute ID of WFD attribute to search + * @buf_attr: If not NULL and the WFD attribute is found, WFD attribute will be copied to the buf starting from buf_attr + * @len_attr: If not NULL and the WFD attribute is found, will set to the length of the entire WFD attribute + * + * Returns: the address of the specific WPS attribute found, or NULL + */ +u8 *rtw_get_wfd_attr(u8 *wfd_ie, uint wfd_ielen, u8 target_attr_id, u8 *buf_attr, u32 *len_attr) +{ + u8 *attr_ptr = NULL; + u8 *target_attr_ptr = NULL; + u8 wfd_oui[4] = {0x50, 0x6F, 0x9A, 0x0A}; + + if (len_attr) + *len_attr = 0; + + if (!wfd_ie + || wfd_ielen <= 6 + || (wfd_ie[0] != WLAN_EID_VENDOR_SPECIFIC) + || (_rtw_memcmp(wfd_ie + 2, wfd_oui, 4) != _TRUE)) + return attr_ptr; + + /* 6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type) */ + attr_ptr = wfd_ie + 6; /* goto first attr */ + + while ((attr_ptr - wfd_ie + 3) <= wfd_ielen) { + /* 3 = 1(Attribute ID) + 2(Length) */ + u8 attr_id = *attr_ptr; + u16 attr_data_len = RTW_GET_BE16(attr_ptr + 1); + u16 attr_len = attr_data_len + 3; + + if (0) + RTW_INFO("%s attr_ptr:%p, id:%u, length:%u\n", __func__, attr_ptr, attr_id, attr_data_len); + + if ((attr_ptr - wfd_ie + attr_len) > wfd_ielen) + break; + + if (attr_id == target_attr_id) { + target_attr_ptr = attr_ptr; + + if (buf_attr) + _rtw_memcpy(buf_attr, attr_ptr, attr_len); + + if (len_attr) + *len_attr = attr_len; + + break; + } else + attr_ptr += attr_len; + } + + return target_attr_ptr; +} + +/** + * rtw_get_wfd_attr_content - Search a specific WFD attribute content from a given WFD IE + * @wfd_ie: Address of WFD IE to search + * @wfd_ielen: Length limit from wfd_ie + * @target_attr_id: The attribute ID of WFD attribute to search + * @buf_content: If not NULL and the WFD attribute is found, WFD attribute content will be copied to the buf starting from buf_content + * @len_content: If not NULL and the WFD attribute is found, will set to the length of the WFD attribute content + * + * Returns: the address of the specific WFD attribute content found, or NULL + */ +u8 *rtw_get_wfd_attr_content(u8 *wfd_ie, uint wfd_ielen, u8 target_attr_id, u8 *buf_content, uint *len_content) +{ + u8 *attr_ptr; + u32 attr_len; + + if (len_content) + *len_content = 0; + + attr_ptr = rtw_get_wfd_attr(wfd_ie, wfd_ielen, target_attr_id, NULL, &attr_len); + + if (attr_ptr && attr_len) { + if (buf_content) + _rtw_memcpy(buf_content, attr_ptr + 3, attr_len - 3); + + if (len_content) + *len_content = attr_len - 3; + + return attr_ptr + 3; + } + + return NULL; +} + +uint rtw_del_wfd_ie(u8 *ies, uint ies_len_ori, const char *msg) +{ +#define DBG_DEL_WFD_IE 0 + + u8 *target_ie; + u32 target_ie_len; + uint ies_len = ies_len_ori; + int index = 0; + + while (1) { + target_ie = rtw_get_wfd_ie(ies, ies_len, NULL, &target_ie_len); + if (target_ie && target_ie_len) { + u8 *next_ie = target_ie + target_ie_len; + uint remain_len = ies_len - (next_ie - ies); + + if (DBG_DEL_WFD_IE && msg) { + RTW_INFO("%s %d before\n", __func__, index); + dump_ies(RTW_DBGDUMP, ies, ies_len); + + RTW_INFO("ies:%p, ies_len:%u\n", ies, ies_len); + RTW_INFO("target_ie:%p, target_ie_len:%u\n", target_ie, target_ie_len); + RTW_INFO("next_ie:%p, remain_len:%u\n", next_ie, remain_len); + } + + _rtw_memmove(target_ie, next_ie, remain_len); + _rtw_memset(target_ie + remain_len, 0, target_ie_len); + ies_len -= target_ie_len; + + if (DBG_DEL_WFD_IE && msg) { + RTW_INFO("%s %d after\n", __func__, index); + dump_ies(RTW_DBGDUMP, ies, ies_len); + } + + index++; + } else + break; + } + + return ies_len; +} + +uint rtw_del_wfd_attr(u8 *ie, uint ielen_ori, u8 attr_id) +{ +#define DBG_DEL_WFD_ATTR 0 + + u8 *target_attr; + u32 target_attr_len; + uint ielen = ielen_ori; + int index = 0; + + while (1) { + target_attr = rtw_get_wfd_attr(ie, ielen, attr_id, NULL, &target_attr_len); + if (target_attr && target_attr_len) { + u8 *next_attr = target_attr + target_attr_len; + uint remain_len = ielen - (next_attr - ie); + + if (DBG_DEL_WFD_ATTR) { + RTW_INFO("%s %d before\n", __func__, index); + dump_ies(RTW_DBGDUMP, ie, ielen); + + RTW_INFO("ie:%p, ielen:%u\n", ie, ielen); + RTW_INFO("target_attr:%p, target_attr_len:%u\n", target_attr, target_attr_len); + RTW_INFO("next_attr:%p, remain_len:%u\n", next_attr, remain_len); + } + + _rtw_memmove(target_attr, next_attr, remain_len); + _rtw_memset(target_attr + remain_len, 0, target_attr_len); + *(ie + 1) -= target_attr_len; + ielen -= target_attr_len; + + if (DBG_DEL_WFD_ATTR) { + RTW_INFO("%s %d after\n", __func__, index); + dump_ies(RTW_DBGDUMP, ie, ielen); + } + + index++; + } else + break; + } + + return ielen; +} + +inline u8 *rtw_bss_ex_get_wfd_ie(WLAN_BSSID_EX *bss_ex, u8 *wfd_ie, uint *wfd_ielen) +{ + return rtw_get_wfd_ie(BSS_EX_TLV_IES(bss_ex), BSS_EX_TLV_IES_LEN(bss_ex), wfd_ie, wfd_ielen); +} + +void rtw_bss_ex_del_wfd_ie(WLAN_BSSID_EX *bss_ex) +{ +#define DBG_BSS_EX_DEL_WFD_IE 0 + u8 *ies = BSS_EX_TLV_IES(bss_ex); + uint ies_len_ori = BSS_EX_TLV_IES_LEN(bss_ex); + uint ies_len; + + ies_len = rtw_del_wfd_ie(ies, ies_len_ori, DBG_BSS_EX_DEL_WFD_IE ? __func__ : NULL); + bss_ex->IELength -= ies_len_ori - ies_len; +} + +void rtw_bss_ex_del_wfd_attr(WLAN_BSSID_EX *bss_ex, u8 attr_id) +{ +#define DBG_BSS_EX_DEL_WFD_ATTR 0 + + u8 *ies = BSS_EX_TLV_IES(bss_ex); + uint ies_len = BSS_EX_TLV_IES_LEN(bss_ex); + + u8 *ie; + uint ie_len, ie_len_ori; + + int index = 0; + + while (1) { + ie = rtw_get_wfd_ie(ies, ies_len, NULL, &ie_len_ori); + if (ie) { + u8 *next_ie_ori = ie + ie_len_ori; + uint remain_len = bss_ex->IELength - (next_ie_ori - bss_ex->IEs); + u8 has_target_attr = 0; + + if (DBG_BSS_EX_DEL_WFD_ATTR) { + if (rtw_get_wfd_attr(ie, ie_len_ori, attr_id, NULL, NULL)) { + RTW_INFO("%s %d before\n", __func__, index); + dump_ies(RTW_DBGDUMP, BSS_EX_TLV_IES(bss_ex), BSS_EX_TLV_IES_LEN(bss_ex)); + + RTW_INFO("ies:%p, ies_len:%u\n", ies, ies_len); + RTW_INFO("ie:%p, ie_len_ori:%u\n", ie, ie_len_ori); + RTW_INFO("next_ie_ori:%p, remain_len:%u\n", next_ie_ori, remain_len); + has_target_attr = 1; + } + } + + ie_len = rtw_del_wfd_attr(ie, ie_len_ori, attr_id); + if (ie_len != ie_len_ori) { + u8 *next_ie = ie + ie_len; + + _rtw_memmove(next_ie, next_ie_ori, remain_len); + _rtw_memset(next_ie + remain_len, 0, ie_len_ori - ie_len); + bss_ex->IELength -= ie_len_ori - ie_len; + + ies = next_ie; + } else + ies = next_ie_ori; + + if (DBG_BSS_EX_DEL_WFD_ATTR) { + if (has_target_attr) { + RTW_INFO("%s %d after\n", __func__, index); + dump_ies(RTW_DBGDUMP, BSS_EX_TLV_IES(bss_ex), BSS_EX_TLV_IES_LEN(bss_ex)); + } + } + + ies_len = remain_len; + + index++; + } else + break; + } +} + +/* Baron adds to avoid FreeBSD warning */ +int ieee80211_is_empty_essid(const char *essid, int essid_len) +{ + /* Single white space is for Linksys APs */ + if (essid_len == 1 && essid[0] == ' ') + return 1; + + /* Otherwise, if the entire essid is 0, we assume it is hidden */ + while (essid_len) { + essid_len--; + if (essid[essid_len] != '\0') + return 0; + } + + return 1; +} + +int ieee80211_get_hdrlen(u16 fc) +{ + int hdrlen = 24; + + switch (WLAN_FC_GET_TYPE(fc)) { + case RTW_IEEE80211_FTYPE_DATA: + if (fc & RTW_IEEE80211_STYPE_QOS_DATA) + hdrlen += 2; + if ((fc & RTW_IEEE80211_FCTL_FROMDS) && (fc & RTW_IEEE80211_FCTL_TODS)) + hdrlen += 6; /* Addr4 */ + break; + case RTW_IEEE80211_FTYPE_CTL: + switch (WLAN_FC_GET_STYPE(fc)) { + case RTW_IEEE80211_STYPE_CTS: + case RTW_IEEE80211_STYPE_ACK: + hdrlen = 10; + break; + default: + hdrlen = 16; + break; + } + break; + } + + return hdrlen; +} + +int rtw_get_cipher_info(struct wlan_network *pnetwork) +{ + u32 wpa_ielen; + unsigned char *pbuf; + int group_cipher = 0, pairwise_cipher = 0, is8021x = 0; + int ret = _FAIL; + pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12); + + if (pbuf && (wpa_ielen > 0)) { + if (_SUCCESS == rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x)) { + + pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; + pnetwork->BcnInfo.group_cipher = group_cipher; + pnetwork->BcnInfo.is_8021x = is8021x; + ret = _SUCCESS; + } + } else { + + pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12); + + if (pbuf && (wpa_ielen > 0)) { + if (_SUCCESS == rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is8021x)) { + pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher; + pnetwork->BcnInfo.group_cipher = group_cipher; + pnetwork->BcnInfo.is_8021x = is8021x; + ret = _SUCCESS; + } + } + } + + return ret; +} + +void rtw_get_bcn_info(struct wlan_network *pnetwork) +{ + unsigned short cap = 0; + u8 bencrypt = 0; + /* u8 wpa_ie[255],rsn_ie[255]; */ + u16 wpa_len = 0, rsn_len = 0; + struct HT_info_element *pht_info = NULL; + struct rtw_ieee80211_ht_cap *pht_cap = NULL; + unsigned int len; + unsigned char *p; + + _rtw_memcpy((u8 *)&cap, rtw_get_capability_from_ie(pnetwork->network.IEs), 2); + cap = le16_to_cpu(cap); + if (cap & WLAN_CAPABILITY_PRIVACY) { + bencrypt = 1; + pnetwork->network.Privacy = 1; + } else + pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS; + rtw_get_sec_ie(pnetwork->network.IEs , pnetwork->network.IELength, NULL, &rsn_len, NULL, &wpa_len); + + if (rsn_len > 0) + pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2; + else if (wpa_len > 0) + pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA; + else { + if (bencrypt) + pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP; + } + rtw_get_cipher_info(pnetwork); + + /* get bwmode and ch_offset */ + /* parsing HT_CAP_IE */ + p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_); + if (p && len > 0) { + pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2); + pnetwork->BcnInfo.ht_cap_info = pht_cap->cap_info; + } else + pnetwork->BcnInfo.ht_cap_info = 0; + /* parsing HT_INFO_IE */ + p = rtw_get_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, pnetwork->network.IELength - _FIXED_IE_LENGTH_); + if (p && len > 0) { + pht_info = (struct HT_info_element *)(p + 2); + pnetwork->BcnInfo.ht_info_infos_0 = pht_info->infos[0]; + } else + pnetwork->BcnInfo.ht_info_infos_0 = 0; +} + +u8 rtw_ht_mcsset_to_nss(u8 *supp_mcs_set) +{ + u8 nss = 1; + + if (supp_mcs_set[3]) + nss = 4; + else if (supp_mcs_set[2]) + nss = 3; + else if (supp_mcs_set[1]) + nss = 2; + else if (supp_mcs_set[0]) + nss = 1; + else + RTW_INFO("%s,%d, warning! supp_mcs_set is zero\n", __func__, __LINE__); + /* RTW_INFO("%s HT: %dSS\n", __FUNCTION__, nss); */ + return nss; +} + +u32 rtw_ht_mcs_set_to_bitmap(u8 *mcs_set, u8 nss) +{ + u8 i; + u32 bitmap = 0; + + for (i = 0; i < nss; i++) + bitmap |= mcs_set[i] << (i * 8); + + RTW_INFO("ht_mcs_set=%02x %02x %02x %02x, nss=%u, bitmap=%08x\n" + , mcs_set[0], mcs_set[1], mcs_set[2], mcs_set[3], nss, bitmap); + + return bitmap; +} + +/* show MCS rate, unit: 100Kbps */ +u16 rtw_mcs_rate(u8 rf_type, u8 bw_40MHz, u8 short_GI, unsigned char *MCS_rate) +{ + u16 max_rate = 0; + + if (MCS_rate[3]) { + if (MCS_rate[3] & BIT(7)) + max_rate = (bw_40MHz) ? ((short_GI) ? 6000 : 5400) : ((short_GI) ? 2889 : 2600); + else if (MCS_rate[3] & BIT(6)) + max_rate = (bw_40MHz) ? ((short_GI) ? 5400 : 4860) : ((short_GI) ? 2600 : 2340); + else if (MCS_rate[3] & BIT(5)) + max_rate = (bw_40MHz) ? ((short_GI) ? 4800 : 4320) : ((short_GI) ? 2311 : 2080); + else if (MCS_rate[3] & BIT(4)) + max_rate = (bw_40MHz) ? ((short_GI) ? 3600 : 3240) : ((short_GI) ? 1733 : 1560); + else if (MCS_rate[3] & BIT(3)) + max_rate = (bw_40MHz) ? ((short_GI) ? 2400 : 2160) : ((short_GI) ? 1156 : 1040); + else if (MCS_rate[3] & BIT(2)) + max_rate = (bw_40MHz) ? ((short_GI) ? 1800 : 1620) : ((short_GI) ? 867 : 780); + else if (MCS_rate[3] & BIT(1)) + max_rate = (bw_40MHz) ? ((short_GI) ? 1200 : 1080) : ((short_GI) ? 578 : 520); + else if (MCS_rate[3] & BIT(0)) + max_rate = (bw_40MHz) ? ((short_GI) ? 600 : 540) : ((short_GI) ? 289 : 260); + } else if (MCS_rate[2]) { + if (MCS_rate[2] & BIT(7)) + max_rate = (bw_40MHz) ? ((short_GI) ? 4500 : 4050) : ((short_GI) ? 2167 : 1950); + else if (MCS_rate[2] & BIT(6)) + max_rate = (bw_40MHz) ? ((short_GI) ? 4050 : 3645) : ((short_GI) ? 1950 : 1750); + else if (MCS_rate[2] & BIT(5)) + max_rate = (bw_40MHz) ? ((short_GI) ? 3600 : 3240) : ((short_GI) ? 1733 : 1560); + else if (MCS_rate[2] & BIT(4)) + max_rate = (bw_40MHz) ? ((short_GI) ? 2700 : 2430) : ((short_GI) ? 1300 : 1170); + else if (MCS_rate[2] & BIT(3)) + max_rate = (bw_40MHz) ? ((short_GI) ? 1800 : 1620) : ((short_GI) ? 867 : 780); + else if (MCS_rate[2] & BIT(2)) + max_rate = (bw_40MHz) ? ((short_GI) ? 1350 : 1215) : ((short_GI) ? 650 : 585); + else if (MCS_rate[2] & BIT(1)) + max_rate = (bw_40MHz) ? ((short_GI) ? 900 : 810) : ((short_GI) ? 433 : 390); + else if (MCS_rate[2] & BIT(0)) + max_rate = (bw_40MHz) ? ((short_GI) ? 450 : 405) : ((short_GI) ? 217 : 195); + } else if (MCS_rate[1]) { + if (MCS_rate[1] & BIT(7)) + max_rate = (bw_40MHz) ? ((short_GI) ? 3000 : 2700) : ((short_GI) ? 1444 : 1300); + else if (MCS_rate[1] & BIT(6)) + max_rate = (bw_40MHz) ? ((short_GI) ? 2700 : 2430) : ((short_GI) ? 1300 : 1170); + else if (MCS_rate[1] & BIT(5)) + max_rate = (bw_40MHz) ? ((short_GI) ? 2400 : 2160) : ((short_GI) ? 1156 : 1040); + else if (MCS_rate[1] & BIT(4)) + max_rate = (bw_40MHz) ? ((short_GI) ? 1800 : 1620) : ((short_GI) ? 867 : 780); + else if (MCS_rate[1] & BIT(3)) + max_rate = (bw_40MHz) ? ((short_GI) ? 1200 : 1080) : ((short_GI) ? 578 : 520); + else if (MCS_rate[1] & BIT(2)) + max_rate = (bw_40MHz) ? ((short_GI) ? 900 : 810) : ((short_GI) ? 433 : 390); + else if (MCS_rate[1] & BIT(1)) + max_rate = (bw_40MHz) ? ((short_GI) ? 600 : 540) : ((short_GI) ? 289 : 260); + else if (MCS_rate[1] & BIT(0)) + max_rate = (bw_40MHz) ? ((short_GI) ? 300 : 270) : ((short_GI) ? 144 : 130); + } else { + if (MCS_rate[0] & BIT(7)) + max_rate = (bw_40MHz) ? ((short_GI) ? 1500 : 1350) : ((short_GI) ? 722 : 650); + else if (MCS_rate[0] & BIT(6)) + max_rate = (bw_40MHz) ? ((short_GI) ? 1350 : 1215) : ((short_GI) ? 650 : 585); + else if (MCS_rate[0] & BIT(5)) + max_rate = (bw_40MHz) ? ((short_GI) ? 1200 : 1080) : ((short_GI) ? 578 : 520); + else if (MCS_rate[0] & BIT(4)) + max_rate = (bw_40MHz) ? ((short_GI) ? 900 : 810) : ((short_GI) ? 433 : 390); + else if (MCS_rate[0] & BIT(3)) + max_rate = (bw_40MHz) ? ((short_GI) ? 600 : 540) : ((short_GI) ? 289 : 260); + else if (MCS_rate[0] & BIT(2)) + max_rate = (bw_40MHz) ? ((short_GI) ? 450 : 405) : ((short_GI) ? 217 : 195); + else if (MCS_rate[0] & BIT(1)) + max_rate = (bw_40MHz) ? ((short_GI) ? 300 : 270) : ((short_GI) ? 144 : 130); + else if (MCS_rate[0] & BIT(0)) + max_rate = (bw_40MHz) ? ((short_GI) ? 150 : 135) : ((short_GI) ? 72 : 65); + } + + return max_rate; +} + +int rtw_action_frame_parse(const u8 *frame, u32 frame_len, u8 *category, u8 *action) +{ + const u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr); + u16 fc; + u8 c; + u8 a = ACT_PUBLIC_MAX; + + fc = le16_to_cpu(((struct rtw_ieee80211_hdr_3addr *)frame)->frame_ctl); + + if ((fc & (RTW_IEEE80211_FCTL_FTYPE | RTW_IEEE80211_FCTL_STYPE)) + != (RTW_IEEE80211_FTYPE_MGMT | RTW_IEEE80211_STYPE_ACTION) + ) + return _FALSE; + + c = frame_body[0]; + + switch (c) { + case RTW_WLAN_CATEGORY_P2P: /* vendor-specific */ + break; + default: + a = frame_body[1]; + } + + if (category) + *category = c; + if (action) + *action = a; + + return _TRUE; +} + +static const char *_action_public_str[] = { + "ACT_PUB_BSSCOEXIST", + "ACT_PUB_DSE_ENABLE", + "ACT_PUB_DSE_DEENABLE", + "ACT_PUB_DSE_REG_LOCATION", + "ACT_PUB_EXT_CHL_SWITCH", + "ACT_PUB_DSE_MSR_REQ", + "ACT_PUB_DSE_MSR_RPRT", + "ACT_PUB_MP", + "ACT_PUB_DSE_PWR_CONSTRAINT", + "ACT_PUB_VENDOR", + "ACT_PUB_GAS_INITIAL_REQ", + "ACT_PUB_GAS_INITIAL_RSP", + "ACT_PUB_GAS_COMEBACK_REQ", + "ACT_PUB_GAS_COMEBACK_RSP", + "ACT_PUB_TDLS_DISCOVERY_RSP", + "ACT_PUB_LOCATION_TRACK", + "ACT_PUB_RSVD", +}; + +const char *action_public_str(u8 action) +{ + action = (action >= ACT_PUBLIC_MAX) ? ACT_PUBLIC_MAX : action; + return _action_public_str[action]; +} + diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_io.c b/linux-bsp/drivers/rtl8188eus/core/rtw_io.c new file mode 100644 index 0000000..683da16 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_io.c @@ -0,0 +1,701 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +/* + +The purpose of rtw_io.c + +a. provides the API + +b. provides the protocol engine + +c. provides the software interface between caller and the hardware interface + + +Compiler Flag Option: + +1. CONFIG_SDIO_HCI: + a. USE_SYNC_IRP: Only sync operations are provided. + b. USE_ASYNC_IRP:Both sync/async operations are provided. + +2. CONFIG_USB_HCI: + a. USE_ASYNC_IRP: Both sync/async operations are provided. + +3. CONFIG_CFIO_HCI: + b. USE_SYNC_IRP: Only sync operations are provided. + + +Only sync read/rtw_write_mem operations are provided. + +jackson@realtek.com.tw + +*/ + +#define _RTW_IO_C_ + +#include <drv_types.h> +#include <hal_data.h> + +#if defined(PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) + #error "Shall be Linux or Windows, but not both!\n" +#endif + +#ifdef CONFIG_SDIO_HCI + #define rtw_le16_to_cpu(val) val + #define rtw_le32_to_cpu(val) val + #define rtw_cpu_to_le16(val) val + #define rtw_cpu_to_le32(val) val +#else + #define rtw_le16_to_cpu(val) le16_to_cpu(val) + #define rtw_le32_to_cpu(val) le32_to_cpu(val) + #define rtw_cpu_to_le16(val) cpu_to_le16(val) + #define rtw_cpu_to_le32(val) cpu_to_le32(val) +#endif + + +u8 _rtw_read8(_adapter *adapter, u32 addr) +{ + u8 r_val; + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + u8(*_read8)(struct intf_hdl *pintfhdl, u32 addr); + _read8 = pintfhdl->io_ops._read8; + + r_val = _read8(pintfhdl, addr); + return r_val; +} + +u16 _rtw_read16(_adapter *adapter, u32 addr) +{ + u16 r_val; + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + u16(*_read16)(struct intf_hdl *pintfhdl, u32 addr); + _read16 = pintfhdl->io_ops._read16; + + r_val = _read16(pintfhdl, addr); + return rtw_le16_to_cpu(r_val); +} + +u32 _rtw_read32(_adapter *adapter, u32 addr) +{ + u32 r_val; + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + u32(*_read32)(struct intf_hdl *pintfhdl, u32 addr); + _read32 = pintfhdl->io_ops._read32; + + r_val = _read32(pintfhdl, addr); + return rtw_le32_to_cpu(r_val); + +} + +int _rtw_write8(_adapter *adapter, u32 addr, u8 val) +{ + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); + int ret; + _write8 = pintfhdl->io_ops._write8; + + ret = _write8(pintfhdl, addr, val); + + return RTW_STATUS_CODE(ret); +} +int _rtw_write16(_adapter *adapter, u32 addr, u16 val) +{ + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); + int ret; + _write16 = pintfhdl->io_ops._write16; + + val = rtw_cpu_to_le16(val); + ret = _write16(pintfhdl, addr, val); + + return RTW_STATUS_CODE(ret); +} +int _rtw_write32(_adapter *adapter, u32 addr, u32 val) +{ + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); + int ret; + _write32 = pintfhdl->io_ops._write32; + + val = rtw_cpu_to_le32(val); + ret = _write32(pintfhdl, addr, val); + + return RTW_STATUS_CODE(ret); +} + +int _rtw_writeN(_adapter *adapter, u32 addr , u32 length , u8 *pdata) +{ + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = (struct intf_hdl *)(&(pio_priv->intf)); + int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata); + int ret; + _writeN = pintfhdl->io_ops._writeN; + + ret = _writeN(pintfhdl, addr, length, pdata); + + return RTW_STATUS_CODE(ret); +} + +#ifdef CONFIG_SDIO_HCI +u8 _rtw_sd_f0_read8(_adapter *adapter, u32 addr) +{ + u8 r_val = 0x00; + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + u8(*_sd_f0_read8)(struct intf_hdl *pintfhdl, u32 addr); + + _sd_f0_read8 = pintfhdl->io_ops._sd_f0_read8; + + if (_sd_f0_read8) + r_val = _sd_f0_read8(pintfhdl, addr); + else + RTW_WARN(FUNC_ADPT_FMT" _sd_f0_read8 callback is NULL\n", FUNC_ADPT_ARG(adapter)); + + return r_val; +} + +#ifdef CONFIG_SDIO_INDIRECT_ACCESS +u8 _rtw_sd_iread8(_adapter *adapter, u32 addr) +{ + u8 r_val = 0x00; + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + u8(*_sd_iread8)(struct intf_hdl *pintfhdl, u32 addr); + + _sd_iread8 = pintfhdl->io_ops._sd_iread8; + + if (_sd_iread8) + r_val = _sd_iread8(pintfhdl, addr); + else + RTW_ERR(FUNC_ADPT_FMT" _sd_iread8 callback is NULL\n", FUNC_ADPT_ARG(adapter)); + + return r_val; +} + +u16 _rtw_sd_iread16(_adapter *adapter, u32 addr) +{ + u16 r_val = 0x00; + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + u16(*_sd_iread16)(struct intf_hdl *pintfhdl, u32 addr); + + _sd_iread16 = pintfhdl->io_ops._sd_iread16; + + if (_sd_iread16) + r_val = _sd_iread16(pintfhdl, addr); + else + RTW_ERR(FUNC_ADPT_FMT" _sd_iread16 callback is NULL\n", FUNC_ADPT_ARG(adapter)); + + return r_val; +} + +u32 _rtw_sd_iread32(_adapter *adapter, u32 addr) +{ + u32 r_val = 0x00; + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + u32(*_sd_iread32)(struct intf_hdl *pintfhdl, u32 addr); + + _sd_iread32 = pintfhdl->io_ops._sd_iread32; + + if (_sd_iread32) + r_val = _sd_iread32(pintfhdl, addr); + else + RTW_ERR(FUNC_ADPT_FMT" _sd_iread32 callback is NULL\n", FUNC_ADPT_ARG(adapter)); + + return r_val; +} + +int _rtw_sd_iwrite8(_adapter *adapter, u32 addr, u8 val) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + int (*_sd_iwrite8)(struct intf_hdl *pintfhdl, u32 addr, u8 val); + int ret = -1; + + _sd_iwrite8 = pintfhdl->io_ops._sd_iwrite8; + + if (_sd_iwrite8) + ret = _sd_iwrite8(pintfhdl, addr, val); + else + RTW_ERR(FUNC_ADPT_FMT" _sd_iwrite8 callback is NULL\n", FUNC_ADPT_ARG(adapter)); + + return RTW_STATUS_CODE(ret); +} + +int _rtw_sd_iwrite16(_adapter *adapter, u32 addr, u16 val) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + int (*_sd_iwrite16)(struct intf_hdl *pintfhdl, u32 addr, u16 val); + int ret = -1; + + _sd_iwrite16 = pintfhdl->io_ops._sd_iwrite16; + + if (_sd_iwrite16) + ret = _sd_iwrite16(pintfhdl, addr, val); + else + RTW_ERR(FUNC_ADPT_FMT" _sd_iwrite16 callback is NULL\n", FUNC_ADPT_ARG(adapter)); + + return RTW_STATUS_CODE(ret); +} +int _rtw_sd_iwrite32(_adapter *adapter, u32 addr, u32 val) +{ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + int (*_sd_iwrite32)(struct intf_hdl *pintfhdl, u32 addr, u32 val); + int ret = -1; + + _sd_iwrite32 = pintfhdl->io_ops._sd_iwrite32; + + if (_sd_iwrite32) + ret = _sd_iwrite32(pintfhdl, addr, val); + else + RTW_ERR(FUNC_ADPT_FMT" _sd_iwrite32 callback is NULL\n", FUNC_ADPT_ARG(adapter)); + + return RTW_STATUS_CODE(ret); +} + +#endif /* CONFIG_SDIO_INDIRECT_ACCESS */ + +#endif /* CONFIG_SDIO_HCI */ + +int _rtw_write8_async(_adapter *adapter, u32 addr, u8 val) +{ + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val); + int ret; + _write8_async = pintfhdl->io_ops._write8_async; + + ret = _write8_async(pintfhdl, addr, val); + + return RTW_STATUS_CODE(ret); +} +int _rtw_write16_async(_adapter *adapter, u32 addr, u16 val) +{ + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val); + int ret; + _write16_async = pintfhdl->io_ops._write16_async; + val = rtw_cpu_to_le16(val); + ret = _write16_async(pintfhdl, addr, val); + + return RTW_STATUS_CODE(ret); +} +int _rtw_write32_async(_adapter *adapter, u32 addr, u32 val) +{ + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val); + int ret; + _write32_async = pintfhdl->io_ops._write32_async; + val = rtw_cpu_to_le32(val); + ret = _write32_async(pintfhdl, addr, val); + + return RTW_STATUS_CODE(ret); +} + +void _rtw_read_mem(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem) +{ + void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + + + if (RTW_CANNOT_RUN(adapter)) { + return; + } + + _read_mem = pintfhdl->io_ops._read_mem; + + _read_mem(pintfhdl, addr, cnt, pmem); + + +} + +void _rtw_write_mem(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem) +{ + void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + + + _write_mem = pintfhdl->io_ops._write_mem; + + _write_mem(pintfhdl, addr, cnt, pmem); + + +} + +void _rtw_read_port(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem) +{ + u32(*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + + + if (RTW_CANNOT_RUN(adapter)) { + return; + } + + _read_port = pintfhdl->io_ops._read_port; + + _read_port(pintfhdl, addr, cnt, pmem); + + +} + +void _rtw_read_port_cancel(_adapter *adapter) +{ + void (*_read_port_cancel)(struct intf_hdl *pintfhdl); + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + + _read_port_cancel = pintfhdl->io_ops._read_port_cancel; + + RTW_DISABLE_FUNC(adapter, DF_RX_BIT); + + if (_read_port_cancel) + _read_port_cancel(pintfhdl); +} + +u32 _rtw_write_port(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem) +{ + u32(*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); + /* struct io_queue *pio_queue = (struct io_queue *)adapter->pio_queue; */ + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + u32 ret = _SUCCESS; + + + _write_port = pintfhdl->io_ops._write_port; + + ret = _write_port(pintfhdl, addr, cnt, pmem); + + + return ret; +} + +u32 _rtw_write_port_and_wait(_adapter *adapter, u32 addr, u32 cnt, u8 *pmem, int timeout_ms) +{ + int ret = _SUCCESS; + struct xmit_buf *pxmitbuf = (struct xmit_buf *)pmem; + struct submit_ctx sctx; + + rtw_sctx_init(&sctx, timeout_ms); + pxmitbuf->sctx = &sctx; + + ret = _rtw_write_port(adapter, addr, cnt, pmem); + + if (ret == _SUCCESS) + ret = rtw_sctx_wait(&sctx, __func__); + + return ret; +} + +void _rtw_write_port_cancel(_adapter *adapter) +{ + void (*_write_port_cancel)(struct intf_hdl *pintfhdl); + struct io_priv *pio_priv = &adapter->iopriv; + struct intf_hdl *pintfhdl = &(pio_priv->intf); + + _write_port_cancel = pintfhdl->io_ops._write_port_cancel; + + RTW_DISABLE_FUNC(adapter, DF_TX_BIT); + + if (_write_port_cancel) + _write_port_cancel(pintfhdl); +} +int rtw_init_io_priv(_adapter *padapter, void (*set_intf_ops)(_adapter *padapter, struct _io_ops *pops)) +{ + struct io_priv *piopriv = &padapter->iopriv; + struct intf_hdl *pintf = &piopriv->intf; + + if (set_intf_ops == NULL) + return _FAIL; + + piopriv->padapter = padapter; + pintf->padapter = padapter; + pintf->pintf_dev = adapter_to_dvobj(padapter); + + set_intf_ops(padapter, &pintf->io_ops); + + return _SUCCESS; +} + +/* +* Increase and check if the continual_io_error of this @param dvobjprive is larger than MAX_CONTINUAL_IO_ERR +* @return _TRUE: +* @return _FALSE: +*/ +int rtw_inc_and_chk_continual_io_error(struct dvobj_priv *dvobj) +{ + int ret = _FALSE; + int value; + + value = ATOMIC_INC_RETURN(&dvobj->continual_io_error); + if (value > MAX_CONTINUAL_IO_ERR) { + RTW_INFO("[dvobj:%p][ERROR] continual_io_error:%d > %d\n", dvobj, value, MAX_CONTINUAL_IO_ERR); + ret = _TRUE; + } else { + /* RTW_INFO("[dvobj:%p] continual_io_error:%d\n", dvobj, value); */ + } + return ret; +} + +/* +* Set the continual_io_error of this @param dvobjprive to 0 +*/ +void rtw_reset_continual_io_error(struct dvobj_priv *dvobj) +{ + ATOMIC_SET(&dvobj->continual_io_error, 0); +} + +#ifdef DBG_IO + +u32 read_sniff_ranges[][2] = { + /* {0x520, 0x523}, */ +}; + +u32 write_sniff_ranges[][2] = { + /* {0x520, 0x523}, */ + /* {0x4c, 0x4c}, */ +}; + +int read_sniff_num = sizeof(read_sniff_ranges) / sizeof(u32) / 2; +int write_sniff_num = sizeof(write_sniff_ranges) / sizeof(u32) / 2; + +bool match_read_sniff_ranges(u32 addr, u16 len) +{ + int i; + for (i = 0; i < read_sniff_num; i++) { + if (addr + len > read_sniff_ranges[i][0] && addr <= read_sniff_ranges[i][1]) + return _TRUE; + } + + return _FALSE; +} + +bool match_write_sniff_ranges(u32 addr, u16 len) +{ + int i; + for (i = 0; i < write_sniff_num; i++) { + if (addr + len > write_sniff_ranges[i][0] && addr <= write_sniff_ranges[i][1]) + return _TRUE; + } + + return _FALSE; +} + +struct rf_sniff_ent { + u8 path; + u16 reg; + u32 mask; +}; + +struct rf_sniff_ent rf_read_sniff_ranges[] = { + /* example for all path addr 0x55 with all RF Reg mask */ + /* {MAX_RF_PATH, 0x55, bRFRegOffsetMask}, */ +}; + +struct rf_sniff_ent rf_write_sniff_ranges[] = { + /* example for all path addr 0x55 with all RF Reg mask */ + /* {MAX_RF_PATH, 0x55, bRFRegOffsetMask}, */ +}; + +int rf_read_sniff_num = sizeof(rf_read_sniff_ranges) / sizeof(struct rf_sniff_ent); +int rf_write_sniff_num = sizeof(rf_write_sniff_ranges) / sizeof(struct rf_sniff_ent); + +bool match_rf_read_sniff_ranges(u8 path, u32 addr, u32 mask) +{ + int i; + + for (i = 0; i < rf_read_sniff_num; i++) { + if (rf_read_sniff_ranges[i].path == MAX_RF_PATH || rf_read_sniff_ranges[i].path == path) + if (addr == rf_read_sniff_ranges[i].reg && (mask & rf_read_sniff_ranges[i].mask)) + return _TRUE; + } + + return _FALSE; +} + +bool match_rf_write_sniff_ranges(u8 path, u32 addr, u32 mask) +{ + int i; + + for (i = 0; i < rf_write_sniff_num; i++) { + if (rf_write_sniff_ranges[i].path == MAX_RF_PATH || rf_write_sniff_ranges[i].path == path) + if (addr == rf_write_sniff_ranges[i].reg && (mask & rf_write_sniff_ranges[i].mask)) + return _TRUE; + } + + return _FALSE; +} + +u8 dbg_rtw_read8(_adapter *adapter, u32 addr, const char *caller, const int line) +{ + u8 val = _rtw_read8(adapter, addr); + + if (match_read_sniff_ranges(addr, 1)) + RTW_INFO("DBG_IO %s:%d rtw_read8(0x%04x) return 0x%02x\n", caller, line, addr, val); + + return val; +} + +u16 dbg_rtw_read16(_adapter *adapter, u32 addr, const char *caller, const int line) +{ + u16 val = _rtw_read16(adapter, addr); + + if (match_read_sniff_ranges(addr, 2)) + RTW_INFO("DBG_IO %s:%d rtw_read16(0x%04x) return 0x%04x\n", caller, line, addr, val); + + return val; +} + +u32 dbg_rtw_read32(_adapter *adapter, u32 addr, const char *caller, const int line) +{ + u32 val = _rtw_read32(adapter, addr); + + if (match_read_sniff_ranges(addr, 4)) + RTW_INFO("DBG_IO %s:%d rtw_read32(0x%04x) return 0x%08x\n", caller, line, addr, val); + + return val; +} + +int dbg_rtw_write8(_adapter *adapter, u32 addr, u8 val, const char *caller, const int line) +{ + if (match_write_sniff_ranges(addr, 1)) + RTW_INFO("DBG_IO %s:%d rtw_write8(0x%04x, 0x%02x)\n", caller, line, addr, val); + + return _rtw_write8(adapter, addr, val); +} +int dbg_rtw_write16(_adapter *adapter, u32 addr, u16 val, const char *caller, const int line) +{ + if (match_write_sniff_ranges(addr, 2)) + RTW_INFO("DBG_IO %s:%d rtw_write16(0x%04x, 0x%04x)\n", caller, line, addr, val); + + return _rtw_write16(adapter, addr, val); +} +int dbg_rtw_write32(_adapter *adapter, u32 addr, u32 val, const char *caller, const int line) +{ + if (match_write_sniff_ranges(addr, 4)) + RTW_INFO("DBG_IO %s:%d rtw_write32(0x%04x, 0x%08x)\n", caller, line, addr, val); + + return _rtw_write32(adapter, addr, val); +} +int dbg_rtw_writeN(_adapter *adapter, u32 addr , u32 length , u8 *data, const char *caller, const int line) +{ + if (match_write_sniff_ranges(addr, length)) + RTW_INFO("DBG_IO %s:%d rtw_writeN(0x%04x, %u)\n", caller, line, addr, length); + + return _rtw_writeN(adapter, addr, length, data); +} + +#ifdef CONFIG_SDIO_HCI +u8 dbg_rtw_sd_f0_read8(_adapter *adapter, u32 addr, const char *caller, const int line) +{ + u8 val = _rtw_sd_f0_read8(adapter, addr); + +#if 0 + if (match_read_sniff_ranges(addr, 1)) + RTW_INFO("DBG_IO %s:%d rtw_sd_f0_read8(0x%04x) return 0x%02x\n", caller, line, addr, val); +#endif + + return val; +} + +#ifdef CONFIG_SDIO_INDIRECT_ACCESS +u8 dbg_rtw_sd_iread8(_adapter *adapter, u32 addr, const char *caller, const int line) +{ + u8 val = rtw_sd_iread8(adapter, addr); + + if (match_read_sniff_ranges(addr, 1)) + RTW_INFO("DBG_IO %s:%d rtw_sd_iread8(0x%04x) return 0x%02x\n", caller, line, addr, val); + + return val; +} + +u16 dbg_rtw_sd_iread16(_adapter *adapter, u32 addr, const char *caller, const int line) +{ + u16 val = _rtw_sd_iread16(adapter, addr); + + if (match_read_sniff_ranges(addr, 2)) + RTW_INFO("DBG_IO %s:%d rtw_sd_iread16(0x%04x) return 0x%04x\n", caller, line, addr, val); + + return val; +} + +u32 dbg_rtw_sd_iread32(_adapter *adapter, u32 addr, const char *caller, const int line) +{ + u32 val = _rtw_sd_iread32(adapter, addr); + + if (match_read_sniff_ranges(addr, 4)) + RTW_INFO("DBG_IO %s:%d rtw_sd_iread32(0x%04x) return 0x%08x\n", caller, line, addr, val); + + return val; +} + +int dbg_rtw_sd_iwrite8(_adapter *adapter, u32 addr, u8 val, const char *caller, const int line) +{ + if (match_write_sniff_ranges(addr, 1)) + RTW_INFO("DBG_IO %s:%d rtw_sd_iwrite8(0x%04x, 0x%02x)\n", caller, line, addr, val); + + return _rtw_sd_iwrite8(adapter, addr, val); +} +int dbg_rtw_sd_iwrite16(_adapter *adapter, u32 addr, u16 val, const char *caller, const int line) +{ + if (match_write_sniff_ranges(addr, 2)) + RTW_INFO("DBG_IO %s:%d rtw_sd_iwrite16(0x%04x, 0x%04x)\n", caller, line, addr, val); + + return _rtw_sd_iwrite16(adapter, addr, val); +} +int dbg_rtw_sd_iwrite32(_adapter *adapter, u32 addr, u32 val, const char *caller, const int line) +{ + if (match_write_sniff_ranges(addr, 4)) + RTW_INFO("DBG_IO %s:%d rtw_sd_iwrite32(0x%04x, 0x%08x)\n", caller, line, addr, val); + + return _rtw_sd_iwrite32(adapter, addr, val); +} + +#endif /* CONFIG_SDIO_INDIRECT_ACCESS */ + +#endif /* CONFIG_SDIO_HCI */ + +#endif diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_query.c b/linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_query.c new file mode 100644 index 0000000..4f8232d --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_query.c @@ -0,0 +1,171 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_IOCTL_QUERY_C_ + +#include <drv_types.h> + + +#ifdef PLATFORM_WINDOWS +/* + * Added for WPA2-PSK, by Annie, 2005-09-20. + * */ +u8 +query_802_11_capability( + _adapter *Adapter, + u8 *pucBuf, + u32 *pulOutLen +) +{ + static NDIS_802_11_AUTHENTICATION_ENCRYPTION szAuthEnc[] = { + {Ndis802_11AuthModeOpen, Ndis802_11EncryptionDisabled}, + {Ndis802_11AuthModeOpen, Ndis802_11Encryption1Enabled}, + {Ndis802_11AuthModeShared, Ndis802_11EncryptionDisabled}, + {Ndis802_11AuthModeShared, Ndis802_11Encryption1Enabled}, + {Ndis802_11AuthModeWPA, Ndis802_11Encryption2Enabled}, + {Ndis802_11AuthModeWPA, Ndis802_11Encryption3Enabled}, + {Ndis802_11AuthModeWPAPSK, Ndis802_11Encryption2Enabled}, + {Ndis802_11AuthModeWPAPSK, Ndis802_11Encryption3Enabled}, + {Ndis802_11AuthModeWPANone, Ndis802_11Encryption2Enabled}, + {Ndis802_11AuthModeWPANone, Ndis802_11Encryption3Enabled}, + {Ndis802_11AuthModeWPA2, Ndis802_11Encryption2Enabled}, + {Ndis802_11AuthModeWPA2, Ndis802_11Encryption3Enabled}, + {Ndis802_11AuthModeWPA2PSK, Ndis802_11Encryption2Enabled}, + {Ndis802_11AuthModeWPA2PSK, Ndis802_11Encryption3Enabled} + }; + static ULONG ulNumOfPairSupported = sizeof(szAuthEnc) / sizeof(NDIS_802_11_AUTHENTICATION_ENCRYPTION); + NDIS_802_11_CAPABILITY *pCap = (NDIS_802_11_CAPABILITY *)pucBuf; + u8 *pucAuthEncryptionSupported = (u8 *) pCap->AuthenticationEncryptionSupported; + + + pCap->Length = sizeof(NDIS_802_11_CAPABILITY); + if (ulNumOfPairSupported > 1) + pCap->Length += (ulNumOfPairSupported - 1) * sizeof(NDIS_802_11_AUTHENTICATION_ENCRYPTION); + + pCap->Version = 2; + pCap->NoOfPMKIDs = NUM_PMKID_CACHE; + pCap->NoOfAuthEncryptPairsSupported = ulNumOfPairSupported; + + if (sizeof(szAuthEnc) <= 240) /* 240 = 256 - 4*4 */ { /* SecurityInfo.szCapability: only 256 bytes in size. */ + _rtw_memcpy(pucAuthEncryptionSupported, (u8 *)szAuthEnc, sizeof(szAuthEnc)); + *pulOutLen = pCap->Length; + return _TRUE; + } else { + *pulOutLen = 0; + return _FALSE; + } +} + +u8 query_802_11_association_information(_adapter *padapter, PNDIS_802_11_ASSOCIATION_INFORMATION pAssocInfo) +{ + struct wlan_network *tgt_network; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct security_priv *psecuritypriv = &(padapter->securitypriv); + WLAN_BSSID_EX *psecnetwork = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; + u8 *pDest = (u8 *)pAssocInfo + sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); + unsigned char i, *auth_ie, *supp_ie; + + /* NdisZeroMemory(pAssocInfo, sizeof(NDIS_802_11_ASSOCIATION_INFORMATION)); */ + _rtw_memset(pAssocInfo, 0, sizeof(NDIS_802_11_ASSOCIATION_INFORMATION)); + /* pAssocInfo->Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); */ + + /* ------------------------------------------------------ */ + /* Association Request related information */ + /* ------------------------------------------------------ */ + /* Req_1. AvailableRequestFixedIEs */ + if (psecnetwork != NULL) { + + pAssocInfo->AvailableRequestFixedIEs |= NDIS_802_11_AI_REQFI_CAPABILITIES | NDIS_802_11_AI_REQFI_CURRENTAPADDRESS; + pAssocInfo->RequestFixedIEs.Capabilities = (unsigned short) *&psecnetwork->IEs[10]; + _rtw_memcpy(pAssocInfo->RequestFixedIEs.CurrentAPAddress, + &psecnetwork->MacAddress, 6); + + pAssocInfo->OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION); + + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING | _FW_LINKED) == _TRUE) { + + if (psecuritypriv->ndisauthtype >= Ndis802_11AuthModeWPA2) + pDest[0] = 48; /* RSN Information Element */ + else + pDest[0] = 221; /* WPA(SSN) Information Element */ + + supp_ie = &psecuritypriv->supplicant_ie[0]; + + i = 13; /* 0~11 is fixed information element */ + while ((i < supp_ie[0]) && (i < 256)) { + if ((unsigned char)supp_ie[i] == pDest[0]) { + _rtw_memcpy((u8 *)(pDest), + &supp_ie[i], + supp_ie[1 + i] + 2); + + break; + } + + i = i + supp_ie[i + 1] + 2; + if (supp_ie[1 + i] == 0) + i = i + 1; + + } + + + pAssocInfo->RequestIELength += (2 + supp_ie[1 + i]); /* (2 + psecnetwork->IEs[1+i]+4); */ + + } + + + + } + + + /* ------------------------------------------------------ */ + /* Association Response related information */ + /* ------------------------------------------------------ */ + + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + tgt_network = &(pmlmepriv->cur_network); + if (tgt_network != NULL) { + pAssocInfo->AvailableResponseFixedIEs = + NDIS_802_11_AI_RESFI_CAPABILITIES + | NDIS_802_11_AI_RESFI_ASSOCIATIONID + ; + + pAssocInfo->ResponseFixedIEs.Capabilities = (unsigned short) *&tgt_network->network.IEs[10]; + pAssocInfo->ResponseFixedIEs.StatusCode = 0; + pAssocInfo->ResponseFixedIEs.AssociationId = (unsigned short) tgt_network->aid; + + pDest = (u8 *)pAssocInfo + sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAssocInfo->RequestIELength; + auth_ie = &psecuritypriv->authenticator_ie[0]; + + + i = auth_ie[0] - 12; + if (i > 0) { + _rtw_memcpy((u8 *)&pDest[0], &auth_ie[1], i); + pAssocInfo->ResponseIELength = i; + } + + + pAssocInfo->OffsetResponseIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION) + pAssocInfo->RequestIELength; + + + } + } + + return _TRUE; +} +#endif diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_rtl.c b/linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_rtl.c new file mode 100644 index 0000000..ab4a387 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_rtl.c @@ -0,0 +1,904 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_IOCTL_RTL_C_ + +#include <drv_types.h> + +#ifdef CONFIG_MP_INCLUDED + #include <rtw_mp_ioctl.h> +#endif + +struct oid_obj_priv oid_rtl_seg_01_01[] = { + {1, &oid_null_function}, /* 0x80 */ + {1, &oid_null_function}, /* 0x81 */ + {1, &oid_null_function}, /* 0x82 */ + {1, &oid_null_function}, /* 0x83 */ /* OID_RT_SET_SNIFFER_MODE */ + {1, &oid_rt_get_signal_quality_hdl}, /* 0x84 */ + {1, &oid_rt_get_small_packet_crc_hdl}, /* 0x85 */ + {1, &oid_rt_get_middle_packet_crc_hdl}, /* 0x86 */ + {1, &oid_rt_get_large_packet_crc_hdl}, /* 0x87 */ + {1, &oid_rt_get_tx_retry_hdl}, /* 0x88 */ + {1, &oid_rt_get_rx_retry_hdl}, /* 0x89 */ + {1, &oid_rt_pro_set_fw_dig_state_hdl}, /* 0x8A */ + {1, &oid_rt_pro_set_fw_ra_state_hdl} , /* 0x8B */ + {1, &oid_null_function}, /* 0x8C */ + {1, &oid_null_function}, /* 0x8D */ + {1, &oid_null_function}, /* 0x8E */ + {1, &oid_null_function}, /* 0x8F */ + {1, &oid_rt_get_rx_total_packet_hdl}, /* 0x90 */ + {1, &oid_rt_get_tx_beacon_ok_hdl}, /* 0x91 */ + {1, &oid_rt_get_tx_beacon_err_hdl}, /* 0x92 */ + {1, &oid_rt_get_rx_icv_err_hdl}, /* 0x93 */ + {1, &oid_rt_set_encryption_algorithm_hdl}, /* 0x94 */ + {1, &oid_null_function}, /* 0x95 */ + {1, &oid_rt_get_preamble_mode_hdl}, /* 0x96 */ + {1, &oid_null_function}, /* 0x97 */ + {1, &oid_rt_get_ap_ip_hdl}, /* 0x98 */ + {1, &oid_rt_get_channelplan_hdl}, /* 0x99 */ + {1, &oid_rt_set_preamble_mode_hdl}, /* 0x9A */ + {1, &oid_rt_set_bcn_intvl_hdl}, /* 0x9B */ + {1, &oid_null_function}, /* 0x9C */ + {1, &oid_rt_dedicate_probe_hdl}, /* 0x9D */ + {1, &oid_null_function}, /* 0x9E */ + {1, &oid_null_function}, /* 0x9F */ + {1, &oid_null_function}, /* 0xA0 */ + {1, &oid_null_function}, /* 0xA1 */ + {1, &oid_null_function}, /* 0xA2 */ + {1, &oid_null_function}, /* 0xA3 */ + {1, &oid_null_function}, /* 0xA4 */ + {1, &oid_null_function}, /* 0xA5 */ + {1, &oid_null_function}, /* 0xA6 */ + {1, &oid_rt_get_total_tx_bytes_hdl}, /* 0xA7 */ + {1, &oid_rt_get_total_rx_bytes_hdl}, /* 0xA8 */ + {1, &oid_rt_current_tx_power_level_hdl}, /* 0xA9 */ + {1, &oid_rt_get_enc_key_mismatch_count_hdl}, /* 0xAA */ + {1, &oid_rt_get_enc_key_match_count_hdl}, /* 0xAB */ + {1, &oid_rt_get_channel_hdl}, /* 0xAC */ + {1, &oid_rt_set_channelplan_hdl}, /* 0xAD */ + {1, &oid_rt_get_hardware_radio_off_hdl}, /* 0xAE */ + {1, &oid_null_function}, /* 0xAF */ + {1, &oid_null_function}, /* 0xB0 */ + {1, &oid_null_function}, /* 0xB1 */ + {1, &oid_null_function}, /* 0xB2 */ + {1, &oid_null_function}, /* 0xB3 */ + {1, &oid_rt_get_key_mismatch_hdl}, /* 0xB4 */ + {1, &oid_null_function}, /* 0xB5 */ + {1, &oid_null_function}, /* 0xB6 */ + {1, &oid_null_function}, /* 0xB7 */ + {1, &oid_null_function}, /* 0xB8 */ + {1, &oid_null_function}, /* 0xB9 */ + {1, &oid_null_function}, /* 0xBA */ + {1, &oid_rt_supported_wireless_mode_hdl}, /* 0xBB */ + {1, &oid_rt_get_channel_list_hdl}, /* 0xBC */ + {1, &oid_rt_get_scan_in_progress_hdl}, /* 0xBD */ + {1, &oid_null_function}, /* 0xBE */ + {1, &oid_null_function}, /* 0xBF */ + {1, &oid_null_function}, /* 0xC0 */ + {1, &oid_rt_forced_data_rate_hdl}, /* 0xC1 */ + {1, &oid_rt_wireless_mode_for_scan_list_hdl}, /* 0xC2 */ + {1, &oid_rt_get_bss_wireless_mode_hdl}, /* 0xC3 */ + {1, &oid_rt_scan_with_magic_packet_hdl}, /* 0xC4 */ + {1, &oid_null_function}, /* 0xC5 */ + {1, &oid_null_function}, /* 0xC6 */ + {1, &oid_null_function}, /* 0xC7 */ + {1, &oid_null_function}, /* 0xC8 */ + {1, &oid_null_function}, /* 0xC9 */ + {1, &oid_null_function}, /* 0xCA */ + {1, &oid_null_function}, /* 0xCB */ + {1, &oid_null_function}, /* 0xCC */ + {1, &oid_null_function}, /* 0xCD */ + {1, &oid_null_function}, /* 0xCE */ + {1, &oid_null_function}, /* 0xCF */ + +}; + +struct oid_obj_priv oid_rtl_seg_01_03[] = { + {1, &oid_rt_ap_get_associated_station_list_hdl}, /* 0x00 */ + {1, &oid_null_function}, /* 0x01 */ + {1, &oid_rt_ap_switch_into_ap_mode_hdl}, /* 0x02 */ + {1, &oid_null_function}, /* 0x03 */ + {1, &oid_rt_ap_supported_hdl}, /* 0x04 */ + {1, &oid_rt_ap_set_passphrase_hdl}, /* 0x05 */ + +}; + +struct oid_obj_priv oid_rtl_seg_01_11[] = { + {1, &oid_null_function}, /* 0xC0 OID_RT_PRO_RX_FILTER */ + {1, &oid_null_function}, /* 0xC1 OID_CE_USB_WRITE_REGISTRY */ + {1, &oid_null_function}, /* 0xC2 OID_CE_USB_READ_REGISTRY */ + {1, &oid_null_function}, /* 0xC3 OID_RT_PRO_SET_INITIAL_GAIN */ + {1, &oid_null_function}, /* 0xC4 OID_RT_PRO_SET_BB_RF_STANDBY_MODE */ + {1, &oid_null_function}, /* 0xC5 OID_RT_PRO_SET_BB_RF_SHUTDOWN_MODE */ + {1, &oid_null_function}, /* 0xC6 OID_RT_PRO_SET_TX_CHARGE_PUMP */ + {1, &oid_null_function}, /* 0xC7 OID_RT_PRO_SET_RX_CHARGE_PUMP */ + {1, &oid_rt_pro_rf_write_registry_hdl}, /* 0xC8 */ + {1, &oid_rt_pro_rf_read_registry_hdl}, /* 0xC9 */ + {1, &oid_null_function} /* 0xCA OID_RT_PRO_QUERY_RF_TYPE */ + +}; + +struct oid_obj_priv oid_rtl_seg_03_00[] = { + {1, &oid_null_function}, /* 0x00 */ + {1, &oid_rt_get_connect_state_hdl}, /* 0x01 */ + {1, &oid_null_function}, /* 0x02 */ + {1, &oid_null_function}, /* 0x03 */ + {1, &oid_rt_set_default_key_id_hdl}, /* 0x04 */ + + +}; + + +/* ************** oid_rtl_seg_01_01 section start ************** */ + +NDIS_STATUS oid_rt_pro_set_fw_dig_state_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + _irqL oldirql; + + + if (poid_par_priv->type_of_oid != SET_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + _irqlevel_changed_(&oldirql, LOWER); + if (poid_par_priv->information_buf_len >= sizeof(struct setdig_parm)) { + /* DEBUG_ERR(("===> oid_rt_pro_set_fw_dig_state_hdl. type:0x%02x.\n",*((unsigned char*)poid_par_priv->information_buf ))); */ + if (!rtw_setfwdig_cmd(Adapter, *((unsigned char *)poid_par_priv->information_buf))) + status = NDIS_STATUS_NOT_ACCEPTED; + + } else + status = NDIS_STATUS_NOT_ACCEPTED; + _irqlevel_changed_(&oldirql, RAISE); +#endif + return status; +} +/* ----------------------------------------------------------------------------- */ +NDIS_STATUS oid_rt_pro_set_fw_ra_state_hdl(struct oid_par_priv *poid_par_priv) +{ + + NDIS_STATUS status = NDIS_STATUS_SUCCESS; +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + _irqL oldirql; + + if (poid_par_priv->type_of_oid != SET_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + + _irqlevel_changed_(&oldirql, LOWER); + + if (poid_par_priv->information_buf_len >= sizeof(struct setra_parm)) { + /* DEBUG_ERR(("===> oid_rt_pro_set_fw_ra_state_hdl. type:0x%02x.\n",*((unsigned char*)poid_par_priv->information_buf ))); */ + if (!rtw_setfwra_cmd(Adapter, *((unsigned char *)poid_par_priv->information_buf))) + status = NDIS_STATUS_NOT_ACCEPTED; + + } else + status = NDIS_STATUS_NOT_ACCEPTED; + _irqlevel_changed_(&oldirql, RAISE); +#endif + return status; +} +/* ----------------------------------------------------------------------------- */ +NDIS_STATUS oid_rt_get_signal_quality_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + /* DEBUG_ERR(("<**********************oid_rt_get_signal_quality_hdl\n")); */ + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + +#if 0 + if (pMgntInfo->mAssoc || pMgntInfo->mIbss) { + ulInfo = pAdapter->RxStats.SignalQuality; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else { + ulInfo = 0xffffffff; /* It stands for -1 in 4-byte integer. */ + } + break; +#endif + + return status; +} + +/* ------------------------------------------------------------------------------ */ + +NDIS_STATUS oid_rt_get_small_packet_crc_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + if (poid_par_priv->information_buf_len >= sizeof(ULONG)) { + *(ULONG *)poid_par_priv->information_buf = padapter->recvpriv.rx_smallpacket_crcerr; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_INVALID_LENGTH; + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_middle_packet_crc_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + if (poid_par_priv->information_buf_len >= sizeof(ULONG)) { + *(ULONG *)poid_par_priv->information_buf = padapter->recvpriv.rx_middlepacket_crcerr; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_INVALID_LENGTH; + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_large_packet_crc_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + if (poid_par_priv->information_buf_len >= sizeof(ULONG)) { + *(ULONG *)poid_par_priv->information_buf = padapter->recvpriv.rx_largepacket_crcerr; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_INVALID_LENGTH; + + + return status; +} + +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_tx_retry_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} +NDIS_STATUS oid_rt_get_rx_retry_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_rx_total_packet_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + if (poid_par_priv->information_buf_len >= sizeof(ULONG)) { + *(u64 *)poid_par_priv->information_buf = padapter->recvpriv.rx_pkts + padapter->recvpriv.rx_drop; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_INVALID_LENGTH; + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_tx_beacon_ok_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} +NDIS_STATUS oid_rt_get_tx_beacon_err_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_rx_icv_err_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + if (poid_par_priv->information_buf_len >= sizeof(u32)) { + /* _rtw_memcpy(*(uint *)poid_par_priv->information_buf,padapter->recvpriv.rx_icv_err,sizeof(u32)); */ + *(uint *)poid_par_priv->information_buf = padapter->recvpriv.rx_icv_err; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_INVALID_LENGTH ; + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_set_encryption_algorithm_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != SET_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_preamble_mode_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + ULONG preamblemode = 0 ; + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + if (poid_par_priv->information_buf_len >= sizeof(ULONG)) { + if (padapter->registrypriv.preamble == PREAMBLE_LONG) + preamblemode = 0; + else if (padapter->registrypriv.preamble == PREAMBLE_AUTO) + preamblemode = 1; + else if (padapter->registrypriv.preamble == PREAMBLE_SHORT) + preamblemode = 2; + + + *(ULONG *)poid_par_priv->information_buf = preamblemode ; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_INVALID_LENGTH ; + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_ap_ip_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} + +NDIS_STATUS oid_rt_get_channelplan_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + *(u16 *)poid_par_priv->information_buf = padapter->mlmepriv.ChannelPlan ; + + return status; +} +NDIS_STATUS oid_rt_set_channelplan_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != SET_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + padapter->mlmepriv.ChannelPlan = *(u16 *)poid_par_priv->information_buf ; + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_set_preamble_mode_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + ULONG preamblemode = 0; + if (poid_par_priv->type_of_oid != SET_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + if (poid_par_priv->information_buf_len >= sizeof(ULONG)) { + preamblemode = *(ULONG *)poid_par_priv->information_buf ; + if (preamblemode == 0) + padapter->registrypriv.preamble = PREAMBLE_LONG; + else if (preamblemode == 1) + padapter->registrypriv.preamble = PREAMBLE_AUTO; + else if (preamblemode == 2) + padapter->registrypriv.preamble = PREAMBLE_SHORT; + + *(ULONG *)poid_par_priv->information_buf = preamblemode ; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_INVALID_LENGTH ; + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_set_bcn_intvl_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != SET_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} +NDIS_STATUS oid_rt_dedicate_probe_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_total_tx_bytes_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + if (poid_par_priv->information_buf_len >= sizeof(ULONG)) { + *(u64 *)poid_par_priv->information_buf = padapter->xmitpriv.tx_bytes; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_INVALID_LENGTH ; + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_total_rx_bytes_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + if (poid_par_priv->information_buf_len >= sizeof(ULONG)) { + /* _rtw_memcpy(*(uint *)poid_par_priv->information_buf,padapter->recvpriv.rx_icv_err,sizeof(u32)); */ + *(u64 *)poid_par_priv->information_buf = padapter->recvpriv.rx_bytes; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_INVALID_LENGTH ; + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_current_tx_power_level_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + return status; +} +NDIS_STATUS oid_rt_get_enc_key_mismatch_count_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} +NDIS_STATUS oid_rt_get_enc_key_match_count_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} +NDIS_STATUS oid_rt_get_channel_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + NDIS_802_11_CONFIGURATION *pnic_Config; + + ULONG channelnum; + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) + pnic_Config = &pmlmepriv->cur_network.network.Configuration; + else + pnic_Config = &padapter->registrypriv.dev_network.Configuration; + + channelnum = pnic_Config->DSConfig; + *(ULONG *)poid_par_priv->information_buf = channelnum; + + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + + + return status; +} +NDIS_STATUS oid_rt_get_hardware_radio_off_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} +NDIS_STATUS oid_rt_get_key_mismatch_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} +NDIS_STATUS oid_rt_supported_wireless_mode_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + ULONG ulInfo = 0 ; + /* DEBUG_ERR(("<**********************oid_rt_supported_wireless_mode_hdl\n")); */ + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + if (poid_par_priv->information_buf_len >= sizeof(ULONG)) { + ulInfo |= 0x0100; /* WIRELESS_MODE_B */ + ulInfo |= 0x0200; /* WIRELESS_MODE_G */ + ulInfo |= 0x0400; /* WIRELESS_MODE_A */ + + *(ULONG *) poid_par_priv->information_buf = ulInfo; + /* DEBUG_ERR(("<===oid_rt_supported_wireless_mode %x\n",ulInfo)); */ + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_INVALID_LENGTH; + + return status; +} +NDIS_STATUS oid_rt_get_channel_list_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} +NDIS_STATUS oid_rt_get_scan_in_progress_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} + + +NDIS_STATUS oid_rt_forced_data_rate_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + return status; +} +NDIS_STATUS oid_rt_wireless_mode_for_scan_list_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + return status; +} +NDIS_STATUS oid_rt_get_bss_wireless_mode_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} + +NDIS_STATUS oid_rt_scan_with_magic_packet_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + return status; +} +/* ************** oid_rtl_seg_01_01 section end ************** */ + +/* ************** oid_rtl_seg_01_03 section start ************** */ +NDIS_STATUS oid_rt_ap_get_associated_station_list_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} +NDIS_STATUS oid_rt_ap_switch_into_ap_mode_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + return status; +} +NDIS_STATUS oid_rt_ap_supported_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + return status; +} +NDIS_STATUS oid_rt_ap_set_passphrase_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != SET_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} + +/* ************** oid_rtl_seg_01_03 section end ************** */ + +/* **************** oid_rtl_seg_01_11 section start **************** */ +NDIS_STATUS oid_rt_pro_rf_write_registry_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + _irqL oldirql; + /* DEBUG_ERR(("<**********************oid_rt_pro_rf_write_registry_hdl\n")); */ + if (poid_par_priv->type_of_oid != SET_OID) { /* QUERY_OID */ + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + _irqlevel_changed_(&oldirql, LOWER); + if (poid_par_priv->information_buf_len == (sizeof(unsigned long) * 3)) { + /* RegOffsetValue - The offset of RF register to write. */ + /* RegDataWidth - The data width of RF register to write. */ + /* RegDataValue - The value to write. */ + /* RegOffsetValue = *((unsigned long*)InformationBuffer); */ + /* RegDataWidth = *((unsigned long*)InformationBuffer+1); */ + /* RegDataValue = *((unsigned long*)InformationBuffer+2); */ + if (!rtw_setrfreg_cmd(Adapter, + *(unsigned char *)poid_par_priv->information_buf, + (unsigned long)(*((unsigned long *)poid_par_priv->information_buf + 2)))) + status = NDIS_STATUS_NOT_ACCEPTED; + + } else + status = NDIS_STATUS_INVALID_LENGTH; + _irqlevel_changed_(&oldirql, RAISE); + + return status; +} + +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_rf_read_registry_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + _irqL oldirql; + + /* DEBUG_ERR(("<**********************oid_rt_pro_rf_read_registry_hdl\n")); */ + if (poid_par_priv->type_of_oid != SET_OID) { /* QUERY_OID */ + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + _irqlevel_changed_(&oldirql, LOWER); + if (poid_par_priv->information_buf_len == (sizeof(unsigned long) * 3)) { + if (Adapter->mppriv.act_in_progress == _TRUE) + status = NDIS_STATUS_NOT_ACCEPTED; + else { + /* init workparam */ + Adapter->mppriv.act_in_progress = _TRUE; + Adapter->mppriv.workparam.bcompleted = _FALSE; + Adapter->mppriv.workparam.act_type = MPT_READ_RF; + Adapter->mppriv.workparam.io_offset = *(unsigned long *)poid_par_priv->information_buf; + Adapter->mppriv.workparam.io_value = 0xcccccccc; + + /* RegOffsetValue - The offset of RF register to read. */ + /* RegDataWidth - The data width of RF register to read. */ + /* RegDataValue - The value to read. */ + /* RegOffsetValue = *((unsigned long*)InformationBuffer); */ + /* RegDataWidth = *((unsigned long*)InformationBuffer+1); */ + /* RegDataValue = *((unsigned long*)InformationBuffer+2); */ + if (!rtw_getrfreg_cmd(Adapter, + *(unsigned char *)poid_par_priv->information_buf, + (unsigned char *)&Adapter->mppriv.workparam.io_value)) + status = NDIS_STATUS_NOT_ACCEPTED; + } + + + } else + status = NDIS_STATUS_INVALID_LENGTH; + _irqlevel_changed_(&oldirql, RAISE); +#endif + return status; +} + +/* **************** oid_rtl_seg_01_11 section end**************** */ + + +/* ************** oid_rtl_seg_03_00 section start ************** */ +enum _CONNECT_STATE_ { + CHECKINGSTATUS, + ASSOCIATED, + ADHOCMODE, + NOTASSOCIATED +}; + +NDIS_STATUS oid_rt_get_connect_state_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + + ULONG ulInfo; + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + /* nStatus==0 CheckingStatus */ + /* nStatus==1 Associated */ + /* nStatus==2 AdHocMode */ + /* nStatus==3 NotAssociated */ + + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) + ulInfo = CHECKINGSTATUS; + else if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + ulInfo = ASSOCIATED; + else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) + ulInfo = ADHOCMODE; + else + ulInfo = NOTASSOCIATED ; + + *(ULONG *)poid_par_priv->information_buf = ulInfo; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + +#if 0 + /* Rearrange the order to let the UI still shows connection when scan is in progress */ + if (pMgntInfo->mAssoc) + ulInfo = 1; + else if (pMgntInfo->mIbss) + ulInfo = 2; + else if (pMgntInfo->bScanInProgress) + ulInfo = 0; + else + ulInfo = 3; + ulInfoLen = sizeof(ULONG); +#endif + + return status; +} + +NDIS_STATUS oid_rt_set_default_key_id_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + if (poid_par_priv->type_of_oid != SET_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + return status; +} +/* ************** oid_rtl_seg_03_00 section end ************** */ diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_set.c b/linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_set.c new file mode 100644 index 0000000..45bb5e4 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_ioctl_set.c @@ -0,0 +1,1254 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_IOCTL_SET_C_ + +#include <drv_types.h> +#include <hal_data.h> + + +extern void indicate_wx_scan_complete_event(_adapter *padapter); + +#define IS_MAC_ADDRESS_BROADCAST(addr) \ + (\ + ((addr[0] == 0xff) && (addr[1] == 0xff) && \ + (addr[2] == 0xff) && (addr[3] == 0xff) && \ + (addr[4] == 0xff) && (addr[5] == 0xff)) ? _TRUE : _FALSE \ + ) + +u8 rtw_validate_bssid(u8 *bssid) +{ + u8 ret = _TRUE; + + if (is_zero_mac_addr(bssid) + || is_broadcast_mac_addr(bssid) + || is_multicast_mac_addr(bssid) + ) + ret = _FALSE; + + return ret; +} + +u8 rtw_validate_ssid(NDIS_802_11_SSID *ssid) +{ + u8 i; + u8 ret = _TRUE; + + + if (ssid->SsidLength > 32) { + ret = _FALSE; + goto exit; + } + +#ifdef CONFIG_VALIDATE_SSID + for (i = 0; i < ssid->SsidLength; i++) { + /* wifi, printable ascii code must be supported */ + if (!((ssid->Ssid[i] >= 0x20) && (ssid->Ssid[i] <= 0x7e))) { + ret = _FALSE; + break; + } + } +#endif /* CONFIG_VALIDATE_SSID */ + +exit: + + + return ret; +} + +u8 rtw_do_join(_adapter *padapter); +u8 rtw_do_join(_adapter *padapter) +{ + _irqL irqL; + _list *plist, *phead; + u8 *pibss = NULL; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + _queue *queue = &(pmlmepriv->scanned_queue); + u8 ret = _SUCCESS; + + + _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + phead = get_list_head(queue); + plist = get_next(phead); + + + pmlmepriv->cur_network.join_res = -2; + + set_fwstate(pmlmepriv, _FW_UNDER_LINKING); + + pmlmepriv->pscanned = plist; + + pmlmepriv->to_join = _TRUE; + + if (_rtw_queue_empty(queue) == _TRUE) { + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + + /* when set_ssid/set_bssid for rtw_do_join(), but scanning queue is empty */ + /* we try to issue sitesurvey firstly */ + + if (pmlmepriv->LinkDetectInfo.bBusyTraffic == _FALSE + || rtw_to_roam(padapter) > 0 + ) { + /* submit site_survey_cmd */ + ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0); + if (_SUCCESS != ret) { + pmlmepriv->to_join = _FALSE; + } + } else { + pmlmepriv->to_join = _FALSE; + ret = _FAIL; + } + + goto exit; + } else { + int select_ret; + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + select_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv); + if (select_ret == _SUCCESS) { + pmlmepriv->to_join = _FALSE; + _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); + } else { + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) { + /* submit createbss_cmd to change to a ADHOC_MASTER */ + + /* pmlmepriv->lock has been acquired by caller... */ + WLAN_BSSID_EX *pdev_network = &(padapter->registrypriv.dev_network); + + /*pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;*/ + init_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE); + + pibss = padapter->registrypriv.dev_network.MacAddress; + + _rtw_memset(&pdev_network->Ssid, 0, sizeof(NDIS_802_11_SSID)); + _rtw_memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(NDIS_802_11_SSID)); + + rtw_update_registrypriv_dev_network(padapter); + + rtw_generate_random_ibss(pibss); + + if (rtw_create_ibss_cmd(padapter, 0) != _SUCCESS) { + ret = _FALSE; + goto exit; + } + + pmlmepriv->to_join = _FALSE; + + + } else { + /* can't associate ; reset under-linking */ + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + +#if 0 + if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)) { + if (_rtw_memcmp(pmlmepriv->cur_network.network.Ssid.Ssid, pmlmepriv->assoc_ssid.Ssid, pmlmepriv->assoc_ssid.SsidLength)) { + /* for funk to do roaming */ + /* funk will reconnect, but funk will not sitesurvey before reconnect */ + if (pmlmepriv->sitesurveyctrl.traffic_busy == _FALSE) + rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0); + } + + } +#endif + + /* when set_ssid/set_bssid for rtw_do_join(), but there are no desired bss in scanning queue */ + /* we try to issue sitesurvey firstly */ + if (pmlmepriv->LinkDetectInfo.bBusyTraffic == _FALSE + || rtw_to_roam(padapter) > 0 + ) { + /* RTW_INFO("rtw_do_join() when no desired bss in scanning queue\n"); */ + ret = rtw_sitesurvey_cmd(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0); + if (_SUCCESS != ret) { + pmlmepriv->to_join = _FALSE; + } + } else { + ret = _FAIL; + pmlmepriv->to_join = _FALSE; + } + } + + } + + } + +exit: + + return ret; +} + +#ifdef PLATFORM_WINDOWS +u8 rtw_pnp_set_power_wakeup(_adapter *padapter) +{ + u8 res = _SUCCESS; + + + + res = rtw_setstandby_cmd(padapter, 0); + + + + return res; +} + +u8 rtw_pnp_set_power_sleep(_adapter *padapter) +{ + u8 res = _SUCCESS; + + + /* DbgPrint("+rtw_pnp_set_power_sleep\n"); */ + + res = rtw_setstandby_cmd(padapter, 1); + + + + return res; +} + +u8 rtw_set_802_11_reload_defaults(_adapter *padapter, NDIS_802_11_RELOAD_DEFAULTS reloadDefaults) +{ + + + + /* SecClearAllKeys(Adapter); */ + /* 8711 CAM was not for En/Decrypt only */ + /* so, we can't clear all keys. */ + /* should we disable WPAcfg (ox0088) bit 1-2, instead of clear all CAM */ + + /* TO DO... */ + + + return _TRUE; +} + +u8 set_802_11_test(_adapter *padapter, NDIS_802_11_TEST *test) +{ + u8 ret = _TRUE; + + + switch (test->Type) { + case 1: + NdisMIndicateStatus(padapter->hndis_adapter, NDIS_STATUS_MEDIA_SPECIFIC_INDICATION, (PVOID)&test->AuthenticationEvent, test->Length - 8); + NdisMIndicateStatusComplete(padapter->hndis_adapter); + break; + + case 2: + NdisMIndicateStatus(padapter->hndis_adapter, NDIS_STATUS_MEDIA_SPECIFIC_INDICATION, (PVOID)&test->RssiTrigger, sizeof(NDIS_802_11_RSSI)); + NdisMIndicateStatusComplete(padapter->hndis_adapter); + break; + + default: + ret = _FALSE; + break; + } + + + return ret; +} + +u8 rtw_set_802_11_pmkid(_adapter *padapter, NDIS_802_11_PMKID *pmkid) +{ + u8 ret = _SUCCESS; + + return ret; +} + +#endif + +u8 rtw_set_802_11_bssid(_adapter *padapter, u8 *bssid) +{ + _irqL irqL; + u8 status = _SUCCESS; + + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + + RTW_PRINT("set bssid:%pM\n", bssid); + + if ((bssid[0] == 0x00 && bssid[1] == 0x00 && bssid[2] == 0x00 && bssid[3] == 0x00 && bssid[4] == 0x00 && bssid[5] == 0x00) || + (bssid[0] == 0xFF && bssid[1] == 0xFF && bssid[2] == 0xFF && bssid[3] == 0xFF && bssid[4] == 0xFF && bssid[5] == 0xFF)) { + status = _FAIL; + goto exit; + } + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + + RTW_INFO("Set BSSID under fw_state=0x%08x\n", get_fwstate(pmlmepriv)); + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) + goto handle_tkip_countermeasure; + else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) + goto release_mlme_lock; + + if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE) == _TRUE) { + + if (_rtw_memcmp(&pmlmepriv->cur_network.network.MacAddress, bssid, ETH_ALEN) == _TRUE) { + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _FALSE) + goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */ + } else { + + rtw_disassoc_cmd(padapter, 0, _TRUE); + + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + rtw_indicate_disconnect(padapter, 0, _FALSE); + + rtw_free_assoc_resources(padapter, 1); + + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) { + _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + } + } + } + +handle_tkip_countermeasure: + if (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) { + status = _FAIL; + goto release_mlme_lock; + } + + _rtw_memset(&pmlmepriv->assoc_ssid, 0, sizeof(NDIS_802_11_SSID)); + _rtw_memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN); + pmlmepriv->assoc_by_bssid = _TRUE; + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) + pmlmepriv->to_join = _TRUE; + else + status = rtw_do_join(padapter); + +release_mlme_lock: + _exit_critical_bh(&pmlmepriv->lock, &irqL); + +exit: + + + return status; +} + +u8 rtw_set_802_11_ssid(_adapter *padapter, NDIS_802_11_SSID *ssid) +{ + _irqL irqL; + u8 status = _SUCCESS; + u32 cur_time = 0; + + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *pnetwork = &pmlmepriv->cur_network; + + + RTW_PRINT("set ssid [%s] fw_state=0x%08x\n", + ssid->Ssid, get_fwstate(pmlmepriv)); + + if (!rtw_is_hw_init_completed(padapter)) { + status = _FAIL; + goto exit; + } + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + RTW_INFO("Set SSID under fw_state=0x%08x\n", get_fwstate(pmlmepriv)); + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) + goto handle_tkip_countermeasure; + else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) + goto release_mlme_lock; + + if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE) == _TRUE) { + + if ((pmlmepriv->assoc_ssid.SsidLength == ssid->SsidLength) && + (_rtw_memcmp(&pmlmepriv->assoc_ssid.Ssid, ssid->Ssid, ssid->SsidLength) == _TRUE)) { + if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _FALSE)) { + + if (rtw_is_same_ibss(padapter, pnetwork) == _FALSE) { + /* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */ + rtw_disassoc_cmd(padapter, 0, _TRUE); + + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + rtw_indicate_disconnect(padapter, 0, _FALSE); + + rtw_free_assoc_resources(padapter, 1); + + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) { + _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + } + } else { + goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */ + } + } +#ifdef CONFIG_LPS + else + rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_JOINBSS, 1); +#endif + } else { + + rtw_disassoc_cmd(padapter, 0, _TRUE); + + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + rtw_indicate_disconnect(padapter, 0, _FALSE); + + rtw_free_assoc_resources(padapter, 1); + + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) { + _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + } + } + } + +handle_tkip_countermeasure: + if (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) { + status = _FAIL; + goto release_mlme_lock; + } + + if (rtw_validate_ssid(ssid) == _FALSE) { + status = _FAIL; + goto release_mlme_lock; + } + + _rtw_memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(NDIS_802_11_SSID)); + pmlmepriv->assoc_by_bssid = _FALSE; + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) + pmlmepriv->to_join = _TRUE; + else + status = rtw_do_join(padapter); + +release_mlme_lock: + _exit_critical_bh(&pmlmepriv->lock, &irqL); + +exit: + + + return status; + +} + +u8 rtw_set_802_11_connect(_adapter *padapter, u8 *bssid, NDIS_802_11_SSID *ssid) +{ + _irqL irqL; + u8 status = _SUCCESS; + u32 cur_time = 0; + bool bssid_valid = _TRUE; + bool ssid_valid = _TRUE; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + + if (!ssid || rtw_validate_ssid(ssid) == _FALSE) + ssid_valid = _FALSE; + + if (!bssid || rtw_validate_bssid(bssid) == _FALSE) + bssid_valid = _FALSE; + + if (ssid_valid == _FALSE && bssid_valid == _FALSE) { + RTW_INFO(FUNC_ADPT_FMT" ssid:%p, ssid_valid:%d, bssid:%p, bssid_valid:%d\n", + FUNC_ADPT_ARG(padapter), ssid, ssid_valid, bssid, bssid_valid); + status = _FAIL; + goto exit; + } + + if (!rtw_is_hw_init_completed(padapter)) { + status = _FAIL; + goto exit; + } + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + RTW_PRINT(FUNC_ADPT_FMT" fw_state=0x%08x\n", + FUNC_ADPT_ARG(padapter), get_fwstate(pmlmepriv)); + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) + goto handle_tkip_countermeasure; + else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) + goto release_mlme_lock; + +handle_tkip_countermeasure: + if (rtw_handle_tkip_countermeasure(padapter, __func__) == _FAIL) { + status = _FAIL; + goto release_mlme_lock; + } + + if (ssid && ssid_valid) + _rtw_memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(NDIS_802_11_SSID)); + else + _rtw_memset(&pmlmepriv->assoc_ssid, 0, sizeof(NDIS_802_11_SSID)); + + if (bssid && bssid_valid) { + _rtw_memcpy(&pmlmepriv->assoc_bssid, bssid, ETH_ALEN); + pmlmepriv->assoc_by_bssid = _TRUE; + } else + pmlmepriv->assoc_by_bssid = _FALSE; + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) + pmlmepriv->to_join = _TRUE; + else + status = rtw_do_join(padapter); + +release_mlme_lock: + _exit_critical_bh(&pmlmepriv->lock, &irqL); + +exit: + + + return status; +} + +u8 rtw_set_802_11_infrastructure_mode(_adapter *padapter, + NDIS_802_11_NETWORK_INFRASTRUCTURE networktype) +{ + _irqL irqL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + NDIS_802_11_NETWORK_INFRASTRUCTURE *pold_state = &(cur_network->network.InfrastructureMode); + u8 ap2sta_mode = _FALSE; + + + + if (*pold_state != networktype) { + /* RTW_INFO("change mode, old_mode=%d, new_mode=%d, fw_state=0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */ + + if (*pold_state == Ndis802_11APMode) { + /* change to other mode from Ndis802_11APMode */ + cur_network->join_res = -1; + ap2sta_mode = _TRUE; +#ifdef CONFIG_NATIVEAP_MLME + stop_ap_mode(padapter); +#endif + } + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) || (*pold_state == Ndis802_11IBSS)) + rtw_disassoc_cmd(padapter, 0, _TRUE); + + if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) + rtw_free_assoc_resources(padapter, 1); + + if ((*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + rtw_indicate_disconnect(padapter, 0, _FALSE); /*will clr Linked_state; before this function, we must have checked whether issue dis-assoc_cmd or not*/ + } + } + + *pold_state = networktype; + + _clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE); + + switch (networktype) { + case Ndis802_11IBSS: + set_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + break; + + case Ndis802_11Infrastructure: + set_fwstate(pmlmepriv, WIFI_STATION_STATE); + + if (ap2sta_mode) + rtw_init_bcmc_stainfo(padapter); + break; + + case Ndis802_11APMode: + set_fwstate(pmlmepriv, WIFI_AP_STATE); +#ifdef CONFIG_NATIVEAP_MLME + start_ap_mode(padapter); + /* rtw_indicate_connect(padapter); */ +#endif + + break; + + case Ndis802_11AutoUnknown: + case Ndis802_11InfrastructureMax: + break; + case Ndis802_11Monitor: + set_fwstate(pmlmepriv, WIFI_MONITOR_STATE); + break; + } + + /* SecClearAllKeys(adapter); */ + + + _exit_critical_bh(&pmlmepriv->lock, &irqL); + } + + + return _TRUE; +} + + +u8 rtw_set_802_11_disassociate(_adapter *padapter) +{ + _irqL irqL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + + rtw_disassoc_cmd(padapter, 0, _TRUE); + rtw_indicate_disconnect(padapter, 0, _FALSE); + /* modify for CONFIG_IEEE80211W, none 11w can use it */ + rtw_free_assoc_resources_cmd(padapter); + if (_FAIL == rtw_pwr_wakeup(padapter)) + RTW_INFO("%s(): rtw_pwr_wakeup fail !!!\n", __FUNCTION__); + } + + _exit_critical_bh(&pmlmepriv->lock, &irqL); + + + return _TRUE; +} + +#if 1 +u8 rtw_set_802_11_bssid_list_scan(_adapter *padapter, NDIS_802_11_SSID *pssid, int ssid_max_num, struct rtw_ieee80211_channel *ch, int ch_num) +{ + _irqL irqL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + u8 res = _TRUE; + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, ch, ch_num); + _exit_critical_bh(&pmlmepriv->lock, &irqL); + + return res; +} + +#else +u8 rtw_set_802_11_bssid_list_scan(_adapter *padapter, NDIS_802_11_SSID *pssid, int ssid_max_num, struct rtw_ieee80211_channel *ch, int ch_num) +{ + _irqL irqL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + u8 res = _TRUE; + + + + if (padapter == NULL) { + res = _FALSE; + goto exit; + } + if (!rtw_is_hw_init_completed(padapter)) { + res = _FALSE; + goto exit; + } + + if ((check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) == _TRUE) || + (pmlmepriv->LinkDetectInfo.bBusyTraffic == _TRUE)) { + /* Scan or linking is in progress, do nothing. */ + res = _TRUE; + + + } else { + if (rtw_is_scan_deny(padapter)) { + RTW_INFO(FUNC_ADPT_FMT": scan deny\n", FUNC_ADPT_ARG(padapter)); + indicate_wx_scan_complete_event(padapter); + return _SUCCESS; + } + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + res = rtw_sitesurvey_cmd(padapter, pssid, ssid_max_num, NULL, 0, ch, ch_num); + + _exit_critical_bh(&pmlmepriv->lock, &irqL); + } +exit: + + + return res; +} +#endif +u8 rtw_set_802_11_authentication_mode(_adapter *padapter, NDIS_802_11_AUTHENTICATION_MODE authmode) +{ + struct security_priv *psecuritypriv = &padapter->securitypriv; + int res; + u8 ret; + + + + psecuritypriv->ndisauthtype = authmode; + + + if (psecuritypriv->ndisauthtype > 3) + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; + +#ifdef CONFIG_WAPI_SUPPORT + if (psecuritypriv->ndisauthtype == 6) + psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_WAPI; +#endif + + res = rtw_set_auth(padapter, psecuritypriv); + + if (res == _SUCCESS) + ret = _TRUE; + else + ret = _FALSE; + + + return ret; +} + +u8 rtw_set_802_11_add_wep(_adapter *padapter, NDIS_802_11_WEP *wep) +{ + + u8 bdefaultkey; + u8 btransmitkey; + sint keyid, res; + struct security_priv *psecuritypriv = &(padapter->securitypriv); + u8 ret = _SUCCESS; + + + bdefaultkey = (wep->KeyIndex & 0x40000000) > 0 ? _FALSE : _TRUE; /* for ??? */ + btransmitkey = (wep->KeyIndex & 0x80000000) > 0 ? _TRUE : _FALSE; /* for ??? */ + keyid = wep->KeyIndex & 0x3fffffff; + + if (keyid >= 4) { + ret = _FALSE; + goto exit; + } + + switch (wep->KeyLength) { + case 5: + psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; + break; + case 13: + psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; + break; + default: + psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; + break; + } + + + _rtw_memcpy(&(psecuritypriv->dot11DefKey[keyid].skey[0]), &(wep->KeyMaterial), wep->KeyLength); + + psecuritypriv->dot11DefKeylen[keyid] = wep->KeyLength; + + psecuritypriv->dot11PrivacyKeyIndex = keyid; + + + res = rtw_set_key(padapter, psecuritypriv, keyid, 1, _TRUE); + + if (res == _FAIL) + ret = _FALSE; +exit: + + + return ret; + +} + +u8 rtw_set_802_11_remove_wep(_adapter *padapter, u32 keyindex) +{ + + u8 ret = _SUCCESS; + + + if (keyindex >= 0x80000000 || padapter == NULL) { + + ret = _FALSE; + goto exit; + + } else { + int res; + struct security_priv *psecuritypriv = &(padapter->securitypriv); + if (keyindex < 4) { + + _rtw_memset(&psecuritypriv->dot11DefKey[keyindex], 0, 16); + + res = rtw_set_key(padapter, psecuritypriv, keyindex, 0, _TRUE); + + psecuritypriv->dot11DefKeylen[keyindex] = 0; + + if (res == _FAIL) + ret = _FAIL; + + } else + ret = _FAIL; + + } + +exit: + + + return ret; + +} + +u8 rtw_set_802_11_add_key(_adapter *padapter, NDIS_802_11_KEY *key) +{ + + uint encryptionalgo; + u8 *pbssid; + struct sta_info *stainfo; + u8 bgroup = _FALSE; + u8 bgrouptkey = _FALSE;/* can be remove later */ + u8 ret = _SUCCESS; + + + if (((key->KeyIndex & 0x80000000) == 0) && ((key->KeyIndex & 0x40000000) > 0)) { + + /* It is invalid to clear bit 31 and set bit 30. If the miniport driver encounters this combination, */ + /* it must fail the request and return NDIS_STATUS_INVALID_DATA. */ + ret = _FAIL; + goto exit; + } + + if (key->KeyIndex & 0x40000000) { + /* Pairwise key */ + + + pbssid = get_bssid(&padapter->mlmepriv); + stainfo = rtw_get_stainfo(&padapter->stapriv, pbssid); + + if ((stainfo != NULL) && (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)) { + encryptionalgo = stainfo->dot118021XPrivacy; + } else { + encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm; + } + + + + + if (key->KeyIndex & 0x000000FF) { + /* The key index is specified in the lower 8 bits by values of zero to 255. */ + /* The key index should be set to zero for a Pairwise key, and the driver should fail with */ + /* NDIS_STATUS_INVALID_DATA if the lower 8 bits is not zero */ + ret = _FAIL; + goto exit; + } + + /* check BSSID */ + if (IS_MAC_ADDRESS_BROADCAST(key->BSSID) == _TRUE) { + + ret = _FALSE; + goto exit; + } + + /* Check key length for TKIP. */ + /* if(encryptionAlgorithm == RT_ENC_TKIP_ENCRYPTION && key->KeyLength != 32) */ + if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) { + ret = _FAIL; + goto exit; + + } + + /* Check key length for AES. */ + if ((encryptionalgo == _AES_) && (key->KeyLength != 16)) { + /* For our supplicant, EAPPkt9x.vxd, cannot differentiate TKIP and AES case. */ + if (key->KeyLength == 32) + key->KeyLength = 16; + else { + ret = _FAIL; + goto exit; + } + } + + /* Check key length for WEP. For NDTEST, 2005.01.27, by rcnjko. -> modify checking condition*/ + if (((encryptionalgo == _WEP40_) && (key->KeyLength != 5)) || ((encryptionalgo == _WEP104_) && (key->KeyLength != 13))) { + ret = _FAIL; + goto exit; + } + + bgroup = _FALSE; + + /* Check the pairwise key. Added by Annie, 2005-07-06. */ + + } else { + /* Group key - KeyIndex(BIT30==0) */ + + + /* when add wep key through add key and didn't assigned encryption type before */ + if ((padapter->securitypriv.ndisauthtype <= 3) && (padapter->securitypriv.dot118021XGrpPrivacy == 0)) { + + switch (key->KeyLength) { + case 5: + padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; + break; + case 13: + padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; + break; + default: + padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; + break; + } + + encryptionalgo = padapter->securitypriv.dot11PrivacyAlgrthm; + + + } else { + encryptionalgo = padapter->securitypriv.dot118021XGrpPrivacy; + + } + + if ((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE) == _TRUE) && (IS_MAC_ADDRESS_BROADCAST(key->BSSID) == _FALSE)) { + ret = _FAIL; + goto exit; + } + + /* Check key length for TKIP */ + if ((encryptionalgo == _TKIP_) && (key->KeyLength != 32)) { + + ret = _FAIL; + goto exit; + + } else if (encryptionalgo == _AES_ && (key->KeyLength != 16 && key->KeyLength != 32)) { + + /* Check key length for AES */ + /* For NDTEST, we allow keylen=32 in this case. 2005.01.27, by rcnjko. */ + ret = _FAIL; + goto exit; + } + + /* Change the key length for EAPPkt9x.vxd. Added by Annie, 2005-11-03. */ + if ((encryptionalgo == _AES_) && (key->KeyLength == 32)) { + key->KeyLength = 16; + } + + if (key->KeyIndex & 0x8000000) /* error ??? 0x8000_0000 */ + bgrouptkey = _TRUE; + + if ((check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE) == _TRUE) && (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == _TRUE)) + bgrouptkey = _TRUE; + + bgroup = _TRUE; + + + } + + /* If WEP encryption algorithm, just call rtw_set_802_11_add_wep(). */ + if ((padapter->securitypriv.dot11AuthAlgrthm != dot11AuthAlgrthm_8021X) && (encryptionalgo == _WEP40_ || encryptionalgo == _WEP104_)) { + u8 ret; + u32 keyindex; + u32 len = FIELD_OFFSET(NDIS_802_11_KEY, KeyMaterial) + key->KeyLength; + NDIS_802_11_WEP *wep = &padapter->securitypriv.ndiswep; + + + wep->Length = len; + keyindex = key->KeyIndex & 0x7fffffff; + wep->KeyIndex = keyindex ; + wep->KeyLength = key->KeyLength; + + + _rtw_memcpy(wep->KeyMaterial, key->KeyMaterial, key->KeyLength); + _rtw_memcpy(&(padapter->securitypriv.dot11DefKey[keyindex].skey[0]), key->KeyMaterial, key->KeyLength); + + padapter->securitypriv.dot11DefKeylen[keyindex] = key->KeyLength; + padapter->securitypriv.dot11PrivacyKeyIndex = keyindex; + + ret = rtw_set_802_11_add_wep(padapter, wep); + + goto exit; + + } + + if (key->KeyIndex & 0x20000000) { + /* SetRSC */ + if (bgroup == _TRUE) { + NDIS_802_11_KEY_RSC keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL; + _rtw_memcpy(&padapter->securitypriv.dot11Grprxpn, &keysrc, 8); + } else { + NDIS_802_11_KEY_RSC keysrc = key->KeyRSC & 0x00FFFFFFFFFFFFULL; + _rtw_memcpy(&padapter->securitypriv.dot11Grptxpn, &keysrc, 8); + } + + } + + /* Indicate this key idx is used for TX */ + /* Save the key in KeyMaterial */ + if (bgroup == _TRUE) { /* Group transmit key */ + int res; + + if (bgrouptkey == _TRUE) + padapter->securitypriv.dot118021XGrpKeyid = (u8)key->KeyIndex; + + if ((key->KeyIndex & 0x3) == 0) { + ret = _FAIL; + goto exit; + } + + _rtw_memset(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], 0, 16); + _rtw_memset(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16); + _rtw_memset(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], 0, 16); + + if ((key->KeyIndex & 0x10000000)) { + _rtw_memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8); + _rtw_memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8); + + + } else { + _rtw_memcpy(&padapter->securitypriv.dot118021XGrptxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 24, 8); + _rtw_memcpy(&padapter->securitypriv.dot118021XGrprxmickey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial + 16, 8); + + + } + + /* set group key by index */ + _rtw_memcpy(&padapter->securitypriv.dot118021XGrpKey[(u8)((key->KeyIndex) & 0x03)], key->KeyMaterial, key->KeyLength); + + key->KeyIndex = key->KeyIndex & 0x03; + + padapter->securitypriv.binstallGrpkey = _TRUE; + + padapter->securitypriv.bcheck_grpkey = _FALSE; + + + res = rtw_set_key(padapter, &padapter->securitypriv, key->KeyIndex, 1, _TRUE); + + if (res == _FAIL) + ret = _FAIL; + + goto exit; + + } else { /* Pairwise Key */ + u8 res; + + pbssid = get_bssid(&padapter->mlmepriv); + stainfo = rtw_get_stainfo(&padapter->stapriv , pbssid); + + if (stainfo != NULL) { + _rtw_memset(&stainfo->dot118021x_UncstKey, 0, 16); /* clear keybuffer */ + + _rtw_memcpy(&stainfo->dot118021x_UncstKey, key->KeyMaterial, 16); + + if (encryptionalgo == _TKIP_) { + padapter->securitypriv.busetkipkey = _FALSE; + + /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */ + + + /* if TKIP, save the Receive/Transmit MIC key in KeyMaterial[128-255] */ + if ((key->KeyIndex & 0x10000000)) { + _rtw_memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 16, 8); + _rtw_memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 24, 8); + + } else { + _rtw_memcpy(&stainfo->dot11tkiptxmickey, key->KeyMaterial + 24, 8); + _rtw_memcpy(&stainfo->dot11tkiprxmickey, key->KeyMaterial + 16, 8); + + } + + } else if (encryptionalgo == _AES_) { + + } + + + /* Set key to CAM through H2C command */ +#if 0 + if (bgrouptkey) { /* never go to here */ + res = rtw_setstakey_cmd(padapter, stainfo, GROUP_KEY, _TRUE); + } else { + res = rtw_setstakey_cmd(padapter, stainfo, UNICAST_KEY, _TRUE); + } +#else + + res = rtw_setstakey_cmd(padapter, stainfo, UNICAST_KEY, _TRUE); +#endif + + if (res == _FALSE) + ret = _FAIL; + + } + + } + +exit: + + + return ret; +} + +u8 rtw_set_802_11_remove_key(_adapter *padapter, NDIS_802_11_REMOVE_KEY *key) +{ + + uint encryptionalgo; + u8 *pbssid; + struct sta_info *stainfo; + u8 bgroup = (key->KeyIndex & 0x4000000) > 0 ? _FALSE : _TRUE; + u8 keyIndex = (u8)key->KeyIndex & 0x03; + u8 ret = _SUCCESS; + + + if ((key->KeyIndex & 0xbffffffc) > 0) { + ret = _FAIL; + goto exit; + } + + if (bgroup == _TRUE) { + encryptionalgo = padapter->securitypriv.dot118021XGrpPrivacy; + /* clear group key by index */ + /* NdisZeroMemory(Adapter->MgntInfo.SecurityInfo.KeyBuf[keyIndex], MAX_WEP_KEY_LEN); */ + /* Adapter->MgntInfo.SecurityInfo.KeyLen[keyIndex] = 0; */ + + _rtw_memset(&padapter->securitypriv.dot118021XGrpKey[keyIndex], 0, 16); + + /* ! \todo Send a H2C Command to Firmware for removing this Key in CAM Entry. */ + + } else { + + pbssid = get_bssid(&padapter->mlmepriv); + stainfo = rtw_get_stainfo(&padapter->stapriv , pbssid); + if (stainfo != NULL) { + encryptionalgo = stainfo->dot118021XPrivacy; + + /* clear key by BSSID */ + _rtw_memset(&stainfo->dot118021x_UncstKey, 0, 16); + + /* ! \todo Send a H2C Command to Firmware for disable this Key in CAM Entry. */ + + } else { + ret = _FAIL; + goto exit; + } + } + +exit: + + + return _TRUE; + +} + +/* +* rtw_get_cur_max_rate - +* @adapter: pointer to _adapter structure +* +* Return 0 or 100Kbps +*/ +u16 rtw_get_cur_max_rate(_adapter *adapter) +{ + int i = 0; + u16 rate = 0, max_rate = 0; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + WLAN_BSSID_EX *pcur_bss = &pmlmepriv->cur_network.network; + struct sta_info *psta = NULL; + u8 short_GI = 0; +#ifdef CONFIG_80211N_HT + u8 rf_type = 0; +#endif + +#ifdef CONFIG_MP_INCLUDED + if (adapter->registrypriv.mp_mode == 1) { + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) + return 0; + } +#endif + + if ((check_fwstate(pmlmepriv, _FW_LINKED) != _TRUE) + && (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) != _TRUE)) + return 0; + + psta = rtw_get_stainfo(&adapter->stapriv, get_bssid(pmlmepriv)); + if (psta == NULL) + return 0; + + short_GI = query_ra_short_GI(psta, psta->bw_mode); + +#ifdef CONFIG_80211N_HT + if (is_supported_ht(psta->wireless_mode)) { + rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + max_rate = rtw_mcs_rate(rf_type + , (psta->bw_mode == CHANNEL_WIDTH_40) ? 1 : 0 + , short_GI + , psta->htpriv.ht_cap.supp_mcs_set + ); + } +#ifdef CONFIG_80211AC_VHT + else if (is_supported_vht(psta->wireless_mode)) + max_rate = ((rtw_vht_mcs_to_data_rate(psta->bw_mode, short_GI, pmlmepriv->vhtpriv.vht_highest_rate) + 1) >> 1) * 10; +#endif /* CONFIG_80211AC_VHT */ + else +#endif /* CONFIG_80211N_HT */ + { + while ((pcur_bss->SupportedRates[i] != 0) && (pcur_bss->SupportedRates[i] != 0xFF)) { + rate = pcur_bss->SupportedRates[i] & 0x7F; + if (rate > max_rate) + max_rate = rate; + i++; + } + + max_rate = max_rate * 10 / 2; + } + + return max_rate; +} + +/* +* rtw_set_scan_mode - +* @adapter: pointer to _adapter structure +* @scan_mode: +* +* Return _SUCCESS or _FAIL +*/ +int rtw_set_scan_mode(_adapter *adapter, RT_SCAN_TYPE scan_mode) +{ + if (scan_mode != SCAN_ACTIVE && scan_mode != SCAN_PASSIVE) + return _FAIL; + + adapter->mlmepriv.scan_mode = scan_mode; + + return _SUCCESS; +} + +/* +* rtw_set_channel_plan - +* @adapter: pointer to _adapter structure +* @channel_plan: +* +* Return _SUCCESS or _FAIL +*/ +int rtw_set_channel_plan(_adapter *adapter, u8 channel_plan) +{ + struct registry_priv *pregistrypriv = &adapter->registrypriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + /* handle by cmd_thread to sync with scan operation */ + return rtw_set_chplan_cmd(adapter, RTW_CMDF_WAIT_ACK, channel_plan, 1); +} + +/* +* rtw_set_country - +* @adapter: pointer to _adapter structure +* @country_code: string of country code +* +* Return _SUCCESS or _FAIL +*/ +int rtw_set_country(_adapter *adapter, const char *country_code) +{ +#ifdef CONFIG_RTW_IOCTL_SET_COUNTRY + return rtw_set_country_cmd(adapter, RTW_CMDF_WAIT_ACK, country_code, 1); +#else + return _FAIL; +#endif +} + +/* +* rtw_set_band - +* @adapter: pointer to _adapter structure +* @band: band to set +* +* Return _SUCCESS or _FAIL +*/ +int rtw_set_band(_adapter *adapter, u8 band) +{ + if (rtw_band_valid(band)) { + RTW_INFO(FUNC_ADPT_FMT" band:%d\n", FUNC_ADPT_ARG(adapter), band); + adapter->setband = band; + return _SUCCESS; + } + + RTW_PRINT(FUNC_ADPT_FMT" band:%d fail\n", FUNC_ADPT_ARG(adapter), band); + return _FAIL; +} diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_iol.c b/linux-bsp/drivers/rtl8188eus/core/rtw_iol.c new file mode 100644 index 0000000..42d0b6b --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_iol.c @@ -0,0 +1,387 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#include <drv_types.h> + +#ifdef CONFIG_IOL +struct xmit_frame *rtw_IOL_accquire_xmit_frame(ADAPTER *adapter) +{ + struct xmit_frame *xmit_frame; + struct xmit_buf *xmitbuf; + struct pkt_attrib *pattrib; + struct xmit_priv *pxmitpriv = &(adapter->xmitpriv); + +#if 1 + xmit_frame = rtw_alloc_xmitframe(pxmitpriv); + if (xmit_frame == NULL) { + RTW_INFO("%s rtw_alloc_xmitframe return null\n", __FUNCTION__); + goto exit; + } + + xmitbuf = rtw_alloc_xmitbuf(pxmitpriv); + if (xmitbuf == NULL) { + RTW_INFO("%s rtw_alloc_xmitbuf return null\n", __FUNCTION__); + rtw_free_xmitframe(pxmitpriv, xmit_frame); + xmit_frame = NULL; + goto exit; + } + + xmit_frame->frame_tag = MGNT_FRAMETAG; + xmit_frame->pxmitbuf = xmitbuf; + xmit_frame->buf_addr = xmitbuf->pbuf; + xmitbuf->priv_data = xmit_frame; + + pattrib = &xmit_frame->attrib; + update_mgntframe_attrib(adapter, pattrib); + pattrib->qsel = QSLT_BEACON;/* Beacon */ + pattrib->subtype = WIFI_BEACON; + pattrib->pktlen = pattrib->last_txcmdsz = 0; + +#else + xmit_frame = alloc_mgtxmitframe(pxmitpriv); + if (xmit_frame == NULL) + RTW_INFO("%s alloc_mgtxmitframe return null\n", __FUNCTION__); + else { + pattrib = &xmit_frame->attrib; + update_mgntframe_attrib(adapter, pattrib); + pattrib->qsel = QSLT_BEACON; + pattrib->pktlen = pattrib->last_txcmdsz = 0; + } +#endif + +exit: + return xmit_frame; +} + + +int rtw_IOL_append_cmds(struct xmit_frame *xmit_frame, u8 *IOL_cmds, u32 cmd_len) +{ + struct pkt_attrib *pattrib = &xmit_frame->attrib; + u16 buf_offset; + u32 ori_len; + + buf_offset = TXDESC_OFFSET; + ori_len = buf_offset + pattrib->pktlen; + + /* check if the io_buf can accommodate new cmds */ + if (ori_len + cmd_len + 8 > MAX_XMITBUF_SZ) { + RTW_INFO("%s %u is large than MAX_XMITBUF_SZ:%u, can't accommodate new cmds\n", __FUNCTION__ + , ori_len + cmd_len + 8, MAX_XMITBUF_SZ); + return _FAIL; + } + + _rtw_memcpy(xmit_frame->buf_addr + buf_offset + pattrib->pktlen, IOL_cmds, cmd_len); + pattrib->pktlen += cmd_len; + pattrib->last_txcmdsz += cmd_len; + + /* RTW_INFO("%s ori:%u + cmd_len:%u = %u\n", __FUNCTION__, ori_len, cmd_len, buf_offset+pattrib->pktlen); */ + + return _SUCCESS; +} + +bool rtw_IOL_applied(ADAPTER *adapter) +{ + if (1 == adapter->registrypriv.fw_iol) + return _TRUE; + +#ifdef CONFIG_USB_HCI + if ((2 == adapter->registrypriv.fw_iol) && (IS_FULL_SPEED_USB(adapter))) + return _TRUE; +#endif + + return _FALSE; +} + +int rtw_IOL_exec_cmds_sync(ADAPTER *adapter, struct xmit_frame *xmit_frame, u32 max_wating_ms, u32 bndy_cnt) +{ + return rtw_hal_iol_cmd(adapter, xmit_frame, max_wating_ms, bndy_cnt); +} + +#ifdef CONFIG_IOL_NEW_GENERATION +int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary) +{ + return _SUCCESS; +} +int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, u8 mask) +{ + struct ioreg_cfg cmd = {8, IOREG_CMD_WB_REG, 0x0, 0x0, 0x0}; + + /* RTW_PUT_LE16((u8*)&cmd.address, addr); */ + /* RTW_PUT_LE32((u8*)&cmd.value, (u32)value); */ + cmd.address = cpu_to_le16(addr); + cmd.data = cpu_to_le32(value); + + if (mask != 0xFF) { + cmd.length = 12; + /* RTW_PUT_LE32((u8*)&cmd.mask, (u32)mask); */ + cmd.mask = cpu_to_le32(mask); + } + + /* RTW_INFO("%s addr:0x%04x,value:0x%08x,mask:0x%08x\n", __FUNCTION__, addr,value,mask); */ + + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); + +} +int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u16 mask) +{ + struct ioreg_cfg cmd = {8, IOREG_CMD_WW_REG, 0x0, 0x0, 0x0}; + + /* RTW_PUT_LE16((u8*)&cmd.address, addr); */ + /* RTW_PUT_LE32((u8*)&cmd.value, (u32)value); */ + cmd.address = cpu_to_le16(addr); + cmd.data = cpu_to_le32(value); + + if (mask != 0xFFFF) { + cmd.length = 12; + /* RTW_PUT_LE32((u8*)&cmd.mask, (u32)mask); */ + cmd.mask = cpu_to_le32(mask); + } + + /* RTW_INFO("%s addr:0x%04x,value:0x%08x,mask:0x%08x\n", __FUNCTION__, addr,value,mask); */ + + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); + +} +int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u32 mask) +{ + struct ioreg_cfg cmd = {8, IOREG_CMD_WD_REG, 0x0, 0x0, 0x0}; + + /* RTW_PUT_LE16((u8*)&cmd.address, addr); */ + /* RTW_PUT_LE32((u8*)&cmd.value, (u32)value); */ + cmd.address = cpu_to_le16(addr); + cmd.data = cpu_to_le32(value); + + if (mask != 0xFFFFFFFF) { + cmd.length = 12; + /* RTW_PUT_LE32((u8*)&cmd.mask, (u32)mask); */ + cmd.mask = cpu_to_le32(mask); + } + + /* RTW_INFO("%s addr:0x%04x,value:0x%08x,mask:0x%08x\n", __FU2NCTION__, addr,value,mask); */ + + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); + +} + +int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, u16 addr, u32 value, u32 mask) +{ + struct ioreg_cfg cmd = {8, IOREG_CMD_W_RF, 0x0, 0x0, 0x0}; + + /* RTW_PUT_LE16((u8*)&cmd.address, addr); */ + /* RTW_PUT_LE32((u8*)&cmd.value, (u32)value); */ + cmd.address = (rf_path << 8) | ((addr) & 0xFF); + cmd.data = cpu_to_le32(value); + + if (mask != 0x000FFFFF) { + cmd.length = 12; + /* RTW_PUT_LE32((u8*)&cmd.mask, (u32)mask); */ + cmd.mask = cpu_to_le32(mask); + } + + /* RTW_INFO("%s rf_path:0x%02x addr:0x%04x,value:0x%08x,mask:0x%08x\n", __FU2NCTION__,rf_path, addr,value,mask); */ + + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); + +} + + + +int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us) +{ + struct ioreg_cfg cmd = {4, IOREG_CMD_DELAY_US, 0x0, 0x0, 0x0}; + /* RTW_PUT_LE16((u8*)&cmd.address, us); */ + cmd.address = cpu_to_le16(us); + + /* RTW_INFO("%s %u\n", __FUNCTION__, us); */ + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4); +} + +int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms) +{ + struct ioreg_cfg cmd = {4, IOREG_CMD_DELAY_US, 0x0, 0x0, 0x0}; + + /* RTW_PUT_LE16((u8*)&cmd.address, ms); */ + cmd.address = cpu_to_le16(ms); + + /* RTW_INFO("%s %u\n", __FUNCTION__, ms); */ + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4); +} +int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame) +{ + struct ioreg_cfg cmd = {4, IOREG_CMD_END, 0xFFFF, 0xFF, 0x0}; + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 4); + +} + +u8 rtw_IOL_cmd_boundary_handle(struct xmit_frame *pxmit_frame) +{ + u8 is_cmd_bndy = _FALSE; + if (((pxmit_frame->attrib.pktlen + 32) % 256) + 8 >= 256) { + rtw_IOL_append_END_cmd(pxmit_frame); + pxmit_frame->attrib.pktlen = ((((pxmit_frame->attrib.pktlen + 32) / 256) + 1) * 256); + + /* printk("==> %s, pktlen(%d)\n",__FUNCTION__,pxmit_frame->attrib.pktlen); */ + pxmit_frame->attrib.last_txcmdsz = pxmit_frame->attrib.pktlen; + is_cmd_bndy = _TRUE; + } + return is_cmd_bndy; +} + +void rtw_IOL_cmd_buf_dump(ADAPTER *Adapter, int buf_len, u8 *pbuf) +{ + int i; + int j = 1; + + printk("###### %s ######\n", __FUNCTION__); + for (i = 0; i < buf_len; i++) { + printk("%02x-", *(pbuf + i)); + + if (j % 32 == 0) + printk("\n"); + j++; + } + printk("\n"); + printk("============= ioreg_cmd len = %d ===============\n", buf_len); +} + + +#else /* CONFIG_IOL_NEW_GENERATION */ +int rtw_IOL_append_LLT_cmd(struct xmit_frame *xmit_frame, u8 page_boundary) +{ + IOL_CMD cmd = {0x0, IOL_CMD_LLT, 0x0, 0x0}; + + RTW_PUT_BE32((u8 *)&cmd.value, (u32)page_boundary); + + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 8); +} + +int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value) +{ + IOL_CMD cmd = {0x0, IOL_CMD_WB_REG, 0x0, 0x0}; + + RTW_PUT_BE16((u8 *)&cmd.address, (u16)addr); + RTW_PUT_BE32((u8 *)&cmd.value, (u32)value); + + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 8); +} + +int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value) +{ + IOL_CMD cmd = {0x0, IOL_CMD_WW_REG, 0x0, 0x0}; + + RTW_PUT_BE16((u8 *)&cmd.address, (u16)addr); + RTW_PUT_BE32((u8 *)&cmd.value, (u32)value); + + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 8); +} + +int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value) +{ + IOL_CMD cmd = {0x0, IOL_CMD_WD_REG, 0x0, 0x0}; + u8 *pos = (u8 *)&cmd; + + RTW_PUT_BE16((u8 *)&cmd.address, (u16)addr); + RTW_PUT_BE32((u8 *)&cmd.value, (u32)value); + + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 8); +} + +#ifdef DBG_IO +int dbg_rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, const char *caller, const int line) +{ + if (match_write_sniff_ranges(addr, 1)) + RTW_INFO("DBG_IO %s:%d IOL_WB(0x%04x, 0x%02x)\n", caller, line, addr, value); + + return _rtw_IOL_append_WB_cmd(xmit_frame, addr, value); +} + +int dbg_rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, const char *caller, const int line) +{ + if (match_write_sniff_ranges(addr, 2)) + RTW_INFO("DBG_IO %s:%d IOL_WW(0x%04x, 0x%04x)\n", caller, line, addr, value); + + return _rtw_IOL_append_WW_cmd(xmit_frame, addr, value); +} + +int dbg_rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, const char *caller, const int line) +{ + if (match_write_sniff_ranges(addr, 4)) + RTW_INFO("DBG_IO %s:%d IOL_WD(0x%04x, 0x%08x)\n", caller, line, addr, value); + + return _rtw_IOL_append_WD_cmd(xmit_frame, addr, value); +} +#endif + +int rtw_IOL_append_DELAY_US_cmd(struct xmit_frame *xmit_frame, u16 us) +{ + IOL_CMD cmd = {0x0, IOL_CMD_DELAY_US, 0x0, 0x0}; + + RTW_PUT_BE32((u8 *)&cmd.value, (u32)us); + + /* RTW_INFO("%s %u\n", __FUNCTION__, us); */ + + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 8); +} + +int rtw_IOL_append_DELAY_MS_cmd(struct xmit_frame *xmit_frame, u16 ms) +{ + IOL_CMD cmd = {0x0, IOL_CMD_DELAY_MS, 0x0, 0x0}; + + RTW_PUT_BE32((u8 *)&cmd.value, (u32)ms); + + /* RTW_INFO("%s %u\n", __FUNCTION__, ms); */ + + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, 8); +} + +int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame) +{ + IOL_CMD end_cmd = {0x0, IOL_CMD_END, 0x0, 0x0}; + + + return rtw_IOL_append_cmds(xmit_frame, (u8 *)&end_cmd, 8); + +} + +int rtw_IOL_exec_cmd_array_sync(PADAPTER adapter, u8 *IOL_cmds, u32 cmd_num, u32 max_wating_ms) +{ + struct xmit_frame *xmit_frame; + + xmit_frame = rtw_IOL_accquire_xmit_frame(adapter); + if (xmit_frame == NULL) + return _FAIL; + + if (rtw_IOL_append_cmds(xmit_frame, IOL_cmds, cmd_num << 3) == _FAIL) + return _FAIL; + + return rtw_IOL_exec_cmds_sync(adapter, xmit_frame, max_wating_ms, 0); +} + +int rtw_IOL_exec_empty_cmds_sync(ADAPTER *adapter, u32 max_wating_ms) +{ + IOL_CMD end_cmd = {0x0, IOL_CMD_END, 0x0, 0x0}; + return rtw_IOL_exec_cmd_array_sync(adapter, (u8 *)&end_cmd, 1, max_wating_ms); +} +#endif /* CONFIG_IOL_NEW_GENERATION */ + + + + +#endif /* CONFIG_IOL */ diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_mem.c b/linux-bsp/drivers/rtl8188eus/core/rtw_mem.c new file mode 100644 index 0000000..b68a456 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_mem.c @@ -0,0 +1,114 @@ + +#include <drv_types.h> +#include <rtw_mem.h> + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek Wireless Lan Driver"); +MODULE_AUTHOR("Realtek Semiconductor Corp."); +MODULE_VERSION("DRIVERVERSION"); + +struct sk_buff_head rtk_skb_mem_q; +struct u8 *rtk_buf_mem[NR_RECVBUFF]; + +struct u8 *rtw_get_buf_premem(int index) +{ + printk("%s, rtk_buf_mem index : %d\n", __func__, index); + return rtk_buf_mem[index]; +} + +u16 rtw_rtkm_get_buff_size(void) +{ + return MAX_RTKM_RECVBUF_SZ; +} +EXPORT_SYMBOL(rtw_rtkm_get_buff_size); + +u8 rtw_rtkm_get_nr_recv_skb(void) +{ + return MAX_RTKM_NR_PREALLOC_RECV_SKB; +} +EXPORT_SYMBOL(rtw_rtkm_get_nr_recv_skb); + +struct sk_buff *rtw_alloc_skb_premem(u16 in_size) +{ + struct sk_buff *skb = NULL; + + if (in_size > MAX_RTKM_RECVBUF_SZ) { + pr_info("warning %s: driver buffer size(%d) > rtkm buffer size(%d)\n", __func__, in_size, MAX_RTKM_RECVBUF_SZ); + WARN_ON(1); + return skb; + } + + skb = skb_dequeue(&rtk_skb_mem_q); + + printk("%s, rtk_skb_mem_q len : %d\n", __func__, skb_queue_len(&rtk_skb_mem_q)); + + return skb; +} +EXPORT_SYMBOL(rtw_alloc_skb_premem); + +int rtw_free_skb_premem(struct sk_buff *pskb) +{ + if (!pskb) + return -1; + + if (skb_queue_len(&rtk_skb_mem_q) >= MAX_RTKM_NR_PREALLOC_RECV_SKB) + return -1; + + skb_queue_tail(&rtk_skb_mem_q, pskb); + + printk("%s, rtk_skb_mem_q len : %d\n", __func__, skb_queue_len(&rtk_skb_mem_q)); + + return 0; +} +EXPORT_SYMBOL(rtw_free_skb_premem); + +static int __init rtw_mem_init(void) +{ + int i; + SIZE_PTR tmpaddr = 0; + SIZE_PTR alignment = 0; + struct sk_buff *pskb = NULL; + + printk("%s\n", __func__); + pr_info("MAX_RTKM_NR_PREALLOC_RECV_SKB: %d\n", MAX_RTKM_NR_PREALLOC_RECV_SKB); + pr_info("MAX_RTKM_RECVBUF_SZ: %d\n", MAX_RTKM_RECVBUF_SZ); + +#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX + for (i = 0; i < NR_RECVBUFF; i++) + rtk_buf_mem[i] = usb_buffer_alloc(dev, size, (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL), dma); +#endif /* CONFIG_USE_USB_BUFFER_ALLOC_RX */ + + skb_queue_head_init(&rtk_skb_mem_q); + + for (i = 0; i < MAX_RTKM_NR_PREALLOC_RECV_SKB; i++) { + pskb = __dev_alloc_skb(MAX_RTKM_RECVBUF_SZ + RECVBUFF_ALIGN_SZ, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + if (pskb) { + tmpaddr = (SIZE_PTR)pskb->data; + alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1); + skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment)); + + skb_queue_tail(&rtk_skb_mem_q, pskb); + } else + printk("%s, alloc skb memory fail!\n", __func__); + + pskb = NULL; + } + + printk("%s, rtk_skb_mem_q len : %d\n", __func__, skb_queue_len(&rtk_skb_mem_q)); + + return 0; + +} + +static void __exit rtw_mem_exit(void) +{ + if (skb_queue_len(&rtk_skb_mem_q)) + printk("%s, rtk_skb_mem_q len : %d\n", __func__, skb_queue_len(&rtk_skb_mem_q)); + + skb_queue_purge(&rtk_skb_mem_q); + + printk("%s\n", __func__); +} + +module_init(rtw_mem_init); +module_exit(rtw_mem_exit); diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_mi.c b/linux-bsp/drivers/rtl8188eus/core/rtw_mi.c new file mode 100644 index 0000000..6038e57 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_mi.c @@ -0,0 +1,1286 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2015 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_MI_C_ + +#include <drv_types.h> +#include <hal_data.h> + +void rtw_mi_update_union_chan_inf(_adapter *adapter, u8 ch, u8 offset , u8 bw) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mi_state *iface_state = &dvobj->iface_state; + + iface_state->union_ch = ch; + iface_state->union_bw = bw; + iface_state->union_offset = offset; +} + +/* Find union about ch, bw, ch_offset of all linked/linking interfaces */ +int _rtw_mi_get_ch_setting_union(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset, bool include_self) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + _adapter *iface; + struct mlme_ext_priv *mlmeext; + int i; + u8 ch_ret = 0; + u8 bw_ret = CHANNEL_WIDTH_20; + u8 offset_ret = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + int num = 0; + + if (ch) + *ch = 0; + if (bw) + *bw = CHANNEL_WIDTH_20; + if (offset) + *offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + mlmeext = &iface->mlmeextpriv; + + if (!check_fwstate(&iface->mlmepriv, _FW_LINKED | _FW_UNDER_LINKING)) + continue; + + if (check_fwstate(&iface->mlmepriv, WIFI_OP_CH_SWITCHING)) + continue; + + if (include_self == _FALSE && adapter == iface) + continue; + + if (num == 0) { + ch_ret = mlmeext->cur_channel; + bw_ret = mlmeext->cur_bwmode; + offset_ret = mlmeext->cur_ch_offset; + num++; + continue; + } + + if (ch_ret != mlmeext->cur_channel) { + num = 0; + break; + } + + if (bw_ret < mlmeext->cur_bwmode) { + bw_ret = mlmeext->cur_bwmode; + offset_ret = mlmeext->cur_ch_offset; + } else if (bw_ret == mlmeext->cur_bwmode && offset_ret != mlmeext->cur_ch_offset) { + num = 0; + break; + } + + num++; + } + + if (num) { + if (ch) + *ch = ch_ret; + if (bw) + *bw = bw_ret; + if (offset) + *offset = offset_ret; + } + + return num; +} + +inline int rtw_mi_get_ch_setting_union(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset) +{ + return _rtw_mi_get_ch_setting_union(adapter, ch, bw, offset, 1); +} + +inline int rtw_mi_get_ch_setting_union_no_self(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset) +{ + return _rtw_mi_get_ch_setting_union(adapter, ch, bw, offset, 0); +} + +/* For now, not return union_ch/bw/offset */ +void _rtw_mi_status(_adapter *adapter, struct mi_state *mstate, bool include_self) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + _adapter *iface; + int i; + + _rtw_memset(mstate, 0, sizeof(struct mi_state)); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + + if (include_self == _FALSE && iface == adapter) + continue; + + if (check_fwstate(&iface->mlmepriv, WIFI_STATION_STATE) == _TRUE) { + MSTATE_STA_NUM(mstate)++; + if (check_fwstate(&iface->mlmepriv, _FW_LINKED) == _TRUE) + MSTATE_STA_LD_NUM(mstate)++; + + if (check_fwstate(&iface->mlmepriv, _FW_UNDER_LINKING) == _TRUE) + MSTATE_STA_LG_NUM(mstate)++; + + } else if (check_fwstate(&iface->mlmepriv, WIFI_AP_STATE) == _TRUE + && check_fwstate(&iface->mlmepriv, _FW_LINKED) == _TRUE + ) { + MSTATE_AP_NUM(mstate)++; + if (iface->stapriv.asoc_sta_count > 2) + MSTATE_AP_LD_NUM(mstate)++; + + } else if (check_fwstate(&iface->mlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE) == _TRUE + && check_fwstate(&iface->mlmepriv, _FW_LINKED) == _TRUE + ) { + MSTATE_ADHOC_NUM(mstate)++; + if (iface->stapriv.asoc_sta_count > 2) + MSTATE_ADHOC_LD_NUM(mstate)++; + } + + if (check_fwstate(&iface->mlmepriv, WIFI_UNDER_WPS) == _TRUE) + MSTATE_WPS_NUM(mstate)++; + +#ifdef CONFIG_IOCTL_CFG80211 + if (rtw_cfg80211_get_is_mgmt_tx(iface)) + MSTATE_MGMT_TX_NUM(mstate)++; + #ifdef CONFIG_P2P + if (rtw_cfg80211_get_is_roch(iface) == _TRUE) + MSTATE_ROCH_NUM(mstate)++; + #endif +#endif /* CONFIG_IOCTL_CFG80211 */ + + } +} + +inline void rtw_mi_status(_adapter *adapter, struct mi_state *mstate) +{ + return _rtw_mi_status(adapter, mstate, 1); +} +inline void rtw_mi_status_no_self(_adapter *adapter, struct mi_state *mstate) +{ + return _rtw_mi_status(adapter, mstate, 0); +} +void dump_mi_status(void *sel, struct dvobj_priv *dvobj) +{ + RTW_PRINT_SEL(sel, "== dvobj-iface_state ==\n"); + RTW_PRINT_SEL(sel, "sta_num:%d\n", DEV_STA_NUM(dvobj)); + RTW_PRINT_SEL(sel, "linking_sta_num:%d\n", DEV_STA_LG_NUM(dvobj)); + RTW_PRINT_SEL(sel, "linked_sta_num:%d\n", DEV_STA_LD_NUM(dvobj)); + RTW_PRINT_SEL(sel, "ap_num:%d\n", DEV_AP_NUM(dvobj)); + RTW_PRINT_SEL(sel, "linked_ap_num:%d\n", DEV_AP_LD_NUM(dvobj)); + RTW_PRINT_SEL(sel, "adhoc_num:%d\n", DEV_ADHOC_NUM(dvobj)); + RTW_PRINT_SEL(sel, "linked_adhoc_num:%d\n", DEV_ADHOC_LD_NUM(dvobj)); +#ifdef CONFIG_P2P + RTW_PRINT_SEL(sel, "p2p_device_num:%d\n", rtw_mi_stay_in_p2p_mode(dvobj->padapters[IFACE_ID0])); +#endif +#if defined(CONFIG_IOCTL_CFG80211) + #if defined(CONFIG_P2P) + RTW_PRINT_SEL(sel, "roch_num:%d\n", DEV_ROCH_NUM(dvobj)); + #endif + RTW_PRINT_SEL(sel, "mgmt_tx_num:%d\n", DEV_MGMT_TX_NUM(dvobj)); +#endif + RTW_PRINT_SEL(sel, "under_wps_num:%d\n", DEV_WPS_NUM(dvobj)); + RTW_PRINT_SEL(sel, "union_ch:%d\n", DEV_U_CH(dvobj)); + RTW_PRINT_SEL(sel, "union_bw:%d\n", DEV_U_BW(dvobj)); + RTW_PRINT_SEL(sel, "union_offset:%d\n", DEV_U_OFFSET(dvobj)); + RTW_PRINT_SEL(sel, "================\n\n"); +} + +void dump_dvobj_mi_status(void *sel, const char *fun_name, _adapter *adapter) +{ + RTW_INFO("\n[ %s ] call %s\n", fun_name, __func__); + dump_mi_status(sel, adapter_to_dvobj(adapter)); +} + +inline void rtw_mi_update_iface_status(struct mlme_priv *pmlmepriv, sint state) +{ + _adapter *adapter = container_of(pmlmepriv, _adapter, mlmepriv); + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mi_state *iface_state = &dvobj->iface_state; + struct mi_state tmp_mstate; + u8 i; + u8 u_ch, u_offset, u_bw; + _adapter *iface; + + if (state == WIFI_MONITOR_STATE + || state == WIFI_SITE_MONITOR + || state == 0xFFFFFFFF + ) + return; + + if (0) + RTW_INFO("%s => will change or clean state to 0x%08x\n", __func__, state); + + rtw_mi_status(adapter, &tmp_mstate); + _rtw_memcpy(iface_state, &tmp_mstate, sizeof(struct mi_state)); + + if (rtw_mi_get_ch_setting_union(adapter, &u_ch, &u_bw, &u_offset)) + rtw_mi_update_union_chan_inf(adapter , u_ch, u_offset , u_bw); + else { + if (0) { + dump_adapters_status(RTW_DBGDUMP , dvobj); + RTW_INFO("%s-[ERROR] cannot get union channel\n", __func__); + rtw_warn_on(1); + } + } + +#ifdef DBG_IFACE_STATUS + DBG_IFACE_STATUS_DUMP(adapter); +#endif +} +u8 rtw_mi_check_status(_adapter *adapter, u8 type) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mi_state *iface_state = &dvobj->iface_state; + u8 ret = _FALSE; + +#ifdef DBG_IFACE_STATUS + DBG_IFACE_STATUS_DUMP(adapter); + RTW_INFO("%s-"ADPT_FMT" check type:%d\n", __func__, ADPT_ARG(adapter), type); +#endif + + switch (type) { + case MI_LINKED: + if (MSTATE_STA_LD_NUM(iface_state) || MSTATE_AP_NUM(iface_state) || MSTATE_ADHOC_NUM(iface_state)) /*check_fwstate(&iface->mlmepriv, _FW_LINKED)*/ + ret = _TRUE; + break; + case MI_ASSOC: + if (MSTATE_STA_LD_NUM(iface_state) || MSTATE_AP_LD_NUM(iface_state) || MSTATE_ADHOC_LD_NUM(iface_state)) + ret = _TRUE; + break; + case MI_UNDER_WPS: + if (MSTATE_WPS_NUM(iface_state)) + ret = _TRUE; + break; + + case MI_AP_MODE: + if (MSTATE_AP_NUM(iface_state)) + ret = _TRUE; + break; + case MI_AP_ASSOC: + if (MSTATE_AP_LD_NUM(iface_state)) + ret = _TRUE; + break; + + case MI_ADHOC: + if (MSTATE_ADHOC_NUM(iface_state)) + ret = _TRUE; + break; + case MI_ADHOC_ASSOC: + if (MSTATE_ADHOC_LD_NUM(iface_state)) + ret = _TRUE; + break; + + case MI_STA_NOLINK: /* this is misleading, but not used now */ + if (MSTATE_STA_NUM(iface_state) && (!(MSTATE_STA_LD_NUM(iface_state) || MSTATE_STA_LG_NUM(iface_state)))) + ret = _TRUE; + break; + case MI_STA_LINKED: + if (MSTATE_STA_LD_NUM(iface_state)) + ret = _TRUE; + break; + case MI_STA_LINKING: + if (MSTATE_STA_LG_NUM(iface_state)) + ret = _TRUE; + break; + + default: + break; + } + return ret; +} + +u8 rtw_mi_mp_mode_check(_adapter *padapter) +{ +#ifdef CONFIG_MP_INCLUDED +#ifdef CONFIG_CONCURRENT_MODE + int i; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + _adapter *iface = NULL; + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + + if ((iface) && (iface->registrypriv.mp_mode == 1)) + return _TRUE; + } +#else + if (padapter->registrypriv.mp_mode == 1) + return _TRUE; +#endif +#endif /* CONFIG_MP_INCLUDED */ + return _FALSE; +} + +/* +* return value : 0 is failed or have not interface meet condition +* return value : !0 is success or interface numbers which meet condition +* return value of ops_func must be _TRUE or _FALSE +*/ +static u8 _rtw_mi_process(_adapter *padapter, bool exclude_self, + void *data, u8(*ops_func)(_adapter *padapter, void *data)) +{ + int i; + _adapter *iface; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + + u8 ret = 0; + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if ((iface) && rtw_is_adapter_up(iface)) { + + if ((exclude_self) && (iface == padapter)) + continue; + + if (ops_func) + if (_TRUE == ops_func(iface, data)) + ret++; + } + } + return ret; +} +static u8 _rtw_mi_netif_stop_queue(_adapter *padapter, void *data) +{ + bool carrier_off = *(bool *)data; + struct net_device *pnetdev = padapter->pnetdev; + + if (carrier_off) + netif_carrier_off(pnetdev); + rtw_netif_stop_queue(pnetdev); + return _TRUE; +} +u8 rtw_mi_netif_stop_queue(_adapter *padapter, bool carrier_off) +{ + bool in_data = carrier_off; + + return _rtw_mi_process(padapter, _FALSE, &in_data, _rtw_mi_netif_stop_queue); +} +u8 rtw_mi_buddy_netif_stop_queue(_adapter *padapter, bool carrier_off) +{ + bool in_data = carrier_off; + + return _rtw_mi_process(padapter, _TRUE, &in_data, _rtw_mi_netif_stop_queue); +} + +static u8 _rtw_mi_netif_wake_queue(_adapter *padapter, void *data) +{ + struct net_device *pnetdev = padapter->pnetdev; + + if (pnetdev) + rtw_netif_wake_queue(pnetdev); + return _TRUE; +} +u8 rtw_mi_netif_wake_queue(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_netif_wake_queue); +} +u8 rtw_mi_buddy_netif_wake_queue(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_netif_wake_queue); +} + +static u8 _rtw_mi_netif_carrier_on(_adapter *padapter, void *data) +{ + struct net_device *pnetdev = padapter->pnetdev; + + if (pnetdev) + rtw_netif_carrier_on(pnetdev); + return _TRUE; +} +u8 rtw_mi_netif_carrier_on(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_netif_carrier_on); +} +u8 rtw_mi_buddy_netif_carrier_on(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_netif_carrier_on); +} + +static u8 _rtw_mi_scan_abort(_adapter *adapter, void *data) +{ + bool bwait = *(bool *)data; + + if (bwait) + rtw_scan_abort(adapter); + else + rtw_scan_abort_no_wait(adapter); + + return _TRUE; +} +void rtw_mi_scan_abort(_adapter *adapter, bool bwait) +{ + bool in_data = bwait; + + _rtw_mi_process(adapter, _FALSE, &in_data, _rtw_mi_scan_abort); + +} +void rtw_mi_buddy_scan_abort(_adapter *adapter, bool bwait) +{ + bool in_data = bwait; + + _rtw_mi_process(adapter, _TRUE, &in_data, _rtw_mi_scan_abort); +} + +static u8 _rtw_mi_start_drv_threads(_adapter *adapter, void *data) +{ + rtw_start_drv_threads(adapter); + return _TRUE; +} +void rtw_mi_start_drv_threads(_adapter *adapter) +{ + _rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_start_drv_threads); +} +void rtw_mi_buddy_start_drv_threads(_adapter *adapter) +{ + _rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_start_drv_threads); +} + +static u8 _rtw_mi_stop_drv_threads(_adapter *adapter, void *data) +{ + rtw_stop_drv_threads(adapter); + return _TRUE; +} +void rtw_mi_stop_drv_threads(_adapter *adapter) +{ + _rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_stop_drv_threads); +} +void rtw_mi_buddy_stop_drv_threads(_adapter *adapter) +{ + _rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_stop_drv_threads); +} + +static u8 _rtw_mi_cancel_all_timer(_adapter *adapter, void *data) +{ + rtw_cancel_all_timer(adapter); + return _TRUE; +} +void rtw_mi_cancel_all_timer(_adapter *adapter) +{ + _rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_cancel_all_timer); +} +void rtw_mi_buddy_cancel_all_timer(_adapter *adapter) +{ + _rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_cancel_all_timer); +} + +static u8 _rtw_mi_reset_drv_sw(_adapter *adapter, void *data) +{ + rtw_reset_drv_sw(adapter); + return _TRUE; +} +void rtw_mi_reset_drv_sw(_adapter *adapter) +{ + _rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_reset_drv_sw); +} +void rtw_mi_buddy_reset_drv_sw(_adapter *adapter) +{ + _rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_reset_drv_sw); +} + +static u8 _rtw_mi_intf_start(_adapter *adapter, void *data) +{ + rtw_intf_start(adapter); + return _TRUE; +} +void rtw_mi_intf_start(_adapter *adapter) +{ + _rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_intf_start); +} +void rtw_mi_buddy_intf_start(_adapter *adapter) +{ + _rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_intf_start); +} + +static u8 _rtw_mi_intf_stop(_adapter *adapter, void *data) +{ + rtw_intf_stop(adapter); + return _TRUE; +} +void rtw_mi_intf_stop(_adapter *adapter) +{ + _rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_intf_stop); +} +void rtw_mi_buddy_intf_stop(_adapter *adapter) +{ + _rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_intf_stop); +} + +static u8 _rtw_mi_suspend_free_assoc_resource(_adapter *padapter, void *data) +{ + return rtw_suspend_free_assoc_resource(padapter); +} +void rtw_mi_suspend_free_assoc_resource(_adapter *adapter) +{ + _rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_suspend_free_assoc_resource); +} +void rtw_mi_buddy_suspend_free_assoc_resource(_adapter *adapter) +{ + _rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_suspend_free_assoc_resource); +} + +static u8 _rtw_mi_is_scan_deny(_adapter *adapter, void *data) +{ + return rtw_is_scan_deny(adapter); +} + +u8 rtw_mi_is_scan_deny(_adapter *adapter) +{ + return _rtw_mi_process(adapter, _FALSE, NULL, _rtw_mi_is_scan_deny); + +} +u8 rtw_mi_buddy_is_scan_deny(_adapter *adapter) +{ + return _rtw_mi_process(adapter, _TRUE, NULL, _rtw_mi_is_scan_deny); +} + +#ifdef CONFIG_SET_SCAN_DENY_TIMER +static u8 _rtw_mi_set_scan_deny(_adapter *adapter, void *data) +{ + u32 ms = *(u32 *)data; + + rtw_set_scan_deny(adapter, ms); + return _TRUE; +} +void rtw_mi_set_scan_deny(_adapter *adapter, u32 ms) +{ + u32 in_data = ms; + + _rtw_mi_process(adapter, _FALSE, &in_data, _rtw_mi_set_scan_deny); +} +void rtw_mi_buddy_set_scan_deny(_adapter *adapter, u32 ms) +{ + u32 in_data = ms; + + _rtw_mi_process(adapter, _TRUE, &in_data, _rtw_mi_set_scan_deny); +} +#endif + +struct nulldata_param { + unsigned char *da; + unsigned int power_mode; + int try_cnt; + int wait_ms; +}; + +static u8 _rtw_mi_issue_nulldata(_adapter *padapter, void *data) +{ + struct nulldata_param *pnulldata_param = (struct nulldata_param *)data; + + if (is_client_associated_to_ap(padapter) == _TRUE) { + /* TODO: TDLS peers */ + issue_nulldata(padapter, pnulldata_param->da, pnulldata_param->power_mode, pnulldata_param->try_cnt, pnulldata_param->wait_ms); + return _TRUE; + } + return _FALSE; +} + +u8 rtw_mi_issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms) +{ + struct nulldata_param nparam; + + nparam.da = da; + nparam.power_mode = power_mode;/*0 or 1*/ + nparam.try_cnt = try_cnt; + nparam.wait_ms = wait_ms; + + return _rtw_mi_process(padapter, _FALSE, &nparam, _rtw_mi_issue_nulldata); +} +u8 rtw_mi_buddy_issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms) +{ + struct nulldata_param nparam; + + nparam.da = da; + nparam.power_mode = power_mode; + nparam.try_cnt = try_cnt; + nparam.wait_ms = wait_ms; + + return _rtw_mi_process(padapter, _TRUE, &nparam, _rtw_mi_issue_nulldata); +} + +static u8 _rtw_mi_beacon_update(_adapter *padapter, void *data) +{ + struct mlme_ext_priv *mlmeext = &padapter->mlmeextpriv; + + if (mlmeext_msr(mlmeext) == WIFI_FW_AP_STATE + && check_fwstate(&padapter->mlmepriv, _FW_LINKED) == _TRUE) { + RTW_INFO(ADPT_FMT"-WIFI_FW_AP_STATE - update_beacon\n", ADPT_ARG(padapter)); + update_beacon(padapter, 0, NULL, _TRUE); + } + return _TRUE; +} + +void rtw_mi_beacon_update(_adapter *padapter) +{ + _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_beacon_update); +} + +void rtw_mi_buddy_beacon_update(_adapter *padapter) +{ + _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_beacon_update); +} + +static u8 _rtw_mi_hal_dump_macaddr(_adapter *padapter, void *data) +{ + u8 mac_addr[ETH_ALEN] = {0}; + + rtw_hal_get_macaddr_port(padapter, mac_addr); + RTW_INFO(ADPT_FMT"MAC Address ="MAC_FMT"\n", ADPT_ARG(padapter), MAC_ARG(mac_addr)); + return _TRUE; +} +void rtw_mi_hal_dump_macaddr(_adapter *padapter) +{ + _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_hal_dump_macaddr); +} +void rtw_mi_buddy_hal_dump_macaddr(_adapter *padapter) +{ + _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_hal_dump_macaddr); +} + +#ifdef CONFIG_PCI_HCI +static u8 _rtw_mi_xmit_tasklet_schedule(_adapter *padapter, void *data) +{ + if (rtw_txframes_pending(padapter)) { + /* try to deal with the pending packets */ + tasklet_hi_schedule(&(padapter->xmitpriv.xmit_tasklet)); + } + return _TRUE; +} +void rtw_mi_xmit_tasklet_schedule(_adapter *padapter) +{ + _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_xmit_tasklet_schedule); +} +void rtw_mi_buddy_xmit_tasklet_schedule(_adapter *padapter) +{ + _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_xmit_tasklet_schedule); +} +#endif + +u8 _rtw_mi_busy_traffic_check(_adapter *padapter, void *data) +{ + u32 passtime; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + bool check_sc_interval = *(bool *)data; + + if (pmlmepriv->LinkDetectInfo.bBusyTraffic == _TRUE) { + if (check_sc_interval) { + /* Miracast can't do AP scan*/ + passtime = rtw_get_passing_time_ms(pmlmepriv->lastscantime); + pmlmepriv->lastscantime = rtw_get_current_time(); + if (passtime > BUSY_TRAFFIC_SCAN_DENY_PERIOD) { + RTW_INFO(ADPT_FMT" bBusyTraffic == _TRUE\n", ADPT_ARG(padapter)); + return _TRUE; + } + } else + return _TRUE; + } + + return _FALSE; +} + +u8 rtw_mi_busy_traffic_check(_adapter *padapter, bool check_sc_interval) +{ + bool in_data = check_sc_interval; + + return _rtw_mi_process(padapter, _FALSE, &in_data, _rtw_mi_busy_traffic_check); +} +u8 rtw_mi_buddy_busy_traffic_check(_adapter *padapter, bool check_sc_interval) +{ + bool in_data = check_sc_interval; + + return _rtw_mi_process(padapter, _TRUE, &in_data, _rtw_mi_busy_traffic_check); +} +static u8 _rtw_mi_check_mlmeinfo_state(_adapter *padapter, void *data) +{ + u32 state = *(u32 *)data; + struct mlme_ext_priv *mlmeext = &padapter->mlmeextpriv; + + /*if (mlmeext_msr(mlmeext) == state)*/ + if (check_mlmeinfo_state(mlmeext, state)) + return _TRUE; + else + return _FALSE; +} + +u8 rtw_mi_check_mlmeinfo_state(_adapter *padapter, u32 state) +{ + u32 in_data = state; + + return _rtw_mi_process(padapter, _FALSE, &in_data, _rtw_mi_check_mlmeinfo_state); +} + +u8 rtw_mi_buddy_check_mlmeinfo_state(_adapter *padapter, u32 state) +{ + u32 in_data = state; + + return _rtw_mi_process(padapter, _TRUE, &in_data, _rtw_mi_check_mlmeinfo_state); +} + +/*#define DBG_DUMP_FW_STATE*/ +#ifdef DBG_DUMP_FW_STATE +static void rtw_dbg_dump_fwstate(_adapter *padapter, sint state) +{ + u8 buf[32] = {0}; + + if (state & WIFI_FW_NULL_STATE) { + _rtw_memset(buf, 0, 32); + sprintf(buf, "WIFI_FW_NULL_STATE"); + RTW_INFO(FUNC_ADPT_FMT"fwstate-%s\n", FUNC_ADPT_ARG(padapter), buf); + } + + if (state & _FW_LINKED) { + _rtw_memset(buf, 0, 32); + sprintf(buf, "_FW_LINKED"); + RTW_INFO(FUNC_ADPT_FMT"fwstate-%s\n", FUNC_ADPT_ARG(padapter), buf); + } + + if (state & _FW_UNDER_LINKING) { + _rtw_memset(buf, 0, 32); + sprintf(buf, "_FW_UNDER_LINKING"); + RTW_INFO(FUNC_ADPT_FMT"fwstate-%s\n", FUNC_ADPT_ARG(padapter), buf); + } + + if (state & _FW_UNDER_SURVEY) { + _rtw_memset(buf, 0, 32); + sprintf(buf, "_FW_UNDER_SURVEY"); + RTW_INFO(FUNC_ADPT_FMT"fwstate-%s\n", FUNC_ADPT_ARG(padapter), buf); + } +} +#endif + +static u8 _rtw_mi_check_fwstate(_adapter *padapter, void *data) +{ + u8 ret = _FALSE; + + sint state = *(sint *)data; + + if ((state == WIFI_FW_NULL_STATE) && + (padapter->mlmepriv.fw_state == WIFI_FW_NULL_STATE)) + ret = _TRUE; + else if (_TRUE == check_fwstate(&padapter->mlmepriv, state)) + ret = _TRUE; +#ifdef DBG_DUMP_FW_STATE + if (ret) + rtw_dbg_dump_fwstate(padapter, state); +#endif + return ret; +} +u8 rtw_mi_check_fwstate(_adapter *padapter, sint state) +{ + sint in_data = state; + + return _rtw_mi_process(padapter, _FALSE, &in_data, _rtw_mi_check_fwstate); +} +u8 rtw_mi_buddy_check_fwstate(_adapter *padapter, sint state) +{ + sint in_data = state; + + return _rtw_mi_process(padapter, _TRUE, &in_data, _rtw_mi_check_fwstate); +} + +static u8 _rtw_mi_traffic_statistics(_adapter *padapter , void *data) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); + + /* Tx */ + pdvobjpriv->traffic_stat.tx_bytes += padapter->xmitpriv.tx_bytes; + pdvobjpriv->traffic_stat.tx_pkts += padapter->xmitpriv.tx_pkts; + pdvobjpriv->traffic_stat.tx_drop += padapter->xmitpriv.tx_drop; + + /* Rx */ + pdvobjpriv->traffic_stat.rx_bytes += padapter->recvpriv.rx_bytes; + pdvobjpriv->traffic_stat.rx_pkts += padapter->recvpriv.rx_pkts; + pdvobjpriv->traffic_stat.rx_drop += padapter->recvpriv.rx_drop; + return _TRUE; +} +u8 rtw_mi_traffic_statistics(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_traffic_statistics); +} + +static u8 _rtw_mi_check_miracast_enabled(_adapter *padapter , void *data) +{ + return is_miracast_enabled(padapter); +} +u8 rtw_mi_check_miracast_enabled(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_check_miracast_enabled); +} + +#ifdef CONFIG_XMIT_THREAD_MODE +static u8 _rtw_mi_check_pending_xmitbuf(_adapter *padapter , void *data) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + return check_pending_xmitbuf(pxmitpriv); +} +u8 rtw_mi_check_pending_xmitbuf(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_check_pending_xmitbuf); +} +u8 rtw_mi_buddy_check_pending_xmitbuf(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_check_pending_xmitbuf); +} +#endif + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) +static u8 _rtw_mi_dequeue_writeport(_adapter *padapter , bool exclude_self) +{ + int i; + u8 queue_empty = _TRUE; + _adapter *iface; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if ((iface) && rtw_is_adapter_up(iface)) { + + if ((exclude_self) && (iface == padapter)) + continue; + + queue_empty &= _dequeue_writeport(iface); + } + } + return queue_empty; +} +u8 rtw_mi_dequeue_writeport(_adapter *padapter) +{ + return _rtw_mi_dequeue_writeport(padapter, _FALSE); +} +u8 rtw_mi_buddy_dequeue_writeport(_adapter *padapter) +{ + return _rtw_mi_dequeue_writeport(padapter, _TRUE); +} +#endif +static void _rtw_mi_adapter_reset(_adapter *padapter , u8 exclude_self) +{ + int i; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + + for (i = 0; i < dvobj->iface_nums; i++) { + if (dvobj->padapters[i]) { + if ((exclude_self) && (dvobj->padapters[i] == padapter)) + continue; + dvobj->padapters[i] = NULL; + } + } +} + +void rtw_mi_adapter_reset(_adapter *padapter) +{ + _rtw_mi_adapter_reset(padapter, _FALSE); +} + +void rtw_mi_buddy_adapter_reset(_adapter *padapter) +{ + _rtw_mi_adapter_reset(padapter, _TRUE); +} + +static u8 _rtw_mi_dynamic_check_timer_handlder(_adapter *adapter, void *data) +{ + rtw_iface_dynamic_check_timer_handlder(adapter); + return _TRUE; +} +u8 rtw_mi_dynamic_check_timer_handlder(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_dynamic_check_timer_handlder); +} +u8 rtw_mi_buddy_dynamic_check_timer_handlder(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_dynamic_check_timer_handlder); +} + +static u8 _rtw_mi_dev_unload(_adapter *adapter, void *data) +{ + rtw_dev_unload(adapter); + return _TRUE; +} +u8 rtw_mi_dev_unload(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_dev_unload); +} +u8 rtw_mi_buddy_dev_unload(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_dev_unload); +} + +static u8 _rtw_mi_dynamic_chk_wk_hdl(_adapter *adapter, void *data) +{ + rtw_iface_dynamic_chk_wk_hdl(adapter); + return _TRUE; +} +u8 rtw_mi_dynamic_chk_wk_hdl(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_dynamic_chk_wk_hdl); +} +u8 rtw_mi_buddy_dynamic_chk_wk_hdl(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_dynamic_chk_wk_hdl); +} + +static u8 _rtw_mi_os_xmit_schedule(_adapter *adapter, void *data) +{ + rtw_os_xmit_schedule(adapter); + return _TRUE; +} +u8 rtw_mi_os_xmit_schedule(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_os_xmit_schedule); +} +u8 rtw_mi_buddy_os_xmit_schedule(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_os_xmit_schedule); +} + +static u8 _rtw_mi_report_survey_event(_adapter *adapter, void *data) +{ + union recv_frame *precv_frame = (union recv_frame *)data; + + report_survey_event(adapter, precv_frame); + return _TRUE; +} +u8 rtw_mi_report_survey_event(_adapter *padapter, union recv_frame *precv_frame) +{ + return _rtw_mi_process(padapter, _FALSE, precv_frame, _rtw_mi_report_survey_event); +} +u8 rtw_mi_buddy_report_survey_event(_adapter *padapter, union recv_frame *precv_frame) +{ + return _rtw_mi_process(padapter, _TRUE, precv_frame, _rtw_mi_report_survey_event); +} + +static u8 _rtw_mi_sreset_adapter_hdl(_adapter *adapter, void *data) +{ + u8 bstart = *(u8 *)data; + + if (bstart) + sreset_start_adapter(adapter); + else + sreset_stop_adapter(adapter); + return _TRUE; +} +u8 rtw_mi_sreset_adapter_hdl(_adapter *padapter, u8 bstart) +{ + u8 in_data = bstart; + + return _rtw_mi_process(padapter, _FALSE, &in_data, _rtw_mi_sreset_adapter_hdl); +} +u8 rtw_mi_buddy_sreset_adapter_hdl(_adapter *padapter, u8 bstart) +{ + u8 in_data = bstart; + + return _rtw_mi_process(padapter, _TRUE, &in_data, _rtw_mi_sreset_adapter_hdl); +} +static u8 _rtw_mi_tx_beacon_hdl(_adapter *adapter, void *data) +{ + if (check_fwstate(&adapter->mlmepriv, WIFI_AP_STATE) == _TRUE + && check_fwstate(&adapter->mlmepriv, WIFI_ASOC_STATE) == _TRUE + ) { + adapter->mlmepriv.update_bcn = _TRUE; +#ifndef CONFIG_INTERRUPT_BASED_TXBCN +#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + tx_beacon_hdl(adapter, NULL); +#endif +#endif + } + return _TRUE; +} +u8 rtw_mi_tx_beacon_hdl(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_tx_beacon_hdl); +} +u8 rtw_mi_buddy_tx_beacon_hdl(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_sreset_adapter_hdl); +} + +static u8 _rtw_mi_set_tx_beacon_cmd(_adapter *adapter, void *data) +{ + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + if (pmlmepriv->update_bcn == _TRUE) + set_tx_beacon_cmd(adapter); + } + return _TRUE; +} +u8 rtw_mi_set_tx_beacon_cmd(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_set_tx_beacon_cmd); +} +u8 rtw_mi_buddy_set_tx_beacon_cmd(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_set_tx_beacon_cmd); +} + +#ifdef CONFIG_P2P +static u8 _rtw_mi_p2p_chk_state(_adapter *adapter, void *data) +{ + struct wifidirect_info *pwdinfo = &(adapter->wdinfo); + enum P2P_STATE state = *(enum P2P_STATE *)data; + + return rtw_p2p_chk_state(pwdinfo, state); +} +u8 rtw_mi_p2p_chk_state(_adapter *padapter, enum P2P_STATE p2p_state) +{ + u8 in_data = p2p_state; + + return _rtw_mi_process(padapter, _FALSE, &in_data, _rtw_mi_p2p_chk_state); +} +u8 rtw_mi_buddy_p2p_chk_state(_adapter *padapter, enum P2P_STATE p2p_state) +{ + u8 in_data = p2p_state; + + return _rtw_mi_process(padapter, _TRUE, &in_data, _rtw_mi_p2p_chk_state); +} +static u8 _rtw_mi_stay_in_p2p_mode(_adapter *adapter, void *data) +{ + struct wifidirect_info *pwdinfo = &(adapter->wdinfo); + + if (rtw_p2p_role(pwdinfo) != P2P_ROLE_DISABLE) + return _TRUE; + return _FALSE; +} +u8 rtw_mi_stay_in_p2p_mode(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _FALSE, NULL, _rtw_mi_stay_in_p2p_mode); +} +u8 rtw_mi_buddy_stay_in_p2p_mode(_adapter *padapter) +{ + return _rtw_mi_process(padapter, _TRUE, NULL, _rtw_mi_stay_in_p2p_mode); +} +#endif /*CONFIG_P2P*/ + +_adapter *rtw_get_iface_by_id(_adapter *padapter, u8 iface_id) +{ + _adapter *iface = NULL; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + + if ((padapter == NULL) || (iface_id >= CONFIG_IFACE_NUMBER)) { + rtw_warn_on(1); + return iface; + } + + return dvobj->padapters[iface_id]; +} + +_adapter *rtw_get_iface_by_macddr(_adapter *padapter, u8 *mac_addr) +{ + int i; + _adapter *iface = NULL; + u8 bmatch = _FALSE; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if ((iface) && (_rtw_memcmp(mac_addr, adapter_mac_addr(iface), ETH_ALEN))) { + bmatch = _TRUE; + break; + } + } + if (bmatch) + return iface; + else + return NULL; +} + +_adapter *rtw_get_iface_by_hwport(_adapter *padapter, u8 hw_port) +{ + int i; + _adapter *iface = NULL; + u8 bmatch = _FALSE; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if ((iface) && (hw_port == iface->hw_port)) { + bmatch = _TRUE; + break; + } + } + if (bmatch) + return iface; + else + return NULL; +} + +/*#define CONFIG_SKB_ALLOCATED*/ +#define DBG_SKB_PROCESS +#ifdef DBG_SKB_PROCESS +void rtw_dbg_skb_process(_adapter *padapter, union recv_frame *precvframe, union recv_frame *pcloneframe) +{ + _pkt *pkt_copy, *pkt_org; + + pkt_org = precvframe->u.hdr.pkt; + pkt_copy = pcloneframe->u.hdr.pkt; + /* + RTW_INFO("%s ===== ORG SKB =====\n", __func__); + RTW_INFO(" SKB head(%p)\n", pkt_org->head); + RTW_INFO(" SKB data(%p)\n", pkt_org->data); + RTW_INFO(" SKB tail(%p)\n", pkt_org->tail); + RTW_INFO(" SKB end(%p)\n", pkt_org->end); + + RTW_INFO(" recv frame head(%p)\n", precvframe->u.hdr.rx_head); + RTW_INFO(" recv frame data(%p)\n", precvframe->u.hdr.rx_data); + RTW_INFO(" recv frame tail(%p)\n", precvframe->u.hdr.rx_tail); + RTW_INFO(" recv frame end(%p)\n", precvframe->u.hdr.rx_end); + + RTW_INFO("%s ===== COPY SKB =====\n", __func__); + RTW_INFO(" SKB head(%p)\n", pkt_copy->head); + RTW_INFO(" SKB data(%p)\n", pkt_copy->data); + RTW_INFO(" SKB tail(%p)\n", pkt_copy->tail); + RTW_INFO(" SKB end(%p)\n", pkt_copy->end); + + RTW_INFO(" recv frame head(%p)\n", pcloneframe->u.hdr.rx_head); + RTW_INFO(" recv frame data(%p)\n", pcloneframe->u.hdr.rx_data); + RTW_INFO(" recv frame tail(%p)\n", pcloneframe->u.hdr.rx_tail); + RTW_INFO(" recv frame end(%p)\n", pcloneframe->u.hdr.rx_end); + */ + /* + RTW_INFO("%s => recv_frame adapter(%p,%p)\n", __func__, precvframe->u.hdr.adapter, pcloneframe->u.hdr.adapter); + RTW_INFO("%s => recv_frame dev(%p,%p)\n", __func__, pkt_org->dev , pkt_copy->dev); + RTW_INFO("%s => recv_frame len(%d,%d)\n", __func__, precvframe->u.hdr.len, pcloneframe->u.hdr.len); + */ + if (precvframe->u.hdr.len != pcloneframe->u.hdr.len) + RTW_INFO("%s [WARN] recv_frame length(%d:%d) compare failed\n", __func__, precvframe->u.hdr.len, pcloneframe->u.hdr.len); + + if (_rtw_memcmp(&precvframe->u.hdr.attrib, &pcloneframe->u.hdr.attrib, sizeof(struct rx_pkt_attrib)) == _FALSE) + RTW_INFO("%s [WARN] recv_frame attrib compare failed\n", __func__); + + if (_rtw_memcmp(precvframe->u.hdr.rx_data, pcloneframe->u.hdr.rx_data, precvframe->u.hdr.len) == _FALSE) + RTW_INFO("%s [WARN] recv_frame rx_data compare failed\n", __func__); + +} +#endif + +static s32 _rtw_mi_buddy_clone_bcmc_packet(_adapter *adapter, union recv_frame *precvframe, u8 *pphy_status, union recv_frame *pcloneframe) +{ + s32 ret = _SUCCESS; + u8 *pbuf = precvframe->u.hdr.rx_data; + struct rx_pkt_attrib *pattrib = NULL; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); + + if (pcloneframe) { + pcloneframe->u.hdr.adapter = adapter; + + _rtw_init_listhead(&pcloneframe->u.hdr.list); + pcloneframe->u.hdr.precvbuf = NULL; /*can't access the precvbuf for new arch.*/ + pcloneframe->u.hdr.len = 0; + + _rtw_memcpy(&pcloneframe->u.hdr.attrib, &precvframe->u.hdr.attrib, sizeof(struct rx_pkt_attrib)); + + pattrib = &pcloneframe->u.hdr.attrib; +#ifdef CONFIG_SKB_ALLOCATED + if (rtw_os_alloc_recvframe(adapter, pcloneframe, pbuf, NULL) == _SUCCESS) +#else + if (rtw_os_recvframe_duplicate_skb(adapter, pcloneframe, precvframe->u.hdr.pkt) == _SUCCESS) +#endif + { +#ifdef CONFIG_SKB_ALLOCATED + recvframe_put(pcloneframe, pattrib->pkt_len); +#endif + +#ifdef DBG_SKB_PROCESS + rtw_dbg_skb_process(adapter, precvframe, pcloneframe); +#endif + + if (pattrib->physt && pphy_status) + rx_query_phy_status(pcloneframe, pphy_status); + + ret = rtw_recv_entry(pcloneframe); + } else { + ret = -1; + RTW_INFO("%s()-%d: rtw_os_alloc_recvframe() failed!\n", __func__, __LINE__); + } + + } + return ret; +} + +void rtw_mi_buddy_clone_bcmc_packet(_adapter *padapter, union recv_frame *precvframe, u8 *pphy_status) +{ + int i; + s32 ret = _SUCCESS; + _adapter *iface = NULL; + union recv_frame *pcloneframe = NULL; + struct recv_priv *precvpriv = &padapter->recvpriv;/*primary_padapter*/ + _queue *pfree_recv_queue = &precvpriv->free_recv_queue; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (!iface || iface == padapter) + continue; + if (rtw_is_adapter_up(iface) == _FALSE || iface->registered == 0) + continue; + + pcloneframe = rtw_alloc_recvframe(pfree_recv_queue); + if (pcloneframe) { + ret = _rtw_mi_buddy_clone_bcmc_packet(iface, precvframe, pphy_status, pcloneframe); + if (_SUCCESS != ret) { + if (ret == -1) + rtw_free_recvframe(pcloneframe, pfree_recv_queue); + /*RTW_INFO(ADPT_FMT"-clone BC/MC frame failed\n", ADPT_ARG(iface));*/ + } + } + } + +} + +#ifdef CONFIG_PCI_HCI +/*API be created temporary for MI, caller is interrupt-handler, PCIE's interrupt handler cannot apply to multi-AP*/ +_adapter *rtw_mi_get_ap_adapter(_adapter *padapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + int i; + _adapter *iface = NULL; + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (!iface) + continue; + + if (check_fwstate(&iface->mlmepriv, WIFI_AP_STATE) == _TRUE + && check_fwstate(&iface->mlmepriv, WIFI_ASOC_STATE) == _TRUE) + break; + + } + return iface; +} +#endif + +void rtw_mi_update_ap_bmc_camid(_adapter *padapter, u8 camid_a, u8 camid_b) +{ +#ifdef CONFIG_CONCURRENT_MODE + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + + int i; + _adapter *iface = NULL; + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (!iface) + continue; + + if (macid_ctl->iface_bmc[iface->iface_id] != INVALID_SEC_MAC_CAM_ID) { + if (macid_ctl->iface_bmc[iface->iface_id] == camid_a) + macid_ctl->iface_bmc[iface->iface_id] = camid_b; + else if (macid_ctl->iface_bmc[iface->iface_id] == camid_b) + macid_ctl->iface_bmc[iface->iface_id] = camid_a; + iface->securitypriv.dot118021x_bmc_cam_id = macid_ctl->iface_bmc[iface->iface_id]; + } + } +#endif +} diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_mlme.c b/linux-bsp/drivers/rtl8188eus/core/rtw_mlme.c new file mode 100644 index 0000000..e261acb --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_mlme.c @@ -0,0 +1,4669 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_MLME_C_ + +#include <hal_data.h> + +extern void indicate_wx_scan_complete_event(_adapter *padapter); +extern u8 rtw_do_join(_adapter *padapter); + + +sint _rtw_init_mlme_priv(_adapter *padapter) +{ + sint i; + u8 *pbuf; + struct wlan_network *pnetwork; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + sint res = _SUCCESS; + + + /* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */ + /* _rtw_memset((u8 *)pmlmepriv, 0, sizeof(struct mlme_priv)); */ + + + /*qos_priv*/ + /*pmlmepriv->qospriv.qos_option = pregistrypriv->wmm_enable;*/ + + /*ht_priv*/ +#ifdef CONFIG_80211N_HT + pmlmepriv->htpriv.ampdu_enable = _FALSE;/*set to disabled*/ +#endif + + pmlmepriv->nic_hdl = (u8 *)padapter; + + pmlmepriv->pscanned = NULL; + /*pmlmepriv->fw_state = WIFI_STATION_STATE; */ /*Must sync with rtw_wdev_alloc()*/ + /*init_fwstate(pmlmepriv, WIFI_STATION_STATE);*/ + init_fwstate(pmlmepriv, WIFI_NULL_STATE);/*assigned interface role(STA/AP) must after execute set_opmode*/ + + /* wdev->iftype = NL80211_IFTYPE_STATION*/ + pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown; + pmlmepriv->scan_mode = SCAN_ACTIVE; /* 1: active, 0: pasive. Maybe someday we should rename this varable to "active_mode" (Jeff) */ + + _rtw_spinlock_init(&(pmlmepriv->lock)); + _rtw_init_queue(&(pmlmepriv->free_bss_pool)); + _rtw_init_queue(&(pmlmepriv->scanned_queue)); + + set_scanned_network_val(pmlmepriv, 0); + + _rtw_memset(&pmlmepriv->assoc_ssid, 0, sizeof(NDIS_802_11_SSID)); + + pbuf = rtw_zvmalloc(MAX_BSS_CNT * (sizeof(struct wlan_network))); + + if (pbuf == NULL) { + res = _FAIL; + goto exit; + } + pmlmepriv->free_bss_buf = pbuf; + + pnetwork = (struct wlan_network *)pbuf; + + for (i = 0; i < MAX_BSS_CNT; i++) { + _rtw_init_listhead(&(pnetwork->list)); + + rtw_list_insert_tail(&(pnetwork->list), &(pmlmepriv->free_bss_pool.queue)); + + pnetwork++; + } + + /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ + + rtw_clear_scan_deny(padapter); +#ifdef CONFIG_ARP_KEEP_ALIVE + pmlmepriv->bGetGateway = 0; + pmlmepriv->GetGatewayTryCnt = 0; +#endif + +#ifdef CONFIG_LAYER2_ROAMING +#define RTW_ROAM_SCAN_RESULT_EXP_MS (5*1000) +#define RTW_ROAM_RSSI_DIFF_TH 10 +#define RTW_ROAM_SCAN_INTERVAL_MS (10*1000) +#define RTW_ROAM_RSSI_THRESHOLD 70 + + pmlmepriv->roam_flags = 0 + | RTW_ROAM_ON_EXPIRED +#ifdef CONFIG_LAYER2_ROAMING_RESUME + | RTW_ROAM_ON_RESUME +#endif +#ifdef CONFIG_LAYER2_ROAMING_ACTIVE + | RTW_ROAM_ACTIVE +#endif + ; + + pmlmepriv->roam_scanr_exp_ms = RTW_ROAM_SCAN_RESULT_EXP_MS; + pmlmepriv->roam_rssi_diff_th = RTW_ROAM_RSSI_DIFF_TH; + pmlmepriv->roam_scan_int_ms = RTW_ROAM_SCAN_INTERVAL_MS; + pmlmepriv->roam_rssi_threshold = RTW_ROAM_RSSI_THRESHOLD; +#endif /* CONFIG_LAYER2_ROAMING */ + +#ifdef CONFIG_RTW_80211R + memset(&pmlmepriv->ftpriv, 0, sizeof(ft_priv)); + pmlmepriv->ftpriv.ft_flags = 0 + | RTW_FT_STA_SUPPORTED + | RTW_FT_STA_OVER_DS_SUPPORTED + ; +#endif + rtw_init_mlme_timer(padapter); + +exit: + + + return res; +} + +void rtw_mfree_mlme_priv_lock(struct mlme_priv *pmlmepriv); +void rtw_mfree_mlme_priv_lock(struct mlme_priv *pmlmepriv) +{ + _rtw_spinlock_free(&pmlmepriv->lock); + _rtw_spinlock_free(&(pmlmepriv->free_bss_pool.lock)); + _rtw_spinlock_free(&(pmlmepriv->scanned_queue.lock)); +} + +static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen) +{ + if (*ppie) { + rtw_mfree(*ppie, *plen); + *plen = 0; + *ppie = NULL; + } +} + +void rtw_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv) +{ +#if defined(CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) + rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len); + rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len); + rtw_free_mlme_ie_data(&pmlmepriv->wps_beacon_ie, &pmlmepriv->wps_beacon_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_req_ie, &pmlmepriv->wps_probe_req_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_resp_ie, &pmlmepriv->wps_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wps_assoc_resp_ie, &pmlmepriv->wps_assoc_resp_ie_len); + + rtw_free_mlme_ie_data(&pmlmepriv->p2p_beacon_ie, &pmlmepriv->p2p_beacon_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_req_ie, &pmlmepriv->p2p_probe_req_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_resp_ie, &pmlmepriv->p2p_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->p2p_go_probe_resp_ie, &pmlmepriv->p2p_go_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_req_ie, &pmlmepriv->p2p_assoc_req_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_resp_ie, &pmlmepriv->p2p_assoc_resp_ie_len); +#endif + +#if defined(CONFIG_WFD) && defined(CONFIG_IOCTL_CFG80211) + rtw_free_mlme_ie_data(&pmlmepriv->wfd_beacon_ie, &pmlmepriv->wfd_beacon_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_req_ie, &pmlmepriv->wfd_probe_req_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_resp_ie, &pmlmepriv->wfd_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wfd_go_probe_resp_ie, &pmlmepriv->wfd_go_probe_resp_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wfd_assoc_req_ie, &pmlmepriv->wfd_assoc_req_ie_len); + rtw_free_mlme_ie_data(&pmlmepriv->wfd_assoc_resp_ie, &pmlmepriv->wfd_assoc_resp_ie_len); +#endif + +#ifdef CONFIG_RTW_80211R + rtw_free_mlme_ie_data(&pmlmepriv->auth_rsp, &pmlmepriv->auth_rsp_len); +#endif +} + +#if defined(CONFIG_WFD) && defined(CONFIG_IOCTL_CFG80211) +int rtw_mlme_update_wfd_ie_data(struct mlme_priv *mlme, u8 type, u8 *ie, u32 ie_len) +{ + _adapter *adapter = mlme_to_adapter(mlme); + struct wifi_display_info *wfd_info = &adapter->wfd_info; + u8 clear = 0; + u8 **t_ie = NULL; + u32 *t_ie_len = NULL; + int ret = _FAIL; + + if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST)) + goto success; + + if (wfd_info->wfd_enable == _TRUE) + goto success; /* WFD IE is build by self */ + + if (!ie && !ie_len) + clear = 1; + else if (!ie || !ie_len) { + RTW_PRINT(FUNC_ADPT_FMT" type:%u, ie:%p, ie_len:%u" + , FUNC_ADPT_ARG(adapter), type, ie, ie_len); + rtw_warn_on(1); + goto exit; + } + + switch (type) { + case MLME_BEACON_IE: + t_ie = &mlme->wfd_beacon_ie; + t_ie_len = &mlme->wfd_beacon_ie_len; + break; + case MLME_PROBE_REQ_IE: + t_ie = &mlme->wfd_probe_req_ie; + t_ie_len = &mlme->wfd_probe_req_ie_len; + break; + case MLME_PROBE_RESP_IE: + t_ie = &mlme->wfd_probe_resp_ie; + t_ie_len = &mlme->wfd_probe_resp_ie_len; + break; + case MLME_GO_PROBE_RESP_IE: + t_ie = &mlme->wfd_go_probe_resp_ie; + t_ie_len = &mlme->wfd_go_probe_resp_ie_len; + break; + case MLME_ASSOC_REQ_IE: + t_ie = &mlme->wfd_assoc_req_ie; + t_ie_len = &mlme->wfd_assoc_req_ie_len; + break; + case MLME_ASSOC_RESP_IE: + t_ie = &mlme->wfd_assoc_resp_ie; + t_ie_len = &mlme->wfd_assoc_resp_ie_len; + break; + default: + RTW_PRINT(FUNC_ADPT_FMT" unsupported type:%u" + , FUNC_ADPT_ARG(adapter), type); + rtw_warn_on(1); + goto exit; + } + + if (*t_ie) { + u32 free_len = *t_ie_len; + *t_ie_len = 0; + rtw_mfree(*t_ie, free_len); + *t_ie = NULL; + } + + if (!clear) { + *t_ie = rtw_malloc(ie_len); + if (*t_ie == NULL) { + RTW_ERR(FUNC_ADPT_FMT" type:%u, rtw_malloc() fail\n" + , FUNC_ADPT_ARG(adapter), type); + goto exit; + } + _rtw_memcpy(*t_ie, ie, ie_len); + *t_ie_len = ie_len; + } + + if (*t_ie && *t_ie_len) { + u8 *attr_content; + u32 attr_contentlen = 0; + + attr_content = rtw_get_wfd_attr_content(*t_ie, *t_ie_len, WFD_ATTR_DEVICE_INFO, NULL, &attr_contentlen); + if (attr_content && attr_contentlen) { + if (RTW_GET_BE16(attr_content + 2) != wfd_info->rtsp_ctrlport) { + wfd_info->rtsp_ctrlport = RTW_GET_BE16(attr_content + 2); + RTW_INFO(FUNC_ADPT_FMT" type:%u, RTSP CTRL port = %u\n" + , FUNC_ADPT_ARG(adapter), type, wfd_info->rtsp_ctrlport); + } + } + } + +success: + ret = _SUCCESS; + +exit: + return ret; +} +#endif /* defined(CONFIG_WFD) && defined(CONFIG_IOCTL_CFG80211) */ + +void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv) +{ + if (NULL == pmlmepriv) { + rtw_warn_on(1); + goto exit; + } + rtw_free_mlme_priv_ie_data(pmlmepriv); + + if (pmlmepriv) { + rtw_mfree_mlme_priv_lock(pmlmepriv); + + if (pmlmepriv->free_bss_buf) + rtw_vmfree(pmlmepriv->free_bss_buf, MAX_BSS_CNT * sizeof(struct wlan_network)); + } +exit: + return; +} + +sint _rtw_enqueue_network(_queue *queue, struct wlan_network *pnetwork) +{ + _irqL irqL; + + + if (pnetwork == NULL) + goto exit; + + _enter_critical_bh(&queue->lock, &irqL); + + rtw_list_insert_tail(&pnetwork->list, &queue->queue); + + _exit_critical_bh(&queue->lock, &irqL); + +exit: + + + return _SUCCESS; +} + +/* +struct wlan_network *_rtw_dequeue_network(_queue *queue) +{ + _irqL irqL; + + struct wlan_network *pnetwork; + + + _enter_critical_bh(&queue->lock, &irqL); + + if (_rtw_queue_empty(queue) == _TRUE) + + pnetwork = NULL; + + else + { + pnetwork = LIST_CONTAINOR(get_next(&queue->queue), struct wlan_network, list); + + rtw_list_delete(&(pnetwork->list)); + } + + _exit_critical_bh(&queue->lock, &irqL); + + + return pnetwork; +} +*/ + +struct wlan_network *_rtw_alloc_network(struct mlme_priv *pmlmepriv) /* (_queue *free_queue) */ +{ + _irqL irqL; + struct wlan_network *pnetwork; + _queue *free_queue = &pmlmepriv->free_bss_pool; + _list *plist = NULL; + + + _enter_critical_bh(&free_queue->lock, &irqL); + + if (_rtw_queue_empty(free_queue) == _TRUE) { + pnetwork = NULL; + goto exit; + } + plist = get_next(&(free_queue->queue)); + + pnetwork = LIST_CONTAINOR(plist , struct wlan_network, list); + + rtw_list_delete(&pnetwork->list); + + pnetwork->network_type = 0; + pnetwork->fixed = _FALSE; + pnetwork->last_scanned = rtw_get_current_time(); + pnetwork->aid = 0; + pnetwork->join_res = 0; + + pmlmepriv->num_of_scanned++; + +exit: + _exit_critical_bh(&free_queue->lock, &irqL); + + + return pnetwork; +} + +void _rtw_free_network(struct mlme_priv *pmlmepriv , struct wlan_network *pnetwork, u8 isfreeall) +{ + u32 delta_time; + u32 lifetime = SCANQUEUE_LIFETIME; + _irqL irqL; + _queue *free_queue = &(pmlmepriv->free_bss_pool); + + + if (pnetwork == NULL) + goto exit; + + if (pnetwork->fixed == _TRUE) + goto exit; + + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)) + lifetime = 1; + + if (!isfreeall) { + delta_time = (u32) rtw_get_passing_time_ms(pnetwork->last_scanned); + if (delta_time < lifetime) /* unit:msec */ + goto exit; + } + + _enter_critical_bh(&free_queue->lock, &irqL); + + rtw_list_delete(&(pnetwork->list)); + + rtw_list_insert_tail(&(pnetwork->list), &(free_queue->queue)); + + pmlmepriv->num_of_scanned--; + + + /* RTW_INFO("_rtw_free_network:SSID=%s\n", pnetwork->network.Ssid.Ssid); */ + + _exit_critical_bh(&free_queue->lock, &irqL); + +exit: + return; +} + +void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork) +{ + + _queue *free_queue = &(pmlmepriv->free_bss_pool); + + + if (pnetwork == NULL) + goto exit; + + if (pnetwork->fixed == _TRUE) + goto exit; + + /* _enter_critical(&free_queue->lock, &irqL); */ + + rtw_list_delete(&(pnetwork->list)); + + rtw_list_insert_tail(&(pnetwork->list), get_list_head(free_queue)); + + pmlmepriv->num_of_scanned--; + + /* _exit_critical(&free_queue->lock, &irqL); */ + +exit: + return; +} + + +/* + return the wlan_network with the matching addr + + Shall be calle under atomic context... to avoid possible racing condition... +*/ +struct wlan_network *_rtw_find_network(_queue *scanned_queue, u8 *addr) +{ + + /* _irqL irqL; */ + _list *phead, *plist; + struct wlan_network *pnetwork = NULL; + u8 zero_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; + + + if (_rtw_memcmp(zero_addr, addr, ETH_ALEN)) { + pnetwork = NULL; + goto exit; + } + + /* _enter_critical_bh(&scanned_queue->lock, &irqL); */ + + phead = get_list_head(scanned_queue); + plist = get_next(phead); + + while (plist != phead) { + pnetwork = LIST_CONTAINOR(plist, struct wlan_network , list); + + if (_rtw_memcmp(addr, pnetwork->network.MacAddress, ETH_ALEN) == _TRUE) + break; + + plist = get_next(plist); + } + + if (plist == phead) + pnetwork = NULL; + + /* _exit_critical_bh(&scanned_queue->lock, &irqL); */ + +exit: + + + return pnetwork; + +} + + +void _rtw_free_network_queue(_adapter *padapter, u8 isfreeall) +{ + _irqL irqL; + _list *phead, *plist; + struct wlan_network *pnetwork; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + _queue *scanned_queue = &pmlmepriv->scanned_queue; + + + + _enter_critical_bh(&scanned_queue->lock, &irqL); + + phead = get_list_head(scanned_queue); + plist = get_next(phead); + + while (rtw_end_of_queue_search(phead, plist) == _FALSE) { + + pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); + + plist = get_next(plist); + + _rtw_free_network(pmlmepriv, pnetwork, isfreeall); + + } + + _exit_critical_bh(&scanned_queue->lock, &irqL); + + +} + + + + +sint rtw_if_up(_adapter *padapter) +{ + + sint res; + + if (RTW_CANNOT_RUN(padapter) || + (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == _FALSE)) { + res = _FALSE; + } else + res = _TRUE; + + return res; +} + + +void rtw_generate_random_ibss(u8 *pibss) +{ + *((u32 *)(&pibss[2])) = rtw_random32(); + pibss[0] = 0x02; /* in ad-hoc mode local bit must set to 1 */ + pibss[1] = 0x11; + pibss[2] = 0x87; +} + +u8 *rtw_get_capability_from_ie(u8 *ie) +{ + return ie + 8 + 2; +} + + +u16 rtw_get_capability(WLAN_BSSID_EX *bss) +{ + u16 val; + + _rtw_memcpy((u8 *)&val, rtw_get_capability_from_ie(bss->IEs), 2); + + return le16_to_cpu(val); +} + +u8 *rtw_get_timestampe_from_ie(u8 *ie) +{ + return ie + 0; +} + +u8 *rtw_get_beacon_interval_from_ie(u8 *ie) +{ + return ie + 8; +} + + +int rtw_init_mlme_priv(_adapter *padapter) /* (struct mlme_priv *pmlmepriv) */ +{ + int res; + res = _rtw_init_mlme_priv(padapter);/* (pmlmepriv); */ + return res; +} + +void rtw_free_mlme_priv(struct mlme_priv *pmlmepriv) +{ + _rtw_free_mlme_priv(pmlmepriv); +} + +int rtw_enqueue_network(_queue *queue, struct wlan_network *pnetwork); +int rtw_enqueue_network(_queue *queue, struct wlan_network *pnetwork) +{ + int res; + res = _rtw_enqueue_network(queue, pnetwork); + return res; +} + +/* +static struct wlan_network *rtw_dequeue_network(_queue *queue) +{ + struct wlan_network *pnetwork; + pnetwork = _rtw_dequeue_network(queue); + return pnetwork; +} +*/ + +struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv); +struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv) /* (_queue *free_queue) */ +{ + struct wlan_network *pnetwork; + pnetwork = _rtw_alloc_network(pmlmepriv); + return pnetwork; +} + +void rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 is_freeall); +void rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 is_freeall)/* (struct wlan_network *pnetwork, _queue *free_queue) */ +{ + _rtw_free_network(pmlmepriv, pnetwork, is_freeall); +} + +void rtw_free_network_nolock(_adapter *padapter, struct wlan_network *pnetwork); +void rtw_free_network_nolock(_adapter *padapter, struct wlan_network *pnetwork) +{ + _rtw_free_network_nolock(&(padapter->mlmepriv), pnetwork); +#ifdef CONFIG_IOCTL_CFG80211 + rtw_cfg80211_unlink_bss(padapter, pnetwork); +#endif /* CONFIG_IOCTL_CFG80211 */ +} + + +void rtw_free_network_queue(_adapter *dev, u8 isfreeall) +{ + _rtw_free_network_queue(dev, isfreeall); +} + +/* + return the wlan_network with the matching addr + + Shall be calle under atomic context... to avoid possible racing condition... +*/ +struct wlan_network *rtw_find_network(_queue *scanned_queue, u8 *addr) +{ + struct wlan_network *pnetwork = _rtw_find_network(scanned_queue, addr); + + return pnetwork; +} + +int rtw_is_same_ibss(_adapter *adapter, struct wlan_network *pnetwork) +{ + int ret = _TRUE; + struct security_priv *psecuritypriv = &adapter->securitypriv; + + if ((psecuritypriv->dot11PrivacyAlgrthm != _NO_PRIVACY_) && + (pnetwork->network.Privacy == 0)) + ret = _FALSE; + else if ((psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_) && + (pnetwork->network.Privacy == 1)) + ret = _FALSE; + else + ret = _TRUE; + + return ret; + +} + +inline int is_same_ess(WLAN_BSSID_EX *a, WLAN_BSSID_EX *b) +{ + return (a->Ssid.SsidLength == b->Ssid.SsidLength) + && _rtw_memcmp(a->Ssid.Ssid, b->Ssid.Ssid, a->Ssid.SsidLength) == _TRUE; +} + +int is_same_network(WLAN_BSSID_EX *src, WLAN_BSSID_EX *dst, u8 feature) +{ + u16 s_cap, d_cap; + + + if (rtw_bug_check(dst, src, &s_cap, &d_cap) == _FALSE) + return _FALSE; + + _rtw_memcpy((u8 *)&s_cap, rtw_get_capability_from_ie(src->IEs), 2); + _rtw_memcpy((u8 *)&d_cap, rtw_get_capability_from_ie(dst->IEs), 2); + + + s_cap = le16_to_cpu(s_cap); + d_cap = le16_to_cpu(d_cap); + + +#ifdef CONFIG_P2P + if ((feature == 1) && /* 1: P2P supported */ + (_rtw_memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN) == _TRUE) + ) + return _TRUE; +#endif + + return ((src->Ssid.SsidLength == dst->Ssid.SsidLength) && + /* (src->Configuration.DSConfig == dst->Configuration.DSConfig) && */ + ((_rtw_memcmp(src->MacAddress, dst->MacAddress, ETH_ALEN)) == _TRUE) && + ((_rtw_memcmp(src->Ssid.Ssid, dst->Ssid.Ssid, src->Ssid.SsidLength)) == _TRUE) && + ((s_cap & WLAN_CAPABILITY_IBSS) == + (d_cap & WLAN_CAPABILITY_IBSS)) && + ((s_cap & WLAN_CAPABILITY_BSS) == + (d_cap & WLAN_CAPABILITY_BSS))); + +} + +struct wlan_network *_rtw_find_same_network(_queue *scanned_queue, struct wlan_network *network) +{ + _list *phead, *plist; + struct wlan_network *found = NULL; + + phead = get_list_head(scanned_queue); + plist = get_next(phead); + + while (plist != phead) { + found = LIST_CONTAINOR(plist, struct wlan_network , list); + + if (is_same_network(&network->network, &found->network, 0)) + break; + + plist = get_next(plist); + } + + if (plist == phead) + found = NULL; +exit: + return found; +} + +struct wlan_network *rtw_find_same_network(_queue *scanned_queue, struct wlan_network *network) +{ + _irqL irqL; + struct wlan_network *found = NULL; + + if (scanned_queue == NULL || network == NULL) + goto exit; + + _enter_critical_bh(&scanned_queue->lock, &irqL); + found = _rtw_find_same_network(scanned_queue, network); + _exit_critical_bh(&scanned_queue->lock, &irqL); + +exit: + return found; +} + +struct wlan_network *rtw_get_oldest_wlan_network(_queue *scanned_queue) +{ + _list *plist, *phead; + + + struct wlan_network *pwlan = NULL; + struct wlan_network *oldest = NULL; + phead = get_list_head(scanned_queue); + + plist = get_next(phead); + + while (1) { + + if (rtw_end_of_queue_search(phead, plist) == _TRUE) + break; + + pwlan = LIST_CONTAINOR(plist, struct wlan_network, list); + + if (pwlan->fixed != _TRUE) { + if (oldest == NULL || time_after(oldest->last_scanned, pwlan->last_scanned)) + oldest = pwlan; + } + + plist = get_next(plist); + } + return oldest; + +} + +void update_network(WLAN_BSSID_EX *dst, WLAN_BSSID_EX *src, + _adapter *padapter, bool update_ie) +{ + u8 ss_ori = dst->PhyInfo.SignalStrength; + u8 sq_ori = dst->PhyInfo.SignalQuality; + long rssi_ori = dst->Rssi; + + u8 ss_smp = src->PhyInfo.SignalStrength; + u8 sq_smp = src->PhyInfo.SignalQuality; + long rssi_smp = src->Rssi; + + u8 ss_final; + u8 sq_final; + long rssi_final; + + +#ifdef CONFIG_ANTENNA_DIVERSITY + rtw_hal_antdiv_rssi_compared(padapter, dst, src); /* this will update src.Rssi, need consider again */ +#endif + +#if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) && 1 + if (strcmp(dst->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { + RTW_INFO(FUNC_ADPT_FMT" %s("MAC_FMT", ch%u) ss_ori:%3u, sq_ori:%3u, rssi_ori:%3ld, ss_smp:%3u, sq_smp:%3u, rssi_smp:%3ld\n" + , FUNC_ADPT_ARG(padapter) + , src->Ssid.Ssid, MAC_ARG(src->MacAddress), src->Configuration.DSConfig + , ss_ori, sq_ori, rssi_ori + , ss_smp, sq_smp, rssi_smp + ); + } +#endif + + /* The rule below is 1/5 for sample value, 4/5 for history value */ + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&(padapter->mlmepriv.cur_network.network), src, 0)) { + /* Take the recvpriv's value for the connected AP*/ + ss_final = padapter->recvpriv.signal_strength; + sq_final = padapter->recvpriv.signal_qual; + /* the rssi value here is undecorated, and will be used for antenna diversity */ + if (sq_smp != 101) /* from the right channel */ + rssi_final = (src->Rssi + dst->Rssi * 4) / 5; + else + rssi_final = rssi_ori; + } else { + if (sq_smp != 101) { /* from the right channel */ + ss_final = ((u32)(src->PhyInfo.SignalStrength) + (u32)(dst->PhyInfo.SignalStrength) * 4) / 5; + sq_final = ((u32)(src->PhyInfo.SignalQuality) + (u32)(dst->PhyInfo.SignalQuality) * 4) / 5; + rssi_final = (src->Rssi + dst->Rssi * 4) / 5; + } else { + /* bss info not receving from the right channel, use the original RX signal infos */ + ss_final = dst->PhyInfo.SignalStrength; + sq_final = dst->PhyInfo.SignalQuality; + rssi_final = dst->Rssi; + } + + } + + if (update_ie) { + dst->Reserved[0] = src->Reserved[0]; + dst->Reserved[1] = src->Reserved[1]; + _rtw_memcpy((u8 *)dst, (u8 *)src, get_WLAN_BSSID_EX_sz(src)); + } + + dst->PhyInfo.SignalStrength = ss_final; + dst->PhyInfo.SignalQuality = sq_final; + dst->Rssi = rssi_final; + +#if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) && 1 + if (strcmp(dst->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { + RTW_INFO(FUNC_ADPT_FMT" %s("MAC_FMT"), SignalStrength:%u, SignalQuality:%u, RawRSSI:%ld\n" + , FUNC_ADPT_ARG(padapter) + , dst->Ssid.Ssid, MAC_ARG(dst->MacAddress), dst->PhyInfo.SignalStrength, dst->PhyInfo.SignalQuality, dst->Rssi); + } +#endif + +#if 0 /* old codes, may be useful one day... + * RTW_INFO("update_network: rssi=0x%lx dst->Rssi=%d ,dst->Rssi=0x%lx , src->Rssi=0x%lx",(dst->Rssi+src->Rssi)/2,dst->Rssi,dst->Rssi,src->Rssi); */ + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network(&(padapter->mlmepriv.cur_network.network), src)) { + + /* RTW_INFO("b:ssid=%s update_network: src->rssi=0x%d padapter->recvpriv.ui_rssi=%d\n",src->Ssid.Ssid,src->Rssi,padapter->recvpriv.signal); */ + if (padapter->recvpriv.signal_qual_data.total_num++ >= PHY_LINKQUALITY_SLID_WIN_MAX) { + padapter->recvpriv.signal_qual_data.total_num = PHY_LINKQUALITY_SLID_WIN_MAX; + last_evm = padapter->recvpriv.signal_qual_data.elements[padapter->recvpriv.signal_qual_data.index]; + padapter->recvpriv.signal_qual_data.total_val -= last_evm; + } + padapter->recvpriv.signal_qual_data.total_val += query_rx_pwr_percentage(src->Rssi); + + padapter->recvpriv.signal_qual_data.elements[padapter->recvpriv.signal_qual_data.index++] = query_rx_pwr_percentage(src->Rssi); + if (padapter->recvpriv.signal_qual_data.index >= PHY_LINKQUALITY_SLID_WIN_MAX) + padapter->recvpriv.signal_qual_data.index = 0; + + /* RTW_INFO("Total SQ=%d pattrib->signal_qual= %d\n", padapter->recvpriv.signal_qual_data.total_val, src->Rssi); */ + + /* <1> Showed on UI for user,in percentage. */ + tmpVal = padapter->recvpriv.signal_qual_data.total_val / padapter->recvpriv.signal_qual_data.total_num; + padapter->recvpriv.signal = (u8)tmpVal; /* Link quality */ + + src->Rssi = translate_percentage_to_dbm(padapter->recvpriv.signal) ; + } else { + /* RTW_INFO("ELSE:ssid=%s update_network: src->rssi=0x%d dst->rssi=%d\n",src->Ssid.Ssid,src->Rssi,dst->Rssi); */ + src->Rssi = (src->Rssi + dst->Rssi) / 2; /* dBM */ + } + + /* RTW_INFO("a:update_network: src->rssi=0x%d padapter->recvpriv.ui_rssi=%d\n",src->Rssi,padapter->recvpriv.signal); */ + +#endif + +} + +static void update_current_network(_adapter *adapter, WLAN_BSSID_EX *pnetwork) +{ + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + + + rtw_bug_check(&(pmlmepriv->cur_network.network), + &(pmlmepriv->cur_network.network), + &(pmlmepriv->cur_network.network), + &(pmlmepriv->cur_network.network)); + + if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) && (is_same_network(&(pmlmepriv->cur_network.network), pnetwork, 0))) { + + /* if(pmlmepriv->cur_network.network.IELength<= pnetwork->IELength) */ + { + update_network(&(pmlmepriv->cur_network.network), pnetwork, adapter, _TRUE); + rtw_update_protection(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof(NDIS_802_11_FIXED_IEs), + pmlmepriv->cur_network.network.IELength); + } + } + + +} + + +/* + +Caller must hold pmlmepriv->lock first. + + +*/ +void rtw_update_scanned_network(_adapter *adapter, WLAN_BSSID_EX *target) +{ + _irqL irqL; + _list *plist, *phead; + ULONG bssid_ex_sz; + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(adapter->wdinfo); +#endif /* CONFIG_P2P */ + _queue *queue = &(pmlmepriv->scanned_queue); + struct wlan_network *pnetwork = NULL; + struct wlan_network *oldest = NULL; + int target_find = 0; + u8 feature = 0; + + + _enter_critical_bh(&queue->lock, &irqL); + phead = get_list_head(queue); + plist = get_next(phead); + +#ifdef CONFIG_P2P + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + feature = 1; /* p2p enable */ +#endif + + while (1) { + if (rtw_end_of_queue_search(phead, plist) == _TRUE) + break; + + pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); + + rtw_bug_check(pnetwork, pnetwork, pnetwork, pnetwork); + +#ifdef CONFIG_P2P + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && + (_rtw_memcmp(pnetwork->network.MacAddress, target->MacAddress, ETH_ALEN) == _TRUE)) { + target_find = 1; + break; + } +#endif + + if (is_same_network(&(pnetwork->network), target, feature)) { + target_find = 1; + break; + } + + if (rtw_roam_flags(adapter)) { + /* TODO: don't select netowrk in the same ess as oldest if it's new enough*/ + } + + if (oldest == NULL || time_after(oldest->last_scanned, pnetwork->last_scanned)) + oldest = pnetwork; + + plist = get_next(plist); + + } + + + /* If we didn't find a match, then get a new network slot to initialize + * with this beacon's information */ + /* if (rtw_end_of_queue_search(phead,plist)== _TRUE) { */ + if (!target_find) { + if (_rtw_queue_empty(&(pmlmepriv->free_bss_pool)) == _TRUE) { + /* If there are no more slots, expire the oldest */ + /* list_del_init(&oldest->list); */ + pnetwork = oldest; + if (pnetwork == NULL) { + goto exit; + } +#ifdef CONFIG_ANTENNA_DIVERSITY + rtw_hal_get_odm_var(adapter, HAL_ODM_ANTDIV_SELECT, &(target->PhyInfo.Optimum_antenna), NULL); +#endif + _rtw_memcpy(&(pnetwork->network), target, get_WLAN_BSSID_EX_sz(target)); + /* pnetwork->last_scanned = rtw_get_current_time(); */ + /* variable initialize */ + pnetwork->fixed = _FALSE; + pnetwork->last_scanned = rtw_get_current_time(); + + pnetwork->network_type = 0; + pnetwork->aid = 0; + pnetwork->join_res = 0; + + /* bss info not receving from the right channel */ + if (pnetwork->network.PhyInfo.SignalQuality == 101) + pnetwork->network.PhyInfo.SignalQuality = 0; + } else { + /* Otherwise just pull from the free list */ + + pnetwork = rtw_alloc_network(pmlmepriv); /* will update scan_time */ + + if (pnetwork == NULL) { + goto exit; + } + + bssid_ex_sz = get_WLAN_BSSID_EX_sz(target); + target->Length = bssid_ex_sz; +#ifdef CONFIG_ANTENNA_DIVERSITY + rtw_hal_get_odm_var(adapter, HAL_ODM_ANTDIV_SELECT, &(target->PhyInfo.Optimum_antenna), NULL); +#endif + _rtw_memcpy(&(pnetwork->network), target, bssid_ex_sz); + + pnetwork->last_scanned = rtw_get_current_time(); + + /* bss info not receving from the right channel */ + if (pnetwork->network.PhyInfo.SignalQuality == 101) + pnetwork->network.PhyInfo.SignalQuality = 0; + + rtw_list_insert_tail(&(pnetwork->list), &(queue->queue)); + + } + } else { + /* we have an entry and we are going to update it. But this entry may + * be already expired. In this case we do the same as we found a new + * net and call the new_net handler + */ + bool update_ie = _TRUE; + + pnetwork->last_scanned = rtw_get_current_time(); + + /* target.Reserved[0]==1, means that scaned network is a bcn frame. */ + if ((pnetwork->network.IELength > target->IELength) && (target->Reserved[0] == 1)) + update_ie = _FALSE; + + /* probe resp(3) > beacon(1) > probe req(2) */ + if ((target->Reserved[0] != 2) && + (target->Reserved[0] >= pnetwork->network.Reserved[0]) + ) + update_ie = _TRUE; + else + update_ie = _FALSE; + + update_network(&(pnetwork->network), target, adapter, update_ie); + } + +exit: + _exit_critical_bh(&queue->lock, &irqL); + +} + +void rtw_add_network(_adapter *adapter, WLAN_BSSID_EX *pnetwork); +void rtw_add_network(_adapter *adapter, WLAN_BSSID_EX *pnetwork) +{ + _irqL irqL; + struct mlme_priv *pmlmepriv = &(((_adapter *)adapter)->mlmepriv); + /* _queue *queue = &(pmlmepriv->scanned_queue); */ + + + /* _enter_critical_bh(&queue->lock, &irqL); */ + +#if defined(CONFIG_P2P) && defined(CONFIG_P2P_REMOVE_GROUP_INFO) + if (adapter->registrypriv.wifi_spec == 0) + rtw_bss_ex_del_p2p_attr(pnetwork, P2P_ATTR_GROUP_INFO); +#endif + + if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST)) + rtw_bss_ex_del_wfd_ie(pnetwork); + + update_current_network(adapter, pnetwork); + + rtw_update_scanned_network(adapter, pnetwork); + + /* _exit_critical_bh(&queue->lock, &irqL); */ + +} + +/* select the desired network based on the capability of the (i)bss. + * check items: (1) security + * (2) network_type + * (3) WMM + * (4) HT + * (5) others */ +int rtw_is_desired_network(_adapter *adapter, struct wlan_network *pnetwork); +int rtw_is_desired_network(_adapter *adapter, struct wlan_network *pnetwork) +{ + struct security_priv *psecuritypriv = &adapter->securitypriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + u32 desired_encmode; + u32 privacy; + + /* u8 wps_ie[512]; */ + uint wps_ielen; + + int bselected = _TRUE; + + desired_encmode = psecuritypriv->ndisencryptstatus; + privacy = pnetwork->network.Privacy; + + if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) { + if (rtw_get_wps_ie(pnetwork->network.IEs + _FIXED_IE_LENGTH_, pnetwork->network.IELength - _FIXED_IE_LENGTH_, NULL, &wps_ielen) != NULL) + return _TRUE; + else + return _FALSE; + } + if (adapter->registrypriv.wifi_spec == 1) { /* for correct flow of 8021X to do.... */ + u8 *p = NULL; + uint ie_len = 0; + + if ((desired_encmode == Ndis802_11EncryptionDisabled) && (privacy != 0)) + bselected = _FALSE; + + if (psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) { + p = rtw_get_ie(pnetwork->network.IEs + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pnetwork->network.IELength - _BEACON_IE_OFFSET_)); + if (p && ie_len > 0) + bselected = _TRUE; + else + bselected = _FALSE; + } + } + + + if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) { + RTW_INFO("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy); + bselected = _FALSE; + } + + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) { + if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode) + bselected = _FALSE; + } + + + return bselected; +} + +/* TODO: Perry : For Power Management */ +void rtw_atimdone_event_callback(_adapter *adapter , u8 *pbuf) +{ + + return; +} + + +void rtw_survey_event_callback(_adapter *adapter, u8 *pbuf) +{ + _irqL irqL; + u32 len; + WLAN_BSSID_EX *pnetwork; + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + + + pnetwork = (WLAN_BSSID_EX *)pbuf; + + +#ifdef CONFIG_RTL8712 + /* endian_convert */ + pnetwork->Length = le32_to_cpu(pnetwork->Length); + pnetwork->Ssid.SsidLength = le32_to_cpu(pnetwork->Ssid.SsidLength); + pnetwork->Privacy = le32_to_cpu(pnetwork->Privacy); + pnetwork->Rssi = le32_to_cpu(pnetwork->Rssi); + pnetwork->NetworkTypeInUse = le32_to_cpu(pnetwork->NetworkTypeInUse); + pnetwork->Configuration.ATIMWindow = le32_to_cpu(pnetwork->Configuration.ATIMWindow); + pnetwork->Configuration.BeaconPeriod = le32_to_cpu(pnetwork->Configuration.BeaconPeriod); + pnetwork->Configuration.DSConfig = le32_to_cpu(pnetwork->Configuration.DSConfig); + pnetwork->Configuration.FHConfig.DwellTime = le32_to_cpu(pnetwork->Configuration.FHConfig.DwellTime); + pnetwork->Configuration.FHConfig.HopPattern = le32_to_cpu(pnetwork->Configuration.FHConfig.HopPattern); + pnetwork->Configuration.FHConfig.HopSet = le32_to_cpu(pnetwork->Configuration.FHConfig.HopSet); + pnetwork->Configuration.FHConfig.Length = le32_to_cpu(pnetwork->Configuration.FHConfig.Length); + pnetwork->Configuration.Length = le32_to_cpu(pnetwork->Configuration.Length); + pnetwork->InfrastructureMode = le32_to_cpu(pnetwork->InfrastructureMode); + pnetwork->IELength = le32_to_cpu(pnetwork->IELength); +#endif + + len = get_WLAN_BSSID_EX_sz(pnetwork); + if (len > (sizeof(WLAN_BSSID_EX))) { + return; + } + + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + /* update IBSS_network 's timestamp */ + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == _TRUE) { + if (_rtw_memcmp(&(pmlmepriv->cur_network.network.MacAddress), pnetwork->MacAddress, ETH_ALEN)) { + struct wlan_network *ibss_wlan = NULL; + _irqL irqL; + + _rtw_memcpy(pmlmepriv->cur_network.network.IEs, pnetwork->IEs, 8); + _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + ibss_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->MacAddress); + if (ibss_wlan) { + _rtw_memcpy(ibss_wlan->network.IEs , pnetwork->IEs, 8); + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + goto exit; + } + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + } + } + + /* lock pmlmepriv->lock when you accessing network_q */ + if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == _FALSE) { + if (pnetwork->Ssid.Ssid[0] == 0) + pnetwork->Ssid.SsidLength = 0; + rtw_add_network(adapter, pnetwork); + } + +exit: + + _exit_critical_bh(&pmlmepriv->lock, &irqL); + + + return; +} + +void rtw_surveydone_event_callback(_adapter *adapter, u8 *pbuf) +{ + _irqL irqL; + u8 timer_cancelled; + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); +#ifdef CONFIG_RTW_80211R + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; +#endif + +#ifdef CONFIG_MLME_EXT + mlmeext_surveydone_event_callback(adapter); +#endif + + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + if (pmlmepriv->wps_probe_req_ie) { + u32 free_len = pmlmepriv->wps_probe_req_ie_len; + pmlmepriv->wps_probe_req_ie_len = 0; + rtw_mfree(pmlmepriv->wps_probe_req_ie, free_len); + pmlmepriv->wps_probe_req_ie = NULL; + } + + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _FALSE) { + RTW_INFO(FUNC_ADPT_FMT" fw_state:0x%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv)); + /* rtw_warn_on(1); */ + } + + _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); + _exit_critical_bh(&pmlmepriv->lock, &irqL); + + _cancel_timer(&pmlmepriv->scan_to_timer, &timer_cancelled); + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + +#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS + rtw_set_signal_stat_timer(&adapter->recvpriv); +#endif + + if (pmlmepriv->to_join == _TRUE) { + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) { + set_fwstate(pmlmepriv, _FW_UNDER_LINKING); + + if (rtw_select_and_join_from_scanned_queue(pmlmepriv) == _SUCCESS) + _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); + else { + WLAN_BSSID_EX *pdev_network = &(adapter->registrypriv.dev_network); + u8 *pibss = adapter->registrypriv.dev_network.MacAddress; + + /* pmlmepriv->fw_state ^= _FW_UNDER_SURVEY; */ /* because don't set assoc_timer */ + _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); + + + _rtw_memset(&pdev_network->Ssid, 0, sizeof(NDIS_802_11_SSID)); + _rtw_memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(NDIS_802_11_SSID)); + + rtw_update_registrypriv_dev_network(adapter); + rtw_generate_random_ibss(pibss); + + /*pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;*/ + init_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE); + + if (rtw_create_ibss_cmd(adapter, 0) != _SUCCESS) + RTW_ERR("rtw_create_ibss_cmd FAIL\n"); + + pmlmepriv->to_join = _FALSE; + } + } + } else { + int s_ret; + set_fwstate(pmlmepriv, _FW_UNDER_LINKING); + pmlmepriv->to_join = _FALSE; + s_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv); + if (_SUCCESS == s_ret) + _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); + else if (s_ret == 2) { /* there is no need to wait for join */ + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + rtw_indicate_connect(adapter); + } else { + RTW_INFO("try_to_join, but select scanning queue fail, to_roam:%d\n", rtw_to_roam(adapter)); + + if (rtw_to_roam(adapter) != 0) { + if (rtw_dec_to_roam(adapter) == 0 + || _SUCCESS != rtw_sitesurvey_cmd(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0) + ) { + rtw_set_to_roam(adapter, 0); +#ifdef CONFIG_INTEL_WIDI + if (adapter->mlmepriv.widi_state == INTEL_WIDI_STATE_ROAMING) { + _rtw_memset(pmlmepriv->sa_ext, 0x00, L2SDTA_SERVICE_VE_LEN); + intel_widi_wk_cmd(adapter, INTEL_WIDI_LISTEN_WK, NULL, 0); + RTW_INFO("change to widi listen\n"); + } +#endif /* CONFIG_INTEL_WIDI */ + rtw_free_assoc_resources(adapter, 1); + rtw_indicate_disconnect(adapter, 0, _FALSE); + } else + pmlmepriv->to_join = _TRUE; + } else + rtw_indicate_disconnect(adapter, 0, _FALSE); + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + } + } + } else { + if (rtw_chk_roam_flags(adapter, RTW_ROAM_ACTIVE)) { + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) + && check_fwstate(pmlmepriv, _FW_LINKED)) { + if (rtw_select_roaming_candidate(pmlmepriv) == _SUCCESS) { +#ifdef CONFIG_RTW_80211R + if (rtw_chk_ft_flags(adapter, RTW_FT_OVER_DS_SUPPORTED)) { + start_clnt_ft_action(adapter, (u8 *)pmlmepriv->roam_network->network.MacAddress); + } else { + /*wait a little time to retrieve packets buffered in the current ap while scan*/ + _set_timer(&pmlmeext->ft_roam_timer, 30); + } +#else + receive_disconnect(adapter, pmlmepriv->cur_network.network.MacAddress + , WLAN_REASON_ACTIVE_ROAM, _FALSE); +#endif + } + } + } + } + + /* RTW_INFO("scan complete in %dms\n",rtw_get_passing_time_ms(pmlmepriv->scan_start_time)); */ + + _exit_critical_bh(&pmlmepriv->lock, &irqL); + +#ifdef CONFIG_P2P_PS + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + p2p_ps_wk_cmd(adapter, P2P_PS_SCAN_DONE, 0); +#endif /* CONFIG_P2P_PS */ + + rtw_mi_os_xmit_schedule(adapter); + +#ifdef CONFIG_DRVEXT_MODULE_WSC + drvext_surveydone_callback(&adapter->drvextpriv); +#endif + +#ifdef DBG_CONFIG_ERROR_DETECT + { + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + if (pmlmeext->sitesurvey_res.bss_cnt == 0) { + /* rtw_hal_sreset_reset(adapter); */ + } + } +#endif + +#ifdef CONFIG_IOCTL_CFG80211 + rtw_cfg80211_surveydone_event_callback(adapter); +#endif /* CONFIG_IOCTL_CFG80211 */ + + rtw_indicate_scan_done(adapter, _FALSE); + +#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_IOCTL_CFG80211) + rtw_cfg80211_indicate_scan_done_for_buddy(adapter, _FALSE); +#endif + +} + +void rtw_dummy_event_callback(_adapter *adapter , u8 *pbuf) +{ + +} + +void rtw_fwdbg_event_callback(_adapter *adapter , u8 *pbuf) +{ + +} + +static void free_scanqueue(struct mlme_priv *pmlmepriv) +{ + _irqL irqL, irqL0; + _queue *free_queue = &pmlmepriv->free_bss_pool; + _queue *scan_queue = &pmlmepriv->scanned_queue; + _list *plist, *phead, *ptemp; + + + _enter_critical_bh(&scan_queue->lock, &irqL0); + _enter_critical_bh(&free_queue->lock, &irqL); + + phead = get_list_head(scan_queue); + plist = get_next(phead); + + while (plist != phead) { + ptemp = get_next(plist); + rtw_list_delete(plist); + rtw_list_insert_tail(plist, &free_queue->queue); + plist = ptemp; + pmlmepriv->num_of_scanned--; + } + + _exit_critical_bh(&free_queue->lock, &irqL); + _exit_critical_bh(&scan_queue->lock, &irqL0); + +} + +void rtw_reset_rx_info(struct debug_priv *pdbgpriv) +{ + pdbgpriv->dbg_rx_ampdu_drop_count = 0; + pdbgpriv->dbg_rx_ampdu_forced_indicate_count = 0; + pdbgpriv->dbg_rx_ampdu_loss_count = 0; + pdbgpriv->dbg_rx_dup_mgt_frame_drop_count = 0; + pdbgpriv->dbg_rx_ampdu_window_shift_cnt = 0; +} + +/* +*rtw_free_assoc_resources: the caller has to lock pmlmepriv->lock +*/ +void rtw_free_assoc_resources(_adapter *adapter, int lock_scanned_queue) +{ + _irqL irqL; + struct wlan_network *pwlan = NULL; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct sta_priv *pstapriv = &adapter->stapriv; + struct wlan_network *tgt_network = &pmlmepriv->cur_network; + struct dvobj_priv *psdpriv = adapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; + + +#ifdef CONFIG_TDLS + struct tdls_info *ptdlsinfo = &adapter->tdlsinfo; +#endif /* CONFIG_TDLS */ + + + RTW_INFO("%s-"ADPT_FMT" tgt_network MacAddress=" MAC_FMT"ssid=%s\n", + __func__, ADPT_ARG(adapter), MAC_ARG(tgt_network->network.MacAddress), tgt_network->network.Ssid.Ssid); + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + struct sta_info *psta; + + psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.MacAddress); + +#ifdef CONFIG_TDLS + if (ptdlsinfo->link_established == _TRUE) { + rtw_tdls_cmd(adapter, NULL, TDLS_RS_RCR); + rtw_reset_tdls_info(adapter); + rtw_free_all_stainfo(adapter); + /* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + } else +#endif /* CONFIG_TDLS */ + { + /* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + rtw_free_stainfo(adapter, psta); + } + + /* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + + } + + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) { + struct sta_info *psta; + + rtw_free_all_stainfo(adapter); + + psta = rtw_get_bcmc_stainfo(adapter); + /* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + rtw_free_stainfo(adapter, psta); + /* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + + rtw_init_bcmc_stainfo(adapter); + } + + if (lock_scanned_queue) + _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + + pwlan = _rtw_find_same_network(&pmlmepriv->scanned_queue, tgt_network); + if ((pwlan) && (!check_fwstate(pmlmepriv, WIFI_UNDER_WPS))) { + pwlan->fixed = _FALSE; + + RTW_INFO("free disconnecting network of scanned_queue\n"); + rtw_free_network_nolock(adapter, pwlan); +#ifdef CONFIG_P2P + if (!rtw_p2p_chk_state(&adapter->wdinfo, P2P_STATE_NONE)) { + rtw_mi_set_scan_deny(adapter, 2000); + /* rtw_clear_scan_deny(adapter); */ + } +#endif /* CONFIG_P2P */ + } else { + if (pwlan == NULL) + RTW_INFO("free disconnecting network of scanned_queue failed due to pwlan== NULL\n\n"); + if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) + RTW_INFO("donot free disconnecting network of scanned_queue when WIFI_UNDER_WPS\n\n"); + } + + + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1)) + /*||check_fwstate(pmlmepriv, WIFI_STATION_STATE)*/) { + if (pwlan) + rtw_free_network_nolock(adapter, pwlan); + } + + if (lock_scanned_queue) + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + + adapter->securitypriv.key_mask = 0; + + rtw_reset_rx_info(pdbgpriv); + + +} + +/* +*rtw_indicate_connect: the caller has to lock pmlmepriv->lock +*/ +void rtw_indicate_connect(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + + + pmlmepriv->to_join = _FALSE; + + if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { + + set_fwstate(pmlmepriv, _FW_LINKED); + + rtw_led_control(padapter, LED_CTL_LINK); + + +#ifdef CONFIG_DRVEXT_MODULE + if (padapter->drvextpriv.enable_wpa) + indicate_l2_connect(padapter); + else +#endif + { + rtw_os_indicate_connect(padapter); + } + + } + + rtw_set_to_roam(padapter, 0); +#ifdef CONFIG_INTEL_WIDI + if (padapter->mlmepriv.widi_state == INTEL_WIDI_STATE_ROAMING) { + _rtw_memset(pmlmepriv->sa_ext, 0x00, L2SDTA_SERVICE_VE_LEN); + intel_widi_wk_cmd(padapter, INTEL_WIDI_LISTEN_WK, NULL, 0); + RTW_INFO("change to widi listen\n"); + } +#endif /* CONFIG_INTEL_WIDI */ + if (!check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE)) + rtw_mi_set_scan_deny(padapter, 3000); + + +} + + +/* +*rtw_indicate_disconnect: the caller has to lock pmlmepriv->lock +*/ +void rtw_indicate_disconnect(_adapter *padapter, u16 reason, u8 locally_generated) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *wps_ie = NULL; + uint wpsie_len = 0; + + + + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING | WIFI_UNDER_WPS); + + /* force to clear cur_network_scanned's SELECTED REGISTRAR */ + if (pmlmepriv->cur_network_scanned) { + WLAN_BSSID_EX *current_joined_bss = &(pmlmepriv->cur_network_scanned->network); + if (current_joined_bss) { + wps_ie = rtw_get_wps_ie(current_joined_bss->IEs + _FIXED_IE_LENGTH_, + current_joined_bss->IELength - _FIXED_IE_LENGTH_, NULL, &wpsie_len); + if (wps_ie && wpsie_len > 0) { + u8 *attr = NULL; + u32 attr_len; + attr = rtw_get_wps_attr(wps_ie, wpsie_len, WPS_ATTR_SELECTED_REGISTRAR, + NULL, &attr_len); + if (attr) + *(attr + 4) = 0; + } + } + } + /* RTW_INFO("clear wps when %s\n", __func__); */ + + if (rtw_to_roam(padapter) > 0) + _clr_fwstate_(pmlmepriv, _FW_LINKED); + +#ifdef CONFIG_WAPI_SUPPORT + psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress); + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) + rtw_wapi_return_one_sta_info(padapter, psta->hwaddr); + else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || + check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) + rtw_wapi_return_all_sta_info(padapter); +#endif + + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) + || (rtw_to_roam(padapter) <= 0) + ) { + + rtw_os_indicate_disconnect(padapter, reason, locally_generated); + + /* set ips_deny_time to avoid enter IPS before LPS leave */ + rtw_set_ips_deny(padapter, 3000); + + _clr_fwstate_(pmlmepriv, _FW_LINKED); + + rtw_led_control(padapter, LED_CTL_NO_LINK); + + rtw_clear_scan_deny(padapter); + } + +#ifdef CONFIG_P2P_PS + p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1); +#endif /* CONFIG_P2P_PS */ + +#ifdef CONFIG_LPS + rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_DISCONNECT, 1); +#endif + +#ifdef CONFIG_BEAMFORMING + beamforming_wk_cmd(padapter, BEAMFORMING_CTRL_LEAVE, cur_network->MacAddress, ETH_ALEN, 1); +#endif /*CONFIG_BEAMFORMING*/ + +} + +inline void rtw_indicate_scan_done(_adapter *padapter, bool aborted) +{ + RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); + + rtw_os_indicate_scan_done(padapter, aborted); + +#ifdef CONFIG_IPS + if (is_primary_adapter(padapter) + && (_FALSE == adapter_to_pwrctl(padapter)->bInSuspend) + && (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE | WIFI_UNDER_LINKING) == _FALSE)) { + struct pwrctrl_priv *pwrpriv; + + pwrpriv = adapter_to_pwrctl(padapter); + rtw_set_ips_deny(padapter, 0); +#ifdef CONFIG_IPS_CHECK_IN_WD + _set_timer(&adapter_to_dvobj(padapter)->dynamic_chk_timer, 1); +#else /* !CONFIG_IPS_CHECK_IN_WD */ + _rtw_set_pwr_state_check_timer(pwrpriv, 1); +#endif /* !CONFIG_IPS_CHECK_IN_WD */ + } +#endif /* CONFIG_IPS */ +} + +static u32 _rtw_wait_scan_done(_adapter *adapter, u8 abort, u32 timeout_ms) +{ + u32 start; + u32 pass_ms; + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); + + start = rtw_get_current_time(); + + pmlmeext->scan_abort = abort; + + while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) + && rtw_get_passing_time_ms(start) <= timeout_ms) { + + if (RTW_CANNOT_RUN(adapter)) + break; + + RTW_INFO(FUNC_NDEV_FMT"fw_state=_FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev)); + rtw_msleep_os(20); + } + + if (_TRUE == abort) { + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) { + if (!RTW_CANNOT_RUN(adapter)) + RTW_INFO(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev)); +#ifdef CONFIG_PLATFORM_MSTAR + /*_clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);*/ + set_survey_timer(pmlmeext, 0); + mlme_set_scan_to_timer(pmlmepriv, 50); +#endif + rtw_indicate_scan_done(adapter, _TRUE); + } + } + + pmlmeext->scan_abort = _FALSE; + pass_ms = rtw_get_passing_time_ms(start); + + return pass_ms; + +} + +void rtw_scan_wait_completed(_adapter *adapter) +{ + u32 scan_to = SCANNING_TIMEOUT; + +#ifdef CONFIG_SCAN_BACKOP + if (is_supported_5g(adapter->registrypriv.wireless_mode) + && IsSupported24G(adapter->registrypriv.wireless_mode)) /*dual band*/ + scan_to = CONC_SCANNING_TIMEOUT_DUAL_BAND; + else /*single band*/ + scan_to = CONC_SCANNING_TIMEOUT_SINGLE_BAND; +#endif /* CONFIG_SCAN_BACKOP */ + + _rtw_wait_scan_done(adapter, _FALSE, scan_to); +} + +u32 rtw_scan_abort_timeout(_adapter *adapter, u32 timeout_ms) +{ + return _rtw_wait_scan_done(adapter, _TRUE, timeout_ms); +} + +void rtw_scan_abort_no_wait(_adapter *adapter) +{ + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) + pmlmeext->scan_abort = _TRUE; +} + +void rtw_scan_abort(_adapter *adapter) +{ + rtw_scan_abort_timeout(adapter, 200); +} + +static struct sta_info *rtw_joinbss_update_stainfo(_adapter *padapter, struct wlan_network *pnetwork) +{ + int i; + struct sta_info *bmc_sta, *psta = NULL; + struct recv_reorder_ctrl *preorder_ctrl; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + psta = rtw_get_stainfo(pstapriv, pnetwork->network.MacAddress); + if (psta == NULL) + psta = rtw_alloc_stainfo(pstapriv, pnetwork->network.MacAddress); + + if (psta) { /* update ptarget_sta */ + RTW_INFO("%s\n", __FUNCTION__); + + psta->aid = pnetwork->join_res; + +#if 0 /* alloc macid when call rtw_alloc_stainfo(), and release macid when call rtw_free_stainfo() */ +#ifdef CONFIG_CONCURRENT_MODE + + if (PRIMARY_ADAPTER == padapter->adapter_type) + psta->mac_id = 0; + else + psta->mac_id = 2; +#else + psta->mac_id = 0; +#endif +#endif /* removed */ + + update_sta_info(padapter, psta); + + /* update station supportRate */ + psta->bssratelen = rtw_get_rateset_len(pnetwork->network.SupportedRates); + _rtw_memcpy(psta->bssrateset, pnetwork->network.SupportedRates, psta->bssratelen); + rtw_hal_update_sta_rate_mask(padapter, psta); + + psta->wireless_mode = pmlmeext->cur_wireless_mode; + psta->raid = rtw_hal_networktype_to_raid(padapter, psta); + + + /* sta mode */ + rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, _TRUE); + + /* security related */ +#ifdef CONFIG_RTW_80211R + if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (psta->ft_pairwise_key_installed == _FALSE)) { +#else + if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { +#endif + padapter->securitypriv.binstallGrpkey = _FALSE; + padapter->securitypriv.busetkipkey = _FALSE; + padapter->securitypriv.bgrpkey_handshake = _FALSE; + + psta->ieee8021x_blocked = _TRUE; + psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; + + _rtw_memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof(union Keytype)); + + _rtw_memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof(union Keytype)); + _rtw_memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof(union Keytype)); + + _rtw_memset((u8 *)&psta->dot11txpn, 0, sizeof(union pn48)); + psta->dot11txpn.val = psta->dot11txpn.val + 1; +#ifdef CONFIG_IEEE80211W + _rtw_memset((u8 *)&psta->dot11wtxpn, 0, sizeof(union pn48)); +#endif /* CONFIG_IEEE80211W */ + _rtw_memset((u8 *)&psta->dot11rxpn, 0, sizeof(union pn48)); + } + + /* Commented by Albert 2012/07/21 */ + /* When doing the WPS, the wps_ie_len won't equal to 0 */ + /* And the Wi-Fi driver shouldn't allow the data packet to be tramsmitted. */ + if (padapter->securitypriv.wps_ie_len != 0) { + psta->ieee8021x_blocked = _TRUE; + padapter->securitypriv.wps_ie_len = 0; + } + + + /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info */ + /* if A-MPDU Rx is enabled, reseting rx_ordering_ctrl wstart_b(indicate_seq) to default value=0xffff */ + /* todo: check if AP can send A-MPDU packets */ + for (i = 0; i < 16 ; i++) { + /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ + preorder_ctrl = &psta->recvreorder_ctrl[i]; + preorder_ctrl->enable = _FALSE; + preorder_ctrl->indicate_seq = 0xffff; +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d indicate_seq:%u\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq); +#endif + preorder_ctrl->wend_b = 0xffff; + preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; */ /* ex. 32(kbytes) -> wsize_b=32 */ + preorder_ctrl->ampdu_size = RX_AMPDU_SIZE_INVALID; + } + + + bmc_sta = rtw_get_bcmc_stainfo(padapter); + if (bmc_sta) { + for (i = 0; i < 16 ; i++) { + /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ + preorder_ctrl = &bmc_sta->recvreorder_ctrl[i]; + preorder_ctrl->enable = _FALSE; + preorder_ctrl->indicate_seq = 0xffff; +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d indicate_seq:%u\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq); +#endif + preorder_ctrl->wend_b = 0xffff; + preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; */ /* ex. 32(kbytes) -> wsize_b=32 */ + preorder_ctrl->ampdu_size = RX_AMPDU_SIZE_INVALID; + } + } + } + + return psta; + +} + +/* pnetwork : returns from rtw_joinbss_event_callback + * ptarget_wlan: found from scanned_queue */ +static void rtw_joinbss_update_network(_adapter *padapter, struct wlan_network *ptarget_wlan, struct wlan_network *pnetwork) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct wlan_network *cur_network = &(pmlmepriv->cur_network); + + RTW_INFO("%s\n", __FUNCTION__); + + + + /* why not use ptarget_wlan?? */ + _rtw_memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length); + /* some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs */ + cur_network->network.IELength = ptarget_wlan->network.IELength; + _rtw_memcpy(&cur_network->network.IEs[0], &ptarget_wlan->network.IEs[0], MAX_IE_SZ); + + cur_network->aid = pnetwork->join_res; + + +#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS + rtw_set_signal_stat_timer(&padapter->recvpriv); +#endif + padapter->recvpriv.signal_strength = ptarget_wlan->network.PhyInfo.SignalStrength; + padapter->recvpriv.signal_qual = ptarget_wlan->network.PhyInfo.SignalQuality; + /* the ptarget_wlan->network.Rssi is raw data, we use ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled) */ + padapter->recvpriv.rssi = translate_percentage_to_dbm(ptarget_wlan->network.PhyInfo.SignalStrength); +#if defined(DBG_RX_SIGNAL_DISPLAY_PROCESSING) && 1 + RTW_INFO(FUNC_ADPT_FMT" signal_strength:%3u, rssi:%3d, signal_qual:%3u" + "\n" + , FUNC_ADPT_ARG(padapter) + , padapter->recvpriv.signal_strength + , padapter->recvpriv.rssi + , padapter->recvpriv.signal_qual + ); +#endif +#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS + rtw_set_signal_stat_timer(&padapter->recvpriv); +#endif + + /* update fw_state */ /* will clr _FW_UNDER_LINKING here indirectly */ + + switch (pnetwork->network.InfrastructureMode) { + case Ndis802_11Infrastructure: + + if (pmlmepriv->fw_state & WIFI_UNDER_WPS) + /*pmlmepriv->fw_state = WIFI_STATION_STATE|WIFI_UNDER_WPS;*/ + init_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_UNDER_WPS); + else + /*pmlmepriv->fw_state = WIFI_STATION_STATE;*/ + init_fwstate(pmlmepriv, WIFI_STATION_STATE); + break; + case Ndis802_11IBSS: + /*pmlmepriv->fw_state = WIFI_ADHOC_STATE;*/ + init_fwstate(pmlmepriv, WIFI_ADHOC_STATE); + break; + default: + /*pmlmepriv->fw_state = WIFI_NULL_STATE;*/ + init_fwstate(pmlmepriv, WIFI_NULL_STATE); + break; + } + + rtw_update_protection(padapter, (cur_network->network.IEs) + sizeof(NDIS_802_11_FIXED_IEs), + (cur_network->network.IELength)); + +#ifdef CONFIG_80211N_HT + rtw_update_ht_cap(padapter, cur_network->network.IEs, cur_network->network.IELength, (u8) cur_network->network.Configuration.DSConfig); +#endif +} + +/* Notes: the fucntion could be > passive_level (the same context as Rx tasklet) + * pnetwork : returns from rtw_joinbss_event_callback + * ptarget_wlan: found from scanned_queue + * if join_res > 0, for (fw_state==WIFI_STATION_STATE), we check if "ptarget_sta" & "ptarget_wlan" exist. + * if join_res > 0, for (fw_state==WIFI_ADHOC_STATE), we only check if "ptarget_wlan" exist. + * if join_res > 0, update "cur_network->network" from "pnetwork->network" if (ptarget_wlan !=NULL). + */ +/* #define REJOIN */ +void rtw_joinbss_event_prehandle(_adapter *adapter, u8 *pbuf) +{ + _irqL irqL, irqL2; + static u8 retry = 0; + u8 timer_cancelled; + struct sta_info *ptarget_sta = NULL, *pcur_sta = NULL; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct wlan_network *pnetwork = (struct wlan_network *)pbuf; + struct wlan_network *cur_network = &(pmlmepriv->cur_network); + struct wlan_network *pcur_wlan = NULL, *ptarget_wlan = NULL; + unsigned int the_same_macaddr = _FALSE; + + +#ifdef CONFIG_RTL8712 + /* endian_convert */ + pnetwork->join_res = le32_to_cpu(pnetwork->join_res); + pnetwork->network_type = le32_to_cpu(pnetwork->network_type); + pnetwork->network.Length = le32_to_cpu(pnetwork->network.Length); + pnetwork->network.Ssid.SsidLength = le32_to_cpu(pnetwork->network.Ssid.SsidLength); + pnetwork->network.Privacy = le32_to_cpu(pnetwork->network.Privacy); + pnetwork->network.Rssi = le32_to_cpu(pnetwork->network.Rssi); + pnetwork->network.NetworkTypeInUse = le32_to_cpu(pnetwork->network.NetworkTypeInUse) ; + pnetwork->network.Configuration.ATIMWindow = le32_to_cpu(pnetwork->network.Configuration.ATIMWindow); + pnetwork->network.Configuration.BeaconPeriod = le32_to_cpu(pnetwork->network.Configuration.BeaconPeriod); + pnetwork->network.Configuration.DSConfig = le32_to_cpu(pnetwork->network.Configuration.DSConfig); + pnetwork->network.Configuration.FHConfig.DwellTime = le32_to_cpu(pnetwork->network.Configuration.FHConfig.DwellTime); + pnetwork->network.Configuration.FHConfig.HopPattern = le32_to_cpu(pnetwork->network.Configuration.FHConfig.HopPattern); + pnetwork->network.Configuration.FHConfig.HopSet = le32_to_cpu(pnetwork->network.Configuration.FHConfig.HopSet); + pnetwork->network.Configuration.FHConfig.Length = le32_to_cpu(pnetwork->network.Configuration.FHConfig.Length); + pnetwork->network.Configuration.Length = le32_to_cpu(pnetwork->network.Configuration.Length); + pnetwork->network.InfrastructureMode = le32_to_cpu(pnetwork->network.InfrastructureMode); + pnetwork->network.IELength = le32_to_cpu(pnetwork->network.IELength); +#endif + + + rtw_get_encrypt_decrypt_from_registrypriv(adapter); + + + + the_same_macaddr = _rtw_memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN); + + pnetwork->network.Length = get_WLAN_BSSID_EX_sz(&pnetwork->network); + if (pnetwork->network.Length > sizeof(WLAN_BSSID_EX)) { + goto ignore_joinbss_callback; + } + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0; + pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0; + + + if (pnetwork->join_res > 0) { + _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + retry = 0; + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { + /* s1. find ptarget_wlan */ + if (check_fwstate(pmlmepriv, _FW_LINKED)) { + if (the_same_macaddr == _TRUE) + ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); + else { + pcur_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); + if (pcur_wlan) + pcur_wlan->fixed = _FALSE; + + pcur_sta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); + if (pcur_sta) { + /* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); */ + rtw_free_stainfo(adapter, pcur_sta); + /* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); */ + } + + ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress); + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) { + if (ptarget_wlan) + ptarget_wlan->fixed = _TRUE; + } + } + + } else { + ptarget_wlan = _rtw_find_same_network(&pmlmepriv->scanned_queue, pnetwork); + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) { + if (ptarget_wlan) + ptarget_wlan->fixed = _TRUE; + } + } + + /* s2. update cur_network */ + if (ptarget_wlan) + rtw_joinbss_update_network(adapter, ptarget_wlan, pnetwork); + else { + RTW_PRINT("Can't find ptarget_wlan when joinbss_event callback\n"); + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + goto ignore_joinbss_callback; + } + + + /* s3. find ptarget_sta & update ptarget_sta after update cur_network only for station mode */ + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) { + ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork); + if (ptarget_sta == NULL) { + RTW_ERR("Can't update stainfo when joinbss_event callback\n"); + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + goto ignore_joinbss_callback; + } + } + + /* s4. indicate connect */ + if (MLME_IS_STA(adapter) || MLME_IS_ADHOC(adapter)) { + pmlmepriv->cur_network_scanned = ptarget_wlan; + rtw_indicate_connect(adapter); + } + + /* s5. Cancle assoc_timer */ + _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled); + + + } else { + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + goto ignore_joinbss_callback; + } + + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + + } else if (pnetwork->join_res == -4) { + rtw_reset_securitypriv(adapter); + _set_timer(&pmlmepriv->assoc_timer, 1); + + /* rtw_free_assoc_resources(adapter, 1); */ + + if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == _TRUE) { + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + } + + } else { /* if join_res < 0 (join fails), then try again */ + +#ifdef REJOIN + res = _FAIL; + if (retry < 2) { + res = rtw_select_and_join_from_scanned_queue(pmlmepriv); + } + + if (res == _SUCCESS) { + /* extend time of assoc_timer */ + _set_timer(&pmlmepriv->assoc_timer, MAX_JOIN_TIMEOUT); + retry++; + } else if (res == 2) { /* there is no need to wait for join */ + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + rtw_indicate_connect(adapter); + } else { +#endif + + _set_timer(&pmlmepriv->assoc_timer, 1); + /* rtw_free_assoc_resources(adapter, 1); */ + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + +#ifdef REJOIN + retry = 0; + } +#endif + } + +ignore_joinbss_callback: + _exit_critical_bh(&pmlmepriv->lock, &irqL); +} + +void rtw_joinbss_event_callback(_adapter *adapter, u8 *pbuf) +{ + struct wlan_network *pnetwork = (struct wlan_network *)pbuf; + + + mlmeext_joinbss_event_callback(adapter, pnetwork->join_res); + + rtw_mi_os_xmit_schedule(adapter); + +} + +void rtw_sta_media_status_rpt(_adapter *adapter, struct sta_info *sta, bool connected) +{ + struct macid_ctl_t *macid_ctl = &adapter->dvobj->macid_ctl; + bool miracast_enabled = 0; + bool miracast_sink = 0; + u8 role = H2C_MSR_ROLE_RSVD; + + if (sta == NULL) { + RTW_PRINT(FUNC_ADPT_FMT" sta is NULL\n" + , FUNC_ADPT_ARG(adapter)); + rtw_warn_on(1); + return; + } + + if (sta->mac_id >= macid_ctl->num) { + RTW_PRINT(FUNC_ADPT_FMT" invalid macid:%u\n" + , FUNC_ADPT_ARG(adapter), sta->mac_id); + rtw_warn_on(1); + return; + } + + if (!rtw_macid_is_used(macid_ctl, sta->mac_id)) { + RTW_PRINT(FUNC_ADPT_FMT" macid:%u not is used, set connected to 0\n" + , FUNC_ADPT_ARG(adapter), sta->mac_id); + connected = 0; + rtw_warn_on(1); + } + + if (connected && !rtw_macid_is_bmc(macid_ctl, sta->mac_id)) { + miracast_enabled = STA_OP_WFD_MODE(sta) != 0 && is_miracast_enabled(adapter); + miracast_sink = miracast_enabled && (STA_OP_WFD_MODE(sta) & MIRACAST_SINK); + +#ifdef CONFIG_TDLS + if (sta->tdls_sta_state & TDLS_LINKED_STATE) + role = H2C_MSR_ROLE_TDLS; + else +#endif + if (MLME_IS_STA(adapter)) { + if (MLME_IS_GC(adapter)) + role = H2C_MSR_ROLE_GO; + else + role = H2C_MSR_ROLE_AP; + } else if (MLME_IS_AP(adapter)) { + if (MLME_IS_GO(adapter)) + role = H2C_MSR_ROLE_GC; + else + role = H2C_MSR_ROLE_STA; + } else if (MLME_IS_ADHOC(adapter) || MLME_IS_ADHOC_MASTER(adapter)) + role = H2C_MSR_ROLE_ADHOC; + +#ifdef CONFIG_WFD + if (role == H2C_MSR_ROLE_GC + || role == H2C_MSR_ROLE_GO + || role == H2C_MSR_ROLE_TDLS + ) { + if (adapter->wfd_info.rtsp_ctrlport + || adapter->wfd_info.tdls_rtsp_ctrlport + || adapter->wfd_info.peer_rtsp_ctrlport) + rtw_wfd_st_switch(sta, 1); + } +#endif + } + + rtw_hal_set_FwMediaStatusRpt_single_cmd(adapter + , connected + , miracast_enabled + , miracast_sink + , role + , sta->mac_id + ); +} + +u8 rtw_sta_media_status_rpt_cmd(_adapter *adapter, struct sta_info *sta, bool connected) +{ + struct cmd_priv *cmdpriv = &adapter->cmdpriv; + struct cmd_obj *cmdobj; + struct drvextra_cmd_parm *cmd_parm; + struct sta_media_status_rpt_cmd_parm *rpt_parm; + u8 res = _SUCCESS; + + cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (cmdobj == NULL) { + res = _FAIL; + goto exit; + } + + cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (cmd_parm == NULL) { + rtw_mfree((u8 *)cmdobj, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + rpt_parm = (struct sta_media_status_rpt_cmd_parm *)rtw_zmalloc(sizeof(struct sta_media_status_rpt_cmd_parm)); + if (rpt_parm == NULL) { + rtw_mfree((u8 *)cmdobj, sizeof(struct cmd_obj)); + rtw_mfree((u8 *)cmd_parm, sizeof(struct drvextra_cmd_parm)); + res = _FAIL; + goto exit; + } + + rpt_parm->sta = sta; + rpt_parm->connected = connected; + + cmd_parm->ec_id = STA_MSTATUS_RPT_WK_CID; + cmd_parm->type = 0; + cmd_parm->size = sizeof(struct sta_media_status_rpt_cmd_parm); + cmd_parm->pbuf = (u8 *)rpt_parm; + init_h2fwcmd_w_parm_no_rsp(cmdobj, cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(cmdpriv, cmdobj); + +exit: + return res; +} + +inline void rtw_sta_media_status_rpt_cmd_hdl(_adapter *adapter, struct sta_media_status_rpt_cmd_parm *parm) +{ + rtw_sta_media_status_rpt(adapter, parm->sta, parm->connected); +} + +void rtw_stassoc_event_callback(_adapter *adapter, u8 *pbuf) +{ + _irqL irqL; + struct sta_info *psta; + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct stassoc_event *pstassoc = (struct stassoc_event *)pbuf; + struct wlan_network *cur_network = &(pmlmepriv->cur_network); + struct wlan_network *ptarget_wlan = NULL; + + +#if CONFIG_RTW_MACADDR_ACL + if (rtw_access_ctrl(adapter, pstassoc->macaddr) == _FALSE) + return; +#endif + +#if defined(CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr); + if (psta) { + u8 *passoc_req = NULL; + u32 assoc_req_len = 0; + + rtw_sta_media_status_rpt(adapter, psta, 1); + +#ifndef CONFIG_AUTO_AP_MODE + + ap_sta_info_defer_update(adapter, psta); + + /* report to upper layer */ + RTW_INFO("indicate_sta_assoc_event to upper layer - hostapd\n"); +#ifdef CONFIG_IOCTL_CFG80211 + _enter_critical_bh(&psta->lock, &irqL); + if (psta->passoc_req && psta->assoc_req_len > 0) { + passoc_req = rtw_zmalloc(psta->assoc_req_len); + if (passoc_req) { + assoc_req_len = psta->assoc_req_len; + _rtw_memcpy(passoc_req, psta->passoc_req, assoc_req_len); + + rtw_mfree(psta->passoc_req , psta->assoc_req_len); + psta->passoc_req = NULL; + psta->assoc_req_len = 0; + } + } + _exit_critical_bh(&psta->lock, &irqL); + + if (passoc_req && assoc_req_len > 0) { + rtw_cfg80211_indicate_sta_assoc(adapter, passoc_req, assoc_req_len); + + rtw_mfree(passoc_req, assoc_req_len); + } +#else /* !CONFIG_IOCTL_CFG80211 */ + rtw_indicate_sta_assoc_event(adapter, psta); +#endif /* !CONFIG_IOCTL_CFG80211 */ +#endif /* !CONFIG_AUTO_AP_MODE */ + +#ifdef CONFIG_BEAMFORMING + beamforming_wk_cmd(adapter, BEAMFORMING_CTRL_ENTER, (u8 *)psta, sizeof(struct sta_info), 0); +#endif/*CONFIG_BEAMFORMING*/ + if (is_wep_enc(adapter->securitypriv.dot11PrivacyAlgrthm)) + rtw_ap_wep_pk_setting(adapter, psta); + } + goto exit; + } +#endif /* defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ + + /* for AD-HOC mode */ + psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr); + if (psta == NULL) { + RTW_ERR(FUNC_ADPT_FMT" get no sta_info with "MAC_FMT"\n" + , FUNC_ADPT_ARG(adapter), MAC_ARG(pstassoc->macaddr)); + rtw_warn_on(1); + goto exit; + } + + rtw_hal_set_odm_var(adapter, HAL_ODM_STA_INFO, psta, _TRUE); + + rtw_sta_media_status_rpt(adapter, psta, 1); + + if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) + psta->dot118021XPrivacy = adapter->securitypriv.dot11PrivacyAlgrthm; + + + psta->ieee8021x_blocked = _FALSE; + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)) { + if (adapter->stapriv.asoc_sta_count == 2) { + _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); + pmlmepriv->cur_network_scanned = ptarget_wlan; + if (ptarget_wlan) + ptarget_wlan->fixed = _TRUE; + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ + rtw_indicate_connect(adapter); + } + } + + _exit_critical_bh(&pmlmepriv->lock, &irqL); + + + mlmeext_sta_add_event_callback(adapter, psta); + +#ifdef CONFIG_RTL8711 + /* submit SetStaKey_cmd to tell fw, fw will allocate an CAM entry for this sta */ + rtw_setstakey_cmd(adapter, psta, GROUP_KEY, _TRUE); +#endif + +exit: + return; +} + +#ifdef CONFIG_IEEE80211W +void rtw_sta_timeout_event_callback(_adapter *adapter, u8 *pbuf) +{ + _irqL irqL; + struct sta_info *psta; + struct stadel_event *pstadel = (struct stadel_event *)pbuf; + struct sta_priv *pstapriv = &adapter->stapriv; + + + psta = rtw_get_stainfo(&adapter->stapriv, pstadel->macaddr); + + if (psta) { + u8 updated = _FALSE; + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + if (rtw_is_list_empty(&psta->asoc_list) == _FALSE) { + rtw_list_delete(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + updated = ap_free_sta(adapter, psta, _TRUE, WLAN_REASON_PREV_AUTH_NOT_VALID, _TRUE); + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + associated_clients_update(adapter, updated, STA_INFO_UPDATE_ALL); + } + + + +} +#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_RTW_80211R +void rtw_update_ft_stainfo(_adapter *padapter, WLAN_BSSID_EX *pnetwork) +{ + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta = NULL; + + psta = rtw_get_stainfo(pstapriv, pnetwork->MacAddress); + if (psta == NULL) + psta = rtw_alloc_stainfo(pstapriv, pnetwork->MacAddress); + + if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { + + padapter->securitypriv.binstallGrpkey = _FALSE; + padapter->securitypriv.busetkipkey = _FALSE; + padapter->securitypriv.bgrpkey_handshake = _FALSE; + + psta->ieee8021x_blocked = _TRUE; + psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; + psta->dot11txpn.val = psta->dot11txpn.val + 1; + + _rtw_memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof(union Keytype)); + _rtw_memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof(union Keytype)); + _rtw_memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof(union Keytype)); + _rtw_memset((u8 *)&psta->dot11txpn, 0, sizeof(union pn48)); +#ifdef CONFIG_IEEE80211W + _rtw_memset((u8 *)&psta->dot11wtxpn, 0, sizeof(union pn48)); +#endif + _rtw_memset((u8 *)&psta->dot11rxpn, 0, sizeof(union pn48)); + } + +} + +void rtw_ft_reassoc_event_callback(_adapter *padapter, u8 *pbuf) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct stassoc_event *pstassoc = (struct stassoc_event *)pbuf; + ft_priv *pftpriv = &pmlmepriv->ftpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network)); + struct cfg80211_ft_event_params ft_evt_parms; + _irqL irqL; + + _rtw_memset(&ft_evt_parms, 0, sizeof(ft_evt_parms)); + rtw_update_ft_stainfo(padapter, pnetwork); + ft_evt_parms.ies_len = pftpriv->ft_event.ies_len; + ft_evt_parms.ies = rtw_zmalloc(ft_evt_parms.ies_len); + if (ft_evt_parms.ies) + _rtw_memcpy((void *)ft_evt_parms.ies, pftpriv->ft_event.ies, ft_evt_parms.ies_len); + else + goto err_2; + + ft_evt_parms.target_ap = rtw_zmalloc(ETH_ALEN); + if (ft_evt_parms.target_ap) + _rtw_memcpy((void *)ft_evt_parms.target_ap, pstassoc->macaddr, ETH_ALEN); + else + goto err_1; + + ft_evt_parms.ric_ies = pftpriv->ft_event.ric_ies; + ft_evt_parms.ric_ies_len = pftpriv->ft_event.ric_ies_len; + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + rtw_set_ft_status(padapter, RTW_FT_AUTHENTICATED_STA); + _exit_critical_bh(&pmlmepriv->lock, &irqL); + + rtw_cfg80211_ft_event(padapter, &ft_evt_parms); + RTW_INFO("%s: to "MAC_FMT"\n", __func__, MAC_ARG(ft_evt_parms.target_ap)); + + rtw_mfree((u8 *)pftpriv->ft_event.target_ap, ETH_ALEN); +err_1: + rtw_mfree((u8 *)ft_evt_parms.ies, ft_evt_parms.ies_len); +err_2: + return; +} +#endif + +void rtw_sta_mstatus_disc_rpt(_adapter *adapter, u8 mac_id) +{ + struct macid_ctl_t *macid_ctl = &adapter->dvobj->macid_ctl; + + RTW_INFO("%s "ADPT_FMT" - mac_id=%d\n", __func__, ADPT_ARG(adapter), mac_id); + + if (mac_id >= 0 && mac_id < macid_ctl->num) { + rtw_hal_set_FwMediaStatusRpt_single_cmd(adapter, 0, 0, 0, 0, mac_id); + /* + * For safety, prevent from keeping macid sleep. + * If we can sure all power mode enter/leave are paired, + * this check can be removed. + * Lucas@20131113 + */ + /* wakeup macid after disconnect. */ + /*if (MLME_IS_STA(adapter))*/ + rtw_hal_macid_wakeup(adapter, mac_id); + } else { + RTW_PRINT(FUNC_ADPT_FMT" invalid macid:%u\n" + , FUNC_ADPT_ARG(adapter), mac_id); + rtw_warn_on(1); + } +} +void rtw_sta_mstatus_report(_adapter *adapter) +{ + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct wlan_network *tgt_network = &pmlmepriv->cur_network; + struct sta_info *psta = NULL; + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + psta = rtw_get_stainfo(&adapter->stapriv, tgt_network->network.MacAddress); + if (psta) + rtw_sta_mstatus_disc_rpt(adapter, psta->mac_id); + else { + RTW_INFO("%s "ADPT_FMT" - mac_addr: "MAC_FMT" psta == NULL\n", __func__, ADPT_ARG(adapter), MAC_ARG(tgt_network->network.MacAddress)); + rtw_warn_on(1); + } + } +} + +void rtw_stadel_event_callback(_adapter *adapter, u8 *pbuf) +{ + _irqL irqL, irqL2; + + struct sta_info *psta; + struct wlan_network *pwlan = NULL; + WLAN_BSSID_EX *pdev_network = NULL; + u8 *pibss = NULL; + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + struct stadel_event *pstadel = (struct stadel_event *)pbuf; + struct sta_priv *pstapriv = &adapter->stapriv; + struct wlan_network *tgt_network = &(pmlmepriv->cur_network); + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + + RTW_INFO("%s(mac_id=%d)=" MAC_FMT "\n", __func__, pstadel->mac_id, MAC_ARG(pstadel->macaddr)); + rtw_sta_mstatus_disc_rpt(adapter, pstadel->mac_id); + + psta = rtw_get_stainfo(&adapter->stapriv, pstadel->macaddr); + + if (psta == NULL) { + RTW_INFO("%s(mac_id=%d)=" MAC_FMT " psta == NULL\n", __func__, pstadel->mac_id, MAC_ARG(pstadel->macaddr)); + /*rtw_warn_on(1);*/ + } + + if (psta) + rtw_wfd_st_switch(psta, 0); + + /* if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) */ + if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { +#ifdef CONFIG_IOCTL_CFG80211 +#ifdef COMPAT_KERNEL_RELEASE + +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)) || defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) + rtw_cfg80211_indicate_sta_disassoc(adapter, pstadel->macaddr, *(u16 *)pstadel->rsvd); +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37)) || defined(CONFIG_CFG80211_FORCE_COMPATIBLE_2_6_37_UNDER) */ +#endif /* CONFIG_IOCTL_CFG80211 */ + + return; + } + + mlmeext_sta_del_event_callback(adapter); + + _enter_critical_bh(&pmlmepriv->lock, &irqL2); + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + u16 reason = *((unsigned short *)(pstadel->rsvd)); + bool roam = _FALSE; + struct wlan_network *roam_target = NULL; + +#ifdef CONFIG_LAYER2_ROAMING +#ifdef CONFIG_RTW_80211R + if (reason == WLAN_REASON_EXPIRATION_CHK && rtw_chk_roam_flags(adapter, RTW_ROAM_ON_EXPIRED)) + pmlmepriv->ftpriv.ft_roam_on_expired = _TRUE; + else + pmlmepriv->ftpriv.ft_roam_on_expired = _FALSE; +#endif + if (adapter->registrypriv.wifi_spec == 1) + roam = _FALSE; + else if (reason == WLAN_REASON_EXPIRATION_CHK && rtw_chk_roam_flags(adapter, RTW_ROAM_ON_EXPIRED)) + roam = _TRUE; + else if (reason == WLAN_REASON_ACTIVE_ROAM && rtw_chk_roam_flags(adapter, RTW_ROAM_ACTIVE)) { + roam = _TRUE; + roam_target = pmlmepriv->roam_network; + } +#ifdef CONFIG_INTEL_WIDI + else if (adapter->mlmepriv.widi_state == INTEL_WIDI_STATE_CONNECTED) + roam = _TRUE; +#endif /* CONFIG_INTEL_WIDI */ + + if (roam == _TRUE) { + if (rtw_to_roam(adapter) > 0) + rtw_dec_to_roam(adapter); /* this stadel_event is caused by roaming, decrease to_roam */ + else if (rtw_to_roam(adapter) == 0) + rtw_set_to_roam(adapter, adapter->registrypriv.max_roaming_times); + } else + rtw_set_to_roam(adapter, 0); +#endif /* CONFIG_LAYER2_ROAMING */ + + rtw_free_uc_swdec_pending_queue(adapter); + + rtw_free_assoc_resources(adapter, 1); + rtw_free_mlme_priv_ie_data(pmlmepriv); + + _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + /* remove the network entry in scanned_queue */ + pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); + if ((pwlan) && (!check_fwstate(pmlmepriv, WIFI_UNDER_WPS))) { + pwlan->fixed = _FALSE; + rtw_free_network_nolock(adapter, pwlan); + } + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + + rtw_indicate_disconnect(adapter, *(u16 *)pstadel->rsvd, pstadel->locally_generated); +#ifdef CONFIG_INTEL_WIDI + if (!rtw_to_roam(adapter)) + process_intel_widi_disconnect(adapter, 1); +#endif /* CONFIG_INTEL_WIDI */ + + _rtw_roaming(adapter, roam_target); + } + + if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || + check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { + + /* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + rtw_free_stainfo(adapter, psta); + /* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + + if (adapter->stapriv.asoc_sta_count == 1) { /* a sta + bc/mc_stainfo (not Ibss_stainfo) */ + /* rtw_indicate_disconnect(adapter); */ /* removed@20091105 */ + _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + /* free old ibss network */ + /* pwlan = rtw_find_network(&pmlmepriv->scanned_queue, pstadel->macaddr); */ + pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); + if (pwlan) { + pwlan->fixed = _FALSE; + rtw_free_network_nolock(adapter, pwlan); + } + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + /* re-create ibss */ + pdev_network = &(adapter->registrypriv.dev_network); + pibss = adapter->registrypriv.dev_network.MacAddress; + + _rtw_memcpy(pdev_network, &tgt_network->network, get_WLAN_BSSID_EX_sz(&tgt_network->network)); + + _rtw_memset(&pdev_network->Ssid, 0, sizeof(NDIS_802_11_SSID)); + _rtw_memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(NDIS_802_11_SSID)); + + rtw_update_registrypriv_dev_network(adapter); + + rtw_generate_random_ibss(pibss); + + if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { + set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE); + _clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE); + } + + if (rtw_create_ibss_cmd(adapter, 0) != _SUCCESS) + RTW_ERR("rtw_create_ibss_cmd FAIL\n"); + + } + + } + + _exit_critical_bh(&pmlmepriv->lock, &irqL2); + + +} + + +void rtw_cpwm_event_callback(PADAPTER padapter, u8 *pbuf) +{ +#ifdef CONFIG_LPS_LCLK + struct reportpwrstate_parm *preportpwrstate; +#endif + + +#ifdef CONFIG_LPS_LCLK + preportpwrstate = (struct reportpwrstate_parm *)pbuf; + preportpwrstate->state |= (u8)(adapter_to_pwrctl(padapter)->cpwm_tog + 0x80); + cpwm_int_hdl(padapter, preportpwrstate); +#endif + + +} + + +void rtw_wmm_event_callback(PADAPTER padapter, u8 *pbuf) +{ + + WMMOnAssocRsp(padapter); + + +} + +/* +* _rtw_join_timeout_handler - Timeout/faliure handler for CMD JoinBss +* @adapter: pointer to _adapter structure +*/ +void _rtw_join_timeout_handler(_adapter *adapter) +{ + _irqL irqL; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + +#if 0 + if (rtw_is_drv_stopped(adapter)) { + _rtw_up_sema(&pmlmepriv->assoc_terminate); + return; + } +#endif + + + + RTW_INFO("%s, fw_state=%x\n", __FUNCTION__, get_fwstate(pmlmepriv)); + + if (RTW_CANNOT_RUN(adapter)) + return; + + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + +#ifdef CONFIG_LAYER2_ROAMING + if (rtw_to_roam(adapter) > 0) { /* join timeout caused by roaming */ + while (1) { + rtw_dec_to_roam(adapter); + if (rtw_to_roam(adapter) != 0) { /* try another */ + int do_join_r; + RTW_INFO("%s try another roaming\n", __FUNCTION__); + do_join_r = rtw_do_join(adapter); + if (_SUCCESS != do_join_r) { + RTW_INFO("%s roaming do_join return %d\n", __FUNCTION__ , do_join_r); + continue; + } + break; + } else { +#ifdef CONFIG_INTEL_WIDI + if (adapter->mlmepriv.widi_state == INTEL_WIDI_STATE_ROAMING) { + _rtw_memset(pmlmepriv->sa_ext, 0x00, L2SDTA_SERVICE_VE_LEN); + intel_widi_wk_cmd(adapter, INTEL_WIDI_LISTEN_WK, NULL, 0); + RTW_INFO("change to widi listen\n"); + } +#endif /* CONFIG_INTEL_WIDI */ + RTW_INFO("%s We've try roaming but fail\n", __FUNCTION__); +#ifdef CONFIG_RTW_80211R + rtw_clr_ft_flags(adapter, RTW_FT_SUPPORTED|RTW_FT_OVER_DS_SUPPORTED); + rtw_reset_ft_status(adapter); +#endif + rtw_indicate_disconnect(adapter, 0, _FALSE); + break; + } + } + + } else +#endif + { + rtw_indicate_disconnect(adapter, 0, _FALSE); + free_scanqueue(pmlmepriv);/* ??? */ + +#ifdef CONFIG_IOCTL_CFG80211 + /* indicate disconnect for the case that join_timeout and check_fwstate != FW_LINKED */ + rtw_cfg80211_indicate_disconnect(adapter, 0, _FALSE); +#endif /* CONFIG_IOCTL_CFG80211 */ + + } + + _exit_critical_bh(&pmlmepriv->lock, &irqL); + + +#ifdef CONFIG_DRVEXT_MODULE_WSC + drvext_assoc_fail_indicate(&adapter->drvextpriv); +#endif + + + +} + +/* +* rtw_scan_timeout_handler - Timeout/Faliure handler for CMD SiteSurvey +* @adapter: pointer to _adapter structure +*/ +void rtw_scan_timeout_handler(_adapter *adapter) +{ + _irqL irqL; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + RTW_INFO(FUNC_ADPT_FMT" fw_state=%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv)); + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); + + _exit_critical_bh(&pmlmepriv->lock, &irqL); + +#ifdef CONFIG_IOCTL_CFG80211 + rtw_cfg80211_surveydone_event_callback(adapter); +#endif /* CONFIG_IOCTL_CFG80211 */ + + rtw_indicate_scan_done(adapter, _TRUE); + +#if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_IOCTL_CFG80211) + rtw_cfg80211_indicate_scan_done_for_buddy(adapter, _TRUE); +#endif +} + +void rtw_mlme_reset_auto_scan_int(_adapter *adapter, u8 *reason) +{ + struct mlme_priv *mlme = &adapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 u_ch; + u32 interval_ms = 0xffffffff; /* 0xffffffff: special value to make min() works well, also means no auto scan */ + + *reason = RTW_AUTO_SCAN_REASON_UNSPECIFIED; + rtw_mi_get_ch_setting_union(adapter, &u_ch, NULL, NULL); + + if (hal_chk_bw_cap(adapter, BW_CAP_40M) + && is_client_associated_to_ap(adapter) == _TRUE + && u_ch >= 1 && u_ch <= 14 + && adapter->registrypriv.wifi_spec + /* TODO: AP Connected is 40MHz capability? */ + ) { + interval_ms = rtw_min(interval_ms, 60 * 1000); + *reason |= RTW_AUTO_SCAN_REASON_2040_BSS; + } + +exit: + if (interval_ms == 0xffffffff) + interval_ms = 0; + + rtw_mlme_set_auto_scan_int(adapter, interval_ms); + return; +} + +void rtw_drv_scan_by_self(_adapter *padapter, u8 reason) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct rtw_ieee80211_channel ch_for_2040_bss[14] = { + {1, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + {2, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + {3, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + {4, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + {5, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + {6, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + {7, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + {8, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + {9, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + {10, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + {11, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + {12, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + {13, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + {14, RTW_IEEE80211_CHAN_PASSIVE_SCAN}, + }; + struct rtw_ieee80211_channel *ch_sel = NULL; + int ch_num = 0; + + if (rtw_is_scan_deny(padapter)) + goto exit; + + if (!rtw_is_adapter_up(padapter)) + goto exit; + + if (rtw_mi_busy_traffic_check(padapter, _FALSE)) { +#ifdef CONFIG_LAYER2_ROAMING + if (rtw_chk_roam_flags(padapter, RTW_ROAM_ACTIVE) && pmlmepriv->need_to_roam == _TRUE) { + RTW_INFO("need to roam, don't care BusyTraffic\n"); + } else +#endif + { + RTW_INFO(FUNC_ADPT_FMT" exit BusyTraffic\n", FUNC_ADPT_ARG(padapter)); + goto exit; + } + } + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) && check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) { + RTW_INFO(FUNC_ADPT_FMT" WIFI_AP_STATE && WIFI_UNDER_WPS\n", FUNC_ADPT_ARG(padapter)); + goto exit; + } + if (check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY | _FW_UNDER_LINKING)) == _TRUE) { + RTW_INFO(FUNC_ADPT_FMT" _FW_UNDER_SURVEY|_FW_UNDER_LINKING\n", FUNC_ADPT_ARG(padapter)); + goto exit; + } + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_buddy_check_fwstate(padapter, (_FW_UNDER_SURVEY | _FW_UNDER_LINKING | WIFI_UNDER_WPS))) { + RTW_INFO(FUNC_ADPT_FMT", but buddy_intf is under scanning or linking or wps_phase\n", FUNC_ADPT_ARG(padapter)); + goto exit; + } +#endif + + RTW_INFO(FUNC_ADPT_FMT" reason:0x%02x\n", FUNC_ADPT_ARG(padapter), reason); + + /* only for 20/40 BSS */ + if (reason == RTW_AUTO_SCAN_REASON_2040_BSS) { + ch_sel = ch_for_2040_bss; + ch_num = 14; + } + + rtw_set_802_11_bssid_list_scan(padapter, NULL, 0, ch_sel, ch_num); +exit: + return; +} + +static void rtw_auto_scan_handler(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + u8 reason = RTW_AUTO_SCAN_REASON_UNSPECIFIED; + + rtw_mlme_reset_auto_scan_int(padapter, &reason); + +#ifdef CONFIG_P2P + if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE)) + goto exit; +#endif + +#ifdef CONFIG_TDLS + if (padapter->tdlsinfo.link_established == _TRUE) + goto exit; +#endif + + if (pmlmepriv->auto_scan_int_ms == 0 + || rtw_get_passing_time_ms(pmlmepriv->scan_start_time) < pmlmepriv->auto_scan_int_ms) + goto exit; + + rtw_drv_scan_by_self(padapter, reason); + +exit: + return; +} +static u8 is_drv_in_lps(_adapter *adapter) +{ + u8 is_in_lps = _FALSE; + + #ifdef CONFIG_LPS_LCLK_WD_TIMER /* to avoid leaving lps 32k frequently*/ + if ((adapter_to_pwrctl(adapter)->bFwCurrentInPSMode == _TRUE) + #ifdef CONFIG_BT_COEXIST + && (rtw_btcoex_IsBtControlLps(adapter) == _FALSE) + #endif + ) + is_in_lps = _TRUE; + #endif /* CONFIG_LPS_LCLK_WD_TIMER*/ + return is_in_lps; +} +void rtw_iface_dynamic_check_timer_handlder(_adapter *adapter) +{ +#ifdef CONFIG_AP_MODE + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; +#endif /* CONFIG_AP_MODE */ + + if (adapter->net_closed == _TRUE) + return; + #ifdef CONFIG_LPS_LCLK_WD_TIMER /* to avoid leaving lps 32k frequently*/ + if (is_drv_in_lps(adapter)) { + u8 bEnterPS; + + linked_status_chk(adapter, 1); + + bEnterPS = traffic_status_watchdog(adapter, 1); + if (bEnterPS) { + /* rtw_lps_ctrl_wk_cmd(adapter, LPS_CTRL_ENTER, 1); */ + rtw_hal_dm_watchdog_in_lps(adapter); + } else { + /* call rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, 1) in traffic_status_watchdog() */ + } + } + #endif /* CONFIG_LPS_LCLK_WD_TIMER */ + + /* auto site survey */ + rtw_auto_scan_handler(adapter); + +#ifndef CONFIG_ACTIVE_KEEP_ALIVE_CHECK +#ifdef CONFIG_AP_MODE + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) + expire_timeout_chk(adapter); +#endif +#endif /* !CONFIG_ACTIVE_KEEP_ALIVE_CHECK */ + +#ifdef CONFIG_BR_EXT + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) + rcu_read_lock(); +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) */ + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) + if (adapter->pnetdev->br_port +#else /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */ + if (rcu_dereference(adapter->pnetdev->rx_handler_data) +#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */ + && (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) == _TRUE)) { + /* expire NAT2.5 entry */ + void nat25_db_expire(_adapter *priv); + nat25_db_expire(adapter); + + if (adapter->pppoe_connection_in_progress > 0) + adapter->pppoe_connection_in_progress--; + /* due to rtw_dynamic_check_timer_handlder() is called every 2 seconds */ + if (adapter->pppoe_connection_in_progress > 0) + adapter->pppoe_connection_in_progress--; + } + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) + rcu_read_unlock(); +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35)) */ + +#endif /* CONFIG_BR_EXT */ + +} + +/*#define DBG_TRAFFIC_STATISTIC*/ +static void collect_traffic_statistics(_adapter *padapter) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); + + /*_rtw_memset(&pdvobjpriv->traffic_stat, 0, sizeof(struct rtw_traffic_statistics));*/ + + /* Tx bytes reset*/ + pdvobjpriv->traffic_stat.tx_bytes = 0; + pdvobjpriv->traffic_stat.tx_pkts = 0; + pdvobjpriv->traffic_stat.tx_drop = 0; + + /* Rx bytes reset*/ + pdvobjpriv->traffic_stat.rx_bytes = 0; + pdvobjpriv->traffic_stat.rx_pkts = 0; + pdvobjpriv->traffic_stat.rx_drop = 0; + + rtw_mi_traffic_statistics(padapter); + + /* Calculate throughput in last interval */ + pdvobjpriv->traffic_stat.cur_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes - pdvobjpriv->traffic_stat.last_tx_bytes; + pdvobjpriv->traffic_stat.cur_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes - pdvobjpriv->traffic_stat.last_rx_bytes; + pdvobjpriv->traffic_stat.last_tx_bytes = pdvobjpriv->traffic_stat.tx_bytes; + pdvobjpriv->traffic_stat.last_rx_bytes = pdvobjpriv->traffic_stat.rx_bytes; + + pdvobjpriv->traffic_stat.cur_tx_tp = (u32)(pdvobjpriv->traffic_stat.cur_tx_bytes * 8 / 2 / 1024 / 1024); + pdvobjpriv->traffic_stat.cur_rx_tp = (u32)(pdvobjpriv->traffic_stat.cur_rx_bytes * 8 / 2 / 1024 / 1024); + + #ifdef DBG_TRAFFIC_STATISTIC + RTW_INFO("\n========================\n"); + RTW_INFO("cur_tx_bytes:%lld\n", pdvobjpriv->traffic_stat.cur_tx_bytes); + RTW_INFO("cur_rx_bytes:%lld\n", pdvobjpriv->traffic_stat.cur_rx_bytes); + + RTW_INFO("last_tx_bytes:%lld\n", pdvobjpriv->traffic_stat.last_tx_bytes); + RTW_INFO("last_rx_bytes:%lld\n", pdvobjpriv->traffic_stat.last_rx_bytes); + + RTW_INFO("cur_tx_tp:%d\n", pdvobjpriv->traffic_stat.cur_tx_tp); + RTW_INFO("cur_rx_tp:%d\n", pdvobjpriv->traffic_stat.cur_rx_tp); + #endif +} + +void rtw_dynamic_check_timer_handlder(_adapter *adapter) +{ + if (!adapter) + return; + + if (!rtw_is_hw_init_completed(adapter)) + return; + + if (RTW_CANNOT_RUN(adapter)) + return; + + collect_traffic_statistics(adapter); + + rtw_mi_dynamic_check_timer_handlder(adapter); + + if (!is_drv_in_lps(adapter)) + rtw_dynamic_chk_wk_cmd(adapter); +} + + +#ifdef CONFIG_SET_SCAN_DENY_TIMER +inline bool rtw_is_scan_deny(_adapter *adapter) +{ + struct mlme_priv *mlmepriv = &adapter->mlmepriv; + return (ATOMIC_READ(&mlmepriv->set_scan_deny) != 0) ? _TRUE : _FALSE; +} + +inline void rtw_clear_scan_deny(_adapter *adapter) +{ + struct mlme_priv *mlmepriv = &adapter->mlmepriv; + ATOMIC_SET(&mlmepriv->set_scan_deny, 0); + if (0) + RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); +} + +void rtw_set_scan_deny_timer_hdl(_adapter *adapter) +{ + rtw_clear_scan_deny(adapter); +} +void rtw_set_scan_deny(_adapter *adapter, u32 ms) +{ + struct mlme_priv *mlmepriv = &adapter->mlmepriv; + if (0) + RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter)); + ATOMIC_SET(&mlmepriv->set_scan_deny, 1); + _set_timer(&mlmepriv->set_scan_deny_timer, ms); +} +#endif + +#ifdef CONFIG_LAYER2_ROAMING +/* +* Select a new roaming candidate from the original @param candidate and @param competitor +* @return _TRUE: candidate is updated +* @return _FALSE: candidate is not updated +*/ +static int rtw_check_roaming_candidate(struct mlme_priv *mlme + , struct wlan_network **candidate, struct wlan_network *competitor) +{ + int updated = _FALSE; + _adapter *adapter = container_of(mlme, _adapter, mlmepriv); +#ifdef CONFIG_RTW_80211R + ft_priv *pftpriv = &mlme->ftpriv; + u32 mdie_len = 0; + u8 *ptmp = NULL; +#endif + + + if (is_same_ess(&competitor->network, &mlme->cur_network.network) == _FALSE) + goto exit; + + if (rtw_is_desired_network(adapter, competitor) == _FALSE) + goto exit; + +#ifdef CONFIG_LAYER2_ROAMING + if (mlme->need_to_roam == _FALSE) + goto exit; +#endif + +#ifdef CONFIG_RTW_80211R + if (rtw_chk_ft_flags(adapter, RTW_FT_SUPPORTED)) { + ptmp = rtw_get_ie(&competitor->network.IEs[12], _MDIE_, &mdie_len, competitor->network.IELength-12); + if (ptmp) { + if (!_rtw_memcmp(&pftpriv->mdid, ptmp+2, 2)) + goto exit; + + /*The candidate don't support over-the-DS*/ + if (rtw_chk_ft_flags(adapter, RTW_FT_STA_OVER_DS_SUPPORTED)) { + if ((rtw_chk_ft_flags(adapter, RTW_FT_OVER_DS_SUPPORTED) && !(*(ptmp+4) & 0x01)) || + (!rtw_chk_ft_flags(adapter, RTW_FT_OVER_DS_SUPPORTED) && (*(ptmp+4) & 0x01))) { + RTW_INFO("FT: ignore the candidate(" MAC_FMT ") for over-the-DS\n", MAC_ARG(competitor->network.MacAddress)); + rtw_clr_ft_flags(adapter, RTW_FT_OVER_DS_SUPPORTED); + goto exit; + } + } + } else + goto exit; + } +#endif + + RTW_INFO("roam candidate:%s %s("MAC_FMT", ch%3u) rssi:%d, age:%5d\n", + (competitor == mlme->cur_network_scanned) ? "*" : " " , + competitor->network.Ssid.Ssid, + MAC_ARG(competitor->network.MacAddress), + competitor->network.Configuration.DSConfig, + (int)competitor->network.Rssi, + rtw_get_passing_time_ms(competitor->last_scanned) + ); + + /* got specific addr to roam */ + if (!is_zero_mac_addr(mlme->roam_tgt_addr)) { + if (_rtw_memcmp(mlme->roam_tgt_addr, competitor->network.MacAddress, ETH_ALEN) == _TRUE) + goto update; + else + goto exit; + } +#if 1 + if (rtw_get_passing_time_ms((u32)competitor->last_scanned) >= mlme->roam_scanr_exp_ms) + goto exit; + + if (competitor->network.Rssi - mlme->cur_network_scanned->network.Rssi < mlme->roam_rssi_diff_th) + goto exit; + + if (*candidate != NULL && (*candidate)->network.Rssi >= competitor->network.Rssi) + goto exit; +#else + goto exit; +#endif + +update: + *candidate = competitor; + updated = _TRUE; + +exit: + return updated; +} + +int rtw_select_roaming_candidate(struct mlme_priv *mlme) +{ + _irqL irqL; + int ret = _FAIL; + _list *phead; + _adapter *adapter; + _queue *queue = &(mlme->scanned_queue); + struct wlan_network *pnetwork = NULL; + struct wlan_network *candidate = NULL; + u8 bSupportAntDiv = _FALSE; + + + if (mlme->cur_network_scanned == NULL) { + rtw_warn_on(1); + goto exit; + } + + _enter_critical_bh(&(mlme->scanned_queue.lock), &irqL); + phead = get_list_head(queue); + adapter = (_adapter *)mlme->nic_hdl; + + mlme->pscanned = get_next(phead); + + while (!rtw_end_of_queue_search(phead, mlme->pscanned)) { + + pnetwork = LIST_CONTAINOR(mlme->pscanned, struct wlan_network, list); + if (pnetwork == NULL) { + ret = _FAIL; + goto exit; + } + + mlme->pscanned = get_next(mlme->pscanned); + + if (0) + RTW_INFO("%s("MAC_FMT", ch%u) rssi:%d\n" + , pnetwork->network.Ssid.Ssid + , MAC_ARG(pnetwork->network.MacAddress) + , pnetwork->network.Configuration.DSConfig + , (int)pnetwork->network.Rssi); + + rtw_check_roaming_candidate(mlme, &candidate, pnetwork); + + } + + if (candidate == NULL) { + RTW_INFO("%s: return _FAIL(candidate == NULL)\n", __FUNCTION__); + ret = _FAIL; + goto exit; + } else { + RTW_INFO("%s: candidate: %s("MAC_FMT", ch:%u)\n", __FUNCTION__, + candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress), + candidate->network.Configuration.DSConfig); + + mlme->roam_network = candidate; + + if (_rtw_memcmp(candidate->network.MacAddress, mlme->roam_tgt_addr, ETH_ALEN) == _TRUE) + _rtw_memset(mlme->roam_tgt_addr, 0, ETH_ALEN); + } + + ret = _SUCCESS; +exit: + _exit_critical_bh(&(mlme->scanned_queue.lock), &irqL); + + return ret; +} +#endif /* CONFIG_LAYER2_ROAMING */ + +/* +* Select a new join candidate from the original @param candidate and @param competitor +* @return _TRUE: candidate is updated +* @return _FALSE: candidate is not updated +*/ +static int rtw_check_join_candidate(struct mlme_priv *mlme + , struct wlan_network **candidate, struct wlan_network *competitor) +{ + int updated = _FALSE; + _adapter *adapter = container_of(mlme, _adapter, mlmepriv); + + + /* check bssid, if needed */ + if (mlme->assoc_by_bssid == _TRUE) { + if (_rtw_memcmp(competitor->network.MacAddress, mlme->assoc_bssid, ETH_ALEN) == _FALSE) + goto exit; + } + + /* check ssid, if needed */ + if (mlme->assoc_ssid.Ssid[0] && mlme->assoc_ssid.SsidLength) { + if (competitor->network.Ssid.SsidLength != mlme->assoc_ssid.SsidLength + || _rtw_memcmp(competitor->network.Ssid.Ssid, mlme->assoc_ssid.Ssid, mlme->assoc_ssid.SsidLength) == _FALSE + ) + goto exit; + } + + if (rtw_is_desired_network(adapter, competitor) == _FALSE) + goto exit; + +#ifdef CONFIG_LAYER2_ROAMING + if (rtw_to_roam(adapter) > 0) { + if (rtw_get_passing_time_ms((u32)competitor->last_scanned) >= mlme->roam_scanr_exp_ms + || is_same_ess(&competitor->network, &mlme->cur_network.network) == _FALSE + ) + goto exit; + } +#endif + + if (*candidate == NULL || (*candidate)->network.Rssi < competitor->network.Rssi) { + *candidate = competitor; + updated = _TRUE; + } + + if (updated) { + RTW_INFO("[by_bssid:%u][assoc_ssid:%s][to_roam:%u] " + "new candidate: %s("MAC_FMT", ch%u) rssi:%d\n", + mlme->assoc_by_bssid, + mlme->assoc_ssid.Ssid, + rtw_to_roam(adapter), + (*candidate)->network.Ssid.Ssid, + MAC_ARG((*candidate)->network.MacAddress), + (*candidate)->network.Configuration.DSConfig, + (int)(*candidate)->network.Rssi + ); + } + +exit: + return updated; +} + +/* +Calling context: +The caller of the sub-routine will be in critical section... + +The caller must hold the following spinlock + +pmlmepriv->lock + + +*/ + +int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) +{ + _irqL irqL; + int ret; + _list *phead; + _adapter *adapter; + _queue *queue = &(pmlmepriv->scanned_queue); + struct wlan_network *pnetwork = NULL; + struct wlan_network *candidate = NULL; + u8 bSupportAntDiv = _FALSE; + + + adapter = (_adapter *)pmlmepriv->nic_hdl; + + _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + +#ifdef CONFIG_LAYER2_ROAMING + if (pmlmepriv->roam_network) { + candidate = pmlmepriv->roam_network; + pmlmepriv->roam_network = NULL; + goto candidate_exist; + } +#endif + + phead = get_list_head(queue); + pmlmepriv->pscanned = get_next(phead); + + while (!rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) { + + pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list); + if (pnetwork == NULL) { + ret = _FAIL; + goto exit; + } + + pmlmepriv->pscanned = get_next(pmlmepriv->pscanned); + + if (0) + RTW_INFO("%s("MAC_FMT", ch%u) rssi:%d\n" + , pnetwork->network.Ssid.Ssid + , MAC_ARG(pnetwork->network.MacAddress) + , pnetwork->network.Configuration.DSConfig + , (int)pnetwork->network.Rssi); + + rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork); + + } + + if (candidate == NULL) { + RTW_INFO("%s: return _FAIL(candidate == NULL)\n", __FUNCTION__); +#ifdef CONFIG_WOWLAN + _clr_fwstate_(pmlmepriv, _FW_LINKED | _FW_UNDER_LINKING); +#endif + ret = _FAIL; + goto exit; + } else { + RTW_INFO("%s: candidate: %s("MAC_FMT", ch:%u)\n", __FUNCTION__, + candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress), + candidate->network.Configuration.DSConfig); + goto candidate_exist; + } + +candidate_exist: + + /* check for situation of _FW_LINKED */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + RTW_INFO("%s: _FW_LINKED while ask_for_joinbss!!!\n", __FUNCTION__); + +#if 0 /* for WPA/WPA2 authentication, wpa_supplicant will expect authentication from AP, it is needed to reconnect AP... */ + if (is_same_network(&pmlmepriv->cur_network.network, &candidate->network)) { + RTW_INFO("%s: _FW_LINKED and is same network, it needn't join again\n", __FUNCTION__); + + rtw_indicate_connect(adapter);/* rtw_indicate_connect again */ + + ret = 2; + goto exit; + } else +#endif + { + rtw_disassoc_cmd(adapter, 0, _TRUE); + rtw_indicate_disconnect(adapter, 0, _FALSE); + rtw_free_assoc_resources(adapter, 0); + } + } + +#ifdef CONFIG_ANTENNA_DIVERSITY + rtw_hal_get_def_var(adapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &(bSupportAntDiv)); + if (_TRUE == bSupportAntDiv) { + u8 CurrentAntenna; + rtw_hal_get_odm_var(adapter, HAL_ODM_ANTDIV_SELECT, &(CurrentAntenna), NULL); + RTW_INFO("#### Opt_Ant_(%s) , cur_Ant(%s)\n", + (MAIN_ANT == candidate->network.PhyInfo.Optimum_antenna) ? "MAIN_ANT" : "AUX_ANT", + (MAIN_ANT == CurrentAntenna) ? "MAIN_ANT" : "AUX_ANT" + ); + } +#endif + set_fwstate(pmlmepriv, _FW_UNDER_LINKING); + ret = rtw_joinbss_cmd(adapter, candidate); + +exit: + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + + + return ret; +} + +sint rtw_set_auth(_adapter *adapter, struct security_priv *psecuritypriv) +{ + struct cmd_obj *pcmd; + struct setauth_parm *psetauthparm; + struct cmd_priv *pcmdpriv = &(adapter->cmdpriv); + sint res = _SUCCESS; + + + pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmd == NULL) { + res = _FAIL; /* try again */ + goto exit; + } + + psetauthparm = (struct setauth_parm *)rtw_zmalloc(sizeof(struct setauth_parm)); + if (psetauthparm == NULL) { + rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + _rtw_memset(psetauthparm, 0, sizeof(struct setauth_parm)); + psetauthparm->mode = (unsigned char)psecuritypriv->dot11AuthAlgrthm; + + pcmd->cmdcode = _SetAuth_CMD_; + pcmd->parmbuf = (unsigned char *)psetauthparm; + pcmd->cmdsz = (sizeof(struct setauth_parm)); + pcmd->rsp = NULL; + pcmd->rspsz = 0; + + + _rtw_init_listhead(&pcmd->list); + + + res = rtw_enqueue_cmd(pcmdpriv, pcmd); + +exit: + + + return res; + +} + + +sint rtw_set_key(_adapter *adapter, struct security_priv *psecuritypriv, sint keyid, u8 set_tx, bool enqueue) +{ + u8 keylen; + struct cmd_obj *pcmd; + struct setkey_parm *psetkeyparm; + struct cmd_priv *pcmdpriv = &(adapter->cmdpriv); + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + sint res = _SUCCESS; + + + psetkeyparm = (struct setkey_parm *)rtw_zmalloc(sizeof(struct setkey_parm)); + if (psetkeyparm == NULL) { + res = _FAIL; + goto exit; + } + _rtw_memset(psetkeyparm, 0, sizeof(struct setkey_parm)); + + if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { + psetkeyparm->algorithm = (unsigned char)psecuritypriv->dot118021XGrpPrivacy; + } else { + psetkeyparm->algorithm = (u8)psecuritypriv->dot11PrivacyAlgrthm; + + } + psetkeyparm->keyid = (u8)keyid;/* 0~3 */ + psetkeyparm->set_tx = set_tx; + if (is_wep_enc(psetkeyparm->algorithm)) + adapter->securitypriv.key_mask |= BIT(psetkeyparm->keyid); + + RTW_INFO("==> rtw_set_key algorithm(%x),keyid(%x),key_mask(%x)\n", psetkeyparm->algorithm, psetkeyparm->keyid, adapter->securitypriv.key_mask); + + switch (psetkeyparm->algorithm) { + + case _WEP40_: + keylen = 5; + _rtw_memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen); + break; + case _WEP104_: + keylen = 13; + _rtw_memcpy(&(psetkeyparm->key[0]), &(psecuritypriv->dot11DefKey[keyid].skey[0]), keylen); + break; + case _TKIP_: + keylen = 16; + _rtw_memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen); + psetkeyparm->grpkey = 1; + break; + case _AES_: + keylen = 16; + _rtw_memcpy(&psetkeyparm->key, &psecuritypriv->dot118021XGrpKey[keyid], keylen); + psetkeyparm->grpkey = 1; + break; + default: + res = _FAIL; + rtw_mfree((unsigned char *)psetkeyparm, sizeof(struct setkey_parm)); + goto exit; + } + + + if (enqueue) { + pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmd == NULL) { + rtw_mfree((unsigned char *)psetkeyparm, sizeof(struct setkey_parm)); + res = _FAIL; /* try again */ + goto exit; + } + + pcmd->cmdcode = _SetKey_CMD_; + pcmd->parmbuf = (u8 *)psetkeyparm; + pcmd->cmdsz = (sizeof(struct setkey_parm)); + pcmd->rsp = NULL; + pcmd->rspsz = 0; + + _rtw_init_listhead(&pcmd->list); + + /* _rtw_init_sema(&(pcmd->cmd_sem), 0); */ + + res = rtw_enqueue_cmd(pcmdpriv, pcmd); + } else { + setkey_hdl(adapter, (u8 *)psetkeyparm); + rtw_mfree((u8 *) psetkeyparm, sizeof(struct setkey_parm)); + } +exit: + return res; + +} + + +/* adjust IEs for rtw_joinbss_cmd in WMM */ +int rtw_restruct_wmm_ie(_adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len, uint initial_out_len) +{ + unsigned int ielength = 0; + unsigned int i, j; + + i = 12; /* after the fixed IE */ + while (i < in_len) { + ielength = initial_out_len; + + if (in_ie[i] == 0xDD && in_ie[i + 2] == 0x00 && in_ie[i + 3] == 0x50 && in_ie[i + 4] == 0xF2 && in_ie[i + 5] == 0x02 && i + 5 < in_len) { /* WMM element ID and OUI */ + + /* Append WMM IE to the last index of out_ie */ +#if 0 + for (j = i; j < i + (in_ie[i + 1] + 2); j++) { + out_ie[ielength] = in_ie[j]; + ielength++; + } + out_ie[initial_out_len + 8] = 0x00; /* force the QoS Info Field to be zero */ +#endif + + for (j = i; j < i + 9; j++) { + out_ie[ielength] = in_ie[j]; + ielength++; + } + out_ie[initial_out_len + 1] = 0x07; + out_ie[initial_out_len + 6] = 0x00; + out_ie[initial_out_len + 8] = 0x00; + + break; + } + + i += (in_ie[i + 1] + 2); /* to the next IE element */ + } + + return ielength; + +} + + +/* + * Ported from 8185: IsInPreAuthKeyList(). (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.) + * Added by Annie, 2006-05-07. + * + * Search by BSSID, + * Return Value: + * -1 :if there is no pre-auth key in the table + * >=0 :if there is pre-auth key, and return the entry id + * + * */ + +static int SecIsInPMKIDList(_adapter *Adapter, u8 *bssid) +{ + struct security_priv *psecuritypriv = &Adapter->securitypriv; + int i = 0; + + do { + if ((psecuritypriv->PMKIDList[i].bUsed) && + (_rtw_memcmp(psecuritypriv->PMKIDList[i].Bssid, bssid, ETH_ALEN) == _TRUE)) + break; + else { + i++; + /* continue; */ + } + + } while (i < NUM_PMKID_CACHE); + + if (i == NUM_PMKID_CACHE) { + i = -1;/* Could not find. */ + } else { + /* There is one Pre-Authentication Key for the specific BSSID. */ + } + + return i; + +} + +/* + * Check the RSN IE length + * If the RSN IE length <= 20, the RSN IE didn't include the PMKID information + * 0-11th element in the array are the fixed IE + * 12th element in the array is the IE + * 13th element in the array is the IE length + * */ + +static int rtw_append_pmkid(_adapter *adapter, int iEntry, u8 *ie, uint ie_len) +{ + struct security_priv *sec = &adapter->securitypriv; + + if (ie[13] > 20) { + int i; + u16 pmkid_cnt = RTW_GET_LE16(ie + 14 + 20); + if (pmkid_cnt == 1 && _rtw_memcmp(ie + 14 + 20 + 2, &sec->PMKIDList[iEntry].PMKID, 16)) { + RTW_INFO(FUNC_ADPT_FMT" has carried the same PMKID:"KEY_FMT"\n" + , FUNC_ADPT_ARG(adapter), KEY_ARG(&sec->PMKIDList[iEntry].PMKID)); + goto exit; + } + + RTW_INFO(FUNC_ADPT_FMT" remove original PMKID, count:%u\n" + , FUNC_ADPT_ARG(adapter), pmkid_cnt); + + for (i = 0; i < pmkid_cnt; i++) + RTW_INFO(" "KEY_FMT"\n", KEY_ARG(ie + 14 + 20 + 2 + i * 16)); + + ie_len -= 2 + pmkid_cnt * 16; + ie[13] = 20; + } + + if (ie[13] <= 20) { + /* The RSN IE didn't include the PMK ID, append the PMK information */ + + RTW_INFO(FUNC_ADPT_FMT" append PMKID:"KEY_FMT"\n" + , FUNC_ADPT_ARG(adapter), KEY_ARG(&sec->PMKIDList[iEntry].PMKID)); + + RTW_PUT_LE16(&ie[ie_len], 1); + ie_len += 2; + + _rtw_memcpy(&ie[ie_len], &sec->PMKIDList[iEntry].PMKID, 16); + ie_len += 16; + + ie[13] += 18;/* PMKID length = 2+16 */ + } + +exit: + return ie_len; +} + +static int rtw_remove_pmkid(_adapter *adapter, u8 *ie, uint ie_len) +{ + struct security_priv *sec = &adapter->securitypriv; + int i; + u16 pmkid_cnt = RTW_GET_LE16(ie + 14 + 20); + + if (ie[13] <= 20) + goto exit; + + RTW_INFO(FUNC_ADPT_FMT" remove original PMKID, count:%u\n" + , FUNC_ADPT_ARG(adapter), pmkid_cnt); + + for (i = 0; i < pmkid_cnt; i++) + RTW_INFO(" "KEY_FMT"\n", KEY_ARG(ie + 14 + 20 + 2 + i * 16)); + + ie_len -= 2 + pmkid_cnt * 16; + ie[13] = 20; + +exit: + return ie_len; +} + +sint rtw_restruct_sec_ie(_adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_len) +{ + u8 authmode = 0x0, securitytype, match; + u8 sec_ie[255], uncst_oui[4], bkup_ie[255]; + u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01}; + uint ielength, cnt, remove_cnt; + int iEntry; + + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct security_priv *psecuritypriv = &adapter->securitypriv; + uint ndisauthmode = psecuritypriv->ndisauthtype; + uint ndissecuritytype = psecuritypriv->ndisencryptstatus; + + + + /* copy fixed ie only */ + _rtw_memcpy(out_ie, in_ie, 12); + ielength = 12; + if ((ndisauthmode == Ndis802_11AuthModeWPA) || (ndisauthmode == Ndis802_11AuthModeWPAPSK)) + authmode = _WPA_IE_ID_; + if ((ndisauthmode == Ndis802_11AuthModeWPA2) || (ndisauthmode == Ndis802_11AuthModeWPA2PSK)) + authmode = _WPA2_IE_ID_; + + if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) { + _rtw_memcpy(out_ie + ielength, psecuritypriv->wps_ie, psecuritypriv->wps_ie_len); + + ielength += psecuritypriv->wps_ie_len; + } else if ((authmode == _WPA_IE_ID_) || (authmode == _WPA2_IE_ID_)) { + /* copy RSN or SSN */ + _rtw_memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0], psecuritypriv->supplicant_ie[1] + 2); + /* debug for CONFIG_IEEE80211W + { + int jj; + printk("supplicant_ie_length=%d &&&&&&&&&&&&&&&&&&&\n", psecuritypriv->supplicant_ie[1]+2); + for(jj=0; jj < psecuritypriv->supplicant_ie[1]+2; jj++) + printk(" %02x ", psecuritypriv->supplicant_ie[jj]); + printk("\n"); + }*/ + ielength += psecuritypriv->supplicant_ie[1] + 2; + rtw_report_sec_ie(adapter, authmode, psecuritypriv->supplicant_ie); + +#ifdef CONFIG_DRVEXT_MODULE + drvext_report_sec_ie(&adapter->drvextpriv, authmode, sec_ie); +#endif + } + + iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid); + if (iEntry < 0) { + if (authmode == _WPA2_IE_ID_) + ielength = rtw_remove_pmkid(adapter, out_ie, ielength); + } else { + if (authmode == _WPA2_IE_ID_) + ielength = rtw_append_pmkid(adapter, iEntry, out_ie, ielength); + } + + + return ielength; +} + +void rtw_init_registrypriv_dev_network(_adapter *adapter) +{ + struct registry_priv *pregistrypriv = &adapter->registrypriv; + WLAN_BSSID_EX *pdev_network = &pregistrypriv->dev_network; + u8 *myhwaddr = adapter_mac_addr(adapter); + + + _rtw_memcpy(pdev_network->MacAddress, myhwaddr, ETH_ALEN); + + _rtw_memcpy(&pdev_network->Ssid, &pregistrypriv->ssid, sizeof(NDIS_802_11_SSID)); + + pdev_network->Configuration.Length = sizeof(NDIS_802_11_CONFIGURATION); + pdev_network->Configuration.BeaconPeriod = 100; + pdev_network->Configuration.FHConfig.Length = 0; + pdev_network->Configuration.FHConfig.HopPattern = 0; + pdev_network->Configuration.FHConfig.HopSet = 0; + pdev_network->Configuration.FHConfig.DwellTime = 0; + + + +} + +void rtw_update_registrypriv_dev_network(_adapter *adapter) +{ + int sz = 0; + struct registry_priv *pregistrypriv = &adapter->registrypriv; + WLAN_BSSID_EX *pdev_network = &pregistrypriv->dev_network; + struct security_priv *psecuritypriv = &adapter->securitypriv; + struct wlan_network *cur_network = &adapter->mlmepriv.cur_network; + /* struct xmit_priv *pxmitpriv = &adapter->xmitpriv; */ + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + + +#if 0 + pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense; + pxmitpriv->vcs = pregistrypriv->vcs_type; + pxmitpriv->vcs_type = pregistrypriv->vcs_type; + /* pxmitpriv->rts_thresh = pregistrypriv->rts_thresh; */ + pxmitpriv->frag_len = pregistrypriv->frag_thresh; + + adapter->qospriv.qos_option = pregistrypriv->wmm_enable; +#endif + + pdev_network->Privacy = (psecuritypriv->dot11PrivacyAlgrthm > 0 ? 1 : 0) ; /* adhoc no 802.1x */ + + pdev_network->Rssi = 0; + + switch (pregistrypriv->wireless_mode) { + case WIRELESS_11B: + pdev_network->NetworkTypeInUse = (Ndis802_11DS); + break; + case WIRELESS_11G: + case WIRELESS_11BG: + case WIRELESS_11_24N: + case WIRELESS_11G_24N: + case WIRELESS_11BG_24N: + pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24); + break; + case WIRELESS_11A: + case WIRELESS_11A_5N: + pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5); + break; + case WIRELESS_11ABGN: + if (pregistrypriv->channel > 14) + pdev_network->NetworkTypeInUse = (Ndis802_11OFDM5); + else + pdev_network->NetworkTypeInUse = (Ndis802_11OFDM24); + break; + default: + /* TODO */ + break; + } + + pdev_network->Configuration.DSConfig = (pregistrypriv->channel); + + if (cur_network->network.InfrastructureMode == Ndis802_11IBSS) { + pdev_network->Configuration.ATIMWindow = (0); + + if (pmlmeext->cur_channel != 0) + pdev_network->Configuration.DSConfig = pmlmeext->cur_channel; + else + pdev_network->Configuration.DSConfig = 1; + } + + pdev_network->InfrastructureMode = (cur_network->network.InfrastructureMode); + + /* 1. Supported rates */ + /* 2. IE */ + + /* rtw_set_supported_rate(pdev_network->SupportedRates, pregistrypriv->wireless_mode) ; */ /* will be called in rtw_generate_ie */ + sz = rtw_generate_ie(pregistrypriv); + + pdev_network->IELength = sz; + + pdev_network->Length = get_WLAN_BSSID_EX_sz((WLAN_BSSID_EX *)pdev_network); + + /* notes: translate IELength & Length after assign the Length to cmdsz in createbss_cmd(); */ + /* pdev_network->IELength = cpu_to_le32(sz); */ + + +} + +void rtw_get_encrypt_decrypt_from_registrypriv(_adapter *adapter) +{ + + + +} + +/* the fucntion is at passive_level */ +void rtw_joinbss_reset(_adapter *padapter) +{ + u8 threshold; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + /* todo: if you want to do something io/reg/hw setting before join_bss, please add code here */ + +#ifdef CONFIG_80211N_HT + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + + pmlmepriv->num_FortyMHzIntolerant = 0; + + pmlmepriv->num_sta_no_ht = 0; + + phtpriv->ampdu_enable = _FALSE;/* reset to disabled */ + +#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) + /* TH=1 => means that invalidate usb rx aggregation */ + /* TH=0 => means that validate usb rx aggregation, use init value. */ + if (phtpriv->ht_option) { + if (padapter->registrypriv.wifi_spec == 1) + threshold = 1; + else + threshold = 0; + rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); + } else { + threshold = 1; + rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); + } +#endif/* #if defined( CONFIG_USB_HCI) || defined (CONFIG_SDIO_HCI) */ + +#endif/* #ifdef CONFIG_80211N_HT */ + +} + + +#ifdef CONFIG_80211N_HT +void rtw_ht_use_default_setting(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + BOOLEAN bHwLDPCSupport = _FALSE, bHwSTBCSupport = _FALSE; +#ifdef CONFIG_BEAMFORMING + BOOLEAN bHwSupportBeamformer = _FALSE, bHwSupportBeamformee = _FALSE; +#endif /* CONFIG_BEAMFORMING */ + + if (pregistrypriv->wifi_spec) + phtpriv->bss_coexist = 1; + else + phtpriv->bss_coexist = 0; + + phtpriv->sgi_40m = TEST_FLAG(pregistrypriv->short_gi, BIT1) ? _TRUE : _FALSE; + phtpriv->sgi_20m = TEST_FLAG(pregistrypriv->short_gi, BIT0) ? _TRUE : _FALSE; + + /* LDPC support */ + rtw_hal_get_def_var(padapter, HAL_DEF_RX_LDPC, (u8 *)&bHwLDPCSupport); + CLEAR_FLAGS(phtpriv->ldpc_cap); + if (bHwLDPCSupport) { + if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT4)) + SET_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_RX); + } + rtw_hal_get_def_var(padapter, HAL_DEF_TX_LDPC, (u8 *)&bHwLDPCSupport); + if (bHwLDPCSupport) { + if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT5)) + SET_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_TX); + } + if (phtpriv->ldpc_cap) + RTW_INFO("[HT] HAL Support LDPC = 0x%02X\n", phtpriv->ldpc_cap); + + /* STBC */ + rtw_hal_get_def_var(padapter, HAL_DEF_TX_STBC, (u8 *)&bHwSTBCSupport); + CLEAR_FLAGS(phtpriv->stbc_cap); + if (bHwSTBCSupport) { + if (TEST_FLAG(pregistrypriv->stbc_cap, BIT5)) + SET_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX); + } + rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)&bHwSTBCSupport); + if (bHwSTBCSupport) { + if (TEST_FLAG(pregistrypriv->stbc_cap, BIT4)) + SET_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_RX); + } + if (phtpriv->stbc_cap) + RTW_INFO("[HT] HAL Support STBC = 0x%02X\n", phtpriv->stbc_cap); + + /* Beamforming setting */ + CLEAR_FLAGS(phtpriv->beamform_cap); +#ifdef CONFIG_BEAMFORMING + rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMER, (u8 *)&bHwSupportBeamformer); + rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMEE, (u8 *)&bHwSupportBeamformee); + if (TEST_FLAG(pregistrypriv->beamform_cap, BIT4) && bHwSupportBeamformer) { + SET_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE); + RTW_INFO("[HT] HAL Support Beamformer\n"); + } + if (TEST_FLAG(pregistrypriv->beamform_cap, BIT5) && bHwSupportBeamformee) { + SET_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE); + RTW_INFO("[HT] HAL Support Beamformee\n"); + } +#endif /* CONFIG_BEAMFORMING */ +} +void rtw_build_wmm_ie_ht(_adapter *padapter, u8 *out_ie, uint *pout_len) +{ + unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00}; + int out_len; + u8 *pframe; + + if (padapter->mlmepriv.qospriv.qos_option == 0) { + out_len = *pout_len; + pframe = rtw_set_ie(out_ie + out_len, _VENDOR_SPECIFIC_IE_, + _WMM_IE_Length_, WMM_IE, pout_len); + + padapter->mlmepriv.qospriv.qos_option = 1; + } +} + +/* the fucntion is >= passive_level */ +unsigned int rtw_restructure_ht_ie(_adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len, u8 channel) +{ + u32 ielen, out_len; + u32 rx_packet_offset, max_recvbuf_sz; + HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor; + HT_CAP_AMPDU_DENSITY best_ampdu_density; + unsigned char *p, *pframe; + struct rtw_ieee80211_ht_cap ht_capie; + u8 cbw40_enable = 0, rf_type = 0, operation_bw = 0, rf_num = 0, rx_stbc_nss = 0, rx_nss = 0; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); + + phtpriv->ht_option = _FALSE; + + out_len = *pout_len; + + _rtw_memset(&ht_capie, 0, sizeof(struct rtw_ieee80211_ht_cap)); + + ht_capie.cap_info = IEEE80211_HT_CAP_DSSSCCK40; + + if (phtpriv->sgi_20m) + ht_capie.cap_info |= IEEE80211_HT_CAP_SGI_20; + + /* Get HT BW */ + if (in_ie == NULL) { + /* TDLS: TODO 20/40 issue */ + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + operation_bw = padapter->mlmeextpriv.cur_bwmode; + if (operation_bw > CHANNEL_WIDTH_40) + operation_bw = CHANNEL_WIDTH_40; + } else + /* TDLS: TODO 40? */ + operation_bw = CHANNEL_WIDTH_40; + } else { + p = rtw_get_ie(in_ie, _HT_ADD_INFO_IE_, &ielen, in_len); + if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) { + struct HT_info_element *pht_info = (struct HT_info_element *)(p + 2); + if (pht_info->infos[0] & BIT(2)) { + switch (pht_info->infos[0] & 0x3) { + case 1: + case 3: + operation_bw = CHANNEL_WIDTH_40; + break; + default: + operation_bw = CHANNEL_WIDTH_20; + break; + } + } else + operation_bw = CHANNEL_WIDTH_20; + } + } + + /* to disable 40M Hz support while gd_bw_40MHz_en = 0 */ + if (hal_chk_bw_cap(padapter, BW_CAP_40M)) { + if (channel > 14) { + if (REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40)) + cbw40_enable = 1; + } else { + if (REGSTY_IS_BW_2G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40)) + cbw40_enable = 1; + } + } + + if ((cbw40_enable == 1) && (operation_bw == CHANNEL_WIDTH_40)) { + ht_capie.cap_info |= IEEE80211_HT_CAP_SUP_WIDTH; + if (phtpriv->sgi_40m) + ht_capie.cap_info |= IEEE80211_HT_CAP_SGI_40; + } + + /* todo: disable SM power save mode */ + ht_capie.cap_info |= IEEE80211_HT_CAP_SM_PS; + + /* RX LDPC */ + if (TEST_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_RX)) { + ht_capie.cap_info |= IEEE80211_HT_CAP_LDPC_CODING; + RTW_INFO("[HT] Declare supporting RX LDPC\n"); + } + + /* TX STBC */ + if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX)) { + ht_capie.cap_info |= IEEE80211_HT_CAP_TX_STBC; + RTW_INFO("[HT] Declare supporting TX STBC\n"); + } + + /* RX STBC */ + if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_RX)) { + if ((pregistrypriv->rx_stbc == 0x3) || /* enable for 2.4/5 GHz */ + ((channel <= 14) && (pregistrypriv->rx_stbc == 0x1)) || /* enable for 2.4GHz */ + ((channel > 14) && (pregistrypriv->rx_stbc == 0x2)) || /* enable for 5GHz */ + (pregistrypriv->wifi_spec == 1)) { + /* HAL_DEF_RX_STBC means STBC RX spatial stream, todo: VHT 4 streams */ + rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)(&rx_stbc_nss)); + SET_HT_CAP_ELE_RX_STBC(&ht_capie, rx_stbc_nss); + RTW_INFO("[HT] Declare supporting RX STBC = %d\n", rx_stbc_nss); + } + } + + /* fill default supported_mcs_set */ + _rtw_memcpy(ht_capie.supp_mcs_set, pmlmeext->default_supported_mcs_set, 16); + + /* update default supported_mcs_set */ + rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + rx_nss = rtw_min(rf_type_to_rf_rx_cnt(rf_type), hal_spec->rx_nss_num); + + switch (rx_nss) { + case 1: + set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_1R); + break; + case 2: + #ifdef CONFIG_DISABLE_MCS13TO15 + if (((cbw40_enable == 1) && (operation_bw == CHANNEL_WIDTH_40)) && (pregistrypriv->wifi_spec != 1)) + set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_2R_13TO15_OFF); + else + #endif + set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_2R); + break; + case 3: + set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_3R); + break; + case 4: + set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_4R); + break; + default: + RTW_WARN("rf_type:%d or rx_nss:%u is not expected\n", rf_type, hal_spec->rx_nss_num); + } + + { + rtw_hal_get_def_var(padapter, HAL_DEF_RX_PACKET_OFFSET, &rx_packet_offset); + rtw_hal_get_def_var(padapter, HAL_DEF_MAX_RECVBUF_SZ, &max_recvbuf_sz); + if (max_recvbuf_sz - rx_packet_offset >= (8191 - 256)) { + RTW_INFO("%s IEEE80211_HT_CAP_MAX_AMSDU is set\n", __FUNCTION__); + ht_capie.cap_info = ht_capie.cap_info | IEEE80211_HT_CAP_MAX_AMSDU; + } + } + /* + AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k + AMPDU_para [4:2]:Min MPDU Start Spacing + */ + + /* + #if defined(CONFIG_RTL8188E) && defined(CONFIG_SDIO_HCI) + ht_capie.ampdu_params_info = 2; + #else + ht_capie.ampdu_params_info = (IEEE80211_HT_CAP_AMPDU_FACTOR&0x03); + #endif + */ + + if (padapter->driver_rx_ampdu_factor != 0xFF) + max_rx_ampdu_factor = (HT_CAP_AMPDU_FACTOR)padapter->driver_rx_ampdu_factor; + else + rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); + + /* rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); */ + ht_capie.ampdu_params_info = (max_rx_ampdu_factor & 0x03); + + if (padapter->driver_rx_ampdu_spacing != 0xFF) + ht_capie.ampdu_params_info |= ((padapter->driver_rx_ampdu_spacing & 0x07) << 2); + else { + if (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_) { + /* + * Todo : Each chip must to ask DD , this chip best ampdu_density setting + * By yiwei.sun + */ + rtw_hal_get_def_var(padapter, HW_VAR_BEST_AMPDU_DENSITY, &best_ampdu_density); + + ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & (best_ampdu_density << 2)); + + } else + ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & 0x00); + } +#ifdef CONFIG_BEAMFORMING + ht_capie.tx_BF_cap_info = 0; + + /* HT Beamformer*/ + if (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) { + /* Transmit NDP Capable */ + SET_HT_CAP_TXBF_TRANSMIT_NDP_CAP(&ht_capie, 1); + /* Explicit Compressed Steering Capable */ + SET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP(&ht_capie, 1); + /* Compressed Steering Number Antennas */ + SET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(&ht_capie, 1); + rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMER_CAP, (u8 *)&rf_num); + SET_HT_CAP_TXBF_CHNL_ESTIMATION_NUM_ANTENNAS(&ht_capie, rf_num); + } + + /* HT Beamformee */ + if (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) { + /* Receive NDP Capable */ + SET_HT_CAP_TXBF_RECEIVE_NDP_CAP(&ht_capie, 1); + /* Explicit Compressed Beamforming Feedback Capable */ + SET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP(&ht_capie, 2); + rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMEE_CAP, (u8 *)&rf_num); + SET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(&ht_capie, rf_num); + } +#endif/*CONFIG_BEAMFORMING*/ + + pframe = rtw_set_ie(out_ie + out_len, _HT_CAPABILITY_IE_, + sizeof(struct rtw_ieee80211_ht_cap), (unsigned char *)&ht_capie, pout_len); + + phtpriv->ht_option = _TRUE; + + if (in_ie != NULL) { + p = rtw_get_ie(in_ie, _HT_ADD_INFO_IE_, &ielen, in_len); + if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) { + out_len = *pout_len; + pframe = rtw_set_ie(out_ie + out_len, _HT_ADD_INFO_IE_, ielen, p + 2 , pout_len); + } + } + + return phtpriv->ht_option; + +} + +/* the fucntion is > passive_level (in critical_section) */ +void rtw_update_ht_cap(_adapter *padapter, u8 *pie, uint ie_len, u8 channel) +{ + u8 *p, max_ampdu_sz; + int len; + /* struct sta_info *bmc_sta, *psta; */ + struct rtw_ieee80211_ht_cap *pht_capie; + struct ieee80211_ht_addt_info *pht_addtinfo; + /* struct recv_reorder_ctrl *preorder_ctrl; */ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + /* struct recv_priv *precvpriv = &padapter->recvpriv; */ + struct registry_priv *pregistrypriv = &padapter->registrypriv; + /* struct wlan_network *pcur_network = &(pmlmepriv->cur_network);; */ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 cbw40_enable = 0; + + + if (!phtpriv->ht_option) + return; + + if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable)) + return; + + RTW_INFO("+rtw_update_ht_cap()\n"); + + /* maybe needs check if ap supports rx ampdu. */ + if ((phtpriv->ampdu_enable == _FALSE) && (pregistrypriv->ampdu_enable == 1)) { + if (pregistrypriv->wifi_spec == 1) { + /* remove this part because testbed AP should disable RX AMPDU */ + /* phtpriv->ampdu_enable = _FALSE; */ + phtpriv->ampdu_enable = _TRUE; + } else + phtpriv->ampdu_enable = _TRUE; + } + + + /* check Max Rx A-MPDU Size */ + len = 0; + p = rtw_get_ie(pie + sizeof(NDIS_802_11_FIXED_IEs), _HT_CAPABILITY_IE_, &len, ie_len - sizeof(NDIS_802_11_FIXED_IEs)); + if (p && len > 0) { + pht_capie = (struct rtw_ieee80211_ht_cap *)(p + 2); + max_ampdu_sz = (pht_capie->ampdu_params_info & IEEE80211_HT_CAP_AMPDU_FACTOR); + max_ampdu_sz = 1 << (max_ampdu_sz + 3); /* max_ampdu_sz (kbytes); */ + + /* RTW_INFO("rtw_update_ht_cap(): max_ampdu_sz=%d\n", max_ampdu_sz); */ + phtpriv->rx_ampdu_maxlen = max_ampdu_sz; + + } + + + len = 0; + p = rtw_get_ie(pie + sizeof(NDIS_802_11_FIXED_IEs), _HT_ADD_INFO_IE_, &len, ie_len - sizeof(NDIS_802_11_FIXED_IEs)); + if (p && len > 0) { + pht_addtinfo = (struct ieee80211_ht_addt_info *)(p + 2); + /* todo: */ + } + + if (hal_chk_bw_cap(padapter, BW_CAP_40M)) { + if (channel > 14) { + if (REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40)) + cbw40_enable = 1; + } else { + if (REGSTY_IS_BW_2G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40)) + cbw40_enable = 1; + } + } + + /* update cur_bwmode & cur_ch_offset */ + if ((cbw40_enable) && + (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & BIT(1)) && + (pmlmeinfo->HT_info.infos[0] & BIT(2))) { + struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); + int i; + u8 rf_type = RF_1T1R; + u8 tx_nss = 0; + + rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); + + /* update the MCS set */ + for (i = 0; i < 16; i++) + pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= pmlmeext->default_supported_mcs_set[i]; + + /* update the MCS rates */ + switch (tx_nss) { + case 1: + set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_1R); + break; + case 2: + #ifdef CONFIG_DISABLE_MCS13TO15 + if (pmlmeext->cur_bwmode == CHANNEL_WIDTH_40 && pregistrypriv->wifi_spec != 1) + set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R_13TO15_OFF); + else + #endif + set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R); + break; + case 3: + set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_3R); + break; + case 4: + set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_4R); + break; + default: + RTW_WARN("rf_type:%d or tx_nss_num:%u is not expected\n", rf_type, hal_spec->tx_nss_num); + } + + /* switch to the 40M Hz mode accoring to the AP */ + /* pmlmeext->cur_bwmode = CHANNEL_WIDTH_40; */ + switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) { + case EXTCHNL_OFFSET_UPPER: + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; + break; + + case EXTCHNL_OFFSET_LOWER: + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; + break; + + default: + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + break; + } + } + + /* */ + /* Config SM Power Save setting */ + /* */ + pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2; + if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) { +#if 0 + u8 i; + /* update the MCS rates */ + for (i = 0; i < 16; i++) + pmlmeinfo->HT_caps.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; +#endif + RTW_INFO("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __FUNCTION__); + } + + /* */ + /* Config current HT Protection mode. */ + /* */ + pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; + + + +#if 0 /* move to rtw_update_sta_info_client() */ + /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info */ + /* if A-MPDU Rx is enabled, reseting rx_ordering_ctrl wstart_b(indicate_seq) to default value=0xffff */ + /* todo: check if AP can send A-MPDU packets */ + bmc_sta = rtw_get_bcmc_stainfo(padapter); + if (bmc_sta) { + for (i = 0; i < 16 ; i++) { + /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ + preorder_ctrl = &bmc_sta->recvreorder_ctrl[i]; + preorder_ctrl->enable = _FALSE; + preorder_ctrl->indicate_seq = 0xffff; +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d indicate_seq:%u\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq); +#endif + preorder_ctrl->wend_b = 0xffff; + preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; */ /* ex. 32(kbytes) -> wsize_b=32 */ + } + } + + psta = rtw_get_stainfo(&padapter->stapriv, pcur_network->network.MacAddress); + if (psta) { + for (i = 0; i < 16 ; i++) { + /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */ + preorder_ctrl = &psta->recvreorder_ctrl[i]; + preorder_ctrl->enable = _FALSE; + preorder_ctrl->indicate_seq = 0xffff; +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d indicate_seq:%u\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq); +#endif + preorder_ctrl->wend_b = 0xffff; + preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; */ /* ex. 32(kbytes) -> wsize_b=32 */ + } + } +#endif + +} + +#ifdef CONFIG_TDLS +void rtw_issue_addbareq_cmd_tdls(_adapter *padapter, struct xmit_frame *pxmitframe) +{ + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_info *ptdls_sta = NULL; + u8 issued; + int priority; + struct ht_priv *phtpriv; + + priority = pattrib->priority; + + if (pattrib->direct_link == _TRUE) { + ptdls_sta = rtw_get_stainfo(&padapter->stapriv, pattrib->dst); + if ((ptdls_sta != NULL) && (ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE)) { + phtpriv = &ptdls_sta->htpriv; + + if ((phtpriv->ht_option == _TRUE) && (phtpriv->ampdu_enable == _TRUE)) { + issued = (phtpriv->agg_enable_bitmap >> priority) & 0x1; + issued |= (phtpriv->candidate_tid_bitmap >> priority) & 0x1; + + if (0 == issued) { + RTW_INFO("[%s], p=%d\n", __FUNCTION__, priority); + ptdls_sta->htpriv.candidate_tid_bitmap |= BIT((u8)priority); + rtw_addbareq_cmd(padapter, (u8)priority, pattrib->dst); + } + } + } + } +} +#endif /* CONFIG_TDLS */ + +void rtw_issue_addbareq_cmd(_adapter *padapter, struct xmit_frame *pxmitframe) +{ + u8 issued; + int priority; + struct sta_info *psta = NULL; + struct ht_priv *phtpriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + s32 bmcst = IS_MCAST(pattrib->ra); + + /* if(bmcst || (padapter->mlmepriv.LinkDetectInfo.bTxBusyTraffic == _FALSE)) */ + if (bmcst || (padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod < 100)) + return; + + priority = pattrib->priority; + +#ifdef CONFIG_TDLS + rtw_issue_addbareq_cmd_tdls(padapter, pxmitframe); +#endif /* CONFIG_TDLS */ + + psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); + if (pattrib->psta != psta) { + RTW_INFO("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); + return; + } + + if (psta == NULL) { + RTW_INFO("%s, psta==NUL\n", __func__); + return; + } + + if (!(psta->state & _FW_LINKED)) { + RTW_INFO("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + return; + } + + + phtpriv = &psta->htpriv; + + if ((phtpriv->ht_option == _TRUE) && (phtpriv->ampdu_enable == _TRUE)) { + issued = (phtpriv->agg_enable_bitmap >> priority) & 0x1; + issued |= (phtpriv->candidate_tid_bitmap >> priority) & 0x1; + + if (0 == issued) { + RTW_INFO("rtw_issue_addbareq_cmd, p=%d\n", priority); + psta->htpriv.candidate_tid_bitmap |= BIT((u8)priority); + rtw_addbareq_cmd(padapter, (u8) priority, pattrib->ra); + } + } + +} + +void rtw_append_exented_cap(_adapter *padapter, u8 *out_ie, uint *pout_len) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; +#ifdef CONFIG_80211AC_VHT + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; +#endif /* CONFIG_80211AC_VHT */ + u8 cap_content[8] = { 0 }; + u8 *pframe; + u8 null_content[8] = {0}; + + if (phtpriv->bss_coexist) + SET_EXT_CAPABILITY_ELE_BSS_COEXIST(cap_content, 1); + +#ifdef CONFIG_80211AC_VHT + if (pvhtpriv->vht_option) + SET_EXT_CAPABILITY_ELE_OP_MODE_NOTIF(cap_content, 1); +#endif /* CONFIG_80211AC_VHT */ + /* + From 802.11 specification,if a STA does not support any of capabilities defined + in the Extended Capabilities element, then the STA is not required to + transmit the Extended Capabilities element. + */ + if (_FALSE == _rtw_memcmp(cap_content, null_content, 8)) + pframe = rtw_set_ie(out_ie + *pout_len, EID_EXTCapability, 8, cap_content , pout_len); +} +#endif + +#ifdef CONFIG_LAYER2_ROAMING +inline void rtw_set_to_roam(_adapter *adapter, u8 to_roam) +{ + if (to_roam == 0) + adapter->mlmepriv.to_join = _FALSE; + adapter->mlmepriv.to_roam = to_roam; +} + +inline u8 rtw_dec_to_roam(_adapter *adapter) +{ + adapter->mlmepriv.to_roam--; + return adapter->mlmepriv.to_roam; +} + +inline u8 rtw_to_roam(_adapter *adapter) +{ + return adapter->mlmepriv.to_roam; +} + +void rtw_roaming(_adapter *padapter, struct wlan_network *tgt_network) +{ + _irqL irqL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + _rtw_roaming(padapter, tgt_network); + _exit_critical_bh(&pmlmepriv->lock, &irqL); +} +void _rtw_roaming(_adapter *padapter, struct wlan_network *tgt_network) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + int do_join_r; + + if (0 < rtw_to_roam(padapter)) { + RTW_INFO("roaming from %s("MAC_FMT"), length:%d\n", + cur_network->network.Ssid.Ssid, MAC_ARG(cur_network->network.MacAddress), + cur_network->network.Ssid.SsidLength); + _rtw_memcpy(&pmlmepriv->assoc_ssid, &cur_network->network.Ssid, sizeof(NDIS_802_11_SSID)); + + pmlmepriv->assoc_by_bssid = _FALSE; + +#ifdef CONFIG_WAPI_SUPPORT + rtw_wapi_return_all_sta_info(padapter); +#endif + + while (1) { + do_join_r = rtw_do_join(padapter); + if (_SUCCESS == do_join_r) + break; + else { + RTW_INFO("roaming do_join return %d\n", do_join_r); + rtw_dec_to_roam(padapter); + + if (rtw_to_roam(padapter) > 0) + continue; + else { + RTW_INFO("%s(%d) -to roaming fail, indicate_disconnect\n", __FUNCTION__, __LINE__); +#ifdef CONFIG_RTW_80211R + rtw_clr_ft_flags(padapter, RTW_FT_SUPPORTED|RTW_FT_OVER_DS_SUPPORTED); + rtw_reset_ft_status(padapter); +#endif + rtw_indicate_disconnect(padapter, 0, _FALSE); + break; + } + } + } + } + +} +#endif /* CONFIG_LAYER2_ROAMING */ + +bool rtw_adjust_chbw(_adapter *adapter, u8 req_ch, u8 *req_bw, u8 *req_offset) +{ + struct registry_priv *regsty = adapter_to_regsty(adapter); + u8 allowed_bw; + + if (req_ch <= 14) + allowed_bw = REGSTY_BW_2G(regsty); + else + allowed_bw = REGSTY_BW_5G(regsty); + + allowed_bw = hal_largest_bw(adapter, allowed_bw); + + if (allowed_bw == CHANNEL_WIDTH_80 && *req_bw > CHANNEL_WIDTH_80) + *req_bw = CHANNEL_WIDTH_80; + else if (allowed_bw == CHANNEL_WIDTH_40 && *req_bw > CHANNEL_WIDTH_40) + *req_bw = CHANNEL_WIDTH_40; + else if (allowed_bw == CHANNEL_WIDTH_20 && *req_bw > CHANNEL_WIDTH_20) { + *req_bw = CHANNEL_WIDTH_20; + *req_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + } else + return _FALSE; + + return _TRUE; +} + +sint rtw_linked_check(_adapter *padapter) +{ + if ((check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) || + (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE) == _TRUE)) { + if (padapter->stapriv.asoc_sta_count > 2) + return _TRUE; + } else { + /* Station mode */ + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == _TRUE) + return _TRUE; + } + return _FALSE; +} +u8 rtw_is_adapter_up(_adapter *padapter) +{ + if (padapter == NULL) + return _FALSE; + + if (RTW_CANNOT_RUN(padapter)) { + RTW_INFO(FUNC_ADPT_FMT "-(bSurpriseRemoved == _TRUE) || ( bDriverStopped == _TRUE)\n", FUNC_ADPT_ARG(padapter)); + return _FALSE; + } + + if (!rtw_is_hw_init_completed(padapter)) { + /*RTW_INFO(FUNC_ADPT_FMT "-(hw_init_completed == _FALSE)\n", FUNC_ADPT_ARG(padapter));*/ + return _FALSE; + } + + if (padapter->bup == _FALSE) { + /*RTW_INFO(FUNC_ADPT_FMT "-(bup == _FALSE)\n", FUNC_ADPT_ARG(padapter));*/ + return _FALSE; + } + + return _TRUE; +} + +bool is_miracast_enabled(_adapter *adapter) +{ + bool enabled = 0; +#ifdef CONFIG_WFD + struct wifi_display_info *wfdinfo = &adapter->wfd_info; + + enabled = (wfdinfo->stack_wfd_mode & (MIRACAST_SOURCE | MIRACAST_SINK)) + || (wfdinfo->op_wfd_mode & (MIRACAST_SOURCE | MIRACAST_SINK)); +#endif + + return enabled; +} + +bool rtw_chk_miracast_mode(_adapter *adapter, u8 mode) +{ + bool ret = 0; +#ifdef CONFIG_WFD + struct wifi_display_info *wfdinfo = &adapter->wfd_info; + + ret = (wfdinfo->stack_wfd_mode & mode) || (wfdinfo->op_wfd_mode & mode); +#endif + + return ret; +} + +const char *get_miracast_mode_str(int mode) +{ + if (mode == MIRACAST_SOURCE) + return "SOURCE"; + else if (mode == MIRACAST_SINK) + return "SINK"; + else if (mode == (MIRACAST_SOURCE | MIRACAST_SINK)) + return "SOURCE&SINK"; + else if (mode == MIRACAST_DISABLED) + return "DISABLED"; + else + return "INVALID"; +} + +#ifdef CONFIG_WFD +static bool wfd_st_match_rule(_adapter *adapter, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port) +{ + struct wifi_display_info *wfdinfo = &adapter->wfd_info; + + if (ntohs(*((u16 *)local_port)) == wfdinfo->rtsp_ctrlport + || ntohs(*((u16 *)local_port)) == wfdinfo->tdls_rtsp_ctrlport + || ntohs(*((u16 *)remote_port)) == wfdinfo->peer_rtsp_ctrlport) + return _TRUE; + return _FALSE; +} + +static struct st_register wfd_st_reg = { + .s_proto = 0x06, + .rule = wfd_st_match_rule, +}; +#endif /* CONFIG_WFD */ + +inline void rtw_wfd_st_switch(struct sta_info *sta, bool on) +{ +#ifdef CONFIG_WFD + if (on) + rtw_st_ctl_register(&sta->st_ctl, SESSION_TRACKER_REG_ID_WFD, &wfd_st_reg); + else + rtw_st_ctl_unregister(&sta->st_ctl, SESSION_TRACKER_REG_ID_WFD); +#endif +} diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_mlme_ext.c b/linux-bsp/drivers/rtl8188eus/core/rtw_mlme_ext.c new file mode 100644 index 0000000..f133516 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_mlme_ext.c @@ -0,0 +1,15724 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_MLME_EXT_C_ + +#include <drv_types.h> +#ifdef CONFIG_IOCTL_CFG80211 + #include <rtw_wifi_regd.h> +#endif /* CONFIG_IOCTL_CFG80211 */ +#include <hal_data.h> + + +struct mlme_handler mlme_sta_tbl[] = { + {WIFI_ASSOCREQ, "OnAssocReq", &OnAssocReq}, + {WIFI_ASSOCRSP, "OnAssocRsp", &OnAssocRsp}, + {WIFI_REASSOCREQ, "OnReAssocReq", &OnAssocReq}, + {WIFI_REASSOCRSP, "OnReAssocRsp", &OnAssocRsp}, + {WIFI_PROBEREQ, "OnProbeReq", &OnProbeReq}, + {WIFI_PROBERSP, "OnProbeRsp", &OnProbeRsp}, + + /*---------------------------------------------------------- + below 2 are reserved + -----------------------------------------------------------*/ + {0, "DoReserved", &DoReserved}, + {0, "DoReserved", &DoReserved}, + {WIFI_BEACON, "OnBeacon", &OnBeacon}, + {WIFI_ATIM, "OnATIM", &OnAtim}, + {WIFI_DISASSOC, "OnDisassoc", &OnDisassoc}, + {WIFI_AUTH, "OnAuth", &OnAuthClient}, + {WIFI_DEAUTH, "OnDeAuth", &OnDeAuth}, + {WIFI_ACTION, "OnAction", &OnAction}, + {WIFI_ACTION_NOACK, "OnActionNoAck", &OnAction}, +}; + +#ifdef _CONFIG_NATIVEAP_MLME_ +struct mlme_handler mlme_ap_tbl[] = { + {WIFI_ASSOCREQ, "OnAssocReq", &OnAssocReq}, + {WIFI_ASSOCRSP, "OnAssocRsp", &OnAssocRsp}, + {WIFI_REASSOCREQ, "OnReAssocReq", &OnAssocReq}, + {WIFI_REASSOCRSP, "OnReAssocRsp", &OnAssocRsp}, + {WIFI_PROBEREQ, "OnProbeReq", &OnProbeReq}, + {WIFI_PROBERSP, "OnProbeRsp", &OnProbeRsp}, + + /*---------------------------------------------------------- + below 2 are reserved + -----------------------------------------------------------*/ + {0, "DoReserved", &DoReserved}, + {0, "DoReserved", &DoReserved}, + {WIFI_BEACON, "OnBeacon", &OnBeacon}, + {WIFI_ATIM, "OnATIM", &OnAtim}, + {WIFI_DISASSOC, "OnDisassoc", &OnDisassoc}, + {WIFI_AUTH, "OnAuth", &OnAuth}, + {WIFI_DEAUTH, "OnDeAuth", &OnDeAuth}, + {WIFI_ACTION, "OnAction", &OnAction}, + {WIFI_ACTION_NOACK, "OnActionNoAck", &OnAction}, +}; +#endif + +struct action_handler OnAction_tbl[] = { + {RTW_WLAN_CATEGORY_SPECTRUM_MGMT, "ACTION_SPECTRUM_MGMT", on_action_spct}, + {RTW_WLAN_CATEGORY_QOS, "ACTION_QOS", &OnAction_qos}, + {RTW_WLAN_CATEGORY_DLS, "ACTION_DLS", &OnAction_dls}, + {RTW_WLAN_CATEGORY_BACK, "ACTION_BACK", &OnAction_back}, + {RTW_WLAN_CATEGORY_PUBLIC, "ACTION_PUBLIC", on_action_public}, + {RTW_WLAN_CATEGORY_RADIO_MEASUREMENT, "ACTION_RADIO_MEASUREMENT", &DoReserved}, + {RTW_WLAN_CATEGORY_FT, "ACTION_FT", &OnAction_ft}, + {RTW_WLAN_CATEGORY_HT, "ACTION_HT", &OnAction_ht}, +#ifdef CONFIG_IEEE80211W + {RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &OnAction_sa_query}, +#else + {RTW_WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &DoReserved}, +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_RTW_WNM + {RTW_WLAN_CATEGORY_WNM, "ACTION_WNM", &on_action_wnm}, +#endif + {RTW_WLAN_CATEGORY_UNPROTECTED_WNM, "ACTION_UNPROTECTED_WNM", &DoReserved}, + {RTW_WLAN_CATEGORY_SELF_PROTECTED, "ACTION_SELF_PROTECTED", &DoReserved}, + {RTW_WLAN_CATEGORY_WMM, "ACTION_WMM", &OnAction_wmm}, + {RTW_WLAN_CATEGORY_VHT, "ACTION_VHT", &OnAction_vht}, + {RTW_WLAN_CATEGORY_P2P, "ACTION_P2P", &OnAction_p2p}, +}; + + +u8 null_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; + +/************************************************** +OUI definitions for the vendor specific IE +***************************************************/ +unsigned char RTW_WPA_OUI[] = {0x00, 0x50, 0xf2, 0x01}; +unsigned char WMM_OUI[] = {0x00, 0x50, 0xf2, 0x02}; +unsigned char WPS_OUI[] = {0x00, 0x50, 0xf2, 0x04}; +unsigned char P2P_OUI[] = {0x50, 0x6F, 0x9A, 0x09}; +unsigned char WFD_OUI[] = {0x50, 0x6F, 0x9A, 0x0A}; + +unsigned char WMM_INFO_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; +unsigned char WMM_PARA_OUI[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; + +unsigned char WPA_TKIP_CIPHER[4] = {0x00, 0x50, 0xf2, 0x02}; +unsigned char RSN_TKIP_CIPHER[4] = {0x00, 0x0f, 0xac, 0x02}; + +extern unsigned char REALTEK_96B_IE[]; + +#ifdef LEGACY_CHANNEL_PLAN_REF +/******************************************************** +ChannelPlan definitions +*********************************************************/ +static RT_CHANNEL_PLAN legacy_channel_plan[] = { + /* 0x00, RTW_CHPLAN_FCC */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}, 32}, + /* 0x01, RTW_CHPLAN_IC */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 31}, + /* 0x02, RTW_CHPLAN_ETSI */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 32}, + /* 0x03, RTW_CHPLAN_SPAIN */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, + /* 0x04, RTW_CHPLAN_FRANCE */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, + /* 0x05, RTW_CHPLAN_MKK */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, + /* 0x06, RTW_CHPLAN_MKK1 */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, + /* 0x07, RTW_CHPLAN_ISRAEL */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21}, + /* 0x08, RTW_CHPLAN_TELEC */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52, 56, 60, 64}, 22}, + /* 0x09, RTW_CHPLAN_GLOBAL_DOAMIN */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}, + /* 0x0A, RTW_CHPLAN_WORLD_WIDE_13 */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13}, + /* 0x0B, RTW_CHPLAN_TAIWAN */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 26}, + /* 0x0C, RTW_CHPLAN_CHINA */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 149, 153, 157, 161, 165}, 18}, + /* 0x0D, RTW_CHPLAN_SINGAPORE_INDIA_MEXICO */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}, 24}, + /* 0x0E, RTW_CHPLAN_KOREA */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 149, 153, 157, 161, 165}, 31}, + /* 0x0F, RTW_CHPLAN_TURKEY */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64}, 19}, + /* 0x10, RTW_CHPLAN_JAPAN */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 32}, + /* 0x11, RTW_CHPLAN_FCC_NO_DFS */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 149, 153, 157, 161, 165}, 20}, + /* 0x12, RTW_CHPLAN_JAPAN_NO_DFS */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48}, 17}, + /* 0x13, RTW_CHPLAN_WORLD_WIDE_5G */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}, 37}, + /* 0x14, RTW_CHPLAN_TAIWAN_NO_DFS */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 56, 60, 64, 149, 153, 157, 161, 165}, 19}, +}; +#endif + +static struct ch_list_t RTW_ChannelPlan2G[] = { + /* 0, RTW_RD_2G_NULL */ CH_LIST_ENT(0), + /* 1, RTW_RD_2G_WORLD */ CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13), + /* 2, RTW_RD_2G_ETSI1 */ CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13), + /* 3, RTW_RD_2G_FCC1 */ CH_LIST_ENT(11, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), + /* 4, RTW_RD_2G_MKK1 */ CH_LIST_ENT(14, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14), + /* 5, RTW_RD_2G_ETSI2 */ CH_LIST_ENT(4, 10, 11, 12, 13), + /* 6, RTW_RD_2G_GLOBAL */ CH_LIST_ENT(14, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14), + /* 7, RTW_RD_2G_MKK2 */ CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13), + /* 8, RTW_RD_2G_FCC2 */ CH_LIST_ENT(13, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13), +}; + +#ifdef CONFIG_IEEE80211_BAND_5GHZ +static struct ch_list_t RTW_ChannelPlan5G[] = { + /* 0, RTW_RD_5G_NULL */ CH_LIST_ENT(0), + /* 1, RTW_RD_5G_ETSI1 */ CH_LIST_ENT(19, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140), + /* 2, RTW_RD_5G_ETSI2 */ CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165), + /* 3, RTW_RD_5G_ETSI3 */ CH_LIST_ENT(22, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 149, 153, 157, 161, 165), + /* 4, RTW_RD_5G_FCC1 */ CH_LIST_ENT(24, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165), + /* 5, RTW_RD_5G_FCC2 */ CH_LIST_ENT(9, 36, 40, 44, 48, 149, 153, 157, 161, 165), + /* 6, RTW_RD_5G_FCC3 */ CH_LIST_ENT(13, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165), + /* 7, RTW_RD_5G_FCC4 */ CH_LIST_ENT(12, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161), + /* 8, RTW_RD_5G_FCC5 */ CH_LIST_ENT(5, 149, 153, 157, 161, 165), + /* 9, RTW_RD_5G_FCC6 */ CH_LIST_ENT(8, 36, 40, 44, 48, 52, 56, 60, 64), + /* 10, RTW_RD_5G_FCC7 */ CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165), + /* 11, RTW_RD_5G_KCC1 */ CH_LIST_ENT(19, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 149, 153, 157, 161), + /* 12, RTW_RD_5G_MKK1 */ CH_LIST_ENT(19, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140), + /* 13, RTW_RD_5G_MKK2 */ CH_LIST_ENT(8, 36, 40, 44, 48, 52, 56, 60, 64), + /* 14, RTW_RD_5G_MKK3 */ CH_LIST_ENT(11, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140), + /* 15, RTW_RD_5G_NCC1 */ CH_LIST_ENT(16, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165), + /* 16, RTW_RD_5G_NCC2 */ CH_LIST_ENT(8, 56, 60, 64, 149, 153, 157, 161, 165), + /* 17, RTW_RD_5G_NCC3 */ CH_LIST_ENT(5, 149, 153, 157, 161, 165), + /* 18, RTW_RD_5G_ETSI4 */ CH_LIST_ENT(4, 36, 40, 44, 48), + /* 19, RTW_RD_5G_ETSI5 */ CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165), + /* 20, RTW_RD_5G_FCC8 */ CH_LIST_ENT(4, 149, 153, 157, 161), + /* 21, RTW_RD_5G_ETSI6 */ CH_LIST_ENT(8, 36, 40, 44, 48, 52, 56, 60, 64), + /* 22, RTW_RD_5G_ETSI7 */ CH_LIST_ENT(13, 36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165), + /* 23, RTW_RD_5G_ETSI8 */ CH_LIST_ENT(9, 36, 40, 44, 48, 149, 153, 157, 161, 165), + /* 24, RTW_RD_5G_ETSI9 */ CH_LIST_ENT(11, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140), + /* 25, RTW_RD_5G_ETSI10 */ CH_LIST_ENT(5, 149, 153, 157, 161, 165), + /* 26, RTW_RD_5G_ETSI11 */ CH_LIST_ENT(16, 36, 40, 44, 48, 52, 56, 60, 64, 132, 136, 140, 149, 153, 157, 161, 165), + /* 27, RTW_RD_5G_NCC4 */ CH_LIST_ENT(17, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165), + /* 28, RTW_RD_5G_ETSI12 */ CH_LIST_ENT(4, 149, 153, 157, 161), + /* 29, RTW_RD_5G_FCC9 */ CH_LIST_ENT(21, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165), + /* 30, RTW_RD_5G_ETSI13 */ CH_LIST_ENT(16, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140), + /* 31, RTW_RD_5G_FCC10 */ CH_LIST_ENT(20, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161), + /* 32, RTW_RD_5G_MKK4 */ CH_LIST_ENT(4, 36, 40, 44, 48), + /* 33, RTW_RD_5G_ETSI14 */ CH_LIST_ENT(11, 36, 40, 44, 48, 52, 56, 60, 64, 132, 136, 140), + /* 34, RTW_RD_5G_FCC11 */ CH_LIST_ENT(25, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165), + + /* === Below are driver defined for legacy channel plan compatible, NO static index assigned ==== */ + /* RTW_RD_5G_OLD_FCC1 */ CH_LIST_ENT(20, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165), + /* RTW_RD_5G_OLD_NCC1 */ CH_LIST_ENT(15, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165), + /* RTW_RD_5G_OLD_KCC1 */ CH_LIST_ENT(20, 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 149, 153, 157, 161, 165), +}; +#endif /* CONFIG_IEEE80211_BAND_5GHZ */ + +static RT_CHANNEL_PLAN_MAP RTW_ChannelPlanMap[] = { + /* ===== 0x00 ~ 0x1F, legacy channel plan ===== */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_KCC1, TXPWR_LMT_FCC), /* 0x00, RTW_CHPLAN_FCC */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_OLD_FCC1, TXPWR_LMT_FCC), /* 0x01, RTW_CHPLAN_IC */ + CHPLAN_ENT(RTW_RD_2G_ETSI1, RTW_RD_5G_ETSI1, TXPWR_LMT_ETSI), /* 0x02, RTW_CHPLAN_ETSI */ + CHPLAN_ENT(RTW_RD_2G_ETSI1, RTW_RD_5G_NULL, TXPWR_LMT_ETSI), /* 0x03, RTW_CHPLAN_SPAIN */ + CHPLAN_ENT(RTW_RD_2G_ETSI1, RTW_RD_5G_NULL, TXPWR_LMT_ETSI), /* 0x04, RTW_CHPLAN_FRANCE */ + CHPLAN_ENT(RTW_RD_2G_MKK1, RTW_RD_5G_NULL, TXPWR_LMT_MKK), /* 0x05, RTW_CHPLAN_MKK */ + CHPLAN_ENT(RTW_RD_2G_MKK1, RTW_RD_5G_NULL, TXPWR_LMT_MKK), /* 0x06, RTW_CHPLAN_MKK1 */ + CHPLAN_ENT(RTW_RD_2G_ETSI1, RTW_RD_5G_FCC6, TXPWR_LMT_ETSI), /* 0x07, RTW_CHPLAN_ISRAEL */ + CHPLAN_ENT(RTW_RD_2G_MKK1, RTW_RD_5G_FCC6, TXPWR_LMT_MKK), /* 0x08, RTW_CHPLAN_TELEC */ + CHPLAN_ENT(RTW_RD_2G_MKK1, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x09, RTW_CHPLAN_GLOBAL_DOAMIN */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x0A, RTW_CHPLAN_WORLD_WIDE_13 */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_OLD_NCC1, TXPWR_LMT_FCC), /* 0x0B, RTW_CHPLAN_TAIWAN */ + CHPLAN_ENT(RTW_RD_2G_ETSI1, RTW_RD_5G_FCC5, TXPWR_LMT_ETSI), /* 0x0C, RTW_CHPLAN_CHINA */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_FCC3, TXPWR_LMT_WW), /* 0x0D, RTW_CHPLAN_SINGAPORE_INDIA_MEXICO */ /* ETSI:Singapore, India. FCC:Mexico => WW */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_OLD_KCC1, TXPWR_LMT_ETSI), /* 0x0E, RTW_CHPLAN_KOREA */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_FCC6, TXPWR_LMT_ETSI), /* 0x0F, RTW_CHPLAN_TURKEY */ + CHPLAN_ENT(RTW_RD_2G_ETSI1, RTW_RD_5G_ETSI1, TXPWR_LMT_MKK), /* 0x10, RTW_CHPLAN_JAPAN */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_FCC2, TXPWR_LMT_FCC), /* 0x11, RTW_CHPLAN_FCC_NO_DFS */ + CHPLAN_ENT(RTW_RD_2G_ETSI1, RTW_RD_5G_FCC7, TXPWR_LMT_MKK), /* 0x12, RTW_CHPLAN_JAPAN_NO_DFS */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_FCC1, TXPWR_LMT_WW), /* 0x13, RTW_CHPLAN_WORLD_WIDE_5G */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_NCC2, TXPWR_LMT_FCC), /* 0x14, RTW_CHPLAN_TAIWAN_NO_DFS */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_FCC7, TXPWR_LMT_ETSI), /* 0x15, RTW_CHPLAN_ETSI_NO_DFS */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_NCC1, TXPWR_LMT_ETSI), /* 0x16, RTW_CHPLAN_KOREA_NO_DFS */ + CHPLAN_ENT(RTW_RD_2G_MKK1, RTW_RD_5G_FCC7, TXPWR_LMT_MKK), /* 0x17, RTW_CHPLAN_JAPAN_NO_DFS */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_FCC5, TXPWR_LMT_ETSI), /* 0x18, RTW_CHPLAN_PAKISTAN_NO_DFS */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_FCC5, TXPWR_LMT_FCC), /* 0x19, RTW_CHPLAN_TAIWAN2_NO_DFS */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x1A, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x1B, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x1C, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x1D, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x1E, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_FCC1, TXPWR_LMT_WW), /* 0x1F, RTW_CHPLAN_WORLD_WIDE_ONLY_5G */ + + /* ===== 0x20 ~ 0x7F, new channel plan ===== */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x20, RTW_CHPLAN_WORLD_NULL */ + CHPLAN_ENT(RTW_RD_2G_ETSI1, RTW_RD_5G_NULL, TXPWR_LMT_ETSI), /* 0x21, RTW_CHPLAN_ETSI1_NULL */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_NULL, TXPWR_LMT_FCC), /* 0x22, RTW_CHPLAN_FCC1_NULL */ + CHPLAN_ENT(RTW_RD_2G_MKK1, RTW_RD_5G_NULL, TXPWR_LMT_MKK), /* 0x23, RTW_CHPLAN_MKK1_NULL */ + CHPLAN_ENT(RTW_RD_2G_ETSI2, RTW_RD_5G_NULL, TXPWR_LMT_ETSI), /* 0x24, RTW_CHPLAN_ETSI2_NULL */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_FCC1, TXPWR_LMT_FCC), /* 0x25, RTW_CHPLAN_FCC1_FCC1 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_ETSI1, TXPWR_LMT_ETSI), /* 0x26, RTW_CHPLAN_WORLD_ETSI1 */ + CHPLAN_ENT(RTW_RD_2G_MKK1, RTW_RD_5G_MKK1, TXPWR_LMT_MKK), /* 0x27, RTW_CHPLAN_MKK1_MKK1 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_KCC1, TXPWR_LMT_ETSI), /* 0x28, RTW_CHPLAN_WORLD_KCC1 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_FCC2, TXPWR_LMT_FCC), /* 0x29, RTW_CHPLAN_WORLD_FCC2 */ + CHPLAN_ENT(RTW_RD_2G_FCC2, RTW_RD_5G_NULL, TXPWR_LMT_FCC), /* 0x2A, RTW_CHPLAN_FCC2_NULL */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x2B, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x2C, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x2D, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x2E, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x2F, */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_FCC3, TXPWR_LMT_FCC), /* 0x30, RTW_CHPLAN_WORLD_FCC3 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_FCC4, TXPWR_LMT_FCC), /* 0x31, RTW_CHPLAN_WORLD_FCC4 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_FCC5, TXPWR_LMT_FCC), /* 0x32, RTW_CHPLAN_WORLD_FCC5 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_FCC6, TXPWR_LMT_FCC), /* 0x33, RTW_CHPLAN_WORLD_FCC6 */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_FCC7, TXPWR_LMT_FCC), /* 0x34, RTW_CHPLAN_FCC1_FCC7 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_ETSI2, TXPWR_LMT_ETSI), /* 0x35, RTW_CHPLAN_WORLD_ETSI2 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_ETSI3, TXPWR_LMT_ETSI), /* 0x36, RTW_CHPLAN_WORLD_ETSI3 */ + CHPLAN_ENT(RTW_RD_2G_MKK1, RTW_RD_5G_MKK2, TXPWR_LMT_MKK), /* 0x37, RTW_CHPLAN_MKK1_MKK2 */ + CHPLAN_ENT(RTW_RD_2G_MKK1, RTW_RD_5G_MKK3, TXPWR_LMT_MKK), /* 0x38, RTW_CHPLAN_MKK1_MKK3 */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_NCC1, TXPWR_LMT_FCC), /* 0x39, RTW_CHPLAN_FCC1_NCC1 */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x3A, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x3B, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x3C, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x3D, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x3E, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x3F, */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_NCC2, TXPWR_LMT_FCC), /* 0x40, RTW_CHPLAN_FCC1_NCC2 */ + CHPLAN_ENT(RTW_RD_2G_GLOBAL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x41, RTW_CHPLAN_GLOBAL_NULL */ + CHPLAN_ENT(RTW_RD_2G_ETSI1, RTW_RD_5G_ETSI4, TXPWR_LMT_ETSI), /* 0x42, RTW_CHPLAN_ETSI1_ETSI4 */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_FCC2, TXPWR_LMT_FCC), /* 0x43, RTW_CHPLAN_FCC1_FCC2 */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_NCC3, TXPWR_LMT_FCC), /* 0x44, RTW_CHPLAN_FCC1_NCC3 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_ETSI5, TXPWR_LMT_ETSI), /* 0x45, RTW_CHPLAN_WORLD_ETSI5 */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_FCC8, TXPWR_LMT_FCC), /* 0x46, RTW_CHPLAN_FCC1_FCC8 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_ETSI6, TXPWR_LMT_ETSI), /* 0x47, RTW_CHPLAN_WORLD_ETSI6 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_ETSI7, TXPWR_LMT_ETSI), /* 0x48, RTW_CHPLAN_WORLD_ETSI7 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_ETSI8, TXPWR_LMT_ETSI), /* 0x49, RTW_CHPLAN_WORLD_ETSI8 */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x4A, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x4B, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x4C, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x4D, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x4E, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x4F, */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_ETSI9, TXPWR_LMT_ETSI), /* 0x50, RTW_CHPLAN_WORLD_ETSI9 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_ETSI10, TXPWR_LMT_ETSI), /* 0x51, RTW_CHPLAN_WORLD_ETSI10 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_ETSI11, TXPWR_LMT_ETSI), /* 0x52, RTW_CHPLAN_WORLD_ETSI11 */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_NCC4, TXPWR_LMT_FCC), /* 0x53, RTW_CHPLAN_FCC1_NCC4 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_ETSI12, TXPWR_LMT_ETSI), /* 0x54, RTW_CHPLAN_WORLD_ETSI12 */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_FCC9, TXPWR_LMT_FCC), /* 0x55, RTW_CHPLAN_FCC1_FCC9 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_ETSI13, TXPWR_LMT_ETSI), /* 0x56, RTW_CHPLAN_WORLD_ETSI13 */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_FCC10, TXPWR_LMT_FCC), /* 0x57, RTW_CHPLAN_FCC1_FCC10 */ + CHPLAN_ENT(RTW_RD_2G_MKK2, RTW_RD_5G_MKK4, TXPWR_LMT_MKK), /* 0x58, RTW_CHPLAN_MKK2_MKK4 */ + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_ETSI14, TXPWR_LMT_ETSI), /* 0x59, RTW_CHPLAN_WORLD_ETSI14 */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x5A, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x5B, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x5C, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x5D, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x5E, */ + CHPLAN_ENT(RTW_RD_2G_NULL, RTW_RD_5G_NULL, TXPWR_LMT_WW), /* 0x5F, */ + CHPLAN_ENT(RTW_RD_2G_FCC1, RTW_RD_5G_FCC5, TXPWR_LMT_FCC), /* 0x60, RTW_CHPLAN_FCC1_FCC5 */ + CHPLAN_ENT(RTW_RD_2G_FCC2, RTW_RD_5G_FCC7, TXPWR_LMT_FCC), /* 0x61, RTW_CHPLAN_FCC2_FCC7 */ + CHPLAN_ENT(RTW_RD_2G_FCC2, RTW_RD_5G_FCC1, TXPWR_LMT_FCC), /* 0x62, RTW_CHPLAN_FCC2_FCC1 */ +}; + +static RT_CHANNEL_PLAN_MAP RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = + CHPLAN_ENT(RTW_RD_2G_WORLD, RTW_RD_5G_FCC1, TXPWR_LMT_FCC); /* 0x7F, Realtek Define */ + +bool rtw_chplan_is_empty(u8 id) +{ + RT_CHANNEL_PLAN_MAP *chplan_map; + + if (id == RTW_CHPLAN_REALTEK_DEFINE) + chplan_map = &RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE; + else + chplan_map = &RTW_ChannelPlanMap[id]; + + if (chplan_map->Index2G == RTW_RD_2G_NULL + #ifdef CONFIG_IEEE80211_BAND_5GHZ + && chplan_map->Index5G == RTW_RD_5G_NULL + #endif + ) + return _TRUE; + + return _FALSE; +} + +void rtw_rfctl_init(_adapter *adapter) +{ + struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); + + _rtw_memset(rfctl, 0, sizeof(*rfctl)); + +#ifdef CONFIG_DFS_MASTER + rfctl->cac_start_time = rfctl->cac_end_time = RTW_CAC_STOPPED; + + /* TODO: dfs_master_timer */ +#endif +} + +#ifdef CONFIG_DFS_MASTER +/* +* called in rtw_dfs_master_enable() +* assume the request channel coverage is DFS range +* base on the current status and the request channel coverage to check if need to reset complete CAC time +*/ +bool rtw_is_cac_reset_needed(_adapter *adapter, u8 ch, u8 bw, u8 offset) +{ + struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); + bool needed = _FALSE; + u32 cur_hi, cur_lo, hi, lo; + + if (rfctl->radar_detected == 1) { + needed = _TRUE; + goto exit; + } + + if (rfctl->radar_detect_ch == 0) { + needed = _TRUE; + goto exit; + } + + if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE) { + RTW_ERR("request detection range ch:%u, bw:%u, offset:%u\n", ch, bw, offset); + rtw_warn_on(1); + } + + if (rtw_chbw_to_freq_range(rfctl->radar_detect_ch, rfctl->radar_detect_bw, rfctl->radar_detect_offset, &cur_hi, &cur_lo) == _FALSE) { + RTW_ERR("cur detection range ch:%u, bw:%u, offset:%u\n", rfctl->radar_detect_ch, rfctl->radar_detect_bw, rfctl->radar_detect_offset); + rtw_warn_on(1); + } + + if (hi <= lo || cur_hi <= cur_lo) { + RTW_ERR("hi:%u, lo:%u, cur_hi:%u, cur_lo:%u\n", hi, lo, cur_hi, cur_lo); + rtw_warn_on(1); + } + + if (rtw_is_range_a_in_b(hi, lo, cur_hi, cur_lo)) { + /* request is in current detect range */ + goto exit; + } + + /* check if request channel coverage has new range and the new range is in DFS range */ + if (!rtw_is_range_overlap(hi, lo, cur_hi, cur_lo)) { + /* request has no overlap with current */ + needed = _TRUE; + } else if (rtw_is_range_a_in_b(cur_hi, cur_lo, hi, lo)) { + /* request is supper set of current */ + if ((hi != cur_hi && rtw_is_dfs_range(hi, cur_hi)) || (lo != cur_lo && rtw_is_dfs_range(cur_lo, lo))) + needed = _TRUE; + } else { + /* request is not supper set of current, but has overlap */ + if ((lo < cur_lo && rtw_is_dfs_range(cur_lo, lo)) || (hi > cur_hi && rtw_is_dfs_range(hi, cur_hi))) + needed = _TRUE; + } + +exit: + return needed; +} + +bool _rtw_rfctl_overlap_radar_detect_ch(struct rf_ctl_t *rfctl, u8 ch, u8 bw, u8 offset) +{ + bool ret = _FALSE; + u32 hi = 0, lo = 0; + u32 r_hi = 0, r_lo = 0; + int i; + + if (rfctl->radar_detect_by_others) + goto exit; + + if (rfctl->radar_detect_ch == 0) + goto exit; + + if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE) { + rtw_warn_on(1); + goto exit; + } + + if (rtw_chbw_to_freq_range(rfctl->radar_detect_ch + , rfctl->radar_detect_bw, rfctl->radar_detect_offset + , &r_hi, &r_lo) == _FALSE) { + rtw_warn_on(1); + goto exit; + } + + if (rtw_is_range_overlap(hi, lo, r_hi, r_lo)) + ret = _TRUE; + +exit: + return ret; +} + +bool rtw_rfctl_overlap_radar_detect_ch(struct rf_ctl_t *rfctl) +{ + return _rtw_rfctl_overlap_radar_detect_ch(rfctl + , rfctl_to_dvobj(rfctl)->oper_channel + , rfctl_to_dvobj(rfctl)->oper_bwmode + , rfctl_to_dvobj(rfctl)->oper_ch_offset); +} + +bool rtw_rfctl_is_tx_blocked_by_ch_waiting(struct rf_ctl_t *rfctl) +{ + return rtw_rfctl_overlap_radar_detect_ch(rfctl) && IS_CH_WAITING(rfctl); +} + +bool rtw_chset_is_ch_non_ocp(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset) +{ + bool ret = _FALSE; + u32 hi = 0, lo = 0; + int i; + + if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE) + goto exit; + + for (i = 0; ch_set[i].ChannelNum != 0; i++) { + if (!rtw_ch2freq(ch_set[i].ChannelNum)) { + rtw_warn_on(1); + continue; + } + + if (!CH_IS_NON_OCP(&ch_set[i])) + continue; + + if (lo <= rtw_ch2freq(ch_set[i].ChannelNum) + && rtw_ch2freq(ch_set[i].ChannelNum) <= hi + ) { + ret = _TRUE; + break; + } + } + +exit: + return ret; +} + +u32 rtw_chset_get_ch_non_ocp_ms(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset) +{ + int ms = 0; + u32 current_time; + u32 hi = 0, lo = 0; + int i; + + if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE) + goto exit; + + current_time = rtw_get_current_time(); + + for (i = 0; ch_set[i].ChannelNum != 0; i++) { + if (!rtw_ch2freq(ch_set[i].ChannelNum)) { + rtw_warn_on(1); + continue; + } + + if (!CH_IS_NON_OCP(&ch_set[i])) + continue; + + if (lo <= rtw_ch2freq(ch_set[i].ChannelNum) + && rtw_ch2freq(ch_set[i].ChannelNum) <= hi + ) { + if (rtw_systime_to_ms(ch_set[i].non_ocp_end_time - current_time) > ms) + ms = rtw_systime_to_ms(ch_set[i].non_ocp_end_time - current_time); + } + } + +exit: + return ms; +} + +/** + * rtw_chset_update_non_ocp - update non_ocp_end_time according to the given @ch, @bw, @offset into @ch_set + * @ch_set: the given channel set + * @ch: channel number on which radar is detected + * @bw: bandwidth on which radar is detected + * @offset: bandwidth offset on which radar is detected + * @ms: ms to add from now to update non_ocp_end_time, ms < 0 means use NON_OCP_TIME_MS + */ +static void _rtw_chset_update_non_ocp(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset, int ms) +{ + u32 hi = 0, lo = 0; + int i; + + if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE) + goto exit; + + for (i = 0; ch_set[i].ChannelNum != 0; i++) { + if (!rtw_ch2freq(ch_set[i].ChannelNum)) { + rtw_warn_on(1); + continue; + } + + if (lo <= rtw_ch2freq(ch_set[i].ChannelNum) + && rtw_ch2freq(ch_set[i].ChannelNum) <= hi + ) { + if (ms >= 0) + ch_set[i].non_ocp_end_time = rtw_get_current_time() + rtw_ms_to_systime(ms); + else + ch_set[i].non_ocp_end_time = rtw_get_current_time() + rtw_ms_to_systime(NON_OCP_TIME_MS); + } + } + +exit: + return; +} + +inline void rtw_chset_update_non_ocp(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset) +{ + _rtw_chset_update_non_ocp(ch_set, ch, bw, offset, -1); +} + +inline void rtw_chset_update_non_ocp_ms(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset, int ms) +{ + _rtw_chset_update_non_ocp(ch_set, ch, bw, offset, ms); +} + +u32 rtw_get_ch_waiting_ms(_adapter *adapter, u8 ch, u8 bw, u8 offset, u32 *r_non_ocp_ms, u32 *r_cac_ms) +{ + struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + u32 non_ocp_ms; + u32 cac_ms; + u8 in_rd_range = 0; /* if in current radar detection range*/ + + if (rtw_chset_is_ch_non_ocp(mlmeext->channel_set, ch, bw, offset)) + non_ocp_ms = rtw_chset_get_ch_non_ocp_ms(mlmeext->channel_set, ch, bw, offset); + else + non_ocp_ms = 0; + + if (rfctl->dfs_master_enabled) { + u32 cur_hi, cur_lo, hi, lo; + + if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE) { + RTW_ERR("input range ch:%u, bw:%u, offset:%u\n", ch, bw, offset); + rtw_warn_on(1); + } + + if (rtw_chbw_to_freq_range(rfctl->radar_detect_ch, rfctl->radar_detect_bw, rfctl->radar_detect_offset, &cur_hi, &cur_lo) == _FALSE) { + RTW_ERR("cur detection range ch:%u, bw:%u, offset:%u\n", rfctl->radar_detect_ch, rfctl->radar_detect_bw, rfctl->radar_detect_offset); + rtw_warn_on(1); + } + + if (rtw_is_range_a_in_b(hi, lo, cur_hi, cur_lo)) + in_rd_range = 1; + } + + if (!rtw_is_dfs_ch(ch, bw, offset)) + cac_ms = 0; + else if (in_rd_range && !non_ocp_ms) { + if (IS_CH_WAITING(rfctl)) + cac_ms = rtw_systime_to_ms(rfctl->cac_end_time - rtw_get_current_time()); + else + cac_ms = 0; + } else if (rtw_is_long_cac_ch(ch, bw, offset, rtw_odm_get_dfs_domain(adapter))) + cac_ms = CAC_TIME_CE_MS; + else + cac_ms = CAC_TIME_MS; + + if (r_non_ocp_ms) + *r_non_ocp_ms = non_ocp_ms; + if (r_cac_ms) + *r_cac_ms = cac_ms; + + return non_ocp_ms + cac_ms; +} + +void rtw_reset_cac(_adapter *adapter, u8 ch, u8 bw, u8 offset) +{ + struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); + u32 non_ocp_ms; + u32 cac_ms; + + rtw_get_ch_waiting_ms(adapter + , ch + , bw + , offset + , &non_ocp_ms + , &cac_ms + ); + + rfctl->cac_start_time = rtw_get_current_time() + rtw_ms_to_systime(non_ocp_ms); + rfctl->cac_end_time = rfctl->cac_start_time + rtw_ms_to_systime(cac_ms); + + /* skip special value */ + if (rfctl->cac_start_time == RTW_CAC_STOPPED) { + rfctl->cac_start_time++; + rfctl->cac_end_time++; + } + if (rfctl->cac_end_time == RTW_CAC_STOPPED) + rfctl->cac_end_time++; +} +#endif /* CONFIG_DFS_MASTER */ + +/* choose channel with shortest waiting (non ocp + cac) time */ +bool rtw_choose_shortest_waiting_ch(_adapter *adapter, u8 req_bw, u8 *dec_ch, u8 *dec_bw, u8 *dec_offset, u8 d_flags) +{ +#ifndef DBG_CHOOSE_SHORTEST_WAITING_CH +#define DBG_CHOOSE_SHORTEST_WAITING_CH 0 +#endif + + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); + struct registry_priv *regsty = adapter_to_regsty(adapter); + u8 ch, bw, offset; + u8 ch_c = 0, bw_c = 0, offset_c = 0; + int i; + u32 min_waiting_ms = 0; + + if (!dec_ch || !dec_bw || !dec_offset) { + rtw_warn_on(1); + return _FALSE; + } + + /* full search and narrow bw judegement first to avoid potetial judegement timing issue */ + for (bw = CHANNEL_WIDTH_20; bw <= req_bw; bw++) { + if (!hal_is_bw_support(adapter, bw)) + continue; + + for (i = 0; i < mlmeext->max_chan_nums; i++) { + u32 non_ocp_ms = 0; + u32 cac_ms = 0; + u32 waiting_ms = 0; + + ch = mlmeext->channel_set[i].ChannelNum; + + if ((d_flags & RTW_CHF_2G) && ch <= 14) + continue; + + if ((d_flags & RTW_CHF_5G) && ch > 14) + continue; + + if (ch > 14) { + if (bw > REGSTY_BW_5G(regsty)) + continue; + } else { + if (bw > REGSTY_BW_2G(regsty)) + continue; + } + + if (!rtw_get_offset_by_chbw(ch, bw, &offset)) + continue; + + if (!rtw_chset_is_chbw_valid(mlmeext->channel_set, ch, bw, offset)) + continue; + + if ((d_flags & RTW_CHF_NON_OCP) && rtw_chset_is_ch_non_ocp(mlmeext->channel_set, ch, bw, offset)) + continue; + + if ((d_flags & RTW_CHF_DFS) && rtw_is_dfs_ch(ch, bw, offset)) + continue; + + if ((d_flags & RTW_CHF_LONG_CAC) && rtw_is_long_cac_ch(ch, bw, offset, rtw_odm_get_dfs_domain(adapter))) + continue; + + if ((d_flags & RTW_CHF_NON_DFS) && !rtw_is_dfs_ch(ch, bw, offset)) + continue; + + if ((d_flags & RTW_CHF_NON_LONG_CAC) && !rtw_is_long_cac_ch(ch, bw, offset, rtw_odm_get_dfs_domain(adapter))) + continue; + + #ifdef CONFIG_DFS_MASTER + waiting_ms = rtw_get_ch_waiting_ms(adapter, ch, bw, offset, &non_ocp_ms, &cac_ms); + #endif + + if (DBG_CHOOSE_SHORTEST_WAITING_CH) + RTW_INFO(FUNC_ADPT_FMT":%u,%u,%u %u(non_ocp:%u, cac:%u)\n" + , FUNC_ADPT_ARG(adapter), ch, bw, offset, waiting_ms, non_ocp_ms, cac_ms); + + if (ch_c == 0 + || min_waiting_ms > waiting_ms + || (min_waiting_ms == waiting_ms && bw > bw_c) /* wider bw first */ + ) { + ch_c = ch; + bw_c = bw; + offset_c = offset; + min_waiting_ms = waiting_ms; + } + } + } + + if (ch_c != 0) { + RTW_INFO(FUNC_ADPT_FMT": d_flags:0x%02x %u,%u,%u waiting_ms:%u\n" + , FUNC_ADPT_ARG(adapter), d_flags, ch_c, bw_c, offset_c, min_waiting_ms); + + *dec_ch = ch_c; + *dec_bw = bw_c; + *dec_offset = offset_c; + return _TRUE; + } + + if (d_flags == 0) + rtw_warn_on(1); + + return _FALSE; +} + +void dump_country_chplan(void *sel, const struct country_chplan *ent) +{ + _RTW_PRINT_SEL(sel, "\"%c%c\", 0x%02X%s\n" + , ent->alpha2[0], ent->alpha2[1], ent->chplan + , COUNTRY_CHPLAN_EN_11AC(ent) ? " ac" : "" + ); +} + +void dump_country_chplan_map(void *sel) +{ + const struct country_chplan *ent; + u8 code[2]; + +#if RTW_DEF_MODULE_REGULATORY_CERT + _RTW_PRINT_SEL(sel, "RTW_DEF_MODULE_REGULATORY_CERT:0x%x\n", RTW_DEF_MODULE_REGULATORY_CERT); +#endif +#ifdef CONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP + _RTW_PRINT_SEL(sel, "CONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP\n"); +#endif + + for (code[0] = 'A'; code[0] <= 'Z'; code[0]++) { + for (code[1] = 'A'; code[1] <= 'Z'; code[1]++) { + ent = rtw_get_chplan_from_country(code); + if (!ent) + continue; + + dump_country_chplan(sel, ent); + } + } +} + +void dump_chplan_id_list(void *sel) +{ + int i; + + for (i = 0; i < RTW_CHPLAN_MAX; i++) { + if (!rtw_is_channel_plan_valid(i)) + continue; + + _RTW_PRINT_SEL(sel, "0x%02X ", i); + } + + RTW_PRINT_SEL(sel, "0x7F\n"); +} + +void dump_chplan_test(void *sel) +{ + int i, j; + + /* check invalid channel */ + for (i = 0; i < RTW_RD_2G_MAX; i++) { + for (j = 0; j < CH_LIST_LEN(RTW_ChannelPlan2G[i]); j++) { + if (rtw_ch2freq(CH_LIST_CH(RTW_ChannelPlan2G[i], j)) == 0) + RTW_PRINT_SEL(sel, "invalid ch:%u at (%d,%d)\n", CH_LIST_CH(RTW_ChannelPlan2G[i], j), i, j); + } + } + +#ifdef CONFIG_IEEE80211_BAND_5GHZ + for (i = 0; i < RTW_RD_5G_MAX; i++) { + for (j = 0; j < CH_LIST_LEN(RTW_ChannelPlan5G[i]); j++) { + if (rtw_ch2freq(CH_LIST_CH(RTW_ChannelPlan5G[i], j)) == 0) + RTW_PRINT_SEL(sel, "invalid ch:%u at (%d,%d)\n", CH_LIST_CH(RTW_ChannelPlan5G[i], j), i, j); + } + } +#endif +} + +void dump_chset(void *sel, RT_CHANNEL_INFO *ch_set) +{ + u8 i; + + for (i = 0; ch_set[i].ChannelNum != 0; i++) { + RTW_PRINT_SEL(sel, "ch:%3u, freq:%u, scan_type:%d" + , ch_set[i].ChannelNum, rtw_ch2freq(ch_set[i].ChannelNum), ch_set[i].ScanType); + +#ifdef CONFIG_FIND_BEST_CHANNEL + _RTW_PRINT_SEL(sel, ", rx_count:%u", ch_set[i].rx_count); +#endif + +#ifdef CONFIG_DFS_MASTER + if (rtw_is_dfs_ch(ch_set[i].ChannelNum, CHANNEL_WIDTH_20, HAL_PRIME_CHNL_OFFSET_DONT_CARE)) { + if (CH_IS_NON_OCP(&ch_set[i])) + _RTW_PRINT_SEL(sel, ", non_ocp:%d" + , rtw_systime_to_ms(ch_set[i].non_ocp_end_time - rtw_get_current_time())); + else + _RTW_PRINT_SEL(sel, ", non_ocp:N/A"); + } +#endif + + _RTW_PRINT_SEL(sel, "\n"); + } + + RTW_PRINT_SEL(sel, "total ch number:%d\n", i); +} + +void dump_cur_chset(void *sel, _adapter *adapter) +{ + struct mlme_priv *mlme = &adapter->mlmepriv; + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + struct registry_priv *regsty = adapter_to_regsty(adapter); + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + int i; + + if (mlme->country_ent) + dump_country_chplan(sel, mlme->country_ent); + else + RTW_PRINT_SEL(sel, "chplan:0x%02X\n", mlme->ChannelPlan); + + RTW_PRINT_SEL(sel, "2G_PLS:%u, 5G_PLS:%u\n" + , hal_data->Regulation2_4G, hal_data->Regulation5G); + +#ifdef CONFIG_DFS_MASTER + RTW_PRINT_SEL(sel, "dfs_domain:%u\n", rtw_odm_get_dfs_domain(adapter)); +#endif + + for (i = 0; i < MAX_CHANNEL_NUM; i++) + if (regsty->excl_chs[i] != 0) + break; + + if (i < MAX_CHANNEL_NUM) { + _RTW_PRINT_SEL(sel, "excl_chs:"); + for (i = 0; i < MAX_CHANNEL_NUM; i++) { + if (regsty->excl_chs[i] == 0) + break; + _RTW_PRINT_SEL(sel, "%u ", regsty->excl_chs[i]); + } + RTW_PRINT_SEL(sel, "\n"); + } + + dump_chset(sel, mlmeext->channel_set); +} + +/* + * Search the @param ch in given @param ch_set + * @ch_set: the given channel set + * @ch: the given channel number + * + * return the index of channel_num in channel_set, -1 if not found + */ +int rtw_ch_set_search_ch(RT_CHANNEL_INFO *ch_set, const u32 ch) +{ + int i; + for (i = 0; ch_set[i].ChannelNum != 0; i++) { + if (ch == ch_set[i].ChannelNum) + break; + } + + if (i >= ch_set[i].ChannelNum) + return -1; + return i; +} + +/* + * Check if the @param ch, bw, offset is valid for the given @param ch_set + * @ch_set: the given channel set + * @ch: the given channel number + * @bw: the given bandwidth + * @offset: the given channel offset + * + * return valid (1) or not (0) + */ +u8 rtw_chset_is_chbw_valid(RT_CHANNEL_INFO *ch_set, u8 ch, u8 bw, u8 offset) +{ + u8 cch; + u8 *op_chs; + u8 op_ch_num; + u8 valid = 0; + int i; + + cch = rtw_get_center_ch(ch, bw, offset); + + if (!rtw_get_op_chs_by_cch_bw(cch, bw, &op_chs, &op_ch_num)) + goto exit; + + for (i = 0; i < op_ch_num; i++) { + if (0) + RTW_INFO("%u,%u,%u - cch:%u, bw:%u, op_ch:%u\n", ch, bw, offset, cch, bw, *(op_chs + i)); + if (rtw_ch_set_search_ch(ch_set, *(op_chs + i)) == -1) + break; + } + + if (op_ch_num != 0 && i == op_ch_num) + valid = 1; + +exit: + return valid; +} + +/* + * Check the @param ch is fit with setband setting of @param adapter + * @adapter: the given adapter + * @ch: the given channel number + * + * return _TRUE when check valid, _FALSE not valid + */ +bool rtw_mlme_band_check(_adapter *adapter, const u32 ch) +{ + if (adapter->setband == WIFI_FREQUENCY_BAND_AUTO /* 2.4G and 5G */ + || (adapter->setband == WIFI_FREQUENCY_BAND_2GHZ && ch < 35) /* 2.4G only */ + || (adapter->setband == WIFI_FREQUENCY_BAND_5GHZ && ch > 35) /* 5G only */ + ) + return _TRUE; + return _FALSE; +} +inline void RTW_SET_SCAN_BAND_SKIP(_adapter *padapter, int skip_band) +{ + int bs = ATOMIC_READ(&padapter->bandskip); + + bs |= skip_band; + ATOMIC_SET(&padapter->bandskip, bs); +} + +inline void RTW_CLR_SCAN_BAND_SKIP(_adapter *padapter, int skip_band) +{ + int bs = ATOMIC_READ(&padapter->bandskip); + + bs &= ~(skip_band); + ATOMIC_SET(&padapter->bandskip, bs); +} +inline int RTW_GET_SCAN_BAND_SKIP(_adapter *padapter) +{ + return ATOMIC_READ(&padapter->bandskip); +} + +#define RTW_IS_SCAN_BAND_SKIP(padapter, skip_band) (ATOMIC_READ(&padapter->bandskip) & (skip_band)) + +bool rtw_mlme_ignore_chan(_adapter *adapter, const u32 ch) +{ + if (RTW_IS_SCAN_BAND_SKIP(adapter, BAND_24G) && ch < 35) /* SKIP 2.4G Band channel */ + return _TRUE; + if (RTW_IS_SCAN_BAND_SKIP(adapter, BAND_5G) && ch > 35) /* SKIP 5G Band channel */ + return _TRUE; + + return _FALSE; +} + + +/**************************************************************************** + +Following are the initialization functions for WiFi MLME + +*****************************************************************************/ + +int init_hw_mlme_ext(_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + /* set_opmode_cmd(padapter, infra_client_with_mlme); */ /* removed */ + + set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + + return _SUCCESS; +} + +void init_mlme_default_rate_set(_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + unsigned char mixed_datarate[NumRates] = {_1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, _9M_RATE_, _12M_RATE_, _18M_RATE_, _24M_RATE_, _36M_RATE_, _48M_RATE_, _54M_RATE_, 0xff}; + unsigned char mixed_basicrate[NumRates] = {_1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_, _12M_RATE_, _24M_RATE_, 0xff,}; + unsigned char supported_mcs_set[16] = {0xff, 0xff, 0xff, 0x00, 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + + _rtw_memcpy(pmlmeext->datarate, mixed_datarate, NumRates); + _rtw_memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates); + + _rtw_memcpy(pmlmeext->default_supported_mcs_set, supported_mcs_set, sizeof(pmlmeext->default_supported_mcs_set)); +} + +static void init_mlme_ext_priv_value(_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + ATOMIC_SET(&pmlmeext->event_seq, 0); + pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */ +#ifdef CONFIG_IEEE80211W + pmlmeext->sa_query_seq = 0; + pmlmeext->mgnt_80211w_IPN = 0; + pmlmeext->mgnt_80211w_IPN_rx = 0; +#endif /* CONFIG_IEEE80211W */ + pmlmeext->cur_channel = padapter->registrypriv.channel; + pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + + pmlmeext->retry = 0; + + pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode; + + init_mlme_default_rate_set(padapter); + + if (pmlmeext->cur_channel > 14) + pmlmeext->tx_rate = IEEE80211_OFDM_RATE_6MB; + else + pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB; + + mlmeext_set_scan_state(pmlmeext, SCAN_DISABLE); + pmlmeext->sitesurvey_res.channel_idx = 0; + pmlmeext->sitesurvey_res.bss_cnt = 0; + pmlmeext->sitesurvey_res.scan_ch_ms = SURVEY_TO; + pmlmeext->sitesurvey_res.rx_ampdu_accept = RX_AMPDU_ACCEPT_INVALID; + pmlmeext->sitesurvey_res.rx_ampdu_size = RX_AMPDU_SIZE_INVALID; +#ifdef CONFIG_SCAN_BACKOP + mlmeext_assign_scan_backop_flags_sta(pmlmeext, /*SS_BACKOP_EN|*/SS_BACKOP_PS_ANNC | SS_BACKOP_TX_RESUME); + mlmeext_assign_scan_backop_flags_ap(pmlmeext, SS_BACKOP_EN | SS_BACKOP_PS_ANNC | SS_BACKOP_TX_RESUME); + pmlmeext->sitesurvey_res.scan_cnt = 0; + pmlmeext->sitesurvey_res.scan_cnt_max = RTW_SCAN_NUM_OF_CH; + pmlmeext->sitesurvey_res.backop_ms = RTW_BACK_OP_CH_MS; +#endif +#if defined(CONFIG_ANTENNA_DIVERSITY) || defined(DBG_SCAN_SW_ANTDIV_BL) + pmlmeext->sitesurvey_res.is_sw_antdiv_bl_scan = 0; +#endif + pmlmeext->scan_abort = _FALSE; + + pmlmeinfo->state = WIFI_FW_NULL_STATE; + pmlmeinfo->reauth_count = 0; + pmlmeinfo->reassoc_count = 0; + pmlmeinfo->link_count = 0; + pmlmeinfo->auth_seq = 0; + pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; + pmlmeinfo->key_index = 0; + pmlmeinfo->iv = 0; + + pmlmeinfo->enc_algo = _NO_PRIVACY_; + pmlmeinfo->authModeToggle = 0; + + _rtw_memset(pmlmeinfo->chg_txt, 0, 128); + + pmlmeinfo->slotTime = SHORT_SLOT_TIME; + pmlmeinfo->preamble_mode = PREAMBLE_AUTO; + + pmlmeinfo->dialogToken = 0; + + pmlmeext->action_public_rxseq = 0xffff; + pmlmeext->action_public_dialog_token = 0xff; +} + +static int has_channel(RT_CHANNEL_INFO *channel_set, + u8 chanset_size, + u8 chan) +{ + int i; + + for (i = 0; i < chanset_size; i++) { + if (channel_set[i].ChannelNum == chan) + return 1; + } + + return 0; +} + +static void init_channel_list(_adapter *padapter, RT_CHANNEL_INFO *channel_set, + u8 chanset_size, + struct p2p_channels *channel_list) +{ + struct registry_priv *regsty = adapter_to_regsty(padapter); + + struct p2p_oper_class_map op_class[] = { + { IEEE80211G, 81, 1, 13, 1, BW20 }, + { IEEE80211G, 82, 14, 14, 1, BW20 }, +#if 0 /* Do not enable HT40 on 2 GHz */ + { IEEE80211G, 83, 1, 9, 1, BW40PLUS }, + { IEEE80211G, 84, 5, 13, 1, BW40MINUS }, +#endif + { IEEE80211A, 115, 36, 48, 4, BW20 }, + { IEEE80211A, 116, 36, 44, 8, BW40PLUS }, + { IEEE80211A, 117, 40, 48, 8, BW40MINUS }, + { IEEE80211A, 124, 149, 161, 4, BW20 }, + { IEEE80211A, 125, 149, 169, 4, BW20 }, + { IEEE80211A, 126, 149, 157, 8, BW40PLUS }, + { IEEE80211A, 127, 153, 161, 8, BW40MINUS }, + { -1, 0, 0, 0, 0, BW20 } + }; + + int cla, op; + + cla = 0; + + for (op = 0; op_class[op].op_class; op++) { + u8 ch; + struct p2p_oper_class_map *o = &op_class[op]; + struct p2p_reg_class *reg = NULL; + + for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { + if (!has_channel(channel_set, chanset_size, ch)) + continue; + + if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc)) + continue; + + if ((REGSTY_IS_BW_5G_SUPPORT(regsty, CHANNEL_WIDTH_40)) && + ((BW40MINUS == o->bw) || (BW40PLUS == o->bw))) + continue; + + if (reg == NULL) { + reg = &channel_list->reg_class[cla]; + cla++; + reg->reg_class = o->op_class; + reg->channels = 0; + } + reg->channel[reg->channels] = ch; + reg->channels++; + } + } + channel_list->reg_classes = cla; + +} + +bool rtw_regsty_is_excl_chs(struct registry_priv *regsty, u8 ch) +{ + int i; + + for (i = 0; i < MAX_CHANNEL_NUM; i++) { + if (regsty->excl_chs[i] == 0) + break; + if (regsty->excl_chs[i] == ch) + return _TRUE; + } + return _FALSE; +} + +static u8 init_channel_set(_adapter *padapter, u8 ChannelPlan, RT_CHANNEL_INFO *channel_set) +{ + struct registry_priv *regsty = adapter_to_regsty(padapter); + u8 index, chanset_size = 0; + u8 b5GBand = _FALSE, b2_4GBand = _FALSE; + u8 Index2G = 0, Index5G = 0; + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter); + int i; + + if (!rtw_is_channel_plan_valid(ChannelPlan)) { + RTW_ERR("ChannelPlan ID 0x%02X error !!!!!\n", ChannelPlan); + return chanset_size; + } + + _rtw_memset(channel_set, 0, sizeof(RT_CHANNEL_INFO) * MAX_CHANNEL_NUM); + + if (IsSupported24G(padapter->registrypriv.wireless_mode)) + b2_4GBand = _TRUE; + + if (is_supported_5g(padapter->registrypriv.wireless_mode)) + b5GBand = _TRUE; + + if (b2_4GBand) { + if (RTW_CHPLAN_REALTEK_DEFINE == ChannelPlan) + Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G; + else + Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G; + + for (index = 0; index < CH_LIST_LEN(RTW_ChannelPlan2G[Index2G]); index++) { + if (rtw_regsty_is_excl_chs(regsty, CH_LIST_CH(RTW_ChannelPlan2G[Index2G], index)) == _TRUE) + continue; + + channel_set[chanset_size].ChannelNum = CH_LIST_CH(RTW_ChannelPlan2G[Index2G], index); + + if (RTW_CHPLAN_GLOBAL_DOAMIN == ChannelPlan + || RTW_CHPLAN_GLOBAL_NULL == ChannelPlan + ) { + /* Channel 1~11 is active, and 12~14 is passive */ + if (channel_set[chanset_size].ChannelNum >= 1 && channel_set[chanset_size].ChannelNum <= 11) + channel_set[chanset_size].ScanType = SCAN_ACTIVE; + else if ((channel_set[chanset_size].ChannelNum >= 12 && channel_set[chanset_size].ChannelNum <= 14)) + channel_set[chanset_size].ScanType = SCAN_PASSIVE; + } else if (RTW_CHPLAN_WORLD_WIDE_13 == ChannelPlan + || RTW_CHPLAN_WORLD_WIDE_5G == ChannelPlan + || RTW_RD_2G_WORLD == Index2G + ) { + /* channel 12~13, passive scan */ + if (channel_set[chanset_size].ChannelNum <= 11) + channel_set[chanset_size].ScanType = SCAN_ACTIVE; + else + channel_set[chanset_size].ScanType = SCAN_PASSIVE; + } else + channel_set[chanset_size].ScanType = SCAN_ACTIVE; + + chanset_size++; + } + } + +#ifdef CONFIG_IEEE80211_BAND_5GHZ + if (b5GBand) { + if (RTW_CHPLAN_REALTEK_DEFINE == ChannelPlan) + Index5G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index5G; + else + Index5G = RTW_ChannelPlanMap[ChannelPlan].Index5G; + + for (index = 0; index < CH_LIST_LEN(RTW_ChannelPlan5G[Index5G]); index++) { + if (rtw_regsty_is_excl_chs(regsty, CH_LIST_CH(RTW_ChannelPlan5G[Index5G], index)) == _TRUE) + continue; +#ifdef CONFIG_DFS + channel_set[chanset_size].ChannelNum = CH_LIST_CH(RTW_ChannelPlan5G[Index5G], index); + if (channel_set[chanset_size].ChannelNum <= 48 + || channel_set[chanset_size].ChannelNum >= 149 + ) { + if (RTW_CHPLAN_WORLD_WIDE_5G == ChannelPlan) /* passive scan for all 5G channels */ + channel_set[chanset_size].ScanType = SCAN_PASSIVE; + else + channel_set[chanset_size].ScanType = SCAN_ACTIVE; + } else + channel_set[chanset_size].ScanType = SCAN_PASSIVE; + chanset_size++; +#else /* CONFIG_DFS */ + if (CH_LIST_CH(RTW_ChannelPlan5G[Index5G], index) <= 48 + || CH_LIST_CH(RTW_ChannelPlan5G[Index5G], index) >= 149 + ) { + channel_set[chanset_size].ChannelNum = CH_LIST_CH(RTW_ChannelPlan5G[Index5G], index); + if (RTW_CHPLAN_WORLD_WIDE_5G == ChannelPlan) /* passive scan for all 5G channels */ + channel_set[chanset_size].ScanType = SCAN_PASSIVE; + else + channel_set[chanset_size].ScanType = SCAN_ACTIVE; + chanset_size++; + } +#endif /* CONFIG_DFS */ + } + } + + #ifdef CONFIG_DFS_MASTER + for (i = 0; i < chanset_size; i++) + channel_set[i].non_ocp_end_time = rtw_get_current_time(); + #endif +#endif /* CONFIG_IEEE80211_BAND_5GHZ */ + + if (RTW_CHPLAN_REALTEK_DEFINE == ChannelPlan) { + hal_data->Regulation2_4G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.regd; + hal_data->Regulation5G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.regd; + } else { + hal_data->Regulation2_4G = RTW_ChannelPlanMap[ChannelPlan].regd; + hal_data->Regulation5G = RTW_ChannelPlanMap[ChannelPlan].regd; + } + + RTW_INFO(FUNC_ADPT_FMT" ChannelPlan ID:0x%02x, ch num:%d\n" + , FUNC_ADPT_ARG(padapter), ChannelPlan, chanset_size); + + return chanset_size; +} + +int init_mlme_ext_priv(_adapter *padapter) +{ + int res = _SUCCESS; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + /* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */ + /* _rtw_memset((u8 *)pmlmeext, 0, sizeof(struct mlme_ext_priv)); */ + + pmlmeext->padapter = padapter; + + /* fill_fwpriv(padapter, &(pmlmeext->fwpriv)); */ + + init_mlme_ext_priv_value(padapter); + pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq; + + init_mlme_ext_timer(padapter); + +#ifdef CONFIG_AP_MODE + init_mlme_ap_info(padapter); +#endif + + pmlmeext->max_chan_nums = init_channel_set(padapter, pmlmepriv->ChannelPlan, pmlmeext->channel_set); + init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list); + pmlmeext->last_scan_time = 0; + pmlmeext->mlmeext_init = _TRUE; + + +#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK + pmlmeext->active_keep_alive_check = _TRUE; +#else + pmlmeext->active_keep_alive_check = _FALSE; +#endif + +#ifdef DBG_FIXED_CHAN + pmlmeext->fixed_chan = 0xFF; +#endif + + return res; + +} + +void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext) +{ + _adapter *padapter = pmlmeext->padapter; + + if (!padapter) + return; + + if (rtw_is_drv_stopped(padapter)) { + _cancel_timer_ex(&pmlmeext->survey_timer); + _cancel_timer_ex(&pmlmeext->link_timer); + /* _cancel_timer_ex(&pmlmeext->ADDBA_timer); */ + } +} + +static u8 cmp_pkt_chnl_diff(_adapter *padapter, u8 *pframe, uint packet_len) +{ + /* if the channel is same, return 0. else return channel differential */ + uint len; + u8 channel; + u8 *p; + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_, _DSSET_IE_, &len, packet_len - _BEACON_IE_OFFSET_); + if (p) { + channel = *(p + 2); + if (padapter->mlmeextpriv.cur_channel >= channel) + return padapter->mlmeextpriv.cur_channel - channel; + else + return channel - padapter->mlmeextpriv.cur_channel; + } else + return 0; +} + +static void _mgt_dispatcher(_adapter *padapter, struct mlme_handler *ptable, union recv_frame *precv_frame) +{ + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 *pframe = precv_frame->u.hdr.rx_data; + + if (ptable->func) { + /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ + if (!_rtw_memcmp(GetAddr1Ptr(pframe), adapter_mac_addr(padapter), ETH_ALEN) && + !_rtw_memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) + return; + + ptable->func(padapter, precv_frame); + } + +} + +void mgt_dispatcher(_adapter *padapter, union recv_frame *precv_frame) +{ + int index; + struct mlme_handler *ptable; +#ifdef CONFIG_AP_MODE + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +#endif /* CONFIG_AP_MODE */ + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 *pframe = precv_frame->u.hdr.rx_data; + struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, get_addr2_ptr(pframe)); + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; + + +#if 0 + { + u8 *pbuf; + pbuf = GetAddr1Ptr(pframe); + RTW_INFO("A1-%x:%x:%x:%x:%x:%x\n", *pbuf, *(pbuf + 1), *(pbuf + 2), *(pbuf + 3), *(pbuf + 4), *(pbuf + 5)); + pbuf = get_addr2_ptr(pframe); + RTW_INFO("A2-%x:%x:%x:%x:%x:%x\n", *pbuf, *(pbuf + 1), *(pbuf + 2), *(pbuf + 3), *(pbuf + 4), *(pbuf + 5)); + pbuf = GetAddr3Ptr(pframe); + RTW_INFO("A3-%x:%x:%x:%x:%x:%x\n", *pbuf, *(pbuf + 1), *(pbuf + 2), *(pbuf + 3), *(pbuf + 4), *(pbuf + 5)); + } +#endif + + if (GetFrameType(pframe) != WIFI_MGT_TYPE) { + return; + } + + /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ + if (!_rtw_memcmp(GetAddr1Ptr(pframe), adapter_mac_addr(padapter), ETH_ALEN) && + !_rtw_memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) + return; + + ptable = mlme_sta_tbl; + + index = get_frame_sub_type(pframe) >> 4; + +#ifdef CONFIG_TDLS + if ((index << 4) == WIFI_ACTION) { + /* category==public (4), action==TDLS_DISCOVERY_RESPONSE */ + if (*(pframe + 24) == RTW_WLAN_CATEGORY_PUBLIC && *(pframe + 25) == TDLS_DISCOVERY_RESPONSE) { + RTW_INFO("[TDLS] Recv %s from "MAC_FMT"\n", rtw_tdls_action_txt(TDLS_DISCOVERY_RESPONSE), MAC_ARG(get_addr2_ptr(pframe))); + On_TDLS_Dis_Rsp(padapter, precv_frame); + } + } +#endif /* CONFIG_TDLS */ + + if (index >= (sizeof(mlme_sta_tbl) / sizeof(struct mlme_handler))) { + return; + } + ptable += index; + +#if 1 + if (psta != NULL) { + if (GetRetry(pframe)) { + if (precv_frame->u.hdr.attrib.seq_num == psta->RxMgmtFrameSeqNum) { + /* drop the duplicate management frame */ + pdbgpriv->dbg_rx_dup_mgt_frame_drop_count++; + RTW_INFO("Drop duplicate management frame with seq_num = %d.\n", precv_frame->u.hdr.attrib.seq_num); + return; + } + } + psta->RxMgmtFrameSeqNum = precv_frame->u.hdr.attrib.seq_num; + } +#else + + if (GetRetry(pframe)) { + /* return; */ + } +#endif + +#ifdef CONFIG_AP_MODE + switch (get_frame_sub_type(pframe)) { + case WIFI_AUTH: + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) + ptable->func = &OnAuth; + else + ptable->func = &OnAuthClient; + /* pass through */ + case WIFI_ASSOCREQ: + case WIFI_REASSOCREQ: + _mgt_dispatcher(padapter, ptable, precv_frame); +#ifdef CONFIG_HOSTAPD_MLME + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) + rtw_hostapd_mlme_rx(padapter, precv_frame); +#endif + break; + case WIFI_PROBEREQ: + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { +#ifdef CONFIG_HOSTAPD_MLME + rtw_hostapd_mlme_rx(padapter, precv_frame); +#else + _mgt_dispatcher(padapter, ptable, precv_frame); +#endif + } else + _mgt_dispatcher(padapter, ptable, precv_frame); + break; + case WIFI_BEACON: + _mgt_dispatcher(padapter, ptable, precv_frame); + break; + case WIFI_ACTION: + /* if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) */ + _mgt_dispatcher(padapter, ptable, precv_frame); + break; + default: + _mgt_dispatcher(padapter, ptable, precv_frame); + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) + rtw_hostapd_mlme_rx(padapter, precv_frame); + break; + } +#else + + _mgt_dispatcher(padapter, ptable, precv_frame); + +#endif + +} + +#ifdef CONFIG_P2P +u32 p2p_listen_state_process(_adapter *padapter, unsigned char *da) +{ + bool response = _TRUE; + +#ifdef CONFIG_IOCTL_CFG80211 + if (padapter->wdinfo.driver_interface == DRIVER_CFG80211) { + if (rtw_cfg80211_get_is_roch(padapter) == _FALSE + || rtw_get_oper_ch(padapter) != padapter->wdinfo.listen_channel + || adapter_wdev_data(padapter)->p2p_enabled == _FALSE + || padapter->mlmepriv.wps_probe_resp_ie == NULL + || padapter->mlmepriv.p2p_probe_resp_ie == NULL + ) { +#ifdef CONFIG_DEBUG_CFG80211 + RTW_INFO(ADPT_FMT" DON'T issue_probersp_p2p: p2p_enabled:%d, wps_probe_resp_ie:%p, p2p_probe_resp_ie:%p\n" + , ADPT_ARG(padapter) + , adapter_wdev_data(padapter)->p2p_enabled + , padapter->mlmepriv.wps_probe_resp_ie + , padapter->mlmepriv.p2p_probe_resp_ie); + RTW_INFO(ADPT_FMT" DON'T issue_probersp_p2p: is_ro_ch:%d, op_ch:%d, p2p_listen_channel:%d\n" + , ADPT_ARG(padapter) + , rtw_cfg80211_get_is_roch(padapter) + , rtw_get_oper_ch(padapter) + , padapter->wdinfo.listen_channel); +#endif + response = _FALSE; + } + } else +#endif /* CONFIG_IOCTL_CFG80211 */ + if (padapter->wdinfo.driver_interface == DRIVER_WEXT) { + /* do nothing if the device name is empty */ + if (!padapter->wdinfo.device_name_len) + response = _FALSE; + } + + if (response == _TRUE) + issue_probersp_p2p(padapter, da); + + return _SUCCESS; +} +#endif /* CONFIG_P2P */ + + +/**************************************************************************** + +Following are the callback functions for each subtype of the management frames + +*****************************************************************************/ + +unsigned int OnProbeReq(_adapter *padapter, union recv_frame *precv_frame) +{ + unsigned int ielen; + unsigned char *p; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *cur = &(pmlmeinfo->network); + u8 *pframe = precv_frame->u.hdr.rx_data; + uint len = precv_frame->u.hdr.len; + u8 is_valid_p2p_probereq = _FALSE; + +#ifdef CONFIG_ATMEL_RC_PATCH + u8 *target_ie = NULL, *wps_ie = NULL; + u8 *start; + uint search_len = 0, wps_ielen = 0, target_ielen = 0; + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; +#endif + + +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + u8 wifi_test_chk_rate = 1; + +#ifdef CONFIG_IOCTL_CFG80211 + if ((pwdinfo->driver_interface == DRIVER_CFG80211) + && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) + && (GET_CFG80211_REPORT_MGMT(adapter_wdev_data(padapter), IEEE80211_STYPE_PROBE_REQ) == _TRUE) + ) { + rtw_cfg80211_rx_probe_request(padapter, precv_frame); + return _SUCCESS; + } +#endif /* CONFIG_IOCTL_CFG80211 */ + + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && + !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE) && + !rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) && + !rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) && + !rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) + ) { + /* Commented by Albert 2011/03/17 */ + /* mcs_rate = 0->CCK 1M rate */ + /* mcs_rate = 1->CCK 2M rate */ + /* mcs_rate = 2->CCK 5.5M rate */ + /* mcs_rate = 3->CCK 11M rate */ + /* In the P2P mode, the driver should not support the CCK rate */ + + /* Commented by Kurt 2012/10/16 */ + /* IOT issue: Google Nexus7 use 1M rate to send p2p_probe_req after GO nego completed and Nexus7 is client */ + if (padapter->registrypriv.wifi_spec == 1) { + if (pattrib->data_rate <= 3) + wifi_test_chk_rate = 0; + } + + if (wifi_test_chk_rate == 1) { + is_valid_p2p_probereq = process_probe_req_p2p_ie(pwdinfo, pframe, len); + if (is_valid_p2p_probereq == _TRUE) { + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) { + /* FIXME */ + if (padapter->wdinfo.driver_interface == DRIVER_WEXT) + report_survey_event(padapter, precv_frame); + + p2p_listen_state_process(padapter, get_sa(pframe)); + + return _SUCCESS; + } + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + goto _continue; + } + } + } + +_continue: +#endif /* CONFIG_P2P */ + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) + return _SUCCESS; + + if (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE && + check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE) == _FALSE) + return _SUCCESS; + + + /* RTW_INFO("+OnProbeReq\n"); */ + + +#ifdef CONFIG_ATMEL_RC_PATCH + wps_ie = rtw_get_wps_ie( + pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, + len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_, + NULL, &wps_ielen); + if (wps_ie) + target_ie = rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_MANUFACTURER, NULL, &target_ielen); + if ((target_ie && (target_ielen == 4)) && (_TRUE == _rtw_memcmp((void *)target_ie, "Ozmo", 4))) { + /* psta->flag_atmel_rc = 1; */ + unsigned char *sa_addr = get_sa(pframe); + printk("%s: Find Ozmo RC -- %02x:%02x:%02x:%02x:%02x:%02x \n\n", + __func__, *sa_addr, *(sa_addr + 1), *(sa_addr + 2), *(sa_addr + 3), *(sa_addr + 4), *(sa_addr + 5)); + _rtw_memcpy(pstapriv->atmel_rc_pattern, get_sa(pframe), ETH_ALEN); + } +#endif + + +#ifdef CONFIG_AUTO_AP_MODE + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE && + pmlmepriv->cur_network.join_res == _TRUE) { + _irqL irqL; + struct sta_info *psta; + u8 *mac_addr, *peer_addr; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 RC_OUI[4] = {0x00, 0xE0, 0x4C, 0x0A}; + /* EID[1] + EID_LEN[1] + RC_OUI[4] + MAC[6] + PairingID[2] + ChannelNum[2] */ + + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, (int *)&ielen, + len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); + + if (!p || ielen != 14) + goto _non_rc_device; + + if (!_rtw_memcmp(p + 2, RC_OUI, sizeof(RC_OUI))) + goto _non_rc_device; + + if (!_rtw_memcmp(p + 6, get_sa(pframe), ETH_ALEN)) { + RTW_INFO("%s, do rc pairing ("MAC_FMT"), but mac addr mismatch!("MAC_FMT")\n", __FUNCTION__, + MAC_ARG(get_sa(pframe)), MAC_ARG(p + 6)); + + goto _non_rc_device; + } + + RTW_INFO("%s, got the pairing device("MAC_FMT")\n", __FUNCTION__, MAC_ARG(get_sa(pframe))); + + /* new a station */ + psta = rtw_get_stainfo(pstapriv, get_sa(pframe)); + if (psta == NULL) { + /* allocate a new one */ + RTW_INFO("going to alloc stainfo for rc="MAC_FMT"\n", MAC_ARG(get_sa(pframe))); + psta = rtw_alloc_stainfo(pstapriv, get_sa(pframe)); + if (psta == NULL) { + /* TODO: */ + RTW_INFO(" Exceed the upper limit of supported clients...\n"); + return _SUCCESS; + } + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + if (rtw_is_list_empty(&psta->asoc_list)) { + psta->expire_to = pstapriv->expire_to; + rtw_list_insert_tail(&psta->asoc_list, &pstapriv->asoc_list); + pstapriv->asoc_list_cnt++; + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + /* generate pairing ID */ + mac_addr = adapter_mac_addr(padapter); + peer_addr = psta->hwaddr; + psta->pid = (u16)(((mac_addr[4] << 8) + mac_addr[5]) + ((peer_addr[4] << 8) + peer_addr[5])); + + /* update peer stainfo */ + psta->isrc = _TRUE; + + /* get a unique AID */ + if (psta->aid > 0) + RTW_INFO("old AID %d\n", psta->aid); + else { + for (psta->aid = 1; psta->aid <= NUM_STA; psta->aid++) + if (pstapriv->sta_aid[psta->aid - 1] == NULL) + break; + + if (psta->aid > pstapriv->max_num_sta) { + psta->aid = 0; + RTW_INFO("no room for more AIDs\n"); + return _SUCCESS; + } else { + pstapriv->sta_aid[psta->aid - 1] = psta; + RTW_INFO("allocate new AID = (%d)\n", psta->aid); + } + } + + psta->qos_option = 1; + psta->bw_mode = CHANNEL_WIDTH_20; + psta->ieee8021x_blocked = _FALSE; +#ifdef CONFIG_80211N_HT + psta->htpriv.ht_option = _TRUE; + psta->htpriv.ampdu_enable = _FALSE; + psta->htpriv.sgi_20m = _FALSE; + psta->htpriv.sgi_40m = _FALSE; + psta->htpriv.ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ + psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ +#endif + + rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, _TRUE); + + _rtw_memset((void *)&psta->sta_stats, 0, sizeof(struct stainfo_stats)); + + _enter_critical_bh(&psta->lock, &irqL); + psta->state |= _FW_LINKED; + _exit_critical_bh(&psta->lock, &irqL); + + report_add_sta_event(padapter, psta->hwaddr); + + } + + issue_probersp(padapter, get_sa(pframe), _FALSE); + + return _SUCCESS; + + } + +_non_rc_device: + + return _SUCCESS; + +#endif /* CONFIG_AUTO_AP_MODE */ + + +#ifdef CONFIG_CONCURRENT_MODE + if (((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) && + rtw_mi_buddy_check_fwstate(padapter, _FW_UNDER_LINKING | _FW_UNDER_SURVEY)) { + /* don't process probe req */ + return _SUCCESS; + } +#endif + + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ielen, + len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); + + + /* check (wildcard) SSID */ + if (p != NULL) { + if (is_valid_p2p_probereq == _TRUE) + goto _issue_probersp; + + if ((ielen != 0 && _FALSE == _rtw_memcmp((void *)(p + 2), (void *)cur->Ssid.Ssid, cur->Ssid.SsidLength)) + || (ielen == 0 && pmlmeinfo->hidden_ssid_mode) + ) + return _SUCCESS; + +_issue_probersp: + if (((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE && + pmlmepriv->cur_network.join_res == _TRUE)) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { + /* RTW_INFO("+issue_probersp during ap mode\n"); */ + issue_probersp(padapter, get_sa(pframe), is_valid_p2p_probereq); + } + + } + + return _SUCCESS; + +} + +unsigned int OnProbeRsp(_adapter *padapter, union recv_frame *precv_frame) +{ + struct sta_info *psta; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *pframe = precv_frame->u.hdr.rx_data; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif + + +#ifdef CONFIG_P2P + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) { + if (_TRUE == pwdinfo->tx_prov_disc_info.benable) { + if (_rtw_memcmp(pwdinfo->tx_prov_disc_info.peerIFAddr, get_addr2_ptr(pframe), ETH_ALEN)) { + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { + pwdinfo->tx_prov_disc_info.benable = _FALSE; + issue_p2p_provision_request(padapter, + pwdinfo->tx_prov_disc_info.ssid.Ssid, + pwdinfo->tx_prov_disc_info.ssid.SsidLength, + pwdinfo->tx_prov_disc_info.peerDevAddr); + } else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + pwdinfo->tx_prov_disc_info.benable = _FALSE; + issue_p2p_provision_request(padapter, + NULL, + 0, + pwdinfo->tx_prov_disc_info.peerDevAddr); + } + } + } + return _SUCCESS; + } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) { + if (_TRUE == pwdinfo->nego_req_info.benable) { + RTW_INFO("[%s] P2P State is GONEGO ING!\n", __FUNCTION__); + if (_rtw_memcmp(pwdinfo->nego_req_info.peerDevAddr, get_addr2_ptr(pframe), ETH_ALEN)) { + pwdinfo->nego_req_info.benable = _FALSE; + issue_p2p_GO_request(padapter, pwdinfo->nego_req_info.peerDevAddr); + } + } + } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) { + if (_TRUE == pwdinfo->invitereq_info.benable) { + RTW_INFO("[%s] P2P_STATE_TX_INVITE_REQ!\n", __FUNCTION__); + if (_rtw_memcmp(pwdinfo->invitereq_info.peer_macaddr, get_addr2_ptr(pframe), ETH_ALEN)) { + pwdinfo->invitereq_info.benable = _FALSE; + issue_p2p_invitation_request(padapter, pwdinfo->invitereq_info.peer_macaddr); + } + } + } +#endif + + + if (mlmeext_chk_scan_state(pmlmeext, SCAN_PROCESS)) { + rtw_mi_report_survey_event(padapter, precv_frame); + return _SUCCESS; + } + +#if 0 /* move to validate_recv_mgnt_frame */ + if (_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) { + if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { + psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe)); + if (psta != NULL) + psta->sta_stats.rx_mgnt_pkts++; + } + } +#endif + + return _SUCCESS; + +} + +/* for 11n Logo 4.2.31/4.2.32 */ +static void rtw_check_legacy_ap(_adapter *padapter, u8 *pframe, u32 len) +{ + + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (!padapter->registrypriv.wifi_spec) + return; + + if(!MLME_IS_AP(padapter)) + return; + + + if (pmlmeext->bstart_bss == _TRUE) { + int left; + u16 capability; + unsigned char *pos; + struct rtw_ieee802_11_elems elems; + struct HT_info_element *pht_info = NULL; + u16 cur_op_mode; + + /* checking IEs */ + left = len - sizeof(struct rtw_ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_; + pos = pframe + sizeof(struct rtw_ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_; + if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) { + RTW_INFO("%s: parse fail for "MAC_FMT"\n", __func__, MAC_ARG(GetAddr3Ptr(pframe))); + return; + } + + cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK; + + /* for legacy ap */ + if (elems.ht_capabilities == NULL && elems.ht_capabilities_len == 0) { + + if (0) + RTW_INFO("%s: "MAC_FMT" is legacy ap\n", __func__, MAC_ARG(GetAddr3Ptr(pframe))); + + ATOMIC_SET(&pmlmepriv->olbc, _TRUE); + ATOMIC_SET(&pmlmepriv->olbc_ht, _TRUE); + } + + } +} + +unsigned int OnBeacon(_adapter *padapter, union recv_frame *precv_frame) +{ + struct sta_info *psta; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *pframe = precv_frame->u.hdr.rx_data; + uint len = precv_frame->u.hdr.len; + WLAN_BSSID_EX *pbss; + int ret = _SUCCESS; + u8 *p = NULL; + u32 ielen = 0; +#ifdef CONFIG_TDLS + struct sta_info *ptdls_sta; + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; +#ifdef CONFIG_TDLS_CH_SW + struct tdls_ch_switch *pchsw_info = &padapter->tdlsinfo.chsw_info; +#endif +#endif /* CONFIG_TDLS */ + + if (validate_beacon_len(pframe, len) == _FALSE) + return _SUCCESS; +#ifdef CONFIG_ATTEMPT_TO_FIX_AP_BEACON_ERROR + p = rtw_get_ie(pframe + sizeof(struct rtw_ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ielen, + precv_frame->u.hdr.len - sizeof(struct rtw_ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_); + if ((p != NULL) && (ielen > 0)) { + if ((*(p + 1 + ielen) == 0x2D) && (*(p + 2 + ielen) != 0x2D)) { + /* Invalid value 0x2D is detected in Extended Supported Rates (ESR) IE. Try to fix the IE length to avoid failed Beacon parsing. */ + RTW_INFO("[WIFIDBG] Error in ESR IE is detected in Beacon of BSSID:"MAC_FMT". Fix the length of ESR IE to avoid failed Beacon parsing.\n", MAC_ARG(GetAddr3Ptr(pframe))); + *(p + 1) = ielen - 1; + } + } +#endif + + if (mlmeext_chk_scan_state(pmlmeext, SCAN_PROCESS)) { + rtw_mi_report_survey_event(padapter, precv_frame); + return _SUCCESS; + } + + + rtw_check_legacy_ap(padapter, pframe, len); + + if (_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) { + if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { + /* we should update current network before auth, or some IE is wrong */ + pbss = (WLAN_BSSID_EX *)rtw_malloc(sizeof(WLAN_BSSID_EX)); + if (pbss) { + if (collect_bss_info(padapter, precv_frame, pbss) == _SUCCESS) { + struct beacon_keys recv_beacon; + + update_network(&(pmlmepriv->cur_network.network), pbss, padapter, _TRUE); + rtw_get_bcn_info(&(pmlmepriv->cur_network)); + + /* update bcn keys */ + if (rtw_get_bcn_keys(padapter, pframe, len, &recv_beacon) == _TRUE) { + RTW_INFO("%s: beacon keys ready\n", __func__); + _rtw_memcpy(&pmlmepriv->cur_beacon_keys, + &recv_beacon, sizeof(recv_beacon)); + pmlmepriv->new_beacon_cnts = 0; + } else { + RTW_ERR("%s: get beacon keys failed\n", __func__); + _rtw_memset(&pmlmepriv->cur_beacon_keys, 0, sizeof(recv_beacon)); + pmlmepriv->new_beacon_cnts = 0; + } + } + rtw_mfree((u8 *)pbss, sizeof(WLAN_BSSID_EX)); + } + + /* check the vendor of the assoc AP */ + pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pframe + sizeof(struct rtw_ieee80211_hdr_3addr), len - sizeof(struct rtw_ieee80211_hdr_3addr)); + + /* update TSF Value */ + update_TSF(pmlmeext, pframe, len); + + /* reset for adaptive_early_32k */ + pmlmeext->adaptive_tsf_done = _FALSE; + pmlmeext->DrvBcnEarly = 0xff; + pmlmeext->DrvBcnTimeOut = 0xff; + pmlmeext->bcn_cnt = 0; + _rtw_memset(pmlmeext->bcn_delay_cnt, 0, sizeof(pmlmeext->bcn_delay_cnt)); + _rtw_memset(pmlmeext->bcn_delay_ratio, 0, sizeof(pmlmeext->bcn_delay_ratio)); + +#ifdef CONFIG_P2P_PS + process_p2p_ps_ie(padapter, (pframe + WLAN_HDR_A3_LEN), (len - WLAN_HDR_A3_LEN)); +#endif /* CONFIG_P2P_PS */ + +#if defined(CONFIG_P2P) && defined(CONFIG_CONCURRENT_MODE) + if (padapter->registrypriv.wifi_spec) { + if (process_p2p_cross_connect_ie(padapter, (pframe + WLAN_HDR_A3_LEN), (len - WLAN_HDR_A3_LEN)) == _FALSE) { + if (rtw_mi_buddy_check_mlmeinfo_state(padapter, WIFI_FW_AP_STATE)) { + RTW_PRINT("no issue auth, P2P cross-connect does not permit\n "); + return _SUCCESS; + } + } + } +#endif /* CONFIG_P2P CONFIG_P2P and CONFIG_CONCURRENT_MODE */ + + /* start auth */ + start_clnt_auth(padapter); + + return _SUCCESS; + } + + if (((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) && (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { + psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe)); + if (psta != NULL) { +#ifdef CONFIG_PATCH_JOIN_WRONG_CHANNEL + /* Merge from 8712 FW code */ + if (cmp_pkt_chnl_diff(padapter, pframe, len) != 0) { + /* join wrong channel, deauth and reconnect */ + issue_deauth(padapter, (&(pmlmeinfo->network))->MacAddress, WLAN_REASON_DEAUTH_LEAVING); + + report_del_sta_event(padapter, (&(pmlmeinfo->network))->MacAddress, WLAN_REASON_JOIN_WRONG_CHANNEL, _TRUE, _FALSE); + pmlmeinfo->state &= (~WIFI_FW_ASSOC_SUCCESS); + return _SUCCESS; + } +#endif /* CONFIG_PATCH_JOIN_WRONG_CHANNEL */ + + ret = rtw_check_bcn_info(padapter, pframe, len); + if (!ret) { + RTW_PRINT("ap has changed, disconnect now\n "); + receive_disconnect(padapter, pmlmeinfo->network.MacAddress , 0, _FALSE); + return _SUCCESS; + } + /* update WMM, ERP in the beacon */ + /* todo: the timer is used instead of the number of the beacon received */ + if ((sta_rx_pkts(psta) & 0xf) == 0) { + /* RTW_INFO("update_bcn_info\n"); */ + update_beacon_info(padapter, pframe, len, psta); + } + + pmlmepriv->cur_network_scanned->network.Rssi = precv_frame->u.hdr.attrib.phy_info.RecvSignalPower; + + adaptive_early_32k(pmlmeext, pframe, len); + +#ifdef CONFIG_TDLS +#ifdef CONFIG_TDLS_CH_SW + if (rtw_tdls_is_chsw_allowed(padapter) == _TRUE) { + /* Send TDLS Channel Switch Request when receiving Beacon */ + if ((padapter->tdlsinfo.chsw_info.ch_sw_state & TDLS_CH_SW_INITIATOR_STATE) && (ATOMIC_READ(&pchsw_info->chsw_on) == _TRUE) + && (pmlmeext->cur_channel == rtw_get_oper_ch(padapter))) { + ptdls_sta = rtw_get_stainfo(&padapter->stapriv, padapter->tdlsinfo.chsw_info.addr); + if (ptdls_sta != NULL) { + if (ptdls_sta->tdls_sta_state | TDLS_LINKED_STATE) + _set_timer(&ptdls_sta->stay_on_base_chnl_timer, TDLS_CH_SW_STAY_ON_BASE_CHNL_TIMEOUT); + } + } + } +#endif +#endif /* CONFIG_TDLS */ + +#ifdef CONFIG_DFS + process_csa_ie(padapter, pframe, len); /* channel switch announcement */ +#endif /* CONFIG_DFS */ + +#ifdef CONFIG_P2P_PS + process_p2p_ps_ie(padapter, (pframe + WLAN_HDR_A3_LEN), (len - WLAN_HDR_A3_LEN)); +#endif /* CONFIG_P2P_PS */ + + if (pmlmeext->en_hw_update_tsf) + rtw_enable_hw_update_tsf_cmd(padapter); + +#if 0 /* move to validate_recv_mgnt_frame */ + psta->sta_stats.rx_mgnt_pkts++; +#endif + } + + } else if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { + _irqL irqL; + u8 rate_set[16]; + u8 rate_num = 0; + + psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe)); + if (psta != NULL) { + /* + * update WMM, ERP in the beacon + * todo: the timer is used instead of the number of the beacon received + */ + if ((sta_rx_pkts(psta) & 0xf) == 0) + update_beacon_info(padapter, pframe, len, psta); + + if (pmlmeext->en_hw_update_tsf) + rtw_enable_hw_update_tsf_cmd(padapter); + } else { + rtw_ies_get_supported_rate(pframe + WLAN_HDR_A3_LEN + _BEACON_IE_OFFSET_, len - WLAN_HDR_A3_LEN - _BEACON_IE_OFFSET_, rate_set, &rate_num); + if (rate_num == 0) { + RTW_INFO(FUNC_ADPT_FMT" RX beacon with no supported rate\n", FUNC_ADPT_ARG(padapter)); + goto _END_ONBEACON_; + } + + psta = rtw_alloc_stainfo(pstapriv, get_addr2_ptr(pframe)); + if (psta == NULL) { + RTW_INFO(FUNC_ADPT_FMT" Exceed the upper limit of supported clients\n", FUNC_ADPT_ARG(padapter)); + goto _END_ONBEACON_; + } + + psta->expire_to = pstapriv->adhoc_expire_to; + + _rtw_memcpy(psta->bssrateset, rate_set, rate_num); + psta->bssratelen = rate_num; + + /* update TSF Value */ + update_TSF(pmlmeext, pframe, len); + + /* report sta add event */ + report_add_sta_event(padapter, get_addr2_ptr(pframe)); + } + } + } + +_END_ONBEACON_: + + return _SUCCESS; + +} + +unsigned int OnAuth(_adapter *padapter, union recv_frame *precv_frame) +{ +#ifdef CONFIG_AP_MODE + _irqL irqL; + unsigned int auth_mode, seq, ie_len; + unsigned char *sa, *p; + u16 algorithm; + int status; + static struct sta_info stat; + struct sta_info *pstat = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 *pframe = precv_frame->u.hdr.rx_data; + uint len = precv_frame->u.hdr.len; + u8 offset = 0; + + +#ifdef CONFIG_CONCURRENT_MODE + if (((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) && + rtw_mi_buddy_check_fwstate(padapter, _FW_UNDER_LINKING | _FW_UNDER_SURVEY)) { + /* don't process auth request; */ + return _SUCCESS; + } +#endif /* CONFIG_CONCURRENT_MODE */ + + if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) + return _FAIL; + + RTW_INFO("+OnAuth\n"); + + sa = get_addr2_ptr(pframe); + + auth_mode = psecuritypriv->dot11AuthAlgrthm; + + if (GetPrivacy(pframe)) { + u8 *iv; + struct rx_pkt_attrib *prxattrib = &(precv_frame->u.hdr.attrib); + + prxattrib->hdrlen = WLAN_HDR_A3_LEN; + prxattrib->encrypt = _WEP40_; + + iv = pframe + prxattrib->hdrlen; + prxattrib->key_index = ((iv[3] >> 6) & 0x3); + + prxattrib->iv_len = 4; + prxattrib->icv_len = 4; + + rtw_wep_decrypt(padapter, (u8 *)precv_frame); + + offset = 4; + } + + algorithm = le16_to_cpu(*(u16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset)); + seq = le16_to_cpu(*(u16 *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 2)); + + RTW_INFO("auth alg=%x, seq=%X\n", algorithm, seq); + + if (auth_mode == 2 && + psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ && + psecuritypriv->dot11PrivacyAlgrthm != _WEP104_) + auth_mode = 0; + + if ((algorithm > 0 && auth_mode == 0) || /* rx a shared-key auth but shared not enabled */ + (algorithm == 0 && auth_mode == 1)) { /* rx a open-system auth but shared-key is enabled */ + RTW_INFO("auth rejected due to bad alg [alg=%d, auth_mib=%d] %02X%02X%02X%02X%02X%02X\n", + algorithm, auth_mode, sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]); + + status = _STATS_NO_SUPP_ALG_; + + goto auth_fail; + } + +#if CONFIG_RTW_MACADDR_ACL + if (rtw_access_ctrl(padapter, sa) == _FALSE) { + status = _STATS_UNABLE_HANDLE_STA_; + goto auth_fail; + } +#endif + + pstat = rtw_get_stainfo(pstapriv, sa); + if (pstat == NULL) { + + /* allocate a new one */ + RTW_INFO("going to alloc stainfo for sa="MAC_FMT"\n", MAC_ARG(sa)); + pstat = rtw_alloc_stainfo(pstapriv, sa); + if (pstat == NULL) { + RTW_INFO(" Exceed the upper limit of supported clients...\n"); + status = _STATS_UNABLE_HANDLE_STA_; + goto auth_fail; + } + + pstat->state = WIFI_FW_AUTH_NULL; + pstat->auth_seq = 0; + + /* pstat->flags = 0; */ + /* pstat->capability = 0; */ + } else { +#ifdef CONFIG_IEEE80211W + if (pstat->bpairwise_key_installed != _TRUE && !(pstat->state & WIFI_FW_ASSOC_SUCCESS)) +#endif /* CONFIG_IEEE80211W */ + { + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + if (rtw_is_list_empty(&pstat->asoc_list) == _FALSE) { + rtw_list_delete(&pstat->asoc_list); + pstapriv->asoc_list_cnt--; + if (pstat->expire_to > 0) + ;/* TODO: STA re_auth within expire_to */ + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + if (seq == 1) + ; /* TODO: STA re_auth and auth timeout */ + + } + } + +#ifdef CONFIG_IEEE80211W + if (pstat->bpairwise_key_installed != _TRUE && !(pstat->state & WIFI_FW_ASSOC_SUCCESS)) +#endif /* CONFIG_IEEE80211W */ + { + _enter_critical_bh(&pstapriv->auth_list_lock, &irqL); + if (rtw_is_list_empty(&pstat->auth_list)) { + + rtw_list_insert_tail(&pstat->auth_list, &pstapriv->auth_list); + pstapriv->auth_list_cnt++; + } + _exit_critical_bh(&pstapriv->auth_list_lock, &irqL); + } + + if (pstat->auth_seq == 0) + pstat->expire_to = pstapriv->auth_to; + + + if ((pstat->auth_seq + 1) != seq) { + RTW_INFO("(1)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", + seq, pstat->auth_seq + 1); + status = _STATS_OUT_OF_AUTH_SEQ_; + goto auth_fail; + } + + if (algorithm == 0 && (auth_mode == 0 || auth_mode == 2 || auth_mode == 3)) { + if (seq == 1) { +#ifdef CONFIG_IEEE80211W + if (pstat->bpairwise_key_installed != _TRUE && !(pstat->state & WIFI_FW_ASSOC_SUCCESS)) +#endif /* CONFIG_IEEE80211W */ + { + pstat->state &= ~WIFI_FW_AUTH_NULL; + pstat->state |= WIFI_FW_AUTH_SUCCESS; + pstat->expire_to = pstapriv->assoc_to; + } + pstat->authalg = algorithm; + } else { + RTW_INFO("(2)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", + seq, pstat->auth_seq + 1); + status = _STATS_OUT_OF_AUTH_SEQ_; + goto auth_fail; + } + } else { /* shared system or auto authentication */ + if (seq == 1) { + /* prepare for the challenging txt... */ + + /* get_random_bytes((void *)pstat->chg_txt, 128); */ /* TODO: */ + _rtw_memset((void *)pstat->chg_txt, 78, 128); +#ifdef CONFIG_IEEE80211W + if (pstat->bpairwise_key_installed != _TRUE && !(pstat->state & WIFI_FW_ASSOC_SUCCESS)) +#endif /* CONFIG_IEEE80211W */ + { + pstat->state &= ~WIFI_FW_AUTH_NULL; + pstat->state |= WIFI_FW_AUTH_STATE; + } + pstat->authalg = algorithm; + pstat->auth_seq = 2; + } else if (seq == 3) { + /* checking for challenging txt... */ + RTW_INFO("checking for challenging txt...\n"); + + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + 4 + _AUTH_IE_OFFSET_ , _CHLGETXT_IE_, (int *)&ie_len, + len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_ - 4); + + if ((p == NULL) || (ie_len <= 0)) { + RTW_INFO("auth rejected because challenge failure!(1)\n"); + status = _STATS_CHALLENGE_FAIL_; + goto auth_fail; + } + + if (_rtw_memcmp((void *)(p + 2), pstat->chg_txt, 128)) { +#ifdef CONFIG_IEEE80211W + if (pstat->bpairwise_key_installed != _TRUE && !(pstat->state & WIFI_FW_ASSOC_SUCCESS)) +#endif /* CONFIG_IEEE80211W */ + { + pstat->state &= (~WIFI_FW_AUTH_STATE); + pstat->state |= WIFI_FW_AUTH_SUCCESS; + /* challenging txt is correct... */ + pstat->expire_to = pstapriv->assoc_to; + } + } else { + RTW_INFO("auth rejected because challenge failure!\n"); + status = _STATS_CHALLENGE_FAIL_; + goto auth_fail; + } + } else { + RTW_INFO("(3)auth rejected because out of seq [rx_seq=%d, exp_seq=%d]!\n", + seq, pstat->auth_seq + 1); + status = _STATS_OUT_OF_AUTH_SEQ_; + goto auth_fail; + } + } + + + /* Now, we are going to issue_auth... */ + pstat->auth_seq = seq + 1; + +#ifdef CONFIG_NATIVEAP_MLME + issue_auth(padapter, pstat, (unsigned short)(_STATS_SUCCESSFUL_)); +#endif + + if ((pstat->state & WIFI_FW_AUTH_SUCCESS) || (pstat->state & WIFI_FW_ASSOC_SUCCESS)) + pstat->auth_seq = 0; + + + return _SUCCESS; + +auth_fail: + + if (pstat) + rtw_free_stainfo(padapter , pstat); + + pstat = &stat; + _rtw_memset((char *)pstat, '\0', sizeof(stat)); + pstat->auth_seq = 2; + _rtw_memcpy(pstat->hwaddr, sa, 6); + +#ifdef CONFIG_NATIVEAP_MLME + issue_auth(padapter, pstat, (unsigned short)status); +#endif + +#endif + return _FAIL; + +} + +unsigned int OnAuthClient(_adapter *padapter, union recv_frame *precv_frame) +{ + unsigned int seq, len, status, algthm, offset; + unsigned char *p; + unsigned int go2asoc = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); +#ifdef CONFIG_RTW_80211R + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + ft_priv *pftpriv = &pmlmepriv->ftpriv; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta = NULL; +#endif + u8 *pframe = precv_frame->u.hdr.rx_data; + uint pkt_len = precv_frame->u.hdr.len; + + RTW_INFO("%s\n", __FUNCTION__); + + /* check A1 matches or not */ + if (!_rtw_memcmp(adapter_mac_addr(padapter), get_da(pframe), ETH_ALEN)) + return _SUCCESS; + + if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE)) + return _SUCCESS; + + offset = (GetPrivacy(pframe)) ? 4 : 0; + + algthm = le16_to_cpu(*(unsigned short *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset)); + seq = le16_to_cpu(*(unsigned short *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 2)); + status = le16_to_cpu(*(unsigned short *)((SIZE_PTR)pframe + WLAN_HDR_A3_LEN + offset + 4)); + + if (status != 0) { + RTW_INFO("clnt auth fail, status: %d\n", status); + if (status == 13) { /* && pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */ + if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) + pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open; + else + pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; + /* pmlmeinfo->reauth_count = 0; */ + } + + set_link_timer(pmlmeext, 1); + goto authclnt_fail; + } + + if (seq == 2) { + if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) { + /* legendary shared system */ + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&len, + pkt_len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_); + + if (p == NULL) { + /* RTW_INFO("marc: no challenge text?\n"); */ + goto authclnt_fail; + } + + _rtw_memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len); + pmlmeinfo->auth_seq = 3; + issue_auth(padapter, NULL, 0); + set_link_timer(pmlmeext, REAUTH_TO); + + return _SUCCESS; + } else { + /* open, or 802.11r FTAA system */ + go2asoc = 1; + } + } else if (seq == 4) { + if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) + go2asoc = 1; + else + goto authclnt_fail; + } else { + /* this is also illegal */ + /* RTW_INFO("marc: clnt auth failed due to illegal seq=%x\n", seq); */ + goto authclnt_fail; + } + + if (go2asoc) { +#ifdef CONFIG_RTW_80211R + if ((rtw_to_roam(padapter) > 0) && rtw_chk_ft_flags(padapter, RTW_FT_SUPPORTED)) { + u8 target_ap_addr[ETH_ALEN] = {0}; + + if ((rtw_chk_ft_status(padapter, RTW_FT_AUTHENTICATED_STA)) || + (rtw_chk_ft_status(padapter, RTW_FT_ASSOCIATING_STA)) || + (rtw_chk_ft_status(padapter, RTW_FT_ASSOCIATED_STA))) { + /*report_ft_reassoc_event already, and waiting for cfg80211_rtw_update_ft_ies*/ + return _SUCCESS; + } + + rtw_buf_update(&pmlmepriv->auth_rsp, &pmlmepriv->auth_rsp_len, pframe, pkt_len); + pftpriv->ft_event.ies = pmlmepriv->auth_rsp + sizeof(struct rtw_ieee80211_hdr_3addr) + 6; + pftpriv->ft_event.ies_len = pmlmepriv->auth_rsp_len - sizeof(struct rtw_ieee80211_hdr_3addr) - 6; + + /*Not support RIC*/ + pftpriv->ft_event.ric_ies = NULL; + pftpriv->ft_event.ric_ies_len = 0; + _rtw_memcpy(target_ap_addr, pmlmepriv->assoc_bssid, ETH_ALEN); + report_ft_reassoc_event(padapter, target_ap_addr); + return _SUCCESS; + } +#endif + + RTW_PRINT("auth success, start assoc\n"); + start_clnt_assoc(padapter); + return _SUCCESS; + } + +authclnt_fail: + + /* pmlmeinfo->state &= ~(WIFI_FW_AUTH_STATE); */ + + return _FAIL; + +} + +unsigned int OnAssocReq(_adapter *padapter, union recv_frame *precv_frame) +{ +#ifdef CONFIG_AP_MODE + _irqL irqL; + u16 capab_info, listen_interval; + struct rtw_ieee802_11_elems elems; + struct sta_info *pstat; + unsigned char reassoc, *p, *pos, *wpa_ie; + unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01}; + int i, ie_len, wpa_ie_len, left; + u8 rate_set[16]; + u8 rate_num; + unsigned short status = _STATS_SUCCESSFUL_; + unsigned short frame_type, ie_offset = 0; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *cur = &(pmlmeinfo->network); + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *pframe = precv_frame->u.hdr.rx_data; + uint pkt_len = precv_frame->u.hdr.len; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + u8 p2p_status_code = P2P_STATUS_SUCCESS; + u8 *p2pie; + u32 p2pielen = 0; +#endif /* CONFIG_P2P */ + +#ifdef CONFIG_CONCURRENT_MODE + if (((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) && + rtw_mi_buddy_check_fwstate(padapter, _FW_UNDER_LINKING | _FW_UNDER_SURVEY)) { + /* don't process assoc request; */ + return _SUCCESS; + } +#endif /* CONFIG_CONCURRENT_MODE */ + + if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) + return _FAIL; + + frame_type = get_frame_sub_type(pframe); + if (frame_type == WIFI_ASSOCREQ) { + reassoc = 0; + ie_offset = _ASOCREQ_IE_OFFSET_; + } else { /* WIFI_REASSOCREQ */ + reassoc = 1; + ie_offset = _REASOCREQ_IE_OFFSET_; + } + + + if (pkt_len < IEEE80211_3ADDR_LEN + ie_offset) { + RTW_INFO("handle_assoc(reassoc=%d) - too short payload (len=%lu)" + "\n", reassoc, (unsigned long)pkt_len); + return _FAIL; + } + + pstat = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe)); + if (pstat == (struct sta_info *)NULL) { + status = _RSON_CLS2_; + goto asoc_class2_error; + } + + capab_info = RTW_GET_LE16(pframe + WLAN_HDR_A3_LEN); + /* capab_info = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN)); */ + /* listen_interval = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN+2)); */ + listen_interval = RTW_GET_LE16(pframe + WLAN_HDR_A3_LEN + 2); + + left = pkt_len - (IEEE80211_3ADDR_LEN + ie_offset); + pos = pframe + (IEEE80211_3ADDR_LEN + ie_offset); + + + RTW_INFO("%s\n", __FUNCTION__); + + /* check if this stat has been successfully authenticated/assocated */ + if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS)) { + if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS)) { + status = _RSON_CLS2_; + goto asoc_class2_error; + } else { + pstat->state &= (~WIFI_FW_ASSOC_SUCCESS); + pstat->state |= WIFI_FW_ASSOC_STATE; + } + } else { + pstat->state &= (~WIFI_FW_AUTH_SUCCESS); + pstat->state |= WIFI_FW_ASSOC_STATE; + } + + +#if 0/* todo:tkip_countermeasures */ + if (hapd->tkip_countermeasures) { + resp = WLAN_REASON_MICHAEL_MIC_FAILURE; + goto fail; + } +#endif + + pstat->capability = capab_info; + +#if 0/* todo: */ + /* check listen_interval */ + if (listen_interval > hapd->conf->max_listen_interval) { + hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "Too large Listen Interval (%d)", + listen_interval); + resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE; + goto fail; + } + + pstat->listen_interval = listen_interval; +#endif + + /* now parse all ieee802_11 ie to point to elems */ + if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed || + !elems.ssid) { + RTW_INFO("STA " MAC_FMT " sent invalid association request\n", + MAC_ARG(pstat->hwaddr)); + status = _STATS_FAILURE_; + goto OnAssocReqFail; + } + + + /* now we should check all the fields... */ + /* checking SSID */ + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + ie_offset, _SSID_IE_, &ie_len, + pkt_len - WLAN_HDR_A3_LEN - ie_offset); + if (p == NULL) + status = _STATS_FAILURE_; + + if (ie_len == 0) /* broadcast ssid, however it is not allowed in assocreq */ + status = _STATS_FAILURE_; + else { + /* check if ssid match */ + if (!_rtw_memcmp((void *)(p + 2), cur->Ssid.Ssid, cur->Ssid.SsidLength)) + status = _STATS_FAILURE_; + + if (ie_len != cur->Ssid.SsidLength) + status = _STATS_FAILURE_; + } + + if (_STATS_SUCCESSFUL_ != status) + goto OnAssocReqFail; + + rtw_ies_get_supported_rate(pframe + WLAN_HDR_A3_LEN + ie_offset, pkt_len - WLAN_HDR_A3_LEN - ie_offset, rate_set, &rate_num); + if (rate_num == 0) { + RTW_INFO(FUNC_ADPT_FMT" RX assoc-req with no supported rate\n", FUNC_ADPT_ARG(padapter)); + status = _STATS_FAILURE_; + goto OnAssocReqFail; + } + _rtw_memcpy(pstat->bssrateset, rate_set, rate_num); + pstat->bssratelen = rate_num; + UpdateBrateTblForSoftAP(pstat->bssrateset, pstat->bssratelen); + + /* check RSN/WPA/WPS */ + pstat->dot8021xalg = 0; + pstat->wpa_psk = 0; + pstat->wpa_group_cipher = 0; + pstat->wpa2_group_cipher = 0; + pstat->wpa_pairwise_cipher = 0; + pstat->wpa2_pairwise_cipher = 0; + _rtw_memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie)); + if ((psecuritypriv->wpa_psk & BIT(1)) && elems.rsn_ie) { + + int group_cipher = 0, pairwise_cipher = 0; + + wpa_ie = elems.rsn_ie; + wpa_ie_len = elems.rsn_ie_len; + + if (rtw_parse_wpa2_ie(wpa_ie - 2, wpa_ie_len + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { + pstat->dot8021xalg = 1;/* psk, todo:802.1x */ + pstat->wpa_psk |= BIT(1); + + pstat->wpa2_group_cipher = group_cipher & psecuritypriv->wpa2_group_cipher; + pstat->wpa2_pairwise_cipher = pairwise_cipher & psecuritypriv->wpa2_pairwise_cipher; + + if (!pstat->wpa2_group_cipher) + status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; + + if (!pstat->wpa2_pairwise_cipher) + status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; + } else + status = WLAN_STATUS_INVALID_IE; + + } else if ((psecuritypriv->wpa_psk & BIT(0)) && elems.wpa_ie) { + + int group_cipher = 0, pairwise_cipher = 0; + + wpa_ie = elems.wpa_ie; + wpa_ie_len = elems.wpa_ie_len; + + if (rtw_parse_wpa_ie(wpa_ie - 2, wpa_ie_len + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { + pstat->dot8021xalg = 1;/* psk, todo:802.1x */ + pstat->wpa_psk |= BIT(0); + + pstat->wpa_group_cipher = group_cipher & psecuritypriv->wpa_group_cipher; + pstat->wpa_pairwise_cipher = pairwise_cipher & psecuritypriv->wpa_pairwise_cipher; + + if (!pstat->wpa_group_cipher) + status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; + + if (!pstat->wpa_pairwise_cipher) + status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; + + } else + status = WLAN_STATUS_INVALID_IE; + + } else { + wpa_ie = NULL; + wpa_ie_len = 0; + } + + if (_STATS_SUCCESSFUL_ != status) + goto OnAssocReqFail; + + pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); + /* if (hapd->conf->wps_state && wpa_ie == NULL) { */ /* todo: to check ap if supporting WPS */ + if (wpa_ie == NULL) { + if (elems.wps_ie) { + RTW_INFO("STA included WPS IE in " + "(Re)Association Request - assume WPS is " + "used\n"); + pstat->flags |= WLAN_STA_WPS; + /* wpabuf_free(sta->wps_ie); */ + /* sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, */ + /* elems.wps_ie_len - 4); */ + } else { + RTW_INFO("STA did not include WPA/RSN IE " + "in (Re)Association Request - possible WPS " + "use\n"); + pstat->flags |= WLAN_STA_MAYBE_WPS; + } + + + /* AP support WPA/RSN, and sta is going to do WPS, but AP is not ready */ + /* that the selected registrar of AP is _FLASE */ + if ((psecuritypriv->wpa_psk > 0) + && (pstat->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { + if (pmlmepriv->wps_beacon_ie) { + u8 selected_registrar = 0; + + rtw_get_wps_attr_content(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len, WPS_ATTR_SELECTED_REGISTRAR , &selected_registrar, NULL); + + if (!selected_registrar) { + RTW_INFO("selected_registrar is _FALSE , or AP is not ready to do WPS\n"); + + status = _STATS_UNABLE_HANDLE_STA_; + + goto OnAssocReqFail; + } + } + } + + } else { + int copy_len; + + if (psecuritypriv->wpa_psk == 0) { + RTW_INFO("STA " MAC_FMT ": WPA/RSN IE in association " + "request, but AP don't support WPA/RSN\n", MAC_ARG(pstat->hwaddr)); + + status = WLAN_STATUS_INVALID_IE; + + goto OnAssocReqFail; + + } + + if (elems.wps_ie) { + RTW_INFO("STA included WPS IE in " + "(Re)Association Request - WPS is " + "used\n"); + pstat->flags |= WLAN_STA_WPS; + copy_len = 0; + } else + copy_len = ((wpa_ie_len + 2) > sizeof(pstat->wpa_ie)) ? (sizeof(pstat->wpa_ie)) : (wpa_ie_len + 2); + + + if (copy_len > 0) + _rtw_memcpy(pstat->wpa_ie, wpa_ie - 2, copy_len); + + } + + + /* check if there is WMM IE & support WWM-PS */ + pstat->flags &= ~WLAN_STA_WME; + pstat->qos_option = 0; + pstat->qos_info = 0; + pstat->has_legacy_ac = _TRUE; + pstat->uapsd_vo = 0; + pstat->uapsd_vi = 0; + pstat->uapsd_be = 0; + pstat->uapsd_bk = 0; + if (pmlmepriv->qospriv.qos_option) { + p = pframe + WLAN_HDR_A3_LEN + ie_offset; + ie_len = 0; + for (;;) { + p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, pkt_len - WLAN_HDR_A3_LEN - ie_offset); + if (p != NULL) { + if (_rtw_memcmp(p + 2, WMM_IE, 6)) { + + pstat->flags |= WLAN_STA_WME; + + pstat->qos_option = 1; + pstat->qos_info = *(p + 8); + + pstat->max_sp_len = (pstat->qos_info >> 5) & 0x3; + + if ((pstat->qos_info & 0xf) != 0xf) + pstat->has_legacy_ac = _TRUE; + else + pstat->has_legacy_ac = _FALSE; + + if (pstat->qos_info & 0xf) { + if (pstat->qos_info & BIT(0)) + pstat->uapsd_vo = BIT(0) | BIT(1); + else + pstat->uapsd_vo = 0; + + if (pstat->qos_info & BIT(1)) + pstat->uapsd_vi = BIT(0) | BIT(1); + else + pstat->uapsd_vi = 0; + + if (pstat->qos_info & BIT(2)) + pstat->uapsd_bk = BIT(0) | BIT(1); + else + pstat->uapsd_bk = 0; + + if (pstat->qos_info & BIT(3)) + pstat->uapsd_be = BIT(0) | BIT(1); + else + pstat->uapsd_be = 0; + + } + + break; + } + } else + break; + p = p + ie_len + 2; + } + } + + +#ifdef CONFIG_80211N_HT + if (pmlmepriv->htpriv.ht_option == _FALSE) + goto bypass_ht_chk; + + /* save HT capabilities in the sta object */ + _rtw_memset(&pstat->htpriv.ht_cap, 0, sizeof(struct rtw_ieee80211_ht_cap)); + if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct rtw_ieee80211_ht_cap)) { + pstat->flags |= WLAN_STA_HT; + + pstat->flags |= WLAN_STA_WME; + + _rtw_memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct rtw_ieee80211_ht_cap)); + + } else + pstat->flags &= ~WLAN_STA_HT; +bypass_ht_chk: + + if ((pmlmepriv->htpriv.ht_option == _FALSE) && (pstat->flags & WLAN_STA_HT)) { + rtw_warn_on(1); + status = _STATS_FAILURE_; + goto OnAssocReqFail; + } +#endif /* CONFIG_80211N_HT */ + +#ifdef CONFIG_80211AC_VHT + if (pmlmepriv->vhtpriv.vht_option == _FALSE) + goto bypass_vht_chk; + + _rtw_memset(&pstat->vhtpriv, 0, sizeof(struct vht_priv)); + if (elems.vht_capabilities && elems.vht_capabilities_len == 12) { + pstat->flags |= WLAN_STA_VHT; + + _rtw_memcpy(pstat->vhtpriv.vht_cap, elems.vht_capabilities, 12); + + if (elems.vht_op_mode_notify && elems.vht_op_mode_notify_len == 1) + _rtw_memcpy(&pstat->vhtpriv.vht_op_mode_notify, elems.vht_op_mode_notify, 1); + else /* for Frame without Operating Mode notify ie; default: 80M */ + pstat->vhtpriv.vht_op_mode_notify = CHANNEL_WIDTH_80; + } else + pstat->flags &= ~WLAN_STA_VHT; +bypass_vht_chk: + + if ((pmlmepriv->vhtpriv.vht_option == _FALSE) && (pstat->flags & WLAN_STA_VHT)) { + rtw_warn_on(1); + status = _STATS_FAILURE_; + goto OnAssocReqFail; + } +#endif /* CONFIG_80211AC_VHT */ + + if (((pstat->flags & WLAN_STA_HT) || (pstat->flags & WLAN_STA_VHT)) && + ((pstat->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) || + (pstat->wpa_pairwise_cipher & WPA_CIPHER_TKIP))) { + + RTW_INFO("(V)HT: " MAC_FMT " tried to use TKIP with (V)HT association\n", MAC_ARG(pstat->hwaddr)); + + pstat->flags &= ~WLAN_STA_HT; + pstat->flags &= ~WLAN_STA_VHT; + /*status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; + * goto OnAssocReqFail; + */ + } + + + /* + * if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) */ /* ? */ + pstat->flags |= WLAN_STA_NONERP; + for (i = 0; i < pstat->bssratelen; i++) { + if ((pstat->bssrateset[i] & 0x7f) > 22) { + pstat->flags &= ~WLAN_STA_NONERP; + break; + } + } + + if (pstat->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + pstat->flags |= WLAN_STA_SHORT_PREAMBLE; + else + pstat->flags &= ~WLAN_STA_SHORT_PREAMBLE; + + + + if (status != _STATS_SUCCESSFUL_) + goto OnAssocReqFail; + +#ifdef CONFIG_P2P + pstat->is_p2p_device = _FALSE; + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + p2pie = rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + ie_offset , pkt_len - WLAN_HDR_A3_LEN - ie_offset , NULL, &p2pielen); + if (p2pie) { + pstat->is_p2p_device = _TRUE; + p2p_status_code = (u8)process_assoc_req_p2p_ie(pwdinfo, pframe, pkt_len, pstat); + if (p2p_status_code > 0) { + pstat->p2p_status_code = p2p_status_code; + status = _STATS_CAP_FAIL_; + goto OnAssocReqFail; + } + } +#ifdef CONFIG_WFD + rtw_process_wfd_ies(padapter, pframe + WLAN_HDR_A3_LEN + ie_offset, pkt_len - WLAN_HDR_A3_LEN - ie_offset, __func__); +#endif + } + pstat->p2p_status_code = p2p_status_code; +#endif /* CONFIG_P2P */ + + /* TODO: identify_proprietary_vendor_ie(); */ + /* Realtek proprietary IE */ + /* identify if this is Broadcom sta */ + /* identify if this is ralink sta */ + /* Customer proprietary IE */ + + + + /* get a unique AID */ + if (pstat->aid > 0) + RTW_INFO(" old AID %d\n", pstat->aid); + else { + for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++) { + if (pstapriv->sta_aid[pstat->aid - 1] == NULL) { + if (pstat->aid > pstapriv->max_num_sta) { + pstat->aid = 0; + + RTW_INFO(" no room for more AIDs\n"); + + status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + + goto OnAssocReqFail; + + + } else { + pstapriv->sta_aid[pstat->aid - 1] = pstat; + RTW_INFO("allocate new AID = (%d)\n", pstat->aid); + break; + } + } + } + } + + + pstat->state &= (~WIFI_FW_ASSOC_STATE); + pstat->state |= WIFI_FW_ASSOC_SUCCESS; + /* RTW_INFO("==================%s, %d, (%x), bpairwise_key_installed=%d, MAC:"MAC_FMT"\n" + , __func__, __LINE__, pstat->state, pstat->bpairwise_key_installed, MAC_ARG(pstat->hwaddr)); */ +#ifdef CONFIG_IEEE80211W + if (pstat->bpairwise_key_installed != _TRUE) +#endif /* CONFIG_IEEE80211W */ + { + _enter_critical_bh(&pstapriv->auth_list_lock, &irqL); + if (!rtw_is_list_empty(&pstat->auth_list)) { + rtw_list_delete(&pstat->auth_list); + pstapriv->auth_list_cnt--; + } + _exit_critical_bh(&pstapriv->auth_list_lock, &irqL); + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + if (rtw_is_list_empty(&pstat->asoc_list)) { + pstat->expire_to = pstapriv->expire_to; + rtw_list_insert_tail(&pstat->asoc_list, &pstapriv->asoc_list); + pstapriv->asoc_list_cnt++; + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + } + + /* now the station is qualified to join our BSS... */ + if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && (_STATS_SUCCESSFUL_ == status)) { +#ifdef CONFIG_NATIVEAP_MLME +#ifdef CONFIG_IEEE80211W + if (pstat->bpairwise_key_installed != _TRUE) +#endif /* CONFIG_IEEE80211W */ + { + /* .1 bss_cap_update & sta_info_update */ + bss_cap_update_on_sta_join(padapter, pstat); + sta_info_update(padapter, pstat); + } +#ifdef CONFIG_IEEE80211W + if (pstat->bpairwise_key_installed == _TRUE) + status = _STATS_REFUSED_TEMPORARILY_; +#endif /* CONFIG_IEEE80211W */ + /* .2 issue assoc rsp before notify station join event. */ + if (frame_type == WIFI_ASSOCREQ) + issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); + else + issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); + +#ifdef CONFIG_IOCTL_CFG80211 + _enter_critical_bh(&pstat->lock, &irqL); + if (pstat->passoc_req) { + rtw_mfree(pstat->passoc_req, pstat->assoc_req_len); + pstat->passoc_req = NULL; + pstat->assoc_req_len = 0; + } + + pstat->passoc_req = rtw_zmalloc(pkt_len); + if (pstat->passoc_req) { + _rtw_memcpy(pstat->passoc_req, pframe, pkt_len); + pstat->assoc_req_len = pkt_len; + } + _exit_critical_bh(&pstat->lock, &irqL); +#endif /* CONFIG_IOCTL_CFG80211 */ +#ifdef CONFIG_IEEE80211W + if (pstat->bpairwise_key_installed != _TRUE) +#endif /* CONFIG_IEEE80211W */ + { + /* .3-(1) report sta add event */ + report_add_sta_event(padapter, pstat->hwaddr); + } +#ifdef CONFIG_IEEE80211W + if (pstat->bpairwise_key_installed == _TRUE && padapter->securitypriv.binstallBIPkey == _TRUE) { + RTW_INFO(MAC_FMT"\n", MAC_ARG(pstat->hwaddr)); + issue_action_SA_Query(padapter, pstat->hwaddr, 0, 0, IEEE80211W_RIGHT_KEY); + } +#endif /* CONFIG_IEEE80211W */ +#endif /* CONFIG_NATIVEAP_MLME */ + } + + return _SUCCESS; + +asoc_class2_error: + +#ifdef CONFIG_NATIVEAP_MLME + issue_deauth(padapter, (void *)get_addr2_ptr(pframe), status); +#endif + + return _FAIL; + +OnAssocReqFail: + + +#ifdef CONFIG_NATIVEAP_MLME + pstat->aid = 0; + if (frame_type == WIFI_ASSOCREQ) + issue_asocrsp(padapter, status, pstat, WIFI_ASSOCRSP); + else + issue_asocrsp(padapter, status, pstat, WIFI_REASSOCRSP); +#endif + + +#endif /* CONFIG_AP_MODE */ + + return _FAIL; + +} + +unsigned int OnAssocRsp(_adapter *padapter, union recv_frame *precv_frame) +{ + uint i; + int res; + unsigned short status; + PNDIS_802_11_VARIABLE_IEs pIE; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + /* WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); */ + u8 *pframe = precv_frame->u.hdr.rx_data; + uint pkt_len = precv_frame->u.hdr.len; + PNDIS_802_11_VARIABLE_IEs pWapiIE = NULL; + + RTW_INFO("%s\n", __FUNCTION__); + + /* check A1 matches or not */ + if (!_rtw_memcmp(adapter_mac_addr(padapter), get_da(pframe), ETH_ALEN)) + return _SUCCESS; + + if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE))) + return _SUCCESS; + + if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) + return _SUCCESS; + + _cancel_timer_ex(&pmlmeext->link_timer); + + /* status */ + status = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN + 2)); + if (status > 0) { + RTW_INFO("assoc reject, status code: %d\n", status); + pmlmeinfo->state = WIFI_FW_NULL_STATE; + res = -4; + goto report_assoc_result; + } + + /* get capabilities */ + pmlmeinfo->capability = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN)); + + /* set slot time */ + pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10)) ? 9 : 20; + + /* AID */ + res = pmlmeinfo->aid = (int)(le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN + 4)) & 0x3fff); + + /* following are moved to join event callback function */ + /* to handle HT, WMM, rate adaptive, update MAC reg */ + /* for not to handle the synchronous IO in the tasklet */ + for (i = (6 + WLAN_HDR_A3_LEN); i < pkt_len;) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(pframe + i); + + switch (pIE->ElementID) { + case _VENDOR_SPECIFIC_IE_: + if (_rtw_memcmp(pIE->data, WMM_PARA_OUI, 6)) /* WMM */ + WMM_param_handler(padapter, pIE); +#if defined(CONFIG_P2P) && defined(CONFIG_WFD) + else if (_rtw_memcmp(pIE->data, WFD_OUI, 4)) /* WFD */ + rtw_process_wfd_ie(padapter, (u8 *)pIE, pIE->Length, __func__); +#endif + break; + +#ifdef CONFIG_WAPI_SUPPORT + case _WAPI_IE_: + pWapiIE = pIE; + break; +#endif + + case _HT_CAPABILITY_IE_: /* HT caps */ + HT_caps_handler(padapter, pIE); + break; + + case _HT_EXTRA_INFO_IE_: /* HT info */ + HT_info_handler(padapter, pIE); + break; + +#ifdef CONFIG_80211AC_VHT + case EID_VHTCapability: + VHT_caps_handler(padapter, pIE); + break; + + case EID_VHTOperation: + VHT_operation_handler(padapter, pIE); + break; +#endif + + case _ERPINFO_IE_: + ERP_IE_handler(padapter, pIE); + break; +#ifdef CONFIG_TDLS + case _EXT_CAP_IE_: + if (check_ap_tdls_prohibited(pIE->data, pIE->Length) == _TRUE) + padapter->tdlsinfo.ap_prohibited = _TRUE; + if (check_ap_tdls_ch_switching_prohibited(pIE->data, pIE->Length) == _TRUE) + padapter->tdlsinfo.ch_switch_prohibited = _TRUE; + break; +#endif /* CONFIG_TDLS */ + default: + break; + } + + i += (pIE->Length + 2); + } + +#ifdef CONFIG_WAPI_SUPPORT + rtw_wapi_on_assoc_ok(padapter, pIE); +#endif + + pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE); + pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; + + /* Update Basic Rate Table for spec, 2010-12-28 , by thomas */ + UpdateBrateTbl(padapter, pmlmeinfo->network.SupportedRates); + +report_assoc_result: + if (res > 0) + rtw_buf_update(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len, pframe, pkt_len); + else + rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len); + + report_join_res(padapter, res); + + return _SUCCESS; +} + +unsigned int OnDeAuth(_adapter *padapter, union recv_frame *precv_frame) +{ + unsigned short reason; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 *pframe = precv_frame->u.hdr.rx_data; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#endif /* CONFIG_P2P */ + + /* check A3 */ + if (!(_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) + return _SUCCESS; + + RTW_INFO(FUNC_ADPT_FMT" - Start to Disconnect\n", FUNC_ADPT_ARG(padapter)); + +#ifdef CONFIG_P2P + if (pwdinfo->rx_invitereq_info.scan_op_ch_only) { + _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); + _set_timer(&pwdinfo->reset_ch_sitesurvey, 10); + } +#endif /* CONFIG_P2P */ + + reason = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN)); + + rtw_lock_rx_suspend_timeout(8000); + +#ifdef CONFIG_AP_MODE + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { + _irqL irqL; + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + + /* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + /* rtw_free_stainfo(padapter, psta); */ + /* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + + RTW_PRINT(FUNC_ADPT_FMT" reason=%u, ta=%pM\n" + , FUNC_ADPT_ARG(padapter), reason, get_addr2_ptr(pframe)); + + psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe)); + if (psta) { + u8 updated = _FALSE; + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + if (rtw_is_list_empty(&psta->asoc_list) == _FALSE) { + rtw_list_delete(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + updated = ap_free_sta(padapter, psta, _FALSE, reason, _TRUE); + + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + associated_clients_update(padapter, updated, STA_INFO_UPDATE_ALL); + } + + + return _SUCCESS; + } else +#endif + { + int ignore_received_deauth = 0; + + /* Commented by Albert 20130604 */ + /* Before sending the auth frame to start the STA/GC mode connection with AP/GO, */ + /* we will send the deauth first. */ + /* However, the Win8.1 with BRCM Wi-Fi will send the deauth with reason code 6 to us after receieving our deauth. */ + /* Added the following code to avoid this case. */ + if ((pmlmeinfo->state & WIFI_FW_AUTH_STATE) || + (pmlmeinfo->state & WIFI_FW_ASSOC_STATE)) { + if (reason == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA) + ignore_received_deauth = 1; + else if (WLAN_REASON_PREV_AUTH_NOT_VALID == reason) { + /* TODO: 802.11r */ + ignore_received_deauth = 1; + } + } + + RTW_PRINT(FUNC_ADPT_FMT" reason=%u, ta=%pM, ignore=%d\n" + , FUNC_ADPT_ARG(padapter), reason, get_addr2_ptr(pframe), ignore_received_deauth); + + if (0 == ignore_received_deauth) + receive_disconnect(padapter, get_addr2_ptr(pframe), reason, _FALSE); + } + pmlmepriv->LinkDetectInfo.bBusyTraffic = _FALSE; + return _SUCCESS; + +} + +unsigned int OnDisassoc(_adapter *padapter, union recv_frame *precv_frame) +{ + unsigned short reason; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 *pframe = precv_frame->u.hdr.rx_data; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#endif /* CONFIG_P2P */ + + /* check A3 */ + if (!(_rtw_memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) + return _SUCCESS; + + RTW_INFO(FUNC_ADPT_FMT" - Start to Disconnect\n", FUNC_ADPT_ARG(padapter)); + +#ifdef CONFIG_P2P + if (pwdinfo->rx_invitereq_info.scan_op_ch_only) { + _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); + _set_timer(&pwdinfo->reset_ch_sitesurvey, 10); + } +#endif /* CONFIG_P2P */ + + reason = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN)); + + rtw_lock_rx_suspend_timeout(8000); + +#ifdef CONFIG_AP_MODE + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { + _irqL irqL; + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + + /* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + /* rtw_free_stainfo(padapter, psta); */ + /* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); */ + + RTW_PRINT(FUNC_ADPT_FMT" reason=%u, ta=%pM\n" + , FUNC_ADPT_ARG(padapter), reason, get_addr2_ptr(pframe)); + + psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe)); + if (psta) { + u8 updated = _FALSE; + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + if (rtw_is_list_empty(&psta->asoc_list) == _FALSE) { + rtw_list_delete(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + updated = ap_free_sta(padapter, psta, _FALSE, reason, _TRUE); + + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + associated_clients_update(padapter, updated, STA_INFO_UPDATE_ALL); + } + + return _SUCCESS; + } else +#endif + { + RTW_PRINT(FUNC_ADPT_FMT" reason=%u, ta=%pM\n" + , FUNC_ADPT_ARG(padapter), reason, get_addr2_ptr(pframe)); + + receive_disconnect(padapter, get_addr2_ptr(pframe), reason, _FALSE); + } + pmlmepriv->LinkDetectInfo.bBusyTraffic = _FALSE; + return _SUCCESS; + +} + +unsigned int OnAtim(_adapter *padapter, union recv_frame *precv_frame) +{ + RTW_INFO("%s\n", __FUNCTION__); + return _SUCCESS; +} + +unsigned int on_action_spct_ch_switch(_adapter *padapter, struct sta_info *psta, u8 *ies, uint ies_len) +{ + unsigned int ret = _FAIL; + struct mlme_ext_priv *mlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(mlmeext->mlmext_info); + + if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { + ret = _SUCCESS; + goto exit; + } + + if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) { + + int ch_switch_mode = -1, ch = -1, ch_switch_cnt = -1; + int ch_offset = -1; + u8 bwmode; + struct ieee80211_info_element *ie; + + RTW_INFO(FUNC_NDEV_FMT" from "MAC_FMT"\n", + FUNC_NDEV_ARG(padapter->pnetdev), MAC_ARG(psta->hwaddr)); + + for_each_ie(ie, ies, ies_len) { + if (ie->id == WLAN_EID_CHANNEL_SWITCH) { + ch_switch_mode = ie->data[0]; + ch = ie->data[1]; + ch_switch_cnt = ie->data[2]; + RTW_INFO("ch_switch_mode:%d, ch:%d, ch_switch_cnt:%d\n", + ch_switch_mode, ch, ch_switch_cnt); + } else if (ie->id == WLAN_EID_SECONDARY_CHANNEL_OFFSET) { + ch_offset = secondary_ch_offset_to_hal_ch_offset(ie->data[0]); + RTW_INFO("ch_offset:%d\n", ch_offset); + } + } + + if (ch == -1) + return _SUCCESS; + + if (ch_offset == -1) + bwmode = mlmeext->cur_bwmode; + else + bwmode = (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) ? + CHANNEL_WIDTH_20 : CHANNEL_WIDTH_40; + + ch_offset = (ch_offset == -1) ? mlmeext->cur_ch_offset : ch_offset; + + /* todo: + * 1. the decision of channel switching + * 2. things after channel switching + */ + + ret = rtw_set_ch_cmd(padapter, ch, bwmode, ch_offset, _TRUE); + } + +exit: + return ret; +} + +unsigned int on_action_spct(_adapter *padapter, union recv_frame *precv_frame) +{ + unsigned int ret = _FAIL; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *pframe = precv_frame->u.hdr.rx_data; + uint frame_len = precv_frame->u.hdr.len; + u8 *frame_body = (u8 *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); + u8 category; + u8 action; + + RTW_INFO(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev)); + + psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe)); + + if (!psta) + goto exit; + + category = frame_body[0]; + if (category != RTW_WLAN_CATEGORY_SPECTRUM_MGMT) + goto exit; + + action = frame_body[1]; + switch (action) { + case RTW_WLAN_ACTION_SPCT_MSR_REQ: + case RTW_WLAN_ACTION_SPCT_MSR_RPRT: + case RTW_WLAN_ACTION_SPCT_TPC_REQ: + case RTW_WLAN_ACTION_SPCT_TPC_RPRT: + break; + case RTW_WLAN_ACTION_SPCT_CHL_SWITCH: +#ifdef CONFIG_SPCT_CH_SWITCH + ret = on_action_spct_ch_switch(padapter, psta, &frame_body[2], + frame_len - (frame_body - pframe) - 2); +#endif + break; + default: + break; + } + +exit: + return ret; +} + +unsigned int OnAction_qos(_adapter *padapter, union recv_frame *precv_frame) +{ + return _SUCCESS; +} + +unsigned int OnAction_dls(_adapter *padapter, union recv_frame *precv_frame) +{ + return _SUCCESS; +} + +#ifdef CONFIG_RTW_WNM +unsigned int on_action_wnm(_adapter *adapter, union recv_frame *rframe) +{ + unsigned int ret = _FAIL; + struct sta_info *sta = NULL; + struct sta_priv *stapriv = &adapter->stapriv; + u8 *frame = rframe->u.hdr.rx_data; + uint frame_len = rframe->u.hdr.len; + u8 *frame_body = (u8 *)(frame + sizeof(struct rtw_ieee80211_hdr_3addr)); + u8 category; + u8 action; + int cnt = 0; + char msg[16]; + + sta = rtw_get_stainfo(stapriv, get_addr2_ptr(frame)); + if (!sta) + goto exit; + + category = frame_body[0]; + if (category != RTW_WLAN_CATEGORY_WNM) + goto exit; + + action = frame_body[1]; + + switch (action) { + default: + #ifdef CONFIG_IOCTL_CFG80211 + cnt += sprintf((msg + cnt), "ACT_WNM %u", action); + rtw_cfg80211_rx_action(adapter, rframe, msg); + #endif + ret = _SUCCESS; + break; + } + +exit: + return ret; +} +#endif /* CONFIG_RTW_WNM */ + +/** + * rtw_rx_ampdu_size - Get the target RX AMPDU buffer size for the specific @adapter + * @adapter: the adapter to get target RX AMPDU buffer size + * + * Returns: the target RX AMPDU buffer size + */ +u8 rtw_rx_ampdu_size(_adapter *adapter) +{ + u8 size; + HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor; + + if (adapter->fix_rx_ampdu_size != RX_AMPDU_SIZE_INVALID) { + size = adapter->fix_rx_ampdu_size; + goto exit; + } + +#ifdef CONFIG_BT_COEXIST + if (rtw_btcoex_IsBTCoexCtrlAMPDUSize(adapter) == _TRUE) { + size = rtw_btcoex_GetAMPDUSize(adapter); + goto exit; + } +#endif + + /* for scan */ + if (!mlmeext_chk_scan_state(&adapter->mlmeextpriv, SCAN_DISABLE) + && !mlmeext_chk_scan_state(&adapter->mlmeextpriv, SCAN_COMPLETE) + && adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_size != RX_AMPDU_SIZE_INVALID + ) { + size = adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_size; + goto exit; + } + + /* default value based on max_rx_ampdu_factor */ + if (adapter->driver_rx_ampdu_factor != 0xFF) + max_rx_ampdu_factor = (HT_CAP_AMPDU_FACTOR)adapter->driver_rx_ampdu_factor; + else + rtw_hal_get_def_var(adapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor); + + /* In Maximum A-MPDU Length Exponent subfield of A-MPDU Parameters field of HT Capabilities element, + the unit of max_rx_ampdu_factor are octets. 8K, 16K, 32K, 64K is right. + But the buffer size subfield of Block Ack Parameter Set field in ADDBA action frame indicates + the number of buffers available for this particular TID. Each buffer is equal to max. size of + MSDU or AMSDU. + The size variable means how many MSDUs or AMSDUs, it's not Kbytes. + */ + if (MAX_AMPDU_FACTOR_64K == max_rx_ampdu_factor) + size = 64; + else if (MAX_AMPDU_FACTOR_32K == max_rx_ampdu_factor) + size = 32; + else if (MAX_AMPDU_FACTOR_16K == max_rx_ampdu_factor) + size = 16; + else if (MAX_AMPDU_FACTOR_8K == max_rx_ampdu_factor) + size = 8; + else + size = 64; + +exit: + + if (size > 127) + size = 127; + + return size; +} + +/** + * rtw_rx_ampdu_is_accept - Get the permission if RX AMPDU should be set up for the specific @adapter + * @adapter: the adapter to get the permission if RX AMPDU should be set up + * + * Returns: accept or not + */ +bool rtw_rx_ampdu_is_accept(_adapter *adapter) +{ + bool accept; + + if (adapter->fix_rx_ampdu_accept != RX_AMPDU_ACCEPT_INVALID) { + accept = adapter->fix_rx_ampdu_accept; + goto exit; + } + +#ifdef CONFIG_BT_COEXIST + if (rtw_btcoex_IsBTCoexRejectAMPDU(adapter) == _TRUE) { + accept = _FALSE; + goto exit; + } +#endif + + /* for scan */ + if (!mlmeext_chk_scan_state(&adapter->mlmeextpriv, SCAN_DISABLE) + && !mlmeext_chk_scan_state(&adapter->mlmeextpriv, SCAN_COMPLETE) + && adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_accept != RX_AMPDU_ACCEPT_INVALID + ) { + accept = adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_accept; + goto exit; + } + + /* default value for other cases */ + accept = adapter->mlmeextpriv.mlmext_info.bAcceptAddbaReq; + +exit: + return accept; +} + +/** + * rtw_rx_ampdu_set_size - Set the target RX AMPDU buffer size for the specific @adapter and specific @reason + * @adapter: the adapter to set target RX AMPDU buffer size + * @size: the target RX AMPDU buffer size to set + * @reason: reason for the target RX AMPDU buffer size setting + * + * Returns: whether the target RX AMPDU buffer size is changed + */ +bool rtw_rx_ampdu_set_size(_adapter *adapter, u8 size, u8 reason) +{ + bool is_adj = _FALSE; + struct mlme_ext_priv *mlmeext; + struct mlme_ext_info *mlmeinfo; + + mlmeext = &adapter->mlmeextpriv; + mlmeinfo = &mlmeext->mlmext_info; + + if (reason == RX_AMPDU_DRV_FIXED) { + if (adapter->fix_rx_ampdu_size != size) { + adapter->fix_rx_ampdu_size = size; + is_adj = _TRUE; + RTW_INFO(FUNC_ADPT_FMT" fix_rx_ampdu_size:%u\n", FUNC_ADPT_ARG(adapter), size); + } + } else if (reason == RX_AMPDU_DRV_SCAN) { + struct ss_res *ss = &adapter->mlmeextpriv.sitesurvey_res; + + if (ss->rx_ampdu_size != size) { + ss->rx_ampdu_size = size; + is_adj = _TRUE; + RTW_INFO(FUNC_ADPT_FMT" ss.rx_ampdu_size:%u\n", FUNC_ADPT_ARG(adapter), size); + } + } + + return is_adj; +} + +/** + * rtw_rx_ampdu_set_accept - Set the permission if RX AMPDU should be set up for the specific @adapter and specific @reason + * @adapter: the adapter to set if RX AMPDU should be set up + * @accept: if RX AMPDU should be set up + * @reason: reason for the permission if RX AMPDU should be set up + * + * Returns: whether the permission if RX AMPDU should be set up is changed + */ +bool rtw_rx_ampdu_set_accept(_adapter *adapter, u8 accept, u8 reason) +{ + bool is_adj = _FALSE; + struct mlme_ext_priv *mlmeext; + struct mlme_ext_info *mlmeinfo; + + mlmeext = &adapter->mlmeextpriv; + mlmeinfo = &mlmeext->mlmext_info; + + if (reason == RX_AMPDU_DRV_FIXED) { + if (adapter->fix_rx_ampdu_accept != accept) { + adapter->fix_rx_ampdu_accept = accept; + is_adj = _TRUE; + RTW_INFO(FUNC_ADPT_FMT" fix_rx_ampdu_accept:%u\n", FUNC_ADPT_ARG(adapter), accept); + } + } else if (reason == RX_AMPDU_DRV_SCAN) { + if (adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_accept != accept) { + adapter->mlmeextpriv.sitesurvey_res.rx_ampdu_accept = accept; + is_adj = _TRUE; + RTW_INFO(FUNC_ADPT_FMT" ss.rx_ampdu_accept:%u\n", FUNC_ADPT_ARG(adapter), accept); + } + } + + return is_adj; +} + +/** + * rx_ampdu_apply_sta_tid - Apply RX AMPDU setting to the specific @sta and @tid + * @adapter: the adapter to which @sta belongs + * @sta: the sta to be checked + * @tid: the tid to be checked + * @accept: the target permission if RX AMPDU should be set up + * @size: the target RX AMPDU buffer size + * + * Returns: + * 0: no canceled + * 1: canceled by no permission + * 2: canceled by different buffer size + * 3: canceled by potential mismatched status + * + * Blocking function, may sleep + */ +u8 rx_ampdu_apply_sta_tid(_adapter *adapter, struct sta_info *sta, u8 tid, u8 accept, u8 size) +{ + u8 ret = 0; + struct recv_reorder_ctrl *reorder_ctl = &sta->recvreorder_ctrl[tid]; + + if (reorder_ctl->enable == _FALSE) { + if (reorder_ctl->ampdu_size != RX_AMPDU_SIZE_INVALID) { + send_delba_sta_tid_wait_ack(adapter, 0, sta, tid, 1); + ret = 3; + } + goto exit; + } + + if (accept == _FALSE) { + send_delba_sta_tid_wait_ack(adapter, 0, sta, tid, 0); + ret = 1; + } else if (reorder_ctl->ampdu_size != size) { + send_delba_sta_tid_wait_ack(adapter, 0, sta, tid, 0); + ret = 2; + } + +exit: + return ret; +} + +/** + * rx_ampdu_apply_sta - Apply RX AMPDU setting to the specific @sta + * @adapter: the adapter to which @sta belongs + * @sta: the sta to be checked + * @accept: the target permission if RX AMPDU should be set up + * @size: the target RX AMPDU buffer size + * + * Returns: number of the RX AMPDU assciation canceled for applying current target setting + * + * Blocking function, may sleep + */ +u8 rx_ampdu_apply_sta(_adapter *adapter, struct sta_info *sta, u8 accept, u8 size) +{ + u8 change_cnt = 0; + int i; + + for (i = 0; i < TID_NUM; i++) { + if (rx_ampdu_apply_sta_tid(adapter, sta, i, accept, size) != 0) + change_cnt++; + } + + return change_cnt; +} + +/** + * rtw_rx_ampdu_apply - Apply the current target RX AMPDU setting for the specific @adapter + * @adapter: the adapter to be applied + * + * Returns: number of the RX AMPDU assciation canceled for applying current target setting + */ +u16 rtw_rx_ampdu_apply(_adapter *adapter) +{ + u16 adj_cnt = 0; + struct mlme_ext_priv *mlmeext; + struct sta_info *sta; + u8 accept = rtw_rx_ampdu_is_accept(adapter); + u8 size = rtw_rx_ampdu_size(adapter); + + mlmeext = &adapter->mlmeextpriv; + + if (mlmeext_msr(mlmeext) == WIFI_FW_STATION_STATE) { + sta = rtw_get_stainfo(&adapter->stapriv, get_bssid(&adapter->mlmepriv)); + if (sta) + adj_cnt += rx_ampdu_apply_sta(adapter, sta, accept, size); + + } else if (mlmeext_msr(mlmeext) == WIFI_FW_AP_STATE) { + _irqL irqL; + _list *phead, *plist; + u8 peer_num = 0; + char peers[NUM_STA]; + struct sta_priv *pstapriv = &adapter->stapriv; + int i; + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + phead = &pstapriv->asoc_list; + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + int stainfo_offset; + + sta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); + plist = get_next(plist); + + stainfo_offset = rtw_stainfo_offset(pstapriv, sta); + if (stainfo_offset_valid(stainfo_offset)) + peers[peer_num++] = stainfo_offset; + } + + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + for (i = 0; i < peer_num; i++) { + sta = rtw_get_stainfo_by_offset(pstapriv, peers[i]); + if (sta) + adj_cnt += rx_ampdu_apply_sta(adapter, sta, accept, size); + } + } + + return adj_cnt; +} + +unsigned int OnAction_back(_adapter *padapter, union recv_frame *precv_frame) +{ + u8 *addr; + struct sta_info *psta = NULL; + struct recv_reorder_ctrl *preorder_ctrl; + unsigned char *frame_body; + unsigned char category, action; + unsigned short tid, status, reason_code = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 *pframe = precv_frame->u.hdr.rx_data; + struct sta_priv *pstapriv = &padapter->stapriv; + +#ifdef CONFIG_80211N_HT + + RTW_INFO("%s\n", __FUNCTION__); + + /* check RA matches or not */ + if (!_rtw_memcmp(adapter_mac_addr(padapter), GetAddr1Ptr(pframe), ETH_ALEN)) + return _SUCCESS; + +#if 0 + /* check A1 matches or not */ + if (!_rtw_memcmp(adapter_mac_addr(padapter), get_da(pframe), ETH_ALEN)) + return _SUCCESS; +#endif + + if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) + if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) + return _SUCCESS; + + addr = get_addr2_ptr(pframe); + psta = rtw_get_stainfo(pstapriv, addr); + + if (psta == NULL) + return _SUCCESS; + + frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); + + category = frame_body[0]; + if (category == RTW_WLAN_CATEGORY_BACK) { /* representing Block Ack */ +#ifdef CONFIG_TDLS + if ((psta->tdls_sta_state & TDLS_LINKED_STATE) && + (psta->htpriv.ht_option == _TRUE) && + (psta->htpriv.ampdu_enable == _TRUE)) + RTW_INFO("Recv [%s] from direc link\n", __FUNCTION__); + else +#endif /* CONFIG_TDLS */ + if (!pmlmeinfo->HT_enable) + return _SUCCESS; + + action = frame_body[1]; + RTW_INFO("%s, action=%d\n", __FUNCTION__, action); + switch (action) { + case RTW_WLAN_ACTION_ADDBA_REQ: /* ADDBA request */ + + _rtw_memcpy(&(pmlmeinfo->ADDBA_req), &(frame_body[2]), sizeof(struct ADDBA_request)); + /* process_addba_req(padapter, (u8*)&(pmlmeinfo->ADDBA_req), GetAddr3Ptr(pframe)); */ + process_addba_req(padapter, (u8 *)&(pmlmeinfo->ADDBA_req), addr); + + break; + + case RTW_WLAN_ACTION_ADDBA_RESP: /* ADDBA response */ + + /* status = frame_body[3] | (frame_body[4] << 8); */ /* endian issue */ + status = RTW_GET_LE16(&frame_body[3]); + tid = ((frame_body[5] >> 2) & 0x7); + if (status == 0) { + /* successful */ + RTW_INFO("agg_enable for TID=%d\n", tid); + psta->htpriv.agg_enable_bitmap |= 1 << tid; + psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); + /* amsdu in ampdu */ + if (frame_body[5] & 1) + psta->htpriv.tx_amsdu_enable = _TRUE; + } else + psta->htpriv.agg_enable_bitmap &= ~BIT(tid); + + if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { + RTW_INFO("%s alive check - rx ADDBA response\n", __func__); + psta->htpriv.agg_enable_bitmap &= ~BIT(tid); + psta->expire_to = pstapriv->expire_to; + psta->state ^= WIFI_STA_ALIVE_CHK_STATE; + } + + /* RTW_INFO("marc: ADDBA RSP: %x\n", pmlmeinfo->agg_enable_bitmap); */ + break; + + case RTW_WLAN_ACTION_DELBA: /* DELBA */ + if ((frame_body[3] & BIT(3)) == 0) { + psta->htpriv.agg_enable_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); + psta->htpriv.candidate_tid_bitmap &= ~(1 << ((frame_body[3] >> 4) & 0xf)); + + /* reason_code = frame_body[4] | (frame_body[5] << 8); */ + reason_code = RTW_GET_LE16(&frame_body[4]); + } else if ((frame_body[3] & BIT(3)) == BIT(3)) { + tid = (frame_body[3] >> 4) & 0x0F; + + preorder_ctrl = &psta->recvreorder_ctrl[tid]; + preorder_ctrl->enable = _FALSE; + preorder_ctrl->ampdu_size = RX_AMPDU_SIZE_INVALID; + } + + RTW_INFO("%s(): DELBA: %x(%x)\n", __FUNCTION__, pmlmeinfo->agg_enable_bitmap, reason_code); + /* todo: how to notify the host while receiving DELETE BA */ + break; + + default: + break; + } + } +#endif /* CONFIG_80211N_HT */ + return _SUCCESS; +} + +#ifdef CONFIG_P2P + +static int get_reg_classes_full_count(struct p2p_channels channel_list) +{ + int cnt = 0; + int i; + + for (i = 0; i < channel_list.reg_classes; i++) + cnt += channel_list.reg_class[i].channels; + + return cnt; +} + +static void get_channel_cnt_24g_5gl_5gh(struct mlme_ext_priv *pmlmeext, u8 *p24g_cnt, u8 *p5gl_cnt, u8 *p5gh_cnt) +{ + int i = 0; + + *p24g_cnt = 0; + *p5gl_cnt = 0; + *p5gh_cnt = 0; + + for (i = 0; i < pmlmeext->max_chan_nums; i++) { + if (pmlmeext->channel_set[i].ChannelNum <= 14) + (*p24g_cnt)++; + else if ((pmlmeext->channel_set[i].ChannelNum > 14) && (pmlmeext->channel_set[i].ChannelNum <= 48)) { + /* Just include the channel 36, 40, 44, 48 channels for 5G low */ + (*p5gl_cnt)++; + } else if ((pmlmeext->channel_set[i].ChannelNum >= 149) && (pmlmeext->channel_set[i].ChannelNum <= 161)) { + /* Just include the channel 149, 153, 157, 161 channels for 5G high */ + (*p5gh_cnt)++; + } + } +} + +void issue_p2p_GO_request(_adapter *padapter, u8 *raddr) +{ + + unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_GO_NEGO_REQ; + u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; + u8 wpsielen = 0, p2pielen = 0, i; + u8 channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh = 0; + u16 len_channellist_attr = 0; +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif + + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + RTW_INFO("[%s] In\n", __FUNCTION__); + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); + pwdinfo->negotiation_dialog_token = 1; /* Initialize the dialog value */ + pframe = rtw_set_fixed_ie(pframe, 1, &pwdinfo->negotiation_dialog_token, &(pattrib->pktlen)); + + + + /* WPS Section */ + wpsielen = 0; + /* WPS OUI */ + *(u32 *)(wpsie) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* WPS version */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ + + /* Device Password ID */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + + if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC); + else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN) + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); + else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC); + + wpsielen += 2; + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen); + + + /* P2P IE Section. */ + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20110306 */ + /* According to the P2P Specification, the group negoitation request frame should contain 9 P2P attributes */ + /* 1. P2P Capability */ + /* 2. Group Owner Intent */ + /* 3. Configuration Timeout */ + /* 4. Listen Channel */ + /* 5. Extended Listen Timing */ + /* 6. Intended P2P Interface Address */ + /* 7. Channel List */ + /* 8. P2P Device Info */ + /* 9. Operating Channel */ + + + /* P2P Capability */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; + + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; + else + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; + + + /* Group Owner Intent */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GO_INTENT; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: */ + /* Todo the tie breaker bit. */ + p2pie[p2pielen++] = ((pwdinfo->intent << 1) & 0xFE); + + /* Configuration Timeout */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ + + + /* Listen Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ + + /* Channel Number */ + p2pie[p2pielen++] = pwdinfo->listen_channel; /* listening channel number */ + + + /* Extended Listen Timing ATTR */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004); + p2pielen += 2; + + /* Value: */ + /* Availability Period */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); + p2pielen += 2; + + /* Availability Interval */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); + p2pielen += 2; + + + /* Intended P2P Interface Address */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_INTENDED_IF_ADDR; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); + p2pielen += 2; + + /* Value: */ + _rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN); + p2pielen += ETH_ALEN; + + + /* Channel List */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CH_LIST; + + /* Length: */ + /* Country String(3) */ + /* + ( Operating Class (1) + Number of Channels(1) ) * Operation Classes (?) */ + /* + number of channels in all classes */ + len_channellist_attr = 3 + + (1 + 1) * (u16)(pmlmeext->channel_list.reg_classes) + + get_reg_classes_full_count(pmlmeext->channel_list); + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(5 + 1); + else + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); +#else + + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); + +#endif + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Channel Entry List */ + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) { + u8 union_ch = rtw_mi_get_union_chan(padapter); + + /* Operating Class */ + if (union_ch > 14) { + if (union_ch >= 149) + p2pie[p2pielen++] = 0x7c; + else + p2pie[p2pielen++] = 0x73; + } else + p2pie[p2pielen++] = 0x51; + + + /* Number of Channels */ + /* Just support 1 channel and this channel is AP's channel */ + p2pie[p2pielen++] = 1; + + /* Channel List */ + p2pie[p2pielen++] = union_ch; + } else { + int i, j; + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } +#else /* CONFIG_CONCURRENT_MODE */ + { + int i, j; + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } +#endif /* CONFIG_CONCURRENT_MODE */ + + /* Device Info */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + /* 21->P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ + /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address */ + _rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Config Method */ + /* This field should be big endian. Noted by P2P specification. */ + + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); + + p2pielen += 2; + + /* Primary Device Type */ + /* Category ID */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + p2pielen += 2; + + /* OUI */ + *(u32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + p2pielen += 2; + + /* Number of Secondary Device Types */ + p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ + + /* Device Name */ + /* Type: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + p2pielen += 2; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->device_name , pwdinfo->device_name_len); + p2pielen += pwdinfo->device_name_len; + + + /* Operating Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + if (pwdinfo->operating_channel <= 14) { + /* Operating Class */ + p2pie[p2pielen++] = 0x51; + } else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48)) { + /* Operating Class */ + p2pie[p2pielen++] = 0x73; + } else { + /* Operating Class */ + p2pie[p2pielen++] = 0x7c; + } + + /* Channel Number */ + p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen); + +#ifdef CONFIG_WFD + wfdielen = build_nego_req_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + + return; + +} + + +void issue_p2p_GO_response(_adapter *padapter, u8 *raddr, u8 *frame_body, uint len, u8 result) +{ + + unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_GO_NEGO_RESP; + u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; + u8 p2pielen = 0, i; + uint wpsielen = 0; + u16 wps_devicepassword_id = 0x0000; + uint wps_devicepassword_id_len = 0; + u8 channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh; + u16 len_channellist_attr = 0; + + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + RTW_INFO("[%s] In, result = %d\n", __FUNCTION__, result); + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); + pwdinfo->negotiation_dialog_token = frame_body[7]; /* The Dialog Token of provisioning discovery request frame. */ + pframe = rtw_set_fixed_ie(pframe, 1, &(pwdinfo->negotiation_dialog_token), &(pattrib->pktlen)); + + /* Commented by Albert 20110328 */ + /* Try to get the device password ID from the WPS IE of group negotiation request frame */ + /* WiFi Direct test plan 5.1.15 */ + rtw_get_wps_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, &wpsielen); + rtw_get_wps_attr_content(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID, (u8 *) &wps_devicepassword_id, &wps_devicepassword_id_len); + wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id); + + _rtw_memset(wpsie, 0x00, 255); + wpsielen = 0; + + /* WPS Section */ + wpsielen = 0; + /* WPS OUI */ + *(u32 *)(wpsie) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* WPS version */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ + + /* Device Password ID */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + if (wps_devicepassword_id == WPS_DPID_USER_SPEC) + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); + else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC); + else + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC); + wpsielen += 2; + + /* Commented by Kurt 20120113 */ + /* If some device wants to do p2p handshake without sending prov_disc_req */ + /* We have to get peer_req_cm from here. */ + if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) { + if (wps_devicepassword_id == WPS_DPID_USER_SPEC) + _rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3); + else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) + _rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3); + else + _rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3); + } + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen); + + + /* P2P IE Section. */ + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20100908 */ + /* According to the P2P Specification, the group negoitation response frame should contain 9 P2P attributes */ + /* 1. Status */ + /* 2. P2P Capability */ + /* 3. Group Owner Intent */ + /* 4. Configuration Timeout */ + /* 5. Operating Channel */ + /* 6. Intended P2P Interface Address */ + /* 7. Channel List */ + /* 8. Device Info */ + /* 9. Group ID ( Only GO ) */ + + + /* ToDo: */ + + /* P2P Status */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_STATUS; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: */ + p2pie[p2pielen++] = result; + + /* P2P Capability */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { + /* Commented by Albert 2011/03/08 */ + /* According to the P2P specification */ + /* if the sending device will be client, the P2P Capability should be reserved of group negotation response frame */ + p2pie[p2pielen++] = 0; + } else { + /* Be group owner or meet the error case */ + p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; + } + + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; + else + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; + + /* Group Owner Intent */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GO_INTENT; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: */ + if (pwdinfo->peer_intent & 0x01) { + /* Peer's tie breaker bit is 1, our tie breaker bit should be 0 */ + p2pie[p2pielen++] = (pwdinfo->intent << 1); + } else { + /* Peer's tie breaker bit is 0, our tie breaker bit should be 1 */ + p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0)); + } + + + /* Configuration Timeout */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ + + /* Operating Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + if (pwdinfo->operating_channel <= 14) { + /* Operating Class */ + p2pie[p2pielen++] = 0x51; + } else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48)) { + /* Operating Class */ + p2pie[p2pielen++] = 0x73; + } else { + /* Operating Class */ + p2pie[p2pielen++] = 0x7c; + } + + /* Channel Number */ + p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ + + /* Intended P2P Interface Address */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_INTENDED_IF_ADDR; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); + p2pielen += 2; + + /* Value: */ + _rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Channel List */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CH_LIST; + + /* Country String(3) */ + /* + ( Operating Class (1) + Number of Channels(1) ) * Operation Classes (?) */ + /* + number of channels in all classes */ + len_channellist_attr = 3 + + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes + + get_reg_classes_full_count(pmlmeext->channel_list); + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(5 + 1); + else + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); +#else + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); + +#endif + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Channel Entry List */ + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) { + + u8 union_chan = rtw_mi_get_union_chan(padapter); + + /*Operating Class*/ + if (union_chan > 14) { + if (union_chan >= 149) + p2pie[p2pielen++] = 0x7c; + else + p2pie[p2pielen++] = 0x73; + + } else + p2pie[p2pielen++] = 0x51; + + /* Number of Channels + Just support 1 channel and this channel is AP's channel*/ + p2pie[p2pielen++] = 1; + + /*Channel List*/ + p2pie[p2pielen++] = union_chan; + } else { + int i, j; + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } +#else /* CONFIG_CONCURRENT_MODE */ + { + int i, j; + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } +#endif /* CONFIG_CONCURRENT_MODE */ + + + /* Device Info */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + /* 21->P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ + /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address */ + _rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Config Method */ + /* This field should be big endian. Noted by P2P specification. */ + + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); + + p2pielen += 2; + + /* Primary Device Type */ + /* Category ID */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + p2pielen += 2; + + /* OUI */ + *(u32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + p2pielen += 2; + + /* Number of Secondary Device Types */ + p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ + + /* Device Name */ + /* Type: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + p2pielen += 2; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->device_name , pwdinfo->device_name_len); + p2pielen += pwdinfo->device_name_len; + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + /* Group ID Attribute */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen); + p2pielen += 2; + + /* Value: */ + /* p2P Device Address */ + _rtw_memcpy(p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN); + p2pielen += ETH_ALEN; + + /* SSID */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); + p2pielen += pwdinfo->nego_ssidlen; + + } + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen); + +#ifdef CONFIG_WFD + wfdielen = build_nego_resp_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + + return; + +} + +void issue_p2p_GO_confirm(_adapter *padapter, u8 *raddr, u8 result) +{ + + unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_GO_NEGO_CONF; + u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; + u8 wpsielen = 0, p2pielen = 0; + + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + RTW_INFO("[%s] In\n", __FUNCTION__); + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(pwdinfo->negotiation_dialog_token), &(pattrib->pktlen)); + + + + /* P2P IE Section. */ + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20110306 */ + /* According to the P2P Specification, the group negoitation request frame should contain 5 P2P attributes */ + /* 1. Status */ + /* 2. P2P Capability */ + /* 3. Operating Channel */ + /* 4. Channel List */ + /* 5. Group ID ( if this WiFi is GO ) */ + + /* P2P Status */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_STATUS; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: */ + p2pie[p2pielen++] = result; + + /* P2P Capability */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; + + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; + else + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; + + + /* Operating Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { + if (pwdinfo->peer_operating_ch <= 14) { + /* Operating Class */ + p2pie[p2pielen++] = 0x51; + } else if ((pwdinfo->peer_operating_ch >= 36) && (pwdinfo->peer_operating_ch <= 48)) { + /* Operating Class */ + p2pie[p2pielen++] = 0x73; + } else { + /* Operating Class */ + p2pie[p2pielen++] = 0x7c; + } + + p2pie[p2pielen++] = pwdinfo->peer_operating_ch; + } else { + if (pwdinfo->operating_channel <= 14) { + /* Operating Class */ + p2pie[p2pielen++] = 0x51; + } else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48)) { + /* Operating Class */ + p2pie[p2pielen++] = 0x73; + } else { + /* Operating Class */ + p2pie[p2pielen++] = 0x7c; + } + + /* Channel Number */ + p2pie[p2pielen++] = pwdinfo->operating_channel; /* Use the listen channel as the operating channel */ + } + + + /* Channel List */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CH_LIST; + + *(u16 *)(p2pie + p2pielen) = 6; + p2pielen += 2; + + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Value: */ + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { + if (pwdinfo->peer_operating_ch <= 14) { + /* Operating Class */ + p2pie[p2pielen++] = 0x51; + } else if ((pwdinfo->peer_operating_ch >= 36) && (pwdinfo->peer_operating_ch <= 48)) { + /* Operating Class */ + p2pie[p2pielen++] = 0x73; + } else { + /* Operating Class */ + p2pie[p2pielen++] = 0x7c; + } + p2pie[p2pielen++] = 1; + p2pie[p2pielen++] = pwdinfo->peer_operating_ch; + } else { + if (pwdinfo->operating_channel <= 14) { + /* Operating Class */ + p2pie[p2pielen++] = 0x51; + } else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48)) { + /* Operating Class */ + p2pie[p2pielen++] = 0x73; + } else { + /* Operating Class */ + p2pie[p2pielen++] = 0x7c; + } + + /* Channel Number */ + p2pie[p2pielen++] = 1; + p2pie[p2pielen++] = pwdinfo->operating_channel; /* Use the listen channel as the operating channel */ + } + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + /* Group ID Attribute */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen); + p2pielen += 2; + + /* Value: */ + /* p2P Device Address */ + _rtw_memcpy(p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN); + p2pielen += ETH_ALEN; + + /* SSID */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); + p2pielen += pwdinfo->nego_ssidlen; + } + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen); + +#ifdef CONFIG_WFD + wfdielen = build_nego_confirm_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + + return; + +} + +void issue_p2p_invitation_request(_adapter *padapter, u8 *raddr) +{ + + unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_INVIT_REQ; + u8 p2pie[255] = { 0x00 }; + u8 p2pielen = 0, i; + u8 dialogToken = 3; + u8 channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh = 0; + u16 len_channellist_attr = 0; +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif + + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, raddr, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); + + /* P2P IE Section. */ + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20101011 */ + /* According to the P2P Specification, the P2P Invitation request frame should contain 7 P2P attributes */ + /* 1. Configuration Timeout */ + /* 2. Invitation Flags */ + /* 3. Operating Channel ( Only GO ) */ + /* 4. P2P Group BSSID ( Should be included if I am the GO ) */ + /* 5. Channel List */ + /* 6. P2P Group ID */ + /* 7. P2P Device Info */ + + /* Configuration Timeout */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ + + /* Invitation Flags */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_INVITATION_FLAGS; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: */ + p2pie[p2pielen++] = P2P_INVITATION_FLAGS_PERSISTENT; + + + /* Operating Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + if (pwdinfo->invitereq_info.operating_ch <= 14) + p2pie[p2pielen++] = 0x51; + else if ((pwdinfo->invitereq_info.operating_ch >= 36) && (pwdinfo->invitereq_info.operating_ch <= 48)) + p2pie[p2pielen++] = 0x73; + else + p2pie[p2pielen++] = 0x7c; + + /* Channel Number */ + p2pie[p2pielen++] = pwdinfo->invitereq_info.operating_ch; /* operating channel number */ + + if (_rtw_memcmp(adapter_mac_addr(padapter), pwdinfo->invitereq_info.go_bssid, ETH_ALEN)) { + /* P2P Group BSSID */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address for GO */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN); + p2pielen += ETH_ALEN; + } + + /* Channel List */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CH_LIST; + + + /* Length: */ + /* Country String(3) */ + /* + ( Operating Class (1) + Number of Channels(1) ) * Operation Classes (?) */ + /* + number of channels in all classes */ + len_channellist_attr = 3 + + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes + + get_reg_classes_full_count(pmlmeext->channel_list); + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(5 + 1); + else + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); +#else + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); +#endif + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Channel Entry List */ +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) { + u8 union_ch = rtw_mi_get_union_chan(padapter); + + /* Operating Class */ + if (union_ch > 14) { + if (union_ch >= 149) + p2pie[p2pielen++] = 0x7c; + else + p2pie[p2pielen++] = 0x73; + } else + p2pie[p2pielen++] = 0x51; + + + /* Number of Channels */ + /* Just support 1 channel and this channel is AP's channel */ + p2pie[p2pielen++] = 1; + + /* Channel List */ + p2pie[p2pielen++] = union_ch; + } else { + int i, j; + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } +#else /* CONFIG_CONCURRENT_MODE */ + { + int i, j; + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } +#endif /* CONFIG_CONCURRENT_MODE */ + + + /* P2P Group ID */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(6 + pwdinfo->invitereq_info.ssidlen); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address for GO */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN); + p2pielen += ETH_ALEN; + + /* SSID */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_ssid, pwdinfo->invitereq_info.ssidlen); + p2pielen += pwdinfo->invitereq_info.ssidlen; + + + /* Device Info */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + /* 21->P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ + /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address */ + _rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Config Method */ + /* This field should be big endian. Noted by P2P specification. */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); + p2pielen += 2; + + /* Primary Device Type */ + /* Category ID */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + p2pielen += 2; + + /* OUI */ + *(u32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + p2pielen += 2; + + /* Number of Secondary Device Types */ + p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ + + /* Device Name */ + /* Type: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + p2pielen += 2; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); + p2pielen += pwdinfo->device_name_len; + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen); + +#ifdef CONFIG_WFD + wfdielen = build_invitation_req_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + + return; + +} + +void issue_p2p_invitation_response(_adapter *padapter, u8 *raddr, u8 dialogToken, u8 status_code) +{ + + unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_INVIT_RESP; + u8 p2pie[255] = { 0x00 }; + u8 p2pielen = 0, i; + u8 channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh = 0; + u16 len_channellist_attr = 0; +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif + + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, raddr, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); + + /* P2P IE Section. */ + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20101005 */ + /* According to the P2P Specification, the P2P Invitation response frame should contain 5 P2P attributes */ + /* 1. Status */ + /* 2. Configuration Timeout */ + /* 3. Operating Channel ( Only GO ) */ + /* 4. P2P Group BSSID ( Only GO ) */ + /* 5. Channel List */ + + /* P2P Status */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_STATUS; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: */ + /* When status code is P2P_STATUS_FAIL_INFO_UNAVAILABLE. */ + /* Sent the event receiving the P2P Invitation Req frame to DMP UI. */ + /* DMP had to compare the MAC address to find out the profile. */ + /* So, the WiFi driver will send the P2P_STATUS_FAIL_INFO_UNAVAILABLE to NB. */ + /* If the UI found the corresponding profile, the WiFi driver sends the P2P Invitation Req */ + /* to NB to rebuild the persistent group. */ + p2pie[p2pielen++] = status_code; + + /* Configuration Timeout */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ + + if (status_code == P2P_STATUS_SUCCESS) { + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + /* The P2P Invitation request frame asks this Wi-Fi device to be the P2P GO */ + /* In this case, the P2P Invitation response frame should carry the two more P2P attributes. */ + /* First one is operating channel attribute. */ + /* Second one is P2P Group BSSID attribute. */ + + /* Operating Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ + + /* Channel Number */ + p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ + + + /* P2P Group BSSID */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address for GO */ + _rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN); + p2pielen += ETH_ALEN; + + } + + /* Channel List */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CH_LIST; + + /* Length: */ + /* Country String(3) */ + /* + ( Operating Class (1) + Number of Channels(1) ) * Operation Classes (?) */ + /* + number of channels in all classes */ + len_channellist_attr = 3 + + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes + + get_reg_classes_full_count(pmlmeext->channel_list); + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(5 + 1); + else + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); +#else + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); +#endif + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Channel Entry List */ +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) { + u8 union_ch = rtw_mi_get_union_chan(padapter); + + /* Operating Class */ + if (union_ch > 14) { + if (union_ch >= 149) + p2pie[p2pielen++] = 0x7c; + else + p2pie[p2pielen++] = 0x73; + } else + p2pie[p2pielen++] = 0x51; + + + /* Number of Channels */ + /* Just support 1 channel and this channel is AP's channel */ + p2pie[p2pielen++] = 1; + + /* Channel List */ + p2pie[p2pielen++] = union_ch; + } else { + int i, j; + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } +#else /* CONFIG_CONCURRENT_MODE */ + { + int i, j; + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } +#endif /* CONFIG_CONCURRENT_MODE */ + } + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen); + +#ifdef CONFIG_WFD + wfdielen = build_invitation_resp_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + + return; + +} + +void issue_p2p_provision_request(_adapter *padapter, u8 *pssid, u8 ussidlen, u8 *pdev_raddr) +{ + unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u8 dialogToken = 1; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_PROVISION_DISC_REQ; + u8 wpsie[100] = { 0x00 }; + u8 wpsielen = 0; + u32 p2pielen = 0; +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif + + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + RTW_INFO("[%s] In\n", __FUNCTION__); + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, pdev_raddr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, pdev_raddr, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); + + p2pielen = build_prov_disc_request_p2p_ie(pwdinfo, pframe, pssid, ussidlen, pdev_raddr); + + pframe += p2pielen; + pattrib->pktlen += p2pielen; + + wpsielen = 0; + /* WPS OUI */ + *(u32 *)(wpsie) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* WPS version */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ + + /* Config Method */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request); + wpsielen += 2; + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen); + + +#ifdef CONFIG_WFD + wfdielen = build_provdisc_req_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + + return; + +} + + +u8 is_matched_in_profilelist(u8 *peermacaddr, struct profile_info *profileinfo) +{ + u8 i, match_result = 0; + + RTW_INFO("[%s] peermac = %.2X %.2X %.2X %.2X %.2X %.2X\n", __FUNCTION__, + peermacaddr[0], peermacaddr[1], peermacaddr[2], peermacaddr[3], peermacaddr[4], peermacaddr[5]); + + for (i = 0; i < P2P_MAX_PERSISTENT_GROUP_NUM; i++, profileinfo++) { + RTW_INFO("[%s] profileinfo_mac = %.2X %.2X %.2X %.2X %.2X %.2X\n", __FUNCTION__, + profileinfo->peermac[0], profileinfo->peermac[1], profileinfo->peermac[2], profileinfo->peermac[3], profileinfo->peermac[4], profileinfo->peermac[5]); + if (_rtw_memcmp(peermacaddr, profileinfo->peermac, ETH_ALEN)) { + match_result = 1; + RTW_INFO("[%s] Match!\n", __FUNCTION__); + break; + } + } + + return match_result ; +} + +void issue_probersp_p2p(_adapter *padapter, unsigned char *da) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned char *mac; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + /* WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); */ + u16 beacon_interval = 100; + u16 capInfo = 0; + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + u8 wpsie[255] = { 0x00 }; + u32 wpsielen = 0, p2pielen = 0; +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif +#ifdef CONFIG_INTEL_WIDI + u8 zero_array_check[L2SDTA_SERVICE_VE_LEN] = { 0x00 }; +#endif /* CONFIG_INTEL_WIDI */ + + /* RTW_INFO("%s\n", __FUNCTION__); */ + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + if (IS_CCK_RATE(pattrib->rate)) { + /* force OFDM 6M rate */ + pattrib->rate = MGN_6M; + pattrib->raid = rtw_get_mgntframe_raid(padapter, WIRELESS_11G); + } + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + mac = adapter_mac_addr(padapter); + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); + + /* Use the device address for BSSID field. */ + _rtw_memcpy(pwlanhdr->addr3, mac, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(fctrl, WIFI_PROBERSP); + + pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = pattrib->hdrlen; + pframe += pattrib->hdrlen; + + /* timestamp will be inserted by hardware */ + pframe += 8; + pattrib->pktlen += 8; + + /* beacon interval: 2 bytes */ + _rtw_memcpy(pframe, (unsigned char *) &beacon_interval, 2); + pframe += 2; + pattrib->pktlen += 2; + + /* capability info: 2 bytes */ + /* ESS and IBSS bits must be 0 (defined in the 3.1.2.1.1 of WiFi Direct Spec) */ + capInfo |= cap_ShortPremble; + capInfo |= cap_ShortSlot; + + _rtw_memcpy(pframe, (unsigned char *) &capInfo, 2); + pframe += 2; + pattrib->pktlen += 2; + + + /* SSID */ + pframe = rtw_set_ie(pframe, _SSID_IE_, 7, pwdinfo->p2p_wildcard_ssid, &pattrib->pktlen); + + /* supported rates... */ + /* Use the OFDM rate in the P2P probe response frame. ( 6(B), 9(B), 12, 18, 24, 36, 48, 54 ) */ + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pattrib->pktlen); + + /* DS parameter set */ + pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&pwdinfo->listen_channel, &pattrib->pktlen); + +#ifdef CONFIG_IOCTL_CFG80211 + if (adapter_wdev_data(padapter)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211) { + if (pmlmepriv->wps_probe_resp_ie != NULL && pmlmepriv->p2p_probe_resp_ie != NULL) { + /* WPS IE */ + _rtw_memcpy(pframe, pmlmepriv->wps_probe_resp_ie, pmlmepriv->wps_probe_resp_ie_len); + pattrib->pktlen += pmlmepriv->wps_probe_resp_ie_len; + pframe += pmlmepriv->wps_probe_resp_ie_len; + + /* P2P IE */ + _rtw_memcpy(pframe, pmlmepriv->p2p_probe_resp_ie, pmlmepriv->p2p_probe_resp_ie_len); + pattrib->pktlen += pmlmepriv->p2p_probe_resp_ie_len; + pframe += pmlmepriv->p2p_probe_resp_ie_len; + } + } else +#endif /* CONFIG_IOCTL_CFG80211 */ + { + + /* Todo: WPS IE */ + /* Noted by Albert 20100907 */ + /* According to the WPS specification, all the WPS attribute is presented by Big Endian. */ + + wpsielen = 0; + /* WPS OUI */ + *(u32 *)(wpsie) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* WPS version */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ + +#ifdef CONFIG_INTEL_WIDI + /* Commented by Kurt */ + /* Appended WiDi info. only if we did issued_probereq_widi(), and then we saved ven. ext. in pmlmepriv->sa_ext. */ + if (_rtw_memcmp(pmlmepriv->sa_ext, zero_array_check, L2SDTA_SERVICE_VE_LEN) == _FALSE + || pmlmepriv->num_p2p_sdt != 0) { + /* Sec dev type */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SEC_DEV_TYPE_LIST); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008); + wpsielen += 2; + + /* Value: */ + /* Category ID */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_DISPLAYS); + wpsielen += 2; + + /* OUI */ + *(u32 *)(wpsie + wpsielen) = cpu_to_be32(INTEL_DEV_TYPE_OUI); + wpsielen += 4; + + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_WIDI_CONSUMER_SINK); + wpsielen += 2; + + if (_rtw_memcmp(pmlmepriv->sa_ext, zero_array_check, L2SDTA_SERVICE_VE_LEN) == _FALSE) { + /* Vendor Extension */ + _rtw_memcpy(wpsie + wpsielen, pmlmepriv->sa_ext, L2SDTA_SERVICE_VE_LEN); + wpsielen += L2SDTA_SERVICE_VE_LEN; + } + } +#endif /* CONFIG_INTEL_WIDI */ + + /* WiFi Simple Config State */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SIMPLE_CONF_STATE); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_WSC_STATE_NOT_CONFIG; /* Not Configured. */ + + /* Response Type */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_RESP_TYPE); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_RESPONSE_TYPE_8021X; + + /* UUID-E */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010); + wpsielen += 2; + + /* Value: */ + if (pwdinfo->external_uuid == 0) { + _rtw_memset(wpsie + wpsielen, 0x0, 16); + _rtw_memcpy(wpsie + wpsielen, mac, ETH_ALEN); + } else + _rtw_memcpy(wpsie + wpsielen, pwdinfo->uuid, 0x10); + wpsielen += 0x10; + + /* Manufacturer */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MANUFACTURER); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0007); + wpsielen += 2; + + /* Value: */ + _rtw_memcpy(wpsie + wpsielen, "Realtek", 7); + wpsielen += 7; + + /* Model Name */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NAME); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0006); + wpsielen += 2; + + /* Value: */ + _rtw_memcpy(wpsie + wpsielen, "8192CU", 6); + wpsielen += 6; + + /* Model Number */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NUMBER); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = 0x31; /* character 1 */ + + /* Serial Number */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SERIAL_NUMBER); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(ETH_ALEN); + wpsielen += 2; + + /* Value: */ + _rtw_memcpy(wpsie + wpsielen, "123456" , ETH_ALEN); + wpsielen += ETH_ALEN; + + /* Primary Device Type */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008); + wpsielen += 2; + + /* Value: */ + /* Category ID */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + wpsielen += 2; + + /* OUI */ + *(u32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* Sub Category ID */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + wpsielen += 2; + + /* Device Name */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len); + wpsielen += 2; + + /* Value: */ + _rtw_memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len); + wpsielen += pwdinfo->device_name_len; + + /* Config Method */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm); + wpsielen += 2; + + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen); + + + p2pielen = build_probe_resp_p2p_ie(pwdinfo, pframe); + pframe += p2pielen; + pattrib->pktlen += p2pielen; + } + +#ifdef CONFIG_WFD + wfdielen = rtw_append_probe_resp_wfd_ie(padapter, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif + + pattrib->last_txcmdsz = pattrib->pktlen; + + + dump_mgntframe(padapter, pmgntframe); + + return; + +} + +int _issue_probereq_p2p(_adapter *padapter, u8 *da, int wait_ack) +{ + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned char *mac; + unsigned char bssrate[NumRates]; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + int bssrate_len = 0; + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; + u16 wpsielen = 0, p2pielen = 0; +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif + + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + if (IS_CCK_RATE(pattrib->rate)) { + /* force OFDM 6M rate */ + pattrib->rate = MGN_6M; + pattrib->raid = rtw_get_mgntframe_raid(padapter, WIRELESS_11G); + } + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + mac = adapter_mac_addr(padapter); + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + if (da) { + _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, da, ETH_ALEN); + } else { + if ((pwdinfo->p2p_info.scan_op_ch_only) || (pwdinfo->rx_invitereq_info.scan_op_ch_only)) { + /* This two flags will be set when this is only the P2P client mode. */ + _rtw_memcpy(pwlanhdr->addr1, pwdinfo->p2p_peer_interface_addr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, pwdinfo->p2p_peer_interface_addr, ETH_ALEN); + } else { + /* broadcast probe request frame */ + _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); + } + } + _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_PROBEREQ); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) + pframe = rtw_set_ie(pframe, _SSID_IE_, pwdinfo->tx_prov_disc_info.ssid.SsidLength, pwdinfo->tx_prov_disc_info.ssid.Ssid, &(pattrib->pktlen)); + else + pframe = rtw_set_ie(pframe, _SSID_IE_, P2P_WILDCARD_SSID_LEN, pwdinfo->p2p_wildcard_ssid, &(pattrib->pktlen)); + /* Use the OFDM rate in the P2P probe request frame. ( 6(B), 9(B), 12(B), 24(B), 36, 48, 54 ) */ + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pattrib->pktlen); + +#ifdef CONFIG_IOCTL_CFG80211 + if (adapter_wdev_data(padapter)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211) { + if (pmlmepriv->wps_probe_req_ie != NULL && pmlmepriv->p2p_probe_req_ie != NULL) { + /* WPS IE */ + _rtw_memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len); + pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; + pframe += pmlmepriv->wps_probe_req_ie_len; + + /* P2P IE */ + _rtw_memcpy(pframe, pmlmepriv->p2p_probe_req_ie, pmlmepriv->p2p_probe_req_ie_len); + pattrib->pktlen += pmlmepriv->p2p_probe_req_ie_len; + pframe += pmlmepriv->p2p_probe_req_ie_len; + } + } else +#endif /* CONFIG_IOCTL_CFG80211 */ + { + + /* WPS IE */ + /* Noted by Albert 20110221 */ + /* According to the WPS specification, all the WPS attribute is presented by Big Endian. */ + + wpsielen = 0; + /* WPS OUI */ + *(u32 *)(wpsie) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* WPS version */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ + + if (pmlmepriv->wps_probe_req_ie == NULL) { + /* UUID-E */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010); + wpsielen += 2; + + /* Value: */ + if (pwdinfo->external_uuid == 0) { + _rtw_memset(wpsie + wpsielen, 0x0, 16); + _rtw_memcpy(wpsie + wpsielen, mac, ETH_ALEN); + } else + _rtw_memcpy(wpsie + wpsielen, pwdinfo->uuid, 0x10); + wpsielen += 0x10; + + /* Config Method */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm); + wpsielen += 2; + } + + /* Device Name */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len); + wpsielen += 2; + + /* Value: */ + _rtw_memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len); + wpsielen += pwdinfo->device_name_len; + + /* Primary Device Type */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008); + wpsielen += 2; + + /* Value: */ + /* Category ID */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_RTK_WIDI); + wpsielen += 2; + + /* OUI */ + *(u32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* Sub Category ID */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_RTK_DMP); + wpsielen += 2; + + /* Device Password ID */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); /* Registrar-specified */ + wpsielen += 2; + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen); + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20110221 */ + /* According to the P2P Specification, the probe request frame should contain 5 P2P attributes */ + /* 1. P2P Capability */ + /* 2. P2P Device ID if this probe request wants to find the specific P2P device */ + /* 3. Listen Channel */ + /* 4. Extended Listen Timing */ + /* 5. Operating Channel if this WiFi is working as the group owner now */ + + /* P2P Capability */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; + + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) + p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; + else + p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; + + /* Listen Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ + + /* Channel Number */ + p2pie[p2pielen++] = pwdinfo->listen_channel; /* listen channel */ + + + /* Extended Listen Timing */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004); + p2pielen += 2; + + /* Value: */ + /* Availability Period */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); + p2pielen += 2; + + /* Availability Interval */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); + p2pielen += 2; + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + /* Operating Channel (if this WiFi is working as the group owner now) */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ + + /* Channel Number */ + p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ + + } + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen); + + } + +#ifdef CONFIG_WFD + wfdielen = rtw_append_probe_req_wfd_ie(padapter, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif + + pattrib->last_txcmdsz = pattrib->pktlen; + + + if (wait_ack) + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + } + +exit: + return ret; +} + +inline void issue_probereq_p2p(_adapter *adapter, u8 *da) +{ + _issue_probereq_p2p(adapter, da, _FALSE); +} + +/* + * wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT + * wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX + * try_cnt means the maximal TX count to try + */ +int issue_probereq_p2p_ex(_adapter *adapter, u8 *da, int try_cnt, int wait_ms) +{ + int ret; + int i = 0; + u32 start = rtw_get_current_time(); + + do { + ret = _issue_probereq_p2p(adapter, da, wait_ms > 0 ? _TRUE : _FALSE); + + i++; + + if (RTW_CANNOT_RUN(adapter)) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + rtw_msleep_os(wait_ms); + + } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + + if (ret != _FAIL) { + ret = _SUCCESS; +#ifndef DBG_XMIT_ACK + goto exit; +#endif + } + + if (try_cnt && wait_ms) { + if (da) + RTW_INFO(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(adapter), MAC_ARG(da), rtw_get_oper_ch(adapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + else + RTW_INFO(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(adapter), rtw_get_oper_ch(adapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + } +exit: + return ret; +} + +#endif /* CONFIG_P2P */ + +s32 rtw_action_public_decache(union recv_frame *rframe, u8 token_offset) +{ + _adapter *adapter = rframe->u.hdr.adapter; + struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv); + u8 *frame = rframe->u.hdr.rx_data; + u16 seq_ctrl = ((rframe->u.hdr.attrib.seq_num & 0xffff) << 4) | (rframe->u.hdr.attrib.frag_num & 0xf); + u8 token = *(rframe->u.hdr.rx_data + sizeof(struct rtw_ieee80211_hdr_3addr) + token_offset); + + if (GetRetry(frame)) { + if ((seq_ctrl == mlmeext->action_public_rxseq) + && (token == mlmeext->action_public_dialog_token) + ) { + RTW_INFO(FUNC_ADPT_FMT" seq_ctrl=0x%x, rxseq=0x%x, token:%d\n", + FUNC_ADPT_ARG(adapter), seq_ctrl, mlmeext->action_public_rxseq, token); + return _FAIL; + } + } + + /* TODO: per sta seq & token */ + mlmeext->action_public_rxseq = seq_ctrl; + mlmeext->action_public_dialog_token = token; + + return _SUCCESS; +} + +unsigned int on_action_public_p2p(union recv_frame *precv_frame) +{ + _adapter *padapter = precv_frame->u.hdr.adapter; + u8 *pframe = precv_frame->u.hdr.rx_data; + uint len = precv_frame->u.hdr.len; + u8 *frame_body; +#ifdef CONFIG_P2P + u8 *p2p_ie; + u32 p2p_ielen, wps_ielen; + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + u8 result = P2P_STATUS_SUCCESS; + u8 empty_addr[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + u8 *merged_p2pie = NULL; + u32 merged_p2p_ielen = 0; +#endif /* CONFIG_P2P */ + + frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); + +#ifdef CONFIG_P2P + _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); +#ifdef CONFIG_IOCTL_CFG80211 + if (adapter_wdev_data(padapter)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211) + rtw_cfg80211_rx_p2p_action_public(padapter, precv_frame); + else +#endif /* CONFIG_IOCTL_CFG80211 */ + { + /* Do nothing if the driver doesn't enable the P2P function. */ + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) + return _SUCCESS; + + len -= sizeof(struct rtw_ieee80211_hdr_3addr); + + switch (frame_body[6]) { /* OUI Subtype */ + case P2P_GO_NEGO_REQ: { + RTW_INFO("[%s] Got GO Nego Req Frame\n", __FUNCTION__); + _rtw_memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info)); + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) + rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) { + /* Commented by Albert 20110526 */ + /* In this case, this means the previous nego fail doesn't be reset yet. */ + _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); + /* Restore the previous p2p state */ + rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); + RTW_INFO("[%s] Restore the previous p2p state to %d\n", __FUNCTION__, rtw_p2p_state(pwdinfo)); + } +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_buddy_check_fwstate(padapter, _FW_LINKED)) + _cancel_timer_ex(&pwdinfo->ap_p2p_switch_timer); +#endif /* CONFIG_CONCURRENT_MODE */ + + /* Commented by Kurt 20110902 */ + /* Add if statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */ + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) + rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); + + /* Commented by Kurt 20120113 */ + /* Get peer_dev_addr here if peer doesn't issue prov_disc frame. */ + if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.peerDevAddr, empty_addr, ETH_ALEN)) + _rtw_memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, get_addr2_ptr(pframe), ETH_ALEN); + + result = process_p2p_group_negotation_req(pwdinfo, frame_body, len); + issue_p2p_GO_response(padapter, get_addr2_ptr(pframe), frame_body, len, result); +#ifdef CONFIG_INTEL_WIDI + if (padapter->mlmepriv.widi_state == INTEL_WIDI_STATE_LISTEN) { + padapter->mlmepriv.widi_state = INTEL_WIDI_STATE_WFD_CONNECTION; + _cancel_timer_ex(&(padapter->mlmepriv.listen_timer)); + intel_widi_wk_cmd(padapter, INTEL_WIDI_LISTEN_STOP_WK, NULL, 0); + } +#endif /* CONFIG_INTEL_WIDI */ + + /* Commented by Albert 20110718 */ + /* No matter negotiating or negotiation failure, the driver should set up the restore P2P state timer. */ +#ifdef CONFIG_CONCURRENT_MODE + /* Commented by Albert 20120107 */ + _set_timer(&pwdinfo->restore_p2p_state_timer, 3000); +#else /* CONFIG_CONCURRENT_MODE */ + _set_timer(&pwdinfo->restore_p2p_state_timer, 5000); +#endif /* CONFIG_CONCURRENT_MODE */ + break; + } + case P2P_GO_NEGO_RESP: { + RTW_INFO("[%s] Got GO Nego Resp Frame\n", __FUNCTION__); + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) { + /* Commented by Albert 20110425 */ + /* The restore timer is enabled when issuing the nego request frame of rtw_p2p_connect function. */ + _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); + pwdinfo->nego_req_info.benable = _FALSE; + result = process_p2p_group_negotation_resp(pwdinfo, frame_body, len); + issue_p2p_GO_confirm(pwdinfo->padapter, get_addr2_ptr(pframe), result); + if (P2P_STATUS_SUCCESS == result) { + if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT) { + pwdinfo->p2p_info.operation_ch[0] = pwdinfo->peer_operating_ch; +#ifdef CONFIG_P2P_OP_CHK_SOCIAL_CH + pwdinfo->p2p_info.operation_ch[1] = 1; /* Check whether GO is operating in channel 1; */ + pwdinfo->p2p_info.operation_ch[2] = 6; /* Check whether GO is operating in channel 6; */ + pwdinfo->p2p_info.operation_ch[3] = 11; /* Check whether GO is operating in channel 11; */ +#endif /* CONFIG_P2P_OP_CHK_SOCIAL_CH */ + pwdinfo->p2p_info.scan_op_ch_only = 1; + _set_timer(&pwdinfo->reset_ch_sitesurvey2, P2P_RESET_SCAN_CH); + } + } + + /* Reset the dialog token for group negotiation frames. */ + pwdinfo->negotiation_dialog_token = 1; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) + _set_timer(&pwdinfo->restore_p2p_state_timer, 5000); + } else + RTW_INFO("[%s] Skipped GO Nego Resp Frame (p2p_state != P2P_STATE_GONEGO_ING)\n", __FUNCTION__); + + break; + } + case P2P_GO_NEGO_CONF: { + RTW_INFO("[%s] Got GO Nego Confirm Frame\n", __FUNCTION__); + result = process_p2p_group_negotation_confirm(pwdinfo, frame_body, len); + if (P2P_STATUS_SUCCESS == result) { + if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT) { + pwdinfo->p2p_info.operation_ch[0] = pwdinfo->peer_operating_ch; +#ifdef CONFIG_P2P_OP_CHK_SOCIAL_CH + pwdinfo->p2p_info.operation_ch[1] = 1; /* Check whether GO is operating in channel 1; */ + pwdinfo->p2p_info.operation_ch[2] = 6; /* Check whether GO is operating in channel 6; */ + pwdinfo->p2p_info.operation_ch[3] = 11; /* Check whether GO is operating in channel 11; */ +#endif /* CONFIG_P2P_OP_CHK_SOCIAL_CH */ + pwdinfo->p2p_info.scan_op_ch_only = 1; + _set_timer(&pwdinfo->reset_ch_sitesurvey2, P2P_RESET_SCAN_CH); + } + } + break; + } + case P2P_INVIT_REQ: { + /* Added by Albert 2010/10/05 */ + /* Received the P2P Invite Request frame. */ + + RTW_INFO("[%s] Got invite request frame!\n", __FUNCTION__); + p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen); + if (p2p_ie) { + /* Parse the necessary information from the P2P Invitation Request frame. */ + /* For example: The MAC address of sending this P2P Invitation Request frame. */ + u32 attr_contentlen = 0; + u8 status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + struct group_id_info group_id; + u8 invitation_flag = 0; + int j = 0; + + merged_p2p_ielen = rtw_get_p2p_merged_ies_len(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_); + + merged_p2pie = rtw_zmalloc(merged_p2p_ielen + 2); /* 2 is for EID and Length */ + if (merged_p2pie == NULL) { + RTW_INFO("[%s] Malloc p2p ie fail\n", __FUNCTION__); + goto exit; + } + _rtw_memset(merged_p2pie, 0x00, merged_p2p_ielen); + + merged_p2p_ielen = rtw_p2p_merge_ies(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, merged_p2pie); + + rtw_get_p2p_attr_content(merged_p2pie, merged_p2p_ielen, P2P_ATTR_INVITATION_FLAGS, &invitation_flag, &attr_contentlen); + if (attr_contentlen) { + + rtw_get_p2p_attr_content(merged_p2pie, merged_p2p_ielen, P2P_ATTR_GROUP_BSSID, pwdinfo->p2p_peer_interface_addr, &attr_contentlen); + /* Commented by Albert 20120510 */ + /* Copy to the pwdinfo->p2p_peer_interface_addr. */ + /* So that the WFD UI ( or Sigma ) can get the peer interface address by using the following command. */ + /* #> iwpriv wlan0 p2p_get peer_ifa */ + /* After having the peer interface address, the sigma can find the correct conf file for wpa_supplicant. */ + + if (attr_contentlen) { + RTW_INFO("[%s] GO's BSSID = %.2X %.2X %.2X %.2X %.2X %.2X\n", __FUNCTION__, + pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], + pwdinfo->p2p_peer_interface_addr[2], pwdinfo->p2p_peer_interface_addr[3], + pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]); + } + + if (invitation_flag & P2P_INVITATION_FLAGS_PERSISTENT) { + /* Re-invoke the persistent group. */ + + _rtw_memset(&group_id, 0x00, sizeof(struct group_id_info)); + rtw_get_p2p_attr_content(merged_p2pie, merged_p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *) &group_id, &attr_contentlen); + if (attr_contentlen) { + if (_rtw_memcmp(group_id.go_device_addr, adapter_mac_addr(padapter), ETH_ALEN)) { + /* The p2p device sending this p2p invitation request wants this Wi-Fi device to be the persistent GO. */ + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_GO); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + status_code = P2P_STATUS_SUCCESS; + } else { + /* The p2p device sending this p2p invitation request wants to be the persistent GO. */ + if (is_matched_in_profilelist(pwdinfo->p2p_peer_interface_addr, &pwdinfo->profileinfo[0])) { + u8 operatingch_info[5] = { 0x00 }; + if (rtw_get_p2p_attr_content(merged_p2pie, merged_p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, + &attr_contentlen)) { + if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, (u32)operatingch_info[4]) >= 0) { + /* The operating channel is acceptable for this device. */ + pwdinfo->rx_invitereq_info.operation_ch[0] = operatingch_info[4]; +#ifdef CONFIG_P2P_OP_CHK_SOCIAL_CH + pwdinfo->rx_invitereq_info.operation_ch[1] = 1; /* Check whether GO is operating in channel 1; */ + pwdinfo->rx_invitereq_info.operation_ch[2] = 6; /* Check whether GO is operating in channel 6; */ + pwdinfo->rx_invitereq_info.operation_ch[3] = 11; /* Check whether GO is operating in channel 11; */ +#endif /* CONFIG_P2P_OP_CHK_SOCIAL_CH */ + pwdinfo->rx_invitereq_info.scan_op_ch_only = 1; + _set_timer(&pwdinfo->reset_ch_sitesurvey, P2P_RESET_SCAN_CH); + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + status_code = P2P_STATUS_SUCCESS; + } else { + /* The operating channel isn't supported by this device. */ + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + status_code = P2P_STATUS_FAIL_NO_COMMON_CH; + _set_timer(&pwdinfo->restore_p2p_state_timer, 3000); + } + } else { + /* Commented by Albert 20121130 */ + /* Intel will use the different P2P IE to store the operating channel information */ + /* Workaround for Intel WiDi 3.5 */ + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + status_code = P2P_STATUS_SUCCESS; + } + } else { + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); +#ifdef CONFIG_INTEL_WIDI + _rtw_memcpy(pwdinfo->p2p_peer_device_addr, group_id.go_device_addr , ETH_ALEN); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); +#endif /* CONFIG_INTEL_WIDI */ + + status_code = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP; + } + } + } else { + RTW_INFO("[%s] P2P Group ID Attribute NOT FOUND!\n", __FUNCTION__); + status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + } + } else { + /* Received the invitation to join a P2P group. */ + + _rtw_memset(&group_id, 0x00, sizeof(struct group_id_info)); + rtw_get_p2p_attr_content(merged_p2pie, merged_p2p_ielen, P2P_ATTR_GROUP_ID, (u8 *) &group_id, &attr_contentlen); + if (attr_contentlen) { + if (_rtw_memcmp(group_id.go_device_addr, adapter_mac_addr(padapter), ETH_ALEN)) { + /* In this case, the GO can't be myself. */ + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH); + status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + } else { + /* The p2p device sending this p2p invitation request wants to join an existing P2P group */ + /* Commented by Albert 2012/06/28 */ + /* In this case, this Wi-Fi device should use the iwpriv command to get the peer device address. */ + /* The peer device address should be the destination address for the provisioning discovery request. */ + /* Then, this Wi-Fi device should use the iwpriv command to get the peer interface address. */ + /* The peer interface address should be the address for WPS mac address */ + _rtw_memcpy(pwdinfo->p2p_peer_device_addr, group_id.go_device_addr , ETH_ALEN); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_JOIN); + status_code = P2P_STATUS_SUCCESS; + } + } else { + RTW_INFO("[%s] P2P Group ID Attribute NOT FOUND!\n", __FUNCTION__); + status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + } + } + } else { + RTW_INFO("[%s] P2P Invitation Flags Attribute NOT FOUND!\n", __FUNCTION__); + status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + } + + RTW_INFO("[%s] status_code = %d\n", __FUNCTION__, status_code); + + pwdinfo->inviteresp_info.token = frame_body[7]; + issue_p2p_invitation_response(padapter, get_addr2_ptr(pframe), pwdinfo->inviteresp_info.token, status_code); + _set_timer(&pwdinfo->restore_p2p_state_timer, 3000); + } +#ifdef CONFIG_INTEL_WIDI + if (padapter->mlmepriv.widi_state == INTEL_WIDI_STATE_LISTEN) { + padapter->mlmepriv.widi_state = INTEL_WIDI_STATE_WFD_CONNECTION; + _cancel_timer_ex(&(padapter->mlmepriv.listen_timer)); + intel_widi_wk_cmd(padapter, INTEL_WIDI_LISTEN_STOP_WK, NULL, 0); + } +#endif /* CONFIG_INTEL_WIDI */ + break; + } + case P2P_INVIT_RESP: { + u8 attr_content = 0x00; + u32 attr_contentlen = 0; + + RTW_INFO("[%s] Got invite response frame!\n", __FUNCTION__); + _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); + p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen); + if (p2p_ie) { + rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); + + if (attr_contentlen == 1) { + RTW_INFO("[%s] Status = %d\n", __FUNCTION__, attr_content); + pwdinfo->invitereq_info.benable = _FALSE; + + if (attr_content == P2P_STATUS_SUCCESS) { + if (_rtw_memcmp(pwdinfo->invitereq_info.go_bssid, adapter_mac_addr(padapter), ETH_ALEN)) + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + else + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_OK); + } else { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); + } + } else { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); + } + } else { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL); + } + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL)) + _set_timer(&pwdinfo->restore_p2p_state_timer, 5000); + break; + } + case P2P_DEVDISC_REQ: + + process_p2p_devdisc_req(pwdinfo, pframe, len); + + break; + + case P2P_DEVDISC_RESP: + + process_p2p_devdisc_resp(pwdinfo, pframe, len); + + break; + + case P2P_PROVISION_DISC_REQ: + RTW_INFO("[%s] Got Provisioning Discovery Request Frame\n", __FUNCTION__); + process_p2p_provdisc_req(pwdinfo, pframe, len); + _rtw_memcpy(pwdinfo->rx_prov_disc_info.peerDevAddr, get_addr2_ptr(pframe), ETH_ALEN); + + /* 20110902 Kurt */ + /* Add the following statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */ + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) + rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo)); + + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ); + _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT); +#ifdef CONFIG_INTEL_WIDI + if (padapter->mlmepriv.widi_state == INTEL_WIDI_STATE_LISTEN) { + padapter->mlmepriv.widi_state = INTEL_WIDI_STATE_WFD_CONNECTION; + _cancel_timer_ex(&(padapter->mlmepriv.listen_timer)); + intel_widi_wk_cmd(padapter, INTEL_WIDI_LISTEN_STOP_WK, NULL, 0); + } +#endif /* CONFIG_INTEL_WIDI */ + break; + + case P2P_PROVISION_DISC_RESP: + /* Commented by Albert 20110707 */ + /* Should we check the pwdinfo->tx_prov_disc_info.bsent flag here?? */ + RTW_INFO("[%s] Got Provisioning Discovery Response Frame\n", __FUNCTION__); + /* Commented by Albert 20110426 */ + /* The restore timer is enabled when issuing the provisioing request frame in rtw_p2p_prov_disc function. */ + _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP); + process_p2p_provdisc_resp(pwdinfo, pframe); + _set_timer(&pwdinfo->restore_p2p_state_timer, P2P_PROVISION_TIMEOUT); + break; + + } + } + + +exit: + + if (merged_p2pie) + rtw_mfree(merged_p2pie, merged_p2p_ielen + 2); +#endif /* CONFIG_P2P */ + return _SUCCESS; +} + +unsigned int on_action_public_vendor(union recv_frame *precv_frame) +{ + unsigned int ret = _FAIL; + u8 *pframe = precv_frame->u.hdr.rx_data; + uint frame_len = precv_frame->u.hdr.len; + u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + + if (_rtw_memcmp(frame_body + 2, P2P_OUI, 4) == _TRUE) { + if (rtw_action_public_decache(precv_frame, 7) == _FAIL) + goto exit; + + if (!hal_chk_wl_func(precv_frame->u.hdr.adapter, WL_FUNC_MIRACAST)) + rtw_rframe_del_wfd_ie(precv_frame, 8); + + ret = on_action_public_p2p(precv_frame); + } + +exit: + return ret; +} + +unsigned int on_action_public_default(union recv_frame *precv_frame, u8 action) +{ + unsigned int ret = _FAIL; + u8 *pframe = precv_frame->u.hdr.rx_data; + uint frame_len = precv_frame->u.hdr.len; + u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + u8 token; + _adapter *adapter = precv_frame->u.hdr.adapter; + int cnt = 0; + char msg[64]; + + token = frame_body[2]; + + if (rtw_action_public_decache(precv_frame, 2) == _FAIL) + goto exit; + +#ifdef CONFIG_IOCTL_CFG80211 + cnt += sprintf((msg + cnt), "%s(token:%u)", action_public_str(action), token); + rtw_cfg80211_rx_action(adapter, precv_frame, msg); +#endif + + ret = _SUCCESS; + +exit: + return ret; +} + +unsigned int on_action_public(_adapter *padapter, union recv_frame *precv_frame) +{ + unsigned int ret = _FAIL; + u8 *pframe = precv_frame->u.hdr.rx_data; + uint frame_len = precv_frame->u.hdr.len; + u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + u8 category, action; + + /* check RA matches or not */ + if (!_rtw_memcmp(adapter_mac_addr(padapter), GetAddr1Ptr(pframe), ETH_ALEN)) + goto exit; + + category = frame_body[0]; + if (category != RTW_WLAN_CATEGORY_PUBLIC) + goto exit; + + action = frame_body[1]; + switch (action) { + case ACT_PUBLIC_BSSCOEXIST: +#ifdef CONFIG_80211N_HT +#ifdef CONFIG_AP_MODE + /*20/40 BSS Coexistence Management frame is a Public Action frame*/ + if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) + rtw_process_public_act_bsscoex(padapter, pframe, frame_len); +#endif /*CONFIG_AP_MODE*/ +#endif /*CONFIG_80211N_HT*/ + break; + case ACT_PUBLIC_VENDOR: + ret = on_action_public_vendor(precv_frame); + break; + default: + ret = on_action_public_default(precv_frame, action); + break; + } + +exit: + return ret; +} + +unsigned int OnAction_ft(_adapter *padapter, union recv_frame *precv_frame) +{ +#ifdef CONFIG_RTW_80211R + u32 ret = _FAIL; + u32 frame_len = 0; + u8 action_code = 0; + u8 category = 0; + u8 *pframe = NULL; + u8 *pframe_body = NULL; + u8 sta_addr[ETH_ALEN] = {0}; + u8 *pie = NULL; + u32 ft_ie_len = 0; + u32 status_code = 0; + struct mlme_ext_priv *pmlmeext = NULL; + struct mlme_ext_info *pmlmeinfo = NULL; + struct mlme_priv *pmlmepriv = NULL; + struct wlan_network *proam_target = NULL; + ft_priv *pftpriv = NULL; + _irqL irqL; + + pmlmeext = &padapter->mlmeextpriv; + pmlmeinfo = &(pmlmeext->mlmext_info); + pmlmepriv = &padapter->mlmepriv; + pftpriv = &pmlmepriv->ftpriv; + pframe = precv_frame->u.hdr.rx_data; + frame_len = precv_frame->u.hdr.len; + pframe_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + category = pframe_body[0]; + + if (category != RTW_WLAN_CATEGORY_FT) + goto exit; + + action_code = pframe_body[1]; + switch (action_code) { + case RTW_WLAN_ACTION_FT_RESPONSE: + RTW_INFO("FT: %s RTW_WLAN_ACTION_FT_RESPONSE\n", __func__); + if (!_rtw_memcmp(adapter_mac_addr(padapter), &pframe_body[2], ETH_ALEN)) { + RTW_ERR("FT: Unmatched STA MAC Address "MAC_FMT"\n", MAC_ARG(&pframe_body[2])); + goto exit; + } + + status_code = le16_to_cpu(*(u16 *)((SIZE_PTR)pframe + sizeof(struct rtw_ieee80211_hdr_3addr) + 14)); + if (status_code != 0) { + RTW_ERR("FT: WLAN ACTION FT RESPONSE fail, status: %d\n", status_code); + goto exit; + } + + if (is_zero_mac_addr(&pframe_body[8]) || is_broadcast_mac_addr(&pframe_body[8])) { + RTW_ERR("FT: Invalid Target MAC Address "MAC_FMT"\n", MAC_ARG(padapter->mlmepriv.roam_tgt_addr)); + goto exit; + } + + pie = rtw_get_ie(pframe_body, _MDIE_, &ft_ie_len, frame_len); + if (pie) { + if (!_rtw_memcmp(&pftpriv->mdid, pie+2, 2)) { + RTW_ERR("FT: Invalid MDID\n"); + goto exit; + } + } + + rtw_set_ft_status(padapter, RTW_FT_REQUESTED_STA); + _cancel_timer_ex(&pmlmeext->ft_link_timer); + + /*Disconnect current AP*/ + receive_disconnect(padapter, pmlmepriv->cur_network.network.MacAddress, WLAN_REASON_ACTIVE_ROAM, _FALSE); + + pftpriv->ft_action_len = frame_len; + _rtw_memcpy(pftpriv->ft_action, pframe, rtw_min(frame_len, RTW_MAX_FTIE_SZ)); + ret = _SUCCESS; + break; + case RTW_WLAN_ACTION_FT_REQUEST: + case RTW_WLAN_ACTION_FT_CONFIRM: + case RTW_WLAN_ACTION_FT_ACK: + default: + RTW_ERR("FT: Unsupported FT Action!\n"); + break; + } + +exit: + return ret; +#else + return _SUCCESS; +#endif +} + +unsigned int OnAction_ht(_adapter *padapter, union recv_frame *precv_frame) +{ + u8 *pframe = precv_frame->u.hdr.rx_data; + uint frame_len = precv_frame->u.hdr.len; + u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + u8 category, action; + + /* check RA matches or not */ + if (!_rtw_memcmp(adapter_mac_addr(padapter), GetAddr1Ptr(pframe), ETH_ALEN)) + goto exit; + + category = frame_body[0]; + if (category != RTW_WLAN_CATEGORY_HT) + goto exit; + + action = frame_body[1]; + switch (action) { + case RTW_WLAN_ACTION_HT_SM_PS: +#ifdef CONFIG_80211N_HT +#ifdef CONFIG_AP_MODE + if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) + rtw_process_ht_action_smps(padapter, get_addr2_ptr(pframe), frame_body[2]); +#endif /*CONFIG_AP_MODE*/ +#endif /*CONFIG_80211N_HT*/ + break; + case RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING: +#ifdef CONFIG_BEAMFORMING + /*RTW_INFO("RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING\n");*/ + rtw_beamforming_get_report_frame(padapter, precv_frame); +#endif /*CONFIG_BEAMFORMING*/ + break; + default: + break; + } + +exit: + + return _SUCCESS; +} + +#ifdef CONFIG_IEEE80211W +unsigned int OnAction_sa_query(_adapter *padapter, union recv_frame *precv_frame) +{ + u8 *pframe = precv_frame->u.hdr.rx_data; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u16 tid; + /* Baron */ + + RTW_INFO("OnAction_sa_query\n"); + + switch (pframe[WLAN_HDR_A3_LEN + 1]) { + case 0: /* SA Query req */ + _rtw_memcpy(&tid, &pframe[WLAN_HDR_A3_LEN + 2], sizeof(u16)); + RTW_INFO("OnAction_sa_query request,action=%d, tid=%04x, pframe=%02x-%02x\n" + , pframe[WLAN_HDR_A3_LEN + 1], tid, pframe[WLAN_HDR_A3_LEN + 2], pframe[WLAN_HDR_A3_LEN + 3]); + issue_action_SA_Query(padapter, get_addr2_ptr(pframe), 1, tid, IEEE80211W_RIGHT_KEY); + break; + + case 1: /* SA Query rsp */ + psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe)); + if (psta != NULL) + _cancel_timer_ex(&psta->dot11w_expire_timer); + + _rtw_memcpy(&tid, &pframe[WLAN_HDR_A3_LEN + 2], sizeof(u16)); + RTW_INFO("OnAction_sa_query response,action=%d, tid=%04x, cancel timer\n", pframe[WLAN_HDR_A3_LEN + 1], tid); + break; + default: + break; + } + if (0) { + int pp; + printk("pattrib->pktlen = %d =>", pattrib->pkt_len); + for (pp = 0; pp < pattrib->pkt_len; pp++) + printk(" %02x ", pframe[pp]); + printk("\n"); + } + + return _SUCCESS; +} +#endif /* CONFIG_IEEE80211W */ + +unsigned int OnAction_wmm(_adapter *padapter, union recv_frame *precv_frame) +{ + return _SUCCESS; +} + +unsigned int OnAction_vht(_adapter *padapter, union recv_frame *precv_frame) +{ +#ifdef CONFIG_80211AC_VHT + struct rx_pkt_attrib *prxattrib = &precv_frame->u.hdr.attrib; + u8 *pframe = precv_frame->u.hdr.rx_data; + uint frame_len = precv_frame->u.hdr.len; + struct rtw_ieee80211_hdr_3addr *whdr = (struct rtw_ieee80211_hdr_3addr *)pframe; + u8 *frame_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + u8 category, action; + struct sta_info *psta = NULL; + + /* check RA matches or not */ + if (!_rtw_memcmp(adapter_mac_addr(padapter), GetAddr1Ptr(pframe), ETH_ALEN)) + goto exit; + + category = frame_body[0]; + if (category != RTW_WLAN_CATEGORY_VHT) + goto exit; + + action = frame_body[1]; + switch (action) { + case RTW_WLAN_ACTION_VHT_COMPRESSED_BEAMFORMING: +#ifdef CONFIG_BEAMFORMING + /*RTW_INFO("RTW_WLAN_ACTION_VHT_COMPRESSED_BEAMFORMING\n");*/ + rtw_beamforming_get_report_frame(padapter, precv_frame); +#endif /*CONFIG_BEAMFORMING*/ + break; + case RTW_WLAN_ACTION_VHT_OPMODE_NOTIFICATION: + /* CategoryCode(1) + ActionCode(1) + OpModeNotification(1) */ + /* RTW_INFO("RTW_WLAN_ACTION_VHT_OPMODE_NOTIFICATION\n"); */ + psta = rtw_get_stainfo(&padapter->stapriv, whdr->addr2); + if (psta) + rtw_process_vht_op_mode_notify(padapter, &frame_body[2], psta); + break; + case RTW_WLAN_ACTION_VHT_GROUPID_MANAGEMENT: +#ifdef CONFIG_BEAMFORMING +#ifdef RTW_BEAMFORMING_VERSION_2 + rtw_beamforming_get_vht_gid_mgnt_frame(padapter, precv_frame); +#endif /* RTW_BEAMFORMING_VERSION_2 */ +#endif /* CONFIG_BEAMFORMING */ + break; + default: + break; + } + +exit: +#endif /* CONFIG_80211AC_VHT */ + + return _SUCCESS; +} + +unsigned int OnAction_p2p(_adapter *padapter, union recv_frame *precv_frame) +{ +#ifdef CONFIG_P2P + u8 *frame_body; + u8 category, OUI_Subtype, dialogToken = 0; + u8 *pframe = precv_frame->u.hdr.rx_data; + uint len = precv_frame->u.hdr.len; + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + + /* check RA matches or not */ + if (!_rtw_memcmp(adapter_mac_addr(padapter), GetAddr1Ptr(pframe), ETH_ALEN)) + return _SUCCESS; + + frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); + + category = frame_body[0]; + if (category != RTW_WLAN_CATEGORY_P2P) + return _SUCCESS; + + if (cpu_to_be32(*((u32 *)(frame_body + 1))) != P2POUI) + return _SUCCESS; + +#ifdef CONFIG_IOCTL_CFG80211 + if (adapter_wdev_data(padapter)->p2p_enabled + && pwdinfo->driver_interface == DRIVER_CFG80211 + ) { + rtw_cfg80211_rx_action_p2p(padapter, precv_frame); + return _SUCCESS; + } else +#endif /* CONFIG_IOCTL_CFG80211 */ + { + len -= sizeof(struct rtw_ieee80211_hdr_3addr); + OUI_Subtype = frame_body[5]; + dialogToken = frame_body[6]; + + switch (OUI_Subtype) { + case P2P_NOTICE_OF_ABSENCE: + + break; + + case P2P_PRESENCE_REQUEST: + + process_p2p_presence_req(pwdinfo, pframe, len); + + break; + + case P2P_PRESENCE_RESPONSE: + + break; + + case P2P_GO_DISC_REQUEST: + + break; + + default: + break; + + } + } +#endif /* CONFIG_P2P */ + + return _SUCCESS; + +} + +unsigned int OnAction(_adapter *padapter, union recv_frame *precv_frame) +{ + int i; + unsigned char category; + struct action_handler *ptable; + unsigned char *frame_body; + u8 *pframe = precv_frame->u.hdr.rx_data; + + frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); + + category = frame_body[0]; + + for (i = 0; i < sizeof(OnAction_tbl) / sizeof(struct action_handler); i++) { + ptable = &OnAction_tbl[i]; + + if (category == ptable->num) + ptable->func(padapter, precv_frame); + + } + + return _SUCCESS; + +} + +unsigned int DoReserved(_adapter *padapter, union recv_frame *precv_frame) +{ + + /* RTW_INFO("rcvd mgt frame(%x, %x)\n", (get_frame_sub_type(pframe) >> 4), *(unsigned int *)GetAddr1Ptr(pframe)); */ + return _SUCCESS; +} + +struct xmit_frame *_alloc_mgtxmitframe(struct xmit_priv *pxmitpriv, bool once) +{ + struct xmit_frame *pmgntframe; + struct xmit_buf *pxmitbuf; + + if (once) + pmgntframe = rtw_alloc_xmitframe_once(pxmitpriv); + else + pmgntframe = rtw_alloc_xmitframe_ext(pxmitpriv); + + if (pmgntframe == NULL) { + RTW_INFO(FUNC_ADPT_FMT" alloc xmitframe fail, once:%d\n", FUNC_ADPT_ARG(pxmitpriv->adapter), once); + goto exit; + } + + pxmitbuf = rtw_alloc_xmitbuf_ext(pxmitpriv); + if (pxmitbuf == NULL) { + RTW_INFO(FUNC_ADPT_FMT" alloc xmitbuf fail\n", FUNC_ADPT_ARG(pxmitpriv->adapter)); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + pmgntframe = NULL; + goto exit; + } + + pmgntframe->frame_tag = MGNT_FRAMETAG; + pmgntframe->pxmitbuf = pxmitbuf; + pmgntframe->buf_addr = pxmitbuf->pbuf; + pxmitbuf->priv_data = pmgntframe; + +exit: + return pmgntframe; + +} + +inline struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv) +{ + return _alloc_mgtxmitframe(pxmitpriv, _FALSE); +} + +inline struct xmit_frame *alloc_mgtxmitframe_once(struct xmit_priv *pxmitpriv) +{ + return _alloc_mgtxmitframe(pxmitpriv, _TRUE); +} + + +/**************************************************************************** + +Following are some TX fuctions for WiFi MLME + +*****************************************************************************/ + +void update_mgnt_tx_rate(_adapter *padapter, u8 rate) +{ + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + + pmlmeext->tx_rate = rate; + /* RTW_INFO("%s(): rate = %x\n",__FUNCTION__, rate); */ +} + + +void update_monitor_frame_attrib(_adapter *padapter, struct pkt_attrib *pattrib) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + u8 wireless_mode; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *pbcmc_sta = NULL; + + psta = rtw_get_stainfo(pstapriv, pattrib->ra); + pbcmc_sta = rtw_get_bcmc_stainfo(padapter); + + pattrib->hdrlen = 24; + pattrib->nr_frags = 1; + pattrib->priority = 7; + + if (pbcmc_sta) + pattrib->mac_id = pbcmc_sta->mac_id; + else { + pattrib->mac_id = 0; + RTW_INFO("mgmt use mac_id 0 will affect RA\n"); + } + pattrib->qsel = QSLT_MGNT; + + pattrib->pktlen = 0; + + if (pmlmeext->tx_rate == IEEE80211_CCK_RATE_1MB) + wireless_mode = WIRELESS_11B; + else + wireless_mode = WIRELESS_11G; + + pattrib->raid = rtw_get_mgntframe_raid(padapter, wireless_mode); +#ifdef CONFIG_80211AC_VHT + if (pHalData->rf_type == RF_1T1R) + pattrib->raid = RATEID_IDX_VHT_1SS; + else if (pHalData->rf_type == RF_2T2R || pHalData->rf_type == RF_2T4R) + pattrib->raid = RATEID_IDX_VHT_2SS; + else if (pHalData->rf_type == RF_3T3R) + pattrib->raid = RATEID_IDX_VHT_3SS; + else + pattrib->raid = RATEID_IDX_BGN_40M_1SS; +#endif + +#ifdef CONFIG_80211AC_VHT + pattrib->rate = MGN_VHT1SS_MCS9; +#else + pattrib->rate = MGN_MCS7; +#endif + + pattrib->encrypt = _NO_PRIVACY_; + pattrib->bswenc = _FALSE; + + pattrib->qos_en = _FALSE; + pattrib->ht_en = 1; + pattrib->bwmode = CHANNEL_WIDTH_20; + pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + pattrib->sgi = _FALSE; + + pattrib->seqnum = pmlmeext->mgnt_seq; + + pattrib->retry_ctrl = _TRUE; + + pattrib->mbssid = 0; + pattrib->hw_ssn_sel = pxmitpriv->hw_ssn_seq_no; + +} + + +void update_mgntframe_attrib(_adapter *padapter, struct pkt_attrib *pattrib) +{ + u8 wireless_mode; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct sta_info *pbcmc_sta = NULL; + /* _rtw_memset((u8 *)(pattrib), 0, sizeof(struct pkt_attrib)); */ + + pbcmc_sta = rtw_get_bcmc_stainfo(padapter); + + pattrib->hdrlen = 24; + pattrib->nr_frags = 1; + pattrib->priority = 7; + + if (pbcmc_sta) + pattrib->mac_id = pbcmc_sta->mac_id; + else { + pattrib->mac_id = 1; /* use STA's BCMC sta-info macid */ + + if (MLME_IS_AP(padapter) || MLME_IS_GO(padapter)) + RTW_INFO("%s-"ADPT_FMT" get bcmc sta_info fail,use MACID=1\n", __func__, ADPT_ARG(padapter)); + } + pattrib->qsel = QSLT_MGNT; + +#ifdef CONFIG_MCC_MODE + update_mcc_mgntframe_attrib(padapter, pattrib); +#endif + + pattrib->pktlen = 0; + + if (IS_CCK_RATE(pmlmeext->tx_rate)) + wireless_mode = WIRELESS_11B; + else + wireless_mode = WIRELESS_11G; + pattrib->raid = rtw_get_mgntframe_raid(padapter, wireless_mode); + pattrib->rate = pmlmeext->tx_rate; + + pattrib->encrypt = _NO_PRIVACY_; + pattrib->bswenc = _FALSE; + + pattrib->qos_en = _FALSE; + pattrib->ht_en = _FALSE; + pattrib->bwmode = CHANNEL_WIDTH_20; + pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + pattrib->sgi = _FALSE; + + pattrib->seqnum = pmlmeext->mgnt_seq; + + pattrib->retry_ctrl = _TRUE; + + pattrib->mbssid = 0; + pattrib->hw_ssn_sel = pxmitpriv->hw_ssn_seq_no; +} + +void update_mgntframe_attrib_addr(_adapter *padapter, struct xmit_frame *pmgntframe) +{ + u8 *pframe; + struct pkt_attrib *pattrib = &pmgntframe->attrib; +#ifdef CONFIG_BEAMFORMING + struct sta_info *sta = NULL; +#endif /* CONFIG_BEAMFORMING */ + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + + _rtw_memcpy(pattrib->ra, GetAddr1Ptr(pframe), ETH_ALEN); + _rtw_memcpy(pattrib->ta, get_addr2_ptr(pframe), ETH_ALEN); + +#ifdef CONFIG_BEAMFORMING + sta = pattrib->psta; + if (!sta) { + sta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); + pattrib->psta = sta; + } + if (sta) + update_attrib_txbf_info(padapter, pattrib, sta); +#endif /* CONFIG_BEAMFORMING */ +} + +void dump_mgntframe(_adapter *padapter, struct xmit_frame *pmgntframe) +{ + if (RTW_CANNOT_RUN(padapter)) { + rtw_free_xmitbuf(&padapter->xmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe); + return; + } + + rtw_hal_mgnt_xmit(padapter, pmgntframe); +} + +s32 dump_mgntframe_and_wait(_adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms) +{ + s32 ret = _FAIL; + _irqL irqL; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf; + struct submit_ctx sctx; + + if (RTW_CANNOT_RUN(padapter)) { + rtw_free_xmitbuf(&padapter->xmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe); + return ret; + } + + rtw_sctx_init(&sctx, timeout_ms); + pxmitbuf->sctx = &sctx; + + ret = rtw_hal_mgnt_xmit(padapter, pmgntframe); + + if (ret == _SUCCESS) + ret = rtw_sctx_wait(&sctx, __func__); + + _enter_critical(&pxmitpriv->lock_sctx, &irqL); + pxmitbuf->sctx = NULL; + _exit_critical(&pxmitpriv->lock_sctx, &irqL); + + return ret; +} + +s32 dump_mgntframe_and_wait_ack_timeout(_adapter *padapter, struct xmit_frame *pmgntframe, int timeout_ms) +{ +#ifdef CONFIG_XMIT_ACK + static u8 seq_no = 0; + s32 ret = _FAIL; + struct xmit_priv *pxmitpriv = &(GET_PRIMARY_ADAPTER(padapter))->xmitpriv; + + if (RTW_CANNOT_RUN(padapter)) { + rtw_free_xmitbuf(&padapter->xmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(&padapter->xmitpriv, pmgntframe); + return -1; + } + + _enter_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL); + pxmitpriv->ack_tx = _TRUE; + pxmitpriv->seq_no = seq_no++; + pmgntframe->ack_report = 1; + rtw_sctx_init(&(pxmitpriv->ack_tx_ops), timeout_ms); + if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS) + ret = rtw_sctx_wait(&(pxmitpriv->ack_tx_ops), __func__); + + pxmitpriv->ack_tx = _FALSE; + _exit_critical_mutex(&pxmitpriv->ack_tx_mutex, NULL); + + return ret; +#else /* !CONFIG_XMIT_ACK */ + dump_mgntframe(padapter, pmgntframe); + rtw_msleep_os(50); + return _SUCCESS; +#endif /* !CONFIG_XMIT_ACK */ +} + +s32 dump_mgntframe_and_wait_ack(_adapter *padapter, struct xmit_frame *pmgntframe) +{ + /* In this case, use 500 ms as the default wait_ack timeout */ + return dump_mgntframe_and_wait_ack_timeout(padapter, pmgntframe, 500); +} + + +int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode) +{ + u8 *ssid_ie; + sint ssid_len_ori; + int len_diff = 0; + + ssid_ie = rtw_get_ie(ies, WLAN_EID_SSID, &ssid_len_ori, ies_len); + + /* RTW_INFO("%s hidden_ssid_mode:%u, ssid_ie:%p, ssid_len_ori:%d\n", __FUNCTION__, hidden_ssid_mode, ssid_ie, ssid_len_ori); */ + + if (ssid_ie && ssid_len_ori > 0) { + switch (hidden_ssid_mode) { + case 1: { + u8 *next_ie = ssid_ie + 2 + ssid_len_ori; + u32 remain_len = 0; + + remain_len = ies_len - (next_ie - ies); + + ssid_ie[1] = 0; + _rtw_memcpy(ssid_ie + 2, next_ie, remain_len); + len_diff -= ssid_len_ori; + + break; + } + case 2: + _rtw_memset(&ssid_ie[2], 0, ssid_len_ori); + break; + default: + break; + } + } + + return len_diff; +} + +#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE +u32 rtw_build_vendor_ie(_adapter *padapter , unsigned char *pframe , u8 mgmt_frame_tyte) +{ + int vendor_ie_num = 0; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u32 len = 0; + + for (vendor_ie_num = 0 ; vendor_ie_num < WLAN_MAX_VENDOR_IE_NUM ; vendor_ie_num++) { + if (pmlmepriv->vendor_ielen[vendor_ie_num] > 0 && pmlmepriv->vendor_ie_mask[vendor_ie_num] & mgmt_frame_tyte) { + _rtw_memcpy(pframe , pmlmepriv->vendor_ie[vendor_ie_num] , pmlmepriv->vendor_ielen[vendor_ie_num]); + pframe += pmlmepriv->vendor_ielen[vendor_ie_num]; + len += pmlmepriv->vendor_ielen[vendor_ie_num]; + } + } + + return len; +} +#endif + +void issue_beacon(_adapter *padapter, int timeout_ms) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned int rate_len; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); +#if defined(CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) + _irqL irqL; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); +#endif /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#endif /* CONFIG_P2P */ + + + /* RTW_INFO("%s\n", __FUNCTION__); */ + +#ifdef CONFIG_BCN_ICF + pmgntframe = rtw_alloc_bcnxmitframe(pxmitpriv); + if (pmgntframe == NULL) +#else + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) +#endif + { + RTW_INFO("%s, alloc mgnt frame fail\n", __FUNCTION__); + return; + } +#if defined(CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) + _enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); +#endif /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + pattrib->qsel = QSLT_BEACON; + +#if defined(CONFIG_CONCURRENT_MODE) && (!defined(CONFIG_SWTIMER_BASED_TXBCN)) + if (padapter->hw_port == HW_PORT1) + pattrib->mbssid = 1; +#endif + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); + + SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); + /* pmlmeext->mgnt_seq++; */ + set_frame_sub_type(pframe, WIFI_BEACON); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { + /* RTW_INFO("ie len=%d\n", cur_network->IELength); */ +#ifdef CONFIG_P2P + /* for P2P : Primary Device Type & Device Name */ + u32 wpsielen = 0, insert_len = 0; + u8 *wpsie = NULL; + wpsie = rtw_get_wps_ie(cur_network->IEs + _FIXED_IE_LENGTH_, cur_network->IELength - _FIXED_IE_LENGTH_, NULL, &wpsielen); + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && wpsie && wpsielen > 0) { + uint wps_offset, remainder_ielen; + u8 *premainder_ie, *pframe_wscie; + + wps_offset = (uint)(wpsie - cur_network->IEs); + + premainder_ie = wpsie + wpsielen; + + remainder_ielen = cur_network->IELength - wps_offset - wpsielen; + +#ifdef CONFIG_IOCTL_CFG80211 + if (adapter_wdev_data(padapter)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211) { + if (pmlmepriv->wps_beacon_ie && pmlmepriv->wps_beacon_ie_len > 0) { + _rtw_memcpy(pframe, cur_network->IEs, wps_offset); + pframe += wps_offset; + pattrib->pktlen += wps_offset; + + _rtw_memcpy(pframe, pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len); + pframe += pmlmepriv->wps_beacon_ie_len; + pattrib->pktlen += pmlmepriv->wps_beacon_ie_len; + + /* copy remainder_ie to pframe */ + _rtw_memcpy(pframe, premainder_ie, remainder_ielen); + pframe += remainder_ielen; + pattrib->pktlen += remainder_ielen; + } else { + _rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength); + pframe += cur_network->IELength; + pattrib->pktlen += cur_network->IELength; + } + } else +#endif /* CONFIG_IOCTL_CFG80211 */ + { + pframe_wscie = pframe + wps_offset; + _rtw_memcpy(pframe, cur_network->IEs, wps_offset + wpsielen); + pframe += (wps_offset + wpsielen); + pattrib->pktlen += (wps_offset + wpsielen); + + /* now pframe is end of wsc ie, insert Primary Device Type & Device Name */ + /* Primary Device Type */ + /* Type: */ + *(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); + insert_len += 2; + + /* Length: */ + *(u16 *)(pframe + insert_len) = cpu_to_be16(0x0008); + insert_len += 2; + + /* Value: */ + /* Category ID */ + *(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + insert_len += 2; + + /* OUI */ + *(u32 *)(pframe + insert_len) = cpu_to_be32(WPSOUI); + insert_len += 4; + + /* Sub Category ID */ + *(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + insert_len += 2; + + + /* Device Name */ + /* Type: */ + *(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + insert_len += 2; + + /* Length: */ + *(u16 *)(pframe + insert_len) = cpu_to_be16(pwdinfo->device_name_len); + insert_len += 2; + + /* Value: */ + _rtw_memcpy(pframe + insert_len, pwdinfo->device_name, pwdinfo->device_name_len); + insert_len += pwdinfo->device_name_len; + + + /* update wsc ie length */ + *(pframe_wscie + 1) = (wpsielen - 2) + insert_len; + + /* pframe move to end */ + pframe += insert_len; + pattrib->pktlen += insert_len; + + /* copy remainder_ie to pframe */ + _rtw_memcpy(pframe, premainder_ie, remainder_ielen); + pframe += remainder_ielen; + pattrib->pktlen += remainder_ielen; + } + } else +#endif /* CONFIG_P2P */ + { + int len_diff; + _rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength); + len_diff = update_hidden_ssid( + pframe + _BEACON_IE_OFFSET_ + , cur_network->IELength - _BEACON_IE_OFFSET_ + , pmlmeinfo->hidden_ssid_mode + ); + pframe += (cur_network->IELength + len_diff); + pattrib->pktlen += (cur_network->IELength + len_diff); + } + + { + u8 *wps_ie; + uint wps_ielen; + u8 sr = 0; + wps_ie = rtw_get_wps_ie(pmgntframe->buf_addr + TXDESC_OFFSET + sizeof(struct rtw_ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_, + pattrib->pktlen - sizeof(struct rtw_ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_, NULL, &wps_ielen); + if (wps_ie && wps_ielen > 0) + rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL); + if (sr != 0) + set_fwstate(pmlmepriv, WIFI_UNDER_WPS); + else + _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS); + } + +#ifdef CONFIG_P2P + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + u32 len; +#ifdef CONFIG_IOCTL_CFG80211 + if (adapter_wdev_data(padapter)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211) { + len = pmlmepriv->p2p_beacon_ie_len; + if (pmlmepriv->p2p_beacon_ie && len > 0) + _rtw_memcpy(pframe, pmlmepriv->p2p_beacon_ie, len); + } else +#endif /* CONFIG_IOCTL_CFG80211 */ + { + len = build_beacon_p2p_ie(pwdinfo, pframe); + } + + pframe += len; + pattrib->pktlen += len; + +#ifdef CONFIG_MCC_MODE + pframe = rtw_hal_mcc_append_go_p2p_ie(padapter, pframe, &pattrib->pktlen); +#endif /* CONFIG_MCC_MODE*/ + +#ifdef CONFIG_WFD + len = rtw_append_beacon_wfd_ie(padapter, pframe); + pframe += len; + pattrib->pktlen += len; +#endif + } +#endif /* CONFIG_P2P */ + +#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE + pattrib->pktlen += rtw_build_vendor_ie(padapter , pframe , WIFI_BEACON_VENDOR_IE_BIT); +#endif + goto _issue_bcn; + + } + + /* below for ad-hoc mode */ + + /* timestamp will be inserted by hardware */ + pframe += 8; + pattrib->pktlen += 8; + + /* beacon interval: 2 bytes */ + + _rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); + + pframe += 2; + pattrib->pktlen += 2; + + /* capability info: 2 bytes */ + + _rtw_memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); + + pframe += 2; + pattrib->pktlen += 2; + + /* SSID */ + pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); + + /* supported rates... */ + rate_len = rtw_get_rateset_len(cur_network->SupportedRates); + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen); + + /* DS parameter set */ + pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen); + + /* if( (pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) */ + { + u8 erpinfo = 0; + u32 ATIMWindow; + /* IBSS Parameter Set... */ + /* ATIMWindow = cur->Configuration.ATIMWindow; */ + ATIMWindow = 0; + pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); + + /* ERP IE */ + pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); + } + + + /* EXTERNDED SUPPORTED RATE */ + if (rate_len > 8) + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); + + + /* todo:HT for adhoc */ + +_issue_bcn: + +#if defined(CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) + pmlmepriv->update_bcn = _FALSE; + + _exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); +#endif /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ + + if ((pattrib->pktlen + TXDESC_SIZE) > 512) { + RTW_INFO("beacon frame too large\n"); + return; + } + + pattrib->last_txcmdsz = pattrib->pktlen; + + /* RTW_INFO("issue bcn_sz=%d\n", pattrib->last_txcmdsz); */ + if (timeout_ms > 0) + dump_mgntframe_and_wait(padapter, pmgntframe, timeout_ms); + else + dump_mgntframe(padapter, pmgntframe); + +} + +void issue_probersp(_adapter *padapter, unsigned char *da, u8 is_valid_p2p_probereq) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned char *mac, *bssid; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); +#if defined(CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) + u8 *pwps_ie; + uint wps_ielen; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +#endif /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); + unsigned int rate_len; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif +#endif /* CONFIG_P2P */ + + /* RTW_INFO("%s\n", __FUNCTION__); */ + + if (da == NULL) + return; + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + return; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) { + RTW_INFO("%s, alloc mgnt frame fail\n", __FUNCTION__); + return; + } + + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + mac = adapter_mac_addr(padapter); + bssid = cur_network->MacAddress; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(fctrl, WIFI_PROBERSP); + + pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = pattrib->hdrlen; + pframe += pattrib->hdrlen; + + + if (cur_network->IELength > MAX_IE_SZ) + return; + +#if defined(CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) + if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { + pwps_ie = rtw_get_wps_ie(cur_network->IEs + _FIXED_IE_LENGTH_, cur_network->IELength - _FIXED_IE_LENGTH_, NULL, &wps_ielen); + + /* inerset & update wps_probe_resp_ie */ + if ((pmlmepriv->wps_probe_resp_ie != NULL) && pwps_ie && (wps_ielen > 0)) { + uint wps_offset, remainder_ielen; + u8 *premainder_ie; + + wps_offset = (uint)(pwps_ie - cur_network->IEs); + + premainder_ie = pwps_ie + wps_ielen; + + remainder_ielen = cur_network->IELength - wps_offset - wps_ielen; + + _rtw_memcpy(pframe, cur_network->IEs, wps_offset); + pframe += wps_offset; + pattrib->pktlen += wps_offset; + + wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];/* to get ie data len */ + if ((wps_offset + wps_ielen + 2) <= MAX_IE_SZ) { + _rtw_memcpy(pframe, pmlmepriv->wps_probe_resp_ie, wps_ielen + 2); + pframe += wps_ielen + 2; + pattrib->pktlen += wps_ielen + 2; + } + + if ((wps_offset + wps_ielen + 2 + remainder_ielen) <= MAX_IE_SZ) { + _rtw_memcpy(pframe, premainder_ie, remainder_ielen); + pframe += remainder_ielen; + pattrib->pktlen += remainder_ielen; + } + } else { + _rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength); + pframe += cur_network->IELength; + pattrib->pktlen += cur_network->IELength; + } + + /* retrieve SSID IE from cur_network->Ssid */ + { + u8 *ssid_ie; + sint ssid_ielen; + sint ssid_ielen_diff; + u8 buf[MAX_IE_SZ]; + u8 *ies = pmgntframe->buf_addr + TXDESC_OFFSET + sizeof(struct rtw_ieee80211_hdr_3addr); + + ssid_ie = rtw_get_ie(ies + _FIXED_IE_LENGTH_, _SSID_IE_, &ssid_ielen, + (pframe - ies) - _FIXED_IE_LENGTH_); + + ssid_ielen_diff = cur_network->Ssid.SsidLength - ssid_ielen; + + if (ssid_ie && cur_network->Ssid.SsidLength) { + uint remainder_ielen; + u8 *remainder_ie; + remainder_ie = ssid_ie + 2; + remainder_ielen = (pframe - remainder_ie); + + if (remainder_ielen > MAX_IE_SZ) { + RTW_WARN(FUNC_ADPT_FMT" remainder_ielen > MAX_IE_SZ\n", FUNC_ADPT_ARG(padapter)); + remainder_ielen = MAX_IE_SZ; + } + + _rtw_memcpy(buf, remainder_ie, remainder_ielen); + _rtw_memcpy(remainder_ie + ssid_ielen_diff, buf, remainder_ielen); + *(ssid_ie + 1) = cur_network->Ssid.SsidLength; + _rtw_memcpy(ssid_ie + 2, cur_network->Ssid.Ssid, cur_network->Ssid.SsidLength); + + pframe += ssid_ielen_diff; + pattrib->pktlen += ssid_ielen_diff; + } + } +#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE + pattrib->pktlen += rtw_build_vendor_ie(padapter , pframe , WIFI_PROBERESP_VENDOR_IE_BIT); +#endif + } else +#endif + { + + /* timestamp will be inserted by hardware */ + pframe += 8; + pattrib->pktlen += 8; + + /* beacon interval: 2 bytes */ + + _rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); + + pframe += 2; + pattrib->pktlen += 2; + + /* capability info: 2 bytes */ + + _rtw_memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); + + pframe += 2; + pattrib->pktlen += 2; + + /* below for ad-hoc mode */ + + /* SSID */ + pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pattrib->pktlen); + + /* supported rates... */ + rate_len = rtw_get_rateset_len(cur_network->SupportedRates); + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pattrib->pktlen); + + /* DS parameter set */ + pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pattrib->pktlen); + + if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { + u8 erpinfo = 0; + u32 ATIMWindow; + /* IBSS Parameter Set... */ + /* ATIMWindow = cur->Configuration.ATIMWindow; */ + ATIMWindow = 0; + pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pattrib->pktlen); + + /* ERP IE */ + pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pattrib->pktlen); + } + + + /* EXTERNDED SUPPORTED RATE */ + if (rate_len > 8) + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pattrib->pktlen); + + + /* todo:HT for adhoc */ + + } + +#ifdef CONFIG_P2P + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) + /* IOT issue, When wifi_spec is not set, send probe_resp with P2P IE even if probe_req has no P2P IE */ + && (is_valid_p2p_probereq || !padapter->registrypriv.wifi_spec)) { + u32 len; +#ifdef CONFIG_IOCTL_CFG80211 + if (adapter_wdev_data(padapter)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211) { + /* if pwdinfo->role == P2P_ROLE_DEVICE will call issue_probersp_p2p() */ + len = pmlmepriv->p2p_go_probe_resp_ie_len; + if (pmlmepriv->p2p_go_probe_resp_ie && len > 0) + _rtw_memcpy(pframe, pmlmepriv->p2p_go_probe_resp_ie, len); + } else +#endif /* CONFIG_IOCTL_CFG80211 */ + { + len = build_probe_resp_p2p_ie(pwdinfo, pframe); + } + + pframe += len; + pattrib->pktlen += len; + +#ifdef CONFIG_MCC_MODE + pframe = rtw_hal_mcc_append_go_p2p_ie(padapter, pframe, &pattrib->pktlen); +#endif /* CONFIG_MCC_MODE*/ + +#ifdef CONFIG_WFD + len = rtw_append_probe_resp_wfd_ie(padapter, pframe); + pframe += len; + pattrib->pktlen += len; +#endif + } +#endif /* CONFIG_P2P */ + + +#ifdef CONFIG_AUTO_AP_MODE + { + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + + RTW_INFO("(%s)\n", __FUNCTION__); + + /* check rc station */ + psta = rtw_get_stainfo(pstapriv, da); + if (psta && psta->isrc && psta->pid > 0) { + u8 RC_OUI[4] = {0x00, 0xE0, 0x4C, 0x0A}; + u8 RC_INFO[14] = {0}; + /* EID[1] + EID_LEN[1] + RC_OUI[4] + MAC[6] + PairingID[2] + ChannelNum[2] */ + u16 cu_ch = (u16)cur_network->Configuration.DSConfig; + + RTW_INFO("%s, reply rc(pid=0x%x) device "MAC_FMT" in ch=%d\n", __FUNCTION__, + psta->pid, MAC_ARG(psta->hwaddr), cu_ch); + + /* append vendor specific ie */ + _rtw_memcpy(RC_INFO, RC_OUI, sizeof(RC_OUI)); + _rtw_memcpy(&RC_INFO[4], mac, ETH_ALEN); + _rtw_memcpy(&RC_INFO[10], (u8 *)&psta->pid, 2); + _rtw_memcpy(&RC_INFO[12], (u8 *)&cu_ch, 2); + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, sizeof(RC_INFO), RC_INFO, &pattrib->pktlen); + } + } +#endif /* CONFIG_AUTO_AP_MODE */ + + + pattrib->last_txcmdsz = pattrib->pktlen; + + + dump_mgntframe(padapter, pmgntframe); + + return; + +} + +int _issue_probereq(_adapter *padapter, NDIS_802_11_SSID *pssid, u8 *da, u8 ch, bool append_wps, int wait_ack) +{ + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned char *mac; + unsigned char bssrate[NumRates]; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + int bssrate_len = 0; + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + goto exit; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + mac = adapter_mac_addr(padapter); + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + if (da) { + /* unicast probe request frame */ + _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, da, ETH_ALEN); + } else { + /* broadcast probe request frame */ + _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); + } + + _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_PROBEREQ); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + if (pssid) + pframe = rtw_set_ie(pframe, _SSID_IE_, pssid->SsidLength, pssid->Ssid, &(pattrib->pktlen)); + else + pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &(pattrib->pktlen)); + + get_rate_set(padapter, bssrate, &bssrate_len); + + if (bssrate_len > 8) { + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); + } else + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); + + if (ch) + pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, &ch, &pattrib->pktlen); + + if (append_wps) { + /* add wps_ie for wps2.0 */ + if (pmlmepriv->wps_probe_req_ie_len > 0 && pmlmepriv->wps_probe_req_ie) { + _rtw_memcpy(pframe, pmlmepriv->wps_probe_req_ie, pmlmepriv->wps_probe_req_ie_len); + pframe += pmlmepriv->wps_probe_req_ie_len; + pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len; + /* pmlmepriv->wps_probe_req_ie_len = 0 ; */ /* reset to zero */ + } + } +#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE + pattrib->pktlen += rtw_build_vendor_ie(padapter , pframe , WIFI_PROBEREQ_VENDOR_IE_BIT); +#endif + + pattrib->last_txcmdsz = pattrib->pktlen; + + + if (wait_ack) + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + } + +exit: + return ret; +} + +inline void issue_probereq(_adapter *padapter, NDIS_802_11_SSID *pssid, u8 *da) +{ + _issue_probereq(padapter, pssid, da, 0, 1, _FALSE); +} + +/* + * wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT + * wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX + * try_cnt means the maximal TX count to try + */ +int issue_probereq_ex(_adapter *padapter, NDIS_802_11_SSID *pssid, u8 *da, u8 ch, bool append_wps, + int try_cnt, int wait_ms) +{ + int ret = _FAIL; + int i = 0; + u32 start = rtw_get_current_time(); + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + goto exit; + + do { + ret = _issue_probereq(padapter, pssid, da, ch, append_wps, wait_ms > 0 ? _TRUE : _FALSE); + + i++; + + if (RTW_CANNOT_RUN(padapter)) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + rtw_msleep_os(wait_ms); + + } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + + if (ret != _FAIL) { + ret = _SUCCESS; +#ifndef DBG_XMIT_ACK + goto exit; +#endif + } + + if (try_cnt && wait_ms) { + if (da) + RTW_INFO(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + else + RTW_INFO(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + } +exit: + return ret; +} + +/* if psta == NULL, indiate we are station(client) now... */ +void issue_auth(_adapter *padapter, struct sta_info *psta, unsigned short status) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned int val32; + unsigned short val16; + int use_shared_key = 0; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); +#ifdef CONFIG_RTW_80211R + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + ft_priv *pftpriv = &pmlmepriv->ftpriv; + u8 is_ft_roaming = _FALSE; + u8 is_ft_roaming_with_rsn_ie = _TRUE; + u8 *pie = NULL; + u32 ft_ie_len = 0; +#endif + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + return; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_AUTH); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + + if (psta) { /* for AP mode */ +#ifdef CONFIG_NATIVEAP_MLME + + _rtw_memcpy(pwlanhdr->addr1, psta->hwaddr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN); + + + /* setting auth algo number */ + val16 = (u16)psta->authalg; + + if (status != _STATS_SUCCESSFUL_) + val16 = 0; + + if (val16) { + val16 = cpu_to_le16(val16); + use_shared_key = 1; + } + + pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&val16, &(pattrib->pktlen)); + + /* setting auth seq number */ + val16 = (u16)psta->auth_seq; + val16 = cpu_to_le16(val16); + pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&val16, &(pattrib->pktlen)); + + /* setting status code... */ + val16 = status; + val16 = cpu_to_le16(val16); + pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&val16, &(pattrib->pktlen)); + + /* added challenging text... */ + if ((psta->auth_seq == 2) && (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) + pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, psta->chg_txt, &(pattrib->pktlen)); +#endif + } else { + _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); + +#ifdef CONFIG_RTW_80211R + /*For Fast BSS Transition */ + if ((rtw_to_roam(padapter) > 0) && rtw_chk_ft_flags(padapter, RTW_FT_SUPPORTED)) { + is_ft_roaming = _TRUE; + val16 = 2; /* 2: 802.11R FTAA */ + val16 = cpu_to_le16(val16); + } else +#endif + { + /* setting auth algo number */ + val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ? 1 : 0; /* 0:OPEN System, 1:Shared key */ + if (val16) { + val16 = cpu_to_le16(val16); + use_shared_key = 1; + } + } + + /* RTW_INFO("%s auth_algo= %s auth_seq=%d\n",__FUNCTION__,(pmlmeinfo->auth_algo==0)?"OPEN":"SHARED",pmlmeinfo->auth_seq); */ + + /* setting IV for auth seq #3 */ + if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { + /* RTW_INFO("==> iv(%d),key_index(%d)\n",pmlmeinfo->iv,pmlmeinfo->key_index); */ + val32 = ((pmlmeinfo->iv++) | (pmlmeinfo->key_index << 30)); + val32 = cpu_to_le32(val32); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *)&val32, &(pattrib->pktlen)); + + pattrib->iv_len = 4; + } + + pframe = rtw_set_fixed_ie(pframe, _AUTH_ALGM_NUM_, (unsigned char *)&val16, &(pattrib->pktlen)); + + /* setting auth seq number */ + val16 = pmlmeinfo->auth_seq; + val16 = cpu_to_le16(val16); + pframe = rtw_set_fixed_ie(pframe, _AUTH_SEQ_NUM_, (unsigned char *)&val16, &(pattrib->pktlen)); + + + /* setting status code... */ + val16 = status; + val16 = cpu_to_le16(val16); + pframe = rtw_set_fixed_ie(pframe, _STATUS_CODE_, (unsigned char *)&val16, &(pattrib->pktlen)); + +#ifdef CONFIG_RTW_80211R + if (is_ft_roaming == _TRUE) { + pie = rtw_get_ie(pftpriv->updated_ft_ies, EID_WPA2, &ft_ie_len, pftpriv->updated_ft_ies_len); + if (pie) + pframe = rtw_set_ie(pframe, EID_WPA2, ft_ie_len, pie+2, &(pattrib->pktlen)); + else + is_ft_roaming_with_rsn_ie = _FALSE; + + pie = rtw_get_ie(pftpriv->updated_ft_ies, _MDIE_, &ft_ie_len, pftpriv->updated_ft_ies_len); + if (pie) + pframe = rtw_set_ie(pframe, _MDIE_, ft_ie_len , pie+2, &(pattrib->pktlen)); + + pie = rtw_get_ie(pftpriv->updated_ft_ies, _FTIE_, &ft_ie_len, pftpriv->updated_ft_ies_len); + if (pie && is_ft_roaming_with_rsn_ie) + pframe = rtw_set_ie(pframe, _FTIE_, ft_ie_len , pie+2, &(pattrib->pktlen)); + } +#endif + + /* then checking to see if sending challenging text... */ + if ((pmlmeinfo->auth_seq == 3) && (pmlmeinfo->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1)) { + pframe = rtw_set_ie(pframe, _CHLGETXT_IE_, 128, pmlmeinfo->chg_txt, &(pattrib->pktlen)); + + SetPrivacy(fctrl); + + pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pattrib->encrypt = _WEP40_; + + pattrib->icv_len = 4; + + pattrib->pktlen += pattrib->icv_len; + + } + + } + + pattrib->last_txcmdsz = pattrib->pktlen; + + rtw_wep_encrypt(padapter, (u8 *)pmgntframe); + RTW_INFO("%s\n", __FUNCTION__); + dump_mgntframe(padapter, pmgntframe); + + return; +} + + +void issue_asocrsp(_adapter *padapter, unsigned short status, struct sta_info *pstat, int pkt_type) +{ +#ifdef CONFIG_AP_MODE + struct xmit_frame *pmgntframe; + struct rtw_ieee80211_hdr *pwlanhdr; + struct pkt_attrib *pattrib; + unsigned char *pbuf, *pframe; + unsigned short val, ie_status; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = &(pmlmeinfo->network); + u8 *ie = pnetwork->IEs; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif + +#endif /* CONFIG_P2P */ + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + return; + + RTW_INFO("%s\n", __FUNCTION__); + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->hwaddr, ETH_ALEN); + _rtw_memcpy((void *)get_addr2_ptr(pwlanhdr), adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy((void *)GetAddr3Ptr(pwlanhdr), get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP)) + set_frame_sub_type(pwlanhdr, pkt_type); + else + return; + + pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen += pattrib->hdrlen; + pframe += pattrib->hdrlen; + + /* capability */ + val = *(unsigned short *)rtw_get_capability_from_ie(ie); + + pframe = rtw_set_fixed_ie(pframe, _CAPABILITY_ , (unsigned char *)&val, &(pattrib->pktlen)); + + ie_status = cpu_to_le16(status); + pframe = rtw_set_fixed_ie(pframe , _STATUS_CODE_ , (unsigned char *)&ie_status, &(pattrib->pktlen)); + + val = cpu_to_le16(pstat->aid | BIT(14) | BIT(15)); + pframe = rtw_set_fixed_ie(pframe, _ASOC_ID_ , (unsigned char *)&val, &(pattrib->pktlen)); + + if (pstat->bssratelen <= 8) + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, pstat->bssratelen, pstat->bssrateset, &(pattrib->pktlen)); + else { + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pstat->bssrateset, &(pattrib->pktlen)); + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (pstat->bssratelen - 8), pstat->bssrateset + 8, &(pattrib->pktlen)); + } + +#ifdef CONFIG_IEEE80211W + if (status == _STATS_REFUSED_TEMPORARILY_) { + u8 timeout_itvl[5]; + u32 timeout_interval = 3000; + /* Association Comeback time */ + timeout_itvl[0] = 0x03; + timeout_interval = cpu_to_le32(timeout_interval); + _rtw_memcpy(timeout_itvl + 1, &timeout_interval, 4); + pframe = rtw_set_ie(pframe, _TIMEOUT_ITVL_IE_, 5, timeout_itvl, &(pattrib->pktlen)); + } +#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_80211N_HT + if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) { + uint ie_len = 0; + + /* FILL HT CAP INFO IE */ + /* p = hostapd_eid_ht_capabilities_info(hapd, p); */ + pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); + if (pbuf && ie_len > 0) { + _rtw_memcpy(pframe, pbuf, ie_len + 2); + pframe += (ie_len + 2); + pattrib->pktlen += (ie_len + 2); + } + + /* FILL HT ADD INFO IE */ + /* p = hostapd_eid_ht_operation(hapd, p); */ + pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); + if (pbuf && ie_len > 0) { + _rtw_memcpy(pframe, pbuf, ie_len + 2); + pframe += (ie_len + 2); + pattrib->pktlen += (ie_len + 2); + } + + } +#endif + + /*adding EXT_CAPAB_IE */ + if (pmlmepriv->ext_capab_ie_len > 0) { + uint ie_len = 0; + + pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _EXT_CAP_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); + if (pbuf && ie_len > 0) { + _rtw_memcpy(pframe, pbuf, ie_len + 2); + pframe += (ie_len + 2); + pattrib->pktlen += (ie_len + 2); + } + } + +#ifdef CONFIG_80211AC_VHT + if ((pstat->flags & WLAN_STA_VHT) && (pmlmepriv->vhtpriv.vht_option) + && (pstat->wpa_pairwise_cipher != WPA_CIPHER_TKIP) + && (pstat->wpa2_pairwise_cipher != WPA_CIPHER_TKIP)) { + u32 ie_len = 0; + + /* FILL VHT CAP IE */ + pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_VHTCapability, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); + if (pbuf && ie_len > 0) { + _rtw_memcpy(pframe, pbuf, ie_len + 2); + pframe += (ie_len + 2); + pattrib->pktlen += (ie_len + 2); + } + + /* FILL VHT OPERATION IE */ + pbuf = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_VHTOperation, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_)); + if (pbuf && ie_len > 0) { + _rtw_memcpy(pframe, pbuf, ie_len + 2); + pframe += (ie_len + 2); + pattrib->pktlen += (ie_len + 2); + } + } +#endif /* CONFIG_80211AC_VHT */ + + /* FILL WMM IE */ + if ((pstat->flags & WLAN_STA_WME) && (pmlmepriv->qospriv.qos_option)) { + uint ie_len = 0; + unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; + + for (pbuf = ie + _BEACON_IE_OFFSET_; ; pbuf += (ie_len + 2)) { + pbuf = rtw_get_ie(pbuf, _VENDOR_SPECIFIC_IE_, &ie_len, (pnetwork->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2))); + if (pbuf && _rtw_memcmp(pbuf + 2, WMM_PARA_IE, 6)) { + _rtw_memcpy(pframe, pbuf, ie_len + 2); + pframe += (ie_len + 2); + pattrib->pktlen += (ie_len + 2); + + break; + } + + if ((pbuf == NULL) || (ie_len == 0)) + break; + } + + } + + + if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen)); + + /* add WPS IE ie for wps 2.0 */ + if (pmlmepriv->wps_assoc_resp_ie && pmlmepriv->wps_assoc_resp_ie_len > 0) { + _rtw_memcpy(pframe, pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len); + + pframe += pmlmepriv->wps_assoc_resp_ie_len; + pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len; + } + +#ifdef CONFIG_P2P + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && (pstat->is_p2p_device == _TRUE)) { + u32 len; + + if (padapter->wdinfo.driver_interface == DRIVER_CFG80211) { + len = 0; + if (pmlmepriv->p2p_assoc_resp_ie && pmlmepriv->p2p_assoc_resp_ie_len > 0) { + len = pmlmepriv->p2p_assoc_resp_ie_len; + _rtw_memcpy(pframe, pmlmepriv->p2p_assoc_resp_ie, len); + } + } else + len = build_assoc_resp_p2p_ie(pwdinfo, pframe, pstat->p2p_status_code); + pframe += len; + pattrib->pktlen += len; + } + +#ifdef CONFIG_WFD + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + wfdielen = rtw_append_assoc_resp_wfd_ie(padapter, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; + } +#endif + +#endif /* CONFIG_P2P */ +#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE + pattrib->pktlen += rtw_build_vendor_ie(padapter , pframe , WIFI_ASSOCRESP_VENDOR_IE_BIT); +#endif + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + +#endif +} + +void _issue_assocreq(_adapter *padapter, u8 is_reassoc) +{ + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe, *p; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned short val16; + unsigned int i, j, ie_len, index = 0; + unsigned char rf_type, bssrate[NumRates], sta_bssrate[NumRates]; + PNDIS_802_11_VARIABLE_IEs pIE; + struct registry_priv *pregpriv = &padapter->registrypriv; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + int bssrate_len = 0, sta_bssrate_len = 0; + u8 vs_ie_length = 0; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + u8 p2pie[255] = { 0x00 }; + u16 p2pielen = 0; +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif +#endif /* CONFIG_P2P */ + +#ifdef CONFIG_DFS + u16 cap; + + /* Dot H */ + u8 pow_cap_ele[2] = { 0x00 }; + u8 sup_ch[30 * 2] = {0x00 }, sup_ch_idx = 0, idx_5g = 2; /* For supported channel */ +#endif /* CONFIG_DFS */ +#ifdef CONFIG_RTW_80211R + u8 *pie = NULL; + u32 ft_ie_len = 0; + ft_priv *pftpriv = &pmlmepriv->ftpriv; +#endif + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + goto exit; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + if (is_reassoc == _TRUE) + set_frame_sub_type(pframe, WIFI_REASSOCREQ); + else + set_frame_sub_type(pframe, WIFI_ASSOCREQ); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + /* caps */ + +#ifdef CONFIG_DFS + _rtw_memcpy(&cap, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2); + cap |= cap_SpecMgmt; + _rtw_memcpy(pframe, &cap, 2); +#else + _rtw_memcpy(pframe, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2); +#endif /* CONFIG_DFS */ + + pframe += 2; + pattrib->pktlen += 2; + + /* listen interval */ + /* todo: listen interval for power saving */ + val16 = cpu_to_le16(3); + _rtw_memcpy(pframe , (unsigned char *)&val16, 2); + pframe += 2; + pattrib->pktlen += 2; + + /*Construct Current AP Field for Reassoc-Req only*/ + if (is_reassoc == _TRUE) { + _rtw_memcpy(pframe, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + pframe += ETH_ALEN; + pattrib->pktlen += ETH_ALEN; + } + + /* SSID */ + pframe = rtw_set_ie(pframe, _SSID_IE_, pmlmeinfo->network.Ssid.SsidLength, pmlmeinfo->network.Ssid.Ssid, &(pattrib->pktlen)); + +#ifdef CONFIG_DFS + /* Dot H */ + if (pmlmeext->cur_channel > 14) { + pow_cap_ele[0] = 13; /* Minimum transmit power capability */ + pow_cap_ele[1] = 21; /* Maximum transmit power capability */ + pframe = rtw_set_ie(pframe, EID_PowerCap, 2, pow_cap_ele, &(pattrib->pktlen)); + + /* supported channels */ + do { + if (pmlmeext->channel_set[sup_ch_idx].ChannelNum <= 14) { + sup_ch[0] = 1; /* First channel number */ + sup_ch[1] = pmlmeext->channel_set[sup_ch_idx].ChannelNum; /* Number of channel */ + } else { + sup_ch[idx_5g++] = pmlmeext->channel_set[sup_ch_idx].ChannelNum; + sup_ch[idx_5g++] = 1; + } + sup_ch_idx++; + } while (pmlmeext->channel_set[sup_ch_idx].ChannelNum != 0); + pframe = rtw_set_ie(pframe, EID_SupportedChannels, idx_5g, sup_ch, &(pattrib->pktlen)); + } +#endif /* CONFIG_DFS */ + + /* supported rate & extended supported rate */ + +#if 1 /* Check if the AP's supported rates are also supported by STA. */ + get_rate_set(padapter, sta_bssrate, &sta_bssrate_len); + /* RTW_INFO("sta_bssrate_len=%d\n", sta_bssrate_len); */ + + if (pmlmeext->cur_channel == 14) /* for JAPAN, channel 14 can only uses B Mode(CCK) */ + sta_bssrate_len = 4; + + + /* for (i = 0; i < sta_bssrate_len; i++) { */ + /* RTW_INFO("sta_bssrate[%d]=%02X\n", i, sta_bssrate[i]); */ + /* } */ + + for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { + if (pmlmeinfo->network.SupportedRates[i] == 0) + break; + RTW_INFO("network.SupportedRates[%d]=%02X\n", i, pmlmeinfo->network.SupportedRates[i]); + } + + + for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { + if (pmlmeinfo->network.SupportedRates[i] == 0) + break; + + + /* Check if the AP's supported rates are also supported by STA. */ + for (j = 0; j < sta_bssrate_len; j++) { + /* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */ + if ((pmlmeinfo->network.SupportedRates[i] | IEEE80211_BASIC_RATE_MASK) + == (sta_bssrate[j] | IEEE80211_BASIC_RATE_MASK)) { + /* RTW_INFO("match i = %d, j=%d\n", i, j); */ + break; + } else { + /* RTW_INFO("not match: %02X != %02X\n", (pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK), (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)); */ + } + } + + if (j == sta_bssrate_len) { + /* the rate is not supported by STA */ + RTW_INFO("%s(): the rate[%d]=%02X is not supported by STA!\n", __FUNCTION__, i, pmlmeinfo->network.SupportedRates[i]); + } else { + /* the rate is supported by STA */ + bssrate[index++] = pmlmeinfo->network.SupportedRates[i]; + } + } + + bssrate_len = index; + RTW_INFO("bssrate_len = %d\n", bssrate_len); + +#else /* Check if the AP's supported rates are also supported by STA. */ +#if 0 + get_rate_set(padapter, bssrate, &bssrate_len); +#else + for (bssrate_len = 0; bssrate_len < NumRates; bssrate_len++) { + if (pmlmeinfo->network.SupportedRates[bssrate_len] == 0) + break; + + if (pmlmeinfo->network.SupportedRates[bssrate_len] == 0x2C) /* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */ + break; + + bssrate[bssrate_len] = pmlmeinfo->network.SupportedRates[bssrate_len]; + } +#endif +#endif /* Check if the AP's supported rates are also supported by STA. */ + + if ((bssrate_len == 0) && (pmlmeinfo->network.SupportedRates[0] != 0)) { + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; /* don't connect to AP if no joint supported rate */ + } + + + if (bssrate_len > 8) { + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); + } else if (bssrate_len > 0) + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); + else + RTW_INFO("%s: Connect to AP without 11b and 11g data rate!\n", __FUNCTION__); + + /* vendor specific IE, such as WPA, WMM, WPS */ + for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pmlmeinfo->network.IELength;) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(pmlmeinfo->network.IEs + i); + + switch (pIE->ElementID) { + case _VENDOR_SPECIFIC_IE_: + if ((_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) || + (_rtw_memcmp(pIE->data, WMM_OUI, 4)) || + (_rtw_memcmp(pIE->data, WPS_OUI, 4))) { + vs_ie_length = pIE->Length; + if ((!padapter->registrypriv.wifi_spec) && (_rtw_memcmp(pIE->data, WPS_OUI, 4))) { + /* Commented by Kurt 20110629 */ + /* In some older APs, WPS handshake */ + /* would be fail if we append vender extensions informations to AP */ + + vs_ie_length = 14; + } + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, vs_ie_length, pIE->data, &(pattrib->pktlen)); + } + break; + + case EID_WPA2: +#ifdef CONFIG_RTW_80211R + if ((is_reassoc == _TRUE) && (rtw_to_roam(padapter) > 0) && rtw_chk_ft_flags(padapter, RTW_FT_SUPPORTED)) { + pie = rtw_get_ie(pftpriv->updated_ft_ies, EID_WPA2, &ft_ie_len, pftpriv->updated_ft_ies_len); + if (pie) + pframe = rtw_set_ie(pframe, EID_WPA2, ft_ie_len, pie+2, &(pattrib->pktlen)); + } else +#endif + pframe = rtw_set_ie(pframe, EID_WPA2, pIE->Length, pIE->data, &(pattrib->pktlen)); + break; +#ifdef CONFIG_80211N_HT + case EID_HTCapability: + if (padapter->mlmepriv.htpriv.ht_option == _TRUE) { + if (!(is_ap_in_tkip(padapter))) { + _rtw_memcpy(&(pmlmeinfo->HT_caps), pIE->data, sizeof(struct HT_caps_element)); + + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info = cpu_to_le16(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info); + + pframe = rtw_set_ie(pframe, EID_HTCapability, pIE->Length , (u8 *)(&(pmlmeinfo->HT_caps)), &(pattrib->pktlen)); + } + } + break; + + case EID_EXTCapability: + if (padapter->mlmepriv.htpriv.ht_option == _TRUE) + pframe = rtw_set_ie(pframe, EID_EXTCapability, pIE->Length, pIE->data, &(pattrib->pktlen)); + break; +#endif /* CONFIG_80211N_HT */ +#ifdef CONFIG_80211AC_VHT + case EID_VHTCapability: + if (padapter->mlmepriv.vhtpriv.vht_option == _TRUE) + pframe = rtw_set_ie(pframe, EID_VHTCapability, pIE->Length, pIE->data, &(pattrib->pktlen)); + break; + + case EID_OpModeNotification: + if (padapter->mlmepriv.vhtpriv.vht_option == _TRUE) + pframe = rtw_set_ie(pframe, EID_OpModeNotification, pIE->Length, pIE->data, &(pattrib->pktlen)); + break; +#endif /* CONFIG_80211AC_VHT */ + default: + break; + } + + i += (pIE->Length + 2); + } + + if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 6 , REALTEK_96B_IE, &(pattrib->pktlen)); + + +#ifdef CONFIG_WAPI_SUPPORT + rtw_build_assoc_req_wapi_ie(padapter, pframe, pattrib); +#endif + + +#ifdef CONFIG_P2P + +#ifdef CONFIG_IOCTL_CFG80211 + if (adapter_wdev_data(padapter)->p2p_enabled && pwdinfo->driver_interface == DRIVER_CFG80211) { + if (pmlmepriv->p2p_assoc_req_ie && pmlmepriv->p2p_assoc_req_ie_len > 0) { + _rtw_memcpy(pframe, pmlmepriv->p2p_assoc_req_ie, pmlmepriv->p2p_assoc_req_ie_len); + pframe += pmlmepriv->p2p_assoc_req_ie_len; + pattrib->pktlen += pmlmepriv->p2p_assoc_req_ie_len; + } + } else +#endif /* CONFIG_IOCTL_CFG80211 */ + { + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) { + /* Should add the P2P IE in the association request frame. */ + /* P2P OUI */ + + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20101109 */ + /* According to the P2P Specification, the association request frame should contain 3 P2P attributes */ + /* 1. P2P Capability */ + /* 2. Extended Listen Timing */ + /* 3. Device Info */ + /* Commented by Albert 20110516 */ + /* 4. P2P Interface */ + + /* P2P Capability */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; + + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) + p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; + else + p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; + + /* Extended Listen Timing */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0004); + p2pielen += 2; + + /* Value: */ + /* Availability Period */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); + p2pielen += 2; + + /* Availability Interval */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0xFFFF); + p2pielen += 2; + + /* Device Info */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + /* 21->P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ + /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address */ + _rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Config Method */ + /* This field should be big endian. Noted by P2P specification. */ + if ((pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) || + (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN)) + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); + else + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC); + + p2pielen += 2; + + /* Primary Device Type */ + /* Category ID */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + p2pielen += 2; + + /* OUI */ + *(u32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + p2pielen += 2; + + /* Number of Secondary Device Types */ + p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ + + /* Device Name */ + /* Type: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + p2pielen += 2; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); + p2pielen += pwdinfo->device_name_len; + + /* P2P Interface */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_INTERFACE; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x000D); + p2pielen += 2; + + /* Value: */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); /* P2P Device Address */ + p2pielen += ETH_ALEN; + + p2pie[p2pielen++] = 1; /* P2P Interface Address Count */ + + _rtw_memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); /* P2P Interface Address List */ + p2pielen += ETH_ALEN; + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen); + } + } + +#endif /* CONFIG_P2P */ + +#ifdef CONFIG_WFD + wfdielen = rtw_append_assoc_req_wfd_ie(padapter, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif +#ifdef CONFIG_APPEND_VENDOR_IE_ENABLE + pattrib->pktlen += rtw_build_vendor_ie(padapter , pframe , WIFI_ASSOCREQ_VENDOR_IE_BIT); +#endif +#ifdef CONFIG_RTW_80211R + if (rtw_chk_ft_flags(padapter, RTW_FT_SUPPORTED)) { + u8 mdieval[3] = {0}; + + _rtw_memcpy(mdieval, &(pftpriv->mdid), 2); + mdieval[2] = pftpriv->ft_cap; + pframe = rtw_set_ie(pframe, _MDIE_, 3, mdieval, &(pattrib->pktlen)); + } + + if (is_reassoc == _TRUE) { + if ((rtw_to_roam(padapter) > 0) && rtw_chk_ft_flags(padapter, RTW_FT_SUPPORTED)) { + u8 is_ft_roaming_with_rsn_ie = _TRUE; + + pie = rtw_get_ie(pftpriv->updated_ft_ies, EID_WPA2, &ft_ie_len, pftpriv->updated_ft_ies_len); + if (!pie) + is_ft_roaming_with_rsn_ie = _FALSE; + + pie = rtw_get_ie(pftpriv->updated_ft_ies, _FTIE_, &ft_ie_len, pftpriv->updated_ft_ies_len); + if (pie && is_ft_roaming_with_rsn_ie) + pframe = rtw_set_ie(pframe, _FTIE_, ft_ie_len , pie+2, &(pattrib->pktlen)); + } + } +#endif + + pattrib->last_txcmdsz = pattrib->pktlen; + dump_mgntframe(padapter, pmgntframe); + + ret = _SUCCESS; + +exit: + if (ret == _SUCCESS) + rtw_buf_update(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len, (u8 *)pwlanhdr, pattrib->pktlen); + else + rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len); + + return; +} + +void issue_assocreq(_adapter *padapter) +{ + _issue_assocreq(padapter, _FALSE); +} + +void issue_reassocreq(_adapter *padapter) +{ + _issue_assocreq(padapter, _TRUE); +} + +/* when wait_ack is ture, this function shoule be called at process context */ +static int _issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int wait_ack) +{ + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv; + struct mlme_ext_priv *pmlmeext; + struct mlme_ext_info *pmlmeinfo; + + /* RTW_INFO("%s:%d\n", __FUNCTION__, power_mode); */ + + if (!padapter) + goto exit; + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + goto exit; + + pxmitpriv = &(padapter->xmitpriv); + pmlmeext = &(padapter->mlmeextpriv); + pmlmeinfo = &(pmlmeext->mlmext_info); + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + pattrib->retry_ctrl = _FALSE; + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) + SetFrDs(fctrl); + else if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) + SetToDs(fctrl); + + if (power_mode) + SetPwrMgt(fctrl); + + _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_DATA_NULL); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pattrib->last_txcmdsz = pattrib->pktlen; + + if (wait_ack) + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + } + +exit: + return ret; +} + +/* + * [IMPORTANT] Don't call this function in interrupt context + * + * When wait_ms > 0, this function should be called at process context + * wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT + * wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX + * try_cnt means the maximal TX count to try + * da == NULL for station mode + */ +int issue_nulldata(_adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms) +{ + int ret = _FAIL; + int i = 0; + u32 start = rtw_get_current_time(); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct sta_info *psta; + u8 macid_sleep_reg_access = _TRUE; + +#ifdef CONFIG_MCC_MODE + if (MCC_EN(padapter)) { + /* driver doesn't access macid sleep reg under MCC */ + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) { + macid_sleep_reg_access = _FALSE; + + if (da == NULL) { + RTW_INFO("Warning: Do not tx null data to AP under MCC mode\n"); + rtw_warn_on(1); + } + + } + } +#endif + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + goto exit; + + /* da == NULL, assum it's null data for sta to ap*/ + if (da == NULL) + da = get_my_bssid(&(pmlmeinfo->network)); + + psta = rtw_get_stainfo(&padapter->stapriv, da); + if (psta) { + if (macid_sleep_reg_access) { + if (power_mode) + rtw_hal_macid_sleep(padapter, psta->mac_id); + else + rtw_hal_macid_wakeup(padapter, psta->mac_id); + } + } else { + RTW_INFO(FUNC_ADPT_FMT ": Can't find sta info for " MAC_FMT ", skip macid %s!!\n", + FUNC_ADPT_ARG(padapter), MAC_ARG(da), power_mode ? "sleep" : "wakeup"); + rtw_warn_on(1); + } + + do { + ret = _issue_nulldata(padapter, da, power_mode, wait_ms > 0 ? _TRUE : _FALSE); + + i++; + + if (RTW_CANNOT_RUN(padapter)) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + rtw_msleep_os(wait_ms); + + } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + + if (ret != _FAIL) { + ret = _SUCCESS; +#ifndef DBG_XMIT_ACK + goto exit; +#endif + } + + if (try_cnt && wait_ms) { + if (da) + RTW_INFO(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + else + RTW_INFO(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + } +exit: + return ret; +} + +/* + * [IMPORTANT] This function run in interrupt context + * + * The null data packet would be sent without power bit, + * and not guarantee success. + */ +s32 issue_nulldata_in_interrupt(PADAPTER padapter, u8 *da, unsigned int power_mode) +{ + int ret; + struct mlme_ext_priv *pmlmeext; + struct mlme_ext_info *pmlmeinfo; + + + pmlmeext = &padapter->mlmeextpriv; + pmlmeinfo = &pmlmeext->mlmext_info; + + /* da == NULL, assum it's null data for sta to ap*/ + if (da == NULL) + da = get_my_bssid(&(pmlmeinfo->network)); + + ret = _issue_nulldata(padapter, da, power_mode, _FALSE); + + return ret; +} + +/* when wait_ack is ture, this function shoule be called at process context */ +static int _issue_qos_nulldata(_adapter *padapter, unsigned char *da, u16 tid, int wait_ack) +{ + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl, *qc; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + goto exit; + + RTW_INFO("%s\n", __FUNCTION__); + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + pattrib->hdrlen += 2; + pattrib->qos_en = _TRUE; + pattrib->eosp = 1; + pattrib->ack_policy = 0; + pattrib->mdata = 0; + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) + SetFrDs(fctrl); + else if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) + SetToDs(fctrl); + + if (pattrib->mdata) + SetMData(fctrl); + + qc = (unsigned short *)(pframe + pattrib->hdrlen - 2); + + SetPriority(qc, tid); + + SetEOSP(qc, pattrib->eosp); + + SetAckpolicy(qc, pattrib->ack_policy); + + _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_QOS_DATA_NULL); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr_qos); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos); + + pattrib->last_txcmdsz = pattrib->pktlen; + + if (wait_ack) + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + } + +exit: + return ret; +} + +/* + * when wait_ms >0 , this function should be called at process context + * wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT + * wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX + * try_cnt means the maximal TX count to try + * da == NULL for station mode + */ +int issue_qos_nulldata(_adapter *padapter, unsigned char *da, u16 tid, int try_cnt, int wait_ms) +{ + int ret = _FAIL; + int i = 0; + u32 start = rtw_get_current_time(); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + goto exit; + + /* da == NULL, assum it's null data for sta to ap*/ + if (da == NULL) + da = get_my_bssid(&(pmlmeinfo->network)); + + do { + ret = _issue_qos_nulldata(padapter, da, tid, wait_ms > 0 ? _TRUE : _FALSE); + + i++; + + if (RTW_CANNOT_RUN(padapter)) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + rtw_msleep_os(wait_ms); + + } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + + if (ret != _FAIL) { + ret = _SUCCESS; +#ifndef DBG_XMIT_ACK + goto exit; +#endif + } + + if (try_cnt && wait_ms) { + if (da) + RTW_INFO(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + else + RTW_INFO(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + } +exit: + return ret; +} + +static int _issue_deauth(_adapter *padapter, unsigned char *da, unsigned short reason, u8 wait_ack, u8 key_type) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + int ret = _FAIL; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#endif /* CONFIG_P2P */ + + /* RTW_INFO("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); */ + +#ifdef CONFIG_P2P + if (!(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) && (pwdinfo->rx_invitereq_info.scan_op_ch_only)) { + _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); + _set_timer(&pwdinfo->reset_ch_sitesurvey, 10); + } +#endif /* CONFIG_P2P */ + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + goto exit; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + pattrib->retry_ctrl = _FALSE; + pattrib->key_type = key_type; + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_DEAUTH); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + reason = cpu_to_le16(reason); + pframe = rtw_set_fixed_ie(pframe, _RSON_CODE_ , (unsigned char *)&reason, &(pattrib->pktlen)); + + pattrib->last_txcmdsz = pattrib->pktlen; + + + if (wait_ack) + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + } + +exit: + return ret; +} + +int issue_deauth(_adapter *padapter, unsigned char *da, unsigned short reason) +{ + RTW_INFO("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); + return _issue_deauth(padapter, da, reason, _FALSE, IEEE80211W_RIGHT_KEY); +} + +#ifdef CONFIG_IEEE80211W +int issue_deauth_11w(_adapter *padapter, unsigned char *da, unsigned short reason, u8 key_type) +{ + RTW_INFO("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); + return _issue_deauth(padapter, da, reason, _FALSE, key_type); +} +#endif /* CONFIG_IEEE80211W */ + +/* + * wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT + * wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX + * try_cnt means the maximal TX count to try + */ +int issue_deauth_ex(_adapter *padapter, u8 *da, unsigned short reason, int try_cnt, + int wait_ms) +{ + int ret = _FAIL; + int i = 0; + u32 start = rtw_get_current_time(); + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + goto exit; + + do { + ret = _issue_deauth(padapter, da, reason, wait_ms > 0 ? _TRUE : _FALSE, IEEE80211W_RIGHT_KEY); + + i++; + + if (RTW_CANNOT_RUN(padapter)) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + rtw_msleep_os(wait_ms); + + } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + + if (ret != _FAIL) { + ret = _SUCCESS; +#ifndef DBG_XMIT_ACK + goto exit; +#endif + } + + if (try_cnt && wait_ms) { + if (da) + RTW_INFO(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + else + RTW_INFO(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + } +exit: + return ret; +} + +void issue_action_spct_ch_switch(_adapter *padapter, u8 *ra, u8 new_ch, u8 ch_offset) +{ + _irqL irqL; + _list *plist, *phead; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + return; + + RTW_INFO(FUNC_NDEV_FMT" ra="MAC_FMT", ch:%u, offset:%u\n", + FUNC_NDEV_ARG(padapter->pnetdev), MAC_ARG(ra), new_ch, ch_offset); + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, ra, ETH_ALEN); /* RA */ + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); /* TA */ + _rtw_memcpy(pwlanhdr->addr3, ra, ETH_ALEN); /* DA = RA */ + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + /* category, action */ + { + u8 category, action; + category = RTW_WLAN_CATEGORY_SPECTRUM_MGMT; + action = RTW_WLAN_ACTION_SPCT_CHL_SWITCH; + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + } + + pframe = rtw_set_ie_ch_switch(pframe, &(pattrib->pktlen), 0, new_ch, 0); + pframe = rtw_set_ie_secondary_ch_offset(pframe, &(pattrib->pktlen), + hal_ch_offset_to_secondary_ch_offset(ch_offset)); + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + +} + +#ifdef CONFIG_IEEE80211W +void issue_action_SA_Query(_adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short tid, u8 key_type) +{ + u8 category = RTW_WLAN_CATEGORY_SA_QUERY; + u16 reason_code; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + u8 *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + u16 *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + struct registry_priv *pregpriv = &padapter->registrypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + return; + + RTW_INFO("%s, %04x\n", __FUNCTION__, tid); + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) { + RTW_INFO("%s: alloc_mgtxmitframe fail\n", __FUNCTION__); + return; + } + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + pattrib->key_type = key_type; + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + if (raddr) + _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); + else + _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie(pframe, 1, &category, &pattrib->pktlen); + pframe = rtw_set_fixed_ie(pframe, 1, &action, &pattrib->pktlen); + + switch (action) { + case 0: /* SA Query req */ + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&pmlmeext->sa_query_seq, &pattrib->pktlen); + pmlmeext->sa_query_seq++; + /* send sa query request to AP, AP should reply sa query response in 1 second */ + if (pattrib->key_type == IEEE80211W_RIGHT_KEY) { + psta = rtw_get_stainfo(pstapriv, raddr); + if (psta != NULL) { + /* RTW_INFO("%s, %d, set dot11w_expire_timer\n", __func__, __LINE__); */ + _set_timer(&psta->dot11w_expire_timer, 1000); + } + } + break; + + case 1: /* SA Query rsp */ + tid = cpu_to_le16(tid); + /* RTW_INFO("rtw_set_fixed_ie, %04x\n", tid); */ + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&tid, &pattrib->pktlen); + break; + default: + break; + } + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); +} +#endif /* CONFIG_IEEE80211W */ + +/** + * issue_action_ba - internal function to TX Block Ack action frame + * @padapter: the adapter to TX + * @raddr: receiver address + * @action: Block Ack Action + * @tid: tid + * @size: the announced AMPDU buffer size. used by ADDBA_RESP + * @status: status/reason code. used by ADDBA_RESP, DELBA + * @initiator: if we are the initiator of AMPDU association. used by DELBA + * @wait_ack: used xmit ack + * + * Returns: + * _SUCCESS: No xmit ack is used or acked + * _FAIL: not acked when using xmit ack + */ +static int issue_action_ba(_adapter *padapter, unsigned char *raddr, unsigned char action + , u8 tid, u8 size, u16 status, u8 initiator, int wait_ack) +{ + int ret = _FAIL; + u8 category = RTW_WLAN_CATEGORY_BACK; + u16 start_seq; + u16 BA_para_set; + u16 BA_timeout_value; + u16 BA_starting_seqctrl; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + u8 *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + u16 *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + struct registry_priv *pregpriv = &padapter->registrypriv; + +#ifdef CONFIG_80211N_HT + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + goto exit; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + /* _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */ + _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + + if (category == 3) { + switch (action) { + case RTW_WLAN_ACTION_ADDBA_REQ: + do { + pmlmeinfo->dialogToken++; + } while (pmlmeinfo->dialogToken == 0); + pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->dialogToken), &(pattrib->pktlen)); + +#if defined(CONFIG_RTL8188E) && defined(CONFIG_SDIO_HCI) + BA_para_set = (0x0802 | ((tid & 0xf) << 2)); /* immediate ack & 16 buffer size */ +#else + BA_para_set = (0x1002 | ((tid & 0xf) << 2)); /* immediate ack & 64 buffer size */ +#endif + +#ifdef CONFIG_TX_AMSDU + if (padapter->tx_amsdu >= 1) /* TX AMSDU enabled */ + BA_para_set |= BIT(0); + else /* TX AMSDU disabled */ + BA_para_set &= ~BIT(0); +#endif + BA_para_set = cpu_to_le16(BA_para_set); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_para_set)), &(pattrib->pktlen)); + + /* BA_timeout_value = 0xffff; */ /* max: 65535 TUs(~ 65 ms) */ + BA_timeout_value = 5000;/* ~ 5ms */ + BA_timeout_value = cpu_to_le16(BA_timeout_value); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_timeout_value)), &(pattrib->pktlen)); + + /* if ((psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress)) != NULL) */ + psta = rtw_get_stainfo(pstapriv, raddr); + if (psta != NULL) { + start_seq = (psta->sta_xmitpriv.txseq_tid[tid & 0x07] & 0xfff) + 1; + + RTW_INFO("BA_starting_seqctrl = %d for TID=%d\n", start_seq, tid & 0x07); + + psta->BA_starting_seqctrl[tid & 0x07] = start_seq; + + BA_starting_seqctrl = start_seq << 4; + } + + BA_starting_seqctrl = cpu_to_le16(BA_starting_seqctrl); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_starting_seqctrl)), &(pattrib->pktlen)); + break; + + case RTW_WLAN_ACTION_ADDBA_RESP: + pframe = rtw_set_fixed_ie(pframe, 1, &(pmlmeinfo->ADDBA_req.dialog_token), &(pattrib->pktlen)); + status = cpu_to_le16(status); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&status), &(pattrib->pktlen)); + + BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set); + + BA_para_set &= ~IEEE80211_ADDBA_PARAM_TID_MASK; + BA_para_set |= (tid << 2) & IEEE80211_ADDBA_PARAM_TID_MASK; + + BA_para_set &= ~RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; + BA_para_set |= (size << 6) & RTW_IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK; + + if (!padapter->registrypriv.wifi_spec) { + if (pregpriv->ampdu_amsdu == 0) /* disabled */ + BA_para_set &= ~BIT(0); + else if (pregpriv->ampdu_amsdu == 1) /* enabled */ + BA_para_set |= BIT(0); + } + + BA_para_set = cpu_to_le16(BA_para_set); + + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_para_set)), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(pmlmeinfo->ADDBA_req.BA_timeout_value)), &(pattrib->pktlen)); + break; + + case RTW_WLAN_ACTION_DELBA: + BA_para_set = 0; + BA_para_set |= (tid << 12) & IEEE80211_DELBA_PARAM_TID_MASK; + BA_para_set |= (initiator << 11) & IEEE80211_DELBA_PARAM_INITIATOR_MASK; + + BA_para_set = cpu_to_le16(BA_para_set); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(BA_para_set)), &(pattrib->pktlen)); + status = cpu_to_le16(status); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)(&(status)), &(pattrib->pktlen)); + break; + default: + break; + } + } + + pattrib->last_txcmdsz = pattrib->pktlen; + + if (wait_ack) + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + } + +exit: +#endif /* CONFIG_80211N_HT */ + return ret; +} + +/** + * issue_addba_req - TX ADDBA_REQ + * @adapter: the adapter to TX + * @ra: receiver address + * @tid: tid + */ +inline void issue_addba_req(_adapter *adapter, unsigned char *ra, u8 tid) +{ + issue_action_ba(adapter, ra, RTW_WLAN_ACTION_ADDBA_REQ + , tid + , 0 /* unused */ + , 0 /* unused */ + , 0 /* unused */ + , _FALSE + ); + RTW_INFO(FUNC_ADPT_FMT" ra="MAC_FMT" tid=%u\n" + , FUNC_ADPT_ARG(adapter), MAC_ARG(ra), tid); + +} + +/** + * issue_addba_rsp - TX ADDBA_RESP + * @adapter: the adapter to TX + * @ra: receiver address + * @tid: tid + * @status: status code + * @size: the announced AMPDU buffer size + */ +inline void issue_addba_rsp(_adapter *adapter, unsigned char *ra, u8 tid, u16 status, u8 size) +{ + issue_action_ba(adapter, ra, RTW_WLAN_ACTION_ADDBA_RESP + , tid + , size + , status + , 0 /* unused */ + , _FALSE + ); + RTW_INFO(FUNC_ADPT_FMT" ra="MAC_FMT" status=%u, tid=%u, size=%u\n" + , FUNC_ADPT_ARG(adapter), MAC_ARG(ra), status, tid, size); +} + +/** + * issue_addba_rsp_wait_ack - TX ADDBA_RESP and wait ack + * @adapter: the adapter to TX + * @ra: receiver address + * @tid: tid + * @status: status code + * @size: the announced AMPDU buffer size + * @try_cnt: the maximal TX count to try + * @wait_ms: == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT + * > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX + */ +inline u8 issue_addba_rsp_wait_ack(_adapter *adapter, unsigned char *ra, u8 tid, u16 status, u8 size, int try_cnt, int wait_ms) +{ + int ret = _FAIL; + int i = 0; + u32 start = rtw_get_current_time(); + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(adapter))) + goto exit; + + do { + ret = issue_action_ba(adapter, ra, RTW_WLAN_ACTION_ADDBA_RESP + , tid + , size + , status + , 0 /* unused */ + , _TRUE + ); + + i++; + + if (RTW_CANNOT_RUN(adapter)) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + rtw_msleep_os(wait_ms); + + } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + + if (ret != _FAIL) { + ret = _SUCCESS; +#ifndef DBG_XMIT_ACK + /* goto exit; */ +#endif + } + + if (try_cnt && wait_ms) { + RTW_INFO(FUNC_ADPT_FMT" ra="MAC_FMT" tid=%u%s, %d/%d in %u ms\n" + , FUNC_ADPT_ARG(adapter), MAC_ARG(ra), tid + , ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + } + +exit: + return ret; +} + +/** + * issue_del_ba - TX DELBA + * @adapter: the adapter to TX + * @ra: receiver address + * @tid: tid + * @reason: reason code + * @initiator: if we are the initiator of AMPDU association. used by DELBA + */ +inline void issue_del_ba(_adapter *adapter, unsigned char *ra, u8 tid, u16 reason, u8 initiator) +{ + issue_action_ba(adapter, ra, RTW_WLAN_ACTION_DELBA + , tid + , 0 /* unused */ + , reason + , initiator + , _FALSE + ); + RTW_INFO(FUNC_ADPT_FMT" ra="MAC_FMT" reason=%u, tid=%u, initiator=%u\n" + , FUNC_ADPT_ARG(adapter), MAC_ARG(ra), reason, tid, initiator); +} + +/** + * issue_del_ba_ex - TX DELBA with xmit ack options + * @adapter: the adapter to TX + * @ra: receiver address + * @tid: tid + * @reason: reason code + * @initiator: if we are the initiator of AMPDU association. used by DELBA + * @try_cnt: the maximal TX count to try + * @wait_ms: == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT + * > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX + */ +int issue_del_ba_ex(_adapter *adapter, unsigned char *ra, u8 tid, u16 reason, u8 initiator + , int try_cnt, int wait_ms) +{ + int ret = _FAIL; + int i = 0; + u32 start = rtw_get_current_time(); + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(adapter))) + goto exit; + + do { + ret = issue_action_ba(adapter, ra, RTW_WLAN_ACTION_DELBA + , tid + , 0 /* unused */ + , reason + , initiator + , wait_ms > 0 ? _TRUE : _FALSE + ); + + i++; + + if (RTW_CANNOT_RUN(adapter)) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + rtw_msleep_os(wait_ms); + + } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + + if (ret != _FAIL) { + ret = _SUCCESS; +#ifndef DBG_XMIT_ACK + /* goto exit; */ +#endif + } + + if (try_cnt && wait_ms) { + RTW_INFO(FUNC_ADPT_FMT" ra="MAC_FMT" reason=%u, tid=%u, initiator=%u%s, %d/%d in %u ms\n" + , FUNC_ADPT_ARG(adapter), MAC_ARG(ra), reason, tid, initiator + , ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + } +exit: + return ret; +} + +static void issue_action_BSSCoexistPacket(_adapter *padapter) +{ + _irqL irqL; + _list *plist, *phead; + unsigned char category, action; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct wlan_network *pnetwork = NULL; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + _queue *queue = &(pmlmepriv->scanned_queue); + u8 InfoContent[16] = {0}; + u8 ICS[8][15]; +#ifdef CONFIG_80211N_HT + if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0)) + return; + + if (_TRUE == pmlmeinfo->bwmode_updated) + return; + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + return; + + RTW_INFO("%s\n", __FUNCTION__); + + + category = RTW_WLAN_CATEGORY_PUBLIC; + action = ACT_PUBLIC_BSSCOEXIST; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + + + /* */ + if (pmlmepriv->num_FortyMHzIntolerant > 0) { + u8 iedata = 0; + + iedata |= BIT(2);/* 20 MHz BSS Width Request */ + + pframe = rtw_set_ie(pframe, EID_BSSCoexistence, 1, &iedata, &(pattrib->pktlen)); + + } + + + /* */ + _rtw_memset(ICS, 0, sizeof(ICS)); + if (pmlmepriv->num_sta_no_ht > 0) { + int i; + + _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + + phead = get_list_head(queue); + plist = get_next(phead); + + while (1) { + int len; + u8 *p; + WLAN_BSSID_EX *pbss_network; + + if (rtw_end_of_queue_search(phead, plist) == _TRUE) + break; + + pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); + + plist = get_next(plist); + + pbss_network = (WLAN_BSSID_EX *)&pnetwork->network; + + p = rtw_get_ie(pbss_network->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pbss_network->IELength - _FIXED_IE_LENGTH_); + if ((p == NULL) || (len == 0)) { /* non-HT */ + if ((pbss_network->Configuration.DSConfig <= 0) || (pbss_network->Configuration.DSConfig > 14)) + continue; + + ICS[0][pbss_network->Configuration.DSConfig] = 1; + + if (ICS[0][0] == 0) + ICS[0][0] = 1; + } + + } + + _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); + + + for (i = 0; i < 8; i++) { + if (ICS[i][0] == 1) { + int j, k = 0; + + InfoContent[k] = i; + /* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent,i); */ + k++; + + for (j = 1; j <= 14; j++) { + if (ICS[i][j] == 1) { + if (k < 16) { + InfoContent[k] = j; /* channel number */ + /* SET_BSS_INTOLERANT_ELE_CHANNEL(InfoContent+k, j); */ + k++; + } + } + } + + pframe = rtw_set_ie(pframe, EID_BSSIntolerantChlReport, k, InfoContent, &(pattrib->pktlen)); + + } + + } + + + } + + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); +#endif /* CONFIG_80211N_HT */ +} + +/* Spatial Multiplexing Powersave (SMPS) action frame */ +int _issue_action_SM_PS(_adapter *padapter , unsigned char *raddr , u8 NewMimoPsMode , u8 wait_ack) +{ + + int ret = _FAIL; + unsigned char category = RTW_WLAN_CATEGORY_HT; + u8 action = RTW_WLAN_ACTION_HT_SM_PS; + u8 sm_power_control = 0; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + + if (NewMimoPsMode == WLAN_HT_CAP_SM_PS_DISABLED) { + sm_power_control = sm_power_control & ~(BIT(0)); /* SM Power Save Enable = 0 SM Power Save Disable */ + } else if (NewMimoPsMode == WLAN_HT_CAP_SM_PS_STATIC) { + sm_power_control = sm_power_control | BIT(0); /* SM Power Save Enable = 1 SM Power Save Enable */ + sm_power_control = sm_power_control & ~(BIT(1)); /* SM Mode = 0 Static Mode */ + } else if (NewMimoPsMode == WLAN_HT_CAP_SM_PS_DYNAMIC) { + sm_power_control = sm_power_control | BIT(0); /* SM Power Save Enable = 1 SM Power Save Enable */ + sm_power_control = sm_power_control | BIT(1); /* SM Mode = 1 Dynamic Mode */ + } else + return ret; + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + return ret; + + RTW_INFO("%s, sm_power_control=%u, NewMimoPsMode=%u\n", __FUNCTION__ , sm_power_control , NewMimoPsMode); + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return ret; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); /* RA */ + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); /* TA */ + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); /* DA = RA */ + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + /* category, action */ + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + + pframe = rtw_set_fixed_ie(pframe, 1, &(sm_power_control), &(pattrib->pktlen)); + + pattrib->last_txcmdsz = pattrib->pktlen; + + if (wait_ack) + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + } + + if (ret != _SUCCESS) + RTW_INFO("%s, ack to\n", __func__); + + return ret; +} + +/* + * wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT + * wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX + * try_cnt means the maximal TX count to try + */ +int issue_action_SM_PS_wait_ack(_adapter *padapter, unsigned char *raddr, u8 NewMimoPsMode, int try_cnt, int wait_ms) +{ + int ret = _FAIL; + int i = 0; + u32 start = rtw_get_current_time(); + + if (rtw_rfctl_is_tx_blocked_by_ch_waiting(adapter_to_rfctl(padapter))) + goto exit; + + do { + ret = _issue_action_SM_PS(padapter, raddr, NewMimoPsMode , wait_ms > 0 ? _TRUE : _FALSE); + + i++; + + if (RTW_CANNOT_RUN(padapter)) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + rtw_msleep_os(wait_ms); + + } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0))); + + if (ret != _FAIL) { + ret = _SUCCESS; +#ifndef DBG_XMIT_ACK + goto exit; +#endif + } + + if (try_cnt && wait_ms) { + if (raddr) + RTW_INFO(FUNC_ADPT_FMT" to "MAC_FMT", %s , %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), MAC_ARG(raddr), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + else + RTW_INFO(FUNC_ADPT_FMT", %s , %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + } +exit: + + return ret; +} + +int issue_action_SM_PS(_adapter *padapter , unsigned char *raddr , u8 NewMimoPsMode) +{ + RTW_INFO("%s to "MAC_FMT"\n", __func__, MAC_ARG(raddr)); + return _issue_action_SM_PS(padapter, raddr, NewMimoPsMode , _FALSE); +} + +/** + * _send_delba_sta_tid - Cancel the AMPDU association for the specific @sta, @tid + * @adapter: the adapter to which @sta belongs + * @initiator: if we are the initiator of AMPDU association + * @sta: the sta to be checked + * @tid: the tid to be checked + * @force: cancel and send DELBA even when no AMPDU association is setup + * @wait_ack: send delba with xmit ack (valid when initiator == 0) + * + * Returns: + * _FAIL if sta is NULL + * when initiator is 1, always _SUCCESS + * when initiator is 0, _SUCCESS if DELBA is acked + */ +static unsigned int _send_delba_sta_tid(_adapter *adapter, u8 initiator, struct sta_info *sta, u8 tid + , u8 force, int wait_ack) +{ + int ret = _SUCCESS; + + if (sta == NULL) { + ret = _FAIL; + goto exit; + } + + if (initiator == 0) { + /* recipient */ + if (force || sta->recvreorder_ctrl[tid].enable == _TRUE) { + u8 ampdu_size_bak = sta->recvreorder_ctrl[tid].ampdu_size; + + sta->recvreorder_ctrl[tid].enable = _FALSE; + sta->recvreorder_ctrl[tid].ampdu_size = RX_AMPDU_SIZE_INVALID; + + if (rtw_del_rx_ampdu_test_trigger_no_tx_fail()) + ret = _FAIL; + else if (wait_ack) + ret = issue_del_ba_ex(adapter, sta->hwaddr, tid, 37, initiator, 3, 1); + else + issue_del_ba(adapter, sta->hwaddr, tid, 37, initiator); + + if (ret == _FAIL && sta->recvreorder_ctrl[tid].enable == _FALSE) + sta->recvreorder_ctrl[tid].ampdu_size = ampdu_size_bak; + } + } else if (initiator == 1) { + /* originator */ +#ifdef CONFIG_80211N_HT + if (force || sta->htpriv.agg_enable_bitmap & BIT(tid)) { + sta->htpriv.agg_enable_bitmap &= ~BIT(tid); + sta->htpriv.candidate_tid_bitmap &= ~BIT(tid); + issue_del_ba(adapter, sta->hwaddr, tid, 37, initiator); + } +#endif + } + +exit: + return ret; +} + +inline unsigned int send_delba_sta_tid(_adapter *adapter, u8 initiator, struct sta_info *sta, u8 tid + , u8 force) +{ + return _send_delba_sta_tid(adapter, initiator, sta, tid, force, 0); +} + +inline unsigned int send_delba_sta_tid_wait_ack(_adapter *adapter, u8 initiator, struct sta_info *sta, u8 tid + , u8 force) +{ + return _send_delba_sta_tid(adapter, initiator, sta, tid, force, 1); +} + +unsigned int send_delba(_adapter *padapter, u8 initiator, u8 *addr) +{ + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta = NULL; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u16 tid; + + if ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) + if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) + return _SUCCESS; + + psta = rtw_get_stainfo(pstapriv, addr); + if (psta == NULL) + return _SUCCESS; + +#if 0 + RTW_INFO("%s:%s\n", __func__, (initiator == 0) ? "RX_DIR" : "TX_DIR"); + if (initiator == 1) /* originator */ + RTW_INFO("tx agg_enable_bitmap(0x%08x)\n", psta->htpriv.agg_enable_bitmap); +#endif + + for (tid = 0; tid < TID_NUM; tid++) + send_delba_sta_tid(padapter, initiator, psta, tid, 0); + + return _SUCCESS; +} + +unsigned int send_beacon(_adapter *padapter) +{ + u8 bxmitok = _FALSE; + int issue = 0; + int poll = 0; +#if defined(CONFIG_PCI_HCI) && defined(RTL8814AE_SW_BCN) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); +#endif + +#ifdef CONFIG_PCI_HCI + /* RTW_INFO("%s\n", __FUNCTION__); */ + + rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); + + /* 8192EE Port select for Beacon DL */ + rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL); + + issue_beacon(padapter, 0); + +#ifdef RTL8814AE_SW_BCN + if (pHalData->bCorrectBCN != 0) + RTW_INFO("%s, line%d, Warnning, pHalData->bCorrectBCN != 0\n", __func__, __LINE__); + pHalData->bCorrectBCN = 1; +#endif + + return _SUCCESS; +#endif + +#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + u32 start = rtw_get_current_time(); + + rtw_hal_set_hwreg(padapter, HW_VAR_BCN_VALID, NULL); + rtw_hal_set_hwreg(padapter, HW_VAR_DL_BCN_SEL, NULL); + do { + issue_beacon(padapter, 100); + issue++; + do { + rtw_yield_os(); + rtw_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok)); + poll++; + } while ((poll % 10) != 0 && _FALSE == bxmitok && !RTW_CANNOT_RUN(padapter)); + + } while (_FALSE == bxmitok && issue < 100 && !RTW_CANNOT_RUN(padapter)); + + if (RTW_CANNOT_RUN(padapter)) + return _FAIL; + + + if (_FALSE == bxmitok) { + RTW_INFO("%s fail! %u ms\n", __FUNCTION__, rtw_get_passing_time_ms(start)); + return _FAIL; + } else { + u32 passing_time = rtw_get_passing_time_ms(start); + + if (passing_time > 100 || issue > 3) + RTW_INFO("%s success, issue:%d, poll:%d, %u ms\n", __FUNCTION__, issue, poll, rtw_get_passing_time_ms(start)); + else if (0) + RTW_INFO("%s success, issue:%d, poll:%d, %u ms\n", __FUNCTION__, issue, poll, rtw_get_passing_time_ms(start)); + + rtw_hal_fw_correct_bcn(padapter); + + return _SUCCESS; + } + +#endif + +} + +/**************************************************************************** + +Following are some utitity fuctions for WiFi MLME + +*****************************************************************************/ + +BOOLEAN IsLegal5GChannel( + IN PADAPTER Adapter, + IN u8 channel) +{ + + int i = 0; + u8 Channel_5G[45] = {36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, + 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, + 124, 126, 128, 130, 132, 134, 136, 138, 140, 149, 151, 153, 155, 157, 159, + 161, 163, 165 + }; + for (i = 0; i < sizeof(Channel_5G); i++) + if (channel == Channel_5G[i]) + return _TRUE; + return _FALSE; +} + +/* collect bss info from Beacon and Probe request/response frames. */ +u8 collect_bss_info(_adapter *padapter, union recv_frame *precv_frame, WLAN_BSSID_EX *bssid) +{ + int i; + u32 len; + u8 *p; + u16 val16, subtype; + u8 *pframe = precv_frame->u.hdr.rx_data; + u32 packet_len = precv_frame->u.hdr.len; + u8 ie_offset; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr); + + if (len > MAX_IE_SZ) { + /* RTW_INFO("IE too long for survey event\n"); */ + return _FAIL; + } + + _rtw_memset(bssid, 0, sizeof(WLAN_BSSID_EX)); + + subtype = get_frame_sub_type(pframe); + + if (subtype == WIFI_BEACON) { + bssid->Reserved[0] = 1; + ie_offset = _BEACON_IE_OFFSET_; + } else { + /* FIXME : more type */ + if (subtype == WIFI_PROBERSP) { + ie_offset = _PROBERSP_IE_OFFSET_; + bssid->Reserved[0] = 3; + } else if (subtype == WIFI_PROBEREQ) { + ie_offset = _PROBEREQ_IE_OFFSET_; + bssid->Reserved[0] = 2; + } else { + bssid->Reserved[0] = 0; + ie_offset = _FIXED_IE_LENGTH_; + } + } + + bssid->Length = sizeof(WLAN_BSSID_EX) - MAX_IE_SZ + len; + + /* below is to copy the information element */ + bssid->IELength = len; + _rtw_memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength); + + /* get the signal strength */ + /* bssid->Rssi = precv_frame->u.hdr.attrib.SignalStrength; */ /* 0-100 index. */ + bssid->Rssi = precv_frame->u.hdr.attrib.phy_info.RecvSignalPower; /* in dBM.raw data */ + bssid->PhyInfo.SignalQuality = precv_frame->u.hdr.attrib.phy_info.SignalQuality;/* in percentage */ + bssid->PhyInfo.SignalStrength = precv_frame->u.hdr.attrib.phy_info.SignalStrength;/* in percentage */ +#ifdef CONFIG_ANTENNA_DIVERSITY + rtw_hal_get_odm_var(padapter, HAL_ODM_ANTDIV_SELECT, &(bssid->PhyInfo.Optimum_antenna), NULL); +#endif + + /* checking SSID */ + p = rtw_get_ie(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset); + if (p == NULL) { + RTW_INFO("marc: cannot find SSID for survey event\n"); + return _FAIL; + } + + if (*(p + 1)) { + if (len > NDIS_802_11_LENGTH_SSID) { + RTW_INFO("%s()-%d: IE too long (%d) for survey event\n", __FUNCTION__, __LINE__, len); + return _FAIL; + } + _rtw_memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1)); + bssid->Ssid.SsidLength = *(p + 1); + } else + bssid->Ssid.SsidLength = 0; + + _rtw_memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); + + /* checking rate info... */ + i = 0; + p = rtw_get_ie(bssid->IEs + ie_offset, _SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); + if (p != NULL) { + if (len > NDIS_802_11_LENGTH_RATES_EX) { + RTW_INFO("%s()-%d: IE too long (%d) for survey event\n", __FUNCTION__, __LINE__, len); + return _FAIL; + } + _rtw_memcpy(bssid->SupportedRates, (p + 2), len); + i = len; + } + + p = rtw_get_ie(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset); + if (p != NULL) { + if (len > (NDIS_802_11_LENGTH_RATES_EX - i)) { + RTW_INFO("%s()-%d: IE too long (%d) for survey event\n", __FUNCTION__, __LINE__, len); + return _FAIL; + } + _rtw_memcpy(bssid->SupportedRates + i, (p + 2), len); + } + + /* todo: */ +#if 0 + if (judge_network_type(bssid->SupportedRates, (len + i)) == WIRELESS_11B) + bssid->NetworkTypeInUse = Ndis802_11DS; + else +#endif + { + bssid->NetworkTypeInUse = Ndis802_11OFDM24; + } + +#ifdef CONFIG_P2P + if (subtype == WIFI_PROBEREQ) { + u8 *p2p_ie; + u32 p2p_ielen; + /* Set Listion Channel */ + p2p_ie = rtw_get_p2p_ie(bssid->IEs, bssid->IELength, NULL, &p2p_ielen); + if (p2p_ie) { + u32 attr_contentlen = 0; + u8 listen_ch[5] = { 0x00 }; + + rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_LISTEN_CH, listen_ch, &attr_contentlen); + bssid->Configuration.DSConfig = listen_ch[4]; + } else { + /* use current channel */ + bssid->Configuration.DSConfig = padapter->mlmeextpriv.cur_channel; + RTW_INFO("%s()-%d: Cannot get p2p_ie. set DSconfig to op_ch(%d)\n", __FUNCTION__, __LINE__, bssid->Configuration.DSConfig); + } + + /* FIXME */ + bssid->InfrastructureMode = Ndis802_11Infrastructure; + _rtw_memcpy(bssid->MacAddress, get_addr2_ptr(pframe), ETH_ALEN); + bssid->Privacy = 1; + return _SUCCESS; + } +#endif /* CONFIG_P2P */ + + if (bssid->IELength < 12) + return _FAIL; + + /* Checking for DSConfig */ + p = rtw_get_ie(bssid->IEs + ie_offset, _DSSET_IE_, &len, bssid->IELength - ie_offset); + + bssid->Configuration.DSConfig = 0; + bssid->Configuration.Length = 0; + + if (p) + bssid->Configuration.DSConfig = *(p + 2); + else { + /* In 5G, some ap do not have DSSET IE */ + /* checking HT info for channel */ + p = rtw_get_ie(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset); + if (p) { + struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2); + bssid->Configuration.DSConfig = HT_info->primary_channel; + } else { + /* use current channel */ + bssid->Configuration.DSConfig = rtw_get_oper_ch(padapter); + } + } + + _rtw_memcpy(&bssid->Configuration.BeaconPeriod, rtw_get_beacon_interval_from_ie(bssid->IEs), 2); + bssid->Configuration.BeaconPeriod = le32_to_cpu(bssid->Configuration.BeaconPeriod); + + val16 = rtw_get_capability((WLAN_BSSID_EX *)bssid); + + if (val16 & BIT(0)) { + bssid->InfrastructureMode = Ndis802_11Infrastructure; + _rtw_memcpy(bssid->MacAddress, get_addr2_ptr(pframe), ETH_ALEN); + } else { + bssid->InfrastructureMode = Ndis802_11IBSS; + _rtw_memcpy(bssid->MacAddress, GetAddr3Ptr(pframe), ETH_ALEN); + } + + if (val16 & BIT(4)) + bssid->Privacy = 1; + else + bssid->Privacy = 0; + + bssid->Configuration.ATIMWindow = 0; + + /* 20/40 BSS Coexistence check */ + if ((pregistrypriv->wifi_spec == 1) && (_FALSE == pmlmeinfo->bwmode_updated)) { + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +#ifdef CONFIG_80211N_HT + p = rtw_get_ie(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset); + if (p && len > 0) { + struct HT_caps_element *pHT_caps; + pHT_caps = (struct HT_caps_element *)(p + 2); + + if (pHT_caps->u.HT_cap_element.HT_caps_info & BIT(14)) + pmlmepriv->num_FortyMHzIntolerant++; + } else + pmlmepriv->num_sta_no_ht++; +#endif /* CONFIG_80211N_HT */ + + } + +#ifdef CONFIG_INTEL_WIDI + /* process_intel_widi_query_or_tigger(padapter, bssid); */ + if (process_intel_widi_query_or_tigger(padapter, bssid)) + return _FAIL; +#endif /* CONFIG_INTEL_WIDI */ + +#if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) & 1 + if (strcmp(bssid->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { + RTW_INFO("Receiving %s("MAC_FMT", DSConfig:%u) from ch%u with ss:%3u, sq:%3u, RawRSSI:%3ld\n" + , bssid->Ssid.Ssid, MAC_ARG(bssid->MacAddress), bssid->Configuration.DSConfig + , rtw_get_oper_ch(padapter) + , bssid->PhyInfo.SignalStrength, bssid->PhyInfo.SignalQuality, bssid->Rssi + ); + } +#endif + + /* mark bss info receving from nearby channel as SignalQuality 101 */ + if (bssid->Configuration.DSConfig != rtw_get_oper_ch(padapter)) + bssid->PhyInfo.SignalQuality = 101; + + return _SUCCESS; +} + +void start_create_ibss(_adapter *padapter) +{ + unsigned short caps; + u8 val8; + u8 join_type; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network)); + u8 doiqk = _FALSE; + pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig; + pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); + + /* update wireless mode */ + update_wireless_mode(padapter); + + /* udpate capability */ + caps = rtw_get_capability((WLAN_BSSID_EX *)pnetwork); + update_capinfo(padapter, caps); + if (caps & cap_IBSS) { /* adhoc master */ + /* set_opmode_cmd(padapter, adhoc); */ /* removed */ + + val8 = 0xcf; + rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + + doiqk = _TRUE; + rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk); + + /* switch channel */ + set_channel_bwmode(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); + + doiqk = _FALSE; + rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk); + + beacon_timing_control(padapter); + + /* set msr to WIFI_FW_ADHOC_STATE */ + pmlmeinfo->state = WIFI_FW_ADHOC_STATE; + Set_MSR(padapter, (pmlmeinfo->state & 0x3)); + + /* issue beacon */ + if (send_beacon(padapter) == _FAIL) { + + report_join_res(padapter, -1); + pmlmeinfo->state = WIFI_FW_NULL_STATE; + } else { + rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress); + join_type = 0; + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + + report_join_res(padapter, 1); + pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; + rtw_indicate_connect(padapter); + } + } else { + RTW_INFO("start_create_ibss, invalid cap:%x\n", caps); + return; + } + /* update bc/mc sta_info */ + update_bmc_sta(padapter); + +} + +void start_clnt_join(_adapter *padapter) +{ + unsigned short caps; + u8 val8; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network)); + int beacon_timeout; + u8 ASIX_ID[] = {0x00, 0x0E, 0xC6}; + + /* update wireless mode */ + update_wireless_mode(padapter); + + /* udpate capability */ + caps = rtw_get_capability((WLAN_BSSID_EX *)pnetwork); + update_capinfo(padapter, caps); + + /* check if sta is ASIX peer and fix IOT issue if it is. */ + if (_rtw_memcmp(get_my_bssid(&pmlmeinfo->network) , ASIX_ID , 3)) { + u8 iot_flag = _TRUE; + rtw_hal_set_hwreg(padapter, HW_VAR_ASIX_IOT, (u8 *)(&iot_flag)); + } + + if (caps & cap_ESS) { + Set_MSR(padapter, WIFI_FW_STATION_STATE); + + val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) ? 0xcc : 0xcf; + +#ifdef CONFIG_WAPI_SUPPORT + if (padapter->wapiInfo.bWapiEnable && pmlmeinfo->auth_algo == dot11AuthAlgrthm_WAPI) { + /* Disable TxUseDefaultKey, RxUseDefaultKey, RxBroadcastUseDefaultKey. */ + val8 = 0x4c; + } +#endif + rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + +#ifdef CONFIG_DEAUTH_BEFORE_CONNECT + /* Because of AP's not receiving deauth before */ + /* AP may: 1)not response auth or 2)deauth us after link is complete */ + /* issue deauth before issuing auth to deal with the situation */ + + /* Commented by Albert 2012/07/21 */ + /* For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. */ + { +#ifdef CONFIG_P2P + _queue *queue = &(padapter->mlmepriv.scanned_queue); + _list *head = get_list_head(queue); + _list *pos = get_next(head); + struct wlan_network *scanned = NULL; + u8 ie_offset = 0; + _irqL irqL; + bool has_p2p_ie = _FALSE; + + _enter_critical_bh(&(padapter->mlmepriv.scanned_queue.lock), &irqL); + + for (pos = get_next(head); !rtw_end_of_queue_search(head, pos); pos = get_next(pos)) { + + scanned = LIST_CONTAINOR(pos, struct wlan_network, list); + + if (_rtw_memcmp(&(scanned->network.Ssid), &(pnetwork->Ssid), sizeof(NDIS_802_11_SSID)) == _TRUE + && _rtw_memcmp(scanned->network.MacAddress, pnetwork->MacAddress, sizeof(NDIS_802_11_MAC_ADDRESS)) == _TRUE + ) { + ie_offset = (scanned->network.Reserved[0] == 2 ? 0 : 12); + if (rtw_get_p2p_ie(scanned->network.IEs + ie_offset, scanned->network.IELength - ie_offset, NULL, NULL)) + has_p2p_ie = _TRUE; + break; + } + } + + _exit_critical_bh(&(padapter->mlmepriv.scanned_queue.lock), &irqL); + + if (scanned == NULL || rtw_end_of_queue_search(head, pos) || has_p2p_ie == _FALSE) +#endif /* CONFIG_P2P */ + /* To avoid connecting to AP fail during resume process, change retry count from 5 to 1 */ + issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, 1, 100); + } +#endif /* CONFIG_DEAUTH_BEFORE_CONNECT */ + + /* here wait for receiving the beacon to start auth */ + /* and enable a timer */ + beacon_timeout = decide_wait_for_beacon_timeout(pmlmeinfo->bcn_interval); + set_link_timer(pmlmeext, beacon_timeout); + _set_timer(&padapter->mlmepriv.assoc_timer, + (REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO * REASSOC_LIMIT) + beacon_timeout); + +#ifdef CONFIG_RTW_80211R + if ((rtw_to_roam(padapter) > 0) && rtw_chk_ft_flags(padapter, RTW_FT_SUPPORTED)) { + if (rtw_chk_ft_flags(padapter, RTW_FT_OVER_DS_SUPPORTED)) { + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + ft_priv *pftpriv = &pmlmepriv->ftpriv; + + pmlmeinfo->state = WIFI_FW_AUTH_SUCCESS | WIFI_FW_STATION_STATE; + pftpriv->ft_event.ies = pftpriv->ft_action + sizeof(struct rtw_ieee80211_hdr_3addr) + 16; + pftpriv->ft_event.ies_len = pftpriv->ft_action_len - sizeof(struct rtw_ieee80211_hdr_3addr); + + /*Not support RIC*/ + pftpriv->ft_event.ric_ies = NULL; + pftpriv->ft_event.ric_ies_len = 0; + report_ft_event(padapter); + } else { + pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE; + start_clnt_auth(padapter); + } + } else +#endif + pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE; + } else if (caps & cap_IBSS) { /* adhoc client */ + Set_MSR(padapter, WIFI_FW_ADHOC_STATE); + + val8 = 0xcf; + rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + + beacon_timing_control(padapter); + + pmlmeinfo->state = WIFI_FW_ADHOC_STATE; + + report_join_res(padapter, 1); + } else { + /* RTW_INFO("marc: invalid cap:%x\n", caps); */ + return; + } + +} + +void start_clnt_auth(_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + _cancel_timer_ex(&pmlmeext->link_timer); + + pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL); + pmlmeinfo->state |= WIFI_FW_AUTH_STATE; + + pmlmeinfo->auth_seq = 1; + pmlmeinfo->reauth_count = 0; + pmlmeinfo->reassoc_count = 0; + pmlmeinfo->link_count = 0; + pmlmeext->retry = 0; + +#ifdef CONFIG_RTW_80211R + if ((rtw_to_roam(padapter) > 0) && rtw_chk_ft_flags(padapter, RTW_FT_SUPPORTED)) { + rtw_set_ft_status(padapter, RTW_FT_AUTHENTICATING_STA); + RTW_PRINT("start ft auth\n"); + } else +#endif + RTW_PRINT("start auth\n"); + issue_auth(padapter, NULL, 0); + + set_link_timer(pmlmeext, REAUTH_TO); + +} + + +void start_clnt_assoc(_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + _cancel_timer_ex(&pmlmeext->link_timer); + + pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE)); + pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE); + +#ifdef CONFIG_RTW_80211R + if ((rtw_to_roam(padapter) > 0) && rtw_chk_ft_flags(padapter, RTW_FT_SUPPORTED)) + issue_reassocreq(padapter); + else +#endif + issue_assocreq(padapter); + + set_link_timer(pmlmeext, REASSOC_TO); +} + +unsigned int receive_disconnect(_adapter *padapter, unsigned char *MacAddr, unsigned short reason, u8 locally_generated) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if (!(_rtw_memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) + return _SUCCESS; + + RTW_INFO("%s\n", __FUNCTION__); + + if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) { + if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { + if (report_del_sta_event(padapter, MacAddr, reason, _TRUE, locally_generated) != _FAIL) + pmlmeinfo->state = WIFI_FW_NULL_STATE; + } else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE) { + if (report_join_res(padapter, -2) != _FAIL) + pmlmeinfo->state = WIFI_FW_NULL_STATE; + } else + RTW_INFO(FUNC_ADPT_FMT" - End to Disconnect\n", FUNC_ADPT_ARG(padapter)); +#ifdef CONFIG_RTW_80211R + if ((rtw_to_roam(padapter) > 0) && !rtw_chk_ft_status(padapter, RTW_FT_REQUESTED_STA)) + rtw_reset_ft_status(padapter); +#endif + } + + return _SUCCESS; +} + +#ifdef CONFIG_80211D +static void process_80211d(PADAPTER padapter, WLAN_BSSID_EX *bssid) +{ + struct registry_priv *pregistrypriv; + struct mlme_ext_priv *pmlmeext; + RT_CHANNEL_INFO *chplan_new; + u8 channel; + u8 i; + + + pregistrypriv = &padapter->registrypriv; + pmlmeext = &padapter->mlmeextpriv; + + /* Adjust channel plan by AP Country IE */ + if (pregistrypriv->enable80211d + && (!pmlmeext->update_channel_plan_by_ap_done)) { + u8 *ie, *p; + u32 len; + RT_CHANNEL_PLAN chplan_ap; + RT_CHANNEL_INFO chplan_sta[MAX_CHANNEL_NUM]; + u8 country[4]; + u8 fcn; /* first channel number */ + u8 noc; /* number of channel */ + u8 j, k; + + ie = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _COUNTRY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); + if (!ie) + return; + if (len < 6) + return; + + ie += 2; + p = ie; + ie += len; + + _rtw_memset(country, 0, 4); + _rtw_memcpy(country, p, 3); + p += 3; + RTW_INFO("%s: 802.11d country=%s\n", __FUNCTION__, country); + + i = 0; + while ((ie - p) >= 3) { + fcn = *(p++); + noc = *(p++); + p++; + + for (j = 0; j < noc; j++) { + if (fcn <= 14) + channel = fcn + j; /* 2.4 GHz */ + else + channel = fcn + j * 4; /* 5 GHz */ + + chplan_ap.Channel[i++] = channel; + } + } + chplan_ap.Len = i; + +#ifdef CONFIG_RTW_DEBUG + i = 0; + RTW_INFO("%s: AP[%s] channel plan {", __FUNCTION__, bssid->Ssid.Ssid); + while ((i < chplan_ap.Len) && (chplan_ap.Channel[i] != 0)) { + _RTW_INFO("%02d,", chplan_ap.Channel[i]); + i++; + } + _RTW_INFO("}\n"); +#endif + + _rtw_memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta)); +#ifdef CONFIG_RTW_DEBUG + i = 0; + RTW_INFO("%s: STA channel plan {", __FUNCTION__); + while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) { + _RTW_INFO("%02d(%c),", chplan_sta[i].ChannelNum, chplan_sta[i].ScanType == SCAN_PASSIVE ? 'p' : 'a'); + i++; + } + _RTW_INFO("}\n"); +#endif + + _rtw_memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set)); + chplan_new = pmlmeext->channel_set; + + i = j = k = 0; + if (pregistrypriv->wireless_mode & WIRELESS_11G) { + do { + if ((i == MAX_CHANNEL_NUM) + || (chplan_sta[i].ChannelNum == 0) + || (chplan_sta[i].ChannelNum > 14)) + break; + + if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] > 14)) + break; + + if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + i++; + j++; + k++; + } else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; +#if 0 + chplan_new[k].ScanType = chplan_sta[i].ScanType; +#else + chplan_new[k].ScanType = SCAN_PASSIVE; +#endif + i++; + k++; + } else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + j++; + k++; + } + } while (1); + + /* change AP not support channel to Passive scan */ + while ((i < MAX_CHANNEL_NUM) + && (chplan_sta[i].ChannelNum != 0) + && (chplan_sta[i].ChannelNum <= 14)) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; +#if 0 + chplan_new[k].ScanType = chplan_sta[i].ScanType; +#else + chplan_new[k].ScanType = SCAN_PASSIVE; +#endif + i++; + k++; + } + + /* add channel AP supported */ + while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + j++; + k++; + } + } else { + /* keep original STA 2.4G channel plan */ + while ((i < MAX_CHANNEL_NUM) + && (chplan_sta[i].ChannelNum != 0) + && (chplan_sta[i].ChannelNum <= 14)) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + chplan_new[k].ScanType = chplan_sta[i].ScanType; + i++; + k++; + } + + /* skip AP 2.4G channel plan */ + while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) + j++; + } + + if (pregistrypriv->wireless_mode & WIRELESS_11A) { + do { + if ((i >= MAX_CHANNEL_NUM) + || (chplan_sta[i].ChannelNum == 0)) + break; + + if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] == 0)) + break; + + if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + i++; + j++; + k++; + } else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; +#if 0 + chplan_new[k].ScanType = chplan_sta[i].ScanType; +#else + chplan_new[k].ScanType = SCAN_PASSIVE; +#endif + i++; + k++; + } else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + j++; + k++; + } + } while (1); + + /* change AP not support channel to Passive scan */ + while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; +#if 0 + chplan_new[k].ScanType = chplan_sta[i].ScanType; +#else + chplan_new[k].ScanType = SCAN_PASSIVE; +#endif + i++; + k++; + } + + /* add channel AP supported */ + while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] != 0)) { + chplan_new[k].ChannelNum = chplan_ap.Channel[j]; + chplan_new[k].ScanType = SCAN_ACTIVE; + j++; + k++; + } + } else { + /* keep original STA 5G channel plan */ + while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) { + chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum; + chplan_new[k].ScanType = chplan_sta[i].ScanType; + i++; + k++; + } + } + + pmlmeext->update_channel_plan_by_ap_done = 1; + +#ifdef CONFIG_RTW_DEBUG + k = 0; + RTW_INFO("%s: new STA channel plan {", __FUNCTION__); + while ((k < MAX_CHANNEL_NUM) && (chplan_new[k].ChannelNum != 0)) { + _RTW_INFO("%02d(%c),", chplan_new[k].ChannelNum, chplan_new[k].ScanType == SCAN_PASSIVE ? 'p' : 'c'); + k++; + } + _RTW_INFO("}\n"); +#endif + +#if 0 + /* recover the right channel index */ + channel = chplan_sta[pmlmeext->sitesurvey_res.channel_idx].ChannelNum; + k = 0; + while ((k < MAX_CHANNEL_NUM) && (chplan_new[k].ChannelNum != 0)) { + if (chplan_new[k].ChannelNum == channel) { + RTW_INFO("%s: change mlme_ext sitesurvey channel index from %d to %d\n", + __FUNCTION__, pmlmeext->sitesurvey_res.channel_idx, k); + pmlmeext->sitesurvey_res.channel_idx = k; + break; + } + k++; + } +#endif + } + + /* If channel is used by AP, set channel scan type to active */ + channel = bssid->Configuration.DSConfig; + chplan_new = pmlmeext->channel_set; + i = 0; + while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) { + if (chplan_new[i].ChannelNum == channel) { + if (chplan_new[i].ScanType == SCAN_PASSIVE) { + /* 5G Bnad 2, 3 (DFS) doesn't change to active scan */ + if (channel >= 52 && channel <= 144) + break; + + chplan_new[i].ScanType = SCAN_ACTIVE; + RTW_INFO("%s: change channel %d scan type from passive to active\n", + __FUNCTION__, channel); + } + break; + } + i++; + } +} +#endif + +/**************************************************************************** + +Following are the functions to report events + +*****************************************************************************/ + +void report_survey_event(_adapter *padapter, union recv_frame *precv_frame) +{ + struct cmd_obj *pcmd_obj; + u8 *pevtcmd; + u32 cmdsz; + struct survey_event *psurvey_evt; + struct C2HEvent_Header *pc2h_evt_hdr; + struct mlme_ext_priv *pmlmeext; + struct cmd_priv *pcmdpriv; + /* u8 *pframe = precv_frame->u.hdr.rx_data; */ + /* uint len = precv_frame->u.hdr.len; */ + + if (!padapter) + return; + + pmlmeext = &padapter->mlmeextpriv; + pcmdpriv = &padapter->cmdpriv; + + + pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmd_obj == NULL) + return; + + cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header)); + pevtcmd = (u8 *)rtw_zmalloc(cmdsz); + if (pevtcmd == NULL) { + rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); + return; + } + + _rtw_init_listhead(&pcmd_obj->list); + + pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); + pcmd_obj->cmdsz = cmdsz; + pcmd_obj->parmbuf = pevtcmd; + + pcmd_obj->rsp = NULL; + pcmd_obj->rspsz = 0; + + pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); + pc2h_evt_hdr->len = sizeof(struct survey_event); + pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey); + pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); + + psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); + + if (collect_bss_info(padapter, precv_frame, (WLAN_BSSID_EX *)&psurvey_evt->bss) == _FAIL) { + rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); + rtw_mfree((u8 *)pevtcmd, cmdsz); + return; + } + +#ifdef CONFIG_80211D + process_80211d(padapter, &psurvey_evt->bss); +#endif + + rtw_enqueue_cmd(pcmdpriv, pcmd_obj); + + pmlmeext->sitesurvey_res.bss_cnt++; + + return; + +} + +void report_surveydone_event(_adapter *padapter) +{ + struct cmd_obj *pcmd_obj; + u8 *pevtcmd; + u32 cmdsz; + struct surveydone_event *psurveydone_evt; + struct C2HEvent_Header *pc2h_evt_hdr; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmd_obj == NULL) + return; + + cmdsz = (sizeof(struct surveydone_event) + sizeof(struct C2HEvent_Header)); + pevtcmd = (u8 *)rtw_zmalloc(cmdsz); + if (pevtcmd == NULL) { + rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); + return; + } + + _rtw_init_listhead(&pcmd_obj->list); + + pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); + pcmd_obj->cmdsz = cmdsz; + pcmd_obj->parmbuf = pevtcmd; + + pcmd_obj->rsp = NULL; + pcmd_obj->rspsz = 0; + + pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); + pc2h_evt_hdr->len = sizeof(struct surveydone_event); + pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone); + pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); + + psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); + psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; + + RTW_INFO("survey done event(%x) band:%d for "ADPT_FMT"\n", psurveydone_evt->bss_cnt, padapter->setband, ADPT_ARG(padapter)); + + rtw_enqueue_cmd(pcmdpriv, pcmd_obj); + + return; + +} + +u32 report_join_res(_adapter *padapter, int res) +{ + struct cmd_obj *pcmd_obj; + u8 *pevtcmd; + u32 cmdsz; + struct joinbss_event *pjoinbss_evt; + struct C2HEvent_Header *pc2h_evt_hdr; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u32 ret = _FAIL; + + pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmd_obj == NULL) + goto exit; + + cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header)); + pevtcmd = (u8 *)rtw_zmalloc(cmdsz); + if (pevtcmd == NULL) { + rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); + goto exit; + } + + _rtw_init_listhead(&pcmd_obj->list); + + pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); + pcmd_obj->cmdsz = cmdsz; + pcmd_obj->parmbuf = pevtcmd; + + pcmd_obj->rsp = NULL; + pcmd_obj->rspsz = 0; + + pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); + pc2h_evt_hdr->len = sizeof(struct joinbss_event); + pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss); + pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); + + pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); + _rtw_memcpy((unsigned char *)(&(pjoinbss_evt->network.network)), &(pmlmeinfo->network), sizeof(WLAN_BSSID_EX)); + pjoinbss_evt->network.join_res = pjoinbss_evt->network.aid = res; + + RTW_INFO("report_join_res(%d)\n", res); + + + rtw_joinbss_event_prehandle(padapter, (u8 *)&pjoinbss_evt->network); + + + ret = rtw_enqueue_cmd(pcmdpriv, pcmd_obj); + +exit: + return ret; +} + +void report_wmm_edca_update(_adapter *padapter) +{ + struct cmd_obj *pcmd_obj; + u8 *pevtcmd; + u32 cmdsz; + struct wmm_event *pwmm_event; + struct C2HEvent_Header *pc2h_evt_hdr; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmd_obj == NULL) + return; + + cmdsz = (sizeof(struct wmm_event) + sizeof(struct C2HEvent_Header)); + pevtcmd = (u8 *)rtw_zmalloc(cmdsz); + if (pevtcmd == NULL) { + rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); + return; + } + + _rtw_init_listhead(&pcmd_obj->list); + + pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); + pcmd_obj->cmdsz = cmdsz; + pcmd_obj->parmbuf = pevtcmd; + + pcmd_obj->rsp = NULL; + pcmd_obj->rspsz = 0; + + pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); + pc2h_evt_hdr->len = sizeof(struct wmm_event); + pc2h_evt_hdr->ID = GEN_EVT_CODE(_WMM); + pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); + + pwmm_event = (struct wmm_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); + pwmm_event->wmm = 0; + + rtw_enqueue_cmd(pcmdpriv, pcmd_obj); + + return; + +} + +u32 report_del_sta_event(_adapter *padapter, unsigned char *MacAddr, unsigned short reason, bool enqueue, u8 locally_generated) +{ + struct cmd_obj *pcmd_obj; + u8 *pevtcmd; + u32 cmdsz; + struct sta_info *psta; + int mac_id = -1; + struct stadel_event *pdel_sta_evt; + struct C2HEvent_Header *pc2h_evt_hdr; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + /* prepare cmd parameter */ + cmdsz = (sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header)); + pevtcmd = (u8 *)rtw_zmalloc(cmdsz); + if (pevtcmd == NULL) { + res = _FAIL; + goto exit; + } + + pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); + pc2h_evt_hdr->len = sizeof(struct stadel_event); + pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA); + pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); + + pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); + _rtw_memcpy((unsigned char *)(&(pdel_sta_evt->macaddr)), MacAddr, ETH_ALEN); + _rtw_memcpy((unsigned char *)(pdel_sta_evt->rsvd), (unsigned char *)(&reason), 2); + psta = rtw_get_stainfo(&padapter->stapriv, MacAddr); + if (psta) + mac_id = (int)psta->mac_id; + else + mac_id = (-1); + pdel_sta_evt->mac_id = mac_id; + pdel_sta_evt->locally_generated = locally_generated; + + if (!enqueue) { + /* do directly */ + rtw_stadel_event_callback(padapter, (u8 *)pdel_sta_evt); + rtw_mfree(pevtcmd, cmdsz); + } else { + pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmd_obj == NULL) { + rtw_mfree(pevtcmd, cmdsz); + res = _FAIL; + goto exit; + } + + _rtw_init_listhead(&pcmd_obj->list); + pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); + pcmd_obj->cmdsz = cmdsz; + pcmd_obj->parmbuf = pevtcmd; + + pcmd_obj->rsp = NULL; + pcmd_obj->rspsz = 0; + + res = rtw_enqueue_cmd(pcmdpriv, pcmd_obj); + } + +exit: + + RTW_INFO(FUNC_ADPT_FMT" "MAC_FMT" mac_id=%d, enqueue:%d, res:%u\n" + , FUNC_ADPT_ARG(padapter), MAC_ARG(MacAddr), mac_id, enqueue, res); + + return res; +} + +void report_add_sta_event(_adapter *padapter, unsigned char *MacAddr) +{ + struct cmd_obj *pcmd_obj; + u8 *pevtcmd; + u32 cmdsz; + struct stassoc_event *padd_sta_evt; + struct C2HEvent_Header *pc2h_evt_hdr; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmd_obj == NULL) + return; + + cmdsz = (sizeof(struct stassoc_event) + sizeof(struct C2HEvent_Header)); + pevtcmd = (u8 *)rtw_zmalloc(cmdsz); + if (pevtcmd == NULL) { + rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); + return; + } + + _rtw_init_listhead(&pcmd_obj->list); + + pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); + pcmd_obj->cmdsz = cmdsz; + pcmd_obj->parmbuf = pevtcmd; + + pcmd_obj->rsp = NULL; + pcmd_obj->rspsz = 0; + + pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); + pc2h_evt_hdr->len = sizeof(struct stassoc_event); + pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA); + pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); + + padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); + _rtw_memcpy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr, ETH_ALEN); + + RTW_INFO("report_add_sta_event: add STA\n"); + + rtw_enqueue_cmd(pcmdpriv, pcmd_obj); + + return; +} + + +bool rtw_port_switch_chk(_adapter *adapter) +{ + bool switch_needed = _FALSE; +#ifdef CONFIG_CONCURRENT_MODE +#ifdef CONFIG_RUNTIME_PORT_SWITCH + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(dvobj); + _adapter *if_port0 = NULL; + _adapter *if_port1 = NULL; + struct mlme_ext_info *if_port0_mlmeinfo = NULL; + struct mlme_ext_info *if_port1_mlmeinfo = NULL; + int i; + + for (i = 0; i < dvobj->iface_nums; i++) { + if (get_hw_port(dvobj->padapters[i]) == HW_PORT0) { + if_port0 = dvobj->padapters[i]; + if_port0_mlmeinfo = &(if_port0->mlmeextpriv.mlmext_info); + } else if (get_hw_port(dvobj->padapters[i]) == HW_PORT1) { + if_port1 = dvobj->padapters[i]; + if_port1_mlmeinfo = &(if_port1->mlmeextpriv.mlmext_info); + } + } + + if (if_port0 == NULL) { + rtw_warn_on(1); + goto exit; + } + + if (if_port1 == NULL) { + rtw_warn_on(1); + goto exit; + } + +#ifdef DBG_RUNTIME_PORT_SWITCH + RTW_INFO(FUNC_ADPT_FMT" wowlan_mode:%u\n" + ADPT_FMT", port0, mlmeinfo->state:0x%08x, p2p_state:%d, %d\n" + ADPT_FMT", port1, mlmeinfo->state:0x%08x, p2p_state:%d, %d\n", + FUNC_ADPT_ARG(adapter), pwrctl->wowlan_mode, + ADPT_ARG(if_port0), if_port0_mlmeinfo->state, rtw_p2p_state(&if_port0->wdinfo), rtw_p2p_chk_state(&if_port0->wdinfo, P2P_STATE_NONE), + ADPT_ARG(if_port1), if_port1_mlmeinfo->state, rtw_p2p_state(&if_port1->wdinfo), rtw_p2p_chk_state(&if_port1->wdinfo, P2P_STATE_NONE)); +#endif /* DBG_RUNTIME_PORT_SWITCH */ + +#ifdef CONFIG_WOWLAN + /* WOWLAN interface(primary, for now) should be port0 */ + if (pwrctl->wowlan_mode == _TRUE) { + if (!is_primary_adapter(if_port0)) { + RTW_INFO("%s "ADPT_FMT" enable WOWLAN\n", __func__, ADPT_ARG(if_port1)); + switch_needed = _TRUE; + } + goto exit; + } +#endif /* CONFIG_WOWLAN */ + + /* AP should use port0 for ctl frame's ack */ + if ((if_port1_mlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { + RTW_INFO("%s "ADPT_FMT" is AP/GO\n", __func__, ADPT_ARG(if_port1)); + switch_needed = _TRUE; + goto exit; + } + + /* GC should use port0 for p2p ps */ + if (((if_port1_mlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) + && (if_port1_mlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) +#ifdef CONFIG_P2P + && !rtw_p2p_chk_state(&if_port1->wdinfo, P2P_STATE_NONE) +#endif + && !check_fwstate(&if_port1->mlmepriv, WIFI_UNDER_WPS) + ) { + RTW_INFO("%s "ADPT_FMT" is GC\n", __func__, ADPT_ARG(if_port1)); + switch_needed = _TRUE; + goto exit; + } + + /* port1 linked, but port0 not linked */ + if ((if_port1_mlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) + && !(if_port0_mlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) + && ((if_port0_mlmeinfo->state & 0x03) != WIFI_FW_AP_STATE) + ) { + RTW_INFO("%s "ADPT_FMT" is SINGLE_LINK\n", __func__, ADPT_ARG(if_port1)); + switch_needed = _TRUE; + goto exit; + } + +exit: +#ifdef DBG_RUNTIME_PORT_SWITCH + RTW_INFO(FUNC_ADPT_FMT" ret:%d\n", FUNC_ADPT_ARG(adapter), switch_needed); +#endif /* DBG_RUNTIME_PORT_SWITCH */ +#endif /* CONFIG_RUNTIME_PORT_SWITCH */ +#endif /* CONFIG_CONCURRENT_MODE */ + return switch_needed; +} + +/**************************************************************************** + +Following are the event callback functions + +*****************************************************************************/ + +/* for sta/adhoc mode */ +void update_sta_info(_adapter *padapter, struct sta_info *psta) +{ + _irqL irqL; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + /* ERP */ + VCS_update(padapter, psta); + +#ifdef CONFIG_80211N_HT + /* HT */ + if (pmlmepriv->htpriv.ht_option) { + psta->htpriv.ht_option = _TRUE; + + psta->htpriv.ampdu_enable = pmlmepriv->htpriv.ampdu_enable; + + psta->htpriv.rx_ampdu_min_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2; + + if (support_short_GI(padapter, &(pmlmeinfo->HT_caps), CHANNEL_WIDTH_20)) + psta->htpriv.sgi_20m = _TRUE; + + if (support_short_GI(padapter, &(pmlmeinfo->HT_caps), CHANNEL_WIDTH_40)) + psta->htpriv.sgi_40m = _TRUE; + + psta->qos_option = _TRUE; + + psta->htpriv.ldpc_cap = pmlmepriv->htpriv.ldpc_cap; + psta->htpriv.stbc_cap = pmlmepriv->htpriv.stbc_cap; + psta->htpriv.beamform_cap = pmlmepriv->htpriv.beamform_cap; + + _rtw_memcpy(&psta->htpriv.ht_cap, &pmlmeinfo->HT_caps, sizeof(struct rtw_ieee80211_ht_cap)); + } else +#endif /* CONFIG_80211N_HT */ + { +#ifdef CONFIG_80211N_HT + psta->htpriv.ht_option = _FALSE; + psta->htpriv.ampdu_enable = _FALSE; + psta->htpriv.tx_amsdu_enable = _FALSE; + psta->htpriv.sgi_20m = _FALSE; + psta->htpriv.sgi_40m = _FALSE; +#endif /* CONFIG_80211N_HT */ + psta->qos_option = _FALSE; + + } + +#ifdef CONFIG_80211N_HT + psta->htpriv.ch_offset = pmlmeext->cur_ch_offset; + + psta->htpriv.agg_enable_bitmap = 0x0;/* reset */ + psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */ +#endif /* CONFIG_80211N_HT */ + + psta->bw_mode = pmlmeext->cur_bwmode; + + /* QoS */ + if (pmlmepriv->qospriv.qos_option) + psta->qos_option = _TRUE; + +#ifdef CONFIG_80211AC_VHT + _rtw_memcpy(&psta->vhtpriv, &pmlmepriv->vhtpriv, sizeof(struct vht_priv)); +#endif /* CONFIG_80211AC_VHT */ + + update_ldpc_stbc_cap(psta); + + _enter_critical_bh(&psta->lock, &irqL); + psta->state = _FW_LINKED; + _exit_critical_bh(&psta->lock, &irqL); + +} + +static void rtw_mlmeext_disconnect(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network)); + u8 state_backup = (pmlmeinfo->state & 0x03); + u8 ASIX_ID[] = {0x00, 0x0E, 0xC6}; + + /* set_opmode_cmd(padapter, infra_client_with_mlme); */ + + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, 0); + rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); + + /* set MSR to no link state->infra. mode */ + Set_MSR(padapter, _HW_STATE_STATION_); + + /* check if sta is ASIX peer and fix IOT issue if it is. */ + if (_rtw_memcmp(get_my_bssid(&pmlmeinfo->network) , ASIX_ID , 3)) { + u8 iot_flag = _FALSE; + rtw_hal_set_hwreg(padapter, HW_VAR_ASIX_IOT, (u8 *)(&iot_flag)); + } + pmlmeinfo->state = WIFI_FW_NULL_STATE; + +#ifdef CONFIG_MCC_MODE + /* mcc disconnect setting before download LPS rsvd page */ + rtw_hal_set_mcc_setting_disconnect(padapter); +#endif /* CONFIG_MCC_MODE */ + + if (state_backup == WIFI_FW_STATION_STATE) { + if (rtw_port_switch_chk(padapter) == _TRUE) { + rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, NULL); +#ifdef CONFIG_LPS + { + _adapter *port0_iface = dvobj_get_port0_adapter(adapter_to_dvobj(padapter)); + if (port0_iface) + rtw_lps_ctrl_wk_cmd(port0_iface, LPS_CTRL_CONNECT, 0); + } +#endif + } + } + + /* switch to the 20M Hz mode after disconnect */ + pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + +#ifdef CONFIG_FCS_MODE + if (EN_FCS(padapter)) + rtw_hal_set_hwreg(padapter, HW_VAR_STOP_FCS_MODE, NULL); +#endif + +#ifdef CONFIG_DFS_MASTER + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) + rtw_dfs_master_status_apply(padapter, MLME_AP_STOPPED); + else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) + rtw_dfs_master_status_apply(padapter, MLME_STA_DISCONNECTED); +#endif + + { + u8 ch, bw, offset; + + if (rtw_mi_get_ch_setting_union_no_self(padapter, &ch, &bw, &offset) != 0) { + set_channel_bwmode(padapter, ch, offset, bw); + rtw_mi_update_union_chan_inf(padapter, ch, offset, bw); + } + } + + flush_all_cam_entry(padapter); + + _cancel_timer_ex(&pmlmeext->link_timer); + + /* pmlmepriv->LinkDetectInfo.TrafficBusyState = _FALSE; */ + pmlmepriv->LinkDetectInfo.TrafficTransitionCount = 0; + pmlmepriv->LinkDetectInfo.LowPowerTransitionCount = 0; + +#ifdef CONFIG_TDLS + padapter->tdlsinfo.ap_prohibited = _FALSE; + + /* For TDLS channel switch, currently we only allow it to work in wifi logo test mode */ + if (padapter->registrypriv.wifi_spec == 1) + padapter->tdlsinfo.ch_switch_prohibited = _FALSE; +#endif /* CONFIG_TDLS */ + +} + +void mlmeext_joinbss_event_callback(_adapter *padapter, int join_res) +{ + struct sta_info *psta, *psta_bmc; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); + struct sta_priv *pstapriv = &padapter->stapriv; + u8 join_type; +#ifdef CONFIG_ARP_KEEP_ALIVE + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +#endif + struct security_priv *psecuritypriv = &padapter->securitypriv; + + if (join_res < 0) { + join_type = 1; + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, null_addr); + + goto exit_mlmeext_joinbss_event_callback; + } +#ifdef CONFIG_ARP_KEEP_ALIVE + pmlmepriv->bGetGateway = 1; + pmlmepriv->GetGatewayTryCnt = 0; +#endif + + if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { + /* update bc/mc sta_info */ + update_bmc_sta(padapter); + } + + + /* turn on dynamic functions */ + /* Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, _TRUE); */ + + /* update IOT-releated issue */ + update_IOT_info(padapter); + + rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates); + + /* BCN interval */ + rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pmlmeinfo->bcn_interval)); + + /* udpate capability */ + update_capinfo(padapter, pmlmeinfo->capability); + + /* WMM, Update EDCA param */ + WMMOnAssocRsp(padapter); + + /* HT */ + HTOnAssocRsp(padapter); + +#ifdef CONFIG_80211AC_VHT + /* VHT */ + VHTOnAssocRsp(padapter); +#endif + + psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress); + if (psta) { /* only for infra. mode */ + /* RTW_INFO("set_sta_rate\n"); */ + + psta->wireless_mode = pmlmeext->cur_wireless_mode; + +#ifdef CONFIG_FW_MULTI_PORT_SUPPORT + rtw_hal_set_default_port_id_cmd(padapter, psta->mac_id); +#endif + + /* set per sta rate after updating HT cap. */ + set_sta_rate(padapter, psta); + + rtw_sta_media_status_rpt(padapter, psta, 1); + + /* wakeup macid after join bss successfully to ensure + the subsequent data frames can be sent out normally */ + rtw_hal_macid_wakeup(padapter, psta->mac_id); + } + +#ifndef CONFIG_IOCTL_CFG80211 + if (is_wep_enc(psecuritypriv->dot11PrivacyAlgrthm)) + rtw_sec_restore_wep_key(padapter); +#endif /* CONFIG_IOCTL_CFG80211 */ + + if (rtw_port_switch_chk(padapter) == _TRUE) + rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, NULL); + + join_type = 2; + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + + if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) { + /* correcting TSF */ + correct_TSF(padapter, pmlmeext); + + /* set_link_timer(pmlmeext, DISCONNECT_TO); */ + } + +#ifdef CONFIG_LPS + #ifndef CONFIG_FW_MULTI_PORT_SUPPORT + if (get_hw_port(padapter) == HW_PORT0) + #endif + rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, 0); +#endif + +#ifdef CONFIG_BEAMFORMING + if (psta) + beamforming_wk_cmd(padapter, BEAMFORMING_CTRL_ENTER, (u8 *)psta, sizeof(struct sta_info), 0); +#endif/*CONFIG_BEAMFORMING*/ + +exit_mlmeext_joinbss_event_callback: + + rtw_join_done_chk_ch(padapter, join_res); + + RTW_INFO("=>%s - End to Connection without 4-way\n", __FUNCTION__); +} + +/* currently only adhoc mode will go here */ +void mlmeext_sta_add_event_callback(_adapter *padapter, struct sta_info *psta) +{ + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 join_type; + + RTW_INFO("%s\n", __FUNCTION__); + + if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { + if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { /* adhoc master or sta_count>1 */ + /* nothing to do */ + } else { /* adhoc client */ + /* update TSF Value */ + /* update_TSF(pmlmeext, pframe, len); */ + + /* correcting TSF */ + correct_TSF(padapter, pmlmeext); + + /* start beacon */ + if (send_beacon(padapter) == _FAIL) + rtw_warn_on(1); + + pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; + } + + join_type = 2; + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + } + + /* update adhoc sta_info */ + update_sta_info(padapter, psta); + + rtw_hal_update_sta_rate_mask(padapter, psta); + + /* ToDo: HT for Ad-hoc */ + psta->wireless_mode = rtw_check_network_type(psta->bssrateset, psta->bssratelen, pmlmeext->cur_channel); + psta->raid = rtw_hal_networktype_to_raid(padapter, psta); + + /* rate radaptive */ + Update_RA_Entry(padapter, psta); +} + +void mlmeext_sta_del_event_callback(_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if (is_client_associated_to_ap(padapter) || is_IBSS_empty(padapter)) + rtw_mlmeext_disconnect(padapter); + +} + +/**************************************************************************** + +Following are the functions for the timer handlers + +*****************************************************************************/ +void _linked_info_dump(_adapter *padapter) +{ + int i; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + HAL_DATA_TYPE *HalData = GET_HAL_DATA(padapter); + int undecorated_smoothed_pwdb = 0; + + if (padapter->bLinkInfoDump) { + + RTW_INFO("\n============["ADPT_FMT"] linked status check ===================\n", ADPT_ARG(padapter)); + + if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) { + rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &undecorated_smoothed_pwdb); + + RTW_INFO("AP[" MAC_FMT "] - undecorated_smoothed_pwdb:%d\n", + MAC_ARG(padapter->mlmepriv.cur_network.network.MacAddress), undecorated_smoothed_pwdb); + } else if ((pmlmeinfo->state & 0x03) == _HW_STATE_AP_) { + _irqL irqL; + _list *phead, *plist; + + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + phead = &pstapriv->asoc_list; + plist = get_next(phead); + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); + plist = get_next(plist); + + RTW_INFO("STA[" MAC_FMT "]:undecorated_smoothed_pwdb:%d\n", + MAC_ARG(psta->hwaddr), psta->rssi_stat.undecorated_smoothed_pwdb); + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + } + + /*============ tx info ============ */ + rtw_hal_get_def_var(padapter, HW_DEF_RA_INFO_DUMP, RTW_DBGDUMP); + + rtw_hal_set_odm_var(padapter, HAL_ODM_RX_INFO_DUMP, RTW_DBGDUMP, _FALSE); + + } + + +} +/******************************************************************** + +When station does not receive any packet in MAX_CONTINUAL_NORXPACKET_COUNT*2 seconds, +recipient station will teardown the block ack by issuing DELBA frame. + +*********************************************************************/ +void rtw_delba_check(_adapter *padapter, struct sta_info *psta, u8 from_timer) +{ + int i = 0; + int ret = _SUCCESS; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + /* + IOT issue,occur Broadcom ap(Buffalo WZR-D1800H,Netgear R6300). + AP is originator.AP does not transmit unicast packets when STA response its BAR. + This case probably occur ap issue BAR after AP builds BA. + + Follow 802.11 spec, STA shall maintain an inactivity timer for every negotiated Block Ack setup. + The inactivity timer is not reset when MPDUs corresponding to other TIDs are received. + */ + if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_BROADCOM) { + for (i = 0; i < TID_NUM ; i++) { + if ((psta->recvreorder_ctrl[i].enable) && + (sta_rx_data_qos_pkts(psta, i) == sta_last_rx_data_qos_pkts(psta, i)) ) { + if (_TRUE == rtw_inc_and_chk_continual_no_rx_packet(psta, i)) { + /* send a DELBA frame to the peer STA with the Reason Code field set to TIMEOUT */ + if (!from_timer) + ret = issue_del_ba_ex(padapter, psta->hwaddr, i, 39, 0, 3, 1); + else + issue_del_ba(padapter, psta->hwaddr, i, 39, 0); + psta->recvreorder_ctrl[i].enable = _FALSE; + if (ret != _FAIL) + psta->recvreorder_ctrl[i].ampdu_size = RX_AMPDU_SIZE_INVALID; + rtw_reset_continual_no_rx_packet(psta, i); + } + } else { + /* The inactivity timer is reset when MPDUs to the TID is received. */ + rtw_reset_continual_no_rx_packet(psta, i); + } + } + } +} + +u8 chk_ap_is_alive(_adapter *padapter, struct sta_info *psta) +{ + u8 ret = _FALSE; + int i = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + +#ifdef DBG_EXPIRATION_CHK + RTW_INFO(FUNC_ADPT_FMT" rx:"STA_PKTS_FMT", beacon:%llu, probersp_to_self:%llu" + /*", probersp_bm:%llu, probersp_uo:%llu, probereq:%llu, BI:%u"*/ + ", retry:%u\n" + , FUNC_ADPT_ARG(padapter) + , STA_RX_PKTS_DIFF_ARG(psta) + , psta->sta_stats.rx_beacon_pkts - psta->sta_stats.last_rx_beacon_pkts + , psta->sta_stats.rx_probersp_pkts - psta->sta_stats.last_rx_probersp_pkts + /*, psta->sta_stats.rx_probersp_bm_pkts - psta->sta_stats.last_rx_probersp_bm_pkts + , psta->sta_stats.rx_probersp_uo_pkts - psta->sta_stats.last_rx_probersp_uo_pkts + , psta->sta_stats.rx_probereq_pkts - psta->sta_stats.last_rx_probereq_pkts + , pmlmeinfo->bcn_interval*/ + , pmlmeext->retry + ); + + RTW_INFO(FUNC_ADPT_FMT" tx_pkts:%llu, link_count:%u\n", FUNC_ADPT_ARG(padapter) + , padapter->xmitpriv.tx_pkts + , pmlmeinfo->link_count + ); +#endif + + if ((sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta)) + && sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta) + && sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta) + ) + ret = _FALSE; + else + ret = _TRUE; + + sta_update_last_rx_pkts(psta); + + /* + record last rx data packets for every tid. + */ + for (i = 0; i < TID_NUM; i++) + psta->sta_stats.last_rx_data_qos_pkts[i] = psta->sta_stats.rx_data_qos_pkts[i]; + + return ret; +} + +u8 chk_adhoc_peer_is_alive(struct sta_info *psta) +{ + u8 ret = _TRUE; + +#ifdef DBG_EXPIRATION_CHK + RTW_INFO("sta:"MAC_FMT", rssi:%d, rx:"STA_PKTS_FMT", beacon:%llu, probersp_to_self:%llu" + /*", probersp_bm:%llu, probersp_uo:%llu, probereq:%llu, BI:%u"*/ + ", expire_to:%u\n" + , MAC_ARG(psta->hwaddr) + , psta->rssi_stat.undecorated_smoothed_pwdb + , STA_RX_PKTS_DIFF_ARG(psta) + , psta->sta_stats.rx_beacon_pkts - psta->sta_stats.last_rx_beacon_pkts + , psta->sta_stats.rx_probersp_pkts - psta->sta_stats.last_rx_probersp_pkts + /*, psta->sta_stats.rx_probersp_bm_pkts - psta->sta_stats.last_rx_probersp_bm_pkts + , psta->sta_stats.rx_probersp_uo_pkts - psta->sta_stats.last_rx_probersp_uo_pkts + , psta->sta_stats.rx_probereq_pkts - psta->sta_stats.last_rx_probereq_pkts + , pmlmeinfo->bcn_interval*/ + , psta->expire_to + ); +#endif + + if (sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta) + && sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta) + && sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta)) + ret = _FALSE; + + sta_update_last_rx_pkts(psta); + + return ret; +} + +#ifdef CONFIG_TDLS +u8 chk_tdls_peer_sta_is_alive(_adapter *padapter, struct sta_info *psta) +{ + if ((psta->sta_stats.rx_data_pkts == psta->sta_stats.last_rx_data_pkts) + && (psta->sta_stats.rx_tdls_disc_rsp_pkts == psta->sta_stats.last_rx_tdls_disc_rsp_pkts)) + return _FALSE; + + return _TRUE; +} + +void linked_status_chk_tdls(_adapter *padapter) +{ + struct candidate_pool { + struct sta_info *psta; + u8 addr[ETH_ALEN]; + }; + struct sta_priv *pstapriv = &padapter->stapriv; + _irqL irqL; + u8 ack_chk; + struct sta_info *psta; + int i, num_teardown = 0, num_checkalive = 0; + _list *plist, *phead; + struct tdls_txmgmt txmgmt; + struct candidate_pool checkalive[MAX_ALLOWED_TDLS_STA_NUM]; + struct candidate_pool teardown[MAX_ALLOWED_TDLS_STA_NUM]; + u8 tdls_sta_max = _FALSE; + +#define ALIVE_MIN 2 +#define ALIVE_MAX 5 + + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + _rtw_memset(checkalive, 0x00, sizeof(checkalive)); + _rtw_memset(teardown, 0x00, sizeof(teardown)); + + if ((padapter->tdlsinfo.link_established == _TRUE)) { + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + for (i = 0; i < NUM_STA; i++) { + phead = &(pstapriv->sta_hash[i]); + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + plist = get_next(plist); + + if (psta->tdls_sta_state & TDLS_LINKED_STATE) { + psta->alive_count++; + if (psta->alive_count >= ALIVE_MIN) { + if (chk_tdls_peer_sta_is_alive(padapter, psta) == _FALSE) { + if (psta->alive_count < ALIVE_MAX) { + _rtw_memcpy(checkalive[num_checkalive].addr, psta->hwaddr, ETH_ALEN); + checkalive[num_checkalive].psta = psta; + num_checkalive++; + } else { + _rtw_memcpy(teardown[num_teardown].addr, psta->hwaddr, ETH_ALEN); + teardown[num_teardown].psta = psta; + num_teardown++; + } + } else + psta->alive_count = 0; + } + psta->sta_stats.last_rx_data_pkts = psta->sta_stats.rx_data_pkts; + psta->sta_stats.last_rx_tdls_disc_rsp_pkts = psta->sta_stats.rx_tdls_disc_rsp_pkts; + + if ((num_checkalive >= MAX_ALLOWED_TDLS_STA_NUM) || (num_teardown >= MAX_ALLOWED_TDLS_STA_NUM)) { + tdls_sta_max = _TRUE; + break; + } + } + } + + if (tdls_sta_max == _TRUE) + break; + } + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + if (num_checkalive > 0) { + for (i = 0; i < num_checkalive; i++) { + _rtw_memcpy(txmgmt.peer, checkalive[i].addr, ETH_ALEN); + issue_tdls_dis_req(padapter, &txmgmt); + issue_tdls_dis_req(padapter, &txmgmt); + issue_tdls_dis_req(padapter, &txmgmt); + } + } + + if (num_teardown > 0) { + for (i = 0; i < num_teardown; i++) { + RTW_INFO("[%s %d] Send teardown to "MAC_FMT"\n", __FUNCTION__, __LINE__, MAC_ARG(teardown[i].addr)); + txmgmt.status_code = _RSON_TDLS_TEAR_TOOFAR_; + _rtw_memcpy(txmgmt.peer, teardown[i].addr, ETH_ALEN); + issue_tdls_teardown(padapter, &txmgmt, _FALSE); + } + } + } + +} +#endif /* CONFIG_TDLS */ + +/* from_timer == 1 means driver is in LPS */ +void linked_status_chk(_adapter *padapter, u8 from_timer) +{ + u32 i; + struct sta_info *psta; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct sta_priv *pstapriv = &padapter->stapriv; +#if defined(CONFIG_ARP_KEEP_ALIVE) || defined(CONFIG_LAYER2_ROAMING) + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +#endif +#ifdef CONFIG_LAYER2_ROAMING + struct recv_priv *precvpriv = &padapter->recvpriv; +#endif + + if (padapter->registrypriv.mp_mode == _TRUE) + return; + + if (is_client_associated_to_ap(padapter)) { + /* linked infrastructure client mode */ + + int tx_chk = _SUCCESS, rx_chk = _SUCCESS; + int rx_chk_limit; + int link_count_limit; + +#ifdef CONFIG_LAYER2_ROAMING + if (rtw_chk_roam_flags(padapter, RTW_ROAM_ACTIVE)) { + RTW_INFO("signal_strength_data.avg_val = %d\n", precvpriv->signal_strength_data.avg_val); + if (precvpriv->signal_strength_data.avg_val < pmlmepriv->roam_rssi_threshold) { + pmlmepriv->need_to_roam = _TRUE; + rtw_drv_scan_by_self(padapter, RTW_AUTO_SCAN_REASON_ROAM); + } else { + pmlmepriv->need_to_roam = _FALSE; + } + } +#endif +#ifdef CONFIG_MCC_MODE + /* + * due to tx ps null date to ao, so ap doest not tx pkt to driver + * we may check chk_ap_is_alive fail, and may issue_probereq to wrong channel under sitesurvey + * don't keep alive check under MCC + */ + if (rtw_hal_mcc_link_status_chk(padapter, __func__) == _FALSE) + return; +#endif + +#if defined(DBG_ROAMING_TEST) + rx_chk_limit = 1; +#elif defined(CONFIG_ACTIVE_KEEP_ALIVE_CHECK) && !defined(CONFIG_LPS_LCLK_WD_TIMER) + rx_chk_limit = 4; +#else + rx_chk_limit = 8; +#endif +#ifdef CONFIG_ARP_KEEP_ALIVE + if (!from_timer && pmlmepriv->bGetGateway == 1 && pmlmepriv->GetGatewayTryCnt < 3) { + RTW_INFO("do rtw_gw_addr_query() : %d\n", pmlmepriv->GetGatewayTryCnt); + pmlmepriv->GetGatewayTryCnt++; + if (rtw_gw_addr_query(padapter) == 0) + pmlmepriv->bGetGateway = 0; + else { + _rtw_memset(pmlmepriv->gw_ip, 0, 4); + _rtw_memset(pmlmepriv->gw_mac_addr, 0, 6); + } + } +#endif +#ifdef CONFIG_P2P + if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE)) { + if (!from_timer) + link_count_limit = 3; /* 8 sec */ + else + link_count_limit = 15; /* 32 sec */ + } else +#endif /* CONFIG_P2P */ + { + if (!from_timer) + link_count_limit = 7; /* 16 sec */ + else + link_count_limit = 29; /* 60 sec */ + } + +#ifdef CONFIG_TDLS +#ifdef CONFIG_TDLS_CH_SW + if (ATOMIC_READ(&padapter->tdlsinfo.chsw_info.chsw_on) == _TRUE) + return; +#endif /* CONFIG_TDLS_CH_SW */ + +#ifdef CONFIG_TDLS_AUTOCHECKALIVE + linked_status_chk_tdls(padapter); +#endif /* CONFIG_TDLS_AUTOCHECKALIVE */ +#endif /* CONFIG_TDLS */ + + psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress); + if (psta != NULL) { + bool is_p2p_enable = _FALSE; +#ifdef CONFIG_P2P + is_p2p_enable = !rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE); +#endif + +#ifdef CONFIG_ISSUE_DELBA_WHEN_NO_TRAFFIC + /*issue delba when ap does not tx data packet that is Broadcom ap */ + rtw_delba_check(padapter, psta, from_timer); +#endif + if (chk_ap_is_alive(padapter, psta) == _FALSE) + rx_chk = _FAIL; + + if (pxmitpriv->last_tx_pkts == pxmitpriv->tx_pkts) + tx_chk = _FAIL; + +#if defined(CONFIG_ACTIVE_KEEP_ALIVE_CHECK) && !defined(CONFIG_LPS_LCLK_WD_TIMER) + if (pmlmeext->active_keep_alive_check && (rx_chk == _FAIL || tx_chk == _FAIL) + #ifdef CONFIG_MCC_MODE + /* Driver don't know operation channel under MCC*/ + /* So driver don't do KEEP_ALIVE_CHECK */ + && (!rtw_hal_check_mcc_status(padapter, MCC_STATUS_NEED_MCC)) + #endif + ) { + u8 backup_ch = 0, backup_bw, backup_offset; + u8 union_ch = 0, union_bw, union_offset; + + if (!rtw_mi_get_ch_setting_union(padapter, &union_ch, &union_bw, &union_offset) + || pmlmeext->cur_channel != union_ch) + goto bypass_active_keep_alive; + + /* switch to correct channel of current network before issue keep-alive frames */ + if (rtw_get_oper_ch(padapter) != pmlmeext->cur_channel) { + backup_ch = rtw_get_oper_ch(padapter); + backup_bw = rtw_get_oper_bw(padapter); + backup_offset = rtw_get_oper_choffset(padapter); + set_channel_bwmode(padapter, union_ch, union_offset, union_bw); + } + + if (rx_chk != _SUCCESS) + issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, psta->hwaddr, 0, 0, 3, 1); + + if ((tx_chk != _SUCCESS && pmlmeinfo->link_count++ == link_count_limit) || rx_chk != _SUCCESS) { + tx_chk = issue_nulldata(padapter, psta->hwaddr, 0, 3, 1); + /* if tx acked and p2p disabled, set rx_chk _SUCCESS to reset retry count */ + if (tx_chk == _SUCCESS && !is_p2p_enable) + rx_chk = _SUCCESS; + } + + /* back to the original operation channel */ + if (backup_ch > 0) + set_channel_bwmode(padapter, backup_ch, backup_offset, backup_bw); + +bypass_active_keep_alive: + ; + } else +#endif /* CONFIG_ACTIVE_KEEP_ALIVE_CHECK */ + { + if (rx_chk != _SUCCESS) { + if (pmlmeext->retry == 0) { +#ifdef DBG_EXPIRATION_CHK + RTW_INFO("issue_probereq to trigger probersp, retry=%d\n", pmlmeext->retry); +#endif + issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress, 0, 0, 0, 0); + issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress, 0, 0, 0, 0); + issue_probereq_ex(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress, 0, 0, 0, 0); + } + } + + if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == link_count_limit +#ifdef CONFIG_MCC_MODE + /* FW tx nulldata under MCC mode, we just check ap is alive */ + && (!rtw_hal_check_mcc_status(padapter, MCC_STATUS_NEED_MCC)) +#endif /* CONFIG_MCC_MODE */ + ) { +#ifdef DBG_EXPIRATION_CHK + RTW_INFO("%s issue_nulldata(%d)\n", __FUNCTION__, from_timer ? 1 : 0); +#endif + tx_chk = issue_nulldata_in_interrupt(padapter, NULL, from_timer ? 1 : 0); + } + } + + if (rx_chk == _FAIL) { + pmlmeext->retry++; + if (pmlmeext->retry > rx_chk_limit) { + RTW_PRINT(FUNC_ADPT_FMT" disconnect or roaming\n", + FUNC_ADPT_ARG(padapter)); + receive_disconnect(padapter, pmlmeinfo->network.MacAddress + , WLAN_REASON_EXPIRATION_CHK, _FALSE); + return; + } + } else + pmlmeext->retry = 0; + + if (tx_chk == _FAIL) + pmlmeinfo->link_count %= (link_count_limit + 1); + else { + pxmitpriv->last_tx_pkts = pxmitpriv->tx_pkts; + pmlmeinfo->link_count = 0; + } + + } /* end of if ((psta = rtw_get_stainfo(pstapriv, passoc_res->network.MacAddress)) != NULL) */ + + } else if (is_client_associated_to_ibss(padapter)) { + _irqL irqL; + _list *phead, *plist, dlist; + + _rtw_init_listhead(&dlist); + + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + for (i = 0; i < NUM_STA; i++) { + + phead = &(pstapriv->sta_hash[i]); + plist = get_next(phead); + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + plist = get_next(plist); + + if (is_broadcast_mac_addr(psta->hwaddr)) + continue; + + if (chk_adhoc_peer_is_alive(psta) || !psta->expire_to) + psta->expire_to = pstapriv->adhoc_expire_to; + else + psta->expire_to--; + + if (psta->expire_to <= 0) { + rtw_list_delete(&psta->list); + rtw_list_insert_tail(&psta->list, &dlist); + } + } + } + + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + plist = get_next(&dlist); + while (rtw_end_of_queue_search(&dlist, plist) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, list); + plist = get_next(plist); + rtw_list_delete(&psta->list); + RTW_INFO(FUNC_ADPT_FMT" ibss expire "MAC_FMT"\n" + , FUNC_ADPT_ARG(padapter), MAC_ARG(psta->hwaddr)); + report_del_sta_event(padapter, psta->hwaddr, WLAN_REASON_EXPIRATION_CHK, from_timer ? _TRUE : _FALSE, _FALSE); + } + } + +} + +void survey_timer_hdl(_adapter *padapter) +{ + struct cmd_obj *cmd; + struct sitesurvey_parm *psurveyPara; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#endif + + if (mlmeext_scan_state(pmlmeext) > SCAN_DISABLE) { + cmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (cmd == NULL) { + rtw_warn_on(1); + goto exit; + } + + psurveyPara = (struct sitesurvey_parm *)rtw_zmalloc(sizeof(struct sitesurvey_parm)); + if (psurveyPara == NULL) { + rtw_warn_on(1); + rtw_mfree((unsigned char *)cmd, sizeof(struct cmd_obj)); + goto exit; + } + + init_h2fwcmd_w_parm_no_rsp(cmd, psurveyPara, GEN_CMD_CODE(_SiteSurvey)); + rtw_enqueue_cmd(pcmdpriv, cmd); + } + +exit: + return; +} + +void link_timer_hdl(_adapter *padapter) +{ + /* static unsigned int rx_pkt = 0; */ + /* static u64 tx_cnt = 0; */ + /* struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); */ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + /* struct sta_priv *pstapriv = &padapter->stapriv; */ +#ifdef CONFIG_RTW_80211R + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta = NULL; + WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network)); +#endif + + if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) { + RTW_INFO("link_timer_hdl:no beacon while connecting\n"); + pmlmeinfo->state = WIFI_FW_NULL_STATE; + report_join_res(padapter, -3); + } else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE) { + /* re-auth timer */ + if (++pmlmeinfo->reauth_count > REAUTH_LIMIT) { + /* if (pmlmeinfo->auth_algo != dot11AuthAlgrthm_Auto) */ + /* { */ + pmlmeinfo->state = 0; + report_join_res(padapter, -1); + return; + /* } */ + /* else */ + /* { */ + /* pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; */ + /* pmlmeinfo->reauth_count = 0; */ + /* } */ + } + + RTW_INFO("link_timer_hdl: auth timeout and try again\n"); + pmlmeinfo->auth_seq = 1; + issue_auth(padapter, NULL, 0); + set_link_timer(pmlmeext, REAUTH_TO); + } else if (pmlmeinfo->state & WIFI_FW_ASSOC_STATE) { + /* re-assoc timer */ + if (++pmlmeinfo->reassoc_count > REASSOC_LIMIT) { + pmlmeinfo->state = WIFI_FW_NULL_STATE; +#ifdef CONFIG_RTW_80211R + if ((rtw_to_roam(padapter) > 0) && rtw_chk_ft_flags(padapter, RTW_FT_SUPPORTED)) { + psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress); + if (psta) + rtw_free_stainfo(padapter, psta); + } +#endif + report_join_res(padapter, -2); + return; + } + +#ifdef CONFIG_RTW_80211R + if ((rtw_to_roam(padapter) > 0) && rtw_chk_ft_flags(padapter, RTW_FT_SUPPORTED)) { + RTW_INFO("link_timer_hdl: reassoc timeout and try again\n"); + issue_reassocreq(padapter); + } else +#endif + { + RTW_INFO("link_timer_hdl: assoc timeout and try again\n"); + issue_assocreq(padapter); + } + + set_link_timer(pmlmeext, REASSOC_TO); + } + + return; +} + +void addba_timer_hdl(struct sta_info *psta) +{ +#ifdef CONFIG_80211N_HT + struct ht_priv *phtpriv; + + if (!psta) + return; + + phtpriv = &psta->htpriv; + + if ((phtpriv->ht_option == _TRUE) && (phtpriv->ampdu_enable == _TRUE)) { + if (phtpriv->candidate_tid_bitmap) + phtpriv->candidate_tid_bitmap = 0x0; + + } +#endif /* CONFIG_80211N_HT */ +} + +#ifdef CONFIG_IEEE80211W +void report_sta_timeout_event(_adapter *padapter, u8 *MacAddr, unsigned short reason) +{ + struct cmd_obj *pcmd_obj; + u8 *pevtcmd; + u32 cmdsz; + struct sta_info *psta; + int mac_id; + struct stadel_event *pdel_sta_evt; + struct C2HEvent_Header *pc2h_evt_hdr; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + + pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmd_obj == NULL) + return; + + cmdsz = (sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header)); + pevtcmd = (u8 *)rtw_zmalloc(cmdsz); + if (pevtcmd == NULL) { + rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); + return; + } + + _rtw_init_listhead(&pcmd_obj->list); + + pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); + pcmd_obj->cmdsz = cmdsz; + pcmd_obj->parmbuf = pevtcmd; + + pcmd_obj->rsp = NULL; + pcmd_obj->rspsz = 0; + + pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); + pc2h_evt_hdr->len = sizeof(struct stadel_event); + pc2h_evt_hdr->ID = GEN_EVT_CODE(_TimeoutSTA); + pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); + + pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); + _rtw_memcpy((unsigned char *)(&(pdel_sta_evt->macaddr)), MacAddr, ETH_ALEN); + _rtw_memcpy((unsigned char *)(pdel_sta_evt->rsvd), (unsigned char *)(&reason), 2); + + + psta = rtw_get_stainfo(&padapter->stapriv, MacAddr); + if (psta) + mac_id = (int)psta->mac_id; + else + mac_id = (-1); + + pdel_sta_evt->mac_id = mac_id; + + RTW_INFO("report_del_sta_event: delete STA, mac_id=%d\n", mac_id); + + rtw_enqueue_cmd(pcmdpriv, pcmd_obj); + + return; +} + +void clnt_sa_query_timeout(_adapter *padapter) +{ + + rtw_disassoc_cmd(padapter, 0, _TRUE); + rtw_indicate_disconnect(padapter, 0, _FALSE); + rtw_free_assoc_resources(padapter, 1); + + RTW_INFO("SA query timeout client disconnect\n"); +} + +void sa_query_timer_hdl(struct sta_info *psta) +{ + _adapter *padapter = psta->padapter; + _irqL irqL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE && + check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + clnt_sa_query_timeout(padapter); + else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) + report_sta_timeout_event(padapter, psta->hwaddr, WLAN_REASON_PREV_AUTH_NOT_VALID); +} + +#endif /* CONFIG_IEEE80211W */ + +#ifdef CONFIG_RTW_80211R +void start_clnt_ft_action(_adapter *padapter, u8 *pTargetAddr) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + rtw_set_ft_status(padapter, RTW_FT_REQUESTING_STA); + issue_action_ft_request(padapter, pTargetAddr); + _set_timer(&pmlmeext->ft_link_timer, REASSOC_TO); +} + +void ft_link_timer_hdl(_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + ft_priv *pftpriv = &pmlmepriv->ftpriv; + + if (rtw_chk_ft_status(padapter, RTW_FT_REQUESTING_STA)) { + if (pftpriv->ft_req_retry_cnt < FT_ACTION_REQ_LIMIT) { + pftpriv->ft_req_retry_cnt++; + issue_action_ft_request(padapter, (u8 *)pmlmepriv->roam_network->network.MacAddress); + _set_timer(&pmlmeext->ft_link_timer, REASSOC_TO); + } else { + pftpriv->ft_req_retry_cnt = 0; + + if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) + rtw_set_ft_status(padapter, RTW_FT_ASSOCIATED_STA); + else + rtw_reset_ft_status(padapter); + } + } +} + +void ft_roam_timer_hdl(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + + receive_disconnect(padapter, pmlmepriv->cur_network.network.MacAddress + , WLAN_REASON_ACTIVE_ROAM, _FALSE); +} + +void issue_action_ft_request(_adapter *padapter, u8 *pTargetAddr) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct xmit_frame *pmgntframe = NULL; + struct rtw_ieee80211_hdr *pwlanhdr = NULL; + struct pkt_attrib *pattrib = NULL; + ft_priv *pftpriv = NULL; + u8 *pframe = NULL; + u8 category = RTW_WLAN_CATEGORY_FT; + u8 action = RTW_WLAN_ACTION_FT_REQUEST; + u8 is_ft_roaming_with_rsn_ie = _TRUE; + u8 *pie = NULL; + u16 *fctrl = NULL; + u32 ft_ie_len = 0; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + + _rtw_memcpy(pframe, adapter_mac_addr(padapter), ETH_ALEN); + pframe += ETH_ALEN; + pattrib->pktlen += ETH_ALEN; + + _rtw_memcpy(pframe, pTargetAddr, ETH_ALEN); + pframe += ETH_ALEN; + pattrib->pktlen += ETH_ALEN; + + pftpriv = &pmlmepriv->ftpriv; + pie = rtw_get_ie(pftpriv->updated_ft_ies, EID_WPA2, &ft_ie_len, pftpriv->updated_ft_ies_len); + if (pie) + pframe = rtw_set_ie(pframe, EID_WPA2, ft_ie_len, pie+2, &(pattrib->pktlen)); + else + is_ft_roaming_with_rsn_ie = _FALSE; + + pie = rtw_get_ie(pftpriv->updated_ft_ies, _MDIE_, &ft_ie_len, pftpriv->updated_ft_ies_len); + if (pie) + pframe = rtw_set_ie(pframe, _MDIE_, ft_ie_len , pie+2, &(pattrib->pktlen)); + + pie = rtw_get_ie(pftpriv->updated_ft_ies, _FTIE_, &ft_ie_len, pftpriv->updated_ft_ies_len); + if (pie && is_ft_roaming_with_rsn_ie) + pframe = rtw_set_ie(pframe, _FTIE_, ft_ie_len , pie+2, &(pattrib->pktlen)); + + pattrib->last_txcmdsz = pattrib->pktlen; + dump_mgntframe(padapter, pmgntframe); +} + +void report_ft_event(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + ft_priv *pftpriv = &pmlmepriv->ftpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network)); + struct cfg80211_ft_event_params ft_evt_parms; + _irqL irqL; + + _rtw_memset(&ft_evt_parms, 0, sizeof(ft_evt_parms)); + rtw_update_ft_stainfo(padapter, pnetwork); + + if (!pnetwork) + goto err_2; + + ft_evt_parms.ies_len = pftpriv->ft_event.ies_len; + ft_evt_parms.ies = rtw_zmalloc(ft_evt_parms.ies_len); + if (ft_evt_parms.ies) + _rtw_memcpy((void *)ft_evt_parms.ies, pftpriv->ft_event.ies, ft_evt_parms.ies_len); + else + goto err_2; + + ft_evt_parms.target_ap = rtw_zmalloc(ETH_ALEN); + if (ft_evt_parms.target_ap) + _rtw_memcpy((void *)ft_evt_parms.target_ap, pnetwork->MacAddress, ETH_ALEN); + else + goto err_1; + + ft_evt_parms.ric_ies = pftpriv->ft_event.ric_ies; + ft_evt_parms.ric_ies_len = pftpriv->ft_event.ric_ies_len; + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + rtw_set_ft_status(padapter, RTW_FT_AUTHENTICATED_STA); + _exit_critical_bh(&pmlmepriv->lock, &irqL); + + rtw_cfg80211_ft_event(padapter, &ft_evt_parms); + RTW_INFO("FT: report_ft_event\n"); + rtw_mfree((u8 *)pftpriv->ft_event.target_ap, ETH_ALEN); +err_1: + rtw_mfree((u8 *)ft_evt_parms.ies, ft_evt_parms.ies_len); +err_2: + return; +} + +void report_ft_reassoc_event(_adapter *padapter, u8 *pMacAddr) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + struct cmd_obj *pcmd_obj = NULL; + struct stassoc_event *passoc_sta_evt = NULL; + struct C2HEvent_Header *pc2h_evt_hdr = NULL; + u8 *pevtcmd = NULL; + u32 cmdsz = 0; + + pcmd_obj = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (pcmd_obj == NULL) + return; + + cmdsz = (sizeof(struct stassoc_event) + sizeof(struct C2HEvent_Header)); + pevtcmd = (u8 *)rtw_zmalloc(cmdsz); + if (pevtcmd == NULL) { + rtw_mfree((u8 *)pcmd_obj, sizeof(struct cmd_obj)); + return; + } + + _rtw_init_listhead(&pcmd_obj->list); + pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT); + pcmd_obj->cmdsz = cmdsz; + pcmd_obj->parmbuf = pevtcmd; + pcmd_obj->rsp = NULL; + pcmd_obj->rspsz = 0; + + pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); + pc2h_evt_hdr->len = sizeof(struct stassoc_event); + pc2h_evt_hdr->ID = GEN_EVT_CODE(_FT_REASSOC); + pc2h_evt_hdr->seq = ATOMIC_INC_RETURN(&pmlmeext->event_seq); + + passoc_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); + _rtw_memcpy((unsigned char *)(&(passoc_sta_evt->macaddr)), pMacAddr, ETH_ALEN); + rtw_enqueue_cmd(pcmdpriv, pcmd_obj); +} +#endif + +u8 NULL_hdl(_adapter *padapter, u8 *pbuf) +{ + return H2C_SUCCESS; +} + +#ifdef CONFIG_AUTO_AP_MODE +void rtw_start_auto_ap(_adapter *adapter) +{ + RTW_INFO("%s\n", __FUNCTION__); + + rtw_set_802_11_infrastructure_mode(adapter, Ndis802_11APMode); + + rtw_setopmode_cmd(adapter, Ndis802_11APMode, _TRUE); +} + +static int rtw_auto_ap_start_beacon(_adapter *adapter) +{ + int ret = 0; + u8 *pbuf = NULL; + uint len; + u8 supportRate[16]; + int sz = 0, rateLen; + u8 *ie; + u8 wireless_mode, oper_channel; + u8 ssid[3] = {0}; /* hidden ssid */ + u32 ssid_len = sizeof(ssid); + struct mlme_priv *pmlmepriv = &(adapter->mlmepriv); + + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE) + return -EINVAL; + + + len = 128; + pbuf = rtw_zmalloc(len); + if (!pbuf) + return -ENOMEM; + + + /* generate beacon */ + ie = pbuf; + + /* timestamp will be inserted by hardware */ + sz += 8; + ie += sz; + + /* beacon interval : 2bytes */ + *(u16 *)ie = cpu_to_le16((u16)100); /* BCN_INTERVAL=100; */ + sz += 2; + ie += 2; + + /* capability info */ + *(u16 *)ie = 0; + *(u16 *)ie |= cpu_to_le16(cap_ESS); + *(u16 *)ie |= cpu_to_le16(cap_ShortPremble); + /* *(u16*)ie |= cpu_to_le16(cap_Privacy); */ + sz += 2; + ie += 2; + + /* SSID */ + ie = rtw_set_ie(ie, _SSID_IE_, ssid_len, ssid, &sz); + + /* supported rates */ + wireless_mode = WIRELESS_11BG_24N; + rtw_set_supported_rate(supportRate, wireless_mode) ; + rateLen = rtw_get_rateset_len(supportRate); + if (rateLen > 8) + ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, 8, supportRate, &sz); + else + ie = rtw_set_ie(ie, _SUPPORTEDRATES_IE_, rateLen, supportRate, &sz); + + + /* DS parameter set */ + if (rtw_mi_check_status(adapter, MI_LINKED)) + oper_channel = rtw_mi_get_union_chan(adapter); + else + oper_channel = adapter_to_dvobj(adapter)->oper_channel; + + ie = rtw_set_ie(ie, _DSSET_IE_, 1, &oper_channel, &sz); + + /* ext supported rates */ + if (rateLen > 8) + ie = rtw_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (supportRate + 8), &sz); + + RTW_INFO("%s, start auto ap beacon sz=%d\n", __FUNCTION__, sz); + + /* lunch ap mode & start to issue beacon */ + if (rtw_check_beacon_data(adapter, pbuf, sz) == _SUCCESS) { + + } else + ret = -EINVAL; + + + rtw_mfree(pbuf, len); + + return ret; + +} +#endif/* CONFIG_AUTO_AP_MODE */ + +u8 setopmode_hdl(_adapter *padapter, u8 *pbuf) +{ + u8 type; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf; + + if (psetop->mode == Ndis802_11APMode) { + pmlmeinfo->state = WIFI_FW_AP_STATE; + type = _HW_STATE_AP_; +#ifdef CONFIG_NATIVEAP_MLME + /* start_ap_mode(padapter); */ +#endif + } else if (psetop->mode == Ndis802_11Infrastructure) { + pmlmeinfo->state &= ~(BIT(0) | BIT(1)); /* clear state */ + pmlmeinfo->state |= WIFI_FW_STATION_STATE;/* set to STATION_STATE */ + type = _HW_STATE_STATION_; + } else if (psetop->mode == Ndis802_11IBSS) + type = _HW_STATE_ADHOC_; + else if (psetop->mode == Ndis802_11Monitor) + type = _HW_STATE_MONITOR_; + else + type = _HW_STATE_NOLINK_; + +#ifdef CONFIG_AP_PORT_SWAP + rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, (u8 *)(&type)); +#endif + + rtw_hal_set_hwreg(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type)); + +#ifdef CONFIG_AUTO_AP_MODE + if (psetop->mode == Ndis802_11APMode) + rtw_auto_ap_start_beacon(padapter); +#endif + + if (rtw_port_switch_chk(padapter) == _TRUE) { + rtw_hal_set_hwreg(padapter, HW_VAR_PORT_SWITCH, NULL); + + if (psetop->mode == Ndis802_11APMode) + adapter_to_pwrctl(padapter)->fw_psmode_iface_id = 0xff; /* ap mode won't dowload rsvd pages */ + else if (psetop->mode == Ndis802_11Infrastructure) { +#ifdef CONFIG_LPS + _adapter *port0_iface = dvobj_get_port0_adapter(adapter_to_dvobj(padapter)); + if (port0_iface) + rtw_lps_ctrl_wk_cmd(port0_iface, LPS_CTRL_CONNECT, 0); +#endif + } + } + +#ifdef CONFIG_BT_COEXIST + if (psetop->mode == Ndis802_11APMode || + psetop->mode == Ndis802_11Monitor) { + /* Do this after port switch to */ + /* prevent from downloading rsvd page to wrong port */ + rtw_btcoex_MediaStatusNotify(padapter, 1); /* connect */ + } +#endif /* CONFIG_BT_COEXIST */ + + return H2C_SUCCESS; + +} + +u8 createbss_hdl(_adapter *padapter, u8 *pbuf) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network)); + WLAN_BSSID_EX *pdev_network = &padapter->registrypriv.dev_network; + struct createbss_parm *parm = (struct createbss_parm *)pbuf; + u8 ret = H2C_SUCCESS; + /* u8 initialgain; */ + +#ifdef CONFIG_AP_MODE + if (pmlmeinfo->state == WIFI_FW_AP_STATE) { + start_bss_network(padapter, parm); + goto exit; + } +#endif + + /* below is for ad-hoc master */ + if (parm->adhoc) { + rtw_warn_on(pdev_network->InfrastructureMode != Ndis802_11IBSS); + rtw_joinbss_reset(padapter); + + pmlmeext->cur_bwmode = CHANNEL_WIDTH_20; + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + pmlmeinfo->ERP_enable = 0; + pmlmeinfo->WMM_enable = 0; + pmlmeinfo->HT_enable = 0; + pmlmeinfo->HT_caps_enable = 0; + pmlmeinfo->HT_info_enable = 0; + pmlmeinfo->agg_enable_bitmap = 0; + pmlmeinfo->candidate_tid_bitmap = 0; + + /* config the initial gain under linking, need to write the BB registers */ + /* initialgain = 0x1E; */ + /*rtw_hal_set_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &initialgain, _FALSE);*/ + + /* disable dynamic functions, such as high power, DIG */ + rtw_phydm_ability_backup(padapter); + rtw_phydm_func_disable_all(padapter); + + /* cancel link timer */ + _cancel_timer_ex(&pmlmeext->link_timer); + + /* clear CAM */ + flush_all_cam_entry(padapter); + + pdev_network->Length = get_WLAN_BSSID_EX_sz(pdev_network); + _rtw_memcpy(pnetwork, pdev_network, FIELD_OFFSET(WLAN_BSSID_EX, IELength)); + pnetwork->IELength = pdev_network->IELength; + + if (pnetwork->IELength > MAX_IE_SZ) { + ret = H2C_PARAMETERS_ERROR; + goto ibss_post_hdl; + } + + _rtw_memcpy(pnetwork->IEs, pdev_network->IEs, pnetwork->IELength); + start_create_ibss(padapter); + } else { + rtw_warn_on(1); + ret = H2C_PARAMETERS_ERROR; + } + +ibss_post_hdl: + rtw_create_ibss_post_hdl(padapter, ret); + +exit: + return ret; +} + +u8 join_cmd_hdl(_adapter *padapter, u8 *pbuf) +{ + u8 join_type; + PNDIS_802_11_VARIABLE_IEs pIE; + struct registry_priv *pregpriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network)); +#ifdef CONFIG_ANTENNA_DIVERSITY + struct joinbss_parm *pparm = (struct joinbss_parm *)pbuf; +#endif /* CONFIG_ANTENNA_DIVERSITY */ + u32 i; + /* u8 initialgain; */ + /* u32 acparm; */ + u8 u_ch, u_bw, u_offset; + u8 doiqk = _FALSE; + + /* check already connecting to AP or not */ + if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { + if (pmlmeinfo->state & WIFI_FW_STATION_STATE) + issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, 1, 100); + pmlmeinfo->state = WIFI_FW_NULL_STATE; + + /* clear CAM */ + flush_all_cam_entry(padapter); + + _cancel_timer_ex(&pmlmeext->link_timer); + + /* set MSR to nolink->infra. mode */ + /* Set_MSR(padapter, _HW_STATE_NOLINK_); */ + Set_MSR(padapter, _HW_STATE_STATION_); + + + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_DISCONNECT, 0); + } + +#ifdef CONFIG_ANTENNA_DIVERSITY + rtw_antenna_select_cmd(padapter, pparm->network.PhyInfo.Optimum_antenna, _FALSE); +#endif + +#ifdef CONFIG_WAPI_SUPPORT + rtw_wapi_clear_all_cam_entry(padapter); +#endif + + rtw_joinbss_reset(padapter); + + pmlmeinfo->ERP_enable = 0; + pmlmeinfo->WMM_enable = 0; + pmlmeinfo->HT_enable = 0; + pmlmeinfo->HT_caps_enable = 0; + pmlmeinfo->HT_info_enable = 0; + pmlmeinfo->agg_enable_bitmap = 0; + pmlmeinfo->candidate_tid_bitmap = 0; + pmlmeinfo->bwmode_updated = _FALSE; + /* pmlmeinfo->assoc_AP_vendor = HT_IOT_PEER_MAX; */ + pmlmeinfo->VHT_enable = 0; + + _rtw_memcpy(pnetwork, pbuf, FIELD_OFFSET(WLAN_BSSID_EX, IELength)); + pnetwork->IELength = ((WLAN_BSSID_EX *)pbuf)->IELength; + + if (pnetwork->IELength > MAX_IE_SZ) /* Check pbuf->IELength */ + return H2C_PARAMETERS_ERROR; + + if (pnetwork->IELength < 2) { + report_join_res(padapter, (-4)); + return H2C_SUCCESS; + } + _rtw_memcpy(pnetwork->IEs, ((WLAN_BSSID_EX *)pbuf)->IEs, pnetwork->IELength); + + pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork); + + /* Check AP vendor to move rtw_joinbss_cmd() */ + /* pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pnetwork->IEs, pnetwork->IELength); */ + + /* sizeof(NDIS_802_11_FIXED_IEs) */ + for (i = _FIXED_IE_LENGTH_ ; i < pnetwork->IELength - 2 ;) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(pnetwork->IEs + i); + + switch (pIE->ElementID) { + case _VENDOR_SPECIFIC_IE_: /* Get WMM IE. */ + if (_rtw_memcmp(pIE->data, WMM_OUI, 4)) + WMM_param_handler(padapter, pIE); + break; + +#ifdef CONFIG_80211N_HT + case _HT_CAPABILITY_IE_: /* Get HT Cap IE. */ + pmlmeinfo->HT_caps_enable = 1; + break; + + case _HT_EXTRA_INFO_IE_: /* Get HT Info IE. */ + pmlmeinfo->HT_info_enable = 1; + break; +#endif /* CONFIG_80211N_HT */ + +#ifdef CONFIG_80211AC_VHT + case EID_VHTCapability: /* Get VHT Cap IE. */ + pmlmeinfo->VHT_enable = 1; + break; + + case EID_VHTOperation: /* Get VHT Operation IE. */ + break; +#endif /* CONFIG_80211AC_VHT */ + default: + break; + } + + i += (pIE->Length + 2); + } + + rtw_bss_get_chbw(pnetwork + , &pmlmeext->cur_channel, &pmlmeext->cur_bwmode, &pmlmeext->cur_ch_offset); + + rtw_adjust_chbw(padapter, pmlmeext->cur_channel, &pmlmeext->cur_bwmode, &pmlmeext->cur_ch_offset); + +#if 0 + if (padapter->registrypriv.wifi_spec) { + /* for WiFi test, follow WMM test plan spec */ + acparm = 0x002F431C; /* VO */ + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm)); + acparm = 0x005E541C; /* VI */ + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm)); + acparm = 0x0000A525; /* BE */ + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm)); + acparm = 0x0000A549; /* BK */ + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm)); + + /* for WiFi test, mixed mode with intel STA under bg mode throughput issue */ + if (padapter->mlmepriv.htpriv.ht_option == _FALSE) { + acparm = 0x00004320; + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm)); + } + } else { + acparm = 0x002F3217; /* VO */ + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm)); + acparm = 0x005E4317; /* VI */ + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm)); + acparm = 0x00105320; /* BE */ + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm)); + acparm = 0x0000A444; /* BK */ + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm)); + } +#endif + + /* check channel, bandwidth, offset and switch */ + if (rtw_chk_start_clnt_join(padapter, &u_ch, &u_bw, &u_offset) == _FAIL) { + report_join_res(padapter, (-4)); + return H2C_SUCCESS; + } + + /* disable dynamic functions, such as high power, DIG */ + /*rtw_phydm_func_disable_all(padapter);*/ + + /* config the initial gain under linking, need to write the BB registers */ + /* initialgain = 0x1E; */ + /*rtw_hal_set_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &initialgain, _FALSE);*/ + + rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress); + join_type = 0; + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + doiqk = _TRUE; + rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk); + + set_channel_bwmode(padapter, u_ch, u_offset, u_bw); + rtw_mi_update_union_chan_inf(padapter, u_ch, u_offset, u_bw); + + doiqk = _FALSE; + rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk); + + /* cancel link timer */ + _cancel_timer_ex(&pmlmeext->link_timer); + + start_clnt_join(padapter); + + return H2C_SUCCESS; + +} + +u8 disconnect_hdl(_adapter *padapter, unsigned char *pbuf) +{ + struct disconnect_parm *param = (struct disconnect_parm *)pbuf; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network)); + u8 val8; + + if (is_client_associated_to_ap(padapter)) { +#ifdef CONFIG_DFS + if (padapter->mlmepriv.handle_dfs == _FALSE) +#endif /* CONFIG_DFS */ +#ifdef CONFIG_PLATFORM_ROCKCHIPS + /* To avoid connecting to AP fail during resume process, change retry count from 5 to 1 */ + issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, 1, 100); +#else + issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, param->deauth_timeout_ms / 100, 100); +#endif /* CONFIG_PLATFORM_ROCKCHIPS */ + } + +#ifdef CONFIG_DFS + if (padapter->mlmepriv.handle_dfs == _TRUE) + padapter->mlmepriv.handle_dfs = _FALSE; +#endif /* CONFIG_DFS */ + + if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) { + /* Stop BCN */ + val8 = 0; + rtw_hal_set_hwreg(padapter, HW_VAR_BCN_FUNC, (u8 *)(&val8)); + } + + rtw_mlmeext_disconnect(padapter); + + rtw_free_uc_swdec_pending_queue(padapter); + + return H2C_SUCCESS; +} + +static const char *const _scan_state_str[] = { + "SCAN_DISABLE", + "SCAN_START", + "SCAN_PS_ANNC_WAIT", + "SCAN_ENTER", + "SCAN_PROCESS", + "SCAN_BACKING_OP", + "SCAN_BACK_OP", + "SCAN_LEAVING_OP", + "SCAN_LEAVE_OP", + "SCAN_SW_ANTDIV_BL", + "SCAN_TO_P2P_LISTEN", + "SCAN_P2P_LISTEN", + "SCAN_COMPLETE", + "SCAN_STATE_MAX", +}; + +const char *scan_state_str(u8 state) +{ + state = (state >= SCAN_STATE_MAX) ? SCAN_STATE_MAX : state; + return _scan_state_str[state]; +} + +static bool scan_abort_hdl(_adapter *adapter) +{ + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct ss_res *ss = &pmlmeext->sitesurvey_res; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &adapter->wdinfo; +#endif + bool ret = _FALSE; + + if (pmlmeext->scan_abort == _TRUE) { +#ifdef CONFIG_P2P + if (!rtw_p2p_chk_state(&adapter->wdinfo, P2P_STATE_NONE)) { + rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX); + ss->channel_idx = 3; + RTW_INFO("%s idx:%d, cnt:%u\n", __FUNCTION__ + , ss->channel_idx + , pwdinfo->find_phase_state_exchange_cnt + ); + } else +#endif + { + ss->channel_idx = ss->ch_num; + RTW_INFO("%s idx:%d\n", __FUNCTION__ + , ss->channel_idx + ); + } + pmlmeext->scan_abort = _FALSE; + ret = _TRUE; + } + + return ret; +} + +u8 rtw_scan_sparse(_adapter *adapter, struct rtw_ieee80211_channel *ch, u8 ch_num) +{ + /* interval larger than this is treated as backgroud scan */ +#ifndef RTW_SCAN_SPARSE_BG_INTERVAL_MS +#define RTW_SCAN_SPARSE_BG_INTERVAL_MS 12000 +#endif + +#ifndef RTW_SCAN_SPARSE_CH_NUM_MIRACAST +#define RTW_SCAN_SPARSE_CH_NUM_MIRACAST 1 +#endif +#ifndef RTW_SCAN_SPARSE_CH_NUM_BG +#define RTW_SCAN_SPARSE_CH_NUM_BG 4 +#endif +#ifdef CONFIG_LAYER2_ROAMING +#ifndef RTW_SCAN_SPARSE_CH_NUM_ROAMING_ACTIVE +#define RTW_SCAN_SPARSE_CH_NUM_ROAMING_ACTIVE 1 +#endif +#endif + +#define SCAN_SPARSE_CH_NUM_INVALID 255 + + static u8 token = 255; + u32 interval; + bool busy_traffic = _FALSE; + bool miracast_enabled = _FALSE; + bool bg_scan = _FALSE; + u8 max_allow_ch = SCAN_SPARSE_CH_NUM_INVALID; + u8 scan_division_num; + u8 ret_num = ch_num; + struct registry_priv *regsty = dvobj_to_regsty(adapter_to_dvobj(adapter)); + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + + if (regsty->wifi_spec) + goto exit; + + /* assume ch_num > 6 is normal scan */ + if (ch_num <= 6) + goto exit; + + if (mlmeext->last_scan_time == 0) + mlmeext->last_scan_time = rtw_get_current_time(); + + interval = rtw_get_passing_time_ms(mlmeext->last_scan_time); + + + if (rtw_mi_busy_traffic_check(adapter, _FALSE)) + busy_traffic = _TRUE; + + if (rtw_mi_check_miracast_enabled(adapter)) + miracast_enabled = _TRUE; + + if (interval > RTW_SCAN_SPARSE_BG_INTERVAL_MS) + bg_scan = _TRUE; + + /* max_allow_ch by conditions*/ + +#if RTW_SCAN_SPARSE_MIRACAST + if (miracast_enabled == _TRUE && busy_traffic == _TRUE) + max_allow_ch = rtw_min(max_allow_ch, RTW_SCAN_SPARSE_CH_NUM_MIRACAST); +#endif + +#if RTW_SCAN_SPARSE_BG + if (bg_scan == _TRUE) + max_allow_ch = rtw_min(max_allow_ch, RTW_SCAN_SPARSE_CH_NUM_BG); +#endif + +#if defined(CONFIG_LAYER2_ROAMING) && defined(RTW_SCAN_SPARSE_ROAMING_ACTIVE) + if (rtw_chk_roam_flags(adapter, RTW_ROAM_ACTIVE)) { + if (busy_traffic == _TRUE && adapter->mlmepriv.need_to_roam == _TRUE) + max_allow_ch = rtw_min(max_allow_ch, RTW_SCAN_SPARSE_CH_NUM_ROAMING_ACTIVE); + } +#endif + + + if (max_allow_ch != SCAN_SPARSE_CH_NUM_INVALID) { + int i; + int k = 0; + + scan_division_num = (ch_num / max_allow_ch) + ((ch_num % max_allow_ch) ? 1 : 0); + token = (token + 1) % scan_division_num; + + if (0) + RTW_INFO("scan_division_num:%u, token:%u\n", scan_division_num, token); + + for (i = 0; i < ch_num; i++) { + if (ch[i].hw_value && (i % scan_division_num) == token + ) { + if (i != k) + _rtw_memcpy(&ch[k], &ch[i], sizeof(struct rtw_ieee80211_channel)); + k++; + } + } + + _rtw_memset(&ch[k], 0, sizeof(struct rtw_ieee80211_channel)); + + ret_num = k; + mlmeext->last_scan_time = rtw_get_current_time(); + } + +exit: + return ret_num; +} + +static int rtw_scan_ch_decision(_adapter *padapter, struct rtw_ieee80211_channel *out, + u32 out_num, struct rtw_ieee80211_channel *in, u32 in_num) +{ + int i, j; + int scan_ch_num = 0; + int set_idx; + u8 chan; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + /* clear first */ + _rtw_memset(out, 0, sizeof(struct rtw_ieee80211_channel) * out_num); + + /* acquire channels from in */ + j = 0; + for (i = 0; i < in_num; i++) { + + if (0) + RTW_INFO(FUNC_ADPT_FMT" "CHAN_FMT"\n", FUNC_ADPT_ARG(padapter), CHAN_ARG(&in[i])); + + if (!in[i].hw_value || (in[i].flags & RTW_IEEE80211_CHAN_DISABLED)) + continue; + if (rtw_mlme_band_check(padapter, in[i].hw_value) == _FALSE) + continue; + + set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, in[i].hw_value); + if (set_idx >= 0) { + if (j >= out_num) { + RTW_PRINT(FUNC_ADPT_FMT" out_num:%u not enough\n", + FUNC_ADPT_ARG(padapter), out_num); + break; + } + + _rtw_memcpy(&out[j], &in[i], sizeof(struct rtw_ieee80211_channel)); + + if (pmlmeext->channel_set[set_idx].ScanType == SCAN_PASSIVE) + out[j].flags |= RTW_IEEE80211_CHAN_PASSIVE_SCAN; + + j++; + } + if (j >= out_num) + break; + } + + /* if out is empty, use channel_set as default */ + if (j == 0) { + for (i = 0; i < pmlmeext->max_chan_nums; i++) { + chan = pmlmeext->channel_set[i].ChannelNum; + if (rtw_mlme_band_check(padapter, chan) == _TRUE) { + if (rtw_mlme_ignore_chan(padapter, chan) == _TRUE) + continue; + + if (0) + RTW_INFO(FUNC_ADPT_FMT" ch:%u\n", FUNC_ADPT_ARG(padapter), chan); + + if (j >= out_num) { + RTW_PRINT(FUNC_ADPT_FMT" out_num:%u not enough\n", + FUNC_ADPT_ARG(padapter), out_num); + break; + } + + out[j].hw_value = chan; + + if (pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE) + out[j].flags |= RTW_IEEE80211_CHAN_PASSIVE_SCAN; + + j++; + } + } + } + + /* scan_sparse */ + j = rtw_scan_sparse(padapter, out, j); + + return j; +} + +static void sitesurvey_res_reset(_adapter *adapter, struct sitesurvey_parm *parm) +{ + struct ss_res *ss = &adapter->mlmeextpriv.sitesurvey_res; + int i; + + ss->bss_cnt = 0; + ss->channel_idx = 0; + ss->igi_scan = 0; + ss->igi_before_scan = 0; +#ifdef CONFIG_SCAN_BACKOP + ss->scan_cnt = 0; +#endif +#if defined(CONFIG_ANTENNA_DIVERSITY) || defined(DBG_SCAN_SW_ANTDIV_BL) + ss->is_sw_antdiv_bl_scan = 0; +#endif + + for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) { + if (parm->ssid[i].SsidLength) { + _rtw_memcpy(ss->ssid[i].Ssid, parm->ssid[i].Ssid, IW_ESSID_MAX_SIZE); + ss->ssid[i].SsidLength = parm->ssid[i].SsidLength; + } else + ss->ssid[i].SsidLength = 0; + } + + ss->ch_num = rtw_scan_ch_decision(adapter + , ss->ch, RTW_CHANNEL_SCAN_AMOUNT + , parm->ch, parm->ch_num + ); + + ss->scan_mode = parm->scan_mode; +} + +static u8 sitesurvey_pick_ch_behavior(_adapter *padapter, u8 *ch, RT_SCAN_TYPE *type) +{ + u8 next_state; + u8 scan_ch = 0; + RT_SCAN_TYPE scan_type = SCAN_PASSIVE; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + struct ss_res *ss = &pmlmeext->sitesurvey_res; + +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif + + /* handle scan abort request */ + scan_abort_hdl(padapter); + +#ifdef CONFIG_P2P + if (pwdinfo->rx_invitereq_info.scan_op_ch_only || pwdinfo->p2p_info.scan_op_ch_only) { + if (pwdinfo->rx_invitereq_info.scan_op_ch_only) + scan_ch = pwdinfo->rx_invitereq_info.operation_ch[ss->channel_idx]; + else + scan_ch = pwdinfo->p2p_info.operation_ch[ss->channel_idx]; + scan_type = SCAN_ACTIVE; + } else if (rtw_p2p_findphase_ex_is_social(pwdinfo)) { + /* + * Commented by Albert 2011/06/03 + * The driver is in the find phase, it should go through the social channel. + */ + int ch_set_idx; + + scan_ch = pwdinfo->social_chan[ss->channel_idx]; + ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, scan_ch); + if (ch_set_idx >= 0) + scan_type = pmlmeext->channel_set[ch_set_idx].ScanType; + else + scan_type = SCAN_ACTIVE; + } else +#endif /* CONFIG_P2P */ + { + struct rtw_ieee80211_channel *ch; + + if (ss->channel_idx < ss->ch_num) { + ch = &ss->ch[ss->channel_idx]; + scan_ch = ch->hw_value; + scan_type = (ch->flags & RTW_IEEE80211_CHAN_PASSIVE_SCAN) ? SCAN_PASSIVE : SCAN_ACTIVE; + } + } + + if (scan_ch != 0) { + next_state = SCAN_PROCESS; +#ifdef CONFIG_SCAN_BACKOP + { + struct mi_state mstate; + u8 backop_flags = 0; + + rtw_mi_status(padapter, &mstate); + + if ((MSTATE_STA_LD_NUM(&mstate) && mlmeext_chk_scan_backop_flags_sta(pmlmeext, SS_BACKOP_EN)) + || (MSTATE_STA_NUM(&mstate) && mlmeext_chk_scan_backop_flags_sta(pmlmeext, SS_BACKOP_EN_NL))) + backop_flags |= mlmeext_scan_backop_flags_sta(pmlmeext); + + if ((MSTATE_AP_LD_NUM(&mstate) && mlmeext_chk_scan_backop_flags_ap(pmlmeext, SS_BACKOP_EN)) + || (MSTATE_AP_NUM(&mstate) && mlmeext_chk_scan_backop_flags_ap(pmlmeext, SS_BACKOP_EN_NL))) + backop_flags |= mlmeext_scan_backop_flags_ap(pmlmeext); + + if (backop_flags) { + if (ss->scan_cnt < ss->scan_cnt_max) + ss->scan_cnt++; + else { + mlmeext_assign_scan_backop_flags(pmlmeext, backop_flags); + next_state = SCAN_BACKING_OP; + } + } + } +#endif /* CONFIG_SCAN_BACKOP */ + } else if (rtw_p2p_findphase_ex_is_needed(pwdinfo)) { + /* go p2p listen */ + next_state = SCAN_TO_P2P_LISTEN; + +#ifdef CONFIG_ANTENNA_DIVERSITY + } else if (rtw_hal_antdiv_before_linked(padapter)) { + /* go sw antdiv before link */ + next_state = SCAN_SW_ANTDIV_BL; +#endif + } else { + next_state = SCAN_COMPLETE; + +#if defined(DBG_SCAN_SW_ANTDIV_BL) + { + /* for SCAN_SW_ANTDIV_BL state testing */ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + int i; + bool is_linked = _FALSE; + + for (i = 0; i < dvobj->iface_nums; i++) { + if (rtw_linked_check(dvobj->padapters[i])) + is_linked = _TRUE; + } + + if (!is_linked) { + static bool fake_sw_antdiv_bl_state = 0; + + if (fake_sw_antdiv_bl_state == 0) { + next_state = SCAN_SW_ANTDIV_BL; + fake_sw_antdiv_bl_state = 1; + } else + fake_sw_antdiv_bl_state = 0; + } + } +#endif /* defined(DBG_SCAN_SW_ANTDIV_BL) */ + } + +#ifdef CONFIG_SCAN_BACKOP + if (next_state != SCAN_PROCESS) + ss->scan_cnt = 0; +#endif + + +#ifdef DBG_FIXED_CHAN + if (pmlmeext->fixed_chan != 0xff && next_state == SCAN_PROCESS) + scan_ch = pmlmeext->fixed_chan; +#endif + + if (ch) + *ch = scan_ch; + if (type) + *type = scan_type; + + return next_state; +} + +void site_survey(_adapter *padapter, u8 survey_channel, RT_SCAN_TYPE ScanType) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#endif + + if (survey_channel != 0) { + set_channel_bwmode(padapter, survey_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); + +#ifdef CONFIG_AUTO_CHNL_SEL_NHM + if (ACS_ENABLE == GET_ACS_STATE(padapter)) { + ACS_OP acs_op = ACS_RESET; + + rtw_hal_set_odm_var(padapter, HAL_ODM_AUTO_CHNL_SEL, &acs_op, _TRUE); + rtw_set_acs_channel(padapter, survey_channel); +#ifdef DBG_AUTO_CHNL_SEL_NHM + RTW_INFO("[ACS-"ADPT_FMT"]-set ch:%u\n", + ADPT_ARG(padapter), rtw_get_acs_channel(padapter)); +#endif + } +#endif + + if (ScanType == SCAN_ACTIVE) { +#ifdef CONFIG_P2P + #ifdef CONFIG_IOCTL_CFG80211 + if (rtw_cfg80211_is_p2p_scan(padapter)) + #else + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) + || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)) + #endif + { + issue_probereq_p2p(padapter, NULL); + issue_probereq_p2p(padapter, NULL); + issue_probereq_p2p(padapter, NULL); + } else +#endif /* CONFIG_P2P */ + { + int i; + + for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) { + if (pmlmeext->sitesurvey_res.ssid[i].SsidLength) { + /* IOT issue, When wifi_spec is not set, send one probe req without WPS IE. */ + if (padapter->registrypriv.wifi_spec) + issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL); + else + issue_probereq_ex(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL, 0, 0, 0, 0); + issue_probereq(padapter, &(pmlmeext->sitesurvey_res.ssid[i]), NULL); + } + } + + if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) { + /* IOT issue, When wifi_spec is not set, send one probe req without WPS IE. */ + if (padapter->registrypriv.wifi_spec) + issue_probereq(padapter, NULL, NULL); + else + issue_probereq_ex(padapter, NULL, NULL, 0, 0, 0, 0); + issue_probereq(padapter, NULL, NULL); + } + } + } + } else { + /* channel number is 0 or this channel is not valid. */ + rtw_warn_on(1); + } + + return; +} + +void survey_done_set_ch_bw(_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + u8 cur_channel = 0; + u8 cur_bwmode; + u8 cur_ch_offset; + +#ifdef CONFIG_MCC_MODE + if (!rtw_hal_mcc_change_scan_flag(padapter, &cur_channel, &cur_bwmode, &cur_ch_offset)) { + if (0) + RTW_INFO(FUNC_ADPT_FMT" back to AP channel - ch:%u, bw:%u, offset:%u\n", + FUNC_ADPT_ARG(padapter), cur_channel, cur_bwmode, cur_ch_offset); + goto exit; + } +#endif + + if (rtw_mi_get_ch_setting_union(padapter, &cur_channel, &cur_bwmode, &cur_ch_offset) != 0) { + if (0) + RTW_INFO(FUNC_ADPT_FMT" back to linked/linking union - ch:%u, bw:%u, offset:%u\n", + FUNC_ADPT_ARG(padapter), cur_channel, cur_bwmode, cur_ch_offset); + } else { +#ifdef CONFIG_P2P + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + _adapter *iface; + int i; + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (!iface) + continue; + +#ifdef CONFIG_IOCTL_CFG80211 + if (iface->wdinfo.driver_interface == DRIVER_CFG80211 && !adapter_wdev_data(iface)->p2p_enabled) + continue; +#endif + + if (rtw_p2p_chk_state(&iface->wdinfo, P2P_STATE_LISTEN)) { + cur_channel = iface->wdinfo.listen_channel; + cur_bwmode = CHANNEL_WIDTH_20; + cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + if (0) + RTW_INFO(FUNC_ADPT_FMT" back to "ADPT_FMT"'s listen ch - ch:%u, bw:%u, offset:%u\n", + FUNC_ADPT_ARG(padapter), ADPT_ARG(iface), cur_channel, cur_bwmode, cur_ch_offset); + break; + } + } +#endif /* CONFIG_P2P */ + + if (cur_channel == 0) { + cur_channel = pmlmeext->cur_channel; + cur_bwmode = pmlmeext->cur_bwmode; + cur_ch_offset = pmlmeext->cur_ch_offset; + if (0) + RTW_INFO(FUNC_ADPT_FMT" back to ch:%u, bw:%u, offset:%u\n", + FUNC_ADPT_ARG(padapter), cur_channel, cur_bwmode, cur_ch_offset); + } + } +exit: + set_channel_bwmode(padapter, cur_channel, cur_ch_offset, cur_bwmode); +} + +#if 1 +/** + * sitesurvey_ps_annc - check and doing ps announcement for all the adapters of given @dvobj + * @padapter + * @ps: power saving or not + * + * Returns: 0: no ps announcement is doing. 1: ps announcement is doing + */ + +u8 sitesurvey_ps_annc(_adapter *padapter, bool ps) +{ + u8 ps_anc = 0; + + if (rtw_mi_issue_nulldata(padapter, NULL, ps, 3, 500)) + ps_anc = 1; + return ps_anc; +} +#else +/** + * sitesurvey_ps_annc - check and doing ps announcement for all the adapters of given @dvobj + * @dvobj: the dvobj to check + * @ps: power saving or not + * + * Returns: 0: no ps announcement is doing. 1: ps announcement is doing + */ + +u8 sitesurvey_ps_annc(struct dvobj_priv *dvobj, bool ps) +{ + _adapter *adapter; + int i; + u8 ps_anc = 0; + + for (i = 0; i < dvobj->iface_nums; i++) { + adapter = dvobj->padapters[i]; + if (!adapter) + continue; + + if (ps) { + if (is_client_associated_to_ap(adapter) == _TRUE) { + /* TODO: TDLS peers */ + issue_nulldata(adapter, NULL, 1, 3, 500); + ps_anc = 1; + } + } else { + if (is_client_associated_to_ap(adapter) == _TRUE) { + /* TODO: TDLS peers */ + issue_nulldata(adapter, NULL, 0, 3, 500); + ps_anc = 1; + } + } + } + return ps_anc; +} +#endif + +void sitesurvey_set_igi(_adapter *adapter) +{ + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + struct ss_res *ss = &mlmeext->sitesurvey_res; + u8 igi; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &adapter->wdinfo; +#endif + + switch (mlmeext_scan_state(mlmeext)) { + case SCAN_ENTER: + #ifdef CONFIG_P2P + #ifdef CONFIG_IOCTL_CFG80211 + if (adapter_wdev_data(adapter)->p2p_enabled == _TRUE && pwdinfo->driver_interface == DRIVER_CFG80211) + igi = 0x30; + else + #endif /* CONFIG_IOCTL_CFG80211 */ + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + igi = 0x28; + else + #endif /* CONFIG_P2P */ + igi = 0x1e; + + /* record IGI status */ + ss->igi_scan = igi; + rtw_hal_get_odm_var(adapter, HAL_ODM_INITIAL_GAIN, &ss->igi_before_scan, NULL); + + /* disable DIG and set IGI for scan */ + rtw_hal_set_odm_var(adapter, HAL_ODM_INITIAL_GAIN, &igi, _FALSE); + break; + case SCAN_COMPLETE: + case SCAN_TO_P2P_LISTEN: + /* enable DIG and restore IGI */ + igi = 0xff; + rtw_hal_set_odm_var(adapter, HAL_ODM_INITIAL_GAIN, &igi, _FALSE); + break; +#ifdef CONFIG_SCAN_BACKOP + case SCAN_BACKING_OP: + /* write IGI for op channel when DIG is not enabled */ + odm_write_dig(GET_ODM(adapter), ss->igi_before_scan); + break; + case SCAN_LEAVE_OP: + /* write IGI for scan when DIG is not enabled */ + odm_write_dig(GET_ODM(adapter), ss->igi_scan); + break; +#endif /* CONFIG_SCAN_BACKOP */ + default: + rtw_warn_on(1); + break; + } +} +void sitesurvey_set_msr(_adapter *adapter, bool enter) +{ + u8 network_type; + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if (enter) { +#ifdef CONFIG_MI_WITH_MBSSID_CAM + rtw_hal_get_hwreg(adapter, HW_VAR_MEDIA_STATUS, (u8 *)(&pmlmeinfo->hw_media_state)); +#endif + /* set MSR to no link state */ + network_type = _HW_STATE_NOLINK_; + } else { +#ifdef CONFIG_MI_WITH_MBSSID_CAM + network_type = pmlmeinfo->hw_media_state; +#else + network_type = pmlmeinfo->state & 0x3; +#endif + } + Set_MSR(adapter, network_type); +} +u8 sitesurvey_cmd_hdl(_adapter *padapter, u8 *pbuf) +{ + struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf; + struct dvobj_priv *dvobj = padapter->dvobj; + struct debug_priv *pdbgpriv = &dvobj->drv_dbg; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct ss_res *ss = &pmlmeext->sitesurvey_res; + u8 val8; + +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; +#endif + +#ifdef DBG_CHECK_FW_PS_STATE + if (rtw_fw_ps_state(padapter) == _FAIL) { + RTW_INFO("scan without leave 32k\n"); + pdbgpriv->dbg_scan_pwr_state_cnt++; + } +#endif /* DBG_CHECK_FW_PS_STATE */ + + /* increase channel idx */ + if (mlmeext_chk_scan_state(pmlmeext, SCAN_PROCESS)) + ss->channel_idx++; + + /* update scan state to next state (assigned by previous cmd hdl) */ + if (mlmeext_scan_state(pmlmeext) != mlmeext_scan_next_state(pmlmeext)) + mlmeext_set_scan_state(pmlmeext, mlmeext_scan_next_state(pmlmeext)); + +operation_by_state: + switch (mlmeext_scan_state(pmlmeext)) { + + case SCAN_DISABLE: + /* + * SW parameter initialization + */ + + sitesurvey_res_reset(padapter, pparm); + mlmeext_set_scan_state(pmlmeext, SCAN_START); + goto operation_by_state; + + case SCAN_START: + /* + * prepare to leave operating channel + */ + +#ifdef CONFIG_MCC_MODE + rtw_hal_set_mcc_setting_scan_start(padapter); +#endif /* CONFIG_MCC_MODE */ + + /* apply rx ampdu setting */ + if (ss->rx_ampdu_accept != RX_AMPDU_ACCEPT_INVALID + || ss->rx_ampdu_size != RX_AMPDU_SIZE_INVALID) + rtw_rx_ampdu_apply(padapter); + + /* clear HW TX queue before scan */ + rtw_hal_set_hwreg(padapter, HW_VAR_CHECK_TXBUF, 0); + + /* power save state announcement */ + if (sitesurvey_ps_annc(padapter, 1)) { + mlmeext_set_scan_state(pmlmeext, SCAN_PS_ANNC_WAIT); + mlmeext_set_scan_next_state(pmlmeext, SCAN_ENTER); + set_survey_timer(pmlmeext, 50); /* delay 50ms to protect nulldata(1) */ + } else { + mlmeext_set_scan_state(pmlmeext, SCAN_ENTER); + goto operation_by_state; + } + + break; + + case SCAN_ENTER: + /* + * HW register and DM setting for enter scan + */ + + rtw_phydm_ability_backup(padapter); + + sitesurvey_set_igi(padapter); + + /* config dynamic functions for off channel */ + rtw_phydm_func_for_offchannel(padapter); + /* set MSR to no link state */ + sitesurvey_set_msr(padapter, _TRUE); + + val8 = 1; /* under site survey */ + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + + mlmeext_set_scan_state(pmlmeext, SCAN_PROCESS); + goto operation_by_state; + + case SCAN_PROCESS: { + u8 scan_ch; + RT_SCAN_TYPE scan_type; + u8 next_state; + u32 scan_ms; + +#ifdef CONFIG_AUTO_CHNL_SEL_NHM + if ((ACS_ENABLE == GET_ACS_STATE(padapter)) && (0 != rtw_get_acs_channel(padapter))) { + ACS_OP acs_op = ACS_SELECT; + + rtw_hal_set_odm_var(padapter, HAL_ODM_AUTO_CHNL_SEL, &acs_op, _TRUE); + } +#endif + + next_state = sitesurvey_pick_ch_behavior(padapter, &scan_ch, &scan_type); + if (next_state != SCAN_PROCESS) { +#ifdef CONFIG_AUTO_CHNL_SEL_NHM + if (ACS_ENABLE == GET_ACS_STATE(padapter)) { + rtw_set_acs_channel(padapter, 0); +#ifdef DBG_AUTO_CHNL_SEL_NHM + RTW_INFO("[ACS-"ADPT_FMT"]-set ch:%u\n", ADPT_ARG(padapter), rtw_get_acs_channel(padapter)); +#endif + } +#endif + + mlmeext_set_scan_state(pmlmeext, next_state); + goto operation_by_state; + } + + /* still SCAN_PROCESS state */ + if (0) +#ifdef CONFIG_P2P + RTW_INFO(FUNC_ADPT_FMT" %s ch:%u (cnt:%u,idx:%d) at %dms, %c%c%c\n" + , FUNC_ADPT_ARG(padapter) + , mlmeext_scan_state_str(pmlmeext) + , scan_ch + , pwdinfo->find_phase_state_exchange_cnt, ss->channel_idx + , rtw_get_passing_time_ms(padapter->mlmepriv.scan_start_time) + , scan_type ? 'A' : 'P', ss->scan_mode ? 'A' : 'P' + , ss->ssid[0].SsidLength ? 'S' : ' ' + ); +#else + RTW_INFO(FUNC_ADPT_FMT" %s ch:%u (idx:%d) at %dms, %c%c%c\n" + , FUNC_ADPT_ARG(padapter) + , mlmeext_scan_state_str(pmlmeext) + , scan_ch + , ss->channel_idx + , rtw_get_passing_time_ms(padapter->mlmepriv.scan_start_time) + , scan_type ? 'A' : 'P', ss->scan_mode ? 'A' : 'P' + , ss->ssid[0].SsidLength ? 'S' : ' ' + ); +#endif /* CONFIG_P2P */ + +#ifdef DBG_FIXED_CHAN + if (pmlmeext->fixed_chan != 0xff) + RTW_INFO(FUNC_ADPT_FMT" fixed_chan:%u\n", pmlmeext->fixed_chan); +#endif + + site_survey(padapter, scan_ch, scan_type); + +#if defined(CONFIG_ATMEL_RC_PATCH) + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + scan_ms = 20; + else + scan_ms = 40; +#else + scan_ms = ss->scan_ch_ms; +#endif + +#if defined(CONFIG_ANTENNA_DIVERSITY) || defined(DBG_SCAN_SW_ANTDIV_BL) + if (ss->is_sw_antdiv_bl_scan) + scan_ms = scan_ms / 2; +#endif + +#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) + { + struct noise_info info; + + info.bPauseDIG = _FALSE; + info.IGIValue = 0; + info.max_time = scan_ms / 2; + info.chan = scan_ch; + rtw_hal_set_odm_var(padapter, HAL_ODM_NOISE_MONITOR, &info, _FALSE); + } +#endif + + set_survey_timer(pmlmeext, scan_ms); + break; + } + +#ifdef CONFIG_SCAN_BACKOP + case SCAN_BACKING_OP: { + u8 back_ch, back_bw, back_ch_offset; + u8 need_ch_setting_union = _TRUE; + +#ifdef CONFIG_MCC_MODE + need_ch_setting_union = rtw_hal_mcc_change_scan_flag(padapter, + &back_ch, &back_bw, &back_ch_offset); +#endif /* CONFIG_MCC_MODE */ + + if (need_ch_setting_union) { + if (rtw_mi_get_ch_setting_union(padapter, &back_ch, &back_bw, &back_ch_offset) == 0) + rtw_warn_on(1); + } + + if (0) + RTW_INFO(FUNC_ADPT_FMT" %s ch:%u, bw:%u, offset:%u at %dms\n" + , FUNC_ADPT_ARG(padapter) + , mlmeext_scan_state_str(pmlmeext) + , back_ch, back_bw, back_ch_offset + , rtw_get_passing_time_ms(padapter->mlmepriv.scan_start_time) + ); + + set_channel_bwmode(padapter, back_ch, back_ch_offset, back_bw); + + sitesurvey_set_msr(padapter, _FALSE); + + val8 = 0; /* survey done */ + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + + if (mlmeext_chk_scan_backop_flags(pmlmeext, SS_BACKOP_PS_ANNC)) { + sitesurvey_set_igi(padapter); + sitesurvey_ps_annc(padapter, 0); + } + + mlmeext_set_scan_state(pmlmeext, SCAN_BACK_OP); + ss->backop_time = rtw_get_current_time(); + + if (mlmeext_chk_scan_backop_flags(pmlmeext, SS_BACKOP_TX_RESUME)) + rtw_mi_os_xmit_schedule(padapter); + + + goto operation_by_state; + } + + case SCAN_BACK_OP: + if (rtw_get_passing_time_ms(ss->backop_time) >= ss->backop_ms + || pmlmeext->scan_abort + ) { + mlmeext_set_scan_state(pmlmeext, SCAN_LEAVING_OP); + goto operation_by_state; + } + set_survey_timer(pmlmeext, 50); + break; + + case SCAN_LEAVING_OP: + /* + * prepare to leave operating channel + */ + + /* clear HW TX queue before scan */ + rtw_hal_set_hwreg(padapter, HW_VAR_CHECK_TXBUF, 0); + + if (mlmeext_chk_scan_backop_flags(pmlmeext, SS_BACKOP_PS_ANNC) + && sitesurvey_ps_annc(padapter, 1) + ) { + mlmeext_set_scan_state(pmlmeext, SCAN_PS_ANNC_WAIT); + mlmeext_set_scan_next_state(pmlmeext, SCAN_LEAVE_OP); + set_survey_timer(pmlmeext, 50); /* delay 50ms to protect nulldata(1) */ + } else { + mlmeext_set_scan_state(pmlmeext, SCAN_LEAVE_OP); + goto operation_by_state; + } + + break; + + case SCAN_LEAVE_OP: + /* + * HW register and DM setting for enter scan + */ + + if (mlmeext_chk_scan_backop_flags(pmlmeext, SS_BACKOP_PS_ANNC)) + sitesurvey_set_igi(padapter); + + sitesurvey_set_msr(padapter, _TRUE); + + val8 = 1; /* under site survey */ + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + + mlmeext_set_scan_state(pmlmeext, SCAN_PROCESS); + goto operation_by_state; + +#endif /* CONFIG_SCAN_BACKOP */ + +#if defined(CONFIG_ANTENNA_DIVERSITY) || defined(DBG_SCAN_SW_ANTDIV_BL) + case SCAN_SW_ANTDIV_BL: + /* + * 20100721 + * For SW antenna diversity before link, it needs to switch to another antenna and scan again. + * It compares the scan result and select better one to do connection. + */ + ss->bss_cnt = 0; + ss->channel_idx = 0; + ss->is_sw_antdiv_bl_scan = 1; + + mlmeext_set_scan_next_state(pmlmeext, SCAN_PROCESS); + set_survey_timer(pmlmeext, ss->scan_ch_ms); + break; +#endif + +#ifdef CONFIG_P2P + case SCAN_TO_P2P_LISTEN: + /* + * Set the P2P State to the listen state of find phase + * and set the current channel to the listen channel + */ + set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); + rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_LISTEN); + + /* turn on phy-dynamic functions */ + rtw_phydm_ability_restore(padapter); + + sitesurvey_set_igi(padapter); + + mlmeext_set_scan_state(pmlmeext, SCAN_P2P_LISTEN); + _set_timer(&pwdinfo->find_phase_timer, (u32)((u32)pwdinfo->listen_dwell * 100)); + break; + + case SCAN_P2P_LISTEN: + mlmeext_set_scan_state(pmlmeext, SCAN_PROCESS); + ss->channel_idx = 0; + goto operation_by_state; +#endif /* CONFIG_P2P */ + + case SCAN_COMPLETE: +#ifdef CONFIG_P2P + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) + || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) + ) { +#ifdef CONFIG_CONCURRENT_MODE + if (pwdinfo->driver_interface == DRIVER_WEXT) { + if (rtw_mi_check_status(padapter, MI_LINKED)) + _set_timer(&pwdinfo->ap_p2p_switch_timer, 500); + } +#endif + + rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); + } + rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); +#endif /* CONFIG_P2P */ + + /* switch channel */ + survey_done_set_ch_bw(padapter); + + sitesurvey_set_msr(padapter, _FALSE); + + val8 = 0; /* survey done */ + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + + /* turn on phy-dynamic functions */ + rtw_phydm_ability_restore(padapter); + + sitesurvey_set_igi(padapter); + +#ifdef CONFIG_MCC_MODE + /* start MCC fail, then tx null data */ + if (!rtw_hal_set_mcc_setting_scan_complete(padapter)) +#endif /* CONFIG_MCC_MODE */ + sitesurvey_ps_annc(padapter, 0); + + /* apply rx ampdu setting */ + rtw_rx_ampdu_apply(padapter); + + mlmeext_set_scan_state(pmlmeext, SCAN_DISABLE); + + report_surveydone_event(padapter); + + issue_action_BSSCoexistPacket(padapter); + issue_action_BSSCoexistPacket(padapter); + issue_action_BSSCoexistPacket(padapter); + } + + return H2C_SUCCESS; +} + +u8 setauth_hdl(_adapter *padapter, unsigned char *pbuf) +{ + struct setauth_parm *pparm = (struct setauth_parm *)pbuf; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if (pparm->mode < 4) + pmlmeinfo->auth_algo = pparm->mode; + + return H2C_SUCCESS; +} + +/* +SEC CAM Entry format (32 bytes) +DW0 - MAC_ADDR[15:0] | Valid[15] | MFB[14:8] | RSVD[7] | GK[6] | MIC_KEY[5] | SEC_TYPE[4:2] | KID[1:0] +DW0 - MAC_ADDR[15:0] | Valid[15] |RSVD[14:9] | RPT_MODE[8] | SPP_MODE[7] | GK[6] | MIC_KEY[5] | SEC_TYPE[4:2] | KID[1:0] (92E/8812A/8814A) +DW1 - MAC_ADDR[47:16] +DW2 - KEY[31:0] +DW3 - KEY[63:32] +DW4 - KEY[95:64] +DW5 - KEY[127:96] +DW6 - RSVD +DW7 - RSVD +*/ + +/*Set WEP key or Group Key*/ +u8 setkey_hdl(_adapter *padapter, u8 *pbuf) +{ + u16 ctrl = 0; + s16 cam_id = 0; + struct setkey_parm *pparm = (struct setkey_parm *)pbuf; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + unsigned char null_addr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + u8 *addr; + bool used = _FALSE; + + /* main tx key for wep. */ + if (pparm->set_tx) + pmlmeinfo->key_index = pparm->keyid; + +#ifdef CONFIG_CONCURRENT_MODE + if (((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) + cam_id = rtw_iface_bcmc_id_get(padapter); + else +#endif + cam_id = rtw_camid_alloc(padapter, NULL, pparm->keyid, &used); + + if (cam_id < 0) + goto enable_mc; + +#ifndef CONFIG_CONCURRENT_MODE + if (cam_id >= 0 && cam_id <= 3) + addr = null_addr; + else +#endif + { + if (((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) + /* for AP mode ,we will force sec cam entry_id so hw dont search cam when tx*/ + addr = adapter_mac_addr(padapter); + else + /* not default key, searched by A2 */ + addr = get_bssid(&padapter->mlmepriv); + } + + /* cam entry searched is pairwise key */ + if (used == _TRUE && rtw_camid_is_gk(padapter, cam_id) == _FALSE) { + s16 camid_clr; + + RTW_PRINT(FUNC_ADPT_FMT" group key with "MAC_FMT" id:%u the same key id as pairwise key\n" + , FUNC_ADPT_ARG(padapter), MAC_ARG(addr), pparm->keyid); + + /* HW has problem to distinguish this group key with existing pairwise key, stop HW enc and dec for BMC */ + rtw_camctl_set_flags(padapter, SEC_STATUS_STA_PK_GK_CONFLICT_DIS_BMC_SEARCH); + rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, NULL); + + /* clear group key */ + while ((camid_clr = rtw_camid_search(padapter, addr, -1, 1)) >= 0) { + RTW_PRINT("clear group key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(addr), camid_clr); + clear_cam_entry(padapter, camid_clr); + rtw_camid_free(padapter, camid_clr); + } + + goto enable_mc; + } + + ctrl = BIT(15) | BIT(6) | ((pparm->algorithm) << 2) | pparm->keyid; + + RTW_PRINT("set group key camid:%d, addr:"MAC_FMT", kid:%d, type:%s\n" + , cam_id, MAC_ARG(addr), pparm->keyid, security_type_str(pparm->algorithm)); + + write_cam(padapter, cam_id, ctrl, addr, pparm->key); + + /* if ((cam_id > 3) && (((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)))*/ +#ifdef CONFIG_CONCURRENT_MODE + if (((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) { + if (is_wep_enc(pparm->algorithm)) { + padapter->securitypriv.dot11Def_camid[pparm->keyid] = cam_id; + padapter->securitypriv.dot118021x_bmc_cam_id = + padapter->securitypriv.dot11Def_camid[padapter->securitypriv.dot11PrivacyKeyIndex]; + RTW_PRINT("wep group key - force camid:%d\n", padapter->securitypriv.dot118021x_bmc_cam_id); + } else { + /*u8 org_cam_id = padapter->securitypriv.dot118021x_bmc_cam_id;*/ + + /*force GK's cam id*/ + padapter->securitypriv.dot118021x_bmc_cam_id = cam_id; + + /* for GTK rekey + if ((org_cam_id != INVALID_SEC_MAC_CAM_ID) && + (org_cam_id != cam_id)) { + RTW_PRINT("clear group key for addr:"MAC_FMT", org_camid:%d new_camid:%d\n", MAC_ARG(addr), org_cam_id, cam_id); + clear_cam_entry(padapter, org_cam_id); + rtw_camid_free(padapter, org_cam_id); + }*/ + } + } +#endif + + +#ifndef CONFIG_CONCURRENT_MODE + if (cam_id >= 0 && cam_id <= 3) + rtw_hal_set_hwreg(padapter, HW_VAR_SEC_DK_CFG, (u8 *)_TRUE); +#endif + + /* 8814au should set both broadcast and unicast CAM entry for WEP key in STA mode */ + if (is_wep_enc(pparm->algorithm) && check_mlmeinfo_state(pmlmeext, WIFI_FW_STATION_STATE) && + _rtw_camctl_chk_cap(padapter, SEC_CAP_CHK_BMC)) { + struct set_stakey_parm sta_pparm; + + sta_pparm.algorithm = pparm->algorithm; + sta_pparm.keyid = pparm->keyid; + _rtw_memcpy(sta_pparm.key, pparm->key, 16); + _rtw_memcpy(sta_pparm.addr, get_bssid(&padapter->mlmepriv), ETH_ALEN); + set_stakey_hdl(padapter, (u8 *)&sta_pparm); + } + +enable_mc: + /* allow multicast packets to driver */ + rtw_hal_set_hwreg(padapter, HW_VAR_ON_RCR_AM, null_addr); + + return H2C_SUCCESS; +} + +void rtw_ap_wep_pk_setting(_adapter *adapter, struct sta_info *psta) +{ + struct security_priv *psecuritypriv = &(adapter->securitypriv); + struct set_stakey_parm sta_pparm; + sint keyid; + + if (!is_wep_enc(psecuritypriv->dot11PrivacyAlgrthm)) + return; + + for (keyid = 0; keyid < 4; keyid++) { + if ((psecuritypriv->key_mask & BIT(keyid)) && (keyid == psecuritypriv->dot11PrivacyKeyIndex)) { + sta_pparm.algorithm = psecuritypriv->dot11PrivacyAlgrthm; + sta_pparm.keyid = keyid; + _rtw_memcpy(sta_pparm.key, &(psecuritypriv->dot11DefKey[keyid].skey[0]), 16); + _rtw_memcpy(sta_pparm.addr, psta->hwaddr, ETH_ALEN); + + RTW_PRINT(FUNC_ADPT_FMT"set WEP - PK with "MAC_FMT" keyid:%u\n" + , FUNC_ADPT_ARG(adapter), MAC_ARG(psta->hwaddr), keyid); + + set_stakey_hdl(adapter, (u8 *)&sta_pparm); + } + } +} + +u8 set_stakey_hdl(_adapter *padapter, u8 *pbuf) +{ + u16 ctrl = 0; + s16 cam_id = 0; + bool used; + u8 kid = 0; + u8 ret = H2C_SUCCESS; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct set_stakey_parm *pparm = (struct set_stakey_parm *)pbuf; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta; + + if (pparm->algorithm == _NO_PRIVACY_) + goto write_to_cam; + + psta = rtw_get_stainfo(pstapriv, pparm->addr); + if (!psta) { + RTW_PRINT("%s sta:"MAC_FMT" not found\n", __func__, MAC_ARG(pparm->addr)); + ret = H2C_REJECTED; + goto exit; + } + + pmlmeinfo->enc_algo = pparm->algorithm; + if (is_wep_enc(pparm->algorithm)) + kid = pparm->keyid; + cam_id = rtw_camid_alloc(padapter, psta, kid, &used); + if (cam_id < 0) + goto exit; + + /* cam entry searched is group key */ + if (used == _TRUE && rtw_camid_is_gk(padapter, cam_id) == _TRUE) { + s16 camid_clr; + + RTW_PRINT(FUNC_ADPT_FMT" pairwise key with "MAC_FMT" id:%u the same key id as group key\n" + , FUNC_ADPT_ARG(padapter), MAC_ARG(pparm->addr), pparm->keyid); + + /* HW has problem to distinguish this pairwise key with existing group key, stop HW enc and dec for BMC */ + rtw_camctl_set_flags(padapter, SEC_STATUS_STA_PK_GK_CONFLICT_DIS_BMC_SEARCH); + rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, NULL); + + /* clear group key */ + while ((camid_clr = rtw_camid_search(padapter, pparm->addr, -1, 1)) >= 0) { + RTW_PRINT("clear group key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(pparm->addr), camid_clr); + clear_cam_entry(padapter, camid_clr); + rtw_camid_free(padapter, camid_clr); + } + } + +write_to_cam: + if (pparm->algorithm == _NO_PRIVACY_) { + while ((cam_id = rtw_camid_search(padapter, pparm->addr, -1, -1)) >= 0) { + RTW_PRINT("clear key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(pparm->addr), cam_id); + clear_cam_entry(padapter, cam_id); + rtw_camid_free(padapter, cam_id); + } + } else { + RTW_PRINT("set pairwise key camid:%d, addr:"MAC_FMT", kid:%d, type:%s\n", + cam_id, MAC_ARG(pparm->addr), pparm->keyid, security_type_str(pparm->algorithm)); + ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid; + write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key); + } + ret = H2C_SUCCESS_RSP; + +exit: + return ret; +} + +u8 add_ba_hdl(_adapter *padapter, unsigned char *pbuf) +{ + struct addBaReq_parm *pparm = (struct addBaReq_parm *)pbuf; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, pparm->addr); + + if (!psta) + return H2C_SUCCESS; + +#ifdef CONFIG_80211N_HT + if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && (pmlmeinfo->HT_enable)) || + ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) { + /* pmlmeinfo->ADDBA_retry_count = 0; */ + /* pmlmeinfo->candidate_tid_bitmap |= (0x1 << pparm->tid); */ + /* psta->htpriv.candidate_tid_bitmap |= BIT(pparm->tid); */ + issue_addba_req(padapter, pparm->addr, (u8)pparm->tid); + /* _set_timer(&pmlmeext->ADDBA_timer, ADDBA_TO); */ + _set_timer(&psta->addba_retry_timer, ADDBA_TO); + } +#ifdef CONFIG_TDLS + else if ((psta->tdls_sta_state & TDLS_LINKED_STATE) && + (psta->htpriv.ht_option == _TRUE) && + (psta->htpriv.ampdu_enable == _TRUE)) { + issue_addba_req(padapter, pparm->addr, (u8)pparm->tid); + _set_timer(&psta->addba_retry_timer, ADDBA_TO); + } +#endif /* CONFIG */ + else + psta->htpriv.candidate_tid_bitmap &= ~BIT(pparm->tid); +#endif /* CONFIG_80211N_HT */ + return H2C_SUCCESS; +} + + +u8 add_ba_rsp_hdl(_adapter *padapter, unsigned char *pbuf) +{ + struct addBaRsp_parm *pparm = (struct addBaRsp_parm *)pbuf; + u8 ret = _TRUE, i = 0, try_cnt = 3, wait_ms = 50; + struct recv_reorder_ctrl *preorder_ctrl; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta; + + psta = rtw_get_stainfo(pstapriv, pparm->addr); + if (!psta) + goto exit; + + preorder_ctrl = &psta->recvreorder_ctrl[pparm->tid]; + ret = issue_addba_rsp_wait_ack(padapter, pparm->addr, pparm->tid, pparm->status, pparm->size, 3, 50); + +#ifdef CONFIG_UPDATE_INDICATE_SEQ_WHILE_PROCESS_ADDBA_REQ + /* status = 0 means accept this addba req, so update indicate seq = start_seq under this compile flag */ + if (pparm->status == 0) { + preorder_ctrl->indicate_seq = pparm->start_seq; +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d IndicateSeq: %d, start_seq: %d\n", __func__, __LINE__, + preorder_ctrl->indicate_seq, pparm->start_seq); +#endif + } +#else + preorder_ctrl->indicate_seq = 0xffff; +#endif + + /* + * status = 0 means accept this addba req + * status = 37 means reject this addba req + */ + if (pparm->status == 0) { + preorder_ctrl->enable = _TRUE; + preorder_ctrl->ampdu_size = pparm->size; + } else if (pparm->status == 37) + preorder_ctrl->enable = _FALSE; + +exit: + return H2C_SUCCESS; +} + +u8 chk_bmc_sleepq_cmd(_adapter *padapter) +{ + struct cmd_obj *ph2c; + struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); + u8 res = _SUCCESS; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + init_h2fwcmd_w_parm_no_parm_rsp(ph2c, GEN_CMD_CODE(_ChkBMCSleepq)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + +exit: + + + return res; +} + +u8 set_tx_beacon_cmd(_adapter *padapter) +{ + struct cmd_obj *ph2c; + struct Tx_Beacon_param *ptxBeacon_parm; + struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 res = _SUCCESS; + int len_diff = 0; + + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + ptxBeacon_parm = (struct Tx_Beacon_param *)rtw_zmalloc(sizeof(struct Tx_Beacon_param)); + if (ptxBeacon_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + _rtw_memcpy(&(ptxBeacon_parm->network), &(pmlmeinfo->network), sizeof(WLAN_BSSID_EX)); + + len_diff = update_hidden_ssid( + ptxBeacon_parm->network.IEs + _BEACON_IE_OFFSET_ + , ptxBeacon_parm->network.IELength - _BEACON_IE_OFFSET_ + , pmlmeinfo->hidden_ssid_mode + ); + ptxBeacon_parm->network.IELength += len_diff; + + init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, GEN_CMD_CODE(_TX_Beacon)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + + +exit: + + + return res; +} + + +u8 mlme_evt_hdl(_adapter *padapter, unsigned char *pbuf) +{ + u8 evt_code, evt_seq; + u16 evt_sz; + uint *peventbuf; + void (*event_callback)(_adapter *dev, u8 *pbuf); + struct evt_priv *pevt_priv = &(padapter->evtpriv); + + if (pbuf == NULL) + goto _abort_event_; + + peventbuf = (uint *)pbuf; + evt_sz = (u16)(*peventbuf & 0xffff); + evt_seq = (u8)((*peventbuf >> 24) & 0x7f); + evt_code = (u8)((*peventbuf >> 16) & 0xff); + + +#ifdef CHECK_EVENT_SEQ + /* checking event sequence... */ + if (evt_seq != (ATOMIC_READ(&pevt_priv->event_seq) & 0x7f)) { + + pevt_priv->event_seq = (evt_seq + 1) & 0x7f; + + goto _abort_event_; + } +#endif + + /* checking if event code is valid */ + if (evt_code >= MAX_C2HEVT) { + goto _abort_event_; + } + + /* checking if event size match the event parm size */ + if ((wlanevents[evt_code].parmsize != 0) && + (wlanevents[evt_code].parmsize != evt_sz)) { + + goto _abort_event_; + + } + + ATOMIC_INC(&pevt_priv->event_seq); + + peventbuf += 2; + + if (peventbuf) { + event_callback = wlanevents[evt_code].event_callback; + event_callback(padapter, (u8 *)peventbuf); + + pevt_priv->evt_done_cnt++; + } + + +_abort_event_: + + + return H2C_SUCCESS; + +} + +u8 h2c_msg_hdl(_adapter *padapter, unsigned char *pbuf) +{ + if (!pbuf) + return H2C_PARAMETERS_ERROR; + + return H2C_SUCCESS; +} + +u8 chk_bmc_sleepq_hdl(_adapter *padapter, unsigned char *pbuf) +{ +#ifdef CONFIG_AP_MODE + _irqL irqL; + struct sta_info *psta_bmc; + _list *xmitframe_plist, *xmitframe_phead; + struct xmit_frame *pxmitframe = NULL; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct sta_priv *pstapriv = &padapter->stapriv; + + /* for BC/MC Frames */ + psta_bmc = rtw_get_bcmc_stainfo(padapter); + if (!psta_bmc) + return H2C_SUCCESS; + + if ((pstapriv->tim_bitmap & BIT(0)) && (psta_bmc->sleepq_len > 0)) { +#ifndef CONFIG_PCI_HCI + rtw_msleep_os(10);/* 10ms, ATIM(HIQ) Windows */ +#endif + /* _enter_critical_bh(&psta_bmc->sleep_q.lock, &irqL); */ + _enter_critical_bh(&pxmitpriv->lock, &irqL); + + xmitframe_phead = get_list_head(&psta_bmc->sleep_q); + xmitframe_plist = get_next(xmitframe_phead); + + while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) { + pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); + + xmitframe_plist = get_next(xmitframe_plist); + + rtw_list_delete(&pxmitframe->list); + + psta_bmc->sleepq_len--; + if (psta_bmc->sleepq_len > 0) + pxmitframe->attrib.mdata = 1; + else + pxmitframe->attrib.mdata = 0; + + pxmitframe->attrib.triggered = 1; + + if (xmitframe_hiq_filter(pxmitframe) == _TRUE) + pxmitframe->attrib.qsel = QSLT_HIGH;/* HIQ */ + +#if 0 + _exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL); + if (rtw_hal_xmit(padapter, pxmitframe) == _TRUE) + rtw_os_xmit_complete(padapter, pxmitframe); + _enter_critical_bh(&psta_bmc->sleep_q.lock, &irqL); +#endif + rtw_hal_xmitframe_enqueue(padapter, pxmitframe); + } + + /* _exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL); */ + _exit_critical_bh(&pxmitpriv->lock, &irqL); + + if (rtw_get_intf_type(padapter) != RTW_PCIE) { + /* check hi queue and bmc_sleepq */ + rtw_chk_hi_queue_cmd(padapter); + } + } +#endif + + return H2C_SUCCESS; +} + +u8 tx_beacon_hdl(_adapter *padapter, unsigned char *pbuf) +{ + +#ifdef CONFIG_SWTIMER_BASED_TXBCN + + tx_beacon_handlder(padapter->dvobj); + +#else + + if (send_beacon(padapter) == _FAIL) { + RTW_INFO("issue_beacon, fail!\n"); + return H2C_PARAMETERS_ERROR; + } + + /* tx bc/mc frames after update TIM */ + chk_bmc_sleepq_hdl(padapter, NULL); +#endif + + return H2C_SUCCESS; +} + +/* +* according to channel +* add/remove WLAN_BSSID_EX.IEs's ERP ie +* set WLAN_BSSID_EX.SupportedRates +* update WLAN_BSSID_EX.IEs's Supported Rate and Extended Supported Rate ie +*/ +void change_band_update_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 ch) +{ + u8 network_type, rate_len, total_rate_len, remainder_rate_len; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 erpinfo = 0x4; + + if (ch >= 36) { + network_type = WIRELESS_11A; + total_rate_len = IEEE80211_NUM_OFDM_RATESLEN; + rtw_remove_bcn_ie(padapter, pnetwork, _ERPINFO_IE_); + } else { + network_type = WIRELESS_11BG; + total_rate_len = IEEE80211_CCK_RATE_LEN + IEEE80211_NUM_OFDM_RATESLEN; + rtw_add_bcn_ie(padapter, pnetwork, _ERPINFO_IE_, &erpinfo, 1); + } + + rtw_set_supported_rate(pnetwork->SupportedRates, network_type); + + UpdateBrateTbl(padapter, pnetwork->SupportedRates); + + if (total_rate_len > 8) { + rate_len = 8; + remainder_rate_len = total_rate_len - 8; + } else { + rate_len = total_rate_len; + remainder_rate_len = 0; + } + + rtw_add_bcn_ie(padapter, pnetwork, _SUPPORTEDRATES_IE_, pnetwork->SupportedRates, rate_len); + + if (remainder_rate_len) + rtw_add_bcn_ie(padapter, pnetwork, _EXT_SUPPORTEDRATES_IE_, (pnetwork->SupportedRates + 8), remainder_rate_len); + else + rtw_remove_bcn_ie(padapter, pnetwork, _EXT_SUPPORTEDRATES_IE_); + + pnetwork->Length = get_WLAN_BSSID_EX_sz(pnetwork); +} + +void rtw_join_done_chk_ch(_adapter *adapter, int join_res) +{ +#define DUMP_ADAPTERS_STATUS 0 + + struct dvobj_priv *dvobj; + _adapter *iface; + struct mlme_priv *mlme; + struct mlme_ext_priv *mlmeext; + u8 u_ch, u_offset, u_bw; + int i; + + dvobj = adapter_to_dvobj(adapter); + + if (DUMP_ADAPTERS_STATUS) { + RTW_INFO(FUNC_ADPT_FMT" enter\n", FUNC_ADPT_ARG(adapter)); + dump_adapters_status(RTW_DBGDUMP , dvobj); + } + + if (join_res >= 0) { + +#ifdef CONFIG_MCC_MODE + /* MCC setting success, don't go to ch union process */ + if (rtw_hal_set_mcc_setting_join_done_chk_ch(adapter)) + return; +#endif /* CONFIG_MCC_MODE */ + + if (rtw_mi_get_ch_setting_union(adapter, &u_ch, &u_bw, &u_offset) <= 0) { + dump_adapters_status(RTW_DBGDUMP , dvobj); + rtw_warn_on(1); + } + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + mlme = &iface->mlmepriv; + mlmeext = &iface->mlmeextpriv; + + if (!iface || iface == adapter) + continue; + + if (check_fwstate(mlme, WIFI_AP_STATE) + && check_fwstate(mlme, WIFI_ASOC_STATE) + ) { + bool is_grouped = rtw_is_chbw_grouped(u_ch, u_bw, u_offset + , mlmeext->cur_channel, mlmeext->cur_bwmode, mlmeext->cur_ch_offset); + + if (is_grouped == _FALSE) { + /* handle AP which need to switch ch setting */ + + /* restore original bw, adjust bw by registry setting on target ch */ + mlmeext->cur_bwmode = mlme->ori_bw; + mlmeext->cur_channel = u_ch; + rtw_adjust_chbw(iface + , mlmeext->cur_channel, &mlmeext->cur_bwmode, &mlmeext->cur_ch_offset); + + rtw_sync_chbw(&mlmeext->cur_channel, &mlmeext->cur_bwmode, &mlmeext->cur_ch_offset + , &u_ch, &u_bw, &u_offset); + + rtw_ap_update_bss_chbw(iface, &(mlmeext->mlmext_info.network) + , mlmeext->cur_channel, mlmeext->cur_bwmode, mlmeext->cur_ch_offset); + + _rtw_memcpy(&(mlme->cur_network.network), &(mlmeext->mlmext_info.network), sizeof(WLAN_BSSID_EX)); + + rtw_start_bss_hdl_after_chbw_decided(iface); + } + + update_beacon(iface, 0, NULL, _TRUE); + } + + clr_fwstate(mlme, WIFI_OP_CH_SWITCHING); + } + +#ifdef CONFIG_DFS_MASTER + rtw_dfs_master_status_apply(adapter, MLME_STA_CONNECTED); +#endif + } else { + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + mlme = &iface->mlmepriv; + mlmeext = &iface->mlmeextpriv; + + if (!iface || iface == adapter) + continue; + + if (check_fwstate(mlme, WIFI_AP_STATE) + && check_fwstate(mlme, WIFI_ASOC_STATE)) + update_beacon(iface, 0, NULL, _TRUE); + + clr_fwstate(mlme, WIFI_OP_CH_SWITCHING); + } +#ifdef CONFIG_DFS_MASTER + rtw_dfs_master_status_apply(adapter, MLME_STA_DISCONNECTED); +#endif + } + + if (rtw_mi_get_ch_setting_union(adapter, &u_ch, &u_bw, &u_offset)) { + set_channel_bwmode(adapter, u_ch, u_offset, u_bw); + rtw_mi_update_union_chan_inf(adapter, u_ch, u_offset, u_bw); + } + + if (DUMP_ADAPTERS_STATUS) { + RTW_INFO(FUNC_ADPT_FMT" exit\n", FUNC_ADPT_ARG(adapter)); + dump_adapters_status(RTW_DBGDUMP , dvobj); + } +} + +int rtw_chk_start_clnt_join(_adapter *adapter, u8 *ch, u8 *bw, u8 *offset) +{ + bool chbw_allow = _TRUE; + bool connect_allow = _TRUE; + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + u8 cur_ch, cur_bw, cur_ch_offset; + u8 u_ch, u_offset, u_bw; + + u_ch = cur_ch = pmlmeext->cur_channel; + u_bw = cur_bw = pmlmeext->cur_bwmode; + u_offset = cur_ch_offset = pmlmeext->cur_ch_offset; + + if (!ch || !bw || !offset) { + connect_allow = _FALSE; + rtw_warn_on(1); + goto exit; + } + + if (cur_ch == 0) { + connect_allow = _FALSE; + RTW_ERR(FUNC_ADPT_FMT" cur_ch:%u\n" + , FUNC_ADPT_ARG(adapter), cur_ch); + rtw_warn_on(1); + goto exit; + } + RTW_INFO(FUNC_ADPT_FMT" req: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset); + +#ifdef CONFIG_CONCURRENT_MODE + { + struct dvobj_priv *dvobj; + _adapter *iface; + struct mlme_priv *mlme; + struct mlme_ext_priv *mlmeext; + struct mi_state mstate; + int i; + + dvobj = adapter_to_dvobj(adapter); + + rtw_mi_status_no_self(adapter, &mstate); + RTW_INFO(FUNC_ADPT_FMT" ld_sta_num:%u, ap_num:%u\n" + , FUNC_ADPT_ARG(adapter), MSTATE_STA_LD_NUM(&mstate), MSTATE_AP_NUM(&mstate)); + + if (!MSTATE_STA_LD_NUM(&mstate) && !MSTATE_AP_NUM(&mstate)) { + /* consider linking STA? */ + goto connect_allow_hdl; + } + + if (rtw_mi_get_ch_setting_union_no_self(adapter, &u_ch, &u_bw, &u_offset) <= 0) { + dump_adapters_status(RTW_DBGDUMP , dvobj); + rtw_warn_on(1); + } + RTW_INFO(FUNC_ADPT_FMT" union no self: %u,%u,%u\n" + , FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset); + + /* chbw_allow? */ + chbw_allow = rtw_is_chbw_grouped(pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset + , u_ch, u_bw, u_offset); + + RTW_INFO(FUNC_ADPT_FMT" chbw_allow:%d\n" + , FUNC_ADPT_ARG(adapter), chbw_allow); + +#ifdef CONFIG_MCC_MODE + /* check setting success, don't go to ch union process */ + if (rtw_hal_set_mcc_setting_chk_start_clnt_join(adapter, &u_ch, &u_bw, &u_offset, chbw_allow)) + goto exit; +#endif + + if (chbw_allow == _TRUE) { + rtw_sync_chbw(&cur_ch, &cur_bw, &cur_ch_offset, &u_ch, &u_bw, &u_offset); + rtw_warn_on(cur_ch != pmlmeext->cur_channel); + rtw_warn_on(cur_bw != pmlmeext->cur_bwmode); + rtw_warn_on(cur_ch_offset != pmlmeext->cur_ch_offset); + goto connect_allow_hdl; + } + +#ifdef CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT + /* chbw_allow is _FALSE, connect allow? */ + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + mlme = &iface->mlmepriv; + mlmeext = &iface->mlmeextpriv; + + if (check_fwstate(mlme, WIFI_STATION_STATE) + && check_fwstate(mlme, WIFI_ASOC_STATE) +#if defined(CONFIG_P2P) + && rtw_p2p_chk_state(&(iface->wdinfo), P2P_STATE_NONE) +#endif + ) { + connect_allow = _FALSE; + break; + } + } +#endif /* CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT */ + + if (MSTATE_STA_LD_NUM(&mstate) + MSTATE_AP_LD_NUM(&mstate) >= 2) + connect_allow = _FALSE; + + RTW_INFO(FUNC_ADPT_FMT" connect_allow:%d\n" + , FUNC_ADPT_ARG(adapter), connect_allow); + + if (connect_allow == _FALSE) + goto exit; + +connect_allow_hdl: + /* connect_allow == _TRUE */ + +#ifdef CONFIG_DFS_MASTER + rtw_dfs_master_status_apply(adapter, MLME_STA_CONNECTING); +#endif + + if (chbw_allow == _FALSE) { + u_ch = cur_ch; + u_bw = cur_bw; + u_offset = cur_ch_offset; + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + mlme = &iface->mlmepriv; + mlmeext = &iface->mlmeextpriv; + + if (!iface || iface == adapter) + continue; + + if (check_fwstate(mlme, WIFI_AP_STATE) + && check_fwstate(mlme, WIFI_ASOC_STATE) + ) { +#ifdef CONFIG_SPCT_CH_SWITCH + if (1) + rtw_ap_inform_ch_switch(iface, pmlmeext->cur_channel , pmlmeext->cur_ch_offset); + else +#endif + rtw_sta_flush(iface, _FALSE); + + rtw_hal_set_hwreg(iface, HW_VAR_CHECK_TXBUF, 0); + set_fwstate(mlme, WIFI_OP_CH_SWITCHING); + } else if (check_fwstate(mlme, WIFI_STATION_STATE) + && check_fwstate(mlme, WIFI_ASOC_STATE) + ) { + rtw_disassoc_cmd(iface, 500, _FALSE); + rtw_indicate_disconnect(iface, 0, _FALSE); + rtw_free_assoc_resources(iface, 1); + } + } + } + } +#endif /* CONFIG_CONCURRENT_MODE */ + +exit: + + if (connect_allow == _TRUE) { + RTW_INFO(FUNC_ADPT_FMT" union: %u,%u,%u\n", FUNC_ADPT_ARG(adapter), u_ch, u_bw, u_offset); + *ch = u_ch; + *bw = u_bw; + *offset = u_offset; + } + + return connect_allow == _TRUE ? _SUCCESS : _FAIL; +} + + +u8 set_ch_hdl(_adapter *padapter, u8 *pbuf) +{ + struct set_ch_parm *set_ch_parm; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + if (!pbuf) + return H2C_PARAMETERS_ERROR; + + set_ch_parm = (struct set_ch_parm *)pbuf; + + RTW_INFO(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n", + FUNC_NDEV_ARG(padapter->pnetdev), + set_ch_parm->ch, set_ch_parm->bw, set_ch_parm->ch_offset); + + pmlmeext->cur_channel = set_ch_parm->ch; + pmlmeext->cur_ch_offset = set_ch_parm->ch_offset; + pmlmeext->cur_bwmode = set_ch_parm->bw; + + set_channel_bwmode(padapter, set_ch_parm->ch, set_ch_parm->ch_offset, set_ch_parm->bw); + + return H2C_SUCCESS; +} + +u8 set_chplan_hdl(_adapter *padapter, unsigned char *pbuf) +{ + struct SetChannelPlan_param *setChannelPlan_param; + struct mlme_priv *mlme = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + if (!pbuf) + return H2C_PARAMETERS_ERROR; + + setChannelPlan_param = (struct SetChannelPlan_param *)pbuf; + + if (!rtw_is_channel_plan_valid(setChannelPlan_param->channel_plan)) + return H2C_PARAMETERS_ERROR; + + mlme->country_ent = setChannelPlan_param->country_ent; + mlme->ChannelPlan = setChannelPlan_param->channel_plan; + + pmlmeext->max_chan_nums = init_channel_set(padapter, setChannelPlan_param->channel_plan, pmlmeext->channel_set); + init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list); + + rtw_hal_set_odm_var(padapter, HAL_ODM_REGULATION, NULL, _TRUE); + +#ifdef CONFIG_IOCTL_CFG80211 + rtw_reg_notify_by_driver(padapter); +#endif /* CONFIG_IOCTL_CFG80211 */ + + return H2C_SUCCESS; +} + +u8 led_blink_hdl(_adapter *padapter, unsigned char *pbuf) +{ + struct LedBlink_param *ledBlink_param; + + if (!pbuf) + return H2C_PARAMETERS_ERROR; + + ledBlink_param = (struct LedBlink_param *)pbuf; + +#ifdef CONFIG_LED_HANDLED_BY_CMD_THREAD + BlinkHandler((PLED_DATA)ledBlink_param->pLed); +#endif + + return H2C_SUCCESS; +} + +u8 set_csa_hdl(_adapter *padapter, unsigned char *pbuf) +{ +#ifdef CONFIG_DFS + struct SetChannelSwitch_param *setChannelSwitch_param; + u8 new_ch_no; + u8 gval8 = 0x00, sval8 = 0xff; + + if (!pbuf) + return H2C_PARAMETERS_ERROR; + + setChannelSwitch_param = (struct SetChannelSwitch_param *)pbuf; + new_ch_no = setChannelSwitch_param->new_ch_no; + + rtw_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, &gval8); + + rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, &sval8); + + RTW_INFO("DFS detected! Swiching channel to %d!\n", new_ch_no); + set_channel_bwmode(padapter, new_ch_no, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); + + rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, &gval8); + + rtw_disassoc_cmd(padapter, 0, _FALSE); + rtw_indicate_disconnect(padapter, 0, _FALSE); + rtw_free_assoc_resources(padapter, 1); + rtw_free_network_queue(padapter, _TRUE); + + if (((new_ch_no >= 52) && (new_ch_no <= 64)) || ((new_ch_no >= 100) && (new_ch_no <= 140))) + RTW_INFO("Switched to DFS band (ch %02x) again!!\n", new_ch_no); + + return H2C_SUCCESS; +#else + return H2C_REJECTED; +#endif /* CONFIG_DFS */ + +} + +u8 tdls_hdl(_adapter *padapter, unsigned char *pbuf) +{ +#ifdef CONFIG_TDLS + _irqL irqL; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; +#ifdef CONFIG_TDLS_CH_SW + struct tdls_ch_switch *pchsw_info = &ptdlsinfo->chsw_info; +#endif + struct TDLSoption_param *TDLSoption; + struct sta_info *ptdls_sta = NULL; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u8 survey_channel, i, min, option; + struct tdls_txmgmt txmgmt; + u32 setchtime, resp_sleep = 0, wait_time; + u8 zaddr[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + u8 ret; + u8 doiqk; + + if (!pbuf) + return H2C_PARAMETERS_ERROR; + + TDLSoption = (struct TDLSoption_param *)pbuf; + option = TDLSoption->option; + + if (!_rtw_memcmp(TDLSoption->addr, zaddr, ETH_ALEN)) { + ptdls_sta = rtw_get_stainfo(&(padapter->stapriv), TDLSoption->addr); + if (ptdls_sta == NULL) + return H2C_REJECTED; + } else { + if (!(option == TDLS_RS_RCR)) + return H2C_REJECTED; + } + + /* _enter_critical_bh(&(ptdlsinfo->hdl_lock), &irqL); */ + /* RTW_INFO("[%s] option:%d\n", __FUNCTION__, option); */ + + switch (option) { + case TDLS_ESTABLISHED: { + /* As long as TDLS handshake success, we should set RCR_CBSSID_DATA bit to 0 */ + /* So we can receive all kinds of data frames. */ + u8 sta_band = 0; + + /* leave ALL PS when TDLS is established */ + rtw_pwr_wakeup(padapter); + + rtw_hal_set_hwreg(padapter, HW_VAR_TDLS_WRCR, 0); + RTW_INFO("Created Direct Link with "MAC_FMT"\n", MAC_ARG(ptdls_sta->hwaddr)); + + /* Set TDLS sta rate. */ + /* Update station supportRate */ + rtw_hal_update_sta_rate_mask(padapter, ptdls_sta); + if (pmlmeext->cur_channel > 14) { + if (ptdls_sta->ra_mask & 0xffff000) + sta_band |= WIRELESS_11_5N ; + + if (ptdls_sta->ra_mask & 0xff0) + sta_band |= WIRELESS_11A; + + /* 5G band */ +#ifdef CONFIG_80211AC_VHT + if (ptdls_sta->vhtpriv.vht_option) + sta_band = WIRELESS_11_5AC; +#endif + + } else { + if (ptdls_sta->ra_mask & 0xffff000) + sta_band |= WIRELESS_11_24N; + + if (ptdls_sta->ra_mask & 0xff0) + sta_band |= WIRELESS_11G; + + if (ptdls_sta->ra_mask & 0x0f) + sta_band |= WIRELESS_11B; + } + ptdls_sta->wireless_mode = sta_band; + ptdls_sta->raid = rtw_hal_networktype_to_raid(padapter, ptdls_sta); + set_sta_rate(padapter, ptdls_sta); + rtw_sta_media_status_rpt(padapter, ptdls_sta, 1); + /* Sta mode */ + rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, ptdls_sta, _TRUE); + break; + } + case TDLS_ISSUE_PTI: + ptdls_sta->tdls_sta_state |= TDLS_WAIT_PTR_STATE; + issue_tdls_peer_traffic_indication(padapter, ptdls_sta); + _set_timer(&ptdls_sta->pti_timer, TDLS_PTI_TIME); + break; +#ifdef CONFIG_TDLS_CH_SW + case TDLS_CH_SW_RESP: + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + txmgmt.status_code = 0; + _rtw_memcpy(txmgmt.peer, ptdls_sta->hwaddr, ETH_ALEN); + + issue_nulldata(padapter, NULL, 1, 3, 3); + + RTW_INFO("[TDLS ] issue tdls channel switch response\n"); + ret = issue_tdls_ch_switch_rsp(padapter, &txmgmt, _TRUE); + + /* If we receive TDLS_CH_SW_REQ at off channel which it's target is AP's channel */ + /* then we just switch to AP's channel*/ + if (padapter->mlmeextpriv.cur_channel == pchsw_info->off_ch_num) { + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_END_TO_BASE_CHNL); + break; + } + + if (ret == _SUCCESS) + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_TO_OFF_CHNL); + else + RTW_INFO("[TDLS] issue_tdls_ch_switch_rsp wait ack fail !!!!!!!!!!\n"); + + break; + case TDLS_CH_SW_PREPARE: + pchsw_info->ch_sw_state |= TDLS_CH_SWITCH_PREPARE_STATE; + + /* to collect IQK info of off-chnl */ + doiqk = _TRUE; + rtw_hal_set_hwreg(padapter, HW_VAR_DO_IQK, &doiqk); + set_channel_bwmode(padapter, pchsw_info->off_ch_num, pchsw_info->ch_offset, (pchsw_info->ch_offset) ? CHANNEL_WIDTH_40 : CHANNEL_WIDTH_20); + doiqk = _FALSE; + rtw_hal_set_hwreg(padapter, HW_VAR_DO_IQK, &doiqk); + + /* switch back to base-chnl */ + set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_START); + + pchsw_info->ch_sw_state &= ~(TDLS_CH_SWITCH_PREPARE_STATE); + + break; + case TDLS_CH_SW_START: + rtw_tdls_set_ch_sw_oper_control(padapter, _TRUE); + break; + case TDLS_CH_SW_TO_OFF_CHNL: + issue_nulldata(padapter, NULL, 1, 3, 3); + + if (!(pchsw_info->ch_sw_state & TDLS_CH_SW_INITIATOR_STATE)) + _set_timer(&ptdls_sta->ch_sw_timer, (u32)(ptdls_sta->ch_switch_timeout) / 1000); + + if (rtw_tdls_do_ch_sw(padapter, ptdls_sta, TDLS_CH_SW_OFF_CHNL, pchsw_info->off_ch_num, + pchsw_info->ch_offset, (pchsw_info->ch_offset) ? CHANNEL_WIDTH_40 : CHANNEL_WIDTH_20, ptdls_sta->ch_switch_time) == _SUCCESS) { + pchsw_info->ch_sw_state &= ~(TDLS_PEER_AT_OFF_STATE); + if (pchsw_info->ch_sw_state & TDLS_CH_SW_INITIATOR_STATE) { + if (issue_nulldata_to_TDLS_peer_STA(ptdls_sta->padapter, ptdls_sta->hwaddr, 0, 1, 3) == _FAIL) + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_TO_BASE_CHNL); + } + } else { + u8 bcancelled; + + if (!(pchsw_info->ch_sw_state & TDLS_CH_SW_INITIATOR_STATE)) + _cancel_timer(&ptdls_sta->ch_sw_timer, &bcancelled); + } + + + break; + case TDLS_CH_SW_END: + case TDLS_CH_SW_END_TO_BASE_CHNL: + rtw_tdls_set_ch_sw_oper_control(padapter, _FALSE); + _cancel_timer_ex(&ptdls_sta->ch_sw_timer); + _cancel_timer_ex(&ptdls_sta->stay_on_base_chnl_timer); + _cancel_timer_ex(&ptdls_sta->ch_sw_monitor_timer); +#if 0 + _rtw_memset(pHalData->tdls_ch_sw_iqk_info_base_chnl, 0x00, sizeof(pHalData->tdls_ch_sw_iqk_info_base_chnl)); + _rtw_memset(pHalData->tdls_ch_sw_iqk_info_off_chnl, 0x00, sizeof(pHalData->tdls_ch_sw_iqk_info_off_chnl)); +#endif + + if (option == TDLS_CH_SW_END_TO_BASE_CHNL) + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_TO_BASE_CHNL); + + break; + case TDLS_CH_SW_TO_BASE_CHNL_UNSOLICITED: + case TDLS_CH_SW_TO_BASE_CHNL: + pchsw_info->ch_sw_state &= ~(TDLS_PEER_AT_OFF_STATE | TDLS_WAIT_CH_RSP_STATE); + + if (option == TDLS_CH_SW_TO_BASE_CHNL_UNSOLICITED) { + if (ptdls_sta != NULL) { + /* Send unsolicited channel switch rsp. to peer */ + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + txmgmt.status_code = 0; + _rtw_memcpy(txmgmt.peer, ptdls_sta->hwaddr, ETH_ALEN); + issue_tdls_ch_switch_rsp(padapter, &txmgmt, _FALSE); + } + } + + if (rtw_tdls_do_ch_sw(padapter, ptdls_sta, TDLS_CH_SW_BASE_CHNL, pmlmeext->cur_channel, + pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode, ptdls_sta->ch_switch_time) == _SUCCESS) { + issue_nulldata(padapter, NULL, 0, 3, 3); + /* set ch sw monitor timer for responder */ + if (!(pchsw_info->ch_sw_state & TDLS_CH_SW_INITIATOR_STATE)) + _set_timer(&ptdls_sta->ch_sw_monitor_timer, TDLS_CH_SW_MONITOR_TIMEOUT); + } + + break; +#endif + case TDLS_RS_RCR: + rtw_hal_set_hwreg(padapter, HW_VAR_TDLS_RS_RCR, 0); + RTW_INFO("[TDLS] write REG_RCR, set bit6 on\n"); + break; + case TDLS_TEARDOWN_STA: + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + txmgmt.status_code = 0; + _rtw_memcpy(txmgmt.peer, ptdls_sta->hwaddr, ETH_ALEN); + + issue_tdls_teardown(padapter, &txmgmt, _TRUE); + break; + case TDLS_TEARDOWN_STA_LOCALLY: +#ifdef CONFIG_TDLS_CH_SW + if (_rtw_memcmp(TDLSoption->addr, pchsw_info->addr, ETH_ALEN) == _TRUE) { + pchsw_info->ch_sw_state &= ~(TDLS_CH_SW_INITIATOR_STATE | + TDLS_CH_SWITCH_ON_STATE | + TDLS_PEER_AT_OFF_STATE); + rtw_tdls_set_ch_sw_oper_control(padapter, _FALSE); + _rtw_memset(pchsw_info->addr, 0x00, ETH_ALEN); + } +#endif + rtw_sta_media_status_rpt(padapter, ptdls_sta, 0); + free_tdls_sta(padapter, ptdls_sta); + break; + } + + /* _exit_critical_bh(&(ptdlsinfo->hdl_lock), &irqL); */ + + return H2C_SUCCESS; +#else + return H2C_REJECTED; +#endif /* CONFIG_TDLS */ + +} + +u8 run_in_thread_hdl(_adapter *padapter, u8 *pbuf) +{ + struct RunInThread_param *p; + + + if (NULL == pbuf) + return H2C_PARAMETERS_ERROR; + p = (struct RunInThread_param *)pbuf; + + if (p->func) + p->func(p->context); + + return H2C_SUCCESS; +} + +u8 rtw_getmacreg_hdl(_adapter *padapter, u8 *pbuf) +{ + + struct readMAC_parm *preadmacparm = NULL; + u8 sz = 0; + u32 addr = 0; + u32 value = 0; + + if (!pbuf) + return H2C_PARAMETERS_ERROR; + + preadmacparm = (struct readMAC_parm *) pbuf; + sz = preadmacparm->len; + addr = preadmacparm->addr; + value = 0; + + switch (sz) { + case 1: + value = rtw_read8(padapter, addr); + break; + case 2: + value = rtw_read16(padapter, addr); + break; + case 4: + value = rtw_read32(padapter, addr); + break; + default: + RTW_INFO("%s: Unknown size\n", __func__); + break; + } + RTW_INFO("%s: addr:0x%02x valeu:0x%02x\n", __func__, addr, value); + + return H2C_SUCCESS; +} diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_mp.c b/linux-bsp/drivers/rtl8188eus/core/rtw_mp.c new file mode 100644 index 0000000..ec39412 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_mp.c @@ -0,0 +1,3569 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_MP_C_ +#include <drv_types.h> +#ifdef PLATFORM_FREEBSD + #include <sys/unistd.h> /* for RFHIGHPID */ +#endif + +#include "../hal/phydm/phydm_precomp.h" +#if defined(CONFIG_RTL8723B) || defined(CONFIG_RTL8821A) + #include <rtw_bt_mp.h> +#endif + +#ifdef CONFIG_MP_VHT_HW_TX_MODE +#define CEILING_POS(X) ((X - (int)(X)) > 0 ? (int)(X + 1) : (int)(X)) +#define CEILING_NEG(X) ((X - (int)(X)) < 0 ? (int)(X - 1) : (int)(X)) +#define ceil(X) (((X) > 0) ? CEILING_POS(X) : CEILING_NEG(X)) + +int rtfloor(float x) +{ + int i = x - 2; + while + (++i <= x - 1) + ; + return i; +} +#endif + +#ifdef CONFIG_MP_INCLUDED +u32 read_macreg(_adapter *padapter, u32 addr, u32 sz) +{ + u32 val = 0; + + switch (sz) { + case 1: + val = rtw_read8(padapter, addr); + break; + case 2: + val = rtw_read16(padapter, addr); + break; + case 4: + val = rtw_read32(padapter, addr); + break; + default: + val = 0xffffffff; + break; + } + + return val; + +} + +void write_macreg(_adapter *padapter, u32 addr, u32 val, u32 sz) +{ + switch (sz) { + case 1: + rtw_write8(padapter, addr, (u8)val); + break; + case 2: + rtw_write16(padapter, addr, (u16)val); + break; + case 4: + rtw_write32(padapter, addr, val); + break; + default: + break; + } + +} + +u32 read_bbreg(_adapter *padapter, u32 addr, u32 bitmask) +{ + return rtw_hal_read_bbreg(padapter, addr, bitmask); +} + +void write_bbreg(_adapter *padapter, u32 addr, u32 bitmask, u32 val) +{ + rtw_hal_write_bbreg(padapter, addr, bitmask, val); +} + +u32 _read_rfreg(PADAPTER padapter, u8 rfpath, u32 addr, u32 bitmask) +{ + return rtw_hal_read_rfreg(padapter, rfpath, addr, bitmask); +} + +void _write_rfreg(PADAPTER padapter, u8 rfpath, u32 addr, u32 bitmask, u32 val) +{ + rtw_hal_write_rfreg(padapter, rfpath, addr, bitmask, val); +} + +u32 read_rfreg(PADAPTER padapter, u8 rfpath, u32 addr) +{ + return _read_rfreg(padapter, rfpath, addr, bRFRegOffsetMask); +} + +void write_rfreg(PADAPTER padapter, u8 rfpath, u32 addr, u32 val) +{ + _write_rfreg(padapter, rfpath, addr, bRFRegOffsetMask, val); +} + +static void _init_mp_priv_(struct mp_priv *pmp_priv) +{ + WLAN_BSSID_EX *pnetwork; + + _rtw_memset(pmp_priv, 0, sizeof(struct mp_priv)); + + pmp_priv->mode = MP_OFF; + + pmp_priv->channel = 1; + pmp_priv->bandwidth = CHANNEL_WIDTH_20; + pmp_priv->prime_channel_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + pmp_priv->rateidx = RATE_1M; + pmp_priv->txpoweridx = 0x2A; + + pmp_priv->antenna_tx = ANTENNA_A; + pmp_priv->antenna_rx = ANTENNA_AB; + + pmp_priv->check_mp_pkt = 0; + + pmp_priv->tx_pktcount = 0; + + pmp_priv->rx_bssidpktcount = 0; + pmp_priv->rx_pktcount = 0; + pmp_priv->rx_crcerrpktcount = 0; + + pmp_priv->network_macaddr[0] = 0x00; + pmp_priv->network_macaddr[1] = 0xE0; + pmp_priv->network_macaddr[2] = 0x4C; + pmp_priv->network_macaddr[3] = 0x87; + pmp_priv->network_macaddr[4] = 0x66; + pmp_priv->network_macaddr[5] = 0x55; + + pmp_priv->bSetRxBssid = _FALSE; + pmp_priv->bRTWSmbCfg = _FALSE; + pmp_priv->bloopback = _FALSE; + + pmp_priv->bloadefusemap = _FALSE; + + pnetwork = &pmp_priv->mp_network.network; + _rtw_memcpy(pnetwork->MacAddress, pmp_priv->network_macaddr, ETH_ALEN); + + pnetwork->Ssid.SsidLength = 8; + _rtw_memcpy(pnetwork->Ssid.Ssid, "mp_871x", pnetwork->Ssid.SsidLength); + + pmp_priv->tx.payload = 2; +#ifdef CONFIG_80211N_HT + pmp_priv->tx.attrib.ht_en = 1; +#endif + +} + +#ifdef PLATFORM_WINDOWS +#if 0 +void mp_wi_callback( + IN NDIS_WORK_ITEM *pwk_item, + IN PVOID cntx +) +{ + _adapter *padapter = (_adapter *)cntx; + struct mp_priv *pmppriv = &padapter->mppriv; + struct mp_wi_cntx *pmp_wi_cntx = &pmppriv->wi_cntx; + + /* Execute specified action. */ + if (pmp_wi_cntx->curractfunc != NULL) { + LARGE_INTEGER cur_time; + ULONGLONG start_time, end_time; + NdisGetCurrentSystemTime(&cur_time); /* driver version */ + start_time = cur_time.QuadPart / 10; /* The return value is in microsecond */ + + pmp_wi_cntx->curractfunc(padapter); + + NdisGetCurrentSystemTime(&cur_time); /* driver version */ + end_time = cur_time.QuadPart / 10; /* The return value is in microsecond */ + + } + + NdisAcquireSpinLock(&(pmp_wi_cntx->mp_wi_lock)); + pmp_wi_cntx->bmp_wi_progress = _FALSE; + NdisReleaseSpinLock(&(pmp_wi_cntx->mp_wi_lock)); + + if (pmp_wi_cntx->bmpdrv_unload) + NdisSetEvent(&(pmp_wi_cntx->mp_wi_evt)); + +} +#endif + +static int init_mp_priv_by_os(struct mp_priv *pmp_priv) +{ + struct mp_wi_cntx *pmp_wi_cntx; + + if (pmp_priv == NULL) + return _FAIL; + + pmp_priv->rx_testcnt = 0; + pmp_priv->rx_testcnt1 = 0; + pmp_priv->rx_testcnt2 = 0; + + pmp_priv->tx_testcnt = 0; + pmp_priv->tx_testcnt1 = 0; + + pmp_wi_cntx = &pmp_priv->wi_cntx + pmp_wi_cntx->bmpdrv_unload = _FALSE; + pmp_wi_cntx->bmp_wi_progress = _FALSE; + pmp_wi_cntx->curractfunc = NULL; + + return _SUCCESS; +} +#endif + +#ifdef PLATFORM_LINUX +static int init_mp_priv_by_os(struct mp_priv *pmp_priv) +{ + int i, res; + struct mp_xmit_frame *pmp_xmitframe; + + if (pmp_priv == NULL) + return _FAIL; + + _rtw_init_queue(&pmp_priv->free_mp_xmitqueue); + + pmp_priv->pallocated_mp_xmitframe_buf = NULL; + pmp_priv->pallocated_mp_xmitframe_buf = rtw_zmalloc(NR_MP_XMITFRAME * sizeof(struct mp_xmit_frame) + 4); + if (pmp_priv->pallocated_mp_xmitframe_buf == NULL) { + res = _FAIL; + goto _exit_init_mp_priv; + } + + pmp_priv->pmp_xmtframe_buf = pmp_priv->pallocated_mp_xmitframe_buf + 4 - ((SIZE_PTR)(pmp_priv->pallocated_mp_xmitframe_buf) & 3); + + pmp_xmitframe = (struct mp_xmit_frame *)pmp_priv->pmp_xmtframe_buf; + + for (i = 0; i < NR_MP_XMITFRAME; i++) { + _rtw_init_listhead(&pmp_xmitframe->list); + rtw_list_insert_tail(&pmp_xmitframe->list, &pmp_priv->free_mp_xmitqueue.queue); + + pmp_xmitframe->pkt = NULL; + pmp_xmitframe->frame_tag = MP_FRAMETAG; + pmp_xmitframe->padapter = pmp_priv->papdater; + + pmp_xmitframe++; + } + + pmp_priv->free_mp_xmitframe_cnt = NR_MP_XMITFRAME; + + res = _SUCCESS; + +_exit_init_mp_priv: + + return res; +} +#endif + +static void mp_init_xmit_attrib(struct mp_tx *pmptx, PADAPTER padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + struct pkt_attrib *pattrib; + + /* init xmitframe attribute */ + pattrib = &pmptx->attrib; + _rtw_memset(pattrib, 0, sizeof(struct pkt_attrib)); + _rtw_memset(pmptx->desc, 0, TXDESC_SIZE); + + pattrib->ether_type = 0x8712; +#if 0 + _rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); +#endif + _rtw_memset(pattrib->dst, 0xFF, ETH_ALEN); + + /* pattrib->dhcp_pkt = 0; + * pattrib->pktlen = 0; */ + pattrib->ack_policy = 0; + /* pattrib->pkt_hdrlen = ETH_HLEN; */ + pattrib->hdrlen = WLAN_HDR_A3_LEN; + pattrib->subtype = WIFI_DATA; + pattrib->priority = 0; + pattrib->qsel = pattrib->priority; + /* do_queue_select(padapter, pattrib); */ + pattrib->nr_frags = 1; + pattrib->encrypt = 0; + pattrib->bswenc = _FALSE; + pattrib->qos_en = _FALSE; + + pattrib->pktlen = 1500; + +#ifdef CONFIG_80211AC_VHT + if (pHalData->rf_type == RF_1T1R) + pattrib->raid = RATEID_IDX_VHT_1SS; + else if (pHalData->rf_type == RF_2T2R || pHalData->rf_type == RF_2T4R) + pattrib->raid = RATEID_IDX_VHT_2SS; + else if (pHalData->rf_type == RF_3T3R) + pattrib->raid = RATEID_IDX_VHT_3SS; + else + pattrib->raid = RATEID_IDX_BGN_40M_1SS; +#endif +} + +s32 init_mp_priv(PADAPTER padapter) +{ + struct mp_priv *pmppriv = &padapter->mppriv; + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + + _init_mp_priv_(pmppriv); + pmppriv->papdater = padapter; + pmppriv->mp_dm = 0; + pmppriv->tx.stop = 1; + pmppriv->bSetTxPower = 0; /*for manually set tx power*/ + pmppriv->bTxBufCkFail = _FALSE; + pmppriv->pktInterval = 0; + pmppriv->pktLength = 1000; + + mp_init_xmit_attrib(&pmppriv->tx, padapter); + + switch (padapter->registrypriv.rf_config) { + case RF_1T1R: + pmppriv->antenna_tx = ANTENNA_A; + pmppriv->antenna_rx = ANTENNA_A; + break; + case RF_1T2R: + default: + pmppriv->antenna_tx = ANTENNA_A; + pmppriv->antenna_rx = ANTENNA_AB; + break; + case RF_2T2R: + case RF_2T2R_GREEN: + pmppriv->antenna_tx = ANTENNA_AB; + pmppriv->antenna_rx = ANTENNA_AB; + break; + case RF_2T4R: + pmppriv->antenna_tx = ANTENNA_BC; + pmppriv->antenna_rx = ANTENNA_ABCD; + break; + } + + pHalData->AntennaRxPath = pmppriv->antenna_rx; + pHalData->antenna_tx_path = pmppriv->antenna_tx; + + return _SUCCESS; +} + +void free_mp_priv(struct mp_priv *pmp_priv) +{ + if (pmp_priv->pallocated_mp_xmitframe_buf) { + rtw_mfree(pmp_priv->pallocated_mp_xmitframe_buf, 0); + pmp_priv->pallocated_mp_xmitframe_buf = NULL; + } + pmp_priv->pmp_xmtframe_buf = NULL; +} + + +static VOID PHY_IQCalibrate_default( + IN PADAPTER pAdapter, + IN BOOLEAN bReCovery +) +{ + RTW_INFO("%s\n", __func__); +} + +static VOID PHY_LCCalibrate_default( + IN PADAPTER pAdapter +) +{ + RTW_INFO("%s\n", __func__); +} + +static VOID PHY_SetRFPathSwitch_default( + IN PADAPTER pAdapter, + IN BOOLEAN bMain +) +{ + RTW_INFO("%s\n", __func__); +} + + +void mpt_InitHWConfig(PADAPTER Adapter) +{ + if (IS_HARDWARE_TYPE_8723B(Adapter)) { + /* TODO: <20130114, Kordan> The following setting is only for DPDT and Fixed board type. */ + /* TODO: A better solution is configure it according EFUSE during the run-time. */ + + phy_set_mac_reg(Adapter, 0x64, BIT20, 0x0); /* 0x66[4]=0 */ + phy_set_mac_reg(Adapter, 0x64, BIT24, 0x0); /* 0x66[8]=0 */ + phy_set_mac_reg(Adapter, 0x40, BIT4, 0x0); /* 0x40[4]=0 */ + phy_set_mac_reg(Adapter, 0x40, BIT3, 0x1); /* 0x40[3]=1 */ + phy_set_mac_reg(Adapter, 0x4C, BIT24, 0x1); /* 0x4C[24:23]=10 */ + phy_set_mac_reg(Adapter, 0x4C, BIT23, 0x0); /* 0x4C[24:23]=10 */ + phy_set_bb_reg(Adapter, 0x944, BIT1 | BIT0, 0x3); /* 0x944[1:0]=11 */ + phy_set_bb_reg(Adapter, 0x930, bMaskByte0, 0x77);/* 0x930[7:0]=77 */ + phy_set_mac_reg(Adapter, 0x38, BIT11, 0x1);/* 0x38[11]=1 */ + + /* TODO: <20130206, Kordan> The default setting is wrong, hard-coded here. */ + phy_set_mac_reg(Adapter, 0x778, 0x3, 0x3); /* Turn off hardware PTA control (Asked by Scott) */ + phy_set_mac_reg(Adapter, 0x64, bMaskDWord, 0x36000000);/* Fix BT S0/S1 */ + phy_set_mac_reg(Adapter, 0x948, bMaskDWord, 0x0); /* Fix BT can't Tx */ + + /* <20130522, Kordan> Turn off equalizer to improve Rx sensitivity. (Asked by EEChou) */ + phy_set_bb_reg(Adapter, 0xA00, BIT8, 0x0); /*0xA01[0] = 0*/ + } else if (IS_HARDWARE_TYPE_8821(Adapter)) { + /* <20131121, VincentL> Add for 8821AU DPDT setting and fix switching antenna issue (Asked by Rock) + <20131122, VincentL> Enable for all 8821A/8811AU (Asked by Alex)*/ + phy_set_mac_reg(Adapter, 0x4C, BIT23, 0x0); /*0x4C[23:22]=01*/ + phy_set_mac_reg(Adapter, 0x4C, BIT22, 0x1); /*0x4C[23:22]=01*/ + } else if (IS_HARDWARE_TYPE_8188ES(Adapter)) + phy_set_mac_reg(Adapter, 0x4C , BIT23, 0); /*select DPDT_P and DPDT_N as output pin*/ +#ifdef CONFIG_RTL8814A + else if (IS_HARDWARE_TYPE_8814A(Adapter)) + PlatformEFIOWrite2Byte(Adapter, REG_RXFLTMAP1_8814A, 0x2000); +#endif +#ifdef CONFIG_RTL8822B + else if (IS_HARDWARE_TYPE_8822B(Adapter)) { + u32 tmp_reg = 0; + + PlatformEFIOWrite2Byte(Adapter, REG_RXFLTMAP1_8822B, 0x2000); + /* fixed wifi can't 2.4g tx suggest by Szuyitasi 20160504 */ + phy_set_bb_reg(Adapter, 0x70, bMaskByte3, 0x0e); + RTW_INFO(" 0x73 = 0x%x\n", phy_query_bb_reg(Adapter, 0x70, bMaskByte3)); + phy_set_bb_reg(Adapter, 0x1704, bMaskDWord, 0x0000ff00); + RTW_INFO(" 0x1704 = 0x%x\n", phy_query_bb_reg(Adapter, 0x1704, bMaskDWord)); + phy_set_bb_reg(Adapter, 0x1700, bMaskDWord, 0xc00f0038); + RTW_INFO(" 0x1700 = 0x%x\n", phy_query_bb_reg(Adapter, 0x1700, bMaskDWord)); + } +#endif /* CONFIG_RTL8822B */ +#ifdef CONFIG_RTL8821C + else if (IS_HARDWARE_TYPE_8821C(Adapter)) + PlatformEFIOWrite2Byte(Adapter, REG_RXFLTMAP1_8821C, 0x2000); +#endif /* CONFIG_RTL8821C */ +} + +static void PHY_IQCalibrate(PADAPTER padapter, u8 bReCovery) +{ + PHAL_DATA_TYPE pHalData; + u8 b2ant; /* false:1ant, true:2-ant */ + u8 RF_Path; /* 0:S1, 1:S0 */ + + if (IS_HARDWARE_TYPE_8723B(padapter)) { +#ifdef CONFIG_RTL8723B + pHalData = GET_HAL_DATA(padapter); + b2ant = pHalData->EEPROMBluetoothAntNum == Ant_x2 ? _TRUE : _FALSE; + phy_iq_calibrate_8723b(padapter, bReCovery, _FALSE, b2ant, pHalData->ant_path); +#endif + } else if (IS_HARDWARE_TYPE_8188E(padapter)) { +#ifdef CONFIG_RTL8188E + phy_iq_calibrate_8188e(padapter, bReCovery); +#endif + } else if (IS_HARDWARE_TYPE_8814A(padapter)) { +#ifdef CONFIG_RTL8814A + phy_iq_calibrate_8814a(&(GET_HAL_DATA(padapter)->odmpriv), bReCovery); +#endif + } else if (IS_HARDWARE_TYPE_8812(padapter)) { +#ifdef CONFIG_RTL8812A + phy_iq_calibrate_8812a(padapter, bReCovery); +#endif + } else if (IS_HARDWARE_TYPE_8821(padapter)) { +#ifdef CONFIG_RTL8821A + phy_iq_calibrate_8821a(&(GET_HAL_DATA(padapter)->odmpriv), bReCovery); +#endif + } else if (IS_HARDWARE_TYPE_8192E(padapter)) { +#ifdef CONFIG_RTL8192E + phy_iq_calibrate_8192e(padapter, bReCovery); +#endif + } else if (IS_HARDWARE_TYPE_8703B(padapter)) { +#ifdef CONFIG_RTL8703B + phy_iq_calibrate_8703b(padapter, bReCovery); +#endif + } else if (IS_HARDWARE_TYPE_8188F(padapter)) { +#ifdef CONFIG_RTL8188F + phy_iq_calibrate_8188f(padapter, bReCovery, _FALSE); +#endif + } else if (IS_HARDWARE_TYPE_8822B(padapter)) { +#ifdef CONFIG_RTL8822B + phy_iq_calibrate_8822b(&(GET_HAL_DATA(padapter)->odmpriv), bReCovery); +#endif + } else if (IS_HARDWARE_TYPE_8723D(padapter)) { +#ifdef CONFIG_RTL8723D + phy_iq_calibrate_8723d(padapter, bReCovery); +#endif + } else if (IS_HARDWARE_TYPE_8821C(padapter)) { +#ifdef CONFIG_RTL8821C + phy_iq_calibrate_8821c(&(GET_HAL_DATA(padapter)->odmpriv), bReCovery); +#endif + } + +} + +static void PHY_LCCalibrate(PADAPTER padapter) +{ + if (IS_HARDWARE_TYPE_8723B(padapter)) { +#ifdef CONFIG_RTL8723B + phy_lc_calibrate_8723b(&(GET_HAL_DATA(padapter)->odmpriv)); +#endif + } else if (IS_HARDWARE_TYPE_8188E(padapter)) { +#ifdef CONFIG_RTL8188E + phy_lc_calibrate_8188e(&(GET_HAL_DATA(padapter)->odmpriv)); +#endif + } else if (IS_HARDWARE_TYPE_8814A(padapter)) { +#ifdef CONFIG_RTL8814A + phy_lc_calibrate_8814a(&(GET_HAL_DATA(padapter)->odmpriv)); +#endif + } else if (IS_HARDWARE_TYPE_8812(padapter)) { +#ifdef CONFIG_RTL8812A + phy_lc_calibrate_8812a(&(GET_HAL_DATA(padapter)->odmpriv)); +#endif + } else if (IS_HARDWARE_TYPE_8821(padapter)) { +#ifdef CONFIG_RTL8821A + phy_lc_calibrate_8821a(&(GET_HAL_DATA(padapter)->odmpriv)); +#endif + } else if (IS_HARDWARE_TYPE_8192E(padapter)) { +#ifdef CONFIG_RTL8192E + phy_lc_calibrate_8192e(&(GET_HAL_DATA(padapter)->odmpriv)); +#endif + } else if (IS_HARDWARE_TYPE_8703B(padapter)) { +#ifdef CONFIG_RTL8703B + phy_lc_calibrate_8703b(&(GET_HAL_DATA(padapter)->odmpriv)); +#endif + } else if (IS_HARDWARE_TYPE_8188F(padapter)) { +#ifdef CONFIG_RTL8188F + phy_lc_calibrate_8188f(&(GET_HAL_DATA(padapter)->odmpriv)); +#endif + } else if (IS_HARDWARE_TYPE_8822B(padapter)) { +#ifdef CONFIG_RTL8822B + phy_lc_calibrate_8822b(&(GET_HAL_DATA(padapter)->odmpriv)); +#endif + } else if (IS_HARDWARE_TYPE_8723D(padapter)) { +#ifdef CONFIG_RTL8723D + phy_lc_calibrate_8723d(&(GET_HAL_DATA(padapter)->odmpriv)); +#endif + } else if (IS_HARDWARE_TYPE_8821C(padapter)) { +#ifdef CONFIG_RTL8821C + /*phy_iq_calibrate_8821c(&(GET_HAL_DATA(padapter)->odmpriv));*/ +#endif + } + +} + +static u8 PHY_QueryRFPathSwitch(PADAPTER padapter) +{ + u8 bmain = 0; +/* + if (IS_HARDWARE_TYPE_8723B(padapter)) { +#ifdef CONFIG_RTL8723B + bmain = PHY_QueryRFPathSwitch_8723B(padapter); +#endif + } else if (IS_HARDWARE_TYPE_8188E(padapter)) { +#ifdef CONFIG_RTL8188E + bmain = PHY_QueryRFPathSwitch_8188E(padapter); +#endif + } else if (IS_HARDWARE_TYPE_8814A(padapter)) { +#ifdef CONFIG_RTL8814A + bmain = PHY_QueryRFPathSwitch_8814A(padapter); +#endif + } else if (IS_HARDWARE_TYPE_8812(padapter) || IS_HARDWARE_TYPE_8821(padapter)) { +#if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) + bmain = PHY_QueryRFPathSwitch_8812A(padapter); +#endif + } else if (IS_HARDWARE_TYPE_8192E(padapter)) { +#ifdef CONFIG_RTL8192E + bmain = PHY_QueryRFPathSwitch_8192E(padapter); +#endif + } else if (IS_HARDWARE_TYPE_8703B(padapter)) { +#ifdef CONFIG_RTL8703B + bmain = PHY_QueryRFPathSwitch_8703B(padapter); +#endif + } else if (IS_HARDWARE_TYPE_8188F(padapter)) { +#ifdef CONFIG_RTL8188F + bmain = PHY_QueryRFPathSwitch_8188F(padapter); +#endif + } else if (IS_HARDWARE_TYPE_8822B(padapter)) { +#ifdef CONFIG_RTL8822B + bmain = PHY_QueryRFPathSwitch_8822B(padapter); +#endif + } else if (IS_HARDWARE_TYPE_8723D(padapter)) { +#ifdef CONFIG_RTL8723D + bmain = PHY_QueryRFPathSwitch_8723D(padapter); +#endif + } else +*/ + + if (IS_HARDWARE_TYPE_8821C(padapter)) { +#ifdef CONFIG_RTL8821C + bmain = phy_query_rf_path_switch_8821c(padapter); +#endif + } + + return bmain; +} + +static void PHY_SetRFPathSwitch(PADAPTER padapter , BOOLEAN bMain) { + + if (IS_HARDWARE_TYPE_8723B(padapter)) { +#ifdef CONFIG_RTL8723B + phy_set_rf_path_switch_8723b(padapter, bMain); +#endif + } else if (IS_HARDWARE_TYPE_8188E(padapter)) { +#ifdef CONFIG_RTL8188E + phy_set_rf_path_switch_8188e(padapter, bMain); +#endif + } else if (IS_HARDWARE_TYPE_8814A(padapter)) { +#ifdef CONFIG_RTL8814A + phy_set_rf_path_switch_8814a(padapter, bMain); +#endif + } else if (IS_HARDWARE_TYPE_8812(padapter) || IS_HARDWARE_TYPE_8821(padapter)) { +#if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) + phy_set_rf_path_switch_8812a(padapter, bMain); +#endif + } else if (IS_HARDWARE_TYPE_8192E(padapter)) { +#ifdef CONFIG_RTL8192E + phy_set_rf_path_switch_8192e(padapter, bMain); +#endif + } else if (IS_HARDWARE_TYPE_8703B(padapter)) { +#ifdef CONFIG_RTL8703B + phy_set_rf_path_switch_8703b(padapter, bMain); +#endif + } else if (IS_HARDWARE_TYPE_8188F(padapter)) { +#ifdef CONFIG_RTL8188F + phy_set_rf_path_switch_8188f(padapter, bMain); +#endif + } else if (IS_HARDWARE_TYPE_8822B(padapter)) { +#ifdef CONFIG_RTL8822B + phy_set_rf_path_switch_8822b(padapter, bMain); +#endif + } else if (IS_HARDWARE_TYPE_8723D(padapter)) { +#ifdef CONFIG_RTL8723D + phy_set_rf_path_switch_8723d(padapter, bMain); +#endif + } else if (IS_HARDWARE_TYPE_8821C(padapter)) { +#ifdef CONFIG_RTL8821C + phy_set_rf_path_switch_8821c(padapter, bMain); +#endif + } +} + +s32 +MPT_InitializeAdapter( + IN PADAPTER pAdapter, + IN u8 Channel +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + s32 rtStatus = _SUCCESS; + PMPT_CONTEXT pMptCtx = &pAdapter->mppriv.mpt_ctx; + u32 ledsetting; + struct mlme_priv *pmlmepriv = &pAdapter->mlmepriv; + + pMptCtx->bMptDrvUnload = _FALSE; + pMptCtx->bMassProdTest = _FALSE; + pMptCtx->bMptIndexEven = _TRUE; /* default gain index is -6.0db */ + pMptCtx->h2cReqNum = 0x0; + /* init for BT MP */ +#if defined(CONFIG_RTL8723B) + pMptCtx->bMPh2c_timeout = _FALSE; + pMptCtx->MptH2cRspEvent = _FALSE; + pMptCtx->MptBtC2hEvent = _FALSE; + _rtw_init_sema(&pMptCtx->MPh2c_Sema, 0); + _init_timer(&pMptCtx->MPh2c_timeout_timer, pAdapter->pnetdev, MPh2c_timeout_handle, pAdapter); +#endif + + mpt_InitHWConfig(pAdapter); + +#ifdef CONFIG_RTL8723B + rtl8723b_InitAntenna_Selection(pAdapter); + if (IS_HARDWARE_TYPE_8723B(pAdapter)) { + + /* <20130522, Kordan> Turn off equalizer to improve Rx sensitivity. (Asked by EEChou)*/ + phy_set_bb_reg(pAdapter, 0xA00, BIT8, 0x0); + PHY_SetRFPathSwitch(pAdapter, 1/*pHalData->bDefaultAntenna*/); /*default use Main*/ + /*<20130522, Kordan> 0x51 and 0x71 should be set immediately after path switched, or they might be overwritten. */ + if ((pHalData->PackageType == PACKAGE_TFBGA79) || (pHalData->PackageType == PACKAGE_TFBGA90)) + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x51, bRFRegOffsetMask, 0x6B10E); + else + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x51, bRFRegOffsetMask, 0x6B04E); + } + /*set ant to wifi side in mp mode*/ + rtw_write16(pAdapter, 0x870, 0x300); + rtw_write16(pAdapter, 0x860, 0x110); +#endif + + pMptCtx->bMptWorkItemInProgress = _FALSE; + pMptCtx->CurrMptAct = NULL; + pMptCtx->mpt_rf_path = ODM_RF_PATH_A; + /* ------------------------------------------------------------------------- */ + /* Don't accept any packets */ + rtw_write32(pAdapter, REG_RCR, 0); + + /* ledsetting = rtw_read32(pAdapter, REG_LEDCFG0); */ + /* rtw_write32(pAdapter, REG_LEDCFG0, ledsetting & ~LED0DIS); */ + + /* rtw_write32(pAdapter, REG_LEDCFG0, 0x08080); */ + ledsetting = rtw_read32(pAdapter, REG_LEDCFG0); + + + PHY_LCCalibrate(pAdapter); + PHY_IQCalibrate(pAdapter, _FALSE); + /* dm_check_txpowertracking(&pHalData->odmpriv); */ /* trigger thermal meter */ + + PHY_SetRFPathSwitch(pAdapter, 1/*pHalData->bDefaultAntenna*/); /* default use Main */ + + pMptCtx->backup0xc50 = (u1Byte)phy_query_bb_reg(pAdapter, rOFDM0_XAAGCCore1, bMaskByte0); + pMptCtx->backup0xc58 = (u1Byte)phy_query_bb_reg(pAdapter, rOFDM0_XBAGCCore1, bMaskByte0); + pMptCtx->backup0xc30 = (u1Byte)phy_query_bb_reg(pAdapter, rOFDM0_RxDetector1, bMaskByte0); + pMptCtx->backup0x52_RF_A = (u1Byte)phy_query_rf_reg(pAdapter, RF_PATH_A, RF_0x52, 0x000F0); + pMptCtx->backup0x52_RF_B = (u1Byte)phy_query_rf_reg(pAdapter, RF_PATH_B, RF_0x52, 0x000F0); +#ifdef CONFIG_RTL8188E + rtw_write32(pAdapter, REG_MACID_NO_LINK_0, 0x0); + rtw_write32(pAdapter, REG_MACID_NO_LINK_1, 0x0); +#endif +#ifdef CONFIG_RTL8814A + if (IS_HARDWARE_TYPE_8814A(pAdapter)) { + pHalData->BackUp_IG_REG_4_Chnl_Section[0] = (u1Byte)phy_query_bb_reg(pAdapter, rA_IGI_Jaguar, bMaskByte0); + pHalData->BackUp_IG_REG_4_Chnl_Section[1] = (u1Byte)phy_query_bb_reg(pAdapter, rB_IGI_Jaguar, bMaskByte0); + pHalData->BackUp_IG_REG_4_Chnl_Section[2] = (u1Byte)phy_query_bb_reg(pAdapter, rC_IGI_Jaguar2, bMaskByte0); + pHalData->BackUp_IG_REG_4_Chnl_Section[3] = (u1Byte)phy_query_bb_reg(pAdapter, rD_IGI_Jaguar2, bMaskByte0); + } +#endif + return rtStatus; +} + +/*----------------------------------------------------------------------------- + * Function: MPT_DeInitAdapter() + * + * Overview: Extra DeInitialization for Mass Production Test. + * + * Input: PADAPTER pAdapter + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/08/2007 MHC Create Version 0. + * 05/18/2007 MHC Add normal driver MPHalt code. + * + *---------------------------------------------------------------------------*/ +VOID +MPT_DeInitAdapter( + IN PADAPTER pAdapter +) +{ + PMPT_CONTEXT pMptCtx = &pAdapter->mppriv.mpt_ctx; + + pMptCtx->bMptDrvUnload = _TRUE; +#if defined(CONFIG_RTL8723B) + _rtw_free_sema(&(pMptCtx->MPh2c_Sema)); + _cancel_timer_ex(&pMptCtx->MPh2c_timeout_timer); +#endif +#if defined(CONFIG_RTL8723B) + phy_set_bb_reg(pAdapter, 0xA01, BIT0, 1); /* /suggestion by jerry for MP Rx. */ +#endif +#if 0 /* for Windows */ + PlatformFreeWorkItem(&(pMptCtx->MptWorkItem)); + + while (pMptCtx->bMptWorkItemInProgress) { + if (NdisWaitEvent(&(pMptCtx->MptWorkItemEvent), 50)) + break; + } + NdisFreeSpinLock(&(pMptCtx->MptWorkItemSpinLock)); +#endif +} + +static u8 mpt_ProStartTest(PADAPTER padapter) +{ + PMPT_CONTEXT pMptCtx = &padapter->mppriv.mpt_ctx; + + pMptCtx->bMassProdTest = _TRUE; + pMptCtx->is_start_cont_tx = _FALSE; + pMptCtx->bCckContTx = _FALSE; + pMptCtx->bOfdmContTx = _FALSE; + pMptCtx->bSingleCarrier = _FALSE; + pMptCtx->is_carrier_suppression = _FALSE; + pMptCtx->is_single_tone = _FALSE; + pMptCtx->HWTxmode = PACKETS_TX; + + return _SUCCESS; +} + +/* + * General use + */ +s32 SetPowerTracking(PADAPTER padapter, u8 enable) +{ + + hal_mpt_SetPowerTracking(padapter, enable); + return 0; +} + +void GetPowerTracking(PADAPTER padapter, u8 *enable) +{ + hal_mpt_GetPowerTracking(padapter, enable); +} + +void rtw_mp_trigger_iqk(PADAPTER padapter) +{ + PHY_IQCalibrate(padapter, _FALSE); +} + +void rtw_mp_trigger_lck(PADAPTER padapter) +{ + PHY_LCCalibrate(padapter); +} + +static void disable_dm(PADAPTER padapter) +{ + u8 v8; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + + /* 3 1. disable firmware dynamic mechanism */ + /* disable Power Training, Rate Adaptive */ + v8 = rtw_read8(padapter, REG_BCN_CTRL); + v8 &= ~EN_BCN_FUNCTION; + rtw_write8(padapter, REG_BCN_CTRL, v8); + + /* 3 2. disable driver dynamic mechanism */ + rtw_phydm_func_disable_all(padapter); + + /* enable APK, LCK and IQK but disable power tracking */ + pDM_Odm->rf_calibrate_info.txpowertrack_control = _FALSE; + rtw_phydm_func_set(padapter, ODM_RF_CALIBRATION); + + /* #ifdef CONFIG_BT_COEXIST */ + /* rtw_btcoex_Switch(padapter, 0); */ /* remove for BT MP Down. */ + /* #endif */ +} + + +void MPT_PwrCtlDM(PADAPTER padapter, u32 bstart) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + + if (bstart == 1) { + RTW_INFO("in MPT_PwrCtlDM start\n"); + rtw_phydm_func_set(padapter, ODM_RF_TX_PWR_TRACK | ODM_RF_CALIBRATION); + + pDM_Odm->rf_calibrate_info.txpowertrack_control = _TRUE; + padapter->mppriv.mp_dm = 1; + + } else { + RTW_INFO("in MPT_PwrCtlDM stop\n"); + disable_dm(padapter); + pDM_Odm->rf_calibrate_info.txpowertrack_control = _FALSE; + padapter->mppriv.mp_dm = 0; + { + struct _TXPWRTRACK_CFG c; + u1Byte chnl = 0 ; + _rtw_memset(&c, 0, sizeof(struct _TXPWRTRACK_CFG)); + configure_txpower_track(pDM_Odm, &c); + odm_clear_txpowertracking_state(pDM_Odm); + if (*c.odm_tx_pwr_track_set_pwr) { + if (pDM_Odm->support_ic_type == ODM_RTL8188F) + (*c.odm_tx_pwr_track_set_pwr)(pDM_Odm, MIX_MODE, ODM_RF_PATH_A, chnl); + else if (pDM_Odm->support_ic_type == ODM_RTL8723D) { + (*c.odm_tx_pwr_track_set_pwr)(pDM_Odm, BBSWING, ODM_RF_PATH_A, chnl); + SetTxPower(padapter); + } else { + (*c.odm_tx_pwr_track_set_pwr)(pDM_Odm, BBSWING, ODM_RF_PATH_A, chnl); + (*c.odm_tx_pwr_track_set_pwr)(pDM_Odm, BBSWING, ODM_RF_PATH_B, chnl); + } + } + } + } + +} + + +u32 mp_join(PADAPTER padapter, u8 mode) +{ + WLAN_BSSID_EX bssid; + struct sta_info *psta; + u32 length; + u8 val8, join_type; + _irqL irqL; + s32 res = _SUCCESS; + + struct mp_priv *pmppriv = &padapter->mppriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *tgt_network = &pmlmepriv->cur_network; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)(&(pmlmeinfo->network)); + +#ifdef CONFIG_IOCTL_CFG80211 + struct wireless_dev *pwdev = padapter->rtw_wdev; +#endif /* #ifdef CONFIG_IOCTL_CFG80211 */ + /* 1. initialize a new WLAN_BSSID_EX */ + _rtw_memset(&bssid, 0, sizeof(WLAN_BSSID_EX)); + RTW_INFO("%s ,pmppriv->network_macaddr=%x %x %x %x %x %x\n", __func__, + pmppriv->network_macaddr[0], pmppriv->network_macaddr[1], pmppriv->network_macaddr[2], pmppriv->network_macaddr[3], pmppriv->network_macaddr[4], + pmppriv->network_macaddr[5]); + _rtw_memcpy(bssid.MacAddress, pmppriv->network_macaddr, ETH_ALEN); + + if (mode == WIFI_FW_ADHOC_STATE) { + bssid.Ssid.SsidLength = strlen("mp_pseudo_adhoc"); + _rtw_memcpy(bssid.Ssid.Ssid, (u8 *)"mp_pseudo_adhoc", bssid.Ssid.SsidLength); + bssid.InfrastructureMode = Ndis802_11IBSS; + bssid.NetworkTypeInUse = Ndis802_11DS; + bssid.IELength = 0; + bssid.Configuration.DSConfig = pmppriv->channel; + + } else if (mode == WIFI_FW_STATION_STATE) { + bssid.Ssid.SsidLength = strlen("mp_pseudo_STATION"); + _rtw_memcpy(bssid.Ssid.Ssid, (u8 *)"mp_pseudo_STATION", bssid.Ssid.SsidLength); + bssid.InfrastructureMode = Ndis802_11Infrastructure; + bssid.NetworkTypeInUse = Ndis802_11DS; + bssid.IELength = 0; + } + + length = get_WLAN_BSSID_EX_sz(&bssid); + if (length % 4) + bssid.Length = ((length >> 2) + 1) << 2; /* round up to multiple of 4 bytes. */ + else + bssid.Length = length; + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) + goto end_of_mp_start_test; + + /* init mp_start_test status */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + rtw_disassoc_cmd(padapter, 500, _TRUE); + rtw_indicate_disconnect(padapter, 0, _FALSE); + rtw_free_assoc_resources(padapter, 1); + } + pmppriv->prev_fw_state = get_fwstate(pmlmepriv); + /*pmlmepriv->fw_state = WIFI_MP_STATE;*/ + init_fwstate(pmlmepriv, WIFI_MP_STATE); + + set_fwstate(pmlmepriv, _FW_UNDER_LINKING); + + /* 3 2. create a new psta for mp driver */ + /* clear psta in the cur_network, if any */ + psta = rtw_get_stainfo(&padapter->stapriv, tgt_network->network.MacAddress); + if (psta) + rtw_free_stainfo(padapter, psta); + + psta = rtw_alloc_stainfo(&padapter->stapriv, bssid.MacAddress); + if (psta == NULL) { + /*pmlmepriv->fw_state = pmppriv->prev_fw_state;*/ + init_fwstate(pmlmepriv, pmppriv->prev_fw_state); + res = _FAIL; + goto end_of_mp_start_test; + } + if (mode == WIFI_FW_ADHOC_STATE) + set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE); + else + set_fwstate(pmlmepriv, WIFI_STATION_STATE); + /* 3 3. join psudo AdHoc */ + tgt_network->join_res = 1; + tgt_network->aid = psta->aid = 1; + + _rtw_memcpy(&padapter->registrypriv.dev_network, &bssid, length); + rtw_update_registrypriv_dev_network(padapter); + _rtw_memcpy(&tgt_network->network, &padapter->registrypriv.dev_network, padapter->registrypriv.dev_network.Length); + _rtw_memcpy(pnetwork, &padapter->registrypriv.dev_network, padapter->registrypriv.dev_network.Length); + + rtw_indicate_connect(padapter); + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + set_fwstate(pmlmepriv, _FW_LINKED); + +end_of_mp_start_test: + + _exit_critical_bh(&pmlmepriv->lock, &irqL); + + if (1) { /* (res == _SUCCESS) */ + /* set MSR to WIFI_FW_ADHOC_STATE */ + if (mode == WIFI_FW_ADHOC_STATE) { + /* set msr to WIFI_FW_ADHOC_STATE */ + pmlmeinfo->state = WIFI_FW_ADHOC_STATE; + Set_MSR(padapter, (pmlmeinfo->state & 0x3)); + + rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress); + join_type = 0; + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + + report_join_res(padapter, 1); + pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS; + } else { + Set_MSR(padapter, WIFI_FW_STATION_STATE); + + RTW_INFO("%s , pmppriv->network_macaddr =%x %x %x %x %x %x\n", __func__, + pmppriv->network_macaddr[0], pmppriv->network_macaddr[1], pmppriv->network_macaddr[2], pmppriv->network_macaddr[3], pmppriv->network_macaddr[4], + pmppriv->network_macaddr[5]); + + rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pmppriv->network_macaddr); + } + } + + return res; +} +/* This function initializes the DUT to the MP test mode */ +s32 mp_start_test(PADAPTER padapter) +{ + struct mp_priv *pmppriv = &padapter->mppriv; + s32 res = _SUCCESS; + + padapter->registrypriv.mp_mode = 1; + + /* 3 disable dynamic mechanism */ + disable_dm(padapter); +#ifdef CONFIG_RTL8814A + rtl8814_InitHalDm(padapter); +#endif /* CONFIG_RTL8814A */ +#ifdef CONFIG_RTL8822B + rtl8822b_phy_init_haldm(padapter); +#endif /* CONFIG_RTL8822B */ +#ifdef CONFIG_RTL8821C + rtl8821c_phy_init_haldm(padapter); +#endif /* CONFIG_RTL8821C */ +#ifdef CONFIG_RTL8812A + rtl8812_InitHalDm(padapter); +#endif /* CONFIG_RTL8812A */ +#ifdef CONFIG_RTL8723B + rtl8723b_InitHalDm(padapter); +#endif /* CONFIG_RTL8723B */ +#ifdef CONFIG_RTL8703B + rtl8703b_InitHalDm(padapter); +#endif /* CONFIG_RTL8703B */ +#ifdef CONFIG_RTL8192E + rtl8192e_InitHalDm(padapter); +#endif +#ifdef CONFIG_RTL8188F + rtl8188f_InitHalDm(padapter); +#endif +#ifdef CONFIG_RTL8188E + rtl8188e_InitHalDm(padapter); +#endif +#ifdef CONFIG_RTL8723D + rtl8723d_InitHalDm(padapter); +#endif /* CONFIG_RTL8723D */ + + /* 3 0. update mp_priv */ + + if (!RF_TYPE_VALID(padapter->registrypriv.rf_config)) { + /* switch (phal->rf_type) { */ + switch (GET_RF_TYPE(padapter)) { + case RF_1T1R: + pmppriv->antenna_tx = ANTENNA_A; + pmppriv->antenna_rx = ANTENNA_A; + break; + case RF_1T2R: + default: + pmppriv->antenna_tx = ANTENNA_A; + pmppriv->antenna_rx = ANTENNA_AB; + break; + case RF_2T2R: + case RF_2T2R_GREEN: + pmppriv->antenna_tx = ANTENNA_AB; + pmppriv->antenna_rx = ANTENNA_AB; + break; + case RF_2T4R: + pmppriv->antenna_tx = ANTENNA_AB; + pmppriv->antenna_rx = ANTENNA_ABCD; + break; + } + } + + mpt_ProStartTest(padapter); + + mp_join(padapter, WIFI_FW_ADHOC_STATE); + + return res; +} +/* ------------------------------------------------------------------------------ + * This function change the DUT from the MP test mode into normal mode */ +void mp_stop_test(PADAPTER padapter) +{ + struct mp_priv *pmppriv = &padapter->mppriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *tgt_network = &pmlmepriv->cur_network; + struct sta_info *psta; + + _irqL irqL; + + if (pmppriv->mode == MP_ON) { + pmppriv->bSetTxPower = 0; + _enter_critical_bh(&pmlmepriv->lock, &irqL); + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _FALSE) + goto end_of_mp_stop_test; + + /* 3 1. disconnect psudo AdHoc */ + rtw_indicate_disconnect(padapter, 0, _FALSE); + + /* 3 2. clear psta used in mp test mode. + * rtw_free_assoc_resources(padapter, 1); */ + psta = rtw_get_stainfo(&padapter->stapriv, tgt_network->network.MacAddress); + if (psta) + rtw_free_stainfo(padapter, psta); + + /* 3 3. return to normal state (default:station mode) */ + /*pmlmepriv->fw_state = pmppriv->prev_fw_state; */ /* WIFI_STATION_STATE;*/ + init_fwstate(pmlmepriv, pmppriv->prev_fw_state); + + /* flush the cur_network */ + _rtw_memset(tgt_network, 0, sizeof(struct wlan_network)); + + _clr_fwstate_(pmlmepriv, WIFI_MP_STATE); + +end_of_mp_stop_test: + + _exit_critical_bh(&pmlmepriv->lock, &irqL); + +#ifdef CONFIG_RTL8812A + rtl8812_InitHalDm(padapter); +#endif +#ifdef CONFIG_RTL8723B + rtl8723b_InitHalDm(padapter); +#endif +#ifdef CONFIG_RTL8703B + rtl8703b_InitHalDm(padapter); +#endif +#ifdef CONFIG_RTL8192E + rtl8192e_InitHalDm(padapter); +#endif +#ifdef CONFIG_RTL8188F + rtl8188f_InitHalDm(padapter); +#endif +#ifdef CONFIG_RTL8723D + rtl8723d_InitHalDm(padapter); +#endif + } +} +/*---------------------------hal\rtl8192c\MPT_Phy.c---------------------------*/ +#if 0 +/* #ifdef CONFIG_USB_HCI */ +static VOID mpt_AdjustRFRegByRateByChan92CU(PADAPTER pAdapter, u8 RateIdx, u8 Channel, u8 BandWidthID) +{ + u8 eRFPath; + u32 rfReg0x26; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + + if (RateIdx < MPT_RATE_6M) /* CCK rate,for 88cu */ + rfReg0x26 = 0xf400; + else if ((RateIdx >= MPT_RATE_6M) && (RateIdx <= MPT_RATE_54M)) {/* OFDM rate,for 88cu */ + if ((4 == Channel) || (8 == Channel) || (12 == Channel)) + rfReg0x26 = 0xf000; + else if ((5 == Channel) || (7 == Channel) || (13 == Channel) || (14 == Channel)) + rfReg0x26 = 0xf400; + else + rfReg0x26 = 0x4f200; + } else if ((RateIdx >= MPT_RATE_MCS0) && (RateIdx <= MPT_RATE_MCS15)) { + /* MCS 20M ,for 88cu */ /* MCS40M rate,for 88cu */ + + if (CHANNEL_WIDTH_20 == BandWidthID) { + if ((4 == Channel) || (8 == Channel)) + rfReg0x26 = 0xf000; + else if ((5 == Channel) || (7 == Channel) || (13 == Channel) || (14 == Channel)) + rfReg0x26 = 0xf400; + else + rfReg0x26 = 0x4f200; + } else { + if ((4 == Channel) || (8 == Channel)) + rfReg0x26 = 0xf000; + else if ((5 == Channel) || (7 == Channel)) + rfReg0x26 = 0xf400; + else + rfReg0x26 = 0x4f200; + } + } + + for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) + write_rfreg(pAdapter, eRFPath, RF_SYN_G2, rfReg0x26); +} +#endif +/*----------------------------------------------------------------------------- + * Function: mpt_SwitchRfSetting + * + * Overview: Change RF Setting when we siwthc channel/rate/BW for MP. + * + * Input: IN PADAPTER pAdapter + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 01/08/2009 MHC Suggestion from SD3 Willis for 92S series. + * 01/09/2009 MHC Add CCK modification for 40MHZ. Suggestion from SD3. + * + *---------------------------------------------------------------------------*/ +static void mpt_SwitchRfSetting(PADAPTER pAdapter) +{ + hal_mpt_SwitchRfSetting(pAdapter); +} + +/*---------------------------hal\rtl8192c\MPT_Phy.c---------------------------*/ +/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/ +static void MPT_CCKTxPowerAdjust(PADAPTER Adapter, BOOLEAN bInCH14) +{ + hal_mpt_CCKTxPowerAdjust(Adapter, bInCH14); +} + +/*---------------------------hal\rtl8192c\MPT_HelperFunc.c---------------------------*/ + +/* + * SetChannel + * Description + * Use H2C command to change channel, + * not only modify rf register, but also other setting need to be done. + */ +void SetChannel(PADAPTER pAdapter) +{ + hal_mpt_SetChannel(pAdapter); +} + +/* + * Notice + * Switch bandwitdth may change center frequency(channel) + */ +void SetBandwidth(PADAPTER pAdapter) +{ + hal_mpt_SetBandwidth(pAdapter); + +} + +void SetAntenna(PADAPTER pAdapter) +{ + hal_mpt_SetAntenna(pAdapter); +} + +int SetTxPower(PADAPTER pAdapter) +{ + + hal_mpt_SetTxPower(pAdapter); + return _TRUE; +} + +void SetTxAGCOffset(PADAPTER pAdapter, u32 ulTxAGCOffset) +{ + u32 TxAGCOffset_B, TxAGCOffset_C, TxAGCOffset_D, tmpAGC; + + TxAGCOffset_B = (ulTxAGCOffset & 0x000000ff); + TxAGCOffset_C = ((ulTxAGCOffset & 0x0000ff00) >> 8); + TxAGCOffset_D = ((ulTxAGCOffset & 0x00ff0000) >> 16); + + tmpAGC = (TxAGCOffset_D << 8 | TxAGCOffset_C << 4 | TxAGCOffset_B); + write_bbreg(pAdapter, rFPGA0_TxGainStage, + (bXBTxAGC | bXCTxAGC | bXDTxAGC), tmpAGC); +} + +void SetDataRate(PADAPTER pAdapter) +{ + hal_mpt_SetDataRate(pAdapter); +} + +void MP_PHY_SetRFPathSwitch(PADAPTER pAdapter , BOOLEAN bMain) +{ + + PHY_SetRFPathSwitch(pAdapter, bMain); + +} + +u8 MP_PHY_QueryRFPathSwitch(PADAPTER pAdapter) +{ + return PHY_QueryRFPathSwitch(pAdapter); +} + +s32 SetThermalMeter(PADAPTER pAdapter, u8 target_ther) +{ + return hal_mpt_SetThermalMeter(pAdapter, target_ther); +} + +static void TriggerRFThermalMeter(PADAPTER pAdapter) +{ + hal_mpt_TriggerRFThermalMeter(pAdapter); +} + +static u8 ReadRFThermalMeter(PADAPTER pAdapter) +{ + return hal_mpt_ReadRFThermalMeter(pAdapter); +} + +void GetThermalMeter(PADAPTER pAdapter, u8 *value) +{ + hal_mpt_GetThermalMeter(pAdapter, value); +} + +void SetSingleCarrierTx(PADAPTER pAdapter, u8 bStart) +{ + PhySetTxPowerLevel(pAdapter); + hal_mpt_SetSingleCarrierTx(pAdapter, bStart); +} + +void SetSingleToneTx(PADAPTER pAdapter, u8 bStart) +{ + PhySetTxPowerLevel(pAdapter); + hal_mpt_SetSingleToneTx(pAdapter, bStart); +} + +void SetCarrierSuppressionTx(PADAPTER pAdapter, u8 bStart) +{ + PhySetTxPowerLevel(pAdapter); + hal_mpt_SetCarrierSuppressionTx(pAdapter, bStart); +} + +void SetContinuousTx(PADAPTER pAdapter, u8 bStart) +{ + PhySetTxPowerLevel(pAdapter); + hal_mpt_SetContinuousTx(pAdapter, bStart); +} + + +void PhySetTxPowerLevel(PADAPTER pAdapter) +{ + struct mp_priv *pmp_priv = &pAdapter->mppriv; + + + if (pmp_priv->bSetTxPower == 0) /* for NO manually set power index */ + rtw_hal_set_tx_power_level(pAdapter, pmp_priv->channel); +} + +/* ------------------------------------------------------------------------------ */ +static void dump_mpframe(PADAPTER padapter, struct xmit_frame *pmpframe) +{ + rtw_hal_mgnt_xmit(padapter, pmpframe); +} + +static struct xmit_frame *alloc_mp_xmitframe(struct xmit_priv *pxmitpriv) +{ + struct xmit_frame *pmpframe; + struct xmit_buf *pxmitbuf; + + pmpframe = rtw_alloc_xmitframe(pxmitpriv); + if (pmpframe == NULL) + return NULL; + + pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); + if (pxmitbuf == NULL) { + rtw_free_xmitframe(pxmitpriv, pmpframe); + return NULL; + } + + pmpframe->frame_tag = MP_FRAMETAG; + + pmpframe->pxmitbuf = pxmitbuf; + + pmpframe->buf_addr = pxmitbuf->pbuf; + + pxmitbuf->priv_data = pmpframe; + + return pmpframe; + +} + +static thread_return mp_xmit_packet_thread(thread_context context) +{ + struct xmit_frame *pxmitframe; + struct mp_tx *pmptx; + struct mp_priv *pmp_priv; + struct xmit_priv *pxmitpriv; + PADAPTER padapter; + + pmp_priv = (struct mp_priv *)context; + pmptx = &pmp_priv->tx; + padapter = pmp_priv->papdater; + pxmitpriv = &(padapter->xmitpriv); + + thread_enter("RTW_MP_THREAD"); + + RTW_INFO("%s:pkTx Start\n", __func__); + while (1) { + pxmitframe = alloc_mp_xmitframe(pxmitpriv); + if (pxmitframe == NULL) { + if (pmptx->stop || + RTW_CANNOT_RUN(padapter)) + goto exit; + else { + rtw_usleep_os(10); + continue; + } + } + _rtw_memcpy((u8 *)(pxmitframe->buf_addr + TXDESC_OFFSET), pmptx->buf, pmptx->write_size); + _rtw_memcpy(&(pxmitframe->attrib), &(pmptx->attrib), sizeof(struct pkt_attrib)); + + + rtw_usleep_os(padapter->mppriv.pktInterval); + dump_mpframe(padapter, pxmitframe); + + pmptx->sended++; + pmp_priv->tx_pktcount++; + + if (pmptx->stop || + RTW_CANNOT_RUN(padapter)) + goto exit; + if ((pmptx->count != 0) && + (pmptx->count == pmptx->sended)) + goto exit; + + flush_signals_thread(); + } + +exit: + /* RTW_INFO("%s:pkTx Exit\n", __func__); */ + rtw_mfree(pmptx->pallocated_buf, pmptx->buf_size); + pmptx->pallocated_buf = NULL; + pmptx->stop = 1; + + thread_exit(); +} + +void fill_txdesc_for_mp(PADAPTER padapter, u8 *ptxdesc) +{ + struct mp_priv *pmp_priv = &padapter->mppriv; + _rtw_memcpy(ptxdesc, pmp_priv->tx.desc, TXDESC_SIZE); +} + +#if defined(CONFIG_RTL8188E) +void fill_tx_desc_8188e(PADAPTER padapter) +{ + struct mp_priv *pmp_priv = &padapter->mppriv; + struct tx_desc *desc = (struct tx_desc *)&(pmp_priv->tx.desc); + struct pkt_attrib *pattrib = &(pmp_priv->tx.attrib); + u32 pkt_size = pattrib->last_txcmdsz; + s32 bmcast = IS_MCAST(pattrib->ra); + /* offset 0 */ +#if !defined(CONFIG_RTL8188E_SDIO) && !defined(CONFIG_PCI_HCI) + desc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); + desc->txdw0 |= cpu_to_le32(pkt_size & 0x0000FFFF); /* packet size */ + desc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) & 0x00FF0000); /* 32 bytes for TX Desc */ + if (bmcast) + desc->txdw0 |= cpu_to_le32(BMC); /* broadcast packet */ + + desc->txdw1 |= cpu_to_le32((0x01 << 26) & 0xff000000); +#endif + + desc->txdw1 |= cpu_to_le32((pattrib->mac_id) & 0x3F); /* CAM_ID(MAC_ID) */ + desc->txdw1 |= cpu_to_le32((pattrib->qsel << QSEL_SHT) & 0x00001F00); /* Queue Select, TID */ + desc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000F0000); /* Rate Adaptive ID */ + /* offset 8 */ + /* desc->txdw2 |= cpu_to_le32(AGG_BK); */ /* AGG BK */ + + desc->txdw3 |= cpu_to_le32((pattrib->seqnum << 16) & 0x0fff0000); + desc->txdw4 |= cpu_to_le32(HW_SSN); + + desc->txdw4 |= cpu_to_le32(USERATE); + desc->txdw4 |= cpu_to_le32(DISDATAFB); + + if (pmp_priv->preamble) { + if (HwRateToMPTRate(pmp_priv->rateidx) <= MPT_RATE_54M) + desc->txdw4 |= cpu_to_le32(DATA_SHORT); /* CCK Short Preamble */ + } + + if (pmp_priv->bandwidth == CHANNEL_WIDTH_40) + desc->txdw4 |= cpu_to_le32(DATA_BW); + + /* offset 20 */ + desc->txdw5 |= cpu_to_le32(pmp_priv->rateidx & 0x0000001F); + + if (pmp_priv->preamble) { + if (HwRateToMPTRate(pmp_priv->rateidx) > MPT_RATE_54M) + desc->txdw5 |= cpu_to_le32(SGI); /* MCS Short Guard Interval */ + } + + desc->txdw5 |= cpu_to_le32(RTY_LMT_EN); /* retry limit enable */ + desc->txdw5 |= cpu_to_le32(0x00180000); /* DATA/RTS Rate Fallback Limit */ + + +} +#endif + +#if defined(CONFIG_RTL8814A) +void fill_tx_desc_8814a(PADAPTER padapter) +{ + struct mp_priv *pmp_priv = &padapter->mppriv; + u8 *pDesc = (u8 *)&(pmp_priv->tx.desc); + struct pkt_attrib *pattrib = &(pmp_priv->tx.attrib); + + u32 pkt_size = pattrib->last_txcmdsz; + s32 bmcast = IS_MCAST(pattrib->ra); + u8 data_rate, pwr_status, offset; + + /* SET_TX_DESC_FIRST_SEG_8814A(pDesc, 1); */ + SET_TX_DESC_LAST_SEG_8814A(pDesc, 1); + /* SET_TX_DESC_OWN_(pDesc, 1); */ + + SET_TX_DESC_PKT_SIZE_8814A(pDesc, pkt_size); + + offset = TXDESC_SIZE + OFFSET_SZ; + + SET_TX_DESC_OFFSET_8814A(pDesc, offset); +#if defined(CONFIG_PCI_HCI) + SET_TX_DESC_PKT_OFFSET_8814A(pDesc, 0); /* 8814AE pkt_offset is 0 */ +#else + SET_TX_DESC_PKT_OFFSET_8814A(pDesc, 1); +#endif + + if (bmcast) + SET_TX_DESC_BMC_8814A(pDesc, 1); + + SET_TX_DESC_MACID_8814A(pDesc, pattrib->mac_id); + SET_TX_DESC_RATE_ID_8814A(pDesc, pattrib->raid); + + /* SET_TX_DESC_RATE_ID_8812(pDesc, RATEID_IDX_G); */ + SET_TX_DESC_QUEUE_SEL_8814A(pDesc, pattrib->qsel); + /* SET_TX_DESC_QUEUE_SEL_8812(pDesc, QSLT_MGNT); */ + + if (pmp_priv->preamble) + SET_TX_DESC_DATA_SHORT_8814A(pDesc, 1); + + if (!pattrib->qos_en) { + SET_TX_DESC_HWSEQ_EN_8814A(pDesc, 1); /* Hw set sequence number */ + } else + SET_TX_DESC_SEQ_8814A(pDesc, pattrib->seqnum); + + if (pmp_priv->bandwidth <= CHANNEL_WIDTH_160) + SET_TX_DESC_DATA_BW_8814A(pDesc, pmp_priv->bandwidth); + else { + RTW_INFO("%s:Err: unknown bandwidth %d, use 20M\n", __func__, pmp_priv->bandwidth); + SET_TX_DESC_DATA_BW_8814A(pDesc, CHANNEL_WIDTH_20); + } + + SET_TX_DESC_DISABLE_FB_8814A(pDesc, 1); + SET_TX_DESC_USE_RATE_8814A(pDesc, 1); + SET_TX_DESC_TX_RATE_8814A(pDesc, pmp_priv->rateidx); + +} +#endif + +#if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) +void fill_tx_desc_8812a(PADAPTER padapter) +{ + struct mp_priv *pmp_priv = &padapter->mppriv; + u8 *pDesc = (u8 *)&(pmp_priv->tx.desc); + struct pkt_attrib *pattrib = &(pmp_priv->tx.attrib); + + u32 pkt_size = pattrib->last_txcmdsz; + s32 bmcast = IS_MCAST(pattrib->ra); + u8 data_rate, pwr_status, offset; + + SET_TX_DESC_FIRST_SEG_8812(pDesc, 1); + SET_TX_DESC_LAST_SEG_8812(pDesc, 1); + SET_TX_DESC_OWN_8812(pDesc, 1); + + SET_TX_DESC_PKT_SIZE_8812(pDesc, pkt_size); + + offset = TXDESC_SIZE + OFFSET_SZ; + + SET_TX_DESC_OFFSET_8812(pDesc, offset); + +#if defined(CONFIG_PCI_HCI) + SET_TX_DESC_PKT_OFFSET_8812(pDesc, 0); +#else + SET_TX_DESC_PKT_OFFSET_8812(pDesc, 1); +#endif + if (bmcast) + SET_TX_DESC_BMC_8812(pDesc, 1); + + SET_TX_DESC_MACID_8812(pDesc, pattrib->mac_id); + SET_TX_DESC_RATE_ID_8812(pDesc, pattrib->raid); + + /* SET_TX_DESC_RATE_ID_8812(pDesc, RATEID_IDX_G); */ + SET_TX_DESC_QUEUE_SEL_8812(pDesc, pattrib->qsel); + /* SET_TX_DESC_QUEUE_SEL_8812(pDesc, QSLT_MGNT); */ + + if (!pattrib->qos_en) { + SET_TX_DESC_HWSEQ_EN_8812(pDesc, 1); /* Hw set sequence number */ + } else + SET_TX_DESC_SEQ_8812(pDesc, pattrib->seqnum); + + if (pmp_priv->bandwidth <= CHANNEL_WIDTH_160) + SET_TX_DESC_DATA_BW_8812(pDesc, pmp_priv->bandwidth); + else { + RTW_INFO("%s:Err: unknown bandwidth %d, use 20M\n", __func__, pmp_priv->bandwidth); + SET_TX_DESC_DATA_BW_8812(pDesc, CHANNEL_WIDTH_20); + } + + SET_TX_DESC_DISABLE_FB_8812(pDesc, 1); + SET_TX_DESC_USE_RATE_8812(pDesc, 1); + SET_TX_DESC_TX_RATE_8812(pDesc, pmp_priv->rateidx); + +} +#endif +#if defined(CONFIG_RTL8192E) +void fill_tx_desc_8192e(PADAPTER padapter) +{ + struct mp_priv *pmp_priv = &padapter->mppriv; + u8 *pDesc = (u8 *)&(pmp_priv->tx.desc); + struct pkt_attrib *pattrib = &(pmp_priv->tx.attrib); + + u32 pkt_size = pattrib->last_txcmdsz; + s32 bmcast = IS_MCAST(pattrib->ra); + u8 data_rate, pwr_status, offset; + + + SET_TX_DESC_PKT_SIZE_92E(pDesc, pkt_size); + + offset = TXDESC_SIZE + OFFSET_SZ; + + SET_TX_DESC_OFFSET_92E(pDesc, offset); +#if defined(CONFIG_PCI_HCI) /* 8192EE */ + + SET_TX_DESC_PKT_OFFSET_92E(pDesc, 0); /* 8192EE pkt_offset is 0 */ +#else /* 8192EU 8192ES */ + SET_TX_DESC_PKT_OFFSET_92E(pDesc, 1); +#endif + + if (bmcast) + SET_TX_DESC_BMC_92E(pDesc, 1); + + SET_TX_DESC_MACID_92E(pDesc, pattrib->mac_id); + SET_TX_DESC_RATE_ID_92E(pDesc, pattrib->raid); + + + SET_TX_DESC_QUEUE_SEL_92E(pDesc, pattrib->qsel); + /* SET_TX_DESC_QUEUE_SEL_8812(pDesc, QSLT_MGNT); */ + + if (!pattrib->qos_en) { + SET_TX_DESC_EN_HWSEQ_92E(pDesc, 1);/* Hw set sequence number */ + SET_TX_DESC_HWSEQ_SEL_92E(pDesc, pattrib->hw_ssn_sel); + } else + SET_TX_DESC_SEQ_92E(pDesc, pattrib->seqnum); + + if ((pmp_priv->bandwidth == CHANNEL_WIDTH_20) || (pmp_priv->bandwidth == CHANNEL_WIDTH_40)) + SET_TX_DESC_DATA_BW_92E(pDesc, pmp_priv->bandwidth); + else { + RTW_INFO("%s:Err: unknown bandwidth %d, use 20M\n", __func__, pmp_priv->bandwidth); + SET_TX_DESC_DATA_BW_92E(pDesc, CHANNEL_WIDTH_20); + } + + /* SET_TX_DESC_DATA_SC_92E(pDesc, SCMapping_92E(padapter,pattrib)); */ + + SET_TX_DESC_DISABLE_FB_92E(pDesc, 1); + SET_TX_DESC_USE_RATE_92E(pDesc, 1); + SET_TX_DESC_TX_RATE_92E(pDesc, pmp_priv->rateidx); + +} +#endif + +#if defined(CONFIG_RTL8723B) +void fill_tx_desc_8723b(PADAPTER padapter) +{ + struct mp_priv *pmp_priv = &padapter->mppriv; + struct pkt_attrib *pattrib = &(pmp_priv->tx.attrib); + u8 *ptxdesc = pmp_priv->tx.desc; + + SET_TX_DESC_AGG_BREAK_8723B(ptxdesc, 1); + SET_TX_DESC_MACID_8723B(ptxdesc, pattrib->mac_id); + SET_TX_DESC_QUEUE_SEL_8723B(ptxdesc, pattrib->qsel); + + SET_TX_DESC_RATE_ID_8723B(ptxdesc, pattrib->raid); + SET_TX_DESC_SEQ_8723B(ptxdesc, pattrib->seqnum); + SET_TX_DESC_HWSEQ_EN_8723B(ptxdesc, 1); + SET_TX_DESC_USE_RATE_8723B(ptxdesc, 1); + SET_TX_DESC_DISABLE_FB_8723B(ptxdesc, 1); + + if (pmp_priv->preamble) { + if (HwRateToMPTRate(pmp_priv->rateidx) <= MPT_RATE_54M) + SET_TX_DESC_DATA_SHORT_8723B(ptxdesc, 1); + } + + if (pmp_priv->bandwidth == CHANNEL_WIDTH_40) + SET_TX_DESC_DATA_BW_8723B(ptxdesc, 1); + + SET_TX_DESC_TX_RATE_8723B(ptxdesc, pmp_priv->rateidx); + + SET_TX_DESC_DATA_RATE_FB_LIMIT_8723B(ptxdesc, 0x1F); + SET_TX_DESC_RTS_RATE_FB_LIMIT_8723B(ptxdesc, 0xF); +} +#endif + +#if defined(CONFIG_RTL8703B) +void fill_tx_desc_8703b(PADAPTER padapter) +{ + struct mp_priv *pmp_priv = &padapter->mppriv; + struct pkt_attrib *pattrib = &(pmp_priv->tx.attrib); + u8 *ptxdesc = pmp_priv->tx.desc; + + SET_TX_DESC_AGG_BREAK_8703B(ptxdesc, 1); + SET_TX_DESC_MACID_8703B(ptxdesc, pattrib->mac_id); + SET_TX_DESC_QUEUE_SEL_8703B(ptxdesc, pattrib->qsel); + + SET_TX_DESC_RATE_ID_8703B(ptxdesc, pattrib->raid); + SET_TX_DESC_SEQ_8703B(ptxdesc, pattrib->seqnum); + SET_TX_DESC_HWSEQ_EN_8703B(ptxdesc, 1); + SET_TX_DESC_USE_RATE_8703B(ptxdesc, 1); + SET_TX_DESC_DISABLE_FB_8703B(ptxdesc, 1); + + if (pmp_priv->preamble) { + if (HwRateToMPTRate(pmp_priv->rateidx) <= MPT_RATE_54M) + SET_TX_DESC_DATA_SHORT_8703B(ptxdesc, 1); + } + + if (pmp_priv->bandwidth == CHANNEL_WIDTH_40) + SET_TX_DESC_DATA_BW_8703B(ptxdesc, 1); + + SET_TX_DESC_TX_RATE_8703B(ptxdesc, pmp_priv->rateidx); + + SET_TX_DESC_DATA_RATE_FB_LIMIT_8703B(ptxdesc, 0x1F); + SET_TX_DESC_RTS_RATE_FB_LIMIT_8703B(ptxdesc, 0xF); +} +#endif + +#if defined(CONFIG_RTL8188F) +void fill_tx_desc_8188f(PADAPTER padapter) +{ + struct mp_priv *pmp_priv = &padapter->mppriv; + struct pkt_attrib *pattrib = &(pmp_priv->tx.attrib); + u8 *ptxdesc = pmp_priv->tx.desc; + + SET_TX_DESC_AGG_BREAK_8188F(ptxdesc, 1); + SET_TX_DESC_MACID_8188F(ptxdesc, pattrib->mac_id); + SET_TX_DESC_QUEUE_SEL_8188F(ptxdesc, pattrib->qsel); + + SET_TX_DESC_RATE_ID_8188F(ptxdesc, pattrib->raid); + SET_TX_DESC_SEQ_8188F(ptxdesc, pattrib->seqnum); + SET_TX_DESC_HWSEQ_EN_8188F(ptxdesc, 1); + SET_TX_DESC_USE_RATE_8188F(ptxdesc, 1); + SET_TX_DESC_DISABLE_FB_8188F(ptxdesc, 1); + + if (pmp_priv->preamble) + if (HwRateToMPTRate(pmp_priv->rateidx) <= MPT_RATE_54M) + SET_TX_DESC_DATA_SHORT_8188F(ptxdesc, 1); + + if (pmp_priv->bandwidth == CHANNEL_WIDTH_40) + SET_TX_DESC_DATA_BW_8188F(ptxdesc, 1); + + SET_TX_DESC_TX_RATE_8188F(ptxdesc, pmp_priv->rateidx); + + SET_TX_DESC_DATA_RATE_FB_LIMIT_8188F(ptxdesc, 0x1F); + SET_TX_DESC_RTS_RATE_FB_LIMIT_8188F(ptxdesc, 0xF); +} +#endif + +#if defined(CONFIG_RTL8723D) +void fill_tx_desc_8723d(PADAPTER padapter) +{ + struct mp_priv *pmp_priv = &padapter->mppriv; + struct pkt_attrib *pattrib = &(pmp_priv->tx.attrib); + u8 *ptxdesc = pmp_priv->tx.desc; + + SET_TX_DESC_BK_8723D(ptxdesc, 1); + SET_TX_DESC_MACID_8723D(ptxdesc, pattrib->mac_id); + SET_TX_DESC_QUEUE_SEL_8723D(ptxdesc, pattrib->qsel); + + SET_TX_DESC_RATE_ID_8723D(ptxdesc, pattrib->raid); + SET_TX_DESC_SEQ_8723D(ptxdesc, pattrib->seqnum); + SET_TX_DESC_HWSEQ_EN_8723D(ptxdesc, 1); + SET_TX_DESC_USE_RATE_8723D(ptxdesc, 1); + SET_TX_DESC_DISABLE_FB_8723D(ptxdesc, 1); + + if (pmp_priv->preamble) { + if (HwRateToMPTRate(pmp_priv->rateidx) <= MPT_RATE_54M) + SET_TX_DESC_DATA_SHORT_8723D(ptxdesc, 1); + } + + if (pmp_priv->bandwidth == CHANNEL_WIDTH_40) + SET_TX_DESC_DATA_BW_8723D(ptxdesc, 1); + + SET_TX_DESC_TX_RATE_8723D(ptxdesc, pmp_priv->rateidx); + + SET_TX_DESC_DATA_RATE_FB_LIMIT_8723D(ptxdesc, 0x1F); + SET_TX_DESC_RTS_RATE_FB_LIMIT_8723D(ptxdesc, 0xF); +} +#endif + +static void Rtw_MPSetMacTxEDCA(PADAPTER padapter) +{ + + rtw_write32(padapter, 0x508 , 0x00a422); /* Disable EDCA BE Txop for MP pkt tx adjust Packet interval */ + /* RTW_INFO("%s:write 0x508~~~~~~ 0x%x\n", __func__,rtw_read32(padapter, 0x508)); */ + phy_set_mac_reg(padapter, 0x458 , bMaskDWord , 0x0); + /*RTW_INFO("%s()!!!!! 0x460 = 0x%x\n" ,__func__, phy_query_bb_reg(padapter, 0x460, bMaskDWord));*/ + phy_set_mac_reg(padapter, 0x460 , bMaskLWord , 0x0); /* fast EDCA queue packet interval & time out value*/ + /*phy_set_mac_reg(padapter, ODM_EDCA_VO_PARAM ,bMaskLWord , 0x431C);*/ + /*phy_set_mac_reg(padapter, ODM_EDCA_BE_PARAM ,bMaskLWord , 0x431C);*/ + /*phy_set_mac_reg(padapter, ODM_EDCA_BK_PARAM ,bMaskLWord , 0x431C);*/ + RTW_INFO("%s()!!!!! 0x460 = 0x%x\n" , __func__, phy_query_bb_reg(padapter, 0x460, bMaskDWord)); + +} + +void SetPacketTx(PADAPTER padapter) +{ + u8 *ptr, *pkt_start, *pkt_end, *fctrl; + u32 pkt_size, offset, startPlace, i; + struct rtw_ieee80211_hdr *hdr; + u8 payload; + s32 bmcast; + struct pkt_attrib *pattrib; + struct mp_priv *pmp_priv; + + pmp_priv = &padapter->mppriv; + + if (pmp_priv->tx.stop) + return; + pmp_priv->tx.sended = 0; + pmp_priv->tx.stop = 0; + pmp_priv->tx_pktcount = 0; + + /* 3 1. update_attrib() */ + pattrib = &pmp_priv->tx.attrib; + _rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + bmcast = IS_MCAST(pattrib->ra); + if (bmcast) { + pattrib->mac_id = 1; + pattrib->psta = rtw_get_bcmc_stainfo(padapter); + } else { + pattrib->mac_id = 0; + pattrib->psta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv)); + } + pattrib->mbssid = 0; + + pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->pktlen; + + /* 3 2. allocate xmit buffer */ + pkt_size = pattrib->last_txcmdsz; + + if (pmp_priv->tx.pallocated_buf) + rtw_mfree(pmp_priv->tx.pallocated_buf, pmp_priv->tx.buf_size); + pmp_priv->tx.write_size = pkt_size; + pmp_priv->tx.buf_size = pkt_size + XMITBUF_ALIGN_SZ; + pmp_priv->tx.pallocated_buf = rtw_zmalloc(pmp_priv->tx.buf_size); + if (pmp_priv->tx.pallocated_buf == NULL) { + RTW_INFO("%s: malloc(%d) fail!!\n", __func__, pmp_priv->tx.buf_size); + return; + } + pmp_priv->tx.buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pmp_priv->tx.pallocated_buf), XMITBUF_ALIGN_SZ); + ptr = pmp_priv->tx.buf; + + _rtw_memset(pmp_priv->tx.desc, 0, TXDESC_SIZE); + pkt_start = ptr; + pkt_end = pkt_start + pkt_size; + + /* 3 3. init TX descriptor */ +#if defined(CONFIG_RTL8188E) + if (IS_HARDWARE_TYPE_8188E(padapter)) + fill_tx_desc_8188e(padapter); +#endif + +#if defined(CONFIG_RTL8814A) + if (IS_HARDWARE_TYPE_8814A(padapter)) + fill_tx_desc_8814a(padapter); +#endif /* defined(CONFIG_RTL8814A) */ + +#if defined(CONFIG_RTL8822B) + if (IS_HARDWARE_TYPE_8822B(padapter)) + rtl8822b_prepare_mp_txdesc(padapter, pmp_priv); +#endif /* CONFIG_RTL8822B */ + +#if defined(CONFIG_RTL8821C) + if (IS_HARDWARE_TYPE_8821C(padapter)) + rtl8821c_prepare_mp_txdesc(padapter, pmp_priv); +#endif /* CONFIG_RTL8821C */ + +#if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) + if (IS_HARDWARE_TYPE_8812(padapter) || IS_HARDWARE_TYPE_8821(padapter)) + fill_tx_desc_8812a(padapter); +#endif + +#if defined(CONFIG_RTL8192E) + if (IS_HARDWARE_TYPE_8192E(padapter)) + fill_tx_desc_8192e(padapter); +#endif +#if defined(CONFIG_RTL8723B) + if (IS_HARDWARE_TYPE_8723B(padapter)) + fill_tx_desc_8723b(padapter); +#endif +#if defined(CONFIG_RTL8703B) + if (IS_HARDWARE_TYPE_8703B(padapter)) + fill_tx_desc_8703b(padapter); +#endif + +#if defined(CONFIG_RTL8188F) + if (IS_HARDWARE_TYPE_8188F(padapter)) + fill_tx_desc_8188f(padapter); +#endif + +#if defined(CONFIG_RTL8723D) + if (IS_HARDWARE_TYPE_8723D(padapter)) + fill_tx_desc_8723d(padapter); +#endif + + /* 3 4. make wlan header, make_wlanhdr() */ + hdr = (struct rtw_ieee80211_hdr *)pkt_start; + set_frame_sub_type(&hdr->frame_ctl, pattrib->subtype); + + _rtw_memcpy(hdr->addr1, pattrib->dst, ETH_ALEN); /* DA */ + _rtw_memcpy(hdr->addr2, pattrib->src, ETH_ALEN); /* SA */ + _rtw_memcpy(hdr->addr3, get_bssid(&padapter->mlmepriv), ETH_ALEN); /* RA, BSSID */ + + /* 3 5. make payload */ + ptr = pkt_start + pattrib->hdrlen; + + switch (pmp_priv->tx.payload) { + case 0: + payload = 0x00; + break; + case 1: + payload = 0x5a; + break; + case 2: + payload = 0xa5; + break; + case 3: + payload = 0xff; + break; + default: + payload = 0x00; + break; + } + pmp_priv->TXradomBuffer = rtw_zmalloc(4096); + if (pmp_priv->TXradomBuffer == NULL) { + RTW_INFO("mp create random buffer fail!\n"); + goto exit; + } + + + for (i = 0; i < 4096; i++) + pmp_priv->TXradomBuffer[i] = rtw_random32() % 0xFF; + + /* startPlace = (u32)(rtw_random32() % 3450); */ + _rtw_memcpy(ptr, pmp_priv->TXradomBuffer, pkt_end - ptr); + /* _rtw_memset(ptr, payload, pkt_end - ptr); */ + rtw_mfree(pmp_priv->TXradomBuffer, 4096); + + /* 3 6. start thread */ +#ifdef PLATFORM_LINUX + pmp_priv->tx.PktTxThread = kthread_run(mp_xmit_packet_thread, pmp_priv, "RTW_MP_THREAD"); + if (IS_ERR(pmp_priv->tx.PktTxThread)) + RTW_INFO("Create PktTx Thread Fail !!!!!\n"); +#endif +#ifdef PLATFORM_FREEBSD + { + struct proc *p; + struct thread *td; + pmp_priv->tx.PktTxThread = kproc_kthread_add(mp_xmit_packet_thread, pmp_priv, + &p, &td, RFHIGHPID, 0, "MPXmitThread", "MPXmitThread"); + + if (pmp_priv->tx.PktTxThread < 0) + RTW_INFO("Create PktTx Thread Fail !!!!!\n"); + } +#endif + + Rtw_MPSetMacTxEDCA(padapter); +exit: + return; +} + +void SetPacketRx(PADAPTER pAdapter, u8 bStartRx, u8 bAB) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); + struct mp_priv *pmppriv = &pAdapter->mppriv; + + + if (bStartRx) { +#ifdef CONFIG_RTL8723B + phy_set_mac_reg(pAdapter, 0xe70, BIT23 | BIT22, 0x3); /* Power on adc (in RX_WAIT_CCA state) */ + write_bbreg(pAdapter, 0xa01, BIT0, bDisable);/* improve Rx performance by jerry */ +#endif + pHalData->ReceiveConfig = RCR_AAP | RCR_APM | RCR_AM | RCR_AMF | RCR_HTC_LOC_CTRL; + pHalData->ReceiveConfig |= RCR_ACRC32; + pHalData->ReceiveConfig |= RCR_APP_PHYST_RXFF | RCR_APP_ICV | RCR_APP_MIC; + + if (pmppriv->bSetRxBssid == _TRUE) { + RTW_INFO("%s: pmppriv->network_macaddr=" MAC_FMT "\n", __func__, + MAC_ARG(pmppriv->network_macaddr)); + pHalData->ReceiveConfig = 0; + pHalData->ReceiveConfig |= RCR_CBSSID_DATA | RCR_CBSSID_BCN |RCR_APM | RCR_AM | RCR_AB |RCR_AMF; + +#if defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) + write_bbreg(pAdapter, 0x550, BIT3, bEnable); +#endif + rtw_write16(pAdapter, REG_RXFLTMAP0, 0xFFEF); /* REG_RXFLTMAP0 (RX Filter Map Group 0) */ + + } else { + pHalData->ReceiveConfig |= RCR_ADF; + /* Accept all data frames */ + rtw_write16(pAdapter, REG_RXFLTMAP2, 0xFFFF); + } + + if (bAB) + pHalData->ReceiveConfig |= RCR_AB; + } else { +#ifdef CONFIG_RTL8723B + phy_set_mac_reg(pAdapter, 0xe70, BIT23 | BIT22, 0x00); /* Power off adc (in RX_WAIT_CCA state)*/ + write_bbreg(pAdapter, 0xa01, BIT0, bEnable);/* improve Rx performance by jerry */ +#endif + pHalData->ReceiveConfig = 0; + rtw_write16(pAdapter, REG_RXFLTMAP0, 0xFFFF); /* REG_RXFLTMAP0 (RX Filter Map Group 0) */ + } + + rtw_write32(pAdapter, REG_RCR, pHalData->ReceiveConfig); +} + +void ResetPhyRxPktCount(PADAPTER pAdapter) +{ + u32 i, phyrx_set = 0; + + for (i = 0; i <= 0xF; i++) { + phyrx_set = 0; + phyrx_set |= _RXERR_RPT_SEL(i); /* select */ + phyrx_set |= RXERR_RPT_RST; /* set counter to zero */ + rtw_write32(pAdapter, REG_RXERR_RPT, phyrx_set); + } +} + +static u32 GetPhyRxPktCounts(PADAPTER pAdapter, u32 selbit) +{ + /* selection */ + u32 phyrx_set = 0, count = 0; + + phyrx_set = _RXERR_RPT_SEL(selbit & 0xF); + rtw_write32(pAdapter, REG_RXERR_RPT, phyrx_set); + + /* Read packet count */ + count = rtw_read32(pAdapter, REG_RXERR_RPT) & RXERR_COUNTER_MASK; + + return count; +} + +u32 GetPhyRxPktReceived(PADAPTER pAdapter) +{ + u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0; + + OFDM_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_OFDM_MPDU_OK); + CCK_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_CCK_MPDU_OK); + HT_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_HT_MPDU_OK); + + return OFDM_cnt + CCK_cnt + HT_cnt; +} + +u32 GetPhyRxPktCRC32Error(PADAPTER pAdapter) +{ + u32 OFDM_cnt = 0, CCK_cnt = 0, HT_cnt = 0; + + OFDM_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_OFDM_MPDU_FAIL); + CCK_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_CCK_MPDU_FAIL); + HT_cnt = GetPhyRxPktCounts(pAdapter, RXERR_TYPE_HT_MPDU_FAIL); + + return OFDM_cnt + CCK_cnt + HT_cnt; +} + +/* reg 0x808[9:0]: FFT data x + * reg 0x808[22]: 0 --> 1 to get 1 FFT data y + * reg 0x8B4[15:0]: FFT data y report */ +static u32 rtw_GetPSDData(PADAPTER pAdapter, u32 point) +{ + u32 psd_val = 0; + +#if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) || defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) + u16 psd_reg = 0x910; + u16 psd_regL = 0xF44; +#else + u16 psd_reg = 0x808; + u16 psd_regL = 0x8B4; +#endif + + psd_val = rtw_read32(pAdapter, psd_reg); + + psd_val &= 0xFFBFFC00; + psd_val |= point; + + rtw_write32(pAdapter, psd_reg, psd_val); + rtw_mdelay_os(1); + psd_val |= 0x00400000; + + rtw_write32(pAdapter, psd_reg, psd_val); + rtw_mdelay_os(1); + + psd_val = rtw_read32(pAdapter, psd_regL); + psd_val &= 0x0000FFFF; + + return psd_val; +} + +/* + * pts start_point_min stop_point_max + * 128 64 64 + 128 = 192 + * 256 128 128 + 256 = 384 + * 512 256 256 + 512 = 768 + * 1024 512 512 + 1024 = 1536 + * + */ +u32 mp_query_psd(PADAPTER pAdapter, u8 *data) +{ + u32 i, psd_pts = 0, psd_start = 0, psd_stop = 0; + u32 psd_data = 0; + + +#ifdef PLATFORM_LINUX + if (!netif_running(pAdapter->pnetdev)) { + return 0; + } +#endif + + if (check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE) == _FALSE) { + return 0; + } + + if (strlen(data) == 0) { /* default value */ + psd_pts = 128; + psd_start = 64; + psd_stop = 128; + } else + sscanf(data, "pts=%d,start=%d,stop=%d", &psd_pts, &psd_start, &psd_stop); + + data[0] = '\0'; + + i = psd_start; + while (i < psd_stop) { + if (i >= psd_pts) + psd_data = rtw_GetPSDData(pAdapter, i - psd_pts); + else + psd_data = rtw_GetPSDData(pAdapter, i); + sprintf(data, "%s%x ", data, psd_data); + i++; + } + +#ifdef CONFIG_LONG_DELAY_ISSUE + rtw_msleep_os(100); +#else + rtw_mdelay_os(100); +#endif + + return strlen(data) + 1; +} + + +#if 0 +void _rtw_mp_xmit_priv(struct xmit_priv *pxmitpriv) +{ + int i, res; + _adapter *padapter = pxmitpriv->adapter; + struct xmit_frame *pxmitframe = (struct xmit_frame *) pxmitpriv->pxmit_frame_buf; + struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; + + u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; + u32 num_xmit_extbuf = NR_XMIT_EXTBUFF; + if (padapter->registrypriv.mp_mode == 0) { + max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; + num_xmit_extbuf = NR_XMIT_EXTBUFF; + } else { + max_xmit_extbuf_size = 6000; + num_xmit_extbuf = 8; + } + + pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; + for (i = 0; i < num_xmit_extbuf; i++) { + rtw_os_xmit_resource_free(padapter, pxmitbuf, (max_xmit_extbuf_size + XMITBUF_ALIGN_SZ), _FALSE); + + pxmitbuf++; + } + + if (pxmitpriv->pallocated_xmit_extbuf) + rtw_vmfree(pxmitpriv->pallocated_xmit_extbuf, num_xmit_extbuf * sizeof(struct xmit_buf) + 4); + + if (padapter->registrypriv.mp_mode == 0) { + max_xmit_extbuf_size = 6000; + num_xmit_extbuf = 8; + } else { + max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ; + num_xmit_extbuf = NR_XMIT_EXTBUFF; + } + + /* Init xmit extension buff */ + _rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue); + + pxmitpriv->pallocated_xmit_extbuf = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_buf) + 4); + + if (pxmitpriv->pallocated_xmit_extbuf == NULL) { + res = _FAIL; + goto exit; + } + + pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_xmit_extbuf), 4); + + pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; + + for (i = 0; i < num_xmit_extbuf; i++) { + _rtw_init_listhead(&pxmitbuf->list); + + pxmitbuf->priv_data = NULL; + pxmitbuf->padapter = padapter; + pxmitbuf->buf_tag = XMITBUF_MGNT; + + res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, max_xmit_extbuf_size + XMITBUF_ALIGN_SZ, _TRUE); + if (res == _FAIL) { + res = _FAIL; + goto exit; + } + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + pxmitbuf->phead = pxmitbuf->pbuf; + pxmitbuf->pend = pxmitbuf->pbuf + max_xmit_extbuf_size; + pxmitbuf->len = 0; + pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; +#endif + + rtw_list_insert_tail(&pxmitbuf->list, &(pxmitpriv->free_xmit_extbuf_queue.queue)); +#ifdef DBG_XMIT_BUF_EXT + pxmitbuf->no = i; +#endif + pxmitbuf++; + + } + + pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf; + +exit: + ; +} +#endif + +u8 +mpt_to_mgnt_rate( + IN ULONG MptRateIdx +) +{ + /* Mapped to MGN_XXX defined in MgntGen.h */ + switch (MptRateIdx) { + /* CCK rate. */ + case MPT_RATE_1M: + return MGN_1M; + case MPT_RATE_2M: + return MGN_2M; + case MPT_RATE_55M: + return MGN_5_5M; + case MPT_RATE_11M: + return MGN_11M; + + /* OFDM rate. */ + case MPT_RATE_6M: + return MGN_6M; + case MPT_RATE_9M: + return MGN_9M; + case MPT_RATE_12M: + return MGN_12M; + case MPT_RATE_18M: + return MGN_18M; + case MPT_RATE_24M: + return MGN_24M; + case MPT_RATE_36M: + return MGN_36M; + case MPT_RATE_48M: + return MGN_48M; + case MPT_RATE_54M: + return MGN_54M; + + /* HT rate. */ + case MPT_RATE_MCS0: + return MGN_MCS0; + case MPT_RATE_MCS1: + return MGN_MCS1; + case MPT_RATE_MCS2: + return MGN_MCS2; + case MPT_RATE_MCS3: + return MGN_MCS3; + case MPT_RATE_MCS4: + return MGN_MCS4; + case MPT_RATE_MCS5: + return MGN_MCS5; + case MPT_RATE_MCS6: + return MGN_MCS6; + case MPT_RATE_MCS7: + return MGN_MCS7; + case MPT_RATE_MCS8: + return MGN_MCS8; + case MPT_RATE_MCS9: + return MGN_MCS9; + case MPT_RATE_MCS10: + return MGN_MCS10; + case MPT_RATE_MCS11: + return MGN_MCS11; + case MPT_RATE_MCS12: + return MGN_MCS12; + case MPT_RATE_MCS13: + return MGN_MCS13; + case MPT_RATE_MCS14: + return MGN_MCS14; + case MPT_RATE_MCS15: + return MGN_MCS15; + case MPT_RATE_MCS16: + return MGN_MCS16; + case MPT_RATE_MCS17: + return MGN_MCS17; + case MPT_RATE_MCS18: + return MGN_MCS18; + case MPT_RATE_MCS19: + return MGN_MCS19; + case MPT_RATE_MCS20: + return MGN_MCS20; + case MPT_RATE_MCS21: + return MGN_MCS21; + case MPT_RATE_MCS22: + return MGN_MCS22; + case MPT_RATE_MCS23: + return MGN_MCS23; + case MPT_RATE_MCS24: + return MGN_MCS24; + case MPT_RATE_MCS25: + return MGN_MCS25; + case MPT_RATE_MCS26: + return MGN_MCS26; + case MPT_RATE_MCS27: + return MGN_MCS27; + case MPT_RATE_MCS28: + return MGN_MCS28; + case MPT_RATE_MCS29: + return MGN_MCS29; + case MPT_RATE_MCS30: + return MGN_MCS30; + case MPT_RATE_MCS31: + return MGN_MCS31; + + /* VHT rate. */ + case MPT_RATE_VHT1SS_MCS0: + return MGN_VHT1SS_MCS0; + case MPT_RATE_VHT1SS_MCS1: + return MGN_VHT1SS_MCS1; + case MPT_RATE_VHT1SS_MCS2: + return MGN_VHT1SS_MCS2; + case MPT_RATE_VHT1SS_MCS3: + return MGN_VHT1SS_MCS3; + case MPT_RATE_VHT1SS_MCS4: + return MGN_VHT1SS_MCS4; + case MPT_RATE_VHT1SS_MCS5: + return MGN_VHT1SS_MCS5; + case MPT_RATE_VHT1SS_MCS6: + return MGN_VHT1SS_MCS6; + case MPT_RATE_VHT1SS_MCS7: + return MGN_VHT1SS_MCS7; + case MPT_RATE_VHT1SS_MCS8: + return MGN_VHT1SS_MCS8; + case MPT_RATE_VHT1SS_MCS9: + return MGN_VHT1SS_MCS9; + case MPT_RATE_VHT2SS_MCS0: + return MGN_VHT2SS_MCS0; + case MPT_RATE_VHT2SS_MCS1: + return MGN_VHT2SS_MCS1; + case MPT_RATE_VHT2SS_MCS2: + return MGN_VHT2SS_MCS2; + case MPT_RATE_VHT2SS_MCS3: + return MGN_VHT2SS_MCS3; + case MPT_RATE_VHT2SS_MCS4: + return MGN_VHT2SS_MCS4; + case MPT_RATE_VHT2SS_MCS5: + return MGN_VHT2SS_MCS5; + case MPT_RATE_VHT2SS_MCS6: + return MGN_VHT2SS_MCS6; + case MPT_RATE_VHT2SS_MCS7: + return MGN_VHT2SS_MCS7; + case MPT_RATE_VHT2SS_MCS8: + return MGN_VHT2SS_MCS8; + case MPT_RATE_VHT2SS_MCS9: + return MGN_VHT2SS_MCS9; + case MPT_RATE_VHT3SS_MCS0: + return MGN_VHT3SS_MCS0; + case MPT_RATE_VHT3SS_MCS1: + return MGN_VHT3SS_MCS1; + case MPT_RATE_VHT3SS_MCS2: + return MGN_VHT3SS_MCS2; + case MPT_RATE_VHT3SS_MCS3: + return MGN_VHT3SS_MCS3; + case MPT_RATE_VHT3SS_MCS4: + return MGN_VHT3SS_MCS4; + case MPT_RATE_VHT3SS_MCS5: + return MGN_VHT3SS_MCS5; + case MPT_RATE_VHT3SS_MCS6: + return MGN_VHT3SS_MCS6; + case MPT_RATE_VHT3SS_MCS7: + return MGN_VHT3SS_MCS7; + case MPT_RATE_VHT3SS_MCS8: + return MGN_VHT3SS_MCS8; + case MPT_RATE_VHT3SS_MCS9: + return MGN_VHT3SS_MCS9; + case MPT_RATE_VHT4SS_MCS0: + return MGN_VHT4SS_MCS0; + case MPT_RATE_VHT4SS_MCS1: + return MGN_VHT4SS_MCS1; + case MPT_RATE_VHT4SS_MCS2: + return MGN_VHT4SS_MCS2; + case MPT_RATE_VHT4SS_MCS3: + return MGN_VHT4SS_MCS3; + case MPT_RATE_VHT4SS_MCS4: + return MGN_VHT4SS_MCS4; + case MPT_RATE_VHT4SS_MCS5: + return MGN_VHT4SS_MCS5; + case MPT_RATE_VHT4SS_MCS6: + return MGN_VHT4SS_MCS6; + case MPT_RATE_VHT4SS_MCS7: + return MGN_VHT4SS_MCS7; + case MPT_RATE_VHT4SS_MCS8: + return MGN_VHT4SS_MCS8; + case MPT_RATE_VHT4SS_MCS9: + return MGN_VHT4SS_MCS9; + + case MPT_RATE_LAST: /* fully automatiMGN_VHT2SS_MCS1; */ + default: + RTW_INFO("<===mpt_to_mgnt_rate(), Invalid Rate: %d!!\n", MptRateIdx); + return 0x0; + } +} + + +u8 HwRateToMPTRate(u8 rate) +{ + u8 ret_rate = MGN_1M; + + switch (rate) { + case DESC_RATE1M: + ret_rate = MPT_RATE_1M; + break; + case DESC_RATE2M: + ret_rate = MPT_RATE_2M; + break; + case DESC_RATE5_5M: + ret_rate = MPT_RATE_55M; + break; + case DESC_RATE11M: + ret_rate = MPT_RATE_11M; + break; + case DESC_RATE6M: + ret_rate = MPT_RATE_6M; + break; + case DESC_RATE9M: + ret_rate = MPT_RATE_9M; + break; + case DESC_RATE12M: + ret_rate = MPT_RATE_12M; + break; + case DESC_RATE18M: + ret_rate = MPT_RATE_18M; + break; + case DESC_RATE24M: + ret_rate = MPT_RATE_24M; + break; + case DESC_RATE36M: + ret_rate = MPT_RATE_36M; + break; + case DESC_RATE48M: + ret_rate = MPT_RATE_48M; + break; + case DESC_RATE54M: + ret_rate = MPT_RATE_54M; + break; + case DESC_RATEMCS0: + ret_rate = MPT_RATE_MCS0; + break; + case DESC_RATEMCS1: + ret_rate = MPT_RATE_MCS1; + break; + case DESC_RATEMCS2: + ret_rate = MPT_RATE_MCS2; + break; + case DESC_RATEMCS3: + ret_rate = MPT_RATE_MCS3; + break; + case DESC_RATEMCS4: + ret_rate = MPT_RATE_MCS4; + break; + case DESC_RATEMCS5: + ret_rate = MPT_RATE_MCS5; + break; + case DESC_RATEMCS6: + ret_rate = MPT_RATE_MCS6; + break; + case DESC_RATEMCS7: + ret_rate = MPT_RATE_MCS7; + break; + case DESC_RATEMCS8: + ret_rate = MPT_RATE_MCS8; + break; + case DESC_RATEMCS9: + ret_rate = MPT_RATE_MCS9; + break; + case DESC_RATEMCS10: + ret_rate = MPT_RATE_MCS10; + break; + case DESC_RATEMCS11: + ret_rate = MPT_RATE_MCS11; + break; + case DESC_RATEMCS12: + ret_rate = MPT_RATE_MCS12; + break; + case DESC_RATEMCS13: + ret_rate = MPT_RATE_MCS13; + break; + case DESC_RATEMCS14: + ret_rate = MPT_RATE_MCS14; + break; + case DESC_RATEMCS15: + ret_rate = MPT_RATE_MCS15; + break; + case DESC_RATEMCS16: + ret_rate = MPT_RATE_MCS16; + break; + case DESC_RATEMCS17: + ret_rate = MPT_RATE_MCS17; + break; + case DESC_RATEMCS18: + ret_rate = MPT_RATE_MCS18; + break; + case DESC_RATEMCS19: + ret_rate = MPT_RATE_MCS19; + break; + case DESC_RATEMCS20: + ret_rate = MPT_RATE_MCS20; + break; + case DESC_RATEMCS21: + ret_rate = MPT_RATE_MCS21; + break; + case DESC_RATEMCS22: + ret_rate = MPT_RATE_MCS22; + break; + case DESC_RATEMCS23: + ret_rate = MPT_RATE_MCS23; + break; + case DESC_RATEMCS24: + ret_rate = MPT_RATE_MCS24; + break; + case DESC_RATEMCS25: + ret_rate = MPT_RATE_MCS25; + break; + case DESC_RATEMCS26: + ret_rate = MPT_RATE_MCS26; + break; + case DESC_RATEMCS27: + ret_rate = MPT_RATE_MCS27; + break; + case DESC_RATEMCS28: + ret_rate = MPT_RATE_MCS28; + break; + case DESC_RATEMCS29: + ret_rate = MPT_RATE_MCS29; + break; + case DESC_RATEMCS30: + ret_rate = MPT_RATE_MCS30; + break; + case DESC_RATEMCS31: + ret_rate = MPT_RATE_MCS31; + break; + case DESC_RATEVHTSS1MCS0: + ret_rate = MPT_RATE_VHT1SS_MCS0; + break; + case DESC_RATEVHTSS1MCS1: + ret_rate = MPT_RATE_VHT1SS_MCS1; + break; + case DESC_RATEVHTSS1MCS2: + ret_rate = MPT_RATE_VHT1SS_MCS2; + break; + case DESC_RATEVHTSS1MCS3: + ret_rate = MPT_RATE_VHT1SS_MCS3; + break; + case DESC_RATEVHTSS1MCS4: + ret_rate = MPT_RATE_VHT1SS_MCS4; + break; + case DESC_RATEVHTSS1MCS5: + ret_rate = MPT_RATE_VHT1SS_MCS5; + break; + case DESC_RATEVHTSS1MCS6: + ret_rate = MPT_RATE_VHT1SS_MCS6; + break; + case DESC_RATEVHTSS1MCS7: + ret_rate = MPT_RATE_VHT1SS_MCS7; + break; + case DESC_RATEVHTSS1MCS8: + ret_rate = MPT_RATE_VHT1SS_MCS8; + break; + case DESC_RATEVHTSS1MCS9: + ret_rate = MPT_RATE_VHT1SS_MCS9; + break; + case DESC_RATEVHTSS2MCS0: + ret_rate = MPT_RATE_VHT2SS_MCS0; + break; + case DESC_RATEVHTSS2MCS1: + ret_rate = MPT_RATE_VHT2SS_MCS1; + break; + case DESC_RATEVHTSS2MCS2: + ret_rate = MPT_RATE_VHT2SS_MCS2; + break; + case DESC_RATEVHTSS2MCS3: + ret_rate = MPT_RATE_VHT2SS_MCS3; + break; + case DESC_RATEVHTSS2MCS4: + ret_rate = MPT_RATE_VHT2SS_MCS4; + break; + case DESC_RATEVHTSS2MCS5: + ret_rate = MPT_RATE_VHT2SS_MCS5; + break; + case DESC_RATEVHTSS2MCS6: + ret_rate = MPT_RATE_VHT2SS_MCS6; + break; + case DESC_RATEVHTSS2MCS7: + ret_rate = MPT_RATE_VHT2SS_MCS7; + break; + case DESC_RATEVHTSS2MCS8: + ret_rate = MPT_RATE_VHT2SS_MCS8; + break; + case DESC_RATEVHTSS2MCS9: + ret_rate = MPT_RATE_VHT2SS_MCS9; + break; + case DESC_RATEVHTSS3MCS0: + ret_rate = MPT_RATE_VHT3SS_MCS0; + break; + case DESC_RATEVHTSS3MCS1: + ret_rate = MPT_RATE_VHT3SS_MCS1; + break; + case DESC_RATEVHTSS3MCS2: + ret_rate = MPT_RATE_VHT3SS_MCS2; + break; + case DESC_RATEVHTSS3MCS3: + ret_rate = MPT_RATE_VHT3SS_MCS3; + break; + case DESC_RATEVHTSS3MCS4: + ret_rate = MPT_RATE_VHT3SS_MCS4; + break; + case DESC_RATEVHTSS3MCS5: + ret_rate = MPT_RATE_VHT3SS_MCS5; + break; + case DESC_RATEVHTSS3MCS6: + ret_rate = MPT_RATE_VHT3SS_MCS6; + break; + case DESC_RATEVHTSS3MCS7: + ret_rate = MPT_RATE_VHT3SS_MCS7; + break; + case DESC_RATEVHTSS3MCS8: + ret_rate = MPT_RATE_VHT3SS_MCS8; + break; + case DESC_RATEVHTSS3MCS9: + ret_rate = MPT_RATE_VHT3SS_MCS9; + break; + case DESC_RATEVHTSS4MCS0: + ret_rate = MPT_RATE_VHT4SS_MCS0; + break; + case DESC_RATEVHTSS4MCS1: + ret_rate = MPT_RATE_VHT4SS_MCS1; + break; + case DESC_RATEVHTSS4MCS2: + ret_rate = MPT_RATE_VHT4SS_MCS2; + break; + case DESC_RATEVHTSS4MCS3: + ret_rate = MPT_RATE_VHT4SS_MCS3; + break; + case DESC_RATEVHTSS4MCS4: + ret_rate = MPT_RATE_VHT4SS_MCS4; + break; + case DESC_RATEVHTSS4MCS5: + ret_rate = MPT_RATE_VHT4SS_MCS5; + break; + case DESC_RATEVHTSS4MCS6: + ret_rate = MPT_RATE_VHT4SS_MCS6; + break; + case DESC_RATEVHTSS4MCS7: + ret_rate = MPT_RATE_VHT4SS_MCS7; + break; + case DESC_RATEVHTSS4MCS8: + ret_rate = MPT_RATE_VHT4SS_MCS8; + break; + case DESC_RATEVHTSS4MCS9: + ret_rate = MPT_RATE_VHT4SS_MCS9; + break; + + default: + RTW_INFO("hw_rate_to_m_rate(): Non supported Rate [%x]!!!\n", rate); + break; + } + return ret_rate; +} + +u8 rtw_mpRateParseFunc(PADAPTER pAdapter, u8 *targetStr) +{ + u16 i = 0; + u8 *rateindex_Array[] = { "1M", "2M", "5.5M", "11M", "6M", "9M", "12M", "18M", "24M", "36M", "48M", "54M", + "HTMCS0", "HTMCS1", "HTMCS2", "HTMCS3", "HTMCS4", "HTMCS5", "HTMCS6", "HTMCS7", + "HTMCS8", "HTMCS9", "HTMCS10", "HTMCS11", "HTMCS12", "HTMCS13", "HTMCS14", "HTMCS15", + "HTMCS16", "HTMCS17", "HTMCS18", "HTMCS19", "HTMCS20", "HTMCS21", "HTMCS22", "HTMCS23", + "HTMCS24", "HTMCS25", "HTMCS26", "HTMCS27", "HTMCS28", "HTMCS29", "HTMCS30", "HTMCS31", + "VHT1MCS0", "VHT1MCS1", "VHT1MCS2", "VHT1MCS3", "VHT1MCS4", "VHT1MCS5", "VHT1MCS6", "VHT1MCS7", "VHT1MCS8", "VHT1MCS9", + "VHT2MCS0", "VHT2MCS1", "VHT2MCS2", "VHT2MCS3", "VHT2MCS4", "VHT2MCS5", "VHT2MCS6", "VHT2MCS7", "VHT2MCS8", "VHT2MCS9", + "VHT3MCS0", "VHT3MCS1", "VHT3MCS2", "VHT3MCS3", "VHT3MCS4", "VHT3MCS5", "VHT3MCS6", "VHT3MCS7", "VHT3MCS8", "VHT3MCS9", + "VHT4MCS0", "VHT4MCS1", "VHT4MCS2", "VHT4MCS3", "VHT4MCS4", "VHT4MCS5", "VHT4MCS6", "VHT4MCS7", "VHT4MCS8", "VHT4MCS9" + }; + + for (i = 0; i <= 83; i++) { + if (strcmp(targetStr, rateindex_Array[i]) == 0) { + RTW_INFO("%s , index = %d\n", __func__ , i); + return i; + } + } + + printk("%s ,please input a Data RATE String as:", __func__); + for (i = 0; i <= 83; i++) { + printk("%s ", rateindex_Array[i]); + if (i % 10 == 0) + printk("\n"); + } + return _FAIL; +} + +ULONG mpt_ProQueryCalTxPower( + PADAPTER pAdapter, + u8 RfPath +) +{ + + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + + ULONG TxPower = 1; + u1Byte rate = 0; + struct txpwr_idx_comp tic; + u8 mgn_rate = mpt_to_mgnt_rate(pMptCtx->mpt_rate_index); + + TxPower = rtw_hal_get_tx_power_index(pAdapter, RfPath, mgn_rate, pHalData->current_channel_bw, pHalData->current_channel, &tic); + + RTW_INFO("bw=%d, ch=%d, rate=%d, txPower:%u = %u + (%d=%d:%d) + (%d) + (%d)\n", + pHalData->current_channel_bw, pHalData->current_channel, mgn_rate + , TxPower, tic.base, (tic.by_rate > tic.limit ? tic.limit : tic.by_rate), tic.by_rate, tic.limit, tic.tpt, tic.ebias); + + pAdapter->mppriv.txpoweridx = (u8)TxPower; + pMptCtx->TxPwrLevel[ODM_RF_PATH_A] = (u8)TxPower; + pMptCtx->TxPwrLevel[ODM_RF_PATH_B] = (u8)TxPower; + pMptCtx->TxPwrLevel[ODM_RF_PATH_C] = (u8)TxPower; + pMptCtx->TxPwrLevel[ODM_RF_PATH_D] = (u8)TxPower; + hal_mpt_SetTxPower(pAdapter); + + return TxPower; +} + +#ifdef CONFIG_MP_VHT_HW_TX_MODE +static inline void dump_buf(u8 *buf, u32 len) +{ + u32 i; + + RTW_INFO("-----------------Len %d----------------\n", len); + for (i = 0; i < len; i++) + RTW_INFO("%2.2x-", *(buf + i)); + RTW_INFO("\n"); +} + +void ByteToBit( + UCHAR *out, + bool *in, + UCHAR in_size) +{ + UCHAR i = 0, j = 0; + + for (i = 0; i < in_size; i++) { + for (j = 0; j < 8; j++) { + if (in[8 * i + j]) + out[i] |= (1 << j); + } + } +} + + +void CRC16_generator( + bool *out, + bool *in, + UCHAR in_size +) +{ + UCHAR i = 0; + bool temp = 0, reg[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + + for (i = 0; i < in_size; i++) {/* take one's complement and bit reverse*/ + temp = in[i] ^ reg[15]; + reg[15] = reg[14]; + reg[14] = reg[13]; + reg[13] = reg[12]; + reg[12] = reg[11]; + reg[11] = reg[10]; + reg[10] = reg[9]; + reg[9] = reg[8]; + reg[8] = reg[7]; + + reg[7] = reg[6]; + reg[6] = reg[5]; + reg[5] = reg[4]; + reg[4] = reg[3]; + reg[3] = reg[2]; + reg[2] = reg[1]; + reg[1] = reg[0]; + reg[12] = reg[12] ^ temp; + reg[5] = reg[5] ^ temp; + reg[0] = temp; + } + for (i = 0; i < 16; i++) /* take one's complement and bit reverse*/ + out[i] = 1 - reg[15 - i]; +} + + + +/*======================================== + SFD SIGNAL SERVICE LENGTH CRC + 16 bit 8 bit 8 bit 16 bit 16 bit +========================================*/ +void CCK_generator( + PRT_PMAC_TX_INFO pPMacTxInfo, + PRT_PMAC_PKT_INFO pPMacPktInfo +) +{ + double ratio = 0; + bool crc16_in[32] = {0}, crc16_out[16] = {0}; + bool LengthExtBit; + double LengthExact; + double LengthPSDU; + UCHAR i; + UINT PacketLength = pPMacTxInfo->PacketLength; + + if (pPMacTxInfo->bSPreamble) + pPMacTxInfo->SFD = 0x05CF; + else + pPMacTxInfo->SFD = 0xF3A0; + + switch (pPMacPktInfo->MCS) { + case 0: + pPMacTxInfo->SignalField = 0xA; + ratio = 8; + /*CRC16_in(1,0:7)=[0 1 0 1 0 0 0 0]*/ + crc16_in[1] = crc16_in[3] = 1; + break; + case 1: + pPMacTxInfo->SignalField = 0x14; + ratio = 4; + /*CRC16_in(1,0:7)=[0 0 1 0 1 0 0 0];*/ + crc16_in[2] = crc16_in[4] = 1; + break; + case 2: + pPMacTxInfo->SignalField = 0x37; + ratio = 8.0 / 5.5; + /*CRC16_in(1,0:7)=[1 1 1 0 1 1 0 0];*/ + crc16_in[0] = crc16_in[1] = crc16_in[2] = crc16_in[4] = crc16_in[5] = 1; + break; + case 3: + pPMacTxInfo->SignalField = 0x6E; + ratio = 8.0 / 11.0; + /*CRC16_in(1,0:7)=[0 1 1 1 0 1 1 0];*/ + crc16_in[1] = crc16_in[2] = crc16_in[3] = crc16_in[5] = crc16_in[6] = 1; + break; + } + + LengthExact = PacketLength * ratio; + LengthPSDU = ceil(LengthExact); + + if ((pPMacPktInfo->MCS == 3) && + ((LengthPSDU - LengthExact) >= 0.727 || (LengthPSDU - LengthExact) <= -0.727)) + LengthExtBit = 1; + else + LengthExtBit = 0; + + + pPMacTxInfo->LENGTH = (UINT)LengthPSDU; + /* CRC16_in(1,16:31) = LengthPSDU[0:15]*/ + for (i = 0; i < 16; i++) + crc16_in[i + 16] = (pPMacTxInfo->LENGTH >> i) & 0x1; + + if (LengthExtBit == 0) { + pPMacTxInfo->ServiceField = 0x0; + /* CRC16_in(1,8:15) = [0 0 0 0 0 0 0 0];*/ + } else { + pPMacTxInfo->ServiceField = 0x80; + /*CRC16_in(1,8:15)=[0 0 0 0 0 0 0 1];*/ + crc16_in[15] = 1; + } + + CRC16_generator(crc16_out, crc16_in, 32); + + _rtw_memset(pPMacTxInfo->CRC16, 0, 2); + ByteToBit(pPMacTxInfo->CRC16, crc16_out, 2); + +} + + +void PMAC_Get_Pkt_Param( + PRT_PMAC_TX_INFO pPMacTxInfo, + PRT_PMAC_PKT_INFO pPMacPktInfo) +{ + + UCHAR TX_RATE_HEX = 0, MCS = 0; + UCHAR TX_RATE = pPMacTxInfo->TX_RATE; + + /* TX_RATE & Nss */ + if (MPT_IS_2SS_RATE(TX_RATE)) + pPMacPktInfo->Nss = 2; + else if (MPT_IS_3SS_RATE(TX_RATE)) + pPMacPktInfo->Nss = 3; + else if (MPT_IS_4SS_RATE(TX_RATE)) + pPMacPktInfo->Nss = 4; + else + pPMacPktInfo->Nss = 1; + + RTW_INFO("PMacTxInfo.Nss =%d\n", pPMacPktInfo->Nss); + + /* MCS & TX_RATE_HEX*/ + if (MPT_IS_CCK_RATE(TX_RATE)) { + switch (TX_RATE) { + case MPT_RATE_1M: + TX_RATE_HEX = MCS = 0; + break; + case MPT_RATE_2M: + TX_RATE_HEX = MCS = 1; + break; + case MPT_RATE_55M: + TX_RATE_HEX = MCS = 2; + break; + case MPT_RATE_11M: + TX_RATE_HEX = MCS = 3; + break; + } + } else if (MPT_IS_OFDM_RATE(TX_RATE)) { + MCS = TX_RATE - MPT_RATE_6M; + TX_RATE_HEX = MCS + 4; + } else if (MPT_IS_HT_RATE(TX_RATE)) { + MCS = TX_RATE - MPT_RATE_MCS0; + TX_RATE_HEX = MCS + 12; + } else if (MPT_IS_VHT_RATE(TX_RATE)) { + TX_RATE_HEX = TX_RATE - MPT_RATE_VHT1SS_MCS0 + 44; + + if (MPT_IS_VHT_2S_RATE(TX_RATE)) + MCS = TX_RATE - MPT_RATE_VHT2SS_MCS0; + else if (MPT_IS_VHT_3S_RATE(TX_RATE)) + MCS = TX_RATE - MPT_RATE_VHT3SS_MCS0; + else if (MPT_IS_VHT_4S_RATE(TX_RATE)) + MCS = TX_RATE - MPT_RATE_VHT4SS_MCS0; + else + MCS = TX_RATE - MPT_RATE_VHT1SS_MCS0; + } + + pPMacPktInfo->MCS = MCS; + pPMacTxInfo->TX_RATE_HEX = TX_RATE_HEX; + + RTW_INFO(" MCS=%d, TX_RATE_HEX =0x%x\n", MCS, pPMacTxInfo->TX_RATE_HEX); + /* mSTBC & Nsts*/ + pPMacPktInfo->Nsts = pPMacPktInfo->Nss; + if (pPMacTxInfo->bSTBC) { + if (pPMacPktInfo->Nss == 1) { + pPMacTxInfo->m_STBC = 2; + pPMacPktInfo->Nsts = pPMacPktInfo->Nss * 2; + } else + pPMacTxInfo->m_STBC = 1; + } else + pPMacTxInfo->m_STBC = 1; +} + + +UINT LDPC_parameter_generator( + UINT N_pld_int, + UINT N_CBPSS, + UINT N_SS, + UINT R, + UINT m_STBC, + UINT N_TCB_int +) +{ + double CR = 0.; + double N_pld = (double)N_pld_int; + double N_TCB = (double)N_TCB_int; + double N_CW = 0., N_shrt = 0., N_spcw = 0., N_fshrt = 0.; + double L_LDPC = 0., K_LDPC = 0., L_LDPC_info = 0.; + double N_punc = 0., N_ppcw = 0., N_fpunc = 0., N_rep = 0., N_rpcw = 0., N_frep = 0.; + double R_eff = 0.; + UINT VHTSIGA2B3 = 0;/* extra symbol from VHT-SIG-A2 Bit 3*/ + + if (R == 0) + CR = 0.5; + else if (R == 1) + CR = 2. / 3.; + else if (R == 2) + CR = 3. / 4.; + else if (R == 3) + CR = 5. / 6.; + + if (N_TCB <= 648.) { + N_CW = 1.; + if (N_TCB >= N_pld + 912.*(1. - CR)) + L_LDPC = 1296.; + else + L_LDPC = 648.; + } else if (N_TCB <= 1296.) { + N_CW = 1.; + if (N_TCB >= (double)N_pld + 1464.*(1. - CR)) + L_LDPC = 1944.; + else + L_LDPC = 1296.; + } else if (N_TCB <= 1944.) { + N_CW = 1.; + L_LDPC = 1944.; + } else if (N_TCB <= 2592.) { + N_CW = 2.; + if (N_TCB >= N_pld + 2916.*(1. - CR)) + L_LDPC = 1944.; + else + L_LDPC = 1296.; + } else { + N_CW = ceil(N_pld / 1944. / CR); + L_LDPC = 1944.; + } + /* Number of information bits per CW*/ + K_LDPC = L_LDPC * CR; + /* Number of shortening bits max(0, (N_CW * L_LDPC * R) - N_pld)*/ + N_shrt = (N_CW * K_LDPC - N_pld) > 0. ? (N_CW * K_LDPC - N_pld) : 0.; + /* Number of shortening bits per CW N_spcw = rtfloor(N_shrt/N_CW)*/ + N_spcw = rtfloor(N_shrt / N_CW); + /* The first N_fshrt CWs shorten 1 bit more*/ + N_fshrt = (double)((int)N_shrt % (int)N_CW); + /* Number of data bits for the last N_CW-N_fshrt CWs*/ + L_LDPC_info = K_LDPC - N_spcw; + /* Number of puncturing bits*/ + N_punc = (N_CW * L_LDPC - N_TCB - N_shrt) > 0. ? (N_CW * L_LDPC - N_TCB - N_shrt) : 0.; + if (((N_punc > .1 * N_CW * L_LDPC * (1. - CR)) && (N_shrt < 1.2 * N_punc * CR / (1. - CR))) || + (N_punc > 0.3 * N_CW * L_LDPC * (1. - CR))) { + /*cout << "*** N_TCB and N_punc are Recomputed ***" << endl;*/ + VHTSIGA2B3 = 1; + N_TCB += (double)N_CBPSS * N_SS * m_STBC; + N_punc = (N_CW * L_LDPC - N_TCB - N_shrt) > 0. ? (N_CW * L_LDPC - N_TCB - N_shrt) : 0.; + } else + VHTSIGA2B3 = 0; + + return VHTSIGA2B3; +} /* function end of LDPC_parameter_generator */ + +/*======================================== + Data field of PPDU + Get N_sym and SIGA2BB3 +========================================*/ +void PMAC_Nsym_generator( + PRT_PMAC_TX_INFO pPMacTxInfo, + PRT_PMAC_PKT_INFO pPMacPktInfo) +{ + UINT SIGA2B3 = 0; + UCHAR TX_RATE = pPMacTxInfo->TX_RATE; + + UINT R, R_list[10] = {0, 0, 2, 0, 2, 1, 2, 3, 2, 3}; + double CR = 0; + UINT N_SD, N_BPSC_list[10] = {1, 2, 2, 4, 4, 6, 6, 6, 8, 8}; + UINT N_BPSC = 0, N_CBPS = 0, N_DBPS = 0, N_ES = 0, N_SYM = 0, N_pld = 0, N_TCB = 0; + int D_R = 0; + + RTW_INFO("TX_RATE = %d\n", TX_RATE); + /* N_SD*/ + if (pPMacTxInfo->BandWidth == 0) + N_SD = 52; + else if (pPMacTxInfo->BandWidth == 1) + N_SD = 108; + else + N_SD = 234; + + if (MPT_IS_HT_RATE(TX_RATE)) { + UCHAR MCS_temp; + + if (pPMacPktInfo->MCS > 23) + MCS_temp = pPMacPktInfo->MCS - 24; + else if (pPMacPktInfo->MCS > 15) + MCS_temp = pPMacPktInfo->MCS - 16; + else if (pPMacPktInfo->MCS > 7) + MCS_temp = pPMacPktInfo->MCS - 8; + else + MCS_temp = pPMacPktInfo->MCS; + + R = R_list[MCS_temp]; + + switch (R) { + case 0: + CR = .5; + break; + case 1: + CR = 2. / 3.; + break; + case 2: + CR = 3. / 4.; + break; + case 3: + CR = 5. / 6.; + break; + } + + N_BPSC = N_BPSC_list[MCS_temp]; + N_CBPS = N_BPSC * N_SD * pPMacPktInfo->Nss; + N_DBPS = (UINT)((double)N_CBPS * CR); + + if (pPMacTxInfo->bLDPC == FALSE) { + N_ES = (UINT)ceil((double)(N_DBPS * pPMacPktInfo->Nss) / 4. / 300.); + RTW_INFO("N_ES = %d\n", N_ES); + + /* N_SYM = m_STBC* (8*length+16+6*N_ES) / (m_STBC*N_DBPS)*/ + N_SYM = pPMacTxInfo->m_STBC * (UINT)ceil((double)(pPMacTxInfo->PacketLength * 8 + 16 + N_ES * 6) / + (double)(N_DBPS * pPMacTxInfo->m_STBC)); + + } else { + N_ES = 1; + /* N_pld = length * 8 + 16*/ + N_pld = pPMacTxInfo->PacketLength * 8 + 16; + RTW_INFO("N_pld = %d\n", N_pld); + N_SYM = pPMacTxInfo->m_STBC * (UINT)ceil((double)(N_pld) / + (double)(N_DBPS * pPMacTxInfo->m_STBC)); + RTW_INFO("N_SYM = %d\n", N_SYM); + /* N_avbits = N_CBPS *m_STBC *(N_pld/N_CBPS*R*m_STBC)*/ + N_TCB = N_CBPS * N_SYM; + RTW_INFO("N_TCB = %d\n", N_TCB); + SIGA2B3 = LDPC_parameter_generator(N_pld, N_CBPS, pPMacPktInfo->Nss, R, pPMacTxInfo->m_STBC, N_TCB); + RTW_INFO("SIGA2B3 = %d\n", SIGA2B3); + N_SYM = N_SYM + SIGA2B3 * pPMacTxInfo->m_STBC; + RTW_INFO("N_SYM = %d\n", N_SYM); + } + } else if (MPT_IS_VHT_RATE(TX_RATE)) { + R = R_list[pPMacPktInfo->MCS]; + + switch (R) { + case 0: + CR = .5; + break; + case 1: + CR = 2. / 3.; + break; + case 2: + CR = 3. / 4.; + break; + case 3: + CR = 5. / 6.; + break; + } + N_BPSC = N_BPSC_list[pPMacPktInfo->MCS]; + N_CBPS = N_BPSC * N_SD * pPMacPktInfo->Nss; + N_DBPS = (UINT)((double)N_CBPS * CR); + if (pPMacTxInfo->bLDPC == FALSE) { + if (pPMacTxInfo->bSGI) + N_ES = (UINT)ceil((double)(N_DBPS) / 3.6 / 600.); + else + N_ES = (UINT)ceil((double)(N_DBPS) / 4. / 600.); + /* N_SYM = m_STBC* (8*length+16+6*N_ES) / (m_STBC*N_DBPS)*/ + N_SYM = pPMacTxInfo->m_STBC * (UINT)ceil((double)(pPMacTxInfo->PacketLength * 8 + 16 + N_ES * 6) / (double)(N_DBPS * pPMacTxInfo->m_STBC)); + SIGA2B3 = 0; + } else { + N_ES = 1; + /* N_SYM = m_STBC* (8*length+N_service) / (m_STBC*N_DBPS)*/ + N_SYM = pPMacTxInfo->m_STBC * (UINT)ceil((double)(pPMacTxInfo->PacketLength * 8 + 16) / (double)(N_DBPS * pPMacTxInfo->m_STBC)); + /* N_avbits = N_sys_init * N_CBPS*/ + N_TCB = N_CBPS * N_SYM; + /* N_pld = N_sys_init * N_DBPS*/ + N_pld = N_SYM * N_DBPS; + SIGA2B3 = LDPC_parameter_generator(N_pld, N_CBPS, pPMacPktInfo->Nss, R, pPMacTxInfo->m_STBC, N_TCB); + N_SYM = N_SYM + SIGA2B3 * pPMacTxInfo->m_STBC; + } + + switch (R) { + case 0: + D_R = 2; + break; + case 1: + D_R = 3; + break; + case 2: + D_R = 4; + break; + case 3: + D_R = 6; + break; + } + + if (((N_CBPS / N_ES) % D_R) != 0) { + RTW_INFO("MCS= %d is not supported when Nss=%d and BW= %d !!\n", pPMacPktInfo->MCS, pPMacPktInfo->Nss, pPMacTxInfo->BandWidth); + return; + } + + RTW_INFO("MCS= %d Nss=%d and BW= %d !!\n", pPMacPktInfo->MCS, pPMacPktInfo->Nss, pPMacTxInfo->BandWidth); + } + + pPMacPktInfo->N_sym = N_SYM; + pPMacPktInfo->SIGA2B3 = SIGA2B3; +} + +/*======================================== + L-SIG Rate R Length P Tail + 4b 1b 12b 1b 6b +========================================*/ + +void L_SIG_generator( + UINT N_SYM, /* Max: 750*/ + PRT_PMAC_TX_INFO pPMacTxInfo, + PRT_PMAC_PKT_INFO pPMacPktInfo) +{ + u8 sig_bi[24] = {0}; /* 24 BIT*/ + UINT mode, LENGTH; + int i; + + if (MPT_IS_OFDM_RATE(pPMacTxInfo->TX_RATE)) { + mode = pPMacPktInfo->MCS; + LENGTH = pPMacTxInfo->PacketLength; + } else { + UCHAR N_LTF; + double T_data; + UINT OFDM_symbol; + + mode = 0; + + /* Table 20-13 Num of HT-DLTFs request*/ + if (pPMacPktInfo->Nsts <= 2) + N_LTF = pPMacPktInfo->Nsts; + else + N_LTF = 4; + + if (pPMacTxInfo->bSGI) + T_data = 3.6; + else + T_data = 4.0; + + /*(L-SIG, HT-SIG, HT-STF, HT-LTF....HT-LTF, Data)*/ + if (MPT_IS_VHT_RATE(pPMacTxInfo->TX_RATE)) + OFDM_symbol = (UINT)ceil((double)(8 + 4 + N_LTF * 4 + N_SYM * T_data + 4) / 4.); + else + OFDM_symbol = (UINT)ceil((double)(8 + 4 + N_LTF * 4 + N_SYM * T_data) / 4.); + + RTW_INFO("%s , OFDM_symbol =%d\n", __func__, OFDM_symbol); + LENGTH = OFDM_symbol * 3 - 3; + RTW_INFO("%s , LENGTH =%d\n", __func__, LENGTH); + + } + /* Rate Field*/ + switch (mode) { + case 0: + sig_bi[0] = 1; + sig_bi[1] = 1; + sig_bi[2] = 0; + sig_bi[3] = 1; + break; + case 1: + sig_bi[0] = 1; + sig_bi[1] = 1; + sig_bi[2] = 1; + sig_bi[3] = 1; + break; + case 2: + sig_bi[0] = 0; + sig_bi[1] = 1; + sig_bi[2] = 0; + sig_bi[3] = 1; + break; + case 3: + sig_bi[0] = 0; + sig_bi[1] = 1; + sig_bi[2] = 1; + sig_bi[3] = 1; + break; + case 4: + sig_bi[0] = 1; + sig_bi[1] = 0; + sig_bi[2] = 0; + sig_bi[3] = 1; + break; + case 5: + sig_bi[0] = 1; + sig_bi[1] = 0; + sig_bi[2] = 1; + sig_bi[3] = 1; + break; + case 6: + sig_bi[0] = 0; + sig_bi[1] = 0; + sig_bi[2] = 0; + sig_bi[3] = 1; + break; + case 7: + sig_bi[0] = 0; + sig_bi[1] = 0; + sig_bi[2] = 1; + sig_bi[3] = 1; + break; + } + /*Reserved bit*/ + sig_bi[4] = 0; + + /* Length Field*/ + for (i = 0; i < 12; i++) + sig_bi[i + 5] = (LENGTH >> i) & 1; + + /* Parity Bit*/ + sig_bi[17] = 0; + for (i = 0; i < 17; i++) + sig_bi[17] = sig_bi[17] + sig_bi[i]; + + sig_bi[17] %= 2; + + /* Tail Field*/ + for (i = 18; i < 24; i++) + sig_bi[i] = 0; + + /* dump_buf(sig_bi,24);*/ + _rtw_memset(pPMacTxInfo->LSIG, 0, 3); + ByteToBit(pPMacTxInfo->LSIG, (bool *)sig_bi, 3); +} + + +void CRC8_generator( + bool *out, + bool *in, + UCHAR in_size +) +{ + UCHAR i = 0; + bool temp = 0, reg[] = {1, 1, 1, 1, 1, 1, 1, 1}; + + for (i = 0; i < in_size; i++) { /* take one's complement and bit reverse*/ + temp = in[i] ^ reg[7]; + reg[7] = reg[6]; + reg[6] = reg[5]; + reg[5] = reg[4]; + reg[4] = reg[3]; + reg[3] = reg[2]; + reg[2] = reg[1] ^ temp; + reg[1] = reg[0] ^ temp; + reg[0] = temp; + } + for (i = 0; i < 8; i++)/* take one's complement and bit reverse*/ + out[i] = reg[7 - i] ^ 1; +} + +/*/================================================================================ + HT-SIG1 MCS CW Length 24BIT + 24BIT + 7b 1b 16b + HT-SIG2 Smoothing Not sounding Rsvd AGG STBC FEC SGI N_ELTF CRC Tail + 1b 1b 1b 1b 2b 1b 1b 2b 8b 6b +================================================================================*/ +void HT_SIG_generator( + PRT_PMAC_TX_INFO pPMacTxInfo, + PRT_PMAC_PKT_INFO pPMacPktInfo +) +{ + UINT i; + bool sig_bi[48] = {0}, crc8[8] = {0}; + /* MCS Field*/ + for (i = 0; i < 7; i++) + sig_bi[i] = (pPMacPktInfo->MCS >> i) & 0x1; + /* Packet BW Setting*/ + sig_bi[7] = pPMacTxInfo->BandWidth; + /* HT-Length Field*/ + for (i = 0; i < 16; i++) + sig_bi[i + 8] = (pPMacTxInfo->PacketLength >> i) & 0x1; + /* Smoothing; 1->allow smoothing*/ + sig_bi[24] = 1; + /*Not Sounding*/ + sig_bi[25] = 1 - pPMacTxInfo->NDP_sound; + /*Reserved bit*/ + sig_bi[26] = 1; + /*/Aggregate*/ + sig_bi[27] = 0; + /*STBC Field*/ + if (pPMacTxInfo->bSTBC) { + sig_bi[28] = 1; + sig_bi[29] = 0; + } else { + sig_bi[28] = 0; + sig_bi[29] = 0; + } + /*Advance Coding, 0: BCC, 1: LDPC*/ + sig_bi[30] = pPMacTxInfo->bLDPC; + /* Short GI*/ + sig_bi[31] = pPMacTxInfo->bSGI; + /* N_ELTFs*/ + if (pPMacTxInfo->NDP_sound == FALSE) { + sig_bi[32] = 0; + sig_bi[33] = 0; + } else { + int N_ELTF = pPMacTxInfo->Ntx - pPMacPktInfo->Nss; + + for (i = 0; i < 2; i++) + sig_bi[32 + i] = (N_ELTF >> i) % 2; + } + /* CRC-8*/ + CRC8_generator(crc8, sig_bi, 34); + + for (i = 0; i < 8; i++) + sig_bi[34 + i] = crc8[i]; + + /*Tail*/ + for (i = 42; i < 48; i++) + sig_bi[i] = 0; + + _rtw_memset(pPMacTxInfo->HT_SIG, 0, 6); + ByteToBit(pPMacTxInfo->HT_SIG, sig_bi, 6); +} + + +/*====================================================================================== + VHT-SIG-A1 + BW Reserved STBC G_ID SU_Nsts P_AID TXOP_PS_NOT_ALLOW Reserved + 2b 1b 1b 6b 3b 9b 1b 2b 1b + VHT-SIG-A2 + SGI SGI_Nsym SU/MU coding LDPC_Extra SU_NCS Beamformed Reserved CRC Tail + 1b 1b 1b 1b 4b 1b 1b 8b 6b +======================================================================================*/ +void VHT_SIG_A_generator( + PRT_PMAC_TX_INFO pPMacTxInfo, + PRT_PMAC_PKT_INFO pPMacPktInfo) +{ + UINT i; + bool sig_bi[48], crc8[8]; + + _rtw_memset(sig_bi, 0, 48); + _rtw_memset(crc8, 0, 8); + + /* BW Setting*/ + for (i = 0; i < 2; i++) + sig_bi[i] = (pPMacTxInfo->BandWidth >> i) & 0x1; + /* Reserved Bit*/ + sig_bi[2] = 1; + /*STBC Field*/ + sig_bi[3] = pPMacTxInfo->bSTBC; + /*Group ID: Single User->A value of 0 or 63 indicates an SU PPDU. */ + for (i = 0; i < 6; i++) + sig_bi[4 + i] = 0; + /* N_STS/Partial AID*/ + for (i = 0; i < 12; i++) { + if (i < 3) + sig_bi[10 + i] = ((pPMacPktInfo->Nsts - 1) >> i) & 0x1; + else + sig_bi[10 + i] = 0; + } + /*TXOP_PS_NOT_ALLPWED*/ + sig_bi[22] = 0; + /*Reserved Bits*/ + sig_bi[23] = 1; + /*Short GI*/ + sig_bi[24] = pPMacTxInfo->bSGI; + if (pPMacTxInfo->bSGI > 0 && (pPMacPktInfo->N_sym % 10) == 9) + sig_bi[25] = 1; + else + sig_bi[25] = 0; + /* SU/MU[0] Coding*/ + sig_bi[26] = pPMacTxInfo->bLDPC; /* 0:BCC, 1:LDPC */ + sig_bi[27] = pPMacPktInfo->SIGA2B3; /*/ Record Extra OFDM Symols is added or not when LDPC is used*/ + /*SU MCS/MU[1-3] Coding*/ + for (i = 0; i < 4; i++) + sig_bi[28 + i] = (pPMacPktInfo->MCS >> i) & 0x1; + /*SU Beamform */ + sig_bi[32] = 0; /*packet.TXBF_en;*/ + /*Reserved Bit*/ + sig_bi[33] = 1; + /*CRC-8*/ + CRC8_generator(crc8, sig_bi, 34); + for (i = 0; i < 8; i++) + sig_bi[34 + i] = crc8[i]; + /*Tail*/ + for (i = 42; i < 48; i++) + sig_bi[i] = 0; + + _rtw_memset(pPMacTxInfo->VHT_SIG_A, 0, 6); + ByteToBit(pPMacTxInfo->VHT_SIG_A, sig_bi, 6); +} + +/*====================================================================================== + VHT-SIG-B + Length Resesrved Trail + 17/19/21 BIT 3/2/2 BIT 6b +======================================================================================*/ +void VHT_SIG_B_generator( + PRT_PMAC_TX_INFO pPMacTxInfo) +{ + bool sig_bi[32], crc8_bi[8]; + UINT i, len, res, tail = 6, total_len, crc8_in_len; + UINT sigb_len; + + _rtw_memset(sig_bi, 0, 32); + _rtw_memset(crc8_bi, 0, 8); + + /*Sounding Packet*/ + if (pPMacTxInfo->NDP_sound == 1) { + if (pPMacTxInfo->BandWidth == 0) { + bool sigb_temp[26] = {0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}; + + _rtw_memcpy(sig_bi, sigb_temp, 26); + } else if (pPMacTxInfo->BandWidth == 1) { + bool sigb_temp[27] = {1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0}; + + _rtw_memcpy(sig_bi, sigb_temp, 27); + } else if (pPMacTxInfo->BandWidth == 2) { + bool sigb_temp[29] = {0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}; + + _rtw_memcpy(sig_bi, sigb_temp, 29); + } + } else { /* Not NDP Sounding*/ + bool *sigb_temp[29] = {0}; + + if (pPMacTxInfo->BandWidth == 0) { + len = 17; + res = 3; + } else if (pPMacTxInfo->BandWidth == 1) { + len = 19; + res = 2; + } else if (pPMacTxInfo->BandWidth == 2) { + len = 21; + res = 2; + } else { + len = 21; + res = 2; + } + total_len = len + res + tail; + crc8_in_len = len + res; + + /*Length Field*/ + sigb_len = (pPMacTxInfo->PacketLength + 3) >> 2; + + for (i = 0; i < len; i++) + sig_bi[i] = (sigb_len >> i) & 0x1; + /*Reserved Field*/ + for (i = 0; i < res; i++) + sig_bi[len + i] = 1; + /* CRC-8*/ + CRC8_generator(crc8_bi, sig_bi, crc8_in_len); + + /* Tail */ + for (i = 0; i < tail; i++) + sig_bi[len + res + i] = 0; + } + + _rtw_memset(pPMacTxInfo->VHT_SIG_B, 0, 4); + ByteToBit(pPMacTxInfo->VHT_SIG_B, sig_bi, 4); + + pPMacTxInfo->VHT_SIG_B_CRC = 0; + ByteToBit(&(pPMacTxInfo->VHT_SIG_B_CRC), crc8_bi, 1); +} + +/*======================= + VHT Delimiter +=======================*/ +void VHT_Delimiter_generator( + PRT_PMAC_TX_INFO pPMacTxInfo +) +{ + bool sig_bi[32] = {0}, crc8[8] = {0}; + UINT crc8_in_len = 16; + UINT PacketLength = pPMacTxInfo->PacketLength; + int j; + + /* Delimiter[0]: EOF*/ + sig_bi[0] = 1; + /* Delimiter[1]: Reserved*/ + sig_bi[1] = 0; + /* Delimiter[3:2]: MPDU Length High*/ + sig_bi[2] = ((PacketLength - 4) >> 12) % 2; + sig_bi[3] = ((PacketLength - 4) >> 13) % 2; + /* Delimiter[15:4]: MPDU Length Low*/ + for (j = 4; j < 16; j++) + sig_bi[j] = ((PacketLength - 4) >> (j - 4)) % 2; + CRC8_generator(crc8, sig_bi, crc8_in_len); + for (j = 16; j < 24; j++) /* Delimiter[23:16]: CRC 8*/ + sig_bi[j] = crc8[j - 16]; + for (j = 24; j < 32; j++) /* Delimiter[31:24]: Signature ('4E' in Hex, 78 in Dec)*/ + sig_bi[j] = (78 >> (j - 24)) % 2; + + _rtw_memset(pPMacTxInfo->VHT_Delimiter, 0, 4); + ByteToBit(pPMacTxInfo->VHT_Delimiter, sig_bi, 4); +} + +#endif +#endif diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_mp_ioctl.c b/linux-bsp/drivers/rtl8188eus/core/rtw_mp_ioctl.c new file mode 100644 index 0000000..33bd6d2 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_mp_ioctl.c @@ -0,0 +1,2534 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_MP_IOCTL_C_ + +#include <drv_types.h> +#include <rtw_mp_ioctl.h> +#include "../hal/phydm/phydm_precomp.h" + +/* **************** oid_rtl_seg_81_85 section start **************** */ +NDIS_STATUS oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + if (poid_par_priv->information_buf_len < sizeof(u8)) + return NDIS_STATUS_INVALID_LENGTH; + + if (poid_par_priv->type_of_oid == SET_OID) + Adapter->registrypriv.wireless_mode = *(u8 *)poid_par_priv->information_buf; + else if (poid_par_priv->type_of_oid == QUERY_OID) { + *(u8 *)poid_par_priv->information_buf = Adapter->registrypriv.wireless_mode; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_NOT_ACCEPTED; + + + return status; +} +/* **************** oid_rtl_seg_81_87_80 section start **************** */ +NDIS_STATUS oid_rt_pro_write_bb_reg_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + struct bb_reg_param *pbbreg; + u16 offset; + u32 value; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param)) + return NDIS_STATUS_INVALID_LENGTH; + + pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf); + + offset = (u16)(pbbreg->offset) & 0xFFF; /* 0ffset :0x800~0xfff */ + if (offset < BB_REG_BASE_ADDR) + offset |= BB_REG_BASE_ADDR; + + value = pbbreg->value; + + + _irqlevel_changed_(&oldirql, LOWER); + write_bbreg(Adapter, offset, 0xFFFFFFFF, value); + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_read_bb_reg_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + struct bb_reg_param *pbbreg; + u16 offset; + u32 value; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(struct bb_reg_param)) + return NDIS_STATUS_INVALID_LENGTH; + + pbbreg = (struct bb_reg_param *)(poid_par_priv->information_buf); + + offset = (u16)(pbbreg->offset) & 0xFFF; /* 0ffset :0x800~0xfff */ + if (offset < BB_REG_BASE_ADDR) + offset |= BB_REG_BASE_ADDR; + + _irqlevel_changed_(&oldirql, LOWER); + value = read_bbreg(Adapter, offset, 0xFFFFFFFF); + _irqlevel_changed_(&oldirql, RAISE); + + pbbreg->value = value; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + struct rf_reg_param *pbbreg; + u8 path; + u8 offset; + u32 value; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param)) + return NDIS_STATUS_INVALID_LENGTH; + + pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf); + + if (pbbreg->path >= MAX_RF_PATH_NUMS) + return NDIS_STATUS_NOT_ACCEPTED; + if (pbbreg->offset > 0xFF) + return NDIS_STATUS_NOT_ACCEPTED; + if (pbbreg->value > 0xFFFFF) + return NDIS_STATUS_NOT_ACCEPTED; + + path = (u8)pbbreg->path; + offset = (u8)pbbreg->offset; + value = pbbreg->value; + + + _irqlevel_changed_(&oldirql, LOWER); + write_rfreg(Adapter, path, offset, value); + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + struct rf_reg_param *pbbreg; + u8 path; + u8 offset; + u32 value; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(struct rf_reg_param)) + return NDIS_STATUS_INVALID_LENGTH; + + pbbreg = (struct rf_reg_param *)(poid_par_priv->information_buf); + + if (pbbreg->path >= MAX_RF_PATH_NUMS) + return NDIS_STATUS_NOT_ACCEPTED; + if (pbbreg->offset > 0xFF) + return NDIS_STATUS_NOT_ACCEPTED; + + path = (u8)pbbreg->path; + offset = (u8)pbbreg->offset; + + _irqlevel_changed_(&oldirql, LOWER); + value = read_rfreg(Adapter, path, offset); + _irqlevel_changed_(&oldirql, RAISE); + + pbbreg->value = value; + + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + + return status; +} +/* **************** oid_rtl_seg_81_87_00 section end**************** + * ------------------------------------------------------------------------------ */ + +/* **************** oid_rtl_seg_81_80_00 section start **************** + * ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u32 ratevalue;/* 4 */ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len != sizeof(u32)) + return NDIS_STATUS_INVALID_LENGTH; + + ratevalue = *((u32 *)poid_par_priv->information_buf); /* 4 */ + if (ratevalue >= MPT_RATE_LAST) + return NDIS_STATUS_INVALID_DATA; + + Adapter->mppriv.rateidx = ratevalue; + + _irqlevel_changed_(&oldirql, LOWER); + SetDataRate(Adapter); + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_start_test_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u32 mode; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (Adapter->registrypriv.mp_mode == 0) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + _irqlevel_changed_(&oldirql, LOWER); + + /* IQCalibrateBcut(Adapter); */ + + mode = *((u32 *)poid_par_priv->information_buf); + Adapter->mppriv.mode = mode;/* 1 for loopback */ + + if (mp_start_test(Adapter) == _FAIL) { + status = NDIS_STATUS_NOT_ACCEPTED; + goto exit; + } + +exit: + _irqlevel_changed_(&oldirql, RAISE); + + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + _irqlevel_changed_(&oldirql, LOWER); + mp_stop_test(Adapter); + _irqlevel_changed_(&oldirql, RAISE); + + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u32 Channel; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->information_buf_len != sizeof(u32)) + return NDIS_STATUS_INVALID_LENGTH; + + if (poid_par_priv->type_of_oid == QUERY_OID) { + *((u32 *)poid_par_priv->information_buf) = Adapter->mppriv.channel; + return NDIS_STATUS_SUCCESS; + } + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + Channel = *((u32 *)poid_par_priv->information_buf); + if (Channel > 14) + return NDIS_STATUS_NOT_ACCEPTED; + Adapter->mppriv.channel = Channel; + + _irqlevel_changed_(&oldirql, LOWER); + SetChannel(Adapter); + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u16 bandwidth; + u16 channel_offset; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(u32)) + return NDIS_STATUS_INVALID_LENGTH; + + bandwidth = *((u32 *)poid_par_priv->information_buf); /* 4 */ + channel_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + + if (bandwidth != CHANNEL_WIDTH_40) + bandwidth = CHANNEL_WIDTH_20; + padapter->mppriv.bandwidth = (u8)bandwidth; + padapter->mppriv.prime_channel_offset = (u8)channel_offset; + + _irqlevel_changed_(&oldirql, LOWER); + SetBandwidth(padapter); + _irqlevel_changed_(&oldirql, RAISE); + + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u32 antenna; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->information_buf_len != sizeof(u32)) + return NDIS_STATUS_INVALID_LENGTH; + + if (poid_par_priv->type_of_oid == SET_OID) { + antenna = *(u32 *)poid_par_priv->information_buf; + + Adapter->mppriv.antenna_tx = (u16)((antenna & 0xFFFF0000) >> 16); + Adapter->mppriv.antenna_rx = (u16)(antenna & 0x0000FFFF); + + _irqlevel_changed_(&oldirql, LOWER); + SetAntenna(Adapter); + _irqlevel_changed_(&oldirql, RAISE); + } else { + antenna = (Adapter->mppriv.antenna_tx << 16) | Adapter->mppriv.antenna_rx; + *(u32 *)poid_par_priv->information_buf = antenna; + } + + + return status; +} + +NDIS_STATUS oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u32 tx_pwr_idx; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len != sizeof(u32)) + return NDIS_STATUS_INVALID_LENGTH; + + tx_pwr_idx = *((u32 *)poid_par_priv->information_buf); + if (tx_pwr_idx > MAX_TX_PWR_INDEX_N_MODE) + return NDIS_STATUS_NOT_ACCEPTED; + + Adapter->mppriv.txpoweridx = (u8)tx_pwr_idx; + + + _irqlevel_changed_(&oldirql, LOWER); + SetTxPower(Adapter); + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} + +/* ------------------------------------------------------------------------------ + * **************** oid_rtl_seg_81_80_20 section start **************** + * ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_query_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + if (poid_par_priv->information_buf_len == sizeof(ULONG)) { + *(ULONG *)poid_par_priv->information_buf = Adapter->mppriv.tx_pktcount; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_INVALID_LENGTH; + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_query_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + if (poid_par_priv->information_buf_len == sizeof(ULONG)) { + *(ULONG *)poid_par_priv->information_buf = Adapter->mppriv.rx_pktcount; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_INVALID_LENGTH; + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_query_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + if (poid_par_priv->information_buf_len == sizeof(ULONG)) { + *(ULONG *)poid_par_priv->information_buf = Adapter->mppriv.rx_crcerrpktcount; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_INVALID_LENGTH; + + + return status; +} +/* ------------------------------------------------------------------------------ */ + +NDIS_STATUS oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + if (poid_par_priv->type_of_oid != SET_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + Adapter->mppriv.tx_pktcount = 0; + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + if (poid_par_priv->type_of_oid != SET_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + if (poid_par_priv->information_buf_len == sizeof(ULONG)) { + Adapter->mppriv.rx_pktcount = 0; + Adapter->mppriv.rx_crcerrpktcount = 0; + } else + status = NDIS_STATUS_INVALID_LENGTH; + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + if (poid_par_priv->type_of_oid != SET_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + _irqlevel_changed_(&oldirql, LOWER); + ResetPhyRxPktCount(Adapter); + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len != sizeof(ULONG)) + return NDIS_STATUS_INVALID_LENGTH; + + _irqlevel_changed_(&oldirql, LOWER); + *(ULONG *)poid_par_priv->information_buf = GetPhyRxPktReceived(Adapter); + _irqlevel_changed_(&oldirql, RAISE); + + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + + if (poid_par_priv->information_buf_len != sizeof(ULONG)) + return NDIS_STATUS_INVALID_LENGTH; + + _irqlevel_changed_(&oldirql, LOWER); + *(ULONG *)poid_par_priv->information_buf = GetPhyRxPktCRC32Error(Adapter); + _irqlevel_changed_(&oldirql, RAISE); + + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + + return status; +} +/* **************** oid_rtl_seg_81_80_20 section end **************** */ +NDIS_STATUS oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u32 bStartTest; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + bStartTest = *((u32 *)poid_par_priv->information_buf); + + _irqlevel_changed_(&oldirql, LOWER); + SetContinuousTx(Adapter, (u8)bStartTest); + if (bStartTest) { + struct mp_priv *pmp_priv = &Adapter->mppriv; + if (pmp_priv->tx.stop == 0) { + pmp_priv->tx.stop = 1; + RTW_INFO("%s: pkt tx is running...\n", __func__); + rtw_msleep_os(5); + } + pmp_priv->tx.stop = 0; + pmp_priv->tx.count = 1; + SetPacketTx(Adapter); + } + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} + +NDIS_STATUS oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u32 bStartTest; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + bStartTest = *((u32 *)poid_par_priv->information_buf); + + _irqlevel_changed_(&oldirql, LOWER); + SetSingleCarrierTx(Adapter, (u8)bStartTest); + if (bStartTest) { + struct mp_priv *pmp_priv = &Adapter->mppriv; + if (pmp_priv->tx.stop == 0) { + pmp_priv->tx.stop = 1; + RTW_INFO("%s: pkt tx is running...\n", __func__); + rtw_msleep_os(5); + } + pmp_priv->tx.stop = 0; + pmp_priv->tx.count = 1; + SetPacketTx(Adapter); + } + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} + +NDIS_STATUS oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u32 bStartTest; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + bStartTest = *((u32 *)poid_par_priv->information_buf); + + _irqlevel_changed_(&oldirql, LOWER); + SetCarrierSuppressionTx(Adapter, (u8)bStartTest); + if (bStartTest) { + struct mp_priv *pmp_priv = &Adapter->mppriv; + if (pmp_priv->tx.stop == 0) { + pmp_priv->tx.stop = 1; + RTW_INFO("%s: pkt tx is running...\n", __func__); + rtw_msleep_os(5); + } + pmp_priv->tx.stop = 0; + pmp_priv->tx.count = 1; + SetPacketTx(Adapter); + } + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} + +NDIS_STATUS oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u32 bStartTest; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + bStartTest = *((u32 *)poid_par_priv->information_buf); + + _irqlevel_changed_(&oldirql, LOWER); + SetSingleToneTx(Adapter, (u8)bStartTest); + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} + +NDIS_STATUS oid_rt_pro_set_modulation_hdl(struct oid_par_priv *poid_par_priv) +{ + return 0; +} + +NDIS_STATUS oid_rt_pro_trigger_gpio_hdl(struct oid_par_priv *poid_par_priv) +{ + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + _irqlevel_changed_(&oldirql, LOWER); + rtw_hal_set_hwreg(Adapter, HW_VAR_TRIGGER_GPIO_0, 0); + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} +/* **************** oid_rtl_seg_81_80_00 section end **************** + * ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro8711_join_bss_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + PNDIS_802_11_SSID pssid; + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + *poid_par_priv->bytes_needed = (u32)sizeof(NDIS_802_11_SSID); + *poid_par_priv->bytes_rw = 0; + if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed) + return NDIS_STATUS_INVALID_LENGTH; + + pssid = (PNDIS_802_11_SSID)poid_par_priv->information_buf; + + _irqlevel_changed_(&oldirql, LOWER); + + if (mp_start_joinbss(Adapter, pssid) == _FAIL) + status = NDIS_STATUS_NOT_ACCEPTED; + + _irqlevel_changed_(&oldirql, RAISE); + + *poid_par_priv->bytes_rw = sizeof(NDIS_802_11_SSID); + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + pRW_Reg RegRWStruct; + u32 offset, width; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + RegRWStruct = (pRW_Reg)poid_par_priv->information_buf; + offset = RegRWStruct->offset; + width = RegRWStruct->width; + + if (offset > 0xFFF) + return NDIS_STATUS_NOT_ACCEPTED; + + _irqlevel_changed_(&oldirql, LOWER); + + switch (width) { + case 1: + RegRWStruct->value = rtw_read8(Adapter, offset); + break; + case 2: + RegRWStruct->value = rtw_read16(Adapter, offset); + break; + default: + width = 4; + RegRWStruct->value = rtw_read32(Adapter, offset); + break; + } + + _irqlevel_changed_(&oldirql, RAISE); + + *poid_par_priv->bytes_rw = width; + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + pRW_Reg RegRWStruct; + u32 offset, width, value; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + RegRWStruct = (pRW_Reg)poid_par_priv->information_buf; + offset = RegRWStruct->offset; + width = RegRWStruct->width; + value = RegRWStruct->value; + + if (offset > 0xFFF) + return NDIS_STATUS_NOT_ACCEPTED; + + _irqlevel_changed_(&oldirql, LOWER); + + switch (RegRWStruct->width) { + case 1: + if (value > 0xFF) { + status = NDIS_STATUS_NOT_ACCEPTED; + break; + } + rtw_write8(padapter, offset, (u8)value); + break; + case 2: + if (value > 0xFFFF) { + status = NDIS_STATUS_NOT_ACCEPTED; + break; + } + rtw_write16(padapter, offset, (u16)value); + break; + case 4: + rtw_write32(padapter, offset, value); + break; + default: + status = NDIS_STATUS_NOT_ACCEPTED; + break; + } + + _irqlevel_changed_(&oldirql, RAISE); + + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_burst_read_register_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + pBurst_RW_Reg pBstRwReg; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + pBstRwReg = (pBurst_RW_Reg)poid_par_priv->information_buf; + + _irqlevel_changed_(&oldirql, LOWER); + rtw_read_mem(padapter, pBstRwReg->offset, (u32)pBstRwReg->len, pBstRwReg->Data); + _irqlevel_changed_(&oldirql, RAISE); + + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_burst_write_register_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + pBurst_RW_Reg pBstRwReg; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + pBstRwReg = (pBurst_RW_Reg)poid_par_priv->information_buf; + + _irqlevel_changed_(&oldirql, LOWER); + rtw_write_mem(padapter, pBstRwReg->offset, (u32)pBstRwReg->len, pBstRwReg->Data); + _irqlevel_changed_(&oldirql, RAISE); + + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_write_txcmd_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + + TX_CMD_Desc *TxCmd_Info; + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + + TxCmd_Info = (TX_CMD_Desc *)poid_par_priv->information_buf; + + + _irqlevel_changed_(&oldirql, LOWER); + + rtw_write32(Adapter, TxCmd_Info->offset + 0, (unsigned int)TxCmd_Info->TxCMD.value[0]); + rtw_write32(Adapter, TxCmd_Info->offset + 4, (unsigned int)TxCmd_Info->TxCMD.value[1]); + + _irqlevel_changed_(&oldirql, RAISE); + + + + return status; +#else + return 0; +#endif +} + +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + pEEPROM_RWParam pEEPROM; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + pEEPROM = (pEEPROM_RWParam)poid_par_priv->information_buf; + + _irqlevel_changed_(&oldirql, LOWER); + pEEPROM->value = eeprom_read16(padapter, (u16)(pEEPROM->offset >> 1)); + _irqlevel_changed_(&oldirql, RAISE); + + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + + return status; +#else + return 0; +#endif +} + +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_write16_eeprom_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + pEEPROM_RWParam pEEPROM; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + pEEPROM = (pEEPROM_RWParam)poid_par_priv->information_buf; + + _irqlevel_changed_(&oldirql, LOWER); + eeprom_write16(padapter, (u16)(pEEPROM->offset >> 1), pEEPROM->value); + _irqlevel_changed_(&oldirql, RAISE); + + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + struct mp_wiparam *pwi_param; + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(struct mp_wiparam)) + return NDIS_STATUS_INVALID_LENGTH; + + if (Adapter->mppriv.workparam.bcompleted == _FALSE) + return NDIS_STATUS_NOT_ACCEPTED; + + pwi_param = (struct mp_wiparam *)poid_par_priv->information_buf; + + _rtw_memcpy(pwi_param, &Adapter->mppriv.workparam, sizeof(struct mp_wiparam)); + Adapter->mppriv.act_in_progress = _FALSE; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(uint) * 2) { + return NDIS_STATUS_INVALID_LENGTH; + } + + if (*(uint *)poid_par_priv->information_buf == 1) /* init==1 */ + Adapter->mppriv.rx_pktloss = 0; + + *((uint *)poid_par_priv->information_buf + 1) = Adapter->mppriv.rx_pktloss; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_rd_attrib_mem_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + struct io_queue *pio_queue = (struct io_queue *)Adapter->pio_queue; + struct intf_hdl *pintfhdl = &pio_queue->intf; + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + +#ifdef CONFIG_SDIO_HCI + void (*_attrib_read)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); +#endif + + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + +#ifdef CONFIG_SDIO_HCI + _irqlevel_changed_(&oldirql, LOWER); + { + u32 *plmem = (u32 *)poid_par_priv->information_buf + 2; + _attrib_read = pintfhdl->io_ops._attrib_read; + _attrib_read(pintfhdl, *((u32 *)poid_par_priv->information_buf), + *((u32 *)poid_par_priv->information_buf + 1), (u8 *)plmem); + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } + _irqlevel_changed_(&oldirql, RAISE); +#endif + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_wr_attrib_mem_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + struct io_queue *pio_queue = (struct io_queue *)Adapter->pio_queue; + struct intf_hdl *pintfhdl = &pio_queue->intf; + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + +#ifdef CONFIG_SDIO_HCI + void (*_attrib_write)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); +#endif + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + +#ifdef CONFIG_SDIO_HCI + _irqlevel_changed_(&oldirql, LOWER); + { + u32 *plmem = (u32 *)poid_par_priv->information_buf + 2; + _attrib_write = pintfhdl->io_ops._attrib_write; + _attrib_write(pintfhdl, *(u32 *)poid_par_priv->information_buf, + *((u32 *)poid_par_priv->information_buf + 1), (u8 *)plmem); + } + _irqlevel_changed_(&oldirql, RAISE); +#endif + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + _irqlevel_changed_(&oldirql, LOWER); + + if (rtw_setrfintfs_cmd(Adapter, *(unsigned char *)poid_par_priv->information_buf) == _FAIL) + status = NDIS_STATUS_NOT_ACCEPTED; + + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_poll_rx_status_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + _rtw_memcpy(poid_par_priv->information_buf, (unsigned char *)&Adapter->mppriv.rxstat, sizeof(struct recv_stat)); + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_cfg_debug_message_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + PCFG_DBG_MSG_STRUCT pdbg_msg; + + + +#if 0/*#ifdef CONFIG_DEBUG_RTL871X*/ + + pdbg_msg = (PCFG_DBG_MSG_STRUCT)(poid_par_priv->information_buf); + + if (poid_par_priv->type_of_oid == SET_OID) { + + GlobalDebugLevel = pdbg_msg->DebugLevel; + GlobalDebugComponents = (pdbg_msg->DebugComponent_H32 << 32) | pdbg_msg->DebugComponent_L32; + } else { + pdbg_msg->DebugLevel = GlobalDebugLevel; + pdbg_msg->DebugComponent_H32 = (u32)(GlobalDebugComponents >> 32); + pdbg_msg->DebugComponent_L32 = (u32)GlobalDebugComponents; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + } + +#endif + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_set_data_rate_ex_hdl(struct oid_par_priv *poid_par_priv) +{ + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + _irqlevel_changed_(&oldirql, LOWER); + + if (rtw_setdatarate_cmd(Adapter, poid_par_priv->information_buf) != _SUCCESS) + status = NDIS_STATUS_NOT_ACCEPTED; + + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} +/* ----------------------------------------------------------------------------- */ +NDIS_STATUS oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + u8 thermal = 0; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(u32)) + return NDIS_STATUS_INVALID_LENGTH; + + _irqlevel_changed_(&oldirql, LOWER); + GetThermalMeter(Adapter, &thermal); + _irqlevel_changed_(&oldirql, RAISE); + + *(u32 *)poid_par_priv->information_buf = (u32)thermal; + *poid_par_priv->bytes_rw = sizeof(u32); + + + return status; +} +/* ----------------------------------------------------------------------------- */ +NDIS_STATUS oid_rt_pro_read_tssi_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (Adapter->mppriv.act_in_progress == _TRUE) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(u8)) + return NDIS_STATUS_INVALID_LENGTH; + + /* init workparam */ + Adapter->mppriv.act_in_progress = _TRUE; + Adapter->mppriv.workparam.bcompleted = _FALSE; + Adapter->mppriv.workparam.act_type = MPT_READ_TSSI; + Adapter->mppriv.workparam.io_offset = 0; + Adapter->mppriv.workparam.io_value = 0xFFFFFFFF; + + _irqlevel_changed_(&oldirql, LOWER); + + if (!rtw_gettssi_cmd(Adapter, 0, (u8 *)&Adapter->mppriv.workparam.io_value)) + status = NDIS_STATUS_NOT_ACCEPTED; + + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + /* if (poid_par_priv->type_of_oid != SET_OID) + * return NDIS_STATUS_NOT_ACCEPTED; */ + + if (poid_par_priv->information_buf_len < sizeof(u8)) + return NDIS_STATUS_INVALID_LENGTH; + + _irqlevel_changed_(&oldirql, LOWER); + if (poid_par_priv->type_of_oid == SET_OID) { + u8 enable; + + enable = *(u8 *)poid_par_priv->information_buf; + + SetPowerTracking(Adapter, enable); + } else + GetPowerTracking(Adapter, (u8 *)poid_par_priv->information_buf); + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} +/* ----------------------------------------------------------------------------- */ +NDIS_STATUS oid_rt_pro_set_basic_rate_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u32 ratevalue; + u8 datarates[NumRates]; + int i; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; +#if 0 + ratevalue = *((u32 *)poid_par_priv->information_buf); + + for (i = 0; i < NumRates; i++) { + if (ratevalue == mpdatarate[i]) + datarates[i] = mpdatarate[i]; + else + datarates[i] = 0xff; + } + + _irqlevel_changed_(&oldirql, LOWER); + + if (rtw_setbasicrate_cmd(padapter, datarates) != _SUCCESS) + status = NDIS_STATUS_NOT_ACCEPTED; + + _irqlevel_changed_(&oldirql, RAISE); +#endif + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_qry_pwrstate_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < 8) + return NDIS_STATUS_INVALID_LENGTH; + + *poid_par_priv->bytes_rw = 8; + _rtw_memcpy(poid_par_priv->information_buf, &(adapter_to_pwrctl(Adapter)->pwr_mode), 8); + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_set_pwrstate_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + uint pwr_mode, smart_ps; + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + *poid_par_priv->bytes_rw = 0; + *poid_par_priv->bytes_needed = 8; + + if (poid_par_priv->information_buf_len < 8) + return NDIS_STATUS_INVALID_LENGTH; + + pwr_mode = *(uint *)(poid_par_priv->information_buf); + smart_ps = *(uint *)((int)poid_par_priv->information_buf + 4); + + *poid_par_priv->bytes_rw = 8; + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_h2c_set_rate_table_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + struct setratable_parm *prate_table; + u8 res; + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + *poid_par_priv->bytes_needed = sizeof(struct setratable_parm); + if (poid_par_priv->information_buf_len < sizeof(struct setratable_parm)) + return NDIS_STATUS_INVALID_LENGTH; + + prate_table = (struct setratable_parm *)poid_par_priv->information_buf; + + _irqlevel_changed_(&oldirql, LOWER); + res = rtw_setrttbl_cmd(Adapter, prate_table); + _irqlevel_changed_(&oldirql, RAISE); + + if (res == _FAIL) + status = NDIS_STATUS_FAILURE; + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_h2c_get_rate_table_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + +#if 0 + struct mp_wi_cntx *pmp_wi_cntx = &(Adapter->mppriv.wi_cntx); + u8 res = _SUCCESS; + DEBUG_INFO(("===> Set OID_RT_PRO_H2C_GET_RATE_TABLE.\n")); + + if (pmp_wi_cntx->bmp_wi_progress == _TRUE) { + DEBUG_ERR(("\n mp workitem is progressing, not allow to set another workitem right now!!!\n")); + Status = NDIS_STATUS_NOT_ACCEPTED; + break; + } else { + pmp_wi_cntx->bmp_wi_progress = _TRUE; + pmp_wi_cntx->param.bcompleted = _FALSE; + pmp_wi_cntx->param.act_type = MPT_GET_RATE_TABLE; + pmp_wi_cntx->param.io_offset = 0x0; + pmp_wi_cntx->param.bytes_cnt = sizeof(struct getratable_rsp); + pmp_wi_cntx->param.io_value = 0xffffffff; + + res = rtw_getrttbl_cmd(Adapter, (struct getratable_rsp *)pmp_wi_cntx->param.data); + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + if (res != _SUCCESS) + Status = NDIS_STATUS_NOT_ACCEPTED; + } + DEBUG_INFO(("\n <=== Set OID_RT_PRO_H2C_GET_RATE_TABLE.\n")); +#endif + + + return status; +#else + return 0; +#endif +} + +/* **************** oid_rtl_seg_87_12_00 section start **************** */ +NDIS_STATUS oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + struct security_priv *psecuritypriv = &Adapter->securitypriv; + + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + ENCRY_CTRL_STATE encry_mode; + + + *poid_par_priv->bytes_needed = sizeof(u8); + if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed) + return NDIS_STATUS_INVALID_LENGTH; + + if (poid_par_priv->type_of_oid == SET_OID) { + encry_mode = *((u8 *)poid_par_priv->information_buf); + switch (encry_mode) { + case HW_CONTROL: +#if 0 + Adapter->registrypriv.software_decrypt = _FALSE; + Adapter->registrypriv.software_encrypt = _FALSE; +#else + psecuritypriv->sw_decrypt = _FALSE; + psecuritypriv->sw_encrypt = _FALSE; +#endif + break; + case SW_CONTROL: +#if 0 + Adapter->registrypriv.software_decrypt = _TRUE; + Adapter->registrypriv.software_encrypt = _TRUE; +#else + psecuritypriv->sw_decrypt = _TRUE; + psecuritypriv->sw_encrypt = _TRUE; +#endif + break; + case HW_ENCRY_SW_DECRY: +#if 0 + Adapter->registrypriv.software_decrypt = _TRUE; + Adapter->registrypriv.software_encrypt = _FALSE; +#else + psecuritypriv->sw_decrypt = _TRUE; + psecuritypriv->sw_encrypt = _FALSE; +#endif + break; + case SW_ENCRY_HW_DECRY: +#if 0 + Adapter->registrypriv.software_decrypt = _FALSE; + Adapter->registrypriv.software_encrypt = _TRUE; +#else + psecuritypriv->sw_decrypt = _FALSE; + psecuritypriv->sw_encrypt = _TRUE; +#endif + break; + } + + } else { +#if 0 + if (Adapter->registrypriv.software_encrypt == _FALSE) { + if (Adapter->registrypriv.software_decrypt == _FALSE) + encry_mode = HW_CONTROL; + else + encry_mode = HW_ENCRY_SW_DECRY; + } else { + if (Adapter->registrypriv.software_decrypt == _FALSE) + encry_mode = SW_ENCRY_HW_DECRY; + else + encry_mode = SW_CONTROL; + } +#else + + if ((psecuritypriv->sw_encrypt == _FALSE) && (psecuritypriv->sw_decrypt == _FALSE)) + encry_mode = HW_CONTROL; + else if ((psecuritypriv->sw_encrypt == _FALSE) && (psecuritypriv->sw_decrypt == _TRUE)) + encry_mode = HW_ENCRY_SW_DECRY; + else if ((psecuritypriv->sw_encrypt == _TRUE) && (psecuritypriv->sw_decrypt == _FALSE)) + encry_mode = SW_ENCRY_HW_DECRY; + else if ((psecuritypriv->sw_encrypt == _TRUE) && (psecuritypriv->sw_decrypt == _TRUE)) + encry_mode = SW_CONTROL; + +#endif + + *(u8 *)poid_par_priv->information_buf = encry_mode; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + } + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_add_sta_info_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + struct sta_info *psta = NULL; + UCHAR *macaddr; + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + *poid_par_priv->bytes_needed = ETH_ALEN; + if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed) + return NDIS_STATUS_INVALID_LENGTH; + + macaddr = (UCHAR *) poid_par_priv->information_buf ; + + + _irqlevel_changed_(&oldirql, LOWER); + + psta = rtw_get_stainfo(&Adapter->stapriv, macaddr); + + if (psta == NULL) { /* the sta have been in sta_info_queue => do nothing */ + psta = rtw_alloc_stainfo(&Adapter->stapriv, macaddr); + + if (psta == NULL) { + status = NDIS_STATUS_FAILURE; + } + } + + _irqlevel_changed_(&oldirql, RAISE); + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + struct sta_info *psta = NULL; + UCHAR *macaddr; + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + *poid_par_priv->bytes_needed = ETH_ALEN; + if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed) + return NDIS_STATUS_INVALID_LENGTH; + + macaddr = (UCHAR *) poid_par_priv->information_buf ; + + psta = rtw_get_stainfo(&Adapter->stapriv, macaddr); + if (psta != NULL) { + /* _enter_critical(&(Adapter->stapriv.sta_hash_lock), &irqL); */ + rtw_free_stainfo(Adapter, psta); + /* _exit_critical(&(Adapter->stapriv.sta_hash_lock), &irqL); */ + } + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +#if 0 +static u32 mp_query_drv_var(_adapter *padapter, u8 offset, u32 var) +{ +#ifdef CONFIG_SDIO_HCI + + if (offset == 1) { + u16 tmp_blk_num; + tmp_blk_num = rtw_read16(padapter, SDIO_RX0_RDYBLK_NUM); + if (adapter_to_dvobj(padapter)->rxblknum != tmp_blk_num) { + /* sd_recv_rxfifo(padapter); */ + } + } + +#if 0 + if (offset <= 100) { /* For setting data rate and query data rate */ + if (offset == 100) { /* For query data rate */ + var = padapter->registrypriv.tx_rate; + + } else if (offset < 0x1d) { /* For setting data rate */ + padapter->registrypriv.tx_rate = offset; + var = padapter->registrypriv.tx_rate; + padapter->registrypriv.use_rate = _TRUE; + } else { /* not use the data rate */ + padapter->registrypriv.use_rate = _FALSE; + } + } else if (offset <= 110) { /* for setting debug level */ + if (offset == 110) { /* For query data rate */ + padapter->registrypriv.dbg_level = GlobalDebugLevel; + var = padapter->registrypriv.dbg_level; + } else if (offset < 110 && offset > 100) { + padapter->registrypriv.dbg_level = GlobalDebugLevel = offset - 100; + var = padapter->registrypriv.dbg_level; + + } + } else if (offset > 110 && offset < 116) { + if (115 == offset) { + } else { + switch (offset) { + case 111: + adapter_to_dvobj(padapter)->tx_block_mode = 1; + adapter_to_dvobj(padapter)->rx_block_mode = 1; + break; + case 112: + adapter_to_dvobj(padapter)->tx_block_mode = 1; + adapter_to_dvobj(padapter)->rx_block_mode = 0; + break; + case 113: + adapter_to_dvobj(padapter)->tx_block_mode = 0; + adapter_to_dvobj(padapter)->rx_block_mode = 1; + break; + case 114: + adapter_to_dvobj(padapter)->tx_block_mode = 0; + adapter_to_dvobj(padapter)->rx_block_mode = 0; + break; + default: + break; + + } + + } + + } else if (offset >= 127) { + u64 prnt_dbg_comp; + u8 chg_idx; + u64 tmp_dbg_comp; + chg_idx = offset - 0x80; + tmp_dbg_comp = BIT(chg_idx); + prnt_dbg_comp = padapter->registrypriv.dbg_component = GlobalDebugComponents; + if (offset == 127) { + /* prnt_dbg_comp=padapter->registrypriv.dbg_component= GlobalDebugComponents; */ + var = (u32)(padapter->registrypriv.dbg_component); + prnt_dbg_comp = GlobalDebugComponents; + prnt_dbg_comp = GlobalDebugComponents = padapter->registrypriv.dbg_component; + + } else { + prnt_dbg_comp = GlobalDebugComponents; + prnt_dbg_comp = GlobalDebugComponents = padapter->registrypriv.dbg_component; + + if (GlobalDebugComponents & tmp_dbg_comp) { + /* this bit is already set, now clear it */ + GlobalDebugComponents = GlobalDebugComponents & (~tmp_dbg_comp); + } else { + /* this bit is not set, now set it. */ + GlobalDebugComponents = GlobalDebugComponents | tmp_dbg_comp; + } + prnt_dbg_comp = GlobalDebugComponents; + + var = (u32)(GlobalDebugComponents); + /* GlobalDebugComponents=padapter->registrypriv.dbg_component; */ + + } + } +#endif +#endif + + return var; +} +#endif + +NDIS_STATUS oid_rt_pro_query_dr_variable_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + DR_VARIABLE_STRUCT *pdrv_var; + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + *poid_par_priv->bytes_needed = sizeof(DR_VARIABLE_STRUCT); + if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed) + return NDIS_STATUS_INVALID_LENGTH; + + + pdrv_var = (struct _DR_VARIABLE_STRUCT_ *)poid_par_priv->information_buf; + + _irqlevel_changed_(&oldirql, LOWER); + pdrv_var->variable = mp_query_drv_var(Adapter, pdrv_var->offset, pdrv_var->variable); + _irqlevel_changed_(&oldirql, RAISE); + + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + return status; +#else + return 0; +#endif +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + + if (poid_par_priv->information_buf_len < sizeof(UCHAR)) { + status = NDIS_STATUS_INVALID_LENGTH; + *poid_par_priv->bytes_needed = sizeof(UCHAR); + return status; + } + + if (poid_par_priv->type_of_oid == SET_OID) { + Adapter->mppriv.rx_with_status = *(UCHAR *) poid_par_priv->information_buf; + + + } else { + *(UCHAR *) poid_par_priv->information_buf = Adapter->mppriv.rx_with_status; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + /* *(u32 *)&Adapter->eeprompriv.mac_addr[0]=rtw_read32(Adapter, 0x10250050); */ + /* *(u16 *)&Adapter->eeprompriv.mac_addr[4]=rtw_read16(Adapter, 0x10250054); */ + } +#endif + + return NDIS_STATUS_SUCCESS; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + PEFUSE_ACCESS_STRUCT pefuse; + u8 *data; + u16 addr = 0, cnts = 0, max_available_size = 0; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(EFUSE_ACCESS_STRUCT)) + return NDIS_STATUS_INVALID_LENGTH; + + pefuse = (PEFUSE_ACCESS_STRUCT)poid_par_priv->information_buf; + addr = pefuse->start_addr; + cnts = pefuse->cnts; + data = pefuse->data; + + + EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE); + + if ((addr + cnts) > max_available_size) { + return NDIS_STATUS_NOT_ACCEPTED; + } + + _irqlevel_changed_(&oldirql, LOWER); + if (rtw_efuse_access(Adapter, _FALSE, addr, cnts, data) == _FAIL) { + status = NDIS_STATUS_FAILURE; + } else + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + PEFUSE_ACCESS_STRUCT pefuse; + u8 *data; + u16 addr = 0, cnts = 0, max_available_size = 0; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + pefuse = (PEFUSE_ACCESS_STRUCT)poid_par_priv->information_buf; + addr = pefuse->start_addr; + cnts = pefuse->cnts; + data = pefuse->data; + + + EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (PVOID)&max_available_size, _FALSE); + + if ((addr + cnts) > max_available_size) { + return NDIS_STATUS_NOT_ACCEPTED; + } + + _irqlevel_changed_(&oldirql, LOWER); + if (rtw_efuse_access(Adapter, _TRUE, addr, cnts, data) == _FAIL) + status = NDIS_STATUS_FAILURE; + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + PPGPKT_STRUCT ppgpkt; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + + *poid_par_priv->bytes_rw = 0; + + if (poid_par_priv->information_buf_len < sizeof(PGPKT_STRUCT)) + return NDIS_STATUS_INVALID_LENGTH; + + ppgpkt = (PPGPKT_STRUCT)poid_par_priv->information_buf; + + _irqlevel_changed_(&oldirql, LOWER); + + if (poid_par_priv->type_of_oid == QUERY_OID) { + + Efuse_PowerSwitch(Adapter, _FALSE, _TRUE); + if (Efuse_PgPacketRead(Adapter, ppgpkt->offset, ppgpkt->data, _FALSE) == _TRUE) + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + else + status = NDIS_STATUS_FAILURE; + Efuse_PowerSwitch(Adapter, _FALSE, _FALSE); + } else { + + Efuse_PowerSwitch(Adapter, _TRUE, _TRUE); + if (Efuse_PgPacketWrite(Adapter, ppgpkt->offset, ppgpkt->word_en, ppgpkt->data, _FALSE) == _TRUE) + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + else + status = NDIS_STATUS_FAILURE; + Efuse_PowerSwitch(Adapter, _TRUE, _FALSE); + } + + _irqlevel_changed_(&oldirql, RAISE); + + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u16 size; + u8 ret; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(u32)) + return NDIS_STATUS_INVALID_LENGTH; + + _irqlevel_changed_(&oldirql, LOWER); + ret = efuse_GetCurrentSize(Adapter, &size); + _irqlevel_changed_(&oldirql, RAISE); + if (ret == _SUCCESS) { + *(u32 *)poid_par_priv->information_buf = size; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + } else + status = NDIS_STATUS_FAILURE; + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + + if (poid_par_priv->type_of_oid != QUERY_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(u32)) + return NDIS_STATUS_INVALID_LENGTH; + + *(u32 *)poid_par_priv->information_buf = efuse_GetMaxSize(Adapter); + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status; + + + + if (poid_par_priv->type_of_oid == QUERY_OID) + status = oid_rt_pro_read_efuse_hdl(poid_par_priv); + else + status = oid_rt_pro_write_efuse_hdl(poid_par_priv); + + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u8 *data; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + u16 mapLen = 0; + + + + EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&mapLen, _FALSE); + + *poid_par_priv->bytes_rw = 0; + + if (poid_par_priv->information_buf_len < mapLen) + return NDIS_STATUS_INVALID_LENGTH; + + data = (u8 *)poid_par_priv->information_buf; + + _irqlevel_changed_(&oldirql, LOWER); + + if (poid_par_priv->type_of_oid == QUERY_OID) { + + if (rtw_efuse_map_read(Adapter, 0, mapLen, data) == _SUCCESS) + *poid_par_priv->bytes_rw = mapLen; + else { + status = NDIS_STATUS_FAILURE; + } + } else { + /* SET_OID */ + + if (rtw_efuse_map_write(Adapter, 0, mapLen, data) == _SUCCESS) + *poid_par_priv->bytes_rw = mapLen; + else { + status = NDIS_STATUS_FAILURE; + } + } + + _irqlevel_changed_(&oldirql, RAISE); + + + + return status; +} + +NDIS_STATUS oid_rt_set_crystal_cap_hdl(struct oid_par_priv *poid_par_priv) +{ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + + u32 crystal_cap = 0; + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(u32)) + return NDIS_STATUS_INVALID_LENGTH; + + crystal_cap = *((u32 *)poid_par_priv->information_buf); /* 4 */ + if (crystal_cap > 0xf) + return NDIS_STATUS_NOT_ACCEPTED; + + Adapter->mppriv.curr_crystalcap = crystal_cap; + + _irqlevel_changed_(&oldirql, LOWER); + SetCrystalCap(Adapter); + _irqlevel_changed_(&oldirql, RAISE); + + +#endif + return status; +} + +NDIS_STATUS oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u8 rx_pkt_type; + /* u32 rcr_val32; */ + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + /* PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); */ + + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(u8)) + return NDIS_STATUS_INVALID_LENGTH; + + rx_pkt_type = *((u8 *)poid_par_priv->information_buf); /* 4 */ + +#if 0 + _irqlevel_changed_(&oldirql, LOWER); +#if 0 + rcr_val8 = rtw_read8(Adapter, 0x10250048);/* RCR */ + rcr_val8 &= ~(RCR_AB | RCR_AM | RCR_APM | RCR_AAP); + + if (rx_pkt_type == RX_PKT_BROADCAST) + rcr_val8 |= (RCR_AB | RCR_ACRC32); + else if (rx_pkt_type == RX_PKT_DEST_ADDR) + rcr_val8 |= (RCR_AAP | RCR_AM | RCR_ACRC32); + else if (rx_pkt_type == RX_PKT_PHY_MATCH) + rcr_val8 |= (RCR_APM | RCR_ACRC32); + else + rcr_val8 &= ~(RCR_AAP | RCR_APM | RCR_AM | RCR_AB | RCR_ACRC32); + rtw_write8(padapter, 0x10250048, rcr_val8); +#else + rcr_val32 = rtw_read32(padapter, RCR);/* RCR = 0x10250048 */ + rcr_val32 &= ~(RCR_CBSSID | RCR_AB | RCR_AM | RCR_APM | RCR_AAP); +#if 0 + if (rx_pkt_type == RX_PKT_BROADCAST) + rcr_val32 |= (RCR_AB | RCR_AM | RCR_APM | RCR_AAP | RCR_ACRC32); + else if (rx_pkt_type == RX_PKT_DEST_ADDR) { + /* rcr_val32 |= (RCR_CBSSID|RCR_AAP|RCR_AM|RCR_ACRC32); */ + rcr_val32 |= (RCR_CBSSID | RCR_APM | RCR_ACRC32); + } else if (rx_pkt_type == RX_PKT_PHY_MATCH) { + rcr_val32 |= (RCR_APM | RCR_ACRC32); + /* rcr_val32 |= (RCR_AAP|RCR_ACRC32); */ + } else + rcr_val32 &= ~(RCR_AAP | RCR_APM | RCR_AM | RCR_AB | RCR_ACRC32); +#else + switch (rx_pkt_type) { + case RX_PKT_BROADCAST: + rcr_val32 |= (RCR_AB | RCR_AM | RCR_APM | RCR_AAP | RCR_ACRC32); + break; + case RX_PKT_DEST_ADDR: + rcr_val32 |= (RCR_AB | RCR_AM | RCR_APM | RCR_AAP | RCR_ACRC32); + break; + case RX_PKT_PHY_MATCH: + rcr_val32 |= (RCR_APM | RCR_ACRC32); + break; + default: + rcr_val32 &= ~(RCR_AAP | RCR_APM | RCR_AM | RCR_AB | RCR_ACRC32); + break; + } + + if (rx_pkt_type == RX_PKT_DEST_ADDR) + padapter->mppriv.check_mp_pkt = 1; + else + padapter->mppriv.check_mp_pkt = 0; +#endif + rtw_write32(padapter, RCR, rcr_val32); + +#endif + _irqlevel_changed_(&oldirql, RAISE); +#endif + + return status; +} + +NDIS_STATUS oid_rt_pro_set_tx_agc_offset_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + u32 txagc; + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(u32)) + return NDIS_STATUS_INVALID_LENGTH; + + txagc = *(u32 *)poid_par_priv->information_buf; + + _irqlevel_changed_(&oldirql, LOWER); + SetTxAGCOffset(Adapter, txagc); + _irqlevel_changed_(&oldirql, RAISE); + + + return status; +#else + return 0; +#endif +} + +NDIS_STATUS oid_rt_pro_set_pkt_test_mode_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; + struct mp_priv *pmppriv = &Adapter->mppriv; + u32 type; + + + if (poid_par_priv->type_of_oid != SET_OID) + return NDIS_STATUS_NOT_ACCEPTED; + + if (poid_par_priv->information_buf_len < sizeof(u32)) + return NDIS_STATUS_INVALID_LENGTH; + + type = *(u32 *)poid_par_priv->information_buf; + + if (_LOOPBOOK_MODE_ == type) { + pmppriv->mode = type; + set_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE); /* append txdesc */ + } else if (_2MAC_MODE_ == type) { + pmppriv->mode = type; + _clr_fwstate_(pmlmepriv, WIFI_MP_LPBK_STATE); + } else + status = NDIS_STATUS_NOT_ACCEPTED; + + + return status; +#else + return 0; +#endif +} + +unsigned int mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv) +{ + PMP_XMIT_PARM pparm; + PADAPTER padapter; + struct mp_priv *pmp_priv; + struct pkt_attrib *pattrib; + + + pparm = (PMP_XMIT_PARM)poid_par_priv->information_buf; + padapter = (PADAPTER)poid_par_priv->adapter_context; + pmp_priv = &padapter->mppriv; + + if (poid_par_priv->type_of_oid == QUERY_OID) { + pparm->enable = !pmp_priv->tx.stop; + pparm->count = pmp_priv->tx.sended; + } else { + if (pparm->enable == 0) + pmp_priv->tx.stop = 1; + else if (pmp_priv->tx.stop == 1) { + pmp_priv->tx.stop = 0; + pmp_priv->tx.count = pparm->count; + pmp_priv->tx.payload = pparm->payload_type; + pattrib = &pmp_priv->tx.attrib; + pattrib->pktlen = pparm->length; + _rtw_memcpy(pattrib->dst, pparm->da, ETH_ALEN); + SetPacketTx(padapter); + } else + return NDIS_STATUS_FAILURE; + } + + return NDIS_STATUS_SUCCESS; +} + +#if 0 +unsigned int mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv) +{ + unsigned char *pframe, *pmp_pkt; + struct ethhdr *pethhdr; + struct pkt_attrib *pattrib; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + int llc_sz, payload_len; + struct mp_xmit_frame *pxframe = NULL; + struct mp_xmit_packet *pmp_xmitpkt = (struct mp_xmit_packet *)param; + u8 addr3[] = {0x02, 0xE0, 0x4C, 0x87, 0x66, 0x55}; + + /* RTW_INFO("+mp_ioctl_xmit_packet_hdl\n"); */ + + pxframe = alloc_mp_xmitframe(&padapter->mppriv); + if (pxframe == NULL) { + DEBUG_ERR(("Can't alloc pmpframe %d:%s\n", __LINE__, __FILE__)); + return -1; + } + + /* mp_xmit_pkt */ + payload_len = pmp_xmitpkt->len - 14; + pmp_pkt = (unsigned char *)pmp_xmitpkt->mem; + pethhdr = (struct ethhdr *)pmp_pkt; + + /* RTW_INFO("payload_len=%d, pkt_mem=0x%x\n", pmp_xmitpkt->len, (void*)pmp_xmitpkt->mem); */ + + /* RTW_INFO("pxframe=0x%x\n", (void*)pxframe); */ + /* RTW_INFO("pxframe->mem=0x%x\n", (void*)pxframe->mem); */ + + /* update attribute */ + pattrib = &pxframe->attrib; + memset((u8 *)(pattrib), 0, sizeof(struct pkt_attrib)); + pattrib->pktlen = pmp_xmitpkt->len; + pattrib->ether_type = ntohs(pethhdr->h_proto); + pattrib->hdrlen = 24; + pattrib->nr_frags = 1; + pattrib->priority = 0; +#ifndef CONFIG_MP_LINUX + if (IS_MCAST(pethhdr->h_dest)) + pattrib->mac_id = 4; + else + pattrib->mac_id = 5; +#else + pattrib->mac_id = 5; +#endif + + /* */ + memset(pxframe->mem, 0 , WLANHDR_OFFSET); + pframe = (u8 *)(pxframe->mem) + WLANHDR_OFFSET; + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + set_frame_sub_type(pframe, WIFI_DATA); + + _rtw_memcpy(pwlanhdr->addr1, pethhdr->h_dest, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, pethhdr->h_source, ETH_ALEN); + + _rtw_memcpy(pwlanhdr->addr3, addr3, ETH_ALEN); + + pwlanhdr->seq_ctl = 0; + pframe += pattrib->hdrlen; + + llc_sz = rtw_put_snap(pframe, pattrib->ether_type); + pframe += llc_sz; + + _rtw_memcpy(pframe, (void *)(pmp_pkt + 14), payload_len); + + pattrib->last_txcmdsz = pattrib->hdrlen + llc_sz + payload_len; + + DEBUG_INFO(("issuing mp_xmit_frame, tx_len=%d, ether_type=0x%x\n", pattrib->last_txcmdsz, pattrib->ether_type)); + xmit_mp_frame(padapter, pxframe); + + return _SUCCESS; +} +#endif +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_set_power_down_hdl(struct oid_par_priv *poid_par_priv) +{ +#ifdef PLATFORM_OS_XP + _irqL oldirql; +#endif + u8 bpwrup; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; +#ifdef PLATFORM_LINUX +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + PADAPTER padapter = (PADAPTER)(poid_par_priv->adapter_context); +#endif +#endif + + + if (poid_par_priv->type_of_oid != SET_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + + + _irqlevel_changed_(&oldirql, LOWER); + + bpwrup = *(u8 *)poid_par_priv->information_buf; + /* CALL the power_down function */ +#ifdef PLATFORM_LINUX +#if defined(CONFIG_RTL8712) /* Linux MP insmod unknown symbol */ + dev_power_down(padapter, bpwrup); +#endif +#endif + _irqlevel_changed_(&oldirql, RAISE); + + /* DEBUG_ERR(("\n <=== Query OID_RT_PRO_READ_REGISTER. */ + /* Add:0x%08x Width:%d Value:0x%08x\n",RegRWStruct->offset,RegRWStruct->width,RegRWStruct->value)); */ + + + return status; +} +/* ------------------------------------------------------------------------------ */ +NDIS_STATUS oid_rt_get_power_mode_hdl(struct oid_par_priv *poid_par_priv) +{ +#if 0 + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + PADAPTER Adapter = (PADAPTER)(poid_par_priv->adapter_context); + /* #ifdef PLATFORM_OS_XP */ + /* _irqL oldirql; + * #endif */ + + + if (poid_par_priv->type_of_oid != QUERY_OID) { + status = NDIS_STATUS_NOT_ACCEPTED; + return status; + } + if (poid_par_priv->information_buf_len < sizeof(u32)) { + status = NDIS_STATUS_INVALID_LENGTH; + return status; + } + + + /* _irqlevel_changed_(&oldirql, LOWER); */ + *(int *)poid_par_priv->information_buf = Adapter->registrypriv.low_power ? POWER_LOW : POWER_NORMAL; + *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; + /* _irqlevel_changed_(&oldirql, RAISE); */ + + + return status; +#else + return 0; +#endif +} diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_odm.c b/linux-bsp/drivers/rtl8188eus/core/rtw_odm.c new file mode 100644 index 0000000..95b7b9b --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_odm.c @@ -0,0 +1,446 @@ +/****************************************************************************** + * + * Copyright(c) 2013 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#include <rtw_odm.h> +#include <hal_data.h> + + + +/* set ODM_CMNINFO_IC_TYPE based on chip_type */ +void rtw_odm_init_ic_type(_adapter *adapter) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct PHY_DM_STRUCT *odm = &hal_data->odmpriv; + u4Byte ic_type = chip_type_to_odm_ic_type(rtw_get_chip_type(adapter)); + + rtw_warn_on(!ic_type); + + odm_cmn_info_init(odm, ODM_CMNINFO_IC_TYPE, ic_type); +} + +inline void rtw_odm_set_force_igi_lb(_adapter *adapter, u8 lb) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + + hal_data->u1ForcedIgiLb = lb; +} + +inline u8 rtw_odm_get_force_igi_lb(_adapter *adapter) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + + return hal_data->u1ForcedIgiLb; +} + +void rtw_odm_adaptivity_ver_msg(void *sel, _adapter *adapter) +{ + RTW_PRINT_SEL(sel, "ADAPTIVITY_VERSION "ADAPTIVITY_VERSION"\n"); +} + +#define RTW_ADAPTIVITY_EN_DISABLE 0 +#define RTW_ADAPTIVITY_EN_ENABLE 1 + +void rtw_odm_adaptivity_en_msg(void *sel, _adapter *adapter) +{ + struct registry_priv *regsty = &adapter->registrypriv; + struct mlme_priv *mlme = &adapter->mlmepriv; + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct PHY_DM_STRUCT *odm = &hal_data->odmpriv; + + RTW_PRINT_SEL(sel, "RTW_ADAPTIVITY_EN_"); + + if (regsty->adaptivity_en == RTW_ADAPTIVITY_EN_DISABLE) + _RTW_PRINT_SEL(sel, "DISABLE\n"); + else if (regsty->adaptivity_en == RTW_ADAPTIVITY_EN_ENABLE) + _RTW_PRINT_SEL(sel, "ENABLE\n"); + else + _RTW_PRINT_SEL(sel, "INVALID\n"); +} + +#define RTW_ADAPTIVITY_MODE_NORMAL 0 +#define RTW_ADAPTIVITY_MODE_CARRIER_SENSE 1 + +void rtw_odm_adaptivity_mode_msg(void *sel, _adapter *adapter) +{ + struct registry_priv *regsty = &adapter->registrypriv; + + RTW_PRINT_SEL(sel, "RTW_ADAPTIVITY_MODE_"); + + if (regsty->adaptivity_mode == RTW_ADAPTIVITY_MODE_NORMAL) + _RTW_PRINT_SEL(sel, "NORMAL\n"); + else if (regsty->adaptivity_mode == RTW_ADAPTIVITY_MODE_CARRIER_SENSE) + _RTW_PRINT_SEL(sel, "CARRIER_SENSE\n"); + else + _RTW_PRINT_SEL(sel, "INVALID\n"); +} + +#define RTW_ADAPTIVITY_DML_DISABLE 0 +#define RTW_ADAPTIVITY_DML_ENABLE 1 + +void rtw_odm_adaptivity_dml_msg(void *sel, _adapter *adapter) +{ + struct registry_priv *regsty = &adapter->registrypriv; + + RTW_PRINT_SEL(sel, "RTW_ADAPTIVITY_DML_"); + + if (regsty->adaptivity_dml == RTW_ADAPTIVITY_DML_DISABLE) + _RTW_PRINT_SEL(sel, "DISABLE\n"); + else if (regsty->adaptivity_dml == RTW_ADAPTIVITY_DML_ENABLE) + _RTW_PRINT_SEL(sel, "ENABLE\n"); + else + _RTW_PRINT_SEL(sel, "INVALID\n"); +} + +void rtw_odm_adaptivity_dc_backoff_msg(void *sel, _adapter *adapter) +{ + struct registry_priv *regsty = &adapter->registrypriv; + + RTW_PRINT_SEL(sel, "RTW_ADAPTIVITY_DC_BACKOFF:%u\n", regsty->adaptivity_dc_backoff); +} + +void rtw_odm_adaptivity_config_msg(void *sel, _adapter *adapter) +{ + rtw_odm_adaptivity_ver_msg(sel, adapter); + rtw_odm_adaptivity_en_msg(sel, adapter); + rtw_odm_adaptivity_mode_msg(sel, adapter); + rtw_odm_adaptivity_dml_msg(sel, adapter); + rtw_odm_adaptivity_dc_backoff_msg(sel, adapter); +} + +bool rtw_odm_adaptivity_needed(_adapter *adapter) +{ + struct registry_priv *regsty = &adapter->registrypriv; + struct mlme_priv *mlme = &adapter->mlmepriv; + bool ret = _FALSE; + + if (regsty->adaptivity_en == RTW_ADAPTIVITY_EN_ENABLE) + ret = _TRUE; + + return ret; +} + +void rtw_odm_adaptivity_parm_msg(void *sel, _adapter *adapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); + struct PHY_DM_STRUCT *odm = &pHalData->odmpriv; + + rtw_odm_adaptivity_config_msg(sel, adapter); + + RTW_PRINT_SEL(sel, "%10s %16s %16s %22s %12s\n" + , "th_l2h_ini", "th_edcca_hl_diff", "th_l2h_ini_mode2", "th_edcca_hl_diff_mode2", "edcca_enable"); + RTW_PRINT_SEL(sel, "0x%-8x %-16d 0x%-14x %-22d %-12d\n" + , (u8)odm->th_l2h_ini + , odm->th_edcca_hl_diff + , (u8)odm->th_l2h_ini_mode2 + , odm->th_edcca_hl_diff_mode2 + , odm->edcca_enable + ); + + RTW_PRINT_SEL(sel, "%15s %9s\n", "AdapEnableState", "Adap_Flag"); + RTW_PRINT_SEL(sel, "%-15x %-9x\n" + , odm->adaptivity_enable + , odm->adaptivity_flag + ); +} + +void rtw_odm_adaptivity_parm_set(_adapter *adapter, s8 th_l2h_ini, s8 th_edcca_hl_diff, s8 th_l2h_ini_mode2, s8 th_edcca_hl_diff_mode2, u8 edcca_enable) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); + struct PHY_DM_STRUCT *odm = &pHalData->odmpriv; + + odm->th_l2h_ini = th_l2h_ini; + odm->th_edcca_hl_diff = th_edcca_hl_diff; + odm->th_l2h_ini_mode2 = th_l2h_ini_mode2; + odm->th_edcca_hl_diff_mode2 = th_edcca_hl_diff_mode2; + odm->edcca_enable = edcca_enable; +} + +void rtw_odm_get_perpkt_rssi(void *sel, _adapter *adapter) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct PHY_DM_STRUCT *odm = &(hal_data->odmpriv); + + RTW_PRINT_SEL(sel, "rx_rate = %s, RSSI_A = %d(%%), RSSI_B = %d(%%)\n", + HDATA_RATE(odm->rx_rate), odm->RSSI_A, odm->RSSI_B); +} + + +void rtw_odm_acquirespinlock(_adapter *adapter, enum rt_spinlock_type type) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(adapter); + _irqL irqL; + + switch (type) { + case RT_IQK_SPINLOCK: + _enter_critical_bh(&pHalData->IQKSpinLock, &irqL); + default: + break; + } +} + +void rtw_odm_releasespinlock(_adapter *adapter, enum rt_spinlock_type type) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(adapter); + _irqL irqL; + + switch (type) { + case RT_IQK_SPINLOCK: + _exit_critical_bh(&pHalData->IQKSpinLock, &irqL); + default: + break; + } +} + +inline u8 rtw_odm_get_dfs_domain(_adapter *adapter) +{ +#ifdef CONFIG_DFS_MASTER + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct PHY_DM_STRUCT *pDM_Odm = &(hal_data->odmpriv); + + return pDM_Odm->dfs_region_domain; +#else + return PHYDM_DFS_DOMAIN_UNKNOWN; +#endif +} + +inline u8 rtw_odm_dfs_domain_unknown(_adapter *adapter) +{ +#ifdef CONFIG_DFS_MASTER + return rtw_odm_get_dfs_domain(adapter) == PHYDM_DFS_DOMAIN_UNKNOWN; +#else + return 1; +#endif +} + +#ifdef CONFIG_DFS_MASTER +inline VOID rtw_odm_radar_detect_reset(_adapter *adapter) +{ + phydm_radar_detect_reset(GET_ODM(adapter)); +} + +inline VOID rtw_odm_radar_detect_disable(_adapter *adapter) +{ + phydm_radar_detect_disable(GET_ODM(adapter)); +} + +/* called after ch, bw is set */ +inline VOID rtw_odm_radar_detect_enable(_adapter *adapter) +{ + phydm_radar_detect_enable(GET_ODM(adapter)); +} + +inline BOOLEAN rtw_odm_radar_detect(_adapter *adapter) +{ + return phydm_radar_detect(GET_ODM(adapter)); +} +#endif /* CONFIG_DFS_MASTER */ + +void rtw_odm_parse_rx_phy_status_chinfo(union recv_frame *rframe, u8 *phys) +{ +#ifndef DBG_RX_PHYSTATUS_CHINFO +#define DBG_RX_PHYSTATUS_CHINFO 0 +#endif + +#if (ODM_PHY_STATUS_NEW_TYPE_SUPPORT == 1) + _adapter *adapter = rframe->u.hdr.adapter; + struct PHY_DM_STRUCT *phydm = GET_ODM(adapter); + struct rx_pkt_attrib *attrib = &rframe->u.hdr.attrib; + u8 *wlanhdr = get_recvframe_data(rframe); + + if (phydm->support_ic_type & ODM_IC_PHY_STATUE_NEW_TYPE) { + /* + * 8723D: + * type_0(CCK) + * l_rxsc + * is filled with primary channel SC, not real rxsc. + * 0:LSC, 1:USC + * type_1(OFDM) + * rf_mode + * RF bandwidth when RX + * l_rxsc(legacy), ht_rxsc + * see below RXSC N-series + * type_2(Not used) + */ + /* + * 8821C, 8822B: + * type_0(CCK) + * l_rxsc + * is filled with primary channel SC, not real rxsc. + * 0:LSC, 1:USC + * type_1(OFDM) + * rf_mode + * RF bandwidth when RX + * l_rxsc(legacy), ht_rxsc + * see below RXSC AC-series + * type_2(Not used) + */ + + if ((*phys & 0xf) == 0) { + struct _phy_status_rpt_jaguar2_type0 *phys_t0 = (struct _phy_status_rpt_jaguar2_type0 *)phys; + + if (DBG_RX_PHYSTATUS_CHINFO) { + RTW_PRINT("phys_t%u ta="MAC_FMT" %s, %s(band:%u, ch:%u, l_rxsc:%u)\n" + , *phys & 0xf + , MAC_ARG(get_ta(wlanhdr)) + , is_broadcast_mac_addr(get_ra(wlanhdr)) ? "BC" : is_multicast_mac_addr(get_ra(wlanhdr)) ? "MC" : "UC" + , HDATA_RATE(attrib->data_rate) + , phys_t0->band, phys_t0->channel, phys_t0->rxsc + ); + } + + } else if ((*phys & 0xf) == 1) { + struct _phy_status_rpt_jaguar2_type1 *phys_t1 = (struct _phy_status_rpt_jaguar2_type1 *)phys; + u8 rxsc = (attrib->data_rate > DESC_RATE11M && attrib->data_rate < DESC_RATEMCS0) ? phys_t1->l_rxsc : phys_t1->ht_rxsc; + u8 pkt_cch = 0; + u8 pkt_bw = CHANNEL_WIDTH_20; + + #if ODM_IC_11N_SERIES_SUPPORT + if (phydm->support_ic_type & ODM_IC_11N_SERIES) { + /* RXSC N-series */ + #define RXSC_DUP 0 + #define RXSC_LSC 1 + #define RXSC_USC 2 + #define RXSC_40M 3 + + static const s8 cch_offset_by_rxsc[4] = {0, -2, 2, 0}; + + if (phys_t1->rf_mode == 0) { + pkt_cch = phys_t1->channel; + pkt_bw = CHANNEL_WIDTH_20; + } else if (phys_t1->rf_mode == 1) { + if (rxsc == RXSC_LSC || rxsc == RXSC_USC) { + pkt_cch = phys_t1->channel + cch_offset_by_rxsc[rxsc]; + pkt_bw = CHANNEL_WIDTH_20; + } else if (rxsc == RXSC_40M) { + pkt_cch = phys_t1->channel; + pkt_bw = CHANNEL_WIDTH_40; + } + } else + rtw_warn_on(1); + + goto type1_end; + } + #endif /* ODM_IC_11N_SERIES_SUPPORT */ + + #if ODM_IC_11AC_SERIES_SUPPORT + if (phydm->support_ic_type & ODM_IC_11AC_SERIES) { + /* RXSC AC-series */ + #define RXSC_DUP 0 /* 0: RX from all SC of current rf_mode */ + + #define RXSC_LL20M_OF_160M 8 /* 1~8: RX from 20MHz SC */ + #define RXSC_L20M_OF_160M 6 + #define RXSC_L20M_OF_80M 4 + #define RXSC_L20M_OF_40M 2 + #define RXSC_U20M_OF_40M 1 + #define RXSC_U20M_OF_80M 3 + #define RXSC_U20M_OF_160M 5 + #define RXSC_UU20M_OF_160M 7 + + #define RXSC_L40M_OF_160M 12 /* 9~12: RX from 40MHz SC */ + #define RXSC_L40M_OF_80M 10 + #define RXSC_U40M_OF_80M 9 + #define RXSC_U40M_OF_160M 11 + + #define RXSC_L80M_OF_160M 14 /* 13~14: RX from 80MHz SC */ + #define RXSC_U80M_OF_160M 13 + + static const s8 cch_offset_by_rxsc[15] = {0, 2, -2, 6, -6, 10, -10, 14, -14, 4, -4, 12, -12, 8, -8}; + + if (phys_t1->rf_mode > 3) { + /* invalid rf_mode */ + rtw_warn_on(1); + goto type1_end; + } + + if (phys_t1->rf_mode == 0) { + /* RF 20MHz */ + pkt_cch = phys_t1->channel; + pkt_bw = CHANNEL_WIDTH_20; + goto type1_end; + } + + if (rxsc == 0) { + /* RF and RX with same BW */ + if (attrib->data_rate >= DESC_RATEMCS0) { + pkt_cch = phys_t1->channel; + pkt_bw = phys_t1->rf_mode; + } + goto type1_end; + } + + if ((phys_t1->rf_mode == 1 && rxsc >= 1 && rxsc <= 2) /* RF 40MHz, RX 20MHz */ + || (phys_t1->rf_mode == 2 && rxsc >= 1 && rxsc <= 4) /* RF 80MHz, RX 20MHz */ + || (phys_t1->rf_mode == 3 && rxsc >= 1 && rxsc <= 8) /* RF 160MHz, RX 20MHz */ + ) { + pkt_cch = phys_t1->channel + cch_offset_by_rxsc[rxsc]; + pkt_bw = CHANNEL_WIDTH_20; + } else if ((phys_t1->rf_mode == 2 && rxsc >= 9 && rxsc <= 10) /* RF 80MHz, RX 40MHz */ + || (phys_t1->rf_mode == 3 && rxsc >= 9 && rxsc <= 12) /* RF 160MHz, RX 40MHz */ + ) { + if (attrib->data_rate >= DESC_RATEMCS0) { + pkt_cch = phys_t1->channel + cch_offset_by_rxsc[rxsc]; + pkt_bw = CHANNEL_WIDTH_40; + } + } else if ((phys_t1->rf_mode == 3 && rxsc >= 13 && rxsc <= 14) /* RF 160MHz, RX 80MHz */ + ) { + if (attrib->data_rate >= DESC_RATEMCS0) { + pkt_cch = phys_t1->channel + cch_offset_by_rxsc[rxsc]; + pkt_bw = CHANNEL_WIDTH_80; + } + } else + rtw_warn_on(1); + + } + #endif /* ODM_IC_11AC_SERIES_SUPPORT */ + +type1_end: + if (DBG_RX_PHYSTATUS_CHINFO) { + RTW_PRINT("phys_t%u ta="MAC_FMT" %s, %s(band:%u, ch:%u, rf_mode:%u, l_rxsc:%u, ht_rxsc:%u) => %u,%u\n" + , *phys & 0xf + , MAC_ARG(get_ta(wlanhdr)) + , is_broadcast_mac_addr(get_ra(wlanhdr)) ? "BC" : is_multicast_mac_addr(get_ra(wlanhdr)) ? "MC" : "UC" + , HDATA_RATE(attrib->data_rate) + , phys_t1->band, phys_t1->channel, phys_t1->rf_mode, phys_t1->l_rxsc, phys_t1->ht_rxsc + , pkt_cch, pkt_bw + ); + } + + /* for now, only return cneter channel of 20MHz packet */ + if (pkt_cch && pkt_bw == CHANNEL_WIDTH_20) + attrib->ch = pkt_cch; + + } else { + struct _phy_status_rpt_jaguar2_type2 *phys_t2 = (struct _phy_status_rpt_jaguar2_type2 *)phys; + + if (DBG_RX_PHYSTATUS_CHINFO) { + RTW_PRINT("phys_t%u ta="MAC_FMT" %s, %s(band:%u, ch:%u, l_rxsc:%u, ht_rxsc:%u)\n" + , *phys & 0xf + , MAC_ARG(get_ta(wlanhdr)) + , is_broadcast_mac_addr(get_ra(wlanhdr)) ? "BC" : is_multicast_mac_addr(get_ra(wlanhdr)) ? "MC" : "UC" + , HDATA_RATE(attrib->data_rate) + , phys_t2->band, phys_t2->channel, phys_t2->l_rxsc, phys_t2->ht_rxsc + ); + } + } + } +#endif /* (ODM_PHY_STATUS_NEW_TYPE_SUPPORT == 1) */ + +} + diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_p2p.c b/linux-bsp/drivers/rtl8188eus/core/rtw_p2p.c new file mode 100644 index 0000000..4a7c55a --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_p2p.c @@ -0,0 +1,5310 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_P2P_C_ + +#include <drv_types.h> + +#ifdef CONFIG_P2P + +int rtw_p2p_is_channel_list_ok(u8 desired_ch, u8 *ch_list, u8 ch_cnt) +{ + int found = 0, i = 0; + + for (i = 0; i < ch_cnt; i++) { + if (ch_list[i] == desired_ch) { + found = 1; + break; + } + } + return found ; +} + +int is_any_client_associated(_adapter *padapter) +{ + return padapter->stapriv.asoc_list_cnt ? _TRUE : _FALSE; +} + +static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + _irqL irqL; + _list *phead, *plist; + u32 len = 0; + u16 attr_len = 0; + u8 tmplen, *pdata_attr, *pstart, *pcur; + struct sta_info *psta = NULL; + _adapter *padapter = pwdinfo->padapter; + struct sta_priv *pstapriv = &padapter->stapriv; + + RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); + + pdata_attr = rtw_zmalloc(MAX_P2P_IE_LEN); + + if (NULL == pdata_attr) { + RTW_INFO("%s pdata_attr malloc failed\n", __FUNCTION__); + goto _exit; + } + + pstart = pdata_attr; + pcur = pdata_attr; + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + phead = &pstapriv->asoc_list; + plist = get_next(phead); + + /* look up sta asoc_queue */ + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); + + plist = get_next(plist); + + + if (psta->is_p2p_device) { + tmplen = 0; + + pcur++; + + /* P2P device address */ + _rtw_memcpy(pcur, psta->dev_addr, ETH_ALEN); + pcur += ETH_ALEN; + + /* P2P interface address */ + _rtw_memcpy(pcur, psta->hwaddr, ETH_ALEN); + pcur += ETH_ALEN; + + *pcur = psta->dev_cap; + pcur++; + + /* *(u16*)(pcur) = cpu_to_be16(psta->config_methods); */ + RTW_PUT_BE16(pcur, psta->config_methods); + pcur += 2; + + _rtw_memcpy(pcur, psta->primary_dev_type, 8); + pcur += 8; + + *pcur = psta->num_of_secdev_type; + pcur++; + + _rtw_memcpy(pcur, psta->secdev_types_list, psta->num_of_secdev_type * 8); + pcur += psta->num_of_secdev_type * 8; + + if (psta->dev_name_len > 0) { + /* *(u16*)(pcur) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); */ + RTW_PUT_BE16(pcur, WPS_ATTR_DEVICE_NAME); + pcur += 2; + + /* *(u16*)(pcur) = cpu_to_be16( psta->dev_name_len ); */ + RTW_PUT_BE16(pcur, psta->dev_name_len); + pcur += 2; + + _rtw_memcpy(pcur, psta->dev_name, psta->dev_name_len); + pcur += psta->dev_name_len; + } + + + tmplen = (u8)(pcur - pstart); + + *pstart = (tmplen - 1); + + attr_len += tmplen; + + /* pstart += tmplen; */ + pstart = pcur; + + } + + + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + if (attr_len > 0) + len = rtw_set_p2p_attr_content(pbuf, P2P_ATTR_GROUP_INFO, attr_len, pdata_attr); + + rtw_mfree(pdata_attr, MAX_P2P_IE_LEN); + +_exit: + return len; + +} + +static void issue_group_disc_req(struct wifidirect_info *pwdinfo, u8 *da) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + _adapter *padapter = pwdinfo->padapter; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + unsigned char category = RTW_WLAN_CATEGORY_P2P;/* P2P action frame */ + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_GO_DISC_REQUEST; + u8 dialogToken = 0; + + RTW_INFO("[%s]\n", __FUNCTION__); + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + /* Build P2P action frame header */ + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); + + /* there is no IE in this P2P action frame */ + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + +} + +static void issue_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + _adapter *padapter = pwdinfo->padapter; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_DEVDISC_RESP; + u8 p2pie[8] = { 0x00 }; + u32 p2pielen = 0; + + RTW_INFO("[%s]\n", __FUNCTION__); + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, pwdinfo->device_addr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, pwdinfo->device_addr, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + /* Build P2P public action frame header */ + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); + + + /* Build P2P IE */ + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* P2P_ATTR_STATUS */ + p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status); + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &pattrib->pktlen); + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + +} + +static void issue_p2p_provision_resp(struct wifidirect_info *pwdinfo, u8 *raddr, u8 *frame_body, u16 config_method) +{ + _adapter *padapter = pwdinfo->padapter; + unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u8 dialogToken = frame_body[7]; /* The Dialog Token of provisioning discovery request frame. */ + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_PROVISION_DISC_RESP; + u8 wpsie[100] = { 0x00 }; + u8 wpsielen = 0; +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif + + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); + + wpsielen = 0; + /* WPS OUI */ + /* *(u32*) ( wpsie ) = cpu_to_be32( WPSOUI ); */ + RTW_PUT_BE32(wpsie, WPSOUI); + wpsielen += 4; + +#if 0 + /* WPS version */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ +#endif + + /* Config Method */ + /* Type: */ + /* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_CONF_METHOD ); */ + RTW_PUT_BE16(wpsie + wpsielen, WPS_ATTR_CONF_METHOD); + wpsielen += 2; + + /* Length: */ + /* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0002 ); */ + RTW_PUT_BE16(wpsie + wpsielen, 0x0002); + wpsielen += 2; + + /* Value: */ + /* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( config_method ); */ + RTW_PUT_BE16(wpsie + wpsielen, config_method); + wpsielen += 2; + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen); + +#ifdef CONFIG_WFD + wfdielen = build_provdisc_resp_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; +#endif + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + + return; + +} + +static void issue_p2p_presence_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + _adapter *padapter = pwdinfo->padapter; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + unsigned char category = RTW_WLAN_CATEGORY_P2P;/* P2P action frame */ + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_PRESENCE_RESPONSE; + u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; + u8 noa_attr_content[32] = { 0x00 }; + u32 p2pielen = 0; + + RTW_INFO("[%s]\n", __FUNCTION__); + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + return; + + /* update attribute */ + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + /* Build P2P action frame header */ + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pattrib->pktlen)); + + + /* Add P2P IE header */ + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Add Status attribute in P2P IE */ + p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status); + + /* Add NoA attribute in P2P IE */ + noa_attr_content[0] = 0x1;/* index */ + noa_attr_content[1] = 0x0;/* CTWindow and OppPS Parameters */ + + /* todo: Notice of Absence Descriptor(s) */ + + p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_NOA, 2, noa_attr_content); + + + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &(pattrib->pktlen)); + + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + +} + +u32 build_beacon_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; + u16 capability = 0; + u32 len = 0, p2pielen = 0; + + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + + /* According to the P2P Specification, the beacon frame should contain 3 P2P attributes */ + /* 1. P2P Capability */ + /* 2. P2P Device ID */ + /* 3. Notice of Absence ( NOA ) */ + + /* P2P Capability ATTR */ + /* Type: */ + /* Length: */ + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + /* Be able to participate in additional P2P Groups and */ + /* support the P2P Invitation Procedure */ + /* Group Capability Bitmap, 1 byte */ + capability = P2P_DEVCAP_INVITATION_PROC | P2P_DEVCAP_CLIENT_DISCOVERABILITY; + capability |= ((P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS) << 8); + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) + capability |= (P2P_GRPCAP_GROUP_FORMATION << 8); + + capability = cpu_to_le16(capability); + + p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_CAPABILITY, 2, (u8 *)&capability); + + + /* P2P Device ID ATTR */ + p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_DEVICE_ID, ETH_ALEN, pwdinfo->device_addr); + + + /* Notice of Absence ATTR */ + /* Type: */ + /* Length: */ + /* Value: */ + + /* go_add_noa_attr(pwdinfo); */ + + + pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); + + + return len; + +} + +#ifdef CONFIG_WFD +u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 }; + u16 val16 = 0; + u32 len = 0, wfdielen = 0; + _adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info; + + if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + goto exit; + + /* WFD OUI */ + wfdielen = 0; + wfdie[wfdielen++] = 0x50; + wfdie[wfdielen++] = 0x6F; + wfdie[wfdielen++] = 0x9A; + wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110812 */ + /* According to the WFD Specification, the beacon frame should contain 4 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID */ + /* 3. Coupled Sink Information */ + + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + + if (P2P_ROLE_GO == pwdinfo->role) { + if (is_any_client_associated(pwdinfo->padapter)) { + /* WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) */ + val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD; + RTW_PUT_BE16(wfdie + wfdielen, val16); + } else { + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */ + val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD; + RTW_PUT_BE16(wfdie + wfdielen, val16); + } + + } else { + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */ + val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD; + RTW_PUT_BE16(wfdie + wfdielen, val16); + } + + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + _rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + else + _rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN); + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[wfdielen++] = 0; + /* MAC Addr. */ + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + + rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + +exit: + return len; +} + +u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 }; + u16 val16 = 0; + u32 len = 0, wfdielen = 0; + _adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info; + + if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + goto exit; + + /* WFD OUI */ + wfdielen = 0; + wfdie[wfdielen++] = 0x50; + wfdie[wfdielen++] = 0x6F; + wfdie[wfdielen++] = 0x9A; + wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110812 */ + /* According to the WFD Specification, the probe request frame should contain 4 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID */ + /* 3. Coupled Sink Information */ + + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + + if (1 == pwdinfo->wfd_tdls_enable) { + /* WFD primary sink + available for WFD session + WiFi TDLS mode + WSC ( WFD Service Discovery ) */ + val16 = pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | + WFD_DEVINFO_WSD | + WFD_DEVINFO_PC_TDLS; + RTW_PUT_BE16(wfdie + wfdielen, val16); + } else { + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSC ( WFD Service Discovery ) */ + val16 = pwfd_info->wfd_device_type | + WFD_DEVINFO_SESSION_AVAIL | + WFD_DEVINFO_WSD; + RTW_PUT_BE16(wfdie + wfdielen, val16); + } + + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + _rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + else + _rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN); + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[wfdielen++] = 0; + /* MAC Addr. */ + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + + rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + +exit: + return len; +} + +u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunneled) +{ + u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + _adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info; + + if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + goto exit; + + /* WFD OUI */ + wfdielen = 0; + wfdie[wfdielen++] = 0x50; + wfdie[wfdielen++] = 0x6F; + wfdie[wfdielen++] = 0x9A; + wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110812 */ + /* According to the WFD Specification, the probe response frame should contain 4 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID */ + /* 3. Coupled Sink Information */ + /* 4. WFD Session Information */ + + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode */ + + if (_TRUE == pwdinfo->session_available) { + if (P2P_ROLE_GO == pwdinfo->role) { + if (is_any_client_associated(pwdinfo->padapter)) { + if (pwdinfo->wfd_tdls_enable) { + /* TDLS mode + WSD ( WFD Service Discovery ) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); + } else { + /* WiFi Direct mode + WSD ( WFD Service Discovery ) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); + } + } else { + if (pwdinfo->wfd_tdls_enable) { + /* available for WFD session + TDLS mode + WSD ( WFD Service Discovery ) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); + } else { + /* available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); + } + } + } else { + if (pwdinfo->wfd_tdls_enable) { + /* available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); + } else { + + /* available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); + } + } + } else { + if (pwdinfo->wfd_tdls_enable) + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT); + else + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT); + + } + + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + _rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + else + _rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN); + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[wfdielen++] = 0; + /* MAC Addr. */ + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + /* WFD Session Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_SESSION_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0000); + wfdielen += 2; + + /* Todo: to add the list of WFD device info descriptor in WFD group. */ + + } +#ifdef CONFIG_CONCURRENT_MODE +#ifdef CONFIG_TDLS + { + int i; + _adapter *iface = NULL; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if ((iface) && rtw_is_adapter_up(iface)) { + if (iface == padapter) + continue; + + if ((tunneled == 0) && (iface->wdinfo.wfd_tdls_enable == 1)) { + /* Alternative MAC Address ATTR + Type: */ + wfdie[wfdielen++] = WFD_ATTR_ALTER_MAC; + + /* Length: + Note: In the WFD specification, the size of length field is 2.*/ + RTW_PUT_BE16(wfdie + wfdielen, ETH_ALEN); + wfdielen += 2; + + /* Value: + Alternative MAC Address*/ + _rtw_memcpy(wfdie + wfdielen, adapter_mac_addr(iface), ETH_ALEN); + wfdielen += ETH_ALEN; + } + } + } + } + +#endif /* CONFIG_TDLS*/ +#endif /* CONFIG_CONCURRENT_MODE */ + + pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + +exit: + return len; +} + +u32 build_assoc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 }; + u16 val16 = 0; + u32 len = 0, wfdielen = 0; + _adapter *padapter = NULL; + struct mlme_priv *pmlmepriv = NULL; + struct wifi_display_info *pwfd_info = NULL; + + padapter = pwdinfo->padapter; + pmlmepriv = &padapter->mlmepriv; + pwfd_info = padapter->wdinfo.wfd_info; + + if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + goto exit; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) + goto exit; + + /* WFD OUI */ + wfdielen = 0; + wfdie[wfdielen++] = 0x50; + wfdie[wfdielen++] = 0x6F; + wfdie[wfdielen++] = 0x9A; + wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110812 */ + /* According to the WFD Specification, the probe request frame should contain 4 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID */ + /* 3. Coupled Sink Information */ + + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */ + val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD; + RTW_PUT_BE16(wfdie + wfdielen, val16); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + _rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + else + _rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN); + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[wfdielen++] = 0; + /* MAC Addr. */ + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + + rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + +exit: + return len; +} + +u32 build_assoc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + u16 val16 = 0; + _adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info; + + if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + goto exit; + + /* WFD OUI */ + wfdielen = 0; + wfdie[wfdielen++] = 0x50; + wfdie[wfdielen++] = 0x6F; + wfdie[wfdielen++] = 0x9A; + wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110812 */ + /* According to the WFD Specification, the probe request frame should contain 4 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID */ + /* 3. Coupled Sink Information */ + + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */ + val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD; + RTW_PUT_BE16(wfdie + wfdielen, val16); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + _rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + else + _rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN); + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[wfdielen++] = 0; + /* MAC Addr. */ + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + + rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + +exit: + return len; +} + +u32 build_nego_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + u16 val16 = 0; + _adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info; + + if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + goto exit; + + /* WFD OUI */ + wfdielen = 0; + wfdie[wfdielen++] = 0x50; + wfdie[wfdielen++] = 0x6F; + wfdie[wfdielen++] = 0x9A; + wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID ( Optional ) */ + /* 3. Local IP Adress ( Optional ) */ + + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + WiFi Direct mode + WSD ( WFD Service Discovery ) + WFD Session Available */ + val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL; + RTW_PUT_BE16(wfdie + wfdielen, val16); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + _rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + else + _rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN); + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[wfdielen++] = 0; + /* MAC Addr. */ + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + + rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + +exit: + return len; +} + +u32 build_nego_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + u16 val16 = 0; + _adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info; + + if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + goto exit; + + /* WFD OUI */ + wfdielen = 0; + wfdie[wfdielen++] = 0x50; + wfdie[wfdielen++] = 0x6F; + wfdie[wfdielen++] = 0x9A; + wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID ( Optional ) */ + /* 3. Local IP Adress ( Optional ) */ + + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + WiFi Direct mode + WSD ( WFD Service Discovery ) + WFD Session Available */ + val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL; + RTW_PUT_BE16(wfdie + wfdielen, val16); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + _rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + else + _rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN); + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[wfdielen++] = 0; + /* MAC Addr. */ + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + + + rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + +exit: + return len; +} + +u32 build_nego_confirm_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + u16 val16 = 0; + _adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info; + + if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + goto exit; + + /* WFD OUI */ + wfdielen = 0; + wfdie[wfdielen++] = 0x50; + wfdie[wfdielen++] = 0x6F; + wfdie[wfdielen++] = 0x9A; + wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID ( Optional ) */ + /* 3. Local IP Adress ( Optional ) */ + + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + WiFi Direct mode + WSD ( WFD Service Discovery ) + WFD Session Available */ + val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL; + RTW_PUT_BE16(wfdie + wfdielen, val16); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + _rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + else + _rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN); + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[wfdielen++] = 0; + /* MAC Addr. */ + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + + + pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + +exit: + return len; +} + +u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + u16 val16 = 0; + _adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info; + + if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + goto exit; + + /* WFD OUI */ + wfdielen = 0; + wfdie[wfdielen++] = 0x50; + wfdie[wfdielen++] = 0x6F; + wfdie[wfdielen++] = 0x9A; + wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID ( Optional ) */ + /* 3. Local IP Adress ( Optional ) */ + + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */ + val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD; + RTW_PUT_BE16(wfdie + wfdielen, val16); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + _rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + else + _rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN); + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[wfdielen++] = 0; + /* MAC Addr. */ + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + + if (P2P_ROLE_GO == pwdinfo->role) { + /* WFD Session Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_SESSION_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0000); + wfdielen += 2; + + /* Todo: to add the list of WFD device info descriptor in WFD group. */ + + } + + rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + +exit: + return len; +} + +u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 }; + u16 val16 = 0; + u32 len = 0, wfdielen = 0; + _adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info; + + if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + goto exit; + + /* WFD OUI */ + wfdielen = 0; + wfdie[wfdielen++] = 0x50; + wfdie[wfdielen++] = 0x6F; + wfdie[wfdielen++] = 0x9A; + wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID ( Optional ) */ + /* 3. Local IP Adress ( Optional ) */ + + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */ + val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD; + RTW_PUT_BE16(wfdie + wfdielen, val16); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + _rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + else + _rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN); + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[wfdielen++] = 0; + /* MAC Addr. */ + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + + if (P2P_ROLE_GO == pwdinfo->role) { + /* WFD Session Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_SESSION_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0000); + wfdielen += 2; + + /* Todo: to add the list of WFD device info descriptor in WFD group. */ + + } + + rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + +exit: + return len; +} + +u32 build_provdisc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + u16 val16 = 0; + _adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info; + + if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + goto exit; + + /* WFD OUI */ + wfdielen = 0; + wfdie[wfdielen++] = 0x50; + wfdie[wfdielen++] = 0x6F; + wfdie[wfdielen++] = 0x9A; + wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID ( Optional ) */ + /* 3. Local IP Adress ( Optional ) */ + + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */ + val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD; + RTW_PUT_BE16(wfdie + wfdielen, val16); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + _rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + else + _rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN); + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[wfdielen++] = 0; + /* MAC Addr. */ + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + + + rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + +exit: + return len; +} + +u32 build_provdisc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 }; + u32 len = 0, wfdielen = 0; + u16 val16 = 0; + _adapter *padapter = pwdinfo->padapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info *pwfd_info = padapter->wdinfo.wfd_info; + + if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + goto exit; + + /* WFD OUI */ + wfdielen = 0; + wfdie[wfdielen++] = 0x50; + wfdie[wfdielen++] = 0x6F; + wfdie[wfdielen++] = 0x9A; + wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */ + + /* Commented by Albert 20110825 */ + /* According to the WFD Specification, the provision discovery response frame should contain 3 WFD attributes */ + /* 1. WFD Device Information */ + /* 2. Associated BSSID ( Optional ) */ + /* 3. Local IP Adress ( Optional ) */ + + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* WFD primary sink + available for WFD session + WiFi Direct mode + WSD ( WFD Service Discovery ) */ + val16 = pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD; + RTW_PUT_BE16(wfdie + wfdielen, val16); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + _rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + else + _rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN); + + wfdielen += ETH_ALEN; + + /* Coupled Sink Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_COUPLED_SINK_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0007); + wfdielen += 2; + + /* Value: */ + /* Coupled Sink Status bitmap */ + /* Not coupled/available for Coupling */ + wfdie[wfdielen++] = 0; + /* MAC Addr. */ + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + wfdie[wfdielen++] = 0; + + rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len); + +exit: + return len; +} +#endif /* CONFIG_WFD */ + +u32 build_probe_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; + u32 len = 0, p2pielen = 0; +#ifdef CONFIG_INTEL_WIDI + struct mlme_priv *pmlmepriv = &(pwdinfo->padapter->mlmepriv); + u8 zero_array_check[L2SDTA_SERVICE_VE_LEN] = { 0x00 }; + u8 widi_version = 0, i = 0; + + if (_rtw_memcmp(pmlmepriv->sa_ext, zero_array_check, L2SDTA_SERVICE_VE_LEN) == _FALSE) + widi_version = 35; + else if (pmlmepriv->num_p2p_sdt != 0) + widi_version = 40; +#endif /* CONFIG_INTEL_WIDI */ + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20100907 */ + /* According to the P2P Specification, the probe response frame should contain 5 P2P attributes */ + /* 1. P2P Capability */ + /* 2. Extended Listen Timing */ + /* 3. Notice of Absence ( NOA ) ( Only GO needs this ) */ + /* 4. Device Info */ + /* 5. Group Info ( Only GO need this ) */ + + /* P2P Capability ATTR */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); */ + RTW_PUT_LE16(p2pie + p2pielen, 0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; + + /* Group Capability Bitmap, 1 byte */ + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + p2pie[p2pielen] = (P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS); + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING)) + p2pie[p2pielen] |= P2P_GRPCAP_GROUP_FORMATION; + + p2pielen++; + } else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) { + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) + p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; + else + p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; + } + + /* Extended Listen Timing ATTR */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING; + + /* Length: */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0004 ); */ + RTW_PUT_LE16(p2pie + p2pielen, 0x0004); + p2pielen += 2; + + /* Value: */ + /* Availability Period */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0xFFFF ); */ + RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF); + p2pielen += 2; + + /* Availability Interval */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0xFFFF ); */ + RTW_PUT_LE16(p2pie + p2pielen, 0xFFFF); + p2pielen += 2; + + + /* Notice of Absence ATTR */ + /* Type: */ + /* Length: */ + /* Value: */ + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + /* go_add_noa_attr(pwdinfo); */ + } + + /* Device Info ATTR */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + /* 21->P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ + /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 21 + pwdinfo->device_name_len ); */ +#ifdef CONFIG_INTEL_WIDI + if (widi_version == 35) + RTW_PUT_LE16(p2pie + p2pielen, 21 + 8 + pwdinfo->device_name_len); + else if (widi_version == 40) + RTW_PUT_LE16(p2pie + p2pielen, 21 + 8 * pmlmepriv->num_p2p_sdt + pwdinfo->device_name_len); + else +#endif /* CONFIG_INTEL_WIDI */ + RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Config Method */ + /* This field should be big endian. Noted by P2P specification. */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->supported_wps_cm ); */ + RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->supported_wps_cm); + p2pielen += 2; + +#ifdef CONFIG_INTEL_WIDI + if (widi_version == 40) { + /* Primary Device Type */ + /* Category ID */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); */ + RTW_PUT_BE16(p2pie + p2pielen, pmlmepriv->p2p_pdt_cid); + p2pielen += 2; + + /* OUI */ + /* *(u32*) ( p2pie + p2pielen ) = cpu_to_be32( WPSOUI ); */ + RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); */ + RTW_PUT_BE16(p2pie + p2pielen, pmlmepriv->p2p_pdt_scid); + p2pielen += 2; + } else +#endif /* CONFIG_INTEL_WIDI */ + { + /* Primary Device Type */ + /* Category ID */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA); + p2pielen += 2; + + /* OUI */ + /* *(u32*) ( p2pie + p2pielen ) = cpu_to_be32( WPSOUI ); */ + RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER); + p2pielen += 2; + } + + /* Number of Secondary Device Types */ +#ifdef CONFIG_INTEL_WIDI + if (widi_version == 35) { + p2pie[p2pielen++] = 0x01; + + RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_DISPLAYS); + p2pielen += 2; + + RTW_PUT_BE32(p2pie + p2pielen, INTEL_DEV_TYPE_OUI); + p2pielen += 4; + + RTW_PUT_BE16(p2pie + p2pielen, P2P_SCID_WIDI_CONSUMER_SINK); + p2pielen += 2; + } else if (widi_version == 40) { + p2pie[p2pielen++] = pmlmepriv->num_p2p_sdt; + for (; i < pmlmepriv->num_p2p_sdt; i++) { + RTW_PUT_BE16(p2pie + p2pielen, pmlmepriv->p2p_sdt_cid[i]); + p2pielen += 2; + + RTW_PUT_BE32(p2pie + p2pielen, INTEL_DEV_TYPE_OUI); + p2pielen += 4; + + RTW_PUT_BE16(p2pie + p2pielen, pmlmepriv->p2p_sdt_scid[i]); + p2pielen += 2; + } + } else +#endif /* CONFIG_INTEL_WIDI */ + p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ + + /* Device Name */ + /* Type: */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME); + p2pielen += 2; + + /* Length: */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->device_name_len ); */ + RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); + p2pielen += pwdinfo->device_name_len; + + /* Group Info ATTR */ + /* Type: */ + /* Length: */ + /* Value: */ + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + p2pielen += go_add_group_info_attr(pwdinfo, p2pie + p2pielen); + + + pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); + + + return len; + +} + +u32 build_prov_disc_request_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 *pssid, u8 ussidlen, u8 *pdev_raddr) +{ + u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; + u32 len = 0, p2pielen = 0; + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20110301 */ + /* According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */ + /* 1. P2P Capability */ + /* 2. Device Info */ + /* 3. Group ID ( When joining an operating P2P Group ) */ + + /* P2P Capability ATTR */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 0x0002 ); */ + RTW_PUT_LE16(p2pie + p2pielen, 0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; + + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) + p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT; + else + p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT; + + + /* Device Info ATTR */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + /* 21->P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ + /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( 21 + pwdinfo->device_name_len ); */ + RTW_PUT_LE16(p2pie + p2pielen, 21 + pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Config Method */ + /* This field should be big endian. Noted by P2P specification. */ + if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC) { + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_CONFIG_METHOD_PBC ); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_PBC); + } else { + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_CONFIG_METHOD_DISPLAY ); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_CONFIG_METHOD_DISPLAY); + } + + p2pielen += 2; + + /* Primary Device Type */ + /* Category ID */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_CID_MULIT_MEDIA ); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_CID_MULIT_MEDIA); + p2pielen += 2; + + /* OUI */ + /* *(u32*) ( p2pie + p2pielen ) = cpu_to_be32( WPSOUI ); */ + RTW_PUT_BE32(p2pie + p2pielen, WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_PDT_SCID_MEDIA_SERVER ); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_PDT_SCID_MEDIA_SERVER); + p2pielen += 2; + + /* Number of Secondary Device Types */ + p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ + + /* Device Name */ + /* Type: */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( WPS_ATTR_DEVICE_NAME ); */ + RTW_PUT_BE16(p2pie + p2pielen, WPS_ATTR_DEVICE_NAME); + p2pielen += 2; + + /* Length: */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_be16( pwdinfo->device_name_len ); */ + RTW_PUT_BE16(p2pie + p2pielen, pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len); + p2pielen += pwdinfo->device_name_len; + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { + /* Added by Albert 2011/05/19 */ + /* In this case, the pdev_raddr is the device address of the group owner. */ + + /* P2P Group ID ATTR */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; + + /* Length: */ + /* *(u16*) ( p2pie + p2pielen ) = cpu_to_le16( ETH_ALEN + ussidlen ); */ + RTW_PUT_LE16(p2pie + p2pielen, ETH_ALEN + ussidlen); + p2pielen += 2; + + /* Value: */ + _rtw_memcpy(p2pie + p2pielen, pdev_raddr, ETH_ALEN); + p2pielen += ETH_ALEN; + + _rtw_memcpy(p2pie + p2pielen, pssid, ussidlen); + p2pielen += ussidlen; + + } + + pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); + + + return len; + +} + + +u32 build_assoc_resp_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 status_code) +{ + u8 p2pie[MAX_P2P_IE_LEN] = { 0x00 }; + u32 len = 0, p2pielen = 0; + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* According to the P2P Specification, the Association response frame should contain 2 P2P attributes */ + /* 1. Status */ + /* 2. Extended Listen Timing (optional) */ + + + /* Status ATTR */ + p2pielen += rtw_set_p2p_attr_content(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status_code); + + + /* Extended Listen Timing ATTR */ + /* Type: */ + /* Length: */ + /* Value: */ + + + pbuf = rtw_set_ie(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len); + + return len; + +} + +u32 build_deauth_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pbuf) +{ + u32 len = 0; + + return len; +} + +u32 process_probe_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + u8 *p; + u32 ret = _FALSE; + u8 *p2pie; + u32 p2pielen = 0; + int ssid_len = 0, rate_cnt = 0; + + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SUPPORTEDRATES_IE_, (int *)&rate_cnt, + len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); + + if (rate_cnt <= 4) { + int i, g_rate = 0; + + for (i = 0; i < rate_cnt; i++) { + if (((*(p + 2 + i) & 0xff) != 0x02) && + ((*(p + 2 + i) & 0xff) != 0x04) && + ((*(p + 2 + i) & 0xff) != 0x0B) && + ((*(p + 2 + i) & 0xff) != 0x16)) + g_rate = 1; + } + + if (g_rate == 0) { + /* There is no OFDM rate included in SupportedRates IE of this probe request frame */ + /* The driver should response this probe request. */ + return ret; + } + } else { + /* rate_cnt > 4 means the SupportRates IE contains the OFDM rate because the count of CCK rates are 4. */ + /* We should proceed the following check for this probe request. */ + } + + /* Added comments by Albert 20100906 */ + /* There are several items we should check here. */ + /* 1. This probe request frame must contain the P2P IE. (Done) */ + /* 2. This probe request frame must contain the wildcard SSID. (Done) */ + /* 3. Wildcard BSSID. (Todo) */ + /* 4. Destination Address. ( Done in mgt_dispatcher function ) */ + /* 5. Requested Device Type in WSC IE. (Todo) */ + /* 6. Device ID attribute in P2P IE. (Todo) */ + + p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ssid_len, + len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_); + + ssid_len &= 0xff; /* Just last 1 byte is valid for ssid len of the probe request */ + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + p2pie = rtw_get_p2p_ie(pframe + WLAN_HDR_A3_LEN + _PROBEREQ_IE_OFFSET_ , len - WLAN_HDR_A3_LEN - _PROBEREQ_IE_OFFSET_ , NULL, &p2pielen); + if (p2pie) { + if ((p != NULL) && _rtw_memcmp((void *)(p + 2), (void *) pwdinfo->p2p_wildcard_ssid , 7)) { + /* todo: */ + /* Check Requested Device Type attributes in WSC IE. */ + /* Check Device ID attribute in P2P IE */ + + ret = _TRUE; + } else if ((p != NULL) && (ssid_len == 0)) + ret = _TRUE; + } else { + /* non -p2p device */ + } + + } + + + return ret; + +} + +u32 process_assoc_req_p2p_ie(struct wifidirect_info *pwdinfo, u8 *pframe, uint len, struct sta_info *psta) +{ + u8 status_code = P2P_STATUS_SUCCESS; + u8 *pbuf, *pattr_content = NULL; + u32 attr_contentlen = 0; + u16 cap_attr = 0; + unsigned short frame_type, ie_offset = 0; + u8 *ies; + u32 ies_len; + u8 *p2p_ie; + u32 p2p_ielen = 0; + + if (!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) + return P2P_STATUS_FAIL_REQUEST_UNABLE; + + frame_type = get_frame_sub_type(pframe); + if (frame_type == WIFI_ASSOCREQ) + ie_offset = _ASOCREQ_IE_OFFSET_; + else /* WIFI_REASSOCREQ */ + ie_offset = _REASOCREQ_IE_OFFSET_; + + ies = pframe + WLAN_HDR_A3_LEN + ie_offset; + ies_len = len - WLAN_HDR_A3_LEN - ie_offset; + + p2p_ie = rtw_get_p2p_ie(ies , ies_len , NULL, &p2p_ielen); + + if (!p2p_ie) { + RTW_INFO("[%s] P2P IE not Found!!\n", __FUNCTION__); + status_code = P2P_STATUS_FAIL_INVALID_PARAM; + } else + RTW_INFO("[%s] P2P IE Found!!\n", __FUNCTION__); + + while (p2p_ie) { + /* Check P2P Capability ATTR */ + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8 *)&cap_attr, (uint *) &attr_contentlen)) { + RTW_INFO("[%s] Got P2P Capability Attr!!\n", __FUNCTION__); + cap_attr = le16_to_cpu(cap_attr); + psta->dev_cap = cap_attr & 0xff; + } + + /* Check Extended Listen Timing ATTR */ + + + /* Check P2P Device Info ATTR */ + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, NULL, (uint *)&attr_contentlen)) { + RTW_INFO("[%s] Got P2P DEVICE INFO Attr!!\n", __FUNCTION__); + pattr_content = pbuf = rtw_zmalloc(attr_contentlen); + if (pattr_content) { + u8 num_of_secdev_type; + u16 dev_name_len; + + + rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO , pattr_content, (uint *)&attr_contentlen); + + _rtw_memcpy(psta->dev_addr, pattr_content, ETH_ALEN);/* P2P Device Address */ + + pattr_content += ETH_ALEN; + + _rtw_memcpy(&psta->config_methods, pattr_content, 2);/* Config Methods */ + psta->config_methods = be16_to_cpu(psta->config_methods); + + pattr_content += 2; + + _rtw_memcpy(psta->primary_dev_type, pattr_content, 8); + + pattr_content += 8; + + num_of_secdev_type = *pattr_content; + pattr_content += 1; + + if (num_of_secdev_type == 0) + psta->num_of_secdev_type = 0; + else { + u32 len; + + psta->num_of_secdev_type = num_of_secdev_type; + + len = (sizeof(psta->secdev_types_list) < (num_of_secdev_type * 8)) ? (sizeof(psta->secdev_types_list)) : (num_of_secdev_type * 8); + + _rtw_memcpy(psta->secdev_types_list, pattr_content, len); + + pattr_content += (num_of_secdev_type * 8); + } + + + /* dev_name_len = attr_contentlen - ETH_ALEN - 2 - 8 - 1 - (num_of_secdev_type*8); */ + psta->dev_name_len = 0; + if (WPS_ATTR_DEVICE_NAME == be16_to_cpu(*(u16 *)pattr_content)) { + dev_name_len = be16_to_cpu(*(u16 *)(pattr_content + 2)); + + psta->dev_name_len = (sizeof(psta->dev_name) < dev_name_len) ? sizeof(psta->dev_name) : dev_name_len; + + _rtw_memcpy(psta->dev_name, pattr_content + 4, psta->dev_name_len); + } + + rtw_mfree(pbuf, attr_contentlen); + + } + + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); + + } + + return status_code; + +} + +u32 process_p2p_devdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + u8 *frame_body; + u8 status, dialogToken; + struct sta_info *psta = NULL; + _adapter *padapter = pwdinfo->padapter; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *p2p_ie; + u32 p2p_ielen = 0; + + frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); + + dialogToken = frame_body[7]; + status = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP; + + p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen); + if (p2p_ie) { + u8 groupid[38] = { 0x00 }; + u8 dev_addr[ETH_ALEN] = { 0x00 }; + u32 attr_contentlen = 0; + + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) { + if (_rtw_memcmp(pwdinfo->device_addr, groupid, ETH_ALEN) && + _rtw_memcmp(pwdinfo->p2p_group_ssid, groupid + ETH_ALEN, pwdinfo->p2p_group_ssid_len)) { + attr_contentlen = 0; + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_ID, dev_addr, &attr_contentlen)) { + _irqL irqL; + _list *phead, *plist; + + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); + phead = &pstapriv->asoc_list; + plist = get_next(phead); + + /* look up sta asoc_queue */ + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); + + plist = get_next(plist); + + if (psta->is_p2p_device && (psta->dev_cap & P2P_DEVCAP_CLIENT_DISCOVERABILITY) && + _rtw_memcmp(psta->dev_addr, dev_addr, ETH_ALEN)) { + + /* _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); */ + /* issue GO Discoverability Request */ + issue_group_disc_req(pwdinfo, psta->hwaddr); + /* _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); */ + + status = P2P_STATUS_SUCCESS; + + break; + } else + status = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + + } + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); + + } else + status = P2P_STATUS_FAIL_INVALID_PARAM; + + } else + status = P2P_STATUS_FAIL_INVALID_PARAM; + + } + + } + + + /* issue Device Discoverability Response */ + issue_p2p_devdisc_resp(pwdinfo, get_addr2_ptr(pframe), status, dialogToken); + + + return (status == P2P_STATUS_SUCCESS) ? _TRUE : _FALSE; + +} + +u32 process_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + return _TRUE; +} + +u8 process_p2p_provdisc_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + u8 *frame_body; + u8 *wpsie; + uint wps_ielen = 0, attr_contentlen = 0; + u16 uconfig_method = 0; + + + frame_body = (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); + + wpsie = rtw_get_wps_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen); + if (wpsie) { + if (rtw_get_wps_attr_content(wpsie, wps_ielen, WPS_ATTR_CONF_METHOD , (u8 *) &uconfig_method, &attr_contentlen)) { + uconfig_method = be16_to_cpu(uconfig_method); + switch (uconfig_method) { + case WPS_CM_DISPLYA: { + _rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3); + break; + } + case WPS_CM_LABEL: { + _rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "lab", 3); + break; + } + case WPS_CM_PUSH_BUTTON: { + _rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3); + break; + } + case WPS_CM_KEYPAD: { + _rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3); + break; + } + } + issue_p2p_provision_resp(pwdinfo, get_addr2_ptr(pframe), frame_body, uconfig_method); + } + } + RTW_INFO("[%s] config method = %s\n", __FUNCTION__, pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req); + return _TRUE; + +} + +u8 process_p2p_provdisc_resp(struct wifidirect_info *pwdinfo, u8 *pframe) +{ + + return _TRUE; +} + +u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8 ch_cnt, u8 *peer_ch_list) +{ + u8 i = 0, j = 0; + u8 temp = 0; + u8 ch_no = 0; + ch_content += 3; + ch_cnt -= 3; + + while (ch_cnt > 0) { + ch_content += 1; + ch_cnt -= 1; + temp = *ch_content; + for (i = 0 ; i < temp ; i++, j++) + peer_ch_list[j] = *(ch_content + 1 + i); + ch_content += (temp + 1); + ch_cnt -= (temp + 1); + ch_no += temp ; + } + + return ch_no; +} + +u8 rtw_p2p_check_peer_oper_ch(struct mlme_ext_priv *pmlmeext, u8 ch) +{ + u8 i = 0; + + for (i = 0; i < pmlmeext->max_chan_nums; i++) { + if (pmlmeext->channel_set[i].ChannelNum == ch) + return _SUCCESS; + } + + return _FAIL; +} + +u8 rtw_p2p_ch_inclusion(struct mlme_ext_priv *pmlmeext, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned) +{ + int i = 0, j = 0, temp = 0; + u8 ch_no = 0; + + for (i = 0; i < peer_ch_num; i++) { + for (j = temp; j < pmlmeext->max_chan_nums; j++) { + if (*(peer_ch_list + i) == pmlmeext->channel_set[j].ChannelNum) { + ch_list_inclusioned[ch_no++] = *(peer_ch_list + i); + temp = j; + break; + } + } + } + + return ch_no; +} + +u8 process_p2p_group_negotation_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + _adapter *padapter = pwdinfo->padapter; + u8 result = P2P_STATUS_SUCCESS; + u32 p2p_ielen = 0, wps_ielen = 0; + u8 *ies; + u32 ies_len; + u8 *p2p_ie; + u8 *wpsie; + u16 wps_devicepassword_id = 0x0000; + uint wps_devicepassword_id_len = 0; +#ifdef CONFIG_WFD +#ifdef CONFIG_TDLS + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; +#endif /* CONFIG_TDLS */ +#endif /* CONFIG_WFD */ + wpsie = rtw_get_wps_ie(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen); + if (wpsie) { + /* Commented by Kurt 20120113 */ + /* If some device wants to do p2p handshake without sending prov_disc_req */ + /* We have to get peer_req_cm from here. */ + if (_rtw_memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) { + rtw_get_wps_attr_content(wpsie, wps_ielen, WPS_ATTR_DEVICE_PWID, (u8 *) &wps_devicepassword_id, &wps_devicepassword_id_len); + wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id); + + if (wps_devicepassword_id == WPS_DPID_USER_SPEC) + _rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3); + else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) + _rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3); + else + _rtw_memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3); + } + } else { + RTW_INFO("[%s] WPS IE not Found!!\n", __FUNCTION__); + result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + return result ; + } + + ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; + ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; + + p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); + + if (!p2p_ie) { + RTW_INFO("[%s] P2P IE not Found!!\n", __FUNCTION__); + result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + } + + while (p2p_ie) { + u8 attr_content = 0x00; + u32 attr_contentlen = 0; + u8 ch_content[100] = { 0x00 }; + uint ch_cnt = 0; + u8 peer_ch_list[100] = { 0x00 }; + u8 peer_ch_num = 0; + u8 ch_list_inclusioned[100] = { 0x00 }; + u8 ch_num_inclusioned = 0; + u16 cap_attr; + u8 listen_ch_attr[5] = { 0x00 }; + + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING); + + /* Check P2P Capability ATTR */ + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8 *)&cap_attr, (uint *)&attr_contentlen)) { + cap_attr = le16_to_cpu(cap_attr); + +#if defined(CONFIG_WFD) && defined(CONFIG_TDLS) + if (!(cap_attr & P2P_GRPCAP_INTRABSS)) + ptdlsinfo->ap_prohibited = _TRUE; +#endif /* defined(CONFIG_WFD) && defined(CONFIG_TDLS) */ + } + + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT , &attr_content, &attr_contentlen)) { + RTW_INFO("[%s] GO Intent = %d, tie = %d\n", __FUNCTION__, attr_content >> 1, attr_content & 0x01); + pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */ + + if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) { + /* Try to match the tie breaker value */ + if (pwdinfo->intent == P2P_MAX_INTENT) { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + result = P2P_STATUS_FAIL_BOTH_GOINTENT_15; + } else { + if (attr_content & 0x01) + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + else + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + } + } else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + else + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + /* Store the group id information. */ + _rtw_memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN); + _rtw_memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); + } + } + + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_LISTEN_CH, (u8 *)listen_ch_attr, (uint *) &attr_contentlen) && attr_contentlen == 5) + pwdinfo->nego_req_info.peer_ch = listen_ch_attr[4]; + + RTW_INFO(FUNC_ADPT_FMT" listen channel :%u\n", FUNC_ADPT_ARG(padapter), pwdinfo->nego_req_info.peer_ch); + + attr_contentlen = 0; + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENDED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) { + if (attr_contentlen != ETH_ALEN) + _rtw_memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); + } + + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, ch_content, &ch_cnt)) { + peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, ch_content, ch_cnt, peer_ch_list); + ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned); + + if (ch_num_inclusioned == 0) { + RTW_INFO("[%s] No common channel in channel list!\n", __FUNCTION__); + result = P2P_STATUS_FAIL_NO_COMMON_CH; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + break; + } + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel, + ch_list_inclusioned, ch_num_inclusioned)) { +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED) + && padapter->registrypriv.full_ch_in_p2p_handshake == 0) { + RTW_INFO("[%s] desired channel NOT Found!\n", __FUNCTION__); + result = P2P_STATUS_FAIL_NO_COMMON_CH; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + break; + } else +#endif /* CONFIG_CONCURRENT_MODE */ + { + u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0; + attr_contentlen = 0; + + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) + peer_operating_ch = operatingch_info[4]; + + if (rtw_p2p_is_channel_list_ok(peer_operating_ch, + ch_list_inclusioned, ch_num_inclusioned)) { + /** + * Change our operating channel as peer's for compatibility. + */ + pwdinfo->operating_channel = peer_operating_ch; + RTW_INFO("[%s] Change op ch to %02x as peer's\n", __FUNCTION__, pwdinfo->operating_channel); + } else { + /* Take first channel of ch_list_inclusioned as operating channel */ + pwdinfo->operating_channel = ch_list_inclusioned[0]; + RTW_INFO("[%s] Change op ch to %02x\n", __FUNCTION__, pwdinfo->operating_channel); + } + } + + } + } + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); + } + + if (pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO) { + result = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INFOR_NOREADY); + return result; + } + +#ifdef CONFIG_WFD + rtw_process_wfd_ies(padapter, pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, __func__); +#endif + + return result ; +} + +u8 process_p2p_group_negotation_resp(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + _adapter *padapter = pwdinfo->padapter; + u8 result = P2P_STATUS_SUCCESS; + u32 p2p_ielen, wps_ielen; + u8 *ies; + u32 ies_len; + u8 *p2p_ie; +#ifdef CONFIG_WFD +#ifdef CONFIG_TDLS + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; +#endif /* CONFIG_TDLS */ +#endif /* CONFIG_WFD */ + + ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; + ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; + + /* Be able to know which one is the P2P GO and which one is P2P client. */ + + if (rtw_get_wps_ie(ies, ies_len, NULL, &wps_ielen)) { + + } else { + RTW_INFO("[%s] WPS IE not Found!!\n", __FUNCTION__); + result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + } + + p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); + if (!p2p_ie) { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM; + } else { + + u8 attr_content = 0x00; + u32 attr_contentlen = 0; + u8 operatingch_info[5] = { 0x00 }; + uint ch_cnt = 0; + u8 ch_content[100] = { 0x00 }; + u8 groupid[38]; + u16 cap_attr; + u8 peer_ch_list[100] = { 0x00 }; + u8 peer_ch_num = 0; + u8 ch_list_inclusioned[100] = { 0x00 }; + u8 ch_num_inclusioned = 0; + + while (p2p_ie) { /* Found the P2P IE. */ + + /* Check P2P Capability ATTR */ + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8 *)&cap_attr, (uint *)&attr_contentlen)) { + cap_attr = le16_to_cpu(cap_attr); +#ifdef CONFIG_TDLS + if (!(cap_attr & P2P_GRPCAP_INTRABSS)) + ptdlsinfo->ap_prohibited = _TRUE; +#endif /* CONFIG_TDLS */ + } + + rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); + if (attr_contentlen == 1) { + RTW_INFO("[%s] Status = %d\n", __FUNCTION__, attr_content); + if (attr_content == P2P_STATUS_SUCCESS) { + /* Do nothing. */ + } else { + if (P2P_STATUS_FAIL_INFO_UNAVAILABLE == attr_content) + rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INFOR_NOREADY); + else + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + result = attr_content; + break; + } + } + + /* Try to get the peer's interface address */ + attr_contentlen = 0; + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENDED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen)) { + if (attr_contentlen != ETH_ALEN) + _rtw_memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); + } + + /* Try to get the peer's intent and tie breaker value. */ + attr_content = 0x00; + attr_contentlen = 0; + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT , &attr_content, &attr_contentlen)) { + RTW_INFO("[%s] GO Intent = %d, tie = %d\n", __FUNCTION__, attr_content >> 1, attr_content & 0x01); + pwdinfo->peer_intent = attr_content; /* include both intent and tie breaker values. */ + + if (pwdinfo->intent == (pwdinfo->peer_intent >> 1)) { + /* Try to match the tie breaker value */ + if (pwdinfo->intent == P2P_MAX_INTENT) { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + result = P2P_STATUS_FAIL_BOTH_GOINTENT_15; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + } else { + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); + if (attr_content & 0x01) + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + else + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + } + } else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1)) { + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + } else { + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + } + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + /* Store the group id information. */ + _rtw_memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN); + _rtw_memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); + + } + } + + /* Try to get the operation channel information */ + + attr_contentlen = 0; + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) { + RTW_INFO("[%s] Peer's operating channel = %d\n", __FUNCTION__, operatingch_info[4]); + pwdinfo->peer_operating_ch = operatingch_info[4]; + } + + /* Try to get the channel list information */ + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, pwdinfo->channel_list_attr, &pwdinfo->channel_list_attr_len)) { + RTW_INFO("[%s] channel list attribute found, len = %d\n", __FUNCTION__, pwdinfo->channel_list_attr_len); + + peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len, peer_ch_list); + ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned); + + if (ch_num_inclusioned == 0) { + RTW_INFO("[%s] No common channel in channel list!\n", __FUNCTION__); + result = P2P_STATUS_FAIL_NO_COMMON_CH; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + break; + } + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel, + ch_list_inclusioned, ch_num_inclusioned)) { +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED) + && padapter->registrypriv.full_ch_in_p2p_handshake == 0) { + RTW_INFO("[%s] desired channel NOT Found!\n", __FUNCTION__); + result = P2P_STATUS_FAIL_NO_COMMON_CH; + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + break; + } else +#endif /* CONFIG_CONCURRENT_MODE */ + { + u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0; + attr_contentlen = 0; + + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) + peer_operating_ch = operatingch_info[4]; + + if (rtw_p2p_is_channel_list_ok(peer_operating_ch, + ch_list_inclusioned, ch_num_inclusioned)) { + /** + * Change our operating channel as peer's for compatibility. + */ + pwdinfo->operating_channel = peer_operating_ch; + RTW_INFO("[%s] Change op ch to %02x as peer's\n", __FUNCTION__, pwdinfo->operating_channel); + } else { + /* Take first channel of ch_list_inclusioned as operating channel */ + pwdinfo->operating_channel = ch_list_inclusioned[0]; + RTW_INFO("[%s] Change op ch to %02x\n", __FUNCTION__, pwdinfo->operating_channel); + } + } + + } + } + + } else + RTW_INFO("[%s] channel list attribute not found!\n", __FUNCTION__); + + /* Try to get the group id information if peer is GO */ + attr_contentlen = 0; + _rtw_memset(groupid, 0x00, 38); + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) { + _rtw_memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN); + _rtw_memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN); + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); + } + + } + +#ifdef CONFIG_WFD + rtw_process_wfd_ies(padapter, pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, __func__); +#endif + + return result ; + +} + +u8 process_p2p_group_negotation_confirm(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + _adapter *padapter = pwdinfo->padapter; + u8 *ies; + u32 ies_len; + u8 *p2p_ie; + u32 p2p_ielen = 0; + u8 result = P2P_STATUS_SUCCESS; + ies = pframe + _PUBLIC_ACTION_IE_OFFSET_; + ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; + + p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); + while (p2p_ie) { /* Found the P2P IE. */ + u8 attr_content = 0x00, operatingch_info[5] = { 0x00 }; + u8 groupid[38] = { 0x00 }; + u32 attr_contentlen = 0; + + pwdinfo->negotiation_dialog_token = 1; + rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen); + if (attr_contentlen == 1) { + RTW_INFO("[%s] Status = %d\n", __FUNCTION__, attr_content); + result = attr_content; + + if (attr_content == P2P_STATUS_SUCCESS) { + u8 bcancelled = 0; + + _cancel_timer(&pwdinfo->restore_p2p_state_timer, &bcancelled); + + /* Commented by Albert 20100911 */ + /* Todo: Need to handle the case which both Intents are the same. */ + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); + if ((pwdinfo->intent) > (pwdinfo->peer_intent >> 1)) + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + else if ((pwdinfo->intent) < (pwdinfo->peer_intent >> 1)) + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + else { + /* Have to compare the Tie Breaker */ + if (pwdinfo->peer_intent & 0x01) + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + else + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + } + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED) + && padapter->registrypriv.full_ch_in_p2p_handshake == 0) { + /* Switch back to the AP channel soon. */ + _set_timer(&pwdinfo->ap_p2p_switch_timer, 100); + } +#endif + } else { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL); + break; + } + } + + /* Try to get the group id information */ + attr_contentlen = 0; + _rtw_memset(groupid, 0x00, 38); + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen)) { + RTW_INFO("[%s] Ssid = %s, ssidlen = %zu\n", __FUNCTION__, &groupid[ETH_ALEN], strlen(&groupid[ETH_ALEN])); + _rtw_memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN); + _rtw_memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN); + } + + attr_contentlen = 0; + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen)) { + RTW_INFO("[%s] Peer's operating channel = %d\n", __FUNCTION__, operatingch_info[4]); + pwdinfo->peer_operating_ch = operatingch_info[4]; + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); + + } + + return result ; +} + +u8 process_p2p_presence_req(struct wifidirect_info *pwdinfo, u8 *pframe, uint len) +{ + u8 *frame_body; + u8 dialogToken = 0; + u8 status = P2P_STATUS_SUCCESS; + + frame_body = (unsigned char *)(pframe + sizeof(struct rtw_ieee80211_hdr_3addr)); + + dialogToken = frame_body[6]; + + /* todo: check NoA attribute */ + + issue_p2p_presence_resp(pwdinfo, get_addr2_ptr(pframe), status, dialogToken); + + return _TRUE; +} + +void find_phase_handler(_adapter *padapter) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + NDIS_802_11_SSID ssid; + _irqL irqL; + u8 _status = 0; + + + _rtw_memset((unsigned char *)&ssid, 0, sizeof(NDIS_802_11_SSID)); + _rtw_memcpy(ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN); + ssid.SsidLength = P2P_WILDCARD_SSID_LEN; + + rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH); + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + _status = rtw_sitesurvey_cmd(padapter, &ssid, 1, NULL, 0); + _exit_critical_bh(&pmlmepriv->lock, &irqL); + + +} + +void p2p_concurrent_handler(_adapter *padapter); + +void restore_p2p_state_handler(_adapter *padapter) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL)) + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED)) { + u8 union_ch = rtw_mi_get_union_chan(padapter); + u8 union_bw = rtw_mi_get_union_bw(padapter); + u8 union_offset = rtw_mi_get_union_offset(padapter); + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP)) { + set_channel_bwmode(padapter, union_ch, union_offset, union_bw); + rtw_mi_buddy_issue_nulldata(padapter, NULL, 0, 3, 500); + } + } +#endif + + rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) { +#ifdef CONFIG_CONCURRENT_MODE + p2p_concurrent_handler(padapter); +#else + /* In the P2P client mode, the driver should not switch back to its listen channel */ + /* because this P2P client should stay at the operating channel of P2P GO. */ + set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); +#endif + } +} + +void pre_tx_invitereq_handler(_adapter *padapter) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 val8 = 1; + + set_channel_bwmode(padapter, pwdinfo->invitereq_info.peer_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + issue_probereq_p2p(padapter, NULL); + _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); + +} + +void pre_tx_provdisc_handler(_adapter *padapter) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 val8 = 1; + + set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + issue_probereq_p2p(padapter, NULL); + _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); + +} + +void pre_tx_negoreq_handler(_adapter *padapter) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 val8 = 1; + + set_channel_bwmode(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + issue_probereq_p2p(padapter , NULL); + /* WIN Phone only accept unicast probe request when nego back */ + issue_probereq_p2p(padapter , pwdinfo->nego_req_info.peerDevAddr); + _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); + +} + +#ifdef CONFIG_CONCURRENT_MODE +void p2p_concurrent_handler(_adapter *padapter) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 val8; + + if (rtw_mi_check_status(padapter, MI_LINKED)) { + u8 union_ch = rtw_mi_get_union_chan(padapter); + u8 union_bw = rtw_mi_get_union_bw(padapter); + u8 union_offset = rtw_mi_get_union_offset(padapter); + + pwdinfo->operating_channel = union_ch; + + if (pwdinfo->driver_interface == DRIVER_CFG80211) { + RTW_INFO("%s, switch ch back to union_ch=%d\n", __func__, union_ch); + set_channel_bwmode(padapter, union_ch, union_offset, union_bw); + + rtw_mi_buddy_issue_nulldata(padapter, NULL, 0, 3, 500); + + } else if (pwdinfo->driver_interface == DRIVER_WEXT) { + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) { + /* Now, the driver stays on the AP's channel. */ + /* If the pwdinfo->ext_listen_period = 0, that means the P2P listen state is not available on listen channel. */ + if (pwdinfo->ext_listen_period > 0) { + RTW_INFO("[%s] P2P_STATE_IDLE, ext_listen_period = %d\n", __FUNCTION__, pwdinfo->ext_listen_period); + + if (union_ch != pwdinfo->listen_channel) { + /* Will switch to listen channel so that need to send the NULL data with PW bit to AP. */ + rtw_mi_buddy_issue_nulldata(padapter, NULL, 1, 3, 500); + set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); + } + + rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); + + if (!rtw_mi_check_mlmeinfo_state(padapter, WIFI_FW_AP_STATE)) { + val8 = 1; + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + } + /* Todo: To check the value of pwdinfo->ext_listen_period is equal to 0 or not. */ + _set_timer(&pwdinfo->ap_p2p_switch_timer, pwdinfo->ext_listen_period); + } + } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN) || + rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL) || + (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) && pwdinfo->nego_req_info.benable == _FALSE) || + rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ)) { + /* Now, the driver is in the listen state of P2P mode. */ + RTW_INFO("[%s] P2P_STATE_IDLE, ext_listen_interval = %d\n", __FUNCTION__, pwdinfo->ext_listen_interval); + + /* Commented by Albert 2012/11/01 */ + /* If the AP's channel is the same as the listen channel, we should still be in the listen state */ + /* Other P2P device is still able to find this device out even this device is in the AP's channel. */ + /* So, configure this device to be able to receive the probe request frame and set it to listen state. */ + if (union_ch != pwdinfo->listen_channel) { + + set_channel_bwmode(padapter, union_ch, union_offset, union_bw); + if (!rtw_mi_check_status(padapter, MI_AP_MODE)) { + val8 = 0; + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + } + rtw_p2p_set_state(pwdinfo, P2P_STATE_IDLE); + rtw_mi_buddy_issue_nulldata(padapter, NULL, 0, 3, 500); + } + + /* Todo: To check the value of pwdinfo->ext_listen_interval is equal to 0 or not. */ + _set_timer(&pwdinfo->ap_p2p_switch_timer, pwdinfo->ext_listen_interval); + } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_OK)) { + /* The driver had finished the P2P handshake successfully. */ + val8 = 0; + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + set_channel_bwmode(padapter, union_ch, union_offset, union_bw); + rtw_mi_buddy_issue_nulldata(padapter, NULL, 0, 3, 500); + } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) { + val8 = 1; + set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + issue_probereq_p2p(padapter, NULL); + _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); + } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) && pwdinfo->nego_req_info.benable == _TRUE) { + val8 = 1; + set_channel_bwmode(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + issue_probereq_p2p(padapter, NULL); + _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); + } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ) && pwdinfo->invitereq_info.benable == _TRUE) { + /* + val8 = 1; + set_channel_bwmode(padapter, , HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + issue_probereq_p2p(padapter, NULL); + _set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT ); + */ + } + } + } else { + /* In p2p+softap. When in P2P_STATE_GONEGO_OK, not back to listen channel.*/ + if (!rtw_p2p_chk_state(pwdinfo , P2P_STATE_GONEGO_OK) || padapter->registrypriv.full_ch_in_p2p_handshake == 0) + set_channel_bwmode(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20); + else + RTW_INFO("%s, buddy not linked, go nego ok, not back to listen channel\n", __func__); + } + +} +#endif + +#ifdef CONFIG_IOCTL_CFG80211 +static int ro_ch_handler(_adapter *adapter, u8 *buf) +{ + /* TODO: move remain on channel logical here */ + return H2C_SUCCESS; +} + +static int cancel_ro_ch_handler(_adapter *padapter, u8 *buf) +{ + int ret = H2C_SUCCESS; + struct p2p_roch_parm *roch_parm = (struct p2p_roch_parm *)buf; + struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter); + struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; + struct wireless_dev *wdev; + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + u8 ch, bw, offset; + + _enter_critical_mutex(&pwdev_priv->roch_mutex, NULL); + + if (rtw_cfg80211_get_is_roch(padapter) != _TRUE) + goto exit; + + if (roch_parm->wdev && roch_parm->cookie) { + if (pcfg80211_wdinfo->ro_ch_wdev != roch_parm->wdev) { + RTW_WARN(FUNC_ADPT_FMT" ongoing wdev:%p, wdev:%p\n" + , FUNC_ADPT_ARG(padapter), pcfg80211_wdinfo->ro_ch_wdev, roch_parm->wdev); + rtw_warn_on(1); + } + + if (pcfg80211_wdinfo->remain_on_ch_cookie != roch_parm->cookie) { + RTW_WARN(FUNC_ADPT_FMT" ongoing cookie:0x%llx, cookie:0x%llx\n" + , FUNC_ADPT_ARG(padapter), pcfg80211_wdinfo->remain_on_ch_cookie, roch_parm->cookie); + rtw_warn_on(1); + } + } + + if (rtw_mi_get_ch_setting_union(padapter, &ch, &bw, &offset) != 0) { + if (0) + RTW_INFO(FUNC_ADPT_FMT" back to linked/linking union - ch:%u, bw:%u, offset:%u\n", + FUNC_ADPT_ARG(padapter), ch, bw, offset); + } else if (adapter_wdev_data(padapter)->p2p_enabled && pwdinfo->listen_channel) { + ch = pwdinfo->listen_channel; + bw = CHANNEL_WIDTH_20; + offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + if (0) + RTW_INFO(FUNC_ADPT_FMT" back to listen ch - ch:%u, bw:%u, offset:%u\n", + FUNC_ADPT_ARG(padapter), ch, bw, offset); + } else { + ch = pcfg80211_wdinfo->restore_channel; + bw = CHANNEL_WIDTH_20; + offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + if (0) + RTW_INFO(FUNC_ADPT_FMT" back to restore ch - ch:%u, bw:%u, offset:%u\n", + FUNC_ADPT_ARG(padapter), ch, bw, offset); + } + + set_channel_bwmode(padapter, ch, offset, bw); + + rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo)); +#ifdef CONFIG_DEBUG_CFG80211 + RTW_INFO("%s, role=%d, p2p_state=%d\n", __func__, rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo)); +#endif + + wdev = pcfg80211_wdinfo->ro_ch_wdev; + + rtw_cfg80211_set_is_roch(padapter, _FALSE); + pcfg80211_wdinfo->ro_ch_wdev = NULL; + pcfg80211_wdinfo->last_ro_ch_time = rtw_get_current_time(); + + rtw_cfg80211_remain_on_channel_expired(wdev + , pcfg80211_wdinfo->remain_on_ch_cookie + , &pcfg80211_wdinfo->remain_on_ch_channel + , pcfg80211_wdinfo->remain_on_ch_type, GFP_KERNEL); + + RTW_INFO("cfg80211_remain_on_channel_expired cookie:0x%llx\n" + , pcfg80211_wdinfo->remain_on_ch_cookie); + +#ifdef CONFIG_BT_COEXIST + rtw_btcoex_ScanNotify(padapter, _FALSE); +#endif + +exit: + _exit_critical_mutex(&pwdev_priv->roch_mutex, NULL); + + return ret; +} + +static void ro_ch_timer_process(void *FunctionContext) +{ + _adapter *adapter = (_adapter *)FunctionContext; + + p2p_cancel_roch_cmd(adapter, 0, NULL, 0); +} + +static void rtw_change_p2pie_op_ch(_adapter *padapter, const u8 *frame_body, u32 len, u8 ch) +{ + u8 *ies, *p2p_ie; + u32 ies_len, p2p_ielen; + +#ifdef CONFIG_MCC_MODE + if (MCC_EN(padapter)) + return; +#endif /* CONFIG_MCC_MODE */ + + ies = (u8 *)(frame_body + _PUBLIC_ACTION_IE_OFFSET_); + ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; + + p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); + + while (p2p_ie) { + u32 attr_contentlen = 0; + u8 *pattr = NULL; + + /* Check P2P_ATTR_OPERATING_CH */ + attr_contentlen = 0; + pattr = NULL; + pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, (uint *)&attr_contentlen); + if (pattr != NULL) + *(pattr + 4) = ch; + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); + } +} + +static void rtw_change_p2pie_ch_list(_adapter *padapter, const u8 *frame_body, u32 len, u8 ch) +{ + u8 *ies, *p2p_ie; + u32 ies_len, p2p_ielen; + +#ifdef CONFIG_MCC_MODE + if (MCC_EN(padapter)) + return; +#endif /* CONFIG_MCC_MODE */ + + ies = (u8 *)(frame_body + _PUBLIC_ACTION_IE_OFFSET_); + ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; + + p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); + + while (p2p_ie) { + u32 attr_contentlen = 0; + u8 *pattr = NULL; + + /* Check P2P_ATTR_CH_LIST */ + pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, NULL, (uint *)&attr_contentlen); + if (pattr != NULL) { + int i; + u32 num_of_ch; + u8 *pattr_temp = pattr + 3 ; + + attr_contentlen -= 3; + + while (attr_contentlen > 0) { + num_of_ch = *(pattr_temp + 1); + + for (i = 0; i < num_of_ch; i++) + *(pattr_temp + 2 + i) = ch; + + pattr_temp += (2 + num_of_ch); + attr_contentlen -= (2 + num_of_ch); + } + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); + } +} + +static bool rtw_chk_p2pie_ch_list_with_buddy(_adapter *padapter, const u8 *frame_body, u32 len) +{ + bool fit = _FALSE; +#ifdef CONFIG_CONCURRENT_MODE + u8 *ies, *p2p_ie; + u32 ies_len, p2p_ielen; + u8 union_ch = rtw_mi_get_union_chan(padapter); + + ies = (u8 *)(frame_body + _PUBLIC_ACTION_IE_OFFSET_); + ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; + + p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); + + while (p2p_ie) { + u32 attr_contentlen = 0; + u8 *pattr = NULL; + + /* Check P2P_ATTR_CH_LIST */ + pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, NULL, (uint *)&attr_contentlen); + if (pattr != NULL) { + int i; + u32 num_of_ch; + u8 *pattr_temp = pattr + 3 ; + + attr_contentlen -= 3; + + while (attr_contentlen > 0) { + num_of_ch = *(pattr_temp + 1); + + for (i = 0; i < num_of_ch; i++) { + if (*(pattr_temp + 2 + i) == union_ch) { + RTW_INFO(FUNC_ADPT_FMT" ch_list fit buddy_ch:%u\n", FUNC_ADPT_ARG(padapter), union_ch); + fit = _TRUE; + break; + } + } + + pattr_temp += (2 + num_of_ch); + attr_contentlen -= (2 + num_of_ch); + } + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); + } +#endif + return fit; +} + +static bool rtw_chk_p2pie_op_ch_with_buddy(_adapter *padapter, const u8 *frame_body, u32 len) +{ + bool fit = _FALSE; +#ifdef CONFIG_CONCURRENT_MODE + u8 *ies, *p2p_ie; + u32 ies_len, p2p_ielen; + u8 union_ch = rtw_mi_get_union_chan(padapter); + + ies = (u8 *)(frame_body + _PUBLIC_ACTION_IE_OFFSET_); + ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; + + p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); + + while (p2p_ie) { + u32 attr_contentlen = 0; + u8 *pattr = NULL; + + /* Check P2P_ATTR_OPERATING_CH */ + attr_contentlen = 0; + pattr = NULL; + pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, (uint *)&attr_contentlen); + if (pattr != NULL) { + if (*(pattr + 4) == union_ch) { + RTW_INFO(FUNC_ADPT_FMT" op_ch fit buddy_ch:%u\n", FUNC_ADPT_ARG(padapter), union_ch); + fit = _TRUE; + break; + } + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); + } +#endif + return fit; +} + +static void rtw_cfg80211_adjust_p2pie_channel(_adapter *padapter, const u8 *frame_body, u32 len) +{ +#ifdef CONFIG_CONCURRENT_MODE + u8 *ies, *p2p_ie; + u32 ies_len, p2p_ielen; + u8 union_ch = rtw_mi_get_union_chan(padapter); + +#ifdef CONFIG_MCC_MODE + if (MCC_EN(padapter)) + return; +#endif /* CONFIG_MCC_MODE */ + + ies = (u8 *)(frame_body + _PUBLIC_ACTION_IE_OFFSET_); + ies_len = len - _PUBLIC_ACTION_IE_OFFSET_; + + p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); + + while (p2p_ie) { + u32 attr_contentlen = 0; + u8 *pattr = NULL; + + /* Check P2P_ATTR_CH_LIST */ + pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, NULL, (uint *)&attr_contentlen); + if (pattr != NULL) { + int i; + u32 num_of_ch; + u8 *pattr_temp = pattr + 3 ; + + attr_contentlen -= 3; + + while (attr_contentlen > 0) { + num_of_ch = *(pattr_temp + 1); + + for (i = 0; i < num_of_ch; i++) { + if (*(pattr_temp + 2 + i) && *(pattr_temp + 2 + i) != union_ch) { + #ifdef RTW_SINGLE_WIPHY + RTW_ERR("replace ch_list:%u with:%u\n", *(pattr_temp + 2 + i), union_ch); + #endif + *(pattr_temp + 2 + i) = union_ch; /*forcing to the same channel*/ + } + } + + pattr_temp += (2 + num_of_ch); + attr_contentlen -= (2 + num_of_ch); + } + } + + /* Check P2P_ATTR_OPERATING_CH */ + attr_contentlen = 0; + pattr = NULL; + pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, (uint *)&attr_contentlen); + if (pattr != NULL) { + if (*(pattr + 4) && *(pattr + 4) != union_ch) { + #ifdef RTW_SINGLE_WIPHY + RTW_ERR("replace op_ch:%u with:%u\n", *(pattr + 4), union_ch); + #endif + *(pattr + 4) = union_ch; /*forcing to the same channel */ + } + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); + + } + +#endif +} + +#ifdef CONFIG_WFD +u32 rtw_xframe_build_wfd_ie(struct xmit_frame *xframe) +{ + _adapter *adapter = xframe->padapter; + struct wifidirect_info *wdinfo = &adapter->wdinfo; + u8 *frame = xframe->buf_addr + TXDESC_OFFSET; + u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr); + u8 *frame_tail = frame + xframe->attrib.pktlen; + u8 category, action, OUI_Subtype, dialogToken = 0; + u32 wfdielen = 0; + + category = frame_body[0]; + if (category == RTW_WLAN_CATEGORY_PUBLIC) { + action = frame_body[1]; + if (action == ACT_PUBLIC_VENDOR + && _rtw_memcmp(frame_body + 2, P2P_OUI, 4) == _TRUE + ) { + OUI_Subtype = frame_body[6]; + dialogToken = frame_body[7]; + + switch (OUI_Subtype) { + case P2P_GO_NEGO_REQ: + wfdielen = build_nego_req_wfd_ie(wdinfo, frame_tail); + break; + case P2P_GO_NEGO_RESP: + wfdielen = build_nego_resp_wfd_ie(wdinfo, frame_tail); + break; + case P2P_GO_NEGO_CONF: + wfdielen = build_nego_confirm_wfd_ie(wdinfo, frame_tail); + break; + case P2P_INVIT_REQ: + wfdielen = build_invitation_req_wfd_ie(wdinfo, frame_tail); + break; + case P2P_INVIT_RESP: + wfdielen = build_invitation_resp_wfd_ie(wdinfo, frame_tail); + break; + case P2P_PROVISION_DISC_REQ: + wfdielen = build_provdisc_req_wfd_ie(wdinfo, frame_tail); + break; + case P2P_PROVISION_DISC_RESP: + wfdielen = build_provdisc_resp_wfd_ie(wdinfo, frame_tail); + break; + case P2P_DEVDISC_REQ: + case P2P_DEVDISC_RESP: + default: + break; + } + + } + } else if (category == RTW_WLAN_CATEGORY_P2P) { + OUI_Subtype = frame_body[5]; + dialogToken = frame_body[6]; + +#ifdef CONFIG_DEBUG_CFG80211 + RTW_INFO("ACTION_CATEGORY_P2P: OUI=0x%x, OUI_Subtype=%d, dialogToken=%d\n" + , cpu_to_be32(*((u32 *)(frame_body + 1))), OUI_Subtype, dialogToken); +#endif + + switch (OUI_Subtype) { + case P2P_NOTICE_OF_ABSENCE: + break; + case P2P_PRESENCE_REQUEST: + break; + case P2P_PRESENCE_RESPONSE: + break; + case P2P_GO_DISC_REQUEST: + break; + default: + break; + } + } else + RTW_INFO("%s, action frame category=%d\n", __func__, category); + + xframe->attrib.pktlen += wfdielen; + + return wfdielen; +} +#endif /* CONFIG_WFD */ + +bool rtw_xframe_del_wfd_ie(struct xmit_frame *xframe) +{ +#define DBG_XFRAME_DEL_WFD_IE 0 + + _adapter *adapter = xframe->padapter; + u8 *frame = xframe->buf_addr + TXDESC_OFFSET; + u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr); + u8 *frame_tail = frame + xframe->attrib.pktlen; + u8 category, action, OUI_Subtype; + u8 *ies = NULL; + uint ies_len_ori = 0; + uint ies_len = 0; + + category = frame_body[0]; + if (category == RTW_WLAN_CATEGORY_PUBLIC) { + action = frame_body[1]; + if (action == ACT_PUBLIC_VENDOR + && _rtw_memcmp(frame_body + 2, P2P_OUI, 4) == _TRUE + ) { + OUI_Subtype = frame_body[6]; + + switch (OUI_Subtype) { + case P2P_GO_NEGO_REQ: + case P2P_GO_NEGO_RESP: + case P2P_GO_NEGO_CONF: + case P2P_INVIT_REQ: + case P2P_INVIT_RESP: + case P2P_PROVISION_DISC_REQ: + case P2P_PROVISION_DISC_RESP: + ies = frame_body + 8; + ies_len_ori = frame_tail - (frame_body + 8); + break; + } + } + } + + if (ies && ies_len_ori) { + ies_len = rtw_del_wfd_ie(ies, ies_len_ori, DBG_XFRAME_DEL_WFD_IE ? __func__ : NULL); + xframe->attrib.pktlen -= (ies_len_ori - ies_len); + } + + return ies_len_ori != ies_len; +} + +/* +* rtw_xframe_chk_wfd_ie - +* +*/ +void rtw_xframe_chk_wfd_ie(struct xmit_frame *xframe) +{ + _adapter *adapter = xframe->padapter; + u8 *frame = xframe->buf_addr + TXDESC_OFFSET; + u8 *frame_body = frame + sizeof(struct rtw_ieee80211_hdr_3addr); + u8 *frame_tail = frame + xframe->attrib.pktlen; + + struct wifidirect_info *wdinfo = &adapter->wdinfo; + struct mlme_priv *mlme = &adapter->mlmepriv; + u8 build = 0; + u8 del = 0; + + if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST)) + del = 1; + +#ifdef CONFIG_IOCTL_CFG80211 + if (_TRUE == wdinfo->wfd_info->wfd_enable) +#endif + del = build = 1; + + if (del) + rtw_xframe_del_wfd_ie(xframe); + +#ifdef CONFIG_WFD + if (build) + rtw_xframe_build_wfd_ie(xframe); +#endif +} + +u8 *dump_p2p_attr_ch_list(u8 *p2p_ie, uint p2p_ielen, u8 *buf, u32 buf_len) +{ + uint attr_contentlen = 0; + u8 *pattr = NULL; + int w_sz = 0; + u8 ch_cnt = 0; + u8 ch_list[40]; + bool continuous = _FALSE; + + pattr = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, NULL, &attr_contentlen); + if (pattr != NULL) { + int i, j; + u32 num_of_ch; + u8 *pattr_temp = pattr + 3 ; + + attr_contentlen -= 3; + + _rtw_memset(ch_list, 0, 40); + + while (attr_contentlen > 0) { + num_of_ch = *(pattr_temp + 1); + + for (i = 0; i < num_of_ch; i++) { + for (j = 0; j < ch_cnt; j++) { + if (ch_list[j] == *(pattr_temp + 2 + i)) + break; + } + if (j >= ch_cnt) + ch_list[ch_cnt++] = *(pattr_temp + 2 + i); + + } + + pattr_temp += (2 + num_of_ch); + attr_contentlen -= (2 + num_of_ch); + } + + for (j = 0; j < ch_cnt; j++) { + if (j == 0) + w_sz += snprintf(buf + w_sz, buf_len - w_sz, "%u", ch_list[j]); + else if (ch_list[j] - ch_list[j - 1] != 1) + w_sz += snprintf(buf + w_sz, buf_len - w_sz, ", %u", ch_list[j]); + else if (j != ch_cnt - 1 && ch_list[j + 1] - ch_list[j] == 1) { + /* empty */ + } else + w_sz += snprintf(buf + w_sz, buf_len - w_sz, "-%u", ch_list[j]); + } + } + return buf; +} + +/* + * return _TRUE if requester is GO, _FALSE if responder is GO + */ +bool rtw_p2p_nego_intent_compare(u8 req, u8 resp) +{ + if (req >> 1 == resp >> 1) + return req & 0x01 ? _TRUE : _FALSE; + else if (req >> 1 > resp >> 1) + return _TRUE; + else + return _FALSE; +} + +int rtw_p2p_check_frames(_adapter *padapter, const u8 *buf, u32 len, u8 tx) +{ + int is_p2p_frame = (-1); + unsigned char *frame_body; + u8 category, action, OUI_Subtype, dialogToken = 0; + u8 *p2p_ie = NULL; + uint p2p_ielen = 0; + struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter); + int status = -1; + u8 ch_list_buf[128] = {'\0'}; + int op_ch = -1; + int listen_ch = -1; + u8 intent = 0; + u8 *iaddr = NULL; + u8 *gbssid = NULL; + + frame_body = (unsigned char *)(buf + sizeof(struct rtw_ieee80211_hdr_3addr)); + category = frame_body[0]; + /* just for check */ + if (category == RTW_WLAN_CATEGORY_PUBLIC) { + action = frame_body[1]; + if (action == ACT_PUBLIC_VENDOR + && _rtw_memcmp(frame_body + 2, P2P_OUI, 4) == _TRUE + ) { + OUI_Subtype = frame_body[6]; + dialogToken = frame_body[7]; + is_p2p_frame = OUI_Subtype; + + #ifdef CONFIG_DEBUG_CFG80211 + RTW_INFO("ACTION_CATEGORY_PUBLIC: ACT_PUBLIC_VENDOR, OUI=0x%x, OUI_Subtype=%d, dialogToken=%d\n", + cpu_to_be32(*((u32 *)(frame_body + 2))), OUI_Subtype, dialogToken); + #endif + + p2p_ie = rtw_get_p2p_ie( + (u8 *)buf + sizeof(struct rtw_ieee80211_hdr_3addr) + _PUBLIC_ACTION_IE_OFFSET_ + , len - sizeof(struct rtw_ieee80211_hdr_3addr) - _PUBLIC_ACTION_IE_OFFSET_ + , NULL, &p2p_ielen); + + switch (OUI_Subtype) { /* OUI Subtype */ + u8 *cont; + uint cont_len; + case P2P_GO_NEGO_REQ: { + struct rtw_wdev_nego_info *nego_info = &pwdev_priv->nego_info; + + if (tx) { + #ifdef CONFIG_DRV_ISSUE_PROV_REQ /* IOT FOR S2 */ + if (pwdev_priv->provdisc_req_issued == _FALSE) + rtw_cfg80211_issue_p2p_provision_request(padapter, buf, len); + #endif /* CONFIG_DRV_ISSUE_PROV_REQ */ + + /* pwdev_priv->provdisc_req_issued = _FALSE; */ + + #if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT) + if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) + rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)); + #endif + } + + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len); + if (cont) + op_ch = *(cont + 4); + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_LISTEN_CH, NULL, &cont_len); + if (cont) + listen_ch = *(cont + 4); + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, NULL, &cont_len); + if (cont) + intent = *cont; + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENDED_IF_ADDR, NULL, &cont_len); + if (cont && cont_len == 6) + iaddr = cont; + + if (nego_info->token != dialogToken) + rtw_wdev_nego_info_init(nego_info); + + _rtw_memcpy(nego_info->peer_mac, tx ? GetAddr1Ptr(buf) : get_addr2_ptr(buf), ETH_ALEN); + if (iaddr) + _rtw_memcpy(tx ? nego_info->iface_addr : nego_info->peer_iface_addr, iaddr, ETH_ALEN); + nego_info->active = tx ? 1 : 0; + nego_info->token = dialogToken; + nego_info->req_op_ch = op_ch; + nego_info->req_listen_ch = listen_ch; + nego_info->req_intent = intent; + nego_info->state = 0; + + dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128); + RTW_INFO("RTW_%s:P2P_GO_NEGO_REQ, dialogToken=%d, intent:%u%s, listen_ch:%d, op_ch:%d, ch_list:%s" + , (tx == _TRUE) ? "Tx" : "Rx" , dialogToken , (intent >> 1) , intent & 0x1 ? "+" : "-" , listen_ch , op_ch , ch_list_buf); + if (iaddr) + _RTW_INFO(", iaddr:"MAC_FMT, MAC_ARG(iaddr)); + _RTW_INFO("\n"); + + if (!tx) { + #if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT) + if (rtw_mi_check_status(padapter, MI_LINKED) + && rtw_chk_p2pie_ch_list_with_buddy(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE + && padapter->registrypriv.full_ch_in_p2p_handshake == 0) { + RTW_INFO(FUNC_ADPT_FMT" ch_list has no intersect with buddy\n", FUNC_ADPT_ARG(padapter)); + rtw_change_p2pie_ch_list(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr), 0); + } + #endif + } + + break; + } + case P2P_GO_NEGO_RESP: { + struct rtw_wdev_nego_info *nego_info = &pwdev_priv->nego_info; + + if (tx) { + #if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT) + if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) + rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)); + #endif + } + + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len); + if (cont) + op_ch = *(cont + 4); + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, NULL, &cont_len); + if (cont) + intent = *cont; + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len); + if (cont) + status = *cont; + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENDED_IF_ADDR, NULL, &cont_len); + if (cont && cont_len == 6) + iaddr = cont; + + if (nego_info->token == dialogToken && nego_info->state == 0 + && _rtw_memcmp(nego_info->peer_mac, tx ? GetAddr1Ptr(buf) : get_addr2_ptr(buf), ETH_ALEN) == _TRUE + ) { + if (iaddr) + _rtw_memcpy(tx ? nego_info->iface_addr : nego_info->peer_iface_addr, iaddr, ETH_ALEN); + nego_info->status = (status == -1) ? 0xff : status; + nego_info->rsp_op_ch = op_ch; + nego_info->rsp_intent = intent; + nego_info->state = 1; + if (status != 0) + nego_info->token = 0; /* init */ + } + + dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128); + RTW_INFO("RTW_%s:P2P_GO_NEGO_RESP, dialogToken=%d, intent:%u%s, status:%d, op_ch:%d, ch_list:%s" + , (tx == _TRUE) ? "Tx" : "Rx", dialogToken, (intent >> 1), intent & 0x1 ? "+" : "-", status, op_ch, ch_list_buf); + if (iaddr) + _RTW_INFO(", iaddr:"MAC_FMT, MAC_ARG(iaddr)); + _RTW_INFO("\n"); + + if (!tx) { + pwdev_priv->provdisc_req_issued = _FALSE; + #if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT) + if (rtw_mi_check_status(padapter, MI_LINKED) + && rtw_chk_p2pie_ch_list_with_buddy(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE + && padapter->registrypriv.full_ch_in_p2p_handshake == 0) { + RTW_INFO(FUNC_ADPT_FMT" ch_list has no intersect with buddy\n", FUNC_ADPT_ARG(padapter)); + rtw_change_p2pie_ch_list(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr), 0); + } + #endif + } + + break; + } + case P2P_GO_NEGO_CONF: { + struct rtw_wdev_nego_info *nego_info = &pwdev_priv->nego_info; + bool is_go = _FALSE; + + if (tx) { + #if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT) + if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) + rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)); + #endif + } + + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len); + if (cont) + op_ch = *(cont + 4); + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len); + if (cont) + status = *cont; + + if (nego_info->token == dialogToken && nego_info->state == 1 + && _rtw_memcmp(nego_info->peer_mac, tx ? GetAddr1Ptr(buf) : get_addr2_ptr(buf), ETH_ALEN) == _TRUE + ) { + nego_info->status = (status == -1) ? 0xff : status; + nego_info->conf_op_ch = (op_ch == -1) ? 0 : op_ch; + nego_info->state = 2; + + if (status == 0) { + if (rtw_p2p_nego_intent_compare(nego_info->req_intent, nego_info->rsp_intent) ^ !tx) + is_go = _TRUE; + } + + nego_info->token = 0; /* init */ + } + + dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128); + RTW_INFO("RTW_%s:P2P_GO_NEGO_CONF, dialogToken=%d, status:%d, op_ch:%d, ch_list:%s\n" + , (tx == _TRUE) ? "Tx" : "Rx", dialogToken, status, op_ch, ch_list_buf); + + if (!tx) { + } + + break; + } + case P2P_INVIT_REQ: { + struct rtw_wdev_invit_info *invit_info = &pwdev_priv->invit_info; + int flags = -1; + + if (tx) { + #if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT) + if (rtw_mi_check_status(padapter, MI_LINKED) + && padapter->registrypriv.full_ch_in_p2p_handshake == 0) + rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)); + #endif + } + + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_INVITATION_FLAGS, NULL, &cont_len); + if (cont) + flags = *cont; + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len); + if (cont) + op_ch = *(cont + 4); + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_BSSID, NULL, &cont_len); + if (cont && cont_len == 6) + gbssid = cont; + + if (invit_info->token != dialogToken) + rtw_wdev_invit_info_init(invit_info); + + _rtw_memcpy(invit_info->peer_mac, tx ? GetAddr1Ptr(buf) : get_addr2_ptr(buf), ETH_ALEN); + if (gbssid) + _rtw_memcpy(invit_info->group_bssid, gbssid, ETH_ALEN); + invit_info->active = tx ? 1 : 0; + invit_info->token = dialogToken; + invit_info->flags = (flags == -1) ? 0x0 : flags; + invit_info->req_op_ch = op_ch; + invit_info->state = 0; + + dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128); + RTW_INFO("RTW_%s:P2P_INVIT_REQ, dialogToken=%d, flags:0x%02x, op_ch:%d, ch_list:%s" + , (tx == _TRUE) ? "Tx" : "Rx", dialogToken, flags, op_ch, ch_list_buf); + if (gbssid) + _RTW_INFO(", gbssid:"MAC_FMT, MAC_ARG(gbssid)); + _RTW_INFO("\n"); + + if (!tx) { + #if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT) + if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) { + if (op_ch != -1 && rtw_chk_p2pie_op_ch_with_buddy(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE) { + RTW_INFO(FUNC_ADPT_FMT" op_ch:%u has no intersect with buddy\n", FUNC_ADPT_ARG(padapter), op_ch); + rtw_change_p2pie_ch_list(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr), 0); + } else if (rtw_chk_p2pie_ch_list_with_buddy(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)) == _FALSE) { + RTW_INFO(FUNC_ADPT_FMT" ch_list has no intersect with buddy\n", FUNC_ADPT_ARG(padapter)); + rtw_change_p2pie_ch_list(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr), 0); + } + } + #endif + } + + break; + } + case P2P_INVIT_RESP: { + struct rtw_wdev_invit_info *invit_info = &pwdev_priv->invit_info; + + if (tx) { + #if defined(CONFIG_CONCURRENT_MODE) && defined(CONFIG_CFG80211_ONECHANNEL_UNDER_CONCURRENT) + if (rtw_mi_check_status(padapter, MI_LINKED) && padapter->registrypriv.full_ch_in_p2p_handshake == 0) + rtw_cfg80211_adjust_p2pie_channel(padapter, frame_body, len - sizeof(struct rtw_ieee80211_hdr_3addr)); + #endif + } + + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len); + if (cont) { + #ifdef CONFIG_P2P_INVITE_IOT + if (tx && *cont == 7) { + RTW_INFO("TX_P2P_INVITE_RESP, status is no common channel, change to unknown group\n"); + *cont = 8; /* unknow group status */ + } + #endif /* CONFIG_P2P_INVITE_IOT */ + status = *cont; + } + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len); + if (cont) + op_ch = *(cont + 4); + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_BSSID, NULL, &cont_len); + if (cont && cont_len == 6) + gbssid = cont; + + if (invit_info->token == dialogToken && invit_info->state == 0 + && _rtw_memcmp(invit_info->peer_mac, tx ? GetAddr1Ptr(buf) : get_addr2_ptr(buf), ETH_ALEN) == _TRUE + ) { + invit_info->status = (status == -1) ? 0xff : status; + invit_info->rsp_op_ch = op_ch; + invit_info->state = 1; + invit_info->token = 0; /* init */ + } + + dump_p2p_attr_ch_list(p2p_ie, p2p_ielen, ch_list_buf, 128); + RTW_INFO("RTW_%s:P2P_INVIT_RESP, dialogToken=%d, status:%d, op_ch:%d, ch_list:%s" + , (tx == _TRUE) ? "Tx" : "Rx", dialogToken, status, op_ch, ch_list_buf); + if (gbssid) + _RTW_INFO(", gbssid:"MAC_FMT, MAC_ARG(gbssid)); + _RTW_INFO("\n"); + + if (!tx) { + } + + break; + } + case P2P_DEVDISC_REQ: + RTW_INFO("RTW_%s:P2P_DEVDISC_REQ, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken); + break; + case P2P_DEVDISC_RESP: + cont = rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len); + RTW_INFO("RTW_%s:P2P_DEVDISC_RESP, dialogToken=%d, status:%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken, cont ? *cont : -1); + break; + case P2P_PROVISION_DISC_REQ: { + size_t frame_body_len = len - sizeof(struct rtw_ieee80211_hdr_3addr); + u8 *p2p_ie; + uint p2p_ielen = 0; + uint contentlen = 0; + + RTW_INFO("RTW_%s:P2P_PROVISION_DISC_REQ, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken); + + /* if(tx) */ + { + pwdev_priv->provdisc_req_issued = _FALSE; + + p2p_ie = rtw_get_p2p_ie(frame_body + _PUBLIC_ACTION_IE_OFFSET_, frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen); + if (p2p_ie) { + + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, NULL, &contentlen)) { + pwdev_priv->provdisc_req_issued = _FALSE;/* case: p2p_client join p2p GO */ + } else { + #ifdef CONFIG_DEBUG_CFG80211 + RTW_INFO("provdisc_req_issued is _TRUE\n"); + #endif /*CONFIG_DEBUG_CFG80211*/ + pwdev_priv->provdisc_req_issued = _TRUE;/* case: p2p_devices connection before Nego req. */ + } + + } + } + } + break; + case P2P_PROVISION_DISC_RESP: + RTW_INFO("RTW_%s:P2P_PROVISION_DISC_RESP, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", dialogToken); + break; + default: + RTW_INFO("RTW_%s:OUI_Subtype=%d, dialogToken=%d\n", (tx == _TRUE) ? "Tx" : "Rx", OUI_Subtype, dialogToken); + break; + } + + } + + } else if (category == RTW_WLAN_CATEGORY_P2P) { + OUI_Subtype = frame_body[5]; + dialogToken = frame_body[6]; + + #ifdef CONFIG_DEBUG_CFG80211 + RTW_INFO("ACTION_CATEGORY_P2P: OUI=0x%x, OUI_Subtype=%d, dialogToken=%d\n", + cpu_to_be32(*((u32 *)(frame_body + 1))), OUI_Subtype, dialogToken); + #endif + + is_p2p_frame = OUI_Subtype; + + switch (OUI_Subtype) { + case P2P_NOTICE_OF_ABSENCE: + RTW_INFO("RTW_%s:P2P_NOTICE_OF_ABSENCE, dialogToken=%d\n", (tx == _TRUE) ? "TX" : "RX", dialogToken); + break; + case P2P_PRESENCE_REQUEST: + RTW_INFO("RTW_%s:P2P_PRESENCE_REQUEST, dialogToken=%d\n", (tx == _TRUE) ? "TX" : "RX", dialogToken); + break; + case P2P_PRESENCE_RESPONSE: + RTW_INFO("RTW_%s:P2P_PRESENCE_RESPONSE, dialogToken=%d\n", (tx == _TRUE) ? "TX" : "RX", dialogToken); + break; + case P2P_GO_DISC_REQUEST: + RTW_INFO("RTW_%s:P2P_GO_DISC_REQUEST, dialogToken=%d\n", (tx == _TRUE) ? "TX" : "RX", dialogToken); + break; + default: + RTW_INFO("RTW_%s:OUI_Subtype=%d, dialogToken=%d\n", (tx == _TRUE) ? "TX" : "RX", OUI_Subtype, dialogToken); + break; + } + + } else + RTW_INFO("RTW_%s:action frame category=%d\n", (tx == _TRUE) ? "TX" : "RX", category); + + return is_p2p_frame; +} + +void rtw_init_cfg80211_wifidirect_info(_adapter *padapter) +{ + struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; + + _rtw_memset(pcfg80211_wdinfo, 0x00, sizeof(struct cfg80211_wifidirect_info)); + + _init_timer(&pcfg80211_wdinfo->remain_on_ch_timer, padapter->pnetdev, ro_ch_timer_process, padapter); +} +#endif /* CONFIG_IOCTL_CFG80211 */ + +s32 p2p_protocol_wk_hdl(_adapter *padapter, int intCmdType, u8 *buf) +{ + int ret = H2C_SUCCESS; + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + + switch (intCmdType) { + case P2P_FIND_PHASE_WK: + find_phase_handler(padapter); + break; + + case P2P_RESTORE_STATE_WK: + restore_p2p_state_handler(padapter); + break; + + case P2P_PRE_TX_PROVDISC_PROCESS_WK: +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED)) + p2p_concurrent_handler(padapter); + else + pre_tx_provdisc_handler(padapter); +#else + pre_tx_provdisc_handler(padapter); +#endif + break; + + case P2P_PRE_TX_INVITEREQ_PROCESS_WK: +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED)) + p2p_concurrent_handler(padapter); + else + pre_tx_invitereq_handler(padapter); +#else + pre_tx_invitereq_handler(padapter); +#endif + break; + + case P2P_PRE_TX_NEGOREQ_PROCESS_WK: +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED)) + p2p_concurrent_handler(padapter); + else + pre_tx_negoreq_handler(padapter); +#else + pre_tx_negoreq_handler(padapter); +#endif + break; + +#ifdef CONFIG_CONCURRENT_MODE + case P2P_AP_P2P_CH_SWITCH_PROCESS_WK: + p2p_concurrent_handler(padapter); + break; +#endif + +#ifdef CONFIG_IOCTL_CFG80211 + case P2P_RO_CH_WK: + ret = ro_ch_handler(padapter, buf); + break; + case P2P_CANCEL_RO_CH_WK: + ret = cancel_ro_ch_handler(padapter, buf); + break; +#endif + + default: + rtw_warn_on(1); + break; + } + + return ret; +} + +int process_p2p_cross_connect_ie(PADAPTER padapter, u8 *IEs, u32 IELength) +{ + int ret = _TRUE; + u8 *ies; + u32 ies_len; + u8 *p2p_ie; + u32 p2p_ielen = 0; + u8 p2p_attr[MAX_P2P_IE_LEN] = { 0x00 };/* NoA length should be n*(13) + 2 */ + u32 attr_contentlen = 0; + + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + + + if (IELength <= _BEACON_IE_OFFSET_) + return ret; + + ies = IEs + _BEACON_IE_OFFSET_; + ies_len = IELength - _BEACON_IE_OFFSET_; + + p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); + + while (p2p_ie) { + /* Get P2P Manageability IE. */ + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_MANAGEABILITY, p2p_attr, &attr_contentlen)) { + if ((p2p_attr[0] & (BIT(0) | BIT(1))) == 0x01) + ret = _FALSE; + break; + } + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); + } + + return ret; +} + +#ifdef CONFIG_P2P_PS +void process_p2p_ps_ie(PADAPTER padapter, u8 *IEs, u32 IELength) +{ + u8 *ies; + u32 ies_len; + u8 *p2p_ie; + u32 p2p_ielen = 0; + u8 noa_attr[MAX_P2P_IE_LEN] = { 0x00 };/* NoA length should be n*(13) + 2 */ + u32 attr_contentlen = 0; + + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + u8 find_p2p = _FALSE, find_p2p_ps = _FALSE; + u8 noa_offset, noa_num, noa_index; + + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; +#ifdef CONFIG_CONCURRENT_MODE +#ifndef CONFIG_FW_MULTI_PORT_SUPPORT + if (padapter->hw_port != HW_PORT0) + return; +#endif +#endif + if (IELength <= _BEACON_IE_OFFSET_) + return; + + ies = IEs + _BEACON_IE_OFFSET_; + ies_len = IELength - _BEACON_IE_OFFSET_; + + p2p_ie = rtw_get_p2p_ie(ies, ies_len, NULL, &p2p_ielen); + + while (p2p_ie) { + find_p2p = _TRUE; + /* Get Notice of Absence IE. */ + if (rtw_get_p2p_attr_content(p2p_ie, p2p_ielen, P2P_ATTR_NOA, noa_attr, &attr_contentlen)) { + find_p2p_ps = _TRUE; + noa_index = noa_attr[0]; + + if ((pwdinfo->p2p_ps_mode == P2P_PS_NONE) || + (noa_index != pwdinfo->noa_index)) { /* if index change, driver should reconfigure related setting. */ + pwdinfo->noa_index = noa_index; + pwdinfo->opp_ps = noa_attr[1] >> 7; + pwdinfo->ctwindow = noa_attr[1] & 0x7F; + + noa_offset = 2; + noa_num = 0; + /* NoA length should be n*(13) + 2 */ + if (attr_contentlen > 2) { + while (noa_offset < attr_contentlen) { + /* _rtw_memcpy(&wifidirect_info->noa_count[noa_num], &noa_attr[noa_offset], 1); */ + pwdinfo->noa_count[noa_num] = noa_attr[noa_offset]; + noa_offset += 1; + + _rtw_memcpy(&pwdinfo->noa_duration[noa_num], &noa_attr[noa_offset], 4); + noa_offset += 4; + + _rtw_memcpy(&pwdinfo->noa_interval[noa_num], &noa_attr[noa_offset], 4); + noa_offset += 4; + + _rtw_memcpy(&pwdinfo->noa_start_time[noa_num], &noa_attr[noa_offset], 4); + noa_offset += 4; + + noa_num++; + } + } + pwdinfo->noa_num = noa_num; + + if (pwdinfo->opp_ps == 1) { + pwdinfo->p2p_ps_mode = P2P_PS_CTWINDOW; + /* driver should wait LPS for entering CTWindow */ + if (adapter_to_pwrctl(padapter)->bFwCurrentInPSMode == _TRUE) + p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1); + } else if (pwdinfo->noa_num > 0) { + pwdinfo->p2p_ps_mode = P2P_PS_NOA; + p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 1); + } else if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) + p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1); + } + + break; /* find target, just break. */ + } + + /* Get the next P2P IE */ + p2p_ie = rtw_get_p2p_ie(p2p_ie + p2p_ielen, ies_len - (p2p_ie - ies + p2p_ielen), NULL, &p2p_ielen); + + } + + if (find_p2p == _TRUE) { + if ((pwdinfo->p2p_ps_mode > P2P_PS_NONE) && (find_p2p_ps == _FALSE)) + p2p_ps_wk_cmd(padapter, P2P_PS_DISABLE, 1); + } + +} + +void p2p_ps_wk_hdl(_adapter *padapter, u8 p2p_ps_state) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + + + /* Pre action for p2p state */ + switch (p2p_ps_state) { + case P2P_PS_DISABLE: + pwdinfo->p2p_ps_state = p2p_ps_state; + + rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); + + pwdinfo->noa_index = 0; + pwdinfo->ctwindow = 0; + pwdinfo->opp_ps = 0; + pwdinfo->noa_num = 0; + pwdinfo->p2p_ps_mode = P2P_PS_NONE; + if (pwrpriv->bFwCurrentInPSMode == _TRUE) { + if (pwrpriv->smart_ps == 0) { + pwrpriv->smart_ps = 2; + rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&(pwrpriv->pwr_mode))); + } + } + break; + case P2P_PS_ENABLE: + if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { +#ifdef CONFIG_MCC_MODE + if (MCC_EN(padapter)) { + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) { + RTW_INFO("P2P PS enble under MCC\n"); + rtw_warn_on(1); + } + + } +#endif /* CONFIG_MCC_MODE */ + pwdinfo->p2p_ps_state = p2p_ps_state; + + if (pwdinfo->ctwindow > 0) { + if (pwrpriv->smart_ps != 0) { + pwrpriv->smart_ps = 0; + RTW_INFO("%s(): Enter CTW, change SmartPS\n", __FUNCTION__); + rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&(pwrpriv->pwr_mode))); + } + } + rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); + } + break; + case P2P_PS_SCAN: + case P2P_PS_SCAN_DONE: + case P2P_PS_ALLSTASLEEP: + if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) { + pwdinfo->p2p_ps_state = p2p_ps_state; + rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state)); + } + break; + default: + break; + } + +} + +u8 p2p_ps_wk_cmd(_adapter *padapter, u8 p2p_ps_state, u8 enqueue) +{ + struct cmd_obj *ph2c; + struct drvextra_cmd_parm *pdrvextra_cmd_parm; + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; + u8 res = _SUCCESS; + + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) +#ifdef CONFIG_CONCURRENT_MODE +#ifndef CONFIG_FW_MULTI_PORT_SUPPORT + || (padapter->hw_port != HW_PORT0) +#endif +#endif + ) + return res; + + if (enqueue) { + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) { + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + res = _FAIL; + goto exit; + } + + pdrvextra_cmd_parm->ec_id = P2P_PS_WK_CID; + pdrvextra_cmd_parm->type = p2p_ps_state; + pdrvextra_cmd_parm->size = 0; + pdrvextra_cmd_parm->pbuf = NULL; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); + + res = rtw_enqueue_cmd(pcmdpriv, ph2c); + } else + p2p_ps_wk_hdl(padapter, p2p_ps_state); + +exit: + + + return res; + +} +#endif /* CONFIG_P2P_PS */ + +static void reset_ch_sitesurvey_timer_process(void *FunctionContext) +{ + _adapter *adapter = (_adapter *)FunctionContext; + struct wifidirect_info *pwdinfo = &adapter->wdinfo; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; + + RTW_INFO("[%s] In\n", __FUNCTION__); + /* Reset the operation channel information */ + pwdinfo->rx_invitereq_info.operation_ch[0] = 0; +#ifdef CONFIG_P2P_OP_CHK_SOCIAL_CH + pwdinfo->rx_invitereq_info.operation_ch[1] = 0; + pwdinfo->rx_invitereq_info.operation_ch[2] = 0; + pwdinfo->rx_invitereq_info.operation_ch[3] = 0; +#endif /* CONFIG_P2P_OP_CHK_SOCIAL_CH */ + pwdinfo->rx_invitereq_info.scan_op_ch_only = 0; +} + +static void reset_ch_sitesurvey_timer_process2(void *FunctionContext) +{ + _adapter *adapter = (_adapter *)FunctionContext; + struct wifidirect_info *pwdinfo = &adapter->wdinfo; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; + + RTW_INFO("[%s] In\n", __FUNCTION__); + /* Reset the operation channel information */ + pwdinfo->p2p_info.operation_ch[0] = 0; +#ifdef CONFIG_P2P_OP_CHK_SOCIAL_CH + pwdinfo->p2p_info.operation_ch[1] = 0; + pwdinfo->p2p_info.operation_ch[2] = 0; + pwdinfo->p2p_info.operation_ch[3] = 0; +#endif /* CONFIG_P2P_OP_CHK_SOCIAL_CH */ + pwdinfo->p2p_info.scan_op_ch_only = 0; +} + +static void restore_p2p_state_timer_process(void *FunctionContext) +{ + _adapter *adapter = (_adapter *)FunctionContext; + struct wifidirect_info *pwdinfo = &adapter->wdinfo; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; + + p2p_protocol_wk_cmd(adapter, P2P_RESTORE_STATE_WK); +} + +static void pre_tx_scan_timer_process(void *FunctionContext) +{ + _adapter *adapter = (_adapter *) FunctionContext; + struct wifidirect_info *pwdinfo = &adapter->wdinfo; + _irqL irqL; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + u8 _status = 0; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; + + _enter_critical_bh(&pmlmepriv->lock, &irqL); + + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) { + if (_TRUE == pwdinfo->tx_prov_disc_info.benable) { /* the provision discovery request frame is trigger to send or not */ + p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_PROVDISC_PROCESS_WK); + /* issue_probereq_p2p(adapter, NULL); */ + /* _set_timer( &pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT ); */ + } + } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) { + if (_TRUE == pwdinfo->nego_req_info.benable) + p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_NEGOREQ_PROCESS_WK); + } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) { + if (_TRUE == pwdinfo->invitereq_info.benable) + p2p_protocol_wk_cmd(adapter, P2P_PRE_TX_INVITEREQ_PROCESS_WK); + } else + RTW_INFO("[%s] p2p_state is %d, ignore!!\n", __FUNCTION__, rtw_p2p_state(pwdinfo)); + + _exit_critical_bh(&pmlmepriv->lock, &irqL); +} + +static void find_phase_timer_process(void *FunctionContext) +{ + _adapter *adapter = (_adapter *)FunctionContext; + struct wifidirect_info *pwdinfo = &adapter->wdinfo; + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; + + adapter->wdinfo.find_phase_state_exchange_cnt++; + + p2p_protocol_wk_cmd(adapter, P2P_FIND_PHASE_WK); +} + +#ifdef CONFIG_CONCURRENT_MODE +void ap_p2p_switch_timer_process(void *FunctionContext) +{ + _adapter *adapter = (_adapter *)FunctionContext; + struct wifidirect_info *pwdinfo = &adapter->wdinfo; +#ifdef CONFIG_IOCTL_CFG80211 + struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(adapter); +#endif + + if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; + +#ifdef CONFIG_IOCTL_CFG80211 + ATOMIC_SET(&pwdev_priv->switch_ch_to, 1); +#endif + + p2p_protocol_wk_cmd(adapter, P2P_AP_P2P_CH_SWITCH_PROCESS_WK); +} +#endif + +void reset_global_wifidirect_info(_adapter *padapter) +{ + struct wifidirect_info *pwdinfo; + + pwdinfo = &padapter->wdinfo; + pwdinfo->persistent_supported = 0; + pwdinfo->session_available = _TRUE; + rtw_tdls_wfd_enable(padapter, 0); + pwdinfo->wfd_tdls_weaksec = _TRUE; +} + +#ifdef CONFIG_WFD +int rtw_init_wifi_display_info(_adapter *padapter) +{ + int res = _SUCCESS; + struct wifi_display_info *pwfd_info = &padapter->wfd_info; + + /* Used in P2P and TDLS */ + pwfd_info->init_rtsp_ctrlport = 554; +#ifdef CONFIG_IOCTL_CFG80211 + pwfd_info->rtsp_ctrlport = 0; +#else + pwfd_info->rtsp_ctrlport = pwfd_info->init_rtsp_ctrlport; /* set non-zero value for legacy wfd */ +#endif + pwfd_info->tdls_rtsp_ctrlport = 0; + pwfd_info->peer_rtsp_ctrlport = 0; /* Reset to 0 */ + pwfd_info->wfd_enable = _FALSE; + pwfd_info->wfd_device_type = WFD_DEVINFO_PSINK; + pwfd_info->scan_result_type = SCAN_RESULT_P2P_ONLY; + + /* Used in P2P */ + pwfd_info->peer_session_avail = _TRUE; + pwfd_info->wfd_pc = _FALSE; + + /* Used in TDLS */ + _rtw_memset(pwfd_info->ip_address, 0x00, 4); + _rtw_memset(pwfd_info->peer_ip_address, 0x00, 4); + return res; + +} + +inline void rtw_wfd_enable(_adapter *adapter, bool on) +{ + struct wifi_display_info *wfdinfo = &adapter->wfd_info; + + if (on) { + wfdinfo->rtsp_ctrlport = wfdinfo->init_rtsp_ctrlport; + wfdinfo->wfd_enable = _TRUE; + + } else { + wfdinfo->wfd_enable = _FALSE; + wfdinfo->rtsp_ctrlport = 0; + } +} + +inline void rtw_wfd_set_ctrl_port(_adapter *adapter, u16 port) +{ + struct wifi_display_info *wfdinfo = &adapter->wfd_info; + + wfdinfo->init_rtsp_ctrlport = port; + if (wfdinfo->wfd_enable == _TRUE) + wfdinfo->rtsp_ctrlport = port; + if (adapter->wdinfo.wfd_tdls_enable == 1) + wfdinfo->tdls_rtsp_ctrlport = port; +} + +inline void rtw_tdls_wfd_enable(_adapter *adapter, bool on) +{ + struct wifi_display_info *wfdinfo = &adapter->wfd_info; + + if (on) { + wfdinfo->tdls_rtsp_ctrlport = wfdinfo->init_rtsp_ctrlport; + adapter->wdinfo.wfd_tdls_enable = 1; + + } else { + adapter->wdinfo.wfd_tdls_enable = 0; + wfdinfo->tdls_rtsp_ctrlport = 0; + } +} + +u32 rtw_append_beacon_wfd_ie(_adapter *adapter, u8 *pbuf) +{ + struct wifidirect_info *wdinfo = &adapter->wdinfo; + struct mlme_priv *mlme = &adapter->mlmepriv; + u8 build_ie_by_self = 0; + u32 len = 0; + + if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST)) + goto exit; + +#ifdef CONFIG_IOCTL_CFG80211 + if (_TRUE == wdinfo->wfd_info->wfd_enable) +#endif + build_ie_by_self = 1; + + if (build_ie_by_self) + len = build_beacon_wfd_ie(wdinfo, pbuf); +#ifdef CONFIG_IOCTL_CFG80211 + else if (mlme->wfd_beacon_ie && mlme->wfd_beacon_ie_len > 0) { + len = mlme->wfd_beacon_ie_len; + _rtw_memcpy(pbuf, mlme->wfd_beacon_ie, len); + } +#endif + +exit: + return len; +} + +u32 rtw_append_probe_req_wfd_ie(_adapter *adapter, u8 *pbuf) +{ + struct wifidirect_info *wdinfo = &adapter->wdinfo; + struct mlme_priv *mlme = &adapter->mlmepriv; + u8 build_ie_by_self = 0; + u32 len = 0; + + if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST)) + goto exit; + +#ifdef CONFIG_IOCTL_CFG80211 + if (_TRUE == wdinfo->wfd_info->wfd_enable) +#endif + build_ie_by_self = 1; + + if (build_ie_by_self) + len = build_probe_req_wfd_ie(wdinfo, pbuf); +#ifdef CONFIG_IOCTL_CFG80211 + else if (mlme->wfd_probe_req_ie && mlme->wfd_probe_req_ie_len > 0) { + len = mlme->wfd_probe_req_ie_len; + _rtw_memcpy(pbuf, mlme->wfd_probe_req_ie, len); + } +#endif + +exit: + return len; +} + +u32 rtw_append_probe_resp_wfd_ie(_adapter *adapter, u8 *pbuf) +{ + struct wifidirect_info *wdinfo = &adapter->wdinfo; + struct mlme_priv *mlme = &adapter->mlmepriv; + u8 build_ie_by_self = 0; + u32 len = 0; + + if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST)) + goto exit; + +#ifdef CONFIG_IOCTL_CFG80211 + if (_TRUE == wdinfo->wfd_info->wfd_enable) +#endif + build_ie_by_self = 1; + + if (build_ie_by_self) + len = build_probe_resp_wfd_ie(wdinfo, pbuf, 0); +#ifdef CONFIG_IOCTL_CFG80211 + else if (mlme->wfd_probe_resp_ie && mlme->wfd_probe_resp_ie_len > 0) { + len = mlme->wfd_probe_resp_ie_len; + _rtw_memcpy(pbuf, mlme->wfd_probe_resp_ie, len); + } +#endif + +exit: + return len; +} + +u32 rtw_append_assoc_req_wfd_ie(_adapter *adapter, u8 *pbuf) +{ + struct wifidirect_info *wdinfo = &adapter->wdinfo; + struct mlme_priv *mlme = &adapter->mlmepriv; + u8 build_ie_by_self = 0; + u32 len = 0; + + if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST)) + goto exit; + +#ifdef CONFIG_IOCTL_CFG80211 + if (_TRUE == wdinfo->wfd_info->wfd_enable) +#endif + build_ie_by_self = 1; + + if (build_ie_by_self) + len = build_assoc_req_wfd_ie(wdinfo, pbuf); +#ifdef CONFIG_IOCTL_CFG80211 + else if (mlme->wfd_assoc_req_ie && mlme->wfd_assoc_req_ie_len > 0) { + len = mlme->wfd_assoc_req_ie_len; + _rtw_memcpy(pbuf, mlme->wfd_assoc_req_ie, len); + } +#endif + +exit: + return len; +} + +u32 rtw_append_assoc_resp_wfd_ie(_adapter *adapter, u8 *pbuf) +{ + struct wifidirect_info *wdinfo = &adapter->wdinfo; + struct mlme_priv *mlme = &adapter->mlmepriv; + u8 build_ie_by_self = 0; + u32 len = 0; + + if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST)) + goto exit; + +#ifdef CONFIG_IOCTL_CFG80211 + if (_TRUE == wdinfo->wfd_info->wfd_enable) +#endif + build_ie_by_self = 1; + + if (build_ie_by_self) + len = build_assoc_resp_wfd_ie(wdinfo, pbuf); +#ifdef CONFIG_IOCTL_CFG80211 + else if (mlme->wfd_assoc_resp_ie && mlme->wfd_assoc_resp_ie_len > 0) { + len = mlme->wfd_assoc_resp_ie_len; + _rtw_memcpy(pbuf, mlme->wfd_assoc_resp_ie, len); + } +#endif + +exit: + return len; +} + +#endif /* CONFIG_WFD */ + +void rtw_init_wifidirect_timers(_adapter *padapter) +{ + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + + _init_timer(&pwdinfo->find_phase_timer, padapter->pnetdev, find_phase_timer_process, padapter); + _init_timer(&pwdinfo->restore_p2p_state_timer, padapter->pnetdev, restore_p2p_state_timer_process, padapter); + _init_timer(&pwdinfo->pre_tx_scan_timer, padapter->pnetdev, pre_tx_scan_timer_process, padapter); + _init_timer(&pwdinfo->reset_ch_sitesurvey, padapter->pnetdev, reset_ch_sitesurvey_timer_process, padapter); + _init_timer(&pwdinfo->reset_ch_sitesurvey2, padapter->pnetdev, reset_ch_sitesurvey_timer_process2, padapter); +#ifdef CONFIG_CONCURRENT_MODE + _init_timer(&pwdinfo->ap_p2p_switch_timer, padapter->pnetdev, ap_p2p_switch_timer_process, padapter); +#endif +} + +void rtw_init_wifidirect_addrs(_adapter *padapter, u8 *dev_addr, u8 *iface_addr) +{ +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + + /*init device&interface address */ + if (dev_addr) + _rtw_memcpy(pwdinfo->device_addr, dev_addr, ETH_ALEN); + if (iface_addr) + _rtw_memcpy(pwdinfo->interface_addr, iface_addr, ETH_ALEN); +#endif +} + +void init_wifidirect_info(_adapter *padapter, enum P2P_ROLE role) +{ + struct wifidirect_info *pwdinfo; +#ifdef CONFIG_WFD + struct wifi_display_info *pwfd_info = &padapter->wfd_info; +#endif + u8 union_ch = 0; + pwdinfo = &padapter->wdinfo; + + pwdinfo->padapter = padapter; + + /* 1, 6, 11 are the social channel defined in the WiFi Direct specification. */ + pwdinfo->social_chan[0] = 1; + pwdinfo->social_chan[1] = 6; + pwdinfo->social_chan[2] = 11; + pwdinfo->social_chan[3] = 0; /* channel 0 for scanning ending in site survey function. */ + + if (role != P2P_ROLE_DISABLE + && pwdinfo->driver_interface != DRIVER_CFG80211 + ) { + #ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED)) + union_ch = rtw_mi_get_union_chan(padapter); + + if (union_ch != 0 && + (union_ch == 1 || union_ch == 6 || union_ch == 11) + ) { + /* Use the AP's channel as the listen channel */ + /* This will avoid the channel switch between AP's channel and listen channel */ + pwdinfo->listen_channel = union_ch; + } else + #endif /* CONFIG_CONCURRENT_MODE */ + { + /* Use the channel 11 as the listen channel */ + pwdinfo->listen_channel = 11; + } + } + + if (role == P2P_ROLE_DEVICE) { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE); +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED)) + rtw_p2p_set_state(pwdinfo, P2P_STATE_IDLE); + else +#endif + rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN); + + pwdinfo->intent = 1; + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_LISTEN); + } else if (role == P2P_ROLE_CLIENT) { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT); + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + pwdinfo->intent = 1; + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); + } else if (role == P2P_ROLE_GO) { + rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO); + rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK); + pwdinfo->intent = 15; + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK); + } + + /* Use the OFDM rate in the P2P probe response frame. ( 6(B), 9(B), 12, 18, 24, 36, 48, 54 ) */ + pwdinfo->support_rate[0] = 0x8c; /* 6(B) */ + pwdinfo->support_rate[1] = 0x92; /* 9(B) */ + pwdinfo->support_rate[2] = 0x18; /* 12 */ + pwdinfo->support_rate[3] = 0x24; /* 18 */ + pwdinfo->support_rate[4] = 0x30; /* 24 */ + pwdinfo->support_rate[5] = 0x48; /* 36 */ + pwdinfo->support_rate[6] = 0x60; /* 48 */ + pwdinfo->support_rate[7] = 0x6c; /* 54 */ + + _rtw_memcpy((void *) pwdinfo->p2p_wildcard_ssid, "DIRECT-", 7); + + _rtw_memset(pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN); + pwdinfo->device_name_len = 0; + + _rtw_memset(&pwdinfo->invitereq_info, 0x00, sizeof(struct tx_invite_req_info)); + pwdinfo->invitereq_info.token = 3; /* Token used for P2P invitation request frame. */ + + _rtw_memset(&pwdinfo->inviteresp_info, 0x00, sizeof(struct tx_invite_resp_info)); + pwdinfo->inviteresp_info.token = 0; + + pwdinfo->profileindex = 0; + _rtw_memset(&pwdinfo->profileinfo[0], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM); + + rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE); + + pwdinfo->listen_dwell = (u8)((rtw_get_current_time() % 3) + 1); + /* RTW_INFO( "[%s] listen_dwell time is %d00ms\n", __FUNCTION__, pwdinfo->listen_dwell ); */ + + _rtw_memset(&pwdinfo->tx_prov_disc_info, 0x00, sizeof(struct tx_provdisc_req_info)); + pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_NONE; + + _rtw_memset(&pwdinfo->nego_req_info, 0x00, sizeof(struct tx_nego_req_info)); + + pwdinfo->device_password_id_for_nego = WPS_DPID_PBC; + pwdinfo->negotiation_dialog_token = 1; + + _rtw_memset(pwdinfo->nego_ssid, 0x00, WLAN_SSID_MAXLEN); + pwdinfo->nego_ssidlen = 0; + + pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO; +#ifdef CONFIG_WFD + pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC; + pwdinfo->wfd_info = pwfd_info; +#else + pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC | WPS_CONFIG_METHOD_KEYPAD; +#endif /* CONFIG_WFD */ + pwdinfo->channel_list_attr_len = 0; + _rtw_memset(pwdinfo->channel_list_attr, 0x00, 100); + + _rtw_memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, 0x00, 4); + _rtw_memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, '0', 3); + _rtw_memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info)); +#ifdef CONFIG_CONCURRENT_MODE +#ifdef CONFIG_IOCTL_CFG80211 + pwdinfo->ext_listen_interval = 1000; /* The interval to be available with legacy AP during p2p0-find/scan */ + pwdinfo->ext_listen_period = 3000; /* The time period to be available for P2P during nego */ +#else /* !CONFIG_IOCTL_CFG80211 */ + /* pwdinfo->ext_listen_interval = 3000; */ + /* pwdinfo->ext_listen_period = 400; */ + pwdinfo->ext_listen_interval = 1000; + pwdinfo->ext_listen_period = 1000; +#endif /* !CONFIG_IOCTL_CFG80211 */ +#endif + + /* Commented by Kurt 20130319 + * For WiDi purpose: Use CFG80211 interface but controled WFD/RDS frame by driver itself. */ +#ifdef CONFIG_IOCTL_CFG80211 + pwdinfo->driver_interface = DRIVER_CFG80211; +#else + pwdinfo->driver_interface = DRIVER_WEXT; +#endif /* CONFIG_IOCTL_CFG80211 */ + + pwdinfo->wfd_tdls_enable = 0; + _rtw_memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN); + _rtw_memset(pwdinfo->p2p_peer_device_addr, 0x00, ETH_ALEN); + + pwdinfo->rx_invitereq_info.operation_ch[0] = 0; + pwdinfo->rx_invitereq_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */ +#ifdef CONFIG_P2P_OP_CHK_SOCIAL_CH + pwdinfo->rx_invitereq_info.operation_ch[2] = 0; + pwdinfo->rx_invitereq_info.operation_ch[3] = 0; + pwdinfo->rx_invitereq_info.operation_ch[4] = 0; +#endif /* CONFIG_P2P_OP_CHK_SOCIAL_CH */ + pwdinfo->rx_invitereq_info.scan_op_ch_only = 0; + pwdinfo->p2p_info.operation_ch[0] = 0; + pwdinfo->p2p_info.operation_ch[1] = 0; /* Used to indicate the scan end in site survey function */ +#ifdef CONFIG_P2P_OP_CHK_SOCIAL_CH + pwdinfo->p2p_info.operation_ch[2] = 0; + pwdinfo->p2p_info.operation_ch[3] = 0; + pwdinfo->p2p_info.operation_ch[4] = 0; +#endif /* CONFIG_P2P_OP_CHK_SOCIAL_CH */ + pwdinfo->p2p_info.scan_op_ch_only = 0; +} + +#ifdef CONFIG_DBG_P2P + +/** + * rtw_p2p_role_txt - Get the p2p role name as a text string + * @role: P2P role + * Returns: The state name as a printable text string + */ +const char *rtw_p2p_role_txt(enum P2P_ROLE role) +{ + switch (role) { + case P2P_ROLE_DISABLE: + return "P2P_ROLE_DISABLE"; + case P2P_ROLE_DEVICE: + return "P2P_ROLE_DEVICE"; + case P2P_ROLE_CLIENT: + return "P2P_ROLE_CLIENT"; + case P2P_ROLE_GO: + return "P2P_ROLE_GO"; + default: + return "UNKNOWN"; + } +} + +/** + * rtw_p2p_state_txt - Get the p2p state name as a text string + * @state: P2P state + * Returns: The state name as a printable text string + */ +const char *rtw_p2p_state_txt(enum P2P_STATE state) +{ + switch (state) { + case P2P_STATE_NONE: + return "P2P_STATE_NONE"; + case P2P_STATE_IDLE: + return "P2P_STATE_IDLE"; + case P2P_STATE_LISTEN: + return "P2P_STATE_LISTEN"; + case P2P_STATE_SCAN: + return "P2P_STATE_SCAN"; + case P2P_STATE_FIND_PHASE_LISTEN: + return "P2P_STATE_FIND_PHASE_LISTEN"; + case P2P_STATE_FIND_PHASE_SEARCH: + return "P2P_STATE_FIND_PHASE_SEARCH"; + case P2P_STATE_TX_PROVISION_DIS_REQ: + return "P2P_STATE_TX_PROVISION_DIS_REQ"; + case P2P_STATE_RX_PROVISION_DIS_RSP: + return "P2P_STATE_RX_PROVISION_DIS_RSP"; + case P2P_STATE_RX_PROVISION_DIS_REQ: + return "P2P_STATE_RX_PROVISION_DIS_REQ"; + case P2P_STATE_GONEGO_ING: + return "P2P_STATE_GONEGO_ING"; + case P2P_STATE_GONEGO_OK: + return "P2P_STATE_GONEGO_OK"; + case P2P_STATE_GONEGO_FAIL: + return "P2P_STATE_GONEGO_FAIL"; + case P2P_STATE_RECV_INVITE_REQ_MATCH: + return "P2P_STATE_RECV_INVITE_REQ_MATCH"; + case P2P_STATE_PROVISIONING_ING: + return "P2P_STATE_PROVISIONING_ING"; + case P2P_STATE_PROVISIONING_DONE: + return "P2P_STATE_PROVISIONING_DONE"; + case P2P_STATE_TX_INVITE_REQ: + return "P2P_STATE_TX_INVITE_REQ"; + case P2P_STATE_RX_INVITE_RESP_OK: + return "P2P_STATE_RX_INVITE_RESP_OK"; + case P2P_STATE_RECV_INVITE_REQ_DISMATCH: + return "P2P_STATE_RECV_INVITE_REQ_DISMATCH"; + case P2P_STATE_RECV_INVITE_REQ_GO: + return "P2P_STATE_RECV_INVITE_REQ_GO"; + case P2P_STATE_RECV_INVITE_REQ_JOIN: + return "P2P_STATE_RECV_INVITE_REQ_JOIN"; + case P2P_STATE_RX_INVITE_RESP_FAIL: + return "P2P_STATE_RX_INVITE_RESP_FAIL"; + case P2P_STATE_RX_INFOR_NOREADY: + return "P2P_STATE_RX_INFOR_NOREADY"; + case P2P_STATE_TX_INFOR_NOREADY: + return "P2P_STATE_TX_INFOR_NOREADY"; + default: + return "UNKNOWN"; + } +} + +void dbg_rtw_p2p_set_state(struct wifidirect_info *wdinfo, enum P2P_STATE state, const char *caller, int line) +{ + if (!_rtw_p2p_chk_state(wdinfo, state)) { + enum P2P_STATE old_state = _rtw_p2p_state(wdinfo); + _rtw_p2p_set_state(wdinfo, state); + RTW_INFO("[CONFIG_DBG_P2P]%s:%d set_state from %s to %s\n", caller, line + , rtw_p2p_state_txt(old_state), rtw_p2p_state_txt(_rtw_p2p_state(wdinfo)) + ); + } else { + RTW_INFO("[CONFIG_DBG_P2P]%s:%d set_state to same state %s\n", caller, line + , rtw_p2p_state_txt(_rtw_p2p_state(wdinfo)) + ); + } +} +void dbg_rtw_p2p_set_pre_state(struct wifidirect_info *wdinfo, enum P2P_STATE state, const char *caller, int line) +{ + if (_rtw_p2p_pre_state(wdinfo) != state) { + enum P2P_STATE old_state = _rtw_p2p_pre_state(wdinfo); + _rtw_p2p_set_pre_state(wdinfo, state); + RTW_INFO("[CONFIG_DBG_P2P]%s:%d set_pre_state from %s to %s\n", caller, line + , rtw_p2p_state_txt(old_state), rtw_p2p_state_txt(_rtw_p2p_pre_state(wdinfo)) + ); + } else { + RTW_INFO("[CONFIG_DBG_P2P]%s:%d set_pre_state to same state %s\n", caller, line + , rtw_p2p_state_txt(_rtw_p2p_pre_state(wdinfo)) + ); + } +} +#if 0 +void dbg_rtw_p2p_restore_state(struct wifidirect_info *wdinfo, const char *caller, int line) +{ + if (wdinfo->pre_p2p_state != -1) { + RTW_INFO("[CONFIG_DBG_P2P]%s:%d restore from %s to %s\n", caller, line + , p2p_state_str[wdinfo->p2p_state], p2p_state_str[wdinfo->pre_p2p_state] + ); + _rtw_p2p_restore_state(wdinfo); + } else { + RTW_INFO("[CONFIG_DBG_P2P]%s:%d restore no pre state, cur state %s\n", caller, line + , p2p_state_str[wdinfo->p2p_state] + ); + } +} +#endif +void dbg_rtw_p2p_set_role(struct wifidirect_info *wdinfo, enum P2P_ROLE role, const char *caller, int line) +{ + if (wdinfo->role != role) { + enum P2P_ROLE old_role = wdinfo->role; + _rtw_p2p_set_role(wdinfo, role); + RTW_INFO("[CONFIG_DBG_P2P]%s:%d set_role from %s to %s\n", caller, line + , rtw_p2p_role_txt(old_role), rtw_p2p_role_txt(wdinfo->role) + ); + } else { + RTW_INFO("[CONFIG_DBG_P2P]%s:%d set_role to same role %s\n", caller, line + , rtw_p2p_role_txt(wdinfo->role) + ); + } +} +#endif /* CONFIG_DBG_P2P */ + + +int rtw_p2p_enable(_adapter *padapter, enum P2P_ROLE role) +{ + int ret = _SUCCESS; + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + + if (role == P2P_ROLE_DEVICE || role == P2P_ROLE_CLIENT || role == P2P_ROLE_GO) { + u8 channel, ch_offset; + u16 bwmode; + +#if defined(CONFIG_CONCURRENT_MODE) && (!defined(RTW_P2P_GROUP_INTERFACE) || !RTW_P2P_GROUP_INTERFACE) + /* Commented by Albert 2011/12/30 */ + /* The driver just supports 1 P2P group operation. */ + /* So, this function will do nothing if the buddy adapter had enabled the P2P function. */ + /*if(!rtw_p2p_chk_state(pbuddy_wdinfo, P2P_STATE_NONE)) + return ret;*/ + /*The buddy adapter had enabled the P2P function.*/ + if (rtw_mi_buddy_stay_in_p2p_mode(padapter)) + return ret; +#endif /* CONFIG_CONCURRENT_MODE */ + + /* leave IPS/Autosuspend */ + if (_FAIL == rtw_pwr_wakeup(padapter)) { + ret = _FAIL; + goto exit; + } + + /* Added by Albert 2011/03/22 */ + /* In the P2P mode, the driver should not support the b mode. */ + /* So, the Tx packet shouldn't use the CCK rate */ + #ifdef CONFIG_IOCTL_CFG80211 + if (rtw_cfg80211_iface_has_p2p_group_cap(padapter)) + #endif + update_tx_basic_rate(padapter, WIRELESS_11AGN); + + /* Enable P2P function */ + init_wifidirect_info(padapter, role); + + #ifdef CONFIG_IOCTL_CFG80211 + if (padapter->wdinfo.driver_interface == DRIVER_CFG80211) + adapter_wdev_data(padapter)->p2p_enabled = _TRUE; + #endif + + rtw_hal_set_odm_var(padapter, HAL_ODM_P2P_STATE, NULL, _TRUE); +#ifdef CONFIG_WFD + if (hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + rtw_hal_set_odm_var(padapter, HAL_ODM_WIFI_DISPLAY_STATE, NULL, _TRUE); +#endif + + } else if (role == P2P_ROLE_DISABLE) { +#ifdef CONFIG_INTEL_WIDI + if (padapter->mlmepriv.p2p_reject_disable == _TRUE) + return ret; +#endif /* CONFIG_INTEL_WIDI */ + + #ifdef CONFIG_IOCTL_CFG80211 + if (padapter->wdinfo.driver_interface == DRIVER_CFG80211) + adapter_wdev_data(padapter)->p2p_enabled = _FALSE; + #endif + + pwdinfo->listen_channel = 0; + + /* Disable P2P function */ + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { + _cancel_timer_ex(&pwdinfo->find_phase_timer); + _cancel_timer_ex(&pwdinfo->restore_p2p_state_timer); + _cancel_timer_ex(&pwdinfo->pre_tx_scan_timer); + _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey); + _cancel_timer_ex(&pwdinfo->reset_ch_sitesurvey2); + reset_ch_sitesurvey_timer_process(padapter); + reset_ch_sitesurvey_timer_process2(padapter); +#ifdef CONFIG_CONCURRENT_MODE + _cancel_timer_ex(&pwdinfo->ap_p2p_switch_timer); +#endif + rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE); + rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_NONE); + rtw_p2p_set_role(pwdinfo, P2P_ROLE_DISABLE); + _rtw_memset(&pwdinfo->rx_prov_disc_info, 0x00, sizeof(struct rx_provdisc_req_info)); + + /* Remove profiles in wifidirect_info structure. */ + _rtw_memset(&pwdinfo->profileinfo[0], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM); + pwdinfo->profileindex = 0; + } + + rtw_hal_set_odm_var(padapter, HAL_ODM_P2P_STATE, NULL, _FALSE); +#ifdef CONFIG_WFD + if (hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + rtw_hal_set_odm_var(padapter, HAL_ODM_WIFI_DISPLAY_STATE, NULL, _FALSE); +#endif + + if (_FAIL == rtw_pwr_wakeup(padapter)) { + ret = _FAIL; + goto exit; + } + + /* Restore to initial setting. */ + update_tx_basic_rate(padapter, padapter->registrypriv.wireless_mode); + +#ifdef CONFIG_INTEL_WIDI + rtw_reset_widi_info(padapter); +#endif /* CONFIG_INTEL_WIDI */ + + /* For WiDi purpose. */ +#ifdef CONFIG_IOCTL_CFG80211 + pwdinfo->driver_interface = DRIVER_CFG80211; +#else + pwdinfo->driver_interface = DRIVER_WEXT; +#endif /* CONFIG_IOCTL_CFG80211 */ + + } + +exit: + return ret; +} + +#endif /* CONFIG_P2P */ diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_pwrctrl.c b/linux-bsp/drivers/rtl8188eus/core/rtw_pwrctrl.c new file mode 100644 index 0000000..e637c3c --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_pwrctrl.c @@ -0,0 +1,2528 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_PWRCTRL_C_ + +#include <drv_types.h> +#include <hal_data.h> +#include <hal_com_h2c.h> + +int rtw_fw_ps_state(PADAPTER padapter) +{ + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; + int ret = _FAIL, dont_care = 0; + u16 fw_ps_state = 0; + u32 start_time; + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + struct registry_priv *registry_par = &padapter->registrypriv; + + if (registry_par->check_fw_ps != 1) + return _SUCCESS; + + _enter_pwrlock(&pwrpriv->check_32k_lock); + + if (RTW_CANNOT_RUN(padapter)) { + RTW_INFO("%s: bSurpriseRemoved=%s , hw_init_completed=%d, bDriverStopped=%s\n", __func__ + , rtw_is_surprise_removed(padapter) ? "True" : "False" + , rtw_get_hw_init_completed(padapter) + , rtw_is_drv_stopped(padapter) ? "True" : "False"); + goto exit_fw_ps_state; + } + rtw_hal_set_hwreg(padapter, HW_VAR_SET_REQ_FW_PS, (u8 *)&dont_care); + { + /* 4. if 0x88[7]=1, driver set cmd to leave LPS/IPS. */ + /* Else, hw will keep in active mode. */ + /* debug info: */ + /* 0x88[7] = 32kpermission, */ + /* 0x88[6:0] = current_ps_state */ + /* 0x89[7:0] = last_rpwm */ + + rtw_hal_get_hwreg(padapter, HW_VAR_FW_PS_STATE, (u8 *)&fw_ps_state); + + if ((fw_ps_state & 0x80) == 0) + ret = _SUCCESS; + else { + pdbgpriv->dbg_poll_fail_cnt++; + RTW_INFO("%s: fw_ps_state=%04x\n", __FUNCTION__, fw_ps_state); + } + } + + +exit_fw_ps_state: + _exit_pwrlock(&pwrpriv->check_32k_lock); + return ret; +} + +#ifdef CONFIG_IPS +void _ips_enter(_adapter *padapter) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + + pwrpriv->bips_processing = _TRUE; + + /* syn ips_mode with request */ + pwrpriv->ips_mode = pwrpriv->ips_mode_req; + + pwrpriv->ips_enter_cnts++; + RTW_INFO("==>ips_enter cnts:%d\n", pwrpriv->ips_enter_cnts); + + if (rf_off == pwrpriv->change_rfpwrstate) { + pwrpriv->bpower_saving = _TRUE; + RTW_PRINT("nolinked power save enter\n"); + + if (pwrpriv->ips_mode == IPS_LEVEL_2) + pwrpriv->bkeepfwalive = _TRUE; + + rtw_ips_pwr_down(padapter); + pwrpriv->rf_pwrstate = rf_off; + } + pwrpriv->bips_processing = _FALSE; + +} + +void ips_enter(_adapter *padapter) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + + +#ifdef CONFIG_BT_COEXIST + rtw_btcoex_IpsNotify(padapter, pwrpriv->ips_mode_req); +#endif /* CONFIG_BT_COEXIST */ + + _enter_pwrlock(&pwrpriv->lock); + _ips_enter(padapter); + _exit_pwrlock(&pwrpriv->lock); +} + +int _ips_leave(_adapter *padapter) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + int result = _SUCCESS; + + if ((pwrpriv->rf_pwrstate == rf_off) && (!pwrpriv->bips_processing)) { + pwrpriv->bips_processing = _TRUE; + pwrpriv->change_rfpwrstate = rf_on; + pwrpriv->ips_leave_cnts++; + RTW_INFO("==>ips_leave cnts:%d\n", pwrpriv->ips_leave_cnts); + + result = rtw_ips_pwr_up(padapter); + if (result == _SUCCESS) + pwrpriv->rf_pwrstate = rf_on; + RTW_PRINT("nolinked power save leave\n"); + + RTW_INFO("==> ips_leave.....LED(0x%08x)...\n", rtw_read32(padapter, 0x4c)); + pwrpriv->bips_processing = _FALSE; + + pwrpriv->bkeepfwalive = _FALSE; + pwrpriv->bpower_saving = _FALSE; + } + + return result; +} + +int ips_leave(_adapter *padapter) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; + int ret; + + if (!is_primary_adapter(padapter)) + return _SUCCESS; + + _enter_pwrlock(&pwrpriv->lock); + ret = _ips_leave(padapter); +#ifdef DBG_CHECK_FW_PS_STATE + if (rtw_fw_ps_state(padapter) == _FAIL) { + RTW_INFO("ips leave doesn't leave 32k\n"); + pdbgpriv->dbg_leave_ips_fail_cnt++; + } +#endif /* DBG_CHECK_FW_PS_STATE */ + _exit_pwrlock(&pwrpriv->lock); + + if (_SUCCESS == ret) + odm_dm_reset(&GET_HAL_DATA(padapter)->odmpriv); + +#ifdef CONFIG_BT_COEXIST + if (_SUCCESS == ret) + rtw_btcoex_IpsNotify(padapter, IPS_NONE); +#endif /* CONFIG_BT_COEXIST */ + + return ret; +} +#endif /* CONFIG_IPS */ + +#ifdef CONFIG_AUTOSUSPEND + extern void autosuspend_enter(_adapter *padapter); + extern int autoresume_enter(_adapter *padapter); +#endif + +#ifdef SUPPORT_HW_RFOFF_DETECTED + int rtw_hw_suspend(_adapter *padapter); + int rtw_hw_resume(_adapter *padapter); +#endif + +bool rtw_pwr_unassociated_idle(_adapter *adapter) +{ + u8 i; + _adapter *iface; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct xmit_priv *pxmit_priv = &adapter->xmitpriv; + struct mlme_priv *pmlmepriv; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo; +#ifdef CONFIG_IOCTL_CFG80211 + struct cfg80211_wifidirect_info *pcfg80211_wdinfo; +#endif +#endif + + bool ret = _FALSE; + + if (adapter_to_pwrctl(adapter)->bpower_saving == _TRUE) { + /* RTW_INFO("%s: already in LPS or IPS mode\n", __func__); */ + goto exit; + } + + if (adapter_to_pwrctl(adapter)->ips_deny_time >= rtw_get_current_time()) { + /* RTW_INFO("%s ips_deny_time\n", __func__); */ + goto exit; + } + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if ((iface) && rtw_is_adapter_up(iface)) { + pmlmepriv = &(iface->mlmepriv); +#ifdef CONFIG_P2P + pwdinfo = &(iface->wdinfo); +#ifdef CONFIG_IOCTL_CFG80211 + pcfg80211_wdinfo = &iface->cfg80211_wdinfo; +#endif +#endif + if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE | WIFI_SITE_MONITOR) + || check_fwstate(pmlmepriv, WIFI_UNDER_LINKING | WIFI_UNDER_WPS) + || check_fwstate(pmlmepriv, WIFI_AP_STATE) + || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE) +#if defined(CONFIG_P2P) && defined(CONFIG_IOCTL_CFG80211) + || rtw_cfg80211_get_is_roch(iface) == _TRUE +#elif defined(CONFIG_P2P) + || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE) + || rtw_p2p_chk_state(pwdinfo, P2P_STATE_LISTEN) +#endif +#if defined(CONFIG_P2P) && defined(CONFIG_IOCTL_CFG80211) + || rtw_get_passing_time_ms(pcfg80211_wdinfo->last_ro_ch_time) < 3000 +#endif + ) + goto exit; + + } + } + +#if (MP_DRIVER == 1) + if (adapter->registrypriv.mp_mode == 1) + goto exit; +#endif + +#ifdef CONFIG_INTEL_PROXIM + if (adapter->proximity.proxim_on == _TRUE) + return; +#endif + + if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF || + pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) { + RTW_PRINT("There are some pkts to transmit\n"); + RTW_PRINT("free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n", + pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt); + goto exit; + } + + ret = _TRUE; + +exit: + return ret; +} + + +/* + * ATTENTION: + * rtw_ps_processor() doesn't handle LPS. + */ +void rtw_ps_processor(_adapter *padapter) +{ +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#endif /* CONFIG_P2P */ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; +#ifdef SUPPORT_HW_RFOFF_DETECTED + rt_rf_power_state rfpwrstate; +#endif /* SUPPORT_HW_RFOFF_DETECTED */ + u32 ps_deny = 0; + + _enter_pwrlock(&adapter_to_pwrctl(padapter)->lock); + ps_deny = rtw_ps_deny_get(padapter); + _exit_pwrlock(&adapter_to_pwrctl(padapter)->lock); + if (ps_deny != 0) { + RTW_INFO(FUNC_ADPT_FMT ": ps_deny=0x%08X, skip power save!\n", + FUNC_ADPT_ARG(padapter), ps_deny); + goto exit; + } + + if (pwrpriv->bInSuspend == _TRUE) { /* system suspend or autosuspend */ + pdbgpriv->dbg_ps_insuspend_cnt++; + RTW_INFO("%s, pwrpriv->bInSuspend == _TRUE ignore this process\n", __FUNCTION__); + return; + } + + pwrpriv->ps_processing = _TRUE; + +#ifdef SUPPORT_HW_RFOFF_DETECTED + if (pwrpriv->bips_processing == _TRUE) + goto exit; + + /* RTW_INFO("==> fw report state(0x%x)\n",rtw_read8(padapter,0x1ca)); */ + if (pwrpriv->bHWPwrPindetect) { +#ifdef CONFIG_AUTOSUSPEND + if (padapter->registrypriv.usbss_enable) { + if (pwrpriv->rf_pwrstate == rf_on) { + if (padapter->net_closed == _TRUE) + pwrpriv->ps_flag = _TRUE; + + rfpwrstate = RfOnOffDetect(padapter); + RTW_INFO("@@@@- #1 %s==> rfstate:%s\n", __FUNCTION__, (rfpwrstate == rf_on) ? "rf_on" : "rf_off"); + if (rfpwrstate != pwrpriv->rf_pwrstate) { + if (rfpwrstate == rf_off) { + pwrpriv->change_rfpwrstate = rf_off; + + pwrpriv->bkeepfwalive = _TRUE; + pwrpriv->brfoffbyhw = _TRUE; + + autosuspend_enter(padapter); + } + } + } + } else +#endif /* CONFIG_AUTOSUSPEND */ + { + rfpwrstate = RfOnOffDetect(padapter); + RTW_INFO("@@@@- #2 %s==> rfstate:%s\n", __FUNCTION__, (rfpwrstate == rf_on) ? "rf_on" : "rf_off"); + + if (rfpwrstate != pwrpriv->rf_pwrstate) { + if (rfpwrstate == rf_off) { + pwrpriv->change_rfpwrstate = rf_off; + pwrpriv->brfoffbyhw = _TRUE; + rtw_hw_suspend(padapter); + } else { + pwrpriv->change_rfpwrstate = rf_on; + rtw_hw_resume(padapter); + } + RTW_INFO("current rf_pwrstate(%s)\n", (pwrpriv->rf_pwrstate == rf_off) ? "rf_off" : "rf_on"); + } + } + pwrpriv->pwr_state_check_cnts++; + } +#endif /* SUPPORT_HW_RFOFF_DETECTED */ + + if (pwrpriv->ips_mode_req == IPS_NONE) + goto exit; + + if (rtw_pwr_unassociated_idle(padapter) == _FALSE) + goto exit; + + if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts % 4) == 0)) { + RTW_INFO("==>%s .fw_state(%x)\n", __FUNCTION__, get_fwstate(pmlmepriv)); +#if defined(CONFIG_BT_COEXIST) && defined (CONFIG_AUTOSUSPEND) +#else + pwrpriv->change_rfpwrstate = rf_off; +#endif +#ifdef CONFIG_AUTOSUSPEND + if (padapter->registrypriv.usbss_enable) { + if (pwrpriv->bHWPwrPindetect) + pwrpriv->bkeepfwalive = _TRUE; + + if (padapter->net_closed == _TRUE) + pwrpriv->ps_flag = _TRUE; + +#if defined(CONFIG_BT_COEXIST) && defined (CONFIG_AUTOSUSPEND) + if (_TRUE == pwrpriv->bInternalAutoSuspend) + RTW_INFO("<==%s .pwrpriv->bInternalAutoSuspend)(%x)\n", __FUNCTION__, pwrpriv->bInternalAutoSuspend); + else { + pwrpriv->change_rfpwrstate = rf_off; + RTW_INFO("<==%s .pwrpriv->bInternalAutoSuspend)(%x) call autosuspend_enter\n", __FUNCTION__, pwrpriv->bInternalAutoSuspend); + autosuspend_enter(padapter); + } +#else + autosuspend_enter(padapter); +#endif /* if defined (CONFIG_BT_COEXIST)&& defined (CONFIG_AUTOSUSPEND) */ + } else if (pwrpriv->bHWPwrPindetect) { + } else +#endif /* CONFIG_AUTOSUSPEND */ + { +#if defined(CONFIG_BT_COEXIST) && defined (CONFIG_AUTOSUSPEND) + pwrpriv->change_rfpwrstate = rf_off; +#endif /* defined (CONFIG_BT_COEXIST)&& defined (CONFIG_AUTOSUSPEND) */ + +#ifdef CONFIG_IPS + ips_enter(padapter); +#endif + } + } +exit: +#ifndef CONFIG_IPS_CHECK_IN_WD + rtw_set_pwr_state_check_timer(pwrpriv); +#endif + pwrpriv->ps_processing = _FALSE; + return; +} + +void pwr_state_check_handler(RTW_TIMER_HDL_ARGS); +void pwr_state_check_handler(RTW_TIMER_HDL_ARGS) +{ + _adapter *padapter = (_adapter *)FunctionContext; + rtw_ps_cmd(padapter); +} + +#ifdef CONFIG_LPS +void traffic_check_for_leave_lps(PADAPTER padapter, u8 tx, u32 tx_packets) +{ +#ifdef CONFIG_CHECK_LEAVE_LPS + static u32 start_time = 0; + static u32 xmit_cnt = 0; + u8 bLeaveLPS = _FALSE; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + + + if (tx) { /* from tx */ + xmit_cnt += tx_packets; + + if (start_time == 0) + start_time = rtw_get_current_time(); + + if (rtw_get_passing_time_ms(start_time) > 2000) { /* 2 sec == watch dog timer */ + if (xmit_cnt > 8) { + if ((adapter_to_pwrctl(padapter)->bLeisurePs) + && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE) +#ifdef CONFIG_BT_COEXIST + && (rtw_btcoex_IsBtControlLps(padapter) == _FALSE) +#endif + ) { + /* RTW_INFO("leave lps via Tx = %d\n", xmit_cnt); */ + bLeaveLPS = _TRUE; + } + } + + start_time = rtw_get_current_time(); + xmit_cnt = 0; + } + + } else { /* from rx path */ + if (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 4/*2*/) { + if ((adapter_to_pwrctl(padapter)->bLeisurePs) + && (adapter_to_pwrctl(padapter)->pwr_mode != PS_MODE_ACTIVE) +#ifdef CONFIG_BT_COEXIST + && (rtw_btcoex_IsBtControlLps(padapter) == _FALSE) +#endif + ) { + /* RTW_INFO("leave lps via Rx = %d\n", pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod); */ + bLeaveLPS = _TRUE; + } + } + } + + if (bLeaveLPS) { + /* RTW_INFO("leave lps via %s, Tx = %d, Rx = %d\n", tx?"Tx":"Rx", pmlmepriv->LinkDetectInfo.NumTxOkInPeriod,pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod); */ + /* rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, 1); */ + rtw_lps_ctrl_wk_cmd(padapter, tx ? LPS_CTRL_TX_TRAFFIC_LEAVE : LPS_CTRL_RX_TRAFFIC_LEAVE, tx ? 0 : 1); + } +#endif /* CONFIG_CHECK_LEAVE_LPS */ +} + +/* + * Description: + * This function MUST be called under power lock protect + * + * Parameters + * padapter + * pslv power state level, only could be PS_STATE_S0 ~ PS_STATE_S4 + * + */ +void rtw_set_rpwm(PADAPTER padapter, u8 pslv) +{ + u8 rpwm; + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); +#ifdef CONFIG_DETECT_CPWM_BY_POLLING + u8 cpwm_orig; +#endif /* CONFIG_DETECT_CPWM_BY_POLLING */ + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; + + pslv = PS_STATE(pslv); + +#ifdef CONFIG_LPS_RPWM_TIMER + if (pwrpriv->brpwmtimeout == _TRUE) + RTW_INFO("%s: RPWM timeout, force to set RPWM(0x%02X) again!\n", __FUNCTION__, pslv); + else +#endif /* CONFIG_LPS_RPWM_TIMER */ + { + if ((pwrpriv->rpwm == pslv) +#ifdef CONFIG_LPS_LCLK + || ((pwrpriv->rpwm >= PS_STATE_S2) && (pslv >= PS_STATE_S2)) +#endif + ) { + return; + } + } + + if (rtw_is_surprise_removed(padapter) || + (!rtw_is_hw_init_completed(padapter))) { + + pwrpriv->cpwm = PS_STATE_S4; + + return; + } + + if (rtw_is_drv_stopped(padapter)) { + + if (pslv < PS_STATE_S2) { + return; + } + } + + rpwm = pslv | pwrpriv->tog; +#ifdef CONFIG_LPS_LCLK + /* only when from PS_STATE S0/S1 to S2 and higher needs ACK */ + if ((pwrpriv->cpwm < PS_STATE_S2) && (pslv >= PS_STATE_S2)) + rpwm |= PS_ACK; +#endif + + pwrpriv->rpwm = pslv; + +#ifdef CONFIG_DETECT_CPWM_BY_POLLING + cpwm_orig = 0; + if (rpwm & PS_ACK) + rtw_hal_get_hwreg(padapter, HW_VAR_CPWM, &cpwm_orig); +#endif + +#if defined(CONFIG_LPS_RPWM_TIMER) && !defined(CONFIG_DETECT_CPWM_BY_POLLING) + if (rpwm & PS_ACK) + _set_timer(&pwrpriv->pwr_rpwm_timer, LPS_RPWM_WAIT_MS); +#endif /* CONFIG_LPS_RPWM_TIMER & !CONFIG_DETECT_CPWM_BY_POLLING */ + rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm)); + + pwrpriv->tog += 0x80; + +#ifdef CONFIG_LPS_LCLK + /* No LPS 32K, No Ack */ + if (rpwm & PS_ACK) { +#ifdef CONFIG_DETECT_CPWM_BY_POLLING + u32 start_time; + u8 cpwm_now; + u8 poll_cnt = 0; + + start_time = rtw_get_current_time(); + + /* polling cpwm */ + do { + rtw_msleep_os(1); + poll_cnt++; + cpwm_now = 0; + rtw_hal_get_hwreg(padapter, HW_VAR_CPWM, &cpwm_now); + if ((cpwm_orig ^ cpwm_now) & 0x80) { + pwrpriv->cpwm = PS_STATE_S4; + pwrpriv->cpwm_tog = cpwm_now & PS_TOGGLE; +#ifdef DBG_CHECK_FW_PS_STATE + RTW_INFO("%s: polling cpwm OK! poll_cnt=%d, cpwm_orig=%02x, cpwm_now=%02x , 0x100=0x%x\n" + , __FUNCTION__, poll_cnt, cpwm_orig, cpwm_now, rtw_read8(padapter, REG_CR)); + if (rtw_fw_ps_state(padapter) == _FAIL) { + RTW_INFO("leave 32k but fw state in 32k\n"); + pdbgpriv->dbg_rpwm_toogle_cnt++; + } +#endif /* DBG_CHECK_FW_PS_STATE */ + break; + } + + if (rtw_get_passing_time_ms(start_time) > LPS_RPWM_WAIT_MS) { + RTW_INFO("%s: polling cpwm timeout! poll_cnt=%d, cpwm_orig=%02x, cpwm_now=%02x\n", __FUNCTION__, poll_cnt, cpwm_orig, cpwm_now); +#ifdef DBG_CHECK_FW_PS_STATE + if (rtw_fw_ps_state(padapter) == _FAIL) { + RTW_INFO("rpwm timeout and fw ps state in 32k\n"); + pdbgpriv->dbg_rpwm_timeout_fail_cnt++; + } +#endif /* DBG_CHECK_FW_PS_STATE */ +#ifdef CONFIG_LPS_RPWM_TIMER + _set_timer(&pwrpriv->pwr_rpwm_timer, 1); +#endif /* CONFIG_LPS_RPWM_TIMER */ + break; + } + } while (1); +#endif /* CONFIG_DETECT_CPWM_BY_POLLING */ + } else +#endif /* CONFIG_LPS_LCLK */ + { + pwrpriv->cpwm = pslv; + } + +} + +u8 PS_RDY_CHECK(_adapter *padapter) +{ + u32 curr_time, delta_time; + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#ifdef CONFIG_IOCTL_CFG80211 + struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; +#endif /* CONFIG_IOCTL_CFG80211 */ +#endif /* CONFIG_P2P */ + +#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) + if (_TRUE == pwrpriv->bInSuspend && pwrpriv->wowlan_mode) + return _TRUE; + else if (_TRUE == pwrpriv->bInSuspend && pwrpriv->wowlan_ap_mode) + return _TRUE; + else if (_TRUE == pwrpriv->bInSuspend) + return _FALSE; +#else + if (_TRUE == pwrpriv->bInSuspend) + return _FALSE; +#endif + + curr_time = rtw_get_current_time(); + + delta_time = curr_time - pwrpriv->DelayLPSLastTimeStamp; + + if (delta_time < LPS_DELAY_TIME) + return _FALSE; + + if (check_fwstate(pmlmepriv, WIFI_SITE_MONITOR) + || check_fwstate(pmlmepriv, WIFI_UNDER_LINKING | WIFI_UNDER_WPS) + || check_fwstate(pmlmepriv, WIFI_AP_STATE) + || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE) +#if defined(CONFIG_P2P) && defined(CONFIG_IOCTL_CFG80211) + || rtw_cfg80211_get_is_roch(padapter) == _TRUE +#endif + || rtw_is_scan_deny(padapter) +#ifdef CONFIG_TDLS + /* TDLS link is established. */ + || (padapter->tdlsinfo.link_established == _TRUE) +#endif /* CONFIG_TDLS */ + ) + return _FALSE; + + if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == _FALSE)) { + RTW_INFO("Group handshake still in progress !!!\n"); + return _FALSE; + } + +#ifdef CONFIG_IOCTL_CFG80211 + if (!rtw_cfg80211_pwr_mgmt(padapter)) + return _FALSE; +#endif + + return _TRUE; +} + +#if defined(CONFIG_FWLPS_IN_IPS) +void rtw_set_fw_in_ips_mode(PADAPTER padapter, u8 enable) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + int cnt = 0; + u32 start_time; + u8 val8 = 0; + u8 cpwm_orig = 0, cpwm_now = 0; + u8 parm[H2C_INACTIVE_PS_LEN] = {0}; + + if (padapter->netif_up == _FALSE) { + RTW_INFO("%s: ERROR, netif is down\n", __func__); + return; + } + + /* u8 cmd_param; */ /* BIT0:enable, BIT1:NoConnect32k */ + if (enable) { +#ifdef CONFIG_BT_COEXIST + rtw_btcoex_IpsNotify(padapter, pwrpriv->ips_mode_req); +#endif + /* Enter IPS */ + RTW_INFO("%s: issue H2C to FW when entering IPS\n", __func__); + + parm[0] = 0x1;/* suggest by Isaac.Hsu*/ +#ifdef CONFIG_PNO_SUPPORT + if (pwrpriv->pno_inited) { + parm[1] = pwrpriv->pnlo_info->fast_scan_iterations; + parm[2] = pwrpriv->pnlo_info->slow_scan_period; + } +#endif + + rtw_hal_fill_h2c_cmd(padapter, /* H2C_FWLPS_IN_IPS_, */ + H2C_INACTIVE_PS_, + H2C_INACTIVE_PS_LEN, parm); + /* poll 0x1cc to make sure H2C command already finished by FW; MAC_0x1cc=0 means H2C done by FW. */ + do { + val8 = rtw_read8(padapter, REG_HMETFR); + cnt++; + RTW_INFO("%s polling REG_HMETFR=0x%x, cnt=%d\n", + __func__, val8, cnt); + rtw_mdelay_os(10); + } while (cnt < 100 && (val8 != 0)); + +#ifdef CONFIG_LPS_LCLK + /* H2C done, enter 32k */ + if (val8 == 0) { + /* ser rpwm to enter 32k */ + val8 = rtw_read8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1); + RTW_INFO("%s: read rpwm=%02x\n", __FUNCTION__, val8); + val8 += 0x80; + val8 |= BIT(0); + rtw_write8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1, val8); + RTW_INFO("%s: write rpwm=%02x\n", __FUNCTION__, val8); + adapter_to_pwrctl(padapter)->tog = (val8 + 0x80) & 0x80; + cnt = val8 = 0; + if (parm[1] == 0 || parm[2] == 0) { + do { + val8 = rtw_read8(padapter, REG_CR); + cnt++; + RTW_INFO("%s polling 0x100=0x%x, cnt=%d\n", + __func__, val8, cnt); + RTW_INFO("%s 0x08:%02x, 0x03:%02x\n", + __func__, + rtw_read8(padapter, 0x08), + rtw_read8(padapter, 0x03)); + rtw_mdelay_os(10); + } while (cnt < 20 && (val8 != 0xEA)); + } + } +#endif + } else { + /* Leave IPS */ + RTW_INFO("%s: Leaving IPS in FWLPS state\n", __func__); + +#ifdef CONFIG_LPS_LCLK + /* for polling cpwm */ + cpwm_orig = 0; + rtw_hal_get_hwreg(padapter, HW_VAR_CPWM, &cpwm_orig); + + /* ser rpwm */ + val8 = rtw_read8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1); + val8 &= 0x80; + val8 += 0x80; + val8 |= BIT(6); + rtw_write8(padapter, SDIO_LOCAL_BASE | SDIO_REG_HRPWM1, val8); + RTW_INFO("%s: write rpwm=%02x\n", __FUNCTION__, val8); + adapter_to_pwrctl(padapter)->tog = (val8 + 0x80) & 0x80; + + /* do polling cpwm */ + start_time = rtw_get_current_time(); + do { + + rtw_mdelay_os(1); + + rtw_hal_get_hwreg(padapter, HW_VAR_CPWM, &cpwm_now); + if ((cpwm_orig ^ cpwm_now) & 0x80) + break; + + if (rtw_get_passing_time_ms(start_time) > 100) { + RTW_INFO("%s: polling cpwm timeout when leaving IPS in FWLPS state\n", __FUNCTION__); + break; + } + } while (1); + +#endif + parm[0] = 0x0; + parm[1] = 0x0; + parm[2] = 0x0; + rtw_hal_fill_h2c_cmd(padapter, H2C_INACTIVE_PS_, + H2C_INACTIVE_PS_LEN, parm); +#ifdef CONFIG_BT_COEXIST + rtw_btcoex_IpsNotify(padapter, IPS_NONE); +#endif + } +} +#endif /* CONFIG_PNO_SUPPORT */ + +void rtw_set_ps_mode(PADAPTER padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode, const char *msg) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#endif /* CONFIG_P2P */ +#ifdef CONFIG_TDLS + struct sta_priv *pstapriv = &padapter->stapriv; + _irqL irqL; + int i, j; + _list *plist, *phead; + struct sta_info *ptdls_sta; +#endif /* CONFIG_TDLS */ +#ifdef CONFIG_LPS_PG + u8 lps_pg_hdl_id = 0; +#endif + + + + if (ps_mode > PM_Card_Disable) { + return; + } + + if (pwrpriv->pwr_mode == ps_mode) { + if (PS_MODE_ACTIVE == ps_mode) + return; + +#ifndef CONFIG_BT_COEXIST + if ((pwrpriv->smart_ps == smart_ps) && + (pwrpriv->bcn_ant_mode == bcn_ant_mode)) + return; +#endif /* !CONFIG_BT_COEXIST */ + } + +#ifdef CONFIG_FW_MULTI_PORT_SUPPORT + if (PS_MODE_ACTIVE != ps_mode) { + rtw_set_ps_rsvd_page(padapter); + rtw_set_default_port_id(padapter); + } +#endif + +#ifdef CONFIG_LPS_PG + if ((PS_MODE_ACTIVE != ps_mode) && (pwrpriv->blpspg_info_up)) { + /*rtw_hal_set_lps_pg_info(padapter);*/ + lps_pg_hdl_id = LPS_PG_INFO_CFG; + rtw_hal_set_hwreg(padapter, HW_VAR_LPS_PG_HANDLE, (u8 *)(&lps_pg_hdl_id)); + } +#endif + +#ifdef CONFIG_LPS_LCLK + _enter_pwrlock(&pwrpriv->lock); +#endif + + /* if(pwrpriv->pwr_mode == PS_MODE_ACTIVE) */ + if (ps_mode == PS_MODE_ACTIVE) { + if (1 +#ifdef CONFIG_BT_COEXIST + && (((rtw_btcoex_IsBtControlLps(padapter) == _FALSE) +#ifdef CONFIG_P2P_PS + && (pwdinfo->opp_ps == 0) +#endif /* CONFIG_P2P_PS */ + ) + || ((rtw_btcoex_IsBtControlLps(padapter) == _TRUE) + && (rtw_btcoex_IsLpsOn(padapter) == _FALSE)) + ) +#else /* !CONFIG_BT_COEXIST */ +#ifdef CONFIG_P2P_PS + && (pwdinfo->opp_ps == 0) +#endif /* CONFIG_P2P_PS */ +#endif /* !CONFIG_BT_COEXIST */ + ) { + RTW_INFO(FUNC_ADPT_FMT" Leave 802.11 power save - %s\n", + FUNC_ADPT_ARG(padapter), msg); + + if (pwrpriv->lps_leave_cnts < UINT_MAX) + pwrpriv->lps_leave_cnts++; + else + pwrpriv->lps_leave_cnts = 0; +#ifdef CONFIG_TDLS + for (i = 0; i < NUM_STA; i++) { + phead = &(pstapriv->sta_hash[i]); + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + ptdls_sta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + + if (ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE) + issue_nulldata_to_TDLS_peer_STA(padapter, ptdls_sta->hwaddr, 0, 0, 0); + plist = get_next(plist); + } + } +#endif /* CONFIG_TDLS */ + + pwrpriv->pwr_mode = ps_mode; + rtw_set_rpwm(padapter, PS_STATE_S4); + +#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) || defined(CONFIG_P2P_WOWLAN) + if (pwrpriv->wowlan_mode == _TRUE || + pwrpriv->wowlan_ap_mode == _TRUE || + pwrpriv->wowlan_p2p_mode == _TRUE) { + u32 start_time, delay_ms; + u8 val8; + delay_ms = 20; + start_time = rtw_get_current_time(); + do { + rtw_hal_get_hwreg(padapter, HW_VAR_SYS_CLKR, &val8); + if (!(val8 & BIT(4))) { /* 0x08 bit4 =1 --> in 32k, bit4 = 0 --> leave 32k */ + pwrpriv->cpwm = PS_STATE_S4; + break; + } + if (rtw_get_passing_time_ms(start_time) > delay_ms) { + RTW_INFO("%s: Wait for FW 32K leave more than %u ms!!!\n", + __FUNCTION__, delay_ms); + pdbgpriv->dbg_wow_leave_ps_fail_cnt++; + break; + } + rtw_usleep_os(100); + } while (1); + } +#endif +#if 0 /*def CONFIG_LPS_PG*/ + lps_pg_hdl_id = LPS_PG_REDLEMEM; + rtw_hal_set_hwreg(padapter, HW_VAR_LPS_PG_HANDLE, (u8 *)(&lps_pg_hdl_id)); +#endif + rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); + +#if 0 /*def CONFIG_LPS_PG*/ + lps_pg_hdl_id = LPS_PG_RESEND_H2C; + rtw_hal_set_hwreg(padapter, HW_VAR_LPS_PG_HANDLE, (u8 *)(&lps_pg_hdl_id)); +#endif + +#ifdef CONFIG_LPS_POFF + rtw_hal_set_hwreg(padapter, HW_VAR_LPS_POFF_SET_MODE, + (u8 *)(&ps_mode)); +#endif /*CONFIG_LPS_POFF*/ + + pwrpriv->bFwCurrentInPSMode = _FALSE; + +#ifdef CONFIG_BT_COEXIST + rtw_btcoex_LpsNotify(padapter, ps_mode); +#endif /* CONFIG_BT_COEXIST */ + } + } else { + if ((PS_RDY_CHECK(padapter) && check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE)) +#ifdef CONFIG_BT_COEXIST + || ((rtw_btcoex_IsBtControlLps(padapter) == _TRUE) + && (rtw_btcoex_IsLpsOn(padapter) == _TRUE)) +#endif +#ifdef CONFIG_P2P_WOWLAN + || (_TRUE == pwrpriv->wowlan_p2p_mode) +#endif /* CONFIG_P2P_WOWLAN */ + ) { + u8 pslv; + + RTW_INFO(FUNC_ADPT_FMT" Enter 802.11 power save - %s\n", + FUNC_ADPT_ARG(padapter), msg); + + if (pwrpriv->lps_enter_cnts < UINT_MAX) + pwrpriv->lps_enter_cnts++; + else + pwrpriv->lps_enter_cnts = 0; +#ifdef CONFIG_TDLS + for (i = 0; i < NUM_STA; i++) { + phead = &(pstapriv->sta_hash[i]); + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + ptdls_sta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + + if (ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE) + issue_nulldata_to_TDLS_peer_STA(padapter, ptdls_sta->hwaddr, 1, 0, 0); + plist = get_next(plist); + } + } +#endif /* CONFIG_TDLS */ + +#ifdef CONFIG_BT_COEXIST + rtw_btcoex_LpsNotify(padapter, ps_mode); +#endif /* CONFIG_BT_COEXIST */ + +#ifdef CONFIG_LPS_POFF + rtw_hal_set_hwreg(padapter, HW_VAR_LPS_POFF_SET_MODE, + (u8 *)(&ps_mode)); +#endif /*CONFIG_LPS_POFF*/ + + pwrpriv->bFwCurrentInPSMode = _TRUE; + pwrpriv->pwr_mode = ps_mode; + pwrpriv->smart_ps = smart_ps; + pwrpriv->bcn_ant_mode = bcn_ant_mode; + rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode)); + +#ifdef CONFIG_P2P_PS + /* Set CTWindow after LPS */ + if (pwdinfo->opp_ps == 1) + p2p_ps_wk_cmd(padapter, P2P_PS_ENABLE, 0); +#endif /* CONFIG_P2P_PS */ + + pslv = PS_STATE_S2; +#ifdef CONFIG_LPS_LCLK + if (pwrpriv->alives == 0) + pslv = PS_STATE_S0; +#endif /* CONFIG_LPS_LCLK */ + +#ifdef CONFIG_BT_COEXIST + if ((rtw_btcoex_IsBtDisabled(padapter) == _FALSE) + && (rtw_btcoex_IsBtControlLps(padapter) == _TRUE)) { + u8 val8; + + val8 = rtw_btcoex_LpsVal(padapter); + if (val8 & BIT(4)) + pslv = PS_STATE_S2; + + } +#endif /* CONFIG_BT_COEXIST */ + + rtw_set_rpwm(padapter, pslv); + } + } + +#ifdef CONFIG_LPS_LCLK + _exit_pwrlock(&pwrpriv->lock); +#endif + +} + +/* + * Return: + * 0: Leave OK + * -1: Timeout + * -2: Other error + */ +s32 LPS_RF_ON_check(PADAPTER padapter, u32 delay_ms) +{ + u32 start_time; + u8 bAwake = _FALSE; + s32 err = 0; + + + start_time = rtw_get_current_time(); + while (1) { + rtw_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake); + if (_TRUE == bAwake) + break; + + if (rtw_is_surprise_removed(padapter)) { + err = -2; + RTW_INFO("%s: device surprise removed!!\n", __FUNCTION__); + break; + } + + if (rtw_get_passing_time_ms(start_time) > delay_ms) { + err = -1; + RTW_INFO("%s: Wait for FW LPS leave more than %u ms!!!\n", __FUNCTION__, delay_ms); + break; + } + rtw_usleep_os(100); + } + + return err; +} + +/* + * Description: + * Enter the leisure power save mode. + * */ +void LPS_Enter(PADAPTER padapter, const char *msg) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + int n_assoc_iface = 0; + int i; + char buf[32] = {0}; + + + /* RTW_INFO("+LeisurePSEnter\n"); */ + if (_FALSE == padapter->bFWReady) + return; + +#ifdef CONFIG_BT_COEXIST + if (rtw_btcoex_IsBtControlLps(padapter) == _TRUE) + return; +#endif + + /* Skip lps enter request if number of assocated adapters is not 1 */ + for (i = 0; i < dvobj->iface_nums; i++) { + if (check_fwstate(&(dvobj->padapters[i]->mlmepriv), WIFI_ASOC_STATE)) + n_assoc_iface++; + } + if (n_assoc_iface != 1) + return; + +#ifndef CONFIG_FW_MULTI_PORT_SUPPORT + /* Skip lps enter request for adapter not port0 */ + if (get_hw_port(padapter) != HW_PORT0) + return; +#endif + + for (i = 0; i < dvobj->iface_nums; i++) { + if (PS_RDY_CHECK(dvobj->padapters[i]) == _FALSE) + return; + } + +#ifdef CONFIG_P2P_PS + if (padapter->wdinfo.p2p_ps_mode == P2P_PS_NOA) { + return;/* supporting p2p client ps NOA via H2C_8723B_P2P_PS_OFFLOAD */ + } +#endif /* CONFIG_P2P_PS */ + + if (pwrpriv->bLeisurePs) { + /* Idle for a while if we connect to AP a while ago. */ + if (pwrpriv->LpsIdleCount >= 2) { /* 4 Sec */ + if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) { + sprintf(buf, "WIFI-%s", msg); + pwrpriv->bpower_saving = _TRUE; + rtw_set_ps_mode(padapter, pwrpriv->power_mgnt, padapter->registrypriv.smart_ps, 0, buf); + } + } else + pwrpriv->LpsIdleCount++; + } + + /* RTW_INFO("-LeisurePSEnter\n"); */ + +} + +/* + * Description: + * Leave the leisure power save mode. + * */ +void LPS_Leave(PADAPTER padapter, const char *msg) +{ +#define LPS_LEAVE_TIMEOUT_MS 100 + + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); + u32 start_time; + u8 bAwake = _FALSE; + char buf[32] = {0}; + struct debug_priv *pdbgpriv = &dvobj->drv_dbg; + + + /* RTW_INFO("+LeisurePSLeave\n"); */ + +#ifdef CONFIG_BT_COEXIST + if (rtw_btcoex_IsBtControlLps(padapter) == _TRUE) + return; +#endif + + if (pwrpriv->bLeisurePs) { + if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { + sprintf(buf, "WIFI-%s", msg); + rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, buf); + + if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) + LPS_RF_ON_check(padapter, LPS_LEAVE_TIMEOUT_MS); + } + } + + pwrpriv->bpower_saving = _FALSE; +#ifdef DBG_CHECK_FW_PS_STATE + if (rtw_fw_ps_state(padapter) == _FAIL) { + RTW_INFO("leave lps, fw in 32k\n"); + pdbgpriv->dbg_leave_lps_fail_cnt++; + } +#endif /* DBG_CHECK_FW_PS_STATE + * RTW_INFO("-LeisurePSLeave\n"); */ + +} +#endif + +void LeaveAllPowerSaveModeDirect(PADAPTER Adapter) +{ + PADAPTER pri_padapter = GET_PRIMARY_ADAPTER(Adapter); + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(Adapter); + struct dvobj_priv *psdpriv = Adapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; +#ifndef CONFIG_DETECT_CPWM_BY_POLLING + u8 cpwm_orig, cpwm_now; + u32 start_time; +#endif /* CONFIG_DETECT_CPWM_BY_POLLING */ + + + RTW_INFO("%s.....\n", __FUNCTION__); + + if (rtw_is_surprise_removed(Adapter)) { + RTW_INFO(FUNC_ADPT_FMT ": bSurpriseRemoved=_TRUE Skip!\n", FUNC_ADPT_ARG(Adapter)); + return; + } + + if (rtw_mi_check_status(Adapter, MI_LINKED)) { /*connect*/ + + if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) { + RTW_INFO("%s: Driver Already Leave LPS\n", __FUNCTION__); + return; + } + +#ifdef CONFIG_LPS_LCLK + _enter_pwrlock(&pwrpriv->lock); + +#ifndef CONFIG_DETECT_CPWM_BY_POLLING + cpwm_orig = 0; + rtw_hal_get_hwreg(Adapter, HW_VAR_CPWM, &cpwm_orig); +#endif /* CONFIG_DETECT_CPWM_BY_POLLING */ + rtw_set_rpwm(Adapter, PS_STATE_S4); + +#ifndef CONFIG_DETECT_CPWM_BY_POLLING + + start_time = rtw_get_current_time(); + + /* polling cpwm */ + do { + rtw_mdelay_os(1); + + rtw_hal_get_hwreg(Adapter, HW_VAR_CPWM, &cpwm_now); + if ((cpwm_orig ^ cpwm_now) & 0x80) { + pwrpriv->cpwm = PS_STATE_S4; + pwrpriv->cpwm_tog = cpwm_now & PS_TOGGLE; +#ifdef DBG_CHECK_FW_PS_STATE + RTW_INFO("%s: polling cpwm OK! cpwm_orig=%02x, cpwm_now=%02x, 0x100=0x%x\n" + , __FUNCTION__, cpwm_orig, cpwm_now, rtw_read8(Adapter, REG_CR)); + if (rtw_fw_ps_state(Adapter) == _FAIL) { + RTW_INFO("%s: leave 32k but fw state in 32k\n", __FUNCTION__); + pdbgpriv->dbg_rpwm_toogle_cnt++; + } +#endif /* DBG_CHECK_FW_PS_STATE */ + break; + } + + if (rtw_get_passing_time_ms(start_time) > LPS_RPWM_WAIT_MS) { + RTW_INFO("%s: polling cpwm timeout! cpwm_orig=%02x, cpwm_now=%02x\n", __FUNCTION__, cpwm_orig, cpwm_now); +#ifdef DBG_CHECK_FW_PS_STATE + if (rtw_fw_ps_state(Adapter) == _FAIL) { + RTW_INFO("rpwm timeout and fw ps state in 32k\n"); + pdbgpriv->dbg_rpwm_timeout_fail_cnt++; + } +#endif /* DBG_CHECK_FW_PS_STATE */ + break; + } + } while (1); +#endif /* CONFIG_DETECT_CPWM_BY_POLLING */ + + _exit_pwrlock(&pwrpriv->lock); +#endif + +#ifdef CONFIG_P2P_PS + p2p_ps_wk_cmd(pri_padapter, P2P_PS_DISABLE, 0); +#endif /* CONFIG_P2P_PS */ + +#ifdef CONFIG_LPS + rtw_lps_ctrl_wk_cmd(pri_padapter, LPS_CTRL_LEAVE, 0); +#endif + } else { + if (pwrpriv->rf_pwrstate == rf_off) { +#ifdef CONFIG_AUTOSUSPEND + if (Adapter->registrypriv.usbss_enable) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) + usb_disable_autosuspend(adapter_to_dvobj(Adapter)->pusbdev); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)) + adapter_to_dvobj(Adapter)->pusbdev->autosuspend_disabled = Adapter->bDisableAutosuspend;/* autosuspend disabled by the user */ +#endif + } else +#endif + { +#if defined(CONFIG_FWLPS_IN_IPS) || defined(CONFIG_SWLPS_IN_IPS) || defined(CONFIG_RTL8188E) +#ifdef CONFIG_IPS + if (_FALSE == ips_leave(pri_padapter)) + RTW_INFO("======> ips_leave fail.............\n"); +#endif +#endif /* CONFIG_SWLPS_IN_IPS || (CONFIG_PLATFORM_SPRD && CONFIG_RTL8188E) */ + } + } + } + +} + +/* + * Description: Leave all power save mode: LPS, FwLPS, IPS if needed. + * Move code to function by tynli. 2010.03.26. + * */ +void LeaveAllPowerSaveMode(IN PADAPTER Adapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(Adapter); + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + u8 enqueue = 0; + int n_assoc_iface = 0; + int i; + + + /* RTW_INFO("%s.....\n",__FUNCTION__); */ + + if (_FALSE == Adapter->bup) { + RTW_INFO(FUNC_ADPT_FMT ": bup=%d Skip!\n", + FUNC_ADPT_ARG(Adapter), Adapter->bup); + return; + } + + if (rtw_is_surprise_removed(Adapter)) { + RTW_INFO(FUNC_ADPT_FMT ": bSurpriseRemoved=_TRUE Skip!\n", FUNC_ADPT_ARG(Adapter)); + return; + } + + for (i = 0; i < dvobj->iface_nums; i++) { + if (check_fwstate(&(dvobj->padapters[i]->mlmepriv), WIFI_ASOC_STATE)) + n_assoc_iface++; + } + + if (n_assoc_iface) { + /* connect */ +#ifdef CONFIG_LPS_LCLK + enqueue = 1; +#endif + +#ifdef CONFIG_P2P_PS + p2p_ps_wk_cmd(Adapter, P2P_PS_DISABLE, enqueue); +#endif /* CONFIG_P2P_PS */ + +#ifdef CONFIG_LPS + rtw_lps_ctrl_wk_cmd(Adapter, LPS_CTRL_LEAVE, enqueue); +#endif + +#ifdef CONFIG_LPS_LCLK + LPS_Leave_check(Adapter); +#endif + } else { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate == rf_off) { +#ifdef CONFIG_AUTOSUSPEND + if (Adapter->registrypriv.usbss_enable) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) + usb_disable_autosuspend(adapter_to_dvobj(Adapter)->pusbdev); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)) + adapter_to_dvobj(Adapter)->pusbdev->autosuspend_disabled = Adapter->bDisableAutosuspend;/* autosuspend disabled by the user */ +#endif + } else +#endif + { +#if defined(CONFIG_FWLPS_IN_IPS) || defined(CONFIG_SWLPS_IN_IPS) || (defined(CONFIG_PLATFORM_SPRD) && defined(CONFIG_RTL8188E)) +#ifdef CONFIG_IPS + if (_FALSE == ips_leave(Adapter)) + RTW_INFO("======> ips_leave fail.............\n"); +#endif +#endif /* CONFIG_SWLPS_IN_IPS || (CONFIG_PLATFORM_SPRD && CONFIG_RTL8188E) */ + } + } + } + +} + +#ifdef CONFIG_LPS_LCLK +void LPS_Leave_check( + PADAPTER padapter) +{ + struct pwrctrl_priv *pwrpriv; + u32 start_time; + u8 bReady; + + + pwrpriv = adapter_to_pwrctl(padapter); + + bReady = _FALSE; + start_time = rtw_get_current_time(); + + rtw_yield_os(); + + while (1) { + _enter_pwrlock(&pwrpriv->lock); + + if (rtw_is_surprise_removed(padapter) + || (!rtw_is_hw_init_completed(padapter)) +#ifdef CONFIG_USB_HCI + || rtw_is_drv_stopped(padapter) +#endif + || (pwrpriv->pwr_mode == PS_MODE_ACTIVE) + ) + bReady = _TRUE; + + _exit_pwrlock(&pwrpriv->lock); + + if (_TRUE == bReady) + break; + + if (rtw_get_passing_time_ms(start_time) > 100) { + RTW_INFO("Wait for cpwm event than 100 ms!!!\n"); + break; + } + rtw_msleep_os(1); + } + +} + +/* + * Caller:ISR handler... + * + * This will be called when CPWM interrupt is up. + * + * using to update cpwn of drv; and drv willl make a decision to up or down pwr level + */ +void cpwm_int_hdl( + PADAPTER padapter, + struct reportpwrstate_parm *preportpwrstate) +{ + struct pwrctrl_priv *pwrpriv; + + if (!padapter) + goto exit; + + if (RTW_CANNOT_RUN(padapter)) + goto exit; + + pwrpriv = adapter_to_pwrctl(padapter); +#if 0 + if (pwrpriv->cpwm_tog == (preportpwrstate->state & PS_TOGGLE)) { + goto exit; + } +#endif + + _enter_pwrlock(&pwrpriv->lock); + +#ifdef CONFIG_LPS_RPWM_TIMER + if (pwrpriv->rpwm < PS_STATE_S2) { + RTW_INFO("%s: Redundant CPWM Int. RPWM=0x%02X CPWM=0x%02x\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); + _exit_pwrlock(&pwrpriv->lock); + goto exit; + } +#endif /* CONFIG_LPS_RPWM_TIMER */ + + pwrpriv->cpwm = PS_STATE(preportpwrstate->state); + pwrpriv->cpwm_tog = preportpwrstate->state & PS_TOGGLE; + + if (pwrpriv->cpwm >= PS_STATE_S2) { + if (pwrpriv->alives & CMD_ALIVE) + _rtw_up_sema(&padapter->cmdpriv.cmd_queue_sema); + + if (pwrpriv->alives & XMIT_ALIVE) + _rtw_up_sema(&padapter->xmitpriv.xmit_sema); + } + + _exit_pwrlock(&pwrpriv->lock); + +exit: + return; +} + +static void cpwm_event_callback(struct work_struct *work) +{ + struct pwrctrl_priv *pwrpriv = container_of(work, struct pwrctrl_priv, cpwm_event); + struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv); + _adapter *adapter = dvobj_get_primary_adapter(dvobj); + struct reportpwrstate_parm report; + + /* RTW_INFO("%s\n",__FUNCTION__); */ + + report.state = PS_STATE_S2; + cpwm_int_hdl(adapter, &report); +} + +static void dma_event_callback(struct work_struct *work) +{ + struct pwrctrl_priv *pwrpriv = container_of(work, struct pwrctrl_priv, dma_event); + struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv); + _adapter *adapter = dvobj_get_primary_adapter(dvobj); + + rtw_unregister_tx_alive(adapter); +} + +#ifdef CONFIG_LPS_RPWM_TIMER +static void rpwmtimeout_workitem_callback(struct work_struct *work) +{ + PADAPTER padapter; + struct dvobj_priv *dvobj; + struct pwrctrl_priv *pwrpriv; + + + pwrpriv = container_of(work, struct pwrctrl_priv, rpwmtimeoutwi); + dvobj = pwrctl_to_dvobj(pwrpriv); + padapter = dvobj_get_primary_adapter(dvobj); + /* RTW_INFO("+%s: rpwm=0x%02X cpwm=0x%02X\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); */ + + if (!padapter) + return; + + if (RTW_CANNOT_RUN(padapter)) + return; + + _enter_pwrlock(&pwrpriv->lock); + if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) { + RTW_INFO("%s: rpwm=0x%02X cpwm=0x%02X CPWM done!\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); + goto exit; + } + _exit_pwrlock(&pwrpriv->lock); + + if (rtw_read8(padapter, 0x100) != 0xEA) { +#if 1 + struct reportpwrstate_parm report; + + report.state = PS_STATE_S2; + RTW_INFO("\n%s: FW already leave 32K!\n\n", __func__); + cpwm_int_hdl(padapter, &report); +#else + RTW_INFO("\n%s: FW already leave 32K!\n\n", __func__); + cpwm_event_callback(&pwrpriv->cpwm_event); +#endif + return; + } + + _enter_pwrlock(&pwrpriv->lock); + + if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) { + RTW_INFO("%s: cpwm=%d, nothing to do!\n", __func__, pwrpriv->cpwm); + goto exit; + } + pwrpriv->brpwmtimeout = _TRUE; + rtw_set_rpwm(padapter, pwrpriv->rpwm); + pwrpriv->brpwmtimeout = _FALSE; + +exit: + _exit_pwrlock(&pwrpriv->lock); +} + +/* + * This function is a timer handler, can't do any IO in it. + */ +static void pwr_rpwm_timeout_handler(void *FunctionContext) +{ + PADAPTER padapter; + struct pwrctrl_priv *pwrpriv; + + + padapter = (PADAPTER)FunctionContext; + pwrpriv = adapter_to_pwrctl(padapter); + if (!padapter) + return; + + if (RTW_CANNOT_RUN(padapter)) + return; + + RTW_INFO("+%s: rpwm=0x%02X cpwm=0x%02X\n", __func__, pwrpriv->rpwm, pwrpriv->cpwm); + + if ((pwrpriv->rpwm == pwrpriv->cpwm) || (pwrpriv->cpwm >= PS_STATE_S2)) { + RTW_INFO("+%s: cpwm=%d, nothing to do!\n", __func__, pwrpriv->cpwm); + return; + } + + _set_workitem(&pwrpriv->rpwmtimeoutwi); +} +#endif /* CONFIG_LPS_RPWM_TIMER */ + +__inline static void register_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag) +{ + pwrctrl->alives |= tag; +} + +__inline static void unregister_task_alive(struct pwrctrl_priv *pwrctrl, u32 tag) +{ + pwrctrl->alives &= ~tag; +} + + +/* + * Description: + * Check if the fw_pwrstate is okay for I/O. + * If not (cpwm is less than S2), then the sub-routine + * will raise the cpwm to be greater than or equal to S2. + * + * Calling Context: Passive + * + * Constraint: + * 1. this function will request pwrctrl->lock + * + * Return Value: + * _SUCCESS hardware is ready for I/O + * _FAIL can't I/O right now + */ +s32 rtw_register_task_alive(PADAPTER padapter, u32 task) +{ + s32 res; + struct pwrctrl_priv *pwrctrl; + u8 pslv; + + + res = _SUCCESS; + pwrctrl = adapter_to_pwrctl(padapter); + pslv = PS_STATE_S2; + + _enter_pwrlock(&pwrctrl->lock); + + register_task_alive(pwrctrl, task); + + if (pwrctrl->bFwCurrentInPSMode == _TRUE) { + + if (pwrctrl->cpwm < pslv) { + if (pwrctrl->cpwm < PS_STATE_S2) + res = _FAIL; + if (pwrctrl->rpwm < pslv) + rtw_set_rpwm(padapter, pslv); + } + } + + _exit_pwrlock(&pwrctrl->lock); + +#ifdef CONFIG_DETECT_CPWM_BY_POLLING + if (_FAIL == res) { + if (pwrctrl->cpwm >= PS_STATE_S2) + res = _SUCCESS; + } +#endif /* CONFIG_DETECT_CPWM_BY_POLLING */ + + + return res; +} + +/* + * Description: + * If task is done, call this func. to power down firmware again. + * + * Constraint: + * 1. this function will request pwrctrl->lock + * + * Return Value: + * none + */ +void rtw_unregister_task_alive(PADAPTER padapter, u32 task) +{ + struct pwrctrl_priv *pwrctrl; + u8 pslv; + + + pwrctrl = adapter_to_pwrctl(padapter); + pslv = PS_STATE_S0; + +#ifdef CONFIG_BT_COEXIST + if ((rtw_btcoex_IsBtDisabled(padapter) == _FALSE) + && (rtw_btcoex_IsBtControlLps(padapter) == _TRUE)) { + u8 val8; + + val8 = rtw_btcoex_LpsVal(padapter); + if (val8 & BIT(4)) + pslv = PS_STATE_S2; + + } +#endif /* CONFIG_BT_COEXIST */ + + _enter_pwrlock(&pwrctrl->lock); + + unregister_task_alive(pwrctrl, task); + + if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) + && (pwrctrl->bFwCurrentInPSMode == _TRUE)) { + + if (pwrctrl->cpwm > pslv) { + if ((pslv >= PS_STATE_S2) || (pwrctrl->alives == 0)) + rtw_set_rpwm(padapter, pslv); + } + } + + _exit_pwrlock(&pwrctrl->lock); + +} + +/* + * Caller: rtw_xmit_thread + * + * Check if the fw_pwrstate is okay for xmit. + * If not (cpwm is less than S3), then the sub-routine + * will raise the cpwm to be greater than or equal to S3. + * + * Calling Context: Passive + * + * Return Value: + * _SUCCESS rtw_xmit_thread can write fifo/txcmd afterwards. + * _FAIL rtw_xmit_thread can not do anything. + */ +s32 rtw_register_tx_alive(PADAPTER padapter) +{ + s32 res; + struct pwrctrl_priv *pwrctrl; + u8 pslv; + + + res = _SUCCESS; + pwrctrl = adapter_to_pwrctl(padapter); + pslv = PS_STATE_S2; + + _enter_pwrlock(&pwrctrl->lock); + + register_task_alive(pwrctrl, XMIT_ALIVE); + + if (pwrctrl->bFwCurrentInPSMode == _TRUE) { + + if (pwrctrl->cpwm < pslv) { + if (pwrctrl->cpwm < PS_STATE_S2) + res = _FAIL; + if (pwrctrl->rpwm < pslv) + rtw_set_rpwm(padapter, pslv); + } + } + + _exit_pwrlock(&pwrctrl->lock); + +#ifdef CONFIG_DETECT_CPWM_BY_POLLING + if (_FAIL == res) { + if (pwrctrl->cpwm >= PS_STATE_S2) + res = _SUCCESS; + } +#endif /* CONFIG_DETECT_CPWM_BY_POLLING */ + + + return res; +} + +/* + * Caller: rtw_cmd_thread + * + * Check if the fw_pwrstate is okay for issuing cmd. + * If not (cpwm should be is less than S2), then the sub-routine + * will raise the cpwm to be greater than or equal to S2. + * + * Calling Context: Passive + * + * Return Value: + * _SUCCESS rtw_cmd_thread can issue cmds to firmware afterwards. + * _FAIL rtw_cmd_thread can not do anything. + */ +s32 rtw_register_cmd_alive(PADAPTER padapter) +{ + s32 res; + struct pwrctrl_priv *pwrctrl; + u8 pslv; + + + res = _SUCCESS; + pwrctrl = adapter_to_pwrctl(padapter); + pslv = PS_STATE_S2; + + _enter_pwrlock(&pwrctrl->lock); + + register_task_alive(pwrctrl, CMD_ALIVE); + + if (pwrctrl->bFwCurrentInPSMode == _TRUE) { + + if (pwrctrl->cpwm < pslv) { + if (pwrctrl->cpwm < PS_STATE_S2) + res = _FAIL; + if (pwrctrl->rpwm < pslv) + rtw_set_rpwm(padapter, pslv); + } + } + + _exit_pwrlock(&pwrctrl->lock); + +#ifdef CONFIG_DETECT_CPWM_BY_POLLING + if (_FAIL == res) { + if (pwrctrl->cpwm >= PS_STATE_S2) + res = _SUCCESS; + } +#endif /* CONFIG_DETECT_CPWM_BY_POLLING */ + + + return res; +} + +/* + * Caller: rx_isr + * + * Calling Context: Dispatch/ISR + * + * Return Value: + * _SUCCESS + * _FAIL + */ +s32 rtw_register_rx_alive(PADAPTER padapter) +{ + struct pwrctrl_priv *pwrctrl; + + + pwrctrl = adapter_to_pwrctl(padapter); + + _enter_pwrlock(&pwrctrl->lock); + + register_task_alive(pwrctrl, RECV_ALIVE); + + _exit_pwrlock(&pwrctrl->lock); + + + return _SUCCESS; +} + +/* + * Caller: evt_isr or evt_thread + * + * Calling Context: Dispatch/ISR or Passive + * + * Return Value: + * _SUCCESS + * _FAIL + */ +s32 rtw_register_evt_alive(PADAPTER padapter) +{ + struct pwrctrl_priv *pwrctrl; + + + pwrctrl = adapter_to_pwrctl(padapter); + + _enter_pwrlock(&pwrctrl->lock); + + register_task_alive(pwrctrl, EVT_ALIVE); + + _exit_pwrlock(&pwrctrl->lock); + + + return _SUCCESS; +} + +/* + * Caller: ISR + * + * If ISR's txdone, + * No more pkts for TX, + * Then driver shall call this fun. to power down firmware again. + */ +void rtw_unregister_tx_alive(PADAPTER padapter) +{ + struct pwrctrl_priv *pwrctrl; + _adapter *iface; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + u8 pslv, i; + + + pwrctrl = adapter_to_pwrctl(padapter); + pslv = PS_STATE_S0; + +#ifdef CONFIG_BT_COEXIST + if ((rtw_btcoex_IsBtDisabled(padapter) == _FALSE) + && (rtw_btcoex_IsBtControlLps(padapter) == _TRUE)) { + u8 val8; + + val8 = rtw_btcoex_LpsVal(padapter); + if (val8 & BIT(4)) + pslv = PS_STATE_S2; + + } +#endif /* CONFIG_BT_COEXIST */ + +#ifdef CONFIG_P2P_PS + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if ((iface) && rtw_is_adapter_up(iface)) { + if (iface->wdinfo.p2p_ps_mode > P2P_PS_NONE) { + pslv = PS_STATE_S2; + break; + } + } + } +#endif + _enter_pwrlock(&pwrctrl->lock); + + unregister_task_alive(pwrctrl, XMIT_ALIVE); + + if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) + && (pwrctrl->bFwCurrentInPSMode == _TRUE)) { + + if (pwrctrl->cpwm > pslv) { + if ((pslv >= PS_STATE_S2) || (pwrctrl->alives == 0)) + rtw_set_rpwm(padapter, pslv); + } + } + + _exit_pwrlock(&pwrctrl->lock); + +} + +/* + * Caller: ISR + * + * If all commands have been done, + * and no more command to do, + * then driver shall call this fun. to power down firmware again. + */ +void rtw_unregister_cmd_alive(PADAPTER padapter) +{ + _adapter *iface; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct pwrctrl_priv *pwrctrl; + u8 pslv, i; + + + pwrctrl = adapter_to_pwrctl(padapter); + pslv = PS_STATE_S0; + +#ifdef CONFIG_BT_COEXIST + if ((rtw_btcoex_IsBtDisabled(padapter) == _FALSE) + && (rtw_btcoex_IsBtControlLps(padapter) == _TRUE)) { + u8 val8; + + val8 = rtw_btcoex_LpsVal(padapter); + if (val8 & BIT(4)) + pslv = PS_STATE_S2; + + } +#endif /* CONFIG_BT_COEXIST */ + +#ifdef CONFIG_P2P_PS + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if ((iface) && rtw_is_adapter_up(iface)) { + if (iface->wdinfo.p2p_ps_mode > P2P_PS_NONE) { + pslv = PS_STATE_S2; + break; + } + } + } +#endif + + _enter_pwrlock(&pwrctrl->lock); + + unregister_task_alive(pwrctrl, CMD_ALIVE); + + if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) + && (pwrctrl->bFwCurrentInPSMode == _TRUE)) { + + if (pwrctrl->cpwm > pslv) { + if ((pslv >= PS_STATE_S2) || (pwrctrl->alives == 0)) + rtw_set_rpwm(padapter, pslv); + } + } + + _exit_pwrlock(&pwrctrl->lock); + +} + +/* + * Caller: ISR + */ +void rtw_unregister_rx_alive(PADAPTER padapter) +{ + struct pwrctrl_priv *pwrctrl; + + + pwrctrl = adapter_to_pwrctl(padapter); + + _enter_pwrlock(&pwrctrl->lock); + + unregister_task_alive(pwrctrl, RECV_ALIVE); + + + _exit_pwrlock(&pwrctrl->lock); + +} + +void rtw_unregister_evt_alive(PADAPTER padapter) +{ + struct pwrctrl_priv *pwrctrl; + + + pwrctrl = adapter_to_pwrctl(padapter); + + unregister_task_alive(pwrctrl, EVT_ALIVE); + + + _exit_pwrlock(&pwrctrl->lock); + +} +#endif /* CONFIG_LPS_LCLK */ + +#ifdef CONFIG_RESUME_IN_WORKQUEUE + static void resume_workitem_callback(struct work_struct *work); +#endif /* CONFIG_RESUME_IN_WORKQUEUE */ + +void rtw_init_pwrctrl_priv(PADAPTER padapter) +{ + struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); + + u8 val8 = 0; + +#if defined(CONFIG_CONCURRENT_MODE) + if (padapter->adapter_type != PRIMARY_ADAPTER) + return; +#endif + + +#ifdef PLATFORM_WINDOWS + pwrctrlpriv->pnp_current_pwr_state = NdisDeviceStateD0; +#endif + + _init_pwrlock(&pwrctrlpriv->lock); + _init_pwrlock(&pwrctrlpriv->check_32k_lock); + pwrctrlpriv->rf_pwrstate = rf_on; + pwrctrlpriv->ips_enter_cnts = 0; + pwrctrlpriv->ips_leave_cnts = 0; + pwrctrlpriv->lps_enter_cnts = 0; + pwrctrlpriv->lps_leave_cnts = 0; + pwrctrlpriv->bips_processing = _FALSE; + + pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode; + pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode; + + pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL; + pwrctrlpriv->pwr_state_check_cnts = 0; + pwrctrlpriv->bInternalAutoSuspend = _FALSE; + pwrctrlpriv->bInSuspend = _FALSE; + pwrctrlpriv->bkeepfwalive = _FALSE; + +#ifdef CONFIG_AUTOSUSPEND +#ifdef SUPPORT_HW_RFOFF_DETECTED + pwrctrlpriv->pwr_state_check_interval = (pwrctrlpriv->bHWPwrPindetect) ? 1000 : 2000; +#endif +#endif + + pwrctrlpriv->LpsIdleCount = 0; + +#ifdef CONFIG_LPS_PG + pwrctrlpriv->lpspg_rsvd_page_locate = 0; +#endif + + /* pwrctrlpriv->FWCtrlPSMode =padapter->registrypriv.power_mgnt; */ /* PS_MODE_MIN; */ + if (padapter->registrypriv.mp_mode == 1) + pwrctrlpriv->power_mgnt = PS_MODE_ACTIVE ; + else + pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt; /* PS_MODE_MIN; */ + pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? _TRUE : _FALSE; + + pwrctrlpriv->bFwCurrentInPSMode = _FALSE; + + pwrctrlpriv->rpwm = 0; + pwrctrlpriv->cpwm = PS_STATE_S4; + + pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE; + pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps; + pwrctrlpriv->bcn_ant_mode = 0; + pwrctrlpriv->dtim = 0; + + pwrctrlpriv->tog = 0x80; + +#ifdef CONFIG_LPS_LCLK + rtw_hal_set_hwreg(padapter, HW_VAR_SET_RPWM, (u8 *)(&pwrctrlpriv->rpwm)); + + _init_workitem(&pwrctrlpriv->cpwm_event, cpwm_event_callback, NULL); + + _init_workitem(&pwrctrlpriv->dma_event, dma_event_callback, NULL); + +#ifdef CONFIG_LPS_RPWM_TIMER + pwrctrlpriv->brpwmtimeout = _FALSE; + _init_workitem(&pwrctrlpriv->rpwmtimeoutwi, rpwmtimeout_workitem_callback, NULL); + _init_timer(&pwrctrlpriv->pwr_rpwm_timer, padapter->pnetdev, pwr_rpwm_timeout_handler, padapter); +#endif /* CONFIG_LPS_RPWM_TIMER */ +#endif /* CONFIG_LPS_LCLK */ + + rtw_init_timer(&pwrctrlpriv->pwr_state_check_timer, padapter, pwr_state_check_handler); + + pwrctrlpriv->wowlan_mode = _FALSE; + pwrctrlpriv->wowlan_ap_mode = _FALSE; + pwrctrlpriv->wowlan_p2p_mode = _FALSE; + pwrctrlpriv->wowlan_last_wake_reason = 0; + +#ifdef CONFIG_RESUME_IN_WORKQUEUE + _init_workitem(&pwrctrlpriv->resume_work, resume_workitem_callback, NULL); + pwrctrlpriv->rtw_workqueue = create_singlethread_workqueue("rtw_workqueue"); +#endif /* CONFIG_RESUME_IN_WORKQUEUE */ + +#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER) + pwrctrlpriv->early_suspend.suspend = NULL; + rtw_register_early_suspend(pwrctrlpriv); +#endif /* CONFIG_HAS_EARLYSUSPEND || CONFIG_ANDROID_POWER */ + +#ifdef CONFIG_GPIO_WAKEUP + /*default low active*/ + pwrctrlpriv->is_high_active = HIGH_ACTIVE; + val8 = (pwrctrlpriv->is_high_active == 0) ? 1 : 0; + rtw_hal_switch_gpio_wl_ctrl(padapter, WAKEUP_GPIO_IDX, _TRUE); + rtw_hal_set_output_gpio(padapter, WAKEUP_GPIO_IDX, val8); + RTW_INFO("%s: set GPIO_%d %d as default.\n", + __func__, WAKEUP_GPIO_IDX, val8); +#endif /* CONFIG_GPIO_WAKEUP */ + +#ifdef CONFIG_WOWLAN + rtw_wow_pattern_sw_reset(padapter); + pwrctrlpriv->wowlan_in_resume = _FALSE; +#ifdef CONFIG_PNO_SUPPORT + pwrctrlpriv->pno_inited = _FALSE; + pwrctrlpriv->pnlo_info = NULL; + pwrctrlpriv->pscan_info = NULL; + pwrctrlpriv->pno_ssid_list = NULL; +#endif /* CONFIG_PNO_SUPPORT */ +#ifdef CONFIG_WOW_PATTERN_HW_CAM + _rtw_mutex_init(&pwrctrlpriv->wowlan_pattern_cam_mutex); +#endif + pwrctrlpriv->wowlan_aoac_rpt_loc = 0; +#endif /* CONFIG_WOWLAN */ + +#ifdef CONFIG_LPS_POFF + rtw_hal_set_hwreg(padapter, HW_VAR_LPS_POFF_INIT, 0); +#endif + + +} + + +void rtw_free_pwrctrl_priv(PADAPTER adapter) +{ + struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(adapter); + +#if defined(CONFIG_CONCURRENT_MODE) + if (adapter->adapter_type != PRIMARY_ADAPTER) + return; +#endif + + + /* _rtw_memset((unsigned char *)pwrctrlpriv, 0, sizeof(struct pwrctrl_priv)); */ + + +#ifdef CONFIG_RESUME_IN_WORKQUEUE + if (pwrctrlpriv->rtw_workqueue) { + flush_workqueue(pwrctrlpriv->rtw_workqueue); + destroy_workqueue(pwrctrlpriv->rtw_workqueue); + } +#endif + +#ifdef CONFIG_LPS_POFF + rtw_hal_set_hwreg(adapter, HW_VAR_LPS_POFF_DEINIT, 0); +#endif + +#ifdef CONFIG_WOWLAN +#ifdef CONFIG_PNO_SUPPORT + if (pwrctrlpriv->pnlo_info != NULL) + printk("****** pnlo_info memory leak********\n"); + + if (pwrctrlpriv->pscan_info != NULL) + printk("****** pscan_info memory leak********\n"); + + if (pwrctrlpriv->pno_ssid_list != NULL) + printk("****** pno_ssid_list memory leak********\n"); +#endif +#ifdef CONFIG_WOW_PATTERN_HW_CAM + _rtw_mutex_free(&pwrctrlpriv->wowlan_pattern_cam_mutex); +#endif + +#endif /* CONFIG_WOWLAN */ + +#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER) + rtw_unregister_early_suspend(pwrctrlpriv); +#endif /* CONFIG_HAS_EARLYSUSPEND || CONFIG_ANDROID_POWER */ + + _free_pwrlock(&pwrctrlpriv->lock); + _free_pwrlock(&pwrctrlpriv->check_32k_lock); + +} + +#ifdef CONFIG_RESUME_IN_WORKQUEUE +extern int rtw_resume_process(_adapter *padapter); + +static void resume_workitem_callback(struct work_struct *work) +{ + struct pwrctrl_priv *pwrpriv = container_of(work, struct pwrctrl_priv, resume_work); + struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv); + _adapter *adapter = dvobj_get_primary_adapter(dvobj); + + RTW_INFO("%s\n", __FUNCTION__); + + rtw_resume_process(adapter); + + rtw_resume_unlock_suspend(); +} + +void rtw_resume_in_workqueue(struct pwrctrl_priv *pwrpriv) +{ + /* accquire system's suspend lock preventing from falliing asleep while resume in workqueue */ + /* rtw_lock_suspend(); */ + + rtw_resume_lock_suspend(); + +#if 1 + queue_work(pwrpriv->rtw_workqueue, &pwrpriv->resume_work); +#else + _set_workitem(&pwrpriv->resume_work); +#endif +} +#endif /* CONFIG_RESUME_IN_WORKQUEUE */ + +#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_ANDROID_POWER) +inline bool rtw_is_earlysuspend_registered(struct pwrctrl_priv *pwrpriv) +{ + return (pwrpriv->early_suspend.suspend) ? _TRUE : _FALSE; +} + +inline bool rtw_is_do_late_resume(struct pwrctrl_priv *pwrpriv) +{ + return (pwrpriv->do_late_resume) ? _TRUE : _FALSE; +} + +inline void rtw_set_do_late_resume(struct pwrctrl_priv *pwrpriv, bool enable) +{ + pwrpriv->do_late_resume = enable; +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +extern int rtw_resume_process(_adapter *padapter); +static void rtw_early_suspend(struct early_suspend *h) +{ + struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend); + RTW_INFO("%s\n", __FUNCTION__); + + rtw_set_do_late_resume(pwrpriv, _FALSE); +} + +static void rtw_late_resume(struct early_suspend *h) +{ + struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend); + struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv); + _adapter *adapter = dvobj_get_primary_adapter(dvobj); + + RTW_INFO("%s\n", __FUNCTION__); + + if (pwrpriv->do_late_resume) { + rtw_set_do_late_resume(pwrpriv, _FALSE); + rtw_resume_process(adapter); + } +} + +void rtw_register_early_suspend(struct pwrctrl_priv *pwrpriv) +{ + RTW_INFO("%s\n", __FUNCTION__); + + /* jeff: set the early suspend level before blank screen, so we wll do late resume after scree is lit */ + pwrpriv->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 20; + pwrpriv->early_suspend.suspend = rtw_early_suspend; + pwrpriv->early_suspend.resume = rtw_late_resume; + register_early_suspend(&pwrpriv->early_suspend); + + +} + +void rtw_unregister_early_suspend(struct pwrctrl_priv *pwrpriv) +{ + RTW_INFO("%s\n", __FUNCTION__); + + rtw_set_do_late_resume(pwrpriv, _FALSE); + + if (pwrpriv->early_suspend.suspend) + unregister_early_suspend(&pwrpriv->early_suspend); + + pwrpriv->early_suspend.suspend = NULL; + pwrpriv->early_suspend.resume = NULL; +} +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +#ifdef CONFIG_ANDROID_POWER +#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + extern int rtw_resume_process(PADAPTER padapter); +#endif +static void rtw_early_suspend(android_early_suspend_t *h) +{ + struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend); + RTW_INFO("%s\n", __FUNCTION__); + + rtw_set_do_late_resume(pwrpriv, _FALSE); +} + +static void rtw_late_resume(android_early_suspend_t *h) +{ + struct pwrctrl_priv *pwrpriv = container_of(h, struct pwrctrl_priv, early_suspend); + struct dvobj_priv *dvobj = pwrctl_to_dvobj(pwrpriv); + _adapter *adapter = dvobj_get_primary_adapter(dvobj); + + RTW_INFO("%s\n", __FUNCTION__); + if (pwrpriv->do_late_resume) { +#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + rtw_set_do_late_resume(pwrpriv, _FALSE); + rtw_resume_process(adapter); +#endif + } +} + +void rtw_register_early_suspend(struct pwrctrl_priv *pwrpriv) +{ + RTW_INFO("%s\n", __FUNCTION__); + + /* jeff: set the early suspend level before blank screen, so we wll do late resume after scree is lit */ + pwrpriv->early_suspend.level = ANDROID_EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 20; + pwrpriv->early_suspend.suspend = rtw_early_suspend; + pwrpriv->early_suspend.resume = rtw_late_resume; + android_register_early_suspend(&pwrpriv->early_suspend); +} + +void rtw_unregister_early_suspend(struct pwrctrl_priv *pwrpriv) +{ + RTW_INFO("%s\n", __FUNCTION__); + + rtw_set_do_late_resume(pwrpriv, _FALSE); + + if (pwrpriv->early_suspend.suspend) + android_unregister_early_suspend(&pwrpriv->early_suspend); + + pwrpriv->early_suspend.suspend = NULL; + pwrpriv->early_suspend.resume = NULL; +} +#endif /* CONFIG_ANDROID_POWER */ + +u8 rtw_interface_ps_func(_adapter *padapter, HAL_INTF_PS_FUNC efunc_id, u8 *val) +{ + u8 bResult = _TRUE; + rtw_hal_intf_ps_func(padapter, efunc_id, val); + + return bResult; +} + + +inline void rtw_set_ips_deny(_adapter *padapter, u32 ms) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime(ms); +} + +/* +* rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend +* @adapter: pointer to _adapter structure +* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup +* Return _SUCCESS or _FAIL +*/ + +int _rtw_pwr_wakeup(_adapter *padapter, u32 ips_deffer_ms, const char *caller) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); + struct mlme_priv *pmlmepriv; + int ret = _SUCCESS; + int i; + u32 start = rtw_get_current_time(); + + /* for LPS */ + LeaveAllPowerSaveMode(padapter); + + /* IPS still bound with primary adapter */ + padapter = GET_PRIMARY_ADAPTER(padapter); + pmlmepriv = &padapter->mlmepriv; + + if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms)) + pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms); + + + if (pwrpriv->ps_processing) { + RTW_INFO("%s wait ps_processing...\n", __func__); + while (pwrpriv->ps_processing && rtw_get_passing_time_ms(start) <= 3000) + rtw_msleep_os(10); + if (pwrpriv->ps_processing) + RTW_INFO("%s wait ps_processing timeout\n", __func__); + else + RTW_INFO("%s wait ps_processing done\n", __func__); + } + +#ifdef DBG_CONFIG_ERROR_DETECT + if (rtw_hal_sreset_inprogress(padapter)) { + RTW_INFO("%s wait sreset_inprogress...\n", __func__); + while (rtw_hal_sreset_inprogress(padapter) && rtw_get_passing_time_ms(start) <= 4000) + rtw_msleep_os(10); + if (rtw_hal_sreset_inprogress(padapter)) + RTW_INFO("%s wait sreset_inprogress timeout\n", __func__); + else + RTW_INFO("%s wait sreset_inprogress done\n", __func__); + } +#endif + + if (pwrpriv->bInternalAutoSuspend == _FALSE && pwrpriv->bInSuspend) { + RTW_INFO("%s wait bInSuspend...\n", __func__); + while (pwrpriv->bInSuspend + && ((rtw_get_passing_time_ms(start) <= 3000 && !rtw_is_do_late_resume(pwrpriv)) + || (rtw_get_passing_time_ms(start) <= 500 && rtw_is_do_late_resume(pwrpriv))) + ) + rtw_msleep_os(10); + if (pwrpriv->bInSuspend) + RTW_INFO("%s wait bInSuspend timeout\n", __func__); + else + RTW_INFO("%s wait bInSuspend done\n", __func__); + } + + /* System suspend is not allowed to wakeup */ + if ((pwrpriv->bInternalAutoSuspend == _FALSE) && (_TRUE == pwrpriv->bInSuspend)) { + ret = _FAIL; + goto exit; + } + + /* block??? */ + if ((pwrpriv->bInternalAutoSuspend == _TRUE) && (padapter->net_closed == _TRUE)) { + ret = _FAIL; + goto exit; + } + + /* I think this should be check in IPS, LPS, autosuspend functions... */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { +#if defined(CONFIG_BT_COEXIST) && defined (CONFIG_AUTOSUSPEND) + if (_TRUE == pwrpriv->bInternalAutoSuspend) { + if (0 == pwrpriv->autopm_cnt) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)) + if (usb_autopm_get_interface(adapter_to_dvobj(padapter)->pusbintf) < 0) + RTW_INFO("can't get autopm:\n"); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)) + usb_autopm_disable(adapter_to_dvobj(padapter)->pusbintf); +#else + usb_autoresume_device(adapter_to_dvobj(padapter)->pusbdev, 1); +#endif + pwrpriv->autopm_cnt++; + } +#endif /* #if defined (CONFIG_BT_COEXIST) && defined (CONFIG_AUTOSUSPEND) */ + ret = _SUCCESS; + goto exit; +#if defined(CONFIG_BT_COEXIST) && defined (CONFIG_AUTOSUSPEND) + } +#endif /* #if defined (CONFIG_BT_COEXIST) && defined (CONFIG_AUTOSUSPEND) */ + } + + if (rf_off == pwrpriv->rf_pwrstate) { +#ifdef CONFIG_USB_HCI +#ifdef CONFIG_AUTOSUSPEND + if (pwrpriv->brfoffbyhw == _TRUE) { + RTW_INFO("hw still in rf_off state ...........\n"); + ret = _FAIL; + goto exit; + } else if (padapter->registrypriv.usbss_enable) { + RTW_INFO("%s call autoresume_enter....\n", __FUNCTION__); + if (_FAIL == autoresume_enter(padapter)) { + RTW_INFO("======> autoresume fail.............\n"); + ret = _FAIL; + goto exit; + } + } else +#endif +#endif + { +#ifdef CONFIG_IPS + RTW_INFO("%s call ips_leave....\n", __FUNCTION__); + if (_FAIL == ips_leave(padapter)) { + RTW_INFO("======> ips_leave fail.............\n"); + ret = _FAIL; + goto exit; + } +#endif + } + } + + /* TODO: the following checking need to be merged... */ + if (rtw_is_drv_stopped(padapter) + || !padapter->bup + || !rtw_is_hw_init_completed(padapter) + ) { + RTW_INFO("%s: bDriverStopped=%s, bup=%d, hw_init_completed=%u\n" + , caller + , rtw_is_drv_stopped(padapter) ? "True" : "False" + , padapter->bup + , rtw_get_hw_init_completed(padapter)); + ret = _FALSE; + goto exit; + } + +exit: + if (pwrpriv->ips_deny_time < rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms)) + pwrpriv->ips_deny_time = rtw_get_current_time() + rtw_ms_to_systime(ips_deffer_ms); + return ret; + +} + +int rtw_pm_set_lps(_adapter *padapter, u8 mode) +{ + int ret = 0; + struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); + + if (mode < PS_MODE_NUM) { + if (pwrctrlpriv->power_mgnt != mode) { + if (PS_MODE_ACTIVE == mode) + LeaveAllPowerSaveMode(padapter); + else + pwrctrlpriv->LpsIdleCount = 2; + pwrctrlpriv->power_mgnt = mode; + pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt) ? _TRUE : _FALSE; + } + } else + ret = -EINVAL; + + return ret; +} + +int rtw_pm_set_ips(_adapter *padapter, u8 mode) +{ + struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); + + if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) { + rtw_ips_mode_req(pwrctrlpriv, mode); + RTW_INFO("%s %s\n", __FUNCTION__, mode == IPS_NORMAL ? "IPS_NORMAL" : "IPS_LEVEL_2"); + return 0; + } else if (mode == IPS_NONE) { + rtw_ips_mode_req(pwrctrlpriv, mode); + RTW_INFO("%s %s\n", __FUNCTION__, "IPS_NONE"); + if (!rtw_is_surprise_removed(padapter) && (_FAIL == rtw_pwr_wakeup(padapter))) + return -EFAULT; + } else + return -EINVAL; + return 0; +} + +/* + * ATTENTION: + * This function will request pwrctrl LOCK! + */ +void rtw_ps_deny(PADAPTER padapter, PS_DENY_REASON reason) +{ + struct pwrctrl_priv *pwrpriv; + s32 ret; + + + /* RTW_INFO("+" FUNC_ADPT_FMT ": Request PS deny for %d (0x%08X)\n", + * FUNC_ADPT_ARG(padapter), reason, BIT(reason)); */ + + pwrpriv = adapter_to_pwrctl(padapter); + + _enter_pwrlock(&pwrpriv->lock); + if (pwrpriv->ps_deny & BIT(reason)) { + RTW_INFO(FUNC_ADPT_FMT ": [WARNING] Reason %d had been set before!!\n", + FUNC_ADPT_ARG(padapter), reason); + } + pwrpriv->ps_deny |= BIT(reason); + _exit_pwrlock(&pwrpriv->lock); + + /* RTW_INFO("-" FUNC_ADPT_FMT ": Now PS deny for 0x%08X\n", + * FUNC_ADPT_ARG(padapter), pwrpriv->ps_deny); */ +} + +/* + * ATTENTION: + * This function will request pwrctrl LOCK! + */ +void rtw_ps_deny_cancel(PADAPTER padapter, PS_DENY_REASON reason) +{ + struct pwrctrl_priv *pwrpriv; + + + /* RTW_INFO("+" FUNC_ADPT_FMT ": Cancel PS deny for %d(0x%08X)\n", + * FUNC_ADPT_ARG(padapter), reason, BIT(reason)); */ + + pwrpriv = adapter_to_pwrctl(padapter); + + _enter_pwrlock(&pwrpriv->lock); + if ((pwrpriv->ps_deny & BIT(reason)) == 0) { + RTW_INFO(FUNC_ADPT_FMT ": [ERROR] Reason %d had been canceled before!!\n", + FUNC_ADPT_ARG(padapter), reason); + } + pwrpriv->ps_deny &= ~BIT(reason); + _exit_pwrlock(&pwrpriv->lock); + + /* RTW_INFO("-" FUNC_ADPT_FMT ": Now PS deny for 0x%08X\n", + * FUNC_ADPT_ARG(padapter), pwrpriv->ps_deny); */ +} + +/* + * ATTENTION: + * Before calling this function pwrctrl lock should be occupied already, + * otherwise it may return incorrect value. + */ +u32 rtw_ps_deny_get(PADAPTER padapter) +{ + u32 deny; + + + deny = adapter_to_pwrctl(padapter)->ps_deny; + + return deny; +} diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_recv.c b/linux-bsp/drivers/rtl8188eus/core/rtw_recv.c new file mode 100644 index 0000000..734f150 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_recv.c @@ -0,0 +1,4724 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_RECV_C_ + +#include <drv_types.h> +#include <hal_data.h> + +#if defined(PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) + + #error "Shall be Linux or Windows, but not both!\n" + +#endif + + +#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS +void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS); + +enum { + SIGNAL_STAT_CALC_PROFILE_0 = 0, + SIGNAL_STAT_CALC_PROFILE_1, + SIGNAL_STAT_CALC_PROFILE_MAX +}; + +u8 signal_stat_calc_profile[SIGNAL_STAT_CALC_PROFILE_MAX][2] = { + {4, 1}, /* Profile 0 => pre_stat : curr_stat = 4 : 1 */ + {3, 7} /* Profile 1 => pre_stat : curr_stat = 3 : 7 */ +}; + +#ifndef RTW_SIGNAL_STATE_CALC_PROFILE + #define RTW_SIGNAL_STATE_CALC_PROFILE SIGNAL_STAT_CALC_PROFILE_1 +#endif + +#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */ + +void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv) +{ + + + + _rtw_memset((u8 *)psta_recvpriv, 0, sizeof(struct sta_recv_priv)); + + _rtw_spinlock_init(&psta_recvpriv->lock); + + /* for(i=0; i<MAX_RX_NUMBLKS; i++) */ + /* _rtw_init_queue(&psta_recvpriv->blk_strms[i]); */ + + _rtw_init_queue(&psta_recvpriv->defrag_q); + + +} + +sint _rtw_init_recv_priv(struct recv_priv *precvpriv, _adapter *padapter) +{ + sint i; + + union recv_frame *precvframe; + sint res = _SUCCESS; + + + /* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */ + /* _rtw_memset((unsigned char *)precvpriv, 0, sizeof (struct recv_priv)); */ + + _rtw_spinlock_init(&precvpriv->lock); + +#ifdef CONFIG_RECV_THREAD_MODE + _rtw_init_sema(&precvpriv->recv_sema, 0); + _rtw_init_sema(&precvpriv->terminate_recvthread_sema, 0); +#endif + + _rtw_init_queue(&precvpriv->free_recv_queue); + _rtw_init_queue(&precvpriv->recv_pending_queue); + _rtw_init_queue(&precvpriv->uc_swdec_pending_queue); + + precvpriv->adapter = padapter; + + precvpriv->free_recvframe_cnt = NR_RECVFRAME; + + precvpriv->sink_udpport = 0; + precvpriv->pre_rtp_rxseq = 0; + precvpriv->cur_rtp_rxseq = 0; + +#ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA + precvpriv->store_law_data_flag = 1; +#else + precvpriv->store_law_data_flag = 0; +#endif + + rtw_os_recv_resource_init(precvpriv, padapter); + + precvpriv->pallocated_frame_buf = rtw_zvmalloc(NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ); + + if (precvpriv->pallocated_frame_buf == NULL) { + res = _FAIL; + goto exit; + } + /* _rtw_memset(precvpriv->pallocated_frame_buf, 0, NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ); */ + + precvpriv->precv_frame_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ); + /* precvpriv->precv_frame_buf = precvpriv->pallocated_frame_buf + RXFRAME_ALIGN_SZ - */ + /* ((SIZE_PTR) (precvpriv->pallocated_frame_buf) &(RXFRAME_ALIGN_SZ-1)); */ + + precvframe = (union recv_frame *) precvpriv->precv_frame_buf; + + + for (i = 0; i < NR_RECVFRAME ; i++) { + _rtw_init_listhead(&(precvframe->u.list)); + + rtw_list_insert_tail(&(precvframe->u.list), &(precvpriv->free_recv_queue.queue)); + + res = rtw_os_recv_resource_alloc(padapter, precvframe); + + precvframe->u.hdr.len = 0; + + precvframe->u.hdr.adapter = padapter; + precvframe++; + + } + +#ifdef CONFIG_USB_HCI + + ATOMIC_SET(&(precvpriv->rx_pending_cnt), 1); + + _rtw_init_sema(&precvpriv->allrxreturnevt, 0); + +#endif + + res = rtw_hal_init_recv_priv(padapter); + +#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS + rtw_init_timer(&precvpriv->signal_stat_timer, padapter, RTW_TIMER_HDL_NAME(signal_stat)); + + precvpriv->signal_stat_sampling_interval = 2000; /* ms */ + /* precvpriv->signal_stat_converging_constant = 5000; */ /* ms */ + + rtw_set_signal_stat_timer(precvpriv); +#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */ + +exit: + + + return res; + +} + +void rtw_mfree_recv_priv_lock(struct recv_priv *precvpriv); +void rtw_mfree_recv_priv_lock(struct recv_priv *precvpriv) +{ + _rtw_spinlock_free(&precvpriv->lock); +#ifdef CONFIG_RECV_THREAD_MODE + _rtw_free_sema(&precvpriv->recv_sema); + _rtw_free_sema(&precvpriv->terminate_recvthread_sema); +#endif + + _rtw_spinlock_free(&precvpriv->free_recv_queue.lock); + _rtw_spinlock_free(&precvpriv->recv_pending_queue.lock); + + _rtw_spinlock_free(&precvpriv->free_recv_buf_queue.lock); + +#ifdef CONFIG_USE_USB_BUFFER_ALLOC_RX + _rtw_spinlock_free(&precvpriv->recv_buf_pending_queue.lock); +#endif /* CONFIG_USE_USB_BUFFER_ALLOC_RX */ +} + +void _rtw_free_recv_priv(struct recv_priv *precvpriv) +{ + _adapter *padapter = precvpriv->adapter; + + + rtw_free_uc_swdec_pending_queue(padapter); + + rtw_mfree_recv_priv_lock(precvpriv); + + rtw_os_recv_resource_free(precvpriv); + + if (precvpriv->pallocated_frame_buf) + rtw_vmfree(precvpriv->pallocated_frame_buf, NR_RECVFRAME * sizeof(union recv_frame) + RXFRAME_ALIGN_SZ); + + rtw_hal_free_recv_priv(padapter); + + +} + +bool rtw_rframe_del_wfd_ie(union recv_frame *rframe, u8 ies_offset) +{ +#define DBG_RFRAME_DEL_WFD_IE 0 + u8 *ies = rframe->u.hdr.rx_data + sizeof(struct rtw_ieee80211_hdr_3addr) + ies_offset; + uint ies_len_ori = rframe->u.hdr.len - (ies - rframe->u.hdr.rx_data); + uint ies_len; + + ies_len = rtw_del_wfd_ie(ies, ies_len_ori, DBG_RFRAME_DEL_WFD_IE ? __func__ : NULL); + rframe->u.hdr.len -= ies_len_ori - ies_len; + + return ies_len_ori != ies_len; +} + +union recv_frame *_rtw_alloc_recvframe(_queue *pfree_recv_queue) +{ + + union recv_frame *precvframe; + _list *plist, *phead; + _adapter *padapter; + struct recv_priv *precvpriv; + + if (_rtw_queue_empty(pfree_recv_queue) == _TRUE) + precvframe = NULL; + else { + phead = get_list_head(pfree_recv_queue); + + plist = get_next(phead); + + precvframe = LIST_CONTAINOR(plist, union recv_frame, u); + + rtw_list_delete(&precvframe->u.hdr.list); + padapter = precvframe->u.hdr.adapter; + if (padapter != NULL) { + precvpriv = &padapter->recvpriv; + if (pfree_recv_queue == &precvpriv->free_recv_queue) + precvpriv->free_recvframe_cnt--; + } + } + + + return precvframe; + +} + +union recv_frame *rtw_alloc_recvframe(_queue *pfree_recv_queue) +{ + _irqL irqL; + union recv_frame *precvframe; + + _enter_critical_bh(&pfree_recv_queue->lock, &irqL); + + precvframe = _rtw_alloc_recvframe(pfree_recv_queue); + + _exit_critical_bh(&pfree_recv_queue->lock, &irqL); + + return precvframe; +} + +void rtw_init_recvframe(union recv_frame *precvframe, struct recv_priv *precvpriv) +{ + /* Perry: This can be removed */ + _rtw_init_listhead(&precvframe->u.hdr.list); + + precvframe->u.hdr.len = 0; +} + +int rtw_free_recvframe(union recv_frame *precvframe, _queue *pfree_recv_queue) +{ + _irqL irqL; + _adapter *padapter = precvframe->u.hdr.adapter; + struct recv_priv *precvpriv = &padapter->recvpriv; + + +#ifdef CONFIG_CONCURRENT_MODE + padapter = GET_PRIMARY_ADAPTER(padapter); + precvpriv = &padapter->recvpriv; + pfree_recv_queue = &precvpriv->free_recv_queue; + precvframe->u.hdr.adapter = padapter; +#endif + + + rtw_os_free_recvframe(precvframe); + + + _enter_critical_bh(&pfree_recv_queue->lock, &irqL); + + rtw_list_delete(&(precvframe->u.hdr.list)); + + precvframe->u.hdr.len = 0; + + rtw_list_insert_tail(&(precvframe->u.hdr.list), get_list_head(pfree_recv_queue)); + + if (padapter != NULL) { + if (pfree_recv_queue == &precvpriv->free_recv_queue) + precvpriv->free_recvframe_cnt++; + } + + _exit_critical_bh(&pfree_recv_queue->lock, &irqL); + + + return _SUCCESS; + +} + + + + +sint _rtw_enqueue_recvframe(union recv_frame *precvframe, _queue *queue) +{ + + _adapter *padapter = precvframe->u.hdr.adapter; + struct recv_priv *precvpriv = &padapter->recvpriv; + + + /* _rtw_init_listhead(&(precvframe->u.hdr.list)); */ + rtw_list_delete(&(precvframe->u.hdr.list)); + + + rtw_list_insert_tail(&(precvframe->u.hdr.list), get_list_head(queue)); + + if (padapter != NULL) { + if (queue == &precvpriv->free_recv_queue) + precvpriv->free_recvframe_cnt++; + } + + + return _SUCCESS; +} + +sint rtw_enqueue_recvframe(union recv_frame *precvframe, _queue *queue) +{ + sint ret; + _irqL irqL; + + /* _spinlock(&pfree_recv_queue->lock); */ + _enter_critical_bh(&queue->lock, &irqL); + ret = _rtw_enqueue_recvframe(precvframe, queue); + /* _rtw_spinunlock(&pfree_recv_queue->lock); */ + _exit_critical_bh(&queue->lock, &irqL); + + return ret; +} + +/* +sint rtw_enqueue_recvframe(union recv_frame *precvframe, _queue *queue) +{ + return rtw_free_recvframe(precvframe, queue); +} +*/ + + + + +/* +caller : defrag ; recvframe_chk_defrag in recv_thread (passive) +pframequeue: defrag_queue : will be accessed in recv_thread (passive) + +using spinlock to protect + +*/ + +void rtw_free_recvframe_queue(_queue *pframequeue, _queue *pfree_recv_queue) +{ + union recv_frame *precvframe; + _list *plist, *phead; + + _rtw_spinlock(&pframequeue->lock); + + phead = get_list_head(pframequeue); + plist = get_next(phead); + + while (rtw_end_of_queue_search(phead, plist) == _FALSE) { + precvframe = LIST_CONTAINOR(plist, union recv_frame, u); + + plist = get_next(plist); + + /* rtw_list_delete(&precvframe->u.hdr.list); */ /* will do this in rtw_free_recvframe() */ + + rtw_free_recvframe(precvframe, pfree_recv_queue); + } + + _rtw_spinunlock(&pframequeue->lock); + + +} + +u32 rtw_free_uc_swdec_pending_queue(_adapter *adapter) +{ + u32 cnt = 0; + union recv_frame *pending_frame; + while ((pending_frame = rtw_alloc_recvframe(&adapter->recvpriv.uc_swdec_pending_queue))) { + rtw_free_recvframe(pending_frame, &adapter->recvpriv.free_recv_queue); + cnt++; + } + + if (cnt) + RTW_INFO(FUNC_ADPT_FMT" dequeue %d\n", FUNC_ADPT_ARG(adapter), cnt); + + return cnt; +} + + +sint rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, _queue *queue) +{ + _irqL irqL; + + _enter_critical_bh(&queue->lock, &irqL); + + rtw_list_delete(&precvbuf->list); + rtw_list_insert_head(&precvbuf->list, get_list_head(queue)); + + _exit_critical_bh(&queue->lock, &irqL); + + return _SUCCESS; +} + +sint rtw_enqueue_recvbuf(struct recv_buf *precvbuf, _queue *queue) +{ + _irqL irqL; +#ifdef CONFIG_SDIO_HCI + _enter_critical_bh(&queue->lock, &irqL); +#else + _enter_critical_ex(&queue->lock, &irqL); +#endif/*#ifdef CONFIG_SDIO_HCI*/ + + rtw_list_delete(&precvbuf->list); + + rtw_list_insert_tail(&precvbuf->list, get_list_head(queue)); +#ifdef CONFIG_SDIO_HCI + _exit_critical_bh(&queue->lock, &irqL); +#else + _exit_critical_ex(&queue->lock, &irqL); +#endif/*#ifdef CONFIG_SDIO_HCI*/ + return _SUCCESS; + +} + +struct recv_buf *rtw_dequeue_recvbuf(_queue *queue) +{ + _irqL irqL; + struct recv_buf *precvbuf; + _list *plist, *phead; + +#ifdef CONFIG_SDIO_HCI + _enter_critical_bh(&queue->lock, &irqL); +#else + _enter_critical_ex(&queue->lock, &irqL); +#endif/*#ifdef CONFIG_SDIO_HCI*/ + + if (_rtw_queue_empty(queue) == _TRUE) + precvbuf = NULL; + else { + phead = get_list_head(queue); + + plist = get_next(phead); + + precvbuf = LIST_CONTAINOR(plist, struct recv_buf, list); + + rtw_list_delete(&precvbuf->list); + + } + +#ifdef CONFIG_SDIO_HCI + _exit_critical_bh(&queue->lock, &irqL); +#else + _exit_critical_ex(&queue->lock, &irqL); +#endif/*#ifdef CONFIG_SDIO_HCI*/ + + return precvbuf; + +} + +sint recvframe_chkmic(_adapter *adapter, union recv_frame *precvframe); +sint recvframe_chkmic(_adapter *adapter, union recv_frame *precvframe) +{ + + sint i, res = _SUCCESS; + u32 datalen; + u8 miccode[8]; + u8 bmic_err = _FALSE, brpt_micerror = _TRUE; + u8 *pframe, *payload, *pframemic; + u8 *mickey; + /* u8 *iv,rxdata_key_idx=0; */ + struct sta_info *stainfo; + struct rx_pkt_attrib *prxattrib = &precvframe->u.hdr.attrib; + struct security_priv *psecuritypriv = &adapter->securitypriv; + + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + stainfo = rtw_get_stainfo(&adapter->stapriv , &prxattrib->ta[0]); + + if (prxattrib->encrypt == _TKIP_) { + + /* calculate mic code */ + if (stainfo != NULL) { + if (IS_MCAST(prxattrib->ra)) { + /* mickey=&psecuritypriv->dot118021XGrprxmickey.skey[0]; */ + /* iv = precvframe->u.hdr.rx_data+prxattrib->hdrlen; */ + /* rxdata_key_idx =( ((iv[3])>>6)&0x3) ; */ + mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0]; + + /* RTW_INFO("\n recvframe_chkmic: bcmc key psecuritypriv->dot118021XGrpKeyid(%d),pmlmeinfo->key_index(%d) ,recv key_id(%d)\n", */ + /* psecuritypriv->dot118021XGrpKeyid,pmlmeinfo->key_index,rxdata_key_idx); */ + + if (psecuritypriv->binstallGrpkey == _FALSE) { + res = _FAIL; + RTW_INFO("\n recvframe_chkmic:didn't install group key!!!!!!!!!!\n"); + goto exit; + } + } else { + mickey = &stainfo->dot11tkiprxmickey.skey[0]; + } + + datalen = precvframe->u.hdr.len - prxattrib->hdrlen - prxattrib->iv_len - prxattrib->icv_len - 8; /* icv_len included the mic code */ + pframe = precvframe->u.hdr.rx_data; + payload = pframe + prxattrib->hdrlen + prxattrib->iv_len; + + + /* rtw_seccalctkipmic(&stainfo->dot11tkiprxmickey.skey[0],pframe,payload, datalen ,&miccode[0],(unsigned char)prxattrib->priority); */ /* care the length of the data */ + + rtw_seccalctkipmic(mickey, pframe, payload, datalen , &miccode[0], (unsigned char)prxattrib->priority); /* care the length of the data */ + + pframemic = payload + datalen; + + bmic_err = _FALSE; + + for (i = 0; i < 8; i++) { + if (miccode[i] != *(pframemic + i)) { + bmic_err = _TRUE; + } + } + + + if (bmic_err == _TRUE) { + + + + /* double check key_index for some timing issue , */ + /* cannot compare with psecuritypriv->dot118021XGrpKeyid also cause timing issue */ + if ((IS_MCAST(prxattrib->ra) == _TRUE) && (prxattrib->key_index != pmlmeinfo->key_index)) + brpt_micerror = _FALSE; + + if ((prxattrib->bdecrypted == _TRUE) && (brpt_micerror == _TRUE)) { + rtw_handle_tkip_mic_err(adapter, stainfo, (u8)IS_MCAST(prxattrib->ra)); + RTW_INFO(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted); + } else { + RTW_INFO(" mic error :prxattrib->bdecrypted=%d\n", prxattrib->bdecrypted); + } + + res = _FAIL; + + } else { + /* mic checked ok */ + if ((psecuritypriv->bcheck_grpkey == _FALSE) && (IS_MCAST(prxattrib->ra) == _TRUE)) { + psecuritypriv->bcheck_grpkey = _TRUE; + } + } + + } + + recvframe_pull_tail(precvframe, 8); + + } + +exit: + + + return res; + +} + +/*#define DBG_RX_SW_DECRYPTOR*/ + +/* decrypt and set the ivlen,icvlen of the recv_frame */ +union recv_frame *decryptor(_adapter *padapter, union recv_frame *precv_frame); +union recv_frame *decryptor(_adapter *padapter, union recv_frame *precv_frame) +{ + + struct rx_pkt_attrib *prxattrib = &precv_frame->u.hdr.attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + union recv_frame *return_packet = precv_frame; + u32 res = _SUCCESS; + + + DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt); + + + if (prxattrib->encrypt > 0) { + u8 *iv = precv_frame->u.hdr.rx_data + prxattrib->hdrlen; + prxattrib->key_index = (((iv[3]) >> 6) & 0x3) ; + + if (prxattrib->key_index > WEP_KEYS) { + RTW_INFO("prxattrib->key_index(%d) > WEP_KEYS\n", prxattrib->key_index); + + switch (prxattrib->encrypt) { + case _WEP40_: + case _WEP104_: + prxattrib->key_index = psecuritypriv->dot11PrivacyKeyIndex; + break; + case _TKIP_: + case _AES_: + default: + prxattrib->key_index = psecuritypriv->dot118021XGrpKeyid; + break; + } + } + } + + if ((prxattrib->encrypt > 0) && ((prxattrib->bdecrypted == 0) || (psecuritypriv->sw_decrypt == _TRUE))) { + +#ifdef CONFIG_CONCURRENT_MODE + if (!IS_MCAST(prxattrib->ra)) /* bc/mc packets use sw decryption for concurrent mode */ +#endif + psecuritypriv->hw_decrypted = _FALSE; + +#ifdef DBG_RX_SW_DECRYPTOR + RTW_INFO(ADPT_FMT" - sec_type:%s DO SW decryption\n", + ADPT_ARG(padapter), security_type_str(prxattrib->encrypt)); +#endif + +#ifdef DBG_RX_DECRYPTOR + RTW_INFO("[%s] %d:prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n", + __FUNCTION__, + __LINE__, + prxattrib->bdecrypted, + prxattrib->encrypt, + psecuritypriv->hw_decrypted); +#endif + + switch (prxattrib->encrypt) { + case _WEP40_: + case _WEP104_: + DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_wep); + rtw_wep_decrypt(padapter, (u8 *)precv_frame); + break; + case _TKIP_: + DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_tkip); + res = rtw_tkip_decrypt(padapter, (u8 *)precv_frame); + break; + case _AES_: + DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_aes); + res = rtw_aes_decrypt(padapter, (u8 *)precv_frame); + break; +#ifdef CONFIG_WAPI_SUPPORT + case _SMS4_: + DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_wapi); + rtw_sms4_decrypt(padapter, (u8 *)precv_frame); + break; +#endif + default: + break; + } + } else if (prxattrib->bdecrypted == 1 + && prxattrib->encrypt > 0 + && (psecuritypriv->busetkipkey == 1 || prxattrib->encrypt != _TKIP_) + ) { +#if 0 + if ((prxstat->icv == 1) && (prxattrib->encrypt != _AES_)) { + psecuritypriv->hw_decrypted = _FALSE; + + + rtw_free_recvframe(precv_frame, &padapter->recvpriv.free_recv_queue); + + return_packet = NULL; + + } else +#endif + { + DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_hw); + + psecuritypriv->hw_decrypted = _TRUE; +#ifdef DBG_RX_DECRYPTOR + RTW_INFO("[%s] %d:prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n", + __FUNCTION__, + __LINE__, + prxattrib->bdecrypted, + prxattrib->encrypt, + psecuritypriv->hw_decrypted); + +#endif + } + } else { + DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_unknown); +#ifdef DBG_RX_DECRYPTOR + RTW_INFO("[%s] %d:prxstat->bdecrypted:%d, prxattrib->encrypt:%d, Setting psecuritypriv->hw_decrypted = %d\n", + __FUNCTION__, + __LINE__, + prxattrib->bdecrypted, + prxattrib->encrypt, + psecuritypriv->hw_decrypted); +#endif + } + + if (res == _FAIL) { + rtw_free_recvframe(return_packet, &padapter->recvpriv.free_recv_queue); + return_packet = NULL; + } else + prxattrib->bdecrypted = _TRUE; + /* recvframe_chkmic(adapter, precv_frame); */ /* move to recvframme_defrag function */ + + + return return_packet; + +} +/* ###set the security information in the recv_frame */ +union recv_frame *portctrl(_adapter *adapter, union recv_frame *precv_frame); +union recv_frame *portctrl(_adapter *adapter, union recv_frame *precv_frame) +{ + u8 *psta_addr = NULL; + u8 *ptr; + uint auth_alg; + struct recv_frame_hdr *pfhdr; + struct sta_info *psta; + struct sta_priv *pstapriv ; + union recv_frame *prtnframe; + u16 ether_type = 0; + u16 eapol_type = 0x888e;/* for Funia BD's WPA issue */ + struct rx_pkt_attrib *pattrib; + + + pstapriv = &adapter->stapriv; + + auth_alg = adapter->securitypriv.dot11AuthAlgrthm; + + ptr = get_recvframe_data(precv_frame); + pfhdr = &precv_frame->u.hdr; + pattrib = &pfhdr->attrib; + psta_addr = pattrib->ta; + + prtnframe = NULL; + + psta = rtw_get_stainfo(pstapriv, psta_addr); + + + if (auth_alg == dot11AuthAlgrthm_8021X) { + if ((psta != NULL) && (psta->ieee8021x_blocked)) { + /* blocked */ + /* only accept EAPOL frame */ + + prtnframe = precv_frame; + + /* get ether_type */ + ptr = ptr + pfhdr->attrib.hdrlen + pfhdr->attrib.iv_len + LLC_HEADER_SIZE; + _rtw_memcpy(ðer_type, ptr, 2); + ether_type = ntohs((unsigned short)ether_type); + + if (ether_type == eapol_type) + prtnframe = precv_frame; + else { + /* free this frame */ + rtw_free_recvframe(precv_frame, &adapter->recvpriv.free_recv_queue); + prtnframe = NULL; + } + } else { + /* allowed */ + /* check decryption status, and decrypt the frame if needed */ + + + prtnframe = precv_frame; + /* check is the EAPOL frame or not (Rekey) */ + /* if(ether_type == eapol_type){ */ + /* check Rekey */ + + /* prtnframe=precv_frame; */ + /* } */ + } + } else + prtnframe = precv_frame; + + + return prtnframe; + +} + +sint recv_decache(union recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache); +sint recv_decache(union recv_frame *precv_frame, u8 bretry, struct stainfo_rxcache *prxcache) +{ + sint tid = precv_frame->u.hdr.attrib.priority; + + u16 seq_ctrl = ((precv_frame->u.hdr.attrib.seq_num & 0xffff) << 4) | + (precv_frame->u.hdr.attrib.frag_num & 0xf); + + + if (tid > 15) { + + return _FAIL; + } + + if (1) { /* if(bretry) */ + if (seq_ctrl == prxcache->tid_rxseq[tid]) { + /* for non-AMPDU case */ + precv_frame->u.hdr.psta->sta_stats.duplicate_cnt++; + + if (precv_frame->u.hdr.psta->sta_stats.duplicate_cnt % 100 == 0) + RTW_INFO("%s: seq=%d\n", __func__, precv_frame->u.hdr.attrib.seq_num); + + return _FAIL; + } + } + + prxcache->tid_rxseq[tid] = seq_ctrl; + + + return _SUCCESS; + +} + +/* VALID_PN_CHK + * Return true when PN is legal, otherwise false. + * Legal PN: + * 1. If old PN is 0, any PN is legal + * 2. PN > old PN + */ +#define PN_LESS_CHK(a, b) (((a-b) & 0x800000000000) != 0) +#define VALID_PN_CHK(new, old) (((old) == 0) || PN_LESS_CHK(old, new)) +#define CCMPH_2_KEYID(ch) (((ch) & 0x00000000c0000000) >> 30) +#define CCMPH_2_PN(ch) ((ch) & 0x000000000000ffff) \ + | (((ch) & 0xffffffff00000000) >> 16) +sint recv_ucast_pn_decache(union recv_frame *precv_frame, struct stainfo_rxcache *prxcache); +sint recv_ucast_pn_decache(union recv_frame *precv_frame, struct stainfo_rxcache *prxcache) +{ + _adapter *padapter = precv_frame->u.hdr.adapter; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + u8 *pdata = precv_frame->u.hdr.rx_data; + u32 data_len = precv_frame->u.hdr.len; + sint tid = precv_frame->u.hdr.attrib.priority; + u64 tmp_iv_hdr = 0; + u64 curr_pn = 0, pkt_pn = 0; + + if (tid > 15) + return _FAIL; + + if (pattrib->encrypt == _AES_) { + tmp_iv_hdr = le64_to_cpu(*(u64*)(pdata + pattrib->hdrlen)); + pkt_pn = CCMPH_2_PN(tmp_iv_hdr); + + tmp_iv_hdr = le64_to_cpu(*(u64*)prxcache->iv[tid]); + curr_pn = CCMPH_2_PN(tmp_iv_hdr); + + if (!VALID_PN_CHK(pkt_pn, curr_pn)) { + /* return _FAIL; */ + } else + _rtw_memcpy(prxcache->iv[tid], (pdata + pattrib->hdrlen), sizeof(prxcache->iv[tid])); + } + + return _SUCCESS; +} + +sint recv_bcast_pn_decache(union recv_frame *precv_frame); +sint recv_bcast_pn_decache(union recv_frame *precv_frame) +{ + _adapter *padapter = precv_frame->u.hdr.adapter; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + u8 *pdata = precv_frame->u.hdr.rx_data; + u32 data_len = precv_frame->u.hdr.len; + u64 tmp_iv_hdr = 0; + u64 curr_pn = 0, pkt_pn = 0; + u8 key_id; + + if ((pattrib->encrypt == _AES_) && + (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)) { + + tmp_iv_hdr = le64_to_cpu(*(u64*)(pdata + pattrib->hdrlen)); + key_id = CCMPH_2_KEYID(tmp_iv_hdr); + pkt_pn = CCMPH_2_PN(tmp_iv_hdr); + + curr_pn = le64_to_cpu(*(u64*)psecuritypriv->iv_seq[key_id]); + curr_pn &= 0x0000ffffffffffff; + + if (!VALID_PN_CHK(pkt_pn, curr_pn)) + return _FAIL; + + *(u64*)psecuritypriv->iv_seq[key_id] = cpu_to_le64(pkt_pn); + } + + return _SUCCESS; +} + +void process_pwrbit_data(_adapter *padapter, union recv_frame *precv_frame); +void process_pwrbit_data(_adapter *padapter, union recv_frame *precv_frame) +{ +#ifdef CONFIG_AP_MODE + unsigned char pwrbit; + u8 *ptr = precv_frame->u.hdr.rx_data; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta = NULL; + + psta = rtw_get_stainfo(pstapriv, pattrib->src); + + pwrbit = GetPwrMgt(ptr); + + if (psta) { + if (pwrbit) { + if (!(psta->state & WIFI_SLEEP_STATE)) { + /* psta->state |= WIFI_SLEEP_STATE; */ + /* pstapriv->sta_dz_bitmap |= BIT(psta->aid); */ + + stop_sta_xmit(padapter, psta); + + /* RTW_INFO("to sleep, sta_dz_bitmap=%x\n", pstapriv->sta_dz_bitmap); */ + } + } else { + if (psta->state & WIFI_SLEEP_STATE) { + /* psta->state ^= WIFI_SLEEP_STATE; */ + /* pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); */ + + wakeup_sta_to_xmit(padapter, psta); + + /* RTW_INFO("to wakeup, sta_dz_bitmap=%x\n", pstapriv->sta_dz_bitmap); */ + } + } + + } + +#endif +} + +void process_wmmps_data(_adapter *padapter, union recv_frame *precv_frame); +void process_wmmps_data(_adapter *padapter, union recv_frame *precv_frame) +{ +#ifdef CONFIG_AP_MODE + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta = NULL; + + psta = rtw_get_stainfo(pstapriv, pattrib->src); + + if (!psta) + return; + +#ifdef CONFIG_TDLS + if (!(psta->tdls_sta_state & TDLS_LINKED_STATE)) { +#endif /* CONFIG_TDLS */ + + if (!psta->qos_option) + return; + + if (!(psta->qos_info & 0xf)) + return; + +#ifdef CONFIG_TDLS + } +#endif /* CONFIG_TDLS */ + + if (psta->state & WIFI_SLEEP_STATE) { + u8 wmmps_ac = 0; + + switch (pattrib->priority) { + case 1: + case 2: + wmmps_ac = psta->uapsd_bk & BIT(1); + break; + case 4: + case 5: + wmmps_ac = psta->uapsd_vi & BIT(1); + break; + case 6: + case 7: + wmmps_ac = psta->uapsd_vo & BIT(1); + break; + case 0: + case 3: + default: + wmmps_ac = psta->uapsd_be & BIT(1); + break; + } + + if (wmmps_ac) { + if (psta->sleepq_ac_len > 0) { + /* process received triggered frame */ + xmit_delivery_enabled_frames(padapter, psta); + } else { + /* issue one qos null frame with More data bit = 0 and the EOSP bit set (=1) */ + issue_qos_nulldata(padapter, psta->hwaddr, (u16)pattrib->priority, 0, 0); + } + } + + } + + +#endif + +} + +#ifdef CONFIG_TDLS +sint OnTDLS(_adapter *adapter, union recv_frame *precv_frame) +{ + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + sint ret = _SUCCESS; + u8 *paction = get_recvframe_data(precv_frame); + u8 category_field = 1; +#ifdef CONFIG_WFD + u8 WFA_OUI[3] = { 0x50, 0x6f, 0x9a }; +#endif /* CONFIG_WFD */ + struct tdls_info *ptdlsinfo = &(adapter->tdlsinfo); + + /* point to action field */ + paction += pattrib->hdrlen + + pattrib->iv_len + + SNAP_SIZE + + ETH_TYPE_LEN + + PAYLOAD_TYPE_LEN + + category_field; + + RTW_INFO("[TDLS] Recv %s from "MAC_FMT" with SeqNum = %d\n", rtw_tdls_action_txt(*paction), MAC_ARG(pattrib->src), GetSequence(get_recvframe_data(precv_frame))); + + if (hal_chk_wl_func(adapter, WL_FUNC_TDLS) == _FALSE) { + RTW_INFO("Ignore tdls frame since hal doesn't support tdls\n"); + ret = _FAIL; + return ret; + } + + if (ptdlsinfo->tdls_enable == _FALSE) { + RTW_INFO("recv tdls frame, " + "but tdls haven't enabled\n"); + ret = _FAIL; + return ret; + } + + switch (*paction) { + case TDLS_SETUP_REQUEST: + ret = On_TDLS_Setup_Req(adapter, precv_frame); + break; + case TDLS_SETUP_RESPONSE: + ret = On_TDLS_Setup_Rsp(adapter, precv_frame); + break; + case TDLS_SETUP_CONFIRM: + ret = On_TDLS_Setup_Cfm(adapter, precv_frame); + break; + case TDLS_TEARDOWN: + ret = On_TDLS_Teardown(adapter, precv_frame); + break; + case TDLS_DISCOVERY_REQUEST: + ret = On_TDLS_Dis_Req(adapter, precv_frame); + break; + case TDLS_PEER_TRAFFIC_INDICATION: + ret = On_TDLS_Peer_Traffic_Indication(adapter, precv_frame); + break; + case TDLS_PEER_TRAFFIC_RESPONSE: + ret = On_TDLS_Peer_Traffic_Rsp(adapter, precv_frame); + break; +#ifdef CONFIG_TDLS_CH_SW + case TDLS_CHANNEL_SWITCH_REQUEST: + ret = On_TDLS_Ch_Switch_Req(adapter, precv_frame); + break; + case TDLS_CHANNEL_SWITCH_RESPONSE: + ret = On_TDLS_Ch_Switch_Rsp(adapter, precv_frame); + break; +#endif +#ifdef CONFIG_WFD + /* First byte of WFA OUI */ + case 0x50: + if (_rtw_memcmp(WFA_OUI, paction, 3)) { + /* Probe request frame */ + if (*(paction + 3) == 0x04) { + /* WFDTDLS: for sigma test, do not setup direct link automatically */ + ptdlsinfo->dev_discovered = _TRUE; + RTW_INFO("recv tunneled probe request frame\n"); + issue_tunneled_probe_rsp(adapter, precv_frame); + } + /* Probe response frame */ + if (*(paction + 3) == 0x05) { + /* WFDTDLS: for sigma test, do not setup direct link automatically */ + ptdlsinfo->dev_discovered = _TRUE; + RTW_INFO("recv tunneled probe response frame\n"); + } + } + break; +#endif /* CONFIG_WFD */ + default: + RTW_INFO("receive TDLS frame %d but not support\n", *paction); + ret = _FAIL; + break; + } + +exit: + return ret; + +} +#endif /* CONFIG_TDLS */ + +void count_rx_stats(_adapter *padapter, union recv_frame *prframe, struct sta_info *sta); +void count_rx_stats(_adapter *padapter, union recv_frame *prframe, struct sta_info *sta) +{ + int sz; + struct sta_info *psta = NULL; + struct stainfo_stats *pstats = NULL; + struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; + struct recv_priv *precvpriv = &padapter->recvpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + sz = get_recvframe_len(prframe); + precvpriv->rx_bytes += sz; + + padapter->mlmepriv.LinkDetectInfo.NumRxOkInPeriod++; + + if ((!MacAddr_isBcst(pattrib->dst)) && (!IS_MCAST(pattrib->dst))) + padapter->mlmepriv.LinkDetectInfo.NumRxUnicastOkInPeriod++; + + if (sta) + psta = sta; + else + psta = prframe->u.hdr.psta; + + if (psta) { + pstats = &psta->sta_stats; + + pstats->rx_data_pkts++; + pstats->rx_bytes += sz; + + pstats->rxratecnt[pattrib->data_rate]++; + /*record rx packets for every tid*/ + pstats->rx_data_qos_pkts[pattrib->priority]++; + +#ifdef CONFIG_TDLS + if (psta->tdls_sta_state & TDLS_LINKED_STATE) { + struct sta_info *pap_sta = NULL; + pap_sta = rtw_get_stainfo(&padapter->stapriv, get_bssid(&padapter->mlmepriv)); + if (pap_sta) { + pstats = &pap_sta->sta_stats; + pstats->rx_data_pkts++; + pstats->rx_bytes += sz; + } + } +#endif /* CONFIG_TDLS */ + } + +#ifdef CONFIG_CHECK_LEAVE_LPS + traffic_check_for_leave_lps(padapter, _FALSE, 0); +#endif /* CONFIG_LPS */ + +} + +sint sta2sta_data_frame( + _adapter *adapter, + union recv_frame *precv_frame, + struct sta_info **psta +); +sint sta2sta_data_frame( + _adapter *adapter, + union recv_frame *precv_frame, + struct sta_info **psta +) +{ + u8 *ptr = precv_frame->u.hdr.rx_data; + sint ret = _SUCCESS; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + u8 *mybssid = get_bssid(pmlmepriv); + u8 *myhwaddr = adapter_mac_addr(adapter); + u8 *sta_addr = NULL; + sint bmcast = IS_MCAST(pattrib->dst); + +#ifdef CONFIG_TDLS + struct tdls_info *ptdlsinfo = &adapter->tdlsinfo; +#ifdef CONFIG_TDLS_CH_SW + struct tdls_ch_switch *pchsw_info = &ptdlsinfo->chsw_info; +#endif + struct sta_info *ptdls_sta = NULL; + u8 *psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE; + /* frame body located after [+2]: ether-type, [+1]: payload type */ + u8 *pframe_body = psnap_type + 2 + 1; +#endif + + + /* RTW_INFO("[%s] %d, seqnum:%d\n", __FUNCTION__, __LINE__, pattrib->seq_num); */ + + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) { + + /* filter packets that SA is myself or multicast or broadcast */ + if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { + ret = _FAIL; + goto exit; + } + + if ((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) { + ret = _FAIL; + goto exit; + } + + if (_rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || + _rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || + (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN))) { + ret = _FAIL; + goto exit; + } + + sta_addr = pattrib->src; + + } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) { +#ifdef CONFIG_TDLS + + /* direct link data transfer */ + if (ptdlsinfo->link_established == _TRUE) { + ptdls_sta = rtw_get_stainfo(pstapriv, pattrib->src); + if (ptdls_sta == NULL) { + ret = _FAIL; + goto exit; + } else if (ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE) { + /* filter packets that SA is myself or multicast or broadcast */ + if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { + ret = _FAIL; + goto exit; + } + /* da should be for me */ + if ((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) { + ret = _FAIL; + goto exit; + } + /* check BSSID */ + if (_rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || + _rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || + (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN))) { + ret = _FAIL; + goto exit; + } + +#ifdef CONFIG_TDLS_CH_SW + if (ATOMIC_READ(&pchsw_info->chsw_on) == _TRUE) { + if (adapter->mlmeextpriv.cur_channel != rtw_get_oper_ch(adapter)) { + pchsw_info->ch_sw_state |= TDLS_PEER_AT_OFF_STATE; + if (!(pchsw_info->ch_sw_state & TDLS_CH_SW_INITIATOR_STATE)) + _cancel_timer_ex(&ptdls_sta->ch_sw_timer); + /* On_TDLS_Peer_Traffic_Rsp(adapter, precv_frame); */ + } + } +#endif + + /* process UAPSD tdls sta */ + process_pwrbit_data(adapter, precv_frame); + + /* if NULL-frame, check pwrbit */ + if ((get_frame_sub_type(ptr) & WIFI_DATA_NULL) == WIFI_DATA_NULL) { + /* NULL-frame with pwrbit=1, buffer_STA should buffer frames for sleep_STA */ + if (GetPwrMgt(ptr)) { + /* it would be triggered when we are off channel and receiving NULL DATA */ + /* we can confirm that peer STA is at off channel */ + RTW_INFO("TDLS: recv peer null frame with pwr bit 1\n"); + /* ptdls_sta->tdls_sta_state|=TDLS_PEER_SLEEP_STATE; */ + } + + /* TODO: Updated BSSID's seq. */ + /* RTW_INFO("drop Null Data\n"); */ + ptdls_sta->tdls_sta_state &= ~(TDLS_WAIT_PTR_STATE); + ret = _FAIL; + goto exit; + } + + /* receive some of all TDLS management frames, process it at ON_TDLS */ + if (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_TDLS, 2)) { + ret = OnTDLS(adapter, precv_frame); + goto exit; + } + + if ((get_frame_sub_type(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) + process_wmmps_data(adapter, precv_frame); + + ptdls_sta->tdls_sta_state &= ~(TDLS_WAIT_PTR_STATE); + + } + + sta_addr = pattrib->src; + + } else +#endif /* CONFIG_TDLS */ + { + /* For Station mode, sa and bssid should always be BSSID, and DA is my mac-address */ + if (!_rtw_memcmp(pattrib->bssid, pattrib->src, ETH_ALEN)) { + ret = _FAIL; + goto exit; + } + + sta_addr = pattrib->bssid; + } + + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { + if (bmcast) { + /* For AP mode, if DA == MCAST, then BSSID should be also MCAST */ + if (!IS_MCAST(pattrib->bssid)) { + ret = _FAIL; + goto exit; + } + } else { /* not mc-frame */ + /* For AP mode, if DA is non-MCAST, then it must be BSSID, and bssid == BSSID */ + if (!_rtw_memcmp(pattrib->bssid, pattrib->dst, ETH_ALEN)) { + ret = _FAIL; + goto exit; + } + + sta_addr = pattrib->src; + } + + } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) { + _rtw_memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); + _rtw_memcpy(pattrib->src, get_addr2_ptr(ptr), ETH_ALEN); + _rtw_memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); + _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + sta_addr = mybssid; + } else + ret = _FAIL; + + + + if (bmcast) + *psta = rtw_get_bcmc_stainfo(adapter); + else + *psta = rtw_get_stainfo(pstapriv, sta_addr); /* get ap_info */ + +#ifdef CONFIG_TDLS + if (ptdls_sta != NULL) + *psta = ptdls_sta; +#endif /* CONFIG_TDLS */ + + if (*psta == NULL) { +#ifdef CONFIG_MP_INCLUDED + if (adapter->registrypriv.mp_mode == 1) { + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) + adapter->mppriv.rx_pktloss++; + } +#endif + ret = _FAIL; + goto exit; + } + +exit: + return ret; + +} + +sint ap2sta_data_frame( + _adapter *adapter, + union recv_frame *precv_frame, + struct sta_info **psta); +sint ap2sta_data_frame( + _adapter *adapter, + union recv_frame *precv_frame, + struct sta_info **psta) +{ + u8 *ptr = precv_frame->u.hdr.rx_data; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + sint ret = _SUCCESS; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + u8 *mybssid = get_bssid(pmlmepriv); + u8 *myhwaddr = adapter_mac_addr(adapter); + sint bmcast = IS_MCAST(pattrib->dst); + + + if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) + && (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE + || check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == _TRUE) + ) { + + /* filter packets that SA is myself or multicast or broadcast */ + if (_rtw_memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s SA="MAC_FMT", myhwaddr="MAC_FMT"\n", + __FUNCTION__, MAC_ARG(pattrib->src), MAC_ARG(myhwaddr)); +#endif + ret = _FAIL; + goto exit; + } + + /* da should be for me */ + if ((!_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s DA="MAC_FMT"\n", __func__, MAC_ARG(pattrib->dst)); +#endif + ret = _FAIL; + goto exit; + } + + + /* check BSSID */ + if (_rtw_memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || + _rtw_memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || + (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN))) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s BSSID="MAC_FMT", mybssid="MAC_FMT"\n", + __func__, MAC_ARG(pattrib->bssid), MAC_ARG(mybssid)); +#endif + + if (!bmcast) { + RTW_INFO(ADPT_FMT" -issue_deauth to the nonassociated ap=" MAC_FMT " for the reason(7)\n", ADPT_ARG(adapter), MAC_ARG(pattrib->bssid)); + issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + } + + ret = _FAIL; + goto exit; + } + + if (bmcast) + *psta = rtw_get_bcmc_stainfo(adapter); + else + *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get ap_info */ + + if (*psta == NULL) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s can't get psta under STATION_MODE ; drop pkt\n", __FUNCTION__); +#endif + ret = _FAIL; + goto exit; + } + + /*if ((get_frame_sub_type(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { + } + */ + + if (get_frame_sub_type(ptr) & BIT(6)) { + /* No data, will not indicate to upper layer, temporily count it here */ + count_rx_stats(adapter, precv_frame, *psta); + ret = RTW_RX_HANDLED; + goto exit; + } + + } else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) && + (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) { + _rtw_memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); + _rtw_memcpy(pattrib->src, get_addr2_ptr(ptr), ETH_ALEN); + _rtw_memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); + _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + + *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */ + if (*psta == NULL) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s can't get psta under WIFI_MP_STATE ; drop pkt\n", __FUNCTION__); +#endif + ret = _FAIL; + goto exit; + } + + + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { + /* Special case */ + ret = RTW_RX_HANDLED; + goto exit; + } else { + if (_rtw_memcmp(myhwaddr, pattrib->dst, ETH_ALEN) && (!bmcast)) { + *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */ + if (*psta == NULL) { + + /* for AP multicast issue , modify by yiwei */ + static u32 send_issue_deauth_time = 0; + + /* RTW_INFO("After send deauth , %u ms has elapsed.\n", rtw_get_passing_time_ms(send_issue_deauth_time)); */ + + if (rtw_get_passing_time_ms(send_issue_deauth_time) > 10000 || send_issue_deauth_time == 0) { + send_issue_deauth_time = rtw_get_current_time(); + + RTW_INFO("issue_deauth to the ap=" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->bssid)); + + issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + } + } + } + + ret = _FAIL; +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s fw_state:0x%x\n", __FUNCTION__, get_fwstate(pmlmepriv)); +#endif + } + +exit: + + + return ret; + +} + +sint sta2ap_data_frame( + _adapter *adapter, + union recv_frame *precv_frame, + struct sta_info **psta); +sint sta2ap_data_frame( + _adapter *adapter, + union recv_frame *precv_frame, + struct sta_info **psta) +{ + u8 *ptr = precv_frame->u.hdr.rx_data; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + unsigned char *mybssid = get_bssid(pmlmepriv); + sint ret = _SUCCESS; + + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { + /* For AP mode, RA=BSSID, TX=STA(SRC_ADDR), A3=DST_ADDR */ + if (!_rtw_memcmp(pattrib->bssid, mybssid, ETH_ALEN)) { + ret = _FAIL; + goto exit; + } + + *psta = rtw_get_stainfo(pstapriv, pattrib->src); + if (*psta == NULL) { + #ifdef CONFIG_DFS_MASTER + struct rf_ctl_t *rfctl = adapter_to_rfctl(adapter); + + /* prevent RX tasklet blocks cmd_thread */ + if (rfctl->radar_detected == 1) + goto bypass_deauth7; + #endif + + RTW_INFO("issue_deauth to sta=" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->src)); + + issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + +#ifdef CONFIG_DFS_MASTER +bypass_deauth7: +#endif + ret = RTW_RX_HANDLED; + goto exit; + } + + process_pwrbit_data(adapter, precv_frame); + + if ((get_frame_sub_type(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) + process_wmmps_data(adapter, precv_frame); + + if (get_frame_sub_type(ptr) & BIT(6)) { + /* No data, will not indicate to upper layer, temporily count it here */ + count_rx_stats(adapter, precv_frame, *psta); + ret = RTW_RX_HANDLED; + goto exit; + } + } else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) && + (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) { + /* RTW_INFO("%s ,in WIFI_MP_STATE\n",__func__); */ + _rtw_memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); + _rtw_memcpy(pattrib->src, get_addr2_ptr(ptr), ETH_ALEN); + _rtw_memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); + _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + + *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */ + if (*psta == NULL) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s can't get psta under WIFI_MP_STATE ; drop pkt\n", __FUNCTION__); +#endif + ret = _FAIL; + goto exit; + } + + } else { + u8 *myhwaddr = adapter_mac_addr(adapter); + if (!_rtw_memcmp(pattrib->ra, myhwaddr, ETH_ALEN)) { + ret = RTW_RX_HANDLED; + goto exit; + } + RTW_INFO("issue_deauth to sta=" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->src)); + issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + ret = RTW_RX_HANDLED; + goto exit; + } + +exit: + + + return ret; + +} + +sint validate_recv_ctrl_frame(_adapter *padapter, union recv_frame *precv_frame); +sint validate_recv_ctrl_frame(_adapter *padapter, union recv_frame *precv_frame) +{ + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *pframe = precv_frame->u.hdr.rx_data; + struct sta_info *psta = NULL; + /* uint len = precv_frame->u.hdr.len; */ + + /* RTW_INFO("+validate_recv_ctrl_frame\n"); */ + + if (GetFrameType(pframe) != WIFI_CTRL_TYPE) + return _FAIL; + + /* receive the frames that ra(a1) is my address */ + if (!_rtw_memcmp(GetAddr1Ptr(pframe), adapter_mac_addr(padapter), ETH_ALEN)) + return _FAIL; + + psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(pframe)); + if (psta == NULL) + return _FAIL; + + /* for rx pkt statistics */ + psta->sta_stats.rx_ctrl_pkts++; + + /* only handle ps-poll */ + if (get_frame_sub_type(pframe) == WIFI_PSPOLL) { +#ifdef CONFIG_AP_MODE + u16 aid; + u8 wmmps_ac = 0; + + aid = GetAid(pframe); + if (psta->aid != aid) + return _FAIL; + + switch (pattrib->priority) { + case 1: + case 2: + wmmps_ac = psta->uapsd_bk & BIT(0); + break; + case 4: + case 5: + wmmps_ac = psta->uapsd_vi & BIT(0); + break; + case 6: + case 7: + wmmps_ac = psta->uapsd_vo & BIT(0); + break; + case 0: + case 3: + default: + wmmps_ac = psta->uapsd_be & BIT(0); + break; + } + + if (wmmps_ac) + return _FAIL; + + if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { + RTW_INFO("%s alive check-rx ps-poll\n", __func__); + psta->expire_to = pstapriv->expire_to; + psta->state ^= WIFI_STA_ALIVE_CHK_STATE; + } + + if ((psta->state & WIFI_SLEEP_STATE) && (pstapriv->sta_dz_bitmap & BIT(psta->aid))) { + _irqL irqL; + _list *xmitframe_plist, *xmitframe_phead; + struct xmit_frame *pxmitframe = NULL; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + /* _enter_critical_bh(&psta->sleep_q.lock, &irqL); */ + _enter_critical_bh(&pxmitpriv->lock, &irqL); + + xmitframe_phead = get_list_head(&psta->sleep_q); + xmitframe_plist = get_next(xmitframe_phead); + + if ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) { + pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); + + xmitframe_plist = get_next(xmitframe_plist); + + rtw_list_delete(&pxmitframe->list); + + psta->sleepq_len--; + + if (psta->sleepq_len > 0) + pxmitframe->attrib.mdata = 1; + else + pxmitframe->attrib.mdata = 0; + + pxmitframe->attrib.triggered = 1; + + /* RTW_INFO("handling ps-poll, q_len=%d, tim=%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */ + +#if 0 + _exit_critical_bh(&psta->sleep_q.lock, &irqL); + if (rtw_hal_xmit(padapter, pxmitframe) == _TRUE) + rtw_os_xmit_complete(padapter, pxmitframe); + _enter_critical_bh(&psta->sleep_q.lock, &irqL); +#endif + rtw_hal_xmitframe_enqueue(padapter, pxmitframe); + + if (psta->sleepq_len == 0) { + pstapriv->tim_bitmap &= ~BIT(psta->aid); + + /* RTW_INFO("after handling ps-poll, tim=%x\n", pstapriv->tim_bitmap); */ + + /* upate BCN for TIM IE */ + /* update_BCNTIM(padapter); */ + update_beacon(padapter, _TIM_IE_, NULL, _TRUE); + } + + /* _exit_critical_bh(&psta->sleep_q.lock, &irqL); */ + _exit_critical_bh(&pxmitpriv->lock, &irqL); + + } else { + /* _exit_critical_bh(&psta->sleep_q.lock, &irqL); */ + _exit_critical_bh(&pxmitpriv->lock, &irqL); + + /* RTW_INFO("no buffered packets to xmit\n"); */ + if (pstapriv->tim_bitmap & BIT(psta->aid)) { + if (psta->sleepq_len == 0) { + RTW_INFO("no buffered packets to xmit\n"); + + /* issue nulldata with More data bit = 0 to indicate we have no buffered packets */ + issue_nulldata_in_interrupt(padapter, psta->hwaddr, 0); + } else { + RTW_INFO("error!psta->sleepq_len=%d\n", psta->sleepq_len); + psta->sleepq_len = 0; + } + + pstapriv->tim_bitmap &= ~BIT(psta->aid); + + /* upate BCN for TIM IE */ + /* update_BCNTIM(padapter); */ + update_beacon(padapter, _TIM_IE_, NULL, _TRUE); + } + } + } +#endif /* CONFIG_AP_MODE */ + } else if (get_frame_sub_type(pframe) == WIFI_NDPA) { +#ifdef CONFIG_BEAMFORMING + beamforming_get_ndpa_frame(padapter, precv_frame); +#endif/*CONFIG_BEAMFORMING*/ + } + + return _FAIL; + +} + +union recv_frame *recvframe_chk_defrag(PADAPTER padapter, union recv_frame *precv_frame); +sint validate_recv_mgnt_frame(PADAPTER padapter, union recv_frame *precv_frame); +sint validate_recv_mgnt_frame(PADAPTER padapter, union recv_frame *precv_frame) +{ + /* struct mlme_priv *pmlmepriv = &adapter->mlmepriv; */ + + +#if 0 + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { +#ifdef CONFIG_NATIVEAP_MLME + mgt_dispatcher(padapter, precv_frame); +#else + rtw_hostapd_mlme_rx(padapter, precv_frame); +#endif + } else + mgt_dispatcher(padapter, precv_frame); +#endif + + precv_frame = recvframe_chk_defrag(padapter, precv_frame); + if (precv_frame == NULL) { + return _SUCCESS; + } + + { + /* for rx pkt statistics */ + struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, get_addr2_ptr(precv_frame->u.hdr.rx_data)); + if (psta) { + psta->sta_stats.rx_mgnt_pkts++; + if (get_frame_sub_type(precv_frame->u.hdr.rx_data) == WIFI_BEACON) + psta->sta_stats.rx_beacon_pkts++; + else if (get_frame_sub_type(precv_frame->u.hdr.rx_data) == WIFI_PROBEREQ) + psta->sta_stats.rx_probereq_pkts++; + else if (get_frame_sub_type(precv_frame->u.hdr.rx_data) == WIFI_PROBERSP) { + if (_rtw_memcmp(adapter_mac_addr(padapter), GetAddr1Ptr(precv_frame->u.hdr.rx_data), ETH_ALEN) == _TRUE) + psta->sta_stats.rx_probersp_pkts++; + else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data)) + || is_multicast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data))) + psta->sta_stats.rx_probersp_bm_pkts++; + else + psta->sta_stats.rx_probersp_uo_pkts++; + } + } + } + +#ifdef CONFIG_INTEL_PROXIM + if (padapter->proximity.proxim_on == _TRUE) { + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct recv_stat *prxstat = (struct recv_stat *) precv_frame->u.hdr.rx_head ; + u8 *pda, *psa, *pbssid, *ptr; + ptr = precv_frame->u.hdr.rx_data; + pda = get_da(ptr); + psa = get_sa(ptr); + pbssid = get_hdr_bssid(ptr); + + + _rtw_memcpy(pattrib->dst, pda, ETH_ALEN); + _rtw_memcpy(pattrib->src, psa, ETH_ALEN); + + _rtw_memcpy(pattrib->bssid, pbssid, ETH_ALEN); + + switch (pattrib->to_fr_ds) { + case 0: + _rtw_memcpy(pattrib->ra, pda, ETH_ALEN); + _rtw_memcpy(pattrib->ta, psa, ETH_ALEN); + break; + + case 1: + _rtw_memcpy(pattrib->ra, pda, ETH_ALEN); + _rtw_memcpy(pattrib->ta, pbssid, ETH_ALEN); + break; + + case 2: + _rtw_memcpy(pattrib->ra, pbssid, ETH_ALEN); + _rtw_memcpy(pattrib->ta, psa, ETH_ALEN); + break; + + case 3: + _rtw_memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); + _rtw_memcpy(pattrib->ta, get_addr2_ptr(ptr), ETH_ALEN); + break; + + default: + break; + + } + pattrib->priority = 0; + pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 30 : 24; + + padapter->proximity.proxim_rx(padapter, precv_frame); + } +#endif + mgt_dispatcher(padapter, precv_frame); + + return _SUCCESS; + +} + +sint validate_recv_data_frame(_adapter *adapter, union recv_frame *precv_frame); +sint validate_recv_data_frame(_adapter *adapter, union recv_frame *precv_frame) +{ + u8 bretry; + u8 *psa, *pda, *pbssid; + struct sta_info *psta = NULL; + u8 *ptr = precv_frame->u.hdr.rx_data; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct sta_priv *pstapriv = &adapter->stapriv; + struct security_priv *psecuritypriv = &adapter->securitypriv; + sint ret = _SUCCESS; + + + bretry = GetRetry(ptr); + pda = get_da(ptr); + psa = get_sa(ptr); + pbssid = get_hdr_bssid(ptr); + + if (pbssid == NULL) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s pbssid == NULL\n", __func__); +#endif + ret = _FAIL; + goto exit; + } + + _rtw_memcpy(pattrib->dst, pda, ETH_ALEN); + _rtw_memcpy(pattrib->src, psa, ETH_ALEN); + + _rtw_memcpy(pattrib->bssid, pbssid, ETH_ALEN); + + switch (pattrib->to_fr_ds) { + case 0: + _rtw_memcpy(pattrib->ra, pda, ETH_ALEN); + _rtw_memcpy(pattrib->ta, psa, ETH_ALEN); + ret = sta2sta_data_frame(adapter, precv_frame, &psta); + break; + + case 1: + _rtw_memcpy(pattrib->ra, pda, ETH_ALEN); + _rtw_memcpy(pattrib->ta, pbssid, ETH_ALEN); + ret = ap2sta_data_frame(adapter, precv_frame, &psta); + break; + + case 2: + _rtw_memcpy(pattrib->ra, pbssid, ETH_ALEN); + _rtw_memcpy(pattrib->ta, psa, ETH_ALEN); + ret = sta2ap_data_frame(adapter, precv_frame, &psta); + break; + + case 3: + _rtw_memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); + _rtw_memcpy(pattrib->ta, get_addr2_ptr(ptr), ETH_ALEN); + ret = _FAIL; + break; + + default: + ret = _FAIL; + break; + + } + + if (ret == _FAIL) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s case:%d, res:%d\n", __FUNCTION__, pattrib->to_fr_ds, ret); +#endif + goto exit; + } else if (ret == RTW_RX_HANDLED) + goto exit; + + + if (psta == NULL) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s psta == NULL\n", __func__); +#endif + ret = _FAIL; + goto exit; + } + + /* psta->rssi = prxcmd->rssi; */ + /* psta->signal_quality= prxcmd->sq; */ + precv_frame->u.hdr.psta = psta; + + + pattrib->amsdu = 0; + pattrib->ack_policy = 0; + /* parsing QC field */ + if (pattrib->qos == 1) { + pattrib->priority = GetPriority((ptr + 24)); + pattrib->ack_policy = GetAckpolicy((ptr + 24)); + pattrib->amsdu = GetAMsdu((ptr + 24)); + pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 32 : 26; + + if (pattrib->priority != 0 && pattrib->priority != 3) + adapter->recvpriv.is_any_non_be_pkts = _TRUE; + else + adapter->recvpriv.is_any_non_be_pkts = _FALSE; + } else { + pattrib->priority = 0; + pattrib->hdrlen = pattrib->to_fr_ds == 3 ? 30 : 24; + } + + + if (pattrib->order) /* HT-CTRL 11n */ + pattrib->hdrlen += 4; + + precv_frame->u.hdr.preorder_ctrl = &psta->recvreorder_ctrl[pattrib->priority]; + + /* decache, drop duplicate recv packets */ + if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) == _FAIL) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s recv_decache return _FAIL\n", __func__); +#endif + ret = _FAIL; + goto exit; + } + + if (!IS_MCAST(pattrib->ra)) { + if (recv_ucast_pn_decache(precv_frame, &psta->sta_recvpriv.rxcache) == _FAIL) { + #ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s recv_ucast_pn_decache return _FAIL\n", __func__); + #endif + ret = _FAIL; + goto exit; + } + } else { + if (recv_bcast_pn_decache(precv_frame) == _FAIL) { + #ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME "FUNC_ADPT_FMT" recv_bcast_pn_decache _FAIL for invalid PN!\n" + , FUNC_ADPT_ARG(adapter)); + #endif + ret = _FAIL; + goto exit; + } + } + + if (pattrib->privacy) { + + +#ifdef CONFIG_TDLS + if ((psta->tdls_sta_state & TDLS_LINKED_STATE) && (psta->dot118021XPrivacy == _AES_)) + pattrib->encrypt = psta->dot118021XPrivacy; + else +#endif /* CONFIG_TDLS */ + GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, IS_MCAST(pattrib->ra)); + + + SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt); + } else { + pattrib->encrypt = 0; + pattrib->iv_len = pattrib->icv_len = 0; + } + +exit: + + + return ret; +} + +#ifdef CONFIG_IEEE80211W +static sint validate_80211w_mgmt(_adapter *adapter, union recv_frame *precv_frame) +{ + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + u8 *ptr = precv_frame->u.hdr.rx_data; + struct sta_info *psta; + struct sta_priv *pstapriv = &adapter->stapriv; + u8 type; + u8 subtype; + + type = GetFrameType(ptr); + subtype = get_frame_sub_type(ptr); /* bit(7)~bit(2) */ + + if (adapter->securitypriv.binstallBIPkey == _TRUE) { + /* unicast management frame decrypt */ + if (pattrib->privacy && !(IS_MCAST(GetAddr1Ptr(ptr))) && + (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC || subtype == WIFI_ACTION)) { + u8 *ppp, *mgmt_DATA; + u32 data_len = 0; + ppp = get_addr2_ptr(ptr); + + pattrib->bdecrypted = 0; + pattrib->encrypt = _AES_; + pattrib->hdrlen = sizeof(struct rtw_ieee80211_hdr_3addr); + /* set iv and icv length */ + SET_ICE_IV_LEN(pattrib->iv_len, pattrib->icv_len, pattrib->encrypt); + _rtw_memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); + _rtw_memcpy(pattrib->ta, get_addr2_ptr(ptr), ETH_ALEN); + /* actual management data frame body */ + data_len = pattrib->pkt_len - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len; + mgmt_DATA = rtw_zmalloc(data_len); + if (mgmt_DATA == NULL) { + RTW_INFO("%s mgmt allocate fail !!!!!!!!!\n", __FUNCTION__); + goto validate_80211w_fail; + } +#if 0 + /* dump the packet content before decrypt */ + { + int pp; + printk("pattrib->pktlen = %d =>", pattrib->pkt_len); + for (pp = 0; pp < pattrib->pkt_len; pp++) + printk(" %02x ", ptr[pp]); + printk("\n"); + } +#endif + + precv_frame = decryptor(adapter, precv_frame); + /* save actual management data frame body */ + _rtw_memcpy(mgmt_DATA, ptr + pattrib->hdrlen + pattrib->iv_len, data_len); + /* overwrite the iv field */ + _rtw_memcpy(ptr + pattrib->hdrlen, mgmt_DATA, data_len); + /* remove the iv and icv length */ + pattrib->pkt_len = pattrib->pkt_len - pattrib->iv_len - pattrib->icv_len; + rtw_mfree(mgmt_DATA, data_len); +#if 0 + /* print packet content after decryption */ + { + int pp; + printk("after decryption pattrib->pktlen = %d @@=>", pattrib->pkt_len); + for (pp = 0; pp < pattrib->pkt_len; pp++) + printk(" %02x ", ptr[pp]); + printk("\n"); + } +#endif + if (!precv_frame) { + RTW_INFO("%s mgmt descrypt fail !!!!!!!!!\n", __FUNCTION__); + goto validate_80211w_fail; + } + } else if (IS_MCAST(GetAddr1Ptr(ptr)) && + (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC)) { + sint BIP_ret = _SUCCESS; + /* verify BIP MME IE of broadcast/multicast de-auth/disassoc packet */ + BIP_ret = rtw_BIP_verify(adapter, (u8 *)precv_frame); + if (BIP_ret == _FAIL) { + /* RTW_INFO("802.11w BIP verify fail\n"); */ + goto validate_80211w_fail; + } else if (BIP_ret == RTW_RX_HANDLED) { + RTW_INFO("802.11w recv none protected packet\n"); + /* drop pkt, don't issue sa query request */ + /* issue_action_SA_Query(adapter, NULL, 0, 0, 0); */ + goto validate_80211w_fail; + } + } /* 802.11w protect */ + else { + psta = rtw_get_stainfo(pstapriv, get_addr2_ptr(ptr)); + + if (subtype == WIFI_ACTION && psta && psta->bpairwise_key_installed == _TRUE) { + /* according 802.11-2012 standard, these five types are not robust types */ + if (ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_PUBLIC && + ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_HT && + ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_UNPROTECTED_WNM && + ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_SELF_PROTECTED && + ptr[WLAN_HDR_A3_LEN] != RTW_WLAN_CATEGORY_P2P) { + RTW_INFO("action frame category=%d should robust\n", ptr[WLAN_HDR_A3_LEN]); + goto validate_80211w_fail; + } + } else if (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC) { + unsigned short reason; + reason = le16_to_cpu(*(unsigned short *)(ptr + WLAN_HDR_A3_LEN)); + RTW_INFO("802.11w recv none protected packet, reason=%d\n", reason); + if (reason == 6 || reason == 7) { + /* issue sa query request */ + issue_action_SA_Query(adapter, NULL, 0, 0, IEEE80211W_RIGHT_KEY); + } + goto validate_80211w_fail; + } + } + } + return _SUCCESS; + +validate_80211w_fail: + return _FAIL; + +} +#endif /* CONFIG_IEEE80211W */ + +static inline void dump_rx_packet(u8 *ptr) +{ + int i; + + RTW_INFO("#############################\n"); + for (i = 0; i < 64; i = i + 8) + RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr + i), + *(ptr + i + 1), *(ptr + i + 2) , *(ptr + i + 3) , *(ptr + i + 4), *(ptr + i + 5), *(ptr + i + 6), *(ptr + i + 7)); + RTW_INFO("#############################\n"); +} + +sint validate_recv_frame(_adapter *adapter, union recv_frame *precv_frame); +sint validate_recv_frame(_adapter *adapter, union recv_frame *precv_frame) +{ + /* shall check frame subtype, to / from ds, da, bssid */ + + /* then call check if rx seq/frag. duplicated. */ + + u8 type; + u8 subtype; + sint retval = _SUCCESS; + + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + + u8 *ptr = precv_frame->u.hdr.rx_data; + u8 ver = (unsigned char)(*ptr) & 0x3 ; +#ifdef CONFIG_FIND_BEST_CHANNEL + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; +#endif + +#ifdef CONFIG_TDLS + struct tdls_info *ptdlsinfo = &adapter->tdlsinfo; +#endif /* CONFIG_TDLS */ +#ifdef CONFIG_WAPI_SUPPORT + PRT_WAPI_T pWapiInfo = &adapter->wapiInfo; + struct recv_frame_hdr *phdr = &precv_frame->u.hdr; + u8 wai_pkt = 0; + u16 sc; + u8 external_len = 0; +#endif + + +#ifdef CONFIG_FIND_BEST_CHANNEL + if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { + int ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, rtw_get_oper_ch(adapter)); + if (ch_set_idx >= 0) + pmlmeext->channel_set[ch_set_idx].rx_count++; + } +#endif + +#ifdef CONFIG_TDLS + if (ptdlsinfo->ch_sensing == 1 && ptdlsinfo->cur_channel != 0) + ptdlsinfo->collect_pkt_num[ptdlsinfo->cur_channel - 1]++; +#endif /* CONFIG_TDLS */ + +#ifdef RTK_DMP_PLATFORM + if (0) { + RTW_INFO("++\n"); + { + int i; + for (i = 0; i < 64; i = i + 8) + RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:", *(ptr + i), + *(ptr + i + 1), *(ptr + i + 2) , *(ptr + i + 3) , *(ptr + i + 4), *(ptr + i + 5), *(ptr + i + 6), *(ptr + i + 7)); + + } + RTW_INFO("--\n"); + } +#endif /* RTK_DMP_PLATFORM */ + + /* add version chk */ + if (ver != 0) { + retval = _FAIL; + DBG_COUNTER(adapter->rx_logs.core_rx_pre_ver_err); + goto exit; + } + + type = GetFrameType(ptr); + subtype = get_frame_sub_type(ptr); /* bit(7)~bit(2) */ + + pattrib->to_fr_ds = get_tofr_ds(ptr); + + pattrib->frag_num = GetFragNum(ptr); + pattrib->seq_num = GetSequence(ptr); + + pattrib->pw_save = GetPwrMgt(ptr); + pattrib->mfrag = GetMFrag(ptr); + pattrib->mdata = GetMData(ptr); + pattrib->privacy = GetPrivacy(ptr); + pattrib->order = GetOrder(ptr); +#ifdef CONFIG_WAPI_SUPPORT + sc = (pattrib->seq_num << 4) | pattrib->frag_num; +#endif + +#if 1 /* Dump rx packets */ + { + u8 bDumpRxPkt = 0; + + rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt)); + if (bDumpRxPkt == 1) /* dump all rx packets */ + dump_rx_packet(ptr); + else if ((bDumpRxPkt == 2) && (type == WIFI_MGT_TYPE)) + dump_rx_packet(ptr); + else if ((bDumpRxPkt == 3) && (type == WIFI_DATA_TYPE)) + dump_rx_packet(ptr); + } +#endif + switch (type) { + case WIFI_MGT_TYPE: /* mgnt */ + DBG_COUNTER(adapter->rx_logs.core_rx_pre_mgmt); +#ifdef CONFIG_IEEE80211W + if (validate_80211w_mgmt(adapter, precv_frame) == _FAIL) { + retval = _FAIL; + DBG_COUNTER(adapter->rx_logs.core_rx_pre_mgmt_err_80211w); + break; + } +#endif /* CONFIG_IEEE80211W */ + + retval = validate_recv_mgnt_frame(adapter, precv_frame); + if (retval == _FAIL) { + DBG_COUNTER(adapter->rx_logs.core_rx_pre_mgmt_err); + } + retval = _FAIL; /* only data frame return _SUCCESS */ + break; + case WIFI_CTRL_TYPE: /* ctrl */ + DBG_COUNTER(adapter->rx_logs.core_rx_pre_ctrl); + retval = validate_recv_ctrl_frame(adapter, precv_frame); + if (retval == _FAIL) { + DBG_COUNTER(adapter->rx_logs.core_rx_pre_ctrl_err); + } + retval = _FAIL; /* only data frame return _SUCCESS */ + break; + case WIFI_DATA_TYPE: /* data */ + DBG_COUNTER(adapter->rx_logs.core_rx_pre_data); +#ifdef CONFIG_WAPI_SUPPORT + if (pattrib->qos) + external_len = 2; + else + external_len = 0; + + wai_pkt = rtw_wapi_is_wai_packet(adapter, ptr); + + phdr->bIsWaiPacket = wai_pkt; + + if (wai_pkt != 0) { + if (sc != adapter->wapiInfo.wapiSeqnumAndFragNum) + adapter->wapiInfo.wapiSeqnumAndFragNum = sc; + else { + retval = _FAIL; + DBG_COUNTER(adapter->rx_logs.core_rx_pre_data_wapi_seq_err); + break; + } + } else { + + if (rtw_wapi_drop_for_key_absent(adapter, get_addr2_ptr(ptr))) { + retval = _FAIL; + WAPI_TRACE(WAPI_RX, "drop for key absent for rx\n"); + DBG_COUNTER(adapter->rx_logs.core_rx_pre_data_wapi_key_err); + break; + } + } + +#endif + + pattrib->qos = (subtype & BIT(7)) ? 1 : 0; + retval = validate_recv_data_frame(adapter, precv_frame); + if (retval == _FAIL) { + struct recv_priv *precvpriv = &adapter->recvpriv; + precvpriv->rx_drop++; + DBG_COUNTER(adapter->rx_logs.core_rx_pre_data_err); + } else if (retval == _SUCCESS) { +#ifdef DBG_RX_DUMP_EAP + u8 bDumpRxPkt; + u16 eth_type; + + /* dump eapol */ + rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt)); + /* get ether_type */ + _rtw_memcpy(ð_type, ptr + pattrib->hdrlen + pattrib->iv_len + LLC_HEADER_SIZE, 2); + eth_type = ntohs((unsigned short) eth_type); + if ((bDumpRxPkt == 4) && (eth_type == 0x888e)) + dump_rx_packet(ptr); +#endif + } else + DBG_COUNTER(adapter->rx_logs.core_rx_pre_data_handled); + break; + default: + DBG_COUNTER(adapter->rx_logs.core_rx_pre_unknown); +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME validate_recv_data_frame fail! type=0x%x\n", type); +#endif + retval = _FAIL; + break; + } + +exit: + + + return retval; +} + + +/* remove the wlanhdr and add the eth_hdr */ +#if 1 + +sint wlanhdr_to_ethhdr(union recv_frame *precvframe); +sint wlanhdr_to_ethhdr(union recv_frame *precvframe) +{ + sint rmv_len; + u16 eth_type, len; + u8 bsnaphdr; + u8 *psnap_type; + struct ieee80211_snap_hdr *psnap; + + sint ret = _SUCCESS; + _adapter *adapter = precvframe->u.hdr.adapter; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + u8 *ptr = get_recvframe_data(precvframe) ; /* point to frame_ctrl field */ + struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib; + + + if (pattrib->encrypt) + recvframe_pull_tail(precvframe, pattrib->icv_len); + + psnap = (struct ieee80211_snap_hdr *)(ptr + pattrib->hdrlen + pattrib->iv_len); + psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE; + /* convert hdr + possible LLC headers into Ethernet header */ + /* eth_type = (psnap_type[0] << 8) | psnap_type[1]; */ + if ((_rtw_memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) && + (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) == _FALSE) && + (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2) == _FALSE)) || + /* eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || */ + _rtw_memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */ + bsnaphdr = _TRUE; + } else { + /* Leave Ethernet header part of hdr and full payload */ + bsnaphdr = _FALSE; + } + + rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0); + len = precvframe->u.hdr.len - rmv_len; + + + _rtw_memcpy(ð_type, ptr + rmv_len, 2); + eth_type = ntohs((unsigned short)eth_type); /* pattrib->ether_type */ + pattrib->eth_type = eth_type; + +#ifdef CONFIG_AUTO_AP_MODE + if (0x8899 == pattrib->eth_type) { + struct sta_info *psta = precvframe->u.hdr.psta; + + RTW_INFO("wlan rx: got eth_type=0x%x\n", pattrib->eth_type); + + if (psta && psta->isrc && psta->pid > 0) { + u16 rx_pid; + + rx_pid = *(u16 *)(ptr + rmv_len + 2); + + RTW_INFO("wlan rx(pid=0x%x): sta("MAC_FMT") pid=0x%x\n", + rx_pid, MAC_ARG(psta->hwaddr), psta->pid); + + if (rx_pid == psta->pid) { + int i; + u16 len = *(u16 *)(ptr + rmv_len + 4); + /* u16 ctrl_type = *(u16*)(ptr+rmv_len+6); */ + + /* RTW_INFO("RC: len=0x%x, ctrl_type=0x%x\n", len, ctrl_type); */ + RTW_INFO("RC: len=0x%x\n", len); + + for (i = 0; i < len; i++) + RTW_INFO("0x%x\n", *(ptr + rmv_len + 6 + i)); + /* RTW_INFO("0x%x\n", *(ptr+rmv_len+8+i)); */ + + RTW_INFO("RC-end\n"); + } + } + } +#endif /* CONFIG_AUTO_AP_MODE */ + + if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE)) { + ptr += rmv_len ; + *ptr = 0x87; + *(ptr + 1) = 0x12; + + eth_type = 0x8712; + /* append rx status for mp test packets */ + ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + 2) - 24); + if (!ptr) { + ret = _FAIL; + goto exiting; + } + _rtw_memcpy(ptr, get_rxmem(precvframe), 24); + ptr += 24; + } else { + ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0))); + if (!ptr) { + ret = _FAIL; + goto exiting; + } + } + + if (ptr) { + _rtw_memcpy(ptr, pattrib->dst, ETH_ALEN); + _rtw_memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN); + + if (!bsnaphdr) { + len = htons(len); + _rtw_memcpy(ptr + 12, &len, 2); + } + } + +exiting: + return ret; + +} + +#else + +sint wlanhdr_to_ethhdr(union recv_frame *precvframe) +{ + sint rmv_len; + u16 eth_type; + u8 bsnaphdr; + u8 *psnap_type; + struct ieee80211_snap_hdr *psnap; + + sint ret = _SUCCESS; + _adapter *adapter = precvframe->u.hdr.adapter; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + u8 *ptr = get_recvframe_data(precvframe) ; /* point to frame_ctrl field */ + struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib; + struct _vlan *pvlan = NULL; + + + psnap = (struct ieee80211_snap_hdr *)(ptr + pattrib->hdrlen + pattrib->iv_len); + psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE; + if (psnap->dsap == 0xaa && psnap->ssap == 0xaa && psnap->ctrl == 0x03) { + if (_rtw_memcmp(psnap->oui, oui_rfc1042, WLAN_IEEE_OUI_LEN)) + bsnaphdr = _TRUE; /* wlan_pkt_format = WLAN_PKT_FORMAT_SNAP_RFC1042; */ + else if (_rtw_memcmp(psnap->oui, SNAP_HDR_APPLETALK_DDP, WLAN_IEEE_OUI_LEN) && + _rtw_memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_DDP, 2)) + bsnaphdr = _TRUE; /* wlan_pkt_format = WLAN_PKT_FORMAT_APPLETALK; */ + else if (_rtw_memcmp(psnap->oui, oui_8021h, WLAN_IEEE_OUI_LEN)) + bsnaphdr = _TRUE; /* wlan_pkt_format = WLAN_PKT_FORMAT_SNAP_TUNNEL; */ + else { + ret = _FAIL; + goto exit; + } + + } else + bsnaphdr = _FALSE; /* wlan_pkt_format = WLAN_PKT_FORMAT_OTHERS; */ + + rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0); + + if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE) { + ptr += rmv_len ; + *ptr = 0x87; + *(ptr + 1) = 0x12; + + /* back to original pointer */ + ptr -= rmv_len; + } + + ptr += rmv_len ; + + _rtw_memcpy(ð_type, ptr, 2); + eth_type = ntohs((unsigned short)eth_type); /* pattrib->ether_type */ + ptr += 2; + + if (pattrib->encrypt) + recvframe_pull_tail(precvframe, pattrib->icv_len); + + if (eth_type == 0x8100) { /* vlan */ + pvlan = (struct _vlan *) ptr; + + /* eth_type = get_vlan_encap_proto(pvlan); */ + /* eth_type = pvlan->h_vlan_encapsulated_proto; */ /* ? */ + rmv_len += 4; + ptr += 4; + } + + if (eth_type == 0x0800) { /* ip */ + /* struct iphdr* piphdr = (struct iphdr*) ptr; */ + /* __u8 tos = (unsigned char)(pattrib->priority & 0xff); */ + + /* piphdr->tos = tos; */ + + } else if (eth_type == 0x8712) { /* append rx status for mp test packets */ + /* ptr -= 16; */ + /* _rtw_memcpy(ptr, get_rxmem(precvframe), 16); */ + } else { +#ifdef PLATFORM_OS_XP + NDIS_PACKET_8021Q_INFO VlanPriInfo; + UINT32 UserPriority = precvframe->u.hdr.attrib.priority; + UINT32 VlanID = (pvlan != NULL ? get_vlan_id(pvlan) : 0); + + VlanPriInfo.Value = /* Get current value. */ + NDIS_PER_PACKET_INFO_FROM_PACKET(precvframe->u.hdr.pkt, Ieee8021QInfo); + + VlanPriInfo.TagHeader.UserPriority = UserPriority; + VlanPriInfo.TagHeader.VlanId = VlanID ; + + VlanPriInfo.TagHeader.CanonicalFormatId = 0; /* Should be zero. */ + VlanPriInfo.TagHeader.Reserved = 0; /* Should be zero. */ + NDIS_PER_PACKET_INFO_FROM_PACKET(precvframe->u.hdr.pkt, Ieee8021QInfo) = VlanPriInfo.Value; +#endif + } + + if (eth_type == 0x8712) { /* append rx status for mp test packets */ + ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + 2) - 24); + _rtw_memcpy(ptr, get_rxmem(precvframe), 24); + ptr += 24; + } else + ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + 2)); + + _rtw_memcpy(ptr, pattrib->dst, ETH_ALEN); + _rtw_memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN); + + eth_type = htons((unsigned short)eth_type) ; + _rtw_memcpy(ptr + 12, ð_type, 2); + +exit: + + + return ret; +} +#endif + + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) +#ifdef PLATFORM_LINUX +static void recvframe_expand_pkt( + PADAPTER padapter, + union recv_frame *prframe) +{ + struct recv_frame_hdr *pfhdr; + _pkt *ppkt; + u8 shift_sz; + u32 alloc_sz; + u8 *ptr; + + + pfhdr = &prframe->u.hdr; + + /* 6 is for IP header 8 bytes alignment in QoS packet case. */ + if (pfhdr->attrib.qos) + shift_sz = 6; + else + shift_sz = 0; + + /* for first fragment packet, need to allocate */ + /* (1536 + RXDESC_SIZE + drvinfo_sz) to reassemble packet */ + /* 8 is for skb->data 8 bytes alignment. + * alloc_sz = _RND(1536 + RXDESC_SIZE + pfhdr->attrib.drvinfosize + shift_sz + 8, 128); */ + alloc_sz = 1664; /* round (1536 + 24 + 32 + shift_sz + 8) to 128 bytes alignment */ + + /* 3 1. alloc new skb */ + /* prepare extra space for 4 bytes alignment */ + ppkt = rtw_skb_alloc(alloc_sz); + + if (!ppkt) + return; /* no way to expand */ + + /* 3 2. Prepare new skb to replace & release old skb */ + /* force ppkt->data at 8-byte alignment address */ + skb_reserve(ppkt, 8 - ((SIZE_PTR)ppkt->data & 7)); + /* force ip_hdr at 8-byte alignment address according to shift_sz */ + skb_reserve(ppkt, shift_sz); + + /* copy data to new pkt */ + ptr = skb_put(ppkt, pfhdr->len); + if (ptr) + _rtw_memcpy(ptr, pfhdr->rx_data, pfhdr->len); + + rtw_skb_free(pfhdr->pkt); + + /* attach new pkt to recvframe */ + pfhdr->pkt = ppkt; + pfhdr->rx_head = ppkt->head; + pfhdr->rx_data = ppkt->data; + pfhdr->rx_tail = skb_tail_pointer(ppkt); + pfhdr->rx_end = skb_end_pointer(ppkt); +} +#else +#warning "recvframe_expand_pkt not implement, defrag may crash system" +#endif +#endif + +/* perform defrag */ +union recv_frame *recvframe_defrag(_adapter *adapter, _queue *defrag_q); +union recv_frame *recvframe_defrag(_adapter *adapter, _queue *defrag_q) +{ + _list *plist, *phead; + u8 *data, wlanhdr_offset; + u8 curfragnum; + struct recv_frame_hdr *pfhdr, *pnfhdr; + union recv_frame *prframe, *pnextrframe; + _queue *pfree_recv_queue; + + + curfragnum = 0; + pfree_recv_queue = &adapter->recvpriv.free_recv_queue; + + phead = get_list_head(defrag_q); + plist = get_next(phead); + prframe = LIST_CONTAINOR(plist, union recv_frame, u); + pfhdr = &prframe->u.hdr; + rtw_list_delete(&(prframe->u.list)); + + if (curfragnum != pfhdr->attrib.frag_num) { + /* the first fragment number must be 0 */ + /* free the whole queue */ + rtw_free_recvframe(prframe, pfree_recv_queue); + rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); + + return NULL; + } + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) +#ifndef CONFIG_SDIO_RX_COPY + recvframe_expand_pkt(adapter, prframe); +#endif +#endif + + curfragnum++; + + plist = get_list_head(defrag_q); + + plist = get_next(plist); + + data = get_recvframe_data(prframe); + + while (rtw_end_of_queue_search(phead, plist) == _FALSE) { + pnextrframe = LIST_CONTAINOR(plist, union recv_frame , u); + pnfhdr = &pnextrframe->u.hdr; + + + /* check the fragment sequence (2nd ~n fragment frame) */ + + if (curfragnum != pnfhdr->attrib.frag_num) { + /* the fragment number must be increasing (after decache) */ + /* release the defrag_q & prframe */ + rtw_free_recvframe(prframe, pfree_recv_queue); + rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); + return NULL; + } + + curfragnum++; + + /* copy the 2nd~n fragment frame's payload to the first fragment */ + /* get the 2nd~last fragment frame's payload */ + + wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len; + + recvframe_pull(pnextrframe, wlanhdr_offset); + + /* append to first fragment frame's tail (if privacy frame, pull the ICV) */ + recvframe_pull_tail(prframe, pfhdr->attrib.icv_len); + + /* memcpy */ + _rtw_memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len); + + recvframe_put(prframe, pnfhdr->len); + + pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len; + plist = get_next(plist); + + }; + + /* free the defrag_q queue and return the prframe */ + rtw_free_recvframe_queue(defrag_q, pfree_recv_queue); + + + + return prframe; +} + +/* check if need to defrag, if needed queue the frame to defrag_q */ +union recv_frame *recvframe_chk_defrag(PADAPTER padapter, union recv_frame *precv_frame) +{ + u8 ismfrag; + u8 fragnum; + u8 *psta_addr; + struct recv_frame_hdr *pfhdr; + struct sta_info *psta; + struct sta_priv *pstapriv; + _list *phead; + union recv_frame *prtnframe = NULL; + _queue *pfree_recv_queue, *pdefrag_q; + + + pstapriv = &padapter->stapriv; + + pfhdr = &precv_frame->u.hdr; + + pfree_recv_queue = &padapter->recvpriv.free_recv_queue; + + /* need to define struct of wlan header frame ctrl */ + ismfrag = pfhdr->attrib.mfrag; + fragnum = pfhdr->attrib.frag_num; + + psta_addr = pfhdr->attrib.ta; + psta = rtw_get_stainfo(pstapriv, psta_addr); + if (psta == NULL) { + u8 type = GetFrameType(pfhdr->rx_data); + if (type != WIFI_DATA_TYPE) { + psta = rtw_get_bcmc_stainfo(padapter); + pdefrag_q = &psta->sta_recvpriv.defrag_q; + } else + pdefrag_q = NULL; + } else + pdefrag_q = &psta->sta_recvpriv.defrag_q; + + if ((ismfrag == 0) && (fragnum == 0)) { + prtnframe = precv_frame;/* isn't a fragment frame */ + } + + if (ismfrag == 1) { + /* 0~(n-1) fragment frame */ + /* enqueue to defraf_g */ + if (pdefrag_q != NULL) { + if (fragnum == 0) { + /* the first fragment */ + if (_rtw_queue_empty(pdefrag_q) == _FALSE) { + /* free current defrag_q */ + rtw_free_recvframe_queue(pdefrag_q, pfree_recv_queue); + } + } + + + /* Then enqueue the 0~(n-1) fragment into the defrag_q */ + + /* _rtw_spinlock(&pdefrag_q->lock); */ + phead = get_list_head(pdefrag_q); + rtw_list_insert_tail(&pfhdr->list, phead); + /* _rtw_spinunlock(&pdefrag_q->lock); */ + + + prtnframe = NULL; + + } else { + /* can't find this ta's defrag_queue, so free this recv_frame */ + rtw_free_recvframe(precv_frame, pfree_recv_queue); + prtnframe = NULL; + } + + } + + if ((ismfrag == 0) && (fragnum != 0)) { + /* the last fragment frame */ + /* enqueue the last fragment */ + if (pdefrag_q != NULL) { + /* _rtw_spinlock(&pdefrag_q->lock); */ + phead = get_list_head(pdefrag_q); + rtw_list_insert_tail(&pfhdr->list, phead); + /* _rtw_spinunlock(&pdefrag_q->lock); */ + + /* call recvframe_defrag to defrag */ + precv_frame = recvframe_defrag(padapter, pdefrag_q); + prtnframe = precv_frame; + + } else { + /* can't find this ta's defrag_queue, so free this recv_frame */ + rtw_free_recvframe(precv_frame, pfree_recv_queue); + prtnframe = NULL; + } + + } + + + if ((prtnframe != NULL) && (prtnframe->u.hdr.attrib.privacy)) { + /* after defrag we must check tkip mic code */ + if (recvframe_chkmic(padapter, prtnframe) == _FAIL) { + rtw_free_recvframe(prtnframe, pfree_recv_queue); + prtnframe = NULL; + } + } + + + return prtnframe; + +} + +int amsdu_to_msdu(_adapter *padapter, union recv_frame *prframe) +{ + int a_len, padding_len; + u16 nSubframe_Length; + u8 nr_subframes, i; + u8 *pdata; + _pkt *sub_pkt, *subframes[MAX_SUBFRAME_COUNT]; + struct recv_priv *precvpriv = &padapter->recvpriv; + _queue *pfree_recv_queue = &(precvpriv->free_recv_queue); + int ret = _SUCCESS; + + nr_subframes = 0; + + recvframe_pull(prframe, prframe->u.hdr.attrib.hdrlen); + + if (prframe->u.hdr.attrib.iv_len > 0) + recvframe_pull(prframe, prframe->u.hdr.attrib.iv_len); + + a_len = prframe->u.hdr.len; + + pdata = prframe->u.hdr.rx_data; + + while (a_len > ETH_HLEN) { + + /* Offset 12 denote 2 mac address */ + nSubframe_Length = RTW_GET_BE16(pdata + 12); + + if (a_len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) { + RTW_INFO("nRemain_Length is %d and nSubframe_Length is : %d\n", a_len, nSubframe_Length); + break; + } + + sub_pkt = rtw_os_alloc_msdu_pkt(prframe, nSubframe_Length, pdata); + if (sub_pkt == NULL) { + RTW_INFO("%s(): allocate sub packet fail !!!\n", __FUNCTION__); + break; + } + + /* move the data point to data content */ + pdata += ETH_HLEN; + a_len -= ETH_HLEN; + + subframes[nr_subframes++] = sub_pkt; + + if (nr_subframes >= MAX_SUBFRAME_COUNT) { + RTW_INFO("ParseSubframe(): Too many Subframes! Packets dropped!\n"); + break; + } + + pdata += nSubframe_Length; + a_len -= nSubframe_Length; + if (a_len != 0) { + padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & (4 - 1)); + if (padding_len == 4) + padding_len = 0; + + if (a_len < padding_len) { + RTW_INFO("ParseSubframe(): a_len < padding_len !\n"); + break; + } + pdata += padding_len; + a_len -= padding_len; + } + } + + for (i = 0; i < nr_subframes; i++) { + sub_pkt = subframes[i]; + + /* Indicat the packets to upper layer */ + if (sub_pkt) + rtw_os_recv_indicate_pkt(padapter, sub_pkt, &prframe->u.hdr.attrib); + } + + prframe->u.hdr.len = 0; + rtw_free_recvframe(prframe, pfree_recv_queue);/* free this recv_frame */ + + return ret; +} + +int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num); +int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num) +{ + PADAPTER padapter = preorder_ctrl->padapter; + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; + u8 wsize = preorder_ctrl->wsize_b; + u16 wend = (preorder_ctrl->indicate_seq + wsize - 1) & 0xFFF; /* % 4096; */ + + /* Rx Reorder initialize condition. */ + if (preorder_ctrl->indicate_seq == 0xFFFF) { + preorder_ctrl->indicate_seq = seq_num; +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d init IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq, seq_num); +#endif + + /* DbgPrint("check_indicate_seq, 1st->indicate_seq=%d\n", precvpriv->indicate_seq); */ + } + + /* DbgPrint("enter->check_indicate_seq(): IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */ + + /* Drop out the packet which SeqNum is smaller than WinStart */ + if (SN_LESS(seq_num, preorder_ctrl->indicate_seq)) { + /* DbgPrint("CheckRxTsIndicateSeq(): Packet Drop! IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */ + +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("%s IndicateSeq: %d > NewSeq: %d\n", __FUNCTION__, + preorder_ctrl->indicate_seq, seq_num); +#endif + + + return _FALSE; + } + + /* */ + /* Sliding window manipulation. Conditions includes: */ + /* 1. Incoming SeqNum is equal to WinStart =>Window shift 1 */ + /* 2. Incoming SeqNum is larger than the WinEnd => Window shift N */ + /* */ + if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) { + preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; + +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d SN_EQUAL IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq, seq_num); +#endif + } else if (SN_LESS(wend, seq_num)) { + /* DbgPrint("CheckRxTsIndicateSeq(): Window Shift! IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */ + + /* boundary situation, when seq_num cross 0xFFF */ + if (seq_num >= (wsize - 1)) + preorder_ctrl->indicate_seq = seq_num + 1 - wsize; + else + preorder_ctrl->indicate_seq = 0xFFF - (wsize - (seq_num + 1)) + 1; + pdbgpriv->dbg_rx_ampdu_window_shift_cnt++; +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d SN_LESS(wend, seq_num) IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq, seq_num); +#endif + } + + /* DbgPrint("exit->check_indicate_seq(): IndicateSeq: %d, NewSeq: %d\n", precvpriv->indicate_seq, seq_num); */ + + return _TRUE; +} + +int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe); +int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, union recv_frame *prframe) +{ + struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; + _queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; + _list *phead, *plist; + union recv_frame *pnextrframe; + struct rx_pkt_attrib *pnextattrib; + + /* DbgPrint("+enqueue_reorder_recvframe()\n"); */ + + /* _enter_critical_ex(&ppending_recvframe_queue->lock, &irql); */ + /* _rtw_spinlock_ex(&ppending_recvframe_queue->lock); */ + + + phead = get_list_head(ppending_recvframe_queue); + plist = get_next(phead); + + while (rtw_end_of_queue_search(phead, plist) == _FALSE) { + pnextrframe = LIST_CONTAINOR(plist, union recv_frame, u); + pnextattrib = &pnextrframe->u.hdr.attrib; + + if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num)) + plist = get_next(plist); + else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num)) { + /* Duplicate entry is found!! Do not insert current entry. */ + + /* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */ + + return _FALSE; + } else + break; + + /* DbgPrint("enqueue_reorder_recvframe():while\n"); */ + + } + + + /* _enter_critical_ex(&ppending_recvframe_queue->lock, &irql); */ + /* _rtw_spinlock_ex(&ppending_recvframe_queue->lock); */ + + rtw_list_delete(&(prframe->u.hdr.list)); + + rtw_list_insert_tail(&(prframe->u.hdr.list), plist); + + /* _rtw_spinunlock_ex(&ppending_recvframe_queue->lock); */ + /* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */ + + + return _TRUE; + +} + +void recv_indicatepkts_pkt_loss_cnt(struct debug_priv *pdbgpriv, u64 prev_seq, u64 current_seq); +void recv_indicatepkts_pkt_loss_cnt(struct debug_priv *pdbgpriv, u64 prev_seq, u64 current_seq) +{ + if (current_seq < prev_seq) + pdbgpriv->dbg_rx_ampdu_loss_count += (4096 + current_seq - prev_seq); + + else + pdbgpriv->dbg_rx_ampdu_loss_count += (current_seq - prev_seq); +} +int recv_indicatepkts_in_order(_adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced); +int recv_indicatepkts_in_order(_adapter *padapter, struct recv_reorder_ctrl *preorder_ctrl, int bforced) +{ + /* _irqL irql; */ + /* u8 bcancelled; */ + _list *phead, *plist; + union recv_frame *prframe; + struct rx_pkt_attrib *pattrib; + /* u8 index = 0; */ + int bPktInBuf = _FALSE; + struct recv_priv *precvpriv = &padapter->recvpriv; + _queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; + + DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate_in_oder); + + /* DbgPrint("+recv_indicatepkts_in_order\n"); */ + + /* _enter_critical_ex(&ppending_recvframe_queue->lock, &irql); */ + /* _rtw_spinlock_ex(&ppending_recvframe_queue->lock); */ + + phead = get_list_head(ppending_recvframe_queue); + plist = get_next(phead); + +#if 0 + /* Check if there is any other indication thread running. */ + if (pTS->RxIndicateState == RXTS_INDICATE_PROCESSING) + return; +#endif + + /* Handling some condition for forced indicate case. */ + if (bforced == _TRUE) { + pdbgpriv->dbg_rx_ampdu_forced_indicate_count++; + if (rtw_is_list_empty(phead)) { + /* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */ + /* _rtw_spinunlock_ex(&ppending_recvframe_queue->lock); */ + return _TRUE; + } + + prframe = LIST_CONTAINOR(plist, union recv_frame, u); + pattrib = &prframe->u.hdr.attrib; + +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq, pattrib->seq_num); +#endif + recv_indicatepkts_pkt_loss_cnt(pdbgpriv, preorder_ctrl->indicate_seq, pattrib->seq_num); + preorder_ctrl->indicate_seq = pattrib->seq_num; + + } + + /* Prepare indication list and indication. */ + /* Check if there is any packet need indicate. */ + while (!rtw_is_list_empty(phead)) { + + prframe = LIST_CONTAINOR(plist, union recv_frame, u); + pattrib = &prframe->u.hdr.attrib; + + if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) { + +#if 0 + /* This protect buffer from overflow. */ + if (index >= REORDER_WIN_SIZE) { + RT_ASSERT(FALSE, ("IndicateRxReorderList(): Buffer overflow!!\n")); + bPktInBuf = TRUE; + break; + } +#endif + + plist = get_next(plist); + rtw_list_delete(&(prframe->u.hdr.list)); + + if (SN_EQUAL(preorder_ctrl->indicate_seq, pattrib->seq_num)) { + preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) & 0xFFF; +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq, pattrib->seq_num); +#endif + } + +#if 0 + index++; + if (index == 1) { + /* Cancel previous pending timer. */ + /* PlatformCancelTimer(Adapter, &pTS->RxPktPendingTimer); */ + if (bforced != _TRUE) { + /* RTW_INFO("_cancel_timer(&preorder_ctrl->reordering_ctrl_timer, &bcancelled);\n"); */ + _cancel_timer(&preorder_ctrl->reordering_ctrl_timer, &bcancelled); + } + } +#endif + + /* Set this as a lock to make sure that only one thread is indicating packet. */ + /* pTS->RxIndicateState = RXTS_INDICATE_PROCESSING; */ + + /* Indicate packets */ + /* RT_ASSERT((index<=REORDER_WIN_SIZE), ("RxReorderIndicatePacket(): Rx Reorder buffer full!!\n")); */ + + + /* indicate this recv_frame */ + /* DbgPrint("recv_indicatepkts_in_order, indicate_seq=%d, seq_num=%d\n", precvpriv->indicate_seq, pattrib->seq_num); */ + if (!pattrib->amsdu) { + /* RTW_INFO("recv_indicatepkts_in_order, amsdu!=1, indicate_seq=%d, seq_num=%d\n", preorder_ctrl->indicate_seq, pattrib->seq_num); */ + + if (!RTW_CANNOT_RUN(padapter)) + rtw_recv_indicatepkt(padapter, prframe);/*indicate this recv_frame*/ + + } else if (pattrib->amsdu == 1) { + if (amsdu_to_msdu(padapter, prframe) != _SUCCESS) + rtw_free_recvframe(prframe, &precvpriv->free_recv_queue); + } else { + /* error condition; */ + } + + + /* Update local variables. */ + bPktInBuf = _FALSE; + + } else { + bPktInBuf = _TRUE; + break; + } + + /* DbgPrint("recv_indicatepkts_in_order():while\n"); */ + + } + + /* _rtw_spinunlock_ex(&ppending_recvframe_queue->lock); */ + /* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */ + +#if 0 + /* Release the indication lock and set to new indication step. */ + if (bPktInBuf) { + /* Set new pending timer. */ + /* pTS->RxIndicateState = RXTS_INDICATE_REORDER; */ + /* PlatformSetTimer(Adapter, &pTS->RxPktPendingTimer, pHTInfo->RxReorderPendingTime); */ + + _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); + } else { + /* pTS->RxIndicateState = RXTS_INDICATE_IDLE; */ + } +#endif + /* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */ + + /* return _TRUE; */ + return bPktInBuf; + +} + +int recv_indicatepkt_reorder(_adapter *padapter, union recv_frame *prframe); +int recv_indicatepkt_reorder(_adapter *padapter, union recv_frame *prframe) +{ + _irqL irql; + int retval = _SUCCESS; + struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; + struct recv_reorder_ctrl *preorder_ctrl = prframe->u.hdr.preorder_ctrl; + _queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; + + DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate_reoder); + + if (!pattrib->amsdu) { + /* s1. */ + retval = wlanhdr_to_ethhdr(prframe); + if (retval != _SUCCESS) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s wlanhdr_to_ethhdr error!\n", __FUNCTION__); +#endif + return retval; + } + + /* if ((pattrib->qos!=1) || pattrib->priority!=0 || IS_MCAST(pattrib->ra) */ + /* || (pattrib->eth_type==0x0806) || (pattrib->ack_policy!=0)) */ + if (pattrib->qos != 1) { + if (!RTW_CANNOT_RUN(padapter)) { + + rtw_recv_indicatepkt(padapter, prframe); + return _SUCCESS; + + } + +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s pattrib->qos !=1\n", __FUNCTION__); +#endif + + return _FAIL; + + } + + if (preorder_ctrl->enable == _FALSE) { + /* indicate this recv_frame */ + preorder_ctrl->indicate_seq = pattrib->seq_num; +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq, pattrib->seq_num); +#endif + + rtw_recv_indicatepkt(padapter, prframe); + + preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) % 4096; +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq, pattrib->seq_num); +#endif + + return _SUCCESS; + } + +#ifndef CONFIG_RECV_REORDERING_CTRL + /* indicate this recv_frame */ + rtw_recv_indicatepkt(padapter, prframe); + return _SUCCESS; +#endif + + } else if (pattrib->amsdu == 1) { /* temp filter->means didn't support A-MSDUs in a A-MPDU */ + if (preorder_ctrl->enable == _FALSE) { + preorder_ctrl->indicate_seq = pattrib->seq_num; +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq, pattrib->seq_num); +#endif + + retval = amsdu_to_msdu(padapter, prframe); + + preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) % 4096; +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d IndicateSeq: %d, NewSeq: %d\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq, pattrib->seq_num); +#endif + + if (retval != _SUCCESS) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s amsdu_to_msdu fail\n", __FUNCTION__); +#endif + } + + return retval; + } + } else { + + } + + _enter_critical_bh(&ppending_recvframe_queue->lock, &irql); + + + /* s2. check if winstart_b(indicate_seq) needs to been updated */ + if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) { + pdbgpriv->dbg_rx_ampdu_drop_count++; + /* pHTInfo->RxReorderDropCounter++; */ + /* ReturnRFDList(Adapter, pRfd); */ + /* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */ + /* return _FAIL; */ + +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s check_indicate_seq fail\n", __FUNCTION__); +#endif +#if 0 + rtw_recv_indicatepkt(padapter, prframe); + + _exit_critical_bh(&ppending_recvframe_queue->lock, &irql); + + goto _success_exit; +#else + goto _err_exit; +#endif + } + + + /* s3. Insert all packet into Reorder Queue to maintain its ordering. */ + if (!enqueue_reorder_recvframe(preorder_ctrl, prframe)) { + /* DbgPrint("recv_indicatepkt_reorder, enqueue_reorder_recvframe fail!\n"); */ + /* _exit_critical_ex(&ppending_recvframe_queue->lock, &irql); */ + /* return _FAIL; */ +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s enqueue_reorder_recvframe fail\n", __FUNCTION__); +#endif + goto _err_exit; + } + + + /* s4. */ + /* Indication process. */ + /* After Packet dropping and Sliding Window shifting as above, we can now just indicate the packets */ + /* with the SeqNum smaller than latest WinStart and buffer other packets. */ + /* */ + /* For Rx Reorder condition: */ + /* 1. All packets with SeqNum smaller than WinStart => Indicate */ + /* 2. All packets with SeqNum larger than or equal to WinStart => Buffer it. */ + /* */ + + /* recv_indicatepkts_in_order(padapter, preorder_ctrl, _TRUE); */ + if (recv_indicatepkts_in_order(padapter, preorder_ctrl, _FALSE) == _TRUE) { + if (!preorder_ctrl->bReorderWaiting) { + preorder_ctrl->bReorderWaiting = _TRUE; + _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); + } + _exit_critical_bh(&ppending_recvframe_queue->lock, &irql); + } else { + preorder_ctrl->bReorderWaiting = _FALSE; + _exit_critical_bh(&ppending_recvframe_queue->lock, &irql); + _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); + } + + +_success_exit: + + return _SUCCESS; + +_err_exit: + + _exit_critical_bh(&ppending_recvframe_queue->lock, &irql); + + return _FAIL; +} + + +void rtw_reordering_ctrl_timeout_handler(void *pcontext) +{ + _irqL irql; + struct recv_reorder_ctrl *preorder_ctrl = (struct recv_reorder_ctrl *)pcontext; + _adapter *padapter = preorder_ctrl->padapter; + _queue *ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; + + + if (RTW_CANNOT_RUN(padapter)) + return; + + /* RTW_INFO("+rtw_reordering_ctrl_timeout_handler()=>\n"); */ + + _enter_critical_bh(&ppending_recvframe_queue->lock, &irql); + + if (preorder_ctrl) + preorder_ctrl->bReorderWaiting = _FALSE; + + if (recv_indicatepkts_in_order(padapter, preorder_ctrl, _TRUE) == _TRUE) + _set_timer(&preorder_ctrl->reordering_ctrl_timer, REORDER_WAIT_TIME); + + _exit_critical_bh(&ppending_recvframe_queue->lock, &irql); + +} + +int process_recv_indicatepkts(_adapter *padapter, union recv_frame *prframe); +int process_recv_indicatepkts(_adapter *padapter, union recv_frame *prframe) +{ + int retval = _SUCCESS; + /* struct recv_priv *precvpriv = &padapter->recvpriv; */ + /* struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; */ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +#ifdef CONFIG_TDLS + struct sta_info *psta = prframe->u.hdr.psta; +#endif /* CONFIG_TDLS */ + +#ifdef CONFIG_80211N_HT + + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + + DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate); + +#ifdef CONFIG_TDLS + if ((phtpriv->ht_option == _TRUE) || + ((psta->tdls_sta_state & TDLS_LINKED_STATE) && + (psta->htpriv.ht_option == _TRUE) && + (psta->htpriv.ampdu_enable == _TRUE))) /* B/G/N Mode */ +#else + if (phtpriv->ht_option == _TRUE) /* B/G/N Mode */ +#endif /* CONFIG_TDLS */ + { + /* prframe->u.hdr.preorder_ctrl = &precvpriv->recvreorder_ctrl[pattrib->priority]; */ + + if (recv_indicatepkt_reorder(padapter, prframe) != _SUCCESS) { /* including perform A-MPDU Rx Ordering Buffer Control */ +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s recv_indicatepkt_reorder error!\n", __FUNCTION__); +#endif + + if (!RTW_CANNOT_RUN(padapter)) { + retval = _FAIL; + return retval; + } + } + } else /* B/G mode */ +#endif + { + retval = wlanhdr_to_ethhdr(prframe); + if (retval != _SUCCESS) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s wlanhdr_to_ethhdr error!\n", __FUNCTION__); +#endif + return retval; + } + + if (!RTW_CANNOT_RUN(padapter)) { + /* indicate this recv_frame */ + rtw_recv_indicatepkt(padapter, prframe); + } else { + + retval = _FAIL; + return retval; + } + + } + + return retval; + +} + +#ifdef CONFIG_MP_INCLUDED +int validate_mp_recv_frame(_adapter *adapter, union recv_frame *precv_frame) +{ + int ret = _SUCCESS; + u8 *ptr = precv_frame->u.hdr.rx_data; + u8 type, subtype; + struct mp_priv *pmppriv = &adapter->mppriv; + struct mp_tx *pmptx; + unsigned char *sa , *da, *bs; + + pmptx = &pmppriv->tx; + +#if 0 + if (1) { + u8 bDumpRxPkt; + type = GetFrameType(ptr); + subtype = get_frame_sub_type(ptr); /* bit(7)~bit(2) */ + + rtw_hal_get_def_var(adapter, HAL_DEF_DBG_DUMP_RXPKT, &(bDumpRxPkt)); + if (bDumpRxPkt == 1) { /* dump all rx packets */ + int i; + RTW_INFO("############ type:0x%02x subtype:0x%02x #################\n", type, subtype); + + for (i = 0; i < 64; i = i + 8) + RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n", *(ptr + i), + *(ptr + i + 1), *(ptr + i + 2) , *(ptr + i + 3) , *(ptr + i + 4), *(ptr + i + 5), *(ptr + i + 6), *(ptr + i + 7)); + RTW_INFO("#############################\n"); + } + } +#endif + if (pmppriv->bloopback) { + if (_rtw_memcmp(ptr + 24, pmptx->buf + 24, precv_frame->u.hdr.len - 24) == _FALSE) { + RTW_INFO("Compare payload content Fail !!!\n"); + ret = _FAIL; + } + } + if (pmppriv->bSetRxBssid == _TRUE) { + + sa = get_addr2_ptr(ptr); + da = GetAddr1Ptr(ptr); + bs = GetAddr3Ptr(ptr); + type = GetFrameType(ptr); + subtype = get_frame_sub_type(ptr); /* bit(7)~bit(2) */ + + if (_rtw_memcmp(bs, adapter->mppriv.network_macaddr, ETH_ALEN) == _FALSE) + ret = _FAIL; + + RTW_DBG("############ type:0x%02x subtype:0x%02x #################\n", type, subtype); + RTW_DBG("A2 sa %02X:%02X:%02X:%02X:%02X:%02X \n", *(sa) , *(sa + 1), *(sa+ 2), *(sa + 3), *(sa + 4), *(sa + 5)); + RTW_DBG("A1 da %02X:%02X:%02X:%02X:%02X:%02X \n", *(da) , *(da + 1), *(da+ 2), *(da + 3), *(da + 4), *(da + 5)); + RTW_DBG("A3 bs %02X:%02X:%02X:%02X:%02X:%02X \n --------------------------\n", *(bs) , *(bs + 1), *(bs+ 2), *(bs + 3), *(bs + 4), *(bs + 5)); + } + + if (!adapter->mppriv.bmac_filter) + return ret; + + if (_rtw_memcmp(get_addr2_ptr(ptr), adapter->mppriv.mac_filter, ETH_ALEN) == _FALSE) + ret = _FAIL; + + return ret; +} + +static sint MPwlanhdr_to_ethhdr(union recv_frame *precvframe) +{ + sint rmv_len; + u16 eth_type, len; + u8 bsnaphdr; + u8 *psnap_type; + u8 mcastheadermac[] = {0x01, 0x00, 0x5e}; + + struct ieee80211_snap_hdr *psnap; + + sint ret = _SUCCESS; + _adapter *adapter = precvframe->u.hdr.adapter; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + u8 *ptr = get_recvframe_data(precvframe) ; /* point to frame_ctrl field */ + struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib; + + + if (pattrib->encrypt) + recvframe_pull_tail(precvframe, pattrib->icv_len); + + psnap = (struct ieee80211_snap_hdr *)(ptr + pattrib->hdrlen + pattrib->iv_len); + psnap_type = ptr + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE; + /* convert hdr + possible LLC headers into Ethernet header */ + /* eth_type = (psnap_type[0] << 8) | psnap_type[1]; */ + if ((_rtw_memcmp(psnap, rtw_rfc1042_header, SNAP_SIZE) && + (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_IPX, 2) == _FALSE) && + (_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_APPLETALK_AARP, 2) == _FALSE)) || + /* eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || */ + _rtw_memcmp(psnap, rtw_bridge_tunnel_header, SNAP_SIZE)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */ + bsnaphdr = _TRUE; + } else { + /* Leave Ethernet header part of hdr and full payload */ + bsnaphdr = _FALSE; + } + + rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0); + len = precvframe->u.hdr.len - rmv_len; + + + _rtw_memcpy(ð_type, ptr + rmv_len, 2); + eth_type = ntohs((unsigned short)eth_type); /* pattrib->ether_type */ + pattrib->eth_type = eth_type; + + { + ptr = recvframe_pull(precvframe, (rmv_len - sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0))); + } + + _rtw_memcpy(ptr, pattrib->dst, ETH_ALEN); + _rtw_memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN); + + if (!bsnaphdr) { + len = htons(len); + _rtw_memcpy(ptr + 12, &len, 2); + } + + + len = htons(pattrib->seq_num); + /* RTW_INFO("wlan seq = %d ,seq_num =%x\n",len,pattrib->seq_num); */ + _rtw_memcpy(ptr + 12, &len, 2); + if (adapter->mppriv.bRTWSmbCfg == _TRUE) { + /* if(_rtw_memcmp(mcastheadermac, pattrib->dst, 3) == _TRUE) */ /* SimpleConfig Dest. */ + /* _rtw_memcpy(ptr+ETH_ALEN, pattrib->bssid, ETH_ALEN); */ + + if (_rtw_memcmp(mcastheadermac, pattrib->bssid, 3) == _TRUE) /* SimpleConfig Dest. */ + _rtw_memcpy(ptr, pattrib->bssid, ETH_ALEN); + + } + + + return ret; + +} + + +int mp_recv_frame(_adapter *padapter, union recv_frame *rframe) +{ + int ret = _SUCCESS; + struct rx_pkt_attrib *pattrib = &rframe->u.hdr.attrib; + struct recv_priv *precvpriv = &padapter->recvpriv; + _queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; +#ifdef CONFIG_MP_INCLUDED + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mp_priv *pmppriv = &padapter->mppriv; +#endif /* CONFIG_MP_INCLUDED */ + u8 type; + u8 *ptr = rframe->u.hdr.rx_data; + u8 *psa, *pda, *pbssid; + struct sta_info *psta = NULL; + DBG_COUNTER(padapter->rx_logs.core_rx_pre); + + if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) { /* &&(padapter->mppriv.check_mp_pkt == 0)) */ + if (pattrib->crc_err == 1) + padapter->mppriv.rx_crcerrpktcount++; + else { + if (_SUCCESS == validate_mp_recv_frame(padapter, rframe)) + padapter->mppriv.rx_pktcount++; + else + padapter->mppriv.rx_pktcount_filter_out++; + } + + if (pmppriv->rx_bindicatePkt == _FALSE) { + ret = _FAIL; + rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ + goto exit; + } else { + type = GetFrameType(ptr); + pattrib->to_fr_ds = get_tofr_ds(ptr); + pattrib->frag_num = GetFragNum(ptr); + pattrib->seq_num = GetSequence(ptr); + pattrib->pw_save = GetPwrMgt(ptr); + pattrib->mfrag = GetMFrag(ptr); + pattrib->mdata = GetMData(ptr); + pattrib->privacy = GetPrivacy(ptr); + pattrib->order = GetOrder(ptr); + + if (type == WIFI_DATA_TYPE) { + pda = get_da(ptr); + psa = get_sa(ptr); + pbssid = get_hdr_bssid(ptr); + + _rtw_memcpy(pattrib->dst, pda, ETH_ALEN); + _rtw_memcpy(pattrib->src, psa, ETH_ALEN); + _rtw_memcpy(pattrib->bssid, pbssid, ETH_ALEN); + + switch (pattrib->to_fr_ds) { + case 0: + _rtw_memcpy(pattrib->ra, pda, ETH_ALEN); + _rtw_memcpy(pattrib->ta, psa, ETH_ALEN); + ret = sta2sta_data_frame(padapter, rframe, &psta); + break; + + case 1: + + _rtw_memcpy(pattrib->ra, pda, ETH_ALEN); + _rtw_memcpy(pattrib->ta, pbssid, ETH_ALEN); + ret = ap2sta_data_frame(padapter, rframe, &psta); + + break; + + case 2: + _rtw_memcpy(pattrib->ra, pbssid, ETH_ALEN); + _rtw_memcpy(pattrib->ta, psa, ETH_ALEN); + ret = sta2ap_data_frame(padapter, rframe, &psta); + break; + + case 3: + _rtw_memcpy(pattrib->ra, GetAddr1Ptr(ptr), ETH_ALEN); + _rtw_memcpy(pattrib->ta, get_addr2_ptr(ptr), ETH_ALEN); + ret = _FAIL; + break; + + default: + ret = _FAIL; + break; + } + + ret = MPwlanhdr_to_ethhdr(rframe); + + if (ret != _SUCCESS) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s wlanhdr_to_ethhdr: drop pkt\n", __FUNCTION__); +#endif + rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ + ret = _FAIL; + goto exit; + } + if (!RTW_CANNOT_RUN(padapter)) { + /* indicate this recv_frame */ + ret = rtw_recv_indicatepkt(padapter, rframe); + if (ret != _SUCCESS) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s rtw_recv_indicatepkt fail!\n", __FUNCTION__); +#endif + rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ + ret = _FAIL; + + goto exit; + } + } else { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s ecv_func:bDriverStopped(%s) OR bSurpriseRemoved(%s)\n", __func__, + rtw_is_drv_stopped(padapter) ? "True" : "False", + rtw_is_surprise_removed(padapter) ? "True" : "False"); +#endif + ret = _FAIL; + rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ + goto exit; + } + + } + } + + } + + rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ + ret = _FAIL; + +exit: + return ret; + +} +#endif + +static sint fill_radiotap_hdr(_adapter *padapter, union recv_frame *precvframe, u8 *buf) +{ +#define CHAN2FREQ(a) ((a < 14) ? (2407+5*a) : (5000+5*a)) + +#if 0 +#define RTW_RX_RADIOTAP_PRESENT (\ + (1 << IEEE80211_RADIOTAP_TSFT) | \ + (1 << IEEE80211_RADIOTAP_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_CHANNEL) | \ + (0 << IEEE80211_RADIOTAP_FHSS) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | \ + (0 << IEEE80211_RADIOTAP_LOCK_QUALITY) | \ + (0 << IEEE80211_RADIOTAP_TX_ATTENUATION) | \ + (0 << IEEE80211_RADIOTAP_DB_TX_ATTENUATION) | \ + (0 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \ + (1 << IEEE80211_RADIOTAP_ANTENNA) | \ + (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | \ + (0 << IEEE80211_RADIOTAP_DB_ANTNOISE) | \ + (0 << IEEE80211_RADIOTAP_RX_FLAGS) | \ + (0 << IEEE80211_RADIOTAP_TX_FLAGS) | \ + (0 << IEEE80211_RADIOTAP_RTS_RETRIES) | \ + (0 << IEEE80211_RADIOTAP_DATA_RETRIES) | \ + (0 << IEEE80211_RADIOTAP_MCS) | \ + (0 << IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE)| \ + (0 << IEEE80211_RADIOTAP_VENDOR_NAMESPACE) | \ + (0 << IEEE80211_RADIOTAP_EXT) | \ + 0) + + /* (0 << IEEE80211_RADIOTAP_AMPDU_STATUS) | \ */ + /* (0 << IEEE80211_RADIOTAP_VHT) | \ */ +#endif + +#ifndef IEEE80211_RADIOTAP_RX_FLAGS +#define IEEE80211_RADIOTAP_RX_FLAGS 14 +#endif + +#ifndef IEEE80211_RADIOTAP_MCS +#define IEEE80211_RADIOTAP_MCS 19 +#endif +#ifndef IEEE80211_RADIOTAP_VHT +#define IEEE80211_RADIOTAP_VHT 21 +#endif + +#ifndef IEEE80211_RADIOTAP_F_BADFCS +#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* bad FCS */ +#endif + + sint ret = _SUCCESS; + _adapter *adapter = precvframe->u.hdr.adapter; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib; + + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + u16 tmp_16bit = 0; + + u8 data_rate[] = { + 2, 4, 11, 22, /* CCK */ + 12, 18, 24, 36, 48, 72, 93, 108, /* OFDM */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* HT MCS index */ + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* VHT Nss 1 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* VHT Nss 2 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* VHT Nss 3 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* VHT Nss 4 */ + }; + + _pkt *pskb = NULL; + + struct ieee80211_radiotap_header *rtap_hdr = NULL; + u8 *ptr = NULL; + + u8 hdr_buf[64] = {0}; + u16 rt_len = 8; + + /* create header */ + rtap_hdr = (struct ieee80211_radiotap_header *)&hdr_buf[0]; + rtap_hdr->it_version = PKTHDR_RADIOTAP_VERSION; + + /* tsft */ + if (pattrib->tsfl) { + u64 tmp_64bit; + + rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_TSFT); + tmp_64bit = cpu_to_le64(pattrib->tsfl); + memcpy(&hdr_buf[rt_len], &tmp_64bit, 8); + rt_len += 8; + } + + /* flags */ + rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_FLAGS); + if (0) + hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_CFP; + + if (0) + hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_SHORTPRE; + + if ((pattrib->encrypt == 1) || (pattrib->encrypt == 5)) + hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_WEP; + + if (pattrib->mfrag) + hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_FRAG; + + /* always append FCS */ + hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_FCS; + + + if (0) + hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_DATAPAD; + + if (pattrib->crc_err) + hdr_buf[rt_len] |= IEEE80211_RADIOTAP_F_BADFCS; + + if (pattrib->sgi) { + /* Currently unspecified but used */ + hdr_buf[rt_len] |= 0x80; + } + rt_len += 1; + + /* rate */ + if (pattrib->data_rate < 12) { + rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_RATE); + if (pattrib->data_rate < 4) { + /* CCK */ + hdr_buf[rt_len] = data_rate[pattrib->data_rate]; + } else { + /* OFDM */ + hdr_buf[rt_len] = data_rate[pattrib->data_rate]; + } + } + rt_len += 1; /* force padding 1 byte for aligned */ + + /* channel */ + tmp_16bit = 0; + rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_CHANNEL); + tmp_16bit = CHAN2FREQ(rtw_get_oper_ch(padapter)); + /*tmp_16bit = CHAN2FREQ(pHalData->current_channel);*/ + memcpy(&hdr_buf[rt_len], &tmp_16bit, 2); + rt_len += 2; + + /* channel flags */ + tmp_16bit = 0; + if (pHalData->current_band_type == 0) + tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_2GHZ); + else + tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_5GHZ); + + if (pattrib->data_rate < 12) { + if (pattrib->data_rate < 4) { + /* CCK */ + tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_CCK); + } else { + /* OFDM */ + tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_OFDM); + } + } else + tmp_16bit |= cpu_to_le16(IEEE80211_CHAN_DYN); + memcpy(&hdr_buf[rt_len], &tmp_16bit, 2); + rt_len += 2; + + /* dBm Antenna Signal */ + rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL); + hdr_buf[rt_len] = pattrib->phy_info.RecvSignalPower; + rt_len += 1; + +#if 0 + /* dBm Antenna Noise */ + rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE); + hdr_buf[rt_len] = 0; + rt_len += 1; + + /* Signal Quality */ + rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_LOCK_QUALITY); + hdr_buf[rt_len] = pattrib->phy_info.SignalQuality; + rt_len += 1; +#endif + + /* Antenna */ + rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_ANTENNA); + hdr_buf[rt_len] = 0; /* pHalData->rf_type; */ + rt_len += 1; + + /* RX flags */ + rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_RX_FLAGS); +#if 0 + tmp_16bit = cpu_to_le16(0); + memcpy(ptr, &tmp_16bit, 1); +#endif + rt_len += 2; + + /* MCS information */ + if (pattrib->data_rate >= 12 && pattrib->data_rate < 44) { + rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_MCS); + /* known, flag */ + hdr_buf[rt_len] |= BIT1; /* MCS index known */ + + /* bandwidth */ + hdr_buf[rt_len] |= BIT0; + hdr_buf[rt_len + 1] |= (pattrib->bw & 0x03); + + /* guard interval */ + hdr_buf[rt_len] |= BIT2; + hdr_buf[rt_len + 1] |= (pattrib->sgi & 0x01) << 2; + + /* STBC */ + hdr_buf[rt_len] |= BIT5; + hdr_buf[rt_len + 1] |= (pattrib->stbc & 0x03) << 5; + + rt_len += 2; + + /* MCS rate index */ + hdr_buf[rt_len] = data_rate[pattrib->data_rate]; + rt_len += 1; + } + + /* VHT */ + if (pattrib->data_rate >= 44 && pattrib->data_rate < 84) { + rtap_hdr->it_present |= (1 << IEEE80211_RADIOTAP_VHT); + + /* known 16 bit, flag 8 bit */ + tmp_16bit = 0; + + /* Bandwidth */ + tmp_16bit |= BIT6; + + /* Group ID */ + tmp_16bit |= BIT7; + + /* Partial AID */ + tmp_16bit |= BIT8; + + /* STBC */ + tmp_16bit |= BIT0; + hdr_buf[rt_len + 2] |= (pattrib->stbc & 0x01); + + /* Guard interval */ + tmp_16bit |= BIT2; + hdr_buf[rt_len + 2] |= (pattrib->sgi & 0x01) << 2; + + /* LDPC extra OFDM symbol */ + tmp_16bit |= BIT4; + hdr_buf[rt_len + 2] |= (pattrib->ldpc & 0x01) << 4; + + memcpy(&hdr_buf[rt_len], &tmp_16bit, 2); + rt_len += 3; + + /* bandwidth */ + if (pattrib->bw == 0) + hdr_buf[rt_len] |= 0; + else if (pattrib->bw == 1) + hdr_buf[rt_len] |= 1; + else if (pattrib->bw == 2) + hdr_buf[rt_len] |= 4; + else if (pattrib->bw == 3) + hdr_buf[rt_len] |= 11; + rt_len += 1; + + /* mcs_nss */ + if (pattrib->data_rate >= 44 && pattrib->data_rate < 54) { + hdr_buf[rt_len] |= 1; + hdr_buf[rt_len] |= data_rate[pattrib->data_rate] << 4; + } else if (pattrib->data_rate >= 54 && pattrib->data_rate < 64) { + hdr_buf[rt_len + 1] |= 2; + hdr_buf[rt_len + 1] |= data_rate[pattrib->data_rate] << 4; + } else if (pattrib->data_rate >= 64 && pattrib->data_rate < 74) { + hdr_buf[rt_len + 2] |= 3; + hdr_buf[rt_len + 2] |= data_rate[pattrib->data_rate] << 4; + } else if (pattrib->data_rate >= 74 && pattrib->data_rate < 84) { + hdr_buf[rt_len + 3] |= 4; + hdr_buf[rt_len + 3] |= data_rate[pattrib->data_rate] << 4; + } + rt_len += 4; + + /* coding */ + hdr_buf[rt_len] = 0; + rt_len += 1; + + /* group_id */ + hdr_buf[rt_len] = 0; + rt_len += 1; + + /* partial_aid */ + tmp_16bit = 0; + memcpy(&hdr_buf[rt_len], &tmp_16bit, 2); + rt_len += 2; + } + + /* push to skb */ + pskb = (_pkt *)buf; + if (skb_headroom(pskb) < rt_len) { + RTW_INFO("%s:%d %s headroom is too small.\n", __FILE__, __LINE__, __func__); + ret = _FAIL; + return ret; + } + + ptr = skb_push(pskb, rt_len); + if (ptr) { + rtap_hdr->it_len = cpu_to_le16(rt_len); + memcpy(ptr, rtap_hdr, rt_len); + } else + ret = _FAIL; + + return ret; + +} +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)) +int recv_frame_monitor(_adapter *padapter, union recv_frame *rframe) +{ + int ret = _SUCCESS; + struct rx_pkt_attrib *pattrib = &rframe->u.hdr.attrib; + struct recv_priv *precvpriv = &padapter->recvpriv; + _queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; + _pkt *pskb = NULL; + + /* read skb information from recv frame */ + pskb = rframe->u.hdr.pkt; + pskb->len = rframe->u.hdr.len; + pskb->data = rframe->u.hdr.rx_data; + skb_set_tail_pointer(pskb, rframe->u.hdr.len); + + /* fill radiotap header */ + if (fill_radiotap_hdr(padapter, rframe, (u8 *)pskb) == _FAIL) { + ret = _FAIL; + rtw_free_recvframe(rframe, pfree_recv_queue); /* free this recv_frame */ + goto exit; + } + + /* write skb information to recv frame */ + skb_reset_mac_header(pskb); + rframe->u.hdr.len = pskb->len; + rframe->u.hdr.rx_data = pskb->data; + rframe->u.hdr.rx_head = pskb->head; + rframe->u.hdr.rx_tail = skb_tail_pointer(pskb); + rframe->u.hdr.rx_end = skb_end_pointer(pskb); + + if (!RTW_CANNOT_RUN(padapter)) { + /* indicate this recv_frame */ + ret = rtw_recv_monitor(padapter, rframe); + if (ret != _SUCCESS) { + ret = _FAIL; + rtw_free_recvframe(rframe, pfree_recv_queue); /* free this recv_frame */ + goto exit; + } + } else { + ret = _FAIL; + rtw_free_recvframe(rframe, pfree_recv_queue); /* free this recv_frame */ + goto exit; + } + +exit: + return ret; +} +#endif +int recv_func_prehandle(_adapter *padapter, union recv_frame *rframe) +{ + int ret = _SUCCESS; + struct rx_pkt_attrib *pattrib = &rframe->u.hdr.attrib; + struct recv_priv *precvpriv = &padapter->recvpriv; + _queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; + +#ifdef DBG_RX_COUNTER_DUMP + if (padapter->dump_rx_cnt_mode & DUMP_DRV_RX_COUNTER) { + if (pattrib->crc_err == 1) + padapter->drv_rx_cnt_crcerror++; + else + padapter->drv_rx_cnt_ok++; + } +#endif + +#ifdef CONFIG_MP_INCLUDED + if (padapter->registrypriv.mp_mode == 1 || padapter->mppriv.bRTWSmbCfg == _TRUE) { + mp_recv_frame(padapter, rframe); + ret = _FAIL; + goto exit; + } else +#endif + { + /* check the frame crtl field and decache */ + ret = validate_recv_frame(padapter, rframe); + if (ret != _SUCCESS) { + rtw_free_recvframe(rframe, pfree_recv_queue);/* free this recv_frame */ + goto exit; + } + } +exit: + return ret; +} + +/*#define DBG_RX_BMC_FRAME*/ +int recv_func_posthandle(_adapter *padapter, union recv_frame *prframe) +{ + int ret = _SUCCESS; + union recv_frame *orig_prframe = prframe; + struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; + struct recv_priv *precvpriv = &padapter->recvpriv; + _queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; +#ifdef CONFIG_TDLS + u8 *psnap_type, *pcategory; +#endif /* CONFIG_TDLS */ + + DBG_COUNTER(padapter->rx_logs.core_rx_post); + + /* DATA FRAME */ + rtw_led_control(padapter, LED_CTL_RX); + + prframe = decryptor(padapter, prframe); + if (prframe == NULL) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s decryptor: drop pkt\n", __FUNCTION__); +#endif + ret = _FAIL; + DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_err); + goto _recv_data_drop; + } + +#ifdef DBG_RX_BMC_FRAME + if (IS_MCAST(pattrib->ra)) { + u8 *pbuf = prframe->u.hdr.rx_data; + u8 *sa_addr = get_sa(pbuf); + + RTW_INFO("%s =>"ADPT_FMT" Rx BC/MC from MAC: "MAC_FMT"\n", __func__, ADPT_ARG(padapter), MAC_ARG(sa_addr)); + } +#endif + +#if 0 + if (padapter->adapter_type == PRIMARY_ADAPTER) { + RTW_INFO("+++\n"); + { + int i; + u8 *ptr = get_recvframe_data(prframe); + for (i = 0; i < 140; i = i + 8) + RTW_INFO("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:", *(ptr + i), + *(ptr + i + 1), *(ptr + i + 2) , *(ptr + i + 3) , *(ptr + i + 4), *(ptr + i + 5), *(ptr + i + 6), *(ptr + i + 7)); + + } + RTW_INFO("---\n"); + } +#endif + +#ifdef CONFIG_TDLS + /* check TDLS frame */ + psnap_type = get_recvframe_data(orig_prframe) + pattrib->hdrlen + pattrib->iv_len + SNAP_SIZE; + pcategory = psnap_type + ETH_TYPE_LEN + PAYLOAD_TYPE_LEN; + + if ((_rtw_memcmp(psnap_type, SNAP_ETH_TYPE_TDLS, ETH_TYPE_LEN)) && + ((*pcategory == RTW_WLAN_CATEGORY_TDLS) || (*pcategory == RTW_WLAN_CATEGORY_P2P))) { + ret = OnTDLS(padapter, prframe); + if (ret == _FAIL) + goto _exit_recv_func; + } +#endif /* CONFIG_TDLS */ + + prframe = recvframe_chk_defrag(padapter, prframe); + if (prframe == NULL) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s recvframe_chk_defrag: drop pkt\n", __FUNCTION__); +#endif + DBG_COUNTER(padapter->rx_logs.core_rx_post_defrag_err); + goto _recv_data_drop; + } + + prframe = portctrl(padapter, prframe); + if (prframe == NULL) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s portctrl: drop pkt\n", __FUNCTION__); +#endif + ret = _FAIL; + DBG_COUNTER(padapter->rx_logs.core_rx_post_portctrl_err); + goto _recv_data_drop; + } + + count_rx_stats(padapter, prframe, NULL); + +#ifdef CONFIG_WAPI_SUPPORT + rtw_wapi_update_info(padapter, prframe); +#endif + +#ifdef CONFIG_80211N_HT + ret = process_recv_indicatepkts(padapter, prframe); + if (ret != _SUCCESS) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s process_recv_indicatepkts fail!\n", __FUNCTION__); +#endif + rtw_free_recvframe(orig_prframe, pfree_recv_queue);/* free this recv_frame */ + DBG_COUNTER(padapter->rx_logs.core_rx_post_indicate_err); + goto _recv_data_drop; + } +#else /* CONFIG_80211N_HT */ + if (!pattrib->amsdu) { + ret = wlanhdr_to_ethhdr(prframe); + if (ret != _SUCCESS) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s wlanhdr_to_ethhdr: drop pkt\n", __FUNCTION__); +#endif + rtw_free_recvframe(orig_prframe, pfree_recv_queue);/* free this recv_frame */ + goto _recv_data_drop; + } + + if (!RTW_CANNOT_RUN(padapter)) { + /* indicate this recv_frame */ + ret = rtw_recv_indicatepkt(padapter, prframe); + if (ret != _SUCCESS) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s rtw_recv_indicatepkt fail!\n", __FUNCTION__); +#endif + goto _recv_data_drop; + } + } else { + +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s recv_func:bDriverStopped(%s) OR bSurpriseRemoved(%s)\n", __func__ + , rtw_is_drv_stopped(padapter) ? "True" : "False" + , rtw_is_surprise_removed(padapter) ? "True" : "False"); +#endif + ret = _FAIL; + rtw_free_recvframe(orig_prframe, pfree_recv_queue); /* free this recv_frame */ + } + + } else if (pattrib->amsdu == 1) { + + ret = amsdu_to_msdu(padapter, prframe); + if (ret != _SUCCESS) { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s amsdu_to_msdu fail\n", __FUNCTION__); +#endif + rtw_free_recvframe(orig_prframe, pfree_recv_queue); + goto _recv_data_drop; + } + } else { +#ifdef DBG_RX_DROP_FRAME + RTW_INFO("DBG_RX_DROP_FRAME %s what is this condition??\n", __FUNCTION__); +#endif + goto _recv_data_drop; + } +#endif /* CONFIG_80211N_HT */ + +_exit_recv_func: + return ret; + +_recv_data_drop: + precvpriv->rx_drop++; + return ret; +} + + +int recv_func(_adapter *padapter, union recv_frame *rframe); +int recv_func(_adapter *padapter, union recv_frame *rframe) +{ + int ret; + struct rx_pkt_attrib *prxattrib = &rframe->u.hdr.attrib; + struct recv_priv *recvpriv = &padapter->recvpriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_priv *mlmepriv = &padapter->mlmepriv; + + if (check_fwstate(mlmepriv, WIFI_MONITOR_STATE)) { + /* monitor mode */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)) + recv_frame_monitor(padapter, rframe); +#endif + ret = _SUCCESS; + goto exit; + } else + + /* check if need to handle uc_swdec_pending_queue*/ + if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && psecuritypriv->busetkipkey) { + union recv_frame *pending_frame; + int cnt = 0; + + while ((pending_frame = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue))) { + cnt++; + DBG_COUNTER(padapter->rx_logs.core_rx_dequeue); + recv_func_posthandle(padapter, pending_frame); + } + + if (cnt) + RTW_INFO(FUNC_ADPT_FMT" dequeue %d from uc_swdec_pending_queue\n", + FUNC_ADPT_ARG(padapter), cnt); + } + + DBG_COUNTER(padapter->rx_logs.core_rx); + ret = recv_func_prehandle(padapter, rframe); + + if (ret == _SUCCESS) { + + /* check if need to enqueue into uc_swdec_pending_queue*/ + if (check_fwstate(mlmepriv, WIFI_STATION_STATE) && + !IS_MCAST(prxattrib->ra) && prxattrib->encrypt > 0 && + (prxattrib->bdecrypted == 0 || psecuritypriv->sw_decrypt == _TRUE) && + psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPAPSK && + !psecuritypriv->busetkipkey) { + DBG_COUNTER(padapter->rx_logs.core_rx_enqueue); + rtw_enqueue_recvframe(rframe, &padapter->recvpriv.uc_swdec_pending_queue); + /* RTW_INFO("%s: no key, enqueue uc_swdec_pending_queue\n", __func__); */ + + if (recvpriv->free_recvframe_cnt < NR_RECVFRAME / 4) { + /* to prevent from recvframe starvation, get recvframe from uc_swdec_pending_queue to free_recvframe_cnt */ + rframe = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue); + if (rframe) + goto do_posthandle; + } + goto exit; + } + +do_posthandle: + ret = recv_func_posthandle(padapter, rframe); + } + +exit: + return ret; +} + + +s32 rtw_recv_entry(union recv_frame *precvframe) +{ + _adapter *padapter; + struct recv_priv *precvpriv; + s32 ret = _SUCCESS; + + + + padapter = precvframe->u.hdr.adapter; + + precvpriv = &padapter->recvpriv; + + + ret = recv_func(padapter, precvframe); + if (ret == _FAIL) { + goto _recv_entry_drop; + } + + + precvpriv->rx_pkts++; + + + return ret; + +_recv_entry_drop: + +#ifdef CONFIG_MP_INCLUDED + if (padapter->registrypriv.mp_mode == 1) + padapter->mppriv.rx_pktloss = precvpriv->rx_drop; +#endif + + + + return ret; +} + +#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS +void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS) +{ + _adapter *adapter = (_adapter *)FunctionContext; + struct recv_priv *recvpriv = &adapter->recvpriv; + + u32 tmp_s, tmp_q; + u8 avg_signal_strength = 0; + u8 avg_signal_qual = 0; + u32 num_signal_strength = 0; + u32 num_signal_qual = 0; + u8 ratio_pre_stat = 0, ratio_curr_stat = 0, ratio_total = 0, ratio_profile = SIGNAL_STAT_CALC_PROFILE_0; + + if (adapter->recvpriv.is_signal_dbg) { + /* update the user specific value, signal_strength_dbg, to signal_strength, rssi */ + adapter->recvpriv.signal_strength = adapter->recvpriv.signal_strength_dbg; + adapter->recvpriv.rssi = (s8)translate_percentage_to_dbm((u8)adapter->recvpriv.signal_strength_dbg); + } else { + + if (recvpriv->signal_strength_data.update_req == 0) { /* update_req is clear, means we got rx */ + avg_signal_strength = recvpriv->signal_strength_data.avg_val; + num_signal_strength = recvpriv->signal_strength_data.total_num; + /* after avg_vals are accquired, we can re-stat the signal values */ + recvpriv->signal_strength_data.update_req = 1; + } + + if (recvpriv->signal_qual_data.update_req == 0) { /* update_req is clear, means we got rx */ + avg_signal_qual = recvpriv->signal_qual_data.avg_val; + num_signal_qual = recvpriv->signal_qual_data.total_num; + /* after avg_vals are accquired, we can re-stat the signal values */ + recvpriv->signal_qual_data.update_req = 1; + } + + if (num_signal_strength == 0) { + if (rtw_get_on_cur_ch_time(adapter) == 0 + || rtw_get_passing_time_ms(rtw_get_on_cur_ch_time(adapter)) < 2 * adapter->mlmeextpriv.mlmext_info.bcn_interval + ) + goto set_timer; + } + + if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == _TRUE + || check_fwstate(&adapter->mlmepriv, _FW_LINKED) == _FALSE + ) + goto set_timer; + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_buddy_check_fwstate(adapter, _FW_UNDER_SURVEY) == _TRUE) + goto set_timer; +#endif + + if (RTW_SIGNAL_STATE_CALC_PROFILE < SIGNAL_STAT_CALC_PROFILE_MAX) + ratio_profile = RTW_SIGNAL_STATE_CALC_PROFILE; + + ratio_pre_stat = signal_stat_calc_profile[ratio_profile][0]; + ratio_curr_stat = signal_stat_calc_profile[ratio_profile][1]; + ratio_total = ratio_pre_stat + ratio_curr_stat; + + /* update value of signal_strength, rssi, signal_qual */ + tmp_s = (ratio_curr_stat * avg_signal_strength + ratio_pre_stat * recvpriv->signal_strength); + if (tmp_s % ratio_total) + tmp_s = tmp_s / ratio_total + 1; + else + tmp_s = tmp_s / ratio_total; + if (tmp_s > 100) + tmp_s = 100; + + tmp_q = (ratio_curr_stat * avg_signal_qual + ratio_pre_stat * recvpriv->signal_qual); + if (tmp_q % ratio_total) + tmp_q = tmp_q / ratio_total + 1; + else + tmp_q = tmp_q / ratio_total; + if (tmp_q > 100) + tmp_q = 100; + + recvpriv->signal_strength = tmp_s; + recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s); + recvpriv->signal_qual = tmp_q; + +#if defined(DBG_RX_SIGNAL_DISPLAY_PROCESSING) && 1 + RTW_INFO(FUNC_ADPT_FMT" signal_strength:%3u, rssi:%3d, signal_qual:%3u" + ", num_signal_strength:%u, num_signal_qual:%u" + ", on_cur_ch_ms:%d" + "\n" + , FUNC_ADPT_ARG(adapter) + , recvpriv->signal_strength + , recvpriv->rssi + , recvpriv->signal_qual + , num_signal_strength, num_signal_qual + , rtw_get_on_cur_ch_time(adapter) ? rtw_get_passing_time_ms(rtw_get_on_cur_ch_time(adapter)) : 0 + ); +#endif + } + +set_timer: + rtw_set_signal_stat_timer(recvpriv); + +} +#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */ + +static void rx_process_rssi(_adapter *padapter, union recv_frame *prframe) +{ + u32 last_rssi, tmp_val; + struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; +#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS + struct signal_stat *signal_stat = &padapter->recvpriv.signal_strength_data; +#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */ + + /* RTW_INFO("process_rssi=> pattrib->rssil(%d) signal_strength(%d)\n ",pattrib->RecvSignalPower,pattrib->signal_strength); */ + /* if(pRfd->Status.bPacketToSelf || pRfd->Status.bPacketBeacon) */ + { +#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS + if (signal_stat->update_req) { + signal_stat->total_num = 0; + signal_stat->total_val = 0; + signal_stat->update_req = 0; + } + + signal_stat->total_num++; + signal_stat->total_val += pattrib->phy_info.SignalStrength; + signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num; +#else /* CONFIG_NEW_SIGNAL_STAT_PROCESS */ + + /* Adapter->RxStats.RssiCalculateCnt++; */ /* For antenna Test */ + if (padapter->recvpriv.signal_strength_data.total_num++ >= PHY_RSSI_SLID_WIN_MAX) { + padapter->recvpriv.signal_strength_data.total_num = PHY_RSSI_SLID_WIN_MAX; + last_rssi = padapter->recvpriv.signal_strength_data.elements[padapter->recvpriv.signal_strength_data.index]; + padapter->recvpriv.signal_strength_data.total_val -= last_rssi; + } + padapter->recvpriv.signal_strength_data.total_val += pattrib->phy_info.SignalStrength; + + padapter->recvpriv.signal_strength_data.elements[padapter->recvpriv.signal_strength_data.index++] = pattrib->phy_info.SignalStrength; + if (padapter->recvpriv.signal_strength_data.index >= PHY_RSSI_SLID_WIN_MAX) + padapter->recvpriv.signal_strength_data.index = 0; + + + tmp_val = padapter->recvpriv.signal_strength_data.total_val / padapter->recvpriv.signal_strength_data.total_num; + + if (padapter->recvpriv.is_signal_dbg) { + padapter->recvpriv.signal_strength = padapter->recvpriv.signal_strength_dbg; + padapter->recvpriv.rssi = (s8)translate_percentage_to_dbm(padapter->recvpriv.signal_strength_dbg); + } else { + padapter->recvpriv.signal_strength = tmp_val; + padapter->recvpriv.rssi = (s8)translate_percentage_to_dbm(tmp_val); + } + +#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */ + } +} + +static void rx_process_link_qual(_adapter *padapter, union recv_frame *prframe) +{ + u32 last_evm = 0, tmpVal; + struct rx_pkt_attrib *pattrib; +#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS + struct signal_stat *signal_stat; +#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */ + + if (prframe == NULL || padapter == NULL) + return; + + pattrib = &prframe->u.hdr.attrib; +#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS + signal_stat = &padapter->recvpriv.signal_qual_data; +#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */ + + /* RTW_INFO("process_link_qual=> pattrib->signal_qual(%d)\n ",pattrib->signal_qual); */ + +#ifdef CONFIG_NEW_SIGNAL_STAT_PROCESS + if (signal_stat->update_req) { + signal_stat->total_num = 0; + signal_stat->total_val = 0; + signal_stat->update_req = 0; + } + + signal_stat->total_num++; + signal_stat->total_val += pattrib->phy_info.SignalQuality; + signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num; + +#else /* CONFIG_NEW_SIGNAL_STAT_PROCESS */ + if (pattrib->phy_info.SignalQuality != 0) { + /* */ + /* 1. Record the general EVM to the sliding window. */ + /* */ + if (padapter->recvpriv.signal_qual_data.total_num++ >= PHY_LINKQUALITY_SLID_WIN_MAX) { + padapter->recvpriv.signal_qual_data.total_num = PHY_LINKQUALITY_SLID_WIN_MAX; + last_evm = padapter->recvpriv.signal_qual_data.elements[padapter->recvpriv.signal_qual_data.index]; + padapter->recvpriv.signal_qual_data.total_val -= last_evm; + } + padapter->recvpriv.signal_qual_data.total_val += pattrib->phy_info.SignalQuality; + + padapter->recvpriv.signal_qual_data.elements[padapter->recvpriv.signal_qual_data.index++] = pattrib->phy_info.SignalQuality; + if (padapter->recvpriv.signal_qual_data.index >= PHY_LINKQUALITY_SLID_WIN_MAX) + padapter->recvpriv.signal_qual_data.index = 0; + + + /* <1> Showed on UI for user, in percentage. */ + tmpVal = padapter->recvpriv.signal_qual_data.total_val / padapter->recvpriv.signal_qual_data.total_num; + padapter->recvpriv.signal_qual = (u8)tmpVal; + + } +#endif /* CONFIG_NEW_SIGNAL_STAT_PROCESS */ +} + +void rx_process_phy_info(_adapter *padapter, union recv_frame *rframe) +{ + /* Check RSSI */ + rx_process_rssi(padapter, rframe); + + /* Check PWDB */ + /* process_PWDB(padapter, rframe); */ + + /* UpdateRxSignalStatistics8192C(Adapter, pRfd); */ + + /* Check EVM */ + rx_process_link_qual(padapter, rframe); + rtw_store_phy_info(padapter, rframe); +} + +void rx_query_phy_status( + union recv_frame *precvframe, + u8 *pphy_status) +{ + PADAPTER padapter = precvframe->u.hdr.adapter; + struct rx_pkt_attrib *pattrib = &precvframe->u.hdr.attrib; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct _odm_phy_status_info_ *pPHYInfo = (struct _odm_phy_status_info_ *)(&pattrib->phy_info); + u8 *wlanhdr; + struct _odm_per_pkt_info_ pkt_info; + u8 *sa; + struct sta_priv *pstapriv; + struct sta_info *psta = NULL; + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; + /* _irqL irqL; */ + + pkt_info.is_packet_match_bssid = _FALSE; + pkt_info.is_packet_to_self = _FALSE; + pkt_info.is_packet_beacon = _FALSE; + + wlanhdr = get_recvframe_data(precvframe); + + pkt_info.is_packet_match_bssid = (!IsFrameTypeCtrl(wlanhdr)) + && (!pattrib->icv_err) && (!pattrib->crc_err) + && _rtw_memcmp(get_hdr_bssid(wlanhdr), get_bssid(&padapter->mlmepriv), ETH_ALEN); + + pkt_info.is_to_self = (!pattrib->icv_err) && (!pattrib->crc_err) + && _rtw_memcmp(get_ra(wlanhdr), adapter_mac_addr(padapter), ETH_ALEN); + + pkt_info.is_packet_to_self = pkt_info.is_packet_match_bssid + && _rtw_memcmp(get_ra(wlanhdr), adapter_mac_addr(padapter), ETH_ALEN); + + pkt_info.is_packet_beacon = pkt_info.is_packet_match_bssid + && (get_frame_sub_type(wlanhdr) == WIFI_BEACON); + + sa = get_ta(wlanhdr); + + pkt_info.station_id = 0xFF; + + if (_rtw_memcmp(adapter_mac_addr(padapter), sa, ETH_ALEN) == _TRUE) { + static u32 start_time = 0; + +#if 0 /*For debug */ + if (IsFrameTypeCtrl(wlanhdr)) { + RTW_INFO("-->Control frame: Y\n"); + RTW_INFO("-->pkt_len: %d\n", pattrib->pkt_len); + RTW_INFO("-->Sub Type = 0x%X\n", get_frame_sub_type(wlanhdr)); + } + + /* Dump first 40 bytes of header */ + int i = 0; + + for (i = 0; i < 40; i++) + RTW_INFO("%d: %X\n", i, *((u8 *)wlanhdr + i)); + + RTW_INFO("\n"); +#endif + + if ((start_time == 0) || (rtw_get_passing_time_ms(start_time) > 5000)) { + RTW_PRINT("Warning!!! %s: Confilc mac addr!!\n", __func__); + start_time = rtw_get_current_time(); + } + pdbgpriv->dbg_rx_conflic_mac_addr_cnt++; + } else { + pstapriv = &padapter->stapriv; + psta = rtw_get_stainfo(pstapriv, sa); + if (psta) + pkt_info.station_id = psta->mac_id; + } + + pkt_info.data_rate = pattrib->data_rate; + + /* _enter_critical_bh(&pHalData->odm_stainfo_lock, &irqL); */ + odm_phy_status_query(&pHalData->odmpriv, pPHYInfo, pphy_status, &pkt_info); + if (psta) + psta->rssi = pattrib->phy_info.RecvSignalPower; + /* _exit_critical_bh(&pHalData->odm_stainfo_lock, &irqL); */ + + { + precvframe->u.hdr.psta = NULL; + if (pkt_info.is_packet_match_bssid + && (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) + ) { + if (psta) { + precvframe->u.hdr.psta = psta; + rx_process_phy_info(padapter, precvframe); + } + } else if (pkt_info.is_packet_to_self || pkt_info.is_packet_beacon) { + + if (psta) + precvframe->u.hdr.psta = psta; + rx_process_phy_info(padapter, precvframe); + } + } + + rtw_odm_parse_rx_phy_status_chinfo(precvframe, pphy_status); +} +/* +* Increase and check if the continual_no_rx_packet of this @param pmlmepriv is larger than MAX_CONTINUAL_NORXPACKET_COUNT +* @return _TRUE: +* @return _FALSE: +*/ +int rtw_inc_and_chk_continual_no_rx_packet(struct sta_info *sta, int tid_index) +{ + + int ret = _FALSE; + int value = ATOMIC_INC_RETURN(&sta->continual_no_rx_packet[tid_index]); + + if (value >= MAX_CONTINUAL_NORXPACKET_COUNT) + ret = _TRUE; + + return ret; +} + +/* +* Set the continual_no_rx_packet of this @param pmlmepriv to 0 +*/ +void rtw_reset_continual_no_rx_packet(struct sta_info *sta, int tid_index) +{ + ATOMIC_SET(&sta->continual_no_rx_packet[tid_index], 0); +} + + +s32 pre_recv_entry(union recv_frame *precvframe, u8 *pphy_status) +{ + s32 ret = _SUCCESS; +#ifdef CONFIG_CONCURRENT_MODE + u8 *pda; + u8 *pbuf = precvframe->u.hdr.rx_data; + _adapter *iface = NULL; + _adapter *primary_padapter = precvframe->u.hdr.adapter; + + pda = get_ra(pbuf); + + if (IS_MCAST(pda) == _FALSE) { /*unicast packets*/ + iface = rtw_get_iface_by_macddr(primary_padapter , pda); + if (NULL == iface) { + RTW_INFO("%s [WARN] Cannot find appropriate adapter - mac_addr : "MAC_FMT"\n", __func__, MAC_ARG(pda)); + /*rtw_warn_on(1);*/ + } else + precvframe->u.hdr.adapter = iface; + } else /* Handle BC/MC Packets */ + rtw_mi_buddy_clone_bcmc_packet(primary_padapter, precvframe, pphy_status); +#endif + + return ret; +} + +#ifdef CONFIG_RECV_THREAD_MODE +thread_return rtw_recv_thread(thread_context context) +{ + _adapter *adapter = (_adapter *)context; + struct recv_priv *recvpriv = &adapter->recvpriv; + s32 err = _SUCCESS; + + thread_enter("RTW_RECV_THREAD"); + + RTW_INFO(FUNC_ADPT_FMT" enter\n", FUNC_ADPT_ARG(adapter)); + + do { + err = _rtw_down_sema(&recvpriv->recv_sema); + if (_FAIL == err) { + RTW_ERR(FUNC_ADPT_FMT" down recv_sema fail!\n", FUNC_ADPT_ARG(adapter)); + goto exit; + } + + if (RTW_CANNOT_RUN(adapter)) { + RTW_INFO(FUNC_ADPT_FMT" DS:%d, SR:%d\n", FUNC_ADPT_ARG(adapter) + , rtw_is_drv_stopped(adapter), rtw_is_surprise_removed(adapter)); + goto exit; + } + + err = rtw_hal_recv_hdl(adapter); + + if (err == RTW_RFRAME_UNAVAIL + || err == RTW_RFRAME_PKT_UNAVAIL + ) { + rtw_msleep_os(1); + _rtw_up_sema(&recvpriv->recv_sema); + } + + flush_signals_thread(); + + } while (err != _FAIL); + +exit: + _rtw_up_sema(&adapter->recvpriv.terminate_recvthread_sema); + RTW_INFO(FUNC_ADPT_FMT" exit\n", FUNC_ADPT_ARG(adapter)); + thread_exit(); +} +#endif /* CONFIG_RECV_THREAD_MODE */ + diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_rf.c b/linux-bsp/drivers/rtl8188eus/core/rtw_rf.c new file mode 100644 index 0000000..38ea85e --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_rf.c @@ -0,0 +1,1164 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_RF_C_ + +#include <drv_types.h> +#include <hal_data.h> + +u8 center_ch_2g[CENTER_CH_2G_NUM] = { +/* G00 */1, 2, +/* G01 */3, 4, 5, +/* G02 */6, 7, 8, +/* G03 */9, 10, 11, +/* G04 */12, 13, +/* G05 */14 +}; + +u8 center_ch_2g_40m[CENTER_CH_2G_40M_NUM] = { + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, +}; + +u8 op_chs_of_cch_2g_40m[CENTER_CH_2G_40M_NUM][2] = { + {1, 5}, /* 3 */ + {2, 6}, /* 4 */ + {3, 7}, /* 5 */ + {4, 8}, /* 6 */ + {5, 9}, /* 7 */ + {6, 10}, /* 8 */ + {7, 11}, /* 9 */ + {8, 12}, /* 10 */ + {9, 13}, /* 11 */ +}; + +u8 center_ch_5g_all[CENTER_CH_5G_ALL_NUM] = { +/* G00 */36, 38, 40, + 42, +/* G01 */44, 46, 48, + /* 50, */ +/* G02 */52, 54, 56, + 58, +/* G03 */60, 62, 64, +/* G04 */100, 102, 104, + 106, +/* G05 */108, 110, 112, + /* 114, */ +/* G06 */116, 118, 120, + 122, +/* G07 */124, 126, 128, +/* G08 */132, 134, 136, + 138, +/* G09 */140, 142, 144, +/* G10 */149, 151, 153, + 155, +/* G11 */157, 159, 161, + /* 163, */ +/* G12 */165, 167, 169, + 171, +/* G13 */173, 175, 177 +}; + +u8 center_ch_5g_20m[CENTER_CH_5G_20M_NUM] = { +/* G00 */36, 40, +/* G01 */44, 48, +/* G02 */52, 56, +/* G03 */60, 64, +/* G04 */100, 104, +/* G05 */108, 112, +/* G06 */116, 120, +/* G07 */124, 128, +/* G08 */132, 136, +/* G09 */140, 144, +/* G10 */149, 153, +/* G11 */157, 161, +/* G12 */165, 169, +/* G13 */173, 177 +}; + +u8 center_ch_5g_40m[CENTER_CH_5G_40M_NUM] = { +/* G00 */38, +/* G01 */46, +/* G02 */54, +/* G03 */62, +/* G04 */102, +/* G05 */110, +/* G06 */118, +/* G07 */126, +/* G08 */134, +/* G09 */142, +/* G10 */151, +/* G11 */159, +/* G12 */167, +/* G13 */175 +}; + +u8 center_ch_5g_20m_40m[CENTER_CH_5G_20M_NUM + CENTER_CH_5G_40M_NUM] = { +/* G00 */36, 38, 40, +/* G01 */44, 46, 48, +/* G02 */52, 54, 56, +/* G03 */60, 62, 64, +/* G04 */100, 102, 104, +/* G05 */108, 110, 112, +/* G06 */116, 118, 120, +/* G07 */124, 126, 128, +/* G08 */132, 134, 136, +/* G09 */140, 142, 144, +/* G10 */149, 151, 153, +/* G11 */157, 159, 161, +/* G12 */165, 167, 169, +/* G13 */173, 175, 177 +}; + +u8 op_chs_of_cch_5g_40m[CENTER_CH_5G_40M_NUM][2] = { + {36, 40}, /* 38 */ + {44, 48}, /* 46 */ + {52, 56}, /* 54 */ + {60, 64}, /* 62 */ + {100, 104}, /* 102 */ + {108, 112}, /* 110 */ + {116, 120}, /* 118 */ + {124, 128}, /* 126 */ + {132, 136}, /* 134 */ + {140, 144}, /* 142 */ + {149, 153}, /* 151 */ + {157, 161}, /* 159 */ + {165, 169}, /* 167 */ + {173, 177}, /* 175 */ +}; + +u8 center_ch_5g_80m[CENTER_CH_5G_80M_NUM] = { +/* G00 ~ G01*/42, +/* G02 ~ G03*/58, +/* G04 ~ G05*/106, +/* G06 ~ G07*/122, +/* G08 ~ G09*/138, +/* G10 ~ G11*/155, +/* G12 ~ G13*/171 +}; + +u8 op_chs_of_cch_5g_80m[CENTER_CH_5G_80M_NUM][4] = { + {36, 40, 44, 48}, /* 42 */ + {52, 56, 60, 64}, /* 58 */ + {100, 104, 108, 112}, /* 106 */ + {116, 120, 124, 128}, /* 122 */ + {132, 136, 140, 144}, /* 138 */ + {149, 153, 157, 161}, /* 155 */ + {165, 169, 173, 177}, /* 171 */ +}; + +u8 center_ch_5g_160m[CENTER_CH_5G_160M_NUM] = { +/* G00 ~ G03*/50, +/* G04 ~ G07*/114, +/* G10 ~ G13*/163 +}; + +u8 op_chs_of_cch_5g_160m[CENTER_CH_5G_160M_NUM][8] = { + {36, 40, 44, 48, 52, 56, 60, 64}, /* 50 */ + {100, 104, 108, 112, 116, 120, 124, 128}, /* 114 */ + {149, 153, 157, 161, 165, 169, 173, 177}, /* 163 */ +}; + +struct center_chs_ent_t { + u8 ch_num; + u8 *chs; +}; + +struct center_chs_ent_t center_chs_2g_by_bw[] = { + {CENTER_CH_2G_NUM, center_ch_2g}, + {CENTER_CH_2G_40M_NUM, center_ch_2g_40m}, +}; + +struct center_chs_ent_t center_chs_5g_by_bw[] = { + {CENTER_CH_5G_20M_NUM, center_ch_5g_20m}, + {CENTER_CH_5G_40M_NUM, center_ch_5g_40m}, + {CENTER_CH_5G_80M_NUM, center_ch_5g_80m}, + {CENTER_CH_5G_160M_NUM, center_ch_5g_160m}, +}; + +/* + * Get center channel of smaller bandwidth by @param cch, @param bw, @param offset + * @cch: the given center channel + * @bw: the given bandwidth + * @offset: the given primary SC offset of the given bandwidth + * + * return center channel of smaller bandiwdth if valid, or 0 + */ +u8 rtw_get_scch_by_cch_offset(u8 cch, u8 bw, u8 offset) +{ + int i; + u8 t_cch = 0; + + if (bw == CHANNEL_WIDTH_20) { + t_cch = cch; + goto exit; + } + + if (offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) { + rtw_warn_on(1); + goto exit; + } + + /* 2.4G, 40MHz */ + if (cch >= 3 && cch <= 11 && bw == CHANNEL_WIDTH_40) { + t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 2 : cch - 2; + goto exit; + } + + /* 5G, 160MHz */ + if (cch >= 50 && cch <= 163 && bw == CHANNEL_WIDTH_160) { + t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 8 : cch - 8; + goto exit; + + /* 5G, 80MHz */ + } else if (cch >= 42 && cch <= 171 && bw == CHANNEL_WIDTH_80) { + t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 4 : cch - 4; + goto exit; + + /* 5G, 40MHz */ + } else if (cch >= 38 && cch <= 175 && bw == CHANNEL_WIDTH_40) { + t_cch = (offset == HAL_PRIME_CHNL_OFFSET_UPPER) ? cch + 2 : cch - 2; + goto exit; + + } else { + rtw_warn_on(1); + goto exit; + } + +exit: + return t_cch; +} + +struct op_chs_ent_t { + u8 ch_num; + u8 *chs; +}; + +struct op_chs_ent_t op_chs_of_cch_2g_by_bw[] = { + {1, center_ch_2g}, + {2, (u8 *)op_chs_of_cch_2g_40m}, +}; + +struct op_chs_ent_t op_chs_of_cch_5g_by_bw[] = { + {1, center_ch_5g_20m}, + {2, (u8 *)op_chs_of_cch_5g_40m}, + {4, (u8 *)op_chs_of_cch_5g_80m}, + {8, (u8 *)op_chs_of_cch_5g_160m}, +}; + +inline u8 center_chs_2g_num(u8 bw) +{ + if (bw > CHANNEL_WIDTH_40) + return 0; + + return center_chs_2g_by_bw[bw].ch_num; +} + +inline u8 center_chs_2g(u8 bw, u8 id) +{ + if (bw > CHANNEL_WIDTH_40) + return 0; + + if (id >= center_chs_2g_num(bw)) + return 0; + + return center_chs_2g_by_bw[bw].chs[id]; +} + +inline u8 center_chs_5g_num(u8 bw) +{ + if (bw > CHANNEL_WIDTH_80) + return 0; + + return center_chs_5g_by_bw[bw].ch_num; +} + +inline u8 center_chs_5g(u8 bw, u8 id) +{ + if (bw > CHANNEL_WIDTH_80) + return 0; + + if (id >= center_chs_5g_num(bw)) + return 0; + + return center_chs_5g_by_bw[bw].chs[id]; +} + +/* + * Get available op channels by @param cch, @param bw + * @cch: the given center channel + * @bw: the given bandwidth + * @op_chs: the pointer to return pointer of op channel array + * @op_ch_num: the pointer to return pointer of op channel number + * + * return valid (1) or not (0) + */ +u8 rtw_get_op_chs_by_cch_bw(u8 cch, u8 bw, u8 **op_chs, u8 *op_ch_num) +{ + int i; + struct center_chs_ent_t *c_chs_ent = NULL; + struct op_chs_ent_t *op_chs_ent = NULL; + u8 valid = 1; + + if (cch <= 14 + && bw >= CHANNEL_WIDTH_20 && bw <= CHANNEL_WIDTH_40 + ) { + c_chs_ent = ¢er_chs_2g_by_bw[bw]; + op_chs_ent = &op_chs_of_cch_2g_by_bw[bw]; + } else if (cch >= 36 && cch <= 177 + && bw >= CHANNEL_WIDTH_20 && bw <= CHANNEL_WIDTH_160 + ) { + c_chs_ent = ¢er_chs_5g_by_bw[bw]; + op_chs_ent = &op_chs_of_cch_5g_by_bw[bw]; + } else { + valid = 0; + goto exit; + } + + for (i = 0; i < c_chs_ent->ch_num; i++) + if (cch == *(c_chs_ent->chs + i)) + break; + + if (i == c_chs_ent->ch_num) { + valid = 0; + goto exit; + } + + *op_chs = op_chs_ent->chs + op_chs_ent->ch_num * i; + *op_ch_num = op_chs_ent->ch_num; + +exit: + return valid; +} + +u8 rtw_get_ch_group(u8 ch, u8 *group, u8 *cck_group) +{ + BAND_TYPE band = BAND_MAX; + s8 gp = -1, cck_gp = -1; + + if (ch <= 14) { + band = BAND_ON_2_4G; + + if (1 <= ch && ch <= 2) + gp = 0; + else if (3 <= ch && ch <= 5) + gp = 1; + else if (6 <= ch && ch <= 8) + gp = 2; + else if (9 <= ch && ch <= 11) + gp = 3; + else if (12 <= ch && ch <= 14) + gp = 4; + else + band = BAND_MAX; + + if (ch == 14) + cck_gp = 5; + else + cck_gp = gp; + } else { + band = BAND_ON_5G; + + if (36 <= ch && ch <= 42) + gp = 0; + else if (44 <= ch && ch <= 48) + gp = 1; + else if (50 <= ch && ch <= 58) + gp = 2; + else if (60 <= ch && ch <= 64) + gp = 3; + else if (100 <= ch && ch <= 106) + gp = 4; + else if (108 <= ch && ch <= 114) + gp = 5; + else if (116 <= ch && ch <= 122) + gp = 6; + else if (124 <= ch && ch <= 130) + gp = 7; + else if (132 <= ch && ch <= 138) + gp = 8; + else if (140 <= ch && ch <= 144) + gp = 9; + else if (149 <= ch && ch <= 155) + gp = 10; + else if (157 <= ch && ch <= 161) + gp = 11; + else if (165 <= ch && ch <= 171) + gp = 12; + else if (173 <= ch && ch <= 177) + gp = 13; + else + band = BAND_MAX; + } + + if (band == BAND_MAX + || (band == BAND_ON_2_4G && cck_gp == -1) + || gp == -1 + ) { + RTW_WARN("%s invalid channel:%u", __func__, ch); + rtw_warn_on(1); + goto exit; + } + + if (group) + *group = gp; + if (cck_group && band == BAND_ON_2_4G) + *cck_group = cck_gp; + +exit: + return band; +} + +int rtw_ch2freq(int chan) +{ + /* see 802.11 17.3.8.3.2 and Annex J + * there are overlapping channel numbers in 5GHz and 2GHz bands */ + + /* + * RTK: don't consider the overlapping channel numbers: 5G channel <= 14, + * because we don't support it. simply judge from channel number + */ + + if (chan >= 1 && chan <= 14) { + if (chan == 14) + return 2484; + else if (chan < 14) + return 2407 + chan * 5; + } else if (chan >= 36 && chan <= 177) + return 5000 + chan * 5; + + return 0; /* not supported */ +} + +int rtw_freq2ch(int freq) +{ + /* see 802.11 17.3.8.3.2 and Annex J */ + if (freq == 2484) + return 14; + else if (freq < 2484) + return (freq - 2407) / 5; + else if (freq >= 4910 && freq <= 4980) + return (freq - 4000) / 5; + else if (freq <= 45000) /* DMG band lower limit */ + return (freq - 5000) / 5; + else if (freq >= 58320 && freq <= 64800) + return (freq - 56160) / 2160; + else + return 0; +} + +bool rtw_chbw_to_freq_range(u8 ch, u8 bw, u8 offset, u32 *hi, u32 *lo) +{ + u8 c_ch; + u32 freq; + u32 hi_ret = 0, lo_ret = 0; + int i; + bool valid = _FALSE; + + if (hi) + *hi = 0; + if (lo) + *lo = 0; + + c_ch = rtw_get_center_ch(ch, bw, offset); + freq = rtw_ch2freq(c_ch); + + if (!freq) { + rtw_warn_on(1); + goto exit; + } + + if (bw == CHANNEL_WIDTH_80) { + hi_ret = freq + 40; + lo_ret = freq - 40; + } else if (bw == CHANNEL_WIDTH_40) { + hi_ret = freq + 20; + lo_ret = freq - 20; + } else if (bw == CHANNEL_WIDTH_20) { + hi_ret = freq + 10; + lo_ret = freq - 10; + } else + rtw_warn_on(1); + + if (hi) + *hi = hi_ret; + if (lo) + *lo = lo_ret; + + valid = _TRUE; + +exit: + return valid; +} + +const char *const _ch_width_str[] = { + "20MHz", + "40MHz", + "80MHz", + "160MHz", + "80_80MHz", + "CHANNEL_WIDTH_MAX", +}; + +const u8 _ch_width_to_bw_cap[] = { + BW_CAP_20M, + BW_CAP_40M, + BW_CAP_80M, + BW_CAP_160M, + BW_CAP_80_80M, + 0, +}; + +const char *const _band_str[] = { + "2.4G", + "5G", + "BOTH", + "BAND_MAX", +}; + +const u8 _band_to_band_cap[] = { + BAND_CAP_2G, + BAND_CAP_5G, + 0, + 0, +}; + +const u8 _rf_type_to_rf_tx_cnt[] = { + 1, + 2, + 2, + 1, + 2, + 2, + 3, + 3, + 4, +}; + +const u8 _rf_type_to_rf_rx_cnt[] = { + 2, + 4, + 2, + 1, + 2, + 3, + 3, + 4, + 4, +}; + +#ifdef CONFIG_80211AC_VHT +#define COUNTRY_CHPLAN_ASSIGN_EN_11AC(_val) , .en_11ac = (_val) +#else +#define COUNTRY_CHPLAN_ASSIGN_EN_11AC(_val) +#endif + +#if RTW_DEF_MODULE_REGULATORY_CERT +#define COUNTRY_CHPLAN_ASSIGN_DEF_MODULE_FLAGS(_val) , .def_module_flags = (_val) +#else +#define COUNTRY_CHPLAN_ASSIGN_DEF_MODULE_FLAGS(_val) +#endif + +/* has def_module_flags specified, used by common map and HAL dfference map */ +#define COUNTRY_CHPLAN_ENT(_alpha2, _chplan, _en_11ac, _def_module_flags) \ + {.alpha2 = (_alpha2), .chplan = (_chplan) \ + COUNTRY_CHPLAN_ASSIGN_EN_11AC(_en_11ac) \ + COUNTRY_CHPLAN_ASSIGN_DEF_MODULE_FLAGS(_def_module_flags) \ + } + +#ifdef CONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP + +#include "../platform/custom_country_chplan.h" + +#elif RTW_DEF_MODULE_REGULATORY_CERT + +#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8821AE_HMC_M2) +static const struct country_chplan RTL8821AE_HMC_M2_country_chplan_map[] = { + COUNTRY_CHPLAN_ENT("CN", 0x51, 1, 0xFB), /* China */ + COUNTRY_CHPLAN_ENT("RU", 0x59, 0, 0xFB), /* Russia(fac/gost), Kaliningrad */ + COUNTRY_CHPLAN_ENT("UA", 0x26, 0, 0xFB), /* Ukraine */ +}; +static const u16 RTL8821AE_HMC_M2_country_chplan_map_sz = sizeof(RTL8821AE_HMC_M2_country_chplan_map) / sizeof(struct country_chplan); +#endif + +#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8821AU) +static const struct country_chplan RTL8821AU_country_chplan_map[] = { + COUNTRY_CHPLAN_ENT("RU", 0x59, 0, 0xFB), /* Russia(fac/gost), Kaliningrad */ + COUNTRY_CHPLAN_ENT("UA", 0x26, 0, 0xFB), /* Ukraine */ +}; +static const u16 RTL8821AU_country_chplan_map_sz = sizeof(RTL8821AU_country_chplan_map) / sizeof(struct country_chplan); +#endif + +#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8812AENF_NGFF) +static const struct country_chplan RTL8812AENF_NGFF_country_chplan_map[] = { +}; +static const u16 RTL8812AENF_NGFF_country_chplan_map_sz = sizeof(RTL8812AENF_NGFF_country_chplan_map) / sizeof(struct country_chplan); +#endif + +#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8812AEBT_HMC) +static const struct country_chplan RTL8812AEBT_HMC_country_chplan_map[] = { +}; +static const u16 RTL8812AEBT_HMC_country_chplan_map_sz = sizeof(RTL8812AEBT_HMC_country_chplan_map) / sizeof(struct country_chplan); +#endif + +#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8188EE_HMC_M2) +static const struct country_chplan RTL8188EE_HMC_M2_country_chplan_map[] = { +}; +static const u16 RTL8188EE_HMC_M2_country_chplan_map_sz = sizeof(RTL8188EE_HMC_M2_country_chplan_map) / sizeof(struct country_chplan); +#endif + +#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8723BE_HMC_M2) +static const struct country_chplan RTL8723BE_HMC_M2_country_chplan_map[] = { +}; +static const u16 RTL8723BE_HMC_M2_country_chplan_map_sz = sizeof(RTL8723BE_HMC_M2_country_chplan_map) / sizeof(struct country_chplan); +#endif + +#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8723BS_NGFF1216) +static const struct country_chplan RTL8723BS_NGFF1216_country_chplan_map[] = { +}; +static const u16 RTL8723BS_NGFF1216_country_chplan_map_sz = sizeof(RTL8723BS_NGFF1216_country_chplan_map) / sizeof(struct country_chplan); +#endif + +#if (RTW_DEF_MODULE_REGULATORY_CERT & RTW_MODULE_RTL8192EEBT_HMC_M2) +static const struct country_chplan RTL8192EEBT_HMC_M2_country_chplan_map[] = { +}; +static const u16 RTL8192EEBT_HMC_M2_country_chplan_map_sz = sizeof(RTL8192EEBT_HMC_M2_country_chplan_map) / sizeof(struct country_chplan); +#endif + +/** + * rtw_def_module_get_chplan_from_country - + * @country_code: string of country code + * @return: + * Return NULL for case referring to common map + */ +static const struct country_chplan *rtw_def_module_get_chplan_from_country(const char *country_code) +{ + const struct country_chplan *ent = NULL; + const struct country_chplan *hal_map = NULL; + u16 hal_map_sz = 0; + int i; + + /* TODO: runtime selection for multi driver */ +#if (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8821AE_HMC_M2) + hal_map = RTL8821AE_HMC_M2_country_chplan_map; + hal_map_sz = RTL8821AE_HMC_M2_country_chplan_map_sz; +#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8821AU) + hal_map = RTL8821AU_country_chplan_map; + hal_map_sz = RTL8821AU_country_chplan_map_sz; +#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8812AENF_NGFF) + hal_map = RTL8812AENF_NGFF_country_chplan_map; + hal_map_sz = RTL8812AENF_NGFF_country_chplan_map_sz; +#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8812AEBT_HMC) + hal_map = RTL8812AEBT_HMC_country_chplan_map; + hal_map_sz = RTL8812AEBT_HMC_country_chplan_map_sz; +#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8188EE_HMC_M2) + hal_map = RTL8188EE_HMC_M2_country_chplan_map; + hal_map_sz = RTL8188EE_HMC_M2_country_chplan_map_sz; +#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8723BE_HMC_M2) + hal_map = RTL8723BE_HMC_M2_country_chplan_map; + hal_map_sz = RTL8723BE_HMC_M2_country_chplan_map_sz; +#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8723BS_NGFF1216) + hal_map = RTL8723BS_NGFF1216_country_chplan_map; + hal_map_sz = RTL8723BS_NGFF1216_country_chplan_map_sz; +#elif (RTW_DEF_MODULE_REGULATORY_CERT == RTW_MODULE_RTL8192EEBT_HMC_M2) + hal_map = RTL8192EEBT_HMC_M2_country_chplan_map; + hal_map_sz = RTL8192EEBT_HMC_M2_country_chplan_map_sz; +#endif + + if (hal_map == NULL || hal_map_sz == 0) + goto exit; + + for (i = 0; i < hal_map_sz; i++) { + if (strncmp(country_code, hal_map[i].alpha2, 2) == 0) { + ent = &hal_map[i]; + break; + } + } + +exit: + return ent; +} +#endif /* CONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP or RTW_DEF_MODULE_REGULATORY_CERT */ + +static const struct country_chplan country_chplan_map[] = { + COUNTRY_CHPLAN_ENT("AD", 0x26, 1, 0x00), /* Andorra */ + COUNTRY_CHPLAN_ENT("AE", 0x26, 1, 0xFB), /* United Arab Emirates */ + COUNTRY_CHPLAN_ENT("AF", 0x42, 1, 0x00), /* Afghanistan */ + COUNTRY_CHPLAN_ENT("AG", 0x30, 1, 0x00), /* Antigua & Barbuda */ + COUNTRY_CHPLAN_ENT("AI", 0x26, 1, 0x00), /* Anguilla(UK) */ + COUNTRY_CHPLAN_ENT("AL", 0x26, 1, 0xF1), /* Albania */ + COUNTRY_CHPLAN_ENT("AM", 0x26, 1, 0xB0), /* Armenia */ + COUNTRY_CHPLAN_ENT("AO", 0x26, 1, 0xE0), /* Angola */ + COUNTRY_CHPLAN_ENT("AQ", 0x26, 1, 0x00), /* Antarctica */ + COUNTRY_CHPLAN_ENT("AR", 0x57, 1, 0xF3), /* Argentina */ + COUNTRY_CHPLAN_ENT("AS", 0x34, 1, 0x00), /* American Samoa */ + COUNTRY_CHPLAN_ENT("AT", 0x26, 1, 0xFB), /* Austria */ + COUNTRY_CHPLAN_ENT("AU", 0x45, 1, 0xFB), /* Australia */ + COUNTRY_CHPLAN_ENT("AW", 0x34, 1, 0xB0), /* Aruba */ + COUNTRY_CHPLAN_ENT("AZ", 0x26, 1, 0xF1), /* Azerbaijan */ + COUNTRY_CHPLAN_ENT("BA", 0x26, 1, 0xF1), /* Bosnia & Herzegovina */ + COUNTRY_CHPLAN_ENT("BB", 0x34, 1, 0x50), /* Barbados */ + COUNTRY_CHPLAN_ENT("BD", 0x26, 1, 0xF1), /* Bangladesh */ + COUNTRY_CHPLAN_ENT("BE", 0x26, 1, 0xFB), /* Belgium */ + COUNTRY_CHPLAN_ENT("BF", 0x26, 1, 0xB0), /* Burkina Faso */ + COUNTRY_CHPLAN_ENT("BG", 0x26, 1, 0xF1), /* Bulgaria */ + COUNTRY_CHPLAN_ENT("BH", 0x47, 1, 0xF1), /* Bahrain */ + COUNTRY_CHPLAN_ENT("BI", 0x26, 1, 0xB0), /* Burundi */ + COUNTRY_CHPLAN_ENT("BJ", 0x26, 1, 0xB0), /* Benin */ + COUNTRY_CHPLAN_ENT("BN", 0x47, 1, 0x10), /* Brunei */ + COUNTRY_CHPLAN_ENT("BO", 0x30, 1, 0xF1), /* Bolivia */ + COUNTRY_CHPLAN_ENT("BR", 0x34, 1, 0xF1), /* Brazil */ + COUNTRY_CHPLAN_ENT("BS", 0x34, 1, 0x20), /* Bahamas */ + COUNTRY_CHPLAN_ENT("BW", 0x26, 1, 0xF1), /* Botswana */ + COUNTRY_CHPLAN_ENT("BY", 0x26, 1, 0xF1), /* Belarus */ + COUNTRY_CHPLAN_ENT("BZ", 0x34, 1, 0x00), /* Belize */ + COUNTRY_CHPLAN_ENT("CA", 0x34, 1, 0xFB), /* Canada */ + COUNTRY_CHPLAN_ENT("CC", 0x26, 1, 0x00), /* Cocos (Keeling) Islands (Australia) */ + COUNTRY_CHPLAN_ENT("CD", 0x26, 1, 0xB0), /* Congo, Republic of the */ + COUNTRY_CHPLAN_ENT("CF", 0x26, 1, 0xB0), /* Central African Republic */ + COUNTRY_CHPLAN_ENT("CG", 0x26, 1, 0xB0), /* Congo, Democratic Republic of the. Zaire */ + COUNTRY_CHPLAN_ENT("CH", 0x26, 1, 0xFB), /* Switzerland */ + COUNTRY_CHPLAN_ENT("CI", 0x26, 1, 0xF1), /* Cote d'Ivoire */ + COUNTRY_CHPLAN_ENT("CK", 0x26, 1, 0x00), /* Cook Islands */ + COUNTRY_CHPLAN_ENT("CL", 0x30, 1, 0xF1), /* Chile */ + COUNTRY_CHPLAN_ENT("CM", 0x26, 1, 0xB0), /* Cameroon */ + COUNTRY_CHPLAN_ENT("CN", 0x48, 1, 0xFB), /* China */ + COUNTRY_CHPLAN_ENT("CO", 0x34, 1, 0xF1), /* Colombia */ + COUNTRY_CHPLAN_ENT("CR", 0x34, 1, 0xF1), /* Costa Rica */ + COUNTRY_CHPLAN_ENT("CV", 0x26, 1, 0xB0), /* Cape Verde */ + COUNTRY_CHPLAN_ENT("CX", 0x45, 1, 0x00), /* Christmas Island (Australia) */ + COUNTRY_CHPLAN_ENT("CY", 0x26, 1, 0xFB), /* Cyprus */ + COUNTRY_CHPLAN_ENT("CZ", 0x26, 1, 0xFB), /* Czech Republic */ + COUNTRY_CHPLAN_ENT("DE", 0x26, 1, 0xFB), /* Germany */ + COUNTRY_CHPLAN_ENT("DJ", 0x26, 1, 0x80), /* Djibouti */ + COUNTRY_CHPLAN_ENT("DK", 0x26, 1, 0xFB), /* Denmark */ + COUNTRY_CHPLAN_ENT("DM", 0x34, 1, 0x00), /* Dominica */ + COUNTRY_CHPLAN_ENT("DO", 0x34, 1, 0xF1), /* Dominican Republic */ + COUNTRY_CHPLAN_ENT("DZ", 0x26, 1, 0xF1), /* Algeria */ + COUNTRY_CHPLAN_ENT("EC", 0x34, 1, 0xF1), /* Ecuador */ + COUNTRY_CHPLAN_ENT("EE", 0x26, 1, 0xFB), /* Estonia */ + COUNTRY_CHPLAN_ENT("EG", 0x47, 0, 0xF1), /* Egypt */ + COUNTRY_CHPLAN_ENT("EH", 0x47, 1, 0x80), /* Western Sahara */ + COUNTRY_CHPLAN_ENT("ER", 0x26, 1, 0x00), /* Eritrea */ + COUNTRY_CHPLAN_ENT("ES", 0x26, 1, 0xFB), /* Spain, Canary Islands, Ceuta, Melilla */ + COUNTRY_CHPLAN_ENT("ET", 0x26, 1, 0xB0), /* Ethiopia */ + COUNTRY_CHPLAN_ENT("FI", 0x26, 1, 0xFB), /* Finland */ + COUNTRY_CHPLAN_ENT("FJ", 0x34, 1, 0x00), /* Fiji */ + COUNTRY_CHPLAN_ENT("FK", 0x26, 1, 0x00), /* Falkland Islands (Islas Malvinas) (UK) */ + COUNTRY_CHPLAN_ENT("FM", 0x34, 1, 0x00), /* Micronesia, Federated States of (USA) */ + COUNTRY_CHPLAN_ENT("FO", 0x26, 1, 0x00), /* Faroe Islands (Denmark) */ + COUNTRY_CHPLAN_ENT("FR", 0x26, 1, 0xFB), /* France */ + COUNTRY_CHPLAN_ENT("GA", 0x26, 1, 0xB0), /* Gabon */ + COUNTRY_CHPLAN_ENT("GB", 0x26, 1, 0xFB), /* Great Britain (United Kingdom; England) */ + COUNTRY_CHPLAN_ENT("GD", 0x34, 1, 0xB0), /* Grenada */ + COUNTRY_CHPLAN_ENT("GE", 0x26, 1, 0x00), /* Georgia */ + COUNTRY_CHPLAN_ENT("GF", 0x26, 1, 0x80), /* French Guiana */ + COUNTRY_CHPLAN_ENT("GG", 0x26, 1, 0x00), /* Guernsey (UK) */ + COUNTRY_CHPLAN_ENT("GH", 0x26, 1, 0xF1), /* Ghana */ + COUNTRY_CHPLAN_ENT("GI", 0x26, 1, 0x00), /* Gibraltar (UK) */ + COUNTRY_CHPLAN_ENT("GL", 0x26, 1, 0x00), /* Greenland (Denmark) */ + COUNTRY_CHPLAN_ENT("GM", 0x26, 1, 0xB0), /* Gambia */ + COUNTRY_CHPLAN_ENT("GN", 0x26, 1, 0x10), /* Guinea */ + COUNTRY_CHPLAN_ENT("GP", 0x26, 1, 0x00), /* Guadeloupe (France) */ + COUNTRY_CHPLAN_ENT("GQ", 0x26, 1, 0xB0), /* Equatorial Guinea */ + COUNTRY_CHPLAN_ENT("GR", 0x26, 1, 0xFB), /* Greece */ + COUNTRY_CHPLAN_ENT("GS", 0x26, 1, 0x00), /* South Georgia and the Sandwich Islands (UK) */ + COUNTRY_CHPLAN_ENT("GT", 0x34, 1, 0xF1), /* Guatemala */ + COUNTRY_CHPLAN_ENT("GU", 0x34, 1, 0x00), /* Guam (USA) */ + COUNTRY_CHPLAN_ENT("GW", 0x26, 1, 0xB0), /* Guinea-Bissau */ + COUNTRY_CHPLAN_ENT("GY", 0x44, 1, 0x00), /* Guyana */ + COUNTRY_CHPLAN_ENT("HK", 0x26, 1, 0xFB), /* Hong Kong */ + COUNTRY_CHPLAN_ENT("HM", 0x45, 1, 0x00), /* Heard and McDonald Islands (Australia) */ + COUNTRY_CHPLAN_ENT("HN", 0x32, 1, 0xF1), /* Honduras */ + COUNTRY_CHPLAN_ENT("HR", 0x26, 1, 0xF9), /* Croatia */ + COUNTRY_CHPLAN_ENT("HT", 0x34, 1, 0x50), /* Haiti */ + COUNTRY_CHPLAN_ENT("HU", 0x26, 1, 0xFB), /* Hungary */ + COUNTRY_CHPLAN_ENT("ID", 0x54, 0, 0xF3), /* Indonesia */ + COUNTRY_CHPLAN_ENT("IE", 0x26, 1, 0xFB), /* Ireland */ + COUNTRY_CHPLAN_ENT("IL", 0x47, 1, 0xF1), /* Israel */ + COUNTRY_CHPLAN_ENT("IM", 0x26, 1, 0x00), /* Isle of Man (UK) */ + COUNTRY_CHPLAN_ENT("IN", 0x47, 1, 0xF1), /* India */ + COUNTRY_CHPLAN_ENT("IQ", 0x26, 1, 0x00), /* Iraq */ + COUNTRY_CHPLAN_ENT("IR", 0x26, 0, 0x00), /* Iran */ + COUNTRY_CHPLAN_ENT("IS", 0x26, 1, 0xFB), /* Iceland */ + COUNTRY_CHPLAN_ENT("IT", 0x26, 1, 0xFB), /* Italy */ + COUNTRY_CHPLAN_ENT("JE", 0x26, 1, 0x00), /* Jersey (UK) */ + COUNTRY_CHPLAN_ENT("JM", 0x51, 1, 0xF1), /* Jamaica */ + COUNTRY_CHPLAN_ENT("JO", 0x49, 1, 0xFB), /* Jordan */ + COUNTRY_CHPLAN_ENT("JP", 0x27, 1, 0xFF), /* Japan- Telec */ + COUNTRY_CHPLAN_ENT("KE", 0x47, 1, 0xF9), /* Kenya */ + COUNTRY_CHPLAN_ENT("KG", 0x26, 1, 0xF1), /* Kyrgyzstan */ + COUNTRY_CHPLAN_ENT("KH", 0x26, 1, 0xF1), /* Cambodia */ + COUNTRY_CHPLAN_ENT("KI", 0x26, 1, 0x00), /* Kiribati */ + COUNTRY_CHPLAN_ENT("KN", 0x34, 1, 0x00), /* Saint Kitts and Nevis */ + COUNTRY_CHPLAN_ENT("KR", 0x28, 1, 0xFB), /* South Korea */ + COUNTRY_CHPLAN_ENT("KW", 0x47, 1, 0xFB), /* Kuwait */ + COUNTRY_CHPLAN_ENT("KY", 0x34, 1, 0x00), /* Cayman Islands (UK) */ + COUNTRY_CHPLAN_ENT("KZ", 0x26, 1, 0x00), /* Kazakhstan */ + COUNTRY_CHPLAN_ENT("LA", 0x26, 1, 0x00), /* Laos */ + COUNTRY_CHPLAN_ENT("LB", 0x26, 1, 0xF1), /* Lebanon */ + COUNTRY_CHPLAN_ENT("LC", 0x34, 1, 0x00), /* Saint Lucia */ + COUNTRY_CHPLAN_ENT("LI", 0x26, 1, 0xFB), /* Liechtenstein */ + COUNTRY_CHPLAN_ENT("LK", 0x26, 1, 0xF1), /* Sri Lanka */ + COUNTRY_CHPLAN_ENT("LR", 0x26, 1, 0xB0), /* Liberia */ + COUNTRY_CHPLAN_ENT("LS", 0x26, 1, 0xF1), /* Lesotho */ + COUNTRY_CHPLAN_ENT("LT", 0x26, 1, 0xFB), /* Lithuania */ + COUNTRY_CHPLAN_ENT("LU", 0x26, 1, 0xFB), /* Luxembourg */ + COUNTRY_CHPLAN_ENT("LV", 0x26, 1, 0xFB), /* Latvia */ + COUNTRY_CHPLAN_ENT("LY", 0x26, 1, 0x00), /* Libya */ + COUNTRY_CHPLAN_ENT("MA", 0x47, 1, 0xF1), /* Morocco */ + COUNTRY_CHPLAN_ENT("MC", 0x26, 1, 0xFB), /* Monaco */ + COUNTRY_CHPLAN_ENT("MD", 0x26, 1, 0xF1), /* Moldova */ + COUNTRY_CHPLAN_ENT("ME", 0x26, 1, 0xF1), /* Montenegro */ + COUNTRY_CHPLAN_ENT("MF", 0x34, 1, 0x00), /* Saint Martin */ + COUNTRY_CHPLAN_ENT("MG", 0x26, 1, 0x20), /* Madagascar */ + COUNTRY_CHPLAN_ENT("MH", 0x34, 1, 0x00), /* Marshall Islands (USA) */ + COUNTRY_CHPLAN_ENT("MK", 0x26, 1, 0xF1), /* Republic of Macedonia (FYROM) */ + COUNTRY_CHPLAN_ENT("ML", 0x26, 1, 0xB0), /* Mali */ + COUNTRY_CHPLAN_ENT("MM", 0x26, 1, 0x00), /* Burma (Myanmar) */ + COUNTRY_CHPLAN_ENT("MN", 0x26, 1, 0x00), /* Mongolia */ + COUNTRY_CHPLAN_ENT("MO", 0x26, 1, 0x00), /* Macau */ + COUNTRY_CHPLAN_ENT("MP", 0x34, 1, 0x00), /* Northern Mariana Islands (USA) */ + COUNTRY_CHPLAN_ENT("MQ", 0x26, 1, 0x40), /* Martinique (France) */ + COUNTRY_CHPLAN_ENT("MR", 0x26, 1, 0xA0), /* Mauritania */ + COUNTRY_CHPLAN_ENT("MS", 0x26, 1, 0x00), /* Montserrat (UK) */ + COUNTRY_CHPLAN_ENT("MT", 0x26, 1, 0xFB), /* Malta */ + COUNTRY_CHPLAN_ENT("MU", 0x26, 1, 0xB0), /* Mauritius */ + COUNTRY_CHPLAN_ENT("MV", 0x26, 1, 0x00), /* Maldives */ + COUNTRY_CHPLAN_ENT("MW", 0x26, 1, 0xB0), /* Malawi */ + COUNTRY_CHPLAN_ENT("MX", 0x34, 1, 0xF1), /* Mexico */ + COUNTRY_CHPLAN_ENT("MY", 0x47, 1, 0xF1), /* Malaysia */ + COUNTRY_CHPLAN_ENT("MZ", 0x26, 1, 0xF1), /* Mozambique */ + COUNTRY_CHPLAN_ENT("NA", 0x26, 0, 0x00), /* Namibia */ + COUNTRY_CHPLAN_ENT("NC", 0x26, 1, 0x00), /* New Caledonia */ + COUNTRY_CHPLAN_ENT("NE", 0x26, 1, 0xB0), /* Niger */ + COUNTRY_CHPLAN_ENT("NF", 0x45, 1, 0x00), /* Norfolk Island (Australia) */ + COUNTRY_CHPLAN_ENT("NG", 0x50, 1, 0xF9), /* Nigeria */ + COUNTRY_CHPLAN_ENT("NI", 0x34, 1, 0xF1), /* Nicaragua */ + COUNTRY_CHPLAN_ENT("NL", 0x26, 1, 0xFB), /* Netherlands */ + COUNTRY_CHPLAN_ENT("NO", 0x26, 1, 0xFB), /* Norway */ + COUNTRY_CHPLAN_ENT("NP", 0x47, 1, 0xF0), /* Nepal */ + COUNTRY_CHPLAN_ENT("NR", 0x26, 1, 0x00), /* Nauru */ + COUNTRY_CHPLAN_ENT("NU", 0x45, 1, 0x00), /* Niue */ + COUNTRY_CHPLAN_ENT("NZ", 0x45, 1, 0xFB), /* New Zealand */ + COUNTRY_CHPLAN_ENT("OM", 0x26, 1, 0xF9), /* Oman */ + COUNTRY_CHPLAN_ENT("PA", 0x34, 1, 0xF1), /* Panama */ + COUNTRY_CHPLAN_ENT("PE", 0x34, 1, 0xF1), /* Peru */ + COUNTRY_CHPLAN_ENT("PF", 0x26, 1, 0x00), /* French Polynesia (France) */ + COUNTRY_CHPLAN_ENT("PG", 0x26, 1, 0xF1), /* Papua New Guinea */ + COUNTRY_CHPLAN_ENT("PH", 0x26, 1, 0xF1), /* Philippines */ + COUNTRY_CHPLAN_ENT("PK", 0x51, 1, 0xF1), /* Pakistan */ + COUNTRY_CHPLAN_ENT("PL", 0x26, 1, 0xFB), /* Poland */ + COUNTRY_CHPLAN_ENT("PM", 0x26, 1, 0x00), /* Saint Pierre and Miquelon (France) */ + COUNTRY_CHPLAN_ENT("PR", 0x34, 1, 0xF1), /* Puerto Rico */ + COUNTRY_CHPLAN_ENT("PT", 0x26, 1, 0xFB), /* Portugal */ + COUNTRY_CHPLAN_ENT("PW", 0x34, 1, 0x00), /* Palau */ + COUNTRY_CHPLAN_ENT("PY", 0x34, 1, 0xF1), /* Paraguay */ + COUNTRY_CHPLAN_ENT("QA", 0x51, 1, 0xF9), /* Qatar */ + COUNTRY_CHPLAN_ENT("RE", 0x26, 1, 0x00), /* Reunion (France) */ + COUNTRY_CHPLAN_ENT("RO", 0x26, 1, 0xF1), /* Romania */ + COUNTRY_CHPLAN_ENT("RS", 0x26, 1, 0xF1), /* Serbia, Kosovo */ + COUNTRY_CHPLAN_ENT("RU", 0x59, 1, 0xFB), /* Russia(fac/gost), Kaliningrad */ + COUNTRY_CHPLAN_ENT("RW", 0x26, 1, 0xB0), /* Rwanda */ + COUNTRY_CHPLAN_ENT("SA", 0x26, 1, 0xFB), /* Saudi Arabia */ + COUNTRY_CHPLAN_ENT("SB", 0x26, 1, 0x00), /* Solomon Islands */ + COUNTRY_CHPLAN_ENT("SC", 0x34, 1, 0x90), /* Seychelles */ + COUNTRY_CHPLAN_ENT("SE", 0x26, 1, 0xFB), /* Sweden */ + COUNTRY_CHPLAN_ENT("SG", 0x47, 1, 0xFB), /* Singapore */ + COUNTRY_CHPLAN_ENT("SH", 0x26, 1, 0x00), /* Saint Helena (UK) */ + COUNTRY_CHPLAN_ENT("SI", 0x26, 1, 0xFB), /* Slovenia */ + COUNTRY_CHPLAN_ENT("SJ", 0x26, 1, 0x00), /* Svalbard (Norway) */ + COUNTRY_CHPLAN_ENT("SK", 0x26, 1, 0xFB), /* Slovakia */ + COUNTRY_CHPLAN_ENT("SL", 0x26, 1, 0xB0), /* Sierra Leone */ + COUNTRY_CHPLAN_ENT("SM", 0x26, 1, 0x00), /* San Marino */ + COUNTRY_CHPLAN_ENT("SN", 0x26, 1, 0xF1), /* Senegal */ + COUNTRY_CHPLAN_ENT("SO", 0x26, 1, 0x00), /* Somalia */ + COUNTRY_CHPLAN_ENT("SR", 0x34, 1, 0x00), /* Suriname */ + COUNTRY_CHPLAN_ENT("ST", 0x34, 1, 0x80), /* Sao Tome and Principe */ + COUNTRY_CHPLAN_ENT("SV", 0x30, 1, 0xF1), /* El Salvador */ + COUNTRY_CHPLAN_ENT("SX", 0x34, 1, 0x00), /* Sint Marteen */ + COUNTRY_CHPLAN_ENT("SZ", 0x26, 1, 0x20), /* Swaziland */ + COUNTRY_CHPLAN_ENT("TC", 0x26, 1, 0x00), /* Turks and Caicos Islands (UK) */ + COUNTRY_CHPLAN_ENT("TD", 0x26, 1, 0xB0), /* Chad */ + COUNTRY_CHPLAN_ENT("TF", 0x26, 1, 0x80), /* French Southern and Antarctic Lands (FR Southern Territories) */ + COUNTRY_CHPLAN_ENT("TG", 0x26, 1, 0xB0), /* Togo */ + COUNTRY_CHPLAN_ENT("TH", 0x26, 1, 0xF1), /* Thailand */ + COUNTRY_CHPLAN_ENT("TJ", 0x26, 1, 0x40), /* Tajikistan */ + COUNTRY_CHPLAN_ENT("TK", 0x45, 1, 0x00), /* Tokelau */ + COUNTRY_CHPLAN_ENT("TM", 0x26, 1, 0x00), /* Turkmenistan */ + COUNTRY_CHPLAN_ENT("TN", 0x47, 1, 0xF1), /* Tunisia */ + COUNTRY_CHPLAN_ENT("TO", 0x26, 1, 0x00), /* Tonga */ + COUNTRY_CHPLAN_ENT("TR", 0x26, 1, 0xF1), /* Turkey, Northern Cyprus */ + COUNTRY_CHPLAN_ENT("TT", 0x42, 1, 0xF1), /* Trinidad & Tobago */ + COUNTRY_CHPLAN_ENT("TW", 0x39, 1, 0xFF), /* Taiwan */ + COUNTRY_CHPLAN_ENT("TZ", 0x26, 1, 0xF0), /* Tanzania */ + COUNTRY_CHPLAN_ENT("UA", 0x26, 1, 0xFB), /* Ukraine */ + COUNTRY_CHPLAN_ENT("UG", 0x26, 1, 0xF1), /* Uganda */ + COUNTRY_CHPLAN_ENT("US", 0x34, 1, 0xFF), /* United States of America (USA) */ + COUNTRY_CHPLAN_ENT("UY", 0x34, 1, 0xF1), /* Uruguay */ + COUNTRY_CHPLAN_ENT("UZ", 0x47, 1, 0xF0), /* Uzbekistan */ + COUNTRY_CHPLAN_ENT("VA", 0x26, 1, 0x00), /* Holy See (Vatican City) */ + COUNTRY_CHPLAN_ENT("VC", 0x34, 1, 0x10), /* Saint Vincent and the Grenadines */ + COUNTRY_CHPLAN_ENT("VE", 0x30, 1, 0xF1), /* Venezuela */ + COUNTRY_CHPLAN_ENT("VI", 0x34, 1, 0x00), /* United States Virgin Islands (USA) */ + COUNTRY_CHPLAN_ENT("VN", 0x26, 1, 0xF1), /* Vietnam */ + COUNTRY_CHPLAN_ENT("VU", 0x26, 1, 0x00), /* Vanuatu */ + COUNTRY_CHPLAN_ENT("WF", 0x26, 1, 0x00), /* Wallis and Futuna (France) */ + COUNTRY_CHPLAN_ENT("WS", 0x34, 1, 0x00), /* Samoa */ + COUNTRY_CHPLAN_ENT("YE", 0x26, 1, 0x40), /* Yemen */ + COUNTRY_CHPLAN_ENT("YT", 0x26, 1, 0x80), /* Mayotte (France) */ + COUNTRY_CHPLAN_ENT("ZA", 0x26, 1, 0xF1), /* South Africa */ + COUNTRY_CHPLAN_ENT("ZM", 0x26, 1, 0xB0), /* Zambia */ + COUNTRY_CHPLAN_ENT("ZW", 0x26, 1, 0xF1), /* Zimbabwe */ +}; + +u16 const country_chplan_map_sz = sizeof(country_chplan_map) / sizeof(struct country_chplan); + +/* +* rtw_get_chplan_from_country - +* @country_code: string of country code +* +* Return pointer of struct country_chplan entry or NULL when unsupported country_code is given +*/ +const struct country_chplan *rtw_get_chplan_from_country(const char *country_code) +{ + const struct country_chplan *ent = NULL; + const struct country_chplan *map = NULL; + u16 map_sz = 0; + char code[2]; + int i; + + code[0] = alpha_to_upper(country_code[0]); + code[1] = alpha_to_upper(country_code[1]); + +#if !defined(CONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP) && RTW_DEF_MODULE_REGULATORY_CERT + ent = rtw_def_module_get_chplan_from_country(code); + if (ent != NULL) + goto exit; +#endif + +#ifdef CONFIG_CUSTOMIZED_COUNTRY_CHPLAN_MAP + map = CUSTOMIZED_country_chplan_map; + map_sz = CUSTOMIZED_country_chplan_map_sz; +#else + map = country_chplan_map; + map_sz = country_chplan_map_sz; +#endif + + for (i = 0; i < map_sz; i++) { + if (strncmp(code, map[i].alpha2, 2) == 0) { + ent = &map[i]; + break; + } + } + +exit: + #if RTW_DEF_MODULE_REGULATORY_CERT + if (ent && !(COUNTRY_CHPLAN_DEF_MODULE_FALGS(ent) & RTW_DEF_MODULE_REGULATORY_CERT)) + ent = NULL; + #endif + + return ent; +} + +int rtw_ch_to_bb_gain_sel(int ch) +{ + int sel = -1; + + if (ch >= 1 && ch <= 14) + sel = BB_GAIN_2G; +#ifdef CONFIG_IEEE80211_BAND_5GHZ + else if (ch >= 36 && ch < 48) + sel = BB_GAIN_5GLB1; + else if (ch >= 52 && ch <= 64) + sel = BB_GAIN_5GLB2; + else if (ch >= 100 && ch <= 120) + sel = BB_GAIN_5GMB1; + else if (ch >= 124 && ch <= 144) + sel = BB_GAIN_5GMB2; + else if (ch >= 149 && ch <= 177) + sel = BB_GAIN_5GHB; +#endif + + return sel; +} + +s8 rtw_rf_get_kfree_tx_gain_offset(_adapter *padapter, u8 path, u8 ch) +{ + s8 kfree_offset = 0; + +#ifdef CONFIG_RF_POWER_TRIM + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter); + struct kfree_data_t *kfree_data = GET_KFREE_DATA(padapter); + s8 bb_gain_sel = rtw_ch_to_bb_gain_sel(ch); + + if (bb_gain_sel < BB_GAIN_2G || bb_gain_sel >= BB_GAIN_NUM) { + rtw_warn_on(1); + goto exit; + } + + if (kfree_data->flag & KFREE_FLAG_ON) { + kfree_offset = kfree_data->bb_gain[bb_gain_sel][path]; + if (IS_HARDWARE_TYPE_8723D(padapter)) + RTW_INFO("%s path:%s, ch:%u, bb_gain_sel:%d, kfree_offset:%d\n" + , __func__, (path == 0)?"S1":"S0", + ch, bb_gain_sel, kfree_offset); + else + RTW_INFO("%s path:%u, ch:%u, bb_gain_sel:%d, kfree_offset:%d\n" + , __func__, path, ch, bb_gain_sel, kfree_offset); + } +exit: +#endif /* CONFIG_RF_POWER_TRIM */ + return kfree_offset; +} + +void rtw_rf_set_tx_gain_offset(_adapter *adapter, u8 path, s8 offset) +{ + u8 write_value; + u8 target_path = 0; + u32 val32 = 0; + + if (IS_HARDWARE_TYPE_8723D(adapter)) { + target_path = RF_PATH_A; /*in 8723D case path means S0/S1*/ + if (path == PPG_8723D_S1) + RTW_INFO("kfree gain_offset 0x55:0x%x ", + rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff)); + else if (path == PPG_8723D_S0) + RTW_INFO("kfree gain_offset 0x65:0x%x ", + rtw_hal_read_rfreg(adapter, target_path, 0x65, 0xffffffff)); + } else { + target_path = path; + RTW_INFO("kfree gain_offset 0x55:0x%x ", rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff)); + } + + switch (rtw_get_chip_type(adapter)) { +#ifdef CONFIG_RTL8723D + case RTL8723D: + write_value = RF_TX_GAIN_OFFSET_8723D(offset); + if (path == PPG_8723D_S1) + rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value); + else if (path == PPG_8723D_S0) + rtw_hal_write_rfreg(adapter, target_path, 0x65, 0x0f8000, write_value); + break; +#endif /* CONFIG_RTL8723D */ +#ifdef CONFIG_RTL8703B + case RTL8703B: + write_value = RF_TX_GAIN_OFFSET_8703B(offset); + rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value); + break; +#endif /* CONFIG_RTL8703B */ +#ifdef CONFIG_RTL8188F + case RTL8188F: + write_value = RF_TX_GAIN_OFFSET_8188F(offset); + rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0fc000, write_value); + break; +#endif /* CONFIG_RTL8188F */ +#ifdef CONFIG_RTL8192E + case RTL8192E: + write_value = RF_TX_GAIN_OFFSET_8192E(offset); + rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value); + break; +#endif /* CONFIG_RTL8188F */ + +#ifdef CONFIG_RTL8821A + case RTL8821: + write_value = RF_TX_GAIN_OFFSET_8821A(offset); + rtw_hal_write_rfreg(adapter, target_path, 0x55, 0x0f8000, write_value); + break; +#endif /* CONFIG_RTL8821A */ +#if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) + case RTL8814A: + case RTL8822B: + case RTL8821C: + RTW_INFO("\nkfree by PhyDM on the sw CH. path %d\n", path); + break; +#endif /* CONFIG_RTL8814A || CONFIG_RTL8822B || CONFIG_RTL8821C */ + + default: + rtw_warn_on(1); + break; + } + + if (IS_HARDWARE_TYPE_8723D(adapter)) { + if (path == PPG_8723D_S1) + val32 = rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff); + else if (path == PPG_8723D_S0) + val32 = rtw_hal_read_rfreg(adapter, target_path, 0x65, 0xffffffff); + } else { + val32 = rtw_hal_read_rfreg(adapter, target_path, 0x55, 0xffffffff); + } + RTW_INFO(" after :0x%x\n", val32); +} + +void rtw_rf_apply_tx_gain_offset(_adapter *adapter, u8 ch) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + s8 kfree_offset = 0; + s8 tx_pwr_track_offset = 0; /* TODO: 8814A should consider tx pwr track when setting tx gain offset */ + s8 total_offset; + int i, total = 0; + + if (IS_HARDWARE_TYPE_8723D(adapter)) + total = 2; /* S1 and S0 */ + else + total = hal_data->NumTotalRFPath; + + for (i = 0; i < total; i++) { + kfree_offset = rtw_rf_get_kfree_tx_gain_offset(adapter, i, ch); + total_offset = kfree_offset + tx_pwr_track_offset; + rtw_rf_set_tx_gain_offset(adapter, i, total_offset); + } +} + +bool rtw_is_dfs_range(u32 hi, u32 lo) +{ + return rtw_is_range_overlap(hi, lo, 5720 + 10, 5260 - 10) ? _TRUE : _FALSE; +} + +bool rtw_is_dfs_ch(u8 ch, u8 bw, u8 offset) +{ + u32 hi, lo; + + if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE) + return _FALSE; + + return rtw_is_dfs_range(hi, lo) ? _TRUE : _FALSE; +} + +bool rtw_is_long_cac_range(u32 hi, u32 lo, u8 dfs_region) +{ + return (dfs_region == PHYDM_DFS_DOMAIN_ETSI && rtw_is_range_overlap(hi, lo, 5660 + 10, 5600 - 10)) ? _TRUE : _FALSE; +} + +bool rtw_is_long_cac_ch(u8 ch, u8 bw, u8 offset, u8 dfs_region) +{ + u32 hi, lo; + + if (rtw_chbw_to_freq_range(ch, bw, offset, &hi, &lo) == _FALSE) + return _FALSE; + + return rtw_is_long_cac_range(hi, lo, dfs_region) ? _TRUE : _FALSE; +} diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_sdio.c b/linux-bsp/drivers/rtl8188eus/core/rtw_sdio.c new file mode 100644 index 0000000..817d60b --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_sdio.c @@ -0,0 +1,98 @@ +/****************************************************************************** + * + * Copyright(c) 2015 - 2016 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + ******************************************************************************/ +#define _RTW_SDIO_C_ + +#include <drv_types.h> /* struct dvobj_priv and etc. */ +#include <drv_types_sdio.h> /* RTW_SDIO_ADDR_CMD52_GEN */ + +/* + * Description: + * Use SDIO cmd52 or cmd53 to read/write data + * + * Parameters: + * d pointer of device object(struct dvobj_priv) + * addr SDIO address, 17 bits + * buf buffer for I/O + * len length + * write 0:read, 1:write + * cmd52 0:cmd52, 1:cmd53 + * + * Return: + * _SUCCESS I/O ok. + * _FAIL I/O fail. + */ +static u8 sdio_io(struct dvobj_priv *d, u32 addr, void *buf, size_t len, u8 write, u8 cmd52) +{ + int err; + + + if (cmd52) + addr = RTW_SDIO_ADDR_CMD52_GEN(addr); + + if (write) + err = d->intf_ops->write(d, addr, buf, len, 0); + else + err = d->intf_ops->read(d, addr, buf, len, 0); + if (err) { + RTW_INFO("%s: [ERROR] %s FAIL! error(%d)\n", + __FUNCTION__, write ? "write" : "read", err); + return _FAIL; + } + + return _SUCCESS; +} + +u8 rtw_sdio_read_cmd52(struct dvobj_priv *d, u32 addr, void *buf, size_t len) +{ + return sdio_io(d, addr, buf, len, 0, 1); +} + +u8 rtw_sdio_read_cmd53(struct dvobj_priv *d, u32 addr, void *buf, size_t len) +{ + return sdio_io(d, addr, buf, len, 0, 0); +} + +u8 rtw_sdio_write_cmd52(struct dvobj_priv *d, u32 addr, void *buf, size_t len) +{ + return sdio_io(d, addr, buf, len, 1, 1); +} + +u8 rtw_sdio_write_cmd53(struct dvobj_priv *d, u32 addr, void *buf, size_t len) +{ + return sdio_io(d, addr, buf, len, 1, 0); +} + +u8 rtw_sdio_f0_read(struct dvobj_priv *d, u32 addr, void *buf, size_t len) +{ + int err; + u8 ret; + + + ret = _SUCCESS; + addr = RTW_SDIO_ADDR_F0_GEN(addr); + + err = d->intf_ops->read(d, addr, buf, len, 0); + if (err) { + RTW_INFO("%s: [ERROR] Read f0 register FAIL!\n", __FUNCTION__); + ret = _FAIL; + } + + + return ret; +} diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_security.c b/linux-bsp/drivers/rtl8188eus/core/rtw_security.c new file mode 100644 index 0000000..df88f53 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_security.c @@ -0,0 +1,3197 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_SECURITY_C_ + +#include <drv_types.h> + +static const char *_security_type_str[] = { + "N/A", + "WEP40", + "TKIP", + "TKIP_WM", + "AES", + "WEP104", + "SMS4", + "WEP_WPA", + "BIP", +}; + +const char *security_type_str(u8 value) +{ +#ifdef CONFIG_IEEE80211W + if (value <= _BIP_) +#else + if (value <= _WEP_WPA_MIXED_) +#endif + return _security_type_str[value]; + return NULL; +} + +#ifdef DBG_SW_SEC_CNT +#define WEP_SW_ENC_CNT_INC(sec, ra) do {\ + if (is_broadcast_mac_addr(ra)) \ + sec->wep_sw_enc_cnt_bc++; \ + else if (is_multicast_mac_addr(ra)) \ + sec->wep_sw_enc_cnt_mc++; \ + else \ + sec->wep_sw_enc_cnt_uc++; \ + } while (0) + +#define WEP_SW_DEC_CNT_INC(sec, ra) do {\ + if (is_broadcast_mac_addr(ra)) \ + sec->wep_sw_dec_cnt_bc++; \ + else if (is_multicast_mac_addr(ra)) \ + sec->wep_sw_dec_cnt_mc++; \ + else \ + sec->wep_sw_dec_cnt_uc++; \ + } while (0) + +#define TKIP_SW_ENC_CNT_INC(sec, ra) do {\ + if (is_broadcast_mac_addr(ra)) \ + sec->tkip_sw_enc_cnt_bc++; \ + else if (is_multicast_mac_addr(ra)) \ + sec->tkip_sw_enc_cnt_mc++; \ + else \ + sec->tkip_sw_enc_cnt_uc++; \ + } while (0) + +#define TKIP_SW_DEC_CNT_INC(sec, ra) do {\ + if (is_broadcast_mac_addr(ra)) \ + sec->tkip_sw_dec_cnt_bc++; \ + else if (is_multicast_mac_addr(ra)) \ + sec->tkip_sw_dec_cnt_mc++; \ + else \ + sec->tkip_sw_dec_cnt_uc++; \ + } while (0) + +#define AES_SW_ENC_CNT_INC(sec, ra) do {\ + if (is_broadcast_mac_addr(ra)) \ + sec->aes_sw_enc_cnt_bc++; \ + else if (is_multicast_mac_addr(ra)) \ + sec->aes_sw_enc_cnt_mc++; \ + else \ + sec->aes_sw_enc_cnt_uc++; \ + } while (0) + +#define AES_SW_DEC_CNT_INC(sec, ra) do {\ + if (is_broadcast_mac_addr(ra)) \ + sec->aes_sw_dec_cnt_bc++; \ + else if (is_multicast_mac_addr(ra)) \ + sec->aes_sw_dec_cnt_mc++; \ + else \ + sec->aes_sw_dec_cnt_uc++; \ + } while (0) +#else +#define WEP_SW_ENC_CNT_INC(sec, ra) +#define WEP_SW_DEC_CNT_INC(sec, ra) +#define TKIP_SW_ENC_CNT_INC(sec, ra) +#define TKIP_SW_DEC_CNT_INC(sec, ra) +#define AES_SW_ENC_CNT_INC(sec, ra) +#define AES_SW_DEC_CNT_INC(sec, ra) +#endif /* DBG_SW_SEC_CNT */ + +/* *****WEP related***** */ + +#define CRC32_POLY 0x04c11db7 + +struct arc4context { + u32 x; + u32 y; + u8 state[256]; +}; + + +static void arcfour_init(struct arc4context *parc4ctx, u8 *key, u32 key_len) +{ + u32 t, u; + u32 keyindex; + u32 stateindex; + u8 *state; + u32 counter; + state = parc4ctx->state; + parc4ctx->x = 0; + parc4ctx->y = 0; + for (counter = 0; counter < 256; counter++) + state[counter] = (u8)counter; + keyindex = 0; + stateindex = 0; + for (counter = 0; counter < 256; counter++) { + t = state[counter]; + stateindex = (stateindex + key[keyindex] + t) & 0xff; + u = state[stateindex]; + state[stateindex] = (u8)t; + state[counter] = (u8)u; + if (++keyindex >= key_len) + keyindex = 0; + } +} +static u32 arcfour_byte(struct arc4context *parc4ctx) +{ + u32 x; + u32 y; + u32 sx, sy; + u8 *state; + state = parc4ctx->state; + x = (parc4ctx->x + 1) & 0xff; + sx = state[x]; + y = (sx + parc4ctx->y) & 0xff; + sy = state[y]; + parc4ctx->x = x; + parc4ctx->y = y; + state[y] = (u8)sx; + state[x] = (u8)sy; + return state[(sx + sy) & 0xff]; +} + + +static void arcfour_encrypt(struct arc4context *parc4ctx, + u8 *dest, + u8 *src, + u32 len) +{ + u32 i; + for (i = 0; i < len; i++) + dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx); +} + +static sint bcrc32initialized = 0; +static u32 crc32_table[256]; + + +static u8 crc32_reverseBit(u8 data) +{ + return (u8)((data << 7) & 0x80) | ((data << 5) & 0x40) | ((data << 3) & 0x20) | ((data << 1) & 0x10) | ((data >> 1) & 0x08) | ((data >> 3) & 0x04) | ((data >> 5) & 0x02) | (( + data >> 7) & 0x01) ; +} + +static void crc32_init(void) +{ + if (bcrc32initialized == 1) + goto exit; + else { + sint i, j; + u32 c; + u8 *p = (u8 *)&c, *p1; + u8 k; + + c = 0x12340000; + + for (i = 0; i < 256; ++i) { + k = crc32_reverseBit((u8)i); + for (c = ((u32)k) << 24, j = 8; j > 0; --j) + c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1); + p1 = (u8 *)&crc32_table[i]; + + p1[0] = crc32_reverseBit(p[3]); + p1[1] = crc32_reverseBit(p[2]); + p1[2] = crc32_reverseBit(p[1]); + p1[3] = crc32_reverseBit(p[0]); + } + bcrc32initialized = 1; + } +exit: + return; +} + +static u32 getcrc32(u8 *buf, sint len) +{ + u8 *p; + u32 crc; + if (bcrc32initialized == 0) + crc32_init(); + + crc = 0xffffffff; /* preload shift register, per CRC-32 spec */ + + for (p = buf; len > 0; ++p, --len) + crc = crc32_table[(crc ^ *p) & 0xff] ^ (crc >> 8); + return ~crc; /* transmit complement, per CRC-32 spec */ +} + + +/* + Need to consider the fragment situation +*/ +void rtw_wep_encrypt(_adapter *padapter, u8 *pxmitframe) +{ + /* exclude ICV */ + + unsigned char crc[4]; + struct arc4context mycontext; + + sint curfragnum, length; + u32 keylength; + + u8 *pframe, *payload, *iv; /* ,*wepkey */ + u8 wepkey[16]; + u8 hw_hdr_offset = 0; + struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + + + if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) + return; + +#ifdef CONFIG_USB_TX_AGGREGATION + hw_hdr_offset = TXDESC_SIZE + + (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ); +#else +#ifdef CONFIG_TX_EARLY_MODE + hw_hdr_offset = TXDESC_OFFSET + EARLY_MODE_INFO_SIZE; +#else + hw_hdr_offset = TXDESC_OFFSET; +#endif +#endif + + pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset; + + /* start to encrypt each fragment */ + if ((pattrib->encrypt == _WEP40_) || (pattrib->encrypt == _WEP104_)) { + keylength = psecuritypriv->dot11DefKeylen[psecuritypriv->dot11PrivacyKeyIndex]; + + for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { + iv = pframe + pattrib->hdrlen; + _rtw_memcpy(&wepkey[0], iv, 3); + _rtw_memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0], keylength); + payload = pframe + pattrib->iv_len + pattrib->hdrlen; + + if ((curfragnum + 1) == pattrib->nr_frags) { + /* the last fragment */ + + length = pattrib->last_txcmdsz - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len; + + *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length)); + + arcfour_init(&mycontext, wepkey, 3 + keylength); + arcfour_encrypt(&mycontext, payload, payload, length); + arcfour_encrypt(&mycontext, payload + length, crc, 4); + + } else { + length = pxmitpriv->frag_len - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len ; + *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length)); + arcfour_init(&mycontext, wepkey, 3 + keylength); + arcfour_encrypt(&mycontext, payload, payload, length); + arcfour_encrypt(&mycontext, payload + length, crc, 4); + + pframe += pxmitpriv->frag_len; + pframe = (u8 *)RND4((SIZE_PTR)(pframe)); + + } + + } + + WEP_SW_ENC_CNT_INC(psecuritypriv, pattrib->ra); + } + + +} + +void rtw_wep_decrypt(_adapter *padapter, u8 *precvframe) +{ + /* exclude ICV */ + u8 crc[4]; + struct arc4context mycontext; + sint length; + u32 keylength; + u8 *pframe, *payload, *iv, wepkey[16]; + u8 keyindex; + struct rx_pkt_attrib *prxattrib = &(((union recv_frame *)precvframe)->u.hdr.attrib); + struct security_priv *psecuritypriv = &padapter->securitypriv; + + + pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data; + + /* start to decrypt recvframe */ + if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == _WEP104_)) { + iv = pframe + prxattrib->hdrlen; + /* keyindex=(iv[3]&0x3); */ + keyindex = prxattrib->key_index; + keylength = psecuritypriv->dot11DefKeylen[keyindex]; + _rtw_memcpy(&wepkey[0], iv, 3); + /* _rtw_memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0],keylength); */ + _rtw_memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0], keylength); + length = ((union recv_frame *)precvframe)->u.hdr.len - prxattrib->hdrlen - prxattrib->iv_len; + + payload = pframe + prxattrib->iv_len + prxattrib->hdrlen; + + /* decrypt payload include icv */ + arcfour_init(&mycontext, wepkey, 3 + keylength); + arcfour_encrypt(&mycontext, payload, payload, length); + + /* calculate icv and compare the icv */ + *((u32 *)crc) = le32_to_cpu(getcrc32(payload, length - 4)); + + + WEP_SW_DEC_CNT_INC(psecuritypriv, prxattrib->ra); + } + + + return; + +} + +/* 3 =====TKIP related===== */ + +static u32 secmicgetuint32(u8 *p) +/* Convert from Byte[] to Us4Byte32 in a portable way */ +{ + s32 i; + u32 res = 0; + for (i = 0; i < 4; i++) + res |= ((u32)(*p++)) << (8 * i); + return res; +} + +static void secmicputuint32(u8 *p, u32 val) +/* Convert from Us4Byte32 to Byte[] in a portable way */ +{ + long i; + for (i = 0; i < 4; i++) { + *p++ = (u8)(val & 0xff); + val >>= 8; + } +} + +static void secmicclear(struct mic_data *pmicdata) +{ + /* Reset the state to the empty message. */ + pmicdata->L = pmicdata->K0; + pmicdata->R = pmicdata->K1; + pmicdata->nBytesInM = 0; + pmicdata->M = 0; +} + +void rtw_secmicsetkey(struct mic_data *pmicdata, u8 *key) +{ + /* Set the key */ + pmicdata->K0 = secmicgetuint32(key); + pmicdata->K1 = secmicgetuint32(key + 4); + /* and reset the message */ + secmicclear(pmicdata); +} + +void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b) +{ + /* Append the byte to our word-sized buffer */ + pmicdata->M |= ((unsigned long)b) << (8 * pmicdata->nBytesInM); + pmicdata->nBytesInM++; + /* Process the word if it is full. */ + if (pmicdata->nBytesInM >= 4) { + pmicdata->L ^= pmicdata->M; + pmicdata->R ^= ROL32(pmicdata->L, 17); + pmicdata->L += pmicdata->R; + pmicdata->R ^= ((pmicdata->L & 0xff00ff00) >> 8) | ((pmicdata->L & 0x00ff00ff) << 8); + pmicdata->L += pmicdata->R; + pmicdata->R ^= ROL32(pmicdata->L, 3); + pmicdata->L += pmicdata->R; + pmicdata->R ^= ROR32(pmicdata->L, 2); + pmicdata->L += pmicdata->R; + /* Clear the buffer */ + pmicdata->M = 0; + pmicdata->nBytesInM = 0; + } +} + +void rtw_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nbytes) +{ + /* This is simple */ + while (nbytes > 0) { + rtw_secmicappendbyte(pmicdata, *src++); + nbytes--; + } +} + +void rtw_secgetmic(struct mic_data *pmicdata, u8 *dst) +{ + /* Append the minimum padding */ + rtw_secmicappendbyte(pmicdata, 0x5a); + rtw_secmicappendbyte(pmicdata, 0); + rtw_secmicappendbyte(pmicdata, 0); + rtw_secmicappendbyte(pmicdata, 0); + rtw_secmicappendbyte(pmicdata, 0); + /* and then zeroes until the length is a multiple of 4 */ + while (pmicdata->nBytesInM != 0) + rtw_secmicappendbyte(pmicdata, 0); + /* The appendByte function has already computed the result. */ + secmicputuint32(dst, pmicdata->L); + secmicputuint32(dst + 4, pmicdata->R); + /* Reset to the empty message. */ + secmicclear(pmicdata); +} + + +void rtw_seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len, u8 *mic_code, u8 pri) +{ + + struct mic_data micdata; + u8 priority[4] = {0x0, 0x0, 0x0, 0x0}; + rtw_secmicsetkey(&micdata, key); + priority[0] = pri; + + /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ + if (header[1] & 1) { /* ToDS==1 */ + rtw_secmicappend(&micdata, &header[16], 6); /* DA */ + if (header[1] & 2) /* From Ds==1 */ + rtw_secmicappend(&micdata, &header[24], 6); + else + rtw_secmicappend(&micdata, &header[10], 6); + } else { /* ToDS==0 */ + rtw_secmicappend(&micdata, &header[4], 6); /* DA */ + if (header[1] & 2) /* From Ds==1 */ + rtw_secmicappend(&micdata, &header[16], 6); + else + rtw_secmicappend(&micdata, &header[10], 6); + + } + rtw_secmicappend(&micdata, &priority[0], 4); + + + rtw_secmicappend(&micdata, data, data_len); + + rtw_secgetmic(&micdata, mic_code); +} + + + + +/* macros for extraction/creation of unsigned char/unsigned short values */ +#define RotR1(v16) ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15)) +#define Lo8(v16) ((u8)((v16) & 0x00FF)) +#define Hi8(v16) ((u8)(((v16) >> 8) & 0x00FF)) +#define Lo16(v32) ((u16)((v32) & 0xFFFF)) +#define Hi16(v32) ((u16)(((v32) >> 16) & 0xFFFF)) +#define Mk16(hi, lo) ((lo) ^ (((u16)(hi)) << 8)) + +/* select the Nth 16-bit word of the temporal key unsigned char array TK[] */ +#define TK16(N) Mk16(tk[2*(N)+1], tk[2*(N)]) + +/* S-box lookup: 16 bits --> 16 bits */ +#define _S_(v16) (Sbox1[0][Lo8(v16)] ^ Sbox1[1][Hi8(v16)]) + +/* fixed algorithm "parameters" */ +#define PHASE1_LOOP_CNT 8 /* this needs to be "big enough" */ +#define TA_SIZE 6 /* 48-bit transmitter address */ +#define TK_SIZE 16 /* 128-bit temporal key */ +#define P1K_SIZE 10 /* 80-bit Phase1 key */ +#define RC4_KEY_SIZE 16 /* 128-bit RC4KEY (104 bits unknown) */ + + +/* 2-unsigned char by 2-unsigned char subset of the full AES S-box table */ +static const unsigned short Sbox1[2][256] = /* Sbox for hash (can be in ROM) */ +{ { + 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, + 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, + 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, + 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, + 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, + 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, + 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, + 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, + 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, + 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, + 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, + 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, + 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, + 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, + 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, + 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, + 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, + 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, + 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, + 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, + 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, + 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, + 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, + 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, + 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, + 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, + 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, + 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, + 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, + 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, + 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, + 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, + }, + + + { /* second half of table is unsigned char-reversed version of first! */ + 0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491, + 0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC, + 0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB, + 0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B, + 0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83, + 0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A, + 0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F, + 0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA, + 0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B, + 0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713, + 0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6, + 0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85, + 0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411, + 0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B, + 0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1, + 0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF, + 0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E, + 0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6, + 0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B, + 0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD, + 0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8, + 0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2, + 0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049, + 0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810, + 0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197, + 0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F, + 0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C, + 0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927, + 0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733, + 0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5, + 0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0, + 0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C, + } +}; + +/* +********************************************************************** +* Routine: Phase 1 -- generate P1K, given TA, TK, IV32 +* +* Inputs: +* tk[] = temporal key [128 bits] +* ta[] = transmitter's MAC address [ 48 bits] +* iv32 = upper 32 bits of IV [ 32 bits] +* Output: +* p1k[] = Phase 1 key [ 80 bits] +* +* Note: +* This function only needs to be called every 2**16 packets, +* although in theory it could be called every packet. +* +********************************************************************** +*/ +static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32) +{ + sint i; + /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5] */ + p1k[0] = Lo16(iv32); + p1k[1] = Hi16(iv32); + p1k[2] = Mk16(ta[1], ta[0]); /* use TA[] as little-endian */ + p1k[3] = Mk16(ta[3], ta[2]); + p1k[4] = Mk16(ta[5], ta[4]); + + /* Now compute an unbalanced Feistel cipher with 80-bit block */ + /* size on the 80-bit block P1K[], using the 128-bit key TK[] */ + for (i = 0; i < PHASE1_LOOP_CNT ; i++) { + /* Each add operation here is mod 2**16 */ + p1k[0] += _S_(p1k[4] ^ TK16((i & 1) + 0)); + p1k[1] += _S_(p1k[0] ^ TK16((i & 1) + 2)); + p1k[2] += _S_(p1k[1] ^ TK16((i & 1) + 4)); + p1k[3] += _S_(p1k[2] ^ TK16((i & 1) + 6)); + p1k[4] += _S_(p1k[3] ^ TK16((i & 1) + 0)); + p1k[4] += (unsigned short)i; /* avoid "slide attacks" */ + } +} + + +/* +********************************************************************** +* Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16 +* +* Inputs: +* tk[] = Temporal key [128 bits] +* p1k[] = Phase 1 output key [ 80 bits] +* iv16 = low 16 bits of IV counter [ 16 bits] +* Output: +* rc4key[] = the key used to encrypt the packet [128 bits] +* +* Note: +* The value {TA,IV32,IV16} for Phase1/Phase2 must be unique +* across all packets using the same key TK value. Then, for a +* given value of TK[], this TKIP48 construction guarantees that +* the final RC4KEY value is unique across all packets. +* +* Suggested implementation optimization: if PPK[] is "overlaid" +* appropriately on RC4KEY[], there is no need for the final +* for loop below that copies the PPK[] result into RC4KEY[]. +* +********************************************************************** +*/ +static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16) +{ + sint i; + u16 PPK[6]; /* temporary key for mixing */ + /* Note: all adds in the PPK[] equations below are mod 2**16 */ + for (i = 0; i < 5; i++) + PPK[i] = p1k[i]; /* first, copy P1K to PPK */ + PPK[5] = p1k[4] + iv16; /* next, add in IV16 */ + + /* Bijective non-linear mixing of the 96 bits of PPK[0..5] */ + PPK[0] += _S_(PPK[5] ^ TK16(0)); /* Mix key in each "round" */ + PPK[1] += _S_(PPK[0] ^ TK16(1)); + PPK[2] += _S_(PPK[1] ^ TK16(2)); + PPK[3] += _S_(PPK[2] ^ TK16(3)); + PPK[4] += _S_(PPK[3] ^ TK16(4)); + PPK[5] += _S_(PPK[4] ^ TK16(5)); /* Total # S-box lookups == 6 */ + + /* Final sweep: bijective, "linear". Rotates kill LSB correlations */ + PPK[0] += RotR1(PPK[5] ^ TK16(6)); + PPK[1] += RotR1(PPK[0] ^ TK16(7)); /* Use all of TK[] in Phase2 */ + PPK[2] += RotR1(PPK[1]); + PPK[3] += RotR1(PPK[2]); + PPK[4] += RotR1(PPK[3]); + PPK[5] += RotR1(PPK[4]); + /* Note: At this point, for a given key TK[0..15], the 96-bit output */ + /* value PPK[0..5] is guaranteed to be unique, as a function */ + /* of the 96-bit "input" value {TA,IV32,IV16}. That is, P1K */ + /* is now a keyed permutation of {TA,IV32,IV16}. */ + + /* Set RC4KEY[0..3], which includes "cleartext" portion of RC4 key */ + rc4key[0] = Hi8(iv16); /* RC4KEY[0..2] is the WEP IV */ + rc4key[1] = (Hi8(iv16) | 0x20) & 0x7F; /* Help avoid weak (FMS) keys */ + rc4key[2] = Lo8(iv16); + rc4key[3] = Lo8((PPK[5] ^ TK16(0)) >> 1); + + + /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15] (little-endian) */ + for (i = 0; i < 6; i++) { + rc4key[4 + 2 * i] = Lo8(PPK[i]); + rc4key[5 + 2 * i] = Hi8(PPK[i]); + } +} + + +/* The hlen isn't include the IV */ +u32 rtw_tkip_encrypt(_adapter *padapter, u8 *pxmitframe) +{ + /* exclude ICV */ + u16 pnl; + u32 pnh; + u8 rc4key[16]; + u8 ttkey[16]; + u8 crc[4]; + u8 hw_hdr_offset = 0; + struct arc4context mycontext; + sint curfragnum, length; + u32 prwskeylen; + + u8 *pframe, *payload, *iv, *prwskey; + union pn48 dot11txpn; + /* struct sta_info *stainfo; */ + struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + u32 res = _SUCCESS; + + if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) + return _FAIL; + +#ifdef CONFIG_USB_TX_AGGREGATION + hw_hdr_offset = TXDESC_SIZE + + (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ); +#else +#ifdef CONFIG_TX_EARLY_MODE + hw_hdr_offset = TXDESC_OFFSET + EARLY_MODE_INFO_SIZE; +#else + hw_hdr_offset = TXDESC_OFFSET; +#endif +#endif + + pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset; + /* 4 start to encrypt each fragment */ + if (pattrib->encrypt == _TKIP_) { + + /* + if(pattrib->psta) + { + stainfo = pattrib->psta; + } + else + { + RTW_INFO("%s, call rtw_get_stainfo()\n", __func__); + stainfo=rtw_get_stainfo(&padapter->stapriv ,&pattrib->ra[0] ); + } + */ + /* if (stainfo!=NULL) */ + { + /* + if(!(stainfo->state &_FW_LINKED)) + { + RTW_INFO("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, stainfo->state); + return _FAIL; + } + */ + + if (IS_MCAST(pattrib->ra)) + prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; + else { + /* prwskey=&stainfo->dot118021x_UncstKey.skey[0]; */ + prwskey = pattrib->dot118021x_UncstKey.skey; + } + + prwskeylen = 16; + + for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { + iv = pframe + pattrib->hdrlen; + payload = pframe + pattrib->iv_len + pattrib->hdrlen; + + GET_TKIP_PN(iv, dot11txpn); + + pnl = (u16)(dot11txpn.val); + pnh = (u32)(dot11txpn.val >> 16); + + phase1((u16 *)&ttkey[0], prwskey, &pattrib->ta[0], pnh); + + phase2(&rc4key[0], prwskey, (u16 *)&ttkey[0], pnl); + + if ((curfragnum + 1) == pattrib->nr_frags) { /* 4 the last fragment */ + length = pattrib->last_txcmdsz - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len; + *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length)); /* modified by Amy*/ + + arcfour_init(&mycontext, rc4key, 16); + arcfour_encrypt(&mycontext, payload, payload, length); + arcfour_encrypt(&mycontext, payload + length, crc, 4); + + } else { + length = pxmitpriv->frag_len - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len ; + *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length)); /* modified by Amy*/ + arcfour_init(&mycontext, rc4key, 16); + arcfour_encrypt(&mycontext, payload, payload, length); + arcfour_encrypt(&mycontext, payload + length, crc, 4); + + pframe += pxmitpriv->frag_len; + pframe = (u8 *)RND4((SIZE_PTR)(pframe)); + + } + } + + TKIP_SW_ENC_CNT_INC(psecuritypriv, pattrib->ra); + } + /* + else{ + RTW_INFO("%s, psta==NUL\n", __func__); + res=_FAIL; + } + */ + + } + return res; + +} + + +/* The hlen isn't include the IV */ +u32 rtw_tkip_decrypt(_adapter *padapter, u8 *precvframe) +{ + /* exclude ICV */ + u16 pnl; + u32 pnh; + u8 rc4key[16]; + u8 ttkey[16]; + u8 crc[4]; + struct arc4context mycontext; + sint length; + u32 prwskeylen; + + u8 *pframe, *payload, *iv, *prwskey; + union pn48 dot11txpn; + struct sta_info *stainfo; + struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + /* struct recv_priv *precvpriv=&padapter->recvpriv; */ + u32 res = _SUCCESS; + + + pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data; + + /* 4 start to decrypt recvframe */ + if (prxattrib->encrypt == _TKIP_) { + + stainfo = rtw_get_stainfo(&padapter->stapriv , &prxattrib->ta[0]); + if (stainfo != NULL) { + + if (IS_MCAST(prxattrib->ra)) { + static u32 start = 0; + static u32 no_gkey_bc_cnt = 0; + static u32 no_gkey_mc_cnt = 0; + + if (psecuritypriv->binstallGrpkey == _FALSE) { + res = _FAIL; + + if (start == 0) + start = rtw_get_current_time(); + + if (is_broadcast_mac_addr(prxattrib->ra)) + no_gkey_bc_cnt++; + else + no_gkey_mc_cnt++; + + if (rtw_get_passing_time_ms(start) > 1000) { + if (no_gkey_bc_cnt || no_gkey_mc_cnt) { + RTW_PRINT(FUNC_ADPT_FMT" no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", + FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); + } + start = rtw_get_current_time(); + no_gkey_bc_cnt = 0; + no_gkey_mc_cnt = 0; + } + goto exit; + } + + if (no_gkey_bc_cnt || no_gkey_mc_cnt) { + RTW_PRINT(FUNC_ADPT_FMT" gkey installed. no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", + FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); + } + start = 0; + no_gkey_bc_cnt = 0; + no_gkey_mc_cnt = 0; + + /* RTW_INFO("rx bc/mc packets, to perform sw rtw_tkip_decrypt\n"); */ + /* prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; */ + prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; + prwskeylen = 16; + } else { + prwskey = &stainfo->dot118021x_UncstKey.skey[0]; + prwskeylen = 16; + } + + iv = pframe + prxattrib->hdrlen; + payload = pframe + prxattrib->iv_len + prxattrib->hdrlen; + length = ((union recv_frame *)precvframe)->u.hdr.len - prxattrib->hdrlen - prxattrib->iv_len; + + GET_TKIP_PN(iv, dot11txpn); + + pnl = (u16)(dot11txpn.val); + pnh = (u32)(dot11txpn.val >> 16); + + phase1((u16 *)&ttkey[0], prwskey, &prxattrib->ta[0], pnh); + phase2(&rc4key[0], prwskey, (unsigned short *)&ttkey[0], pnl); + + /* 4 decrypt payload include icv */ + + arcfour_init(&mycontext, rc4key, 16); + arcfour_encrypt(&mycontext, payload, payload, length); + + *((u32 *)crc) = le32_to_cpu(getcrc32(payload, length - 4)); + + if (crc[3] != payload[length - 1] || crc[2] != payload[length - 2] || crc[1] != payload[length - 3] || crc[0] != payload[length - 4]) { + res = _FAIL; + } + + TKIP_SW_DEC_CNT_INC(psecuritypriv, prxattrib->ra); + } else { + res = _FAIL; + } + + } +exit: + return res; + +} + + +/* 3 =====AES related===== */ + + + +#define MAX_MSG_SIZE 2048 +/*****************************/ +/******** SBOX Table *********/ +/*****************************/ + +static u8 sbox_table[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +/*****************************/ +/**** Function Prototypes ****/ +/*****************************/ + +static void bitwise_xor(u8 *ina, u8 *inb, u8 *out); +static void construct_mic_iv( + u8 *mic_header1, + sint qc_exists, + sint a4_exists, + u8 *mpdu, + uint payload_length, + u8 *pn_vector, + uint frtype);/* add for CONFIG_IEEE80211W, none 11w also can use */ +static void construct_mic_header1( + u8 *mic_header1, + sint header_length, + u8 *mpdu, + uint frtype);/* add for CONFIG_IEEE80211W, none 11w also can use */ +static void construct_mic_header2( + u8 *mic_header2, + u8 *mpdu, + sint a4_exists, + sint qc_exists); +static void construct_ctr_preload( + u8 *ctr_preload, + sint a4_exists, + sint qc_exists, + u8 *mpdu, + u8 *pn_vector, + sint c, + uint frtype);/* add for CONFIG_IEEE80211W, none 11w also can use */ +static void xor_128(u8 *a, u8 *b, u8 *out); +static void xor_32(u8 *a, u8 *b, u8 *out); +static u8 sbox(u8 a); +static void next_key(u8 *key, sint round); +static void byte_sub(u8 *in, u8 *out); +static void shift_row(u8 *in, u8 *out); +static void mix_column(u8 *in, u8 *out); +#ifndef PLATFORM_FREEBSD +static void add_round_key(u8 *shiftrow_in, + u8 *mcol_in, + u8 *block_in, + sint round, + u8 *out); +#endif /* PLATFORM_FREEBSD */ +static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext); + + +/****************************************/ +/* aes128k128d() */ +/* Performs a 128 bit AES encrypt with */ +/* 128 bit data. */ +/****************************************/ +static void xor_128(u8 *a, u8 *b, u8 *out) +{ + sint i; + for (i = 0; i < 16; i++) + out[i] = a[i] ^ b[i]; +} + + +static void xor_32(u8 *a, u8 *b, u8 *out) +{ + sint i; + for (i = 0; i < 4; i++) + out[i] = a[i] ^ b[i]; +} + + +static u8 sbox(u8 a) +{ + return sbox_table[(sint)a]; +} + + +static void next_key(u8 *key, sint round) +{ + u8 rcon; + u8 sbox_key[4]; + u8 rcon_table[12] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x1b, 0x36, 0x36, 0x36 + }; + sbox_key[0] = sbox(key[13]); + sbox_key[1] = sbox(key[14]); + sbox_key[2] = sbox(key[15]); + sbox_key[3] = sbox(key[12]); + + rcon = rcon_table[round]; + + xor_32(&key[0], sbox_key, &key[0]); + key[0] = key[0] ^ rcon; + + xor_32(&key[4], &key[0], &key[4]); + xor_32(&key[8], &key[4], &key[8]); + xor_32(&key[12], &key[8], &key[12]); +} + + +static void byte_sub(u8 *in, u8 *out) +{ + sint i; + for (i = 0; i < 16; i++) + out[i] = sbox(in[i]); +} + + +static void shift_row(u8 *in, u8 *out) +{ + out[0] = in[0]; + out[1] = in[5]; + out[2] = in[10]; + out[3] = in[15]; + out[4] = in[4]; + out[5] = in[9]; + out[6] = in[14]; + out[7] = in[3]; + out[8] = in[8]; + out[9] = in[13]; + out[10] = in[2]; + out[11] = in[7]; + out[12] = in[12]; + out[13] = in[1]; + out[14] = in[6]; + out[15] = in[11]; +} + + +static void mix_column(u8 *in, u8 *out) +{ + sint i; + u8 add1b[4]; + u8 add1bf7[4]; + u8 rotl[4]; + u8 swap_halfs[4]; + u8 andf7[4]; + u8 rotr[4]; + u8 temp[4]; + u8 tempb[4]; + for (i = 0 ; i < 4; i++) { + if ((in[i] & 0x80) == 0x80) + add1b[i] = 0x1b; + else + add1b[i] = 0x00; + } + + swap_halfs[0] = in[2]; /* Swap halfs */ + swap_halfs[1] = in[3]; + swap_halfs[2] = in[0]; + swap_halfs[3] = in[1]; + + rotl[0] = in[3]; /* Rotate left 8 bits */ + rotl[1] = in[0]; + rotl[2] = in[1]; + rotl[3] = in[2]; + + andf7[0] = in[0] & 0x7f; + andf7[1] = in[1] & 0x7f; + andf7[2] = in[2] & 0x7f; + andf7[3] = in[3] & 0x7f; + + for (i = 3; i > 0; i--) { /* logical shift left 1 bit */ + andf7[i] = andf7[i] << 1; + if ((andf7[i - 1] & 0x80) == 0x80) + andf7[i] = (andf7[i] | 0x01); + } + andf7[0] = andf7[0] << 1; + andf7[0] = andf7[0] & 0xfe; + + xor_32(add1b, andf7, add1bf7); + + xor_32(in, add1bf7, rotr); + + temp[0] = rotr[0]; /* Rotate right 8 bits */ + rotr[0] = rotr[1]; + rotr[1] = rotr[2]; + rotr[2] = rotr[3]; + rotr[3] = temp[0]; + + xor_32(add1bf7, rotr, temp); + xor_32(swap_halfs, rotl, tempb); + xor_32(temp, tempb, out); +} + + +static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext) +{ + sint round; + sint i; + u8 intermediatea[16]; + u8 intermediateb[16]; + u8 round_key[16]; + for (i = 0; i < 16; i++) + round_key[i] = key[i]; + + for (round = 0; round < 11; round++) { + if (round == 0) { + xor_128(round_key, data, ciphertext); + next_key(round_key, round); + } else if (round == 10) { + byte_sub(ciphertext, intermediatea); + shift_row(intermediatea, intermediateb); + xor_128(intermediateb, round_key, ciphertext); + } else { /* 1 - 9 */ + byte_sub(ciphertext, intermediatea); + shift_row(intermediatea, intermediateb); + mix_column(&intermediateb[0], &intermediatea[0]); + mix_column(&intermediateb[4], &intermediatea[4]); + mix_column(&intermediateb[8], &intermediatea[8]); + mix_column(&intermediateb[12], &intermediatea[12]); + xor_128(intermediatea, round_key, ciphertext); + next_key(round_key, round); + } + } +} + + +/************************************************/ +/* construct_mic_iv() */ +/* Builds the MIC IV from header fields and PN */ +/* Baron think the function is construct CCM */ +/* nonce */ +/************************************************/ +static void construct_mic_iv( + u8 *mic_iv, + sint qc_exists, + sint a4_exists, + u8 *mpdu, + uint payload_length, + u8 *pn_vector, + uint frtype/* add for CONFIG_IEEE80211W, none 11w also can use */ +) +{ + sint i; + mic_iv[0] = 0x59; + if (qc_exists && a4_exists) + mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */ + if (qc_exists && !a4_exists) + mic_iv[1] = mpdu[24] & 0x0f; /* mute bits 7-4 */ + if (!qc_exists) + mic_iv[1] = 0x00; +#ifdef CONFIG_IEEE80211W + /* 802.11w management frame should set management bit(4) */ + if (frtype == WIFI_MGT_TYPE) + mic_iv[1] |= BIT(4); +#endif /* CONFIG_IEEE80211W */ + for (i = 2; i < 8; i++) + mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */ +#ifdef CONSISTENT_PN_ORDER + for (i = 8; i < 14; i++) + mic_iv[i] = pn_vector[i - 8]; /* mic_iv[8:13] = PN[0:5] */ +#else + for (i = 8; i < 14; i++) + mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */ +#endif + mic_iv[14] = (unsigned char)(payload_length / 256); + mic_iv[15] = (unsigned char)(payload_length % 256); +} + + +/************************************************/ +/* construct_mic_header1() */ +/* Builds the first MIC header block from */ +/* header fields. */ +/* Build AAD SC,A1,A2 */ +/************************************************/ +static void construct_mic_header1( + u8 *mic_header1, + sint header_length, + u8 *mpdu, + uint frtype/* add for CONFIG_IEEE80211W, none 11w also can use */ +) +{ + mic_header1[0] = (u8)((header_length - 2) / 256); + mic_header1[1] = (u8)((header_length - 2) % 256); +#ifdef CONFIG_IEEE80211W + /* 802.11w management frame don't AND subtype bits 4,5,6 of frame control field */ + if (frtype == WIFI_MGT_TYPE) + mic_header1[2] = mpdu[0]; + else +#endif /* CONFIG_IEEE80211W */ + mic_header1[2] = mpdu[0] & 0xcf; /* Mute CF poll & CF ack bits */ + + mic_header1[3] = mpdu[1] & 0xc7; /* Mute retry, more data and pwr mgt bits */ + mic_header1[4] = mpdu[4]; /* A1 */ + mic_header1[5] = mpdu[5]; + mic_header1[6] = mpdu[6]; + mic_header1[7] = mpdu[7]; + mic_header1[8] = mpdu[8]; + mic_header1[9] = mpdu[9]; + mic_header1[10] = mpdu[10]; /* A2 */ + mic_header1[11] = mpdu[11]; + mic_header1[12] = mpdu[12]; + mic_header1[13] = mpdu[13]; + mic_header1[14] = mpdu[14]; + mic_header1[15] = mpdu[15]; +} + + +/************************************************/ +/* construct_mic_header2() */ +/* Builds the last MIC header block from */ +/* header fields. */ +/************************************************/ +static void construct_mic_header2( + u8 *mic_header2, + u8 *mpdu, + sint a4_exists, + sint qc_exists +) +{ + sint i; + for (i = 0; i < 16; i++) + mic_header2[i] = 0x00; + + mic_header2[0] = mpdu[16]; /* A3 */ + mic_header2[1] = mpdu[17]; + mic_header2[2] = mpdu[18]; + mic_header2[3] = mpdu[19]; + mic_header2[4] = mpdu[20]; + mic_header2[5] = mpdu[21]; + + /* mic_header2[6] = mpdu[22] & 0xf0; SC */ + mic_header2[6] = 0x00; + mic_header2[7] = 0x00; /* mpdu[23]; */ + + + if (!qc_exists && a4_exists) { + for (i = 0; i < 6; i++) + mic_header2[8 + i] = mpdu[24 + i]; /* A4 */ + + } + + if (qc_exists && !a4_exists) { + mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */ + mic_header2[9] = mpdu[25] & 0x00; + } + + if (qc_exists && a4_exists) { + for (i = 0; i < 6; i++) + mic_header2[8 + i] = mpdu[24 + i]; /* A4 */ + + mic_header2[14] = mpdu[30] & 0x0f; + mic_header2[15] = mpdu[31] & 0x00; + } + +} + + +/************************************************/ +/* construct_mic_header2() */ +/* Builds the last MIC header block from */ +/* header fields. */ +/* Baron think the function is construct CCM */ +/* nonce */ +/************************************************/ +static void construct_ctr_preload( + u8 *ctr_preload, + sint a4_exists, + sint qc_exists, + u8 *mpdu, + u8 *pn_vector, + sint c, + uint frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ +) +{ + sint i = 0; + for (i = 0; i < 16; i++) + ctr_preload[i] = 0x00; + i = 0; + + ctr_preload[0] = 0x01; /* flag */ + if (qc_exists && a4_exists) + ctr_preload[1] = mpdu[30] & 0x0f; /* QoC_Control */ + if (qc_exists && !a4_exists) + ctr_preload[1] = mpdu[24] & 0x0f; +#ifdef CONFIG_IEEE80211W + /* 802.11w management frame should set management bit(4) */ + if (frtype == WIFI_MGT_TYPE) + ctr_preload[1] |= BIT(4); +#endif /* CONFIG_IEEE80211W */ + for (i = 2; i < 8; i++) + ctr_preload[i] = mpdu[i + 8]; /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */ +#ifdef CONSISTENT_PN_ORDER + for (i = 8; i < 14; i++) + ctr_preload[i] = pn_vector[i - 8]; /* ctr_preload[8:13] = PN[0:5] */ +#else + for (i = 8; i < 14; i++) + ctr_preload[i] = pn_vector[13 - i]; /* ctr_preload[8:13] = PN[5:0] */ +#endif + ctr_preload[14] = (unsigned char)(c / 256); /* Ctr */ + ctr_preload[15] = (unsigned char)(c % 256); +} + + +/************************************/ +/* bitwise_xor() */ +/* A 128 bit, bitwise exclusive or */ +/************************************/ +static void bitwise_xor(u8 *ina, u8 *inb, u8 *out) +{ + sint i; + for (i = 0; i < 16; i++) + out[i] = ina[i] ^ inb[i]; +} + + +static sint aes_cipher(u8 *key, uint hdrlen, + u8 *pframe, uint plen) +{ + /* static unsigned char message[MAX_MSG_SIZE]; */ + uint qc_exists, a4_exists, i, j, payload_remainder, + num_blocks, payload_index; + + u8 pn_vector[6]; + u8 mic_iv[16]; + u8 mic_header1[16]; + u8 mic_header2[16]; + u8 ctr_preload[16]; + + /* Intermediate Buffers */ + u8 chain_buffer[16]; + u8 aes_out[16]; + u8 padded_buffer[16]; + u8 mic[8]; + /* uint offset = 0; */ + uint frtype = GetFrameType(pframe); + uint frsubtype = get_frame_sub_type(pframe); + + frsubtype = frsubtype >> 4; + + + _rtw_memset((void *)mic_iv, 0, 16); + _rtw_memset((void *)mic_header1, 0, 16); + _rtw_memset((void *)mic_header2, 0, 16); + _rtw_memset((void *)ctr_preload, 0, 16); + _rtw_memset((void *)chain_buffer, 0, 16); + _rtw_memset((void *)aes_out, 0, 16); + _rtw_memset((void *)padded_buffer, 0, 16); + + if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) + a4_exists = 0; + else + a4_exists = 1; + + if ( + ((frtype | frsubtype) == WIFI_DATA_CFACK) || + ((frtype | frsubtype) == WIFI_DATA_CFPOLL) || + ((frtype | frsubtype) == WIFI_DATA_CFACKPOLL)) { + qc_exists = 1; + if (hdrlen != WLAN_HDR_A3_QOS_LEN) + + hdrlen += 2; + } + /* add for CONFIG_IEEE80211W, none 11w also can use */ + else if ((frtype == WIFI_DATA) && + ((frsubtype == 0x08) || + (frsubtype == 0x09) || + (frsubtype == 0x0a) || + (frsubtype == 0x0b))) { + if (hdrlen != WLAN_HDR_A3_QOS_LEN) + + hdrlen += 2; + qc_exists = 1; + } else + qc_exists = 0; + + pn_vector[0] = pframe[hdrlen]; + pn_vector[1] = pframe[hdrlen + 1]; + pn_vector[2] = pframe[hdrlen + 4]; + pn_vector[3] = pframe[hdrlen + 5]; + pn_vector[4] = pframe[hdrlen + 6]; + pn_vector[5] = pframe[hdrlen + 7]; + + construct_mic_iv( + mic_iv, + qc_exists, + a4_exists, + pframe, /* message, */ + plen, + pn_vector, + frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ + ); + + construct_mic_header1( + mic_header1, + hdrlen, + pframe, /* message */ + frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ + ); + construct_mic_header2( + mic_header2, + pframe, /* message, */ + a4_exists, + qc_exists + ); + + + payload_remainder = plen % 16; + num_blocks = plen / 16; + + /* Find start of payload */ + payload_index = (hdrlen + 8); + + /* Calculate MIC */ + aes128k128d(key, mic_iv, aes_out); + bitwise_xor(aes_out, mic_header1, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + bitwise_xor(aes_out, mic_header2, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + + for (i = 0; i < num_blocks; i++) { + bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);/* bitwise_xor(aes_out, &message[payload_index], chain_buffer); */ + + payload_index += 16; + aes128k128d(key, chain_buffer, aes_out); + } + + /* Add on the final payload block if it needs padding */ + if (payload_remainder > 0) { + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) { + padded_buffer[j] = pframe[payload_index++];/* padded_buffer[j] = message[payload_index++]; */ + } + bitwise_xor(aes_out, padded_buffer, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + + } + + for (j = 0 ; j < 8; j++) + mic[j] = aes_out[j]; + + /* Insert MIC into payload */ + for (j = 0; j < 8; j++) + pframe[payload_index + j] = mic[j]; /* message[payload_index+j] = mic[j]; */ + + payload_index = hdrlen + 8; + for (i = 0; i < num_blocks; i++) { + construct_ctr_preload( + ctr_preload, + a4_exists, + qc_exists, + pframe, /* message, */ + pn_vector, + i + 1, + frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);/* bitwise_xor(aes_out, &message[payload_index], chain_buffer); */ + for (j = 0; j < 16; j++) + pframe[payload_index++] = chain_buffer[j];/* for (j=0; j<16;j++) message[payload_index++] = chain_buffer[j]; */ + } + + if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ + /* encrypt it and copy the unpadded part back */ + construct_ctr_preload( + ctr_preload, + a4_exists, + qc_exists, + pframe, /* message, */ + pn_vector, + num_blocks + 1, + frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ + + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) { + padded_buffer[j] = pframe[payload_index + j]; /* padded_buffer[j] = message[payload_index+j]; */ + } + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < payload_remainder; j++) + pframe[payload_index++] = chain_buffer[j];/* for (j=0; j<payload_remainder;j++) message[payload_index++] = chain_buffer[j]; */ + } + + /* Encrypt the MIC */ + construct_ctr_preload( + ctr_preload, + a4_exists, + qc_exists, + pframe, /* message, */ + pn_vector, + 0, + frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ + + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < 8; j++) { + padded_buffer[j] = pframe[j + hdrlen + 8 + plen]; /* padded_buffer[j] = message[j+hdrlen+8+plen]; */ + } + + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < 8; j++) + pframe[payload_index++] = chain_buffer[j];/* for (j=0; j<8;j++) message[payload_index++] = chain_buffer[j]; */ + return _SUCCESS; +} + + + + + +u32 rtw_aes_encrypt(_adapter *padapter, u8 *pxmitframe) +{ + /* exclude ICV */ + + + /*static*/ + /* unsigned char message[MAX_MSG_SIZE]; */ + + /* Intermediate Buffers */ + sint curfragnum, length; + u32 prwskeylen; + u8 *pframe, *prwskey; /* , *payload,*iv */ + u8 hw_hdr_offset = 0; + /* struct sta_info *stainfo=NULL; */ + struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + /* uint offset = 0; */ + u32 res = _SUCCESS; + + if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) + return _FAIL; + +#ifdef CONFIG_USB_TX_AGGREGATION + hw_hdr_offset = TXDESC_SIZE + + (((struct xmit_frame *)pxmitframe)->pkt_offset * PACKET_OFFSET_SZ); +#else +#ifdef CONFIG_TX_EARLY_MODE + hw_hdr_offset = TXDESC_OFFSET + EARLY_MODE_INFO_SIZE; +#else + hw_hdr_offset = TXDESC_OFFSET; +#endif +#endif + + pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + hw_hdr_offset; + + /* 4 start to encrypt each fragment */ + if ((pattrib->encrypt == _AES_)) { + /* + if(pattrib->psta) + { + stainfo = pattrib->psta; + } + else + { + RTW_INFO("%s, call rtw_get_stainfo()\n", __func__); + stainfo=rtw_get_stainfo(&padapter->stapriv ,&pattrib->ra[0] ); + } + */ + /* if (stainfo!=NULL) */ + { + /* + if(!(stainfo->state &_FW_LINKED)) + { + RTW_INFO("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, stainfo->state); + return _FAIL; + } + */ + + if (IS_MCAST(pattrib->ra)) + prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; + else { + /* prwskey=&stainfo->dot118021x_UncstKey.skey[0]; */ + prwskey = pattrib->dot118021x_UncstKey.skey; + } + +#ifdef CONFIG_TDLS + { + /* Swencryption */ + struct sta_info *ptdls_sta; + ptdls_sta = rtw_get_stainfo(&padapter->stapriv , &pattrib->dst[0]); + if ((ptdls_sta != NULL) && (ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE)) { + RTW_INFO("[%s] for tdls link\n", __FUNCTION__); + prwskey = &ptdls_sta->tpk.tk[0]; + } + } +#endif /* CONFIG_TDLS */ + + prwskeylen = 16; + + for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { + + if ((curfragnum + 1) == pattrib->nr_frags) { /* 4 the last fragment */ + length = pattrib->last_txcmdsz - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len; + + aes_cipher(prwskey, pattrib->hdrlen, pframe, length); + } else { + length = pxmitpriv->frag_len - pattrib->hdrlen - pattrib->iv_len - pattrib->icv_len ; + + aes_cipher(prwskey, pattrib->hdrlen, pframe, length); + pframe += pxmitpriv->frag_len; + pframe = (u8 *)RND4((SIZE_PTR)(pframe)); + + } + } + + AES_SW_ENC_CNT_INC(psecuritypriv, pattrib->ra); + } + /* + else{ + RTW_INFO("%s, psta==NUL\n", __func__); + res=_FAIL; + } + */ + } + + + + return res; +} + +static sint aes_decipher(u8 *key, uint hdrlen, + u8 *pframe, uint plen) +{ + static u8 message[MAX_MSG_SIZE]; + uint qc_exists, a4_exists, i, j, payload_remainder, + num_blocks, payload_index; + sint res = _SUCCESS; + u8 pn_vector[6]; + u8 mic_iv[16]; + u8 mic_header1[16]; + u8 mic_header2[16]; + u8 ctr_preload[16]; + + /* Intermediate Buffers */ + u8 chain_buffer[16]; + u8 aes_out[16]; + u8 padded_buffer[16]; + u8 mic[8]; + + + /* uint offset = 0; */ + uint frtype = GetFrameType(pframe); + uint frsubtype = get_frame_sub_type(pframe); + frsubtype = frsubtype >> 4; + + + _rtw_memset((void *)mic_iv, 0, 16); + _rtw_memset((void *)mic_header1, 0, 16); + _rtw_memset((void *)mic_header2, 0, 16); + _rtw_memset((void *)ctr_preload, 0, 16); + _rtw_memset((void *)chain_buffer, 0, 16); + _rtw_memset((void *)aes_out, 0, 16); + _rtw_memset((void *)padded_buffer, 0, 16); + + /* start to decrypt the payload */ + + num_blocks = (plen - 8) / 16; /* (plen including LLC, payload_length and mic ) */ + + payload_remainder = (plen - 8) % 16; + + pn_vector[0] = pframe[hdrlen]; + pn_vector[1] = pframe[hdrlen + 1]; + pn_vector[2] = pframe[hdrlen + 4]; + pn_vector[3] = pframe[hdrlen + 5]; + pn_vector[4] = pframe[hdrlen + 6]; + pn_vector[5] = pframe[hdrlen + 7]; + + if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) + a4_exists = 0; + else + a4_exists = 1; + + if ( + ((frtype | frsubtype) == WIFI_DATA_CFACK) || + ((frtype | frsubtype) == WIFI_DATA_CFPOLL) || + ((frtype | frsubtype) == WIFI_DATA_CFACKPOLL)) { + qc_exists = 1; + if (hdrlen != WLAN_HDR_A3_QOS_LEN) + + hdrlen += 2; + } /* only for data packet . add for CONFIG_IEEE80211W, none 11w also can use */ + else if ((frtype == WIFI_DATA) && + ((frsubtype == 0x08) || + (frsubtype == 0x09) || + (frsubtype == 0x0a) || + (frsubtype == 0x0b))) { + if (hdrlen != WLAN_HDR_A3_QOS_LEN) + + hdrlen += 2; + qc_exists = 1; + } else + qc_exists = 0; + + + /* now, decrypt pframe with hdrlen offset and plen long */ + + payload_index = hdrlen + 8; /* 8 is for extiv */ + + for (i = 0; i < num_blocks; i++) { + construct_ctr_preload( + ctr_preload, + a4_exists, + qc_exists, + pframe, + pn_vector, + i + 1, + frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ + ); + + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); + + for (j = 0; j < 16; j++) + pframe[payload_index++] = chain_buffer[j]; + } + + if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ + /* encrypt it and copy the unpadded part back */ + construct_ctr_preload( + ctr_preload, + a4_exists, + qc_exists, + pframe, + pn_vector, + num_blocks + 1, + frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ + ); + + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) + padded_buffer[j] = pframe[payload_index + j]; + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < payload_remainder; j++) + pframe[payload_index++] = chain_buffer[j]; + } + + /* start to calculate the mic */ + if ((hdrlen + plen + 8) <= MAX_MSG_SIZE) + _rtw_memcpy((void *)message, pframe, (hdrlen + plen + 8)); /* 8 is for ext iv len */ + + + pn_vector[0] = pframe[hdrlen]; + pn_vector[1] = pframe[hdrlen + 1]; + pn_vector[2] = pframe[hdrlen + 4]; + pn_vector[3] = pframe[hdrlen + 5]; + pn_vector[4] = pframe[hdrlen + 6]; + pn_vector[5] = pframe[hdrlen + 7]; + + + + construct_mic_iv( + mic_iv, + qc_exists, + a4_exists, + message, + plen - 8, + pn_vector, + frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ + ); + + construct_mic_header1( + mic_header1, + hdrlen, + message, + frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ + ); + construct_mic_header2( + mic_header2, + message, + a4_exists, + qc_exists + ); + + + payload_remainder = (plen - 8) % 16; + num_blocks = (plen - 8) / 16; + + /* Find start of payload */ + payload_index = (hdrlen + 8); + + /* Calculate MIC */ + aes128k128d(key, mic_iv, aes_out); + bitwise_xor(aes_out, mic_header1, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + bitwise_xor(aes_out, mic_header2, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + + for (i = 0; i < num_blocks; i++) { + bitwise_xor(aes_out, &message[payload_index], chain_buffer); + + payload_index += 16; + aes128k128d(key, chain_buffer, aes_out); + } + + /* Add on the final payload block if it needs padding */ + if (payload_remainder > 0) { + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) + padded_buffer[j] = message[payload_index++]; + bitwise_xor(aes_out, padded_buffer, chain_buffer); + aes128k128d(key, chain_buffer, aes_out); + + } + + for (j = 0 ; j < 8; j++) + mic[j] = aes_out[j]; + + /* Insert MIC into payload */ + for (j = 0; j < 8; j++) + message[payload_index + j] = mic[j]; + + payload_index = hdrlen + 8; + for (i = 0; i < num_blocks; i++) { + construct_ctr_preload( + ctr_preload, + a4_exists, + qc_exists, + message, + pn_vector, + i + 1, + frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, &message[payload_index], chain_buffer); + for (j = 0; j < 16; j++) + message[payload_index++] = chain_buffer[j]; + } + + if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ + /* encrypt it and copy the unpadded part back */ + construct_ctr_preload( + ctr_preload, + a4_exists, + qc_exists, + message, + pn_vector, + num_blocks + 1, + frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ + + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < payload_remainder; j++) + padded_buffer[j] = message[payload_index + j]; + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < payload_remainder; j++) + message[payload_index++] = chain_buffer[j]; + } + + /* Encrypt the MIC */ + construct_ctr_preload( + ctr_preload, + a4_exists, + qc_exists, + message, + pn_vector, + 0, + frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ + + for (j = 0; j < 16; j++) + padded_buffer[j] = 0x00; + for (j = 0; j < 8; j++) + padded_buffer[j] = message[j + hdrlen + 8 + plen - 8]; + + aes128k128d(key, ctr_preload, aes_out); + bitwise_xor(aes_out, padded_buffer, chain_buffer); + for (j = 0; j < 8; j++) + message[payload_index++] = chain_buffer[j]; + + /* compare the mic */ + for (i = 0; i < 8; i++) { + if (pframe[hdrlen + 8 + plen - 8 + i] != message[hdrlen + 8 + plen - 8 + i]) { + RTW_INFO("aes_decipher:mic check error mic[%d]: pframe(%x) != message(%x)\n", + i, pframe[hdrlen + 8 + plen - 8 + i], message[hdrlen + 8 + plen - 8 + i]); + res = _FAIL; + } + } + return res; +} + +u32 rtw_aes_decrypt(_adapter *padapter, u8 *precvframe) +{ + /* exclude ICV */ + + + /*static*/ + /* unsigned char message[MAX_MSG_SIZE]; */ + + + /* Intermediate Buffers */ + + + sint length; + u32 prwskeylen; + u8 *pframe, *prwskey; /* , *payload,*iv */ + struct sta_info *stainfo; + struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + /* struct recv_priv *precvpriv=&padapter->recvpriv; */ + u32 res = _SUCCESS; + pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data; + /* 4 start to encrypt each fragment */ + if ((prxattrib->encrypt == _AES_)) { + + stainfo = rtw_get_stainfo(&padapter->stapriv , &prxattrib->ta[0]); + if (stainfo != NULL) { + + if (IS_MCAST(prxattrib->ra)) { + static u32 start = 0; + static u32 no_gkey_bc_cnt = 0; + static u32 no_gkey_mc_cnt = 0; + + /* RTW_INFO("rx bc/mc packets, to perform sw rtw_aes_decrypt\n"); */ + /* prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; */ + if (psecuritypriv->binstallGrpkey == _FALSE) { + res = _FAIL; + + if (start == 0) + start = rtw_get_current_time(); + + if (is_broadcast_mac_addr(prxattrib->ra)) + no_gkey_bc_cnt++; + else + no_gkey_mc_cnt++; + + if (rtw_get_passing_time_ms(start) > 1000) { + if (no_gkey_bc_cnt || no_gkey_mc_cnt) { + RTW_PRINT(FUNC_ADPT_FMT" no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", + FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); + } + start = rtw_get_current_time(); + no_gkey_bc_cnt = 0; + no_gkey_mc_cnt = 0; + } + + goto exit; + } + + if (no_gkey_bc_cnt || no_gkey_mc_cnt) { + RTW_PRINT(FUNC_ADPT_FMT" gkey installed. no_gkey_bc_cnt:%u, no_gkey_mc_cnt:%u\n", + FUNC_ADPT_ARG(padapter), no_gkey_bc_cnt, no_gkey_mc_cnt); + } + start = 0; + no_gkey_bc_cnt = 0; + no_gkey_mc_cnt = 0; + + prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; + if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) { + RTW_DBG("not match packet_index=%d, install_index=%d\n" + , prxattrib->key_index, psecuritypriv->dot118021XGrpKeyid); + res = _FAIL; + goto exit; + } + } else + prwskey = &stainfo->dot118021x_UncstKey.skey[0]; + + length = ((union recv_frame *)precvframe)->u.hdr.len - prxattrib->hdrlen - prxattrib->iv_len; +#if 0 + /* add for CONFIG_IEEE80211W, debug */ + if (0) + printk("@@@@@@@@@@@@@@@@@@ length=%d, prxattrib->hdrlen=%d, prxattrib->pkt_len=%d\n" + , length, prxattrib->hdrlen, prxattrib->pkt_len); + if (0) { + int no; + /* test print PSK */ + printk("PSK key below:\n"); + for (no = 0; no < 16; no++) + printk(" %02x ", prwskey[no]); + printk("\n"); + } + if (0) { + int no; + /* test print PSK */ + printk("frame:\n"); + for (no = 0; no < prxattrib->pkt_len; no++) + printk(" %02x ", pframe[no]); + printk("\n"); + } +#endif + + res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length); + + AES_SW_DEC_CNT_INC(psecuritypriv, prxattrib->ra); + } else { + res = _FAIL; + } + + } +exit: + return res; +} + +#ifdef CONFIG_IEEE80211W +u32 rtw_BIP_verify(_adapter *padapter, u8 *precvframe) +{ + struct rx_pkt_attrib *pattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; + u8 *pframe; + u8 *BIP_AAD, *p; + u32 res = _FAIL; + uint len, ori_len; + struct rtw_ieee80211_hdr *pwlanhdr; + u8 mic[16]; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + ori_len = pattrib->pkt_len - WLAN_HDR_A3_LEN + BIP_AAD_SIZE; + BIP_AAD = rtw_zmalloc(ori_len); + + if (BIP_AAD == NULL) { + RTW_INFO("BIP AAD allocate fail\n"); + return _FAIL; + } + /* PKT start */ + pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data; + /* mapping to wlan header */ + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + /* save the frame body + MME */ + _rtw_memcpy(BIP_AAD + BIP_AAD_SIZE, pframe + WLAN_HDR_A3_LEN, pattrib->pkt_len - WLAN_HDR_A3_LEN); + /* find MME IE pointer */ + p = rtw_get_ie(BIP_AAD + BIP_AAD_SIZE, _MME_IE_, &len, pattrib->pkt_len - WLAN_HDR_A3_LEN); + /* Baron */ + if (p) { + u16 keyid = 0; + u64 temp_ipn = 0; + /* save packet number */ + _rtw_memcpy(&temp_ipn, p + 4, 6); + temp_ipn = le64_to_cpu(temp_ipn); + /* BIP packet number should bigger than previous BIP packet */ + if (temp_ipn < pmlmeext->mgnt_80211w_IPN_rx) { + RTW_INFO("replay BIP packet\n"); + goto BIP_exit; + } + /* copy key index */ + _rtw_memcpy(&keyid, p + 2, 2); + keyid = le16_to_cpu(keyid); + if (keyid != padapter->securitypriv.dot11wBIPKeyid) { + RTW_INFO("BIP key index error!\n"); + goto BIP_exit; + } + /* clear the MIC field of MME to zero */ + _rtw_memset(p + 2 + len - 8, 0, 8); + + /* conscruct AAD, copy frame control field */ + _rtw_memcpy(BIP_AAD, &pwlanhdr->frame_ctl, 2); + ClearRetry(BIP_AAD); + ClearPwrMgt(BIP_AAD); + ClearMData(BIP_AAD); + /* conscruct AAD, copy address 1 to address 3 */ + _rtw_memcpy(BIP_AAD + 2, pwlanhdr->addr1, 18); + + if (omac1_aes_128(padapter->securitypriv.dot11wBIPKey[padapter->securitypriv.dot11wBIPKeyid].skey + , BIP_AAD, ori_len, mic)) + goto BIP_exit; + +#if 0 + /* management packet content */ + { + int pp; + RTW_INFO("pkt: "); + for (pp = 0; pp < pattrib->pkt_len; pp++) + printk(" %02x ", pframe[pp]); + RTW_INFO("\n"); + /* BIP AAD + management frame body + MME(MIC is zero) */ + RTW_INFO("AAD+PKT: "); + for (pp = 0; pp < ori_len; pp++) + RTW_INFO(" %02x ", BIP_AAD[pp]); + RTW_INFO("\n"); + /* show the MIC result */ + RTW_INFO("mic: "); + for (pp = 0; pp < 16; pp++) + RTW_INFO(" %02x ", mic[pp]); + RTW_INFO("\n"); + } +#endif + /* MIC field should be last 8 bytes of packet (packet without FCS) */ + if (_rtw_memcmp(mic, pframe + pattrib->pkt_len - 8, 8)) { + pmlmeext->mgnt_80211w_IPN_rx = temp_ipn; + res = _SUCCESS; + } else + RTW_INFO("BIP MIC error!\n"); + + } else + res = RTW_RX_HANDLED; +BIP_exit: + + rtw_mfree(BIP_AAD, ori_len); + return res; +} +#endif /* CONFIG_IEEE80211W */ + +#ifndef PLATFORM_FREEBSD +/* compress 512-bits */ +static int sha256_compress(struct sha256_state *md, unsigned char *buf) +{ + u32 S[8], W[64], t0, t1; + u32 t; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) + S[i] = md->state[i]; + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) + W[i] = WPA_GET_BE32(buf + (4 * i)); + + /* fill W[16..63] */ + for (i = 16; i < 64; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + + W[i - 16]; + } + + /* Compress */ +#define RND(a, b, c, d, e, f, g, h, i) do {\ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; \ + } while (0) + + for (i = 0; i < 64; ++i) { + RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i); + t = S[7]; + S[7] = S[6]; + S[6] = S[5]; + S[5] = S[4]; + S[4] = S[3]; + S[3] = S[2]; + S[2] = S[1]; + S[1] = S[0]; + S[0] = t; + } + + /* feedback */ + for (i = 0; i < 8; i++) + md->state[i] = md->state[i] + S[i]; + return 0; +} + +/* Initialize the hash state */ +static void sha256_init(struct sha256_state *md) +{ + md->curlen = 0; + md->length = 0; + md->state[0] = 0x6A09E667UL; + md->state[1] = 0xBB67AE85UL; + md->state[2] = 0x3C6EF372UL; + md->state[3] = 0xA54FF53AUL; + md->state[4] = 0x510E527FUL; + md->state[5] = 0x9B05688CUL; + md->state[6] = 0x1F83D9ABUL; + md->state[7] = 0x5BE0CD19UL; +} + +/** + Process a block of memory though the hash + @param md The hash state + @param in The data to hash + @param inlen The length of the data (octets) + @return CRYPT_OK if successful +*/ +static int sha256_process(struct sha256_state *md, unsigned char *in, + unsigned long inlen) +{ + unsigned long n; +#define block_size 64 + + if (md->curlen > sizeof(md->buf)) + return -1; + + while (inlen > 0) { + if (md->curlen == 0 && inlen >= block_size) { + if (sha256_compress(md, (unsigned char *) in) < 0) + return -1; + md->length += block_size * 8; + in += block_size; + inlen -= block_size; + } else { + n = MIN(inlen, (block_size - md->curlen)); + _rtw_memcpy(md->buf + md->curlen, in, n); + md->curlen += n; + in += n; + inlen -= n; + if (md->curlen == block_size) { + if (sha256_compress(md, md->buf) < 0) + return -1; + md->length += 8 * block_size; + md->curlen = 0; + } + } + } + + return 0; +} + + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful +*/ +static int sha256_done(struct sha256_state *md, unsigned char *out) +{ + int i; + + if (md->curlen >= sizeof(md->buf)) + return -1; + + /* increase the length of the message */ + md->length += md->curlen * 8; + + /* append the '1' bit */ + md->buf[md->curlen++] = (unsigned char) 0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->curlen > 56) { + while (md->curlen < 64) + md->buf[md->curlen++] = (unsigned char) 0; + sha256_compress(md, md->buf); + md->curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->curlen < 56) + md->buf[md->curlen++] = (unsigned char) 0; + + /* store length */ + WPA_PUT_BE64(md->buf + 56, md->length); + sha256_compress(md, md->buf); + + /* copy output */ + for (i = 0; i < 8; i++) + WPA_PUT_BE32(out + (4 * i), md->state[i]); + + return 0; +} + +/** + * sha256_vector - SHA256 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +static int sha256_vector(size_t num_elem, u8 *addr[], size_t *len, + u8 *mac) +{ + struct sha256_state ctx; + size_t i; + + sha256_init(&ctx); + for (i = 0; i < num_elem; i++) + if (sha256_process(&ctx, addr[i], len[i])) + return -1; + if (sha256_done(&ctx, mac)) + return -1; + return 0; +} + +static u8 os_strlen(const char *s) +{ + const char *p = s; + while (*p) + p++; + return p - s; +} + +static int os_memcmp(void *s1, void *s2, u8 n) +{ + unsigned char *p1 = s1, *p2 = s2; + + if (n == 0) + return 0; + + while (*p1 == *p2) { + p1++; + p2++; + n--; + if (n == 0) + return 0; + } + + return *p1 - *p2; +} + +/** + * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104) + * @key: Key for HMAC operations + * @key_len: Length of the key in bytes + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash (32 bytes) + */ +static void hmac_sha256_vector(u8 *key, size_t key_len, size_t num_elem, + u8 *addr[], size_t *len, u8 *mac) +{ + unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ + unsigned char tk[32]; + u8 *_addr[6]; + size_t _len[6], i; + + if (num_elem > 5) { + /* + * Fixed limit on the number of fragments to avoid having to + * allocate memory (which could fail). + */ + return; + } + + /* if key is longer than 64 bytes reset it to key = SHA256(key) */ + if (key_len > 64) { + sha256_vector(1, &key, &key_len, tk); + key = tk; + key_len = 32; + } + + /* the HMAC_SHA256 transform looks like: + * + * SHA256(K XOR opad, SHA256(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected */ + + /* start out by storing key in ipad */ + _rtw_memset(k_pad, 0, sizeof(k_pad)); + _rtw_memcpy(k_pad, key, key_len); + /* XOR key with ipad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x36; + + /* perform inner SHA256 */ + _addr[0] = k_pad; + _len[0] = 64; + for (i = 0; i < num_elem; i++) { + _addr[i + 1] = addr[i]; + _len[i + 1] = len[i]; + } + sha256_vector(1 + num_elem, _addr, _len, mac); + + _rtw_memset(k_pad, 0, sizeof(k_pad)); + _rtw_memcpy(k_pad, key, key_len); + /* XOR key with opad values */ + for (i = 0; i < 64; i++) + k_pad[i] ^= 0x5c; + + /* perform outer SHA256 */ + _addr[0] = k_pad; + _len[0] = 64; + _addr[1] = mac; + _len[1] = 32; + sha256_vector(2, _addr, _len, mac); +} +#endif /* PLATFORM_FREEBSD */ +/** + * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2) + * @key: Key for PRF + * @key_len: Length of the key in bytes + * @label: A unique label for each purpose of the PRF + * @data: Extra data to bind into the key + * @data_len: Length of the data + * @buf: Buffer for the generated pseudo-random key + * @buf_len: Number of bytes of key to generate + * + * This function is used to derive new, cryptographically separate keys from a + * given key. + */ +#ifndef PLATFORM_FREEBSD /* Baron */ +static void sha256_prf(u8 *key, size_t key_len, char *label, + u8 *data, size_t data_len, u8 *buf, size_t buf_len) +{ + u16 counter = 1; + size_t pos, plen; + u8 hash[SHA256_MAC_LEN]; + u8 *addr[4]; + size_t len[4]; + u8 counter_le[2], length_le[2]; + + addr[0] = counter_le; + len[0] = 2; + addr[1] = (u8 *) label; + len[1] = os_strlen(label); + addr[2] = data; + len[2] = data_len; + addr[3] = length_le; + len[3] = sizeof(length_le); + + WPA_PUT_LE16(length_le, buf_len * 8); + pos = 0; + while (pos < buf_len) { + plen = buf_len - pos; + WPA_PUT_LE16(counter_le, counter); + if (plen >= SHA256_MAC_LEN) { + hmac_sha256_vector(key, key_len, 4, addr, len, + &buf[pos]); + pos += SHA256_MAC_LEN; + } else { + hmac_sha256_vector(key, key_len, 4, addr, len, hash); + _rtw_memcpy(&buf[pos], hash, plen); + break; + } + counter++; + } +} +#endif /* PLATFORM_FREEBSD Baron */ + +/* AES tables*/ +const u32 Te0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; +const u32 Td0[256] = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; +const u8 Td4s[256] = { + 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, + 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, + 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, + 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, + 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, + 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, + 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, + 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, + 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, + 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, + 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, + 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, + 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, + 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, + 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, + 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, + 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, + 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, + 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, + 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, + 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, + 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, + 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, + 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, + 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, + 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, + 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, + 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, + 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, + 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, + 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, + 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, +}; +const u8 rcons[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 + /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +/** + * Expand the cipher key into the encryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +#ifndef PLATFORM_FREEBSD /* Baron */ +static void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]) +{ + int i; + u32 temp; + + rk[0] = GETU32(cipherKey); + rk[1] = GETU32(cipherKey + 4); + rk[2] = GETU32(cipherKey + 8); + rk[3] = GETU32(cipherKey + 12); + for (i = 0; i < 10; i++) { + temp = rk[3]; + rk[4] = rk[0] ^ + TE421(temp) ^ TE432(temp) ^ TE443(temp) ^ TE414(temp) ^ + RCON(i); + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + rk += 4; + } +} + +static void rijndaelEncrypt(u32 rk[/*44*/], u8 pt[16], u8 ct[16]) +{ + u32 s0, s1, s2, s3, t0, t1, t2, t3; + int Nr = 10; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(pt) ^ rk[0]; + s1 = GETU32(pt + 4) ^ rk[1]; + s2 = GETU32(pt + 8) ^ rk[2]; + s3 = GETU32(pt + 12) ^ rk[3]; + +#define ROUND(i, d, s) do {\ + d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ + d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ + d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ + d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]; \ + } while (0) + +#ifdef FULL_UNROLL + + ROUND(1, t, s); + ROUND(2, s, t); + ROUND(3, t, s); + ROUND(4, s, t); + ROUND(5, t, s); + ROUND(6, s, t); + ROUND(7, t, s); + ROUND(8, s, t); + ROUND(9, t, s); + + rk += Nr << 2; + +#else /* !FULL_UNROLL */ + + /* Nr - 1 full rounds: */ + r = Nr >> 1; + for (;;) { + ROUND(1, t, s); + rk += 8; + if (--r == 0) + break; + ROUND(0, s, t); + } + +#endif /* ?FULL_UNROLL */ + +#undef ROUND + + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0]; + PUTU32(ct , s0); + s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1]; + PUTU32(ct + 4, s1); + s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2]; + PUTU32(ct + 8, s2); + s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3]; + PUTU32(ct + 12, s3); +} + +static void *aes_encrypt_init(u8 *key, size_t len) +{ + u32 *rk; + if (len != 16) + return NULL; + rk = (u32 *)rtw_malloc(AES_PRIV_SIZE); + if (rk == NULL) + return NULL; + rijndaelKeySetupEnc(rk, key); + return rk; +} + +static void aes_128_encrypt(void *ctx, u8 *plain, u8 *crypt) +{ + rijndaelEncrypt(ctx, plain, crypt); +} + + +static void gf_mulx(u8 *pad) +{ + int i, carry; + + carry = pad[0] & 0x80; + for (i = 0; i < AES_BLOCK_SIZE - 1; i++) + pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); + pad[AES_BLOCK_SIZE - 1] <<= 1; + if (carry) + pad[AES_BLOCK_SIZE - 1] ^= 0x87; +} + +static void aes_encrypt_deinit(void *ctx) +{ + _rtw_memset(ctx, 0, AES_PRIV_SIZE); + rtw_mfree(ctx, AES_PRIV_SIZE); +} + + +/** + * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128 + * @key: 128-bit key for the hash operation + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) + * Returns: 0 on success, -1 on failure + * + * This is a mode for using block cipher (AES in this case) for authentication. + * OMAC1 was standardized with the name CMAC by NIST in a Special Publication + * (SP) 800-38B. + */ +static int omac1_aes_128_vector(u8 *key, size_t num_elem, + u8 *addr[], size_t *len, u8 *mac) +{ + void *ctx; + u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; + u8 *pos, *end; + size_t i, e, left, total_len; + + ctx = aes_encrypt_init(key, 16); + if (ctx == NULL) + return -1; + _rtw_memset(cbc, 0, AES_BLOCK_SIZE); + + total_len = 0; + for (e = 0; e < num_elem; e++) + total_len += len[e]; + left = total_len; + + e = 0; + pos = addr[0]; + end = pos + len[0]; + + while (left >= AES_BLOCK_SIZE) { + for (i = 0; i < AES_BLOCK_SIZE; i++) { + cbc[i] ^= *pos++; + if (pos >= end) { + e++; + pos = addr[e]; + end = pos + len[e]; + } + } + if (left > AES_BLOCK_SIZE) + aes_128_encrypt(ctx, cbc, cbc); + left -= AES_BLOCK_SIZE; + } + + _rtw_memset(pad, 0, AES_BLOCK_SIZE); + aes_128_encrypt(ctx, pad, pad); + gf_mulx(pad); + + if (left || total_len == 0) { + for (i = 0; i < left; i++) { + cbc[i] ^= *pos++; + if (pos >= end) { + e++; + pos = addr[e]; + end = pos + len[e]; + } + } + cbc[left] ^= 0x80; + gf_mulx(pad); + } + + for (i = 0; i < AES_BLOCK_SIZE; i++) + pad[i] ^= cbc[i]; + aes_128_encrypt(ctx, pad, mac); + aes_encrypt_deinit(ctx); + return 0; +} + + +/** + * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) + * @key: 128-bit key for the hash operation + * @data: Data buffer for which a MAC is determined + * @data_len: Length of data buffer in bytes + * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) + * Returns: 0 on success, -1 on failure + * + * This is a mode for using block cipher (AES in this case) for authentication. + * OMAC1 was standardized with the name CMAC by NIST in a Special Publication + * (SP) 800-38B. + */ /* modify for CONFIG_IEEE80211W */ +int omac1_aes_128(u8 *key, u8 *data, size_t data_len, u8 *mac) +{ + return omac1_aes_128_vector(key, 1, &data, &data_len, mac); +} +#endif /* PLATFORM_FREEBSD Baron */ + +#ifdef CONFIG_TDLS +void wpa_tdls_generate_tpk(_adapter *padapter, PVOID sta) +{ + struct sta_info *psta = (struct sta_info *)sta; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + u8 *SNonce = psta->SNonce; + u8 *ANonce = psta->ANonce; + + u8 key_input[SHA256_MAC_LEN]; + u8 *nonce[2]; + size_t len[2]; + u8 data[3 * ETH_ALEN]; + + /* IEEE Std 802.11z-2010 8.5.9.1: + * TPK-Key-Input = SHA-256(min(SNonce, ANonce) || max(SNonce, ANonce)) + */ + len[0] = 32; + len[1] = 32; + if (os_memcmp(SNonce, ANonce, 32) < 0) { + nonce[0] = SNonce; + nonce[1] = ANonce; + } else { + nonce[0] = ANonce; + nonce[1] = SNonce; + } + + sha256_vector(2, nonce, len, key_input); + + /* + * TPK-Key-Data = KDF-N_KEY(TPK-Key-Input, "TDLS PMK", + * min(MAC_I, MAC_R) || max(MAC_I, MAC_R) || BSSID || N_KEY) + * TODO: is N_KEY really included in KDF Context and if so, in which + * presentation format (little endian 16-bit?) is it used? It gets + * added by the KDF anyway.. + */ + + if (os_memcmp(adapter_mac_addr(padapter), psta->hwaddr, ETH_ALEN) < 0) { + _rtw_memcpy(data, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(data + ETH_ALEN, psta->hwaddr, ETH_ALEN); + } else { + _rtw_memcpy(data, psta->hwaddr, ETH_ALEN); + _rtw_memcpy(data + ETH_ALEN, adapter_mac_addr(padapter), ETH_ALEN); + } + _rtw_memcpy(data + 2 * ETH_ALEN, get_bssid(pmlmepriv), ETH_ALEN); + + sha256_prf(key_input, SHA256_MAC_LEN, "TDLS PMK", data, sizeof(data), (u8 *) &psta->tpk, sizeof(psta->tpk)); + + +} + +/** + * wpa_tdls_ftie_mic - Calculate TDLS FTIE MIC + * @kck: TPK-KCK + * @lnkid: Pointer to the beginning of Link Identifier IE + * @rsnie: Pointer to the beginning of RSN IE used for handshake + * @timeoutie: Pointer to the beginning of Timeout IE used for handshake + * @ftie: Pointer to the beginning of FT IE + * @mic: Pointer for writing MIC + * + * Calculate MIC for TDLS frame. + */ +int wpa_tdls_ftie_mic(u8 *kck, u8 trans_seq, + u8 *lnkid, u8 *rsnie, u8 *timeoutie, u8 *ftie, + u8 *mic) +{ + u8 *buf, *pos; + struct wpa_tdls_ftie *_ftie; + struct wpa_tdls_lnkid *_lnkid; + int ret; + int len = 2 * ETH_ALEN + 1 + 2 + lnkid[1] + 2 + rsnie[1] + + 2 + timeoutie[1] + 2 + ftie[1]; + buf = rtw_zmalloc(len); + if (!buf) { + RTW_INFO("TDLS: No memory for MIC calculation\n"); + return -1; + } + + pos = buf; + _lnkid = (struct wpa_tdls_lnkid *) lnkid; + /* 1) TDLS initiator STA MAC address */ + _rtw_memcpy(pos, _lnkid->init_sta, ETH_ALEN); + pos += ETH_ALEN; + /* 2) TDLS responder STA MAC address */ + _rtw_memcpy(pos, _lnkid->resp_sta, ETH_ALEN); + pos += ETH_ALEN; + /* 3) Transaction Sequence number */ + *pos++ = trans_seq; + /* 4) Link Identifier IE */ + _rtw_memcpy(pos, lnkid, 2 + lnkid[1]); + pos += 2 + lnkid[1]; + /* 5) RSN IE */ + _rtw_memcpy(pos, rsnie, 2 + rsnie[1]); + pos += 2 + rsnie[1]; + /* 6) Timeout Interval IE */ + _rtw_memcpy(pos, timeoutie, 2 + timeoutie[1]); + pos += 2 + timeoutie[1]; + /* 7) FTIE, with the MIC field of the FTIE set to 0 */ + _rtw_memcpy(pos, ftie, 2 + ftie[1]); + _ftie = (struct wpa_tdls_ftie *) pos; + _rtw_memset(_ftie->mic, 0, TDLS_MIC_LEN); + pos += 2 + ftie[1]; + + ret = omac1_aes_128(kck, buf, pos - buf, mic); + rtw_mfree(buf, len); + return ret; + +} + +/** + * wpa_tdls_teardown_ftie_mic - Calculate TDLS TEARDOWN FTIE MIC + * @kck: TPK-KCK + * @lnkid: Pointer to the beginning of Link Identifier IE + * @reason: Reason code of TDLS Teardown + * @dialog_token: Dialog token that was used in the MIC calculation for TPK Handshake Message 3 + * @trans_seq: Transaction Sequence number (1 octet) which shall be set to the value 4 + * @ftie: Pointer to the beginning of FT IE + * @mic: Pointer for writing MIC + * + * Calculate MIC for TDLS TEARDOWN frame according to Section 10.22.5 in IEEE 802.11 - 2012. + */ +int wpa_tdls_teardown_ftie_mic(u8 *kck, u8 *lnkid, u16 reason, + u8 dialog_token, u8 trans_seq, u8 *ftie, u8 *mic) +{ + u8 *buf, *pos; + struct wpa_tdls_ftie *_ftie; + int ret; + int len = 2 + lnkid[1] + 2 + 1 + 1 + 2 + ftie[1]; + + buf = rtw_zmalloc(len); + if (!buf) { + RTW_INFO("TDLS: No memory for MIC calculation\n"); + return -1; + } + + pos = buf; + /* 1) Link Identifier IE */ + _rtw_memcpy(pos, lnkid, 2 + lnkid[1]); + pos += 2 + lnkid[1]; + /* 2) Reason Code */ + _rtw_memcpy(pos, (u8 *)&reason, 2); + pos += 2; + /* 3) Dialog Token */ + *pos++ = dialog_token; + /* 4) Transaction Sequence number */ + *pos++ = trans_seq; + /* 5) FTIE, with the MIC field of the FTIE set to 0 */ + _rtw_memcpy(pos, ftie, 2 + ftie[1]); + _ftie = (struct wpa_tdls_ftie *) pos; + _rtw_memset(_ftie->mic, 0, TDLS_MIC_LEN); + pos += 2 + ftie[1]; + + ret = omac1_aes_128(kck, buf, pos - buf, mic); + rtw_mfree(buf, len); + return ret; + +} + +int tdls_verify_mic(u8 *kck, u8 trans_seq, + u8 *lnkid, u8 *rsnie, u8 *timeoutie, u8 *ftie) +{ + u8 *buf, *pos; + int len; + u8 mic[16]; + int ret; + u8 *rx_ftie, *tmp_ftie; + + if (lnkid == NULL || rsnie == NULL || + timeoutie == NULL || ftie == NULL) + return _FAIL; + + len = 2 * ETH_ALEN + 1 + 2 + 18 + 2 + *(rsnie + 1) + 2 + *(timeoutie + 1) + 2 + *(ftie + 1); + + buf = rtw_zmalloc(len); + if (buf == NULL) + return _FAIL; + + pos = buf; + /* 1) TDLS initiator STA MAC address */ + _rtw_memcpy(pos, lnkid + ETH_ALEN + 2, ETH_ALEN); + pos += ETH_ALEN; + /* 2) TDLS responder STA MAC address */ + _rtw_memcpy(pos, lnkid + 2 * ETH_ALEN + 2, ETH_ALEN); + pos += ETH_ALEN; + /* 3) Transaction Sequence number */ + *pos++ = trans_seq; + /* 4) Link Identifier IE */ + _rtw_memcpy(pos, lnkid, 2 + 18); + pos += 2 + 18; + /* 5) RSN IE */ + _rtw_memcpy(pos, rsnie, 2 + *(rsnie + 1)); + pos += 2 + *(rsnie + 1); + /* 6) Timeout Interval IE */ + _rtw_memcpy(pos, timeoutie, 2 + *(timeoutie + 1)); + pos += 2 + *(timeoutie + 1); + /* 7) FTIE, with the MIC field of the FTIE set to 0 */ + _rtw_memcpy(pos, ftie, 2 + *(ftie + 1)); + pos += 2; + tmp_ftie = (u8 *)(pos + 2); + _rtw_memset(tmp_ftie, 0, 16); + pos += *(ftie + 1); + + ret = omac1_aes_128(kck, buf, pos - buf, mic); + rtw_mfree(buf, len); + if (ret) + return _FAIL; + rx_ftie = ftie + 4; + + if (os_memcmp(mic, rx_ftie, 16) == 0) { + /* Valid MIC */ + return _SUCCESS; + } + + /* Invalid MIC */ + RTW_INFO("[%s] Invalid MIC\n", __FUNCTION__); + return _FAIL; + +} +#endif /* CONFIG_TDLS */ + +void rtw_use_tkipkey_handler(RTW_TIMER_HDL_ARGS) +{ + _adapter *padapter = (_adapter *)FunctionContext; + + + + /* + if (RTW_CANNOT_RUN(padapter)) { + + return; + } + */ + + padapter->securitypriv.busetkipkey = _TRUE; + + + +} + +/* Restore HW wep key setting according to key_mask */ +void rtw_sec_restore_wep_key(_adapter *adapter) +{ + struct security_priv *securitypriv = &(adapter->securitypriv); + sint keyid; + + if ((_WEP40_ == securitypriv->dot11PrivacyAlgrthm) || (_WEP104_ == securitypriv->dot11PrivacyAlgrthm)) { + for (keyid = 0; keyid < 4; keyid++) { + if (securitypriv->key_mask & BIT(keyid)) { + if (keyid == securitypriv->dot11PrivacyKeyIndex) + rtw_set_key(adapter, securitypriv, keyid, 1, _FALSE); + else + rtw_set_key(adapter, securitypriv, keyid, 0, _FALSE); + } + } + } +} + +u8 rtw_handle_tkip_countermeasure(_adapter *adapter, const char *caller) +{ + struct security_priv *securitypriv = &(adapter->securitypriv); + u8 status = _SUCCESS; + + if (securitypriv->btkip_countermeasure == _TRUE) { + u32 passing_ms = rtw_get_passing_time_ms(securitypriv->btkip_countermeasure_time); + if (passing_ms > 60 * 1000) { + RTW_PRINT("%s("ADPT_FMT") countermeasure time:%ds > 60s\n", + caller, ADPT_ARG(adapter), passing_ms / 1000); + securitypriv->btkip_countermeasure = _FALSE; + securitypriv->btkip_countermeasure_time = 0; + } else { + RTW_PRINT("%s("ADPT_FMT") countermeasure time:%ds < 60s\n", + caller, ADPT_ARG(adapter), passing_ms / 1000); + status = _FAIL; + } + } + + return status; +} + +#ifdef CONFIG_WOWLAN +u16 rtw_cal_crc16(u8 data, u16 crc) +{ + u8 shift_in, data_bit; + u8 crc_bit4, crc_bit11, crc_bit15; + u16 crc_result; + int index; + + for (index = 0; index < 8; index++) { + crc_bit15 = ((crc & BIT15) ? 1 : 0); + data_bit = (data & (BIT0 << index) ? 1 : 0); + shift_in = crc_bit15 ^ data_bit; + /*printf("crc_bit15=%d, DataBit=%d, shift_in=%d\n", + * crc_bit15, data_bit, shift_in);*/ + + crc_result = crc << 1; + + if (shift_in == 0) + crc_result &= (~BIT0); + else + crc_result |= BIT0; + /*printf("CRC =%x\n",CRC_Result);*/ + + crc_bit11 = ((crc & BIT11) ? 1 : 0) ^ shift_in; + + if (crc_bit11 == 0) + crc_result &= (~BIT12); + else + crc_result |= BIT12; + + /*printf("bit12 CRC =%x\n",CRC_Result);*/ + + crc_bit4 = ((crc & BIT4) ? 1 : 0) ^ shift_in; + + if (crc_bit4 == 0) + crc_result &= (~BIT5); + else + crc_result |= BIT5; + + /* printf("bit5 CRC =%x\n",CRC_Result); */ + /* repeat using the last result*/ + crc = crc_result; + } + return crc; +} + +/* + * function name :rtw_calc_crc + * + * input: char* pattern , pattern size + * + */ +u16 rtw_calc_crc(u8 *pdata, int length) +{ + u16 crc = 0xffff; + int i; + + for (i = 0; i < length; i++) + crc = rtw_cal_crc16(pdata[i], crc); + /* get 1' complement */ + crc = ~crc; + + return crc; +} +#endif /*CONFIG_WOWLAN*/ diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_sreset.c b/linux-bsp/drivers/rtl8188eus/core/rtw_sreset.c new file mode 100644 index 0000000..6d241ca --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_sreset.c @@ -0,0 +1,346 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#include <drv_types.h> +#include <hal_data.h> +#include <rtw_sreset.h> + +void sreset_init_value(_adapter *padapter) +{ +#if defined(DBG_CONFIG_ERROR_DETECT) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct sreset_priv *psrtpriv = &pHalData->srestpriv; + + _rtw_mutex_init(&psrtpriv->silentreset_mutex); + psrtpriv->silent_reset_inprogress = _FALSE; + psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; + psrtpriv->last_tx_time = 0; + psrtpriv->last_tx_complete_time = 0; +#endif +} +void sreset_reset_value(_adapter *padapter) +{ +#if defined(DBG_CONFIG_ERROR_DETECT) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct sreset_priv *psrtpriv = &pHalData->srestpriv; + + psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; + psrtpriv->last_tx_time = 0; + psrtpriv->last_tx_complete_time = 0; +#endif +} + +u8 sreset_get_wifi_status(_adapter *padapter) +{ +#if defined(DBG_CONFIG_ERROR_DETECT) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct sreset_priv *psrtpriv = &pHalData->srestpriv; + + u8 status = WIFI_STATUS_SUCCESS; + u32 val32 = 0; + _irqL irqL; + if (psrtpriv->silent_reset_inprogress == _TRUE) + return status; + val32 = rtw_read32(padapter, REG_TXDMA_STATUS); + if (val32 == 0xeaeaeaea) + psrtpriv->Wifi_Error_Status = WIFI_IF_NOT_EXIST; + else if (val32 != 0) { + RTW_INFO("txdmastatu(%x)\n", val32); + psrtpriv->Wifi_Error_Status = WIFI_MAC_TXDMA_ERROR; + } + + if (WIFI_STATUS_SUCCESS != psrtpriv->Wifi_Error_Status) { + RTW_INFO("==>%s error_status(0x%x)\n", __FUNCTION__, psrtpriv->Wifi_Error_Status); + status = (psrtpriv->Wifi_Error_Status & (~(USB_READ_PORT_FAIL | USB_WRITE_PORT_FAIL))); + } + RTW_INFO("==> %s wifi_status(0x%x)\n", __FUNCTION__, status); + + /* status restore */ + psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; + + return status; +#else + return WIFI_STATUS_SUCCESS; +#endif +} + +void sreset_set_wifi_error_status(_adapter *padapter, u32 status) +{ +#if defined(DBG_CONFIG_ERROR_DETECT) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + pHalData->srestpriv.Wifi_Error_Status = status; +#endif +} + +void sreset_set_trigger_point(_adapter *padapter, s32 tgp) +{ +#if defined(DBG_CONFIG_ERROR_DETECT) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + pHalData->srestpriv.dbg_trigger_point = tgp; +#endif +} + +bool sreset_inprogress(_adapter *padapter) +{ +#if defined(DBG_CONFIG_ERROR_RESET) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + return pHalData->srestpriv.silent_reset_inprogress; +#else + return _FALSE; +#endif +} + +void sreset_restore_security_station(_adapter *padapter) +{ + u8 EntryId = 0; + struct mlme_priv *mlmepriv = &padapter->mlmepriv; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta; + struct security_priv *psecuritypriv = &(padapter->securitypriv); + struct mlme_ext_info *pmlmeinfo = &padapter->mlmeextpriv.mlmext_info; + + { + u8 val8; + + if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X) { + val8 = 0xcc; +#ifdef CONFIG_WAPI_SUPPORT + } else if (padapter->wapiInfo.bWapiEnable && pmlmeinfo->auth_algo == dot11AuthAlgrthm_WAPI) { + /* Disable TxUseDefaultKey, RxUseDefaultKey, RxBroadcastUseDefaultKey. */ + val8 = 0x4c; +#endif + } else + val8 = 0xcf; + rtw_hal_set_hwreg(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8)); + } + +#if 0 + if ((padapter->securitypriv.dot11PrivacyAlgrthm == _WEP40_) || + (padapter->securitypriv.dot11PrivacyAlgrthm == _WEP104_)) { + + for (EntryId = 0; EntryId < 4; EntryId++) { + if (EntryId == psecuritypriv->dot11PrivacyKeyIndex) + rtw_set_key(padapter, &padapter->securitypriv, EntryId, 1, _FALSE); + else + rtw_set_key(padapter, &padapter->securitypriv, EntryId, 0, _FALSE); + } + + } else +#endif + if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) || + (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) { + psta = rtw_get_stainfo(pstapriv, get_bssid(mlmepriv)); + if (psta == NULL) { + /* DEBUG_ERR( ("Set wpa_set_encryption: Obtain Sta_info fail\n")); */ + } else { + /* pairwise key */ + rtw_setstakey_cmd(padapter, psta, UNICAST_KEY, _FALSE); + /* group key */ + rtw_set_key(padapter, &padapter->securitypriv, padapter->securitypriv.dot118021XGrpKeyid, 0, _FALSE); + } + } +} + +void sreset_restore_network_station(_adapter *padapter) +{ + struct mlme_priv *mlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 doiqk = _FALSE; + +#if 0 + { + /* ======================================================= */ + /* reset related register of Beacon control */ + + /* set MSR to nolink */ + Set_MSR(padapter, _HW_STATE_NOLINK_); + /* reject all data frame */ + rtw_write16(padapter, REG_RXFLTMAP2, 0x00); + /* reset TSF */ + rtw_write8(padapter, REG_DUAL_TSF_RST, (BIT(0) | BIT(1))); + + /* disable update TSF */ + SetBcnCtrlReg(padapter, BIT(4), 0); + + /* ======================================================= */ + } +#endif + + rtw_setopmode_cmd(padapter, Ndis802_11Infrastructure, _FALSE); + + { + u8 threshold; +#ifdef CONFIG_USB_HCI + /* TH=1 => means that invalidate usb rx aggregation */ + /* TH=0 => means that validate usb rx aggregation, use init value. */ + if (mlmepriv->htpriv.ht_option) { + if (padapter->registrypriv.wifi_spec == 1) + threshold = 1; + else + threshold = 0; + rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); + } else { + threshold = 1; + rtw_hal_set_hwreg(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold)); + } +#endif + } + + doiqk = _TRUE; + rtw_hal_set_hwreg(padapter, HW_VAR_DO_IQK , &doiqk); + + set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + + doiqk = _FALSE; + rtw_hal_set_hwreg(padapter , HW_VAR_DO_IQK , &doiqk); + /* disable dynamic functions, such as high power, DIG */ + /*rtw_phydm_func_disable_all(padapter);*/ + + rtw_hal_set_hwreg(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress); + + { + u8 join_type = 0; + rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type)); + } + + Set_MSR(padapter, (pmlmeinfo->state & 0x3)); + + mlmeext_joinbss_event_callback(padapter, 1); + /* restore Sequence No. */ + rtw_hal_set_hwreg(padapter, HW_VAR_RESTORE_HW_SEQ, 0); + + sreset_restore_security_station(padapter); +} + + +void sreset_restore_network_status(_adapter *padapter) +{ + struct mlme_priv *mlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if (check_fwstate(mlmepriv, WIFI_STATION_STATE)) { + RTW_INFO(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_STATION_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); + sreset_restore_network_station(padapter); + } else if (check_fwstate(mlmepriv, WIFI_AP_STATE)) { + RTW_INFO(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_AP_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); + rtw_ap_restore_network(padapter); + } else if (check_fwstate(mlmepriv, WIFI_ADHOC_STATE)) + RTW_INFO(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_ADHOC_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); + else + RTW_INFO(FUNC_ADPT_FMT" fwstate:0x%08x - ???\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv)); +} + +void sreset_stop_adapter(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + if (padapter == NULL) + return; + + RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); + + rtw_netif_stop_queue(padapter->pnetdev); + + rtw_cancel_all_timer(padapter); + + /* TODO: OS and HCI independent */ +#if defined(PLATFORM_LINUX) && defined(CONFIG_USB_HCI) + tasklet_kill(&pxmitpriv->xmit_tasklet); +#endif + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) + rtw_scan_abort(padapter); + + if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { + rtw_set_to_roam(padapter, 0); + _rtw_join_timeout_handler(padapter); + } + +} + +void sreset_start_adapter(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + if (padapter == NULL) + return; + + RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); + + if (check_fwstate(pmlmepriv, _FW_LINKED)) + sreset_restore_network_status(padapter); + + /* TODO: OS and HCI independent */ +#if defined(PLATFORM_LINUX) && defined(CONFIG_USB_HCI) + tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); +#endif + + if (is_primary_adapter(padapter)) + _set_timer(&adapter_to_dvobj(padapter)->dynamic_chk_timer, 2000); + + rtw_netif_wake_queue(padapter->pnetdev); +} + +void sreset_reset(_adapter *padapter) +{ +#ifdef DBG_CONFIG_ERROR_RESET + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct sreset_priv *psrtpriv = &pHalData->srestpriv; + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + _irqL irqL; + u32 start = rtw_get_current_time(); + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; + + RTW_INFO("%s\n", __FUNCTION__); + + psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS; + + +#ifdef CONFIG_LPS + rtw_set_ps_mode(padapter, PS_MODE_ACTIVE, 0, 0, "SRESET"); +#endif/* #ifdef CONFIG_LPS */ + + _enter_pwrlock(&pwrpriv->lock); + + psrtpriv->silent_reset_inprogress = _TRUE; + pwrpriv->change_rfpwrstate = rf_off; + + rtw_mi_sreset_adapter_hdl(padapter, _FALSE);/*sreset_stop_adapter*/ +#ifdef CONFIG_IPS + _ips_enter(padapter); + _ips_leave(padapter); +#endif + rtw_mi_sreset_adapter_hdl(padapter, _TRUE);/*sreset_start_adapter*/ + + psrtpriv->silent_reset_inprogress = _FALSE; + + _exit_pwrlock(&pwrpriv->lock); + + RTW_INFO("%s done in %d ms\n", __FUNCTION__, rtw_get_passing_time_ms(start)); + pdbgpriv->dbg_sreset_cnt++; +#endif +} diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_sta_mgt.c b/linux-bsp/drivers/rtl8188eus/core/rtw_sta_mgt.c new file mode 100644 index 0000000..818b9e3 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_sta_mgt.c @@ -0,0 +1,1187 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_STA_MGT_C_ + +#include <drv_types.h> + +#if defined(PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) + + #error "Shall be Linux or Windows, but not both!\n" + +#endif + + +bool test_st_match_rule(_adapter *adapter, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port) +{ + if (ntohs(*((u16 *)local_port)) == 5001 || ntohs(*((u16 *)remote_port)) == 5001) + return _TRUE; + return _FALSE; +} + +struct st_register test_st_reg = { + .s_proto = 0x06, + .rule = test_st_match_rule, +}; + +inline void rtw_st_ctl_init(struct st_ctl_t *st_ctl) +{ + _rtw_memset(st_ctl->reg, 0 , sizeof(struct st_register) * SESSION_TRACKER_REG_ID_NUM); + _rtw_init_queue(&st_ctl->tracker_q); +} + +inline void rtw_st_ctl_clear_tracker_q(struct st_ctl_t *st_ctl) +{ + _irqL irqL; + _list *plist, *phead; + struct session_tracker *st; + + _enter_critical_bh(&st_ctl->tracker_q.lock, &irqL); + phead = &st_ctl->tracker_q.queue; + plist = get_next(phead); + while (rtw_end_of_queue_search(phead, plist) == _FALSE) { + st = LIST_CONTAINOR(plist, struct session_tracker, list); + plist = get_next(plist); + rtw_list_delete(&st->list); + rtw_mfree((u8 *)st, sizeof(struct session_tracker)); + } + _exit_critical_bh(&st_ctl->tracker_q.lock, &irqL); +} + +inline void rtw_st_ctl_deinit(struct st_ctl_t *st_ctl) +{ + rtw_st_ctl_clear_tracker_q(st_ctl); + _rtw_deinit_queue(&st_ctl->tracker_q); +} + +inline void rtw_st_ctl_register(struct st_ctl_t *st_ctl, u8 st_reg_id, struct st_register *reg) +{ + if (st_reg_id >= SESSION_TRACKER_REG_ID_NUM) { + rtw_warn_on(1); + return; + } + + st_ctl->reg[st_reg_id].s_proto = reg->s_proto; + st_ctl->reg[st_reg_id].rule = reg->rule; +} + +inline void rtw_st_ctl_unregister(struct st_ctl_t *st_ctl, u8 st_reg_id) +{ + int i; + + if (st_reg_id >= SESSION_TRACKER_REG_ID_NUM) { + rtw_warn_on(1); + return; + } + + st_ctl->reg[st_reg_id].s_proto = 0; + st_ctl->reg[st_reg_id].rule = NULL; + + /* clear tracker queue if no session trecker registered */ + for (i = 0; i < SESSION_TRACKER_REG_ID_NUM; i++) + if (st_ctl->reg[i].s_proto != 0) + break; + if (i >= SESSION_TRACKER_REG_ID_NUM) + rtw_st_ctl_clear_tracker_q(st_ctl); +} + +inline bool rtw_st_ctl_chk_reg_s_proto(struct st_ctl_t *st_ctl, u8 s_proto) +{ + bool ret = _FALSE; + int i; + + for (i = 0; i < SESSION_TRACKER_REG_ID_NUM; i++) { + if (st_ctl->reg[i].s_proto == s_proto) { + ret = _TRUE; + break; + } + } + + return ret; +} + +inline bool rtw_st_ctl_chk_reg_rule(struct st_ctl_t *st_ctl, _adapter *adapter, u8 *local_naddr, u8 *local_port, u8 *remote_naddr, u8 *remote_port) +{ + bool ret = _FALSE; + int i; + st_match_rule rule; + + for (i = 0; i < SESSION_TRACKER_REG_ID_NUM; i++) { + rule = st_ctl->reg[i].rule; + if (rule && rule(adapter, local_naddr, local_port, remote_naddr, remote_port) == _TRUE) { + ret = _TRUE; + break; + } + } + + return ret; +} + +#define SESSION_TRACKER_FMT IP_FMT":"PORT_FMT" "IP_FMT":"PORT_FMT" %u %d" +#define SESSION_TRACKER_ARG(st) IP_ARG(&(st)->local_naddr), PORT_ARG(&(st)->local_port), IP_ARG(&(st)->remote_naddr), PORT_ARG(&(st)->remote_port), (st)->status, rtw_get_passing_time_ms((st)->set_time) + +void dump_st_ctl(void *sel, struct st_ctl_t *st_ctl) +{ + int i; + _irqL irqL; + _list *plist, *phead; + struct session_tracker *st; + + if (!DBG_SESSION_TRACKER) + return; + + for (i = 0; i < SESSION_TRACKER_REG_ID_NUM; i++) + RTW_PRINT_SEL(sel, "reg%d: %u %p\n", i, st_ctl->reg[i].s_proto, st_ctl->reg[i].rule); + + _enter_critical_bh(&st_ctl->tracker_q.lock, &irqL); + phead = &st_ctl->tracker_q.queue; + plist = get_next(phead); + while (rtw_end_of_queue_search(phead, plist) == _FALSE) { + st = LIST_CONTAINOR(plist, struct session_tracker, list); + plist = get_next(plist); + + RTW_PRINT_SEL(sel, SESSION_TRACKER_FMT"\n", SESSION_TRACKER_ARG(st)); + } + _exit_critical_bh(&st_ctl->tracker_q.lock, &irqL); + +} + +void _rtw_init_stainfo(struct sta_info *psta); +void _rtw_init_stainfo(struct sta_info *psta) +{ + + + _rtw_memset((u8 *)psta, 0, sizeof(struct sta_info)); + + _rtw_spinlock_init(&psta->lock); + _rtw_init_listhead(&psta->list); + _rtw_init_listhead(&psta->hash_list); + /* _rtw_init_listhead(&psta->asoc_list); */ + /* _rtw_init_listhead(&psta->sleep_list); */ + /* _rtw_init_listhead(&psta->wakeup_list); */ + + _rtw_init_queue(&psta->sleep_q); + psta->sleepq_len = 0; + + _rtw_init_sta_xmit_priv(&psta->sta_xmitpriv); + _rtw_init_sta_recv_priv(&psta->sta_recvpriv); + +#ifdef CONFIG_AP_MODE + + _rtw_init_listhead(&psta->asoc_list); + + _rtw_init_listhead(&psta->auth_list); + + psta->expire_to = 0; + + psta->flags = 0; + + psta->capability = 0; + + psta->bpairwise_key_installed = _FALSE; + +#ifdef CONFIG_RTW_80211R + psta->ft_pairwise_key_installed = _FALSE; +#endif + +#ifdef CONFIG_NATIVEAP_MLME + psta->nonerp_set = 0; + psta->no_short_slot_time_set = 0; + psta->no_short_preamble_set = 0; + psta->no_ht_gf_set = 0; + psta->no_ht_set = 0; + psta->ht_20mhz_set = 0; + psta->ht_40mhz_intolerant = 0; +#endif + +#ifdef CONFIG_TX_MCAST2UNI + psta->under_exist_checking = 0; +#endif /* CONFIG_TX_MCAST2UNI */ + + psta->keep_alive_trycnt = 0; + +#endif /* CONFIG_AP_MODE */ + + rtw_st_ctl_init(&psta->st_ctl); + + +} + +u32 _rtw_init_sta_priv(struct sta_priv *pstapriv) +{ + struct sta_info *psta; + s32 i; + + + pstapriv->pallocated_stainfo_buf = rtw_zvmalloc(sizeof(struct sta_info) * NUM_STA + 4); + + if (!pstapriv->pallocated_stainfo_buf) + return _FAIL; + + pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 - + ((SIZE_PTR)(pstapriv->pallocated_stainfo_buf) & 3); + + _rtw_init_queue(&pstapriv->free_sta_queue); + + _rtw_spinlock_init(&pstapriv->sta_hash_lock); + + /* _rtw_init_queue(&pstapriv->asoc_q); */ + pstapriv->asoc_sta_count = 0; + _rtw_init_queue(&pstapriv->sleep_q); + _rtw_init_queue(&pstapriv->wakeup_q); + + psta = (struct sta_info *)(pstapriv->pstainfo_buf); + + + for (i = 0; i < NUM_STA; i++) { + _rtw_init_stainfo(psta); + + _rtw_init_listhead(&(pstapriv->sta_hash[i])); + + rtw_list_insert_tail(&psta->list, get_list_head(&pstapriv->free_sta_queue)); + + psta++; + } + + pstapriv->adhoc_expire_to = 4; /* 4 * 2 = 8 sec */ + +#ifdef CONFIG_AP_MODE + + pstapriv->sta_dz_bitmap = 0; + pstapriv->tim_bitmap = 0; + + _rtw_init_listhead(&pstapriv->asoc_list); + _rtw_init_listhead(&pstapriv->auth_list); + _rtw_spinlock_init(&pstapriv->asoc_list_lock); + _rtw_spinlock_init(&pstapriv->auth_list_lock); + pstapriv->asoc_list_cnt = 0; + pstapriv->auth_list_cnt = 0; + + pstapriv->auth_to = 3; /* 3*2 = 6 sec */ + pstapriv->assoc_to = 3; + /* pstapriv->expire_to = 900; */ /* 900*2 = 1800 sec = 30 min, expire after no any traffic. */ + /* pstapriv->expire_to = 30; */ /* 30*2 = 60 sec = 1 min, expire after no any traffic. */ +#ifdef CONFIG_ACTIVE_KEEP_ALIVE_CHECK + pstapriv->expire_to = 3; /* 3*2 = 6 sec */ +#else + pstapriv->expire_to = 60;/* 60*2 = 120 sec = 2 min, expire after no any traffic. */ +#endif +#ifdef CONFIG_ATMEL_RC_PATCH + _rtw_memset(pstapriv->atmel_rc_pattern, 0, ETH_ALEN); +#endif + pstapriv->max_num_sta = NUM_STA; + +#endif + +#if CONFIG_RTW_MACADDR_ACL + _rtw_init_queue(&(pstapriv->acl_list.acl_node_q)); +#endif + +#if CONFIG_RTW_PRE_LINK_STA + rtw_pre_link_sta_ctl_init(pstapriv); +#endif + + return _SUCCESS; + +} + +inline int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta) +{ + int offset = (((u8 *)sta) - stapriv->pstainfo_buf) / sizeof(struct sta_info); + + if (!stainfo_offset_valid(offset)) + RTW_INFO("%s invalid offset(%d), out of range!!!", __func__, offset); + + return offset; +} + +inline struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int offset) +{ + if (!stainfo_offset_valid(offset)) + RTW_INFO("%s invalid offset(%d), out of range!!!", __func__, offset); + + return (struct sta_info *)(stapriv->pstainfo_buf + offset * sizeof(struct sta_info)); +} + +void _rtw_free_sta_xmit_priv_lock(struct sta_xmit_priv *psta_xmitpriv); +void _rtw_free_sta_xmit_priv_lock(struct sta_xmit_priv *psta_xmitpriv) +{ + + _rtw_spinlock_free(&psta_xmitpriv->lock); + + _rtw_spinlock_free(&(psta_xmitpriv->be_q.sta_pending.lock)); + _rtw_spinlock_free(&(psta_xmitpriv->bk_q.sta_pending.lock)); + _rtw_spinlock_free(&(psta_xmitpriv->vi_q.sta_pending.lock)); + _rtw_spinlock_free(&(psta_xmitpriv->vo_q.sta_pending.lock)); +} + +static void _rtw_free_sta_recv_priv_lock(struct sta_recv_priv *psta_recvpriv) +{ + + _rtw_spinlock_free(&psta_recvpriv->lock); + + _rtw_spinlock_free(&(psta_recvpriv->defrag_q.lock)); + + +} + +void rtw_mfree_stainfo(struct sta_info *psta); +void rtw_mfree_stainfo(struct sta_info *psta) +{ + + if (&psta->lock != NULL) + _rtw_spinlock_free(&psta->lock); + + _rtw_free_sta_xmit_priv_lock(&psta->sta_xmitpriv); + _rtw_free_sta_recv_priv_lock(&psta->sta_recvpriv); + +} + + +/* this function is used to free the memory of lock || sema for all stainfos */ +void rtw_mfree_all_stainfo(struct sta_priv *pstapriv); +void rtw_mfree_all_stainfo(struct sta_priv *pstapriv) +{ + _irqL irqL; + _list *plist, *phead; + struct sta_info *psta = NULL; + + + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + phead = get_list_head(&pstapriv->free_sta_queue); + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info , list); + plist = get_next(plist); + + rtw_mfree_stainfo(psta); + } + + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + +} + +void rtw_mfree_sta_priv_lock(struct sta_priv *pstapriv); +void rtw_mfree_sta_priv_lock(struct sta_priv *pstapriv) +{ + rtw_mfree_all_stainfo(pstapriv); /* be done before free sta_hash_lock */ + + _rtw_spinlock_free(&pstapriv->free_sta_queue.lock); + + _rtw_spinlock_free(&pstapriv->sta_hash_lock); + _rtw_spinlock_free(&pstapriv->wakeup_q.lock); + _rtw_spinlock_free(&pstapriv->sleep_q.lock); + +#ifdef CONFIG_AP_MODE + _rtw_spinlock_free(&pstapriv->asoc_list_lock); + _rtw_spinlock_free(&pstapriv->auth_list_lock); +#endif + +} + +u32 _rtw_free_sta_priv(struct sta_priv *pstapriv) +{ + _irqL irqL; + _list *phead, *plist; + struct sta_info *psta = NULL; + struct recv_reorder_ctrl *preorder_ctrl; + int index; + + if (pstapriv) { + + /* delete all reordering_ctrl_timer */ + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + for (index = 0; index < NUM_STA; index++) { + phead = &(pstapriv->sta_hash[index]); + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + int i; + psta = LIST_CONTAINOR(plist, struct sta_info , hash_list); + plist = get_next(plist); + + for (i = 0; i < 16 ; i++) { + preorder_ctrl = &psta->recvreorder_ctrl[i]; + _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); + } + } + } + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + /*===============================*/ + + rtw_mfree_sta_priv_lock(pstapriv); + +#if CONFIG_RTW_MACADDR_ACL + _rtw_deinit_queue(&(pstapriv->acl_list.acl_node_q)); +#endif + +#if CONFIG_RTW_PRE_LINK_STA + rtw_pre_link_sta_ctl_deinit(pstapriv); +#endif + + if (pstapriv->pallocated_stainfo_buf) + rtw_vmfree(pstapriv->pallocated_stainfo_buf, sizeof(struct sta_info) * NUM_STA + 4); + } + + return _SUCCESS; +} + + +/* struct sta_info *rtw_alloc_stainfo(_queue *pfree_sta_queue, unsigned char *hwaddr) */ +struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) +{ + _irqL irqL, irqL2; + uint tmp_aid; + s32 index; + _list *phash_list; + struct sta_info *psta; + _queue *pfree_sta_queue; + struct recv_reorder_ctrl *preorder_ctrl; + int i = 0; + u16 wRxSeqInitialValue = 0xffff; + + + pfree_sta_queue = &pstapriv->free_sta_queue; + + /* _enter_critical_bh(&(pfree_sta_queue->lock), &irqL); */ + _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); + if (_rtw_queue_empty(pfree_sta_queue) == _TRUE) { + /* _exit_critical_bh(&(pfree_sta_queue->lock), &irqL); */ + _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); + psta = NULL; + } else { + psta = LIST_CONTAINOR(get_next(&pfree_sta_queue->queue), struct sta_info, list); + + rtw_list_delete(&(psta->list)); + + /* _exit_critical_bh(&(pfree_sta_queue->lock), &irqL); */ + + tmp_aid = psta->aid; + + _rtw_init_stainfo(psta); + + psta->padapter = pstapriv->padapter; + + _rtw_memcpy(psta->hwaddr, hwaddr, ETH_ALEN); + + index = wifi_mac_hash(hwaddr); + + + if (index >= NUM_STA) { + psta = NULL; + goto exit; + } + phash_list = &(pstapriv->sta_hash[index]); + + /* _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); */ + + rtw_list_insert_tail(&psta->hash_list, phash_list); + + pstapriv->asoc_sta_count++; + + /* _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); */ + + /* Commented by Albert 2009/08/13 + * For the SMC router, the sequence number of first packet of WPS handshake will be 0. + * In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable. + * So, we initialize the tid_rxseq variable as the 0xffff. */ + + for (i = 0; i < 16; i++) { + _rtw_memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2); + _rtw_memset(&psta->sta_recvpriv.rxcache.iv[i], 0, sizeof(psta->sta_recvpriv.rxcache.iv[i])); + } + + init_addba_retry_timer(pstapriv->padapter, psta); +#ifdef CONFIG_IEEE80211W + init_dot11w_expire_timer(pstapriv->padapter, psta); +#endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_TDLS + rtw_init_tdls_timer(pstapriv->padapter, psta); +#endif /* CONFIG_TDLS */ + + /* for A-MPDU Rx reordering buffer control */ + for (i = 0; i < 16 ; i++) { + preorder_ctrl = &psta->recvreorder_ctrl[i]; + + preorder_ctrl->padapter = pstapriv->padapter; + + preorder_ctrl->enable = _FALSE; + + preorder_ctrl->indicate_seq = 0xffff; +#ifdef DBG_RX_SEQ + RTW_INFO("DBG_RX_SEQ %s:%d IndicateSeq: %d\n", __FUNCTION__, __LINE__, + preorder_ctrl->indicate_seq); +#endif + preorder_ctrl->wend_b = 0xffff; + /* preorder_ctrl->wsize_b = (NR_RECVBUFF-2); */ + preorder_ctrl->wsize_b = 64;/* 64; */ + preorder_ctrl->ampdu_size = RX_AMPDU_SIZE_INVALID; + + _rtw_init_queue(&preorder_ctrl->pending_recvframe_queue); + + rtw_init_recv_timer(preorder_ctrl); + } + + + /* init for DM */ + psta->rssi_stat.undecorated_smoothed_pwdb = (-1); + psta->rssi_stat.undecorated_smoothed_cck = (-1); +#ifdef CONFIG_ATMEL_RC_PATCH + psta->flag_atmel_rc = 0; +#endif + /* init for the sequence number of received management frame */ + psta->RxMgmtFrameSeqNum = 0xffff; + psta->ra_rpt_linked = _FALSE; + + rtw_alloc_macid(pstapriv->padapter, psta); + + } + +exit: + + _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL2); + + + if (psta) + rtw_mi_update_iface_status(&(pstapriv->padapter->mlmepriv), 0); + + return psta; +} + + +/* using pstapriv->sta_hash_lock to protect */ +u32 rtw_free_stainfo(_adapter *padapter , struct sta_info *psta) +{ + int i; + _irqL irqL0; + _queue *pfree_sta_queue; + struct recv_reorder_ctrl *preorder_ctrl; + struct sta_xmit_priv *pstaxmitpriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct sta_priv *pstapriv = &padapter->stapriv; + struct hw_xmit *phwxmit; + int pending_qcnt[4]; + u8 is_pre_link_sta = _FALSE; + + if (psta == NULL) + goto exit; + + is_pre_link_sta = rtw_is_pre_link_sta(pstapriv, psta->hwaddr); + + if (is_pre_link_sta == _FALSE) { + _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL0); + rtw_list_delete(&psta->hash_list); + pstapriv->asoc_sta_count--; + _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL0); + rtw_mi_update_iface_status(&(padapter->mlmepriv), 0); + } else { + _enter_critical_bh(&psta->lock, &irqL0); + psta->state = WIFI_FW_PRE_LINK; + _exit_critical_bh(&psta->lock, &irqL0); + } + + _enter_critical_bh(&psta->lock, &irqL0); + psta->state &= ~_FW_LINKED; + _exit_critical_bh(&psta->lock, &irqL0); + + pfree_sta_queue = &pstapriv->free_sta_queue; + + + pstaxmitpriv = &psta->sta_xmitpriv; + + /* rtw_list_delete(&psta->sleep_list); */ + + /* rtw_list_delete(&psta->wakeup_list); */ + + _enter_critical_bh(&pxmitpriv->lock, &irqL0); + + rtw_free_xmitframe_queue(pxmitpriv, &psta->sleep_q); + psta->sleepq_len = 0; + + /* vo */ + /* _enter_critical_bh(&(pxmitpriv->vo_pending.lock), &irqL0); */ + rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending); + rtw_list_delete(&(pstaxmitpriv->vo_q.tx_pending)); + phwxmit = pxmitpriv->hwxmits; + phwxmit->accnt -= pstaxmitpriv->vo_q.qcnt; + pending_qcnt[0] = pstaxmitpriv->vo_q.qcnt; + pstaxmitpriv->vo_q.qcnt = 0; + /* _exit_critical_bh(&(pxmitpriv->vo_pending.lock), &irqL0); */ + + /* vi */ + /* _enter_critical_bh(&(pxmitpriv->vi_pending.lock), &irqL0); */ + rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending); + rtw_list_delete(&(pstaxmitpriv->vi_q.tx_pending)); + phwxmit = pxmitpriv->hwxmits + 1; + phwxmit->accnt -= pstaxmitpriv->vi_q.qcnt; + pending_qcnt[1] = pstaxmitpriv->vi_q.qcnt; + pstaxmitpriv->vi_q.qcnt = 0; + /* _exit_critical_bh(&(pxmitpriv->vi_pending.lock), &irqL0); */ + + /* be */ + /* _enter_critical_bh(&(pxmitpriv->be_pending.lock), &irqL0); */ + rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->be_q.sta_pending); + rtw_list_delete(&(pstaxmitpriv->be_q.tx_pending)); + phwxmit = pxmitpriv->hwxmits + 2; + phwxmit->accnt -= pstaxmitpriv->be_q.qcnt; + pending_qcnt[2] = pstaxmitpriv->be_q.qcnt; + pstaxmitpriv->be_q.qcnt = 0; + /* _exit_critical_bh(&(pxmitpriv->be_pending.lock), &irqL0); */ + + /* bk */ + /* _enter_critical_bh(&(pxmitpriv->bk_pending.lock), &irqL0); */ + rtw_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending); + rtw_list_delete(&(pstaxmitpriv->bk_q.tx_pending)); + phwxmit = pxmitpriv->hwxmits + 3; + phwxmit->accnt -= pstaxmitpriv->bk_q.qcnt; + pending_qcnt[3] = pstaxmitpriv->bk_q.qcnt; + pstaxmitpriv->bk_q.qcnt = 0; + /* _exit_critical_bh(&(pxmitpriv->bk_pending.lock), &irqL0); */ + + rtw_os_wake_queue_at_free_stainfo(padapter, pending_qcnt); + + _exit_critical_bh(&pxmitpriv->lock, &irqL0); + + + /* re-init sta_info; 20061114 */ /* will be init in alloc_stainfo */ + /* _rtw_init_sta_xmit_priv(&psta->sta_xmitpriv); */ + /* _rtw_init_sta_recv_priv(&psta->sta_recvpriv); */ +#ifdef CONFIG_IEEE80211W + _cancel_timer_ex(&psta->dot11w_expire_timer); +#endif /* CONFIG_IEEE80211W */ + _cancel_timer_ex(&psta->addba_retry_timer); + +#ifdef CONFIG_TDLS + psta->tdls_sta_state = TDLS_STATE_NONE; + rtw_free_tdls_timer(psta); +#endif /* CONFIG_TDLS */ + + /* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */ + for (i = 0; i < 16 ; i++) { + _irqL irqL; + _list *phead, *plist; + union recv_frame *prframe; + _queue *ppending_recvframe_queue; + _queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; + + preorder_ctrl = &psta->recvreorder_ctrl[i]; + + _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); + + + ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; + + _enter_critical_bh(&ppending_recvframe_queue->lock, &irqL); + + phead = get_list_head(ppending_recvframe_queue); + plist = get_next(phead); + + while (!rtw_is_list_empty(phead)) { + prframe = LIST_CONTAINOR(plist, union recv_frame, u); + + plist = get_next(plist); + + rtw_list_delete(&(prframe->u.hdr.list)); + + rtw_free_recvframe(prframe, pfree_recv_queue); + } + + _exit_critical_bh(&ppending_recvframe_queue->lock, &irqL); + + } + + if (!((psta->state & WIFI_AP_STATE) || MacAddr_isBcst(psta->hwaddr)) && is_pre_link_sta == _FALSE) + rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, _FALSE); + + + /* release mac id for non-bc/mc station, */ + if (is_pre_link_sta == _FALSE) + rtw_release_macid(pstapriv->padapter, psta); + +#ifdef CONFIG_AP_MODE + + /* + _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL0); + rtw_list_delete(&psta->asoc_list); + _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL0); + */ + _enter_critical_bh(&pstapriv->auth_list_lock, &irqL0); + if (!rtw_is_list_empty(&psta->auth_list)) { + rtw_list_delete(&psta->auth_list); + pstapriv->auth_list_cnt--; + } + _exit_critical_bh(&pstapriv->auth_list_lock, &irqL0); + + psta->expire_to = 0; +#ifdef CONFIG_ATMEL_RC_PATCH + psta->flag_atmel_rc = 0; +#endif + psta->sleepq_ac_len = 0; + psta->qos_info = 0; + + psta->max_sp_len = 0; + psta->uapsd_bk = 0; + psta->uapsd_be = 0; + psta->uapsd_vi = 0; + psta->uapsd_vo = 0; + + psta->has_legacy_ac = 0; + +#ifdef CONFIG_NATIVEAP_MLME + + pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); + pstapriv->tim_bitmap &= ~BIT(psta->aid); + + /* rtw_indicate_sta_disassoc_event(padapter, psta); */ + + if ((psta->aid > 0) && (pstapriv->sta_aid[psta->aid - 1] == psta)) { + pstapriv->sta_aid[psta->aid - 1] = NULL; + psta->aid = 0; + } + +#endif /* CONFIG_NATIVEAP_MLME */ + +#ifdef CONFIG_TX_MCAST2UNI + psta->under_exist_checking = 0; +#endif /* CONFIG_TX_MCAST2UNI */ + +#endif /* CONFIG_AP_MODE */ + + rtw_st_ctl_deinit(&psta->st_ctl); + + if (is_pre_link_sta == _FALSE) { + _rtw_spinlock_free(&psta->lock); + + /* _enter_critical_bh(&(pfree_sta_queue->lock), &irqL0); */ + _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL0); + rtw_list_insert_tail(&psta->list, get_list_head(pfree_sta_queue)); + _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL0); + /* _exit_critical_bh(&(pfree_sta_queue->lock), &irqL0); */ + } + +exit: + return _SUCCESS; +} + +/* free all stainfo which in sta_hash[all] */ +void rtw_free_all_stainfo(_adapter *padapter) +{ + _irqL irqL; + _list *plist, *phead; + s32 index; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *pbcmc_stainfo = rtw_get_bcmc_stainfo(padapter); + u8 free_sta_num = 0; + char free_sta_list[NUM_STA]; + int stainfo_offset; + + + if (pstapriv->asoc_sta_count == 1) + goto exit; + + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + for (index = 0; index < NUM_STA; index++) { + phead = &(pstapriv->sta_hash[index]); + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + psta = LIST_CONTAINOR(plist, struct sta_info , hash_list); + + plist = get_next(plist); + + if (pbcmc_stainfo != psta) { + if (rtw_is_pre_link_sta(pstapriv, psta->hwaddr) == _FALSE) + rtw_list_delete(&psta->hash_list); + + stainfo_offset = rtw_stainfo_offset(pstapriv, psta); + if (stainfo_offset_valid(stainfo_offset)) + free_sta_list[free_sta_num++] = stainfo_offset; + } + + } + } + + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + + for (index = 0; index < free_sta_num; index++) { + psta = rtw_get_stainfo_by_offset(pstapriv, free_sta_list[index]); + rtw_free_stainfo(padapter , psta); + } + +exit: + return; +} + +/* any station allocated can be searched by hash list */ +struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) +{ + + _irqL irqL; + + _list *plist, *phead; + + struct sta_info *psta = NULL; + + u32 index; + + u8 *addr; + + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + + if (hwaddr == NULL) + return NULL; + + if (IS_MCAST(hwaddr)) + addr = bc_addr; + else + addr = hwaddr; + + index = wifi_mac_hash(addr); + + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + phead = &(pstapriv->sta_hash[index]); + plist = get_next(phead); + + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + + if ((_rtw_memcmp(psta->hwaddr, addr, ETH_ALEN)) == _TRUE) { + /* if found the matched address */ + break; + } + psta = NULL; + plist = get_next(plist); + } + + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + return psta; + +} + +u32 rtw_init_bcmc_stainfo(_adapter *padapter) +{ + + struct sta_info *psta; + struct tx_servq *ptxservq; + u32 res = _SUCCESS; + NDIS_802_11_MAC_ADDRESS bcast_addr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + struct sta_priv *pstapriv = &padapter->stapriv; + /* _queue *pstapending = &padapter->xmitpriv.bm_pending; */ + + + psta = rtw_alloc_stainfo(pstapriv, bcast_addr); + + if (psta == NULL) { + res = _FAIL; + goto exit; + } +#ifdef CONFIG_BEAMFORMING + psta->txbf_gid = 63; + psta->txbf_paid = 0; +#endif + ptxservq = &(psta->sta_xmitpriv.be_q); + + /* + _enter_critical(&pstapending->lock, &irqL0); + + if (rtw_is_list_empty(&ptxservq->tx_pending)) + rtw_list_insert_tail(&ptxservq->tx_pending, get_list_head(pstapending)); + + _exit_critical(&pstapending->lock, &irqL0); + */ + +exit: + return _SUCCESS; + +} + + +struct sta_info *rtw_get_bcmc_stainfo(_adapter *padapter) +{ + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + psta = rtw_get_stainfo(pstapriv, bc_addr); + return psta; + +} + +#if CONFIG_RTW_MACADDR_ACL +const char *const _acl_mode_str[] = { + "DISABLED", + "ACCEPT_UNLESS_LISTED", + "DENY_UNLESS_LISTED", +}; + +u8 rtw_access_ctrl(_adapter *adapter, u8 *mac_addr) +{ + u8 res = _TRUE; + _irqL irqL; + _list *list, *head; + struct rtw_wlan_acl_node *acl_node; + u8 match = _FALSE; + struct sta_priv *stapriv = &adapter->stapriv; + struct wlan_acl_pool *acl = &stapriv->acl_list; + _queue *acl_node_q = &acl->acl_node_q; + + _enter_critical_bh(&(acl_node_q->lock), &irqL); + head = get_list_head(acl_node_q); + list = get_next(head); + while (rtw_end_of_queue_search(head, list) == _FALSE) { + acl_node = LIST_CONTAINOR(list, struct rtw_wlan_acl_node, list); + list = get_next(list); + + if (_rtw_memcmp(acl_node->addr, mac_addr, ETH_ALEN)) { + if (acl_node->valid == _TRUE) { + match = _TRUE; + break; + } + } + } + _exit_critical_bh(&(acl_node_q->lock), &irqL); + + if (acl->mode == RTW_ACL_MODE_ACCEPT_UNLESS_LISTED) + res = (match == _TRUE) ? _FALSE : _TRUE; + else if (acl->mode == RTW_ACL_MODE_DENY_UNLESS_LISTED) + res = (match == _TRUE) ? _TRUE : _FALSE; + else + res = _TRUE; + + return res; +} + +void dump_macaddr_acl(void *sel, _adapter *adapter) +{ + struct sta_priv *stapriv = &adapter->stapriv; + struct wlan_acl_pool *acl = &stapriv->acl_list; + int i; + + RTW_PRINT_SEL(sel, "mode:%s(%d)\n", acl_mode_str(acl->mode), acl->mode); + RTW_PRINT_SEL(sel, "num:%d/%d\n", acl->num, NUM_ACL); + for (i = 0; i < NUM_ACL; i++) { + if (acl->aclnode[i].valid == _FALSE) + continue; + RTW_PRINT_SEL(sel, MAC_FMT"\n", MAC_ARG(acl->aclnode[i].addr)); + } +} +#endif /* CONFIG_RTW_MACADDR_ACL */ + +bool rtw_is_pre_link_sta(struct sta_priv *stapriv, u8 *addr) +{ +#if CONFIG_RTW_PRE_LINK_STA + struct pre_link_sta_ctl_t *pre_link_sta_ctl = &stapriv->pre_link_sta_ctl; + struct sta_info *sta = NULL; + u8 exist = _FALSE; + int i; + _irqL irqL; + + _enter_critical_bh(&(pre_link_sta_ctl->lock), &irqL); + for (i = 0; i < RTW_PRE_LINK_STA_NUM; i++) { + if (pre_link_sta_ctl->node[i].valid == _TRUE + && _rtw_memcmp(pre_link_sta_ctl->node[i].addr, addr, ETH_ALEN) == _TRUE + ) { + exist = _TRUE; + break; + } + } + _exit_critical_bh(&(pre_link_sta_ctl->lock), &irqL); + + return exist; +#else + return _FALSE; +#endif +} + +#if CONFIG_RTW_PRE_LINK_STA +struct sta_info *rtw_pre_link_sta_add(struct sta_priv *stapriv, u8 *hwaddr) +{ + struct pre_link_sta_ctl_t *pre_link_sta_ctl = &stapriv->pre_link_sta_ctl; + struct pre_link_sta_node_t *node = NULL; + struct sta_info *sta = NULL; + u8 exist = _FALSE; + int i; + _irqL irqL; + + if (rtw_check_invalid_mac_address(hwaddr, _FALSE) == _TRUE) + goto exit; + + _enter_critical_bh(&(pre_link_sta_ctl->lock), &irqL); + for (i = 0; i < RTW_PRE_LINK_STA_NUM; i++) { + if (pre_link_sta_ctl->node[i].valid == _TRUE + && _rtw_memcmp(pre_link_sta_ctl->node[i].addr, hwaddr, ETH_ALEN) == _TRUE + ) { + node = &pre_link_sta_ctl->node[i]; + exist = _TRUE; + break; + } + + if (node == NULL && pre_link_sta_ctl->node[i].valid == _FALSE) + node = &pre_link_sta_ctl->node[i]; + } + + if (exist == _FALSE && node) { + _rtw_memcpy(node->addr, hwaddr, ETH_ALEN); + node->valid = _TRUE; + pre_link_sta_ctl->num++; + } + _exit_critical_bh(&(pre_link_sta_ctl->lock), &irqL); + + if (node == NULL) + goto exit; + + sta = rtw_get_stainfo(stapriv, hwaddr); + if (sta) + goto odm_hook; + + sta = rtw_alloc_stainfo(stapriv, hwaddr); + if (!sta) + goto exit; + + sta->state = WIFI_FW_PRE_LINK; + +odm_hook: + rtw_hal_set_odm_var(stapriv->padapter, HAL_ODM_STA_INFO, sta, _TRUE); + +exit: + return sta; +} + +void rtw_pre_link_sta_del(struct sta_priv *stapriv, u8 *hwaddr) +{ + struct pre_link_sta_ctl_t *pre_link_sta_ctl = &stapriv->pre_link_sta_ctl; + struct pre_link_sta_node_t *node = NULL; + struct sta_info *sta = NULL; + u8 exist = _FALSE; + int i; + _irqL irqL; + + if (rtw_check_invalid_mac_address(hwaddr, _FALSE) == _TRUE) + goto exit; + + _enter_critical_bh(&(pre_link_sta_ctl->lock), &irqL); + for (i = 0; i < RTW_PRE_LINK_STA_NUM; i++) { + if (pre_link_sta_ctl->node[i].valid == _TRUE + && _rtw_memcmp(pre_link_sta_ctl->node[i].addr, hwaddr, ETH_ALEN) == _TRUE + ) { + node = &pre_link_sta_ctl->node[i]; + exist = _TRUE; + break; + } + } + + if (exist == _TRUE && node) { + node->valid = _FALSE; + pre_link_sta_ctl->num--; + } + _exit_critical_bh(&(pre_link_sta_ctl->lock), &irqL); + + if (exist == _FALSE) + goto exit; + + sta = rtw_get_stainfo(stapriv, hwaddr); + if (!sta) + goto exit; + + if (sta->state == WIFI_FW_PRE_LINK) + rtw_free_stainfo(stapriv->padapter, sta); + +exit: + return; +} + +void rtw_pre_link_sta_ctl_reset(struct sta_priv *stapriv) +{ + struct pre_link_sta_ctl_t *pre_link_sta_ctl = &stapriv->pre_link_sta_ctl; + struct pre_link_sta_node_t *node = NULL; + struct sta_info *sta = NULL; + int i, j = 0; + _irqL irqL; + + u8 addrs[RTW_PRE_LINK_STA_NUM][ETH_ALEN]; + + _rtw_memset(addrs, 0, RTW_PRE_LINK_STA_NUM * ETH_ALEN); + + _enter_critical_bh(&(pre_link_sta_ctl->lock), &irqL); + for (i = 0; i < RTW_PRE_LINK_STA_NUM; i++) { + if (pre_link_sta_ctl->node[i].valid == _FALSE) + continue; + _rtw_memcpy(&(addrs[j][0]), pre_link_sta_ctl->node[i].addr, ETH_ALEN); + pre_link_sta_ctl->node[i].valid = _FALSE; + pre_link_sta_ctl->num--; + j++; + } + _exit_critical_bh(&(pre_link_sta_ctl->lock), &irqL); + + for (i = 0; i < j; i++) { + sta = rtw_get_stainfo(stapriv, &(addrs[i][0])); + if (!sta) + continue; + + if (sta->state == WIFI_FW_PRE_LINK) + rtw_free_stainfo(stapriv->padapter, sta); + } +} + +void rtw_pre_link_sta_ctl_init(struct sta_priv *stapriv) +{ + struct pre_link_sta_ctl_t *pre_link_sta_ctl = &stapriv->pre_link_sta_ctl; + int i; + + _rtw_spinlock_init(&pre_link_sta_ctl->lock); + pre_link_sta_ctl->num = 0; + for (i = 0; i < RTW_PRE_LINK_STA_NUM; i++) + pre_link_sta_ctl->node[i].valid = _FALSE; +} + +void rtw_pre_link_sta_ctl_deinit(struct sta_priv *stapriv) +{ + struct pre_link_sta_ctl_t *pre_link_sta_ctl = &stapriv->pre_link_sta_ctl; + int i; + + rtw_pre_link_sta_ctl_reset(stapriv); + + _rtw_spinlock_free(&pre_link_sta_ctl->lock); +} + +void dump_pre_link_sta_ctl(void *sel, struct sta_priv *stapriv) +{ + struct pre_link_sta_ctl_t *pre_link_sta_ctl = &stapriv->pre_link_sta_ctl; + int i; + + RTW_PRINT_SEL(sel, "num:%d/%d\n", pre_link_sta_ctl->num, RTW_PRE_LINK_STA_NUM); + + for (i = 0; i < RTW_PRE_LINK_STA_NUM; i++) { + if (pre_link_sta_ctl->node[i].valid == _FALSE) + continue; + RTW_PRINT_SEL(sel, MAC_FMT"\n", MAC_ARG(pre_link_sta_ctl->node[i].addr)); + } +} +#endif /* CONFIG_RTW_PRE_LINK_STA */ + diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_tdls.c b/linux-bsp/drivers/rtl8188eus/core/rtw_tdls.c new file mode 100644 index 0000000..20af92b --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_tdls.c @@ -0,0 +1,3332 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_TDLS_C_ + +#include <drv_types.h> +#include <hal_data.h> + +#ifdef CONFIG_TDLS +#define ONE_SEC 1000 /* 1000 ms */ + +extern unsigned char MCS_rate_2R[16]; +extern unsigned char MCS_rate_1R[16]; +extern void process_wmmps_data(_adapter *padapter, union recv_frame *precv_frame); + +void rtw_reset_tdls_info(_adapter *padapter) +{ + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + + ptdlsinfo->ap_prohibited = _FALSE; + + /* For TDLS channel switch, currently we only allow it to work in wifi logo test mode */ + if (padapter->registrypriv.wifi_spec == 1) + ptdlsinfo->ch_switch_prohibited = _FALSE; + else + ptdlsinfo->ch_switch_prohibited = _TRUE; + + ptdlsinfo->link_established = _FALSE; + ptdlsinfo->sta_cnt = 0; + ptdlsinfo->sta_maximum = _FALSE; + +#ifdef CONFIG_TDLS_CH_SW + ptdlsinfo->chsw_info.ch_sw_state = TDLS_STATE_NONE; + ATOMIC_SET(&ptdlsinfo->chsw_info.chsw_on, _FALSE); + ptdlsinfo->chsw_info.off_ch_num = 0; + ptdlsinfo->chsw_info.ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + ptdlsinfo->chsw_info.cur_time = 0; + ptdlsinfo->chsw_info.delay_switch_back = _FALSE; + ptdlsinfo->chsw_info.dump_stack = _FALSE; +#endif + + ptdlsinfo->ch_sensing = 0; + ptdlsinfo->watchdog_count = 0; + ptdlsinfo->dev_discovered = _FALSE; + +#ifdef CONFIG_WFD + ptdlsinfo->wfd_info = &padapter->wfd_info; +#endif +} + +int rtw_init_tdls_info(_adapter *padapter) +{ + int res = _SUCCESS; + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + + rtw_reset_tdls_info(padapter); + + ptdlsinfo->tdls_enable = _TRUE; +#ifdef CONFIG_TDLS_DRIVER_SETUP + ptdlsinfo->driver_setup = _TRUE; +#else + ptdlsinfo->driver_setup = _FALSE; +#endif /* CONFIG_TDLS_DRIVER_SETUP */ + + _rtw_spinlock_init(&ptdlsinfo->cmd_lock); + _rtw_spinlock_init(&ptdlsinfo->hdl_lock); + + return res; + +} + +void rtw_free_tdls_info(struct tdls_info *ptdlsinfo) +{ + _rtw_spinlock_free(&ptdlsinfo->cmd_lock); + _rtw_spinlock_free(&ptdlsinfo->hdl_lock); + + _rtw_memset(ptdlsinfo, 0, sizeof(struct tdls_info)); + +} + +int check_ap_tdls_prohibited(u8 *pframe, u8 pkt_len) +{ + u8 tdls_prohibited_bit = 0x40; /* bit(38); TDLS_prohibited */ + + if (pkt_len < 5) + return _FALSE; + + pframe += 4; + if ((*pframe) & tdls_prohibited_bit) + return _TRUE; + + return _FALSE; +} + +int check_ap_tdls_ch_switching_prohibited(u8 *pframe, u8 pkt_len) +{ + u8 tdls_ch_swithcing_prohibited_bit = 0x80; /* bit(39); TDLS_channel_switching prohibited */ + + if (pkt_len < 5) + return _FALSE; + + pframe += 4; + if ((*pframe) & tdls_ch_swithcing_prohibited_bit) + return _TRUE; + + return _FALSE; +} + +u8 rtw_tdls_is_setup_allowed(_adapter *padapter) +{ + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + + if (ptdlsinfo->ap_prohibited == _TRUE) + return _FALSE; + + return _TRUE; +} + +#ifdef CONFIG_TDLS_CH_SW +u8 rtw_tdls_is_chsw_allowed(_adapter *padapter) +{ + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + + if (ptdlsinfo->ch_switch_prohibited == _TRUE) + return _FALSE; + + if (padapter->registrypriv.wifi_spec == 0) + return _FALSE; + + return _TRUE; +} +#endif + +int _issue_nulldata_to_TDLS_peer_STA(_adapter *padapter, unsigned char *da, unsigned int power_mode, int wait_ack) +{ + int ret = _FAIL; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl, *qc; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + pattrib->hdrlen += 2; + pattrib->qos_en = _TRUE; + pattrib->eosp = 1; + pattrib->ack_policy = 0; + pattrib->mdata = 0; + pattrib->retry_ctrl = _FALSE; + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + if (power_mode) + SetPwrMgt(fctrl); + + qc = (unsigned short *)(pframe + pattrib->hdrlen - 2); + + SetPriority(qc, 7); /* Set priority to VO */ + + SetEOSP(qc, pattrib->eosp); + + SetAckpolicy(qc, pattrib->ack_policy); + + _rtw_memcpy(pwlanhdr->addr1, da, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_QOS_DATA_NULL); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr_qos); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos); + + pattrib->last_txcmdsz = pattrib->pktlen; + + if (wait_ack) + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + } + +exit: + return ret; + +} + +/* + *wait_ms == 0 means that there is no need to wait ack through C2H_CCX_TX_RPT + *wait_ms > 0 means you want to wait ack through C2H_CCX_TX_RPT, and the value of wait_ms means the interval between each TX + *try_cnt means the maximal TX count to try + */ +int issue_nulldata_to_TDLS_peer_STA(_adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms) +{ + int ret; + int i = 0; + u32 start = rtw_get_current_time(); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + +#if 0 + psta = rtw_get_stainfo(&padapter->stapriv, da); + if (psta) { + if (power_mode) + rtw_hal_macid_sleep(padapter, psta->mac_id); + else + rtw_hal_macid_wakeup(padapter, psta->mac_id); + } else { + RTW_INFO(FUNC_ADPT_FMT ": Can't find sta info for " MAC_FMT ", skip macid %s!!\n", + FUNC_ADPT_ARG(padapter), MAC_ARG(da), power_mode ? "sleep" : "wakeup"); + rtw_warn_on(1); + } +#endif + + do { + ret = _issue_nulldata_to_TDLS_peer_STA(padapter, da, power_mode, wait_ms > 0 ? _TRUE : _FALSE); + + i++; + + if (RTW_CANNOT_RUN(padapter)) + break; + + if (i < try_cnt && wait_ms > 0 && ret == _FAIL) + rtw_msleep_os(wait_ms); + + } while ((i < try_cnt) && (ret == _FAIL || wait_ms == 0)); + + if (ret != _FAIL) { + ret = _SUCCESS; +#ifndef DBG_XMIT_ACK + goto exit; +#endif + } + + if (try_cnt && wait_ms) { + if (da) + RTW_INFO(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + else + RTW_INFO(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n", + FUNC_ADPT_ARG(padapter), rtw_get_oper_ch(padapter), + ret == _SUCCESS ? ", acked" : "", i, try_cnt, rtw_get_passing_time_ms(start)); + } +exit: + return ret; +} + +void free_tdls_sta(_adapter *padapter, struct sta_info *ptdls_sta) +{ + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + struct sta_priv *pstapriv = &padapter->stapriv; + _irqL irqL; + + /* free peer sta_info */ + _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); + if (ptdlsinfo->sta_cnt != 0) + ptdlsinfo->sta_cnt--; + _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); + /* -2: AP + BC/MC sta, -4: default key */ + if (ptdlsinfo->sta_cnt < MAX_ALLOWED_TDLS_STA_NUM) { + ptdlsinfo->sta_maximum = _FALSE; + _rtw_memset(&ptdlsinfo->ss_record, 0x00, sizeof(struct tdls_ss_record)); + } + + /* clear cam */ + rtw_clearstakey_cmd(padapter, ptdls_sta, _TRUE); + + if (ptdlsinfo->sta_cnt == 0) { + rtw_tdls_cmd(padapter, NULL, TDLS_RS_RCR); + ptdlsinfo->link_established = _FALSE; + } else + RTW_INFO("Remain tdls sta:%02x\n", ptdlsinfo->sta_cnt); + + rtw_free_stainfo(padapter, ptdls_sta); + +} + + +/* TDLS encryption(if needed) will always be CCMP */ +void rtw_tdls_set_key(_adapter *padapter, struct sta_info *ptdls_sta) +{ + ptdls_sta->dot118021XPrivacy = _AES_; + rtw_setstakey_cmd(padapter, ptdls_sta, TDLS_KEY, _TRUE); +} + +#ifdef CONFIG_80211N_HT +void rtw_tdls_process_ht_cap(_adapter *padapter, struct sta_info *ptdls_sta, u8 *data, u8 Length) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + u8 max_AMPDU_len, min_MPDU_spacing; + u8 cur_ldpc_cap = 0, cur_stbc_cap = 0, cur_beamform_cap = 0; + + /* Save HT capabilities in the sta object */ + _rtw_memset(&ptdls_sta->htpriv.ht_cap, 0, sizeof(struct rtw_ieee80211_ht_cap)); + if (data && Length >= sizeof(struct rtw_ieee80211_ht_cap)) { + ptdls_sta->flags |= WLAN_STA_HT; + ptdls_sta->flags |= WLAN_STA_WME; + + _rtw_memcpy(&ptdls_sta->htpriv.ht_cap, data, sizeof(struct rtw_ieee80211_ht_cap)); + } else + ptdls_sta->flags &= ~WLAN_STA_HT; + + if (ptdls_sta->flags & WLAN_STA_HT) { + if (padapter->registrypriv.ht_enable == _TRUE) { + ptdls_sta->htpriv.ht_option = _TRUE; + ptdls_sta->qos_option = _TRUE; + } else { + ptdls_sta->htpriv.ht_option = _FALSE; + ptdls_sta->qos_option = _FALSE; + } + } + + /* HT related cap */ + if (ptdls_sta->htpriv.ht_option) { + /* Check if sta supports rx ampdu */ + if (padapter->registrypriv.ampdu_enable == 1) + ptdls_sta->htpriv.ampdu_enable = _TRUE; + + /* AMPDU Parameters field */ + /* Get MIN of MAX AMPDU Length Exp */ + if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3) > (data[2] & 0x3)) + max_AMPDU_len = (data[2] & 0x3); + else + max_AMPDU_len = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3); + /* Get MAX of MIN MPDU Start Spacing */ + if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) > (data[2] & 0x1c)) + min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c); + else + min_MPDU_spacing = (data[2] & 0x1c); + ptdls_sta->htpriv.rx_ampdu_min_spacing = max_AMPDU_len | min_MPDU_spacing; + + /* Check if sta support s Short GI 20M */ + if (ptdls_sta->htpriv.ht_cap.cap_info & cpu_to_le16(IEEE80211_HT_CAP_SGI_20)) + ptdls_sta->htpriv.sgi_20m = _TRUE; + + /* Check if sta support s Short GI 40M */ + if (ptdls_sta->htpriv.ht_cap.cap_info & cpu_to_le16(IEEE80211_HT_CAP_SGI_40)) + ptdls_sta->htpriv.sgi_40m = _TRUE; + + /* Bwmode would still followed AP's setting */ + if (ptdls_sta->htpriv.ht_cap.cap_info & cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH)) { + if (padapter->mlmeextpriv.cur_bwmode >= CHANNEL_WIDTH_40) + ptdls_sta->bw_mode = CHANNEL_WIDTH_40; + ptdls_sta->htpriv.ch_offset = padapter->mlmeextpriv.cur_ch_offset; + } + + /* Config LDPC Coding Capability */ + if (TEST_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_TX) && GET_HT_CAP_ELE_LDPC_CAP(data)) { + SET_FLAG(cur_ldpc_cap, (LDPC_HT_ENABLE_TX | LDPC_HT_CAP_TX)); + RTW_INFO("Enable HT Tx LDPC!\n"); + } + ptdls_sta->htpriv.ldpc_cap = cur_ldpc_cap; + + /* Config STBC setting */ + if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX) && GET_HT_CAP_ELE_RX_STBC(data)) { + SET_FLAG(cur_stbc_cap, (STBC_HT_ENABLE_TX | STBC_HT_CAP_TX)); + RTW_INFO("Enable HT Tx STBC!\n"); + } + ptdls_sta->htpriv.stbc_cap = cur_stbc_cap; + +#ifdef CONFIG_BEAMFORMING + /* Config Tx beamforming setting */ + if (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE) && + GET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP(data)) + SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE); + + if (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE) && + GET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP(data)) + SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE); + ptdls_sta->htpriv.beamform_cap = cur_beamform_cap; + if (cur_beamform_cap) + RTW_INFO("Client HT Beamforming Cap = 0x%02X\n", cur_beamform_cap); +#endif /* CONFIG_BEAMFORMING */ + } + +} + +u8 *rtw_tdls_set_ht_cap(_adapter *padapter, u8 *pframe, struct pkt_attrib *pattrib) +{ + rtw_ht_use_default_setting(padapter); + + rtw_restructure_ht_ie(padapter, NULL, pframe, 0, &(pattrib->pktlen), padapter->mlmeextpriv.cur_channel); + + return pframe + pattrib->pktlen; +} +#endif + +#ifdef CONFIG_80211AC_VHT +void rtw_tdls_process_vht_cap(_adapter *padapter, struct sta_info *ptdls_sta, u8 *data, u8 Length) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; + u8 cur_ldpc_cap = 0, cur_stbc_cap = 0, cur_beamform_cap = 0, rf_type = RF_1T1R, tx_nss = 0; + u8 *pcap_mcs; + + _rtw_memset(&ptdls_sta->vhtpriv, 0, sizeof(struct vht_priv)); + if (data && Length == 12) { + ptdls_sta->flags |= WLAN_STA_VHT; + + _rtw_memcpy(ptdls_sta->vhtpriv.vht_cap, data, 12); + +#if 0 + if (elems.vht_op_mode_notify && elems.vht_op_mode_notify_len == 1) + _rtw_memcpy(&pstat->vhtpriv.vht_op_mode_notify, elems.vht_op_mode_notify, 1); + else /* for Frame without Operating Mode notify ie; default: 80M */ + pstat->vhtpriv.vht_op_mode_notify = CHANNEL_WIDTH_80; +#else + ptdls_sta->vhtpriv.vht_op_mode_notify = CHANNEL_WIDTH_80; +#endif + } else + ptdls_sta->flags &= ~WLAN_STA_VHT; + + if (ptdls_sta->flags & WLAN_STA_VHT) { + if (REGSTY_IS_11AC_ENABLE(&padapter->registrypriv) + && hal_chk_proto_cap(padapter, PROTO_CAP_11AC) + && (!pmlmepriv->country_ent || COUNTRY_CHPLAN_EN_11AC(pmlmepriv->country_ent))) + ptdls_sta->vhtpriv.vht_option = _TRUE; + else + ptdls_sta->vhtpriv.vht_option = _FALSE; + } + + /* B4 Rx LDPC */ + if (TEST_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_TX) && + GET_VHT_CAPABILITY_ELE_RX_LDPC(data)) { + SET_FLAG(cur_ldpc_cap, (LDPC_VHT_ENABLE_TX | LDPC_VHT_CAP_TX)); + RTW_INFO("Current VHT LDPC Setting = %02X\n", cur_ldpc_cap); + } + ptdls_sta->vhtpriv.ldpc_cap = cur_ldpc_cap; + + /* B5 Short GI for 80 MHz */ + ptdls_sta->vhtpriv.sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI80M(data) & pvhtpriv->sgi_80m) ? _TRUE : _FALSE; + + /* B8 B9 B10 Rx STBC */ + if (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX) && + GET_VHT_CAPABILITY_ELE_RX_STBC(data)) { + SET_FLAG(cur_stbc_cap, (STBC_VHT_ENABLE_TX | STBC_VHT_CAP_TX)); + RTW_INFO("Current VHT STBC Setting = %02X\n", cur_stbc_cap); + } + ptdls_sta->vhtpriv.stbc_cap = cur_stbc_cap; + + /* B11 SU Beamformer Capable, the target supports Beamformer and we are Beamformee */ + if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) && + GET_VHT_CAPABILITY_ELE_SU_BFEE(data)) + SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); + + /* B12 SU Beamformee Capable, the target supports Beamformee and we are Beamformer */ + if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) && + GET_VHT_CAPABILITY_ELE_SU_BFER(data)) + SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); + ptdls_sta->vhtpriv.beamform_cap = cur_beamform_cap; + if (cur_beamform_cap) + RTW_INFO("Current VHT Beamforming Setting = %02X\n", cur_beamform_cap); + + /* B23 B24 B25 Maximum A-MPDU Length Exponent */ + ptdls_sta->vhtpriv.ampdu_len = GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(data); + + pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(data); + rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); + rtw_vht_nss_to_mcsmap(tx_nss, ptdls_sta->vhtpriv.vht_mcs_map, pcap_mcs); + ptdls_sta->vhtpriv.vht_highest_rate = rtw_get_vht_highest_rate(ptdls_sta->vhtpriv.vht_mcs_map); +} + +u8 *rtw_tdls_set_aid(_adapter *padapter, u8 *pframe, struct pkt_attrib *pattrib) +{ + return rtw_set_ie(pframe, EID_AID, 2, (u8 *)&(padapter->mlmepriv.cur_network.aid), &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_vht_cap(_adapter *padapter, u8 *pframe, struct pkt_attrib *pattrib) +{ + u32 ie_len = 0; + + rtw_vht_use_default_setting(padapter); + + ie_len = rtw_build_vht_cap_ie(padapter, pframe); + pattrib->pktlen += ie_len; + + return pframe + ie_len; +} + +u8 *rtw_tdls_set_vht_operation(_adapter *padapter, u8 *pframe, struct pkt_attrib *pattrib, u8 channel) +{ + u32 ie_len = 0; + + ie_len = rtw_build_vht_operation_ie(padapter, pframe, channel); + pattrib->pktlen += ie_len; + + return pframe + ie_len; +} + +u8 *rtw_tdls_set_vht_op_mode_notify(_adapter *padapter, u8 *pframe, struct pkt_attrib *pattrib, u8 bw) +{ + u32 ie_len = 0; + + ie_len = rtw_build_vht_op_mode_notify_ie(padapter, pframe, bw); + pattrib->pktlen += ie_len; + + return pframe + ie_len; +} +#endif + + +u8 *rtw_tdls_set_sup_ch(struct mlme_ext_priv *pmlmeext, u8 *pframe, struct pkt_attrib *pattrib) +{ + u8 sup_ch[30 * 2] = {0x00}, ch_set_idx = 0, sup_ch_idx = 2; + + do { + if (pmlmeext->channel_set[ch_set_idx].ChannelNum <= 14) { + sup_ch[0] = 1; /* First channel number */ + sup_ch[1] = pmlmeext->channel_set[ch_set_idx].ChannelNum; /* Number of channel */ + } else { + sup_ch[sup_ch_idx++] = pmlmeext->channel_set[ch_set_idx].ChannelNum; + sup_ch[sup_ch_idx++] = 1; + } + ch_set_idx++; + } while (pmlmeext->channel_set[ch_set_idx].ChannelNum != 0 && ch_set_idx < MAX_CHANNEL_NUM); + + return rtw_set_ie(pframe, _SUPPORTED_CH_IE_, sup_ch_idx, sup_ch, &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_rsnie(struct tdls_txmgmt *ptxmgmt, u8 *pframe, struct pkt_attrib *pattrib, int init, struct sta_info *ptdls_sta) +{ + u8 *p = NULL; + int len = 0; + + if (ptxmgmt->len > 0) + p = rtw_get_ie(ptxmgmt->buf, _RSN_IE_2_, &len, ptxmgmt->len); + + if (p != NULL) + return rtw_set_ie(pframe, _RSN_IE_2_, len, p + 2, &(pattrib->pktlen)); + else if (init == _TRUE) + return rtw_set_ie(pframe, _RSN_IE_2_, sizeof(TDLS_RSNIE), TDLS_RSNIE, &(pattrib->pktlen)); + else + return rtw_set_ie(pframe, _RSN_IE_2_, sizeof(ptdls_sta->TDLS_RSNIE), ptdls_sta->TDLS_RSNIE, &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_ext_cap(u8 *pframe, struct pkt_attrib *pattrib) +{ + return rtw_set_ie(pframe, _EXT_CAP_IE_ , sizeof(TDLS_EXT_CAPIE), TDLS_EXT_CAPIE, &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_qos_cap(u8 *pframe, struct pkt_attrib *pattrib) +{ + return rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, sizeof(TDLS_WMMIE), TDLS_WMMIE, &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_ftie(struct tdls_txmgmt *ptxmgmt, u8 *pframe, struct pkt_attrib *pattrib, u8 *ANonce, u8 *SNonce) +{ + struct wpa_tdls_ftie FTIE = {0}; + u8 *p = NULL; + int len = 0; + + if (ptxmgmt->len > 0) + p = rtw_get_ie(ptxmgmt->buf, _FTIE_, &len, ptxmgmt->len); + + if (p != NULL) + return rtw_set_ie(pframe, _FTIE_, len, p + 2, &(pattrib->pktlen)); + else { + if (ANonce != NULL) + _rtw_memcpy(FTIE.Anonce, ANonce, WPA_NONCE_LEN); + if (SNonce != NULL) + _rtw_memcpy(FTIE.Snonce, SNonce, WPA_NONCE_LEN); + return rtw_set_ie(pframe, _FTIE_ , 82, (u8 *)FTIE.mic_ctrl, &(pattrib->pktlen)); + } +} + +u8 *rtw_tdls_set_timeout_interval(struct tdls_txmgmt *ptxmgmt, u8 *pframe, struct pkt_attrib *pattrib, int init, struct sta_info *ptdls_sta) +{ + u8 timeout_itvl[5]; /* set timeout interval to maximum value */ + u32 timeout_interval = TDLS_TPK_RESEND_COUNT; + u8 *p = NULL; + int len = 0; + + if (ptxmgmt->len > 0) + p = rtw_get_ie(ptxmgmt->buf, _TIMEOUT_ITVL_IE_, &len, ptxmgmt->len); + + if (p != NULL) + return rtw_set_ie(pframe, _TIMEOUT_ITVL_IE_, len, p + 2, &(pattrib->pktlen)); + else { + /* Timeout interval */ + timeout_itvl[0] = 0x02; + if (init == _TRUE) + _rtw_memcpy(timeout_itvl + 1, &timeout_interval, 4); + else + _rtw_memcpy(timeout_itvl + 1, (u8 *)(&ptdls_sta->TDLS_PeerKey_Lifetime), 4); + + return rtw_set_ie(pframe, _TIMEOUT_ITVL_IE_, 5, timeout_itvl, &(pattrib->pktlen)); + } +} + +u8 *rtw_tdls_set_bss_coexist(_adapter *padapter, u8 *pframe, struct pkt_attrib *pattrib) +{ + u8 iedata = 0; + + if (padapter->mlmepriv.num_FortyMHzIntolerant > 0) + iedata |= BIT(2); /* 20 MHz BSS Width Request */ + + /* Information Bit should be set by TDLS test plan 5.9 */ + iedata |= BIT(0); + return rtw_set_ie(pframe, EID_BSSCoexistence, 1, &iedata, &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_payload_type(u8 *pframe, struct pkt_attrib *pattrib) +{ + u8 payload_type = 0x02; + return rtw_set_fixed_ie(pframe, 1, &(payload_type), &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_category(u8 *pframe, struct pkt_attrib *pattrib, u8 category) +{ + return rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_action(u8 *pframe, struct pkt_attrib *pattrib, struct tdls_txmgmt *ptxmgmt) +{ + return rtw_set_fixed_ie(pframe, 1, &(ptxmgmt->action_code), &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_status_code(u8 *pframe, struct pkt_attrib *pattrib, struct tdls_txmgmt *ptxmgmt) +{ + return rtw_set_fixed_ie(pframe, 2, (u8 *)&(ptxmgmt->status_code), &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_dialog(u8 *pframe, struct pkt_attrib *pattrib, struct tdls_txmgmt *ptxmgmt) +{ + u8 dialogtoken = 1; + if (ptxmgmt->dialog_token) + return rtw_set_fixed_ie(pframe, 1, &(ptxmgmt->dialog_token), &(pattrib->pktlen)); + else + return rtw_set_fixed_ie(pframe, 1, &(dialogtoken), &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_reg_class(u8 *pframe, struct pkt_attrib *pattrib, struct sta_info *ptdls_sta) +{ + u8 reg_class = 22; + return rtw_set_fixed_ie(pframe, 1, &(reg_class), &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_second_channel_offset(u8 *pframe, struct pkt_attrib *pattrib, u8 ch_offset) +{ + return rtw_set_ie(pframe, EID_SecondaryChnlOffset , 1, &ch_offset, &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_capability(_adapter *padapter, u8 *pframe, struct pkt_attrib *pattrib) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u8 cap_from_ie[2] = {0}; + + _rtw_memcpy(cap_from_ie, rtw_get_capability_from_ie(pmlmeinfo->network.IEs), 2); + + return rtw_set_fixed_ie(pframe, 2, cap_from_ie, &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_supported_rate(_adapter *padapter, u8 *pframe, struct pkt_attrib *pattrib) +{ + u8 bssrate[NDIS_802_11_LENGTH_RATES_EX]; + int bssrate_len = 0; + u8 more_supportedrates = 0; + + rtw_set_supported_rate(bssrate, (padapter->registrypriv.wireless_mode == WIRELESS_MODE_MAX) ? padapter->mlmeextpriv.cur_wireless_mode : padapter->registrypriv.wireless_mode); + bssrate_len = rtw_get_rateset_len(bssrate); + + if (bssrate_len > 8) { + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &(pattrib->pktlen)); + more_supportedrates = 1; + } else + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &(pattrib->pktlen)); + + /* extended supported rates */ + if (more_supportedrates == 1) + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &(pattrib->pktlen)); + + return pframe; +} + +u8 *rtw_tdls_set_sup_reg_class(u8 *pframe, struct pkt_attrib *pattrib) +{ + return rtw_set_ie(pframe, _SRC_IE_ , sizeof(TDLS_SRC), TDLS_SRC, &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_linkid(u8 *pframe, struct pkt_attrib *pattrib, u8 init) +{ + u8 link_id_addr[18] = {0}; + if (init == _TRUE) { + _rtw_memcpy(link_id_addr, pattrib->ra, 6); + _rtw_memcpy((link_id_addr + 6), pattrib->src, 6); + _rtw_memcpy((link_id_addr + 12), pattrib->dst, 6); + } else { + _rtw_memcpy(link_id_addr, pattrib->ra, 6); + _rtw_memcpy((link_id_addr + 6), pattrib->dst, 6); + _rtw_memcpy((link_id_addr + 12), pattrib->src, 6); + } + return rtw_set_ie(pframe, _LINK_ID_IE_, 18, link_id_addr, &(pattrib->pktlen)); +} + +#ifdef CONFIG_TDLS_CH_SW +u8 *rtw_tdls_set_target_ch(_adapter *padapter, u8 *pframe, struct pkt_attrib *pattrib) +{ + u8 target_ch = 1; + if (padapter->tdlsinfo.chsw_info.off_ch_num) + return rtw_set_fixed_ie(pframe, 1, &(padapter->tdlsinfo.chsw_info.off_ch_num), &(pattrib->pktlen)); + else + return rtw_set_fixed_ie(pframe, 1, &(target_ch), &(pattrib->pktlen)); +} + +u8 *rtw_tdls_set_ch_sw(u8 *pframe, struct pkt_attrib *pattrib, struct sta_info *ptdls_sta) +{ + u8 ch_switch_timing[4] = {0}; + u16 switch_time = (ptdls_sta->ch_switch_time >= TDLS_CH_SWITCH_TIME * 1000) ? + ptdls_sta->ch_switch_time : TDLS_CH_SWITCH_TIME; + u16 switch_timeout = (ptdls_sta->ch_switch_timeout >= TDLS_CH_SWITCH_TIMEOUT * 1000) ? + ptdls_sta->ch_switch_timeout : TDLS_CH_SWITCH_TIMEOUT; + + _rtw_memcpy(ch_switch_timing, &switch_time, 2); + _rtw_memcpy(ch_switch_timing + 2, &switch_timeout, 2); + + return rtw_set_ie(pframe, _CH_SWITCH_TIMING_, 4, ch_switch_timing, &(pattrib->pktlen)); +} + +void rtw_tdls_set_ch_sw_oper_control(_adapter *padapter, u8 enable) +{ + if (ATOMIC_READ(&padapter->tdlsinfo.chsw_info.chsw_on) != enable) + ATOMIC_SET(&padapter->tdlsinfo.chsw_info.chsw_on, enable); + + rtw_hal_set_hwreg(padapter, HW_VAR_TDLS_BCN_EARLY_C2H_RPT, &enable); + RTW_INFO("[TDLS] %s Bcn Early C2H Report\n", (enable == _TRUE) ? "Start" : "Stop"); +} + +void rtw_tdls_ch_sw_back_to_base_chnl(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv; + struct tdls_ch_switch *pchsw_info = &padapter->tdlsinfo.chsw_info; + + pmlmepriv = &padapter->mlmepriv; + + if ((ATOMIC_READ(&pchsw_info->chsw_on) == _TRUE) && + (padapter->mlmeextpriv.cur_channel != rtw_get_oper_ch(padapter))) + rtw_tdls_cmd(padapter, pchsw_info->addr, TDLS_CH_SW_TO_BASE_CHNL_UNSOLICITED); +} + +static void rtw_tdls_chsw_oper_init(_adapter *padapter, u32 timeout_ms) +{ + struct submit_ctx *chsw_sctx = &padapter->tdlsinfo.chsw_info.chsw_sctx; + + rtw_sctx_init(chsw_sctx, timeout_ms); +} + +static int rtw_tdls_chsw_oper_wait(_adapter *padapter) +{ + struct submit_ctx *chsw_sctx = &padapter->tdlsinfo.chsw_info.chsw_sctx; + + return rtw_sctx_wait(chsw_sctx, __func__); +} + +void rtw_tdls_chsw_oper_done(_adapter *padapter) +{ + struct submit_ctx *chsw_sctx = &padapter->tdlsinfo.chsw_info.chsw_sctx; + + rtw_sctx_done(&chsw_sctx); +} + +s32 rtw_tdls_do_ch_sw(_adapter *padapter, struct sta_info *ptdls_sta, u8 chnl_type, u8 channel, u8 channel_offset, u16 bwmode, u16 ch_switch_time) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + u8 center_ch, chnl_offset80 = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + u32 ch_sw_time_start, ch_sw_time_spent, wait_time; + u8 take_care_iqk; + s32 ret = _FAIL; + + ch_sw_time_start = rtw_systime_to_ms(rtw_get_current_time()); + + rtw_tdls_chsw_oper_init(padapter, TDLS_CH_SWITCH_OPER_OFFLOAD_TIMEOUT); + + /* set mac_id sleep before channel switch */ + rtw_hal_macid_sleep(padapter, ptdls_sta->mac_id); + + /* channel switch IOs offload to FW */ + if (rtw_hal_ch_sw_oper_offload(padapter, channel, channel_offset, bwmode) == _SUCCESS) { + if (rtw_tdls_chsw_oper_wait(padapter) == _SUCCESS) { + /* set channel and bw related variables in driver */ + _enter_critical_mutex(&(adapter_to_dvobj(padapter)->setch_mutex), NULL); + + rtw_set_oper_ch(padapter, channel); + rtw_set_oper_choffset(padapter, channel_offset); + rtw_set_oper_bw(padapter, bwmode); + + center_ch = rtw_get_center_ch(channel, bwmode, channel_offset); + pHalData->current_channel = center_ch; + pHalData->CurrentCenterFrequencyIndex1 = center_ch; + pHalData->current_channel_bw = bwmode; + pHalData->nCur40MhzPrimeSC = channel_offset; + + if (bwmode == CHANNEL_WIDTH_80) { + if (center_ch > channel) + chnl_offset80 = HAL_PRIME_CHNL_OFFSET_LOWER; + else if (center_ch < channel) + chnl_offset80 = HAL_PRIME_CHNL_OFFSET_UPPER; + else + chnl_offset80 = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + } + pHalData->nCur80MhzPrimeSC = chnl_offset80; + + pHalData->CurrentCenterFrequencyIndex1 = center_ch; + + _exit_critical_mutex(&(adapter_to_dvobj(padapter)->setch_mutex), NULL); + + rtw_hal_get_hwreg(padapter, HW_VAR_CH_SW_NEED_TO_TAKE_CARE_IQK_INFO, &take_care_iqk); + if (take_care_iqk == _TRUE) + rtw_hal_ch_sw_iqk_info_restore(padapter, CH_SW_USE_CASE_TDLS); + + ch_sw_time_spent = rtw_systime_to_ms(rtw_get_current_time()) - ch_sw_time_start; + + if (chnl_type == TDLS_CH_SW_OFF_CHNL) { + if ((u32)ch_switch_time / 1000 > ch_sw_time_spent) + wait_time = (u32)ch_switch_time / 1000 - ch_sw_time_spent; + else + wait_time = 0; + + if (wait_time > 0) + rtw_msleep_os(wait_time); + } + + ret = _SUCCESS; + } else + RTW_INFO("[TDLS] chsw oper wait fail !!\n"); + } + + /* set mac_id wakeup after channel switch */ + rtw_hal_macid_wakeup(padapter, ptdls_sta->mac_id); + + return ret; +} +#endif + +u8 *rtw_tdls_set_wmm_params(_adapter *padapter, u8 *pframe, struct pkt_attrib *pattrib) +{ + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 wmm_param_ele[24] = {0}; + + if (&pmlmeinfo->WMM_param) { + _rtw_memcpy(wmm_param_ele, WMM_PARA_OUI, 6); + if (_rtw_memcmp(&pmlmeinfo->WMM_param, &wmm_param_ele[6], 18) == _TRUE) + /* Use default WMM Param */ + _rtw_memcpy(wmm_param_ele + 6, (u8 *)&TDLS_WMM_PARAM_IE, sizeof(TDLS_WMM_PARAM_IE)); + else + _rtw_memcpy(wmm_param_ele + 6, (u8 *)&pmlmeinfo->WMM_param, sizeof(pmlmeinfo->WMM_param)); + return rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, 24, wmm_param_ele, &(pattrib->pktlen)); + } else + return pframe; +} + +#ifdef CONFIG_WFD +void rtw_tdls_process_wfd_ie(struct tdls_info *ptdlsinfo, u8 *ptr, u8 length) +{ + u8 *wfd_ie; + u32 wfd_ielen = 0; + + if (!hal_chk_wl_func(tdls_info_to_adapter(ptdlsinfo), WL_FUNC_MIRACAST)) + return; + + /* Try to get the TCP port information when receiving the negotiation response. */ + + wfd_ie = rtw_get_wfd_ie(ptr, length, NULL, &wfd_ielen); + while (wfd_ie) { + u8 *attr_content; + u32 attr_contentlen = 0; + int i; + + RTW_INFO("[%s] WFD IE Found!!\n", __FUNCTION__); + attr_content = rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, NULL, &attr_contentlen); + if (attr_content && attr_contentlen) { + ptdlsinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16(attr_content + 2); + RTW_INFO("[%s] Peer PORT NUM = %d\n", __FUNCTION__, ptdlsinfo->wfd_info->peer_rtsp_ctrlport); + } + + attr_content = rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_LOCAL_IP_ADDR, NULL, &attr_contentlen); + if (attr_content && attr_contentlen) { + _rtw_memcpy(ptdlsinfo->wfd_info->peer_ip_address, (attr_content + 1), 4); + RTW_INFO("[%s] Peer IP = %02u.%02u.%02u.%02u\n", __FUNCTION__, + ptdlsinfo->wfd_info->peer_ip_address[0], ptdlsinfo->wfd_info->peer_ip_address[1], + ptdlsinfo->wfd_info->peer_ip_address[2], ptdlsinfo->wfd_info->peer_ip_address[3]); + } + + wfd_ie = rtw_get_wfd_ie(wfd_ie + wfd_ielen, (ptr + length) - (wfd_ie + wfd_ielen), NULL, &wfd_ielen); + } +} + +int issue_tunneled_probe_req(_adapter *padapter) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + u8 baddr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + struct tdls_txmgmt txmgmt; + int ret = _FAIL; + + RTW_INFO("[%s]\n", __FUNCTION__); + + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + txmgmt.action_code = TUNNELED_PROBE_REQ; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + pattrib = &pmgntframe->attrib; + + pmgntframe->frame_tag = DATA_FRAMETAG; + pattrib->ether_type = 0x890d; + + _rtw_memcpy(pattrib->dst, baddr, ETH_ALEN); + _rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + update_tdls_attrib(padapter, pattrib); + pattrib->qsel = pattrib->priority; + if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, &txmgmt) != _SUCCESS) { + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; + } + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; +exit: + + return ret; +} + +int issue_tunneled_probe_rsp(_adapter *padapter, union recv_frame *precv_frame) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct tdls_txmgmt txmgmt; + int ret = _FAIL; + + RTW_INFO("[%s]\n", __FUNCTION__); + + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + txmgmt.action_code = TUNNELED_PROBE_RSP; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + pattrib = &pmgntframe->attrib; + + pmgntframe->frame_tag = DATA_FRAMETAG; + pattrib->ether_type = 0x890d; + + _rtw_memcpy(pattrib->dst, precv_frame->u.hdr.attrib.src, ETH_ALEN); + _rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + update_tdls_attrib(padapter, pattrib); + pattrib->qsel = pattrib->priority; + if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, &txmgmt) != _SUCCESS) { + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; + } + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; +exit: + + return ret; +} +#endif /* CONFIG_WFD */ + +int issue_tdls_setup_req(_adapter *padapter, struct tdls_txmgmt *ptxmgmt, int wait_ack) +{ + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *ptdls_sta = NULL; + _irqL irqL; + int ret = _FAIL; + /* Retry timer should be set at least 301 sec, using TPK_count counting 301 times. */ + u32 timeout_interval = TDLS_TPK_RESEND_COUNT; + + RTW_INFO("[TDLS] %s\n", __FUNCTION__); + + ptxmgmt->action_code = TDLS_SETUP_REQUEST; + if (rtw_tdls_is_setup_allowed(padapter) == _FALSE) + goto exit; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + pattrib = &pmgntframe->attrib; + pmgntframe->frame_tag = DATA_FRAMETAG; + pattrib->ether_type = 0x890d; + + _rtw_memcpy(pattrib->dst, ptxmgmt->peer, ETH_ALEN); + _rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + update_tdls_attrib(padapter, pattrib); + + /* init peer sta_info */ + ptdls_sta = rtw_get_stainfo(pstapriv, ptxmgmt->peer); + if (ptdls_sta == NULL) { + ptdls_sta = rtw_alloc_stainfo(pstapriv, ptxmgmt->peer); + if (ptdls_sta == NULL) { + RTW_INFO("[%s] rtw_alloc_stainfo fail\n", __FUNCTION__); + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; + } + } + + if (!(ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE)) + ptdlsinfo->sta_cnt++; + + if (ptdlsinfo->sta_cnt == MAX_ALLOWED_TDLS_STA_NUM) + ptdlsinfo->sta_maximum = _TRUE; + + ptdls_sta->tdls_sta_state |= TDLS_RESPONDER_STATE; + + if (rtw_tdls_is_driver_setup(padapter) == _TRUE) { + ptdls_sta->TDLS_PeerKey_Lifetime = timeout_interval; + _set_timer(&ptdls_sta->handshake_timer, TDLS_HANDSHAKE_TIME); + } + + pattrib->qsel = pattrib->priority; + + if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, ptxmgmt) != _SUCCESS) { + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; + } + + if (wait_ack) + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + } + +exit: + + return ret; +} + +int _issue_tdls_teardown(_adapter *padapter, struct tdls_txmgmt *ptxmgmt, u8 wait_ack) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *ptdls_sta = NULL; + _irqL irqL; + int ret = _FAIL; + + RTW_INFO("[TDLS] %s\n", __FUNCTION__); + + ptxmgmt->action_code = TDLS_TEARDOWN; + ptdls_sta = rtw_get_stainfo(pstapriv, ptxmgmt->peer); + if (ptdls_sta == NULL) { + RTW_INFO("Np tdls_sta for tearing down\n"); + goto exit; + } + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + rtw_mi_set_scan_deny(padapter, 550); + rtw_mi_scan_abort(padapter, _TRUE); + + pattrib = &pmgntframe->attrib; + + pmgntframe->frame_tag = DATA_FRAMETAG; + pattrib->ether_type = 0x890d; + + _rtw_memcpy(pattrib->dst, ptxmgmt->peer, ETH_ALEN); + _rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + update_tdls_attrib(padapter, pattrib); + pattrib->qsel = pattrib->priority; + if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, ptxmgmt) != _SUCCESS) { + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; + } + + if (rtw_tdls_is_driver_setup(padapter) == _TRUE) + if (ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE) + if (pattrib->encrypt) + _cancel_timer_ex(&ptdls_sta->TPK_timer); + + if (wait_ack) + ret = dump_mgntframe_and_wait_ack(padapter, pmgntframe); + else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + } + + if (rtw_tdls_is_driver_setup(padapter)) + rtw_tdls_cmd(padapter, ptxmgmt->peer, TDLS_TEARDOWN_STA_LOCALLY); + +exit: + + return ret; +} + +int issue_tdls_teardown(_adapter *padapter, struct tdls_txmgmt *ptxmgmt, u8 wait_ack) +{ + int ret = _FAIL; + + ret = _issue_tdls_teardown(padapter, ptxmgmt, wait_ack); + if ((ptxmgmt->status_code == _RSON_TDLS_TEAR_UN_RSN_) && (ret == _FAIL)) { + /* Change status code and send teardown again via AP */ + ptxmgmt->status_code = _RSON_TDLS_TEAR_TOOFAR_; + ret = _issue_tdls_teardown(padapter, ptxmgmt, wait_ack); + } + + return ret; +} + +int issue_tdls_dis_req(_adapter *padapter, struct tdls_txmgmt *ptxmgmt) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + int ret = _FAIL; + + RTW_INFO("[TDLS] %s\n", __FUNCTION__); + + ptxmgmt->action_code = TDLS_DISCOVERY_REQUEST; + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + pattrib = &pmgntframe->attrib; + pmgntframe->frame_tag = DATA_FRAMETAG; + pattrib->ether_type = 0x890d; + + _rtw_memcpy(pattrib->dst, ptxmgmt->peer, ETH_ALEN); + _rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + update_tdls_attrib(padapter, pattrib); + pattrib->qsel = pattrib->priority; + if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, ptxmgmt) != _SUCCESS) { + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; + } + dump_mgntframe(padapter, pmgntframe); + RTW_INFO("issue tdls dis req\n"); + + ret = _SUCCESS; +exit: + + return ret; +} + +int issue_tdls_setup_rsp(_adapter *padapter, struct tdls_txmgmt *ptxmgmt) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + int ret = _FAIL; + + RTW_INFO("[TDLS] %s\n", __FUNCTION__); + + ptxmgmt->action_code = TDLS_SETUP_RESPONSE; + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + pattrib = &pmgntframe->attrib; + pmgntframe->frame_tag = DATA_FRAMETAG; + pattrib->ether_type = 0x890d; + + _rtw_memcpy(pattrib->dst, ptxmgmt->peer, ETH_ALEN); + _rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->ra, get_bssid(&(padapter->mlmepriv)), ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + update_tdls_attrib(padapter, pattrib); + pattrib->qsel = pattrib->priority; + if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, ptxmgmt) != _SUCCESS) { + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; + } + + dump_mgntframe(padapter, pmgntframe); + + ret = _SUCCESS; +exit: + + return ret; + +} + +int issue_tdls_setup_cfm(_adapter *padapter, struct tdls_txmgmt *ptxmgmt) +{ + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + int ret = _FAIL; + + RTW_INFO("[TDLS] %s\n", __FUNCTION__); + + ptxmgmt->action_code = TDLS_SETUP_CONFIRM; + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + pattrib = &pmgntframe->attrib; + pmgntframe->frame_tag = DATA_FRAMETAG; + pattrib->ether_type = 0x890d; + + _rtw_memcpy(pattrib->dst, ptxmgmt->peer, ETH_ALEN); + _rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->ra, get_bssid(&padapter->mlmepriv), ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + update_tdls_attrib(padapter, pattrib); + pattrib->qsel = pattrib->priority; + if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, ptxmgmt) != _SUCCESS) { + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; + } + + dump_mgntframe(padapter, pmgntframe); + + ret = _SUCCESS; +exit: + + return ret; + +} + +/* TDLS Discovery Response frame is a management action frame */ +int issue_tdls_dis_rsp(_adapter *padapter, struct tdls_txmgmt *ptxmgmt, u8 privacy) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + int ret = _FAIL; + + RTW_INFO("[TDLS] %s\n", __FUNCTION__); + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + /* unicast probe request frame */ + _rtw_memcpy(pwlanhdr->addr1, ptxmgmt->peer, ETH_ALEN); + _rtw_memcpy(pattrib->dst, pwlanhdr->addr1, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->src, pwlanhdr->addr2, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_bssid(&padapter->mlmepriv), ETH_ALEN); + _rtw_memcpy(pattrib->ra, pwlanhdr->addr3, ETH_ALEN); + + SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + pmlmeext->mgnt_seq++; + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pattrib->pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + rtw_build_tdls_dis_rsp_ies(padapter, pmgntframe, pframe, ptxmgmt, privacy); + + pattrib->nr_frags = 1; + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + +exit: + return ret; +} + +int issue_tdls_peer_traffic_rsp(_adapter *padapter, struct sta_info *ptdls_sta, struct tdls_txmgmt *ptxmgmt) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + int ret = _FAIL; + + RTW_INFO("[TDLS] %s\n", __FUNCTION__); + + ptxmgmt->action_code = TDLS_PEER_TRAFFIC_RESPONSE; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + pattrib = &pmgntframe->attrib; + + pmgntframe->frame_tag = DATA_FRAMETAG; + pattrib->ether_type = 0x890d; + + _rtw_memcpy(pattrib->dst, ptdls_sta->hwaddr, ETH_ALEN); + _rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + update_tdls_attrib(padapter, pattrib); + pattrib->qsel = pattrib->priority; + + if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, ptxmgmt) != _SUCCESS) { + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; + } + + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + +exit: + + return ret; +} + +int issue_tdls_peer_traffic_indication(_adapter *padapter, struct sta_info *ptdls_sta) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct tdls_txmgmt txmgmt; + int ret = _FAIL; + + RTW_INFO("[TDLS] %s\n", __FUNCTION__); + + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + txmgmt.action_code = TDLS_PEER_TRAFFIC_INDICATION; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + pattrib = &pmgntframe->attrib; + + pmgntframe->frame_tag = DATA_FRAMETAG; + pattrib->ether_type = 0x890d; + + _rtw_memcpy(pattrib->dst, ptdls_sta->hwaddr, ETH_ALEN); + _rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + /* PTI frame's priority should be AC_VO */ + pattrib->priority = 7; + + update_tdls_attrib(padapter, pattrib); + pattrib->qsel = pattrib->priority; + if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, &txmgmt) != _SUCCESS) { + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; + } + + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + +exit: + + return ret; +} + +#ifdef CONFIG_TDLS_CH_SW +int issue_tdls_ch_switch_req(_adapter *padapter, struct sta_info *ptdls_sta) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct tdls_txmgmt txmgmt; + int ret = _FAIL; + + RTW_INFO("[TDLS] %s\n", __FUNCTION__); + + if (rtw_tdls_is_chsw_allowed(padapter) == _FALSE) { + RTW_INFO("[TDLS] Ignore %s since channel switch is not allowed\n", __func__); + goto exit; + } + + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + txmgmt.action_code = TDLS_CHANNEL_SWITCH_REQUEST; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + pattrib = &pmgntframe->attrib; + + pmgntframe->frame_tag = DATA_FRAMETAG; + pattrib->ether_type = 0x890d; + + _rtw_memcpy(pattrib->dst, ptdls_sta->hwaddr, ETH_ALEN); + _rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + update_tdls_attrib(padapter, pattrib); + pattrib->qsel = pattrib->priority; + if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, &txmgmt) != _SUCCESS) { + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; + } + + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; +exit: + + return ret; +} + +int issue_tdls_ch_switch_rsp(_adapter *padapter, struct tdls_txmgmt *ptxmgmt, int wait_ack) +{ + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + int ret = _FAIL; + + RTW_INFO("[TDLS] %s\n", __FUNCTION__); + + if (rtw_tdls_is_chsw_allowed(padapter) == _FALSE) { + RTW_INFO("[TDLS] Ignore %s since channel switch is not allowed\n", __func__); + goto exit; + } + + ptxmgmt->action_code = TDLS_CHANNEL_SWITCH_RESPONSE; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto exit; + + pattrib = &pmgntframe->attrib; + + pmgntframe->frame_tag = DATA_FRAMETAG; + pattrib->ether_type = 0x890d; + + _rtw_memcpy(pattrib->dst, ptxmgmt->peer, ETH_ALEN); + _rtw_memcpy(pattrib->src, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pattrib->ra, ptxmgmt->peer, ETH_ALEN); + _rtw_memcpy(pattrib->ta, pattrib->src, ETH_ALEN); + + update_tdls_attrib(padapter, pattrib); + pattrib->qsel = pattrib->priority; + /* + _enter_critical_bh(&pxmitpriv->lock, &irqL); + if(xmitframe_enqueue_for_tdls_sleeping_sta(padapter, pmgntframe)==_TRUE){ + _exit_critical_bh(&pxmitpriv->lock, &irqL); + return _FALSE; + } + */ + if (rtw_xmit_tdls_coalesce(padapter, pmgntframe, ptxmgmt) != _SUCCESS) { + rtw_free_xmitbuf(pxmitpriv, pmgntframe->pxmitbuf); + rtw_free_xmitframe(pxmitpriv, pmgntframe); + goto exit; + } + + if (wait_ack) + ret = dump_mgntframe_and_wait_ack_timeout(padapter, pmgntframe, 10); + else { + dump_mgntframe(padapter, pmgntframe); + ret = _SUCCESS; + } +exit: + + return ret; +} +#endif + +int On_TDLS_Dis_Rsp(_adapter *padapter, union recv_frame *precv_frame) +{ + struct sta_info *ptdls_sta = NULL, *psta = rtw_get_stainfo(&(padapter->stapriv), get_bssid(&(padapter->mlmepriv))); + struct recv_priv *precvpriv = &(padapter->recvpriv); + u8 *ptr = precv_frame->u.hdr.rx_data, *psa; + struct rx_pkt_attrib *pattrib = &(precv_frame->u.hdr.attrib); + struct tdls_info *ptdlsinfo = &(padapter->tdlsinfo); + u8 empty_addr[ETH_ALEN] = { 0x00 }; + int undecorated_smoothed_pwdb; + struct tdls_txmgmt txmgmt; + int ret = _SUCCESS; + + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + /* WFDTDLS: for sigma test, not to setup direct link automatically */ + ptdlsinfo->dev_discovered = _TRUE; + + psa = get_sa(ptr); + ptdls_sta = rtw_get_stainfo(&(padapter->stapriv), psa); + if (ptdls_sta != NULL) + ptdls_sta->sta_stats.rx_tdls_disc_rsp_pkts++; + +#ifdef CONFIG_TDLS_AUTOSETUP + if (ptdls_sta != NULL) { + /* Record the tdls sta with lowest signal strength */ + if (ptdlsinfo->sta_maximum == _TRUE && ptdls_sta->alive_count >= 1) { + if (_rtw_memcmp(ptdlsinfo->ss_record.macaddr, empty_addr, ETH_ALEN)) { + _rtw_memcpy(ptdlsinfo->ss_record.macaddr, psa, ETH_ALEN); + ptdlsinfo->ss_record.RxPWDBAll = pattrib->phy_info.RxPWDBAll; + } else { + if (ptdlsinfo->ss_record.RxPWDBAll < pattrib->phy_info.RxPWDBAll) { + _rtw_memcpy(ptdlsinfo->ss_record.macaddr, psa, ETH_ALEN); + ptdlsinfo->ss_record.RxPWDBAll = pattrib->phy_info.RxPWDBAll; + } + } + } + } else { + if (ptdlsinfo->sta_maximum == _TRUE) { + if (_rtw_memcmp(ptdlsinfo->ss_record.macaddr, empty_addr, ETH_ALEN)) { + /* All traffics are busy, do not set up another direct link. */ + ret = _FAIL; + goto exit; + } else { + if (pattrib->phy_info.RxPWDBAll > ptdlsinfo->ss_record.RxPWDBAll) { + _rtw_memcpy(txmgmt.peer, ptdlsinfo->ss_record.macaddr, ETH_ALEN); + /* issue_tdls_teardown(padapter, ptdlsinfo->ss_record.macaddr, _FALSE); */ + } else { + ret = _FAIL; + goto exit; + } + } + } + + rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &undecorated_smoothed_pwdb); + + if (pattrib->phy_info.RxPWDBAll + TDLS_SIGNAL_THRESH >= undecorated_smoothed_pwdb) { + RTW_INFO("pattrib->RxPWDBAll=%d, pdmpriv->undecorated_smoothed_pwdb=%d\n", pattrib->phy_info.RxPWDBAll, undecorated_smoothed_pwdb); + _rtw_memcpy(txmgmt.peer, psa, ETH_ALEN); + issue_tdls_setup_req(padapter, &txmgmt, _FALSE); + } + } +#endif /* CONFIG_TDLS_AUTOSETUP */ + +exit: + return ret; + +} + +sint On_TDLS_Setup_Req(_adapter *padapter, union recv_frame *precv_frame) +{ + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + u8 *psa, *pmyid; + struct sta_info *ptdls_sta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *ptr = precv_frame->u.hdr.rx_data; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct security_priv *psecuritypriv = &padapter->securitypriv; + _irqL irqL; + struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; + u8 *prsnie, *ppairwise_cipher; + u8 i, k; + u8 ccmp_included = 0, rsnie_included = 0; + u16 j, pairwise_count; + u8 SNonce[32]; + u32 timeout_interval = TDLS_TPK_RESEND_COUNT; + sint parsing_length; /* Frame body length, without icv_len */ + PNDIS_802_11_VARIABLE_IEs pIE; + u8 FIXED_IE = 5; + unsigned char supportRate[16]; + int supportRateNum = 0; + struct tdls_txmgmt txmgmt; + + if (rtw_tdls_is_setup_allowed(padapter) == _FALSE) + goto exit; + + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + psa = get_sa(ptr); + ptdls_sta = rtw_get_stainfo(pstapriv, psa); + + pmyid = adapter_mac_addr(padapter); + ptr += prx_pkt_attrib->hdrlen + prx_pkt_attrib->iv_len + LLC_HEADER_SIZE + ETH_TYPE_LEN + PAYLOAD_TYPE_LEN; + parsing_length = ((union recv_frame *)precv_frame)->u.hdr.len + - prx_pkt_attrib->hdrlen + - prx_pkt_attrib->iv_len + - prx_pkt_attrib->icv_len + - LLC_HEADER_SIZE + - ETH_TYPE_LEN + - PAYLOAD_TYPE_LEN + - FIXED_IE; + + if (ptdls_sta == NULL) + ptdls_sta = rtw_alloc_stainfo(pstapriv, psa); + else { + if (ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE) { + /* If the direct link is already set up */ + /* Process as re-setup after tear down */ + RTW_INFO("re-setup a direct link\n"); + } + /* Already receiving TDLS setup request */ + else if (ptdls_sta->tdls_sta_state & TDLS_INITIATOR_STATE) { + RTW_INFO("receive duplicated TDLS setup request frame in handshaking\n"); + goto exit; + } + /* When receiving and sending setup_req to the same link at the same time */ + /* STA with higher MAC_addr would be initiator */ + else if (ptdls_sta->tdls_sta_state & TDLS_RESPONDER_STATE) { + RTW_INFO("receive setup_req after sending setup_req\n"); + for (i = 0; i < 6; i++) { + if (*(pmyid + i) == *(psa + i)) { + } else if (*(pmyid + i) > *(psa + i)) { + ptdls_sta->tdls_sta_state = TDLS_INITIATOR_STATE; + break; + } else if (*(pmyid + i) < *(psa + i)) + goto exit; + } + } + } + + if (ptdls_sta) { + txmgmt.dialog_token = *(ptr + 2); /* Copy dialog token */ + txmgmt.status_code = _STATS_SUCCESSFUL_; + + /* Parsing information element */ + for (j = FIXED_IE; j < parsing_length;) { + + pIE = (PNDIS_802_11_VARIABLE_IEs)(ptr + j); + + switch (pIE->ElementID) { + case _SUPPORTEDRATES_IE_: + _rtw_memcpy(supportRate, pIE->data, pIE->Length); + supportRateNum = pIE->Length; + break; + case _COUNTRY_IE_: + break; + case _EXT_SUPPORTEDRATES_IE_: + if (supportRateNum <= sizeof(supportRate)) { + _rtw_memcpy(supportRate + supportRateNum, pIE->data, pIE->Length); + supportRateNum += pIE->Length; + } + break; + case _SUPPORTED_CH_IE_: + break; + case _RSN_IE_2_: + rsnie_included = 1; + if (prx_pkt_attrib->encrypt) { + prsnie = (u8 *)pIE; + /* Check CCMP pairwise_cipher presence. */ + ppairwise_cipher = prsnie + 10; + _rtw_memcpy(ptdls_sta->TDLS_RSNIE, pIE->data, pIE->Length); + pairwise_count = *(u16 *)(ppairwise_cipher - 2); + for (k = 0; k < pairwise_count; k++) { + if (_rtw_memcmp(ppairwise_cipher + 4 * k, RSN_CIPHER_SUITE_CCMP, 4) == _TRUE) + ccmp_included = 1; + } + + if (ccmp_included == 0) + txmgmt.status_code = _STATS_INVALID_RSNIE_; + } + break; + case _EXT_CAP_IE_: + break; + case _VENDOR_SPECIFIC_IE_: + break; + case _FTIE_: + if (prx_pkt_attrib->encrypt) + _rtw_memcpy(SNonce, (ptr + j + 52), 32); + break; + case _TIMEOUT_ITVL_IE_: + if (prx_pkt_attrib->encrypt) + timeout_interval = cpu_to_le32(*(u32 *)(ptr + j + 3)); + break; + case _RIC_Descriptor_IE_: + break; +#ifdef CONFIG_80211N_HT + case _HT_CAPABILITY_IE_: + rtw_tdls_process_ht_cap(padapter, ptdls_sta, pIE->data, pIE->Length); + break; +#endif +#ifdef CONFIG_80211AC_VHT + case EID_AID: + break; + case EID_VHTCapability: + rtw_tdls_process_vht_cap(padapter, ptdls_sta, pIE->data, pIE->Length); + break; +#endif + case EID_BSSCoexistence: + break; + case _LINK_ID_IE_: + if (_rtw_memcmp(get_bssid(pmlmepriv), pIE->data, 6) == _FALSE) + txmgmt.status_code = _STATS_NOT_IN_SAME_BSS_; + break; + default: + break; + } + + j += (pIE->Length + 2); + + } + + /* Check status code */ + /* If responder STA has/hasn't security on AP, but request hasn't/has RSNIE, it should reject */ + if (txmgmt.status_code == _STATS_SUCCESSFUL_) { + if (rsnie_included && prx_pkt_attrib->encrypt == 0) + txmgmt.status_code = _STATS_SEC_DISABLED_; + else if (rsnie_included == 0 && prx_pkt_attrib->encrypt) + txmgmt.status_code = _STATS_INVALID_PARAMETERS_; + +#ifdef CONFIG_WFD + /* WFD test plan version 0.18.2 test item 5.1.5 */ + /* SoUT does not use TDLS if AP uses weak security */ + if (padapter->wdinfo.wfd_tdls_enable && (rsnie_included && prx_pkt_attrib->encrypt != _AES_)) + txmgmt.status_code = _STATS_SEC_DISABLED_; +#endif /* CONFIG_WFD */ + } + + ptdls_sta->tdls_sta_state |= TDLS_INITIATOR_STATE; + if (prx_pkt_attrib->encrypt) { + _rtw_memcpy(ptdls_sta->SNonce, SNonce, 32); + + if (timeout_interval <= 300) + ptdls_sta->TDLS_PeerKey_Lifetime = TDLS_TPK_RESEND_COUNT; + else + ptdls_sta->TDLS_PeerKey_Lifetime = timeout_interval; + } + + /* Update station supportRate */ + ptdls_sta->bssratelen = supportRateNum; + _rtw_memcpy(ptdls_sta->bssrateset, supportRate, supportRateNum); + + if (!(ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE)) + ptdlsinfo->sta_cnt++; + /* -2: AP + BC/MC sta, -4: default key */ + if (ptdlsinfo->sta_cnt == MAX_ALLOWED_TDLS_STA_NUM) + ptdlsinfo->sta_maximum = _TRUE; + +#ifdef CONFIG_WFD + rtw_tdls_process_wfd_ie(ptdlsinfo, ptr + FIXED_IE, parsing_length); +#endif + + } else + goto exit; + + _rtw_memcpy(txmgmt.peer, prx_pkt_attrib->src, ETH_ALEN); + + if (rtw_tdls_is_driver_setup(padapter)) { + issue_tdls_setup_rsp(padapter, &txmgmt); + + if (txmgmt.status_code == _STATS_SUCCESSFUL_) + _set_timer(&ptdls_sta->handshake_timer, TDLS_HANDSHAKE_TIME); + else + free_tdls_sta(padapter, ptdls_sta); + } + +exit: + + return _SUCCESS; +} + +int On_TDLS_Setup_Rsp(_adapter *padapter, union recv_frame *precv_frame) +{ + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + struct sta_info *ptdls_sta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *ptr = precv_frame->u.hdr.rx_data; + _irqL irqL; + struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; + u8 *psa; + u16 status_code = 0; + sint parsing_length; /* Frame body length, without icv_len */ + PNDIS_802_11_VARIABLE_IEs pIE; + u8 FIXED_IE = 7; + u8 ANonce[32]; + u8 *pftie = NULL, *ptimeout_ie = NULL, *plinkid_ie = NULL, *prsnie = NULL, *pftie_mic = NULL, *ppairwise_cipher = NULL; + u16 pairwise_count, j, k; + u8 verify_ccmp = 0; + unsigned char supportRate[16]; + int supportRateNum = 0; + struct tdls_txmgmt txmgmt; + int ret = _SUCCESS; + u32 timeout_interval = TDLS_TPK_RESEND_COUNT; + + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + psa = get_sa(ptr); + ptdls_sta = rtw_get_stainfo(pstapriv, psa); + + if (ptdls_sta == NULL) { + RTW_INFO("[%s] Direct Link Peer = "MAC_FMT" not found\n", __func__, MAC_ARG(psa)); + ret = _FAIL; + goto exit; + } + + ptr += prx_pkt_attrib->hdrlen + prx_pkt_attrib->iv_len + LLC_HEADER_SIZE + ETH_TYPE_LEN + PAYLOAD_TYPE_LEN; + parsing_length = ((union recv_frame *)precv_frame)->u.hdr.len + - prx_pkt_attrib->hdrlen + - prx_pkt_attrib->iv_len + - prx_pkt_attrib->icv_len + - LLC_HEADER_SIZE + - ETH_TYPE_LEN + - PAYLOAD_TYPE_LEN + - FIXED_IE; + + _rtw_memcpy(&status_code, ptr + 2, 2); + + if (status_code != 0) { + RTW_INFO("[TDLS] %s status_code = %d, free_tdls_sta\n", __FUNCTION__, status_code); + free_tdls_sta(padapter, ptdls_sta); + ret = _FAIL; + goto exit; + } + + status_code = 0; + + /* parsing information element */ + for (j = FIXED_IE; j < parsing_length;) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(ptr + j); + + switch (pIE->ElementID) { + case _SUPPORTEDRATES_IE_: + _rtw_memcpy(supportRate, pIE->data, pIE->Length); + supportRateNum = pIE->Length; + break; + case _COUNTRY_IE_: + break; + case _EXT_SUPPORTEDRATES_IE_: + if (supportRateNum <= sizeof(supportRate)) { + _rtw_memcpy(supportRate + supportRateNum, pIE->data, pIE->Length); + supportRateNum += pIE->Length; + } + break; + case _SUPPORTED_CH_IE_: + break; + case _RSN_IE_2_: + prsnie = (u8 *)pIE; + /* Check CCMP pairwise_cipher presence. */ + ppairwise_cipher = prsnie + 10; + _rtw_memcpy(&pairwise_count, (u16 *)(ppairwise_cipher - 2), 2); + for (k = 0; k < pairwise_count; k++) { + if (_rtw_memcmp(ppairwise_cipher + 4 * k, RSN_CIPHER_SUITE_CCMP, 4) == _TRUE) + verify_ccmp = 1; + } + case _EXT_CAP_IE_: + break; + case _VENDOR_SPECIFIC_IE_: + if (_rtw_memcmp((u8 *)pIE + 2, WMM_INFO_OUI, 6) == _TRUE) { + /* WMM Info ID and OUI */ + if ((pregistrypriv->wmm_enable == _TRUE) || (padapter->mlmepriv.htpriv.ht_option == _TRUE)) + ptdls_sta->qos_option = _TRUE; + } + break; + case _FTIE_: + pftie = (u8 *)pIE; + _rtw_memcpy(ANonce, (ptr + j + 20), 32); + break; + case _TIMEOUT_ITVL_IE_: + ptimeout_ie = (u8 *)pIE; + timeout_interval = cpu_to_le32(*(u32 *)(ptimeout_ie + 3)); + break; + case _RIC_Descriptor_IE_: + break; +#ifdef CONFIG_80211N_HT + case _HT_CAPABILITY_IE_: + rtw_tdls_process_ht_cap(padapter, ptdls_sta, pIE->data, pIE->Length); + break; +#endif +#ifdef CONFIG_80211AC_VHT + case EID_AID: + /* todo in the future if necessary */ + break; + case EID_VHTCapability: + rtw_tdls_process_vht_cap(padapter, ptdls_sta, pIE->data, pIE->Length); + break; + case EID_OpModeNotification: + rtw_process_vht_op_mode_notify(padapter, pIE->data, ptdls_sta); + break; +#endif + case EID_BSSCoexistence: + break; + case _LINK_ID_IE_: + plinkid_ie = (u8 *)pIE; + break; + default: + break; + } + + j += (pIE->Length + 2); + + } + + ptdls_sta->bssratelen = supportRateNum; + _rtw_memcpy(ptdls_sta->bssrateset, supportRate, supportRateNum); + _rtw_memcpy(ptdls_sta->ANonce, ANonce, 32); + +#ifdef CONFIG_WFD + rtw_tdls_process_wfd_ie(ptdlsinfo, ptr + FIXED_IE, parsing_length); +#endif + + if (status_code != _STATS_SUCCESSFUL_) + txmgmt.status_code = status_code; + else { + if (prx_pkt_attrib->encrypt) { + if (verify_ccmp == 1) { + txmgmt.status_code = _STATS_SUCCESSFUL_; + if (rtw_tdls_is_driver_setup(padapter) == _TRUE) { + wpa_tdls_generate_tpk(padapter, ptdls_sta); + if (tdls_verify_mic(ptdls_sta->tpk.kck, 2, plinkid_ie, prsnie, ptimeout_ie, pftie) == _FAIL) { + RTW_INFO("[TDLS] %s tdls_verify_mic fail, free_tdls_sta\n", __FUNCTION__); + free_tdls_sta(padapter, ptdls_sta); + ret = _FAIL; + goto exit; + } + ptdls_sta->TDLS_PeerKey_Lifetime = timeout_interval; + } + } else + txmgmt.status_code = _STATS_INVALID_RSNIE_; + + } else + txmgmt.status_code = _STATS_SUCCESSFUL_; + } + + if (rtw_tdls_is_driver_setup(padapter) == _TRUE) { + _rtw_memcpy(txmgmt.peer, prx_pkt_attrib->src, ETH_ALEN); + issue_tdls_setup_cfm(padapter, &txmgmt); + + if (txmgmt.status_code == _STATS_SUCCESSFUL_) { + ptdlsinfo->link_established = _TRUE; + + if (ptdls_sta->tdls_sta_state & TDLS_RESPONDER_STATE) { + ptdls_sta->tdls_sta_state |= TDLS_LINKED_STATE; + ptdls_sta->state |= _FW_LINKED; + _cancel_timer_ex(&ptdls_sta->handshake_timer); + } + + if (prx_pkt_attrib->encrypt) + rtw_tdls_set_key(padapter, ptdls_sta); + + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_ESTABLISHED); + + } + } + +exit: + if (rtw_tdls_is_driver_setup(padapter) == _TRUE) + return ret; + else + return _SUCCESS; + +} + +int On_TDLS_Setup_Cfm(_adapter *padapter, union recv_frame *precv_frame) +{ + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + struct sta_info *ptdls_sta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *ptr = precv_frame->u.hdr.rx_data; + _irqL irqL; + struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; + u8 *psa; + u16 status_code = 0; + sint parsing_length; + PNDIS_802_11_VARIABLE_IEs pIE; + u8 FIXED_IE = 5; + u8 *pftie = NULL, *ptimeout_ie = NULL, *plinkid_ie = NULL, *prsnie = NULL, *pftie_mic = NULL, *ppairwise_cipher = NULL; + u16 j, pairwise_count; + int ret = _SUCCESS; + + psa = get_sa(ptr); + ptdls_sta = rtw_get_stainfo(pstapriv, psa); + + if (ptdls_sta == NULL) { + RTW_INFO("[%s] Direct Link Peer = "MAC_FMT" not found\n", __FUNCTION__, MAC_ARG(psa)); + ret = _FAIL; + goto exit; + } + + ptr += prx_pkt_attrib->hdrlen + prx_pkt_attrib->iv_len + LLC_HEADER_SIZE + ETH_TYPE_LEN + PAYLOAD_TYPE_LEN; + parsing_length = ((union recv_frame *)precv_frame)->u.hdr.len + - prx_pkt_attrib->hdrlen + - prx_pkt_attrib->iv_len + - prx_pkt_attrib->icv_len + - LLC_HEADER_SIZE + - ETH_TYPE_LEN + - PAYLOAD_TYPE_LEN + - FIXED_IE; + + _rtw_memcpy(&status_code, ptr + 2, 2); + + if (status_code != 0) { + RTW_INFO("[%s] status_code = %d\n, free_tdls_sta", __FUNCTION__, status_code); + free_tdls_sta(padapter, ptdls_sta); + ret = _FAIL; + goto exit; + } + + /* Parsing information element */ + for (j = FIXED_IE; j < parsing_length;) { + + pIE = (PNDIS_802_11_VARIABLE_IEs)(ptr + j); + + switch (pIE->ElementID) { + case _RSN_IE_2_: + prsnie = (u8 *)pIE; + break; + case _VENDOR_SPECIFIC_IE_: + if (_rtw_memcmp((u8 *)pIE + 2, WMM_PARA_OUI, 6) == _TRUE) { + /* WMM Parameter ID and OUI */ + ptdls_sta->qos_option = _TRUE; + } + break; + case _FTIE_: + pftie = (u8 *)pIE; + break; + case _TIMEOUT_ITVL_IE_: + ptimeout_ie = (u8 *)pIE; + break; +#ifdef CONFIG_80211N_HT + case _HT_EXTRA_INFO_IE_: + break; +#endif +#ifdef CONFIG_80211AC_VHT + case EID_VHTOperation: + break; + case EID_OpModeNotification: + rtw_process_vht_op_mode_notify(padapter, pIE->data, ptdls_sta); + break; +#endif + case _LINK_ID_IE_: + plinkid_ie = (u8 *)pIE; + break; + default: + break; + } + + j += (pIE->Length + 2); + + } + + if (prx_pkt_attrib->encrypt) { + /* Verify mic in FTIE MIC field */ + if (rtw_tdls_is_driver_setup(padapter) && + (tdls_verify_mic(ptdls_sta->tpk.kck, 3, plinkid_ie, prsnie, ptimeout_ie, pftie) == _FAIL)) { + free_tdls_sta(padapter, ptdls_sta); + ret = _FAIL; + goto exit; + } + } + + if (rtw_tdls_is_driver_setup(padapter)) { + ptdlsinfo->link_established = _TRUE; + + if (ptdls_sta->tdls_sta_state & TDLS_INITIATOR_STATE) { + ptdls_sta->tdls_sta_state |= TDLS_LINKED_STATE; + ptdls_sta->state |= _FW_LINKED; + _cancel_timer_ex(&ptdls_sta->handshake_timer); + } + + if (prx_pkt_attrib->encrypt) { + rtw_tdls_set_key(padapter, ptdls_sta); + + /* Start TPK timer */ + ptdls_sta->TPK_count = 0; + _set_timer(&ptdls_sta->TPK_timer, ONE_SEC); + } + + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_ESTABLISHED); + } + +exit: + return ret; + +} + +int On_TDLS_Dis_Req(_adapter *padapter, union recv_frame *precv_frame) +{ + struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta_ap; + u8 *ptr = precv_frame->u.hdr.rx_data; + sint parsing_length; /* Frame body length, without icv_len */ + PNDIS_802_11_VARIABLE_IEs pIE; + u8 FIXED_IE = 3, *dst; + u16 j; + struct tdls_txmgmt txmgmt; + int ret = _SUCCESS; + + if (rtw_tdls_is_driver_setup(padapter) == _FALSE) + goto exit; + + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + ptr += prx_pkt_attrib->hdrlen + prx_pkt_attrib->iv_len + LLC_HEADER_SIZE + ETH_TYPE_LEN + PAYLOAD_TYPE_LEN; + txmgmt.dialog_token = *(ptr + 2); + _rtw_memcpy(&txmgmt.peer, precv_frame->u.hdr.attrib.src, ETH_ALEN); + txmgmt.action_code = TDLS_DISCOVERY_RESPONSE; + parsing_length = ((union recv_frame *)precv_frame)->u.hdr.len + - prx_pkt_attrib->hdrlen + - prx_pkt_attrib->iv_len + - prx_pkt_attrib->icv_len + - LLC_HEADER_SIZE + - ETH_TYPE_LEN + - PAYLOAD_TYPE_LEN + - FIXED_IE; + + /* Parsing information element */ + for (j = FIXED_IE; j < parsing_length;) { + + pIE = (PNDIS_802_11_VARIABLE_IEs)(ptr + j); + + switch (pIE->ElementID) { + case _LINK_ID_IE_: + psta_ap = rtw_get_stainfo(pstapriv, pIE->data); + if (psta_ap == NULL) + goto exit; + dst = pIE->data + 12; + if (MacAddr_isBcst(dst) == _FALSE && (_rtw_memcmp(adapter_mac_addr(padapter), dst, 6) == _FALSE)) + goto exit; + break; + default: + break; + } + + j += (pIE->Length + 2); + + } + + issue_tdls_dis_rsp(padapter, &txmgmt, prx_pkt_attrib->privacy); + +exit: + return ret; + +} + +int On_TDLS_Teardown(_adapter *padapter, union recv_frame *precv_frame) +{ + u8 *psa; + u8 *ptr = precv_frame->u.hdr.rx_data; + struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *ptdls_sta = NULL; + _irqL irqL; + u8 reason; + + reason = *(ptr + prx_pkt_attrib->hdrlen + prx_pkt_attrib->iv_len + LLC_HEADER_SIZE + ETH_TYPE_LEN + PAYLOAD_TYPE_LEN + 2); + RTW_INFO("[TDLS] %s Reason code(%d)\n", __FUNCTION__, reason); + + psa = get_sa(ptr); + + ptdls_sta = rtw_get_stainfo(pstapriv, psa); + if (ptdls_sta != NULL) { + if (rtw_tdls_is_driver_setup(padapter)) + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_TEARDOWN_STA_LOCALLY); + } + + return _SUCCESS; + +} + +#if 0 +u8 TDLS_check_ch_state(uint state) +{ + if (state & TDLS_CH_SWITCH_ON_STATE && + state & TDLS_PEER_AT_OFF_STATE) { + if (state & TDLS_PEER_SLEEP_STATE) + return 2; /* U-APSD + ch. switch */ + else + return 1; /* ch. switch */ + } else + return 0; +} +#endif + +int On_TDLS_Peer_Traffic_Indication(_adapter *padapter, union recv_frame *precv_frame) +{ + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct sta_info *ptdls_sta = rtw_get_stainfo(&padapter->stapriv, pattrib->src); + u8 *ptr = precv_frame->u.hdr.rx_data; + struct tdls_txmgmt txmgmt; + + ptr += pattrib->hdrlen + pattrib->iv_len + LLC_HEADER_SIZE + ETH_TYPE_LEN + PAYLOAD_TYPE_LEN; + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + + if (ptdls_sta != NULL) { + txmgmt.dialog_token = *(ptr + 2); + issue_tdls_peer_traffic_rsp(padapter, ptdls_sta, &txmgmt); + /* issue_nulldata_to_TDLS_peer_STA(padapter, ptdls_sta->hwaddr, 0, 0, 0); */ + } else { + RTW_INFO("from unknown sta:"MAC_FMT"\n", MAC_ARG(pattrib->src)); + return _FAIL; + } + + return _SUCCESS; +} + +/* We process buffered data for 1. U-APSD, 2. ch. switch, 3. U-APSD + ch. switch here */ +int On_TDLS_Peer_Traffic_Rsp(_adapter *padapter, union recv_frame *precv_frame) +{ + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *ptdls_sta = rtw_get_stainfo(pstapriv, pattrib->src); + u8 wmmps_ac = 0; + /* u8 state=TDLS_check_ch_state(ptdls_sta->tdls_sta_state); */ + int i; + + ptdls_sta->sta_stats.rx_data_pkts++; + + ptdls_sta->tdls_sta_state &= ~(TDLS_WAIT_PTR_STATE); + + /* Check 4-AC queue bit */ + if (ptdls_sta->uapsd_vo || ptdls_sta->uapsd_vi || ptdls_sta->uapsd_be || ptdls_sta->uapsd_bk) + wmmps_ac = 1; + + /* If it's a direct link and have buffered frame */ + if (ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE) { + if (wmmps_ac) { + _irqL irqL; + _list *xmitframe_plist, *xmitframe_phead; + struct xmit_frame *pxmitframe = NULL; + + _enter_critical_bh(&ptdls_sta->sleep_q.lock, &irqL); + + xmitframe_phead = get_list_head(&ptdls_sta->sleep_q); + xmitframe_plist = get_next(xmitframe_phead); + + /* transmit buffered frames */ + while (rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist) == _FALSE) { + pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); + xmitframe_plist = get_next(xmitframe_plist); + rtw_list_delete(&pxmitframe->list); + + ptdls_sta->sleepq_len--; + ptdls_sta->sleepq_ac_len--; + if (ptdls_sta->sleepq_len > 0) { + pxmitframe->attrib.mdata = 1; + pxmitframe->attrib.eosp = 0; + } else { + pxmitframe->attrib.mdata = 0; + pxmitframe->attrib.eosp = 1; + } + pxmitframe->attrib.triggered = 1; + + rtw_hal_xmitframe_enqueue(padapter, pxmitframe); + } + + if (ptdls_sta->sleepq_len == 0) + RTW_INFO("no buffered packets for tdls to xmit\n"); + else { + RTW_INFO("error!psta->sleepq_len=%d\n", ptdls_sta->sleepq_len); + ptdls_sta->sleepq_len = 0; + } + + _exit_critical_bh(&ptdls_sta->sleep_q.lock, &irqL); + + } + + } + + return _SUCCESS; +} + +#ifdef CONFIG_TDLS_CH_SW +sint On_TDLS_Ch_Switch_Req(_adapter *padapter, union recv_frame *precv_frame) +{ + struct tdls_ch_switch *pchsw_info = &padapter->tdlsinfo.chsw_info; + struct sta_info *ptdls_sta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *ptr = precv_frame->u.hdr.rx_data; + struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; + u8 *psa; + sint parsing_length; + PNDIS_802_11_VARIABLE_IEs pIE; + u8 FIXED_IE = 4; + u16 j; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct tdls_txmgmt txmgmt; + u8 zaddr[ETH_ALEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + u16 switch_time = TDLS_CH_SWITCH_TIME * 1000, switch_timeout = TDLS_CH_SWITCH_TIMEOUT * 1000; + u8 take_care_iqk; + + if (rtw_tdls_is_chsw_allowed(padapter) == _FALSE) { + RTW_INFO("[TDLS] Ignore %s since channel switch is not allowed\n", __func__); + return _FAIL; + } + + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + psa = get_sa(ptr); + ptdls_sta = rtw_get_stainfo(pstapriv, psa); + + if (ptdls_sta == NULL) { + RTW_INFO("[%s] Direct Link Peer = "MAC_FMT" not found\n", __func__, MAC_ARG(psa)); + return _FAIL; + } + + ptdls_sta->ch_switch_time = switch_time; + ptdls_sta->ch_switch_timeout = switch_timeout; + + ptr += prx_pkt_attrib->hdrlen + prx_pkt_attrib->iv_len + LLC_HEADER_SIZE + ETH_TYPE_LEN + PAYLOAD_TYPE_LEN; + parsing_length = ((union recv_frame *)precv_frame)->u.hdr.len + - prx_pkt_attrib->hdrlen + - prx_pkt_attrib->iv_len + - prx_pkt_attrib->icv_len + - LLC_HEADER_SIZE + - ETH_TYPE_LEN + - PAYLOAD_TYPE_LEN + - FIXED_IE; + + pchsw_info->off_ch_num = *(ptr + 2); + + if ((*(ptr + 2) == 2) && (hal_is_band_support(padapter, BAND_ON_5G))) + pchsw_info->off_ch_num = 44; + + if (pchsw_info->off_ch_num != pmlmeext->cur_channel) + pchsw_info->delay_switch_back = _FALSE; + + /* Parsing information element */ + for (j = FIXED_IE; j < parsing_length;) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(ptr + j); + + switch (pIE->ElementID) { + case EID_SecondaryChnlOffset: + switch (*(pIE->data)) { + case EXTCHNL_OFFSET_UPPER: + pchsw_info->ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; + break; + + case EXTCHNL_OFFSET_LOWER: + pchsw_info->ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; + break; + + default: + pchsw_info->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + break; + } + break; + case _LINK_ID_IE_: + break; + case _CH_SWITCH_TIMING_: + ptdls_sta->ch_switch_time = (RTW_GET_LE16(pIE->data) >= TDLS_CH_SWITCH_TIME * 1000) ? + RTW_GET_LE16(pIE->data) : TDLS_CH_SWITCH_TIME * 1000; + ptdls_sta->ch_switch_timeout = (RTW_GET_LE16(pIE->data + 2) >= TDLS_CH_SWITCH_TIMEOUT * 1000) ? + RTW_GET_LE16(pIE->data + 2) : TDLS_CH_SWITCH_TIMEOUT * 1000; + RTW_INFO("[TDLS] %s ch_switch_time:%d, ch_switch_timeout:%d\n" + , __FUNCTION__, RTW_GET_LE16(pIE->data), RTW_GET_LE16(pIE->data + 2)); + default: + break; + } + + j += (pIE->Length + 2); + } + + rtw_hal_get_hwreg(padapter, HW_VAR_CH_SW_NEED_TO_TAKE_CARE_IQK_INFO, &take_care_iqk); + if (take_care_iqk == _TRUE) { + u8 central_chnl; + u8 bw_mode; + + bw_mode = (pchsw_info->ch_offset) ? CHANNEL_WIDTH_40 : CHANNEL_WIDTH_20; + central_chnl = rtw_get_center_ch(pchsw_info->off_ch_num, bw_mode, pchsw_info->ch_offset); + if (rtw_hal_ch_sw_iqk_info_search(padapter, central_chnl, bw_mode) < 0) { + if (!(pchsw_info->ch_sw_state & TDLS_CH_SWITCH_PREPARE_STATE)) + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_PREPARE); + + return _FAIL; + } + } + + /* cancel ch sw monitor timer for responder */ + if (!(pchsw_info->ch_sw_state & TDLS_CH_SW_INITIATOR_STATE)) + _cancel_timer_ex(&ptdls_sta->ch_sw_monitor_timer); + + /* Todo: check status */ + txmgmt.status_code = 0; + _rtw_memcpy(txmgmt.peer, psa, ETH_ALEN); + + if (_rtw_memcmp(pchsw_info->addr, zaddr, ETH_ALEN) == _TRUE) + _rtw_memcpy(pchsw_info->addr, ptdls_sta->hwaddr, ETH_ALEN); + + if (ATOMIC_READ(&pchsw_info->chsw_on) == _FALSE) + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_START); + + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_RESP); + + return _SUCCESS; +} + +sint On_TDLS_Ch_Switch_Rsp(_adapter *padapter, union recv_frame *precv_frame) +{ + struct tdls_ch_switch *pchsw_info = &padapter->tdlsinfo.chsw_info; + struct sta_info *ptdls_sta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + u8 *ptr = precv_frame->u.hdr.rx_data; + struct rx_pkt_attrib *prx_pkt_attrib = &precv_frame->u.hdr.attrib; + u8 *psa; + sint parsing_length; + PNDIS_802_11_VARIABLE_IEs pIE; + u8 FIXED_IE = 4; + u16 status_code, j, switch_time, switch_timeout; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + int ret = _SUCCESS; + + if (rtw_tdls_is_chsw_allowed(padapter) == _FALSE) { + RTW_INFO("[TDLS] Ignore %s since channel switch is not allowed\n", __func__); + return _SUCCESS; + } + + psa = get_sa(ptr); + ptdls_sta = rtw_get_stainfo(pstapriv, psa); + + if (ptdls_sta == NULL) { + RTW_INFO("[%s] Direct Link Peer = "MAC_FMT" not found\n", __func__, MAC_ARG(psa)); + return _FAIL; + } + + /* If we receive Unsolicited TDLS Channel Switch Response when channel switch is running, */ + /* we will go back to base channel and terminate this channel switch procedure */ + if (ATOMIC_READ(&pchsw_info->chsw_on) == _TRUE) { + if (pmlmeext->cur_channel != rtw_get_oper_ch(padapter)) { + RTW_INFO("[TDLS] Rx unsolicited channel switch response\n"); + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_TO_BASE_CHNL); + goto exit; + } + } + + ptr += prx_pkt_attrib->hdrlen + prx_pkt_attrib->iv_len + LLC_HEADER_SIZE + ETH_TYPE_LEN + PAYLOAD_TYPE_LEN; + parsing_length = ((union recv_frame *)precv_frame)->u.hdr.len + - prx_pkt_attrib->hdrlen + - prx_pkt_attrib->iv_len + - prx_pkt_attrib->icv_len + - LLC_HEADER_SIZE + - ETH_TYPE_LEN + - PAYLOAD_TYPE_LEN + - FIXED_IE; + + _rtw_memcpy(&status_code, ptr + 2, 2); + + if (status_code != 0) { + RTW_INFO("[TDLS] %s status_code:%d\n", __func__, status_code); + pchsw_info->ch_sw_state &= ~(TDLS_CH_SW_INITIATOR_STATE); + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_END); + ret = _FAIL; + goto exit; + } + + /* Parsing information element */ + for (j = FIXED_IE; j < parsing_length;) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(ptr + j); + + switch (pIE->ElementID) { + case _LINK_ID_IE_: + break; + case _CH_SWITCH_TIMING_: + _rtw_memcpy(&switch_time, pIE->data, 2); + if (switch_time > ptdls_sta->ch_switch_time) + _rtw_memcpy(&ptdls_sta->ch_switch_time, &switch_time, 2); + + _rtw_memcpy(&switch_timeout, pIE->data + 2, 2); + if (switch_timeout > ptdls_sta->ch_switch_timeout) + _rtw_memcpy(&ptdls_sta->ch_switch_timeout, &switch_timeout, 2); + break; + default: + break; + } + + j += (pIE->Length + 2); + } + + if ((pmlmeext->cur_channel == rtw_get_oper_ch(padapter)) && + (pchsw_info->ch_sw_state & TDLS_WAIT_CH_RSP_STATE)) { + if (ATOMIC_READ(&pchsw_info->chsw_on) == _TRUE) + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_TO_OFF_CHNL); + } + +exit: + return ret; +} +#endif /* CONFIG_TDLS_CH_SW */ + +#ifdef CONFIG_WFD +void wfd_ie_tdls(_adapter *padapter, u8 *pframe, u32 *pktlen) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wifi_display_info *pwfd_info = padapter->tdlsinfo.wfd_info; + u8 wfdie[MAX_WFD_IE_LEN] = { 0x00 }; + u32 wfdielen = 0; + + if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) + return; + + /* WFD OUI */ + wfdielen = 0; + wfdie[wfdielen++] = 0x50; + wfdie[wfdielen++] = 0x6F; + wfdie[wfdielen++] = 0x9A; + wfdie[wfdielen++] = 0x0A; /* WFA WFD v1.0 */ + + /* + * Commented by Albert 20110825 + * According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes + * 1. WFD Device Information + * 2. Associated BSSID ( Optional ) + * 3. Local IP Adress ( Optional ) + */ + + /* WFD Device Information ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_DEVICE_INFO; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value1: */ + /* WFD device information */ + /* available for WFD session + Preferred TDLS + WSD ( WFD Service Discovery ) */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL + | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_WSD); + wfdielen += 2; + + /* Value2: */ + /* Session Management Control Port */ + /* Default TCP port for RTSP messages is 554 */ + RTW_PUT_BE16(wfdie + wfdielen, pwfd_info->tdls_rtsp_ctrlport); + wfdielen += 2; + + /* Value3: */ + /* WFD Device Maximum Throughput */ + /* 300Mbps is the maximum throughput */ + RTW_PUT_BE16(wfdie + wfdielen, 300); + wfdielen += 2; + + /* Associated BSSID ATTR */ + /* Type: */ + wfdie[wfdielen++] = WFD_ATTR_ASSOC_BSSID; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0006); + wfdielen += 2; + + /* Value: */ + /* Associated BSSID */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + _rtw_memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[0], ETH_ALEN); + else + _rtw_memset(wfdie + wfdielen, 0x00, ETH_ALEN); + + /* Local IP Address ATTR */ + wfdie[wfdielen++] = WFD_ATTR_LOCAL_IP_ADDR; + + /* Length: */ + /* Note: In the WFD specification, the size of length field is 2. */ + RTW_PUT_BE16(wfdie + wfdielen, 0x0005); + wfdielen += 2; + + /* Version: */ + /* 0x01: Version1;IPv4 */ + wfdie[wfdielen++] = 0x01; + + /* IPv4 Address */ + _rtw_memcpy(wfdie + wfdielen, pwfd_info->ip_address, 4); + wfdielen += 4; + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, pktlen); + +} +#endif /* CONFIG_WFD */ + +void rtw_build_tdls_setup_req_ies(_adapter *padapter, struct xmit_frame *pxmitframe, u8 *pframe, struct tdls_txmgmt *ptxmgmt) +{ + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_info *ptdls_sta = rtw_get_stainfo((&padapter->stapriv) , pattrib->dst); + + int i = 0 ; + u32 time; + u8 *pframe_head; + + /* SNonce */ + if (pattrib->encrypt) { + for (i = 0; i < 8; i++) { + time = rtw_get_current_time(); + _rtw_memcpy(&ptdls_sta->SNonce[4 * i], (u8 *)&time, 4); + } + } + + pframe_head = pframe; /* For rtw_tdls_set_ht_cap() */ + + pframe = rtw_tdls_set_payload_type(pframe, pattrib); + pframe = rtw_tdls_set_category(pframe, pattrib, RTW_WLAN_CATEGORY_TDLS); + pframe = rtw_tdls_set_action(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_dialog(pframe, pattrib, ptxmgmt); + + pframe = rtw_tdls_set_capability(padapter, pframe, pattrib); + pframe = rtw_tdls_set_supported_rate(padapter, pframe, pattrib); + pframe = rtw_tdls_set_sup_ch(&(padapter->mlmeextpriv), pframe, pattrib); + pframe = rtw_tdls_set_sup_reg_class(pframe, pattrib); + + if (pattrib->encrypt) + pframe = rtw_tdls_set_rsnie(ptxmgmt, pframe, pattrib, _TRUE, ptdls_sta); + + pframe = rtw_tdls_set_ext_cap(pframe, pattrib); + + if (pattrib->encrypt) { + pframe = rtw_tdls_set_ftie(ptxmgmt + , pframe + , pattrib + , NULL + , ptdls_sta->SNonce); + + pframe = rtw_tdls_set_timeout_interval(ptxmgmt, pframe, pattrib, _TRUE, ptdls_sta); + } + +#ifdef CONFIG_80211N_HT + /* Sup_reg_classes(optional) */ + if (pregistrypriv->ht_enable == _TRUE) + pframe = rtw_tdls_set_ht_cap(padapter, pframe_head, pattrib); +#endif + + pframe = rtw_tdls_set_bss_coexist(padapter, pframe, pattrib); + + pframe = rtw_tdls_set_linkid(pframe, pattrib, _TRUE); + + if ((pregistrypriv->wmm_enable == _TRUE) || (padapter->mlmepriv.htpriv.ht_option == _TRUE)) + pframe = rtw_tdls_set_qos_cap(pframe, pattrib); + +#ifdef CONFIG_80211AC_VHT + if ((padapter->mlmepriv.htpriv.ht_option == _TRUE) && (pmlmeext->cur_channel > 14) + && REGSTY_IS_11AC_ENABLE(pregistrypriv) + && hal_chk_proto_cap(padapter, PROTO_CAP_11AC) + && (!padapter->mlmepriv.country_ent || COUNTRY_CHPLAN_EN_11AC(padapter->mlmepriv.country_ent)) + ) { + pframe = rtw_tdls_set_aid(padapter, pframe, pattrib); + pframe = rtw_tdls_set_vht_cap(padapter, pframe, pattrib); + } +#endif + +#ifdef CONFIG_WFD + if (padapter->wdinfo.wfd_tdls_enable == 1) + wfd_ie_tdls(padapter, pframe, &(pattrib->pktlen)); +#endif + +} + +void rtw_build_tdls_setup_rsp_ies(_adapter *padapter, struct xmit_frame *pxmitframe, u8 *pframe, struct tdls_txmgmt *ptxmgmt) +{ + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_info *ptdls_sta; + u8 k; /* for random ANonce */ + u8 *pftie = NULL, *ptimeout_ie = NULL, *plinkid_ie = NULL, *prsnie = NULL, *pftie_mic = NULL; + u32 time; + u8 *pframe_head; + + ptdls_sta = rtw_get_stainfo(&(padapter->stapriv) , pattrib->dst); + + if (ptdls_sta == NULL) + RTW_INFO("[%s] %d ptdls_sta is NULL\n", __FUNCTION__, __LINE__); + + if (pattrib->encrypt && ptdls_sta != NULL) { + for (k = 0; k < 8; k++) { + time = rtw_get_current_time(); + _rtw_memcpy(&ptdls_sta->ANonce[4 * k], (u8 *)&time, 4); + } + } + + pframe_head = pframe; + + pframe = rtw_tdls_set_payload_type(pframe, pattrib); + pframe = rtw_tdls_set_category(pframe, pattrib, RTW_WLAN_CATEGORY_TDLS); + pframe = rtw_tdls_set_action(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_status_code(pframe, pattrib, ptxmgmt); + + if (ptxmgmt->status_code != 0) { + RTW_INFO("[%s] status_code:%04x\n", __FUNCTION__, ptxmgmt->status_code); + return; + } + + pframe = rtw_tdls_set_dialog(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_capability(padapter, pframe, pattrib); + pframe = rtw_tdls_set_supported_rate(padapter, pframe, pattrib); + pframe = rtw_tdls_set_sup_ch(&(padapter->mlmeextpriv), pframe, pattrib); + pframe = rtw_tdls_set_sup_reg_class(pframe, pattrib); + + if (pattrib->encrypt) { + prsnie = pframe; + pframe = rtw_tdls_set_rsnie(ptxmgmt, pframe, pattrib, _FALSE, ptdls_sta); + } + + pframe = rtw_tdls_set_ext_cap(pframe, pattrib); + + if (pattrib->encrypt) { + if (rtw_tdls_is_driver_setup(padapter) == _TRUE) + wpa_tdls_generate_tpk(padapter, ptdls_sta); + + pftie = pframe; + pftie_mic = pframe + 4; + pframe = rtw_tdls_set_ftie(ptxmgmt + , pframe + , pattrib + , ptdls_sta->ANonce + , ptdls_sta->SNonce); + + ptimeout_ie = pframe; + pframe = rtw_tdls_set_timeout_interval(ptxmgmt, pframe, pattrib, _FALSE, ptdls_sta); + } + +#ifdef CONFIG_80211N_HT + /* Sup_reg_classes(optional) */ + if (pregistrypriv->ht_enable == _TRUE) + pframe = rtw_tdls_set_ht_cap(padapter, pframe_head, pattrib); +#endif + + pframe = rtw_tdls_set_bss_coexist(padapter, pframe, pattrib); + + plinkid_ie = pframe; + pframe = rtw_tdls_set_linkid(pframe, pattrib, _FALSE); + + /* Fill FTIE mic */ + if (pattrib->encrypt && rtw_tdls_is_driver_setup(padapter) == _TRUE) + wpa_tdls_ftie_mic(ptdls_sta->tpk.kck, 2, plinkid_ie, prsnie, ptimeout_ie, pftie, pftie_mic); + + if ((pregistrypriv->wmm_enable == _TRUE) || (padapter->mlmepriv.htpriv.ht_option == _TRUE)) + pframe = rtw_tdls_set_qos_cap(pframe, pattrib); + +#ifdef CONFIG_80211AC_VHT + if ((padapter->mlmepriv.htpriv.ht_option == _TRUE) && (pmlmeext->cur_channel > 14) + && REGSTY_IS_11AC_ENABLE(pregistrypriv) + && hal_chk_proto_cap(padapter, PROTO_CAP_11AC) + && (!padapter->mlmepriv.country_ent || COUNTRY_CHPLAN_EN_11AC(padapter->mlmepriv.country_ent)) + ) { + pframe = rtw_tdls_set_aid(padapter, pframe, pattrib); + pframe = rtw_tdls_set_vht_cap(padapter, pframe, pattrib); + pframe = rtw_tdls_set_vht_op_mode_notify(padapter, pframe, pattrib, pmlmeext->cur_bwmode); + } +#endif + +#ifdef CONFIG_WFD + if (padapter->wdinfo.wfd_tdls_enable) + wfd_ie_tdls(padapter, pframe, &(pattrib->pktlen)); +#endif + +} + +void rtw_build_tdls_setup_cfm_ies(_adapter *padapter, struct xmit_frame *pxmitframe, u8 *pframe, struct tdls_txmgmt *ptxmgmt) +{ + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_info *ptdls_sta = rtw_get_stainfo((&padapter->stapriv) , pattrib->dst); + + unsigned int ie_len; + unsigned char *p; + u8 wmm_param_ele[24] = {0}; + u8 *pftie = NULL, *ptimeout_ie = NULL, *plinkid_ie = NULL, *prsnie = NULL, *pftie_mic = NULL; + + pframe = rtw_tdls_set_payload_type(pframe, pattrib); + pframe = rtw_tdls_set_category(pframe, pattrib, RTW_WLAN_CATEGORY_TDLS); + pframe = rtw_tdls_set_action(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_status_code(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_dialog(pframe, pattrib, ptxmgmt); + + if (ptxmgmt->status_code != 0) + return; + + if (pattrib->encrypt) { + prsnie = pframe; + pframe = rtw_tdls_set_rsnie(ptxmgmt, pframe, pattrib, _TRUE, ptdls_sta); + } + + if (pattrib->encrypt) { + pftie = pframe; + pftie_mic = pframe + 4; + pframe = rtw_tdls_set_ftie(ptxmgmt + , pframe + , pattrib + , ptdls_sta->ANonce + , ptdls_sta->SNonce); + + ptimeout_ie = pframe; + pframe = rtw_tdls_set_timeout_interval(ptxmgmt, pframe, pattrib, _TRUE, ptdls_sta); + + if (rtw_tdls_is_driver_setup(padapter) == _TRUE) { + /* Start TPK timer */ + ptdls_sta->TPK_count = 0; + _set_timer(&ptdls_sta->TPK_timer, ONE_SEC); + } + } + + /* HT operation; todo */ + + plinkid_ie = pframe; + pframe = rtw_tdls_set_linkid(pframe, pattrib, _TRUE); + + if (pattrib->encrypt && (rtw_tdls_is_driver_setup(padapter) == _TRUE)) + wpa_tdls_ftie_mic(ptdls_sta->tpk.kck, 3, plinkid_ie, prsnie, ptimeout_ie, pftie, pftie_mic); + + if (ptdls_sta->qos_option == _TRUE) + pframe = rtw_tdls_set_wmm_params(padapter, pframe, pattrib); + +#ifdef CONFIG_80211AC_VHT + if ((padapter->mlmepriv.htpriv.ht_option == _TRUE) + && (ptdls_sta->vhtpriv.vht_option == _TRUE) && (pmlmeext->cur_channel > 14) + && REGSTY_IS_11AC_ENABLE(pregistrypriv) + && hal_chk_proto_cap(padapter, PROTO_CAP_11AC) + && (!padapter->mlmepriv.country_ent || COUNTRY_CHPLAN_EN_11AC(padapter->mlmepriv.country_ent)) + ) { + pframe = rtw_tdls_set_vht_operation(padapter, pframe, pattrib, pmlmeext->cur_channel); + pframe = rtw_tdls_set_vht_op_mode_notify(padapter, pframe, pattrib, pmlmeext->cur_bwmode); + } +#endif +} + +void rtw_build_tdls_teardown_ies(_adapter *padapter, struct xmit_frame *pxmitframe, u8 *pframe, struct tdls_txmgmt *ptxmgmt) +{ + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_info *ptdls_sta = rtw_get_stainfo(&(padapter->stapriv) , pattrib->dst); + u8 *pftie = NULL, *pftie_mic = NULL, *plinkid_ie = NULL; + + pframe = rtw_tdls_set_payload_type(pframe, pattrib); + pframe = rtw_tdls_set_category(pframe, pattrib, RTW_WLAN_CATEGORY_TDLS); + pframe = rtw_tdls_set_action(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_status_code(pframe, pattrib, ptxmgmt); + + if (pattrib->encrypt) { + pftie = pframe; + pftie_mic = pframe + 4; + pframe = rtw_tdls_set_ftie(ptxmgmt + , pframe + , pattrib + , ptdls_sta->ANonce + , ptdls_sta->SNonce); + } + + plinkid_ie = pframe; + if (ptdls_sta->tdls_sta_state & TDLS_INITIATOR_STATE) + pframe = rtw_tdls_set_linkid(pframe, pattrib, _FALSE); + else if (ptdls_sta->tdls_sta_state & TDLS_RESPONDER_STATE) + pframe = rtw_tdls_set_linkid(pframe, pattrib, _TRUE); + + if (pattrib->encrypt && (rtw_tdls_is_driver_setup(padapter) == _TRUE)) + wpa_tdls_teardown_ftie_mic(ptdls_sta->tpk.kck, plinkid_ie, ptxmgmt->status_code, 1, 4, pftie, pftie_mic); +} + +void rtw_build_tdls_dis_req_ies(_adapter *padapter, struct xmit_frame *pxmitframe, u8 *pframe, struct tdls_txmgmt *ptxmgmt) +{ + struct pkt_attrib *pattrib = &pxmitframe->attrib; + + pframe = rtw_tdls_set_payload_type(pframe, pattrib); + pframe = rtw_tdls_set_category(pframe, pattrib, RTW_WLAN_CATEGORY_TDLS); + pframe = rtw_tdls_set_action(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_dialog(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_linkid(pframe, pattrib, _TRUE); + +} + +void rtw_build_tdls_dis_rsp_ies(_adapter *padapter, struct xmit_frame *pxmitframe, u8 *pframe, struct tdls_txmgmt *ptxmgmt, u8 privacy) +{ + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + u8 *pframe_head, pktlen_index; + + pktlen_index = pattrib->pktlen; + pframe_head = pframe; + + pframe = rtw_tdls_set_category(pframe, pattrib, RTW_WLAN_CATEGORY_PUBLIC); + pframe = rtw_tdls_set_action(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_dialog(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_capability(padapter, pframe, pattrib); + + pframe = rtw_tdls_set_supported_rate(padapter, pframe, pattrib); + + pframe = rtw_tdls_set_sup_ch(pmlmeext, pframe, pattrib); + + if (privacy) + pframe = rtw_tdls_set_rsnie(ptxmgmt, pframe, pattrib, _TRUE, NULL); + + pframe = rtw_tdls_set_ext_cap(pframe, pattrib); + + if (privacy) { + pframe = rtw_tdls_set_ftie(ptxmgmt, pframe, pattrib, NULL, NULL); + pframe = rtw_tdls_set_timeout_interval(ptxmgmt, pframe, pattrib, _TRUE, NULL); + } + +#ifdef CONFIG_80211N_HT + if (pregistrypriv->ht_enable == _TRUE) + pframe = rtw_tdls_set_ht_cap(padapter, pframe_head - pktlen_index, pattrib); +#endif + + pframe = rtw_tdls_set_bss_coexist(padapter, pframe, pattrib); + pframe = rtw_tdls_set_linkid(pframe, pattrib, _FALSE); + +} + + +void rtw_build_tdls_peer_traffic_indication_ies(_adapter *padapter, struct xmit_frame *pxmitframe, u8 *pframe, struct tdls_txmgmt *ptxmgmt) +{ + + struct pkt_attrib *pattrib = &pxmitframe->attrib; + u8 AC_queue = 0; + struct sta_info *ptdls_sta = rtw_get_stainfo(&padapter->stapriv, pattrib->dst); + + pframe = rtw_tdls_set_payload_type(pframe, pattrib); + pframe = rtw_tdls_set_category(pframe, pattrib, RTW_WLAN_CATEGORY_TDLS); + pframe = rtw_tdls_set_action(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_dialog(pframe, pattrib, ptxmgmt); + + if (ptdls_sta->tdls_sta_state & TDLS_INITIATOR_STATE) + pframe = rtw_tdls_set_linkid(pframe, pattrib, _FALSE); + else if (ptdls_sta->tdls_sta_state & TDLS_RESPONDER_STATE) + pframe = rtw_tdls_set_linkid(pframe, pattrib, _TRUE); + + /* PTI control */ + /* PU buffer status */ + if (ptdls_sta->uapsd_bk & BIT(1)) + AC_queue = BIT(0); + if (ptdls_sta->uapsd_be & BIT(1)) + AC_queue = BIT(1); + if (ptdls_sta->uapsd_vi & BIT(1)) + AC_queue = BIT(2); + if (ptdls_sta->uapsd_vo & BIT(1)) + AC_queue = BIT(3); + pframe = rtw_set_ie(pframe, _PTI_BUFFER_STATUS_, 1, &AC_queue, &(pattrib->pktlen)); + +} + +void rtw_build_tdls_peer_traffic_rsp_ies(_adapter *padapter, struct xmit_frame *pxmitframe, u8 *pframe, struct tdls_txmgmt *ptxmgmt) +{ + + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_info *ptdls_sta = rtw_get_stainfo(&padapter->stapriv, pattrib->dst); + + pframe = rtw_tdls_set_payload_type(pframe, pattrib); + pframe = rtw_tdls_set_category(pframe, pattrib, RTW_WLAN_CATEGORY_TDLS); + pframe = rtw_tdls_set_action(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_dialog(pframe, pattrib, ptxmgmt); + + if (ptdls_sta->tdls_sta_state & TDLS_INITIATOR_STATE) + pframe = rtw_tdls_set_linkid(pframe, pattrib, _FALSE); + else if (ptdls_sta->tdls_sta_state & TDLS_RESPONDER_STATE) + pframe = rtw_tdls_set_linkid(pframe, pattrib, _TRUE); +} + +#ifdef CONFIG_TDLS_CH_SW +void rtw_build_tdls_ch_switch_req_ies(_adapter *padapter, struct xmit_frame *pxmitframe, u8 *pframe, struct tdls_txmgmt *ptxmgmt) +{ + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *ptdls_sta = rtw_get_stainfo(pstapriv, pattrib->dst); + u16 switch_time = TDLS_CH_SWITCH_TIME * 1000, switch_timeout = TDLS_CH_SWITCH_TIMEOUT * 1000; + + ptdls_sta->ch_switch_time = switch_time; + ptdls_sta->ch_switch_timeout = switch_timeout; + + pframe = rtw_tdls_set_payload_type(pframe, pattrib); + pframe = rtw_tdls_set_category(pframe, pattrib, RTW_WLAN_CATEGORY_TDLS); + pframe = rtw_tdls_set_action(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_target_ch(padapter, pframe, pattrib); + pframe = rtw_tdls_set_reg_class(pframe, pattrib, ptdls_sta); + + if (ptdlsinfo->chsw_info.ch_offset != HAL_PRIME_CHNL_OFFSET_DONT_CARE) { + switch (ptdlsinfo->chsw_info.ch_offset) { + case HAL_PRIME_CHNL_OFFSET_LOWER: + pframe = rtw_tdls_set_second_channel_offset(pframe, pattrib, SCA); + break; + case HAL_PRIME_CHNL_OFFSET_UPPER: + pframe = rtw_tdls_set_second_channel_offset(pframe, pattrib, SCB); + break; + } + } + + if (ptdls_sta->tdls_sta_state & TDLS_INITIATOR_STATE) + pframe = rtw_tdls_set_linkid(pframe, pattrib, _FALSE); + else if (ptdls_sta->tdls_sta_state & TDLS_RESPONDER_STATE) + pframe = rtw_tdls_set_linkid(pframe, pattrib, _TRUE); + + pframe = rtw_tdls_set_ch_sw(pframe, pattrib, ptdls_sta); + +} + +void rtw_build_tdls_ch_switch_rsp_ies(_adapter *padapter, struct xmit_frame *pxmitframe, u8 *pframe, struct tdls_txmgmt *ptxmgmt) +{ + + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *ptdls_sta = rtw_get_stainfo(pstapriv, pattrib->dst); + + pframe = rtw_tdls_set_payload_type(pframe, pattrib); + pframe = rtw_tdls_set_category(pframe, pattrib, RTW_WLAN_CATEGORY_TDLS); + pframe = rtw_tdls_set_action(pframe, pattrib, ptxmgmt); + pframe = rtw_tdls_set_status_code(pframe, pattrib, ptxmgmt); + + if (ptdls_sta->tdls_sta_state & TDLS_INITIATOR_STATE) + pframe = rtw_tdls_set_linkid(pframe, pattrib, _FALSE); + else if (ptdls_sta->tdls_sta_state & TDLS_RESPONDER_STATE) + pframe = rtw_tdls_set_linkid(pframe, pattrib, _TRUE); + + pframe = rtw_tdls_set_ch_sw(pframe, pattrib, ptdls_sta); +} +#endif + +#ifdef CONFIG_WFD +void rtw_build_tunneled_probe_req_ies(_adapter *padapter, struct xmit_frame *pxmitframe, u8 *pframe) +{ + u8 i; + _adapter *iface = NULL; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct wifidirect_info *pwdinfo; + + u8 category = RTW_WLAN_CATEGORY_P2P; + u8 WFA_OUI[3] = { 0x50, 0x6f, 0x9a}; + u8 probe_req = 4; + u8 wfdielen = 0; + + pframe = rtw_tdls_set_payload_type(pframe, pattrib); + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 3, WFA_OUI, &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(probe_req), &(pattrib->pktlen)); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if ((iface) && rtw_is_adapter_up(iface)) { + pwdinfo = &iface->wdinfo; + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { + wfdielen = build_probe_req_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pattrib->pktlen += wfdielen; + } + } + } +} + +void rtw_build_tunneled_probe_rsp_ies(_adapter *padapter, struct xmit_frame *pxmitframe, u8 *pframe) +{ + u8 i; + _adapter *iface = NULL; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct wifidirect_info *pwdinfo; + u8 category = RTW_WLAN_CATEGORY_P2P; + u8 WFA_OUI[3] = { 0x50, 0x6f, 0x9a}; + u8 probe_rsp = 5; + u8 wfdielen = 0; + + pframe = rtw_tdls_set_payload_type(pframe, pattrib); + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 3, WFA_OUI, &(pattrib->pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(probe_rsp), &(pattrib->pktlen)); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if ((iface) && rtw_is_adapter_up(iface)) { + pwdinfo = &iface->wdinfo; + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) { + wfdielen = build_probe_resp_wfd_ie(pwdinfo, pframe, 1); + pframe += wfdielen; + pattrib->pktlen += wfdielen; + } + } + } +} +#endif /* CONFIG_WFD */ + +void _tdls_tpk_timer_hdl(void *FunctionContext) +{ + struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; + struct tdls_txmgmt txmgmt; + + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + ptdls_sta->TPK_count++; + /* TPK_timer expired in a second */ + /* Retry timer should set at least 301 sec. */ + if (ptdls_sta->TPK_count >= (ptdls_sta->TDLS_PeerKey_Lifetime - 3)) { + RTW_INFO("[TDLS] %s, Re-Setup TDLS link with "MAC_FMT" since TPK lifetime expires!\n", __FUNCTION__, MAC_ARG(ptdls_sta->hwaddr)); + ptdls_sta->TPK_count = 0; + _rtw_memcpy(txmgmt.peer, ptdls_sta->hwaddr, ETH_ALEN); + issue_tdls_setup_req(ptdls_sta->padapter, &txmgmt, _FALSE); + } + + _set_timer(&ptdls_sta->TPK_timer, ONE_SEC); +} + +#ifdef CONFIG_TDLS_CH_SW +void _tdls_ch_switch_timer_hdl(void *FunctionContext) +{ + struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; + _adapter *padapter = ptdls_sta->padapter; + struct tdls_ch_switch *pchsw_info = &padapter->tdlsinfo.chsw_info; + + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_END_TO_BASE_CHNL); + RTW_INFO("[TDLS] %s, can't get traffic from op_ch:%d\n", __func__, rtw_get_oper_ch(padapter)); +} + +void _tdls_delay_timer_hdl(void *FunctionContext) +{ + struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; + _adapter *padapter = ptdls_sta->padapter; + struct tdls_ch_switch *pchsw_info = &padapter->tdlsinfo.chsw_info; + + RTW_INFO("[TDLS] %s, op_ch:%d, tdls_state:0x%08x\n", __func__, rtw_get_oper_ch(padapter), ptdls_sta->tdls_sta_state); + pchsw_info->delay_switch_back = _TRUE; +} + +void _tdls_stay_on_base_chnl_timer_hdl(void *FunctionContext) +{ + struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; + _adapter *padapter = ptdls_sta->padapter; + struct tdls_ch_switch *pchsw_info = &padapter->tdlsinfo.chsw_info; + + if (ptdls_sta != NULL) { + issue_tdls_ch_switch_req(padapter, ptdls_sta); + pchsw_info->ch_sw_state |= TDLS_WAIT_CH_RSP_STATE; + } +} + +void _tdls_ch_switch_monitor_timer_hdl(void *FunctionContext) +{ + struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; + _adapter *padapter = ptdls_sta->padapter; + struct tdls_ch_switch *pchsw_info = &padapter->tdlsinfo.chsw_info; + + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_CH_SW_END); + RTW_INFO("[TDLS] %s, does not receive ch sw req\n", __func__); +} + +#endif + +void _tdls_handshake_timer_hdl(void *FunctionContext) +{ + struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; + _adapter *padapter = ptdls_sta->padapter; + struct tdls_txmgmt txmgmt; + + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + _rtw_memcpy(txmgmt.peer, ptdls_sta->hwaddr, ETH_ALEN); + txmgmt.status_code = _RSON_TDLS_TEAR_UN_RSN_; + + if (ptdls_sta != NULL) { + RTW_INFO("[TDLS] Handshake time out\n"); + if (ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE) + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_TEARDOWN_STA); + else + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_TEARDOWN_STA_LOCALLY); + } +} + +void _tdls_pti_timer_hdl(void *FunctionContext) +{ + struct sta_info *ptdls_sta = (struct sta_info *)FunctionContext; + _adapter *padapter = ptdls_sta->padapter; + struct tdls_txmgmt txmgmt; + + _rtw_memset(&txmgmt, 0x00, sizeof(struct tdls_txmgmt)); + _rtw_memcpy(txmgmt.peer, ptdls_sta->hwaddr, ETH_ALEN); + txmgmt.status_code = _RSON_TDLS_TEAR_TOOFAR_; + + if (ptdls_sta != NULL) { + if (ptdls_sta->tdls_sta_state & TDLS_WAIT_PTR_STATE) { + RTW_INFO("[TDLS] Doesn't receive PTR from peer dev:"MAC_FMT"; " + "Send TDLS Tear Down\n", MAC_ARG(ptdls_sta->hwaddr)); + issue_tdls_teardown(padapter, &txmgmt, _FALSE); + } + } +} + +void rtw_init_tdls_timer(_adapter *padapter, struct sta_info *psta) +{ + psta->padapter = padapter; + _init_timer(&psta->TPK_timer, padapter->pnetdev, _tdls_tpk_timer_hdl, psta); +#ifdef CONFIG_TDLS_CH_SW + _init_timer(&psta->ch_sw_timer, padapter->pnetdev, _tdls_ch_switch_timer_hdl, psta); + _init_timer(&psta->delay_timer, padapter->pnetdev, _tdls_delay_timer_hdl, psta); + _init_timer(&psta->stay_on_base_chnl_timer, padapter->pnetdev, _tdls_stay_on_base_chnl_timer_hdl, psta); + _init_timer(&psta->ch_sw_monitor_timer, padapter->pnetdev, _tdls_ch_switch_monitor_timer_hdl, psta); +#endif + _init_timer(&psta->handshake_timer, padapter->pnetdev, _tdls_handshake_timer_hdl, psta); + _init_timer(&psta->pti_timer, padapter->pnetdev, _tdls_pti_timer_hdl, psta); +} + +void rtw_free_tdls_timer(struct sta_info *psta) +{ + _cancel_timer_ex(&psta->TPK_timer); +#ifdef CONFIG_TDLS_CH_SW + _cancel_timer_ex(&psta->ch_sw_timer); + _cancel_timer_ex(&psta->delay_timer); + _cancel_timer_ex(&psta->stay_on_base_chnl_timer); + _cancel_timer_ex(&psta->ch_sw_monitor_timer); +#endif + _cancel_timer_ex(&psta->handshake_timer); + _cancel_timer_ex(&psta->pti_timer); +} + +u32 update_mask_tdls(_adapter *padapter, struct sta_info *psta) +{ + unsigned char sta_band = 0; + unsigned int tx_ra_bitmap = 0; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + WLAN_BSSID_EX *pcur_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; + + rtw_hal_update_sta_rate_mask(padapter, psta); + tx_ra_bitmap = psta->ra_mask; + + if (pcur_network->Configuration.DSConfig > 14) { + if (tx_ra_bitmap & 0xffff000) + sta_band |= WIRELESS_11_5N | WIRELESS_11A; + else + sta_band |= WIRELESS_11A; + } else { + if (tx_ra_bitmap & 0xffff000) + sta_band |= WIRELESS_11_24N | WIRELESS_11G | WIRELESS_11B; + else if (tx_ra_bitmap & 0xff0) + sta_band |= WIRELESS_11G | WIRELESS_11B; + else + sta_band |= WIRELESS_11B; + } + + psta->wireless_mode = sta_band; + + psta->raid = rtw_hal_networktype_to_raid(padapter, psta); + tx_ra_bitmap |= ((psta->raid << 28) & 0xf0000000); + return tx_ra_bitmap; +} + +int rtw_tdls_is_driver_setup(_adapter *padapter) +{ + return padapter->tdlsinfo.driver_setup; +} + +const char *rtw_tdls_action_txt(enum TDLS_ACTION_FIELD action) +{ + switch (action) { + case TDLS_SETUP_REQUEST: + return "TDLS_SETUP_REQUEST"; + case TDLS_SETUP_RESPONSE: + return "TDLS_SETUP_RESPONSE"; + case TDLS_SETUP_CONFIRM: + return "TDLS_SETUP_CONFIRM"; + case TDLS_TEARDOWN: + return "TDLS_TEARDOWN"; + case TDLS_PEER_TRAFFIC_INDICATION: + return "TDLS_PEER_TRAFFIC_INDICATION"; + case TDLS_CHANNEL_SWITCH_REQUEST: + return "TDLS_CHANNEL_SWITCH_REQUEST"; + case TDLS_CHANNEL_SWITCH_RESPONSE: + return "TDLS_CHANNEL_SWITCH_RESPONSE"; + case TDLS_PEER_PSM_REQUEST: + return "TDLS_PEER_PSM_REQUEST"; + case TDLS_PEER_PSM_RESPONSE: + return "TDLS_PEER_PSM_RESPONSE"; + case TDLS_PEER_TRAFFIC_RESPONSE: + return "TDLS_PEER_TRAFFIC_RESPONSE"; + case TDLS_DISCOVERY_REQUEST: + return "TDLS_DISCOVERY_REQUEST"; + case TDLS_DISCOVERY_RESPONSE: + return "TDLS_DISCOVERY_RESPONSE"; + default: + return "UNKNOWN"; + } +} + +#endif /* CONFIG_TDLS */ diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_vht.c b/linux-bsp/drivers/rtl8188eus/core/rtw_vht.c new file mode 100644 index 0000000..fbb26f8 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_vht.c @@ -0,0 +1,803 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_VHT_C + +#include <drv_types.h> +#include <hal_data.h> + +#ifdef CONFIG_80211AC_VHT +/* 20/40/80, ShortGI, MCS Rate */ +const u16 VHT_MCS_DATA_RATE[3][2][30] = { + { { + 13, 26, 39, 52, 78, 104, 117, 130, 156, 156, + 26, 52, 78, 104, 156, 208, 234, 260, 312, 312, + 39, 78, 117, 156, 234, 312, 351, 390, 468, 520 + }, /* Long GI, 20MHz */ + { + 14, 29, 43, 58, 87, 116, 130, 144, 173, 173, + 29, 58, 87, 116, 173, 231, 260, 289, 347, 347, + 43, 87, 130, 173, 260, 347, 390, 433, 520, 578 + } + }, /* Short GI, 20MHz */ + { { + 27, 54, 81, 108, 162, 216, 243, 270, 324, 360, + 54, 108, 162, 216, 324, 432, 486, 540, 648, 720, + 81, 162, 243, 324, 486, 648, 729, 810, 972, 1080 + }, /* Long GI, 40MHz */ + { + 30, 60, 90, 120, 180, 240, 270, 300, 360, 400, + 60, 120, 180, 240, 360, 480, 540, 600, 720, 800, + 90, 180, 270, 360, 540, 720, 810, 900, 1080, 1200 + } + }, /* Short GI, 40MHz */ + { { + 59, 117, 176, 234, 351, 468, 527, 585, 702, 780, + 117, 234, 351, 468, 702, 936, 1053, 1170, 1404, 1560, + 176, 351, 527, 702, 1053, 1404, 1580, 1755, 2106, 2340 + }, /* Long GI, 80MHz */ + { + 65, 130, 195, 260, 390, 520, 585, 650, 780, 867, + 130, 260, 390, 520, 780, 1040, 1170, 1300, 1560, 1734, + 195, 390, 585, 780, 1170, 1560, 1755, 1950, 2340, 2600 + } + } /* Short GI, 80MHz */ +}; + +u8 rtw_get_vht_highest_rate(u8 *pvht_mcs_map) +{ + u8 i, j; + u8 bit_map; + u8 vht_mcs_rate = 0; + + for (i = 0; i < 2; i++) { + if (pvht_mcs_map[i] != 0xff) { + for (j = 0; j < 8; j += 2) { + bit_map = (pvht_mcs_map[i] >> j) & 3; + + if (bit_map != 3) + vht_mcs_rate = MGN_VHT1SS_MCS7 + 10 * j / 2 + i * 40 + bit_map; /* VHT rate indications begin from 0x90 */ + } + } + } + + /* RTW_INFO("HighestVHTMCSRate is %x\n", vht_mcs_rate); */ + return vht_mcs_rate; +} + +u8 rtw_vht_mcsmap_to_nss(u8 *pvht_mcs_map) +{ + u8 i, j; + u8 bit_map; + u8 nss = 0; + + for (i = 0; i < 2; i++) { + if (pvht_mcs_map[i] != 0xff) { + for (j = 0; j < 8; j += 2) { + bit_map = (pvht_mcs_map[i] >> j) & 3; + + if (bit_map != 3) + nss++; + } + } + } + + /* RTW_INFO("%s : %dSS\n", __FUNCTION__, nss); */ + return nss; +} + +void rtw_vht_nss_to_mcsmap(u8 nss, u8 *target_mcs_map, u8 *cur_mcs_map) +{ + u8 i, j; + u8 cur_rate, target_rate; + + for (i = 0; i < 2; i++) { + target_mcs_map[i] = 0; + for (j = 0; j < 8; j += 2) { + cur_rate = (cur_mcs_map[i] >> j) & 3; + if (cur_rate == 3) /* 0x3 indicates not supported that num of SS */ + target_rate = 3; + else if (nss <= ((j / 2) + i * 4)) + target_rate = 3; + else + target_rate = cur_rate; + + target_mcs_map[i] |= (target_rate << j); + } + } + + /* RTW_INFO("%s : %dSS\n", __FUNCTION__, nss); */ +} + +u16 rtw_vht_mcs_to_data_rate(u8 bw, u8 short_GI, u8 vht_mcs_rate) +{ + if (vht_mcs_rate > MGN_VHT3SS_MCS9) + vht_mcs_rate = MGN_VHT3SS_MCS9; + /* RTW_INFO("bw=%d, short_GI=%d, ((vht_mcs_rate - MGN_VHT1SS_MCS0)&0x3f)=%d\n", bw, short_GI, ((vht_mcs_rate - MGN_VHT1SS_MCS0)&0x3f)); */ + return VHT_MCS_DATA_RATE[bw][short_GI][((vht_mcs_rate - MGN_VHT1SS_MCS0) & 0x3f)]; +} + +void rtw_vht_use_default_setting(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + BOOLEAN bHwLDPCSupport = _FALSE, bHwSTBCSupport = _FALSE; +#ifdef CONFIG_BEAMFORMING + BOOLEAN bHwSupportBeamformer = _FALSE, bHwSupportBeamformee = _FALSE; + u8 mu_bfer, mu_bfee; +#endif /* CONFIG_BEAMFORMING */ + u8 rf_type = 0; + u8 tx_nss, rx_nss; + struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + pvhtpriv->sgi_80m = TEST_FLAG(pregistrypriv->short_gi, BIT2) ? _TRUE : _FALSE; + + /* LDPC support */ + rtw_hal_get_def_var(padapter, HAL_DEF_RX_LDPC, (u8 *)&bHwLDPCSupport); + CLEAR_FLAGS(pvhtpriv->ldpc_cap); + if (bHwLDPCSupport) { + if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT0)) + SET_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_RX); + } + rtw_hal_get_def_var(padapter, HAL_DEF_TX_LDPC, (u8 *)&bHwLDPCSupport); + if (bHwLDPCSupport) { + if (TEST_FLAG(pregistrypriv->ldpc_cap, BIT1)) + SET_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_TX); + } + if (pvhtpriv->ldpc_cap) + RTW_INFO("[VHT] Support LDPC = 0x%02X\n", pvhtpriv->ldpc_cap); + + /* STBC */ + rtw_hal_get_def_var(padapter, HAL_DEF_TX_STBC, (u8 *)&bHwSTBCSupport); + CLEAR_FLAGS(pvhtpriv->stbc_cap); + if (bHwSTBCSupport) { + if (TEST_FLAG(pregistrypriv->stbc_cap, BIT1)) + SET_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX); + } + rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)&bHwSTBCSupport); + if (bHwSTBCSupport) { + if (TEST_FLAG(pregistrypriv->stbc_cap, BIT0)) + SET_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_RX); + } + if (pvhtpriv->stbc_cap) + RTW_INFO("[VHT] Support STBC = 0x%02X\n", pvhtpriv->stbc_cap); + + /* Beamforming setting */ + CLEAR_FLAGS(pvhtpriv->beamform_cap); +#ifdef CONFIG_BEAMFORMING + rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMER, (u8 *)&bHwSupportBeamformer); + rtw_hal_get_def_var(padapter, HAL_DEF_EXPLICIT_BEAMFORMEE, (u8 *)&bHwSupportBeamformee); + mu_bfer = _FALSE; + mu_bfee = _FALSE; + rtw_hal_get_def_var(padapter, HAL_DEF_VHT_MU_BEAMFORMER, &mu_bfer); + rtw_hal_get_def_var(padapter, HAL_DEF_VHT_MU_BEAMFORMEE, &mu_bfee); + if (TEST_FLAG(pregistrypriv->beamform_cap, BIT0) && bHwSupportBeamformer) { +#ifdef CONFIG_CONCURRENT_MODE + if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { + SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); + RTW_INFO("[VHT] CONCURRENT AP Support Beamformer\n"); + if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(2)) + && (_TRUE == mu_bfer)) { + SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE); + RTW_INFO("[VHT] Support MU-MIMO AP\n"); + } + } else + RTW_INFO("[VHT] CONCURRENT not AP ;not allow Support Beamformer\n"); +#else + SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); + RTW_INFO("[VHT] Support Beamformer\n"); + if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(2)) + && (_TRUE == mu_bfer) + && ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) { + SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE); + RTW_INFO("[VHT] Support MU-MIMO AP\n"); + } +#endif + } + if (TEST_FLAG(pregistrypriv->beamform_cap, BIT1) && bHwSupportBeamformee) { + SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); + RTW_INFO("[VHT] Support Beamformee\n"); + if (TEST_FLAG(pregistrypriv->beamform_cap, BIT(3)) + && (_TRUE == mu_bfee) + && ((pmlmeinfo->state & 0x03) != WIFI_FW_AP_STATE)) { + SET_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE); + RTW_INFO("[VHT] Support MU-MIMO STA\n"); + } + } +#endif /* CONFIG_BEAMFORMING */ + + pvhtpriv->ampdu_len = pregistrypriv->ampdu_factor; + + rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); + rx_nss = rtw_min(rf_type_to_rf_rx_cnt(rf_type), hal_spec->rx_nss_num); + + /* for now, vhtpriv.vht_mcs_map comes from RX NSS */ + rtw_vht_nss_to_mcsmap(rx_nss, pvhtpriv->vht_mcs_map, pregistrypriv->vht_rx_mcs_map); + pvhtpriv->vht_highest_rate = rtw_get_vht_highest_rate(pvhtpriv->vht_mcs_map); +} + +u64 rtw_vht_mcs_map_to_bitmap(u8 *mcs_map, u8 nss) +{ + u8 i, j, tmp; + u64 bitmap = 0; + u8 bits_nss = nss * 2; + + for (i = j = 0; i < bits_nss; i += 2, j += 10) { + /* every two bits means single sptial stream */ + tmp = (mcs_map[i / 8] >> i) & 3; + + switch (tmp) { + case 2: + bitmap = bitmap | (0x03ff << j); + break; + case 1: + bitmap = bitmap | (0x01ff << j); + break; + case 0: + bitmap = bitmap | (0x00ff << j); + break; + default: + break; + } + } + + RTW_INFO("vht_mcs_map=%02x %02x, nss=%u => bitmap=%016llx\n" + , mcs_map[0], mcs_map[1], nss, bitmap); + + return bitmap; +} + +void update_sta_vht_info_apmode(_adapter *padapter, PVOID sta) +{ + struct sta_info *psta = (struct sta_info *)sta; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct vht_priv *pvhtpriv_ap = &pmlmepriv->vhtpriv; + struct vht_priv *pvhtpriv_sta = &psta->vhtpriv; + struct ht_priv *phtpriv_sta = &psta->htpriv; + u8 cur_ldpc_cap = 0, cur_stbc_cap = 0, bw_mode = 0; + u16 cur_beamform_cap = 0; + u8 *pcap_mcs; + + if (pvhtpriv_sta->vht_option == _FALSE) + return; + + bw_mode = GET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(&pvhtpriv_sta->vht_op_mode_notify); + + /* if (bw_mode > psta->bw_mode) */ + psta->bw_mode = bw_mode; + + /* B4 Rx LDPC */ + if (TEST_FLAG(pvhtpriv_ap->ldpc_cap, LDPC_VHT_ENABLE_TX) && + GET_VHT_CAPABILITY_ELE_RX_LDPC(pvhtpriv_sta->vht_cap)) { + SET_FLAG(cur_ldpc_cap, (LDPC_VHT_ENABLE_TX | LDPC_VHT_CAP_TX)); + RTW_INFO("Current STA(%d) VHT LDPC = %02X\n", psta->aid, cur_ldpc_cap); + } + pvhtpriv_sta->ldpc_cap = cur_ldpc_cap; + + if (psta->bw_mode > pmlmeext->cur_bwmode) + psta->bw_mode = pmlmeext->cur_bwmode; + + if (psta->bw_mode == CHANNEL_WIDTH_80) { + /* B5 Short GI for 80 MHz */ + pvhtpriv_sta->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI80M(pvhtpriv_sta->vht_cap) & pvhtpriv_ap->sgi_80m) ? _TRUE : _FALSE; + /* RTW_INFO("Current STA ShortGI80MHz = %d\n", pvhtpriv_sta->sgi_80m); */ + } else if (psta->bw_mode >= CHANNEL_WIDTH_160) { + /* B5 Short GI for 80 MHz */ + pvhtpriv_sta->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI160M(pvhtpriv_sta->vht_cap) & pvhtpriv_ap->sgi_80m) ? _TRUE : _FALSE; + /* RTW_INFO("Current STA ShortGI160MHz = %d\n", pvhtpriv_sta->sgi_80m); */ + } + + /* B8 B9 B10 Rx STBC */ + if (TEST_FLAG(pvhtpriv_ap->stbc_cap, STBC_VHT_ENABLE_TX) && + GET_VHT_CAPABILITY_ELE_RX_STBC(pvhtpriv_sta->vht_cap)) { + SET_FLAG(cur_stbc_cap, (STBC_VHT_ENABLE_TX | STBC_VHT_CAP_TX)); + RTW_INFO("Current STA(%d) VHT STBC = %02X\n", psta->aid, cur_stbc_cap); + } + pvhtpriv_sta->stbc_cap = cur_stbc_cap; + +#ifdef CONFIG_BEAMFORMING + /* B11 SU Beamformer Capable, the target supports Beamformer and we are Beamformee */ + if (TEST_FLAG(pvhtpriv_ap->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) && + GET_VHT_CAPABILITY_ELE_SU_BFEE(pvhtpriv_sta->vht_cap)) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); + /*Shift to BEAMFORMING_VHT_BEAMFORMER_STS_CAP*/ + SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pvhtpriv_sta->vht_cap) << 8); + } + + /* B12 SU Beamformee Capable, the target supports Beamformee and we are Beamformer */ + if (TEST_FLAG(pvhtpriv_ap->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) && + GET_VHT_CAPABILITY_ELE_SU_BFER(pvhtpriv_sta->vht_cap)) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); + /*Shit to BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM*/ + SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pvhtpriv_sta->vht_cap) << 12); + } + pvhtpriv_sta->beamform_cap = cur_beamform_cap; + if (cur_beamform_cap) + RTW_INFO("Current STA(%d) VHT Beamforming Setting = %02X\n", psta->aid, cur_beamform_cap); +#endif + + /* B23 B24 B25 Maximum A-MPDU Length Exponent */ + pvhtpriv_sta->ampdu_len = GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pvhtpriv_sta->vht_cap); + + pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pvhtpriv_sta->vht_cap); + _rtw_memcpy(pvhtpriv_sta->vht_mcs_map, pcap_mcs, 2); + pvhtpriv_sta->vht_highest_rate = rtw_get_vht_highest_rate(pvhtpriv_sta->vht_mcs_map); +} + +void update_hw_vht_param(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 ht_AMPDU_len; + + ht_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; + + if (pvhtpriv->ampdu_len > ht_AMPDU_len) + rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&pvhtpriv->ampdu_len)); +} + +void VHT_caps_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 cur_ldpc_cap = 0, cur_stbc_cap = 0, rf_type = RF_1T1R, tx_nss = 0; + u16 cur_beamform_cap = 0; + u8 *pcap_mcs; + + if (pIE == NULL) + return; + + if (pvhtpriv->vht_option == _FALSE) + return; + + pmlmeinfo->VHT_enable = 1; + + /* B4 Rx LDPC */ + if (TEST_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_TX) && + GET_VHT_CAPABILITY_ELE_RX_LDPC(pIE->data)) { + SET_FLAG(cur_ldpc_cap, (LDPC_VHT_ENABLE_TX | LDPC_VHT_CAP_TX)); + RTW_INFO("Current VHT LDPC Setting = %02X\n", cur_ldpc_cap); + } + pvhtpriv->ldpc_cap = cur_ldpc_cap; + + /* B5 Short GI for 80 MHz */ + pvhtpriv->sgi_80m = (GET_VHT_CAPABILITY_ELE_SHORT_GI80M(pIE->data) & pvhtpriv->sgi_80m) ? _TRUE : _FALSE; + /* RTW_INFO("Current ShortGI80MHz = %d\n", pvhtpriv->sgi_80m); */ + + /* B8 B9 B10 Rx STBC */ + if (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX) && + GET_VHT_CAPABILITY_ELE_RX_STBC(pIE->data)) { + SET_FLAG(cur_stbc_cap, (STBC_VHT_ENABLE_TX | STBC_VHT_CAP_TX)); + RTW_INFO("Current VHT STBC Setting = %02X\n", cur_stbc_cap); + } + pvhtpriv->stbc_cap = cur_stbc_cap; +#ifdef CONFIG_BEAMFORMING +#ifdef RTW_BEAMFORMING_VERSION_2 + /* + * B11 SU Beamformer Capable, + * the target supports Beamformer and we are Beamformee + */ + if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) + && GET_VHT_CAPABILITY_ELE_SU_BFER(pIE->data)) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); + + /* Shift to BEAMFORMING_VHT_BEAMFORMEE_STS_CAP */ + SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pIE->data) << 8); + + /* + * B19 MU Beamformer Capable, + * the target supports Beamformer and we are Beamformee + */ + if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE) + && GET_VHT_CAPABILITY_ELE_MU_BFER(pIE->data)) + SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE); + } + + /* + * B12 SU Beamformee Capable, + * the target supports Beamformee and we are Beamformer + */ + if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) + && GET_VHT_CAPABILITY_ELE_SU_BFEE(pIE->data)) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); + + /* Shit to BEAMFORMING_VHT_BEAMFORMER_SOUND_DIM */ + SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pIE->data) << 12); + + /* + * B20 MU Beamformee Capable, + * the target supports Beamformee and we are Beamformer + */ + if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE) + && GET_VHT_CAPABILITY_ELE_MU_BFEE(pIE->data)) + SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE); + } + + pvhtpriv->beamform_cap = cur_beamform_cap; + RTW_INFO("Current VHT Beamforming Setting=0x%04X\n", cur_beamform_cap); +#else /* !RTW_BEAMFORMING_VERSION_2 */ + /* B11 SU Beamformer Capable, the target supports Beamformer and we are Beamformee */ + if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE) && + GET_VHT_CAPABILITY_ELE_SU_BFEE(pIE->data)) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE); + /*Shift to BEAMFORMING_VHT_BEAMFORMER_STS_CAP*/ + SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFEE_STS_CAP(pIE->data) << 8); + } + + /* B12 SU Beamformee Capable, the target supports Beamformee and we are Beamformer */ + if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE) && + GET_VHT_CAPABILITY_ELE_SU_BFER(pIE->data)) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE); + /*Shit to BEAMFORMING_VHT_BEAMFORMEE_SOUND_DIM*/ + SET_FLAG(cur_beamform_cap, GET_VHT_CAPABILITY_ELE_SU_BFER_SOUND_DIM_NUM(pIE->data) << 12); + + } + pvhtpriv->beamform_cap = cur_beamform_cap; + if (cur_beamform_cap) + RTW_INFO("Current VHT Beamforming Setting = %02X\n", cur_beamform_cap); +#endif /* !RTW_BEAMFORMING_VERSION_2 */ +#endif /* CONFIG_BEAMFORMING */ + /* B23 B24 B25 Maximum A-MPDU Length Exponent */ + pvhtpriv->ampdu_len = GET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pIE->data); + + pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pIE->data); + rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); + rtw_vht_nss_to_mcsmap(tx_nss, pvhtpriv->vht_mcs_map, pcap_mcs); + pvhtpriv->vht_highest_rate = rtw_get_vht_highest_rate(pvhtpriv->vht_mcs_map); +} + +void VHT_operation_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; + + if (pIE == NULL) + return; + + if (pvhtpriv->vht_option == _FALSE) + return; +} + +void rtw_process_vht_op_mode_notify(_adapter *padapter, u8 *pframe, PVOID sta) +{ + struct sta_info *psta = (struct sta_info *)sta; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct registry_priv *regsty = adapter_to_regsty(padapter); + u8 target_bw; + u8 target_rxss, current_rxss; + u8 update_ra = _FALSE; + + if (pvhtpriv->vht_option == _FALSE) + return; + + target_bw = GET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(pframe); + target_rxss = (GET_VHT_OPERATING_MODE_FIELD_RX_NSS(pframe) + 1); + + if (target_bw != psta->bw_mode) { + if (hal_is_bw_support(padapter, target_bw) + && REGSTY_IS_BW_5G_SUPPORT(regsty, target_bw) + ) { + update_ra = _TRUE; + psta->bw_mode = target_bw; + } + } + + current_rxss = rtw_vht_mcsmap_to_nss(psta->vhtpriv.vht_mcs_map); + if (target_rxss != current_rxss) { + u8 vht_mcs_map[2] = {}; + + update_ra = _TRUE; + + rtw_vht_nss_to_mcsmap(target_rxss, vht_mcs_map, psta->vhtpriv.vht_mcs_map); + _rtw_memcpy(psta->vhtpriv.vht_mcs_map, vht_mcs_map, 2); + + rtw_hal_update_sta_rate_mask(padapter, psta); + } + + if (update_ra) + rtw_dm_ra_mask_wk_cmd(padapter, (u8 *)psta); +} + +u32 rtw_build_vht_operation_ie(_adapter *padapter, u8 *pbuf, u8 channel) +{ + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; + /* struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; */ + u8 ChnlWidth, center_freq, bw_mode; + u32 len = 0; + u8 operation[5]; + + _rtw_memset(operation, 0, 5); + + bw_mode = REGSTY_BW_5G(pregistrypriv); /* TODO: control op bw with other info */ + + if (hal_chk_bw_cap(padapter, BW_CAP_80M | BW_CAP_160M) + && REGSTY_BW_5G(pregistrypriv) >= CHANNEL_WIDTH_80 + ) { + center_freq = rtw_get_center_ch(channel, bw_mode, HAL_PRIME_CHNL_OFFSET_LOWER); + ChnlWidth = 1; + } else { + center_freq = 0; + ChnlWidth = 0; + } + + + SET_VHT_OPERATION_ELE_CHL_WIDTH(operation, ChnlWidth); + /* center frequency */ + SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ1(operation, center_freq);/* Todo: need to set correct center channel */ + SET_VHT_OPERATION_ELE_CHL_CENTER_FREQ2(operation, 0); + + _rtw_memcpy(operation + 3, pvhtpriv->vht_mcs_map, 2); + + rtw_set_ie(pbuf, EID_VHTOperation, 5, operation, &len); + + return len; +} + +u32 rtw_build_vht_op_mode_notify_ie(_adapter *padapter, u8 *pbuf, u8 bw) +{ + /* struct registry_priv *pregistrypriv = &padapter->registrypriv; */ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; + u32 len = 0; + u8 opmode = 0; + u8 chnl_width, rx_nss; + + chnl_width = bw; + rx_nss = rtw_vht_mcsmap_to_nss(pvhtpriv->vht_mcs_map); + + SET_VHT_OPERATING_MODE_FIELD_CHNL_WIDTH(&opmode, chnl_width); + SET_VHT_OPERATING_MODE_FIELD_RX_NSS(&opmode, (rx_nss - 1)); + SET_VHT_OPERATING_MODE_FIELD_RX_NSS_TYPE(&opmode, 0); /* Todo */ + + pvhtpriv->vht_op_mode_notify = opmode; + + pbuf = rtw_set_ie(pbuf, EID_OpModeNotification, 1, &opmode, &len); + + return len; +} + +u32 rtw_build_vht_cap_ie(_adapter *padapter, u8 *pbuf) +{ + u8 bw, rf_type, rf_num, rx_stbc_nss = 0; + u16 HighestRate; + u8 *pcap, *pcap_mcs; + u32 len = 0; + u32 rx_packet_offset, max_recvbuf_sz; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; + + pcap = pvhtpriv->vht_cap; + _rtw_memset(pcap, 0, 32); + + /* B0 B1 Maximum MPDU Length */ + rtw_hal_get_def_var(padapter, HAL_DEF_RX_PACKET_OFFSET, &rx_packet_offset); + rtw_hal_get_def_var(padapter, HAL_DEF_MAX_RECVBUF_SZ, &max_recvbuf_sz); + + RTW_DBG("%s, line%d, Available RX buf size = %d bytes\n.", __FUNCTION__, __LINE__, max_recvbuf_sz - rx_packet_offset); + + if ((max_recvbuf_sz - rx_packet_offset) >= 11454) { + SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 2); + RTW_INFO("%s, line%d, Set MAX MPDU len = 11454 bytes\n.", __FUNCTION__, __LINE__); + } else if ((max_recvbuf_sz - rx_packet_offset) >= 7991) { + SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 1); + RTW_INFO("%s, line%d, Set MAX MPDU len = 7991 bytes\n.", __FUNCTION__, __LINE__); + } else if ((max_recvbuf_sz - rx_packet_offset) >= 3895) { + SET_VHT_CAPABILITY_ELE_MAX_MPDU_LENGTH(pcap, 0); + RTW_INFO("%s, line%d, Set MAX MPDU len = 3895 bytes\n.", __FUNCTION__, __LINE__); + } else + RTW_ERR("%s, line%d, Error!! Available RX buf size < 3895 bytes\n.", __FUNCTION__, __LINE__); + + /* B2 B3 Supported Channel Width Set */ + if (hal_chk_bw_cap(padapter, BW_CAP_160M) && REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_160)) { + if (hal_chk_bw_cap(padapter, BW_CAP_80_80M) && REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_80_80)) + SET_VHT_CAPABILITY_ELE_CHL_WIDTH(pcap, 2); + else + SET_VHT_CAPABILITY_ELE_CHL_WIDTH(pcap, 1); + } else + SET_VHT_CAPABILITY_ELE_CHL_WIDTH(pcap, 0); + + /* B4 Rx LDPC */ + if (TEST_FLAG(pvhtpriv->ldpc_cap, LDPC_VHT_ENABLE_RX)) { + SET_VHT_CAPABILITY_ELE_RX_LDPC(pcap, 1); + RTW_INFO("[VHT] Declare supporting RX LDPC\n"); + } + + /* B5 ShortGI for 80MHz */ + SET_VHT_CAPABILITY_ELE_SHORT_GI80M(pcap, pvhtpriv->sgi_80m ? 1 : 0); /* We can receive Short GI of 80M */ + if (pvhtpriv->sgi_80m) + RTW_INFO("[VHT] Declare supporting SGI 80MHz\n"); + + /* B6 ShortGI for 160MHz */ + /* SET_VHT_CAPABILITY_ELE_SHORT_GI160M(pcap, pvhtpriv->sgi_80m? 1 : 0); */ + + /* B7 Tx STBC */ + if (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_TX)) { + SET_VHT_CAPABILITY_ELE_TX_STBC(pcap, 1); + RTW_INFO("[VHT] Declare supporting TX STBC\n"); + } + + /* B8 B9 B10 Rx STBC */ + if (TEST_FLAG(pvhtpriv->stbc_cap, STBC_VHT_ENABLE_RX)) { + rtw_hal_get_def_var(padapter, HAL_DEF_RX_STBC, (u8 *)(&rx_stbc_nss)); + + SET_VHT_CAPABILITY_ELE_RX_STBC(pcap, rx_stbc_nss); + RTW_INFO("[VHT] Declare supporting RX STBC = %d\n", rx_stbc_nss); + } + + /* B11 SU Beamformer Capable */ + if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMER_ENABLE)) { + SET_VHT_CAPABILITY_ELE_SU_BFER(pcap, 1); + RTW_INFO("[VHT] Declare supporting SU Bfer\n"); + /* B16 17 18 Number of Sounding Dimensions */ + rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMER_CAP, (u8 *)&rf_num); + SET_VHT_CAPABILITY_ELE_SOUNDING_DIMENSIONS(pcap, rf_num); + /* B19 MU Beamformer Capable */ + if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_AP_ENABLE)) { + SET_VHT_CAPABILITY_ELE_MU_BFER(pcap, 1); + RTW_INFO("[VHT] Declare supporting MU Bfer\n"); + } + } + + /* B12 SU Beamformee Capable */ + if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_BEAMFORMEE_ENABLE)) { + SET_VHT_CAPABILITY_ELE_SU_BFEE(pcap, 1); + RTW_INFO("[VHT] Declare supporting SU Bfee\n"); + /* B13 14 15 Compressed Steering Number of Beamformer Antennas Supported */ + rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMEE_CAP, (u8 *)&rf_num); + SET_VHT_CAPABILITY_ELE_BFER_ANT_SUPP(pcap, rf_num); + /* B20 SU Beamformee Capable */ + if (TEST_FLAG(pvhtpriv->beamform_cap, BEAMFORMING_VHT_MU_MIMO_STA_ENABLE)) { + SET_VHT_CAPABILITY_ELE_MU_BFEE(pcap, 1); + RTW_INFO("[VHT] Declare supporting MU Bfee\n"); + } + } + + /* B21 VHT TXOP PS */ + SET_VHT_CAPABILITY_ELE_TXOP_PS(pcap, 0); + /* B22 +HTC-VHT Capable */ + SET_VHT_CAPABILITY_ELE_HTC_VHT(pcap, 1); + /* B23 24 25 Maximum A-MPDU Length Exponent */ + if (pregistrypriv->ampdu_factor != 0xFE) + SET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pcap, pregistrypriv->ampdu_factor); + else + SET_VHT_CAPABILITY_ELE_MAX_RXAMPDU_FACTOR(pcap, 7); + /* B26 27 VHT Link Adaptation Capable */ + SET_VHT_CAPABILITY_ELE_LINK_ADAPTION(pcap, 0); + + pcap_mcs = GET_VHT_CAPABILITY_ELE_RX_MCS(pcap); + _rtw_memcpy(pcap_mcs, pvhtpriv->vht_mcs_map, 2); + + pcap_mcs = GET_VHT_CAPABILITY_ELE_TX_MCS(pcap); + _rtw_memcpy(pcap_mcs, pvhtpriv->vht_mcs_map, 2); + + /* find the largest bw supported by both registry and hal */ + bw = hal_largest_bw(padapter, REGSTY_BW_5G(pregistrypriv)); + + HighestRate = VHT_MCS_DATA_RATE[bw][pvhtpriv->sgi_80m][((pvhtpriv->vht_highest_rate - MGN_VHT1SS_MCS0) & 0x3f)]; + HighestRate = (HighestRate + 1) >> 1; + + SET_VHT_CAPABILITY_ELE_MCS_RX_HIGHEST_RATE(pcap, HighestRate); /* indicate we support highest rx rate is 600Mbps. */ + SET_VHT_CAPABILITY_ELE_MCS_TX_HIGHEST_RATE(pcap, HighestRate); /* indicate we support highest tx rate is 600Mbps. */ + + pbuf = rtw_set_ie(pbuf, EID_VHTCapability, 12, pcap, &len); + + return len; +} + +u32 rtw_restructure_vht_ie(_adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len) +{ + u32 ielen = 0, out_len = 0; + u8 cap_len = 0, notify_len = 0, notify_bw = 0, operation_bw = 0, supported_chnl_width = 0; + u8 *p, *pframe; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; + + rtw_vht_use_default_setting(padapter); + + p = rtw_get_ie(in_ie + 12, EID_VHTCapability, &ielen, in_len - 12); + if (p && ielen > 0) { + supported_chnl_width = GET_VHT_CAPABILITY_ELE_CHL_WIDTH(p + 2); + + /* VHT Capabilities element */ + cap_len = rtw_build_vht_cap_ie(padapter, out_ie + *pout_len); + *pout_len += cap_len; + + /* Get HT BW */ + p = rtw_get_ie(in_ie + 12, _HT_EXTRA_INFO_IE_, &ielen, in_len - 12); + if (p && ielen > 0) { + struct HT_info_element *pht_info = (struct HT_info_element *)(p + 2); + if (pht_info->infos[0] & BIT(2)) + operation_bw = CHANNEL_WIDTH_40; + else + operation_bw = CHANNEL_WIDTH_20; + } + + /* VHT Operation element */ + p = rtw_get_ie(in_ie + 12, EID_VHTOperation, &ielen, in_len - 12); + if (p && ielen > 0) { + out_len = *pout_len; + if (GET_VHT_OPERATION_ELE_CHL_WIDTH(p + 2) >= 1) { + if (supported_chnl_width == 2) + operation_bw = CHANNEL_WIDTH_80_80; + else if (supported_chnl_width == 1) + operation_bw = CHANNEL_WIDTH_160; + else + operation_bw = CHANNEL_WIDTH_80; + } + pframe = rtw_set_ie(out_ie + out_len, EID_VHTOperation, ielen, p + 2 , pout_len); + } + + /* find the largest bw supported by both registry and hal */ + notify_bw = hal_largest_bw(padapter, REGSTY_BW_5G(pregistrypriv)); + + if (notify_bw > operation_bw) + notify_bw = operation_bw; + + /* Operating Mode Notification element */ + notify_len = rtw_build_vht_op_mode_notify_ie(padapter, out_ie + *pout_len, notify_bw); + *pout_len += notify_len; + + pvhtpriv->vht_option = _TRUE; + } + + return pvhtpriv->vht_option; + +} + +void VHTOnAssocRsp(_adapter *padapter) +{ + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct vht_priv *pvhtpriv = &pmlmepriv->vhtpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 ht_AMPDU_len; + + RTW_INFO("%s\n", __FUNCTION__); + + if (!pmlmeinfo->HT_enable) + return; + + if (!pmlmeinfo->VHT_enable) + return; + + ht_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; + + if (pvhtpriv->ampdu_len > ht_AMPDU_len) + rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&pvhtpriv->ampdu_len)); + + rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MAX_TIME, (u8 *)(&pvhtpriv->vht_highest_rate)); +} + +#endif /* CONFIG_80211AC_VHT */ diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_wapi.c b/linux-bsp/drivers/rtl8188eus/core/rtw_wapi.c new file mode 100644 index 0000000..d23ed26 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_wapi.c @@ -0,0 +1,1240 @@ +#ifdef CONFIG_WAPI_SUPPORT + +#include <linux/unistd.h> +#include <linux/etherdevice.h> +#include <drv_types.h> +#include <rtw_wapi.h> + + +u32 wapi_debug_component = + /* WAPI_INIT | + * WAPI_API | + * WAPI_TX | + * WAPI_RX | */ + WAPI_ERR ; /* always open err flags on */ + +void WapiFreeAllStaInfo(_adapter *padapter) +{ + PRT_WAPI_T pWapiInfo; + PRT_WAPI_STA_INFO pWapiStaInfo; + PRT_WAPI_BKID pWapiBkid; + + WAPI_TRACE(WAPI_INIT, "===========> %s\n", __FUNCTION__); + pWapiInfo = &padapter->wapiInfo; + + /* Pust to Idle List */ + rtw_wapi_return_all_sta_info(padapter); + + /* Sta Info List */ + while (!list_empty(&(pWapiInfo->wapiSTAIdleList))) { + pWapiStaInfo = (PRT_WAPI_STA_INFO)list_entry(pWapiInfo->wapiSTAIdleList.next, RT_WAPI_STA_INFO, list); + list_del_init(&pWapiStaInfo->list); + } + + /* BKID List */ + while (!list_empty(&(pWapiInfo->wapiBKIDIdleList))) { + pWapiBkid = (PRT_WAPI_BKID)list_entry(pWapiInfo->wapiBKIDIdleList.next, RT_WAPI_BKID, list); + list_del_init(&pWapiBkid->list); + } + WAPI_TRACE(WAPI_INIT, "<=========== %s\n", __FUNCTION__); + return; +} + +void WapiSetIE(_adapter *padapter) +{ + PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); + /* PRT_WAPI_BKID pWapiBkid; */ + u16 protocolVer = 1; + u16 akmCnt = 1; + u16 suiteCnt = 1; + u16 capability = 0; + u8 OUI[3]; + + OUI[0] = 0x00; + OUI[1] = 0x14; + OUI[2] = 0x72; + + pWapiInfo->wapiIELength = 0; + /* protocol version */ + memcpy(pWapiInfo->wapiIE + pWapiInfo->wapiIELength, &protocolVer, 2); + pWapiInfo->wapiIELength += 2; + /* akm */ + memcpy(pWapiInfo->wapiIE + pWapiInfo->wapiIELength, &akmCnt, 2); + pWapiInfo->wapiIELength += 2; + + if (pWapiInfo->bWapiPSK) { + memcpy(pWapiInfo->wapiIE + pWapiInfo->wapiIELength, OUI, 3); + pWapiInfo->wapiIELength += 3; + pWapiInfo->wapiIE[pWapiInfo->wapiIELength] = 0x2; + pWapiInfo->wapiIELength += 1; + } else { + memcpy(pWapiInfo->wapiIE + pWapiInfo->wapiIELength, OUI, 3); + pWapiInfo->wapiIELength += 3; + pWapiInfo->wapiIE[pWapiInfo->wapiIELength] = 0x1; + pWapiInfo->wapiIELength += 1; + } + + /* usk */ + memcpy(pWapiInfo->wapiIE + pWapiInfo->wapiIELength, &suiteCnt, 2); + pWapiInfo->wapiIELength += 2; + memcpy(pWapiInfo->wapiIE + pWapiInfo->wapiIELength, OUI, 3); + pWapiInfo->wapiIELength += 3; + pWapiInfo->wapiIE[pWapiInfo->wapiIELength] = 0x1; + pWapiInfo->wapiIELength += 1; + + /* msk */ + memcpy(pWapiInfo->wapiIE + pWapiInfo->wapiIELength, OUI, 3); + pWapiInfo->wapiIELength += 3; + pWapiInfo->wapiIE[pWapiInfo->wapiIELength] = 0x1; + pWapiInfo->wapiIELength += 1; + + /* Capbility */ + memcpy(pWapiInfo->wapiIE + pWapiInfo->wapiIELength, &capability, 2); + pWapiInfo->wapiIELength += 2; +} + + +/* PN1 > PN2, return 1, + * else return 0. + */ +u32 WapiComparePN(u8 *PN1, u8 *PN2) +{ + char i; + + if ((NULL == PN1) || (NULL == PN2)) + return 1; + + /* overflow case */ + if ((PN2[15] - PN1[15]) & 0x80) + return 1; + + for (i = 16; i > 0; i--) { + if (PN1[i - 1] == PN2[i - 1]) + continue; + else if (PN1[i - 1] > PN2[i - 1]) + return 1; + else + return 0; + } + + return 0; +} + +u8 +WapiGetEntryForCamWrite(_adapter *padapter, u8 *pMacAddr, u8 KID, BOOLEAN IsMsk) +{ + PRT_WAPI_T pWapiInfo = NULL; + /* PRT_WAPI_CAM_ENTRY pEntry=NULL; */ + u8 i = 0; + u8 ret = 0xff; + + WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); + + pWapiInfo = &padapter->wapiInfo; + + /* exist? */ + for (i = 0; i < WAPI_CAM_ENTRY_NUM; i++) { + if (pWapiInfo->wapiCamEntry[i].IsUsed + && (_rtw_memcmp(pMacAddr, pWapiInfo->wapiCamEntry[i].PeerMacAddr, ETH_ALEN) == _TRUE) + && pWapiInfo->wapiCamEntry[i].keyidx == KID + && pWapiInfo->wapiCamEntry[i].type == IsMsk) { + ret = pWapiInfo->wapiCamEntry[i].entry_idx; /* cover it */ + break; + } + } + + if (i == WAPI_CAM_ENTRY_NUM) { /* not found */ + for (i = 0; i < WAPI_CAM_ENTRY_NUM; i++) { + if (pWapiInfo->wapiCamEntry[i].IsUsed == 0) { + pWapiInfo->wapiCamEntry[i].IsUsed = 1; + pWapiInfo->wapiCamEntry[i].type = IsMsk; + pWapiInfo->wapiCamEntry[i].keyidx = KID; + _rtw_memcpy(pWapiInfo->wapiCamEntry[i].PeerMacAddr, pMacAddr, ETH_ALEN); + ret = pWapiInfo->wapiCamEntry[i].entry_idx; + break; + } + } + } + + WAPI_TRACE(WAPI_API, "<========== %s\n", __FUNCTION__); + return ret; + + /* + if(RTIsListEmpty(&pWapiInfo->wapiCamIdleList)) { + return 0; + } + + pEntry = (PRT_WAPI_CAM_ENTRY)RTRemoveHeadList(&pWapiInfo->wapiCamIdleList); + RTInsertTailList(&pWapiInfo->wapiCamUsedList, &pEntry->list); + + + return pEntry->entry_idx;*/ +} + +u8 WapiGetEntryForCamClear(_adapter *padapter, u8 *pPeerMac, u8 keyid, u8 IsMsk) +{ + PRT_WAPI_T pWapiInfo = NULL; + u8 i = 0; + + WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); + + pWapiInfo = &padapter->wapiInfo; + + for (i = 0; i < WAPI_CAM_ENTRY_NUM; i++) { + if (pWapiInfo->wapiCamEntry[i].IsUsed + && (_rtw_memcmp(pPeerMac, pWapiInfo->wapiCamEntry[i].PeerMacAddr, ETH_ALEN) == _TRUE) + && pWapiInfo->wapiCamEntry[i].keyidx == keyid + && pWapiInfo->wapiCamEntry[i].type == IsMsk) { + pWapiInfo->wapiCamEntry[i].IsUsed = 0; + pWapiInfo->wapiCamEntry[i].keyidx = 2; + _rtw_memset(pWapiInfo->wapiCamEntry[i].PeerMacAddr, 0, ETH_ALEN); + + WAPI_TRACE(WAPI_API, "<========== %s\n", __FUNCTION__); + return pWapiInfo->wapiCamEntry[i].entry_idx; + } + } + + WAPI_TRACE(WAPI_API, "<====WapiGetReturnCamEntry(), No this cam entry.\n"); + return 0xff; + /* + if(RTIsListEmpty(&pWapiInfo->wapiCamUsedList)) { + return FALSE; + } + + pList = &pWapiInfo->wapiCamUsedList; + while(pList->Flink != &pWapiInfo->wapiCamUsedList) + { + pEntry = (PRT_WAPI_CAM_ENTRY)pList->Flink; + if(PlatformCompareMemory(pPeerMac,pEntry->PeerMacAddr, ETHER_ADDRLEN)== 0 + && keyid == pEntry->keyidx) + { + RTRemoveEntryList(pList); + RTInsertHeadList(&pWapiInfo->wapiCamIdleList, pList); + return pEntry->entry_idx; + } + pList = pList->Flink; + } + + return 0; + */ +} + +void +WapiResetAllCamEntry(_adapter *padapter) +{ + PRT_WAPI_T pWapiInfo; + int i; + + WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); + + pWapiInfo = &padapter->wapiInfo; + + for (i = 0; i < WAPI_CAM_ENTRY_NUM; i++) { + _rtw_memset(pWapiInfo->wapiCamEntry[i].PeerMacAddr, 0, ETH_ALEN); + pWapiInfo->wapiCamEntry[i].IsUsed = 0; + pWapiInfo->wapiCamEntry[i].keyidx = 2; /* invalid */ + pWapiInfo->wapiCamEntry[i].entry_idx = 4 + i * 2; + } + + WAPI_TRACE(WAPI_API, "<========== %s\n", __FUNCTION__); + + return; +} + +u8 WapiWriteOneCamEntry( + _adapter *padapter, + u8 *pMacAddr, + u8 KeyId, + u8 EntryId, + u8 EncAlg, + u8 bGroupKey, + u8 *pKey +) +{ + u8 retVal = 0; + u16 usConfig = 0; + + WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); + + if (EntryId >= 32) { + WAPI_TRACE(WAPI_ERR, "<=== CamAddOneEntry(): ulKeyId exceed!\n"); + return retVal; + } + + usConfig = usConfig | (0x01 << 15) | ((u16)(EncAlg) << 2) | (KeyId); + + if (EncAlg == _SMS4_) { + if (bGroupKey == 1) + usConfig |= (0x01 << 6); + if ((EntryId % 2) == 1) /* ==0 sec key; == 1mic key */ + usConfig |= (0x01 << 5); + } + + write_cam(padapter, EntryId, usConfig, pMacAddr, pKey); + + WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); + return 1; +} + +void rtw_wapi_init(_adapter *padapter) +{ + PRT_WAPI_T pWapiInfo; + int i; + + WAPI_TRACE(WAPI_INIT, "===========> %s\n", __FUNCTION__); + RT_ASSERT_RET(padapter); + + if (!padapter->WapiSupport) { + WAPI_TRACE(WAPI_INIT, "<========== %s, WAPI not supported!\n", __FUNCTION__); + return; + } + + pWapiInfo = &padapter->wapiInfo; + pWapiInfo->bWapiEnable = false; + + /* Init BKID List */ + INIT_LIST_HEAD(&pWapiInfo->wapiBKIDIdleList); + INIT_LIST_HEAD(&pWapiInfo->wapiBKIDStoreList); + for (i = 0; i < WAPI_MAX_BKID_NUM; i++) + list_add_tail(&pWapiInfo->wapiBKID[i].list, &pWapiInfo->wapiBKIDIdleList); + + /* Init STA List */ + INIT_LIST_HEAD(&pWapiInfo->wapiSTAIdleList); + INIT_LIST_HEAD(&pWapiInfo->wapiSTAUsedList); + for (i = 0; i < WAPI_MAX_STAINFO_NUM; i++) + list_add_tail(&pWapiInfo->wapiSta[i].list, &pWapiInfo->wapiSTAIdleList); + + for (i = 0; i < WAPI_CAM_ENTRY_NUM; i++) { + pWapiInfo->wapiCamEntry[i].IsUsed = 0; + pWapiInfo->wapiCamEntry[i].keyidx = 2; /* invalid */ + pWapiInfo->wapiCamEntry[i].entry_idx = 4 + i * 2; + } + + WAPI_TRACE(WAPI_INIT, "<========== %s\n", __FUNCTION__); +} + +void rtw_wapi_free(_adapter *padapter) +{ + WAPI_TRACE(WAPI_INIT, "===========> %s\n", __FUNCTION__); + RT_ASSERT_RET(padapter); + + if (!padapter->WapiSupport) { + WAPI_TRACE(WAPI_INIT, "<========== %s, WAPI not supported!\n", __FUNCTION__); + return; + } + + WapiFreeAllStaInfo(padapter); + + WAPI_TRACE(WAPI_INIT, "<========== %s\n", __FUNCTION__); +} + +void rtw_wapi_disable_tx(_adapter *padapter) +{ + WAPI_TRACE(WAPI_INIT, "===========> %s\n", __FUNCTION__); + RT_ASSERT_RET(padapter); + + if (!padapter->WapiSupport) { + WAPI_TRACE(WAPI_INIT, "<========== %s, WAPI not supported!\n", __FUNCTION__); + return; + } + + padapter->wapiInfo.wapiTxMsk.bTxEnable = false; + padapter->wapiInfo.wapiTxMsk.bSet = false; + + WAPI_TRACE(WAPI_INIT, "<========== %s\n", __FUNCTION__); +} + +u8 rtw_wapi_is_wai_packet(_adapter *padapter, u8 *pkt_data) +{ + PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + PRT_WAPI_STA_INFO pWapiSta = NULL; + u8 WaiPkt = 0, *pTaddr, bFind = false; + u8 Offset_TypeWAI = 0 ; /* (mac header len + llc length) */ + + WAPI_TRACE(WAPI_TX | WAPI_RX, "===========> %s\n", __FUNCTION__); + + if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) { + WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); + return 0; + } + + Offset_TypeWAI = 24 + 6 ; + + /* YJ,add,091103. Data frame may also have skb->data[30]=0x88 and skb->data[31]=0xb4. */ + if ((pkt_data[1] & 0x40) != 0) { + /* RTW_INFO("data is privacy\n"); */ + return 0; + } + + pTaddr = get_addr2_ptr(pkt_data); + if (list_empty(&pWapiInfo->wapiSTAUsedList)) + bFind = false; + else { + list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { + if (_rtw_memcmp(pTaddr, pWapiSta->PeerMacAddr, 6) == _TRUE) { + bFind = true; + break; + } + } + } + + WAPI_TRACE(WAPI_TX | WAPI_RX, "%s: bFind=%d pTaddr="MAC_FMT"\n", __FUNCTION__, bFind, MAC_ARG(pTaddr)); + + if (pkt_data[0] == WIFI_QOS_DATA_TYPE) + Offset_TypeWAI += 2; + + /* 88b4? */ + if ((pkt_data[Offset_TypeWAI] == 0x88) && (pkt_data[Offset_TypeWAI + 1] == 0xb4)) { + WaiPkt = pkt_data[Offset_TypeWAI + 5]; + + psecuritypriv->hw_decrypted = _TRUE; + } else + WAPI_TRACE(WAPI_TX | WAPI_RX, "%s(): non wai packet\n", __FUNCTION__); + + WAPI_TRACE(WAPI_TX | WAPI_RX, "%s(): Recvd WAI frame. IsWAIPkt(%d)\n", __FUNCTION__, WaiPkt); + + return WaiPkt; +} + + +void rtw_wapi_update_info(_adapter *padapter, union recv_frame *precv_frame) +{ + PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); + struct recv_frame_hdr *precv_hdr; + u8 *ptr; + u8 *pTA; + u8 *pRecvPN; + + + WAPI_TRACE(WAPI_RX, "===========> %s\n", __FUNCTION__); + + if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) { + WAPI_TRACE(WAPI_RX, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); + return; + } + + precv_hdr = &precv_frame->u.hdr; + ptr = precv_hdr->rx_data; + + if (precv_hdr->attrib.qos == 1) + precv_hdr->UserPriority = GetTid(ptr); + else + precv_hdr->UserPriority = 0; + + pTA = get_addr2_ptr(ptr); + _rtw_memcpy((u8 *)precv_hdr->WapiSrcAddr, pTA, 6); + pRecvPN = ptr + precv_hdr->attrib.hdrlen + 2; + _rtw_memcpy((u8 *)precv_hdr->WapiTempPN, pRecvPN, 16); + + WAPI_TRACE(WAPI_RX, "<========== %s\n", __FUNCTION__); +} + +/**************************************************************************** +TRUE-----------------Drop +FALSE---------------- handle +add to support WAPI to N-mode +*****************************************************************************/ +u8 rtw_wapi_check_for_drop( + _adapter *padapter, + union recv_frame *precv_frame +) +{ + PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); + u8 *pLastRecvPN = NULL; + u8 bFind = false; + PRT_WAPI_STA_INFO pWapiSta = NULL; + u8 bDrop = false; + struct recv_frame_hdr *precv_hdr = &precv_frame->u.hdr; + u8 WapiAEPNInitialValueSrc[16] = {0x37, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ; + u8 WapiAEMultiCastPNInitialValueSrc[16] = {0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ; + u8 *ptr = precv_frame->u.hdr.rx_data; + int i; + + WAPI_TRACE(WAPI_RX, "===========> %s\n", __FUNCTION__); + + if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) { + WAPI_TRACE(WAPI_RX, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); + return false; + } + + if (precv_hdr->bIsWaiPacket != 0) { + if (precv_hdr->bIsWaiPacket == 0x8) { + + RTW_INFO("rtw_wapi_check_for_drop: dump packet\n"); + for (i = 0; i < 50; i++) { + RTW_INFO("%02X ", ptr[i]); + if ((i + 1) % 8 == 0) + RTW_INFO("\n"); + } + RTW_INFO("\n rtw_wapi_check_for_drop: dump packet\n"); + + for (i = 0; i < 16; i++) { + if (ptr[i + 27] != 0) + break; + } + + if (i == 16) { + WAPI_TRACE(WAPI_RX, "rtw_wapi_check_for_drop: drop with zero BKID\n"); + return true; + } else + return false; + } else + return false; + } + + if (list_empty(&pWapiInfo->wapiSTAUsedList)) + bFind = false; + else { + list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { + if (_rtw_memcmp(precv_hdr->WapiSrcAddr, pWapiSta->PeerMacAddr, ETH_ALEN) == _TRUE) { + bFind = true; + break; + } + } + } + WAPI_TRACE(WAPI_RX, "%s: bFind=%d prxb->WapiSrcAddr="MAC_FMT"\n", __FUNCTION__, bFind, MAC_ARG(precv_hdr->WapiSrcAddr)); + + if (bFind) { + if (IS_MCAST(precv_hdr->attrib.ra)) { + WAPI_TRACE(WAPI_RX, "rtw_wapi_check_for_drop: multicast case\n"); + pLastRecvPN = pWapiSta->lastRxMulticastPN; + } else { + WAPI_TRACE(WAPI_RX, "rtw_wapi_check_for_drop: unicast case\n"); + switch (precv_hdr->UserPriority) { + case 0: + case 3: + pLastRecvPN = pWapiSta->lastRxUnicastPNBEQueue; + break; + case 1: + case 2: + pLastRecvPN = pWapiSta->lastRxUnicastPNBKQueue; + break; + case 4: + case 5: + pLastRecvPN = pWapiSta->lastRxUnicastPNVIQueue; + break; + case 6: + case 7: + pLastRecvPN = pWapiSta->lastRxUnicastPNVOQueue; + break; + default: + WAPI_TRACE(WAPI_ERR, "%s: Unknown TID\n", __FUNCTION__); + break; + } + } + + if (!WapiComparePN(precv_hdr->WapiTempPN, pLastRecvPN)) { + WAPI_TRACE(WAPI_RX, "%s: Equal PN!!\n", __FUNCTION__); + if (IS_MCAST(precv_hdr->attrib.ra)) + _rtw_memcpy(pLastRecvPN, WapiAEMultiCastPNInitialValueSrc, 16); + else + _rtw_memcpy(pLastRecvPN, WapiAEPNInitialValueSrc, 16); + bDrop = true; + } else + _rtw_memcpy(pLastRecvPN, precv_hdr->WapiTempPN, 16); + } + + WAPI_TRACE(WAPI_RX, "<========== %s\n", __FUNCTION__); + return bDrop; +} + +void rtw_build_probe_resp_wapi_ie(_adapter *padapter, unsigned char *pframe, struct pkt_attrib *pattrib) +{ + PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); + u8 WapiIELength = 0; + + WAPI_TRACE(WAPI_MLME, "===========> %s\n", __FUNCTION__); + + if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) { + WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported!\n", __FUNCTION__); + return; + } + + WapiSetIE(padapter); + WapiIELength = pWapiInfo->wapiIELength; + pframe[0] = _WAPI_IE_; + pframe[1] = WapiIELength; + _rtw_memcpy(pframe + 2, pWapiInfo->wapiIE, WapiIELength); + pframe += WapiIELength + 2; + pattrib->pktlen += WapiIELength + 2; + + WAPI_TRACE(WAPI_MLME, "<========== %s\n", __FUNCTION__); +} + +void rtw_build_beacon_wapi_ie(_adapter *padapter, unsigned char *pframe, struct pkt_attrib *pattrib) +{ + PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); + u8 WapiIELength = 0; + WAPI_TRACE(WAPI_MLME, "===========> %s\n", __FUNCTION__); + + if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) { + WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported!\n", __FUNCTION__); + return; + } + + WapiSetIE(padapter); + WapiIELength = pWapiInfo->wapiIELength; + pframe[0] = _WAPI_IE_; + pframe[1] = WapiIELength; + _rtw_memcpy(pframe + 2, pWapiInfo->wapiIE, WapiIELength); + pframe += WapiIELength + 2; + pattrib->pktlen += WapiIELength + 2; + + WAPI_TRACE(WAPI_MLME, "<========== %s\n", __FUNCTION__); +} + +void rtw_build_assoc_req_wapi_ie(_adapter *padapter, unsigned char *pframe, struct pkt_attrib *pattrib) +{ + PRT_WAPI_BKID pWapiBKID; + u16 bkidNum; + PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); + u8 WapiIELength = 0; + + WAPI_TRACE(WAPI_MLME, "===========> %s\n", __FUNCTION__); + + if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) { + WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported!\n", __FUNCTION__); + return; + } + + WapiSetIE(padapter); + WapiIELength = pWapiInfo->wapiIELength; + bkidNum = 0; + if (!list_empty(&(pWapiInfo->wapiBKIDStoreList))) { + list_for_each_entry(pWapiBKID, &pWapiInfo->wapiBKIDStoreList, list) { + bkidNum++; + _rtw_memcpy(pWapiInfo->wapiIE + WapiIELength + 2, pWapiBKID->bkid, 16); + WapiIELength += 16; + } + } + _rtw_memcpy(pWapiInfo->wapiIE + WapiIELength, &bkidNum, 2); + WapiIELength += 2; + + pframe[0] = _WAPI_IE_; + pframe[1] = WapiIELength; + _rtw_memcpy(pframe + 2, pWapiInfo->wapiIE, WapiIELength); + pframe += WapiIELength + 2; + pattrib->pktlen += WapiIELength + 2; + WAPI_TRACE(WAPI_MLME, "<========== %s\n", __FUNCTION__); +} + +void rtw_wapi_on_assoc_ok(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) +{ + PRT_WAPI_T pWapiInfo = &(padapter->wapiInfo); + PRT_WAPI_STA_INFO pWapiSta; + u8 WapiAEPNInitialValueSrc[16] = {0x37, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ; + /* u8 WapiASUEPNInitialValueSrc[16] = {0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ; */ + u8 WapiAEMultiCastPNInitialValueSrc[16] = {0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ; + + WAPI_TRACE(WAPI_MLME, "===========> %s\n", __FUNCTION__); + + if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) { + WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); + return; + } + + pWapiSta = (PRT_WAPI_STA_INFO)list_entry(pWapiInfo->wapiSTAIdleList.next, RT_WAPI_STA_INFO, list); + list_del_init(&pWapiSta->list); + list_add_tail(&pWapiSta->list, &pWapiInfo->wapiSTAUsedList); + _rtw_memcpy(pWapiSta->PeerMacAddr, padapter->mlmeextpriv.mlmext_info.network.MacAddress, 6); + _rtw_memcpy(pWapiSta->lastRxMulticastPN, WapiAEMultiCastPNInitialValueSrc, 16); + _rtw_memcpy(pWapiSta->lastRxUnicastPN, WapiAEPNInitialValueSrc, 16); + + /* For chenk PN error with Qos Data after s3: add by ylb 20111114 */ + _rtw_memcpy(pWapiSta->lastRxUnicastPNBEQueue, WapiAEPNInitialValueSrc, 16); + _rtw_memcpy(pWapiSta->lastRxUnicastPNBKQueue, WapiAEPNInitialValueSrc, 16); + _rtw_memcpy(pWapiSta->lastRxUnicastPNVIQueue, WapiAEPNInitialValueSrc, 16); + _rtw_memcpy(pWapiSta->lastRxUnicastPNVOQueue, WapiAEPNInitialValueSrc, 16); + + WAPI_TRACE(WAPI_MLME, "<========== %s\n", __FUNCTION__); +} + + +void rtw_wapi_return_one_sta_info(_adapter *padapter, u8 *MacAddr) +{ + PRT_WAPI_T pWapiInfo; + PRT_WAPI_STA_INFO pWapiStaInfo = NULL; + PRT_WAPI_BKID pWapiBkid = NULL; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + pWapiInfo = &padapter->wapiInfo; + + WAPI_TRACE(WAPI_API, "==========> %s\n", __FUNCTION__); + + if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) { + WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); + return; + } + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + while (!list_empty(&(pWapiInfo->wapiBKIDStoreList))) { + pWapiBkid = (PRT_WAPI_BKID)list_entry(pWapiInfo->wapiBKIDStoreList.next, RT_WAPI_BKID, list); + list_del_init(&pWapiBkid->list); + _rtw_memset(pWapiBkid->bkid, 0, 16); + list_add_tail(&pWapiBkid->list, &pWapiInfo->wapiBKIDIdleList); + } + } + + + WAPI_TRACE(WAPI_API, " %s: after clear bkid\n", __FUNCTION__); + + + /* Remove STA info */ + if (list_empty(&(pWapiInfo->wapiSTAUsedList))) { + WAPI_TRACE(WAPI_API, " %s: wapiSTAUsedList is null\n", __FUNCTION__); + return; + } else { + + WAPI_TRACE(WAPI_API, " %s: wapiSTAUsedList is not null\n", __FUNCTION__); +#if 0 + pWapiStaInfo = (PRT_WAPI_STA_INFO)list_entry((pWapiInfo->wapiSTAUsedList.next), RT_WAPI_STA_INFO, list); + + list_for_each_entry(pWapiStaInfo, &(pWapiInfo->wapiSTAUsedList), list) { + + RTW_INFO("MAC Addr %02x-%02x-%02x-%02x-%02x-%02x\n", MacAddr[0], MacAddr[1], MacAddr[2], MacAddr[3], MacAddr[4], MacAddr[5]); + + + RTW_INFO("peer Addr %02x-%02x-%02x-%02x-%02x-%02x\n", pWapiStaInfo->PeerMacAddr[0], pWapiStaInfo->PeerMacAddr[1], pWapiStaInfo->PeerMacAddr[2], pWapiStaInfo->PeerMacAddr[3], + pWapiStaInfo->PeerMacAddr[4], pWapiStaInfo->PeerMacAddr[5]); + + if (pWapiStaInfo == NULL) { + WAPI_TRACE(WAPI_API, " %s: pWapiStaInfo == NULL Case\n", __FUNCTION__); + return; + } + + if (pWapiStaInfo->PeerMacAddr == NULL) { + WAPI_TRACE(WAPI_API, " %s: pWapiStaInfo->PeerMacAddr == NULL Case\n", __FUNCTION__); + return; + } + + if (MacAddr == NULL) { + WAPI_TRACE(WAPI_API, " %s: MacAddr == NULL Case\n", __FUNCTION__); + return; + } + + if (_rtw_memcmp(pWapiStaInfo->PeerMacAddr, MacAddr, ETH_ALEN) == _TRUE) { + pWapiStaInfo->bAuthenticateInProgress = false; + pWapiStaInfo->bSetkeyOk = false; + _rtw_memset(pWapiStaInfo->PeerMacAddr, 0, ETH_ALEN); + list_del_init(&pWapiStaInfo->list); + list_add_tail(&pWapiStaInfo->list, &pWapiInfo->wapiSTAIdleList); + break; + } + + } +#endif + + while (!list_empty(&(pWapiInfo->wapiSTAUsedList))) { + pWapiStaInfo = (PRT_WAPI_STA_INFO)list_entry(pWapiInfo->wapiSTAUsedList.next, RT_WAPI_STA_INFO, list); + + RTW_INFO("peer Addr %02x-%02x-%02x-%02x-%02x-%02x\n", pWapiStaInfo->PeerMacAddr[0], pWapiStaInfo->PeerMacAddr[1], pWapiStaInfo->PeerMacAddr[2], pWapiStaInfo->PeerMacAddr[3], + pWapiStaInfo->PeerMacAddr[4], pWapiStaInfo->PeerMacAddr[5]); + + list_del_init(&pWapiStaInfo->list); + memset(pWapiStaInfo->PeerMacAddr, 0, ETH_ALEN); + pWapiStaInfo->bSetkeyOk = 0; + list_add_tail(&pWapiStaInfo->list, &pWapiInfo->wapiSTAIdleList); + } + + } + + WAPI_TRACE(WAPI_API, "<========== %s\n", __FUNCTION__); + return; +} + +void rtw_wapi_return_all_sta_info(_adapter *padapter) +{ + PRT_WAPI_T pWapiInfo; + PRT_WAPI_STA_INFO pWapiStaInfo; + PRT_WAPI_BKID pWapiBkid; + WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); + + pWapiInfo = &padapter->wapiInfo; + + if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) { + WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); + return; + } + + /* Sta Info List */ + while (!list_empty(&(pWapiInfo->wapiSTAUsedList))) { + pWapiStaInfo = (PRT_WAPI_STA_INFO)list_entry(pWapiInfo->wapiSTAUsedList.next, RT_WAPI_STA_INFO, list); + list_del_init(&pWapiStaInfo->list); + memset(pWapiStaInfo->PeerMacAddr, 0, ETH_ALEN); + pWapiStaInfo->bSetkeyOk = 0; + list_add_tail(&pWapiStaInfo->list, &pWapiInfo->wapiSTAIdleList); + } + + /* BKID List */ + while (!list_empty(&(pWapiInfo->wapiBKIDStoreList))) { + pWapiBkid = (PRT_WAPI_BKID)list_entry(pWapiInfo->wapiBKIDStoreList.next, RT_WAPI_BKID, list); + list_del_init(&pWapiBkid->list); + memset(pWapiBkid->bkid, 0, 16); + list_add_tail(&pWapiBkid->list, &pWapiInfo->wapiBKIDIdleList); + } + WAPI_TRACE(WAPI_API, "<========== %s\n", __FUNCTION__); +} + +void rtw_wapi_clear_cam_entry(_adapter *padapter, u8 *pMacAddr) +{ + u8 UcIndex = 0; + + WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); + + if ((!padapter->WapiSupport) || (!padapter->wapiInfo.bWapiEnable)) { + WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); + return; + } + + UcIndex = WapiGetEntryForCamClear(padapter, pMacAddr, 0, 0); + if (UcIndex != 0xff) { + /* CAM_mark_invalid(Adapter, UcIndex); */ + CAM_empty_entry(padapter, UcIndex); + } + + UcIndex = WapiGetEntryForCamClear(padapter, pMacAddr, 1, 0); + if (UcIndex != 0xff) { + /* CAM_mark_invalid(Adapter, UcIndex); */ + CAM_empty_entry(padapter, UcIndex); + } + + UcIndex = WapiGetEntryForCamClear(padapter, pMacAddr, 0, 1); + if (UcIndex != 0xff) { + /* CAM_mark_invalid(Adapter, UcIndex); */ + CAM_empty_entry(padapter, UcIndex); + } + + UcIndex = WapiGetEntryForCamClear(padapter, pMacAddr, 1, 1); + if (UcIndex != 0xff) { + /* CAM_mark_invalid(padapter, UcIndex); */ + CAM_empty_entry(padapter, UcIndex); + } + + WAPI_TRACE(WAPI_API, "<========== %s\n", __FUNCTION__); +} + +void rtw_wapi_clear_all_cam_entry(_adapter *padapter) +{ + WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); + + if ((!padapter->WapiSupport) || (!padapter->wapiInfo.bWapiEnable)) { + WAPI_TRACE(WAPI_MLME, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); + return; + } + + invalidate_cam_all(padapter); /* is this ok? */ + WapiResetAllCamEntry(padapter); + + WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); +} + +void rtw_wapi_set_key(_adapter *padapter, RT_WAPI_KEY *pWapiKey, RT_WAPI_STA_INFO *pWapiSta, u8 bGroupKey, u8 bUseDefaultKey) +{ + PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; + u8 *pMacAddr = pWapiSta->PeerMacAddr; + u32 EntryId = 0; + BOOLEAN IsPairWise = false ; + u8 EncAlgo; + + WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); + + if ((!padapter->WapiSupport) || (!padapter->wapiInfo.bWapiEnable)) { + WAPI_TRACE(WAPI_API, "<========== %s, WAPI not supported or not enabled!\n", __FUNCTION__); + return; + } + + EncAlgo = _SMS4_; + + /* For Tx bc/mc pkt,use defualt key entry */ + if (bUseDefaultKey) { + /* when WAPI update key, keyid will be 0 or 1 by turns. */ + if (pWapiKey->keyId == 0) + EntryId = 0; + else + EntryId = 2; + } else { + /* tx/rx unicast pkt, or rx broadcast, find the key entry by peer's MacAddr */ + EntryId = WapiGetEntryForCamWrite(padapter, pMacAddr, pWapiKey->keyId, bGroupKey); + } + + if (EntryId == 0xff) { + WAPI_TRACE(WAPI_API, "===>No entry for WAPI setkey! !!\n"); + return; + } + + /* EntryId is also used to diff Sec key and Mic key */ + /* Sec Key */ + WapiWriteOneCamEntry(padapter, + pMacAddr, + pWapiKey->keyId, /* keyid */ + EntryId, /* entry */ + EncAlgo, /* type */ + bGroupKey, /* pairwise or group key */ + pWapiKey->dataKey); + /* MIC key */ + WapiWriteOneCamEntry(padapter, + pMacAddr, + pWapiKey->keyId, /* keyid */ + EntryId + 1, /* entry */ + EncAlgo, /* type */ + bGroupKey, /* pairwise or group key */ + pWapiKey->micKey); + + WAPI_TRACE(WAPI_API, "Set Wapi Key :KeyId:%d,EntryId:%d,PairwiseKey:%d.\n", pWapiKey->keyId, EntryId, !bGroupKey); + WAPI_TRACE(WAPI_API, "===========> %s\n", __FUNCTION__); + +} + +#if 0 +/* YJ,test,091013 */ +void wapi_test_set_key(struct _adapter *padapter, u8 *buf) +{ + /*Data: keyType(1) + bTxEnable(1) + bAuthenticator(1) + bUpdate(1) + PeerAddr(6) + DataKey(16) + MicKey(16) + KeyId(1)*/ + PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; + PRT_WAPI_BKID pWapiBkid; + PRT_WAPI_STA_INFO pWapiSta; + u8 data[43]; + bool bTxEnable; + bool bUpdate; + bool bAuthenticator; + u8 PeerAddr[6]; + u8 WapiAEPNInitialValueSrc[16] = {0x37, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ; + u8 WapiASUEPNInitialValueSrc[16] = {0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ; + u8 WapiAEMultiCastPNInitialValueSrc[16] = {0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C, 0x36, 0x5C} ; + + WAPI_TRACE(WAPI_INIT, "===========>%s\n", __FUNCTION__); + + if (!padapter->WapiSupport) + return; + + copy_from_user(data, buf, 43); + bTxEnable = data[1]; + bAuthenticator = data[2]; + bUpdate = data[3]; + memcpy(PeerAddr, data + 4, 6); + + if (data[0] == 0x3) { + if (!list_empty(&(pWapiInfo->wapiBKIDIdleList))) { + pWapiBkid = (PRT_WAPI_BKID)list_entry(pWapiInfo->wapiBKIDIdleList.next, RT_WAPI_BKID, list); + list_del_init(&pWapiBkid->list); + memcpy(pWapiBkid->bkid, data + 10, 16); + WAPI_DATA(WAPI_INIT, "SetKey - BKID", pWapiBkid->bkid, 16); + list_add_tail(&pWapiBkid->list, &pWapiInfo->wapiBKIDStoreList); + } + } else { + list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { + if (!memcmp(pWapiSta->PeerMacAddr, PeerAddr, 6)) { + pWapiSta->bAuthenticatorInUpdata = false; + switch (data[0]) { + case 1: /* usk */ + if (bAuthenticator) { /* authenticator */ + memcpy(pWapiSta->lastTxUnicastPN, WapiAEPNInitialValueSrc, 16); + if (!bUpdate) { /* first */ + WAPI_TRACE(WAPI_INIT, "AE fisrt set usk\n"); + pWapiSta->wapiUsk.bSet = true; + memcpy(pWapiSta->wapiUsk.dataKey, data + 10, 16); + memcpy(pWapiSta->wapiUsk.micKey, data + 26, 16); + pWapiSta->wapiUsk.keyId = *(data + 42); + pWapiSta->wapiUsk.bTxEnable = true; + WAPI_DATA(WAPI_INIT, "SetKey - AE USK Data Key", pWapiSta->wapiUsk.dataKey, 16); + WAPI_DATA(WAPI_INIT, "SetKey - AE USK Mic Key", pWapiSta->wapiUsk.micKey, 16); + } else { /* update */ + WAPI_TRACE(WAPI_INIT, "AE update usk\n"); + pWapiSta->wapiUskUpdate.bSet = true; + pWapiSta->bAuthenticatorInUpdata = true; + memcpy(pWapiSta->wapiUskUpdate.dataKey, data + 10, 16); + memcpy(pWapiSta->wapiUskUpdate.micKey, data + 26, 16); + memcpy(pWapiSta->lastRxUnicastPNBEQueue, WapiASUEPNInitialValueSrc, 16); + memcpy(pWapiSta->lastRxUnicastPNBKQueue, WapiASUEPNInitialValueSrc, 16); + memcpy(pWapiSta->lastRxUnicastPNVIQueue, WapiASUEPNInitialValueSrc, 16); + memcpy(pWapiSta->lastRxUnicastPNVOQueue, WapiASUEPNInitialValueSrc, 16); + memcpy(pWapiSta->lastRxUnicastPN, WapiASUEPNInitialValueSrc, 16); + pWapiSta->wapiUskUpdate.keyId = *(data + 42); + pWapiSta->wapiUskUpdate.bTxEnable = true; + } + } else { + if (!bUpdate) { + WAPI_TRACE(WAPI_INIT, "ASUE fisrt set usk\n"); + if (bTxEnable) { + pWapiSta->wapiUsk.bTxEnable = true; + memcpy(pWapiSta->lastTxUnicastPN, WapiASUEPNInitialValueSrc, 16); + } else { + pWapiSta->wapiUsk.bSet = true; + memcpy(pWapiSta->wapiUsk.dataKey, data + 10, 16); + memcpy(pWapiSta->wapiUsk.micKey, data + 26, 16); + pWapiSta->wapiUsk.keyId = *(data + 42); + pWapiSta->wapiUsk.bTxEnable = false; + } + } else { + WAPI_TRACE(WAPI_INIT, "ASUE update usk\n"); + if (bTxEnable) { + pWapiSta->wapiUskUpdate.bTxEnable = true; + if (pWapiSta->wapiUskUpdate.bSet) { + memcpy(pWapiSta->wapiUsk.dataKey, pWapiSta->wapiUskUpdate.dataKey, 16); + memcpy(pWapiSta->wapiUsk.micKey, pWapiSta->wapiUskUpdate.micKey, 16); + pWapiSta->wapiUsk.keyId = pWapiSta->wapiUskUpdate.keyId; + memcpy(pWapiSta->lastRxUnicastPNBEQueue, WapiASUEPNInitialValueSrc, 16); + memcpy(pWapiSta->lastRxUnicastPNBKQueue, WapiASUEPNInitialValueSrc, 16); + memcpy(pWapiSta->lastRxUnicastPNVIQueue, WapiASUEPNInitialValueSrc, 16); + memcpy(pWapiSta->lastRxUnicastPNVOQueue, WapiASUEPNInitialValueSrc, 16); + memcpy(pWapiSta->lastRxUnicastPN, WapiASUEPNInitialValueSrc, 16); + pWapiSta->wapiUskUpdate.bTxEnable = false; + pWapiSta->wapiUskUpdate.bSet = false; + } + memcpy(pWapiSta->lastTxUnicastPN, WapiASUEPNInitialValueSrc, 16); + } else { + pWapiSta->wapiUskUpdate.bSet = true; + memcpy(pWapiSta->wapiUskUpdate.dataKey, data + 10, 16); + memcpy(pWapiSta->wapiUskUpdate.micKey, data + 26, 16); + pWapiSta->wapiUskUpdate.keyId = *(data + 42); + pWapiSta->wapiUskUpdate.bTxEnable = false; + } + } + } + break; + case 2: /* msk */ + if (bAuthenticator) { /* authenticator */ + pWapiInfo->wapiTxMsk.bSet = true; + memcpy(pWapiInfo->wapiTxMsk.dataKey, data + 10, 16); + memcpy(pWapiInfo->wapiTxMsk.micKey, data + 26, 16); + pWapiInfo->wapiTxMsk.keyId = *(data + 42); + pWapiInfo->wapiTxMsk.bTxEnable = true; + memcpy(pWapiInfo->lastTxMulticastPN, WapiAEMultiCastPNInitialValueSrc, 16); + + if (!bUpdate) { /* first */ + WAPI_TRACE(WAPI_INIT, "AE fisrt set msk\n"); + if (!pWapiSta->bSetkeyOk) + pWapiSta->bSetkeyOk = true; + pWapiInfo->bFirstAuthentiateInProgress = false; + } else /* update */ + WAPI_TRACE(WAPI_INIT, "AE update msk\n"); + + WAPI_DATA(WAPI_INIT, "SetKey - AE MSK Data Key", pWapiInfo->wapiTxMsk.dataKey, 16); + WAPI_DATA(WAPI_INIT, "SetKey - AE MSK Mic Key", pWapiInfo->wapiTxMsk.micKey, 16); + } else { + if (!bUpdate) { + WAPI_TRACE(WAPI_INIT, "ASUE fisrt set msk\n"); + pWapiSta->wapiMsk.bSet = true; + memcpy(pWapiSta->wapiMsk.dataKey, data + 10, 16); + memcpy(pWapiSta->wapiMsk.micKey, data + 26, 16); + pWapiSta->wapiMsk.keyId = *(data + 42); + pWapiSta->wapiMsk.bTxEnable = false; + if (!pWapiSta->bSetkeyOk) + pWapiSta->bSetkeyOk = true; + pWapiInfo->bFirstAuthentiateInProgress = false; + WAPI_DATA(WAPI_INIT, "SetKey - ASUE MSK Data Key", pWapiSta->wapiMsk.dataKey, 16); + WAPI_DATA(WAPI_INIT, "SetKey - ASUE MSK Mic Key", pWapiSta->wapiMsk.micKey, 16); + } else { + WAPI_TRACE(WAPI_INIT, "ASUE update msk\n"); + pWapiSta->wapiMskUpdate.bSet = true; + memcpy(pWapiSta->wapiMskUpdate.dataKey, data + 10, 16); + memcpy(pWapiSta->wapiMskUpdate.micKey, data + 26, 16); + pWapiSta->wapiMskUpdate.keyId = *(data + 42); + pWapiSta->wapiMskUpdate.bTxEnable = false; + } + } + break; + default: + WAPI_TRACE(WAPI_ERR, "Unknown Flag\n"); + break; + } + } + } + } + WAPI_TRACE(WAPI_INIT, "<===========%s\n", __FUNCTION__); +} + + +void wapi_test_init(struct _adapter *padapter) +{ + u8 keybuf[100]; + u8 mac_addr[6] = {0x00, 0xe0, 0x4c, 0x72, 0x04, 0x70}; + u8 UskDataKey[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + u8 UskMicKey[16] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; + u8 UskId = 0; + u8 MskDataKey[16] = {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}; + u8 MskMicKey[16] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}; + u8 MskId = 0; + + WAPI_TRACE(WAPI_INIT, "===========>%s\n", __FUNCTION__); + + /* Enable Wapi */ + WAPI_TRACE(WAPI_INIT, "%s: Enable wapi!!!!\n", __FUNCTION__); + padapter->wapiInfo.bWapiEnable = true; + padapter->pairwise_key_type = KEY_TYPE_SMS4; + ieee->group_key_type = KEY_TYPE_SMS4; + padapter->wapiInfo.extra_prefix_len = WAPI_EXT_LEN; + padapter->wapiInfo.extra_postfix_len = SMS4_MIC_LEN; + + /* set usk */ + WAPI_TRACE(WAPI_INIT, "%s: Set USK!!!!\n", __FUNCTION__); + memset(keybuf, 0, 100); + keybuf[0] = 1; /* set usk */ + keybuf[1] = 1; /* enable tx */ + keybuf[2] = 1; /* AE */ + keybuf[3] = 0; /* not update */ + + memcpy(keybuf + 4, mac_addr, 6); + memcpy(keybuf + 10, UskDataKey, 16); + memcpy(keybuf + 26, UskMicKey, 16); + keybuf[42] = UskId; + wapi_test_set_key(padapter, keybuf); + + memset(keybuf, 0, 100); + keybuf[0] = 1; /* set usk */ + keybuf[1] = 1; /* enable tx */ + keybuf[2] = 0; /* AE */ + keybuf[3] = 0; /* not update */ + + memcpy(keybuf + 4, mac_addr, 6); + memcpy(keybuf + 10, UskDataKey, 16); + memcpy(keybuf + 26, UskMicKey, 16); + keybuf[42] = UskId; + wapi_test_set_key(padapter, keybuf); + + /* set msk */ + WAPI_TRACE(WAPI_INIT, "%s: Set MSK!!!!\n", __FUNCTION__); + memset(keybuf, 0, 100); + keybuf[0] = 2; /* set msk */ + keybuf[1] = 1; /* Enable TX */ + keybuf[2] = 1; /* AE */ + keybuf[3] = 0; /* not update */ + memcpy(keybuf + 4, mac_addr, 6); + memcpy(keybuf + 10, MskDataKey, 16); + memcpy(keybuf + 26, MskMicKey, 16); + keybuf[42] = MskId; + wapi_test_set_key(padapter, keybuf); + + memset(keybuf, 0, 100); + keybuf[0] = 2; /* set msk */ + keybuf[1] = 1; /* Enable TX */ + keybuf[2] = 0; /* AE */ + keybuf[3] = 0; /* not update */ + memcpy(keybuf + 4, mac_addr, 6); + memcpy(keybuf + 10, MskDataKey, 16); + memcpy(keybuf + 26, MskMicKey, 16); + keybuf[42] = MskId; + wapi_test_set_key(padapter, keybuf); + WAPI_TRACE(WAPI_INIT, "<===========%s\n", __FUNCTION__); +} +#endif + +void rtw_wapi_get_iv(_adapter *padapter, u8 *pRA, u8 *IV) +{ + PWLAN_HEADER_WAPI_EXTENSION pWapiExt = NULL; + PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; + bool bPNOverflow = false; + bool bFindMatchPeer = false; + PRT_WAPI_STA_INFO pWapiSta = NULL; + + pWapiExt = (PWLAN_HEADER_WAPI_EXTENSION)IV; + + WAPI_DATA(WAPI_RX, "wapi_get_iv: pra", pRA, 6); + + if (IS_MCAST(pRA)) { + if (!pWapiInfo->wapiTxMsk.bTxEnable) { + WAPI_TRACE(WAPI_ERR, "%s: bTxEnable = 0!!\n", __FUNCTION__); + return; + } + + if (pWapiInfo->wapiTxMsk.keyId <= 1) { + pWapiExt->KeyIdx = pWapiInfo->wapiTxMsk.keyId; + pWapiExt->Reserved = 0; + bPNOverflow = WapiIncreasePN(pWapiInfo->lastTxMulticastPN, 1); + memcpy(pWapiExt->PN, pWapiInfo->lastTxMulticastPN, 16); + } + } else { + if (list_empty(&pWapiInfo->wapiSTAUsedList)) { + WAPI_TRACE(WAPI_RX, "rtw_wapi_get_iv: list is empty\n"); + _rtw_memset(IV, 10, 18); + return; + } else { + list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { + WAPI_DATA(WAPI_RX, "rtw_wapi_get_iv: peermacaddr ", pWapiSta->PeerMacAddr, 6); + if (_rtw_memcmp((u8 *)pWapiSta->PeerMacAddr, pRA, 6) == _TRUE) { + bFindMatchPeer = true; + break; + } + } + + WAPI_TRACE(WAPI_RX, "bFindMatchPeer: %d\n", bFindMatchPeer); + WAPI_DATA(WAPI_RX, "Addr", pRA, 6); + + if (bFindMatchPeer) { + if ((!pWapiSta->wapiUskUpdate.bTxEnable) && (!pWapiSta->wapiUsk.bTxEnable)) + return; + + if (pWapiSta->wapiUsk.keyId <= 1) { + if (pWapiSta->wapiUskUpdate.bTxEnable) + pWapiExt->KeyIdx = pWapiSta->wapiUskUpdate.keyId; + else + pWapiExt->KeyIdx = pWapiSta->wapiUsk.keyId; + + pWapiExt->Reserved = 0; + bPNOverflow = WapiIncreasePN(pWapiSta->lastTxUnicastPN, 2); + _rtw_memcpy(pWapiExt->PN, pWapiSta->lastTxUnicastPN, 16); + + } + } + } + + } + +} + +bool rtw_wapi_drop_for_key_absent(_adapter *padapter, u8 *pRA) +{ + PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; + bool bFindMatchPeer = false; + bool bDrop = false; + PRT_WAPI_STA_INFO pWapiSta = NULL; + struct security_priv *psecuritypriv = &padapter->securitypriv; + + WAPI_DATA(WAPI_RX, "rtw_wapi_drop_for_key_absent: ra ", pRA, 6); + + if (psecuritypriv->dot11PrivacyAlgrthm == _SMS4_) { + if ((!padapter->WapiSupport) || (!pWapiInfo->bWapiEnable)) + return true; + + if (IS_MCAST(pRA)) { + if (!pWapiInfo->wapiTxMsk.bTxEnable) { + bDrop = true; + WAPI_TRACE(WAPI_RX, "rtw_wapi_drop_for_key_absent: multicast key is absent\n"); + return bDrop; + } + } else { + if (!list_empty(&pWapiInfo->wapiSTAUsedList)) { + list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { + WAPI_DATA(WAPI_RX, "rtw_wapi_drop_for_key_absent: pWapiSta->PeerMacAddr ", pWapiSta->PeerMacAddr, 6); + if (_rtw_memcmp(pRA, pWapiSta->PeerMacAddr, 6) == _TRUE) { + bFindMatchPeer = true; + break; + } + } + if (bFindMatchPeer) { + if (!pWapiSta->wapiUsk.bTxEnable) { + bDrop = true; + WAPI_TRACE(WAPI_RX, "rtw_wapi_drop_for_key_absent: unicast key is absent\n"); + return bDrop; + } + } else { + bDrop = true; + WAPI_TRACE(WAPI_RX, "rtw_wapi_drop_for_key_absent: no peer find\n"); + return bDrop; + } + + } else { + bDrop = true; + WAPI_TRACE(WAPI_RX, "rtw_wapi_drop_for_key_absent: no sta exist\n"); + return bDrop; + } + } + } else + return bDrop; + + return bDrop; +} + +#endif diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_wapi_sms4.c b/linux-bsp/drivers/rtl8188eus/core/rtw_wapi_sms4.c new file mode 100644 index 0000000..fc01212 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_wapi_sms4.c @@ -0,0 +1,908 @@ +#ifdef CONFIG_WAPI_SUPPORT + +#include <linux/unistd.h> +#include <linux/etherdevice.h> +#include <drv_types.h> +#include <rtw_wapi.h> + + +#ifdef CONFIG_WAPI_SW_SMS4 + +#define WAPI_LITTLE_ENDIAN +/* #define BIG_ENDIAN */ +#define ENCRYPT 0 +#define DECRYPT 1 + + +/********************************************************** + **********************************************************/ +const u8 Sbox[256] = { + 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, + 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, + 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, + 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, + 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, + 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, + 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, + 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, + 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, + 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, + 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, + 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, + 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, + 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, + 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, + 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48 +}; + +const u32 CK[32] = { + 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, + 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, + 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, + 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, + 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, + 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, + 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, + 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 +}; + +#define Rotl(_x, _y) (((_x) << (_y)) | ((_x) >> (32 - (_y)))) + +#define ByteSub(_A) (Sbox[(_A) >> 24 & 0xFF] << 24 | \ + Sbox[(_A) >> 16 & 0xFF] << 16 | \ + Sbox[(_A) >> 8 & 0xFF] << 8 | \ + Sbox[(_A) & 0xFF]) + +#define L1(_B) ((_B) ^ Rotl(_B, 2) ^ Rotl(_B, 10) ^ Rotl(_B, 18) ^ Rotl(_B, 24)) +#define L2(_B) ((_B) ^ Rotl(_B, 13) ^ Rotl(_B, 23)) + +static void +xor_block(void *dst, void *src1, void *src2) +/* 128-bit xor: *dst = *src1 xor *src2. Pointers must be 32-bit aligned */ +{ + ((u32 *)dst)[0] = ((u32 *)src1)[0] ^ ((u32 *)src2)[0]; + ((u32 *)dst)[1] = ((u32 *)src1)[1] ^ ((u32 *)src2)[1]; + ((u32 *)dst)[2] = ((u32 *)src1)[2] ^ ((u32 *)src2)[2]; + ((u32 *)dst)[3] = ((u32 *)src1)[3] ^ ((u32 *)src2)[3]; +} + + +void SMS4Crypt(u8 *Input, u8 *Output, u32 *rk) +{ + u32 r, mid, x0, x1, x2, x3, *p; + p = (u32 *)Input; + x0 = p[0]; + x1 = p[1]; + x2 = p[2]; + x3 = p[3]; +#ifdef WAPI_LITTLE_ENDIAN + x0 = Rotl(x0, 16); + x0 = ((x0 & 0x00FF00FF) << 8) | ((x0 & 0xFF00FF00) >> 8); + x1 = Rotl(x1, 16); + x1 = ((x1 & 0x00FF00FF) << 8) | ((x1 & 0xFF00FF00) >> 8); + x2 = Rotl(x2, 16); + x2 = ((x2 & 0x00FF00FF) << 8) | ((x2 & 0xFF00FF00) >> 8); + x3 = Rotl(x3, 16); + x3 = ((x3 & 0x00FF00FF) << 8) | ((x3 & 0xFF00FF00) >> 8); +#endif + for (r = 0; r < 32; r += 4) { + mid = x1 ^ x2 ^ x3 ^ rk[r + 0]; + mid = ByteSub(mid); + x0 ^= L1(mid); + mid = x2 ^ x3 ^ x0 ^ rk[r + 1]; + mid = ByteSub(mid); + x1 ^= L1(mid); + mid = x3 ^ x0 ^ x1 ^ rk[r + 2]; + mid = ByteSub(mid); + x2 ^= L1(mid); + mid = x0 ^ x1 ^ x2 ^ rk[r + 3]; + mid = ByteSub(mid); + x3 ^= L1(mid); + } +#ifdef WAPI_LITTLE_ENDIAN + x0 = Rotl(x0, 16); + x0 = ((x0 & 0x00FF00FF) << 8) | ((x0 & 0xFF00FF00) >> 8); + x1 = Rotl(x1, 16); + x1 = ((x1 & 0x00FF00FF) << 8) | ((x1 & 0xFF00FF00) >> 8); + x2 = Rotl(x2, 16); + x2 = ((x2 & 0x00FF00FF) << 8) | ((x2 & 0xFF00FF00) >> 8); + x3 = Rotl(x3, 16); + x3 = ((x3 & 0x00FF00FF) << 8) | ((x3 & 0xFF00FF00) >> 8); +#endif + p = (u32 *)Output; + p[0] = x3; + p[1] = x2; + p[2] = x1; + p[3] = x0; +} + + + +void SMS4KeyExt(u8 *Key, u32 *rk, u32 CryptFlag) +{ + u32 r, mid, x0, x1, x2, x3, *p; + + p = (u32 *)Key; + x0 = p[0]; + x1 = p[1]; + x2 = p[2]; + x3 = p[3]; +#ifdef WAPI_LITTLE_ENDIAN + x0 = Rotl(x0, 16); + x0 = ((x0 & 0xFF00FF) << 8) | ((x0 & 0xFF00FF00) >> 8); + x1 = Rotl(x1, 16); + x1 = ((x1 & 0xFF00FF) << 8) | ((x1 & 0xFF00FF00) >> 8); + x2 = Rotl(x2, 16); + x2 = ((x2 & 0xFF00FF) << 8) | ((x2 & 0xFF00FF00) >> 8); + x3 = Rotl(x3, 16); + x3 = ((x3 & 0xFF00FF) << 8) | ((x3 & 0xFF00FF00) >> 8); +#endif + + x0 ^= 0xa3b1bac6; + x1 ^= 0x56aa3350; + x2 ^= 0x677d9197; + x3 ^= 0xb27022dc; + for (r = 0; r < 32; r += 4) { + mid = x1 ^ x2 ^ x3 ^ CK[r + 0]; + mid = ByteSub(mid); + rk[r + 0] = x0 ^= L2(mid); + mid = x2 ^ x3 ^ x0 ^ CK[r + 1]; + mid = ByteSub(mid); + rk[r + 1] = x1 ^= L2(mid); + mid = x3 ^ x0 ^ x1 ^ CK[r + 2]; + mid = ByteSub(mid); + rk[r + 2] = x2 ^= L2(mid); + mid = x0 ^ x1 ^ x2 ^ CK[r + 3]; + mid = ByteSub(mid); + rk[r + 3] = x3 ^= L2(mid); + } + if (CryptFlag == DECRYPT) { + for (r = 0; r < 16; r++) + mid = rk[r], rk[r] = rk[31 - r], rk[31 - r] = mid; + } +} + + +void WapiSMS4Cryption(u8 *Key, u8 *IV, u8 *Input, u16 InputLength, + u8 *Output, u16 *OutputLength, u32 CryptFlag) +{ + u32 blockNum, i, j, rk[32]; + u16 remainder; + u8 blockIn[16], blockOut[16], tempIV[16], k; + + *OutputLength = 0; + remainder = InputLength & 0x0F; + blockNum = InputLength >> 4; + if (remainder != 0) + blockNum++; + else + remainder = 16; + + for (k = 0; k < 16; k++) + tempIV[k] = IV[15 - k]; + + memcpy(blockIn, tempIV, 16); + + SMS4KeyExt((u8 *)Key, rk, CryptFlag); + + for (i = 0; i < blockNum - 1; i++) { + SMS4Crypt((u8 *)blockIn, blockOut, rk); + xor_block(&Output[i * 16], &Input[i * 16], blockOut); + memcpy(blockIn, blockOut, 16); + } + + *OutputLength = i * 16; + + SMS4Crypt((u8 *)blockIn, blockOut, rk); + + for (j = 0; j < remainder; j++) + Output[i * 16 + j] = Input[i * 16 + j] ^ blockOut[j]; + *OutputLength += remainder; + +} + +void WapiSMS4Encryption(u8 *Key, u8 *IV, u8 *Input, u16 InputLength, + u8 *Output, u16 *OutputLength) +{ + + WapiSMS4Cryption(Key, IV, Input, InputLength, Output, OutputLength, ENCRYPT); +} + +void WapiSMS4Decryption(u8 *Key, u8 *IV, u8 *Input, u16 InputLength, + u8 *Output, u16 *OutputLength) +{ + /* OFB mode: is also ENCRYPT flag */ + WapiSMS4Cryption(Key, IV, Input, InputLength, Output, OutputLength, ENCRYPT); +} + +void WapiSMS4CalculateMic(u8 *Key, u8 *IV, u8 *Input1, u8 Input1Length, + u8 *Input2, u16 Input2Length, u8 *Output, u8 *OutputLength) +{ + u32 blockNum, i, remainder, rk[32]; + u8 BlockIn[16], BlockOut[16], TempBlock[16], tempIV[16], k; + + *OutputLength = 0; + remainder = Input1Length & 0x0F; + blockNum = Input1Length >> 4; + + for (k = 0; k < 16; k++) + tempIV[k] = IV[15 - k]; + + memcpy(BlockIn, tempIV, 16); + + SMS4KeyExt((u8 *)Key, rk, ENCRYPT); + + SMS4Crypt((u8 *)BlockIn, BlockOut, rk); + + for (i = 0; i < blockNum; i++) { + xor_block(BlockIn, (Input1 + i * 16), BlockOut); + SMS4Crypt((u8 *)BlockIn, BlockOut, rk); + } + + if (remainder != 0) { + memset(TempBlock, 0, 16); + memcpy(TempBlock, (Input1 + blockNum * 16), remainder); + + xor_block(BlockIn, TempBlock, BlockOut); + SMS4Crypt((u8 *)BlockIn, BlockOut, rk); + } + + remainder = Input2Length & 0x0F; + blockNum = Input2Length >> 4; + + for (i = 0; i < blockNum; i++) { + xor_block(BlockIn, (Input2 + i * 16), BlockOut); + SMS4Crypt((u8 *)BlockIn, BlockOut, rk); + } + + if (remainder != 0) { + memset(TempBlock, 0, 16); + memcpy(TempBlock, (Input2 + blockNum * 16), remainder); + + xor_block(BlockIn, TempBlock, BlockOut); + SMS4Crypt((u8 *)BlockIn, BlockOut, rk); + } + + memcpy(Output, BlockOut, 16); + *OutputLength = 16; +} + +void SecCalculateMicSMS4( + u8 KeyIdx, + u8 *MicKey, + u8 *pHeader, + u8 *pData, + u16 DataLen, + u8 *MicBuffer +) +{ +#if 0 + struct ieee80211_hdr_3addr_qos *header; + u8 TempBuf[34], TempLen = 32, MicLen, QosOffset, *IV; + u16 *pTemp, fc; + + WAPI_TRACE(WAPI_TX | WAPI_RX, "=========>%s\n", __FUNCTION__); + + header = (struct ieee80211_hdr_3addr_qos *)pHeader; + memset(TempBuf, 0, 34); + memcpy(TempBuf, pHeader, 2); /* FrameCtrl */ + pTemp = (u16 *)TempBuf; + *pTemp &= 0xc78f; /* bit4,5,6,11,12,13 */ + + memcpy((TempBuf + 2), (pHeader + 4), 12); /* Addr1, Addr2 */ + memcpy((TempBuf + 14), (pHeader + 22), 2); /* SeqCtrl */ + pTemp = (u16 *)(TempBuf + 14); + *pTemp &= 0x000f; + + memcpy((TempBuf + 16), (pHeader + 16), 6); /* Addr3 */ + + fc = le16_to_cpu(header->frame_ctl); + + + + if (GetFrDs((u16 *)&fc) && GetToDs((u16 *)&fc)) { + memcpy((TempBuf + 22), (pHeader + 24), 6); + QosOffset = 30; + } else { + memset((TempBuf + 22), 0, 6); + QosOffset = 24; + } + + if ((fc & 0x0088) == 0x0088) { + memcpy((TempBuf + 28), (pHeader + QosOffset), 2); + TempLen += 2; + /* IV = pHeader + QosOffset + 2 + SNAP_SIZE + sizeof(u16) + 2; */ + IV = pHeader + QosOffset + 2 + 2; + } else { + IV = pHeader + QosOffset + 2; + /* IV = pHeader + QosOffset + SNAP_SIZE + sizeof(u16) + 2; */ + } + + TempBuf[TempLen - 1] = (u8)(DataLen & 0xff); + TempBuf[TempLen - 2] = (u8)((DataLen & 0xff00) >> 8); + TempBuf[TempLen - 4] = KeyIdx; + + WAPI_DATA(WAPI_TX, "CalculateMic - KEY", MicKey, 16); + WAPI_DATA(WAPI_TX, "CalculateMic - IV", IV, 16); + WAPI_DATA(WAPI_TX, "CalculateMic - TempBuf", TempBuf, TempLen); + WAPI_DATA(WAPI_TX, "CalculateMic - pData", pData, DataLen); + + WapiSMS4CalculateMic(MicKey, IV, TempBuf, TempLen, + pData, DataLen, MicBuffer, &MicLen); + + if (MicLen != 16) + WAPI_TRACE(WAPI_ERR, "%s: MIC Length Error!!\n", __FUNCTION__); + + WAPI_TRACE(WAPI_TX | WAPI_RX, "<=========%s\n", __FUNCTION__); +#endif +} + +/* AddCount: 1 or 2. + * If overflow, return 1, + * else return 0. + */ +u8 WapiIncreasePN(u8 *PN, u8 AddCount) +{ + u8 i; + + if (NULL == PN) + return 1; + /* YJ,test,091102 */ + /* + if(AddCount == 2){ + RTW_INFO("############################%s(): PN[0]=0x%x\n", __FUNCTION__, PN[0]); + if(PN[0] == 0x48){ + PN[0] += AddCount; + return 1; + }else{ + PN[0] += AddCount; + return 0; + } + } + */ + /* YJ,test,091102,end */ + + for (i = 0; i < 16; i++) { + if (PN[i] + AddCount <= 0xff) { + PN[i] += AddCount; + return 0; + } else { + PN[i] += AddCount; + AddCount = 1; + } + } + return 1; +} + + +void WapiGetLastRxUnicastPNForQoSData( + u8 UserPriority, + PRT_WAPI_STA_INFO pWapiStaInfo, + u8 *PNOut +) +{ + WAPI_TRACE(WAPI_RX, "===========> %s\n", __FUNCTION__); + switch (UserPriority) { + case 0: + case 3: + memcpy(PNOut, pWapiStaInfo->lastRxUnicastPNBEQueue, 16); + break; + case 1: + case 2: + memcpy(PNOut, pWapiStaInfo->lastRxUnicastPNBKQueue, 16); + break; + case 4: + case 5: + memcpy(PNOut, pWapiStaInfo->lastRxUnicastPNVIQueue, 16); + break; + case 6: + case 7: + memcpy(PNOut, pWapiStaInfo->lastRxUnicastPNVOQueue, 16); + break; + default: + WAPI_TRACE(WAPI_ERR, "%s: Unknown TID\n", __FUNCTION__); + break; + } + WAPI_TRACE(WAPI_RX, "<=========== %s\n", __FUNCTION__); +} + + +void WapiSetLastRxUnicastPNForQoSData( + u8 UserPriority, + u8 *PNIn, + PRT_WAPI_STA_INFO pWapiStaInfo +) +{ + WAPI_TRACE(WAPI_RX, "===========> %s\n", __FUNCTION__); + switch (UserPriority) { + case 0: + case 3: + memcpy(pWapiStaInfo->lastRxUnicastPNBEQueue, PNIn, 16); + break; + case 1: + case 2: + memcpy(pWapiStaInfo->lastRxUnicastPNBKQueue, PNIn, 16); + break; + case 4: + case 5: + memcpy(pWapiStaInfo->lastRxUnicastPNVIQueue, PNIn, 16); + break; + case 6: + case 7: + memcpy(pWapiStaInfo->lastRxUnicastPNVOQueue, PNIn, 16); + break; + default: + WAPI_TRACE(WAPI_ERR, "%s: Unknown TID\n", __FUNCTION__); + break; + } + WAPI_TRACE(WAPI_RX, "<=========== %s\n", __FUNCTION__); +} + + +/**************************************************************************** + FALSE not RX-Reorder + TRUE do RX Reorder +add to support WAPI to N-mode +*****************************************************************************/ +u8 WapiCheckPnInSwDecrypt( + _adapter *padapter, + struct sk_buff *pskb +) +{ + u8 ret = false; + +#if 0 + struct ieee80211_hdr_3addr_qos *header; + u16 fc; + u8 *pDaddr, *pTaddr, *pRaddr; + + header = (struct ieee80211_hdr_3addr_qos *)pskb->data; + pTaddr = header->addr2; + pRaddr = header->addr1; + fc = le16_to_cpu(header->frame_ctl); + + if (GetToDs(&fc)) + pDaddr = header->addr3; + else + pDaddr = header->addr1; + + if ((_rtw_memcmp(pRaddr, padapter->pnetdev->dev_addr, ETH_ALEN) == 0) + && !(pDaddr) + && (GetFrameType(&fc) == WIFI_QOS_DATA_TYPE)) + /* && ieee->pHTInfo->bCurrentHTSupport && */ + /* ieee->pHTInfo->bCurRxReorderEnable) */ + ret = false; + else + ret = true; +#endif + WAPI_TRACE(WAPI_RX, "%s: return %d\n", __FUNCTION__, ret); + return ret; +} + +int SecSMS4HeaderFillIV(_adapter *padapter, u8 *pxmitframe) +{ + struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; + u8 *frame = ((struct xmit_frame *)pxmitframe)->buf_addr + TXDESC_OFFSET; + u8 *pSecHeader = NULL, *pos = NULL, *pRA = NULL; + u8 bPNOverflow = false, bFindMatchPeer = false, hdr_len = 0; + PWLAN_HEADER_WAPI_EXTENSION pWapiExt = NULL; + PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; + PRT_WAPI_STA_INFO pWapiSta = NULL; + int ret = 0; + + WAPI_TRACE(WAPI_TX, "=========>%s\n", __FUNCTION__); + + return ret; +#if 0 + hdr_len = sMacHdrLng; + if (GetFrameType(pskb->data) == WIFI_QOS_DATA_TYPE) + hdr_len += 2; + /* hdr_len += SNAP_SIZE + sizeof(u16); */ + + pos = skb_push(pskb, padapter->wapiInfo.extra_prefix_len); + memmove(pos, pos + padapter->wapiInfo.extra_prefix_len, hdr_len); + + pSecHeader = pskb->data + hdr_len; + pWapiExt = (PWLAN_HEADER_WAPI_EXTENSION)pSecHeader; + pRA = pskb->data + 4; + + WAPI_DATA(WAPI_TX, "FillIV - Before Fill IV", pskb->data, pskb->len); + + /* Address 1 is always receiver's address */ + if (IS_MCAST(pRA)) { + if (!pWapiInfo->wapiTxMsk.bTxEnable) { + WAPI_TRACE(WAPI_ERR, "%s: bTxEnable = 0!!\n", __FUNCTION__); + return -2; + } + if (pWapiInfo->wapiTxMsk.keyId <= 1) { + pWapiExt->KeyIdx = pWapiInfo->wapiTxMsk.keyId; + pWapiExt->Reserved = 0; + bPNOverflow = WapiIncreasePN(pWapiInfo->lastTxMulticastPN, 1); + memcpy(pWapiExt->PN, pWapiInfo->lastTxMulticastPN, 16); + if (bPNOverflow) { + /* Update MSK Notification. */ + WAPI_TRACE(WAPI_ERR, "===============>%s():multicast PN overflow\n", __FUNCTION__); + rtw_wapi_app_event_handler(padapter, NULL, 0, pRA, false, false, true, 0, false); + } + } else { + WAPI_TRACE(WAPI_ERR, "%s: Invalid Wapi Multicast KeyIdx!!\n", __FUNCTION__); + ret = -3; + } + } else { + list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { + if (!memcmp(pWapiSta->PeerMacAddr, pRA, 6)) { + bFindMatchPeer = true; + break; + } + } + if (bFindMatchPeer) { + if ((!pWapiSta->wapiUskUpdate.bTxEnable) && (!pWapiSta->wapiUsk.bTxEnable)) { + WAPI_TRACE(WAPI_ERR, "%s: bTxEnable = 0!!\n", __FUNCTION__); + return -4; + } + if (pWapiSta->wapiUsk.keyId <= 1) { + if (pWapiSta->wapiUskUpdate.bTxEnable) + pWapiExt->KeyIdx = pWapiSta->wapiUskUpdate.keyId; + else + pWapiExt->KeyIdx = pWapiSta->wapiUsk.keyId; + + pWapiExt->Reserved = 0; + bPNOverflow = WapiIncreasePN(pWapiSta->lastTxUnicastPN, 2); + memcpy(pWapiExt->PN, pWapiSta->lastTxUnicastPN, 16); + if (bPNOverflow) { + /* Update USK Notification. */ + WAPI_TRACE(WAPI_ERR, "===============>%s():unicast PN overflow\n", __FUNCTION__); + rtw_wapi_app_event_handler(padapter, NULL, 0, pWapiSta->PeerMacAddr, false, true, false, 0, false); + } + } else { + WAPI_TRACE(WAPI_ERR, "%s: Invalid Wapi Unicast KeyIdx!!\n", __FUNCTION__); + ret = -5; + } + } else { + WAPI_TRACE(WAPI_ERR, "%s: Can not find Peer Sta "MAC_FMT"!!\n", __FUNCTION__, MAC_ARG(pRA)); + ret = -6; + } + } + + WAPI_DATA(WAPI_TX, "FillIV - After Fill IV", pskb->data, pskb->len); + WAPI_TRACE(WAPI_TX, "<=========%s\n", __FUNCTION__); + return ret; +#endif +} + +/* WAPI SW Enc: must have done Coalesce! */ +void SecSWSMS4Encryption( + _adapter *padapter, + u8 *pxmitframe +) +{ + PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; + PRT_WAPI_STA_INFO pWapiSta = NULL; + u8 *pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + TXDESC_SIZE; + struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; + + u8 *SecPtr = NULL, *pRA, *pMicKey = NULL, *pDataKey = NULL, *pIV = NULL; + u8 IVOffset, DataOffset, bFindMatchPeer = false, KeyIdx = 0, MicBuffer[16]; + u16 OutputLength; + + WAPI_TRACE(WAPI_TX, "=========>%s\n", __FUNCTION__); + + WAPI_TRACE(WAPI_TX, "hdrlen: %d\n", pattrib->hdrlen); + + return; + + DataOffset = pattrib->hdrlen + pattrib->iv_len; + + pRA = pframe + 4; + + + if (IS_MCAST(pRA)) { + KeyIdx = pWapiInfo->wapiTxMsk.keyId; + pIV = pWapiInfo->lastTxMulticastPN; + pMicKey = pWapiInfo->wapiTxMsk.micKey; + pDataKey = pWapiInfo->wapiTxMsk.dataKey; + } else { + if (!list_empty(&(pWapiInfo->wapiSTAUsedList))) { + list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { + if (0 == memcmp(pWapiSta->PeerMacAddr, pRA, 6)) { + bFindMatchPeer = true; + break; + } + } + + if (bFindMatchPeer) { + if (pWapiSta->wapiUskUpdate.bTxEnable) { + KeyIdx = pWapiSta->wapiUskUpdate.keyId; + WAPI_TRACE(WAPI_TX, "%s(): Use update USK!! KeyIdx=%d\n", __FUNCTION__, KeyIdx); + pIV = pWapiSta->lastTxUnicastPN; + pMicKey = pWapiSta->wapiUskUpdate.micKey; + pDataKey = pWapiSta->wapiUskUpdate.dataKey; + } else { + KeyIdx = pWapiSta->wapiUsk.keyId; + WAPI_TRACE(WAPI_TX, "%s(): Use USK!! KeyIdx=%d\n", __FUNCTION__, KeyIdx); + pIV = pWapiSta->lastTxUnicastPN; + pMicKey = pWapiSta->wapiUsk.micKey; + pDataKey = pWapiSta->wapiUsk.dataKey; + } + } else { + WAPI_TRACE(WAPI_ERR, "%s: Can not find Peer Sta!!\n", __FUNCTION__); + return; + } + } else { + WAPI_TRACE(WAPI_ERR, "%s: wapiSTAUsedList is empty!!\n", __FUNCTION__); + return; + } + } + + SecPtr = pframe; + SecCalculateMicSMS4(KeyIdx, pMicKey, SecPtr, (SecPtr + DataOffset), pattrib->pktlen, MicBuffer); + + WAPI_DATA(WAPI_TX, "Encryption - MIC", MicBuffer, padapter->wapiInfo.extra_postfix_len); + + memcpy(pframe + pattrib->hdrlen + pattrib->iv_len + pattrib->pktlen - pattrib->icv_len, + (u8 *)MicBuffer, + padapter->wapiInfo.extra_postfix_len + ); + + + WapiSMS4Encryption(pDataKey, pIV, (SecPtr + DataOffset), pattrib->pktlen + pattrib->icv_len, (SecPtr + DataOffset), &OutputLength); + + WAPI_DATA(WAPI_TX, "Encryption - After SMS4 encryption", pframe, pattrib->hdrlen + pattrib->iv_len + pattrib->pktlen); + + WAPI_TRACE(WAPI_TX, "<=========%s\n", __FUNCTION__); +} + +u8 SecSWSMS4Decryption( + _adapter *padapter, + u8 *precv_frame, + struct recv_priv *precv_priv +) +{ + PRT_WAPI_T pWapiInfo = &padapter->wapiInfo; + struct recv_frame_hdr *precv_hdr; + PRT_WAPI_STA_INFO pWapiSta = NULL; + u8 IVOffset, DataOffset, bFindMatchPeer = false, bUseUpdatedKey = false; + u8 KeyIdx, MicBuffer[16], lastRxPNforQoS[16]; + u8 *pRA, *pTA, *pMicKey, *pDataKey, *pLastRxPN, *pRecvPN, *pSecData, *pRecvMic, *pos; + u8 TID = 0; + u16 OutputLength, DataLen; + u8 bQosData; + struct sk_buff *pskb; + + WAPI_TRACE(WAPI_RX, "=========>%s\n", __FUNCTION__); + + return 0; + + precv_hdr = &((union recv_frame *)precv_frame)->u.hdr; + pskb = (struct sk_buff *)(precv_hdr->rx_data); + precv_hdr->bWapiCheckPNInDecrypt = WapiCheckPnInSwDecrypt(padapter, pskb); + WAPI_TRACE(WAPI_RX, "=========>%s: check PN %d\n", __FUNCTION__, precv_hdr->bWapiCheckPNInDecrypt); + WAPI_DATA(WAPI_RX, "Decryption - Before decryption", pskb->data, pskb->len); + + IVOffset = sMacHdrLng; + bQosData = GetFrameType(pskb->data) == WIFI_QOS_DATA_TYPE; + if (bQosData) + IVOffset += 2; + + /* if(GetHTC()) */ + /* IVOffset += 4; */ + + /* IVOffset += SNAP_SIZE + sizeof(u16); */ + + DataOffset = IVOffset + padapter->wapiInfo.extra_prefix_len; + + pRA = pskb->data + 4; + pTA = pskb->data + 10; + KeyIdx = *(pskb->data + IVOffset); + pRecvPN = pskb->data + IVOffset + 2; + pSecData = pskb->data + DataOffset; + DataLen = pskb->len - DataOffset; + pRecvMic = pskb->data + pskb->len - padapter->wapiInfo.extra_postfix_len; + TID = GetTid(pskb->data); + + if (!list_empty(&(pWapiInfo->wapiSTAUsedList))) { + list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) { + if (0 == memcmp(pWapiSta->PeerMacAddr, pTA, 6)) { + bFindMatchPeer = true; + break; + } + } + } + + if (!bFindMatchPeer) { + WAPI_TRACE(WAPI_ERR, "%s: Can not find Peer Sta "MAC_FMT" for Key Info!!!\n", __FUNCTION__, MAC_ARG(pTA)); + return false; + } + + if (IS_MCAST(pRA)) { + WAPI_TRACE(WAPI_RX, "%s: Multicast decryption !!!\n", __FUNCTION__); + if (pWapiSta->wapiMsk.keyId == KeyIdx && pWapiSta->wapiMsk.bSet) { + pLastRxPN = pWapiSta->lastRxMulticastPN; + if (!WapiComparePN(pRecvPN, pLastRxPN)) { + WAPI_TRACE(WAPI_ERR, "%s: MSK PN is not larger than last, Dropped!!!\n", __FUNCTION__); + WAPI_DATA(WAPI_ERR, "pRecvPN:", pRecvPN, 16); + WAPI_DATA(WAPI_ERR, "pLastRxPN:", pLastRxPN, 16); + return false; + } + + memcpy(pLastRxPN, pRecvPN, 16); + pMicKey = pWapiSta->wapiMsk.micKey; + pDataKey = pWapiSta->wapiMsk.dataKey; + } else if (pWapiSta->wapiMskUpdate.keyId == KeyIdx && pWapiSta->wapiMskUpdate.bSet) { + WAPI_TRACE(WAPI_RX, "%s: Use Updated MSK for Decryption !!!\n", __FUNCTION__); + bUseUpdatedKey = true; + memcpy(pWapiSta->lastRxMulticastPN, pRecvPN, 16); + pMicKey = pWapiSta->wapiMskUpdate.micKey; + pDataKey = pWapiSta->wapiMskUpdate.dataKey; + } else { + WAPI_TRACE(WAPI_ERR, "%s: Can not find MSK with matched KeyIdx(%d), Dropped !!!\n", __FUNCTION__, KeyIdx); + return false; + } + } else { + WAPI_TRACE(WAPI_RX, "%s: Unicast decryption !!!\n", __FUNCTION__); + if (pWapiSta->wapiUsk.keyId == KeyIdx && pWapiSta->wapiUsk.bSet) { + WAPI_TRACE(WAPI_RX, "%s: Use USK for Decryption!!!\n", __FUNCTION__); + if (precv_hdr->bWapiCheckPNInDecrypt) { + if (GetFrameType(pskb->data) == WIFI_QOS_DATA_TYPE) { + WapiGetLastRxUnicastPNForQoSData(TID, pWapiSta, lastRxPNforQoS); + pLastRxPN = lastRxPNforQoS; + } else + pLastRxPN = pWapiSta->lastRxUnicastPN; + if (!WapiComparePN(pRecvPN, pLastRxPN)) + return false; + if (bQosData) + WapiSetLastRxUnicastPNForQoSData(TID, pRecvPN, pWapiSta); + else + memcpy(pWapiSta->lastRxUnicastPN, pRecvPN, 16); + } else + memcpy(precv_hdr->WapiTempPN, pRecvPN, 16); + + if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE)) { + if ((pRecvPN[0] & 0x1) == 0) { + WAPI_TRACE(WAPI_ERR, "%s: Rx USK PN is not odd when Infra STA mode, Dropped !!!\n", __FUNCTION__); + return false; + } + } + + pMicKey = pWapiSta->wapiUsk.micKey; + pDataKey = pWapiSta->wapiUsk.dataKey; + } else if (pWapiSta->wapiUskUpdate.keyId == KeyIdx && pWapiSta->wapiUskUpdate.bSet) { + WAPI_TRACE(WAPI_RX, "%s: Use Updated USK for Decryption!!!\n", __FUNCTION__); + if (pWapiSta->bAuthenticatorInUpdata) + bUseUpdatedKey = true; + else + bUseUpdatedKey = false; + + if (bQosData) + WapiSetLastRxUnicastPNForQoSData(TID, pRecvPN, pWapiSta); + else + memcpy(pWapiSta->lastRxUnicastPN, pRecvPN, 16); + pMicKey = pWapiSta->wapiUskUpdate.micKey; + pDataKey = pWapiSta->wapiUskUpdate.dataKey; + } else { + WAPI_TRACE(WAPI_ERR, "%s: No valid USK!!!KeyIdx=%d pWapiSta->wapiUsk.keyId=%d pWapiSta->wapiUskUpdate.keyId=%d\n", __FUNCTION__, KeyIdx, pWapiSta->wapiUsk.keyId, + pWapiSta->wapiUskUpdate.keyId); + /* dump_buf(pskb->data,pskb->len); */ + return false; + } + } + + WAPI_DATA(WAPI_RX, "Decryption - DataKey", pDataKey, 16); + WAPI_DATA(WAPI_RX, "Decryption - IV", pRecvPN, 16); + WapiSMS4Decryption(pDataKey, pRecvPN, pSecData, DataLen, pSecData, &OutputLength); + + if (OutputLength != DataLen) + WAPI_TRACE(WAPI_ERR, "%s: Output Length Error!!!!\n", __FUNCTION__); + + WAPI_DATA(WAPI_RX, "Decryption - After decryption", pskb->data, pskb->len); + + DataLen -= padapter->wapiInfo.extra_postfix_len; + + SecCalculateMicSMS4(KeyIdx, pMicKey, pskb->data, pSecData, DataLen, MicBuffer); + + WAPI_DATA(WAPI_RX, "Decryption - MIC received", pRecvMic, SMS4_MIC_LEN); + WAPI_DATA(WAPI_RX, "Decryption - MIC calculated", MicBuffer, SMS4_MIC_LEN); + + if (0 == memcmp(MicBuffer, pRecvMic, padapter->wapiInfo.extra_postfix_len)) { + WAPI_TRACE(WAPI_RX, "%s: Check MIC OK!!\n", __FUNCTION__); + if (bUseUpdatedKey) { + /* delete the old key */ + if (IS_MCAST(pRA)) { + WAPI_TRACE(WAPI_API, "%s(): AE use new update MSK!!\n", __FUNCTION__); + pWapiSta->wapiMsk.keyId = pWapiSta->wapiMskUpdate.keyId; + memcpy(pWapiSta->wapiMsk.dataKey, pWapiSta->wapiMskUpdate.dataKey, 16); + memcpy(pWapiSta->wapiMsk.micKey, pWapiSta->wapiMskUpdate.micKey, 16); + pWapiSta->wapiMskUpdate.bTxEnable = pWapiSta->wapiMskUpdate.bSet = false; + } else { + WAPI_TRACE(WAPI_API, "%s(): AE use new update USK!!\n", __FUNCTION__); + pWapiSta->wapiUsk.keyId = pWapiSta->wapiUskUpdate.keyId; + memcpy(pWapiSta->wapiUsk.dataKey, pWapiSta->wapiUskUpdate.dataKey, 16); + memcpy(pWapiSta->wapiUsk.micKey, pWapiSta->wapiUskUpdate.micKey, 16); + pWapiSta->wapiUskUpdate.bTxEnable = pWapiSta->wapiUskUpdate.bSet = false; + } + } + } else { + WAPI_TRACE(WAPI_ERR, "%s: Check MIC Error, Dropped !!!!\n", __FUNCTION__); + return false; + } + + pos = pskb->data; + memmove(pos + padapter->wapiInfo.extra_prefix_len, pos, IVOffset); + skb_pull(pskb, padapter->wapiInfo.extra_prefix_len); + + WAPI_TRACE(WAPI_RX, "<=========%s\n", __FUNCTION__); + + return true; +} + +u32 rtw_sms4_encrypt(_adapter *padapter, u8 *pxmitframe) +{ + + u8 *pframe; + u32 res = _SUCCESS; + + WAPI_TRACE(WAPI_TX, "=========>%s\n", __FUNCTION__); + + if ((!padapter->WapiSupport) || (!padapter->wapiInfo.bWapiEnable)) { + WAPI_TRACE(WAPI_TX, "<========== %s, WAPI not supported or enabled!\n", __FUNCTION__); + return _FAIL; + } + + if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) + return _FAIL; + + pframe = ((struct xmit_frame *)pxmitframe)->buf_addr + TXDESC_OFFSET; + + SecSWSMS4Encryption(padapter, pxmitframe); + + WAPI_TRACE(WAPI_TX, "<=========%s\n", __FUNCTION__); + return res; +} + +u32 rtw_sms4_decrypt(_adapter *padapter, u8 *precvframe) +{ + u8 *pframe; + u32 res = _SUCCESS; + + WAPI_TRACE(WAPI_RX, "=========>%s\n", __FUNCTION__); + + if ((!padapter->WapiSupport) || (!padapter->wapiInfo.bWapiEnable)) { + WAPI_TRACE(WAPI_RX, "<========== %s, WAPI not supported or enabled!\n", __FUNCTION__); + return _FAIL; + } + + + /* drop packet when hw decrypt fail + * return tempraily */ + return _FAIL; + + /* pframe=(unsigned char *)((union recv_frame*)precvframe)->u.hdr.rx_data; */ + + if (false == SecSWSMS4Decryption(padapter, precvframe, &padapter->recvpriv)) { + WAPI_TRACE(WAPI_ERR, "%s():SMS4 decrypt frame error\n", __FUNCTION__); + return _FAIL; + } + + WAPI_TRACE(WAPI_RX, "<=========%s\n", __FUNCTION__); + return res; +} + +#else + +u32 rtw_sms4_encrypt(_adapter *padapter, u8 *pxmitframe) +{ + WAPI_TRACE(WAPI_TX, "=========>Dummy %s\n", __FUNCTION__); + WAPI_TRACE(WAPI_TX, "<=========Dummy %s\n", __FUNCTION__); + return _SUCCESS; +} + +u32 rtw_sms4_decrypt(_adapter *padapter, u8 *precvframe) +{ + WAPI_TRACE(WAPI_RX, "=========>Dummy %s\n", __FUNCTION__); + WAPI_TRACE(WAPI_RX, "<=========Dummy %s\n", __FUNCTION__); + return _SUCCESS; +} + +#endif + +#endif diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_wlan_util.c b/linux-bsp/drivers/rtl8188eus/core/rtw_wlan_util.c new file mode 100644 index 0000000..a81f189 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_wlan_util.c @@ -0,0 +1,4656 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_WLAN_UTIL_C_ + +#include <drv_types.h> +#include <hal_data.h> + +#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) + #include <linux/inetdevice.h> + #define ETH_TYPE_OFFSET 12 + #define PROTOCOL_OFFSET 23 + #define IP_OFFSET 30 +#endif + +unsigned char ARTHEROS_OUI1[] = {0x00, 0x03, 0x7f}; +unsigned char ARTHEROS_OUI2[] = {0x00, 0x13, 0x74}; + +unsigned char BROADCOM_OUI1[] = {0x00, 0x10, 0x18}; +unsigned char BROADCOM_OUI2[] = {0x00, 0x0a, 0xf7}; +unsigned char BROADCOM_OUI3[] = {0x00, 0x05, 0xb5}; + + +unsigned char CISCO_OUI[] = {0x00, 0x40, 0x96}; +unsigned char MARVELL_OUI[] = {0x00, 0x50, 0x43}; +unsigned char RALINK_OUI[] = {0x00, 0x0c, 0x43}; +unsigned char REALTEK_OUI[] = {0x00, 0xe0, 0x4c}; +unsigned char AIRGOCAP_OUI[] = {0x00, 0x0a, 0xf5}; + +unsigned char REALTEK_96B_IE[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20}; + +extern unsigned char RTW_WPA_OUI[]; +extern unsigned char WPA_TKIP_CIPHER[4]; +extern unsigned char RSN_TKIP_CIPHER[4]; + +#define R2T_PHY_DELAY (0) + +/* #define WAIT_FOR_BCN_TO_MIN (3000) */ +#define WAIT_FOR_BCN_TO_MIN (6000) +#define WAIT_FOR_BCN_TO_MAX (20000) + +#define DISCONNECT_BY_CHK_BCN_FAIL_OBSERV_PERIOD_IN_MS 1000 +#define DISCONNECT_BY_CHK_BCN_FAIL_THRESHOLD 3 + +static u8 rtw_basic_rate_cck[4] = { + IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK, + IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK +}; + +static u8 rtw_basic_rate_ofdm[3] = { + IEEE80211_OFDM_RATE_6MB | IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB | IEEE80211_BASIC_RATE_MASK, + IEEE80211_OFDM_RATE_24MB | IEEE80211_BASIC_RATE_MASK +}; + +static u8 rtw_basic_rate_mix[7] = { + IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK, + IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK, + IEEE80211_OFDM_RATE_6MB | IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB | IEEE80211_BASIC_RATE_MASK, + IEEE80211_OFDM_RATE_24MB | IEEE80211_BASIC_RATE_MASK +}; + +int new_bcn_max = 3; + +int cckrates_included(unsigned char *rate, int ratelen) +{ + int i; + + for (i = 0; i < ratelen; i++) { + if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) || + (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22)) + return _TRUE; + } + + return _FALSE; + +} + +int cckratesonly_included(unsigned char *rate, int ratelen) +{ + int i; + + for (i = 0; i < ratelen; i++) { + if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) && + (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22)) + return _FALSE; + } + + return _TRUE; +} + +#ifdef CONFIG_GET_RAID_BY_DRV +s8 rtw_get_tx_nss(_adapter *adapter, struct sta_info *psta) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + u8 rf_type = RF_1T1R, custom_rf_type; + s8 nss = 1; + + if (!psta) + return nss; + + custom_rf_type = adapter->registrypriv.rf_config; + rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + if (RF_TYPE_VALID(custom_rf_type)) + rf_type = custom_rf_type; + +#ifdef CONFIG_80211AC_VHT + if (psta->vhtpriv.vht_option) { + nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); + nss = rtw_min(nss, rtw_vht_mcsmap_to_nss(psta->vhtpriv.vht_mcs_map)); + } else +#endif /* CONFIG_80211AC_VHT */ + if (psta->htpriv.ht_option) { + nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); + nss = rtw_min(nss, rtw_ht_mcsset_to_nss(psta->htpriv.ht_cap.supp_mcs_set)); + } + + RTW_INFO("%s: %d SS\n", __func__, nss); + return nss; +} + +u8 networktype_to_raid(_adapter *adapter, struct sta_info *psta) +{ + unsigned char raid; + switch (psta->wireless_mode) { + case WIRELESS_11B: + raid = RATR_INX_WIRELESS_B; + break; + case WIRELESS_11A: + case WIRELESS_11G: + raid = RATR_INX_WIRELESS_G; + break; + case WIRELESS_11BG: + raid = RATR_INX_WIRELESS_GB; + break; + case WIRELESS_11_24N: + case WIRELESS_11_5N: + raid = RATR_INX_WIRELESS_N; + break; + case WIRELESS_11A_5N: + case WIRELESS_11G_24N: + raid = RATR_INX_WIRELESS_NG; + break; + case WIRELESS_11BG_24N: + raid = RATR_INX_WIRELESS_NGB; + break; + default: + raid = RATR_INX_WIRELESS_GB; + break; + + } + return raid; + +} + +u8 networktype_to_raid_ex(_adapter *adapter, struct sta_info *psta) +{ + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + u8 raid = RATEID_IDX_BGN_40M_1SS, cur_rf_type, rf_type, custom_rf_type; + s8 tx_nss; + + tx_nss = rtw_get_tx_nss(adapter, psta); + + switch (psta->wireless_mode) { + case WIRELESS_11B: + raid = RATEID_IDX_B; + break; + case WIRELESS_11A: + case WIRELESS_11G: + raid = RATEID_IDX_G; + break; + case WIRELESS_11BG: + raid = RATEID_IDX_BG; + break; + case WIRELESS_11_24N: + case WIRELESS_11_5N: + case WIRELESS_11A_5N: + case WIRELESS_11G_24N: + if (tx_nss == 1) + raid = RATEID_IDX_GN_N1SS; + else if (tx_nss == 2) + raid = RATEID_IDX_GN_N2SS; + else if (tx_nss == 3) + raid = RATEID_IDX_BGN_3SS; + else + RTW_INFO("tx_nss error!(tx_nss=%d)\n", tx_nss); + break; + case WIRELESS_11B_24N: + case WIRELESS_11BG_24N: + if (psta->bw_mode == CHANNEL_WIDTH_20) { + if (tx_nss == 1) + raid = RATEID_IDX_BGN_20M_1SS_BN; + else if (tx_nss == 2) + raid = RATEID_IDX_BGN_20M_2SS_BN; + else if (tx_nss == 3) + raid = RATEID_IDX_BGN_3SS; + else + RTW_INFO("tx_nss error!(tx_nss=%d)\n", tx_nss); + } else { + if (tx_nss == 1) + raid = RATEID_IDX_BGN_40M_1SS; + else if (tx_nss == 2) + raid = RATEID_IDX_BGN_40M_2SS; + else if (tx_nss == 3) + raid = RATEID_IDX_BGN_3SS; + else + RTW_INFO("tx_nss error!(tx_nss=%d)\n", tx_nss); + } + break; +#ifdef CONFIG_80211AC_VHT + case WIRELESS_11_5AC: + if (tx_nss == 1) + raid = RATEID_IDX_VHT_1SS; + else if (tx_nss == 2) + raid = RATEID_IDX_VHT_2SS; + else if (tx_nss == 3) + raid = RATEID_IDX_VHT_3SS; + else + RTW_INFO("tx_nss error!(tx_nss=%d)\n", tx_nss); + break; + case WIRELESS_11_24AC: + if (psta->bw_mode >= CHANNEL_WIDTH_80) { + if (tx_nss == 1) + raid = RATEID_IDX_VHT_1SS; + else if (tx_nss == 2) + raid = RATEID_IDX_VHT_2SS; + else if (tx_nss == 3) + raid = RATEID_IDX_VHT_3SS; + else + RTW_INFO("tx_nss error!(tx_nss=%d)\n", tx_nss); + } else { + if (tx_nss == 1) + raid = RATEID_IDX_MIX1; + else if (tx_nss == 2) + raid = RATEID_IDX_MIX2; + else if (tx_nss == 3) + raid = RATEID_IDX_VHT_3SS; + else + RTW_INFO("tx_nss error!(tx_nss=%d)\n", tx_nss); + } + break; +#endif + default: + RTW_INFO("unexpected wireless mode!(psta->wireless_mode=%x)\n", psta->wireless_mode); + break; + + } + + /* RTW_INFO("psta->wireless_mode=%x, tx_nss=%d\n", psta->wireless_mode, tx_nss); */ + + return raid; + +} +#endif +u8 judge_network_type(_adapter *padapter, unsigned char *rate, int ratelen) +{ + u8 network_type = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + + if (pmlmeext->cur_channel > 14) { + if (pmlmeinfo->VHT_enable) + network_type = WIRELESS_11AC; + else if (pmlmeinfo->HT_enable) + network_type = WIRELESS_11_5N; + + network_type |= WIRELESS_11A; + } else { + if (pmlmeinfo->HT_enable) + network_type = WIRELESS_11_24N; + + if ((cckratesonly_included(rate, ratelen)) == _TRUE) + network_type |= WIRELESS_11B; + else if ((cckrates_included(rate, ratelen)) == _TRUE) + network_type |= WIRELESS_11BG; + else + network_type |= WIRELESS_11G; + } + + return network_type; +} + +unsigned char ratetbl_val_2wifirate(unsigned char rate); +unsigned char ratetbl_val_2wifirate(unsigned char rate) +{ + unsigned char val = 0; + + switch (rate & 0x7f) { + case 0: + val = IEEE80211_CCK_RATE_1MB; + break; + + case 1: + val = IEEE80211_CCK_RATE_2MB; + break; + + case 2: + val = IEEE80211_CCK_RATE_5MB; + break; + + case 3: + val = IEEE80211_CCK_RATE_11MB; + break; + + case 4: + val = IEEE80211_OFDM_RATE_6MB; + break; + + case 5: + val = IEEE80211_OFDM_RATE_9MB; + break; + + case 6: + val = IEEE80211_OFDM_RATE_12MB; + break; + + case 7: + val = IEEE80211_OFDM_RATE_18MB; + break; + + case 8: + val = IEEE80211_OFDM_RATE_24MB; + break; + + case 9: + val = IEEE80211_OFDM_RATE_36MB; + break; + + case 10: + val = IEEE80211_OFDM_RATE_48MB; + break; + + case 11: + val = IEEE80211_OFDM_RATE_54MB; + break; + + } + + return val; + +} + +int is_basicrate(_adapter *padapter, unsigned char rate); +int is_basicrate(_adapter *padapter, unsigned char rate) +{ + int i; + unsigned char val; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + for (i = 0; i < NumRates; i++) { + val = pmlmeext->basicrate[i]; + + if ((val != 0xff) && (val != 0xfe)) { + if (rate == ratetbl_val_2wifirate(val)) + return _TRUE; + } + } + + return _FALSE; +} + +unsigned int ratetbl2rateset(_adapter *padapter, unsigned char *rateset); +unsigned int ratetbl2rateset(_adapter *padapter, unsigned char *rateset) +{ + int i; + unsigned char rate; + unsigned int len = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + for (i = 0; i < NumRates; i++) { + rate = pmlmeext->datarate[i]; + + if (rtw_get_oper_ch(padapter) > 14 && rate < _6M_RATE_) /*5G no support CCK rate*/ + continue; + + switch (rate) { + case 0xff: + return len; + + case 0xfe: + continue; + + default: + rate = ratetbl_val_2wifirate(rate); + + if (is_basicrate(padapter, rate) == _TRUE) + rate |= IEEE80211_BASIC_RATE_MASK; + + rateset[len] = rate; + len++; + break; + } + } + return len; +} + +void get_rate_set(_adapter *padapter, unsigned char *pbssrate, int *bssrate_len) +{ + unsigned char supportedrates[NumRates]; + + _rtw_memset(supportedrates, 0, NumRates); + *bssrate_len = ratetbl2rateset(padapter, supportedrates); + _rtw_memcpy(pbssrate, supportedrates, *bssrate_len); +} + +void set_mcs_rate_by_mask(u8 *mcs_set, u32 mask) +{ + u8 mcs_rate_1r = (u8)(mask & 0xff); + u8 mcs_rate_2r = (u8)((mask >> 8) & 0xff); + u8 mcs_rate_3r = (u8)((mask >> 16) & 0xff); + u8 mcs_rate_4r = (u8)((mask >> 24) & 0xff); + + mcs_set[0] &= mcs_rate_1r; + mcs_set[1] &= mcs_rate_2r; + mcs_set[2] &= mcs_rate_3r; + mcs_set[3] &= mcs_rate_4r; +} + +void UpdateBrateTbl( + IN PADAPTER Adapter, + IN u8 *mBratesOS +) +{ + u8 i; + u8 rate; + + /* 1M, 2M, 5.5M, 11M, 6M, 12M, 24M are mandatory. */ + for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { + rate = mBratesOS[i] & 0x7f; + switch (rate) { + case IEEE80211_CCK_RATE_1MB: + case IEEE80211_CCK_RATE_2MB: + case IEEE80211_CCK_RATE_5MB: + case IEEE80211_CCK_RATE_11MB: + case IEEE80211_OFDM_RATE_6MB: + case IEEE80211_OFDM_RATE_12MB: + case IEEE80211_OFDM_RATE_24MB: + mBratesOS[i] |= IEEE80211_BASIC_RATE_MASK; + break; + } + } + +} + +void UpdateBrateTblForSoftAP(u8 *bssrateset, u32 bssratelen) +{ + u8 i; + u8 rate; + + for (i = 0; i < bssratelen; i++) { + rate = bssrateset[i] & 0x7f; + switch (rate) { + case IEEE80211_CCK_RATE_1MB: + case IEEE80211_CCK_RATE_2MB: + case IEEE80211_CCK_RATE_5MB: + case IEEE80211_CCK_RATE_11MB: + bssrateset[i] |= IEEE80211_BASIC_RATE_MASK; + break; + } + } + +} +void Set_MSR(_adapter *padapter, u8 type) +{ + rtw_hal_set_hwreg(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type)); +} + +inline u8 rtw_get_oper_ch(_adapter *adapter) +{ + return adapter_to_dvobj(adapter)->oper_channel; +} + +inline void rtw_set_oper_ch(_adapter *adapter, u8 ch) +{ +#ifdef DBG_CH_SWITCH + const int len = 128; + char msg[128] = {0}; + int cnt = 0; + int i = 0; +#endif /* DBG_CH_SWITCH */ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + + if (dvobj->oper_channel != ch) { + dvobj->on_oper_ch_time = rtw_get_current_time(); + +#ifdef DBG_CH_SWITCH + cnt += snprintf(msg + cnt, len - cnt, "switch to ch %3u", ch); + + for (i = 0; i < dvobj->iface_nums; i++) { + _adapter *iface = dvobj->padapters[i]; + cnt += snprintf(msg + cnt, len - cnt, " ["ADPT_FMT":", ADPT_ARG(iface)); + if (iface->mlmeextpriv.cur_channel == ch) + cnt += snprintf(msg + cnt, len - cnt, "C"); + else + cnt += snprintf(msg + cnt, len - cnt, "_"); + if (iface->wdinfo.listen_channel == ch && !rtw_p2p_chk_state(&iface->wdinfo, P2P_STATE_NONE)) + cnt += snprintf(msg + cnt, len - cnt, "L"); + else + cnt += snprintf(msg + cnt, len - cnt, "_"); + cnt += snprintf(msg + cnt, len - cnt, "]"); + } + + RTW_INFO(FUNC_ADPT_FMT" %s\n", FUNC_ADPT_ARG(adapter), msg); +#endif /* DBG_CH_SWITCH */ + } + + dvobj->oper_channel = ch; +} + +inline u8 rtw_get_oper_bw(_adapter *adapter) +{ + return adapter_to_dvobj(adapter)->oper_bwmode; +} + +inline void rtw_set_oper_bw(_adapter *adapter, u8 bw) +{ + adapter_to_dvobj(adapter)->oper_bwmode = bw; +} + +inline u8 rtw_get_oper_choffset(_adapter *adapter) +{ + return adapter_to_dvobj(adapter)->oper_ch_offset; +} + +inline void rtw_set_oper_choffset(_adapter *adapter, u8 offset) +{ + adapter_to_dvobj(adapter)->oper_ch_offset = offset; +} + +u8 rtw_get_offset_by_chbw(u8 ch, u8 bw, u8 *r_offset) +{ + u8 valid = 1; + u8 offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + + if (bw == CHANNEL_WIDTH_20) + goto exit; + + if (bw >= CHANNEL_WIDTH_80 && ch <= 14) { + valid = 0; + goto exit; + } + + if (ch >= 1 && ch <= 4) + offset = HAL_PRIME_CHNL_OFFSET_LOWER; + else if (ch >= 5 && ch <= 9) { + if (*r_offset == HAL_PRIME_CHNL_OFFSET_LOWER || *r_offset == HAL_PRIME_CHNL_OFFSET_UPPER) + offset = *r_offset; /* both lower and upper is valid, obey input value */ + else + offset = HAL_PRIME_CHNL_OFFSET_UPPER; /* default use upper */ + } else if (ch >= 10 && ch <= 13) + offset = HAL_PRIME_CHNL_OFFSET_UPPER; + else if (ch == 14) { + valid = 0; /* ch14 doesn't support 40MHz bandwidth */ + goto exit; + } else if (ch >= 36 && ch <= 177) { + switch (ch) { + case 36: + case 44: + case 52: + case 60: + case 100: + case 108: + case 116: + case 124: + case 132: + case 140: + case 149: + case 157: + case 165: + case 173: + offset = HAL_PRIME_CHNL_OFFSET_LOWER; + break; + case 40: + case 48: + case 56: + case 64: + case 104: + case 112: + case 120: + case 128: + case 136: + case 144: + case 153: + case 161: + case 169: + case 177: + offset = HAL_PRIME_CHNL_OFFSET_UPPER; + break; + default: + valid = 0; + break; + } + } else + valid = 0; + +exit: + if (valid && r_offset) + *r_offset = offset; + return valid; +} + +u8 rtw_get_offset_by_ch(u8 channel) +{ + u8 offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + + if (channel >= 1 && channel <= 4) + offset = HAL_PRIME_CHNL_OFFSET_LOWER; + else if (channel >= 5 && channel <= 14) + offset = HAL_PRIME_CHNL_OFFSET_UPPER; + else { + switch (channel) { + case 36: + case 44: + case 52: + case 60: + case 100: + case 108: + case 116: + case 124: + case 132: + case 149: + case 157: + offset = HAL_PRIME_CHNL_OFFSET_LOWER; + break; + case 40: + case 48: + case 56: + case 64: + case 104: + case 112: + case 120: + case 128: + case 136: + case 153: + case 161: + offset = HAL_PRIME_CHNL_OFFSET_UPPER; + break; + default: + offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + break; + } + + } + + return offset; + +} + +u8 rtw_get_center_ch(u8 channel, u8 chnl_bw, u8 chnl_offset) +{ + u8 center_ch = channel; + + if (chnl_bw == CHANNEL_WIDTH_80) { + if (channel == 36 || channel == 40 || channel == 44 || channel == 48) + center_ch = 42; + else if (channel == 52 || channel == 56 || channel == 60 || channel == 64) + center_ch = 58; + else if (channel == 100 || channel == 104 || channel == 108 || channel == 112) + center_ch = 106; + else if (channel == 116 || channel == 120 || channel == 124 || channel == 128) + center_ch = 122; + else if (channel == 132 || channel == 136 || channel == 140 || channel == 144) + center_ch = 138; + else if (channel == 149 || channel == 153 || channel == 157 || channel == 161) + center_ch = 155; + else if (channel == 165 || channel == 169 || channel == 173 || channel == 177) + center_ch = 171; + else if (channel <= 14) + center_ch = 7; + } else if (chnl_bw == CHANNEL_WIDTH_40) { + if (chnl_offset == HAL_PRIME_CHNL_OFFSET_LOWER) + center_ch = channel + 2; + else + center_ch = channel - 2; + } else if (chnl_bw == CHANNEL_WIDTH_20) + center_ch = channel; + else + rtw_warn_on(1); + + return center_ch; +} + +inline u32 rtw_get_on_oper_ch_time(_adapter *adapter) +{ + return adapter_to_dvobj(adapter)->on_oper_ch_time; +} + +inline u32 rtw_get_on_cur_ch_time(_adapter *adapter) +{ + if (adapter->mlmeextpriv.cur_channel == adapter_to_dvobj(adapter)->oper_channel) + return adapter_to_dvobj(adapter)->on_oper_ch_time; + else + return 0; +} + +void set_channel_bwmode(_adapter *padapter, unsigned char channel, unsigned char channel_offset, unsigned short bwmode) +{ + u8 center_ch, chnl_offset80 = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; +#if (defined(CONFIG_TDLS) && defined(CONFIG_TDLS_CH_SW)) || defined(CONFIG_MCC_MODE) + u8 iqk_info_backup = _FALSE; +#endif + + if (padapter->bNotifyChannelChange) + RTW_INFO("[%s] ch = %d, offset = %d, bwmode = %d\n", __FUNCTION__, channel, channel_offset, bwmode); + + center_ch = rtw_get_center_ch(channel, bwmode, channel_offset); + + if (bwmode == CHANNEL_WIDTH_80) { + if (center_ch > channel) + chnl_offset80 = HAL_PRIME_CHNL_OFFSET_LOWER; + else if (center_ch < channel) + chnl_offset80 = HAL_PRIME_CHNL_OFFSET_UPPER; + else + chnl_offset80 = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + } + _enter_critical_mutex(&(adapter_to_dvobj(padapter)->setch_mutex), NULL); + +#ifdef CONFIG_MCC_MODE + if (MCC_EN(padapter)) { + /* driver doesn't set channel setting reg under MCC */ + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) { + RTW_INFO("Warning: Do not set channel setting reg MCC mode\n"); + rtw_warn_on(1); + } + } +#endif + +#ifdef CONFIG_DFS_MASTER + { + struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter); + bool ori_overlap_radar_detect_ch = rtw_rfctl_overlap_radar_detect_ch(rfctl); + bool new_overlap_radar_detect_ch = _rtw_rfctl_overlap_radar_detect_ch(rfctl, channel, bwmode, channel_offset); + + if (new_overlap_radar_detect_ch) + rtw_odm_radar_detect_enable(padapter); + + if (new_overlap_radar_detect_ch && IS_CH_WAITING(rfctl)) { + u8 pause = 0xFF; + + rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, &pause); + } +#endif /* CONFIG_DFS_MASTER */ + + /* set Channel */ + /* saved channel/bw info */ + rtw_set_oper_ch(padapter, channel); + rtw_set_oper_bw(padapter, bwmode); + rtw_set_oper_choffset(padapter, channel_offset); + +#if (defined(CONFIG_TDLS) && defined(CONFIG_TDLS_CH_SW)) || defined(CONFIG_MCC_MODE) + /* To check if we need to backup iqk info after switch chnl & bw */ + { + u8 take_care_iqk, do_iqk; + + rtw_hal_get_hwreg(padapter, HW_VAR_CH_SW_NEED_TO_TAKE_CARE_IQK_INFO, &take_care_iqk); + rtw_hal_get_hwreg(padapter, HW_VAR_DO_IQK, &do_iqk); + if ((take_care_iqk == _TRUE) && (do_iqk == _TRUE)) + iqk_info_backup = _TRUE; + } +#endif + + rtw_hal_set_chnl_bw(padapter, center_ch, bwmode, channel_offset, chnl_offset80); /* set center channel */ + +#if (defined(CONFIG_TDLS) && defined(CONFIG_TDLS_CH_SW)) || defined(CONFIG_MCC_MODE) + if (iqk_info_backup == _TRUE) + rtw_hal_ch_sw_iqk_info_backup(padapter); +#endif + +#ifdef CONFIG_DFS_MASTER + if (ori_overlap_radar_detect_ch && !new_overlap_radar_detect_ch) { + u8 pause = 0x00; + + rtw_odm_radar_detect_disable(padapter); + rtw_hal_set_hwreg(padapter, HW_VAR_TXPAUSE, &pause); + } + } +#endif /* CONFIG_DFS_MASTER */ + + _exit_critical_mutex(&(adapter_to_dvobj(padapter)->setch_mutex), NULL); +} + +int get_bsstype(unsigned short capability) +{ + if (capability & BIT(0)) + return WIFI_FW_AP_STATE; + else if (capability & BIT(1)) + return WIFI_FW_ADHOC_STATE; + else + return 0; +} + +__inline u8 *get_my_bssid(WLAN_BSSID_EX *pnetwork) +{ + return pnetwork->MacAddress; +} + +u16 get_beacon_interval(WLAN_BSSID_EX *bss) +{ + unsigned short val; + _rtw_memcpy((unsigned char *)&val, rtw_get_beacon_interval_from_ie(bss->IEs), 2); + + return le16_to_cpu(val); + +} + +int is_client_associated_to_ap(_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext; + struct mlme_ext_info *pmlmeinfo; + + if (!padapter) + return _FAIL; + + pmlmeext = &padapter->mlmeextpriv; + pmlmeinfo = &(pmlmeext->mlmext_info); + + if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE)) + return _TRUE; + else + return _FAIL; +} + +int is_client_associated_to_ibss(_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) + return _TRUE; + else + return _FAIL; +} + +int is_IBSS_empty(_adapter *padapter) +{ + int i; + struct macid_ctl_t *macid_ctl = &padapter->dvobj->macid_ctl; + + for (i = 0; i < macid_ctl->num; i++) { + if (!rtw_macid_is_used(macid_ctl, i)) + continue; + if (rtw_macid_get_if_g(macid_ctl, i) != padapter->iface_id) + continue; + if (!GET_H2CCMD_MSRRPT_PARM_OPMODE(&macid_ctl->h2c_msr[i])) + continue; + if (GET_H2CCMD_MSRRPT_PARM_ROLE(&macid_ctl->h2c_msr[i]) == H2C_MSR_ROLE_ADHOC) + return _FAIL; + } + + return _TRUE; +} + +unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval) +{ + if ((bcn_interval << 2) < WAIT_FOR_BCN_TO_MIN) + return WAIT_FOR_BCN_TO_MIN; + else if ((bcn_interval << 2) > WAIT_FOR_BCN_TO_MAX) + return WAIT_FOR_BCN_TO_MAX; + else + return bcn_interval << 2; +} + +void CAM_empty_entry( + PADAPTER Adapter, + u8 ucIndex +) +{ + rtw_hal_set_hwreg(Adapter, HW_VAR_CAM_EMPTY_ENTRY, (u8 *)(&ucIndex)); +} + +void invalidate_cam_all(_adapter *padapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + u8 val8 = 0; + + rtw_hal_set_hwreg(padapter, HW_VAR_CAM_INVALID_ALL, &val8); + + _enter_critical_bh(&cam_ctl->lock, &irqL); + rtw_sec_cam_map_clr_all(&cam_ctl->used); + _rtw_memset(dvobj->cam_cache, 0, sizeof(struct sec_cam_ent) * SEC_CAM_ENT_NUM_SW_LIMIT); + _exit_critical_bh(&cam_ctl->lock, &irqL); +} + +void _clear_cam_entry(_adapter *padapter, u8 entry) +{ + unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + unsigned char null_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + rtw_sec_write_cam_ent(padapter, entry, 0, null_sta, null_key); +} + +inline void write_cam(_adapter *adapter, u8 id, u16 ctrl, u8 *mac, u8 *key) +{ +#ifdef CONFIG_WRITE_CACHE_ONLY + write_cam_cache(adapter, id , ctrl, mac, key); +#else + rtw_sec_write_cam_ent(adapter, id, ctrl, mac, key); + write_cam_cache(adapter, id , ctrl, mac, key); +#endif +} + +inline void clear_cam_entry(_adapter *adapter, u8 id) +{ + _clear_cam_entry(adapter, id); + clear_cam_cache(adapter, id); +} + +inline void write_cam_from_cache(_adapter *adapter, u8 id) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + struct sec_cam_ent cache; + + _enter_critical_bh(&cam_ctl->lock, &irqL); + _rtw_memcpy(&cache, &dvobj->cam_cache[id], sizeof(struct sec_cam_ent)); + _exit_critical_bh(&cam_ctl->lock, &irqL); + + rtw_sec_write_cam_ent(adapter, id, cache.ctrl, cache.mac, cache.key); +} +void write_cam_cache(_adapter *adapter, u8 id, u16 ctrl, u8 *mac, u8 *key) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + + _enter_critical_bh(&cam_ctl->lock, &irqL); + + dvobj->cam_cache[id].ctrl = ctrl; + _rtw_memcpy(dvobj->cam_cache[id].mac, mac, ETH_ALEN); + _rtw_memcpy(dvobj->cam_cache[id].key, key, 16); + + _exit_critical_bh(&cam_ctl->lock, &irqL); +} + +void clear_cam_cache(_adapter *adapter, u8 id) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + + _enter_critical_bh(&cam_ctl->lock, &irqL); + + _rtw_memset(&(dvobj->cam_cache[id]), 0, sizeof(struct sec_cam_ent)); + + _exit_critical_bh(&cam_ctl->lock, &irqL); +} + +inline bool _rtw_camctl_chk_cap(_adapter *adapter, u8 cap) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + + if (cam_ctl->sec_cap & cap) + return _TRUE; + return _FALSE; +} + +inline void _rtw_camctl_set_flags(_adapter *adapter, u32 flags) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + + cam_ctl->flags |= flags; +} + +inline void rtw_camctl_set_flags(_adapter *adapter, u32 flags) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + + _enter_critical_bh(&cam_ctl->lock, &irqL); + _rtw_camctl_set_flags(adapter, flags); + _exit_critical_bh(&cam_ctl->lock, &irqL); +} + +inline void _rtw_camctl_clr_flags(_adapter *adapter, u32 flags) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + + cam_ctl->flags &= ~flags; +} + +inline void rtw_camctl_clr_flags(_adapter *adapter, u32 flags) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + + _enter_critical_bh(&cam_ctl->lock, &irqL); + _rtw_camctl_clr_flags(adapter, flags); + _exit_critical_bh(&cam_ctl->lock, &irqL); +} + +inline bool _rtw_camctl_chk_flags(_adapter *adapter, u32 flags) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + + if (cam_ctl->flags & flags) + return _TRUE; + return _FALSE; +} + +void dump_sec_cam_map(void *sel, struct sec_cam_bmp *map, u8 max_num) +{ + RTW_PRINT_SEL(sel, "0x%08x\n", map->m0); +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 32) + if (max_num && max_num > 32) + RTW_PRINT_SEL(sel, "0x%08x\n", map->m1); +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 64) + if (max_num && max_num > 64) + RTW_PRINT_SEL(sel, "0x%08x\n", map->m2); +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 96) + if (max_num && max_num > 96) + RTW_PRINT_SEL(sel, "0x%08x\n", map->m3); +#endif +} + +inline bool rtw_sec_camid_is_set(struct sec_cam_bmp *map, u8 id) +{ + if (id < 32) + return map->m0 & BIT(id); +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 32) + else if (id < 64) + return map->m1 & BIT(id - 32); +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 64) + else if (id < 96) + return map->m2 & BIT(id - 64); +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 96) + else if (id < 128) + return map->m3 & BIT(id - 96); +#endif + else + rtw_warn_on(1); + + return 0; +} + +inline void rtw_sec_cam_map_set(struct sec_cam_bmp *map, u8 id) +{ + if (id < 32) + map->m0 |= BIT(id); +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 32) + else if (id < 64) + map->m1 |= BIT(id - 32); +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 64) + else if (id < 96) + map->m2 |= BIT(id - 64); +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 96) + else if (id < 128) + map->m3 |= BIT(id - 96); +#endif + else + rtw_warn_on(1); +} + +inline void rtw_sec_cam_map_clr(struct sec_cam_bmp *map, u8 id) +{ + if (id < 32) + map->m0 &= ~BIT(id); +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 32) + else if (id < 64) + map->m1 &= ~BIT(id - 32); +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 64) + else if (id < 96) + map->m2 &= ~BIT(id - 64); +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 96) + else if (id < 128) + map->m3 &= ~BIT(id - 96); +#endif + else + rtw_warn_on(1); +} + +inline void rtw_sec_cam_map_clr_all(struct sec_cam_bmp *map) +{ + map->m0 = 0; +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 32) + map->m1 = 0; +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 64) + map->m2 = 0; +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 96) + map->m3 = 0; +#endif +} + +inline bool rtw_sec_camid_is_drv_forbid(struct cam_ctl_t *cam_ctl, u8 id) +{ + struct sec_cam_bmp forbid_map; + + forbid_map.m0 = 0x00000ff0; +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 32) + forbid_map.m1 = 0x00000000; +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 64) + forbid_map.m2 = 0x00000000; +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 96) + forbid_map.m3 = 0x00000000; +#endif + + if (id < 32) + return forbid_map.m0 & BIT(id); +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 32) + else if (id < 64) + return forbid_map.m1 & BIT(id - 32); +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 64) + else if (id < 96) + return forbid_map.m2 & BIT(id - 64); +#endif +#if (SEC_CAM_ENT_NUM_SW_LIMIT > 96) + else if (id < 128) + return forbid_map.m3 & BIT(id - 96); +#endif + else + rtw_warn_on(1); + + return 1; +} + +bool _rtw_sec_camid_is_used(struct cam_ctl_t *cam_ctl, u8 id) +{ + bool ret = _FALSE; + + if (id >= cam_ctl->num) { + rtw_warn_on(1); + goto exit; + } + +#if 0 /* for testing */ + if (rtw_sec_camid_is_drv_forbid(cam_ctl, id)) { + ret = _TRUE; + goto exit; + } +#endif + + ret = rtw_sec_camid_is_set(&cam_ctl->used, id); + +exit: + return ret; +} + +inline bool rtw_sec_camid_is_used(struct cam_ctl_t *cam_ctl, u8 id) +{ + _irqL irqL; + bool ret; + + _enter_critical_bh(&cam_ctl->lock, &irqL); + ret = _rtw_sec_camid_is_used(cam_ctl, id); + _exit_critical_bh(&cam_ctl->lock, &irqL); + + return ret; +} +u8 rtw_get_sec_camid(_adapter *adapter, u8 max_bk_key_num, u8 *sec_key_id) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + int i; + _irqL irqL; + u8 sec_cam_num = 0; + + _enter_critical_bh(&cam_ctl->lock, &irqL); + for (i = 0; i < cam_ctl->num; i++) { + if (_rtw_sec_camid_is_used(cam_ctl, i)) { + sec_key_id[sec_cam_num++] = i; + if (sec_cam_num == max_bk_key_num) + break; + } + } + _exit_critical_bh(&cam_ctl->lock, &irqL); + + return sec_cam_num; +} + +inline bool _rtw_camid_is_gk(_adapter *adapter, u8 cam_id) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + bool ret = _FALSE; + + if (cam_id >= cam_ctl->num) { + rtw_warn_on(1); + goto exit; + } + + if (_rtw_sec_camid_is_used(cam_ctl, cam_id) == _FALSE) + goto exit; + + ret = (dvobj->cam_cache[cam_id].ctrl & BIT6) ? _TRUE : _FALSE; + +exit: + return ret; +} + +inline bool rtw_camid_is_gk(_adapter *adapter, u8 cam_id) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + bool ret; + + _enter_critical_bh(&cam_ctl->lock, &irqL); + ret = _rtw_camid_is_gk(adapter, cam_id); + _exit_critical_bh(&cam_ctl->lock, &irqL); + + return ret; +} + +bool cam_cache_chk(_adapter *adapter, u8 id, u8 *addr, s16 kid, s8 gk) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + bool ret = _FALSE; + + if (addr && _rtw_memcmp(dvobj->cam_cache[id].mac, addr, ETH_ALEN) == _FALSE) + goto exit; + if (kid >= 0 && kid != (dvobj->cam_cache[id].ctrl & 0x03)) + goto exit; + if (gk != -1 && (gk ? _TRUE : _FALSE) != _rtw_camid_is_gk(adapter, id)) + goto exit; + + ret = _TRUE; + +exit: + return ret; +} + +s16 _rtw_camid_search(_adapter *adapter, u8 *addr, s16 kid, s8 gk) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + int i; + s16 cam_id = -1; + + for (i = 0; i < cam_ctl->num; i++) { + if (cam_cache_chk(adapter, i, addr, kid, gk)) { + cam_id = i; + break; + } + } + + if (0) { + if (addr) + RTW_INFO(FUNC_ADPT_FMT" addr:"MAC_FMT" kid:%d, gk:%d, return cam_id:%d\n" + , FUNC_ADPT_ARG(adapter), MAC_ARG(addr), kid, gk, cam_id); + else + RTW_INFO(FUNC_ADPT_FMT" addr:%p kid:%d, gk:%d, return cam_id:%d\n" + , FUNC_ADPT_ARG(adapter), addr, kid, gk, cam_id); + } + + return cam_id; +} + +s16 rtw_camid_search(_adapter *adapter, u8 *addr, s16 kid, s8 gk) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + s16 cam_id = -1; + + _enter_critical_bh(&cam_ctl->lock, &irqL); + cam_id = _rtw_camid_search(adapter, addr, kid, gk); + _exit_critical_bh(&cam_ctl->lock, &irqL); + + return cam_id; +} + +s16 rtw_get_camid(_adapter *adapter, struct sta_info *sta, u8 *addr, s16 kid) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + int i; +#if 0 /* for testing */ + static u8 start_id = 0; +#else + u8 start_id = 0; +#endif + s16 cam_id = -1; + + if (addr == NULL) { + RTW_PRINT(FUNC_ADPT_FMT" mac_address is NULL\n" + , FUNC_ADPT_ARG(adapter)); + rtw_warn_on(1); + goto _exit; + } + + /* find cam entry which has the same addr, kid (, gk bit) */ + if (_rtw_camctl_chk_cap(adapter, SEC_CAP_CHK_BMC) == _TRUE) + i = _rtw_camid_search(adapter, addr, kid, sta ? _FALSE : _TRUE); + else + i = _rtw_camid_search(adapter, addr, kid, -1); + + if (i >= 0) { + cam_id = i; + goto _exit; + } + + for (i = 0; i < cam_ctl->num; i++) { + /* bypass default key which is allocated statically */ +#ifndef CONFIG_CONCURRENT_MODE + if (((i + start_id) % cam_ctl->num) < 4) + continue; +#endif + if (_rtw_sec_camid_is_used(cam_ctl, ((i + start_id) % cam_ctl->num)) == _FALSE) + break; + } + + if (i == cam_ctl->num) { + if (sta) + RTW_PRINT(FUNC_ADPT_FMT" pairwise key with "MAC_FMT" id:%u no room\n" + , FUNC_ADPT_ARG(adapter), MAC_ARG(addr), kid); + else + RTW_PRINT(FUNC_ADPT_FMT" group key with "MAC_FMT" id:%u no room\n" + , FUNC_ADPT_ARG(adapter), MAC_ARG(addr), kid); + rtw_warn_on(1); + goto _exit; + } + + cam_id = ((i + start_id) % cam_ctl->num); + start_id = ((i + start_id + 1) % cam_ctl->num); + +_exit: + return cam_id; +} + +s16 rtw_camid_alloc(_adapter *adapter, struct sta_info *sta, u8 kid, bool *used) +{ + struct mlme_ext_info *mlmeinfo = &adapter->mlmeextpriv.mlmext_info; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + s16 cam_id = -1; + + *used = _FALSE; + + _enter_critical_bh(&cam_ctl->lock, &irqL); + + if ((((mlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) || ((mlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) + && !sta) { +#ifndef CONFIG_CONCURRENT_MODE + /* AP/Ad-hoc mode group key static alloction to default key by key ID on Non-concurrent*/ + if (kid > 3) { + RTW_PRINT(FUNC_ADPT_FMT" group key with invalid key id:%u\n" + , FUNC_ADPT_ARG(adapter), kid); + rtw_warn_on(1); + goto bitmap_handle; + } + cam_id = kid; +#else + u8 *addr = adapter_mac_addr(adapter); + + cam_id = rtw_get_camid(adapter, sta, addr, kid); + if (1) + RTW_PRINT(FUNC_ADPT_FMT" group key with "MAC_FMT" assigned cam_id:%u\n" + , FUNC_ADPT_ARG(adapter), MAC_ARG(addr), cam_id); +#endif + } else { + u8 *addr = sta ? sta->hwaddr : NULL; + + if (!sta) { + if (!(mlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) { + /* bypass STA mode group key setting before connected(ex:WEP) because bssid is not ready */ + goto bitmap_handle; + } + addr = get_bssid(&adapter->mlmepriv);/*A2*/ + } + cam_id = rtw_get_camid(adapter, sta, addr, kid); + } + + +bitmap_handle: + if (cam_id >= 0) { + *used = _rtw_sec_camid_is_used(cam_ctl, cam_id); + rtw_sec_cam_map_set(&cam_ctl->used, cam_id); + } + + _exit_critical_bh(&cam_ctl->lock, &irqL); + + return cam_id; +} + +void rtw_camid_set(_adapter *adapter, u8 cam_id) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + + _enter_critical_bh(&cam_ctl->lock, &irqL); + + if (cam_id < cam_ctl->num) + rtw_sec_cam_map_set(&cam_ctl->used, cam_id); + + _exit_critical_bh(&cam_ctl->lock, &irqL); +} + +void rtw_camid_free(_adapter *adapter, u8 cam_id) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + + _enter_critical_bh(&cam_ctl->lock, &irqL); + + if (cam_id < cam_ctl->num) + rtw_sec_cam_map_clr(&cam_ctl->used, cam_id); + + _exit_critical_bh(&cam_ctl->lock, &irqL); +} + +/*Must pause TX/RX before use this API*/ +inline void rtw_sec_cam_swap(_adapter *adapter, u8 cam_id_a, u8 cam_id_b) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + struct sec_cam_ent cache_a, cache_b; + _irqL irqL; + bool cam_a_used, cam_b_used; + + if (1) + RTW_INFO(ADPT_FMT" - sec_cam %d,%d swap\n", ADPT_ARG(adapter), cam_id_a, cam_id_b); + + if (cam_id_a == cam_id_b) + return; + +#ifdef CONFIG_CONCURRENT_MODE + rtw_mi_update_ap_bmc_camid(adapter, cam_id_a, cam_id_b); +#endif + + /*setp-1. backup org cam_info*/ + _enter_critical_bh(&cam_ctl->lock, &irqL); + + cam_a_used = _rtw_sec_camid_is_used(cam_ctl, cam_id_a); + cam_b_used = _rtw_sec_camid_is_used(cam_ctl, cam_id_b); + + if (cam_a_used) + _rtw_memcpy(&cache_a, &dvobj->cam_cache[cam_id_a], sizeof(struct sec_cam_ent)); + + if (cam_b_used) + _rtw_memcpy(&cache_b, &dvobj->cam_cache[cam_id_b], sizeof(struct sec_cam_ent)); + + _exit_critical_bh(&cam_ctl->lock, &irqL); + + /*setp-2. clean cam_info*/ + if (cam_a_used) { + rtw_camid_free(adapter, cam_id_a); + clear_cam_entry(adapter, cam_id_a); + } + if (cam_b_used) { + rtw_camid_free(adapter, cam_id_b); + clear_cam_entry(adapter, cam_id_b); + } + + /*setp-3. set cam_info*/ + if (cam_a_used) { + write_cam(adapter, cam_id_b, cache_a.ctrl, cache_a.mac, cache_a.key); + rtw_camid_set(adapter, cam_id_b); + } + + if (cam_b_used) { + write_cam(adapter, cam_id_a, cache_b.ctrl, cache_b.mac, cache_b.key); + rtw_camid_set(adapter, cam_id_a); + } +} + +s16 rtw_get_empty_cam_entry(_adapter *adapter, u8 start_camid) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + int i; + s16 cam_id = -1; + + _enter_critical_bh(&cam_ctl->lock, &irqL); + for (i = start_camid; i < cam_ctl->num; i++) { + if (_FALSE == _rtw_sec_camid_is_used(cam_ctl, i)) { + cam_id = i; + break; + } + } + _exit_critical_bh(&cam_ctl->lock, &irqL); + + return cam_id; +} +void rtw_clean_dk_section(_adapter *adapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = dvobj_to_sec_camctl(dvobj); + s16 ept_cam_id; + int i; + + for (i = 0; i < 4; i++) { + if (rtw_sec_camid_is_used(cam_ctl, i)) { + ept_cam_id = rtw_get_empty_cam_entry(adapter, 4); + if (ept_cam_id > 0) + rtw_sec_cam_swap(adapter, i, ept_cam_id); + } + } +} +void rtw_clean_hw_dk_cam(_adapter *adapter) +{ + int i; + + for (i = 0; i < 4; i++) + rtw_sec_clr_cam_ent(adapter, i); + /*_clear_cam_entry(adapter, i);*/ +} + +void flush_all_cam_entry(_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct security_priv *psecpriv = &padapter->securitypriv; + +#ifdef CONFIG_CONCURRENT_MODE + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta; + + psta = rtw_get_stainfo(pstapriv, pmlmeinfo->network.MacAddress); + if (psta) { + if (psta->state & WIFI_AP_STATE) { + /*clear cam when ap free per sta_info*/ + } else + rtw_clearstakey_cmd(padapter, psta, _FALSE); + } + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { +#if 1 + int cam_id = -1; + u8 *addr = adapter_mac_addr(padapter); + + while ((cam_id = rtw_camid_search(padapter, addr, -1, -1)) >= 0) { + RTW_PRINT("clear wep or group key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(addr), cam_id); + clear_cam_entry(padapter, cam_id); + rtw_camid_free(padapter, cam_id); + } +#else + /* clear default key */ + int i, cam_id; + u8 null_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; + + for (i = 0; i < 4; i++) { + cam_id = rtw_camid_search(padapter, null_addr, i, -1); + if (cam_id >= 0) { + clear_cam_entry(padapter, cam_id); + rtw_camid_free(padapter, cam_id); + } + } + /* clear default key related key search setting */ + rtw_hal_set_hwreg(padapter, HW_VAR_SEC_DK_CFG, (u8 *)_FALSE); +#endif + } + +#else /*NON CONFIG_CONCURRENT_MODE*/ + + invalidate_cam_all(padapter); + /* clear default key related key search setting */ + rtw_hal_set_hwreg(padapter, HW_VAR_SEC_DK_CFG, (u8 *)_FALSE); +#endif +} + +#if defined(CONFIG_P2P) && defined(CONFIG_WFD) +void rtw_process_wfd_ie(_adapter *adapter, u8 *wfd_ie, u8 wfd_ielen, const char *tag) +{ + struct wifidirect_info *wdinfo = &adapter->wdinfo; + + u8 *attr_content; + u32 attr_contentlen = 0; + + if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST)) + return; + + RTW_INFO("[%s] Found WFD IE\n", tag); + attr_content = rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, NULL, &attr_contentlen); + if (attr_content && attr_contentlen) { + wdinfo->wfd_info->peer_rtsp_ctrlport = RTW_GET_BE16(attr_content + 2); + RTW_INFO("[%s] Peer PORT NUM = %d\n", tag, wdinfo->wfd_info->peer_rtsp_ctrlport); + } +} + +void rtw_process_wfd_ies(_adapter *adapter, u8 *ies, u8 ies_len, const char *tag) +{ + u8 *wfd_ie; + u32 wfd_ielen; + + if (!hal_chk_wl_func(adapter, WL_FUNC_MIRACAST)) + return; + + wfd_ie = rtw_get_wfd_ie(ies, ies_len, NULL, &wfd_ielen); + while (wfd_ie) { + rtw_process_wfd_ie(adapter, wfd_ie, wfd_ielen, tag); + wfd_ie = rtw_get_wfd_ie(wfd_ie + wfd_ielen, (ies + ies_len) - (wfd_ie + wfd_ielen), NULL, &wfd_ielen); + } +} +#endif /* defined(CONFIG_P2P) && defined(CONFIG_WFD) */ + +int WMM_param_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) +{ + /* struct registry_priv *pregpriv = &padapter->registrypriv; */ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if (pmlmepriv->qospriv.qos_option == 0) { + pmlmeinfo->WMM_enable = 0; + return _FALSE; + } + + if (_rtw_memcmp(&(pmlmeinfo->WMM_param), (pIE->data + 6), sizeof(struct WMM_para_element))) + return _FALSE; + else + _rtw_memcpy(&(pmlmeinfo->WMM_param), (pIE->data + 6), sizeof(struct WMM_para_element)); + pmlmeinfo->WMM_enable = 1; + return _TRUE; + +#if 0 + if (pregpriv->wifi_spec == 1) { + if (pmlmeinfo->WMM_enable == 1) { + /* todo: compare the parameter set count & decide wheher to update or not */ + return _FAIL; + } else { + pmlmeinfo->WMM_enable = 1; + _rtw_rtw_memcpy(&(pmlmeinfo->WMM_param), (pIE->data + 6), sizeof(struct WMM_para_element)); + return _TRUE; + } + } else { + pmlmeinfo->WMM_enable = 0; + return _FAIL; + } +#endif + +} + +void WMMOnAssocRsp(_adapter *padapter) +{ + u8 ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime; + u8 acm_mask; + u16 TXOP; + u32 acParm, i; + u32 edca[4], inx[4]; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct registry_priv *pregpriv = &padapter->registrypriv; + + acm_mask = 0; + + if (is_supported_5g(pmlmeext->cur_wireless_mode) || + (pmlmeext->cur_wireless_mode & WIRELESS_11_24N)) + aSifsTime = 16; + else + aSifsTime = 10; + + if (pmlmeinfo->WMM_enable == 0) { + padapter->mlmepriv.acm_mask = 0; + + AIFS = aSifsTime + (2 * pmlmeinfo->slotTime); + + if (pmlmeext->cur_wireless_mode & (WIRELESS_11G | WIRELESS_11A)) { + ECWMin = 4; + ECWMax = 10; + } else if (pmlmeext->cur_wireless_mode & WIRELESS_11B) { + ECWMin = 5; + ECWMax = 10; + } else { + ECWMin = 4; + ECWMax = 10; + } + + TXOP = 0; + acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm)); + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm)); + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm)); + + ECWMin = 2; + ECWMax = 3; + TXOP = 0x2f; + acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm)); + } else { + edca[0] = edca[1] = edca[2] = edca[3] = 0; + + for (i = 0; i < 4; i++) { + ACI = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 5) & 0x03; + ACM = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 4) & 0x01; + + /* AIFS = AIFSN * slot time + SIFS - r2t phy delay */ + AIFS = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN & 0x0f) * pmlmeinfo->slotTime + aSifsTime; + + ECWMin = (pmlmeinfo->WMM_param.ac_param[i].CW & 0x0f); + ECWMax = (pmlmeinfo->WMM_param.ac_param[i].CW & 0xf0) >> 4; + TXOP = le16_to_cpu(pmlmeinfo->WMM_param.ac_param[i].TXOP_limit); + + acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16); + + switch (ACI) { + case 0x0: + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm)); + acm_mask |= (ACM ? BIT(1) : 0); + edca[XMIT_BE_QUEUE] = acParm; + break; + + case 0x1: + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm)); + /* acm_mask |= (ACM? BIT(0):0); */ + edca[XMIT_BK_QUEUE] = acParm; + break; + + case 0x2: + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm)); + acm_mask |= (ACM ? BIT(2) : 0); + edca[XMIT_VI_QUEUE] = acParm; + break; + + case 0x3: + rtw_hal_set_hwreg(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm)); + acm_mask |= (ACM ? BIT(3) : 0); + edca[XMIT_VO_QUEUE] = acParm; + break; + } + + RTW_INFO("WMM(%x): %x, %x\n", ACI, ACM, acParm); + } + + if (padapter->registrypriv.acm_method == 1) + rtw_hal_set_hwreg(padapter, HW_VAR_ACM_CTRL, (u8 *)(&acm_mask)); + else + padapter->mlmepriv.acm_mask = acm_mask; + + inx[0] = 0; + inx[1] = 1; + inx[2] = 2; + inx[3] = 3; + + if (pregpriv->wifi_spec == 1) { + u32 j, tmp, change_inx = _FALSE; + + /* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */ + for (i = 0; i < 4; i++) { + for (j = i + 1; j < 4; j++) { + /* compare CW and AIFS */ + if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) + change_inx = _TRUE; + else if ((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) { + /* compare TXOP */ + if ((edca[j] >> 16) > (edca[i] >> 16)) + change_inx = _TRUE; + } + + if (change_inx) { + tmp = edca[i]; + edca[i] = edca[j]; + edca[j] = tmp; + + tmp = inx[i]; + inx[i] = inx[j]; + inx[j] = tmp; + + change_inx = _FALSE; + } + } + } + } + + for (i = 0; i < 4; i++) { + pxmitpriv->wmm_para_seq[i] = inx[i]; + RTW_INFO("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]); + } +#ifdef CONFIG_WMMPS + if (pmlmeinfo->WMM_param.QoS_info & BIT(7)) + rtw_hal_set_hwreg(padapter, HW_VAR_UAPSD_TID, NULL); +#endif + } +} + +static void bwmode_update_check(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) +{ +#ifdef CONFIG_80211N_HT + unsigned char new_bwmode; + unsigned char new_ch_offset; + struct HT_info_element *pHT_info; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + u8 cbw40_enable = 0; + + if (!pIE) + return; + + if (phtpriv->ht_option == _FALSE) + return; + + if (pmlmeext->cur_bwmode >= CHANNEL_WIDTH_80) + return; + + if (pIE->Length > sizeof(struct HT_info_element)) + return; + + pHT_info = (struct HT_info_element *)pIE->data; + + if (hal_chk_bw_cap(padapter, BW_CAP_40M)) { + if (pmlmeext->cur_channel > 14) { + if (REGSTY_IS_BW_5G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40)) + cbw40_enable = 1; + } else { + if (REGSTY_IS_BW_2G_SUPPORT(pregistrypriv, CHANNEL_WIDTH_40)) + cbw40_enable = 1; + } + } + + if ((pHT_info->infos[0] & BIT(2)) && cbw40_enable) { + new_bwmode = CHANNEL_WIDTH_40; + + switch (pHT_info->infos[0] & 0x3) { + case 1: + new_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; + break; + + case 3: + new_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; + break; + + default: + new_bwmode = CHANNEL_WIDTH_20; + new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + break; + } + } else { + new_bwmode = CHANNEL_WIDTH_20; + new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + } + + + if ((new_bwmode != pmlmeext->cur_bwmode || new_ch_offset != pmlmeext->cur_ch_offset) + && new_bwmode < pmlmeext->cur_bwmode + ) { + pmlmeinfo->bwmode_updated = _TRUE; + + pmlmeext->cur_bwmode = new_bwmode; + pmlmeext->cur_ch_offset = new_ch_offset; + + /* update HT info also */ + HT_info_handler(padapter, pIE); + } else + pmlmeinfo->bwmode_updated = _FALSE; + + + if (_TRUE == pmlmeinfo->bwmode_updated) { + struct sta_info *psta; + WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); + struct sta_priv *pstapriv = &padapter->stapriv; + + /* set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */ + + + /* update ap's stainfo */ + psta = rtw_get_stainfo(pstapriv, cur_network->MacAddress); + if (psta) { + struct ht_priv *phtpriv_sta = &psta->htpriv; + + if (phtpriv_sta->ht_option) { + /* bwmode */ + psta->bw_mode = pmlmeext->cur_bwmode; + phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset; + } else { + psta->bw_mode = CHANNEL_WIDTH_20; + phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + } + + rtw_dm_ra_mask_wk_cmd(padapter, (u8 *)psta); + } + + /* pmlmeinfo->bwmode_updated = _FALSE; */ /* bwmode_updated done, reset it! */ + } +#endif /* CONFIG_80211N_HT */ +} + +void HT_caps_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) +{ +#ifdef CONFIG_80211N_HT + unsigned int i; + u8 rf_type = RF_1T1R; + u8 max_AMPDU_len, min_MPDU_spacing; + u8 cur_ldpc_cap = 0, cur_stbc_cap = 0, cur_beamform_cap = 0, tx_nss = 0; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); + + if (pIE == NULL) + return; + + if (phtpriv->ht_option == _FALSE) + return; + + pmlmeinfo->HT_caps_enable = 1; + + for (i = 0; i < (pIE->Length); i++) { + if (i != 2) { + /* Commented by Albert 2010/07/12 */ + /* Got the endian issue here. */ + pmlmeinfo->HT_caps.u.HT_cap[i] &= (pIE->data[i]); + } else { + /* AMPDU Parameters field */ + + /* Get MIN of MAX AMPDU Length Exp */ + if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3) > (pIE->data[i] & 0x3)) + max_AMPDU_len = (pIE->data[i] & 0x3); + else + max_AMPDU_len = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3); + + /* Get MAX of MIN MPDU Start Spacing */ + if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) > (pIE->data[i] & 0x1c)) + min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c); + else + min_MPDU_spacing = (pIE->data[i] & 0x1c); + + pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para = max_AMPDU_len | min_MPDU_spacing; + } + } + + /* Commented by Albert 2010/07/12 */ + /* Have to handle the endian issue after copying. */ + /* HT_ext_caps didn't be used yet. */ + pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info = le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info); + pmlmeinfo->HT_caps.u.HT_cap_element.HT_ext_caps = le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_ext_caps); + + /* update the MCS set */ + for (i = 0; i < 16; i++) + pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= pmlmeext->default_supported_mcs_set[i]; + + rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); + + switch (tx_nss) { + case 1: + set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_1R); + break; + case 2: + #ifdef CONFIG_DISABLE_MCS13TO15 + if (pmlmeext->cur_bwmode == CHANNEL_WIDTH_40 && pregistrypriv->wifi_spec != 1) + set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R_13TO15_OFF); + else + #endif + set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_2R); + break; + case 3: + set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_3R); + break; + case 4: + set_mcs_rate_by_mask(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_RATE_4R); + break; + default: + RTW_WARN("rf_type:%d or tx_nss:%u is not expected\n", rf_type, hal_spec->tx_nss_num); + } + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + /* Config STBC setting */ + if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX) && GET_HT_CAP_ELE_RX_STBC(pIE->data)) { + SET_FLAG(cur_stbc_cap, STBC_HT_ENABLE_TX); + RTW_INFO("Enable HT Tx STBC !\n"); + } + phtpriv->stbc_cap = cur_stbc_cap; + +#ifdef CONFIG_BEAMFORMING + /* Config Tx beamforming setting */ + if (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE) && + GET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP(pIE->data)) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE); + /* Shift to BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP*/ + SET_FLAG(cur_beamform_cap, GET_HT_CAP_TXBF_CHNL_ESTIMATION_NUM_ANTENNAS(pIE->data) << 6); + } + + if (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE) && + GET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP(pIE->data)) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE); + /* Shift to BEAMFORMING_HT_BEAMFORMER_STEER_NUM*/ + SET_FLAG(cur_beamform_cap, GET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(pIE->data) << 4); + } + phtpriv->beamform_cap = cur_beamform_cap; + if (cur_beamform_cap) + RTW_INFO("AP HT Beamforming Cap = 0x%02X\n", cur_beamform_cap); +#endif /*CONFIG_BEAMFORMING*/ + } else { + /*WIFI_STATION_STATEorI_ADHOC_STATE or WIFI_ADHOC_MASTER_STATE*/ + /* Config LDPC Coding Capability */ + if (TEST_FLAG(phtpriv->ldpc_cap, LDPC_HT_ENABLE_TX) && GET_HT_CAP_ELE_LDPC_CAP(pIE->data)) { + SET_FLAG(cur_ldpc_cap, (LDPC_HT_ENABLE_TX | LDPC_HT_CAP_TX)); + RTW_INFO("Enable HT Tx LDPC!\n"); + } + phtpriv->ldpc_cap = cur_ldpc_cap; + + /* Config STBC setting */ + if (TEST_FLAG(phtpriv->stbc_cap, STBC_HT_ENABLE_TX) && GET_HT_CAP_ELE_RX_STBC(pIE->data)) { + SET_FLAG(cur_stbc_cap, (STBC_HT_ENABLE_TX | STBC_HT_CAP_TX)); + RTW_INFO("Enable HT Tx STBC!\n"); + } + phtpriv->stbc_cap = cur_stbc_cap; + +#ifdef CONFIG_BEAMFORMING +#ifdef RTW_BEAMFORMING_VERSION_2 + /* Config beamforming setting */ + if (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE) && + GET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP(pIE->data)) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE); + /* Shift to BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP*/ + SET_FLAG(cur_beamform_cap, GET_HT_CAP_TXBF_CHNL_ESTIMATION_NUM_ANTENNAS(pIE->data) << 6); + } + + if (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE) && + GET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP(pIE->data)) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE); + /* Shift to BEAMFORMING_HT_BEAMFORMER_STEER_NUM*/ + SET_FLAG(cur_beamform_cap, GET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(pIE->data) << 4); + } +#else /* !RTW_BEAMFORMING_VERSION_2 */ + /* Config Tx beamforming setting */ + if (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE) && + GET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP(pIE->data)) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE); + /* Shift to BEAMFORMING_HT_BEAMFORMEE_CHNL_EST_CAP*/ + SET_FLAG(cur_beamform_cap, GET_HT_CAP_TXBF_CHNL_ESTIMATION_NUM_ANTENNAS(pIE->data) << 6); + } + + if (TEST_FLAG(phtpriv->beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE) && + GET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP(pIE->data)) { + SET_FLAG(cur_beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE); + /* Shift to BEAMFORMING_HT_BEAMFORMER_STEER_NUM*/ + SET_FLAG(cur_beamform_cap, GET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(pIE->data) << 4); + } +#endif /* !RTW_BEAMFORMING_VERSION_2 */ + phtpriv->beamform_cap = cur_beamform_cap; + if (cur_beamform_cap) + RTW_INFO("Client HT Beamforming Cap = 0x%02X\n", cur_beamform_cap); +#endif /*CONFIG_BEAMFORMING*/ + } + +#endif /* CONFIG_80211N_HT */ +} + +void HT_info_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) +{ +#ifdef CONFIG_80211N_HT + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; + + if (pIE == NULL) + return; + + if (phtpriv->ht_option == _FALSE) + return; + + + if (pIE->Length > sizeof(struct HT_info_element)) + return; + + pmlmeinfo->HT_info_enable = 1; + _rtw_memcpy(&(pmlmeinfo->HT_info), pIE->data, pIE->Length); +#endif /* CONFIG_80211N_HT */ + return; +} + +void HTOnAssocRsp(_adapter *padapter) +{ + unsigned char max_AMPDU_len; + unsigned char min_MPDU_spacing; + /* struct registry_priv *pregpriv = &padapter->registrypriv; */ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + RTW_INFO("%s\n", __FUNCTION__); + + if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) + pmlmeinfo->HT_enable = 1; + else { + pmlmeinfo->HT_enable = 0; + /* set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */ + return; + } + + /* handle A-MPDU parameter field */ + /* + AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k + AMPDU_para [4:2]:Min MPDU Start Spacing + */ + max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03; + + min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2; + + rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); + + rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); + +#if 0 /* move to rtw_update_ht_cap() */ + if ((pregpriv->bw_mode > 0) && + (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & BIT(1)) && + (pmlmeinfo->HT_info.infos[0] & BIT(2))) { + /* switch to the 40M Hz mode accoring to the AP */ + pmlmeext->cur_bwmode = CHANNEL_WIDTH_40; + switch ((pmlmeinfo->HT_info.infos[0] & 0x3)) { + case EXTCHNL_OFFSET_UPPER: + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; + break; + + case EXTCHNL_OFFSET_LOWER: + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER; + break; + + default: + pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + break; + } + } +#endif + + /* set_channel_bwmode(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */ + +#if 0 /* move to rtw_update_ht_cap() */ + /* */ + /* Config SM Power Save setting */ + /* */ + pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2; + if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) { +#if 0 + u8 i; + /* update the MCS rates */ + for (i = 0; i < 16; i++) + pmlmeinfo->HT_caps.HT_cap_element.MCS_rate[i] &= MCS_rate_1R[i]; +#endif + RTW_INFO("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __FUNCTION__); + } + + /* */ + /* Config current HT Protection mode. */ + /* */ + pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3; +#endif + +} + +void ERP_IE_handler(_adapter *padapter, PNDIS_802_11_VARIABLE_IEs pIE) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if (pIE->Length > 1) + return; + + pmlmeinfo->ERP_enable = 1; + _rtw_memcpy(&(pmlmeinfo->ERP_IE), pIE->data, pIE->Length); +} + +void VCS_update(_adapter *padapter, struct sta_info *psta) +{ + struct registry_priv *pregpriv = &padapter->registrypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + switch (pregpriv->vrtl_carrier_sense) { /* 0:off 1:on 2:auto */ + case 0: /* off */ + psta->rtsen = 0; + psta->cts2self = 0; + break; + + case 1: /* on */ + if (pregpriv->vcs_type == 1) { /* 1:RTS/CTS 2:CTS to self */ + psta->rtsen = 1; + psta->cts2self = 0; + } else { + psta->rtsen = 0; + psta->cts2self = 1; + } + break; + + case 2: /* auto */ + default: + if (((pmlmeinfo->ERP_enable) && (pmlmeinfo->ERP_IE & BIT(1))) + /*||(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)*/ + ) { + if (pregpriv->vcs_type == 1) { + psta->rtsen = 1; + psta->cts2self = 0; + } else { + psta->rtsen = 0; + psta->cts2self = 1; + } + } else { + psta->rtsen = 0; + psta->cts2self = 0; + } + break; + } +} + +void update_ldpc_stbc_cap(struct sta_info *psta) +{ +#ifdef CONFIG_80211N_HT + +#ifdef CONFIG_80211AC_VHT + if (psta->vhtpriv.vht_option) { + if (TEST_FLAG(psta->vhtpriv.ldpc_cap, LDPC_VHT_ENABLE_TX)) + psta->ldpc = 1; + + if (TEST_FLAG(psta->vhtpriv.stbc_cap, STBC_VHT_ENABLE_TX)) + psta->stbc = 1; + } else +#endif /* CONFIG_80211AC_VHT */ + if (psta->htpriv.ht_option) { + if (TEST_FLAG(psta->htpriv.ldpc_cap, LDPC_HT_ENABLE_TX)) + psta->ldpc = 1; + + if (TEST_FLAG(psta->htpriv.stbc_cap, STBC_HT_ENABLE_TX)) + psta->stbc = 1; + } else { + psta->ldpc = 0; + psta->stbc = 0; + } + +#endif /* CONFIG_80211N_HT */ +} + +int check_ielen(u8 *start, uint len) +{ + int left = len; + u8 *pos = start; + int unknown = 0; + u8 id, elen; + + while (left >= 2) { + id = *pos++; + elen = *pos++; + left -= 2; + + if (elen > left) { + RTW_INFO("IEEE 802.11 element parse failed (id=%d elen=%d left=%lu)\n", + id, elen, (unsigned long) left); + return _FALSE; + } + if ((id == WLAN_EID_VENDOR_SPECIFIC) && (elen < 4)) + return _FALSE; + + left -= elen; + pos += elen; + } + if (left) + return _FALSE; + + return _TRUE; +} + +int validate_beacon_len(u8 *pframe, u32 len) +{ + u8 ie_offset = _BEACON_IE_OFFSET_ + sizeof(struct rtw_ieee80211_hdr_3addr); + + if (len < ie_offset) { + RTW_INFO("%s: incorrect beacon length(%d)\n", __func__, len); + return _FALSE; + } + + if (check_ielen(pframe + ie_offset, len - ie_offset) == _FALSE) + return _FALSE; + + return _TRUE; +} + +/* + * rtw_get_bcn_keys: get beacon keys from recv frame + * + * TODO: + * WLAN_EID_COUNTRY + * WLAN_EID_ERP_INFO + * WLAN_EID_CHANNEL_SWITCH + * WLAN_EID_PWR_CONSTRAINT + */ +int rtw_get_bcn_keys(ADAPTER *Adapter, u8 *pframe, u32 packet_len, + struct beacon_keys *recv_beacon) +{ + int left; + u16 capability; + unsigned char *pos; + struct rtw_ieee802_11_elems elems; + struct rtw_ieee80211_ht_cap *pht_cap = NULL; + struct HT_info_element *pht_info = NULL; + + _rtw_memset(recv_beacon, 0, sizeof(*recv_beacon)); + + /* checking capabilities */ + capability = le16_to_cpu(*(unsigned short *)(pframe + WLAN_HDR_A3_LEN + 10)); + + /* checking IEs */ + left = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_; + pos = pframe + sizeof(struct rtw_ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_; + if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) + return _FALSE; + + /* check bw and channel offset */ + if (elems.ht_capabilities) { + if (elems.ht_capabilities_len != sizeof(*pht_cap)) + return _FALSE; + + pht_cap = (struct rtw_ieee80211_ht_cap *) elems.ht_capabilities; + recv_beacon->ht_cap_info = pht_cap->cap_info; + } + + if (elems.ht_operation) { + if (elems.ht_operation_len != sizeof(*pht_info)) + return _FALSE; + + pht_info = (struct HT_info_element *) elems.ht_operation; + recv_beacon->ht_info_infos_0_sco = pht_info->infos[0] & 0x03; + } + + /* Checking for channel */ + if (elems.ds_params && elems.ds_params_len == sizeof(recv_beacon->bcn_channel)) + _rtw_memcpy(&recv_beacon->bcn_channel, elems.ds_params, + sizeof(recv_beacon->bcn_channel)); + else if (pht_info) + /* In 5G, some ap do not have DSSET IE checking HT info for channel */ + recv_beacon->bcn_channel = pht_info->primary_channel; + else { + /* we don't find channel IE, so don't check it */ + /* RTW_INFO("Oops: %s we don't find channel IE, so don't check it\n", __func__); */ + recv_beacon->bcn_channel = Adapter->mlmeextpriv.cur_channel; + } + + /* checking SSID */ + if (elems.ssid) { + if (elems.ssid_len > sizeof(recv_beacon->ssid)) + return _FALSE; + + _rtw_memcpy(recv_beacon->ssid, elems.ssid, elems.ssid_len); + recv_beacon->ssid_len = elems.ssid_len; + } else + ; /* means hidden ssid */ + + /* checking RSN first */ + if (elems.rsn_ie && elems.rsn_ie_len) { + recv_beacon->encryp_protocol = ENCRYP_PROTOCOL_WPA2; + rtw_parse_wpa2_ie(elems.rsn_ie - 2, elems.rsn_ie_len + 2, + &recv_beacon->group_cipher, &recv_beacon->pairwise_cipher, + &recv_beacon->is_8021x); + } + /* checking WPA secon */ + else if (elems.wpa_ie && elems.wpa_ie_len) { + recv_beacon->encryp_protocol = ENCRYP_PROTOCOL_WPA; + rtw_parse_wpa_ie(elems.wpa_ie - 2, elems.wpa_ie_len + 2, + &recv_beacon->group_cipher, &recv_beacon->pairwise_cipher, + &recv_beacon->is_8021x); + } else if (capability & BIT(4)) + recv_beacon->encryp_protocol = ENCRYP_PROTOCOL_WEP; + + return _TRUE; +} + +void rtw_dump_bcn_keys(struct beacon_keys *recv_beacon) +{ + int i; + char *p; + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + + _rtw_memcpy(ssid, recv_beacon->ssid, recv_beacon->ssid_len); + ssid[recv_beacon->ssid_len] = '\0'; + + RTW_INFO("%s: ssid = %s\n", __func__, ssid); + RTW_INFO("%s: channel = %x\n", __func__, recv_beacon->bcn_channel); + RTW_INFO("%s: ht_cap = %x\n", __func__, recv_beacon->ht_cap_info); + RTW_INFO("%s: ht_info_infos_0_sco = %x\n", __func__, recv_beacon->ht_info_infos_0_sco); + RTW_INFO("%s: sec=%d, group = %x, pair = %x, 8021X = %x\n", __func__, + recv_beacon->encryp_protocol, recv_beacon->group_cipher, + recv_beacon->pairwise_cipher, recv_beacon->is_8021x); +} + +int rtw_check_bcn_info(ADAPTER *Adapter, u8 *pframe, u32 packet_len) +{ +#if 0 + unsigned int len; + unsigned char *p; + unsigned short val16, subtype; + struct wlan_network *cur_network = &(Adapter->mlmepriv.cur_network); + /* u8 wpa_ie[255],rsn_ie[255]; */ + u16 wpa_len = 0, rsn_len = 0; + u8 encryp_protocol = 0; + WLAN_BSSID_EX *bssid; + int group_cipher = 0, pairwise_cipher = 0, is_8021x = 0; + unsigned char *pbuf; + u32 wpa_ielen = 0; + u8 *pbssid = GetAddr3Ptr(pframe); + u32 hidden_ssid = 0; + u8 cur_network_type, network_type = 0; + struct HT_info_element *pht_info = NULL; + struct rtw_ieee80211_ht_cap *pht_cap = NULL; + u32 bcn_channel; + unsigned short ht_cap_info; + unsigned char ht_info_infos_0; +#endif + unsigned int len; + u8 *pbssid = GetAddr3Ptr(pframe); + struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; + struct wlan_network *cur_network = &(Adapter->mlmepriv.cur_network); + struct beacon_keys recv_beacon; + + if (is_client_associated_to_ap(Adapter) == _FALSE) + return _TRUE; + + len = packet_len - sizeof(struct rtw_ieee80211_hdr_3addr); + + if (len > MAX_IE_SZ) { + RTW_WARN("%s IE too long for survey event\n", __func__); + return _FAIL; + } + + if (_rtw_memcmp(cur_network->network.MacAddress, pbssid, 6) == _FALSE) { + RTW_WARN("Oops: rtw_check_network_encrypt linked but recv other bssid bcn\n" MAC_FMT MAC_FMT, + MAC_ARG(pbssid), MAC_ARG(cur_network->network.MacAddress)); + return _TRUE; + } + + if (rtw_get_bcn_keys(Adapter, pframe, packet_len, &recv_beacon) == _FALSE) + return _TRUE; /* parsing failed => broken IE */ + + /* don't care hidden ssid, use current beacon ssid directly */ + if (recv_beacon.ssid_len == 0) { + _rtw_memcpy(recv_beacon.ssid, pmlmepriv->cur_beacon_keys.ssid, + pmlmepriv->cur_beacon_keys.ssid_len); + recv_beacon.ssid_len = pmlmepriv->cur_beacon_keys.ssid_len; + } + + if (_rtw_memcmp(&recv_beacon, &pmlmepriv->cur_beacon_keys, sizeof(recv_beacon)) == _TRUE) + pmlmepriv->new_beacon_cnts = 0; + else if ((pmlmepriv->new_beacon_cnts == 0) || + _rtw_memcmp(&recv_beacon, &pmlmepriv->new_beacon_keys, sizeof(recv_beacon)) == _FALSE) { + RTW_DBG("%s: start new beacon (seq=%d)\n", __func__, GetSequence(pframe)); + + if (pmlmepriv->new_beacon_cnts == 0) { + RTW_ERR("%s: cur beacon key\n", __func__); + RTW_DBG_EXPR(rtw_dump_bcn_keys(&pmlmepriv->cur_beacon_keys)); + } + + RTW_DBG("%s: new beacon key\n", __func__); + RTW_DBG_EXPR(rtw_dump_bcn_keys(&recv_beacon)); + + memcpy(&pmlmepriv->new_beacon_keys, &recv_beacon, sizeof(recv_beacon)); + pmlmepriv->new_beacon_cnts = 1; + } else { + RTW_DBG("%s: new beacon again (seq=%d)\n", __func__, GetSequence(pframe)); + pmlmepriv->new_beacon_cnts++; + } + + /* if counter >= max, it means beacon is changed really */ + if (pmlmepriv->new_beacon_cnts >= new_bcn_max) { + /* check bw mode change only? */ + pmlmepriv->cur_beacon_keys.ht_cap_info = recv_beacon.ht_cap_info; + pmlmepriv->cur_beacon_keys.ht_info_infos_0_sco = recv_beacon.ht_info_infos_0_sco; + if (_rtw_memcmp(&recv_beacon, &pmlmepriv->cur_beacon_keys, + sizeof(recv_beacon)) == _FALSE) { + /* beacon is changed, have to do disconnect/connect */ + RTW_WARN("%s: new beacon occur!!\n", __func__); + return _FAIL; + } + + RTW_INFO("%s bw mode change\n", __func__); + RTW_INFO("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, + cur_network->BcnInfo.ht_cap_info, + cur_network->BcnInfo.ht_info_infos_0); + + cur_network->BcnInfo.ht_cap_info = recv_beacon.ht_cap_info; + cur_network->BcnInfo.ht_info_infos_0 = + (cur_network->BcnInfo.ht_info_infos_0 & (~0x03)) | + recv_beacon.ht_info_infos_0_sco; + + RTW_INFO("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, + cur_network->BcnInfo.ht_cap_info, + cur_network->BcnInfo.ht_info_infos_0); + + memcpy(&pmlmepriv->cur_beacon_keys, &recv_beacon, sizeof(recv_beacon)); + pmlmepriv->new_beacon_cnts = 0; + } + + return _SUCCESS; + +#if 0 + bssid = (WLAN_BSSID_EX *)rtw_zmalloc(sizeof(WLAN_BSSID_EX)); + if (bssid == NULL) { + RTW_INFO("%s rtw_zmalloc fail !!!\n", __func__); + return _TRUE; + } + + if ((pmlmepriv->timeBcnInfoChkStart != 0) && (rtw_get_passing_time_ms(pmlmepriv->timeBcnInfoChkStart) > DISCONNECT_BY_CHK_BCN_FAIL_OBSERV_PERIOD_IN_MS)) { + pmlmepriv->timeBcnInfoChkStart = 0; + pmlmepriv->NumOfBcnInfoChkFail = 0; + } + + subtype = get_frame_sub_type(pframe) >> 4; + + if (subtype == WIFI_BEACON) + bssid->Reserved[0] = 1; + + bssid->Length = sizeof(WLAN_BSSID_EX) - MAX_IE_SZ + len; + + /* below is to copy the information element */ + bssid->IELength = len; + _rtw_memcpy(bssid->IEs, (pframe + sizeof(struct rtw_ieee80211_hdr_3addr)), bssid->IELength); + + /* check bw and channel offset */ + /* parsing HT_CAP_IE */ + p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); + if (p && len > 0) { + pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2); + ht_cap_info = pht_cap->cap_info; + } else + ht_cap_info = 0; + /* parsing HT_INFO_IE */ + p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); + if (p && len > 0) { + pht_info = (struct HT_info_element *)(p + 2); + ht_info_infos_0 = pht_info->infos[0]; + } else + ht_info_infos_0 = 0; + if (ht_cap_info != cur_network->BcnInfo.ht_cap_info || + ((ht_info_infos_0 & 0x03) != (cur_network->BcnInfo.ht_info_infos_0 & 0x03))) { + RTW_INFO("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, + ht_cap_info, ht_info_infos_0); + RTW_INFO("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", __func__, + cur_network->BcnInfo.ht_cap_info, cur_network->BcnInfo.ht_info_infos_0); + RTW_INFO("%s bw mode change\n", __func__); + { + /* bcn_info_update */ + cur_network->BcnInfo.ht_cap_info = ht_cap_info; + cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0; + /* to do : need to check that whether modify related register of BB or not */ + } + /* goto _mismatch; */ + } + + /* Checking for channel */ + p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _DSSET_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); + if (p) + bcn_channel = *(p + 2); + else {/* In 5G, some ap do not have DSSET IE checking HT info for channel */ + rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); + if (pht_info) + bcn_channel = pht_info->primary_channel; + else { /* we don't find channel IE, so don't check it */ + /* RTW_INFO("Oops: %s we don't find channel IE, so don't check it\n", __func__); */ + bcn_channel = Adapter->mlmeextpriv.cur_channel; + } + } + if (bcn_channel != Adapter->mlmeextpriv.cur_channel) { + RTW_INFO("%s beacon channel:%d cur channel:%d disconnect\n", __func__, + bcn_channel, Adapter->mlmeextpriv.cur_channel); + goto _mismatch; + } + + /* checking SSID */ + p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _SSID_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); + if (p == NULL) { + RTW_INFO("%s marc: cannot find SSID for survey event\n", __func__); + hidden_ssid = _TRUE; + } else + hidden_ssid = _FALSE; + + if ((NULL != p) && (_FALSE == hidden_ssid && (*(p + 1)))) { + _rtw_memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1)); + bssid->Ssid.SsidLength = *(p + 1); + } else { + bssid->Ssid.SsidLength = 0; + bssid->Ssid.Ssid[0] = '\0'; + } + + + if (_rtw_memcmp(bssid->Ssid.Ssid, cur_network->network.Ssid.Ssid, 32) == _FALSE || + bssid->Ssid.SsidLength != cur_network->network.Ssid.SsidLength) { + if (bssid->Ssid.Ssid[0] != '\0' && bssid->Ssid.SsidLength != 0) { /* not hidden ssid */ + RTW_INFO("%s(), SSID is not match\n", __func__); + goto _mismatch; + } + } + + /* check encryption info */ + val16 = rtw_get_capability((WLAN_BSSID_EX *)bssid); + + if (val16 & BIT(4)) + bssid->Privacy = 1; + else + bssid->Privacy = 0; + + if (cur_network->network.Privacy != bssid->Privacy) { + RTW_INFO("%s(), privacy is not match\n", __func__); + goto _mismatch; + } + + rtw_get_sec_ie(bssid->IEs, bssid->IELength, NULL, &rsn_len, NULL, &wpa_len); + + if (rsn_len > 0) + encryp_protocol = ENCRYP_PROTOCOL_WPA2; + else if (wpa_len > 0) + encryp_protocol = ENCRYP_PROTOCOL_WPA; + else { + if (bssid->Privacy) + encryp_protocol = ENCRYP_PROTOCOL_WEP; + } + + if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) { + RTW_INFO("%s(): enctyp is not match\n", __func__); + goto _mismatch; + } + + if (encryp_protocol == ENCRYP_PROTOCOL_WPA || encryp_protocol == ENCRYP_PROTOCOL_WPA2) { + pbuf = rtw_get_wpa_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength - 12); + if (pbuf && (wpa_ielen > 0)) { + rtw_parse_wpa_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is_8021x); + } else { + pbuf = rtw_get_wpa2_ie(&bssid->IEs[12], &wpa_ielen, bssid->IELength - 12); + + if (pbuf && (wpa_ielen > 0)) { + rtw_parse_wpa2_ie(pbuf, wpa_ielen + 2, &group_cipher, &pairwise_cipher, &is_8021x); + } + } + + if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || group_cipher != cur_network->BcnInfo.group_cipher) { + RTW_INFO("%s pairwise_cipher(%x:%x) or group_cipher(%x:%x) is not match\n", __func__, + pairwise_cipher, cur_network->BcnInfo.pairwise_cipher, + group_cipher, cur_network->BcnInfo.group_cipher); + goto _mismatch; + } + + if (is_8021x != cur_network->BcnInfo.is_8021x) { + RTW_INFO("%s authentication is not match\n", __func__); + goto _mismatch; + } + } + + rtw_mfree((u8 *)bssid, sizeof(WLAN_BSSID_EX)); + return _SUCCESS; + +_mismatch: + rtw_mfree((u8 *)bssid, sizeof(WLAN_BSSID_EX)); + + if (pmlmepriv->NumOfBcnInfoChkFail == 0) + pmlmepriv->timeBcnInfoChkStart = rtw_get_current_time(); + + pmlmepriv->NumOfBcnInfoChkFail++; + RTW_INFO("%s by "ADPT_FMT" - NumOfChkFail = %d (SeqNum of this Beacon frame = %d).\n", __func__, ADPT_ARG(Adapter), pmlmepriv->NumOfBcnInfoChkFail, GetSequence(pframe)); + + if ((pmlmepriv->timeBcnInfoChkStart != 0) && (rtw_get_passing_time_ms(pmlmepriv->timeBcnInfoChkStart) <= DISCONNECT_BY_CHK_BCN_FAIL_OBSERV_PERIOD_IN_MS) + && (pmlmepriv->NumOfBcnInfoChkFail >= DISCONNECT_BY_CHK_BCN_FAIL_THRESHOLD)) { + RTW_INFO("%s by "ADPT_FMT" - NumOfChkFail = %d >= threshold : %d (in %d ms), return FAIL.\n", __func__, ADPT_ARG(Adapter), pmlmepriv->NumOfBcnInfoChkFail, + DISCONNECT_BY_CHK_BCN_FAIL_THRESHOLD, rtw_get_passing_time_ms(pmlmepriv->timeBcnInfoChkStart)); + pmlmepriv->timeBcnInfoChkStart = 0; + pmlmepriv->NumOfBcnInfoChkFail = 0; + return _FAIL; + } + + return _SUCCESS; +#endif +} + +void update_beacon_info(_adapter *padapter, u8 *pframe, uint pkt_len, struct sta_info *psta) +{ + unsigned int i; + unsigned int len; + PNDIS_802_11_VARIABLE_IEs pIE; + +#ifdef CONFIG_TDLS + struct tdls_info *ptdlsinfo = &padapter->tdlsinfo; + u8 tdls_prohibited[] = { 0x00, 0x00, 0x00, 0x00, 0x10 }; /* bit(38): TDLS_prohibited */ +#endif /* CONFIG_TDLS */ + + len = pkt_len - (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN); + + for (i = 0; i < len;) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(pframe + (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN) + i); + + switch (pIE->ElementID) { + case _VENDOR_SPECIFIC_IE_: + /* to update WMM paramter set while receiving beacon */ + if (_rtw_memcmp(pIE->data, WMM_PARA_OUI, 6) && pIE->Length == WLAN_WMM_LEN) /* WMM */ + if (WMM_param_handler(padapter, pIE)) report_wmm_edca_update(padapter); + + break; + + case _HT_EXTRA_INFO_IE_: /* HT info */ + /* HT_info_handler(padapter, pIE); */ + bwmode_update_check(padapter, pIE); + break; +#ifdef CONFIG_80211AC_VHT + case EID_OpModeNotification: + rtw_process_vht_op_mode_notify(padapter, pIE->data, psta); + break; +#endif /* CONFIG_80211AC_VHT */ + case _ERPINFO_IE_: + ERP_IE_handler(padapter, pIE); + VCS_update(padapter, psta); + break; + +#ifdef CONFIG_TDLS + case _EXT_CAP_IE_: + if (check_ap_tdls_prohibited(pIE->data, pIE->Length) == _TRUE) + ptdlsinfo->ap_prohibited = _TRUE; + if (check_ap_tdls_ch_switching_prohibited(pIE->data, pIE->Length) == _TRUE) + ptdlsinfo->ch_switch_prohibited = _TRUE; + break; +#endif /* CONFIG_TDLS */ + default: + break; + } + + i += (pIE->Length + 2); + } +} + +#ifdef CONFIG_DFS +void process_csa_ie(_adapter *padapter, u8 *pframe, uint pkt_len) +{ + unsigned int i; + unsigned int len; + PNDIS_802_11_VARIABLE_IEs pIE; + u8 new_ch_no = 0; + + if (padapter->mlmepriv.handle_dfs == _TRUE) + return; + + len = pkt_len - (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN); + + for (i = 0; i < len;) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(pframe + (_BEACON_IE_OFFSET_ + WLAN_HDR_A3_LEN) + i); + + switch (pIE->ElementID) { + case _CH_SWTICH_ANNOUNCE_: + padapter->mlmepriv.handle_dfs = _TRUE; + _rtw_memcpy(&new_ch_no, pIE->data + 1, 1); + rtw_set_csa_cmd(padapter, new_ch_no); + break; + default: + break; + } + + i += (pIE->Length + 2); + } +} +#endif /* CONFIG_DFS */ + +unsigned int is_ap_in_tkip(_adapter *padapter) +{ + u32 i; + PNDIS_802_11_VARIABLE_IEs pIE; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); + + if (rtw_get_capability((WLAN_BSSID_EX *)cur_network) & WLAN_CAPABILITY_PRIVACY) { + for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pmlmeinfo->network.IELength;) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(pmlmeinfo->network.IEs + i); + + switch (pIE->ElementID) { + case _VENDOR_SPECIFIC_IE_: + if ((_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) && (_rtw_memcmp((pIE->data + 12), WPA_TKIP_CIPHER, 4))) + return _TRUE; + break; + + case _RSN_IE_2_: + if (_rtw_memcmp((pIE->data + 8), RSN_TKIP_CIPHER, 4)) + return _TRUE; + + default: + break; + } + + i += (pIE->Length + 2); + } + + return _FALSE; + } else + return _FALSE; + +} + +unsigned int should_forbid_n_rate(_adapter *padapter) +{ + u32 i; + PNDIS_802_11_VARIABLE_IEs pIE; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + WLAN_BSSID_EX *cur_network = &pmlmepriv->cur_network.network; + + if (rtw_get_capability((WLAN_BSSID_EX *)cur_network) & WLAN_CAPABILITY_PRIVACY) { + for (i = sizeof(NDIS_802_11_FIXED_IEs); i < cur_network->IELength;) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(cur_network->IEs + i); + + switch (pIE->ElementID) { + case _VENDOR_SPECIFIC_IE_: + if (_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4) && + ((_rtw_memcmp((pIE->data + 12), WPA_CIPHER_SUITE_CCMP, 4)) || + (_rtw_memcmp((pIE->data + 16), WPA_CIPHER_SUITE_CCMP, 4)))) + return _FALSE; + break; + + case _RSN_IE_2_: + if ((_rtw_memcmp((pIE->data + 8), RSN_CIPHER_SUITE_CCMP, 4)) || + (_rtw_memcmp((pIE->data + 12), RSN_CIPHER_SUITE_CCMP, 4))) + return _FALSE; + + default: + break; + } + + i += (pIE->Length + 2); + } + + return _TRUE; + } else + return _FALSE; + +} + + +unsigned int is_ap_in_wep(_adapter *padapter) +{ + u32 i; + PNDIS_802_11_VARIABLE_IEs pIE; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); + + if (rtw_get_capability((WLAN_BSSID_EX *)cur_network) & WLAN_CAPABILITY_PRIVACY) { + for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pmlmeinfo->network.IELength;) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(pmlmeinfo->network.IEs + i); + + switch (pIE->ElementID) { + case _VENDOR_SPECIFIC_IE_: + if (_rtw_memcmp(pIE->data, RTW_WPA_OUI, 4)) + return _FALSE; + break; + + case _RSN_IE_2_: + return _FALSE; + + default: + break; + } + + i += (pIE->Length + 2); + } + + return _TRUE; + } else + return _FALSE; + +} + +int wifirate2_ratetbl_inx(unsigned char rate); +int wifirate2_ratetbl_inx(unsigned char rate) +{ + int inx = 0; + rate = rate & 0x7f; + + switch (rate) { + case 54*2: + inx = 11; + break; + + case 48*2: + inx = 10; + break; + + case 36*2: + inx = 9; + break; + + case 24*2: + inx = 8; + break; + + case 18*2: + inx = 7; + break; + + case 12*2: + inx = 6; + break; + + case 9*2: + inx = 5; + break; + + case 6*2: + inx = 4; + break; + + case 11*2: + inx = 3; + break; + case 11: + inx = 2; + break; + + case 2*2: + inx = 1; + break; + + case 1*2: + inx = 0; + break; + + } + return inx; +} + +unsigned int update_basic_rate(unsigned char *ptn, unsigned int ptn_sz) +{ + unsigned int i, num_of_rate; + unsigned int mask = 0; + + num_of_rate = (ptn_sz > NumRates) ? NumRates : ptn_sz; + + for (i = 0; i < num_of_rate; i++) { + if ((*(ptn + i)) & 0x80) + mask |= 0x1 << wifirate2_ratetbl_inx(*(ptn + i)); + } + return mask; +} + +unsigned int update_supported_rate(unsigned char *ptn, unsigned int ptn_sz) +{ + unsigned int i, num_of_rate; + unsigned int mask = 0; + + num_of_rate = (ptn_sz > NumRates) ? NumRates : ptn_sz; + + for (i = 0; i < num_of_rate; i++) + mask |= 0x1 << wifirate2_ratetbl_inx(*(ptn + i)); + + return mask; +} + +int support_short_GI(_adapter *padapter, struct HT_caps_element *pHT_caps, u8 bwmode) +{ + unsigned char bit_offset; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if (!(pmlmeinfo->HT_enable)) + return _FAIL; + + bit_offset = (bwmode & CHANNEL_WIDTH_40) ? 6 : 5; + + if (pHT_caps->u.HT_cap_element.HT_caps_info & (0x1 << bit_offset)) + return _SUCCESS; + else + return _FAIL; +} + +unsigned char get_highest_rate_idx(u32 mask) +{ + int i; + unsigned char rate_idx = 0; + + for (i = 31; i >= 0; i--) { + if (mask & BIT(i)) { + rate_idx = i; + break; + } + } + + return rate_idx; +} + +void Update_RA_Entry(_adapter *padapter, struct sta_info *psta) +{ + rtw_hal_update_ra_mask(psta, psta->rssi_level, _TRUE); +} + +void set_sta_rate(_adapter *padapter, struct sta_info *psta) +{ + /* rate adaptive */ + rtw_hal_update_ra_mask(psta, psta->rssi_level, _TRUE); +} + +/* Update RRSR and Rate for USERATE */ +void update_tx_basic_rate(_adapter *padapter, u8 wirelessmode) +{ + NDIS_802_11_RATES_EX supported_rates; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &padapter->wdinfo; + + /* Added by Albert 2011/03/22 */ + /* In the P2P mode, the driver should not support the b mode. */ + /* So, the Tx packet shouldn't use the CCK rate */ + if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) + return; +#endif /* CONFIG_P2P */ +#ifdef CONFIG_INTEL_WIDI + if (padapter->mlmepriv.widi_state != INTEL_WIDI_STATE_NONE) + return; +#endif /* CONFIG_INTEL_WIDI */ + + _rtw_memset(supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX); + + /* clear B mod if current channel is in 5G band, avoid tx cck rate in 5G band. */ + if (pmlmeext->cur_channel > 14) + wirelessmode &= ~(WIRELESS_11B); + + if ((wirelessmode & WIRELESS_11B) && (wirelessmode == WIRELESS_11B)) + _rtw_memcpy(supported_rates, rtw_basic_rate_cck, 4); + else if (wirelessmode & WIRELESS_11B) + _rtw_memcpy(supported_rates, rtw_basic_rate_mix, 7); + else + _rtw_memcpy(supported_rates, rtw_basic_rate_ofdm, 3); + + if (wirelessmode & WIRELESS_11B) + update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB); + else + update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB); + + rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, supported_rates); +} + +unsigned char check_assoc_AP(u8 *pframe, uint len) +{ + unsigned int i; + PNDIS_802_11_VARIABLE_IEs pIE; + + for (i = sizeof(NDIS_802_11_FIXED_IEs); i < len;) { + pIE = (PNDIS_802_11_VARIABLE_IEs)(pframe + i); + + switch (pIE->ElementID) { + case _VENDOR_SPECIFIC_IE_: + if ((_rtw_memcmp(pIE->data, ARTHEROS_OUI1, 3)) || (_rtw_memcmp(pIE->data, ARTHEROS_OUI2, 3))) { + RTW_INFO("link to Artheros AP\n"); + return HT_IOT_PEER_ATHEROS; + } else if ((_rtw_memcmp(pIE->data, BROADCOM_OUI1, 3)) + || (_rtw_memcmp(pIE->data, BROADCOM_OUI2, 3)) + || (_rtw_memcmp(pIE->data, BROADCOM_OUI3, 3))) { + RTW_INFO("link to Broadcom AP\n"); + return HT_IOT_PEER_BROADCOM; + } else if (_rtw_memcmp(pIE->data, MARVELL_OUI, 3)) { + RTW_INFO("link to Marvell AP\n"); + return HT_IOT_PEER_MARVELL; + } else if (_rtw_memcmp(pIE->data, RALINK_OUI, 3)) { + RTW_INFO("link to Ralink AP\n"); + return HT_IOT_PEER_RALINK; + } else if (_rtw_memcmp(pIE->data, CISCO_OUI, 3)) { + RTW_INFO("link to Cisco AP\n"); + return HT_IOT_PEER_CISCO; + } else if (_rtw_memcmp(pIE->data, REALTEK_OUI, 3)) { + u32 Vender = HT_IOT_PEER_REALTEK; + + if (pIE->Length >= 5) { + if (pIE->data[4] == 1) { + /* if(pIE->data[5] & RT_HT_CAP_USE_LONG_PREAMBLE) */ + /* bssDesc->BssHT.RT2RT_HT_Mode |= RT_HT_CAP_USE_LONG_PREAMBLE; */ + + if (pIE->data[5] & RT_HT_CAP_USE_92SE) { + /* bssDesc->BssHT.RT2RT_HT_Mode |= RT_HT_CAP_USE_92SE; */ + Vender = HT_IOT_PEER_REALTEK_92SE; + } + } + + if (pIE->data[5] & RT_HT_CAP_USE_SOFTAP) + Vender = HT_IOT_PEER_REALTEK_SOFTAP; + + if (pIE->data[4] == 2) { + if (pIE->data[6] & RT_HT_CAP_USE_JAGUAR_BCUT) { + Vender = HT_IOT_PEER_REALTEK_JAGUAR_BCUTAP; + RTW_INFO("link to Realtek JAGUAR_BCUTAP\n"); + } + if (pIE->data[6] & RT_HT_CAP_USE_JAGUAR_CCUT) { + Vender = HT_IOT_PEER_REALTEK_JAGUAR_CCUTAP; + RTW_INFO("link to Realtek JAGUAR_CCUTAP\n"); + } + } + } + + RTW_INFO("link to Realtek AP\n"); + return Vender; + } else if (_rtw_memcmp(pIE->data, AIRGOCAP_OUI, 3)) { + RTW_INFO("link to Airgo Cap\n"); + return HT_IOT_PEER_AIRGO; + } else + break; + + default: + break; + } + + i += (pIE->Length + 2); + } + + RTW_INFO("link to new AP\n"); + return HT_IOT_PEER_UNKNOWN; +} + +void update_capinfo(PADAPTER Adapter, u16 updateCap) +{ + struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + BOOLEAN ShortPreamble; + + /* Check preamble mode, 2005.01.06, by rcnjko. */ + /* Mark to update preamble value forever, 2008.03.18 by lanhsin */ + /* if( pMgntInfo->RegPreambleMode == PREAMBLE_AUTO ) */ + { + + if (updateCap & cShortPreamble) { + /* Short Preamble */ + if (pmlmeinfo->preamble_mode != PREAMBLE_SHORT) { /* PREAMBLE_LONG or PREAMBLE_AUTO */ + ShortPreamble = _TRUE; + pmlmeinfo->preamble_mode = PREAMBLE_SHORT; + rtw_hal_set_hwreg(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble); + } + } else { + /* Long Preamble */ + if (pmlmeinfo->preamble_mode != PREAMBLE_LONG) { /* PREAMBLE_SHORT or PREAMBLE_AUTO */ + ShortPreamble = _FALSE; + pmlmeinfo->preamble_mode = PREAMBLE_LONG; + rtw_hal_set_hwreg(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble); + } + } + } + + if (updateCap & cIBSS) { + /* Filen: See 802.11-2007 p.91 */ + pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; + } else { + /* Filen: See 802.11-2007 p.90 */ + if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N | WIRELESS_11A | WIRELESS_11_5N | WIRELESS_11AC)) + pmlmeinfo->slotTime = SHORT_SLOT_TIME; + else if (pmlmeext->cur_wireless_mode & (WIRELESS_11G)) { + if ((updateCap & cShortSlotTime) /* && (!(pMgntInfo->pHTInfo->RT2RT_HT_Mode & RT_HT_CAP_USE_LONG_PREAMBLE)) */) { + /* Short Slot Time */ + pmlmeinfo->slotTime = SHORT_SLOT_TIME; + } else { + /* Long Slot Time */ + pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; + } + } else { + /* B Mode */ + pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; + } + } + + rtw_hal_set_hwreg(Adapter, HW_VAR_SLOT_TIME, &pmlmeinfo->slotTime); + +} + +/* +* set adapter.mlmeextpriv.mlmext_info.HT_enable +* set adapter.mlmeextpriv.cur_wireless_mode +* set SIFS register +* set mgmt tx rate +*/ +void update_wireless_mode(_adapter *padapter) +{ + int ratelen, network_type = 0; + u32 SIFS_Timer; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); + unsigned char *rate = cur_network->SupportedRates; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#endif /* CONFIG_P2P */ + + ratelen = rtw_get_rateset_len(cur_network->SupportedRates); + + if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) + pmlmeinfo->HT_enable = 1; + + if (pmlmeext->cur_channel > 14) { + if (pmlmeinfo->VHT_enable) + network_type = WIRELESS_11AC; + else if (pmlmeinfo->HT_enable) + network_type = WIRELESS_11_5N; + + network_type |= WIRELESS_11A; + } else { + if (pmlmeinfo->VHT_enable) + network_type = WIRELESS_11AC; + else if (pmlmeinfo->HT_enable) + network_type = WIRELESS_11_24N; + + if ((cckratesonly_included(rate, ratelen)) == _TRUE) + network_type |= WIRELESS_11B; + else if ((cckrates_included(rate, ratelen)) == _TRUE) + network_type |= WIRELESS_11BG; + else + network_type |= WIRELESS_11G; + } + + pmlmeext->cur_wireless_mode = network_type & padapter->registrypriv.wireless_mode; + /* RTW_INFO("network_type=%02x, padapter->registrypriv.wireless_mode=%02x\n", network_type, padapter->registrypriv.wireless_mode); */ +#if 0 + if ((pmlmeext->cur_wireless_mode == WIRELESS_11G) || + (pmlmeext->cur_wireless_mode == WIRELESS_11BG)) /* WIRELESS_MODE_G) */ + SIFS_Timer = 0x0a0a;/* CCK */ + else + SIFS_Timer = 0x0e0e;/* pHalData->SifsTime; //OFDM */ +#endif + + SIFS_Timer = 0x0a0a0808; /* 0x0808->for CCK, 0x0a0a->for OFDM + * change this value if having IOT issues. */ + + rtw_hal_set_hwreg(padapter, HW_VAR_RESP_SIFS, (u8 *)&SIFS_Timer); + + rtw_hal_set_hwreg(padapter, HW_VAR_WIRELESS_MODE, (u8 *)&(pmlmeext->cur_wireless_mode)); + + if ((pmlmeext->cur_wireless_mode & WIRELESS_11B) + #ifdef CONFIG_P2P + && (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) + #ifdef CONFIG_IOCTL_CFG80211 + || !rtw_cfg80211_iface_has_p2p_group_cap(padapter) + #endif + ) + #endif + ) + update_mgnt_tx_rate(padapter, IEEE80211_CCK_RATE_1MB); + else + update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB); +} + +void fire_write_MAC_cmd(_adapter *padapter, unsigned int addr, unsigned int value); +void fire_write_MAC_cmd(_adapter *padapter, unsigned int addr, unsigned int value) +{ +#if 0 + struct cmd_obj *ph2c; + struct reg_rw_parm *pwriteMacPara; + struct cmd_priv *pcmdpriv = &(padapter->cmdpriv); + + ph2c = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj)); + if (ph2c == NULL) + return; + + pwriteMacPara = (struct reg_rw_parm *)rtw_malloc(sizeof(struct reg_rw_parm)); + if (pwriteMacPara == NULL) { + rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); + return; + } + + pwriteMacPara->rw = 1; + pwriteMacPara->addr = addr; + pwriteMacPara->value = value; + + init_h2fwcmd_w_parm_no_rsp(ph2c, pwriteMacPara, GEN_CMD_CODE(_Write_MACREG)); + rtw_enqueue_cmd(pcmdpriv, ph2c); +#endif +} + +void update_sta_basic_rate(struct sta_info *psta, u8 wireless_mode) +{ + if (IsSupportedTxCCK(wireless_mode)) { + /* Only B, B/G, and B/G/N AP could use CCK rate */ + _rtw_memcpy(psta->bssrateset, rtw_basic_rate_cck, 4); + psta->bssratelen = 4; + } else { + _rtw_memcpy(psta->bssrateset, rtw_basic_rate_ofdm, 3); + psta->bssratelen = 3; + } +} + +int rtw_ies_get_supported_rate(u8 *ies, uint ies_len, u8 *rate_set, u8 *rate_num) +{ + u8 *ie; + unsigned int ie_len; + + if (!rate_set || !rate_num) + return _FALSE; + + *rate_num = 0; + + ie = rtw_get_ie(ies, _SUPPORTEDRATES_IE_, &ie_len, ies_len); + if (ie == NULL) + goto ext_rate; + + _rtw_memcpy(rate_set, ie + 2, ie_len); + *rate_num = ie_len; + +ext_rate: + ie = rtw_get_ie(ies, _EXT_SUPPORTEDRATES_IE_, &ie_len, ies_len); + if (ie) { + _rtw_memcpy(rate_set + *rate_num, ie + 2, ie_len); + *rate_num += ie_len; + } + + if (*rate_num == 0) + return _FAIL; + + if (0) { + int i; + + for (i = 0; i < *rate_num; i++) + RTW_INFO("rate:0x%02x\n", *(rate_set + i)); + } + + return _SUCCESS; +} + +void process_addba_req(_adapter *padapter, u8 *paddba_req, u8 *addr) +{ + struct sta_info *psta; + u16 tid, start_seq, param; + struct sta_priv *pstapriv = &padapter->stapriv; + struct ADDBA_request *preq = (struct ADDBA_request *)paddba_req; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u8 size, accept = _FALSE; + + psta = rtw_get_stainfo(pstapriv, addr); + if (!psta) + goto exit; + + start_seq = le16_to_cpu(preq->BA_starting_seqctrl) >> 4; + + param = le16_to_cpu(preq->BA_para_set); + tid = (param >> 2) & 0x0f; + + + accept = rtw_rx_ampdu_is_accept(padapter); + size = rtw_rx_ampdu_size(padapter); + + if (accept == _TRUE) + rtw_addbarsp_cmd(padapter, addr, tid, 0, size, start_seq); + else + rtw_addbarsp_cmd(padapter, addr, tid, 37, size, start_seq); /* reject ADDBA Req */ + +exit: + return; +} + +void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) +{ + u8 *pIE; + u32 *pbuf; + + pIE = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + pbuf = (u32 *)pIE; + + pmlmeext->TSFValue = le32_to_cpu(*(pbuf + 1)); + + pmlmeext->TSFValue = pmlmeext->TSFValue << 32; + + pmlmeext->TSFValue |= le32_to_cpu(*pbuf); +} + +void correct_TSF(_adapter *padapter, struct mlme_ext_priv *pmlmeext) +{ + rtw_hal_set_hwreg(padapter, HW_VAR_CORRECT_TSF, 0); +} + +void adaptive_early_32k(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) +{ + int i; + u8 *pIE; + u32 *pbuf; + u64 tsf = 0; + u32 delay_ms; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + + pmlmeext->bcn_cnt++; + + pIE = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + pbuf = (u32 *)pIE; + + tsf = le32_to_cpu(*(pbuf + 1)); + tsf = tsf << 32; + tsf |= le32_to_cpu(*pbuf); + + /* RTW_INFO("%s(): tsf_upper= 0x%08x, tsf_lower=0x%08x\n", __func__, (u32)(tsf>>32), (u32)tsf); */ + + /* delay = (timestamp mod 1024*100)/1000 (unit: ms) */ + /* delay_ms = do_div(tsf, (pmlmeinfo->bcn_interval*1024))/1000; */ + delay_ms = rtw_modular64(tsf, (pmlmeinfo->bcn_interval * 1024)); + delay_ms = delay_ms / 1000; + + if (delay_ms >= 8) { + pmlmeext->bcn_delay_cnt[8]++; + /* pmlmeext->bcn_delay_ratio[8] = (pmlmeext->bcn_delay_cnt[8] * 100) /pmlmeext->bcn_cnt; */ + } else { + pmlmeext->bcn_delay_cnt[delay_ms]++; + /* pmlmeext->bcn_delay_ratio[delay_ms] = (pmlmeext->bcn_delay_cnt[delay_ms] * 100) /pmlmeext->bcn_cnt; */ + } + + /* + RTW_INFO("%s(): (a)bcn_cnt = %d\n", __func__, pmlmeext->bcn_cnt); + + + for(i=0; i<9; i++) + { + RTW_INFO("%s():bcn_delay_cnt[%d]=%d, bcn_delay_ratio[%d]=%d\n", __func__, i, + pmlmeext->bcn_delay_cnt[i] , i, pmlmeext->bcn_delay_ratio[i]); + } + */ + + /* dump for adaptive_early_32k */ + if (pmlmeext->bcn_cnt > 100 && (pmlmeext->adaptive_tsf_done == _TRUE)) { + u8 ratio_20_delay, ratio_80_delay; + u8 DrvBcnEarly, DrvBcnTimeOut; + + ratio_20_delay = 0; + ratio_80_delay = 0; + DrvBcnEarly = 0xff; + DrvBcnTimeOut = 0xff; + + RTW_INFO("%s(): bcn_cnt = %d\n", __func__, pmlmeext->bcn_cnt); + + for (i = 0; i < 9; i++) { + pmlmeext->bcn_delay_ratio[i] = (pmlmeext->bcn_delay_cnt[i] * 100) / pmlmeext->bcn_cnt; + + + /* RTW_INFO("%s():bcn_delay_cnt[%d]=%d, bcn_delay_ratio[%d]=%d\n", __func__, i, */ + /* pmlmeext->bcn_delay_cnt[i] , i, pmlmeext->bcn_delay_ratio[i]); */ + + ratio_20_delay += pmlmeext->bcn_delay_ratio[i]; + ratio_80_delay += pmlmeext->bcn_delay_ratio[i]; + + if (ratio_20_delay > 20 && DrvBcnEarly == 0xff) { + DrvBcnEarly = i; + /* RTW_INFO("%s(): DrvBcnEarly = %d\n", __func__, DrvBcnEarly); */ + } + + if (ratio_80_delay > 80 && DrvBcnTimeOut == 0xff) { + DrvBcnTimeOut = i; + /* RTW_INFO("%s(): DrvBcnTimeOut = %d\n", __func__, DrvBcnTimeOut); */ + } + + /* reset adaptive_early_32k cnt */ + pmlmeext->bcn_delay_cnt[i] = 0; + pmlmeext->bcn_delay_ratio[i] = 0; + } + + pmlmeext->DrvBcnEarly = DrvBcnEarly; + pmlmeext->DrvBcnTimeOut = DrvBcnTimeOut; + + pmlmeext->bcn_cnt = 0; + } + +} + + +void beacon_timing_control(_adapter *padapter) +{ + rtw_hal_bcn_related_reg_setting(padapter); +} + +#define CONFIG_SHARED_BMC_MACID + +void dump_macid_map(void *sel, struct macid_bmp *map, u8 max_num) +{ + RTW_PRINT_SEL(sel, "0x%08x\n", map->m0); +#if (MACID_NUM_SW_LIMIT > 32) + if (max_num && max_num > 32) + RTW_PRINT_SEL(sel, "0x%08x\n", map->m1); +#endif +#if (MACID_NUM_SW_LIMIT > 64) + if (max_num && max_num > 64) + RTW_PRINT_SEL(sel, "0x%08x\n", map->m2); +#endif +#if (MACID_NUM_SW_LIMIT > 96) + if (max_num && max_num > 96) + RTW_PRINT_SEL(sel, "0x%08x\n", map->m3); +#endif +} + +inline bool rtw_macid_is_set(struct macid_bmp *map, u8 id) +{ + if (id < 32) + return map->m0 & BIT(id); +#if (MACID_NUM_SW_LIMIT > 32) + else if (id < 64) + return map->m1 & BIT(id - 32); +#endif +#if (MACID_NUM_SW_LIMIT > 64) + else if (id < 96) + return map->m2 & BIT(id - 64); +#endif +#if (MACID_NUM_SW_LIMIT > 96) + else if (id < 128) + return map->m3 & BIT(id - 96); +#endif + else + rtw_warn_on(1); + + return 0; +} + +inline void rtw_macid_map_set(struct macid_bmp *map, u8 id) +{ + if (id < 32) + map->m0 |= BIT(id); +#if (MACID_NUM_SW_LIMIT > 32) + else if (id < 64) + map->m1 |= BIT(id - 32); +#endif +#if (MACID_NUM_SW_LIMIT > 64) + else if (id < 96) + map->m2 |= BIT(id - 64); +#endif +#if (MACID_NUM_SW_LIMIT > 96) + else if (id < 128) + map->m3 |= BIT(id - 96); +#endif + else + rtw_warn_on(1); +} + +/*Record bc's mac-id and sec-cam-id*/ +inline void rtw_iface_bcmc_id_set(_adapter *padapter, u8 mac_id) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + + macid_ctl->iface_bmc[padapter->iface_id] = mac_id; +} +inline u8 rtw_iface_bcmc_id_get(_adapter *padapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + + return macid_ctl->iface_bmc[padapter->iface_id]; +} + +inline void rtw_macid_map_clr(struct macid_bmp *map, u8 id) +{ + if (id < 32) + map->m0 &= ~BIT(id); +#if (MACID_NUM_SW_LIMIT > 32) + else if (id < 64) + map->m1 &= ~BIT(id - 32); +#endif +#if (MACID_NUM_SW_LIMIT > 64) + else if (id < 96) + map->m2 &= ~BIT(id - 64); +#endif +#if (MACID_NUM_SW_LIMIT > 96) + else if (id < 128) + map->m3 &= ~BIT(id - 96); +#endif + else + rtw_warn_on(1); +} + +inline bool rtw_macid_is_used(struct macid_ctl_t *macid_ctl, u8 id) +{ + return rtw_macid_is_set(&macid_ctl->used, id); +} + +inline bool rtw_macid_is_bmc(struct macid_ctl_t *macid_ctl, u8 id) +{ + return rtw_macid_is_set(&macid_ctl->bmc, id); +} + +inline s8 rtw_macid_get_if_g(struct macid_ctl_t *macid_ctl, u8 id) +{ + int i; + +#ifdef CONFIG_SHARED_BMC_MACID + if (rtw_macid_is_bmc(macid_ctl, id)) { + for (i = 0; i < CONFIG_IFACE_NUMBER; i++) + if (macid_ctl->iface_bmc[i] == id) + return i; + return -1; + } +#endif + + for (i = 0; i < CONFIG_IFACE_NUMBER; i++) { + if (rtw_macid_is_set(&macid_ctl->if_g[i], id)) + return i; + } + return -1; +} + +inline s8 rtw_macid_get_ch_g(struct macid_ctl_t *macid_ctl, u8 id) +{ + int i; + + for (i = 0; i < 2; i++) { + if (rtw_macid_is_set(&macid_ctl->ch_g[i], id)) + return i; + } + return -1; +} + +void rtw_alloc_macid(_adapter *padapter, struct sta_info *psta) +{ + int i; + _irqL irqL; + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + struct macid_bmp *used_map = &macid_ctl->used; + /* static u8 last_id = 0; for testing */ + u8 last_id = 0; + u8 is_bc_sta = _FALSE; + + if (_rtw_memcmp(psta->hwaddr, adapter_mac_addr(padapter), ETH_ALEN)) { + psta->mac_id = macid_ctl->num; + return; + } + + if (_rtw_memcmp(psta->hwaddr, bc_addr, ETH_ALEN)) { + is_bc_sta = _TRUE; + rtw_iface_bcmc_id_set(padapter, INVALID_SEC_MAC_CAM_ID); /*init default value*/ + } + +#ifdef CONFIG_SHARED_BMC_MACID + if (is_bc_sta +#ifdef CONFIG_CONCURRENT_MODE + && (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) || check_fwstate(&padapter->mlmepriv, WIFI_NULL_STATE)) +#endif + ) { + /* use shared broadcast & multicast macid 1 for all ifaces which configure to station mode*/ + _enter_critical_bh(&macid_ctl->lock, &irqL); + rtw_macid_map_set(used_map, 1); + rtw_macid_map_set(&macid_ctl->bmc, 1); + rtw_macid_map_set(&macid_ctl->if_g[padapter->iface_id], 1); + macid_ctl->sta[1] = psta; + /* TODO ch_g? */ + _exit_critical_bh(&macid_ctl->lock, &irqL); + i = 1; + goto assigned; + } +#endif + +#ifdef CONFIG_MCC_MODE + if (MCC_EN(padapter)) { + if (MLME_IS_AP(padapter) || MLME_IS_GO(padapter)) + /* GO/AP assign client macid from 8 */ + last_id = 8; + } +#endif /* CONFIG_MCC_MODE */ + + _enter_critical_bh(&macid_ctl->lock, &irqL); + + for (i = last_id; i < macid_ctl->num; i++) { +#ifdef CONFIG_SHARED_BMC_MACID + if (i == 1) + continue; +#endif + +#ifdef CONFIG_MCC_MODE + /* macid 0/1 reserve for mcc for mgnt queue macid */ + if (MCC_EN(padapter)) { + if (i == MCC_ROLE_STA_GC_MGMT_QUEUE_MACID) + continue; + if (i == MCC_ROLE_SOFTAP_GO_MGMT_QUEUE_MACID) + continue; + } +#endif /* CONFIG_MCC_MODE */ + + if (is_bc_sta) {/*for SoftAP's Broadcast sta-info*/ + /*TODO:non-security AP may allociated macid = 1*/ + struct cam_ctl_t *cam_ctl = dvobj_to_sec_camctl(dvobj); + + if ((!rtw_macid_is_used(macid_ctl, i)) && (!rtw_sec_camid_is_used(cam_ctl, i))) + break; + } else { + if (!rtw_macid_is_used(macid_ctl, i)) + break; + } + } + + if (i < macid_ctl->num) { + + rtw_macid_map_set(used_map, i); + + if (is_bc_sta) { + struct cam_ctl_t *cam_ctl = dvobj_to_sec_camctl(dvobj); + + rtw_macid_map_set(&macid_ctl->bmc, i); + rtw_iface_bcmc_id_set(padapter, i); + rtw_sec_cam_map_set(&cam_ctl->used, i); + } + + rtw_macid_map_set(&macid_ctl->if_g[padapter->iface_id], i); + macid_ctl->sta[i] = psta; + + /* TODO ch_g? */ + + last_id++; + last_id %= macid_ctl->num; + } + + _exit_critical_bh(&macid_ctl->lock, &irqL); + + if (i >= macid_ctl->num) { + psta->mac_id = macid_ctl->num; + RTW_ERR(FUNC_ADPT_FMT" if%u, hwaddr:"MAC_FMT" no available macid\n" + , FUNC_ADPT_ARG(padapter), padapter->iface_id + 1, MAC_ARG(psta->hwaddr)); + rtw_warn_on(1); + goto exit; + } else + goto assigned; + +assigned: + psta->mac_id = i; + RTW_INFO(FUNC_ADPT_FMT" if%u, hwaddr:"MAC_FMT" macid:%u\n" + , FUNC_ADPT_ARG(padapter), padapter->iface_id + 1, MAC_ARG(psta->hwaddr), psta->mac_id); + +exit: + return; +} + +void rtw_release_macid(_adapter *padapter, struct sta_info *psta) +{ + _irqL irqL; + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + u8 is_bc_sta = _FALSE; + + if (_rtw_memcmp(psta->hwaddr, adapter_mac_addr(padapter), ETH_ALEN)) + return; + + if (_rtw_memcmp(psta->hwaddr, bc_addr, ETH_ALEN)) + is_bc_sta = _TRUE; + +#ifdef CONFIG_SHARED_BMC_MACID + if (is_bc_sta +#ifdef CONFIG_CONCURRENT_MODE + && (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) || check_fwstate(&padapter->mlmepriv, WIFI_NULL_STATE)) +#endif + ) + return; + + if (psta->mac_id == 1) { + RTW_ERR(FUNC_ADPT_FMT" if%u, hwaddr:"MAC_FMT" with macid:%u\n" + , FUNC_ADPT_ARG(padapter), padapter->iface_id + 1, MAC_ARG(psta->hwaddr), psta->mac_id); + if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) || check_fwstate(&padapter->mlmepriv, WIFI_NULL_STATE)) + rtw_warn_on(1); + return; + } +#endif + + _enter_critical_bh(&macid_ctl->lock, &irqL); + + if (psta->mac_id < macid_ctl->num) { + int i; + + if (!rtw_macid_is_used(macid_ctl, psta->mac_id)) { + RTW_ERR(FUNC_ADPT_FMT" if%u, hwaddr:"MAC_FMT" macid:%u not used\n" + , FUNC_ADPT_ARG(padapter), padapter->iface_id + 1, MAC_ARG(psta->hwaddr), psta->mac_id); + rtw_warn_on(1); + } + + rtw_macid_map_clr(&macid_ctl->used, psta->mac_id); + rtw_macid_map_clr(&macid_ctl->bmc, psta->mac_id); + + if (is_bc_sta) { + struct cam_ctl_t *cam_ctl = dvobj_to_sec_camctl(dvobj); + u8 id = rtw_iface_bcmc_id_get(padapter); + + if ((id != INVALID_SEC_MAC_CAM_ID) && (id < cam_ctl->num)) + rtw_sec_cam_map_clr(&cam_ctl->used, id); + + rtw_iface_bcmc_id_set(padapter, INVALID_SEC_MAC_CAM_ID); + } + + for (i = 0; i < CONFIG_IFACE_NUMBER; i++) + rtw_macid_map_clr(&macid_ctl->if_g[i], psta->mac_id); + for (i = 0; i < 2; i++) + rtw_macid_map_clr(&macid_ctl->ch_g[i], psta->mac_id); + macid_ctl->sta[psta->mac_id] = NULL; + } + + _exit_critical_bh(&macid_ctl->lock, &irqL); + + psta->mac_id = macid_ctl->num; +} + +/* For 8188E RA */ +u8 rtw_search_max_mac_id(_adapter *padapter) +{ + u8 max_mac_id = 0; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + int i; + _irqL irqL; + + /* TODO: Only search for connected macid? */ + + _enter_critical_bh(&macid_ctl->lock, &irqL); + for (i = (macid_ctl->num - 1); i > 0 ; i--) { + if (rtw_macid_is_used(macid_ctl, i)) + break; + } + _exit_critical_bh(&macid_ctl->lock, &irqL); + max_mac_id = i; + + return max_mac_id; +} + +inline void rtw_macid_ctl_set_h2c_msr(struct macid_ctl_t *macid_ctl, u8 id, u8 h2c_msr) +{ + if (id >= macid_ctl->num) { + rtw_warn_on(1); + return; + } + + macid_ctl->h2c_msr[id] = h2c_msr; + if (0) + RTW_INFO("macid:%u, h2c_msr:"H2C_MSR_FMT"\n", id, H2C_MSR_ARG(&macid_ctl->h2c_msr[id])); +} + +inline void rtw_macid_ctl_set_bw(struct macid_ctl_t *macid_ctl, u8 id, u8 bw) +{ + if (id >= macid_ctl->num) { + rtw_warn_on(1); + return; + } + + macid_ctl->bw[id] = bw; + if (0) + RTW_INFO("macid:%u, bw:%s\n", id, ch_width_str(macid_ctl->bw[id])); +} + +inline void rtw_macid_ctl_set_vht_en(struct macid_ctl_t *macid_ctl, u8 id, u8 en) +{ + if (id >= macid_ctl->num) { + rtw_warn_on(1); + return; + } + + macid_ctl->vht_en[id] = en; + if (0) + RTW_INFO("macid:%u, vht_en:%u\n", id, macid_ctl->vht_en[id]); +} + +inline void rtw_macid_ctl_set_rate_bmp0(struct macid_ctl_t *macid_ctl, u8 id, u32 bmp) +{ + if (id >= macid_ctl->num) { + rtw_warn_on(1); + return; + } + + macid_ctl->rate_bmp0[id] = bmp; + if (0) + RTW_INFO("macid:%u, rate_bmp0:0x%08X\n", id, macid_ctl->rate_bmp0[id]); +} + +inline void rtw_macid_ctl_set_rate_bmp1(struct macid_ctl_t *macid_ctl, u8 id, u32 bmp) +{ + if (id >= macid_ctl->num) { + rtw_warn_on(1); + return; + } + + macid_ctl->rate_bmp1[id] = bmp; + if (0) + RTW_INFO("macid:%u, rate_bmp1:0x%08X\n", id, macid_ctl->rate_bmp1[id]); +} + +inline void rtw_macid_ctl_init(struct macid_ctl_t *macid_ctl) +{ + _rtw_spinlock_init(&macid_ctl->lock); +} + +inline void rtw_macid_ctl_deinit(struct macid_ctl_t *macid_ctl) +{ + _rtw_spinlock_free(&macid_ctl->lock); +} + +#if 0 +unsigned int setup_beacon_frame(_adapter *padapter, unsigned char *beacon_frame) +{ + unsigned short ATIMWindow; + unsigned char *pframe; + struct tx_desc *ptxdesc; + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned int rate_len, len = 0; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + _rtw_memset(beacon_frame, 0, 256); + + pframe = beacon_frame + TXDESC_SIZE; + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); + + set_frame_sub_type(pframe, WIFI_BEACON); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + len = sizeof(struct rtw_ieee80211_hdr_3addr); + + /* timestamp will be inserted by hardware */ + pframe += 8; + len += 8; + + /* beacon interval: 2 bytes */ + _rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); + + pframe += 2; + len += 2; + + /* capability info: 2 bytes */ + _rtw_memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); + + pframe += 2; + len += 2; + + /* SSID */ + pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &len); + + /* supported rates... */ + rate_len = rtw_get_rateset_len(cur_network->SupportedRates); + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &len); + + /* DS parameter set */ + pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &len); + + /* IBSS Parameter Set... */ + /* ATIMWindow = cur->Configuration.ATIMWindow; */ + ATIMWindow = 0; + pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &len); + + /* todo: ERP IE */ + + /* EXTERNDED SUPPORTED RATE */ + if (rate_len > 8) + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &len); + + if ((len + TXDESC_SIZE) > 256) { + /* RTW_INFO("marc: beacon frame too large\n"); */ + return 0; + } + + /* fill the tx descriptor */ + ptxdesc = (struct tx_desc *)beacon_frame; + + /* offset 0 */ + ptxdesc->txdw0 |= cpu_to_le32(len & 0x0000ffff); + ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) & 0x00ff0000); /* default = 32 bytes for TX Desc */ + + /* offset 4 */ + ptxdesc->txdw1 |= cpu_to_le32((0x10 << QSEL_SHT) & 0x00001f00); + + /* offset 8 */ + ptxdesc->txdw2 |= cpu_to_le32(BMC); + ptxdesc->txdw2 |= cpu_to_le32(BK); + + /* offset 16 */ + ptxdesc->txdw4 = 0x80000000; + + /* offset 20 */ + ptxdesc->txdw5 = 0x00000000; /* 1M */ + + return len + TXDESC_SIZE; +} +#endif + +_adapter *dvobj_get_port0_adapter(struct dvobj_priv *dvobj) +{ + _adapter *port0_iface = NULL; + int i; + for (i = 0; i < dvobj->iface_nums; i++) { + if (get_hw_port(dvobj->padapters[i]) == HW_PORT0) + break; + } + + if (i < 0 || i >= dvobj->iface_nums) + rtw_warn_on(1); + else + port0_iface = dvobj->padapters[i]; + + return port0_iface; +} + +_adapter *dvobj_get_unregisterd_adapter(struct dvobj_priv *dvobj) +{ + _adapter *adapter = NULL; + int i; + + for (i = 0; i < dvobj->iface_nums; i++) { + if (dvobj->padapters[i]->registered == 0) + break; + } + + if (i < dvobj->iface_nums) + adapter = dvobj->padapters[i]; + + return adapter; +} + +_adapter *dvobj_get_adapter_by_addr(struct dvobj_priv *dvobj, u8 *addr) +{ + _adapter *adapter = NULL; + int i; + + for (i = 0; i < dvobj->iface_nums; i++) { + if (_rtw_memcmp(dvobj->padapters[i]->mac_addr, addr, ETH_ALEN) == _TRUE) + break; + } + + if (i < dvobj->iface_nums) + adapter = dvobj->padapters[i]; + + return adapter; +} + +#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) +void rtw_get_current_ip_address(PADAPTER padapter, u8 *pcurrentip) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct in_device *my_ip_ptr = padapter->pnetdev->ip_ptr; + u8 ipaddress[4]; + + if ((pmlmeinfo->state & WIFI_FW_LINKING_STATE) || + pmlmeinfo->state & WIFI_FW_AP_STATE) { + if (my_ip_ptr != NULL) { + struct in_ifaddr *my_ifa_list = my_ip_ptr->ifa_list ; + if (my_ifa_list != NULL) { + ipaddress[0] = my_ifa_list->ifa_address & 0xFF; + ipaddress[1] = (my_ifa_list->ifa_address >> 8) & 0xFF; + ipaddress[2] = (my_ifa_list->ifa_address >> 16) & 0xFF; + ipaddress[3] = my_ifa_list->ifa_address >> 24; + RTW_INFO("%s: %d.%d.%d.%d ==========\n", __func__, + ipaddress[0], ipaddress[1], ipaddress[2], ipaddress[3]); + _rtw_memcpy(pcurrentip, ipaddress, 4); + } + } + } +} +#endif +#ifdef CONFIG_WOWLAN +bool rtw_wowlan_parser_pattern_cmd(u8 *input, char *pattern, + int *pattern_len, char *bit_mask) +{ + char *cp = NULL, *end = NULL; + size_t len = 0; + int pos = 0, mask_pos = 0, res = 0; + u8 member[2] = {0}; + + cp = strchr(input, '='); + if (cp) { + *cp = 0; + cp++; + input = cp; + } + + while (1) { + cp = strchr(input, ':'); + + if (cp) { + len = strlen(input) - strlen(cp); + *cp = 0; + cp++; + } else + len = 2; + + if (bit_mask && (strcmp(input, "-") == 0 || + strcmp(input, "xx") == 0 || + strcmp(input, "--") == 0)) { + /* skip this byte and leave mask bit unset */ + } else { + u8 hex; + + strncpy(member, input, len); + if (!rtw_check_pattern_valid(member, sizeof(member))) { + RTW_INFO("%s:[ERROR] pattern is invalid!!\n", + __func__); + goto error; + } + + res = sscanf(member, "%02hhx", &hex); + pattern[pos] = hex; + mask_pos = pos / 8; + if (bit_mask) + bit_mask[mask_pos] |= 1 << (pos % 8); + } + + pos++; + if (!cp) + break; + input = cp; + } + + (*pattern_len) = pos; + + return _TRUE; +error: + return _FALSE; +} + +bool rtw_check_pattern_valid(u8 *input, u8 len) +{ + int i = 0; + bool res = _FALSE; + + if (len != 2) + goto exit; + + for (i = 0 ; i < len ; i++) + if (IsHexDigit(input[i]) == _FALSE) + goto exit; + + res = _SUCCESS; + +exit: + return res; +} +void rtw_wow_pattern_sw_reset(_adapter *adapter) +{ + int i; + struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(adapter); + + pwrctrlpriv->wowlan_pattern_idx = DEFAULT_PATTERN_NUM; + + for (i = 0 ; i < MAX_WKFM_CAM_NUM; i++) { + _rtw_memset(pwrctrlpriv->patterns[i].content, '\0', sizeof(pwrctrlpriv->patterns[i].content)); + _rtw_memset(pwrctrlpriv->patterns[i].mask, '\0', sizeof(pwrctrlpriv->patterns[i].mask)); + pwrctrlpriv->patterns[i].len = 0; + } +} + +u8 rtw_set_default_pattern(_adapter *adapter) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); + struct registry_priv *pregistrypriv = &adapter->registrypriv; + u8 index = 0; + u8 currentip[4]; + u8 multicast_addr[3] = {0x01, 0x00, 0x5e}; + u8 multicast_ip[4] = {0xe0, 0x28, 0x28, 0x2a}; + u8 unicast_mask[5] = {0x3f, 0x70, 0x80, 0xc0, 0x03}; + u8 multicast_mask[5] = {0x07, 0x70, 0x80, 0xc0, 0x03}; + u8 ip_protocol[3] = {0x08, 0x00, 0x45}; + u8 icmp_protocol[1] = {0x01}; + u8 tcp_protocol[1] = {0x06}; + u8 udp_protocol[1] = {0x11}; + + if (pregistrypriv->default_patterns_en == _FALSE) + return 0; + + for (index = 0 ; index < DEFAULT_PATTERN_NUM ; index++) { + _rtw_memset(pwrpriv->patterns[index].content, 0, + sizeof(pwrpriv->patterns[index].content)); + _rtw_memset(pwrpriv->patterns[index].mask, 0, + sizeof(pwrpriv->patterns[index].mask)); + pwrpriv->patterns[index].len = 0; + } + + rtw_get_current_ip_address(adapter, currentip); + + /*TCP/ICMP unicast*/ + for (index = 0 ; index < DEFAULT_PATTERN_NUM ; index++) { + switch (index) { + case 0: + _rtw_memcpy(pwrpriv->patterns[index].content, + adapter_mac_addr(adapter), + ETH_ALEN); + _rtw_memcpy(pwrpriv->patterns[index].content + ETH_TYPE_OFFSET, + &ip_protocol, sizeof(ip_protocol)); + _rtw_memcpy(pwrpriv->patterns[index].content + PROTOCOL_OFFSET, + &tcp_protocol, sizeof(tcp_protocol)); + _rtw_memcpy(pwrpriv->patterns[index].content + IP_OFFSET, + ¤tip, sizeof(currentip)); + _rtw_memcpy(pwrpriv->patterns[index].mask, + &unicast_mask, sizeof(unicast_mask)); + pwrpriv->patterns[index].len = IP_OFFSET + sizeof(currentip); + break; + case 1: + _rtw_memcpy(pwrpriv->patterns[index].content, + adapter_mac_addr(adapter), + ETH_ALEN); + _rtw_memcpy(pwrpriv->patterns[index].content + ETH_TYPE_OFFSET, + &ip_protocol, sizeof(ip_protocol)); + _rtw_memcpy(pwrpriv->patterns[index].content + PROTOCOL_OFFSET, + &icmp_protocol, sizeof(icmp_protocol)); + _rtw_memcpy(pwrpriv->patterns[index].content + IP_OFFSET, + ¤tip, sizeof(currentip)); + _rtw_memcpy(pwrpriv->patterns[index].mask, + &unicast_mask, sizeof(unicast_mask)); + pwrpriv->patterns[index].len = IP_OFFSET + sizeof(currentip); + break; + case 2: + _rtw_memcpy(pwrpriv->patterns[index].content, &multicast_addr, + sizeof(multicast_addr)); + _rtw_memcpy(pwrpriv->patterns[index].content + ETH_TYPE_OFFSET, + &ip_protocol, sizeof(ip_protocol)); + _rtw_memcpy(pwrpriv->patterns[index].content + PROTOCOL_OFFSET, + &udp_protocol, sizeof(udp_protocol)); + _rtw_memcpy(pwrpriv->patterns[index].content + IP_OFFSET, + &multicast_ip, sizeof(multicast_ip)); + _rtw_memcpy(pwrpriv->patterns[index].mask, + &multicast_mask, sizeof(multicast_mask)); + pwrpriv->patterns[index].len = + IP_OFFSET + sizeof(multicast_ip); + break; + } + } + + return index; +} + + + +void rtw_dump_priv_pattern(_adapter *adapter, u8 idx) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); + char str_1[128]; + char *p_str; + u8 val8 = 0; + int i = 0, j = 0, len = 0, max_len = 0; + + RTW_INFO("=========[%d]========\n", idx); + + RTW_INFO(">>>priv_pattern_content:\n"); + p_str = str_1; + max_len = sizeof(str_1); + for (i = 0 ; i < MAX_WKFM_PATTERN_SIZE / 8 ; i++) { + _rtw_memset(p_str, 0, max_len); + len = 0; + for (j = 0 ; j < 8 ; j++) { + val8 = pwrctl->patterns[idx].content[i * 8 + j]; + len += snprintf(p_str + len, max_len - len, + "%02x ", val8); + } + RTW_INFO("%s\n", p_str); + } + + RTW_INFO(">>>priv_pattern_mask:\n"); + for (i = 0 ; i < MAX_WKFM_SIZE / 8 ; i++) { + _rtw_memset(p_str, 0, max_len); + len = 0; + for (j = 0 ; j < 8 ; j++) { + val8 = pwrctl->patterns[idx].mask[i * 8 + j]; + len += snprintf(p_str + len, max_len - len, + "%02x ", val8); + } + RTW_INFO("%s\n", p_str); + } + + RTW_INFO(">>>priv_pattern_len:\n"); + RTW_INFO("%s: len: %d\n", __func__, pwrctl->patterns[idx].len); +} + +void rtw_wow_pattern_sw_dump(_adapter *adapter) +{ + int i; + + RTW_INFO("********[RTK priv-patterns]*********\n"); + for (i = 0 ; i < MAX_WKFM_CAM_NUM; i++) + rtw_dump_priv_pattern(adapter, i); +} + +void rtw_get_sec_iv(PADAPTER padapter, u8 *pcur_dot11txpn, u8 *StaAddr) +{ + struct sta_info *psta; + struct security_priv *psecpriv = &padapter->securitypriv; + + _rtw_memset(pcur_dot11txpn, 0, 8); + if (NULL == StaAddr) + return; + psta = rtw_get_stainfo(&padapter->stapriv, StaAddr); + RTW_INFO("%s(): StaAddr: %02x %02x %02x %02x %02x %02x\n", + __func__, StaAddr[0], StaAddr[1], StaAddr[2], + StaAddr[3], StaAddr[4], StaAddr[5]); + + if (psta) { + if (psecpriv->dot11PrivacyAlgrthm == _AES_) + AES_IV(pcur_dot11txpn, psta->dot11txpn, 0); + else if (psecpriv->dot11PrivacyAlgrthm == _TKIP_) + TKIP_IV(pcur_dot11txpn, psta->dot11txpn, 0); + + RTW_INFO("%s(): CurrentIV: %02x %02x %02x %02x %02x %02x %02x %02x\n" + , __func__, pcur_dot11txpn[0], pcur_dot11txpn[1], + pcur_dot11txpn[2], pcur_dot11txpn[3], pcur_dot11txpn[4], + pcur_dot11txpn[5], pcur_dot11txpn[6], pcur_dot11txpn[7]); + } +} +#endif /* CONFIG_WOWLAN */ + +#ifdef CONFIG_PNO_SUPPORT +#define CSCAN_TLV_TYPE_SSID_IE 'S' +#define CIPHER_IE "key_mgmt=" +#define CIPHER_NONE "NONE" +#define CIPHER_WPA_PSK "WPA-PSK" +#define CIPHER_WPA_EAP "WPA-EAP IEEE8021X" +/* + * SSIDs list parsing from cscan tlv list + */ +int rtw_parse_ssid_list_tlv(char **list_str, pno_ssid_t *ssid, + int max, int *bytes_left) +{ + char *str; + + int idx = 0; + + if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { + RTW_INFO("%s error paramters\n", __func__); + return -1; + } + + str = *list_str; + while (*bytes_left > 0) { + + if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { + *list_str = str; + RTW_INFO("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0]); + return idx; + } + + /* Get proper CSCAN_TLV_TYPE_SSID_IE */ + *bytes_left -= 1; + str += 1; + + if (str[0] == 0) { + /* Broadcast SSID */ + ssid[idx].SSID_len = 0; + memset((char *)ssid[idx].SSID, 0x0, WLAN_SSID_MAXLEN); + *bytes_left -= 1; + str += 1; + + RTW_INFO("BROADCAST SCAN left=%d\n", *bytes_left); + } else if (str[0] <= WLAN_SSID_MAXLEN) { + /* Get proper SSID size */ + ssid[idx].SSID_len = str[0]; + *bytes_left -= 1; + str += 1; + + /* Get SSID */ + if (ssid[idx].SSID_len > *bytes_left) { + RTW_INFO("%s out of memory range len=%d but left=%d\n", + __func__, ssid[idx].SSID_len, *bytes_left); + return -1; + } + + memcpy((char *)ssid[idx].SSID, str, ssid[idx].SSID_len); + + *bytes_left -= ssid[idx].SSID_len; + str += ssid[idx].SSID_len; + + RTW_INFO("%s :size=%d left=%d\n", + (char *)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left); + } else { + RTW_INFO("### SSID size more that %d\n", str[0]); + return -1; + } + + if (idx++ > max) { + RTW_INFO("%s number of SSIDs more that %d\n", __func__, idx); + return -1; + } + } + + *list_str = str; + return idx; +} + +int rtw_parse_cipher_list(struct pno_nlo_info *nlo_info, char *list_str) +{ + + char *pch, *pnext, *pend; + u8 key_len = 0, index = 0; + + pch = list_str; + + if (nlo_info == NULL || list_str == NULL) { + RTW_INFO("%s error paramters\n", __func__); + return -1; + } + + while (strlen(pch) != 0) { + pnext = strstr(pch, "key_mgmt="); + if (pnext != NULL) { + pch = pnext + strlen(CIPHER_IE); + pend = strstr(pch, "}"); + if (strncmp(pch, CIPHER_NONE, + strlen(CIPHER_NONE)) == 0) + nlo_info->ssid_cipher_info[index] = 0x00; + else if (strncmp(pch, CIPHER_WPA_PSK, + strlen(CIPHER_WPA_PSK)) == 0) + nlo_info->ssid_cipher_info[index] = 0x66; + else if (strncmp(pch, CIPHER_WPA_EAP, + strlen(CIPHER_WPA_EAP)) == 0) + nlo_info->ssid_cipher_info[index] = 0x01; + index++; + pch = pend + 1; + } else + break; + } + return 0; +} + +int rtw_dev_nlo_info_set(struct pno_nlo_info *nlo_info, pno_ssid_t *ssid, + int num, int pno_time, int pno_repeat, int pno_freq_expo_max) +{ + + int i = 0; + struct file *fp; + mm_segment_t fs; + loff_t pos = 0; + u8 *source = NULL; + long len = 0; + + RTW_INFO("+%s+\n", __func__); + + nlo_info->fast_scan_period = pno_time; + nlo_info->ssid_num = num & BIT_LEN_MASK_32(8); + nlo_info->hidden_ssid_num = num & BIT_LEN_MASK_32(8); + nlo_info->slow_scan_period = (pno_time * 2); + nlo_info->fast_scan_iterations = 5; + + if (nlo_info->hidden_ssid_num > 8) + nlo_info->hidden_ssid_num = 8; + + /* TODO: channel list and probe index is all empty. */ + for (i = 0 ; i < num ; i++) { + nlo_info->ssid_length[i] + = ssid[i].SSID_len; + } + + /* cipher array */ + fp = filp_open("/data/misc/wifi/wpa_supplicant.conf", O_RDONLY, 0644); + if (IS_ERR(fp)) { + RTW_INFO("Error, wpa_supplicant.conf doesn't exist.\n"); + RTW_INFO("Error, cipher array using default value.\n"); + return 0; + } + + len = i_size_read(fp->f_path.dentry->d_inode); + if (len < 0 || len > 2048) { + RTW_INFO("Error, file size is bigger than 2048.\n"); + RTW_INFO("Error, cipher array using default value.\n"); + return 0; + } + + fs = get_fs(); + set_fs(KERNEL_DS); + + source = rtw_zmalloc(2048); + + if (source != NULL) { + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) + len = kernel_read(fp, source, len, &pos); + #else + len = vfs_read(fp, source, len, &pos); + #endif + rtw_parse_cipher_list(nlo_info, source); + rtw_mfree(source, 2048); + } + + set_fs(fs); + filp_close(fp, NULL); + + RTW_INFO("-%s-\n", __func__); + return 0; +} + +int rtw_dev_ssid_list_set(struct pno_ssid_list *pno_ssid_list, + pno_ssid_t *ssid, u8 num) +{ + + int i = 0; + if (num > MAX_PNO_LIST_COUNT) + num = MAX_PNO_LIST_COUNT; + + for (i = 0 ; i < num ; i++) { + _rtw_memcpy(&pno_ssid_list->node[i].SSID, + ssid[i].SSID, ssid[i].SSID_len); + pno_ssid_list->node[i].SSID_len = ssid[i].SSID_len; + } + return 0; +} + +int rtw_dev_scan_info_set(_adapter *padapter, pno_ssid_t *ssid, + unsigned char ch, unsigned char ch_offset, unsigned short bw_mode) +{ + + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); + struct pno_scan_info *scan_info = pwrctl->pscan_info; + int i; + + scan_info->channel_num = MAX_SCAN_LIST_COUNT; + scan_info->orig_ch = ch; + scan_info->orig_bw = bw_mode; + scan_info->orig_40_offset = ch_offset; + + for (i = 0 ; i < scan_info->channel_num ; i++) { + if (i < 11) + scan_info->ssid_channel_info[i].active = 1; + else + scan_info->ssid_channel_info[i].active = 0; + + scan_info->ssid_channel_info[i].timeout = 100; + + scan_info->ssid_channel_info[i].tx_power = + phy_get_tx_power_index(padapter, 0, 0x02, bw_mode, i + 1); + + scan_info->ssid_channel_info[i].channel = i + 1; + } + + RTW_INFO("%s, channel_num: %d, orig_ch: %d, orig_bw: %d orig_40_offset: %d\n", + __func__, scan_info->channel_num, scan_info->orig_ch, + scan_info->orig_bw, scan_info->orig_40_offset); + return 0; +} + +int rtw_dev_pno_set(struct net_device *net, pno_ssid_t *ssid, int num, + int pno_time, int pno_repeat, int pno_freq_expo_max) +{ + + _adapter *padapter = (_adapter *)rtw_netdev_priv(net); + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + int ret = -1; + + if (num == 0) { + RTW_INFO("%s, nssid is zero, no need to setup pno ssid list\n", __func__); + return 0; + } + + if (pwrctl == NULL) { + RTW_INFO("%s, ERROR: pwrctl is NULL\n", __func__); + return -1; + } else { + pwrctl->pnlo_info = + (pno_nlo_info_t *)rtw_zmalloc(sizeof(pno_nlo_info_t)); + pwrctl->pno_ssid_list = + (pno_ssid_list_t *)rtw_zmalloc(sizeof(pno_ssid_list_t)); + pwrctl->pscan_info = + (pno_scan_info_t *)rtw_zmalloc(sizeof(pno_scan_info_t)); + } + + if (pwrctl->pnlo_info == NULL || + pwrctl->pscan_info == NULL || + pwrctl->pno_ssid_list == NULL) { + RTW_INFO("%s, ERROR: alloc nlo_info, ssid_list, scan_info fail\n", __func__); + goto failing; + } + + pwrctl->wowlan_in_resume = _FALSE; + + pwrctl->pno_inited = _TRUE; + /* NLO Info */ + ret = rtw_dev_nlo_info_set(pwrctl->pnlo_info, ssid, num, + pno_time, pno_repeat, pno_freq_expo_max); + + /* SSID Info */ + ret = rtw_dev_ssid_list_set(pwrctl->pno_ssid_list, ssid, num); + + /* SCAN Info */ + ret = rtw_dev_scan_info_set(padapter, ssid, pmlmeext->cur_channel, + pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); + + RTW_INFO("+%s num: %d, pno_time: %d, pno_repeat:%d, pno_freq_expo_max:%d+\n", + __func__, num, pno_time, pno_repeat, pno_freq_expo_max); + + return 0; + +failing: + if (pwrctl->pnlo_info) { + rtw_mfree((u8 *)pwrctl->pnlo_info, sizeof(pno_nlo_info_t)); + pwrctl->pnlo_info = NULL; + } + if (pwrctl->pno_ssid_list) { + rtw_mfree((u8 *)pwrctl->pno_ssid_list, sizeof(pno_ssid_list_t)); + pwrctl->pno_ssid_list = NULL; + } + if (pwrctl->pscan_info) { + rtw_mfree((u8 *)pwrctl->pscan_info, sizeof(pno_scan_info_t)); + pwrctl->pscan_info = NULL; + } + + return -1; +} + +#ifdef CONFIG_PNO_SET_DEBUG +void rtw_dev_pno_debug(struct net_device *net) +{ + _adapter *padapter = (_adapter *)rtw_netdev_priv(net); + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); + int i = 0, j = 0; + + RTW_INFO("*******NLO_INFO********\n"); + RTW_INFO("ssid_num: %d\n", pwrctl->pnlo_info->ssid_num); + RTW_INFO("fast_scan_iterations: %d\n", + pwrctl->pnlo_info->fast_scan_iterations); + RTW_INFO("fast_scan_period: %d\n", pwrctl->pnlo_info->fast_scan_period); + RTW_INFO("slow_scan_period: %d\n", pwrctl->pnlo_info->slow_scan_period); + + + + for (i = 0 ; i < MAX_PNO_LIST_COUNT ; i++) { + RTW_INFO("%d SSID (%s) length (%d) cipher(%x) channel(%d)\n", + i, pwrctl->pno_ssid_list->node[i].SSID, pwrctl->pnlo_info->ssid_length[i], + pwrctl->pnlo_info->ssid_cipher_info[i], pwrctl->pnlo_info->ssid_channel_info[i]); + } + + RTW_INFO("******SCAN_INFO******\n"); + RTW_INFO("ch_num: %d\n", pwrctl->pscan_info->channel_num); + RTW_INFO("orig_ch: %d\n", pwrctl->pscan_info->orig_ch); + RTW_INFO("orig bw: %d\n", pwrctl->pscan_info->orig_bw); + RTW_INFO("orig 40 offset: %d\n", pwrctl->pscan_info->orig_40_offset); + for (i = 0 ; i < MAX_SCAN_LIST_COUNT ; i++) { + RTW_INFO("[%02d] avtive:%d, timeout:%d, tx_power:%d, ch:%02d\n", + i, pwrctl->pscan_info->ssid_channel_info[i].active, + pwrctl->pscan_info->ssid_channel_info[i].timeout, + pwrctl->pscan_info->ssid_channel_info[i].tx_power, + pwrctl->pscan_info->ssid_channel_info[i].channel); + } + RTW_INFO("*****************\n"); +} +#endif /* CONFIG_PNO_SET_DEBUG */ +#endif /* CONFIG_PNO_SUPPORT */ diff --git a/linux-bsp/drivers/rtl8188eus/core/rtw_xmit.c b/linux-bsp/drivers/rtl8188eus/core/rtw_xmit.c new file mode 100644 index 0000000..3cc261b --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/core/rtw_xmit.c @@ -0,0 +1,5545 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _RTW_XMIT_C_ + +#include <drv_types.h> +#include <hal_data.h> + +#if defined(PLATFORM_LINUX) && defined (PLATFORM_WINDOWS) + #error "Shall be Linux or Windows, but not both!\n" +#endif + + +static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; +static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; + +static void _init_txservq(struct tx_servq *ptxservq) +{ + _rtw_init_listhead(&ptxservq->tx_pending); + _rtw_init_queue(&ptxservq->sta_pending); + ptxservq->qcnt = 0; +} + + +void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv) +{ + + + _rtw_memset((unsigned char *)psta_xmitpriv, 0, sizeof(struct sta_xmit_priv)); + + _rtw_spinlock_init(&psta_xmitpriv->lock); + + /* for(i = 0 ; i < MAX_NUMBLKS; i++) */ + /* _init_txservq(&(psta_xmitpriv->blk_q[i])); */ + + _init_txservq(&psta_xmitpriv->be_q); + _init_txservq(&psta_xmitpriv->bk_q); + _init_txservq(&psta_xmitpriv->vi_q); + _init_txservq(&psta_xmitpriv->vo_q); + _rtw_init_listhead(&psta_xmitpriv->legacy_dz); + _rtw_init_listhead(&psta_xmitpriv->apsd); + + +} + +s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, _adapter *padapter) +{ + int i; + struct xmit_buf *pxmitbuf; + struct xmit_frame *pxframe; + sint res = _SUCCESS; + + + /* We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */ + /* _rtw_memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv)); */ + + _rtw_spinlock_init(&pxmitpriv->lock); + _rtw_spinlock_init(&pxmitpriv->lock_sctx); + _rtw_init_sema(&pxmitpriv->xmit_sema, 0); + _rtw_init_sema(&pxmitpriv->terminate_xmitthread_sema, 0); + + /* + Please insert all the queue initializaiton using _rtw_init_queue below + */ + + pxmitpriv->adapter = padapter; + + /* for(i = 0 ; i < MAX_NUMBLKS; i++) */ + /* _rtw_init_queue(&pxmitpriv->blk_strms[i]); */ + + _rtw_init_queue(&pxmitpriv->be_pending); + _rtw_init_queue(&pxmitpriv->bk_pending); + _rtw_init_queue(&pxmitpriv->vi_pending); + _rtw_init_queue(&pxmitpriv->vo_pending); + _rtw_init_queue(&pxmitpriv->bm_pending); + + /* _rtw_init_queue(&pxmitpriv->legacy_dz_queue); */ + /* _rtw_init_queue(&pxmitpriv->apsd_queue); */ + + _rtw_init_queue(&pxmitpriv->free_xmit_queue); + + /* + Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME, + and initialize free_xmit_frame below. + Please also apply free_txobj to link_up all the xmit_frames... + */ + + pxmitpriv->pallocated_frame_buf = rtw_zvmalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4); + + if (pxmitpriv->pallocated_frame_buf == NULL) { + pxmitpriv->pxmit_frame_buf = NULL; + res = _FAIL; + goto exit; + } + pxmitpriv->pxmit_frame_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_frame_buf), 4); + /* pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 - */ + /* ((SIZE_PTR) (pxmitpriv->pallocated_frame_buf) &3); */ + + pxframe = (struct xmit_frame *) pxmitpriv->pxmit_frame_buf; + + for (i = 0; i < NR_XMITFRAME; i++) { + _rtw_init_listhead(&(pxframe->list)); + + pxframe->padapter = padapter; + pxframe->frame_tag = NULL_FRAMETAG; + + pxframe->pkt = NULL; + + pxframe->buf_addr = NULL; + pxframe->pxmitbuf = NULL; + + rtw_list_insert_tail(&(pxframe->list), &(pxmitpriv->free_xmit_queue.queue)); + + pxframe++; + } + + pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME; + + pxmitpriv->frag_len = MAX_FRAG_THRESHOLD; + + + /* init xmit_buf */ + _rtw_init_queue(&pxmitpriv->free_xmitbuf_queue); + _rtw_init_queue(&pxmitpriv->pending_xmitbuf_queue); + + pxmitpriv->pallocated_xmitbuf = rtw_zvmalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4); + + if (pxmitpriv->pallocated_xmitbuf == NULL) { + res = _FAIL; + goto exit; + } + + pxmitpriv->pxmitbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_xmitbuf), 4); + /* pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 - */ + /* ((SIZE_PTR) (pxmitpriv->pallocated_xmitbuf) &3); */ + + pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; + + for (i = 0; i < NR_XMITBUFF; i++) { + _rtw_init_listhead(&pxmitbuf->list); + + pxmitbuf->priv_data = NULL; + pxmitbuf->padapter = padapter; + pxmitbuf->buf_tag = XMITBUF_DATA; + + /* Tx buf allocation may fail sometimes, so sleep and retry. */ + res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ), _TRUE); + if (res == _FAIL) { + rtw_msleep_os(10); + res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ), _TRUE); + if (res == _FAIL) + goto exit; + } + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + pxmitbuf->phead = pxmitbuf->pbuf; + pxmitbuf->pend = pxmitbuf->pbuf + MAX_XMITBUF_SZ; + pxmitbuf->len = 0; + pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; +#endif + + pxmitbuf->flags = XMIT_VO_QUEUE; + + rtw_list_insert_tail(&pxmitbuf->list, &(pxmitpriv->free_xmitbuf_queue.queue)); +#ifdef DBG_XMIT_BUF + pxmitbuf->no = i; +#endif + + pxmitbuf++; + + } + + pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF; + + /* init xframe_ext queue, the same count as extbuf */ + _rtw_init_queue(&pxmitpriv->free_xframe_ext_queue); + + pxmitpriv->xframe_ext_alloc_addr = rtw_zvmalloc(NR_XMIT_EXTBUFF * sizeof(struct xmit_frame) + 4); + + if (pxmitpriv->xframe_ext_alloc_addr == NULL) { + pxmitpriv->xframe_ext = NULL; + res = _FAIL; + goto exit; + } + pxmitpriv->xframe_ext = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->xframe_ext_alloc_addr), 4); + pxframe = (struct xmit_frame *)pxmitpriv->xframe_ext; + + for (i = 0; i < NR_XMIT_EXTBUFF; i++) { + _rtw_init_listhead(&(pxframe->list)); + + pxframe->padapter = padapter; + pxframe->frame_tag = NULL_FRAMETAG; + + pxframe->pkt = NULL; + + pxframe->buf_addr = NULL; + pxframe->pxmitbuf = NULL; + + pxframe->ext_tag = 1; + + rtw_list_insert_tail(&(pxframe->list), &(pxmitpriv->free_xframe_ext_queue.queue)); + + pxframe++; + } + pxmitpriv->free_xframe_ext_cnt = NR_XMIT_EXTBUFF; + + /* Init xmit extension buff */ + _rtw_init_queue(&pxmitpriv->free_xmit_extbuf_queue); + + pxmitpriv->pallocated_xmit_extbuf = rtw_zvmalloc(NR_XMIT_EXTBUFF * sizeof(struct xmit_buf) + 4); + + if (pxmitpriv->pallocated_xmit_extbuf == NULL) { + res = _FAIL; + goto exit; + } + + pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(pxmitpriv->pallocated_xmit_extbuf), 4); + + pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; + + for (i = 0; i < NR_XMIT_EXTBUFF; i++) { + _rtw_init_listhead(&pxmitbuf->list); + + pxmitbuf->priv_data = NULL; + pxmitbuf->padapter = padapter; + pxmitbuf->buf_tag = XMITBUF_MGNT; + + res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, MAX_XMIT_EXTBUF_SZ + XMITBUF_ALIGN_SZ, _TRUE); + if (res == _FAIL) { + res = _FAIL; + goto exit; + } + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + pxmitbuf->phead = pxmitbuf->pbuf; + pxmitbuf->pend = pxmitbuf->pbuf + MAX_XMIT_EXTBUF_SZ; + pxmitbuf->len = 0; + pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; +#endif + + rtw_list_insert_tail(&pxmitbuf->list, &(pxmitpriv->free_xmit_extbuf_queue.queue)); +#ifdef DBG_XMIT_BUF_EXT + pxmitbuf->no = i; +#endif + pxmitbuf++; + + } + + pxmitpriv->free_xmit_extbuf_cnt = NR_XMIT_EXTBUFF; + + for (i = 0; i < CMDBUF_MAX; i++) { + pxmitbuf = &pxmitpriv->pcmd_xmitbuf[i]; + if (pxmitbuf) { + _rtw_init_listhead(&pxmitbuf->list); + + pxmitbuf->priv_data = NULL; + pxmitbuf->padapter = padapter; + pxmitbuf->buf_tag = XMITBUF_CMD; + + res = rtw_os_xmit_resource_alloc(padapter, pxmitbuf, MAX_CMDBUF_SZ + XMITBUF_ALIGN_SZ, _TRUE); + if (res == _FAIL) { + res = _FAIL; + goto exit; + } + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + pxmitbuf->phead = pxmitbuf->pbuf; + pxmitbuf->pend = pxmitbuf->pbuf + MAX_CMDBUF_SZ; + pxmitbuf->len = 0; + pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; +#endif + pxmitbuf->alloc_sz = MAX_CMDBUF_SZ + XMITBUF_ALIGN_SZ; + } + } + + rtw_alloc_hwxmits(padapter); + rtw_init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); + + for (i = 0; i < 4; i++) + pxmitpriv->wmm_para_seq[i] = i; + +#ifdef CONFIG_USB_HCI + pxmitpriv->txirp_cnt = 1; + + _rtw_init_sema(&(pxmitpriv->tx_retevt), 0); + + /* per AC pending irp */ + pxmitpriv->beq_cnt = 0; + pxmitpriv->bkq_cnt = 0; + pxmitpriv->viq_cnt = 0; + pxmitpriv->voq_cnt = 0; +#endif + + +#ifdef CONFIG_XMIT_ACK + pxmitpriv->ack_tx = _FALSE; + _rtw_mutex_init(&pxmitpriv->ack_tx_mutex); + rtw_sctx_init(&pxmitpriv->ack_tx_ops, 0); +#endif + +#ifdef CONFIG_TX_AMSDU + _init_timer(&(pxmitpriv->amsdu_vo_timer), padapter->pnetdev, + rtw_amsdu_vo_timeout_handler, padapter); + pxmitpriv->amsdu_vo_timeout = RTW_AMSDU_TIMER_UNSET; + + _init_timer(&(pxmitpriv->amsdu_vi_timer), padapter->pnetdev, + rtw_amsdu_vi_timeout_handler, padapter); + pxmitpriv->amsdu_vi_timeout = RTW_AMSDU_TIMER_UNSET; + + _init_timer(&(pxmitpriv->amsdu_be_timer), padapter->pnetdev, + rtw_amsdu_be_timeout_handler, padapter); + pxmitpriv->amsdu_be_timeout = RTW_AMSDU_TIMER_UNSET; + + _init_timer(&(pxmitpriv->amsdu_bk_timer), padapter->pnetdev, + rtw_amsdu_bk_timeout_handler, padapter); + pxmitpriv->amsdu_bk_timeout = RTW_AMSDU_TIMER_UNSET; + + pxmitpriv->amsdu_debug_set_timer = 0; + pxmitpriv->amsdu_debug_timeout = 0; + pxmitpriv->amsdu_debug_coalesce_one = 0; + pxmitpriv->amsdu_debug_coalesce_two = 0; +#endif + rtw_hal_init_xmit_priv(padapter); + +exit: + + + return res; +} + +void rtw_mfree_xmit_priv_lock(struct xmit_priv *pxmitpriv); +void rtw_mfree_xmit_priv_lock(struct xmit_priv *pxmitpriv) +{ + _rtw_spinlock_free(&pxmitpriv->lock); + _rtw_free_sema(&pxmitpriv->xmit_sema); + _rtw_free_sema(&pxmitpriv->terminate_xmitthread_sema); + + _rtw_spinlock_free(&pxmitpriv->be_pending.lock); + _rtw_spinlock_free(&pxmitpriv->bk_pending.lock); + _rtw_spinlock_free(&pxmitpriv->vi_pending.lock); + _rtw_spinlock_free(&pxmitpriv->vo_pending.lock); + _rtw_spinlock_free(&pxmitpriv->bm_pending.lock); + + /* _rtw_spinlock_free(&pxmitpriv->legacy_dz_queue.lock); */ + /* _rtw_spinlock_free(&pxmitpriv->apsd_queue.lock); */ + + _rtw_spinlock_free(&pxmitpriv->free_xmit_queue.lock); + _rtw_spinlock_free(&pxmitpriv->free_xmitbuf_queue.lock); + _rtw_spinlock_free(&pxmitpriv->pending_xmitbuf_queue.lock); +} + + +void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv) +{ + int i; + _adapter *padapter = pxmitpriv->adapter; + struct xmit_frame *pxmitframe = (struct xmit_frame *) pxmitpriv->pxmit_frame_buf; + struct xmit_buf *pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; + + + rtw_hal_free_xmit_priv(padapter); + + rtw_mfree_xmit_priv_lock(pxmitpriv); + + if (pxmitpriv->pxmit_frame_buf == NULL) + goto out; + + for (i = 0; i < NR_XMITFRAME; i++) { + rtw_os_xmit_complete(padapter, pxmitframe); + + pxmitframe++; + } + + for (i = 0; i < NR_XMITBUFF; i++) { + rtw_os_xmit_resource_free(padapter, pxmitbuf, (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ), _TRUE); + + pxmitbuf++; + } + + if (pxmitpriv->pallocated_frame_buf) + rtw_vmfree(pxmitpriv->pallocated_frame_buf, NR_XMITFRAME * sizeof(struct xmit_frame) + 4); + + + if (pxmitpriv->pallocated_xmitbuf) + rtw_vmfree(pxmitpriv->pallocated_xmitbuf, NR_XMITBUFF * sizeof(struct xmit_buf) + 4); + + /* free xframe_ext queue, the same count as extbuf */ + if ((pxmitframe = (struct xmit_frame *)pxmitpriv->xframe_ext)) { + for (i = 0; i < NR_XMIT_EXTBUFF; i++) { + rtw_os_xmit_complete(padapter, pxmitframe); + pxmitframe++; + } + } + if (pxmitpriv->xframe_ext_alloc_addr) + rtw_vmfree(pxmitpriv->xframe_ext_alloc_addr, NR_XMIT_EXTBUFF * sizeof(struct xmit_frame) + 4); + _rtw_spinlock_free(&pxmitpriv->free_xframe_ext_queue.lock); + + /* free xmit extension buff */ + _rtw_spinlock_free(&pxmitpriv->free_xmit_extbuf_queue.lock); + + pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; + for (i = 0; i < NR_XMIT_EXTBUFF; i++) { + rtw_os_xmit_resource_free(padapter, pxmitbuf, (MAX_XMIT_EXTBUF_SZ + XMITBUF_ALIGN_SZ), _TRUE); + + pxmitbuf++; + } + + if (pxmitpriv->pallocated_xmit_extbuf) + rtw_vmfree(pxmitpriv->pallocated_xmit_extbuf, NR_XMIT_EXTBUFF * sizeof(struct xmit_buf) + 4); + + for (i = 0; i < CMDBUF_MAX; i++) { + pxmitbuf = &pxmitpriv->pcmd_xmitbuf[i]; + if (pxmitbuf != NULL) + rtw_os_xmit_resource_free(padapter, pxmitbuf, MAX_CMDBUF_SZ + XMITBUF_ALIGN_SZ , _TRUE); + } + + rtw_free_hwxmits(padapter); + +#ifdef CONFIG_XMIT_ACK + _rtw_mutex_free(&pxmitpriv->ack_tx_mutex); +#endif + +out: + return; +} + +u8 rtw_get_tx_bw_mode(_adapter *adapter, struct sta_info *sta) +{ + u8 bw; + + bw = sta->bw_mode; + if (MLME_STATE(adapter) & WIFI_ASOC_STATE) { + if (adapter->mlmeextpriv.cur_channel <= 14) + bw = rtw_min(bw, ADAPTER_TX_BW_2G(adapter)); + else + bw = rtw_min(bw, ADAPTER_TX_BW_5G(adapter)); + } + + return bw; +} + +void rtw_get_adapter_tx_rate_bmp_by_bw(_adapter *adapter, u8 bw, u16 *r_bmp_cck_ofdm, u32 *r_bmp_ht, u32 *r_bmp_vht) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv; + u8 fix_bw = 0xFF; + u16 bmp_cck_ofdm = 0; + u32 bmp_ht = 0; + u32 bmp_vht = 0; + int i; + + if (adapter->fix_rate != 0xFF && adapter->fix_bw != 0xFF) + fix_bw = adapter->fix_bw; + + /* TODO: adapter->fix_rate */ + + for (i = 0; i < macid_ctl->num; i++) { + if (!rtw_macid_is_used(macid_ctl, i)) + continue; + if (rtw_macid_get_if_g(macid_ctl, i) != adapter->iface_id) + continue; + + if (bw == CHANNEL_WIDTH_20) /* CCK, OFDM always 20MHz */ + bmp_cck_ofdm |= macid_ctl->rate_bmp0[i] & 0x00000FFF; + + /* bypass mismatch bandwidth for HT, VHT */ + if ((fix_bw != 0xFF && fix_bw != bw) || (fix_bw == 0xFF && macid_ctl->bw[i] != bw)) + continue; + + if (macid_ctl->vht_en[i]) + bmp_vht |= (macid_ctl->rate_bmp0[i] >> 12) | (macid_ctl->rate_bmp1[i] << 20); + else + bmp_ht |= (macid_ctl->rate_bmp0[i] >> 12) | (macid_ctl->rate_bmp1[i] << 20); + } + + /* TODO: mlmeext->tx_rate*/ + +exit: + if (r_bmp_cck_ofdm) + *r_bmp_cck_ofdm = bmp_cck_ofdm; + if (r_bmp_ht) + *r_bmp_ht = bmp_ht; + if (r_bmp_vht) + *r_bmp_vht = bmp_vht; +} + +void rtw_get_shared_macid_tx_rate_bmp_by_bw(struct dvobj_priv *dvobj, u8 bw, u16 *r_bmp_cck_ofdm, u32 *r_bmp_ht, u32 *r_bmp_vht) +{ + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + u16 bmp_cck_ofdm = 0; + u32 bmp_ht = 0; + u32 bmp_vht = 0; + int i; + + for (i = 0; i < macid_ctl->num; i++) { + if (!rtw_macid_is_used(macid_ctl, i)) + continue; + if (rtw_macid_get_if_g(macid_ctl, i) != -1) + continue; + + if (bw == CHANNEL_WIDTH_20) /* CCK, OFDM always 20MHz */ + bmp_cck_ofdm |= macid_ctl->rate_bmp0[i] & 0x00000FFF; + + /* bypass mismatch bandwidth for HT, VHT */ + if (macid_ctl->bw[i] != bw) + continue; + + if (macid_ctl->vht_en[i]) + bmp_vht |= (macid_ctl->rate_bmp0[i] >> 12) | (macid_ctl->rate_bmp1[i] << 20); + else + bmp_ht |= (macid_ctl->rate_bmp0[i] >> 12) | (macid_ctl->rate_bmp1[i] << 20); + } + + if (r_bmp_cck_ofdm) + *r_bmp_cck_ofdm = bmp_cck_ofdm; + if (r_bmp_ht) + *r_bmp_ht = bmp_ht; + if (r_bmp_vht) + *r_bmp_vht = bmp_vht; +} + +void rtw_update_tx_rate_bmp(struct dvobj_priv *dvobj) +{ + struct rf_ctl_t *rf_ctl = dvobj_to_rfctl(dvobj); + _adapter *adapter = dvobj_get_primary_adapter(dvobj); + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + u8 bw; + u16 bmp_cck_ofdm, tmp_cck_ofdm; + u32 bmp_ht, tmp_ht, ori_bmp_ht[2]; + u8 ori_highest_ht_rate_bw_bmp; + u32 bmp_vht, tmp_vht, ori_bmp_vht[4]; + u8 ori_highest_vht_rate_bw_bmp; + int i; + + /* backup the original ht & vht highest bw bmp */ + ori_highest_ht_rate_bw_bmp = rf_ctl->highest_ht_rate_bw_bmp; + ori_highest_vht_rate_bw_bmp = rf_ctl->highest_vht_rate_bw_bmp; + + for (bw = CHANNEL_WIDTH_20; bw <= CHANNEL_WIDTH_160; bw++) { + /* backup the original ht & vht bmp */ + if (bw <= CHANNEL_WIDTH_40) + ori_bmp_ht[bw] = rf_ctl->rate_bmp_ht_by_bw[bw]; + if (bw <= CHANNEL_WIDTH_160) + ori_bmp_vht[bw] = rf_ctl->rate_bmp_vht_by_bw[bw]; + + bmp_cck_ofdm = bmp_ht = bmp_vht = 0; + if (hal_is_bw_support(dvobj_get_primary_adapter(dvobj), bw)) { + for (i = 0; i < dvobj->iface_nums; i++) { + if (!dvobj->padapters[i]) + continue; + rtw_get_adapter_tx_rate_bmp_by_bw(dvobj->padapters[i], bw, &tmp_cck_ofdm, &tmp_ht, &tmp_vht); + bmp_cck_ofdm |= tmp_cck_ofdm; + bmp_ht |= tmp_ht; + bmp_vht |= tmp_vht; + } + rtw_get_shared_macid_tx_rate_bmp_by_bw(dvobj, bw, &tmp_cck_ofdm, &tmp_ht, &tmp_vht); + bmp_cck_ofdm |= tmp_cck_ofdm; + bmp_ht |= tmp_ht; + bmp_vht |= tmp_vht; + } + if (bw == CHANNEL_WIDTH_20) + rf_ctl->rate_bmp_cck_ofdm = bmp_cck_ofdm; + if (bw <= CHANNEL_WIDTH_40) + rf_ctl->rate_bmp_ht_by_bw[bw] = bmp_ht; + if (bw <= CHANNEL_WIDTH_160) + rf_ctl->rate_bmp_vht_by_bw[bw] = bmp_vht; + } + +#ifndef DBG_HIGHEST_RATE_BMP_BW_CHANGE +#define DBG_HIGHEST_RATE_BMP_BW_CHANGE 0 +#endif + + { + u8 highest_rate_bw; + u8 highest_rate_bw_bmp; + u8 update_ht_rs = _FALSE; + u8 update_vht_rs = _FALSE; + + highest_rate_bw_bmp = BW_CAP_20M; + highest_rate_bw = CHANNEL_WIDTH_20; + for (bw = CHANNEL_WIDTH_20; bw <= CHANNEL_WIDTH_40; bw++) { + if (rf_ctl->rate_bmp_ht_by_bw[highest_rate_bw] < rf_ctl->rate_bmp_ht_by_bw[bw]) { + highest_rate_bw_bmp = ch_width_to_bw_cap(bw); + highest_rate_bw = bw; + } else if (rf_ctl->rate_bmp_ht_by_bw[highest_rate_bw] == rf_ctl->rate_bmp_ht_by_bw[bw]) + highest_rate_bw_bmp |= ch_width_to_bw_cap(bw); + } + rf_ctl->highest_ht_rate_bw_bmp = highest_rate_bw_bmp; + + if (ori_highest_ht_rate_bw_bmp != rf_ctl->highest_ht_rate_bw_bmp + || largest_bit(ori_bmp_ht[highest_rate_bw]) != largest_bit(rf_ctl->rate_bmp_ht_by_bw[highest_rate_bw]) + ) { + if (DBG_HIGHEST_RATE_BMP_BW_CHANGE) { + RTW_INFO("highest_ht_rate_bw_bmp:0x%02x=>0x%02x\n", ori_highest_ht_rate_bw_bmp, rf_ctl->highest_ht_rate_bw_bmp); + RTW_INFO("rate_bmp_ht_by_bw[%u]:0x%08x=>0x%08x\n", highest_rate_bw, ori_bmp_ht[highest_rate_bw], rf_ctl->rate_bmp_ht_by_bw[highest_rate_bw]); + } + update_ht_rs = _TRUE; + } + + highest_rate_bw_bmp = BW_CAP_20M; + highest_rate_bw = CHANNEL_WIDTH_20; + for (bw = CHANNEL_WIDTH_20; bw <= CHANNEL_WIDTH_160; bw++) { + if (rf_ctl->rate_bmp_vht_by_bw[highest_rate_bw] < rf_ctl->rate_bmp_vht_by_bw[bw]) { + highest_rate_bw_bmp = ch_width_to_bw_cap(bw); + highest_rate_bw = bw; + } else if (rf_ctl->rate_bmp_vht_by_bw[highest_rate_bw] == rf_ctl->rate_bmp_vht_by_bw[bw]) + highest_rate_bw_bmp |= ch_width_to_bw_cap(bw); + } + rf_ctl->highest_vht_rate_bw_bmp = highest_rate_bw_bmp; + + if (ori_highest_vht_rate_bw_bmp != rf_ctl->highest_vht_rate_bw_bmp + || largest_bit(ori_bmp_vht[highest_rate_bw]) != largest_bit(rf_ctl->rate_bmp_vht_by_bw[highest_rate_bw]) + ) { + if (DBG_HIGHEST_RATE_BMP_BW_CHANGE) { + RTW_INFO("highest_vht_rate_bw_bmp:0x%02x=>0x%02x\n", ori_highest_vht_rate_bw_bmp, rf_ctl->highest_vht_rate_bw_bmp); + RTW_INFO("rate_bmp_vht_by_bw[%u]:0x%08x=>0x%08x\n", highest_rate_bw, ori_bmp_vht[highest_rate_bw], rf_ctl->rate_bmp_vht_by_bw[highest_rate_bw]); + } + update_vht_rs = _TRUE; + } + + /* TODO: per rfpath and rate section handling? */ + if (update_ht_rs == _TRUE || update_vht_rs == _TRUE) + rtw_hal_set_tx_power_level(dvobj_get_primary_adapter(dvobj), hal_data->current_channel); + } +} + +inline u16 rtw_get_tx_rate_bmp_cck_ofdm(struct dvobj_priv *dvobj) +{ + struct rf_ctl_t *rf_ctl = dvobj_to_rfctl(dvobj); + + return rf_ctl->rate_bmp_cck_ofdm; +} + +inline u32 rtw_get_tx_rate_bmp_ht_by_bw(struct dvobj_priv *dvobj, u8 bw) +{ + struct rf_ctl_t *rf_ctl = dvobj_to_rfctl(dvobj); + + return rf_ctl->rate_bmp_ht_by_bw[bw]; +} + +inline u32 rtw_get_tx_rate_bmp_vht_by_bw(struct dvobj_priv *dvobj, u8 bw) +{ + struct rf_ctl_t *rf_ctl = dvobj_to_rfctl(dvobj); + + return rf_ctl->rate_bmp_vht_by_bw[bw]; +} + +u8 rtw_get_tx_bw_bmp_of_ht_rate(struct dvobj_priv *dvobj, u8 rate, u8 max_bw) +{ + struct rf_ctl_t *rf_ctl = dvobj_to_rfctl(dvobj); + u8 bw; + u8 bw_bmp = 0; + u32 rate_bmp; + + if (!IS_HT_RATE(rate)) { + rtw_warn_on(1); + goto exit; + } + + rate_bmp = 1 << (rate - MGN_MCS0); + + if (max_bw > CHANNEL_WIDTH_40) + max_bw = CHANNEL_WIDTH_40; + + for (bw = CHANNEL_WIDTH_20; bw <= max_bw; bw++) { + /* RA may use lower rate for retry */ + if (rf_ctl->rate_bmp_ht_by_bw[bw] >= rate_bmp) + bw_bmp |= ch_width_to_bw_cap(bw); + } + +exit: + return bw_bmp; +} + +u8 rtw_get_tx_bw_bmp_of_vht_rate(struct dvobj_priv *dvobj, u8 rate, u8 max_bw) +{ + struct rf_ctl_t *rf_ctl = dvobj_to_rfctl(dvobj); + u8 bw; + u8 bw_bmp = 0; + u32 rate_bmp; + + if (!IS_VHT_RATE(rate)) { + rtw_warn_on(1); + goto exit; + } + + rate_bmp = 1 << (rate - MGN_VHT1SS_MCS0); + + if (max_bw > CHANNEL_WIDTH_160) + max_bw = CHANNEL_WIDTH_160; + + for (bw = CHANNEL_WIDTH_20; bw <= max_bw; bw++) { + /* RA may use lower rate for retry */ + if (rf_ctl->rate_bmp_vht_by_bw[bw] >= rate_bmp) + bw_bmp |= ch_width_to_bw_cap(bw); + } + +exit: + return bw_bmp; +} + +u8 query_ra_short_GI(struct sta_info *psta, u8 bw) +{ + u8 sgi = _FALSE, sgi_20m = _FALSE, sgi_40m = _FALSE, sgi_80m = _FALSE; + +#ifdef CONFIG_80211N_HT +#ifdef CONFIG_80211AC_VHT + if (psta->vhtpriv.vht_option) + sgi_80m = psta->vhtpriv.sgi_80m; +#endif + sgi_20m = psta->htpriv.sgi_20m; + sgi_40m = psta->htpriv.sgi_40m; +#endif + + switch (bw) { + case CHANNEL_WIDTH_80: + sgi = sgi_80m; + break; + case CHANNEL_WIDTH_40: + sgi = sgi_40m; + break; + case CHANNEL_WIDTH_20: + default: + sgi = sgi_20m; + break; + } + + return sgi; +} + +static void update_attrib_vcs_info(_adapter *padapter, struct xmit_frame *pxmitframe) +{ + u32 sz; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + /* struct sta_info *psta = pattrib->psta; */ + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + /* + if(pattrib->psta) + { + psta = pattrib->psta; + } + else + { + RTW_INFO("%s, call rtw_get_stainfo()\n", __func__); + psta=rtw_get_stainfo(&padapter->stapriv ,&pattrib->ra[0] ); + } + + if(psta==NULL) + { + RTW_INFO("%s, psta==NUL\n", __func__); + return; + } + + if(!(psta->state &_FW_LINKED)) + { + RTW_INFO("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + return; + } + */ + + if (pattrib->nr_frags != 1) + sz = padapter->xmitpriv.frag_len; + else /* no frag */ + sz = pattrib->last_txcmdsz; + + /* (1) RTS_Threshold is compared to the MPDU, not MSDU. */ + /* (2) If there are more than one frag in this MSDU, only the first frag uses protection frame. */ + /* Other fragments are protected by previous fragment. */ + /* So we only need to check the length of first fragment. */ + if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N || padapter->registrypriv.wifi_spec) { + if (sz > padapter->registrypriv.rts_thresh) + pattrib->vcs_mode = RTS_CTS; + else { + if (pattrib->rtsen) + pattrib->vcs_mode = RTS_CTS; + else if (pattrib->cts2self) + pattrib->vcs_mode = CTS_TO_SELF; + else + pattrib->vcs_mode = NONE_VCS; + } + } else { + while (_TRUE) { +#if 0 /* Todo */ + /* check IOT action */ + if (pHTInfo->IOTAction & HT_IOT_ACT_FORCED_CTS2SELF) { + pattrib->vcs_mode = CTS_TO_SELF; + pattrib->rts_rate = MGN_24M; + break; + } else if (pHTInfo->IOTAction & (HT_IOT_ACT_FORCED_RTS | HT_IOT_ACT_PURE_N_MODE)) { + pattrib->vcs_mode = RTS_CTS; + pattrib->rts_rate = MGN_24M; + break; + } +#endif + + /* IOT action */ + if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS) && (pattrib->ampdu_en == _TRUE) && + (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) { + pattrib->vcs_mode = CTS_TO_SELF; + break; + } + + + /* check ERP protection */ + if (pattrib->rtsen || pattrib->cts2self) { + if (pattrib->rtsen) + pattrib->vcs_mode = RTS_CTS; + else if (pattrib->cts2self) + pattrib->vcs_mode = CTS_TO_SELF; + + break; + } + + /* check HT op mode */ + if (pattrib->ht_en) { + u8 HTOpMode = pmlmeinfo->HT_protection; + if ((pmlmeext->cur_bwmode && (HTOpMode == 2 || HTOpMode == 3)) || + (!pmlmeext->cur_bwmode && HTOpMode == 3)) { + pattrib->vcs_mode = RTS_CTS; + break; + } + } + + /* check rts */ + if (sz > padapter->registrypriv.rts_thresh) { + pattrib->vcs_mode = RTS_CTS; + break; + } + + /* to do list: check MIMO power save condition. */ + + /* check AMPDU aggregation for TXOP */ + if ((pattrib->ampdu_en == _TRUE) && (!IS_HARDWARE_TYPE_8812(padapter))) { + pattrib->vcs_mode = RTS_CTS; + break; + } + + pattrib->vcs_mode = NONE_VCS; + break; + } + } + + /* for debug : force driver control vrtl_carrier_sense. */ + if (padapter->driver_vcs_en == 1) { + /* u8 driver_vcs_en; */ /* Enable=1, Disable=0 driver control vrtl_carrier_sense. */ + /* u8 driver_vcs_type; */ /* force 0:disable VCS, 1:RTS-CTS, 2:CTS-to-self when vcs_en=1. */ + pattrib->vcs_mode = padapter->driver_vcs_type; + } + +} + +static void update_attrib_phy_info(_adapter *padapter, struct pkt_attrib *pattrib, struct sta_info *psta) +{ + struct mlme_ext_priv *mlmeext = &padapter->mlmeextpriv; + u8 bw; + + pattrib->rtsen = psta->rtsen; + pattrib->cts2self = psta->cts2self; + + pattrib->mdata = 0; + pattrib->eosp = 0; + pattrib->triggered = 0; + pattrib->ampdu_spacing = 0; + + /* qos_en, ht_en, init rate, ,bw, ch_offset, sgi */ + pattrib->qos_en = psta->qos_option; + + pattrib->raid = psta->raid; + + bw = rtw_get_tx_bw_mode(padapter, psta); + pattrib->bwmode = rtw_min(bw, mlmeext->cur_bwmode); + pattrib->sgi = query_ra_short_GI(psta, pattrib->bwmode); + + pattrib->ldpc = psta->ldpc; + pattrib->stbc = psta->stbc; + +#ifdef CONFIG_80211N_HT + pattrib->ht_en = psta->htpriv.ht_option; + pattrib->ch_offset = psta->htpriv.ch_offset; + pattrib->ampdu_en = _FALSE; + + if (padapter->driver_ampdu_spacing != 0xFF) /* driver control AMPDU Density for peer sta's rx */ + pattrib->ampdu_spacing = padapter->driver_ampdu_spacing; + else + pattrib->ampdu_spacing = psta->htpriv.rx_ampdu_min_spacing; + + /* check if enable ampdu */ + if (pattrib->ht_en && psta->htpriv.ampdu_enable) { + if (psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority)) { + pattrib->ampdu_en = _TRUE; + if (psta->htpriv.tx_amsdu_enable == _TRUE) + pattrib->amsdu_ampdu_en = _TRUE; + else + pattrib->amsdu_ampdu_en = _FALSE; + } + } +#endif /* CONFIG_80211N_HT */ + /* if(pattrib->ht_en && psta->htpriv.ampdu_enable) */ + /* { */ + /* if(psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority)) */ + /* pattrib->ampdu_en = _TRUE; */ + /* } */ + +#ifdef CONFIG_TDLS + if (pattrib->direct_link == _TRUE) { + psta = pattrib->ptdls_sta; + + pattrib->raid = psta->raid; +#ifdef CONFIG_80211N_HT + pattrib->bwmode = rtw_get_tx_bw_mode(padapter, psta); + pattrib->ht_en = psta->htpriv.ht_option; + pattrib->ch_offset = psta->htpriv.ch_offset; + pattrib->sgi = query_ra_short_GI(psta, pattrib->bwmode); +#endif /* CONFIG_80211N_HT */ + } +#endif /* CONFIG_TDLS */ + + pattrib->retry_ctrl = _FALSE; + +#ifdef CONFIG_AUTO_AP_MODE + if (psta->isrc && psta->pid > 0) + pattrib->pctrl = _TRUE; +#endif + +} + +static s32 update_attrib_sec_info(_adapter *padapter, struct pkt_attrib *pattrib, struct sta_info *psta) +{ + sint res = _SUCCESS; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + sint bmcast = IS_MCAST(pattrib->ra); + + _rtw_memset(pattrib->dot118021x_UncstKey.skey, 0, 16); + _rtw_memset(pattrib->dot11tkiptxmickey.skey, 0, 16); + pattrib->mac_id = psta->mac_id; + + if (psta->ieee8021x_blocked == _TRUE) { + + pattrib->encrypt = 0; + + if ((pattrib->ether_type != 0x888e) && (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _FALSE)) { +#ifdef DBG_TX_DROP_FRAME + RTW_INFO("DBG_TX_DROP_FRAME %s psta->ieee8021x_blocked == _TRUE, pattrib->ether_type(%04x) != 0x888e\n", __FUNCTION__, pattrib->ether_type); +#endif + res = _FAIL; + goto exit; + } + } else { + GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast); + +#ifdef CONFIG_WAPI_SUPPORT + if (pattrib->ether_type == 0x88B4) + pattrib->encrypt = _NO_PRIVACY_; +#endif + + switch (psecuritypriv->dot11AuthAlgrthm) { + case dot11AuthAlgrthm_Open: + case dot11AuthAlgrthm_Shared: + case dot11AuthAlgrthm_Auto: + pattrib->key_idx = (u8)psecuritypriv->dot11PrivacyKeyIndex; + break; + case dot11AuthAlgrthm_8021X: + if (bmcast) + pattrib->key_idx = (u8)psecuritypriv->dot118021XGrpKeyid; + else + pattrib->key_idx = 0; + break; + default: + pattrib->key_idx = 0; + break; + } + + /* For WPS 1.0 WEP, driver should not encrypt EAPOL Packet for WPS handshake. */ + if (((pattrib->encrypt == _WEP40_) || (pattrib->encrypt == _WEP104_)) && (pattrib->ether_type == 0x888e)) + pattrib->encrypt = _NO_PRIVACY_; + + } + +#ifdef CONFIG_TDLS + if (pattrib->direct_link == _TRUE) { + if (pattrib->encrypt > 0) + pattrib->encrypt = _AES_; + } +#endif + + switch (pattrib->encrypt) { + case _WEP40_: + case _WEP104_: + pattrib->iv_len = 4; + pattrib->icv_len = 4; + WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + break; + + case _TKIP_: + pattrib->iv_len = 8; + pattrib->icv_len = 4; + + if (psecuritypriv->busetkipkey == _FAIL) { +#ifdef DBG_TX_DROP_FRAME + RTW_INFO("DBG_TX_DROP_FRAME %s psecuritypriv->busetkipkey(%d)==_FAIL drop packet\n", __FUNCTION__, psecuritypriv->busetkipkey); +#endif + res = _FAIL; + goto exit; + } + + if (bmcast) + TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + else + TKIP_IV(pattrib->iv, psta->dot11txpn, 0); + + + _rtw_memcpy(pattrib->dot11tkiptxmickey.skey, psta->dot11tkiptxmickey.skey, 16); + + break; + + case _AES_: + + pattrib->iv_len = 8; + pattrib->icv_len = 8; + + if (bmcast) + AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + else + AES_IV(pattrib->iv, psta->dot11txpn, 0); + + break; + +#ifdef CONFIG_WAPI_SUPPORT + case _SMS4_: + pattrib->iv_len = 18; + pattrib->icv_len = 16; + rtw_wapi_get_iv(padapter, pattrib->ra, pattrib->iv); + break; +#endif + default: + pattrib->iv_len = 0; + pattrib->icv_len = 0; + break; + } + + if (pattrib->encrypt > 0) + _rtw_memcpy(pattrib->dot118021x_UncstKey.skey, psta->dot118021x_UncstKey.skey, 16); + + + if (pattrib->encrypt && + ((padapter->securitypriv.sw_encrypt == _TRUE) || (psecuritypriv->hw_decrypted == _FALSE))) { + pattrib->bswenc = _TRUE; + } else { + pattrib->bswenc = _FALSE; + } + +#if defined(CONFIG_CONCURRENT_MODE) + pattrib->bmc_camid = padapter->securitypriv.dot118021x_bmc_cam_id; +#endif + + if (pattrib->encrypt && bmcast && _rtw_camctl_chk_flags(padapter, SEC_STATUS_STA_PK_GK_CONFLICT_DIS_BMC_SEARCH)) + pattrib->bswenc = _TRUE; + +#ifdef CONFIG_WAPI_SUPPORT + if (pattrib->encrypt == _SMS4_) + pattrib->bswenc = _FALSE; +#endif + +exit: + + return res; + +} + +u8 qos_acm(u8 acm_mask, u8 priority) +{ + u8 change_priority = priority; + + switch (priority) { + case 0: + case 3: + if (acm_mask & BIT(1)) + change_priority = 1; + break; + case 1: + case 2: + break; + case 4: + case 5: + if (acm_mask & BIT(2)) + change_priority = 0; + break; + case 6: + case 7: + if (acm_mask & BIT(3)) + change_priority = 5; + break; + default: + RTW_INFO("qos_acm(): invalid pattrib->priority: %d!!!\n", priority); + break; + } + + return change_priority; +} + +static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) +{ + struct ethhdr etherhdr; + struct iphdr ip_hdr; + s32 UserPriority = 0; + + + _rtw_open_pktfile(ppktfile->pkt, ppktfile); + _rtw_pktfile_read(ppktfile, (unsigned char *)ðerhdr, ETH_HLEN); + + /* get UserPriority from IP hdr */ + if (pattrib->ether_type == 0x0800) { + _rtw_pktfile_read(ppktfile, (u8 *)&ip_hdr, sizeof(ip_hdr)); + /* UserPriority = (ntohs(ip_hdr.tos) >> 5) & 0x3; */ + UserPriority = ip_hdr.tos >> 5; + } + /* + else if (pattrib->ether_type == 0x888e) { + + + UserPriority = 7; + } + */ + pattrib->priority = UserPriority; + pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; + pattrib->subtype = WIFI_QOS_DATA_TYPE; +} + +#ifdef CONFIG_TDLS +u8 rtw_check_tdls_established(_adapter *padapter, struct pkt_attrib *pattrib) +{ + pattrib->ptdls_sta = NULL; + + pattrib->direct_link = _FALSE; + if (padapter->tdlsinfo.link_established == _TRUE) { + pattrib->ptdls_sta = rtw_get_stainfo(&padapter->stapriv, pattrib->dst); +#if 1 + if ((pattrib->ptdls_sta != NULL) && + (pattrib->ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE) && + (pattrib->ether_type != 0x0806)) { + pattrib->direct_link = _TRUE; + /* RTW_INFO("send ptk to "MAC_FMT" using direct link\n", MAC_ARG(pattrib->dst)); */ + } +#else + if (pattrib->ptdls_sta != NULL && + pattrib->ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE) { + pattrib->direct_link = _TRUE; +#if 0 + RTW_INFO("send ptk to "MAC_FMT" using direct link\n", MAC_ARG(pattrib->dst)); +#endif + } + + /* ARP frame may be helped by AP*/ + if (pattrib->ether_type != 0x0806) + pattrib->direct_link = _FALSE; +#endif + } + + return pattrib->direct_link; +} + +s32 update_tdls_attrib(_adapter *padapter, struct pkt_attrib *pattrib) +{ + + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + + s32 res = _SUCCESS; + + psta = rtw_get_stainfo(pstapriv, pattrib->ra); + if (psta == NULL) { + res = _FAIL; + goto exit; + } + + pattrib->mac_id = psta->mac_id; + pattrib->psta = psta; + pattrib->ack_policy = 0; + /* get ether_hdr_len */ + pattrib->pkt_hdrlen = ETH_HLEN; + + /* [TDLS] TODO: setup req/rsp should be AC_BK */ + if (pqospriv->qos_option && psta->qos_option) { + pattrib->priority = 4; /* tdls management frame should be AC_VI */ + pattrib->hdrlen = WLAN_HDR_A3_QOS_LEN; + pattrib->subtype = WIFI_QOS_DATA_TYPE; + } else { + pattrib->priority = 0; + pattrib->hdrlen = WLAN_HDR_A3_LEN; + pattrib->subtype = WIFI_DATA_TYPE; + } + + /* TODO:_lock */ + if (update_attrib_sec_info(padapter, pattrib, psta) == _FAIL) { + res = _FAIL; + goto exit; + } + + update_attrib_phy_info(padapter, pattrib, psta); + + +exit: + + return res; +} + +#endif /* CONFIG_TDLS */ + +/*get non-qos hw_ssn control register,mapping to REG_HW_SEQ0,1,2,3*/ +inline u8 rtw_get_hwseq_no(_adapter *padapter) +{ + u8 hwseq_num = 0; +#ifdef CONFIG_CONCURRENT_MODE + if (padapter->adapter_type != PRIMARY_ADAPTER) + hwseq_num = 1; + /* else */ + /* hwseq_num = 2; */ +#endif /* CONFIG_CONCURRENT_MODE */ + return hwseq_num; +} +static s32 update_attrib(_adapter *padapter, _pkt *pkt, struct pkt_attrib *pattrib) +{ + uint i; + struct pkt_file pktfile; + struct sta_info *psta = NULL; + struct ethhdr etherhdr; + + sint bmcast; + struct sta_priv *pstapriv = &padapter->stapriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + sint res = _SUCCESS; + + + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib); + + _rtw_open_pktfile(pkt, &pktfile); + i = _rtw_pktfile_read(&pktfile, (u8 *)ðerhdr, ETH_HLEN); + + pattrib->ether_type = ntohs(etherhdr.h_proto); + + + _rtw_memcpy(pattrib->dst, ðerhdr.h_dest, ETH_ALEN); + _rtw_memcpy(pattrib->src, ðerhdr.h_source, ETH_ALEN); + + + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) { + _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + _rtw_memcpy(pattrib->ta, adapter_mac_addr(padapter), ETH_ALEN); + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_adhoc); + } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { +#ifdef CONFIG_TDLS + if (rtw_check_tdls_established(padapter, pattrib) == _TRUE) + _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); /* For TDLS direct link Tx, set ra to be same to dst */ + else +#endif + _rtw_memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN); + _rtw_memcpy(pattrib->ta, adapter_mac_addr(padapter), ETH_ALEN); + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_sta); + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + _rtw_memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); + _rtw_memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_ap); + } else + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_unknown); + + bmcast = IS_MCAST(pattrib->ra); + if (bmcast) { + psta = rtw_get_bcmc_stainfo(padapter); + if (psta == NULL) { /* if we cannot get psta => drop the pkt */ + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_sta); +#ifdef DBG_TX_DROP_FRAME + RTW_INFO("DBG_TX_DROP_FRAME %s get sta_info fail, ra:" MAC_FMT"\n", __func__, MAC_ARG(pattrib->ra)); +#endif + res = _FAIL; + goto exit; + } + } else { + psta = rtw_get_stainfo(pstapriv, pattrib->ra); + if (psta == NULL) { /* if we cannot get psta => drop the pkt */ + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_ucast_sta); +#ifdef DBG_TX_DROP_FRAME + RTW_INFO("DBG_TX_DROP_FRAME %s get sta_info fail, ra:" MAC_FMT"\n", __func__, MAC_ARG(pattrib->ra)); +#endif + res = _FAIL; + goto exit; + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE && !(psta->state & _FW_LINKED)) { + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_ucast_ap_link); + res = _FAIL; + goto exit; + } + } + + if (!(psta->state & _FW_LINKED)) { + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_link); + RTW_INFO("%s-"ADPT_FMT" psta("MAC_FMT")->state(0x%x) != _FW_LINKED\n", __func__, ADPT_ARG(padapter), MAC_ARG(psta->hwaddr), psta->state); + res = _FAIL; + goto exit; + } + + pattrib->pktlen = pktfile.pkt_len; + + /* TODO: 802.1Q VLAN header */ + /* TODO: IPV6 */ + + if (ETH_P_IP == pattrib->ether_type) { + u8 ip[20]; + + _rtw_pktfile_read(&pktfile, ip, 20); + + if (GET_IPV4_IHL(ip) * 4 > 20) + _rtw_pktfile_read(&pktfile, NULL, GET_IPV4_IHL(ip) - 20); + + pattrib->icmp_pkt = 0; + pattrib->dhcp_pkt = 0; + + if (GET_IPV4_PROTOCOL(ip) == 0x01) { /* ICMP */ + pattrib->icmp_pkt = 1; + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_icmp); + + } else if (GET_IPV4_PROTOCOL(ip) == 0x11) { /* UDP */ + u8 udp[8]; + + _rtw_pktfile_read(&pktfile, udp, 8); + + if ((GET_UDP_SRC(udp) == 68 && GET_UDP_DST(udp) == 67) + || (GET_UDP_SRC(udp) == 67 && GET_UDP_DST(udp) == 68) + ) { + /* 67 : UDP BOOTP server, 68 : UDP BOOTP client */ + if (pattrib->pktlen > 282) { /* MINIMUM_DHCP_PACKET_SIZE */ + pattrib->dhcp_pkt = 1; + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_dhcp); + if (0) + RTW_INFO("send DHCP packet\n"); + } + } + + } else if (GET_IPV4_PROTOCOL(ip) == 0x06 /* TCP */ + && rtw_st_ctl_chk_reg_s_proto(&psta->st_ctl, 0x06) == _TRUE + ) { + u8 tcp[20]; + + _rtw_pktfile_read(&pktfile, tcp, 20); + + if (rtw_st_ctl_chk_reg_rule(&psta->st_ctl, padapter, IPV4_SRC(ip), TCP_SRC(tcp), IPV4_DST(ip), TCP_DST(tcp)) == _TRUE) { + if (GET_TCP_SYN(tcp) && GET_TCP_ACK(tcp)) { + session_tracker_add_cmd(padapter, psta + , IPV4_SRC(ip), TCP_SRC(tcp) + , IPV4_SRC(ip), TCP_DST(tcp)); + if (DBG_SESSION_TRACKER) + RTW_INFO(FUNC_ADPT_FMT" local:"IP_FMT":"PORT_FMT", remote:"IP_FMT":"PORT_FMT" SYN-ACK\n" + , FUNC_ADPT_ARG(padapter) + , IP_ARG(IPV4_SRC(ip)), PORT_ARG(TCP_SRC(tcp)) + , IP_ARG(IPV4_DST(ip)), PORT_ARG(TCP_DST(tcp))); + } + if (GET_TCP_FIN(tcp)) { + session_tracker_del_cmd(padapter, psta + , IPV4_SRC(ip), TCP_SRC(tcp) + , IPV4_SRC(ip), TCP_DST(tcp)); + if (DBG_SESSION_TRACKER) + RTW_INFO(FUNC_ADPT_FMT" local:"IP_FMT":"PORT_FMT", remote:"IP_FMT":"PORT_FMT" FIN\n" + , FUNC_ADPT_ARG(padapter) + , IP_ARG(IPV4_SRC(ip)), PORT_ARG(TCP_SRC(tcp)) + , IP_ARG(IPV4_DST(ip)), PORT_ARG(TCP_DST(tcp))); + } + } + } + + } else if (0x888e == pattrib->ether_type) + RTW_PRINT("send eapol packet\n"); + + if ((pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) + rtw_mi_set_scan_deny(padapter, 3000); + +#ifdef CONFIG_LPS + /* If EAPOL , ARP , OR DHCP packet, driver must be in active mode. */ +#ifdef CONFIG_WAPI_SUPPORT + if ((pattrib->ether_type == 0x88B4) || (pattrib->ether_type == 0x0806) || (pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) +#else /* !CONFIG_WAPI_SUPPORT */ +#if 0 + if ((pattrib->ether_type == 0x0806) || (pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) +#else /* only ICMP/DHCP packets is as SPECIAL_PACKET, and leave LPS when tx IMCP/DHCP packets. */ + /* if ((pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1) ) */ + if (pattrib->icmp_pkt == 1) + rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_LEAVE, 1); + else if (pattrib->dhcp_pkt == 1) +#endif +#endif + { + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_active); + rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SPECIAL_PACKET, 1); + } +#endif /* CONFIG_LPS */ + +#ifdef CONFIG_BEAMFORMING + update_attrib_txbf_info(padapter, pattrib, psta); +#endif + + /* TODO:_lock */ + if (update_attrib_sec_info(padapter, pattrib, psta) == _FAIL) { + DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_sec); + res = _FAIL; + goto exit; + } + + update_attrib_phy_info(padapter, pattrib, psta); + + /* RTW_INFO("%s ==> mac_id(%d)\n",__FUNCTION__,pattrib->mac_id ); */ + + pattrib->psta = psta; + /* TODO:_unlock */ + + pattrib->pctrl = 0; + + pattrib->ack_policy = 0; + /* get ether_hdr_len */ + pattrib->pkt_hdrlen = ETH_HLEN;/* (pattrib->ether_type == 0x8100) ? (14 + 4 ): 14; */ /* vlan tag */ + + pattrib->hdrlen = WLAN_HDR_A3_LEN; + pattrib->subtype = WIFI_DATA_TYPE; + pattrib->priority = 0; + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE | WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) { + if (pattrib->qos_en) + set_qos(&pktfile, pattrib); + } else { +#ifdef CONFIG_TDLS + if (pattrib->direct_link == _TRUE) { + if (pattrib->qos_en) + set_qos(&pktfile, pattrib); + } else +#endif + { + if (pqospriv->qos_option) { + set_qos(&pktfile, pattrib); + + if (pmlmepriv->acm_mask != 0) + pattrib->priority = qos_acm(pmlmepriv->acm_mask, pattrib->priority); + } + } + } + + /* pattrib->priority = 5; */ /* force to used VI queue, for testing */ + pattrib->hw_ssn_sel = pxmitpriv->hw_ssn_seq_no; + rtw_set_tx_chksum_offload(pkt, pattrib); + +exit: + + + return res; +} + +static s32 xmitframe_addmic(_adapter *padapter, struct xmit_frame *pxmitframe) +{ + sint curfragnum, length; + u8 *pframe, *payload, mic[8]; + struct mic_data micdata; + /* struct sta_info *stainfo; */ + struct qos_priv *pqospriv = &(padapter->mlmepriv.qospriv); + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + u8 priority[4] = {0x0, 0x0, 0x0, 0x0}; + u8 hw_hdr_offset = 0; + sint bmcst = IS_MCAST(pattrib->ra); + + /* + if(pattrib->psta) + { + stainfo = pattrib->psta; + } + else + { + RTW_INFO("%s, call rtw_get_stainfo()\n", __func__); + stainfo=rtw_get_stainfo(&padapter->stapriv ,&pattrib->ra[0]); + } + + if(stainfo==NULL) + { + RTW_INFO("%s, psta==NUL\n", __func__); + return _FAIL; + } + + if(!(stainfo->state &_FW_LINKED)) + { + RTW_INFO("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, stainfo->state); + return _FAIL; + } + */ + + +#ifdef CONFIG_USB_TX_AGGREGATION + hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ);; +#else +#ifdef CONFIG_TX_EARLY_MODE + hw_hdr_offset = TXDESC_OFFSET + EARLY_MODE_INFO_SIZE; +#else + hw_hdr_offset = TXDESC_OFFSET; +#endif +#endif + + if (pattrib->encrypt == _TKIP_) { /* if(psecuritypriv->dot11PrivacyAlgrthm==_TKIP_PRIVACY_) */ + /* encode mic code */ + /* if(stainfo!= NULL) */ + { + u8 null_key[16] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + + pframe = pxmitframe->buf_addr + hw_hdr_offset; + + if (bmcst) { + if (_rtw_memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16) == _TRUE) { + /* DbgPrint("\nxmitframe_addmic:stainfo->dot11tkiptxmickey==0\n"); */ + /* rtw_msleep_os(10); */ + return _FAIL; + } + /* start to calculate the mic code */ + rtw_secmicsetkey(&micdata, psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey); + } else { + if (_rtw_memcmp(&pattrib->dot11tkiptxmickey.skey[0], null_key, 16) == _TRUE) { + /* DbgPrint("\nxmitframe_addmic:stainfo->dot11tkiptxmickey==0\n"); */ + /* rtw_msleep_os(10); */ + return _FAIL; + } + /* start to calculate the mic code */ + rtw_secmicsetkey(&micdata, &pattrib->dot11tkiptxmickey.skey[0]); + } + + if (pframe[1] & 1) { /* ToDS==1 */ + rtw_secmicappend(&micdata, &pframe[16], 6); /* DA */ + if (pframe[1] & 2) /* From Ds==1 */ + rtw_secmicappend(&micdata, &pframe[24], 6); + else + rtw_secmicappend(&micdata, &pframe[10], 6); + } else { /* ToDS==0 */ + rtw_secmicappend(&micdata, &pframe[4], 6); /* DA */ + if (pframe[1] & 2) /* From Ds==1 */ + rtw_secmicappend(&micdata, &pframe[16], 6); + else + rtw_secmicappend(&micdata, &pframe[10], 6); + + } + + /* if(pqospriv->qos_option==1) */ + if (pattrib->qos_en) + priority[0] = (u8)pxmitframe->attrib.priority; + + + rtw_secmicappend(&micdata, &priority[0], 4); + + payload = pframe; + + for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { + payload = (u8 *)RND4((SIZE_PTR)(payload)); + + payload = payload + pattrib->hdrlen + pattrib->iv_len; + if ((curfragnum + 1) == pattrib->nr_frags) { + length = pattrib->last_txcmdsz - pattrib->hdrlen - pattrib->iv_len - ((pattrib->bswenc) ? pattrib->icv_len : 0); + rtw_secmicappend(&micdata, payload, length); + payload = payload + length; + } else { + length = pxmitpriv->frag_len - pattrib->hdrlen - pattrib->iv_len - ((pattrib->bswenc) ? pattrib->icv_len : 0); + rtw_secmicappend(&micdata, payload, length); + payload = payload + length + pattrib->icv_len; + } + } + rtw_secgetmic(&micdata, &(mic[0])); + /* add mic code and add the mic code length in last_txcmdsz */ + + _rtw_memcpy(payload, &(mic[0]), 8); + pattrib->last_txcmdsz += 8; + + payload = payload - pattrib->last_txcmdsz + 8; + } + } + + + return _SUCCESS; +} + +/*#define DBG_TX_SW_ENCRYPTOR*/ + +static s32 xmitframe_swencrypt(_adapter *padapter, struct xmit_frame *pxmitframe) +{ + + struct pkt_attrib *pattrib = &pxmitframe->attrib; + /* struct security_priv *psecuritypriv=&padapter->securitypriv; */ + + + /* if((psecuritypriv->sw_encrypt)||(pattrib->bswenc)) */ + if (pattrib->bswenc) { +#ifdef DBG_TX_SW_ENCRYPTOR + RTW_INFO(ADPT_FMT" - sec_type:%s DO SW encryption\n", + ADPT_ARG(padapter), security_type_str(pattrib->encrypt)); +#endif + + switch (pattrib->encrypt) { + case _WEP40_: + case _WEP104_: + rtw_wep_encrypt(padapter, (u8 *)pxmitframe); + break; + case _TKIP_: + rtw_tkip_encrypt(padapter, (u8 *)pxmitframe); + break; + case _AES_: + rtw_aes_encrypt(padapter, (u8 *)pxmitframe); + break; +#ifdef CONFIG_WAPI_SUPPORT + case _SMS4_: + rtw_sms4_encrypt(padapter, (u8 *)pxmitframe); +#endif + default: + break; + } + + } + + + return _SUCCESS; +} + +s32 rtw_make_wlanhdr(_adapter *padapter , u8 *hdr, struct pkt_attrib *pattrib) +{ + u16 *qc; + + struct rtw_ieee80211_hdr *pwlanhdr = (struct rtw_ieee80211_hdr *)hdr; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + u8 qos_option = _FALSE; + sint res = _SUCCESS; + u16 *fctrl = &pwlanhdr->frame_ctl; + + /* struct sta_info *psta; */ + + /* sint bmcst = IS_MCAST(pattrib->ra); */ + + + /* + psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); + if(pattrib->psta != psta) + { + RTW_INFO("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); + return; + } + + if(psta==NULL) + { + RTW_INFO("%s, psta==NUL\n", __func__); + return _FAIL; + } + + if(!(psta->state &_FW_LINKED)) + { + RTW_INFO("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + return _FAIL; + } + */ + + _rtw_memset(hdr, 0, WLANHDR_OFFSET); + + set_frame_sub_type(fctrl, pattrib->subtype); + + if (pattrib->subtype & WIFI_DATA_TYPE) { + if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)) { +#ifdef CONFIG_TDLS + if (pattrib->direct_link == _TRUE) { + /* TDLS data transfer, ToDS=0, FrDs=0 */ + _rtw_memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); + + if (pattrib->qos_en) + qos_option = _TRUE; + } else +#endif /* CONFIG_TDLS */ + { + /* to_ds = 1, fr_ds = 0; */ + /* 1.Data transfer to AP */ + /* 2.Arp pkt will relayed by AP */ + SetToDs(fctrl); + _rtw_memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, pattrib->ta, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); + + if (pqospriv->qos_option) + qos_option = _TRUE; + } + } else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE)) { + /* to_ds = 0, fr_ds = 1; */ + SetFrDs(fctrl); + _rtw_memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN); + + if (pattrib->qos_en) + qos_option = _TRUE; + } else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE)) { + _rtw_memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, pattrib->ta, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); + + if (pattrib->qos_en) + qos_option = _TRUE; + } else { + res = _FAIL; + goto exit; + } + + if (pattrib->mdata) + SetMData(fctrl); + + if (pattrib->encrypt) + SetPrivacy(fctrl); + + if (qos_option) { + qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); + + if (pattrib->priority) + SetPriority(qc, pattrib->priority); + + SetEOSP(qc, pattrib->eosp); + + SetAckpolicy(qc, pattrib->ack_policy); + + if(pattrib->amsdu) + SetAMsdu(qc, pattrib->amsdu); + } + + /* TODO: fill HT Control Field */ + + /* Update Seq Num will be handled by f/w */ + { + struct sta_info *psta; + psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); + if (pattrib->psta != psta) { + RTW_INFO("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); + return _FAIL; + } + + if (psta == NULL) { + RTW_INFO("%s, psta==NUL\n", __func__); + return _FAIL; + } + + if (!(psta->state & _FW_LINKED)) { + RTW_INFO("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + return _FAIL; + } + + + if (psta) { + psta->sta_xmitpriv.txseq_tid[pattrib->priority]++; + psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; + pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority]; + + SetSeqNum(hdr, pattrib->seqnum); + +#ifdef CONFIG_80211N_HT +#if 0 /* move into update_attrib_phy_info(). */ + /* check if enable ampdu */ + if (pattrib->ht_en && psta->htpriv.ampdu_enable) { + if (psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority)) + pattrib->ampdu_en = _TRUE; + } +#endif + /* re-check if enable ampdu by BA_starting_seqctrl */ + if (pattrib->ampdu_en == _TRUE) { + u16 tx_seq; + + tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f]; + + /* check BA_starting_seqctrl */ + if (SN_LESS(pattrib->seqnum, tx_seq)) { + /* RTW_INFO("tx ampdu seqnum(%d) < tx_seq(%d)\n", pattrib->seqnum, tx_seq); */ + pattrib->ampdu_en = _FALSE;/* AGG BK */ + } else if (SN_EQUAL(pattrib->seqnum, tx_seq)) { + psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq + 1) & 0xfff; + + pattrib->ampdu_en = _TRUE;/* AGG EN */ + } else { + /* RTW_INFO("tx ampdu over run\n"); */ + psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum + 1) & 0xfff; + pattrib->ampdu_en = _TRUE;/* AGG EN */ + } + + } +#endif /* CONFIG_80211N_HT */ + } + } + + } else { + + } + +exit: + + + return res; +} + +s32 rtw_txframes_pending(_adapter *padapter) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + return ((_rtw_queue_empty(&pxmitpriv->be_pending) == _FALSE) || + (_rtw_queue_empty(&pxmitpriv->bk_pending) == _FALSE) || + (_rtw_queue_empty(&pxmitpriv->vi_pending) == _FALSE) || + (_rtw_queue_empty(&pxmitpriv->vo_pending) == _FALSE)); +} + +s32 rtw_txframes_sta_ac_pending(_adapter *padapter, struct pkt_attrib *pattrib) +{ + struct sta_info *psta; + struct tx_servq *ptxservq; + int priority = pattrib->priority; + /* + if(pattrib->psta) + { + psta = pattrib->psta; + } + else + { + RTW_INFO("%s, call rtw_get_stainfo()\n", __func__); + psta=rtw_get_stainfo(&padapter->stapriv ,&pattrib->ra[0]); + } + */ + psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); + if (pattrib->psta != psta) { + RTW_INFO("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); + return 0; + } + + if (psta == NULL) { + RTW_INFO("%s, psta==NUL\n", __func__); + return 0; + } + + if (!(psta->state & _FW_LINKED)) { + RTW_INFO("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + return 0; + } + + switch (priority) { + case 1: + case 2: + ptxservq = &(psta->sta_xmitpriv.bk_q); + break; + case 4: + case 5: + ptxservq = &(psta->sta_xmitpriv.vi_q); + break; + case 6: + case 7: + ptxservq = &(psta->sta_xmitpriv.vo_q); + break; + case 0: + case 3: + default: + ptxservq = &(psta->sta_xmitpriv.be_q); + break; + + } + + return ptxservq->qcnt; +} + +#ifdef CONFIG_TDLS + +int rtw_build_tdls_ies(_adapter *padapter, struct xmit_frame *pxmitframe, u8 *pframe, struct tdls_txmgmt *ptxmgmt) +{ + int res = _SUCCESS; + + switch (ptxmgmt->action_code) { + case TDLS_SETUP_REQUEST: + rtw_build_tdls_setup_req_ies(padapter, pxmitframe, pframe, ptxmgmt); + break; + case TDLS_SETUP_RESPONSE: + rtw_build_tdls_setup_rsp_ies(padapter, pxmitframe, pframe, ptxmgmt); + break; + case TDLS_SETUP_CONFIRM: + rtw_build_tdls_setup_cfm_ies(padapter, pxmitframe, pframe, ptxmgmt); + break; + case TDLS_TEARDOWN: + rtw_build_tdls_teardown_ies(padapter, pxmitframe, pframe, ptxmgmt); + break; + case TDLS_DISCOVERY_REQUEST: + rtw_build_tdls_dis_req_ies(padapter, pxmitframe, pframe, ptxmgmt); + break; + case TDLS_PEER_TRAFFIC_INDICATION: + rtw_build_tdls_peer_traffic_indication_ies(padapter, pxmitframe, pframe, ptxmgmt); + break; +#ifdef CONFIG_TDLS_CH_SW + case TDLS_CHANNEL_SWITCH_REQUEST: + rtw_build_tdls_ch_switch_req_ies(padapter, pxmitframe, pframe, ptxmgmt); + break; + case TDLS_CHANNEL_SWITCH_RESPONSE: + rtw_build_tdls_ch_switch_rsp_ies(padapter, pxmitframe, pframe, ptxmgmt); + break; +#endif + case TDLS_PEER_TRAFFIC_RESPONSE: + rtw_build_tdls_peer_traffic_rsp_ies(padapter, pxmitframe, pframe, ptxmgmt); + break; +#ifdef CONFIG_WFD + case TUNNELED_PROBE_REQ: + rtw_build_tunneled_probe_req_ies(padapter, pxmitframe, pframe); + break; + case TUNNELED_PROBE_RSP: + rtw_build_tunneled_probe_rsp_ies(padapter, pxmitframe, pframe); + break; +#endif /* CONFIG_WFD */ + default: + res = _FAIL; + break; + } + + return res; +} + +s32 rtw_make_tdls_wlanhdr(_adapter *padapter , u8 *hdr, struct pkt_attrib *pattrib, struct tdls_txmgmt *ptxmgmt) +{ + u16 *qc; + struct rtw_ieee80211_hdr *pwlanhdr = (struct rtw_ieee80211_hdr *)hdr; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta = NULL, *ptdls_sta = NULL; + u8 tdls_seq = 0, baddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + sint res = _SUCCESS; + u16 *fctrl = &pwlanhdr->frame_ctl; + + + _rtw_memset(hdr, 0, WLANHDR_OFFSET); + + set_frame_sub_type(fctrl, pattrib->subtype); + + switch (ptxmgmt->action_code) { + case TDLS_SETUP_REQUEST: + case TDLS_SETUP_RESPONSE: + case TDLS_SETUP_CONFIRM: + case TDLS_PEER_TRAFFIC_INDICATION: + case TDLS_PEER_PSM_REQUEST: + case TUNNELED_PROBE_REQ: + case TUNNELED_PROBE_RSP: + case TDLS_DISCOVERY_REQUEST: + SetToDs(fctrl); + _rtw_memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); + break; + case TDLS_CHANNEL_SWITCH_REQUEST: + case TDLS_CHANNEL_SWITCH_RESPONSE: + case TDLS_PEER_PSM_RESPONSE: + case TDLS_PEER_TRAFFIC_RESPONSE: + _rtw_memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); + tdls_seq = 1; + break; + case TDLS_TEARDOWN: + if (ptxmgmt->status_code == _RSON_TDLS_TEAR_UN_RSN_) { + _rtw_memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); + tdls_seq = 1; + } else { + SetToDs(fctrl); + _rtw_memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN); + } + break; + } + + if (pattrib->encrypt) + SetPrivacy(fctrl); + + if (ptxmgmt->action_code == TDLS_PEER_TRAFFIC_RESPONSE) + SetPwrMgt(fctrl); + + if (pqospriv->qos_option) { + qc = (unsigned short *)(hdr + pattrib->hdrlen - 2); + if (pattrib->priority) + SetPriority(qc, pattrib->priority); + SetAckpolicy(qc, pattrib->ack_policy); + } + + psta = pattrib->psta; + + /* 1. update seq_num per link by sta_info */ + /* 2. rewrite encrypt to _AES_, also rewrite iv_len, icv_len */ + if (tdls_seq == 1) { + ptdls_sta = rtw_get_stainfo(pstapriv, pattrib->dst); + if (ptdls_sta) { + ptdls_sta->sta_xmitpriv.txseq_tid[pattrib->priority]++; + ptdls_sta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; + pattrib->seqnum = ptdls_sta->sta_xmitpriv.txseq_tid[pattrib->priority]; + SetSeqNum(hdr, pattrib->seqnum); + + if (pattrib->encrypt) { + pattrib->encrypt = _AES_; + pattrib->iv_len = 8; + pattrib->icv_len = 8; + pattrib->bswenc = _FALSE; + } + pattrib->mac_id = ptdls_sta->mac_id; + } else { + res = _FAIL; + goto exit; + } + } else if (psta) { + psta->sta_xmitpriv.txseq_tid[pattrib->priority]++; + psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF; + pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority]; + SetSeqNum(hdr, pattrib->seqnum); + } + + +exit: + + + return res; +} + +s32 rtw_xmit_tdls_coalesce(_adapter *padapter, struct xmit_frame *pxmitframe, struct tdls_txmgmt *ptxmgmt) +{ + s32 llc_sz; + + u8 *pframe, *mem_start; + + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + u8 *pbuf_start; + s32 bmcst = IS_MCAST(pattrib->ra); + s32 res = _SUCCESS; + + + if (pattrib->psta) + psta = pattrib->psta; + else { + if (bmcst) + psta = rtw_get_bcmc_stainfo(padapter); + else + psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); + } + + if (psta == NULL) { + res = _FAIL; + goto exit; + } + + if (pxmitframe->buf_addr == NULL) { + res = _FAIL; + goto exit; + } + + pbuf_start = pxmitframe->buf_addr; + mem_start = pbuf_start + TXDESC_OFFSET; + + if (rtw_make_tdls_wlanhdr(padapter, mem_start, pattrib, ptxmgmt) == _FAIL) { + res = _FAIL; + goto exit; + } + + pframe = mem_start; + pframe += pattrib->hdrlen; + + /* adding icv, if necessary... */ + if (pattrib->iv_len) { + if (psta != NULL) { + switch (pattrib->encrypt) { + case _WEP40_: + case _WEP104_: + WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + break; + case _TKIP_: + if (bmcst) + TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + else + TKIP_IV(pattrib->iv, psta->dot11txpn, 0); + break; + case _AES_: + if (bmcst) + AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + else + AES_IV(pattrib->iv, psta->dot11txpn, 0); + break; + } + } + + _rtw_memcpy(pframe, pattrib->iv, pattrib->iv_len); + pframe += pattrib->iv_len; + + } + + llc_sz = rtw_put_snap(pframe, pattrib->ether_type); + pframe += llc_sz; + + /* pattrib->pktlen will be counted in rtw_build_tdls_ies */ + pattrib->pktlen = 0; + + rtw_build_tdls_ies(padapter, pxmitframe, pframe, ptxmgmt); + + if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { + pframe += pattrib->pktlen; + _rtw_memcpy(pframe, pattrib->icv, pattrib->icv_len); + pframe += pattrib->icv_len; + } + + pattrib->nr_frags = 1; + pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + llc_sz + + ((pattrib->bswenc) ? pattrib->icv_len : 0) + pattrib->pktlen; + + if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) { + res = _FAIL; + goto exit; + } + + xmitframe_swencrypt(padapter, pxmitframe); + + update_attrib_vcs_info(padapter, pxmitframe); + +exit: + + + return res; +} +#endif /* CONFIG_TDLS */ + +/* + * Calculate wlan 802.11 packet MAX size from pkt_attrib + * This function doesn't consider fragment case + */ +u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib) +{ + u32 len = 0; + + len = pattrib->hdrlen + pattrib->iv_len; /* WLAN Header and IV */ + len += SNAP_SIZE + sizeof(u16); /* LLC */ + len += pattrib->pktlen; + if (pattrib->encrypt == _TKIP_) + len += 8; /* MIC */ + len += ((pattrib->bswenc) ? pattrib->icv_len : 0); /* ICV */ + + return len; +} + +#ifdef CONFIG_TX_AMSDU +s32 check_amsdu(struct xmit_frame *pxmitframe) +{ + struct pkt_attrib *pattrib; + s32 ret = _TRUE; + + if (!pxmitframe) + ret = _FALSE; + + pattrib = &pxmitframe->attrib; + + if (IS_MCAST(pattrib->ra)) + ret = _FALSE; + + if ((pattrib->ether_type == 0x888e) || + (pattrib->ether_type == 0x0806) || + (pattrib->ether_type == 0x88b4) || + (pattrib->dhcp_pkt == 1)) + ret = _FALSE; + + if ((pattrib->encrypt == _WEP40_) || + (pattrib->encrypt == _WEP104_) || + (pattrib->encrypt == _TKIP_)) + ret = _FALSE; + + if (!pattrib->qos_en) + ret = _FALSE; + + return ret; +} + +s32 check_amsdu_tx_support(_adapter *padapter) +{ + struct dvobj_priv *pdvobjpriv; + int tx_amsdu; + int tx_amsdu_rate; + int current_tx_rate; + s32 ret = _FALSE; + + pdvobjpriv = adapter_to_dvobj(padapter); + tx_amsdu = padapter->tx_amsdu; + tx_amsdu_rate = padapter->tx_amsdu_rate; + current_tx_rate = pdvobjpriv->traffic_stat.cur_tx_tp; + + if (tx_amsdu == 1) + ret = _TRUE; + else if (tx_amsdu == 2 && (tx_amsdu_rate == 0 || current_tx_rate > tx_amsdu_rate)) + ret = _TRUE; + else + ret = _FALSE; + + return ret; +} + +s32 rtw_xmitframe_coalesce_amsdu(_adapter *padapter, struct xmit_frame *pxmitframe, struct xmit_frame *pxmitframe_queue) +{ + + struct pkt_file pktfile; + struct pkt_attrib *pattrib; + _pkt *pkt; + + struct pkt_file pktfile_queue; + struct pkt_attrib *pattrib_queue; + _pkt *pkt_queue; + + s32 llc_sz, mem_sz; + + s32 padding = 0; + + u8 *pframe, *mem_start; + u8 hw_hdr_offset; + + u16* len; + u8 *pbuf_start; + s32 res = _SUCCESS; + + if (pxmitframe->buf_addr == NULL) { + RTW_INFO("==> %s buf_addr==NULL\n", __FUNCTION__); + return _FAIL; + } + + + pbuf_start = pxmitframe->buf_addr; + +#ifdef CONFIG_USB_TX_AGGREGATION + hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ); +#else +#ifdef CONFIG_TX_EARLY_MODE /* for SDIO && Tx Agg */ + hw_hdr_offset = TXDESC_OFFSET + EARLY_MODE_INFO_SIZE; +#else + hw_hdr_offset = TXDESC_OFFSET; +#endif +#endif + + mem_start = pbuf_start + hw_hdr_offset; //for DMA + + pattrib = &pxmitframe->attrib; + + pattrib->amsdu = 1; + + if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n")); + RTW_INFO("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n"); + res = _FAIL; + goto exit; + } + + llc_sz = 0; + + pframe = mem_start; + + //SetMFrag(mem_start); + ClearMFrag(mem_start); + + pframe += pattrib->hdrlen; + + /* adding icv, if necessary... */ + if (pattrib->iv_len) { + _rtw_memcpy(pframe, pattrib->iv, pattrib->iv_len); // queue or new? + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, + ("rtw_xmitframe_coalesce: keyid=%d pattrib->iv[3]=%.2x pframe=%.2x %.2x %.2x %.2x\n", + padapter->securitypriv.dot11PrivacyKeyIndex, pattrib->iv[3], *pframe, *(pframe + 1), *(pframe + 2), *(pframe + 3))); + + pframe += pattrib->iv_len; + } + + pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len; + + if(pxmitframe_queue) + { + pattrib_queue = &pxmitframe_queue->attrib; + pkt_queue = pxmitframe_queue->pkt; + + _rtw_open_pktfile(pkt_queue, &pktfile_queue); + _rtw_pktfile_read(&pktfile_queue, NULL, pattrib_queue->pkt_hdrlen); + + /* 802.3 MAC Header DA(6) SA(6) Len(2)*/ + + _rtw_memcpy(pframe, pattrib_queue->dst, ETH_ALEN); + pframe += ETH_ALEN; + + _rtw_memcpy(pframe, pattrib_queue->src, ETH_ALEN); + pframe += ETH_ALEN; + + len = (u16*) pframe; + pframe += 2; + + llc_sz = rtw_put_snap(pframe, pattrib_queue->ether_type); + pframe += llc_sz; + + mem_sz = _rtw_pktfile_read(&pktfile_queue, pframe, pattrib_queue->pktlen); + pframe += mem_sz; + + *len = htons(llc_sz + mem_sz); + + //calc padding + padding = 4 - ((ETH_HLEN + llc_sz + mem_sz) & (4-1)); + if(padding == 4) + padding = 0; + + //_rtw_memset(pframe,0xaa, padding); + pframe += padding; + + pattrib->last_txcmdsz += ETH_HLEN + llc_sz + mem_sz + padding ; + } + + //2nd mpdu + + pkt = pxmitframe->pkt; + _rtw_open_pktfile(pkt, &pktfile); + _rtw_pktfile_read(&pktfile, NULL, pattrib->pkt_hdrlen); + + /* 802.3 MAC Header DA(6) SA(6) Len(2) */ + + _rtw_memcpy(pframe, pattrib->dst, ETH_ALEN); + pframe += ETH_ALEN; + + _rtw_memcpy(pframe, pattrib->src, ETH_ALEN); + pframe += ETH_ALEN; + + len = (u16*) pframe; + pframe += 2; + + llc_sz = rtw_put_snap(pframe, pattrib->ether_type); + pframe += llc_sz; + + mem_sz = _rtw_pktfile_read(&pktfile, pframe, pattrib->pktlen); + + pframe += mem_sz; + + *len = htons(llc_sz + mem_sz); + + //the last ampdu has no padding + padding = 0; + + pattrib->nr_frags = 1; + + pattrib->last_txcmdsz += ETH_HLEN + llc_sz + mem_sz + padding + + ((pattrib->bswenc) ? pattrib->icv_len : 0) ; + + if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { + _rtw_memcpy(pframe, pattrib->icv, pattrib->icv_len); + pframe += pattrib->icv_len; + } + + if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic(padapter, pxmitframe)==_FAIL\n")); + RTW_INFO("xmitframe_addmic(padapter, pxmitframe)==_FAIL\n"); + res = _FAIL; + goto exit; + } + + xmitframe_swencrypt(padapter, pxmitframe); + + pattrib->vcs_mode = NONE_VCS; + +exit: + return res; +} +#endif /* CONFIG_TX_AMSDU */ + +/* + +This sub-routine will perform all the following: + +1. remove 802.3 header. +2. create wlan_header, based on the info in pxmitframe +3. append sta's iv/ext-iv +4. append LLC +5. move frag chunk from pframe to pxmitframe->mem +6. apply sw-encrypt, if necessary. + +*/ +s32 rtw_xmitframe_coalesce(_adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe) +{ + struct pkt_file pktfile; + + s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz; + + SIZE_PTR addr; + + u8 *pframe, *mem_start; + u8 hw_hdr_offset; + + /* struct sta_info *psta; */ + /* struct sta_priv *pstapriv = &padapter->stapriv; */ + /* struct mlme_priv *pmlmepriv = &padapter->mlmepriv; */ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + struct pkt_attrib *pattrib = &pxmitframe->attrib; + + u8 *pbuf_start; + + s32 bmcst = IS_MCAST(pattrib->ra); + s32 res = _SUCCESS; + + + /* + if (pattrib->psta) + { + psta = pattrib->psta; + } else + { + RTW_INFO("%s, call rtw_get_stainfo()\n", __func__); + psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); + } + + if(psta==NULL) + { + + RTW_INFO("%s, psta==NUL\n", __func__); + return _FAIL; + } + + + if(!(psta->state &_FW_LINKED)) + { + RTW_INFO("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + return _FAIL; + } + */ + if (pxmitframe->buf_addr == NULL) { + RTW_INFO("==> %s buf_addr==NULL\n", __FUNCTION__); + return _FAIL; + } + + pbuf_start = pxmitframe->buf_addr; + +#ifdef CONFIG_USB_TX_AGGREGATION + hw_hdr_offset = TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ); +#else +#ifdef CONFIG_TX_EARLY_MODE /* for SDIO && Tx Agg */ + hw_hdr_offset = TXDESC_OFFSET + EARLY_MODE_INFO_SIZE; +#else + hw_hdr_offset = TXDESC_OFFSET; +#endif +#endif + + mem_start = pbuf_start + hw_hdr_offset; + + if (rtw_make_wlanhdr(padapter, mem_start, pattrib) == _FAIL) { + RTW_INFO("rtw_xmitframe_coalesce: rtw_make_wlanhdr fail; drop pkt\n"); + res = _FAIL; + goto exit; + } + + _rtw_open_pktfile(pkt, &pktfile); + _rtw_pktfile_read(&pktfile, NULL, pattrib->pkt_hdrlen); + + frg_inx = 0; + frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */ + + while (1) { + llc_sz = 0; + + mpdu_len = frg_len; + + pframe = mem_start; + + SetMFrag(mem_start); + + pframe += pattrib->hdrlen; + mpdu_len -= pattrib->hdrlen; + + /* adding icv, if necessary... */ + if (pattrib->iv_len) { +#if 0 + /* if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) */ + /* psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); */ + /* else */ + /* psta = rtw_get_stainfo(pstapriv, pattrib->ra); */ + + if (psta != NULL) { + switch (pattrib->encrypt) { + case _WEP40_: + case _WEP104_: + WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + break; + case _TKIP_: + if (bmcst) + TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + else + TKIP_IV(pattrib->iv, psta->dot11txpn, 0); + break; + case _AES_: + if (bmcst) + AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + else + AES_IV(pattrib->iv, psta->dot11txpn, 0); + break; +#ifdef CONFIG_WAPI_SUPPORT + case _SMS4_: + rtw_wapi_get_iv(padapter, pattrib->ra, pattrib->iv); + break; +#endif + } + } +#endif + _rtw_memcpy(pframe, pattrib->iv, pattrib->iv_len); + + + pframe += pattrib->iv_len; + + mpdu_len -= pattrib->iv_len; + } + + if (frg_inx == 0) { + llc_sz = rtw_put_snap(pframe, pattrib->ether_type); + pframe += llc_sz; + mpdu_len -= llc_sz; + } + + if ((pattrib->icv_len > 0) && (pattrib->bswenc)) + mpdu_len -= pattrib->icv_len; + + + if (bmcst) { + /* don't do fragment to broadcat/multicast packets */ + mem_sz = _rtw_pktfile_read(&pktfile, pframe, pattrib->pktlen); + } else + mem_sz = _rtw_pktfile_read(&pktfile, pframe, mpdu_len); + + pframe += mem_sz; + + if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { + _rtw_memcpy(pframe, pattrib->icv, pattrib->icv_len); + pframe += pattrib->icv_len; + } + + frg_inx++; + + if (bmcst || (rtw_endofpktfile(&pktfile) == _TRUE)) { + pattrib->nr_frags = frg_inx; + + pattrib->last_txcmdsz = pattrib->hdrlen + pattrib->iv_len + ((pattrib->nr_frags == 1) ? llc_sz : 0) + + ((pattrib->bswenc) ? pattrib->icv_len : 0) + mem_sz; + + ClearMFrag(mem_start); + + break; + } + + addr = (SIZE_PTR)(pframe); + + mem_start = (unsigned char *)RND4(addr) + hw_hdr_offset; + _rtw_memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen); + + } + + if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) { + RTW_INFO("xmitframe_addmic(padapter, pxmitframe)==_FAIL\n"); + res = _FAIL; + goto exit; + } + + xmitframe_swencrypt(padapter, pxmitframe); + + if (bmcst == _FALSE) + update_attrib_vcs_info(padapter, pxmitframe); + else + pattrib->vcs_mode = NONE_VCS; + +exit: + + + return res; +} + +#ifdef CONFIG_IEEE80211W +/* broadcast or multicast management pkt use BIP, unicast management pkt use CCMP encryption */ +s32 rtw_mgmt_xmitframe_coalesce(_adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe) +{ + struct pkt_file pktfile; + s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz; + SIZE_PTR addr; + u8 *pframe, *mem_start = NULL, *tmp_buf = NULL; + u8 hw_hdr_offset, subtype ; + struct sta_info *psta = NULL; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + u8 *pbuf_start; + s32 bmcst = IS_MCAST(pattrib->ra); + s32 res = _FAIL; + u8 *BIP_AAD = NULL; + u8 *MGMT_body = NULL; + + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct rtw_ieee80211_hdr *pwlanhdr; + u8 MME[_MME_IE_LENGTH_]; + + _irqL irqL; + u32 ori_len; + mem_start = pframe = (u8 *)(pxmitframe->buf_addr) + TXDESC_OFFSET; + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + ori_len = BIP_AAD_SIZE + pattrib->pktlen; + tmp_buf = BIP_AAD = rtw_zmalloc(ori_len); + subtype = get_frame_sub_type(pframe); /* bit(7)~bit(2) */ + + if (BIP_AAD == NULL) + return _FAIL; + + _enter_critical_bh(&padapter->security_key_mutex, &irqL); + + + /* IGTK key is not install, it may not support 802.11w */ + if (padapter->securitypriv.binstallBIPkey != _TRUE) { + RTW_INFO("no instll BIP key\n"); + goto xmitframe_coalesce_success; + } + /* station mode doesn't need TX BIP, just ready the code */ + if (bmcst) { + int frame_body_len; + u8 mic[16]; + + _rtw_memset(MME, 0, _MME_IE_LENGTH_); + + /* other types doesn't need the BIP */ + if (get_frame_sub_type(pframe) != WIFI_DEAUTH && get_frame_sub_type(pframe) != WIFI_DISASSOC) + goto xmitframe_coalesce_fail; + + MGMT_body = pframe + sizeof(struct rtw_ieee80211_hdr_3addr); + pframe += pattrib->pktlen; + + /* octent 0 and 1 is key index ,BIP keyid is 4 or 5, LSB only need octent 0 */ + MME[0] = padapter->securitypriv.dot11wBIPKeyid; + /* copy packet number */ + _rtw_memcpy(&MME[2], &pmlmeext->mgnt_80211w_IPN, 6); + /* increase the packet number */ + pmlmeext->mgnt_80211w_IPN++; + + /* add MME IE with MIC all zero, MME string doesn't include element id and length */ + pframe = rtw_set_ie(pframe, _MME_IE_ , 16 , MME, &(pattrib->pktlen)); + pattrib->last_txcmdsz = pattrib->pktlen; + /* total frame length - header length */ + frame_body_len = pattrib->pktlen - sizeof(struct rtw_ieee80211_hdr_3addr); + + /* conscruct AAD, copy frame control field */ + _rtw_memcpy(BIP_AAD, &pwlanhdr->frame_ctl, 2); + ClearRetry(BIP_AAD); + ClearPwrMgt(BIP_AAD); + ClearMData(BIP_AAD); + /* conscruct AAD, copy address 1 to address 3 */ + _rtw_memcpy(BIP_AAD + 2, pwlanhdr->addr1, 18); + /* copy management fram body */ + _rtw_memcpy(BIP_AAD + BIP_AAD_SIZE, MGMT_body, frame_body_len); +#if 0 + /* dump total packet include MME with zero MIC */ + { + int i; + printk("Total packet: "); + for (i = 0; i < BIP_AAD_SIZE + frame_body_len; i++) + printk(" %02x ", BIP_AAD[i]); + printk("\n"); + } +#endif + /* calculate mic */ + if (omac1_aes_128(padapter->securitypriv.dot11wBIPKey[padapter->securitypriv.dot11wBIPKeyid].skey + , BIP_AAD, BIP_AAD_SIZE + frame_body_len, mic)) + goto xmitframe_coalesce_fail; + +#if 0 + /* dump calculated mic result */ + { + int i; + printk("Calculated mic result: "); + for (i = 0; i < 16; i++) + printk(" %02x ", mic[i]); + printk("\n"); + } +#endif + /* copy right BIP mic value, total is 128bits, we use the 0~63 bits */ + _rtw_memcpy(pframe - 8, mic, 8); + /*/dump all packet after mic ok + { + int pp; + printk("pattrib->pktlen = %d\n", pattrib->pktlen); + for(pp=0;pp< pattrib->pktlen; pp++) + printk(" %02x ", mem_start[pp]); + printk("\n"); + }*/ + } else { /* unicast mgmt frame TX */ + /* start to encrypt mgmt frame */ + if (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC || + subtype == WIFI_REASSOCREQ || subtype == WIFI_ACTION) { + if (pattrib->psta) + psta = pattrib->psta; + else + psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); + + if (psta == NULL) { + + RTW_INFO("%s, psta==NUL\n", __func__); + goto xmitframe_coalesce_fail; + } + + if (pxmitframe->buf_addr == NULL) { + RTW_INFO("%s, pxmitframe->buf_addr\n", __func__); + goto xmitframe_coalesce_fail; + } + + /* RTW_INFO("%s, action frame category=%d\n", __func__, pframe[WLAN_HDR_A3_LEN]); */ + /* according 802.11-2012 standard, these five types are not robust types */ + if (subtype == WIFI_ACTION && + (pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_PUBLIC || + pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_HT || + pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_UNPROTECTED_WNM || + pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_SELF_PROTECTED || + pframe[WLAN_HDR_A3_LEN] == RTW_WLAN_CATEGORY_P2P)) + goto xmitframe_coalesce_fail; + /* before encrypt dump the management packet content */ + /*{ + int i; + printk("Management pkt: "); + for(i=0; i<pattrib->pktlen; i++) + printk(" %02x ", pframe[i]); + printk("=======\n"); + }*/ + if (pattrib->encrypt > 0) + _rtw_memcpy(pattrib->dot118021x_UncstKey.skey, psta->dot118021x_UncstKey.skey, 16); + + /* To use wrong key */ + if (pattrib->key_type == IEEE80211W_WRONG_KEY) { + RTW_INFO("use wrong key\n"); + pattrib->dot118021x_UncstKey.skey[0] = 0xff; + } + + /* bakeup original management packet */ + _rtw_memcpy(tmp_buf, pframe, pattrib->pktlen); + /* move to data portion */ + pframe += pattrib->hdrlen; + + /* 802.11w unicast management packet must be _AES_ */ + pattrib->iv_len = 8; + /* it's MIC of AES */ + pattrib->icv_len = 8; + + switch (pattrib->encrypt) { + case _AES_: + /* set AES IV header */ + AES_IV(pattrib->iv, psta->dot11wtxpn, 0); + break; + default: + goto xmitframe_coalesce_fail; + } + /* insert iv header into management frame */ + _rtw_memcpy(pframe, pattrib->iv, pattrib->iv_len); + pframe += pattrib->iv_len; + /* copy mgmt data portion after CCMP header */ + _rtw_memcpy(pframe, tmp_buf + pattrib->hdrlen, pattrib->pktlen - pattrib->hdrlen); + /* move pframe to end of mgmt pkt */ + pframe += pattrib->pktlen - pattrib->hdrlen; + /* add 8 bytes CCMP IV header to length */ + pattrib->pktlen += pattrib->iv_len; +#if 0 + /* dump management packet include AES IV header */ + { + int i; + printk("Management pkt + IV: "); + /* for(i=0; i<pattrib->pktlen; i++) */ + + printk("@@@@@@@@@@@@@\n"); + } +#endif + + if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { + _rtw_memcpy(pframe, pattrib->icv, pattrib->icv_len); + pframe += pattrib->icv_len; + } + /* add 8 bytes MIC */ + pattrib->pktlen += pattrib->icv_len; + /* set final tx command size */ + pattrib->last_txcmdsz = pattrib->pktlen; + + /* set protected bit must be beofre SW encrypt */ + SetPrivacy(mem_start); +#if 0 + /* dump management packet include AES header */ + { + int i; + printk("prepare to enc Management pkt + IV: "); + for (i = 0; i < pattrib->pktlen; i++) + printk(" %02x ", mem_start[i]); + printk("@@@@@@@@@@@@@\n"); + } +#endif + /* software encrypt */ + xmitframe_swencrypt(padapter, pxmitframe); + } + } + +xmitframe_coalesce_success: + _exit_critical_bh(&padapter->security_key_mutex, &irqL); + rtw_mfree(BIP_AAD, ori_len); + return _SUCCESS; + +xmitframe_coalesce_fail: + _exit_critical_bh(&padapter->security_key_mutex, &irqL); + rtw_mfree(BIP_AAD, ori_len); + + return _FAIL; +} +#endif /* CONFIG_IEEE80211W */ + +/* Logical Link Control(LLC) SubNetwork Attachment Point(SNAP) header + * IEEE LLC/SNAP header contains 8 octets + * First 3 octets comprise the LLC portion + * SNAP portion, 5 octets, is divided into two fields: + * Organizationally Unique Identifier(OUI), 3 octets, + * type, defined by that organization, 2 octets. + */ +s32 rtw_put_snap(u8 *data, u16 h_proto) +{ + struct ieee80211_snap_hdr *snap; + u8 *oui; + + + snap = (struct ieee80211_snap_hdr *)data; + snap->dsap = 0xaa; + snap->ssap = 0xaa; + snap->ctrl = 0x03; + + if (h_proto == 0x8137 || h_proto == 0x80f3) + oui = P802_1H_OUI; + else + oui = RFC1042_OUI; + + snap->oui[0] = oui[0]; + snap->oui[1] = oui[1]; + snap->oui[2] = oui[2]; + + *(u16 *)(data + SNAP_SIZE) = htons(h_proto); + + + return SNAP_SIZE + sizeof(u16); +} + +void rtw_update_protection(_adapter *padapter, u8 *ie, uint ie_len) +{ + + uint protection; + u8 *perp; + sint erp_len; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + + + switch (pxmitpriv->vcs_setting) { + case DISABLE_VCS: + pxmitpriv->vcs = NONE_VCS; + break; + + case ENABLE_VCS: + break; + + case AUTO_VCS: + default: + perp = rtw_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len); + if (perp == NULL) + pxmitpriv->vcs = NONE_VCS; + else { + protection = (*(perp + 2)) & BIT(1); + if (protection) { + if (pregistrypriv->vcs_type == RTS_CTS) + pxmitpriv->vcs = RTS_CTS; + else + pxmitpriv->vcs = CTS_TO_SELF; + } else + pxmitpriv->vcs = NONE_VCS; + } + + break; + + } + + +} + +void rtw_count_tx_stats(PADAPTER padapter, struct xmit_frame *pxmitframe, int sz) +{ + struct sta_info *psta = NULL; + struct stainfo_stats *pstats = NULL; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + u8 pkt_num = 1; + + if ((pxmitframe->frame_tag & 0x0f) == DATA_FRAMETAG) { +#if defined(CONFIG_USB_TX_AGGREGATION) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + pkt_num = pxmitframe->agg_num; +#endif + pmlmepriv->LinkDetectInfo.NumTxOkInPeriod += pkt_num; + + pxmitpriv->tx_pkts += pkt_num; + + pxmitpriv->tx_bytes += sz; + + psta = pxmitframe->attrib.psta; + if (psta) { + pstats = &psta->sta_stats; + + pstats->tx_pkts += pkt_num; + + pstats->tx_bytes += sz; +#ifdef CONFIG_TDLS + if (pxmitframe->attrib.ptdls_sta != NULL) { + pstats = &(pxmitframe->attrib.ptdls_sta->sta_stats); + pstats->tx_pkts += pkt_num; + pstats->tx_bytes += sz; + } +#endif /* CONFIG_TDLS */ + } + +#ifdef CONFIG_CHECK_LEAVE_LPS + /* traffic_check_for_leave_lps(padapter, _TRUE); */ +#endif /* CONFIG_LPS */ + + } +} + +static struct xmit_buf *__rtw_alloc_cmd_xmitbuf(struct xmit_priv *pxmitpriv, + enum cmdbuf_type buf_type) +{ + struct xmit_buf *pxmitbuf = NULL; + + + pxmitbuf = &pxmitpriv->pcmd_xmitbuf[buf_type]; + if (pxmitbuf != NULL) { + pxmitbuf->priv_data = NULL; + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + pxmitbuf->len = 0; + pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; + pxmitbuf->agg_num = 0; + pxmitbuf->pg_num = 0; +#endif +#ifdef CONFIG_PCI_HCI + pxmitbuf->len = 0; +#ifdef CONFIG_TRX_BD_ARCH + /*pxmitbuf->buf_desc = NULL;*/ +#else + pxmitbuf->desc = NULL; +#endif +#endif + + if (pxmitbuf->sctx) { + RTW_INFO("%s pxmitbuf->sctx is not NULL\n", __func__); + rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); + } + } else + RTW_INFO("%s fail, no xmitbuf available !!!\n", __func__); + +exit: + + + return pxmitbuf; +} + +struct xmit_frame *__rtw_alloc_cmdxmitframe(struct xmit_priv *pxmitpriv, + enum cmdbuf_type buf_type) +{ + struct xmit_frame *pcmdframe; + struct xmit_buf *pxmitbuf; + + pcmdframe = rtw_alloc_xmitframe(pxmitpriv); + if (pcmdframe == NULL) { + RTW_INFO("%s, alloc xmitframe fail\n", __FUNCTION__); + return NULL; + } + + pxmitbuf = __rtw_alloc_cmd_xmitbuf(pxmitpriv, buf_type); + if (pxmitbuf == NULL) { + RTW_INFO("%s, alloc xmitbuf fail\n", __FUNCTION__); + rtw_free_xmitframe(pxmitpriv, pcmdframe); + return NULL; + } + + pcmdframe->frame_tag = MGNT_FRAMETAG; + + pcmdframe->pxmitbuf = pxmitbuf; + + pcmdframe->buf_addr = pxmitbuf->pbuf; + + /* initial memory to zero */ + _rtw_memset(pcmdframe->buf_addr, 0, pxmitbuf->alloc_sz); + + pxmitbuf->priv_data = pcmdframe; + + return pcmdframe; + +} + +struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv) +{ + _irqL irqL; + struct xmit_buf *pxmitbuf = NULL; + _list *plist, *phead; + _queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; + + + _enter_critical(&pfree_queue->lock, &irqL); + + if (_rtw_queue_empty(pfree_queue) == _TRUE) + pxmitbuf = NULL; + else { + + phead = get_list_head(pfree_queue); + + plist = get_next(phead); + + pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); + + rtw_list_delete(&(pxmitbuf->list)); + } + + if (pxmitbuf != NULL) { + pxmitpriv->free_xmit_extbuf_cnt--; +#ifdef DBG_XMIT_BUF_EXT + RTW_INFO("DBG_XMIT_BUF_EXT ALLOC no=%d, free_xmit_extbuf_cnt=%d\n", pxmitbuf->no, pxmitpriv->free_xmit_extbuf_cnt); +#endif + + + pxmitbuf->priv_data = NULL; + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + pxmitbuf->len = 0; + pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; + pxmitbuf->agg_num = 1; +#endif +#ifdef CONFIG_PCI_HCI + pxmitbuf->len = 0; +#ifdef CONFIG_TRX_BD_ARCH + /*pxmitbuf->buf_desc = NULL;*/ +#else + pxmitbuf->desc = NULL; +#endif +#endif + + if (pxmitbuf->sctx) { + RTW_INFO("%s pxmitbuf->sctx is not NULL\n", __func__); + rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); + } + + } + + _exit_critical(&pfree_queue->lock, &irqL); + + + return pxmitbuf; +} + +s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) +{ + _irqL irqL; + _queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue; + + + if (pxmitbuf == NULL) + return _FAIL; + + _enter_critical(&pfree_queue->lock, &irqL); + + rtw_list_delete(&pxmitbuf->list); + + rtw_list_insert_tail(&(pxmitbuf->list), get_list_head(pfree_queue)); + pxmitpriv->free_xmit_extbuf_cnt++; +#ifdef DBG_XMIT_BUF_EXT + RTW_INFO("DBG_XMIT_BUF_EXT FREE no=%d, free_xmit_extbuf_cnt=%d\n", pxmitbuf->no , pxmitpriv->free_xmit_extbuf_cnt); +#endif + + _exit_critical(&pfree_queue->lock, &irqL); + + + return _SUCCESS; +} + +struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv) +{ + _irqL irqL; + struct xmit_buf *pxmitbuf = NULL; + _list *plist, *phead; + _queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; + + + /* RTW_INFO("+rtw_alloc_xmitbuf\n"); */ + + _enter_critical(&pfree_xmitbuf_queue->lock, &irqL); + + if (_rtw_queue_empty(pfree_xmitbuf_queue) == _TRUE) + pxmitbuf = NULL; + else { + + phead = get_list_head(pfree_xmitbuf_queue); + + plist = get_next(phead); + + pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); + + rtw_list_delete(&(pxmitbuf->list)); + } + + if (pxmitbuf != NULL) { + pxmitpriv->free_xmitbuf_cnt--; +#ifdef DBG_XMIT_BUF + RTW_INFO("DBG_XMIT_BUF ALLOC no=%d, free_xmitbuf_cnt=%d\n", pxmitbuf->no, pxmitpriv->free_xmitbuf_cnt); +#endif + /* RTW_INFO("alloc, free_xmitbuf_cnt=%d\n", pxmitpriv->free_xmitbuf_cnt); */ + + pxmitbuf->priv_data = NULL; + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + pxmitbuf->len = 0; + pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; + pxmitbuf->agg_num = 0; + pxmitbuf->pg_num = 0; +#endif +#ifdef CONFIG_PCI_HCI + pxmitbuf->len = 0; +#ifdef CONFIG_TRX_BD_ARCH + /*pxmitbuf->buf_desc = NULL;*/ +#else + pxmitbuf->desc = NULL; +#endif +#endif + + if (pxmitbuf->sctx) { + RTW_INFO("%s pxmitbuf->sctx is not NULL\n", __func__); + rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); + } + } +#ifdef DBG_XMIT_BUF + else + RTW_INFO("DBG_XMIT_BUF rtw_alloc_xmitbuf return NULL\n"); +#endif + + _exit_critical(&pfree_xmitbuf_queue->lock, &irqL); + + + return pxmitbuf; +} + +s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) +{ + _irqL irqL; + _queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue; + + + /* RTW_INFO("+rtw_free_xmitbuf\n"); */ + + if (pxmitbuf == NULL) + return _FAIL; + + if (pxmitbuf->sctx) { + RTW_INFO("%s pxmitbuf->sctx is not NULL\n", __func__); + rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_FREE); + } + + if (pxmitbuf->buf_tag == XMITBUF_CMD) { + } else if (pxmitbuf->buf_tag == XMITBUF_MGNT) + rtw_free_xmitbuf_ext(pxmitpriv, pxmitbuf); + else { + _enter_critical(&pfree_xmitbuf_queue->lock, &irqL); + + rtw_list_delete(&pxmitbuf->list); + + rtw_list_insert_tail(&(pxmitbuf->list), get_list_head(pfree_xmitbuf_queue)); + + pxmitpriv->free_xmitbuf_cnt++; + /* RTW_INFO("FREE, free_xmitbuf_cnt=%d\n", pxmitpriv->free_xmitbuf_cnt); */ +#ifdef DBG_XMIT_BUF + RTW_INFO("DBG_XMIT_BUF FREE no=%d, free_xmitbuf_cnt=%d\n", pxmitbuf->no , pxmitpriv->free_xmitbuf_cnt); +#endif + _exit_critical(&pfree_xmitbuf_queue->lock, &irqL); + } + + + return _SUCCESS; +} + +void rtw_init_xmitframe(struct xmit_frame *pxframe) +{ + if (pxframe != NULL) { /* default value setting */ + pxframe->buf_addr = NULL; + pxframe->pxmitbuf = NULL; + + _rtw_memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib)); + /* pxframe->attrib.psta = NULL; */ + + pxframe->frame_tag = DATA_FRAMETAG; + +#ifdef CONFIG_USB_HCI + pxframe->pkt = NULL; +#ifdef USB_PACKET_OFFSET_SZ + pxframe->pkt_offset = (PACKET_OFFSET_SZ / 8); +#else + pxframe->pkt_offset = 1;/* default use pkt_offset to fill tx desc */ +#endif + +#ifdef CONFIG_USB_TX_AGGREGATION + pxframe->agg_num = 1; +#endif + +#endif /* #ifdef CONFIG_USB_HCI */ + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + pxframe->pg_num = 1; + pxframe->agg_num = 1; +#endif + +#ifdef CONFIG_XMIT_ACK + pxframe->ack_report = 0; +#endif + + } +} + +/* +Calling context: +1. OS_TXENTRY +2. RXENTRY (rx_thread or RX_ISR/RX_CallBack) + +If we turn on USE_RXTHREAD, then, no need for critical section. +Otherwise, we must use _enter/_exit critical to protect free_xmit_queue... + +Must be very very cautious... + +*/ +struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)/* (_queue *pfree_xmit_queue) */ +{ + /* + Please remember to use all the osdep_service api, + and lock/unlock or _enter/_exit critical to protect + pfree_xmit_queue + */ + + _irqL irqL; + struct xmit_frame *pxframe = NULL; + _list *plist, *phead; + _queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue; + + + _enter_critical_bh(&pfree_xmit_queue->lock, &irqL); + + if (_rtw_queue_empty(pfree_xmit_queue) == _TRUE) { + pxframe = NULL; + } else { + phead = get_list_head(pfree_xmit_queue); + + plist = get_next(phead); + + pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list); + + rtw_list_delete(&(pxframe->list)); + pxmitpriv->free_xmitframe_cnt--; + } + + _exit_critical_bh(&pfree_xmit_queue->lock, &irqL); + + rtw_init_xmitframe(pxframe); + + + return pxframe; +} + +struct xmit_frame *rtw_alloc_xmitframe_ext(struct xmit_priv *pxmitpriv) +{ + _irqL irqL; + struct xmit_frame *pxframe = NULL; + _list *plist, *phead; + _queue *queue = &pxmitpriv->free_xframe_ext_queue; + + + _enter_critical_bh(&queue->lock, &irqL); + + if (_rtw_queue_empty(queue) == _TRUE) { + pxframe = NULL; + } else { + phead = get_list_head(queue); + plist = get_next(phead); + pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list); + + rtw_list_delete(&(pxframe->list)); + pxmitpriv->free_xframe_ext_cnt--; + } + + _exit_critical_bh(&queue->lock, &irqL); + + rtw_init_xmitframe(pxframe); + + + return pxframe; +} + +struct xmit_frame *rtw_alloc_xmitframe_once(struct xmit_priv *pxmitpriv) +{ + struct xmit_frame *pxframe = NULL; + u8 *alloc_addr; + + alloc_addr = rtw_zmalloc(sizeof(struct xmit_frame) + 4); + + if (alloc_addr == NULL) + goto exit; + + pxframe = (struct xmit_frame *)N_BYTE_ALIGMENT((SIZE_PTR)(alloc_addr), 4); + pxframe->alloc_addr = alloc_addr; + + pxframe->padapter = pxmitpriv->adapter; + pxframe->frame_tag = NULL_FRAMETAG; + + pxframe->pkt = NULL; + + pxframe->buf_addr = NULL; + pxframe->pxmitbuf = NULL; + + rtw_init_xmitframe(pxframe); + + RTW_INFO("################## %s ##################\n", __func__); + +exit: + return pxframe; +} + +s32 rtw_free_xmitframe(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe) +{ + _irqL irqL; + _queue *queue = NULL; + _adapter *padapter = pxmitpriv->adapter; + _pkt *pndis_pkt = NULL; + + + if (pxmitframe == NULL) { + goto exit; + } + + if (pxmitframe->pkt) { + pndis_pkt = pxmitframe->pkt; + pxmitframe->pkt = NULL; + } + + if (pxmitframe->alloc_addr) { + RTW_INFO("################## %s with alloc_addr ##################\n", __func__); + rtw_mfree(pxmitframe->alloc_addr, sizeof(struct xmit_frame) + 4); + goto check_pkt_complete; + } + + if (pxmitframe->ext_tag == 0) + queue = &pxmitpriv->free_xmit_queue; + else if (pxmitframe->ext_tag == 1) + queue = &pxmitpriv->free_xframe_ext_queue; + else + rtw_warn_on(1); + + _enter_critical_bh(&queue->lock, &irqL); + + rtw_list_delete(&pxmitframe->list); + rtw_list_insert_tail(&pxmitframe->list, get_list_head(queue)); + if (pxmitframe->ext_tag == 0) { + pxmitpriv->free_xmitframe_cnt++; + } else if (pxmitframe->ext_tag == 1) { + pxmitpriv->free_xframe_ext_cnt++; + } else { + } + + _exit_critical_bh(&queue->lock, &irqL); + +check_pkt_complete: + + if (pndis_pkt) + rtw_os_pkt_complete(padapter, pndis_pkt); + +exit: + + + return _SUCCESS; +} + +void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, _queue *pframequeue) +{ + _irqL irqL; + _list *plist, *phead; + struct xmit_frame *pxmitframe; + + + _enter_critical_bh(&(pframequeue->lock), &irqL); + + phead = get_list_head(pframequeue); + plist = get_next(phead); + + while (rtw_end_of_queue_search(phead, plist) == _FALSE) { + + pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list); + + plist = get_next(plist); + + rtw_free_xmitframe(pxmitpriv, pxmitframe); + + } + _exit_critical_bh(&(pframequeue->lock), &irqL); + +} + +s32 rtw_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe) +{ + DBG_COUNTER(padapter->tx_logs.core_tx_enqueue); + if (rtw_xmit_classifier(padapter, pxmitframe) == _FAIL) { + /* pxmitframe->pkt = NULL; */ + return _FAIL; + } + + return _SUCCESS; +} + +static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit, struct tx_servq *ptxservq, _queue *pframe_queue) +{ + _list *xmitframe_plist, *xmitframe_phead; + struct xmit_frame *pxmitframe = NULL; + + xmitframe_phead = get_list_head(pframe_queue); + xmitframe_plist = get_next(xmitframe_phead); + + while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) { + pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); + + /* xmitframe_plist = get_next(xmitframe_plist); */ + + /*#ifdef RTK_DMP_PLATFORM + #ifdef CONFIG_USB_TX_AGGREGATION + if((ptxservq->qcnt>0) && (ptxservq->qcnt<=2)) + { + pxmitframe = NULL; + + tasklet_schedule(&pxmitpriv->xmit_tasklet); + + break; + } + #endif + #endif*/ + rtw_list_delete(&pxmitframe->list); + + ptxservq->qcnt--; + + /* rtw_list_insert_tail(&pxmitframe->list, &phwxmit->pending); */ + + /* ptxservq->qcnt--; */ + + break; + + /* pxmitframe = NULL; */ + + } + + return pxmitframe; +} + +static struct xmit_frame *get_one_xmitframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit, struct tx_servq *ptxservq, _queue *pframe_queue) +{ + _list *xmitframe_plist, *xmitframe_phead; + struct xmit_frame *pxmitframe = NULL; + + xmitframe_phead = get_list_head(pframe_queue); + xmitframe_plist = get_next(xmitframe_phead); + + while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) { + pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); + break; + } + + return pxmitframe; +} + +struct xmit_frame *rtw_get_xframe(struct xmit_priv *pxmitpriv, int *num_frame) +{ + _irqL irqL0; + _list *sta_plist, *sta_phead; + struct hw_xmit *phwxmit_i = pxmitpriv->hwxmits; + sint entry = pxmitpriv->hwxmit_entry; + + struct hw_xmit *phwxmit; + struct tx_servq *ptxservq = NULL; + _queue *pframe_queue = NULL; + struct xmit_frame *pxmitframe = NULL; + _adapter *padapter = pxmitpriv->adapter; + struct registry_priv *pregpriv = &padapter->registrypriv; + int i, inx[4]; + +#ifdef CONFIG_USB_HCI + /* int j, tmp, acirp_cnt[4]; */ +#endif + + inx[0] = 0; + inx[1] = 1; + inx[2] = 2; + inx[3] = 3; + + *num_frame = 0; + + /*No amsdu when wifi_spec on*/ + if (pregpriv->wifi_spec == 1) { + return NULL; + } + + _enter_critical_bh(&pxmitpriv->lock, &irqL0); + + for (i = 0; i < entry; i++) { + phwxmit = phwxmit_i + inx[i]; + + sta_phead = get_list_head(phwxmit->sta_queue); + sta_plist = get_next(sta_phead); + + while ((rtw_end_of_queue_search(sta_phead, sta_plist)) == _FALSE) { + + ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending); + pframe_queue = &ptxservq->sta_pending; + + if(ptxservq->qcnt) + { + *num_frame = ptxservq->qcnt; + pxmitframe = get_one_xmitframe(pxmitpriv, phwxmit, ptxservq, pframe_queue); + goto exit; + } + sta_plist = get_next(sta_plist); + } + } + +exit: + + _exit_critical_bh(&pxmitpriv->lock, &irqL0); + + return pxmitframe; +} + + +struct xmit_frame *rtw_dequeue_xframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit_i, sint entry) +{ + _irqL irqL0; + _list *sta_plist, *sta_phead; + struct hw_xmit *phwxmit; + struct tx_servq *ptxservq = NULL; + _queue *pframe_queue = NULL; + struct xmit_frame *pxmitframe = NULL; + _adapter *padapter = pxmitpriv->adapter; + struct registry_priv *pregpriv = &padapter->registrypriv; + int i, inx[4]; +#ifdef CONFIG_USB_HCI + /* int j, tmp, acirp_cnt[4]; */ +#endif + + + inx[0] = 0; + inx[1] = 1; + inx[2] = 2; + inx[3] = 3; + + if (pregpriv->wifi_spec == 1) { + int j, tmp, acirp_cnt[4]; +#if 0 + if (flags < XMIT_QUEUE_ENTRY) { + /* priority exchange according to the completed xmitbuf flags. */ + inx[flags] = 0; + inx[0] = flags; + } +#endif + +#if defined(CONFIG_USB_HCI) || defined(CONFIG_SDIO_HCI) || defined(CONFIG_PCI_HCI) + for (j = 0; j < 4; j++) + inx[j] = pxmitpriv->wmm_para_seq[j]; +#endif + } + + _enter_critical_bh(&pxmitpriv->lock, &irqL0); + + for (i = 0; i < entry; i++) { + phwxmit = phwxmit_i + inx[i]; + + /* _enter_critical_ex(&phwxmit->sta_queue->lock, &irqL0); */ + + sta_phead = get_list_head(phwxmit->sta_queue); + sta_plist = get_next(sta_phead); + + while ((rtw_end_of_queue_search(sta_phead, sta_plist)) == _FALSE) { + + ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending); + + pframe_queue = &ptxservq->sta_pending; + + pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, ptxservq, pframe_queue); + + if (pxmitframe) { + phwxmit->accnt--; + + /* Remove sta node when there is no pending packets. */ + if (_rtw_queue_empty(pframe_queue)) /* must be done after get_next and before break */ + rtw_list_delete(&ptxservq->tx_pending); + + /* _exit_critical_ex(&phwxmit->sta_queue->lock, &irqL0); */ + + goto exit; + } + + sta_plist = get_next(sta_plist); + + } + + /* _exit_critical_ex(&phwxmit->sta_queue->lock, &irqL0); */ + + } + +exit: + + _exit_critical_bh(&pxmitpriv->lock, &irqL0); + + return pxmitframe; +} + +#if 1 +struct tx_servq *rtw_get_sta_pending(_adapter *padapter, struct sta_info *psta, sint up, u8 *ac) +{ + struct tx_servq *ptxservq = NULL; + + + switch (up) { + case 1: + case 2: + ptxservq = &(psta->sta_xmitpriv.bk_q); + *(ac) = 3; + break; + + case 4: + case 5: + ptxservq = &(psta->sta_xmitpriv.vi_q); + *(ac) = 1; + break; + + case 6: + case 7: + ptxservq = &(psta->sta_xmitpriv.vo_q); + *(ac) = 0; + break; + + case 0: + case 3: + default: + ptxservq = &(psta->sta_xmitpriv.be_q); + *(ac) = 2; + break; + + } + + + return ptxservq; +} +#else +__inline static struct tx_servq *rtw_get_sta_pending +(_adapter *padapter, _queue **ppstapending, struct sta_info *psta, sint up) +{ + struct tx_servq *ptxservq; + struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; + + +#ifdef CONFIG_RTL8711 + + if (IS_MCAST(psta->hwaddr)) { + ptxservq = &(psta->sta_xmitpriv.be_q); /* we will use be_q to queue bc/mc frames in BCMC_stainfo */ + *ppstapending = &padapter->xmitpriv.bm_pending; + } else +#endif + { + switch (up) { + case 1: + case 2: + ptxservq = &(psta->sta_xmitpriv.bk_q); + *ppstapending = &padapter->xmitpriv.bk_pending; + (phwxmits + 3)->accnt++; + break; + + case 4: + case 5: + ptxservq = &(psta->sta_xmitpriv.vi_q); + *ppstapending = &padapter->xmitpriv.vi_pending; + (phwxmits + 1)->accnt++; + break; + + case 6: + case 7: + ptxservq = &(psta->sta_xmitpriv.vo_q); + *ppstapending = &padapter->xmitpriv.vo_pending; + (phwxmits + 0)->accnt++; + break; + + case 0: + case 3: + default: + ptxservq = &(psta->sta_xmitpriv.be_q); + *ppstapending = &padapter->xmitpriv.be_pending; + (phwxmits + 2)->accnt++; + break; + + } + + } + + + return ptxservq; +} +#endif + +/* + * Will enqueue pxmitframe to the proper queue, + * and indicate it to xx_pending list..... + */ +s32 rtw_xmit_classifier(_adapter *padapter, struct xmit_frame *pxmitframe) +{ + /* _irqL irqL0; */ + u8 ac_index; + struct sta_info *psta; + struct tx_servq *ptxservq; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_priv *pstapriv = &padapter->stapriv; + struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; + sint res = _SUCCESS; + + + DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class); + + /* + if (pattrib->psta) { + psta = pattrib->psta; + } else { + RTW_INFO("%s, call rtw_get_stainfo()\n", __func__); + psta = rtw_get_stainfo(pstapriv, pattrib->ra); + } + */ + + psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); + if (pattrib->psta != psta) { + DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class_err_sta); + RTW_INFO("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); + return _FAIL; + } + + if (psta == NULL) { + DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class_err_nosta); + res = _FAIL; + RTW_INFO("rtw_xmit_classifier: psta == NULL\n"); + goto exit; + } + + if (!(psta->state & _FW_LINKED)) { + DBG_COUNTER(padapter->tx_logs.core_tx_enqueue_class_err_fwlink); + RTW_INFO("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + return _FAIL; + } + + ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); + + /* _enter_critical(&pstapending->lock, &irqL0); */ + + if (rtw_is_list_empty(&ptxservq->tx_pending)) + rtw_list_insert_tail(&ptxservq->tx_pending, get_list_head(phwxmits[ac_index].sta_queue)); + + /* _enter_critical(&ptxservq->sta_pending.lock, &irqL1); */ + + rtw_list_insert_tail(&pxmitframe->list, get_list_head(&ptxservq->sta_pending)); + ptxservq->qcnt++; + phwxmits[ac_index].accnt++; + + /* _exit_critical(&ptxservq->sta_pending.lock, &irqL1); */ + + /* _exit_critical(&pstapending->lock, &irqL0); */ + +exit: + + + return res; +} + +void rtw_alloc_hwxmits(_adapter *padapter) +{ + struct hw_xmit *hwxmits; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + pxmitpriv->hwxmit_entry = HWXMIT_ENTRY; + + pxmitpriv->hwxmits = NULL; + + pxmitpriv->hwxmits = (struct hw_xmit *)rtw_zmalloc(sizeof(struct hw_xmit) * pxmitpriv->hwxmit_entry); + + if (pxmitpriv->hwxmits == NULL) { + RTW_INFO("alloc hwxmits fail!...\n"); + return; + } + + hwxmits = pxmitpriv->hwxmits; + + if (pxmitpriv->hwxmit_entry == 5) { + /* pxmitpriv->bmc_txqueue.head = 0; */ + /* hwxmits[0] .phwtxqueue = &pxmitpriv->bmc_txqueue; */ + hwxmits[0] .sta_queue = &pxmitpriv->bm_pending; + + /* pxmitpriv->vo_txqueue.head = 0; */ + /* hwxmits[1] .phwtxqueue = &pxmitpriv->vo_txqueue; */ + hwxmits[1] .sta_queue = &pxmitpriv->vo_pending; + + /* pxmitpriv->vi_txqueue.head = 0; */ + /* hwxmits[2] .phwtxqueue = &pxmitpriv->vi_txqueue; */ + hwxmits[2] .sta_queue = &pxmitpriv->vi_pending; + + /* pxmitpriv->bk_txqueue.head = 0; */ + /* hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; */ + hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; + + /* pxmitpriv->be_txqueue.head = 0; */ + /* hwxmits[4] .phwtxqueue = &pxmitpriv->be_txqueue; */ + hwxmits[4] .sta_queue = &pxmitpriv->be_pending; + + } else if (pxmitpriv->hwxmit_entry == 4) { + + /* pxmitpriv->vo_txqueue.head = 0; */ + /* hwxmits[0] .phwtxqueue = &pxmitpriv->vo_txqueue; */ + hwxmits[0] .sta_queue = &pxmitpriv->vo_pending; + + /* pxmitpriv->vi_txqueue.head = 0; */ + /* hwxmits[1] .phwtxqueue = &pxmitpriv->vi_txqueue; */ + hwxmits[1] .sta_queue = &pxmitpriv->vi_pending; + + /* pxmitpriv->be_txqueue.head = 0; */ + /* hwxmits[2] .phwtxqueue = &pxmitpriv->be_txqueue; */ + hwxmits[2] .sta_queue = &pxmitpriv->be_pending; + + /* pxmitpriv->bk_txqueue.head = 0; */ + /* hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; */ + hwxmits[3] .sta_queue = &pxmitpriv->bk_pending; + } else { + + + } + + +} + +void rtw_free_hwxmits(_adapter *padapter) +{ + struct hw_xmit *hwxmits; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + hwxmits = pxmitpriv->hwxmits; + if (hwxmits) + rtw_mfree((u8 *)hwxmits, (sizeof(struct hw_xmit) * pxmitpriv->hwxmit_entry)); +} + +void rtw_init_hwxmits(struct hw_xmit *phwxmit, sint entry) +{ + sint i; + for (i = 0; i < entry; i++, phwxmit++) { + /* _rtw_spinlock_init(&phwxmit->xmit_lock); */ + /* _rtw_init_listhead(&phwxmit->pending); */ + /* phwxmit->txcmdcnt = 0; */ + phwxmit->accnt = 0; + } +} + +#ifdef CONFIG_BR_EXT +int rtw_br_client_tx(_adapter *padapter, struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + _irqL irqL; + /* if(check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) == _TRUE) */ + { + void dhcp_flag_bcast(_adapter *priv, struct sk_buff *skb); + int res, is_vlan_tag = 0, i, do_nat25 = 1; + unsigned short vlan_hdr = 0; + void *br_port = NULL; + + /* mac_clone_handle_frame(priv, skb); */ + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) + br_port = padapter->pnetdev->br_port; +#else /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */ + rcu_read_lock(); + br_port = rcu_dereference(padapter->pnetdev->rx_handler_data); + rcu_read_unlock(); +#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */ + _enter_critical_bh(&padapter->br_ext_lock, &irqL); + if (!(skb->data[0] & 1) && + br_port && + memcmp(skb->data + MACADDRLEN, padapter->br_mac, MACADDRLEN) && + *((unsigned short *)(skb->data + MACADDRLEN * 2)) != __constant_htons(ETH_P_8021Q) && + *((unsigned short *)(skb->data + MACADDRLEN * 2)) == __constant_htons(ETH_P_IP) && + !memcmp(padapter->scdb_mac, skb->data + MACADDRLEN, MACADDRLEN) && padapter->scdb_entry) { + memcpy(skb->data + MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); + padapter->scdb_entry->ageing_timer = jiffies; + _exit_critical_bh(&padapter->br_ext_lock, &irqL); + } else + /* if (!priv->pmib->ethBrExtInfo.nat25_disable) */ + { + /* if (priv->dev->br_port && + * !memcmp(skb->data+MACADDRLEN, priv->br_mac, MACADDRLEN)) { */ +#if 1 + if (*((unsigned short *)(skb->data + MACADDRLEN * 2)) == __constant_htons(ETH_P_8021Q)) { + is_vlan_tag = 1; + vlan_hdr = *((unsigned short *)(skb->data + MACADDRLEN * 2 + 2)); + for (i = 0; i < 6; i++) + *((unsigned short *)(skb->data + MACADDRLEN * 2 + 2 - i * 2)) = *((unsigned short *)(skb->data + MACADDRLEN * 2 - 2 - i * 2)); + skb_pull(skb, 4); + } + /* if SA == br_mac && skb== IP => copy SIP to br_ip ?? why */ + if (!memcmp(skb->data + MACADDRLEN, padapter->br_mac, MACADDRLEN) && + (*((unsigned short *)(skb->data + MACADDRLEN * 2)) == __constant_htons(ETH_P_IP))) + memcpy(padapter->br_ip, skb->data + WLAN_ETHHDR_LEN + 12, 4); + + if (*((unsigned short *)(skb->data + MACADDRLEN * 2)) == __constant_htons(ETH_P_IP)) { + if (memcmp(padapter->scdb_mac, skb->data + MACADDRLEN, MACADDRLEN)) { + void *scdb_findEntry(_adapter *priv, unsigned char *macAddr, unsigned char *ipAddr); + + padapter->scdb_entry = (struct nat25_network_db_entry *)scdb_findEntry(padapter, + skb->data + MACADDRLEN, skb->data + WLAN_ETHHDR_LEN + 12); + if (padapter->scdb_entry != NULL) { + memcpy(padapter->scdb_mac, skb->data + MACADDRLEN, MACADDRLEN); + memcpy(padapter->scdb_ip, skb->data + WLAN_ETHHDR_LEN + 12, 4); + padapter->scdb_entry->ageing_timer = jiffies; + do_nat25 = 0; + } + } else { + if (padapter->scdb_entry) { + padapter->scdb_entry->ageing_timer = jiffies; + do_nat25 = 0; + } else { + memset(padapter->scdb_mac, 0, MACADDRLEN); + memset(padapter->scdb_ip, 0, 4); + } + } + } + _exit_critical_bh(&padapter->br_ext_lock, &irqL); +#endif /* 1 */ + if (do_nat25) { + int nat25_db_handle(_adapter *priv, struct sk_buff *skb, int method); + if (nat25_db_handle(padapter, skb, NAT25_CHECK) == 0) { + struct sk_buff *newskb; + + if (is_vlan_tag) { + skb_push(skb, 4); + for (i = 0; i < 6; i++) + *((unsigned short *)(skb->data + i * 2)) = *((unsigned short *)(skb->data + 4 + i * 2)); + *((unsigned short *)(skb->data + MACADDRLEN * 2)) = __constant_htons(ETH_P_8021Q); + *((unsigned short *)(skb->data + MACADDRLEN * 2 + 2)) = vlan_hdr; + } + + newskb = rtw_skb_copy(skb); + if (newskb == NULL) { + /* priv->ext_stats.tx_drops++; */ + DEBUG_ERR("TX DROP: rtw_skb_copy fail!\n"); + /* goto stop_proc; */ + return -1; + } + rtw_skb_free(skb); + + *pskb = skb = newskb; + if (is_vlan_tag) { + vlan_hdr = *((unsigned short *)(skb->data + MACADDRLEN * 2 + 2)); + for (i = 0; i < 6; i++) + *((unsigned short *)(skb->data + MACADDRLEN * 2 + 2 - i * 2)) = *((unsigned short *)(skb->data + MACADDRLEN * 2 - 2 - i * 2)); + skb_pull(skb, 4); + } + } + + if (skb_is_nonlinear(skb)) + DEBUG_ERR("%s(): skb_is_nonlinear!!\n", __FUNCTION__); + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) + res = skb_linearize(skb, GFP_ATOMIC); +#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) */ + res = skb_linearize(skb); +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)) */ + if (res < 0) { + DEBUG_ERR("TX DROP: skb_linearize fail!\n"); + /* goto free_and_stop; */ + return -1; + } + + res = nat25_db_handle(padapter, skb, NAT25_INSERT); + if (res < 0) { + if (res == -2) { + /* priv->ext_stats.tx_drops++; */ + DEBUG_ERR("TX DROP: nat25_db_handle fail!\n"); + /* goto free_and_stop; */ + return -1; + + } + /* we just print warning message and let it go */ + /* DEBUG_WARN("%s()-%d: nat25_db_handle INSERT Warning!\n", __FUNCTION__, __LINE__); */ + /* return -1; */ /* return -1 will cause system crash on 2011/08/30! */ + return 0; + } + } + + memcpy(skb->data + MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); + + dhcp_flag_bcast(padapter, skb); + + if (is_vlan_tag) { + skb_push(skb, 4); + for (i = 0; i < 6; i++) + *((unsigned short *)(skb->data + i * 2)) = *((unsigned short *)(skb->data + 4 + i * 2)); + *((unsigned short *)(skb->data + MACADDRLEN * 2)) = __constant_htons(ETH_P_8021Q); + *((unsigned short *)(skb->data + MACADDRLEN * 2 + 2)) = vlan_hdr; + } + } +#if 0 + else { + if (*((unsigned short *)(skb->data + MACADDRLEN * 2)) == __constant_htons(ETH_P_8021Q)) + is_vlan_tag = 1; + + if (is_vlan_tag) { + if (ICMPV6_MCAST_MAC(skb->data) && ICMPV6_PROTO1A_VALN(skb->data)) + memcpy(skb->data + MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); + } else { + if (ICMPV6_MCAST_MAC(skb->data) && ICMPV6_PROTO1A(skb->data)) + memcpy(skb->data + MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN); + } + } +#endif /* 0 */ + + /* check if SA is equal to our MAC */ + if (memcmp(skb->data + MACADDRLEN, GET_MY_HWADDR(padapter), MACADDRLEN)) { + /* priv->ext_stats.tx_drops++; */ + DEBUG_ERR("TX DROP: untransformed frame SA:%02X%02X%02X%02X%02X%02X!\n", + skb->data[6], skb->data[7], skb->data[8], skb->data[9], skb->data[10], skb->data[11]); + /* goto free_and_stop; */ + return -1; + } + } + return 0; +} +#endif /* CONFIG_BR_EXT */ + +u32 rtw_get_ff_hwaddr(struct xmit_frame *pxmitframe) +{ + u32 addr; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + + switch (pattrib->qsel) { + case 0: + case 3: + addr = BE_QUEUE_INX; + break; + case 1: + case 2: + addr = BK_QUEUE_INX; + break; + case 4: + case 5: + addr = VI_QUEUE_INX; + break; + case 6: + case 7: + addr = VO_QUEUE_INX; + break; + case 0x10: + addr = BCN_QUEUE_INX; + break; + case 0x11: /* BC/MC in PS (HIQ) */ + addr = HIGH_QUEUE_INX; + break; + case 0x13: + addr = TXCMD_QUEUE_INX; + break; + case 0x12: + default: + addr = MGT_QUEUE_INX; + break; + + } + + return addr; + +} + +static void do_queue_select(_adapter *padapter, struct pkt_attrib *pattrib) +{ + u8 qsel; + + qsel = pattrib->priority; + +#ifdef CONFIG_CONCURRENT_MODE + /* if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) + * qsel = 7; */ +#endif + +#ifdef CONFIG_MCC_MODE + if (MCC_EN(padapter)) { + /* Under MCC */ + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_NEED_MCC)) { + if (padapter->mcc_adapterpriv.role == MCC_ROLE_GO + || padapter->mcc_adapterpriv.role == MCC_ROLE_AP) { + pattrib->qsel = QSLT_VO; /* AP interface VO queue */ + } else { + pattrib->qsel = QSLT_BE; /* STA interface BE queue */ + } + } else + /* Not Under MCC */ + pattrib->qsel = qsel; + } else + /* Not enable MCC */ + pattrib->qsel = qsel; +#else /* !CONFIG_MCC_MODE */ + pattrib->qsel = qsel; +#endif /* CONFIG_MCC_MODE */ +} + +/* + * The main transmit(tx) entry + * + * Return + * 1 enqueue + * 0 success, hardware will handle this xmit frame(packet) + * <0 fail + */ + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)) +s32 rtw_monitor_xmit_entry(struct sk_buff *skb, struct net_device *ndev) +{ + int ret = 0; + int rtap_len; + int qos_len = 0; + int dot11_hdr_len = 24; + int snap_len = 6; + unsigned char *pdata; + u16 frame_ctl; + unsigned char src_mac_addr[6]; + unsigned char dst_mac_addr[6]; + struct rtw_ieee80211_hdr *dot11_hdr; + struct ieee80211_radiotap_header *rtap_hdr; + _adapter *padapter = (_adapter *)rtw_netdev_priv(ndev); + + if (skb) + rtw_mstat_update(MSTAT_TYPE_SKB, MSTAT_ALLOC_SUCCESS, skb->truesize); + + if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) + goto fail; + + rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; + if (unlikely(rtap_hdr->it_version)) + goto fail; + + rtap_len = ieee80211_get_radiotap_len(skb->data); + if (unlikely(skb->len < rtap_len)) + goto fail; + + if (rtap_len != 12) { + RTW_INFO("radiotap len (should be 14): %d\n", rtap_len); + goto fail; + } + + /* Skip the ratio tap header */ + skb_pull(skb, rtap_len); + + dot11_hdr = (struct rtw_ieee80211_hdr *)skb->data; + frame_ctl = le16_to_cpu(dot11_hdr->frame_ctl); + /* Check if the QoS bit is set */ + + if ((frame_ctl & RTW_IEEE80211_FCTL_FTYPE) == RTW_IEEE80211_FTYPE_DATA) { + + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + u8 *buf = skb->data; + u32 len = skb->len; + u8 category, action; + int type = -1; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) { + rtw_udelay_os(500); + goto fail; + } + pattrib = &pmgntframe->attrib; + + update_monitor_frame_attrib(padapter, pattrib); + + pattrib->retry_ctrl = _FALSE; + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + + _rtw_memcpy(pframe, (void *)buf, len); + + pattrib->pktlen = len; + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + if (is_broadcast_mac_addr(pwlanhdr->addr3) || is_broadcast_mac_addr(pwlanhdr->addr1)) + pattrib->rate = MGN_24M; + + pmlmeext->mgnt_seq = GetSequence(pwlanhdr); + pattrib->seqnum = pmlmeext->mgnt_seq; + pmlmeext->mgnt_seq++; + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + + } else { + struct xmit_frame *pmgntframe; + struct pkt_attrib *pattrib; + unsigned char *pframe; + struct rtw_ieee80211_hdr *pwlanhdr; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + u8 *buf = skb->data; + u32 len = skb->len; + u8 category, action; + int type = -1; + + pmgntframe = alloc_mgtxmitframe(pxmitpriv); + if (pmgntframe == NULL) + goto fail; + + pattrib = &pmgntframe->attrib; + update_mgntframe_attrib(padapter, pattrib); + pattrib->retry_ctrl = _FALSE; + + _rtw_memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); + + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + + _rtw_memcpy(pframe, (void *)buf, len); + + pattrib->pktlen = len; + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + pmlmeext->mgnt_seq = GetSequence(pwlanhdr); + pattrib->seqnum = pmlmeext->mgnt_seq; + pmlmeext->mgnt_seq++; + + pattrib->last_txcmdsz = pattrib->pktlen; + + dump_mgntframe(padapter, pmgntframe); + + } + +fail: + + rtw_skb_free(skb); + + return 0; +} +#endif +/* + * The main transmit(tx) entry + * + * Return + * 1 enqueue + * 0 success, hardware will handle this xmit frame(packet) + * <0 fail + */ +s32 rtw_xmit(_adapter *padapter, _pkt **ppkt) +{ + static u32 start = 0; + static u32 drop_cnt = 0; +#ifdef CONFIG_AP_MODE + _irqL irqL0; +#endif + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct xmit_frame *pxmitframe = NULL; +#ifdef CONFIG_BR_EXT + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + void *br_port = NULL; +#endif /* CONFIG_BR_EXT */ + + s32 res; + + DBG_COUNTER(padapter->tx_logs.core_tx); + + if (start == 0) + start = rtw_get_current_time(); + + pxmitframe = rtw_alloc_xmitframe(pxmitpriv); + + if (rtw_get_passing_time_ms(start) > 2000) { + if (drop_cnt) + RTW_INFO("DBG_TX_DROP_FRAME %s no more pxmitframe, drop_cnt:%u\n", __FUNCTION__, drop_cnt); + start = rtw_get_current_time(); + drop_cnt = 0; + } + + if (pxmitframe == NULL) { + drop_cnt++; + /*RTW_INFO("%s-"ADPT_FMT" no more xmitframe\n", __func__, ADPT_ARG(padapter));*/ + DBG_COUNTER(padapter->tx_logs.core_tx_err_pxmitframe); + return -1; + } + +#ifdef CONFIG_BR_EXT + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) + br_port = padapter->pnetdev->br_port; +#else /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */ + rcu_read_lock(); + br_port = rcu_dereference(padapter->pnetdev->rx_handler_data); + rcu_read_unlock(); +#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 35)) */ + + if (br_port && check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_ADHOC_STATE) == _TRUE) { + res = rtw_br_client_tx(padapter, ppkt); + if (res == -1) { + rtw_free_xmitframe(pxmitpriv, pxmitframe); + DBG_COUNTER(padapter->tx_logs.core_tx_err_brtx); + return -1; + } + } + +#endif /* CONFIG_BR_EXT */ + + res = update_attrib(padapter, *ppkt, &pxmitframe->attrib); + +#ifdef CONFIG_MCC_MODE + /* record data kernel TX to driver to check MCC concurrent TX */ + rtw_hal_mcc_calc_tx_bytes_from_kernel(padapter, pxmitframe->attrib.pktlen); +#endif /* CONFIG_MCC_MODE */ + +#ifdef CONFIG_WAPI_SUPPORT + if (pxmitframe->attrib.ether_type != 0x88B4) { + if (rtw_wapi_drop_for_key_absent(padapter, pxmitframe->attrib.ra)) { + WAPI_TRACE(WAPI_RX, "drop for key absend when tx\n"); + res = _FAIL; + } + } +#endif + if (res == _FAIL) { + /*RTW_INFO("%s-"ADPT_FMT" update attrib fail\n", __func__, ADPT_ARG(padapter));*/ +#ifdef DBG_TX_DROP_FRAME + RTW_INFO("DBG_TX_DROP_FRAME %s update attrib fail\n", __FUNCTION__); +#endif + rtw_free_xmitframe(pxmitpriv, pxmitframe); + return -1; + } + pxmitframe->pkt = *ppkt; + + rtw_led_control(padapter, LED_CTL_TX); + + do_queue_select(padapter, &pxmitframe->attrib); + +#ifdef CONFIG_AP_MODE + _enter_critical_bh(&pxmitpriv->lock, &irqL0); + if (xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe) == _TRUE) { + _exit_critical_bh(&pxmitpriv->lock, &irqL0); + DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue); + return 1; + } + _exit_critical_bh(&pxmitpriv->lock, &irqL0); +#endif + + /* pre_xmitframe */ + if (rtw_hal_xmit(padapter, pxmitframe) == _FALSE) + return 1; + + return 0; +} + +#ifdef CONFIG_TDLS +sint xmitframe_enqueue_for_tdls_sleeping_sta(_adapter *padapter, struct xmit_frame *pxmitframe) +{ + sint ret = _FALSE; + + _irqL irqL; + struct sta_info *ptdls_sta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + int i; + + ptdls_sta = rtw_get_stainfo(pstapriv, pattrib->dst); + if (ptdls_sta == NULL) + return ret; + else if (ptdls_sta->tdls_sta_state & TDLS_LINKED_STATE) { + + if (pattrib->triggered == 1) { + ret = _TRUE; + return ret; + } + + _enter_critical_bh(&ptdls_sta->sleep_q.lock, &irqL); + + if (ptdls_sta->state & WIFI_SLEEP_STATE) { + rtw_list_delete(&pxmitframe->list); + + /* _enter_critical_bh(&psta->sleep_q.lock, &irqL); */ + + rtw_list_insert_tail(&pxmitframe->list, get_list_head(&ptdls_sta->sleep_q)); + + ptdls_sta->sleepq_len++; + ptdls_sta->sleepq_ac_len++; + + /* indicate 4-AC queue bit in TDLS peer traffic indication */ + switch (pattrib->priority) { + case 1: + case 2: + ptdls_sta->uapsd_bk |= BIT(1); + break; + case 4: + case 5: + ptdls_sta->uapsd_vi |= BIT(1); + break; + case 6: + case 7: + ptdls_sta->uapsd_vo |= BIT(1); + break; + case 0: + case 3: + default: + ptdls_sta->uapsd_be |= BIT(1); + break; + } + + /* Transmit TDLS PTI via AP */ + if (ptdls_sta->sleepq_len == 1) + rtw_tdls_cmd(padapter, ptdls_sta->hwaddr, TDLS_ISSUE_PTI); + + ret = _TRUE; + } + + _exit_critical_bh(&ptdls_sta->sleep_q.lock, &irqL); + } + + return ret; + +} +#endif /* CONFIG_TDLS */ + +#define RTW_HIQ_FILTER_ALLOW_ALL 0 +#define RTW_HIQ_FILTER_ALLOW_SPECIAL 1 +#define RTW_HIQ_FILTER_DENY_ALL 2 + +inline bool xmitframe_hiq_filter(struct xmit_frame *xmitframe) +{ + bool allow = _FALSE; + _adapter *adapter = xmitframe->padapter; + struct registry_priv *registry = &adapter->registrypriv; + + if (rtw_get_intf_type(adapter) != RTW_PCIE) { + + if (adapter->registrypriv.wifi_spec == 1) + allow = _TRUE; + else if (registry->hiq_filter == RTW_HIQ_FILTER_ALLOW_SPECIAL) { + + struct pkt_attrib *attrib = &xmitframe->attrib; + + if (attrib->ether_type == 0x0806 + || attrib->ether_type == 0x888e +#ifdef CONFIG_WAPI_SUPPORT + || attrib->ether_type == 0x88B4 +#endif + || attrib->dhcp_pkt + ) { + if (0) + RTW_INFO(FUNC_ADPT_FMT" ether_type:0x%04x%s\n", FUNC_ADPT_ARG(xmitframe->padapter) + , attrib->ether_type, attrib->dhcp_pkt ? " DHCP" : ""); + allow = _TRUE; + } + } else if (registry->hiq_filter == RTW_HIQ_FILTER_ALLOW_ALL) + allow = _TRUE; + else if (registry->hiq_filter == RTW_HIQ_FILTER_DENY_ALL) { + } else + rtw_warn_on(1); + } + return allow; +} + +#if defined(CONFIG_AP_MODE) || defined(CONFIG_TDLS) + +sint xmitframe_enqueue_for_sleeping_sta(_adapter *padapter, struct xmit_frame *pxmitframe) +{ + _irqL irqL; + sint ret = _FALSE; + struct sta_info *psta = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + sint bmcst = IS_MCAST(pattrib->ra); + bool update_tim = _FALSE; +#ifdef CONFIG_TDLS + + if (padapter->tdlsinfo.link_established == _TRUE) + ret = xmitframe_enqueue_for_tdls_sleeping_sta(padapter, pxmitframe); +#endif /* CONFIG_TDLS */ + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _FALSE) { + DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_fwstate); + return ret; + } + /* + if(pattrib->psta) + { + psta = pattrib->psta; + } + else + { + RTW_INFO("%s, call rtw_get_stainfo()\n", __func__); + psta=rtw_get_stainfo(pstapriv, pattrib->ra); + } + */ + psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); + if (pattrib->psta != psta) { + DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_sta); + RTW_INFO("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); + return _FALSE; + } + + if (psta == NULL) { + DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_nosta); + RTW_INFO("%s, psta==NUL\n", __func__); + return _FALSE; + } + + if (!(psta->state & _FW_LINKED)) { + DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_link); + RTW_INFO("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state); + return _FALSE; + } + + if (pattrib->triggered == 1) { + DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_warn_trigger); + /* RTW_INFO("directly xmit pspoll_triggered packet\n"); */ + + /* pattrib->triggered=0; */ + if (bmcst && xmitframe_hiq_filter(pxmitframe) == _TRUE) + pattrib->qsel = QSLT_HIGH;/* HIQ */ + + return ret; + } + + + if (bmcst) { + _enter_critical_bh(&psta->sleep_q.lock, &irqL); + + if (pstapriv->sta_dz_bitmap) { /* if anyone sta is in ps mode */ + /* pattrib->qsel = QSLT_HIGH; */ /* HIQ */ + + rtw_list_delete(&pxmitframe->list); + + /*_enter_critical_bh(&psta->sleep_q.lock, &irqL);*/ + + rtw_list_insert_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); + + psta->sleepq_len++; + + if (!(pstapriv->tim_bitmap & BIT(0))) + update_tim = _TRUE; + + pstapriv->tim_bitmap |= BIT(0); + pstapriv->sta_dz_bitmap |= BIT(0); + + /* RTW_INFO("enqueue, sq_len=%d, tim=%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */ + if (update_tim == _TRUE) { + if (is_broadcast_mac_addr(pattrib->ra)) + _update_beacon(padapter, _TIM_IE_, NULL, _TRUE, "buffer BC"); + else + _update_beacon(padapter, _TIM_IE_, NULL, _TRUE, "buffer MC"); + } else + chk_bmc_sleepq_cmd(padapter); + + /*_exit_critical_bh(&psta->sleep_q.lock, &irqL);*/ + + ret = _TRUE; + + DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_mcast); + + } + + _exit_critical_bh(&psta->sleep_q.lock, &irqL); + + return ret; + + } + + + _enter_critical_bh(&psta->sleep_q.lock, &irqL); + + if (psta->state & WIFI_SLEEP_STATE) { + u8 wmmps_ac = 0; + + if (pstapriv->sta_dz_bitmap & BIT(psta->aid)) { + rtw_list_delete(&pxmitframe->list); + + /* _enter_critical_bh(&psta->sleep_q.lock, &irqL); */ + + rtw_list_insert_tail(&pxmitframe->list, get_list_head(&psta->sleep_q)); + + psta->sleepq_len++; + + switch (pattrib->priority) { + case 1: + case 2: + wmmps_ac = psta->uapsd_bk & BIT(0); + break; + case 4: + case 5: + wmmps_ac = psta->uapsd_vi & BIT(0); + break; + case 6: + case 7: + wmmps_ac = psta->uapsd_vo & BIT(0); + break; + case 0: + case 3: + default: + wmmps_ac = psta->uapsd_be & BIT(0); + break; + } + + if (wmmps_ac) + psta->sleepq_ac_len++; + + if (((psta->has_legacy_ac) && (!wmmps_ac)) || ((!psta->has_legacy_ac) && (wmmps_ac))) { + if (!(pstapriv->tim_bitmap & BIT(psta->aid))) + update_tim = _TRUE; + + pstapriv->tim_bitmap |= BIT(psta->aid); + + /* RTW_INFO("enqueue, sq_len=%d, tim=%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */ + + if (update_tim == _TRUE) { + /* RTW_INFO("sleepq_len==1, update BCNTIM\n"); */ + /* upate BCN for TIM IE */ + _update_beacon(padapter, _TIM_IE_, NULL, _TRUE, "buffer UC"); + } + } + + /* _exit_critical_bh(&psta->sleep_q.lock, &irqL); */ + + /* if(psta->sleepq_len > (NR_XMITFRAME>>3)) */ + /* { */ + /* wakeup_sta_to_xmit(padapter, psta); */ + /* } */ + + ret = _TRUE; + + DBG_COUNTER(padapter->tx_logs.core_tx_ap_enqueue_ucast); + } + + } + + _exit_critical_bh(&psta->sleep_q.lock, &irqL); + + return ret; + +} + +static void dequeue_xmitframes_to_sleeping_queue(_adapter *padapter, struct sta_info *psta, _queue *pframequeue) +{ + sint ret; + _list *plist, *phead; + u8 ac_index; + struct tx_servq *ptxservq; + struct pkt_attrib *pattrib; + struct xmit_frame *pxmitframe; + struct hw_xmit *phwxmits = padapter->xmitpriv.hwxmits; + + phead = get_list_head(pframequeue); + plist = get_next(phead); + + while (rtw_end_of_queue_search(phead, plist) == _FALSE) { + pxmitframe = LIST_CONTAINOR(plist, struct xmit_frame, list); + + plist = get_next(plist); + + pattrib = &pxmitframe->attrib; + + pattrib->triggered = 0; + + ret = xmitframe_enqueue_for_sleeping_sta(padapter, pxmitframe); + + if (_TRUE == ret) { + ptxservq = rtw_get_sta_pending(padapter, psta, pattrib->priority, (u8 *)(&ac_index)); + + ptxservq->qcnt--; + phwxmits[ac_index].accnt--; + } else { + /* RTW_INFO("xmitframe_enqueue_for_sleeping_sta return _FALSE\n"); */ + } + + } + +} + +void stop_sta_xmit(_adapter *padapter, struct sta_info *psta) +{ + _irqL irqL0; + struct sta_info *psta_bmc; + struct sta_xmit_priv *pstaxmitpriv; + struct sta_priv *pstapriv = &padapter->stapriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + pstaxmitpriv = &psta->sta_xmitpriv; + + /* for BC/MC Frames */ + psta_bmc = rtw_get_bcmc_stainfo(padapter); + + + _enter_critical_bh(&pxmitpriv->lock, &irqL0); + + psta->state |= WIFI_SLEEP_STATE; + +#ifdef CONFIG_TDLS + if (!(psta->tdls_sta_state & TDLS_LINKED_STATE)) +#endif /* CONFIG_TDLS */ + pstapriv->sta_dz_bitmap |= BIT(psta->aid); + + + + dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vo_q.sta_pending); + rtw_list_delete(&(pstaxmitpriv->vo_q.tx_pending)); + + + dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vi_q.sta_pending); + rtw_list_delete(&(pstaxmitpriv->vi_q.tx_pending)); + + + dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->be_q.sta_pending); + rtw_list_delete(&(pstaxmitpriv->be_q.tx_pending)); + + + dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->bk_q.sta_pending); + rtw_list_delete(&(pstaxmitpriv->bk_q.tx_pending)); + +#ifdef CONFIG_TDLS + if (!(psta->tdls_sta_state & TDLS_LINKED_STATE) && (psta_bmc != NULL)) { +#endif /* CONFIG_TDLS */ + + + /* for BC/MC Frames */ + pstaxmitpriv = &psta_bmc->sta_xmitpriv; + dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc, &pstaxmitpriv->be_q.sta_pending); + rtw_list_delete(&(pstaxmitpriv->be_q.tx_pending)); + + +#ifdef CONFIG_TDLS + } +#endif /* CONFIG_TDLS */ + _exit_critical_bh(&pxmitpriv->lock, &irqL0); + + +} + +void wakeup_sta_to_xmit(_adapter *padapter, struct sta_info *psta) +{ + _irqL irqL; + u8 update_mask = 0, wmmps_ac = 0; + struct sta_info *psta_bmc; + _list *xmitframe_plist, *xmitframe_phead; + struct xmit_frame *pxmitframe = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + psta_bmc = rtw_get_bcmc_stainfo(padapter); + + + /* _enter_critical_bh(&psta->sleep_q.lock, &irqL); */ + _enter_critical_bh(&pxmitpriv->lock, &irqL); + + xmitframe_phead = get_list_head(&psta->sleep_q); + xmitframe_plist = get_next(xmitframe_phead); + + while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) { + pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); + + xmitframe_plist = get_next(xmitframe_plist); + + rtw_list_delete(&pxmitframe->list); + + switch (pxmitframe->attrib.priority) { + case 1: + case 2: + wmmps_ac = psta->uapsd_bk & BIT(1); + break; + case 4: + case 5: + wmmps_ac = psta->uapsd_vi & BIT(1); + break; + case 6: + case 7: + wmmps_ac = psta->uapsd_vo & BIT(1); + break; + case 0: + case 3: + default: + wmmps_ac = psta->uapsd_be & BIT(1); + break; + } + + psta->sleepq_len--; + if (psta->sleepq_len > 0) + pxmitframe->attrib.mdata = 1; + else + pxmitframe->attrib.mdata = 0; + + if (wmmps_ac) { + psta->sleepq_ac_len--; + if (psta->sleepq_ac_len > 0) { + pxmitframe->attrib.mdata = 1; + pxmitframe->attrib.eosp = 0; + } else { + pxmitframe->attrib.mdata = 0; + pxmitframe->attrib.eosp = 1; + } + } + + pxmitframe->attrib.triggered = 1; + + /* + _exit_critical_bh(&psta->sleep_q.lock, &irqL); + if(rtw_hal_xmit(padapter, pxmitframe) == _TRUE) + { + rtw_os_xmit_complete(padapter, pxmitframe); + } + _enter_critical_bh(&psta->sleep_q.lock, &irqL); + */ + rtw_hal_xmitframe_enqueue(padapter, pxmitframe); + + + } + + if (psta->sleepq_len == 0) { +#ifdef CONFIG_TDLS + if (psta->tdls_sta_state & TDLS_LINKED_STATE) { + if (psta->state & WIFI_SLEEP_STATE) + psta->state ^= WIFI_SLEEP_STATE; + + _exit_critical_bh(&pxmitpriv->lock, &irqL); + return; + } +#endif /* CONFIG_TDLS */ + + if (pstapriv->tim_bitmap & BIT(psta->aid)) { + /* RTW_INFO("wakeup to xmit, qlen==0, update_BCNTIM, tim=%x\n", pstapriv->tim_bitmap); */ + /* upate BCN for TIM IE */ + /* update_BCNTIM(padapter); */ + update_mask = BIT(0); + } + + pstapriv->tim_bitmap &= ~BIT(psta->aid); + + if (psta->state & WIFI_SLEEP_STATE) + psta->state ^= WIFI_SLEEP_STATE; + + if (psta->state & WIFI_STA_ALIVE_CHK_STATE) { + RTW_INFO("%s alive check\n", __func__); + psta->expire_to = pstapriv->expire_to; + psta->state ^= WIFI_STA_ALIVE_CHK_STATE; + } + + pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); + } + + /* for BC/MC Frames */ + if (!psta_bmc) + goto _exit; + + if ((pstapriv->sta_dz_bitmap & 0xfffe) == 0x0) { /* no any sta in ps mode */ + xmitframe_phead = get_list_head(&psta_bmc->sleep_q); + xmitframe_plist = get_next(xmitframe_phead); + + while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) { + pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); + + xmitframe_plist = get_next(xmitframe_plist); + + rtw_list_delete(&pxmitframe->list); + + psta_bmc->sleepq_len--; + if (psta_bmc->sleepq_len > 0) + pxmitframe->attrib.mdata = 1; + else + pxmitframe->attrib.mdata = 0; + + + pxmitframe->attrib.triggered = 1; + /* + _exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL); + if(rtw_hal_xmit(padapter, pxmitframe) == _TRUE) + { + rtw_os_xmit_complete(padapter, pxmitframe); + } + _enter_critical_bh(&psta_bmc->sleep_q.lock, &irqL); + + */ + rtw_hal_xmitframe_enqueue(padapter, pxmitframe); + + } + + if (psta_bmc->sleepq_len == 0) { + if (pstapriv->tim_bitmap & BIT(0)) { + /* RTW_INFO("wakeup to xmit, qlen==0, update_BCNTIM, tim=%x\n", pstapriv->tim_bitmap); */ + /* upate BCN for TIM IE */ + /* update_BCNTIM(padapter); */ + update_mask |= BIT(1); + } + pstapriv->tim_bitmap &= ~BIT(0); + pstapriv->sta_dz_bitmap &= ~BIT(0); + } + + } + +_exit: + + /* _exit_critical_bh(&psta_bmc->sleep_q.lock, &irqL); */ + _exit_critical_bh(&pxmitpriv->lock, &irqL); + + if (update_mask) { + /* update_BCNTIM(padapter); */ + if ((update_mask & (BIT(0) | BIT(1))) == (BIT(0) | BIT(1))) + _update_beacon(padapter, _TIM_IE_, NULL, _TRUE, "clear UC&BMC"); + else if ((update_mask & BIT(1)) == BIT(1)) + _update_beacon(padapter, _TIM_IE_, NULL, _TRUE, "clear BMC"); + else + _update_beacon(padapter, _TIM_IE_, NULL, _TRUE, "clear UC"); + } + +} + +void xmit_delivery_enabled_frames(_adapter *padapter, struct sta_info *psta) +{ + _irqL irqL; + u8 wmmps_ac = 0; + _list *xmitframe_plist, *xmitframe_phead; + struct xmit_frame *pxmitframe = NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + + /* _enter_critical_bh(&psta->sleep_q.lock, &irqL); */ + _enter_critical_bh(&pxmitpriv->lock, &irqL); + + xmitframe_phead = get_list_head(&psta->sleep_q); + xmitframe_plist = get_next(xmitframe_phead); + + while ((rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist)) == _FALSE) { + pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); + + xmitframe_plist = get_next(xmitframe_plist); + + switch (pxmitframe->attrib.priority) { + case 1: + case 2: + wmmps_ac = psta->uapsd_bk & BIT(1); + break; + case 4: + case 5: + wmmps_ac = psta->uapsd_vi & BIT(1); + break; + case 6: + case 7: + wmmps_ac = psta->uapsd_vo & BIT(1); + break; + case 0: + case 3: + default: + wmmps_ac = psta->uapsd_be & BIT(1); + break; + } + + if (!wmmps_ac) + continue; + + rtw_list_delete(&pxmitframe->list); + + psta->sleepq_len--; + psta->sleepq_ac_len--; + + if (psta->sleepq_ac_len > 0) { + pxmitframe->attrib.mdata = 1; + pxmitframe->attrib.eosp = 0; + } else { + pxmitframe->attrib.mdata = 0; + pxmitframe->attrib.eosp = 1; + } + + pxmitframe->attrib.triggered = 1; + rtw_hal_xmitframe_enqueue(padapter, pxmitframe); + + if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) && (wmmps_ac)) { +#ifdef CONFIG_TDLS + if (psta->tdls_sta_state & TDLS_LINKED_STATE) { + /* _exit_critical_bh(&psta->sleep_q.lock, &irqL); */ + goto exit; + } +#endif /* CONFIG_TDLS */ + pstapriv->tim_bitmap &= ~BIT(psta->aid); + + /* RTW_INFO("wakeup to xmit, qlen==0, update_BCNTIM, tim=%x\n", pstapriv->tim_bitmap); */ + /* upate BCN for TIM IE */ + /* update_BCNTIM(padapter); */ + update_beacon(padapter, _TIM_IE_, NULL, _TRUE); + /* update_mask = BIT(0); */ + } + + } + +exit: + /* _exit_critical_bh(&psta->sleep_q.lock, &irqL); */ + _exit_critical_bh(&pxmitpriv->lock, &irqL); + + return; +} + +#endif /* defined(CONFIG_AP_MODE) || defined(CONFIG_TDLS) */ + +#ifdef CONFIG_XMIT_THREAD_MODE +void enqueue_pending_xmitbuf( + struct xmit_priv *pxmitpriv, + struct xmit_buf *pxmitbuf) +{ + _irqL irql; + _queue *pqueue; + _adapter *pri_adapter = pxmitpriv->adapter; + + pqueue = &pxmitpriv->pending_xmitbuf_queue; + + _enter_critical_bh(&pqueue->lock, &irql); + rtw_list_delete(&pxmitbuf->list); + rtw_list_insert_tail(&pxmitbuf->list, get_list_head(pqueue)); + _exit_critical_bh(&pqueue->lock, &irql); + +#if defined(CONFIG_SDIO_HCI) && defined(CONFIG_CONCURRENT_MODE) + pri_adapter = GET_PRIMARY_ADAPTER(pri_adapter); +#endif /*SDIO_HCI + CONCURRENT*/ + _rtw_up_sema(&(pri_adapter->xmitpriv.xmit_sema)); +} + +void enqueue_pending_xmitbuf_to_head( + struct xmit_priv *pxmitpriv, + struct xmit_buf *pxmitbuf) +{ + _irqL irql; + _queue *pqueue = &pxmitpriv->pending_xmitbuf_queue; + + _enter_critical_bh(&pqueue->lock, &irql); + rtw_list_delete(&pxmitbuf->list); + rtw_list_insert_head(&pxmitbuf->list, get_list_head(pqueue)); + _exit_critical_bh(&pqueue->lock, &irql); +} + +struct xmit_buf *dequeue_pending_xmitbuf( + struct xmit_priv *pxmitpriv) +{ + _irqL irql; + struct xmit_buf *pxmitbuf; + _queue *pqueue; + + + pxmitbuf = NULL; + pqueue = &pxmitpriv->pending_xmitbuf_queue; + + _enter_critical_bh(&pqueue->lock, &irql); + + if (_rtw_queue_empty(pqueue) == _FALSE) { + _list *plist, *phead; + + phead = get_list_head(pqueue); + plist = get_next(phead); + pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); + rtw_list_delete(&pxmitbuf->list); + } + + _exit_critical_bh(&pqueue->lock, &irql); + + return pxmitbuf; +} + +static struct xmit_buf *dequeue_pending_xmitbuf_under_survey( + struct xmit_priv *pxmitpriv) +{ + _irqL irql; + struct xmit_buf *pxmitbuf; +#ifdef CONFIG_USB_HCI + struct xmit_frame *pxmitframe; +#endif + _queue *pqueue; + + + pxmitbuf = NULL; + pqueue = &pxmitpriv->pending_xmitbuf_queue; + + _enter_critical_bh(&pqueue->lock, &irql); + + if (_rtw_queue_empty(pqueue) == _FALSE) { + _list *plist, *phead; + u8 type = 0; + + phead = get_list_head(pqueue); + plist = phead; + do { + plist = get_next(plist); + if (plist == phead) + break; + + pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); + +#ifdef CONFIG_USB_HCI + pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; + if (pxmitframe) + type = get_frame_sub_type(pxmitbuf->pbuf + TXDESC_SIZE + pxmitframe->pkt_offset * PACKET_OFFSET_SZ); + else + RTW_INFO("%s, !!!ERROR!!! For USB, TODO ITEM\n", __FUNCTION__); +#else + type = get_frame_sub_type(pxmitbuf->pbuf + TXDESC_OFFSET); +#endif + + if ((type == WIFI_PROBEREQ) || + (type == WIFI_DATA_NULL) || + (type == WIFI_QOS_DATA_NULL)) { + rtw_list_delete(&pxmitbuf->list); + break; + } + pxmitbuf = NULL; + } while (1); + } + + _exit_critical_bh(&pqueue->lock, &irql); + + return pxmitbuf; +} + +static struct xmit_buf *dequeue_pending_xmitbuf_ext( + struct xmit_priv *pxmitpriv) +{ + _irqL irql; + struct xmit_buf *pxmitbuf; + _queue *pqueue; + + pxmitbuf = NULL; + pqueue = &pxmitpriv->pending_xmitbuf_queue; + + _enter_critical_bh(&pqueue->lock, &irql); + + if (_rtw_queue_empty(pqueue) == _FALSE) { + _list *plist, *phead; + u8 type = 0; + + phead = get_list_head(pqueue); + plist = phead; + do { + plist = get_next(plist); + if (plist == phead) + break; + + pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); + + if (pxmitbuf->buf_tag == XMITBUF_MGNT) { + rtw_list_delete(&pxmitbuf->list); + break; + } + pxmitbuf = NULL; + } while (1); + } + + _exit_critical_bh(&pqueue->lock, &irql); + + return pxmitbuf; +} + +struct xmit_buf *select_and_dequeue_pending_xmitbuf(_adapter *padapter) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct xmit_buf *pxmitbuf = NULL; + + if (rtw_xmit_ac_blocked(padapter) == _TRUE) + pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv); + else { + pxmitbuf = dequeue_pending_xmitbuf_ext(pxmitpriv); + if (pxmitbuf == NULL) + pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv); + } + + return pxmitbuf; +} + +sint check_pending_xmitbuf( + struct xmit_priv *pxmitpriv) +{ + _irqL irql; + _queue *pqueue; + sint ret = _FALSE; + + pqueue = &pxmitpriv->pending_xmitbuf_queue; + + _enter_critical_bh(&pqueue->lock, &irql); + + if (_rtw_queue_empty(pqueue) == _FALSE) + ret = _TRUE; + + _exit_critical_bh(&pqueue->lock, &irql); + + return ret; +} + +thread_return rtw_xmit_thread(thread_context context) +{ + s32 err; + PADAPTER padapter; + + + err = _SUCCESS; + padapter = (PADAPTER)context; + + thread_enter("RTW_XMIT_THREAD"); + + do { + err = rtw_hal_xmit_thread_handler(padapter); + flush_signals_thread(); + } while (_SUCCESS == err); + + _rtw_up_sema(&padapter->xmitpriv.terminate_xmitthread_sema); + + thread_exit(); +} +#endif + +bool rtw_xmit_ac_blocked(_adapter *adapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + _adapter *iface; + struct mlme_ext_priv *mlmeext; + struct mlme_ext_info *mlmeextinfo; + bool blocked = _FALSE; + int i; + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + mlmeext = &iface->mlmeextpriv; + + /* check scan state */ + if (mlmeext_scan_state(mlmeext) != SCAN_DISABLE + && mlmeext_scan_state(mlmeext) != SCAN_BACK_OP + ) { + blocked = _TRUE; + goto exit; + } + + if (mlmeext_scan_state(mlmeext) == SCAN_BACK_OP + && !mlmeext_chk_scan_backop_flags(mlmeext, SS_BACKOP_TX_RESUME) + ) { + blocked = _TRUE; + goto exit; + } + } + +#ifdef CONFIG_MCC_MODE + if (MCC_EN(adapter)) { + if (rtw_hal_check_mcc_status(adapter, MCC_STATUS_DOING_MCC)) { + if (MCC_STOP(adapter)) { + blocked = _TRUE; + goto exit; + } + } + } +#endif /* CONFIG_MCC_MODE */ + +exit: + return blocked; +} + +#ifdef CONFIG_TX_AMSDU +void rtw_amsdu_vo_timeout_handler(void *FunctionContext) +{ + _adapter *adapter = (_adapter *)FunctionContext; + + adapter->xmitpriv.amsdu_vo_timeout = RTW_AMSDU_TIMER_TIMEOUT; + + tasklet_hi_schedule(&adapter->xmitpriv.xmit_tasklet); +} + +void rtw_amsdu_vi_timeout_handler(void *FunctionContext) +{ + _adapter *adapter = (_adapter *)FunctionContext; + + adapter->xmitpriv.amsdu_vi_timeout = RTW_AMSDU_TIMER_TIMEOUT; + + tasklet_hi_schedule(&adapter->xmitpriv.xmit_tasklet); +} + +void rtw_amsdu_be_timeout_handler(void *FunctionContext) +{ + _adapter *adapter = (_adapter *)FunctionContext; + + adapter->xmitpriv.amsdu_be_timeout = RTW_AMSDU_TIMER_TIMEOUT; + + if (printk_ratelimit()) + RTW_INFO("%s Timeout!\n",__FUNCTION__); + + tasklet_hi_schedule(&adapter->xmitpriv.xmit_tasklet); +} + +void rtw_amsdu_bk_timeout_handler(void *FunctionContext) +{ + _adapter *adapter = (_adapter *)FunctionContext; + + adapter->xmitpriv.amsdu_bk_timeout = RTW_AMSDU_TIMER_TIMEOUT; + + tasklet_hi_schedule(&adapter->xmitpriv.xmit_tasklet); +} + +u8 rtw_amsdu_get_timer_status(_adapter *padapter, u8 priority) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + u8 status = RTW_AMSDU_TIMER_UNSET; + + switch(priority) + { + case 1: + case 2: + status = pxmitpriv->amsdu_bk_timeout; + break; + case 4: + case 5: + status = pxmitpriv->amsdu_vi_timeout; + break; + case 6: + case 7: + status = pxmitpriv->amsdu_vo_timeout; + break; + case 0: + case 3: + default: + status = pxmitpriv->amsdu_be_timeout; + break; + } + return status; +} + +void rtw_amsdu_set_timer_status(_adapter *padapter, u8 priority, u8 status) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + switch(priority) + { + case 1: + case 2: + pxmitpriv->amsdu_bk_timeout = status; + break; + case 4: + case 5: + pxmitpriv->amsdu_vi_timeout = status; + break; + case 6: + case 7: + pxmitpriv->amsdu_vo_timeout = status; + break; + case 0: + case 3: + default: + pxmitpriv->amsdu_be_timeout = status; + break; + } +} + +void rtw_amsdu_set_timer(_adapter *padapter, u8 priority) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + _timer* amsdu_timer = NULL; + + switch(priority) + { + case 1: + case 2: + amsdu_timer = &pxmitpriv->amsdu_bk_timer; + break; + case 4: + case 5: + amsdu_timer = &pxmitpriv->amsdu_vi_timer; + break; + case 6: + case 7: + amsdu_timer = &pxmitpriv->amsdu_vo_timer; + break; + case 0: + case 3: + default: + amsdu_timer = &pxmitpriv->amsdu_be_timer; + break; + } + _set_timer(amsdu_timer, 1); +} + +void rtw_amsdu_cancel_timer(_adapter *padapter, u8 priority) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + _timer* amsdu_timer = NULL; + u8 cancel; + + switch(priority) + { + case 1: + case 2: + amsdu_timer = &pxmitpriv->amsdu_bk_timer; + break; + case 4: + case 5: + amsdu_timer = &pxmitpriv->amsdu_vi_timer; + break; + case 6: + case 7: + amsdu_timer = &pxmitpriv->amsdu_vo_timer; + break; + case 0: + case 3: + default: + amsdu_timer = &pxmitpriv->amsdu_be_timer; + break; + } + _cancel_timer(amsdu_timer, &cancel); +} +#endif /* CONFIG_TX_AMSDU */ + +void rtw_sctx_init(struct submit_ctx *sctx, int timeout_ms) +{ + sctx->timeout_ms = timeout_ms; + sctx->submit_time = rtw_get_current_time(); +#ifdef PLATFORM_LINUX /* TODO: add condition wating interface for other os */ + init_completion(&sctx->done); +#endif + sctx->status = RTW_SCTX_SUBMITTED; +} + +int rtw_sctx_wait(struct submit_ctx *sctx, const char *msg) +{ + int ret = _FAIL; + unsigned long expire; + int status = 0; + +#ifdef PLATFORM_LINUX + expire = sctx->timeout_ms ? msecs_to_jiffies(sctx->timeout_ms) : MAX_SCHEDULE_TIMEOUT; + if (!wait_for_completion_timeout(&sctx->done, expire)) { + /* timeout, do something?? */ + status = RTW_SCTX_DONE_TIMEOUT; + RTW_INFO("%s timeout: %s\n", __func__, msg); + } else + status = sctx->status; +#endif + + if (status == RTW_SCTX_DONE_SUCCESS) + ret = _SUCCESS; + + return ret; +} + +bool rtw_sctx_chk_waring_status(int status) +{ + switch (status) { + case RTW_SCTX_DONE_UNKNOWN: + case RTW_SCTX_DONE_BUF_ALLOC: + case RTW_SCTX_DONE_BUF_FREE: + + case RTW_SCTX_DONE_DRV_STOP: + case RTW_SCTX_DONE_DEV_REMOVE: + return _TRUE; + default: + return _FALSE; + } +} + +void rtw_sctx_done_err(struct submit_ctx **sctx, int status) +{ + if (*sctx) { + if (rtw_sctx_chk_waring_status(status)) + RTW_INFO("%s status:%d\n", __func__, status); + (*sctx)->status = status; +#ifdef PLATFORM_LINUX + complete(&((*sctx)->done)); +#endif + *sctx = NULL; + } +} + +void rtw_sctx_done(struct submit_ctx **sctx) +{ + rtw_sctx_done_err(sctx, RTW_SCTX_DONE_SUCCESS); +} + +#ifdef CONFIG_XMIT_ACK +int rtw_ack_tx_wait(struct xmit_priv *pxmitpriv, u32 timeout_ms) +{ + struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; + + pack_tx_ops->submit_time = rtw_get_current_time(); + pack_tx_ops->timeout_ms = timeout_ms; + pack_tx_ops->status = RTW_SCTX_SUBMITTED; + + return rtw_sctx_wait(pack_tx_ops, __func__); +} + +void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status) +{ + struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; + + if (pxmitpriv->ack_tx) + rtw_sctx_done_err(&pack_tx_ops, status); + else + RTW_INFO("%s ack_tx not set\n", __func__); +} +#endif /* CONFIG_XMIT_ACK */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/HalPwrSeqCmd.c b/linux-bsp/drivers/rtl8188eus/hal/HalPwrSeqCmd.c new file mode 100644 index 0000000..de709b1 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/HalPwrSeqCmd.c @@ -0,0 +1,161 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +/*++ +Copyright (c) Realtek Semiconductor Corp. All rights reserved. + +Module Name: + HalPwrSeqCmd.c + +Abstract: + Implement HW Power sequence configuration CMD handling routine for Realtek devices. + +Major Change History: + When Who What + ---------- --------------- ------------------------------- + 2011-10-26 Lucas Modify to be compatible with SD4-CE driver. + 2011-07-07 Roger Create. + +--*/ +#include <HalPwrSeqCmd.h> + + +/* + * Description: + * This routine deal with the Power Configuration CMDs parsing for RTL8723/RTL8188E Series IC. + * + * Assumption: + * We should follow specific format which was released from HW SD. + * + * 2011.07.07, added by Roger. + * */ +u8 HalPwrSeqCmdParsing( + PADAPTER padapter, + u8 CutVersion, + u8 FabVersion, + u8 InterfaceType, + WLAN_PWR_CFG PwrSeqCmd[]) +{ + WLAN_PWR_CFG PwrCfgCmd = {0}; + u8 bPollingBit = _FALSE; + u32 AryIdx = 0; + u8 value = 0; + u32 offset = 0; + u32 pollingCount = 0; /* polling autoload done. */ + u32 maxPollingCnt = 5000; + + do { + PwrCfgCmd = PwrSeqCmd[AryIdx]; + + + /* 2 Only Handle the command whose FAB, CUT, and Interface are matched */ + if ((GET_PWR_CFG_FAB_MASK(PwrCfgCmd) & FabVersion) && + (GET_PWR_CFG_CUT_MASK(PwrCfgCmd) & CutVersion) && + (GET_PWR_CFG_INTF_MASK(PwrCfgCmd) & InterfaceType)) { + switch (GET_PWR_CFG_CMD(PwrCfgCmd)) { + case PWR_CMD_READ: + break; + + case PWR_CMD_WRITE: + offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); + +#ifdef CONFIG_SDIO_HCI + /* */ + /* <Roger_Notes> We should deal with interface specific address mapping for some interfaces, e.g., SDIO interface */ + /* 2011.07.07. */ + /* */ + if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) { + /* Read Back SDIO Local value */ + value = SdioLocalCmd52Read1Byte(padapter, offset); + + value &= ~(GET_PWR_CFG_MASK(PwrCfgCmd)); + value |= (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd)); + + /* Write Back SDIO Local value */ + SdioLocalCmd52Write1Byte(padapter, offset, value); + } else +#endif + { +#ifdef CONFIG_GSPI_HCI + if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) + offset = SPI_LOCAL_OFFSET | offset; +#endif + /* Read the value from system register */ + value = rtw_read8(padapter, offset); + + value = value & (~(GET_PWR_CFG_MASK(PwrCfgCmd))); + value = value | (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd)); + + /* Write the value back to sytem register */ + rtw_write8(padapter, offset, value); + } + break; + + case PWR_CMD_POLLING: + + bPollingBit = _FALSE; + offset = GET_PWR_CFG_OFFSET(PwrCfgCmd); +#ifdef CONFIG_GSPI_HCI + if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) + offset = SPI_LOCAL_OFFSET | offset; +#endif + do { +#ifdef CONFIG_SDIO_HCI + if (GET_PWR_CFG_BASE(PwrCfgCmd) == PWR_BASEADDR_SDIO) + value = SdioLocalCmd52Read1Byte(padapter, offset); + else +#endif + value = rtw_read8(padapter, offset); + + value = value & GET_PWR_CFG_MASK(PwrCfgCmd); + if (value == (GET_PWR_CFG_VALUE(PwrCfgCmd) & GET_PWR_CFG_MASK(PwrCfgCmd))) + bPollingBit = _TRUE; + else + rtw_udelay_os(10); + + if (pollingCount++ > maxPollingCnt) { + RTW_ERR("HalPwrSeqCmdParsing: Fail to polling Offset[%#x]=%02x\n", offset, value); + return _FALSE; + } + } while (!bPollingBit); + + break; + + case PWR_CMD_DELAY: + if (GET_PWR_CFG_VALUE(PwrCfgCmd) == PWRSEQ_DELAY_US) + rtw_udelay_os(GET_PWR_CFG_OFFSET(PwrCfgCmd)); + else + rtw_udelay_os(GET_PWR_CFG_OFFSET(PwrCfgCmd) * 1000); + break; + + case PWR_CMD_END: + /* When this command is parsed, end the process */ + return _TRUE; + break; + + default: + break; + } + } + + AryIdx++;/* Add Array Index */ + } while (1); + + return _TRUE; +} diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8188c2Ant.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8188c2Ant.c new file mode 100644 index 0000000..e198992 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8188c2Ant.c @@ -0,0 +1,2053 @@ +//============================================================ +// Description: +// +// This file is for 92CE/92CU BT 1 Antenna Co-exist mechanism +// +// By cosa 02/11/2011 +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8188C_2ANT GLCoexDm8188c2Ant; +static PCOEX_DM_8188C_2ANT pCoexDm=&GLCoexDm8188c2Ant; +static COEX_STA_8188C_2ANT GLCoexSta8188c2Ant; +static PCOEX_STA_8188C_2ANT pCoexSta=&GLCoexSta8188c2Ant; + +//============================================================ +// local function start with btdm_ +//============================================================ +u1Byte +halbtc8188c2ant_WifiRssiState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte index, + IN u1Byte levelNum, + IN u1Byte rssiThresh, + IN u1Byte rssiThresh1 + ) +{ + s4Byte wifiRssi=0; + u1Byte wifiRssiState=pCoexSta->preWifiRssiState[index]; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(levelNum == 2) + { + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8188C_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return pCoexSta->preWifiRssiState[index]; + } + + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8188C_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8188C_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifiRssi < rssiThresh1) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + pCoexSta->preWifiRssiState[index] = wifiRssiState; + + return wifiRssiState; +} + +u1Byte +halbtc8188c2ant_ActionAlgorithm( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + u1Byte algorithm=BT_8188C_2ANT_COEX_ALGO_UNDEFINED; + u1Byte numOfDiffProfile=0; + + if(!pStackInfo->bBtLinkExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No profile exists!!!\n")); + return algorithm; + } + + if(pStackInfo->bScoExist) + numOfDiffProfile++; + if(pStackInfo->bHidExist) + numOfDiffProfile++; + if(pStackInfo->bPanExist) + numOfDiffProfile++; + if(pStackInfo->bA2dpExist) + numOfDiffProfile++; + + if(pStackInfo->bScoExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO algorithm\n")); + algorithm = BT_8188C_2ANT_COEX_ALGO_SCO; + } + else + { + if(numOfDiffProfile == 1) + { + if(pStackInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n")); + algorithm = BT_8188C_2ANT_COEX_ALGO_HID; + } + else if(pStackInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n")); + algorithm = BT_8188C_2ANT_COEX_ALGO_A2DP; + } + else if(pStackInfo->bPanExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN only\n")); + algorithm = BT_8188C_2ANT_COEX_ALGO_PAN; + } + } + else + { + if( pStackInfo->bHidExist && + pStackInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_8188C_2ANT_COEX_ALGO_HID_A2DP; + } + else if( pStackInfo->bHidExist && + pStackInfo->bPanExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN\n")); + algorithm = BT_8188C_2ANT_COEX_ALGO_HID_PAN; + } + else if( pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN + A2DP\n")); + algorithm = BT_8188C_2ANT_COEX_ALGO_PAN_A2DP; + } + } + } + return algorithm; +} + +VOID +halbtc8188c2ant_SetFwBalance( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bBalanceOn, + IN u1Byte ms0, + IN u1Byte ms1 + ) +{ + u1Byte H2C_Parameter[3] ={0}; + + if(bBalanceOn) + { + H2C_Parameter[2] = 1; + H2C_Parameter[1] = ms1; + H2C_Parameter[0] = ms0; + } + else + { + H2C_Parameter[2] = 0; + H2C_Parameter[1] = 0; + H2C_Parameter[0] = 0; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Balance=[%s:%dms:%dms], write 0xc=0x%x\n", + bBalanceOn?"ON":"OFF", ms0, ms1, + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0xc, 3, H2C_Parameter); +} + +VOID +halbtc8188c2ant_Balance( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bBalanceOn, + IN u1Byte ms0, + IN u1Byte ms1 + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Balance %s\n", + (bForceExec? "force to":""), (bBalanceOn? "ON":"OFF"))); + pCoexDm->bCurBalanceOn = bBalanceOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBalanceOn = %d, bCurBalanceOn = %d!!\n", + pCoexDm->bPreBalanceOn, pCoexDm->bCurBalanceOn)); + + if(pCoexDm->bPreBalanceOn == pCoexDm->bCurBalanceOn) + return; + } + halbtc8188c2ant_SetFwBalance(pBtCoexist, bBalanceOn, ms0, ms1); + + pCoexDm->bPreBalanceOn = pCoexDm->bCurBalanceOn; +} + +VOID +halbtc8188c2ant_SetFwDiminishWifi( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bDacOn, + IN BOOLEAN bInterruptOn, + IN u1Byte fwDacSwingLvl, + IN BOOLEAN bNavOn + ) +{ + u1Byte H2C_Parameter[3] ={0}; + + if((pBtCoexist->stackInfo.minBtRssi <= -5) && (fwDacSwingLvl == 0x20)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], DiminishWiFi 0x20 original, but set 0x18 for Low RSSI!\n")); + fwDacSwingLvl = 0x18; + } + + H2C_Parameter[2] = 0; + H2C_Parameter[1] = fwDacSwingLvl; + H2C_Parameter[0] = 0; + if(bDacOn) + { + H2C_Parameter[2] |= 0x01; //BIT0 + if(bInterruptOn) + { + H2C_Parameter[2] |= 0x02; //BIT1 + } + } + if(bNavOn) + { + H2C_Parameter[2] |= 0x08; //BIT3 + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], bDacOn=%s, bInterruptOn=%s, bNavOn=%s, write 0xe=0x%x\n", + (bDacOn?"ON":"OFF"), (bInterruptOn?"ON":"OFF"), (bNavOn?"ON":"OFF"), + (H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2]))); + pBtCoexist->fBtcFillH2c(pBtCoexist, 0xe, 3, H2C_Parameter); +} + +VOID +halbtc8188c2ant_DiminishWifi( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDacOn, + IN BOOLEAN bInterruptOn, + IN u1Byte fwDacSwingLvl, + IN BOOLEAN bNavOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set Diminish Wifi, bDacOn=%s, bInterruptOn=%s, fwDacSwingLvl=%d, bNavOn=%s\n", + (bForceExec? "force to":""), (bDacOn? "ON":"OFF"), (bInterruptOn? "ON":"OFF"), fwDacSwingLvl, (bNavOn? "ON":"OFF"))); + + pCoexDm->bCurDacOn = bDacOn; + pCoexDm->bCurInterruptOn = bInterruptOn; + pCoexDm->curFwDacSwingLvl = fwDacSwingLvl; + pCoexDm->bCurNavOn = bNavOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreDacOn=%d, bCurDacOn=%d!!\n", + pCoexDm->bPreDacOn, pCoexDm->bCurDacOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreInterruptOn=%d, bCurInterruptOn=%d!!\n", + pCoexDm->bPreInterruptOn, pCoexDm->bCurInterruptOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preFwDacSwingLvl=%d, curFwDacSwingLvl=%d!!\n", + pCoexDm->preFwDacSwingLvl, pCoexDm->curFwDacSwingLvl)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreNavOn=%d, bCurNavOn=%d!!\n", + pCoexDm->bPreNavOn, pCoexDm->bCurNavOn)); + + + if( (pCoexDm->bPreDacOn==pCoexDm->bCurDacOn) && + (pCoexDm->bPreInterruptOn==pCoexDm->bCurInterruptOn) && + (pCoexDm->preFwDacSwingLvl==pCoexDm->curFwDacSwingLvl) && + (pCoexDm->bPreNavOn==pCoexDm->bCurNavOn) ) + return; + } + halbtc8188c2ant_SetFwDiminishWifi(pBtCoexist, bDacOn, bInterruptOn, fwDacSwingLvl, bNavOn); + + pCoexDm->bPreDacOn = pCoexDm->bCurDacOn; + pCoexDm->bPreInterruptOn = pCoexDm->bCurInterruptOn; + pCoexDm->preFwDacSwingLvl = pCoexDm->curFwDacSwingLvl; + pCoexDm->bPreNavOn = pCoexDm->bCurNavOn; +} + +VOID +halbtc8188c2ant_SetSwRfRxLpfCorner( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bRxRfShrinkOn + ) +{ + if(bRxRfShrinkOn) + { + //Shrink RF Rx LPF corner + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Shrink RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xf0, 0xf); + } + else + { + //Resume RF Rx LPF corner + // After initialized, we can use pCoexDm->btRf0x1eBackup + if(pBtCoexist->bInitilized) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xf0, pCoexDm->btRf0x1eBackup); + } + } +} + +VOID +halbtc8188c2ant_RfShrink( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRxRfShrinkOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn Rx RF Shrink = %s\n", + (bForceExec? "force to":""), ((bRxRfShrinkOn)? "ON":"OFF"))); + pCoexDm->bCurRfRxLpfShrink = bRxRfShrinkOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreRfRxLpfShrink=%d, bCurRfRxLpfShrink=%d\n", + pCoexDm->bPreRfRxLpfShrink, pCoexDm->bCurRfRxLpfShrink)); + + if(pCoexDm->bPreRfRxLpfShrink == pCoexDm->bCurRfRxLpfShrink) + return; + } + halbtc8188c2ant_SetSwRfRxLpfCorner(pBtCoexist, pCoexDm->bCurRfRxLpfShrink); + + pCoexDm->bPreRfRxLpfShrink = pCoexDm->bCurRfRxLpfShrink; +} + +VOID +halbtc8188c2ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte tmpU1; + + tmpU1 = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x4fd); + if(bLowPenaltyRa) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set low penalty!!\n")); + tmpU1 &= ~BIT2; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set normal!!\n")); + tmpU1 |= BIT2; + } + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x4fd, tmpU1); +} + +VOID +halbtc8188c2ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); + + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8188c2ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8188c2ant_SetSwFullTimeDacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bSwDacSwingOn, + IN u4Byte swDacSwingLvl + ) +{ + u4Byte dacSwingLvl; + + if(bSwDacSwingOn) + { + if((pBtCoexist->stackInfo.minBtRssi <= -5) && (swDacSwingLvl == 0x20)) + { + dacSwingLvl = 0x18; + } + else + { + dacSwingLvl = swDacSwingLvl; + } + pBtCoexist->fBtcSetBbReg(pBtCoexist, 0x880, 0xfc000000, dacSwingLvl); + } + else + { + pBtCoexist->fBtcSetBbReg(pBtCoexist, 0x880, 0xfc000000, 0x30); + } +} + +VOID +halbtc8188c2ant_DacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDacSwingOn, + IN u4Byte dacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn DacSwing=%s, dacSwingLvl=0x%x\n", + (bForceExec? "force to":""), ((bDacSwingOn)? "ON":"OFF"), dacSwingLvl)); + pCoexDm->bCurDacSwingOn = bDacSwingOn; + pCoexDm->curDacSwingLvl = dacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x, bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + pCoexDm->bPreDacSwingOn, pCoexDm->preDacSwingLvl, + pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl)); + + if( (pCoexDm->bPreDacSwingOn == pCoexDm->bCurDacSwingOn) && + (pCoexDm->preDacSwingLvl == pCoexDm->curDacSwingLvl) ) + return; + } + delay_ms(30); + halbtc8188c2ant_SetSwFullTimeDacSwing(pBtCoexist, bDacSwingOn, dacSwingLvl); + + pCoexDm->bPreDacSwingOn = pCoexDm->bCurDacSwingOn; + pCoexDm->preDacSwingLvl = pCoexDm->curDacSwingLvl; +} + +VOID +halbtc8188c2ant_SetAdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAdcBackOff + ) +{ + if(bAdcBackOff) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level On!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc04,0x3a07611); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level Off!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc04,0x3a05611); + } +} + +VOID +halbtc8188c2ant_AdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAdcBackOff + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn AdcBackOff = %s\n", + (bForceExec? "force to":""), ((bAdcBackOff)? "ON":"OFF"))); + pCoexDm->bCurAdcBackOff = bAdcBackOff; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAdcBackOff=%d, bCurAdcBackOff=%d\n", + pCoexDm->bPreAdcBackOff, pCoexDm->bCurAdcBackOff)); + + if(pCoexDm->bPreAdcBackOff == pCoexDm->bCurAdcBackOff) + return; + } + halbtc8188c2ant_SetAdcBackOff(pBtCoexist, pCoexDm->bCurAdcBackOff); + + pCoexDm->bPreAdcBackOff = pCoexDm->bCurAdcBackOff; +} + +VOID +halbtc8188c2ant_SetAgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAgcTableEn + ) +{ + u1Byte rssiAdjustVal=0; + + if(bAgcTableEn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x4e1c0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x4d1d0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x4c1e0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x4b1f0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x4a200001); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0xdc000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x90000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x51000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x12000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1a, 0xfffff, 0x00255); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x641c0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x631d0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x621e0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x611f0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x60200001); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x32000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x71000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0xb0000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0xfc000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1a, 0xfffff, 0x10255); + } + + // set rssiAdjustVal for wifi module. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, &rssiAdjustVal); +} + + +VOID +halbtc8188c2ant_AgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAgcTableEn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s %s Agc Table\n", + (bForceExec? "force to":""), ((bAgcTableEn)? "Enable":"Disable"))); + pCoexDm->bCurAgcTableEn = bAgcTableEn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + pCoexDm->bPreAgcTableEn, pCoexDm->bCurAgcTableEn)); + + if(pCoexDm->bPreAgcTableEn == pCoexDm->bCurAgcTableEn) + return; + } + halbtc8188c2ant_SetAgcTable(pBtCoexist, bAgcTableEn); + + pCoexDm->bPreAgcTableEn = pCoexDm->bCurAgcTableEn; +} + +VOID +halbtc8188c2ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u4Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8188c2ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u4Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c4, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c4 = val0x6c4; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c4=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + pCoexDm->preVal0x6c4, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c4=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + pCoexDm->curVal0x6c4, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8188c2ant_SetCoexTable(pBtCoexist, val0x6c4, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c4 = pCoexDm->curVal0x6c4; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8188c2ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + // fw mechanism + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); +} +VOID +halbtc8188c2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + + +VOID +halbtc8188c2ant_MonitorBtState( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN stateChange=FALSE; + u4Byte BT_Polling, Ratio_Act, Ratio_STA; + u4Byte BT_Active, BT_State; + u4Byte regBTActive=0, regBTState=0, regBTPolling=0; + u4Byte btBusyThresh=0; + u4Byte fwVer=0; + static BOOLEAN bBtBusyTraffic=FALSE; + BOOLEAN bRejApAggPkt=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], FirmwareVersion = 0x%x(%d)\n", fwVer, fwVer)); + if(fwVer < 62) + { + regBTActive = 0x488; + regBTState = 0x48c; + regBTPolling = 0x490; + } + else + { + regBTActive = 0x444; + regBTState = 0x448; + if(fwVer >= 74) + regBTPolling = 0x44c; + else + regBTPolling = 0x700; + } + btBusyThresh = 60; + + BT_Active = pBtCoexist->fBtcRead4Byte(pBtCoexist, regBTActive); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT_Active(0x%x)=0x%x\n", regBTActive, BT_Active)); + BT_Active = BT_Active & 0x00ffffff; + + BT_State = pBtCoexist->fBtcRead4Byte(pBtCoexist, regBTState); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT_State(0x%x)=0x%x\n", regBTState, BT_State)); + BT_State = BT_State & 0x00ffffff; + + BT_Polling = pBtCoexist->fBtcRead4Byte(pBtCoexist, regBTPolling); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT_Polling(0x%x)=0x%x\n", regBTPolling, BT_Polling)); + + if(BT_Active==0xffffffff && BT_State==0xffffffff && BT_Polling==0xffffffff ) + return; + + // 2011/05/04 MH For Slim combo test meet a problem. Surprise remove and WLAN is running + // DHCP process. At the same time, the register read value might be zero. And cause BSOD 0x7f + // EXCEPTION_DIVIDED_BY_ZERO. In This case, the stack content may always be wrong due to + // HW divide trap. + if (BT_Polling==0) + return; + + Ratio_Act = BT_Active*1000/BT_Polling; + Ratio_STA = BT_State*1000/BT_Polling; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Ratio_Act=%d\n", Ratio_Act)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Ratio_STA=%d\n", Ratio_STA)); + + if(BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) + { + if(Ratio_STA < 60) // BT PAN idle + { + } + else + { + // Check if BT PAN (under BT 2.1) is uplink or downlink + if((Ratio_Act/Ratio_STA) < 2) + { // BT PAN Uplink + pCoexSta->bBtUplink = TRUE; + } + else + { // BT PAN downlink + pCoexSta->bBtUplink = FALSE; + } + } + } + + // Check BT is idle or not + if(!pBtCoexist->stackInfo.bBtLinkExist) + { + pCoexSta->bBtBusy = FALSE; + } + else + { + if(BTC_CHIP_CSR_BC4 == pBtCoexist->boardInfo.btChipType) + { + if(Ratio_Act<20) + { + pCoexSta->bBtBusy = FALSE; + } + else + { + pCoexSta->bBtBusy = TRUE; + } + } + else if(BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) + { + if(Ratio_STA < btBusyThresh) + { + pCoexSta->bBtBusy = FALSE; + } + else + { + pCoexSta->bBtBusy = TRUE; + } + + if( (Ratio_STA < btBusyThresh) || + (Ratio_Act<180 && Ratio_STA<130) ) + { + pCoexSta->bA2dpBusy = FALSE; + } + else + { + pCoexSta->bA2dpBusy = TRUE; + } + } + } + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &pCoexSta->bBtBusy); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_LIMITED_DIG, &pCoexSta->bBtBusy); + + if(bBtBusyTraffic != pCoexSta->bBtBusy) + { // BT idle or BT non-idle + bBtBusyTraffic = pCoexSta->bBtBusy; + stateChange = TRUE; + } + + if(stateChange) + { + if(!pCoexSta->bBtBusy) + { + halbtc8188c2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_CoexAllOff(pBtCoexist); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x0); + } + else + { + halbtc8188c2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_RfShrink(pBtCoexist, NORMAL_EXEC, TRUE); + } + } + + if(stateChange) + { + bRejApAggPkt = pCoexSta->bBtBusy; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &bRejApAggPkt); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + } +} + +VOID +halbtc8188c2ant_ActionA2dpBc4( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw, wifiTrafficDir; + + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x0); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + + if(pCoexSta->bBtBusy) + { + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism first + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0xc, 0x18); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x20, FALSE); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + } + + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x20); + } + else + { + wifiRssiState = halbtc8188c2ant_WifiRssiState(pBtCoexist, 0, 2, 47, 0); + + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0xc, 0x18); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x20, FALSE); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x20); + } + else + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x20); + } + } + } + else + { + halbtc8188c2ant_CoexAllOff(pBtCoexist); + } +} + +VOID +halbtc8188c2ant_ActionA2dpBc8( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw, wifiTrafficDir; + BOOLEAN bWifiBusy=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + if(pCoexSta->bA2dpBusy && bWifiBusy) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + wifiRssiState = halbtc8188c2ant_WifiRssiState(pBtCoexist, 0, 2, 47, 0); + + // fw mechanism first + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0xc, 0x18); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x10, 0x18); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + } + else if(pCoexSta->bA2dpBusy) + { + // fw mechanism first + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, TRUE, 0x18, FALSE); + + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8188c2ant_CoexAllOff(pBtCoexist); + } +} + +VOID +halbtc8188c2ant_ActionA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + if(BTC_CHIP_CSR_BC4 == pBtCoexist->boardInfo.btChipType) + { + halbtc8188c2ant_ActionA2dpBc4(pBtCoexist); + } + else if(BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) + { + halbtc8188c2ant_ActionA2dpBc8(pBtCoexist); + } +} + +VOID +halbtc8188c2ant_ActionPanBc4( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x0); + if(bBtHsOn) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + } + else + { + if(pCoexSta->bBtBusy && bWifiBusy) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x20, 0x10); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + else + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + } + } + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); +} + +VOID +halbtc8188c2ant_ActionPanBc8( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + u1Byte wifiRssiState; + u4Byte wifiBw, wifiTrafficDir; + s4Byte wifiRssi; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(bBtHsOn) + { + halbtc8188c2ant_CoexAllOff(pBtCoexist); + } + else + { + wifiRssiState = halbtc8188c2ant_WifiRssiState(pBtCoexist, 0, 3, 25, 50); + + if(pCoexSta->bBtBusy && bWifiBusy) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + // fw mechanism first + if(pCoexSta->bBtUplink) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x20, 0x20); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + else + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + } + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + } + else + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + } + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + if(pCoexSta->bBtUplink) + { + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x20); + } + } + else if( (wifiRssiState == BTC_RSSI_STATE_MEDIUM) || + (wifiRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + // fw mechanism first + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x20, 0x20); + + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + if(BTC_WIFI_BW_HT40 == wifiBw) + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE);//BT_FW_NAV_ON); + else + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + } + else + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + } + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + // fw mechanism first + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x20, 0x20); + + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + if(pCoexSta->bBtUplink) + { + if(BTC_WIFI_BW_HT40 == wifiBw) + { + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE);//BT_FW_NAV_ON); + } + else + { + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + } + else + { + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + } + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + else if(pCoexSta->bBtBusy && !bWifiBusy && (wifiRssi < 30)) + { + // fw mechanism first + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x0a, 0x20); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8188c2ant_CoexAllOff(pBtCoexist); + } + } +} + +VOID +halbtc8188c2ant_ActionPan( + IN PBTC_COEXIST pBtCoexist + ) +{ + if(BTC_CHIP_CSR_BC4 == pBtCoexist->boardInfo.btChipType) + { + halbtc8188c2ant_ActionPanBc4(pBtCoexist); + } + else if(BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) + { + halbtc8188c2ant_ActionPanBc8(pBtCoexist); + } +} + +VOID +halbtc8188c2ant_ActionHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte wifiBw, wifiTrafficDir; + BOOLEAN bWifiBusy=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + if(BTC_WIFI_BW_LEGACY == wifiBw) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + + halbtc8188c2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0x000000f0, 0x40000010); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0xa0); + } + else if(!bWifiBusy) + { + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x0); + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + } + else if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + + halbtc8188c2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0x000000f0, 0x40000010); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0xa0); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x0); + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + } + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); +} + + +VOID +halbtc8188c2ant_ActionSco( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + if(BTC_CHIP_CSR_BC4 == pBtCoexist->boardInfo.btChipType) + { + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x0); + + // fw mechanism + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else if(BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism first + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + wifiRssiState = halbtc8188c2ant_WifiRssiState(pBtCoexist, 0, 2, 47, 0); + // fw mechanism first + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + } +} + +VOID +halbtc8188c2ant_ActionHidA2dpBc4( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw, wifiTrafficDir; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + + if(pCoexSta->bBtBusy) + { + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism first + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x7, 0x20); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x20, FALSE); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + } + + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x18); + } + else + { + wifiRssiState = halbtc8188c2ant_WifiRssiState(pBtCoexist, 0, 2, 47, 0); + // fw mechanism first + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x7, 0x20); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x20, FALSE); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x18); + } + else + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x18); + } + } + } + else + { + halbtc8188c2ant_CoexAllOff(pBtCoexist); + } +} +VOID +halbtc8188c2ant_ActionHidA2dpBc8( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + if(pCoexSta->bBtBusy) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism first + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x18); + } + else + { + wifiRssiState = halbtc8188c2ant_WifiRssiState(pBtCoexist, 0, 2, 47, 0); + // fw mechanism + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x18); + } + else + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x18); + } + } + } + else + { + halbtc8188c2ant_CoexAllOff(pBtCoexist); + } +} + +VOID +halbtc8188c2ant_ActionHidA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + if(BTC_CHIP_CSR_BC4 == pBtCoexist->boardInfo.btChipType) + { + halbtc8188c2ant_ActionHidA2dpBc4(pBtCoexist); + } + else if(BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) + { + halbtc8188c2ant_ActionHidA2dpBc8(pBtCoexist); + } +} + +VOID +halbtc8188c2ant_ActionHidPanBc4( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + u4Byte wifiBw, wifiTrafficDir; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(bBtHsOn) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + + halbtc8188c2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0x000000f0, 0x40000010); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0xa0); + } + else + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + if(BTC_WIFI_BW_LEGACY == wifiBw) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + + halbtc8188c2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0x000000f0, 0x40000010); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0xa0); + } + else if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + + halbtc8188c2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0x000000f0, 0x40000010); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0xa0); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x0); + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x20, 0x10); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + else if(!bWifiBusy) + { + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x0); + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + } + } + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); +} +VOID +halbtc8188c2ant_ActionHidPanBc8( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + u1Byte wifiRssiState; + u4Byte wifiBw, wifiTrafficDir; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(!bBtHsOn) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + wifiRssiState = halbtc8188c2ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + if((pCoexSta->bBtBusy && bWifiBusy)) + { + // fw mechanism first + if(pCoexSta->bBtUplink) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x15, 0x20); + } + else + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x10, 0x20); + } + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + else + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + else + { + halbtc8188c2ant_CoexAllOff(pBtCoexist); + } + } + else + { + if(BTC_INTF_USB == pBtCoexist->chipInterface) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + + halbtc8188c2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0x000000f0, 0x40000010); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0xa0); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x18); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x18); + } + } + else + { + if(pCoexSta->bBtBusy) + { + // fw mechanism + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x20); + } + else + { + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + } +} + +VOID +halbtc8188c2ant_ActionHidPan( + IN PBTC_COEXIST pBtCoexist + ) +{ + if(BTC_CHIP_CSR_BC4 == pBtCoexist->boardInfo.btChipType) + { + halbtc8188c2ant_ActionHidPanBc4(pBtCoexist); + } + else if(BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) + { + halbtc8188c2ant_ActionHidPanBc8(pBtCoexist); + } +} + +VOID +halbtc8188c2ant_ActionPanA2dpBc4( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + u1Byte wifiRssiState; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x0); + if(bBtHsOn) + { + if(pCoexSta->bBtBusy) + { + // fw mechanism + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x20); + } + else + { + halbtc8188c2ant_CoexAllOff(pBtCoexist); + } + } + else + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + if(pCoexSta->bBtBusy && bWifiBusy) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x20, 0x10); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + else + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + } + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } +} +VOID +halbtc8188c2ant_ActionPanA2dpBc8( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + u1Byte wifiRssiState; + u4Byte wifiBw; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(!bBtHsOn) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + wifiRssiState = halbtc8188c2ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + if((pCoexSta->bBtBusy && bWifiBusy)) + { + // fw mechanism first + if(pCoexSta->bBtUplink) + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x15, 0x20); + } + else + { + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x10, 0x20); + } + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + else + { + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + else + { + halbtc8188c2ant_CoexAllOff(pBtCoexist); + } + } + else + { + if(pCoexSta->bBtBusy) + { + // fw mechanism + halbtc8188c2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8188c2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + halbtc8188c2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x20); + } + else + { + halbtc8188c2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } +} + +VOID +halbtc8188c2ant_ActionPanA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + if(BTC_CHIP_CSR_BC4 == pBtCoexist->boardInfo.btChipType) + { + halbtc8188c2ant_ActionPanA2dpBc4(pBtCoexist); + } + else if(BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) + { + halbtc8188c2ant_ActionPanA2dpBc8(pBtCoexist); + } +} + +//============================================================ +// extern function start with EXhalbtc8188c2ant_ +//============================================================ +VOID +EXhalbtc8188c2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte u1Tmp=0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 2Ant Init HW Config!!\n")); + + // backup rf 0x1e value + pCoexDm->btRf0x1eBackup = + pBtCoexist->fBtcGetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xf0); + + if( (BTC_CHIP_CSR_BC4 == pBtCoexist->boardInfo.btChipType) || + (BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) ) + { + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x4fd) & BIT0; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x4fd, u1Tmp); + + halbtc8188c2ant_CoexTable(pBtCoexist, FORCE_EXEC, 0xaaaa9aaa, 0xffbd0040, 0x40000010); + } +} + +VOID +EXhalbtc8188c2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + halbtc8188c2ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8188c2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + pu1Byte cliBuf=pBtCoexist->cliBuf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir; + u1Byte wifiDot11Chnl, wifiHsChnl; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(!pBoardInfo->bBtExist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum); + CL_PRINTF(cliBuf); + + if(pBtCoexist->bManualControl) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "[Action Manual control]!!"); + CL_PRINTF(cliBuf); + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ + wifiDot11Chnl, wifiHsChnl, bBtHsOn); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + + if(pStackInfo->bProfileNotified) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pStackInfo->bScoExist, pStackInfo->bHidExist, pStackInfo->bPanExist, pStackInfo->bA2dpExist); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + } + + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", \ + pCoexDm->bCurAgcTableEn, pCoexDm->bCurAdcBackOff, pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", \ + pCoexDm->btRf0x1eBackup); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x40", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8188c2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + halbtc8188c2ant_CoexAllOff(pBtCoexist); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + //halbtc8188c2ant_InitCoexDm(pBtCoexist); + } +} + +VOID +EXhalbtc8188c2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + halbtc8188c2ant_CoexAllOff(pBtCoexist); + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + halbtc8188c2ant_InitCoexDm(pBtCoexist); + } +} + +VOID +EXhalbtc8188c2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + } +} + +VOID +EXhalbtc8188c2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + } +} + +VOID +EXhalbtc8188c2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } + +} + +VOID +EXhalbtc8188c2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(type == BTC_PACKET_DHCP) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], DHCP Packet notify\n")); + } +} + +VOID +EXhalbtc8188c2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ +} + +VOID +EXhalbtc8188c2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + EXhalbtc8188c2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8188c2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte algorithm; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], 2Ant Periodical!!\n")); + + // NOTE: + // sw mechanism must be done after fw mechanism + // + + if((BTC_CHIP_CSR_BC4 == pBtCoexist->boardInfo.btChipType) || + (BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) ) + { + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_GET_BT_RSSI, NULL); + + halbtc8188c2ant_MonitorBtState(pBtCoexist); + algorithm = halbtc8188c2ant_ActionAlgorithm(pBtCoexist); + pCoexDm->curAlgorithm = algorithm; + switch(pCoexDm->curAlgorithm) + { + case BT_8188C_2ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = SCO\n")); + halbtc8188c2ant_ActionSco(pBtCoexist); + break; + case BT_8188C_2ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID\n")); + halbtc8188c2ant_ActionHid(pBtCoexist); + break; + case BT_8188C_2ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP\n")); + halbtc8188c2ant_ActionA2dp(pBtCoexist); + break; + case BT_8188C_2ANT_COEX_ALGO_PAN: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN\n")); + halbtc8188c2ant_ActionPan(pBtCoexist); + break; + case BT_8188C_2ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP\n")); + halbtc8188c2ant_ActionHidA2dp(pBtCoexist); + break; + case BT_8188C_2ANT_COEX_ALGO_HID_PAN: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN+HID\n")); + halbtc8188c2ant_ActionHidPan(pBtCoexist); + break; + case BT_8188C_2ANT_COEX_ALGO_PAN_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN+A2DP\n")); + halbtc8188c2ant_ActionPanA2dp(pBtCoexist); + break; + default: + break; + } + } +} + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8188c2Ant.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8188c2Ant.h new file mode 100644 index 0000000..1edaa45 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8188c2Ant.h @@ -0,0 +1,144 @@ +//=========================================== +// The following is for 8188C 2Ant BT Co-exist definition +//=========================================== +#define BTC_RSSI_COEX_THRESH_TOL_8188C_2ANT 6 + +typedef enum _BT_INFO_SRC_8188C_2ANT{ + BT_INFO_SRC_8188C_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8188C_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8188C_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8188C_2ANT_MAX +}BT_INFO_SRC_8188C_2ANT,*PBT_INFO_SRC_8188C_2ANT; + +typedef enum _BT_8188C_2ANT_BT_STATUS{ + BT_8188C_2ANT_BT_STATUS_IDLE = 0x0, + BT_8188C_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8188C_2ANT_BT_STATUS_NON_IDLE = 0x2, + BT_8188C_2ANT_BT_STATUS_MAX +}BT_8188C_2ANT_BT_STATUS,*PBT_8188C_2ANT_BT_STATUS; + +typedef enum _BT_8188C_2ANT_COEX_ALGO{ + BT_8188C_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8188C_2ANT_COEX_ALGO_SCO = 0x1, + BT_8188C_2ANT_COEX_ALGO_HID = 0x2, + BT_8188C_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8188C_2ANT_COEX_ALGO_PAN = 0x4, + BT_8188C_2ANT_COEX_ALGO_HID_A2DP = 0x5, + BT_8188C_2ANT_COEX_ALGO_HID_PAN = 0x6, + BT_8188C_2ANT_COEX_ALGO_PAN_A2DP = 0x7, + BT_8188C_2ANT_COEX_ALGO_MAX +}BT_8188C_2ANT_COEX_ALGO,*PBT_8188C_2ANT_COEX_ALGO; + +typedef struct _COEX_DM_8188C_2ANT{ + // fw mechanism + BOOLEAN bPreBalanceOn; + BOOLEAN bCurBalanceOn; + + // diminishWifi + BOOLEAN bPreDacOn; + BOOLEAN bCurDacOn; + BOOLEAN bPreInterruptOn; + BOOLEAN bCurInterruptOn; + u1Byte preFwDacSwingLvl; + u1Byte curFwDacSwingLvl; + BOOLEAN bPreNavOn; + BOOLEAN bCurNavOn; + + // sw mechanism + BOOLEAN bPreRfRxLpfShrink; + BOOLEAN bCurRfRxLpfShrink; + u4Byte btRf0x1eBackup; + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + BOOLEAN bPreDacSwingOn; + u4Byte preDacSwingLvl; + BOOLEAN bCurDacSwingOn; + u4Byte curDacSwingLvl; + BOOLEAN bPreAdcBackOff; + BOOLEAN bCurAdcBackOff; + BOOLEAN bPreAgcTableEn; + BOOLEAN bCurAgcTableEn; + //u4Byte preVal0x6c0; + //u4Byte curVal0x6c0; + u4Byte preVal0x6c4; + u4Byte curVal0x6c4; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u4Byte preVal0x6cc; + u4Byte curVal0x6cc; + //BOOLEAN bLimitedDig; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + //u1Byte btStatus; + //u1Byte wifiChnlInfo[3]; +} COEX_DM_8188C_2ANT, *PCOEX_DM_8188C_2ANT; + +typedef struct _COEX_STA_8188C_2ANT{ + u1Byte preWifiRssiState[4]; + BOOLEAN bBtBusy; + BOOLEAN bBtUplink; + BOOLEAN bBtDownLink; + BOOLEAN bA2dpBusy; +}COEX_STA_8188C_2ANT, *PCOEX_STA_8188C_2ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8188c2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8188c2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8188c2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8188c2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8188c2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8188c2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8188c2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8188c2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8188c2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8188c2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8188c2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8188c2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192d2Ant.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192d2Ant.c new file mode 100644 index 0000000..61855f5 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192d2Ant.c @@ -0,0 +1,2058 @@ +//============================================================ +// Description: +// +// This file is for 92D BT 2 Antenna Co-exist mechanism +// +// By cosa 02/11/2011 +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8192D_2ANT GLCoexDm8192d2Ant; +static PCOEX_DM_8192D_2ANT pCoexDm=&GLCoexDm8192d2Ant; +static COEX_STA_8192D_2ANT GLCoexSta8192d2Ant; +static PCOEX_STA_8192D_2ANT pCoexSta=&GLCoexSta8192d2Ant; + +//============================================================ +// local function start with btdm_ +//============================================================ +u1Byte +halbtc8192d2ant_WifiRssiState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte index, + IN u1Byte levelNum, + IN u1Byte rssiThresh, + IN u1Byte rssiThresh1 + ) +{ + s4Byte wifiRssi=0; + u1Byte wifiRssiState=pCoexSta->preWifiRssiState[index]; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(levelNum == 2) + { + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192D_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return pCoexSta->preWifiRssiState[index]; + } + + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192D_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8192D_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifiRssi < rssiThresh1) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + pCoexSta->preWifiRssiState[index] = wifiRssiState; + + return wifiRssiState; +} + +u1Byte +halbtc8192d2ant_ActionAlgorithm( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + BOOLEAN bBtHsOn=FALSE; + u1Byte algorithm=BT_8192D_2ANT_COEX_ALGO_UNDEFINED; + u1Byte numOfDiffProfile=0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(!pStackInfo->bBtLinkExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No profile exists!!!\n")); + return algorithm; + } + + if(pStackInfo->bScoExist) + numOfDiffProfile++; + if(pStackInfo->bHidExist) + numOfDiffProfile++; + if(pStackInfo->bPanExist) + numOfDiffProfile++; + if(pStackInfo->bA2dpExist) + numOfDiffProfile++; + + if(pStackInfo->bScoExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO algorithm\n")); + algorithm = BT_8192D_2ANT_COEX_ALGO_SCO; + } + else + { + if(numOfDiffProfile == 1) + { + if(pStackInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n")); + algorithm = BT_8192D_2ANT_COEX_ALGO_HID; + } + else if(pStackInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n")); + algorithm = BT_8192D_2ANT_COEX_ALGO_A2DP; + } + else if(pStackInfo->bPanExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN only\n")); + algorithm = BT_8192D_2ANT_COEX_ALGO_PAN; + } + } + else + { + if( pStackInfo->bHidExist && + pStackInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_8192D_2ANT_COEX_ALGO_HID_A2DP; + } + else if( pStackInfo->bHidExist && + pStackInfo->bPanExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN\n")); + algorithm = BT_8192D_2ANT_COEX_ALGO_HID_PAN; + } + else if( pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN + A2DP\n")); + algorithm = BT_8192D_2ANT_COEX_ALGO_PAN_A2DP; + } + } + } + return algorithm; +} + +VOID +halbtc8192d2ant_SetFwBalance( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bBalanceOn, + IN u1Byte ms0, + IN u1Byte ms1 + ) +{ + u1Byte H2C_Parameter[3] ={0}; + + if(bBalanceOn) + { + H2C_Parameter[2] = 1; + H2C_Parameter[1] = ms1; + H2C_Parameter[0] = ms0; + } + else + { + H2C_Parameter[2] = 0; + H2C_Parameter[1] = 0; + H2C_Parameter[0] = 0; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Balance=[%s:%dms:%dms], write 0xc=0x%x\n", + bBalanceOn?"ON":"OFF", ms0, ms1, + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0xc, 3, H2C_Parameter); +} + +VOID +halbtc8192d2ant_Balance( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bBalanceOn, + IN u1Byte ms0, + IN u1Byte ms1 + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Balance %s\n", + (bForceExec? "force to":""), (bBalanceOn? "ON":"OFF"))); + pCoexDm->bCurBalanceOn = bBalanceOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBalanceOn = %d, bCurBalanceOn = %d!!\n", + pCoexDm->bPreBalanceOn, pCoexDm->bCurBalanceOn)); + + if(pCoexDm->bPreBalanceOn == pCoexDm->bCurBalanceOn) + return; + } + halbtc8192d2ant_SetFwBalance(pBtCoexist, bBalanceOn, ms0, ms1); + + pCoexDm->bPreBalanceOn = pCoexDm->bCurBalanceOn; +} + +VOID +halbtc8192d2ant_SetFwDiminishWifi( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bDacOn, + IN BOOLEAN bInterruptOn, + IN u1Byte fwDacSwingLvl, + IN BOOLEAN bNavOn + ) +{ + u1Byte H2C_Parameter[3] ={0}; + + if((pBtCoexist->stackInfo.minBtRssi <= -5) && (fwDacSwingLvl == 0x20)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], DiminishWiFi 0x20 original, but set 0x18 for Low RSSI!\n")); + fwDacSwingLvl = 0x18; + } + + H2C_Parameter[2] = 0; + H2C_Parameter[1] = fwDacSwingLvl; + H2C_Parameter[0] = 0; + if(bDacOn) + { + H2C_Parameter[2] |= 0x01; //BIT0 + if(bInterruptOn) + { + H2C_Parameter[2] |= 0x02; //BIT1 + } + } + if(bNavOn) + { + H2C_Parameter[2] |= 0x08; //BIT3 + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], bDacOn=%s, bInterruptOn=%s, bNavOn=%s, write 0x12=0x%x\n", + (bDacOn?"ON":"OFF"), (bInterruptOn?"ON":"OFF"), (bNavOn?"ON":"OFF"), + (H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2]))); + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x12, 3, H2C_Parameter); +} + + +VOID +halbtc8192d2ant_DiminishWifi( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDacOn, + IN BOOLEAN bInterruptOn, + IN u1Byte fwDacSwingLvl, + IN BOOLEAN bNavOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set Diminish Wifi, bDacOn=%s, bInterruptOn=%s, fwDacSwingLvl=%d, bNavOn=%s\n", + (bForceExec? "force to":""), (bDacOn? "ON":"OFF"), (bInterruptOn? "ON":"OFF"), fwDacSwingLvl, (bNavOn? "ON":"OFF"))); + + pCoexDm->bCurDacOn = bDacOn; + pCoexDm->bCurInterruptOn = bInterruptOn; + pCoexDm->curFwDacSwingLvl = fwDacSwingLvl; + pCoexDm->bCurNavOn = bNavOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreDacOn=%d, bCurDacOn=%d!!\n", + pCoexDm->bPreDacOn, pCoexDm->bCurDacOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreInterruptOn=%d, bCurInterruptOn=%d!!\n", + pCoexDm->bPreInterruptOn, pCoexDm->bCurInterruptOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preFwDacSwingLvl=%d, curFwDacSwingLvl=%d!!\n", + pCoexDm->preFwDacSwingLvl, pCoexDm->curFwDacSwingLvl)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreNavOn=%d, bCurNavOn=%d!!\n", + pCoexDm->bPreNavOn, pCoexDm->bCurNavOn)); + + + if( (pCoexDm->bPreDacOn==pCoexDm->bCurDacOn) && + (pCoexDm->bPreInterruptOn==pCoexDm->bCurInterruptOn) && + (pCoexDm->preFwDacSwingLvl==pCoexDm->curFwDacSwingLvl) && + (pCoexDm->bPreNavOn==pCoexDm->bCurNavOn) ) + return; + } + halbtc8192d2ant_SetFwDiminishWifi(pBtCoexist, bDacOn, bInterruptOn, fwDacSwingLvl, bNavOn); + + pCoexDm->bPreDacOn = pCoexDm->bCurDacOn; + pCoexDm->bPreInterruptOn = pCoexDm->bCurInterruptOn; + pCoexDm->preFwDacSwingLvl = pCoexDm->curFwDacSwingLvl; + pCoexDm->bPreNavOn = pCoexDm->bCurNavOn; +} + +VOID +halbtc8192d2ant_SetSwRfRxLpfCorner( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bRxRfShrinkOn + ) +{ + if(bRxRfShrinkOn) + { + //Shrink RF Rx LPF corner + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Shrink RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, 0xf2ff7); + } + else + { + //Resume RF Rx LPF corner + // After initialized, we can use pCoexDm->btRf0x1eBackup + if(pBtCoexist->bInitilized) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, pCoexDm->btRf0x1eBackup); + } + } +} + + +VOID +halbtc8192d2ant_RfShrink( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRxRfShrinkOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn Rx RF Shrink = %s\n", + (bForceExec? "force to":""), ((bRxRfShrinkOn)? "ON":"OFF"))); + pCoexDm->bCurRfRxLpfShrink = bRxRfShrinkOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreRfRxLpfShrink=%d, bCurRfRxLpfShrink=%d\n", + pCoexDm->bPreRfRxLpfShrink, pCoexDm->bCurRfRxLpfShrink)); + + if(pCoexDm->bPreRfRxLpfShrink == pCoexDm->bCurRfRxLpfShrink) + return; + } + halbtc8192d2ant_SetSwRfRxLpfCorner(pBtCoexist, pCoexDm->bCurRfRxLpfShrink); + + pCoexDm->bPreRfRxLpfShrink = pCoexDm->bCurRfRxLpfShrink; +} + +VOID +halbtc8192d2ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte tmpU1; + + tmpU1 = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x4fd); + if(bLowPenaltyRa) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set low penalty!!\n")); + tmpU1 &= ~BIT2; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set normal!!\n")); + tmpU1 |= BIT2; + } + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x4fd, tmpU1); +} + +VOID +halbtc8192d2ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); + + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8192d2ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8192d2ant_SetSwFullTimeDacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bSwDacSwingOn, + IN u4Byte swDacSwingLvl + ) +{ + u4Byte dacSwingLvl; + + if(bSwDacSwingOn) + { + if((pBtCoexist->stackInfo.minBtRssi <= -5) && (swDacSwingLvl == 0x20)) + { + dacSwingLvl = 0x18; + } + else + { + dacSwingLvl = swDacSwingLvl; + } + pBtCoexist->fBtcSetBbReg(pBtCoexist, 0x880, 0xfc000000, dacSwingLvl); + } + else + { + pBtCoexist->fBtcSetBbReg(pBtCoexist, 0x880, 0xfc000000, 0x30); + } +} + +VOID +halbtc8192d2ant_DacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDacSwingOn, + IN u4Byte dacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn DacSwing=%s, dacSwingLvl=0x%x\n", + (bForceExec? "force to":""), ((bDacSwingOn)? "ON":"OFF"), dacSwingLvl)); + pCoexDm->bCurDacSwingOn = bDacSwingOn; + pCoexDm->curDacSwingLvl = dacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x, bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + pCoexDm->bPreDacSwingOn, pCoexDm->preDacSwingLvl, + pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl)); + + if( (pCoexDm->bPreDacSwingOn == pCoexDm->bCurDacSwingOn) && + (pCoexDm->preDacSwingLvl == pCoexDm->curDacSwingLvl) ) + return; + } + delay_ms(30); + halbtc8192d2ant_SetSwFullTimeDacSwing(pBtCoexist, bDacSwingOn, dacSwingLvl); + + pCoexDm->bPreDacSwingOn = pCoexDm->bCurDacSwingOn; + pCoexDm->preDacSwingLvl = pCoexDm->curDacSwingLvl; +} + +VOID +halbtc8192d2ant_SetAdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAdcBackOff + ) +{ + if(bAdcBackOff) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level On!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc04,0x3a07611); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level Off!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc04,0x3a05611); + } +} + +VOID +halbtc8192d2ant_AdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAdcBackOff + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn AdcBackOff = %s\n", + (bForceExec? "force to":""), ((bAdcBackOff)? "ON":"OFF"))); + pCoexDm->bCurAdcBackOff = bAdcBackOff; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAdcBackOff=%d, bCurAdcBackOff=%d\n", + pCoexDm->bPreAdcBackOff, pCoexDm->bCurAdcBackOff)); + + if(pCoexDm->bPreAdcBackOff == pCoexDm->bCurAdcBackOff) + return; + } + halbtc8192d2ant_SetAdcBackOff(pBtCoexist, pCoexDm->bCurAdcBackOff); + + pCoexDm->bPreAdcBackOff = pCoexDm->bCurAdcBackOff; +} + +VOID +halbtc8192d2ant_SetAgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAgcTableEn + ) +{ + u1Byte rssiAdjustVal=0; + + if(bAgcTableEn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1a, 0xfffff, 0xa99); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0xd4000); + + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7b000001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7b010001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7b020001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7b030001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7b040001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7b050001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7b060001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7b070001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7b080001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7b090001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7b0A0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7b0B0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7a0C0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x790D0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x780E0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x770F0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x76100001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x75110001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x74120001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x73130001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x72140001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x71150001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x70160001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6f170001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6e180001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6d190001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6c1A0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6b1B0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6a1C0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x691D0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x4f1E0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x4e1F0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x4d200001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x4c210001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x4b220001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x4a230001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x49240001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x48250001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x47260001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x46270001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x45280001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x44290001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x432A0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x422B0001); + + rssiAdjustVal = 12; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1a, 0xfffff, 0x30a99); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0xdc000); + + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7B000001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7B010001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7B020001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7B030001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7B040001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7B050001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7B060001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x7A070001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x79080001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x78090001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x770A0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x760B0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x750C0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x740D0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x730E0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x720F0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x71100001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x70110001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6F120001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6E130001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6D140001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6C150001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6B160001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6A170001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x69180001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x68190001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x671A0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x661B0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x651C0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x641D0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x631E0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x621F0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x61200001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x60210001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x49220001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x48230001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x47240001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x46250001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x45260001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x44270001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x43280001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x42290001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x412A0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x402B0001); + } + + // set rssiAdjustVal for wifi module. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, &rssiAdjustVal); +} + + + +VOID +halbtc8192d2ant_AgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAgcTableEn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s %s Agc Table\n", + (bForceExec? "force to":""), ((bAgcTableEn)? "Enable":"Disable"))); + pCoexDm->bCurAgcTableEn = bAgcTableEn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + pCoexDm->bPreAgcTableEn, pCoexDm->bCurAgcTableEn)); + + if(pCoexDm->bPreAgcTableEn == pCoexDm->bCurAgcTableEn) + return; + } + halbtc8192d2ant_SetAgcTable(pBtCoexist, bAgcTableEn); + + pCoexDm->bPreAgcTableEn = pCoexDm->bCurAgcTableEn; +} + +VOID +halbtc8192d2ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u4Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8192d2ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u4Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c4, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c4 = val0x6c4; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c4=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + pCoexDm->preVal0x6c4, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c4=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + pCoexDm->curVal0x6c4, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8192d2ant_SetCoexTable(pBtCoexist, val0x6c4, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c4 = pCoexDm->curVal0x6c4; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8192d2ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + // fw mechanism + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); +} +VOID +halbtc8192d2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +VOID +halbtc8192d2ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte btActive + ) +{ + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtDisabled=FALSE, bForceToRoam=FALSE; + u4Byte u4Tmp=0; + + // This function check if bt is disabled + if(btActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + + bForceToRoam = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_FORCE_TO_ROAM, &bForceToRoam); + + bPreBtDisabled = bBtDisabled; + } +} + +VOID +halbtc8192d2ant_MonitorBtState( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN stateChange=FALSE; + u4Byte BT_Polling, Ratio_Act, Ratio_STA; + u4Byte BT_Active, BT_State; + u4Byte regBTActive=0, regBTState=0, regBTPolling=0; + u4Byte btBusyThresh=0; + u4Byte fwVer=0; + static BOOLEAN bBtBusyTraffic=FALSE; + BOOLEAN bRejApAggPkt=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], FirmwareVersion = 0x%x(%d)\n", fwVer, fwVer)); + + regBTActive = 0x444; + regBTState = 0x448; + regBTPolling = 0x44c; + + btBusyThresh = 40; + + BT_Active = pBtCoexist->fBtcRead4Byte(pBtCoexist, regBTActive); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT_Active(0x%x)=0x%x\n", regBTActive, BT_Active)); + BT_Active = BT_Active & 0x00ffffff; + + BT_State = pBtCoexist->fBtcRead4Byte(pBtCoexist, regBTState); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT_State(0x%x)=0x%x\n", regBTState, BT_State)); + BT_State = BT_State & 0x00ffffff; + + BT_Polling = pBtCoexist->fBtcRead4Byte(pBtCoexist, regBTPolling); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT_Polling(0x%x)=0x%x\n", regBTPolling, BT_Polling)); + + if(BT_Active==0xffffffff && BT_State==0xffffffff && BT_Polling==0xffffffff ) + return; + + // 2011/05/04 MH For Slim combo test meet a problem. Surprise remove and WLAN is running + // DHCP process. At the same time, the register read value might be zero. And cause BSOD 0x7f + // EXCEPTION_DIVIDED_BY_ZERO. In This case, the stack content may always be wrong due to + // HW divide trap. + if (BT_Polling==0) + return; + + halbtc8192d2ant_MonitorBtEnableDisable(pBtCoexist, BT_Active); + + Ratio_Act = BT_Active*1000/BT_Polling; + Ratio_STA = BT_State*1000/BT_Polling; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Ratio_Act=%d\n", Ratio_Act)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Ratio_STA=%d\n", Ratio_STA)); + + if(BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) + { + if(Ratio_STA < 60) // BT PAN idle + { + } + else + { + // Check if BT PAN (under BT 2.1) is uplink or downlink + if((Ratio_Act/Ratio_STA) < 2) + { // BT PAN Uplink + pCoexSta->bBtUplink = TRUE; + } + else + { // BT PAN downlink + pCoexSta->bBtUplink = FALSE; + } + } + } + + // Check BT is idle or not + if(!pBtCoexist->stackInfo.bBtLinkExist) + { + pCoexSta->bBtBusy = FALSE; + } + else + { + if(BTC_CHIP_CSR_BC4 == pBtCoexist->boardInfo.btChipType) + { + if(Ratio_Act<20) + { + pCoexSta->bBtBusy = FALSE; + } + else + { + pCoexSta->bBtBusy = TRUE; + } + } + else if(BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) + { + if(Ratio_STA < btBusyThresh) + { + pCoexSta->bBtBusy = FALSE; + } + else + { + pCoexSta->bBtBusy = TRUE; + } + + if( (Ratio_STA < btBusyThresh) || + (Ratio_Act<180 && Ratio_STA<130) ) + { + pCoexSta->bA2dpBusy = FALSE; + } + else + { + pCoexSta->bA2dpBusy = TRUE; + } + } + } + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &pCoexSta->bBtBusy); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_LIMITED_DIG, &pCoexSta->bBtBusy); + + if(bBtBusyTraffic != pCoexSta->bBtBusy) + { // BT idle or BT non-idle + bBtBusyTraffic = pCoexSta->bBtBusy; + stateChange = TRUE; + } + + if(stateChange) + { + if(!pCoexSta->bBtBusy) + { + halbtc8192d2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_CoexAllOff(pBtCoexist); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x0); + } + else + { + halbtc8192d2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_RfShrink(pBtCoexist, NORMAL_EXEC, TRUE); + } + } + + if(stateChange) + { + bRejApAggPkt = pCoexSta->bBtBusy; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &bRejApAggPkt); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + } +} + +VOID +halbtc8192d2ant_ActionA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw, wifiTrafficDir; + BOOLEAN bWifiBusy=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + + wifiRssiState = halbtc8192d2ant_WifiRssiState(pBtCoexist, 0, 2, 47, 0); + if(pCoexSta->bA2dpBusy && bWifiBusy) + { + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState1 = halbtc8192d2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + } + else + { + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + wifiRssiState1 = halbtc8192d2ant_WifiRssiState(pBtCoexist, 1, 2, 25, 0); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + wifiRssiState1 = halbtc8192d2ant_WifiRssiState(pBtCoexist, 1, 2, 40, 0); + } + } + + // fw mechanism first + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0xc, 0x18); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x10, 0x18); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + } + else + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + } + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + } + else if(pCoexSta->bA2dpBusy) + { + // fw mechanism first + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, TRUE, 0x18, FALSE); + + // sw mechanism + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8192d2ant_CoexAllOff(pBtCoexist); + } +} + +VOID +halbtc8192d2ant_ActionPan( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + u1Byte wifiRssiState, wifiRssiState1; + u4Byte wifiBw, wifiTrafficDir; + s4Byte wifiRssi; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(bBtHsOn) + { + halbtc8192d2ant_CoexAllOff(pBtCoexist); + } + else + { + wifiRssiState = halbtc8192d2ant_WifiRssiState(pBtCoexist, 0, 3, 25, 50); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState1 = halbtc8192d2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + } + else + { + wifiRssiState1 = halbtc8192d2ant_WifiRssiState(pBtCoexist, 1, 2, 25, 0); + } + + if(pCoexSta->bBtBusy && bWifiBusy) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + // fw mechanism first + if(pCoexSta->bBtUplink) + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x20, 0x20); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + else + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + } + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + } + else + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + } + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + if(pCoexSta->bBtUplink) + { + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x20); + } + } + else if( (wifiRssiState == BTC_RSSI_STATE_MEDIUM) || + (wifiRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + // fw mechanism first + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x20, 0x20); + + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + if(BTC_WIFI_BW_HT40 == wifiBw) + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE);//BT_FW_NAV_ON); + else + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + } + else + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + } + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + // fw mechanism first + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x20, 0x20); + + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + if(pCoexSta->bBtUplink) + { + if(BTC_WIFI_BW_HT40 == wifiBw) + { + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE);//BT_FW_NAV_ON); + } + else + { + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + } + else + { + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + } + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + } + else + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + } + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + else if(pCoexSta->bBtBusy && + !bWifiBusy && + (wifiRssi < 30)) + { + // fw mechanism first + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x0a, 0x20); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + // sw mechanism + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8192d2ant_CoexAllOff(pBtCoexist); + } + } +} + + +VOID +halbtc8192d2ant_ActionHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiTrafficDir; + BOOLEAN bWifiBusy=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + wifiRssiState = halbtc8192d2ant_WifiRssiState(pBtCoexist, 0, 2, 45, 0); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + wifiRssiState = halbtc8192d2ant_WifiRssiState(pBtCoexist, 0, 2, 20, 0); + } + + if(pCoexSta->bBtBusy && bWifiBusy) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + // fw mechanism first + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x20); + } + else + { + // fw mechanism first + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, TRUE, 0x18, FALSE); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x15, 0x15); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x30, FALSE); + } + // sw mechanism + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + else + { + halbtc8192d2ant_CoexAllOff(pBtCoexist); + } +} + + + +VOID +halbtc8192d2ant_ActionSco( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + wifiRssiState = halbtc8192d2ant_WifiRssiState(pBtCoexist, 0, 2, 47, 0); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism first + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + // fw mechanism first + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } +} + +VOID +halbtc8192d2ant_ActionHidA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1; + u4Byte wifiBw; + + if(pCoexSta->bBtBusy) + { + wifiRssiState1 = halbtc8192d2ant_WifiRssiState(pBtCoexist, 1, 2, 35, 0); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism first + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + } + else + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + } + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x18); + } + else + { + wifiRssiState = halbtc8192d2ant_WifiRssiState(pBtCoexist, 0, 2, 47, 0); + // fw mechanism + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + } + else + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + } + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x18); + } + else + { + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x18); + } + } + } + else + { + halbtc8192d2ant_CoexAllOff(pBtCoexist); + } +} + + +VOID +halbtc8192d2ant_ActionHidPanBc4( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + u4Byte wifiBw, wifiTrafficDir; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(bBtHsOn) + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + + halbtc8192d2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0x000000f0, 0x40000010); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0xa0); + } + else + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + if(BTC_WIFI_BW_LEGACY == wifiBw) + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + + halbtc8192d2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0x000000f0, 0x40000010); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0xa0); + } + else if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + + halbtc8192d2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0x000000f0, 0x40000010); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0xa0); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x0); + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x20, 0x10); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + else if(!bWifiBusy) + { + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x0); + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + } + } + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); +} +VOID +halbtc8192d2ant_ActionHidPanBc8( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + u1Byte wifiRssiState; + u4Byte wifiBw, wifiTrafficDir; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(!bBtHsOn) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + wifiRssiState = halbtc8192d2ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + if((pCoexSta->bBtBusy && bWifiBusy)) + { + // fw mechanism first + if(pCoexSta->bBtUplink) + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x15, 0x20); + } + else + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x10, 0x20); + } + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + else + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + else + { + halbtc8192d2ant_CoexAllOff(pBtCoexist); + } + } + else + { + if(BTC_INTF_USB == pBtCoexist->chipInterface) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + if(BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + + halbtc8192d2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0x000000f0, 0x40000010); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0xa0); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x18); + } + else if(BTC_WIFI_TRAFFIC_RX == wifiTrafficDir) + { + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x18); + } + } + else + { + if(pCoexSta->bBtBusy) + { + // fw mechanism + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x20); + } + else + { + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + } +} + +VOID +halbtc8192d2ant_ActionHidPan( + IN PBTC_COEXIST pBtCoexist + ) +{ + if(BTC_CHIP_CSR_BC4 == pBtCoexist->boardInfo.btChipType) + { + halbtc8192d2ant_ActionHidPanBc4(pBtCoexist); + } + else if(BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) + { + halbtc8192d2ant_ActionHidPanBc8(pBtCoexist); + } +} + +VOID +halbtc8192d2ant_ActionPanA2dpBc4( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + u1Byte wifiRssiState; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x0); + if(bBtHsOn) + { + if(pCoexSta->bBtBusy) + { + // fw mechanism + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x20); + } + else + { + halbtc8192d2ant_CoexAllOff(pBtCoexist); + } + } + else + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + if(pCoexSta->bBtBusy && bWifiBusy) + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x20, 0x10); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + } + else + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x0, FALSE); + } + // sw mechanism + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } +} +VOID +halbtc8192d2ant_ActionPanA2dpBc8( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + u1Byte wifiRssiState; + u4Byte wifiBw; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(!bBtHsOn) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + wifiRssiState = halbtc8192d2ant_WifiRssiState(pBtCoexist, 0, 2, 25, 0); + if((pCoexSta->bBtBusy && bWifiBusy)) + { + // fw mechanism first + if(pCoexSta->bBtUplink) + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x15, 0x20); + } + else + { + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, TRUE, 0x10, 0x20); + } + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, TRUE, FALSE, 0x20, FALSE); + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + else + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + else + { + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } + else + { + halbtc8192d2ant_CoexAllOff(pBtCoexist); + } + } + else + { + if(pCoexSta->bBtBusy) + { + // fw mechanism + halbtc8192d2ant_Balance(pBtCoexist, NORMAL_EXEC, FALSE, 0, 0); + halbtc8192d2ant_DiminishWifi(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0, FALSE); + + // sw mechanism + halbtc8192d2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0x20); + } + else + { + halbtc8192d2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0x30); + } + } +} + +VOID +halbtc8192d2ant_ActionPanA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + if(BTC_CHIP_CSR_BC4 == pBtCoexist->boardInfo.btChipType) + { + halbtc8192d2ant_ActionPanA2dpBc4(pBtCoexist); + } + else if(BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) + { + halbtc8192d2ant_ActionPanA2dpBc8(pBtCoexist); + } +} + +BOOLEAN +halbtc8192d2ant_IsBtCoexistEnter( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte macPhyMode; + BOOLEAN bRet=TRUE; + BOOLEAN bWifiUnder5G=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_MAC_PHY_MODE, &macPhyMode); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + + if(BTC_SMSP != macPhyMode) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Only support single mac single phy!!\n")); + bRet = FALSE; + } + + if(bWifiUnder5G) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under 5G or A band\n")); + halbtc8192d2ant_CoexAllOff(pBtCoexist); + bRet = FALSE; + } + + return bRet; +} + +//============================================================ +// extern function start with EXhalbtc8192d2ant_ +//============================================================ +VOID +EXhalbtc8192d2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte u1Tmp=0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 2Ant Init HW Config!!\n")); + + // backup rf 0x1e value + pCoexDm->btRf0x1eBackup = + pBtCoexist->fBtcGetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff); + + if( (BTC_CHIP_CSR_BC4 == pBtCoexist->boardInfo.btChipType) || + (BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) ) + { + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x4fd) & BIT0; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x4fd, u1Tmp); + + halbtc8192d2ant_CoexTable(pBtCoexist, FORCE_EXEC, 0xaaaa9aaa, 0xffbd0040, 0x40000010); + + // switch control, here we set pathA to control + // 0x878[13] = 1, 0:pathB, 1:pathA(default) + pBtCoexist->fBtcSetBbReg(pBtCoexist, 0x878, BIT13, 0x1); + + // antsel control, here we use phy0 and enable antsel. + // 0x87c[16:15] = b'11, enable antsel, antsel output pin + // 0x87c[30] = 0, 0: phy0, 1:phy 1 + pBtCoexist->fBtcSetBbReg(pBtCoexist, 0x87c, bMaskDWord, 0x1fff8); + + // antsel to Bt or Wifi, it depends Bt on/off. + // 0x860[9:8] = 'b10, b10:Bt On, WL2G off(default), b01:Bt off, WL2G on. + pBtCoexist->fBtcSetBbReg(pBtCoexist, 0x860, BIT9|BIT8, 0x2); + + // sw/hw control switch, here we set sw control + // 0x870[9:8] = 'b11 sw control, 'b00 hw control + pBtCoexist->fBtcSetBbReg(pBtCoexist, 0x870, BIT9|BIT8, 0x3); + } +} + +VOID +EXhalbtc8192d2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + halbtc8192d2ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8192d2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + pu1Byte cliBuf=pBtCoexist->cliBuf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir; + u1Byte wifiDot11Chnl, wifiHsChnl; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(!pBoardInfo->bBtExist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum); + CL_PRINTF(cliBuf); + + if(pBtCoexist->bManualControl) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "[Action Manual control]!!"); + CL_PRINTF(cliBuf); + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ + wifiDot11Chnl, wifiHsChnl, bBtHsOn); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + + if(pStackInfo->bProfileNotified) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pStackInfo->bScoExist, pStackInfo->bHidExist, pStackInfo->bPanExist, pStackInfo->bA2dpExist); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + } + + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", \ + pCoexDm->bCurAgcTableEn, pCoexDm->bCurAdcBackOff, pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", \ + pCoexDm->btRf0x1eBackup); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x40", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8192d2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + halbtc8192d2ant_CoexAllOff(pBtCoexist); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + //halbtc8192d2ant_InitCoexDm(pBtCoexist); + } +} + +VOID +EXhalbtc8192d2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + halbtc8192d2ant_CoexAllOff(pBtCoexist); + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + halbtc8192d2ant_InitCoexDm(pBtCoexist); + } +} + +VOID +EXhalbtc8192d2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + } +} + +VOID +EXhalbtc8192d2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + } +} + +VOID +EXhalbtc8192d2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } +} + +VOID +EXhalbtc8192d2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(type == BTC_PACKET_DHCP) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], DHCP Packet notify\n")); + } +} + +VOID +EXhalbtc8192d2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ +} + +VOID +EXhalbtc8192d2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + EXhalbtc8192d2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8192d2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte algorithm; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], 2Ant Periodical!!\n")); + + // NOTE: + // sw mechanism must be done after fw mechanism + // + if(!halbtc8192d2ant_IsBtCoexistEnter(pBtCoexist)) + return; + + if(BTC_CHIP_CSR_BC8 == pBtCoexist->boardInfo.btChipType) + { + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_GET_BT_RSSI, NULL); + + halbtc8192d2ant_MonitorBtState(pBtCoexist); + algorithm = halbtc8192d2ant_ActionAlgorithm(pBtCoexist); + pCoexDm->curAlgorithm = algorithm; + switch(pCoexDm->curAlgorithm) + { + case BT_8192D_2ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = SCO\n")); + halbtc8192d2ant_ActionSco(pBtCoexist); + break; + case BT_8192D_2ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID\n")); + halbtc8192d2ant_ActionHid(pBtCoexist); + break; + case BT_8192D_2ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP\n")); + halbtc8192d2ant_ActionA2dp(pBtCoexist); + break; + case BT_8192D_2ANT_COEX_ALGO_PAN: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN\n")); + halbtc8192d2ant_ActionPan(pBtCoexist); + break; + case BT_8192D_2ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP\n")); + halbtc8192d2ant_ActionHidA2dp(pBtCoexist); + break; + case BT_8192D_2ANT_COEX_ALGO_HID_PAN: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN+HID\n")); + halbtc8192d2ant_ActionHidPan(pBtCoexist); + break; + case BT_8192D_2ANT_COEX_ALGO_PAN_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN+A2DP\n")); + halbtc8192d2ant_ActionPanA2dp(pBtCoexist); + break; + default: + break; + } + } +} + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192d2Ant.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192d2Ant.h new file mode 100644 index 0000000..a1a0eb6 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192d2Ant.h @@ -0,0 +1,165 @@ +//=========================================== +// The following is for 8192D 2Ant BT Co-exist definition +//=========================================== +#define BTC_RSSI_COEX_THRESH_TOL_8192D_2ANT 6 + +typedef enum _BT_INFO_SRC_8192D_2ANT{ + BT_INFO_SRC_8192D_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8192D_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8192D_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8192D_2ANT_MAX +}BT_INFO_SRC_8192D_2ANT,*PBT_INFO_SRC_8192D_2ANT; + +typedef enum _BT_8192D_2ANT_BT_STATUS{ + BT_8192D_2ANT_BT_STATUS_IDLE = 0x0, + BT_8192D_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8192D_2ANT_BT_STATUS_NON_IDLE = 0x2, + BT_8192D_2ANT_BT_STATUS_MAX +}BT_8192D_2ANT_BT_STATUS,*PBT_8192D_2ANT_BT_STATUS; + +typedef enum _BT_8192D_2ANT_COEX_ALGO{ + BT_8192D_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8192D_2ANT_COEX_ALGO_SCO = 0x1, + BT_8192D_2ANT_COEX_ALGO_HID = 0x2, + BT_8192D_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8192D_2ANT_COEX_ALGO_PAN = 0x4, + BT_8192D_2ANT_COEX_ALGO_HID_A2DP = 0x5, + BT_8192D_2ANT_COEX_ALGO_HID_PAN = 0x6, + BT_8192D_2ANT_COEX_ALGO_PAN_A2DP = 0x7, + BT_8192D_2ANT_COEX_ALGO_MAX +}BT_8192D_2ANT_COEX_ALGO,*PBT_8192D_2ANT_COEX_ALGO; + +typedef struct _COEX_DM_8192D_2ANT{ + // fw mechanism + BOOLEAN bPreBalanceOn; + BOOLEAN bCurBalanceOn; + + // diminishWifi + BOOLEAN bPreDacOn; + BOOLEAN bCurDacOn; + BOOLEAN bPreInterruptOn; + BOOLEAN bCurInterruptOn; + u1Byte preFwDacSwingLvl; + u1Byte curFwDacSwingLvl; + BOOLEAN bPreNavOn; + BOOLEAN bCurNavOn; + + + + + + //BOOLEAN bPreDecBtPwr; + //BOOLEAN bCurDecBtPwr; + + //u1Byte preFwDacSwingLvl; + //u1Byte curFwDacSwingLvl; + //BOOLEAN bCurIgnoreWlanAct; + //BOOLEAN bPreIgnoreWlanAct; + //u1Byte prePsTdma; + //u1Byte curPsTdma; + //u1Byte psTdmaPara[5]; + //u1Byte psTdmaDuAdjType; + //BOOLEAN bResetTdmaAdjust; + //BOOLEAN bPrePsTdmaOn; + //BOOLEAN bCurPsTdmaOn; + //BOOLEAN bPreBtAutoReport; + //BOOLEAN bCurBtAutoReport; + + // sw mechanism + BOOLEAN bPreRfRxLpfShrink; + BOOLEAN bCurRfRxLpfShrink; + u4Byte btRf0x1eBackup; + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + BOOLEAN bPreDacSwingOn; + u4Byte preDacSwingLvl; + BOOLEAN bCurDacSwingOn; + u4Byte curDacSwingLvl; + BOOLEAN bPreAdcBackOff; + BOOLEAN bCurAdcBackOff; + BOOLEAN bPreAgcTableEn; + BOOLEAN bCurAgcTableEn; + //u4Byte preVal0x6c0; + //u4Byte curVal0x6c0; + u4Byte preVal0x6c4; + u4Byte curVal0x6c4; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u4Byte preVal0x6cc; + u4Byte curVal0x6cc; + //BOOLEAN bLimitedDig; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + //u1Byte btStatus; + //u1Byte wifiChnlInfo[3]; +} COEX_DM_8192D_2ANT, *PCOEX_DM_8192D_2ANT; + +typedef struct _COEX_STA_8192D_2ANT{ + u1Byte preWifiRssiState[4]; + BOOLEAN bBtBusy; + BOOLEAN bBtUplink; + BOOLEAN bBtDownLink; + BOOLEAN bA2dpBusy; +}COEX_STA_8192D_2ANT, *PCOEX_STA_8192D_2ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8192d2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192d2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192d2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192d2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192d2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192d2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192d2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192d2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192d2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192d2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192d2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8192d2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e1Ant.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e1Ant.c new file mode 100644 index 0000000..4a6244a --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e1Ant.c @@ -0,0 +1,3281 @@ +//============================================================ +// Description: +// +// This file is for 8192e1ant Co-exist mechanism +// +// History +// 2012/11/15 Cosa first check in. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8192E_1ANT GLCoexDm8192e1Ant; +static PCOEX_DM_8192E_1ANT pCoexDm=&GLCoexDm8192e1Ant; +static COEX_STA_8192E_1ANT GLCoexSta8192e1Ant; +static PCOEX_STA_8192E_1ANT pCoexSta=&GLCoexSta8192e1Ant; + +const char *const GLBtInfoSrc8192e1Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u4Byte GLCoexVerDate8192e1Ant=20130729; +u4Byte GLCoexVer8192e1Ant=0x10; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8192e1ant_ +//============================================================ +u1Byte +halbtc8192e1ant_BtRssiState( + u1Byte levelNum, + u1Byte rssiThresh, + u1Byte rssiThresh1 + ) +{ + s4Byte btRssi=0; + u1Byte btRssiState=pCoexSta->preBtRssiState; + + btRssi = pCoexSta->btRssi; + + if(levelNum == 2) + { + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else + { + if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); + return pCoexSta->preBtRssiState; + } + + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); + } + } + else + { + if(btRssi < rssiThresh1) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + + pCoexSta->preBtRssiState = btRssiState; + + return btRssiState; +} + +u1Byte +halbtc8192e1ant_WifiRssiState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte index, + IN u1Byte levelNum, + IN u1Byte rssiThresh, + IN u1Byte rssiThresh1 + ) +{ + s4Byte wifiRssi=0; + u1Byte wifiRssiState=pCoexSta->preWifiRssiState[index]; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(levelNum == 2) + { + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return pCoexSta->preWifiRssiState[index]; + } + + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifiRssi < rssiThresh1) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + pCoexSta->preWifiRssiState[index] = wifiRssiState; + + return wifiRssiState; +} + +VOID +halbtc8192e1ant_UpdateRaMask( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type, + IN u4Byte rateMask + ) +{ + if(BTC_RATE_DISABLE == type) + { + pCoexDm->curRaMask |= rateMask; // disable rate + } + else if(BTC_RATE_ENABLE == type) + { + pCoexDm->curRaMask &= ~rateMask; // enable rate + } + + if( bForceExec || (pCoexDm->preRaMask != pCoexDm->curRaMask)) + { + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_UPDATE_RAMASK, &pCoexDm->curRaMask); + } + pCoexDm->preRaMask = pCoexDm->curRaMask; +} + +VOID +halbtc8192e1ant_MonitorBtCtr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte regHPTxRx, regLPTxRx, u4Tmp; + u4Byte regHPTx=0, regHPRx=0, regLPTx=0, regLPRx=0; + u1Byte u1Tmp; + + regHPTxRx = 0x770; + regLPTxRx = 0x774; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); + regHPTx = u4Tmp & bMaskLWord; + regHPRx = (u4Tmp & bMaskHWord)>>16; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); + regLPTx = u4Tmp & bMaskLWord; + regLPRx = (u4Tmp & bMaskHWord)>>16; + + pCoexSta->highPriorityTx = regHPTx; + pCoexSta->highPriorityRx = regHPRx; + pCoexSta->lowPriorityTx = regLPTx; + pCoexSta->lowPriorityRx = regLPRx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regHPTxRx, regHPTx, regHPTx, regHPRx, regHPRx)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regLPTxRx, regLPTx, regLPTx, regLPRx, regLPRx)); + + // reset counter + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); +} + +VOID +halbtc8192e1ant_QueryBtInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + pCoexSta->bC2hBtInfoReqSent = TRUE; + + H2C_Parameter[0] |= BIT0; // trigger + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Query Bt Info, FW write 0x61=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x61, 1, H2C_Parameter); +} + +BOOLEAN +halbtc8192e1ant_IsWifiStatusChanged( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreWifiBusy=FALSE, bPreUnder4way=FALSE, bPreBtHsOn=FALSE; + BOOLEAN bWifiBusy=FALSE, bUnder4way=FALSE, bBtHsOn=FALSE; + BOOLEAN bWifiConnected=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); + + if(bWifiConnected) + { + if(bWifiBusy != bPreWifiBusy) + { + bPreWifiBusy = bWifiBusy; + return TRUE; + } + if(bUnder4way != bPreUnder4way) + { + bPreUnder4way = bUnder4way; + return TRUE; + } + if(bBtHsOn != bPreBtHsOn) + { + bPreBtHsOn = bBtHsOn; + return TRUE; + } + } + + return FALSE; +} + +VOID +halbtc8192e1ant_UpdateBtLinkInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + + pBtLinkInfo->bBtLinkExist = pCoexSta->bBtLinkExist; + pBtLinkInfo->bScoExist = pCoexSta->bScoExist; + pBtLinkInfo->bA2dpExist = pCoexSta->bA2dpExist; + pBtLinkInfo->bPanExist = pCoexSta->bPanExist; + pBtLinkInfo->bHidExist = pCoexSta->bHidExist; + + // check if Sco only + if( pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bScoOnly = TRUE; + else + pBtLinkInfo->bScoOnly = FALSE; + + // check if A2dp only + if( !pBtLinkInfo->bScoExist && + pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bA2dpOnly = TRUE; + else + pBtLinkInfo->bA2dpOnly = FALSE; + + // check if Pan only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bPanOnly = TRUE; + else + pBtLinkInfo->bPanOnly = FALSE; + + // check if Hid only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + pBtLinkInfo->bHidExist ) + pBtLinkInfo->bHidOnly = TRUE; + else + pBtLinkInfo->bHidOnly = FALSE; +} + +u1Byte +halbtc8192e1ant_ActionAlgorithm( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bBtHsOn=FALSE; + u1Byte algorithm=BT_8192E_1ANT_COEX_ALGO_UNDEFINED; + u1Byte numOfDiffProfile=0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(!pBtLinkInfo->bBtLinkExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No BT link exists!!!\n")); + return algorithm; + } + + if(pBtLinkInfo->bScoExist) + numOfDiffProfile++; + if(pBtLinkInfo->bHidExist) + numOfDiffProfile++; + if(pBtLinkInfo->bPanExist) + numOfDiffProfile++; + if(pBtLinkInfo->bA2dpExist) + numOfDiffProfile++; + + if(numOfDiffProfile == 1) + { + if(pBtLinkInfo->bScoExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO only\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_SCO; + } + else + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_A2DP; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(HS) only\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(EDR) only\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR; + } + } + } + } + else if(numOfDiffProfile == 2) + { + if(pBtLinkInfo->bScoExist) + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP ==> SCO\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_SCO; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(HS)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(EDR)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID_A2DP; + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(HS)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_A2DP_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } + else if(numOfDiffProfile == 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP ==> HID\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID; + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(HS)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(EDR)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(HS)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + else if(numOfDiffProfile >= 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n")); + + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n")); + algorithm = BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +VOID +halbtc8192e1ant_SetFwDacSwingLevel( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte dacSwingLvl + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + // There are several type of dacswing + // 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 + H2C_Parameter[0] = dacSwingLvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Set Dac Swing Level=0x%x\n", dacSwingLvl)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x64=0x%x\n", H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x64, 1, H2C_Parameter); +} + +VOID +halbtc8192e1ant_SetFwDecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte decBtPwrLvl + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = decBtPwrLvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], decrease Bt Power level = %d, FW write 0x62=0x%x\n", + decBtPwrLvl, H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x62, 1, H2C_Parameter); +} + +VOID +halbtc8192e1ant_DecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte decBtPwrLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s Dec BT power level = %d\n", + (bForceExec? "force to":""), decBtPwrLvl)); + pCoexDm->curBtDecPwrLvl = decBtPwrLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], BtDecPwrLvl=%d, curBtDecPwrLvl=%d\n", + pCoexDm->preBtDecPwrLvl, pCoexDm->curBtDecPwrLvl)); + + if(pCoexDm->preBtDecPwrLvl == pCoexDm->curBtDecPwrLvl) + return; + } + halbtc8192e1ant_SetFwDecBtPwr(pBtCoexist, pCoexDm->curBtDecPwrLvl); + + pCoexDm->preBtDecPwrLvl = pCoexDm->curBtDecPwrLvl; +} + +VOID +halbtc8192e1ant_SetBtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnableAutoReport + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = 0; + + if(bEnableAutoReport) + { + H2C_Parameter[0] |= BIT0; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], BT FW auto report : %s, FW write 0x68=0x%x\n", + (bEnableAutoReport? "Enabled!!":"Disabled!!"), H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x68, 1, H2C_Parameter); +} + +VOID +halbtc8192e1ant_BtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnableAutoReport + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT Auto report = %s\n", + (bForceExec? "force to":""), ((bEnableAutoReport)? "Enabled":"Disabled"))); + pCoexDm->bCurBtAutoReport = bEnableAutoReport; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtAutoReport=%d, bCurBtAutoReport=%d\n", + pCoexDm->bPreBtAutoReport, pCoexDm->bCurBtAutoReport)); + + if(pCoexDm->bPreBtAutoReport == pCoexDm->bCurBtAutoReport) + return; + } + halbtc8192e1ant_SetBtAutoReport(pBtCoexist, pCoexDm->bCurBtAutoReport); + + pCoexDm->bPreBtAutoReport = pCoexDm->bCurBtAutoReport; +} + +VOID +halbtc8192e1ant_FwDacSwingLvl( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte fwDacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set FW Dac Swing level = %d\n", + (bForceExec? "force to":""), fwDacSwingLvl)); + pCoexDm->curFwDacSwingLvl = fwDacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preFwDacSwingLvl=%d, curFwDacSwingLvl=%d\n", + pCoexDm->preFwDacSwingLvl, pCoexDm->curFwDacSwingLvl)); + + if(pCoexDm->preFwDacSwingLvl == pCoexDm->curFwDacSwingLvl) + return; + } + + halbtc8192e1ant_SetFwDacSwingLevel(pBtCoexist, pCoexDm->curFwDacSwingLvl); + + pCoexDm->preFwDacSwingLvl = pCoexDm->curFwDacSwingLvl; +} + +VOID +halbtc8192e1ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte tmpU1; + + tmpU1 = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x4fd); + tmpU1 |= BIT0; + if(bLowPenaltyRa) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set low penalty!!\n")); + tmpU1 &= ~BIT2; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set normal!!\n")); + tmpU1 |= BIT2; + } + + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x4fd, tmpU1); +} + +VOID +halbtc8192e1ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); + + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8192e1ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8192e1ant_SetDacSwingReg( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte level + ) +{ + u1Byte val=(u1Byte)level; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Write SwDacSwing = 0x%x\n", level)); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x883, 0x3e, val); +} + +VOID +halbtc8192e1ant_SetSwFullTimeDacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bSwDacSwingOn, + IN u4Byte swDacSwingLvl + ) +{ + if(bSwDacSwingOn) + { + halbtc8192e1ant_SetDacSwingReg(pBtCoexist, swDacSwingLvl); + } + else + { + halbtc8192e1ant_SetDacSwingReg(pBtCoexist, 0x18); + } +} + +VOID +halbtc8192e1ant_DacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDacSwingOn, + IN u4Byte dacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn DacSwing=%s, dacSwingLvl=0x%x\n", + (bForceExec? "force to":""), ((bDacSwingOn)? "ON":"OFF"), dacSwingLvl)); + pCoexDm->bCurDacSwingOn = bDacSwingOn; + pCoexDm->curDacSwingLvl = dacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x, bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + pCoexDm->bPreDacSwingOn, pCoexDm->preDacSwingLvl, + pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl)); + + if( (pCoexDm->bPreDacSwingOn == pCoexDm->bCurDacSwingOn) && + (pCoexDm->preDacSwingLvl == pCoexDm->curDacSwingLvl) ) + return; + } + delay_ms(30); + halbtc8192e1ant_SetSwFullTimeDacSwing(pBtCoexist, bDacSwingOn, dacSwingLvl); + + pCoexDm->bPreDacSwingOn = pCoexDm->bCurDacSwingOn; + pCoexDm->preDacSwingLvl = pCoexDm->curDacSwingLvl; +} + +VOID +halbtc8192e1ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8192e1ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c0, val0x6c4, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c0 = val0x6c0; + pCoexDm->curVal0x6c4 = val0x6c4; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c0=0x%x, preVal0x6c4=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + pCoexDm->preVal0x6c0, pCoexDm->preVal0x6c4, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c0=0x%x, curVal0x6c4=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + pCoexDm->curVal0x6c0, pCoexDm->curVal0x6c4, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && + (pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8192e1ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c4, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; + pCoexDm->preVal0x6c4 = pCoexDm->curVal0x6c4; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8192e1ant_CoexTableWithType( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + switch(type) + { + case 0: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x55555555, 0xffffff, 0x3); + break; + case 1: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x5a5a5a5a, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 3: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0xaaaaaaaa, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 4: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0xffffffff, 0xffffffff, 0xffffff, 0x3); + break; + case 5: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x5fff5fff, 0x5fff5fff, 0xffffff, 0x3); + break; + case 6: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 7: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0xddffddff, 0xddffddff, 0xffffff, 0x3); + break; + case 8: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5afa5afa, 0xffffff, 0x3); + break; + case 9: + halbtc8192e1ant_CoexTable(pBtCoexist, bForceExec, 0x5f5f5f5f, 0x5f5f5f5f, 0xffffff, 0x3); + break; + default: + break; + } +} + +VOID +halbtc8192e1ant_SetFwIgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnable + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + if(bEnable) + { + H2C_Parameter[0] |= BIT0; // function enable + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x63, 1, H2C_Parameter); +} + +VOID +halbtc8192e1ant_IgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); + pCoexDm->bCurIgnoreWlanAct = bEnable; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); + + if(pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) + return; + } + halbtc8192e1ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); + + pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; +} + +VOID +halbtc8192e1ant_SetFwPstdma( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte byte1, + IN u1Byte byte2, + IN u1Byte byte3, + IN u1Byte byte4, + IN u1Byte byte5 + ) +{ + u1Byte H2C_Parameter[5] ={0}; + + H2C_Parameter[0] = byte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = byte5; + + pCoexDm->psTdmaPara[0] = byte1; + pCoexDm->psTdmaPara[1] = byte2; + pCoexDm->psTdmaPara[2] = byte3; + pCoexDm->psTdmaPara[3] = byte4; + pCoexDm->psTdmaPara[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x60(5bytes)=0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x60, 5, H2C_Parameter); +} + +VOID +halbtc8192e1ant_SetLpsRpwm( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + u1Byte lps=lpsVal; + u1Byte rpwm=rpwmVal; + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_LPS_VAL, &lps); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +VOID +halbtc8192e1ant_LpsRpwm( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + BOOLEAN bForceExecPwrCmd=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set lps/rpwm=0x%x/0x%x \n", + (bForceExec? "force to":""), lpsVal, rpwmVal)); + pCoexDm->curLps = lpsVal; + pCoexDm->curRpwm = rpwmVal; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preLps/curLps=0x%x/0x%x, preRpwm/curRpwm=0x%x/0x%x!!\n", + pCoexDm->preLps, pCoexDm->curLps, pCoexDm->preRpwm, pCoexDm->curRpwm)); + + if( (pCoexDm->preLps == pCoexDm->curLps) && + (pCoexDm->preRpwm == pCoexDm->curRpwm) ) + { + return; + } + } + halbtc8192e1ant_SetLpsRpwm(pBtCoexist, lpsVal, rpwmVal); + + pCoexDm->preLps = pCoexDm->curLps; + pCoexDm->preRpwm = pCoexDm->curRpwm; +} + +VOID +halbtc8192e1ant_SetAntPath( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte antPosType, + IN BOOLEAN bInitHwCfg, + IN BOOLEAN bWifiOff + ) +{ + u4Byte u4Tmp=0; + + if(bInitHwCfg) + { + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x944, 0x24); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x930, 0x700700); + if(pBtCoexist->chipInterface == BTC_INTF_USB) + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x64, 0x30430004); + else + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x64, 0x30030004); + + // 0x4c[27][24]='00', Set Antenna to BB + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u4Tmp &= ~BIT24; + u4Tmp &= ~BIT27; + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); + } + else if(bWifiOff) + { + if(pBtCoexist->chipInterface == BTC_INTF_USB) + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x64, 0x30430004); + else + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x64, 0x30030004); + + // 0x4c[27][24]='11', Set Antenna to BT, 0x64[8:7]=0, 0x64[2]=1 + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u4Tmp |= BIT24; + u4Tmp |= BIT27; + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); + } + + // ext switch setting + switch(antPosType) + { + case BTC_ANT_PATH_WIFI: + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x92c, 0x4); + break; + case BTC_ANT_PATH_BT: + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x92c, 0x20); + break; + default: + case BTC_ANT_PATH_PTA: + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x92c, 0x4); + break; + } +} + +VOID +halbtc8192e1ant_PsTdma( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bTurnOn, + IN u1Byte type + ) +{ + BOOLEAN bTurnOnByCnt=FALSE; + u1Byte psTdmaTypeByCnt=0, rssiAdjustVal=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type=%d\n", + (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); + pCoexDm->bCurPsTdmaOn = bTurnOn; + pCoexDm->curPsTdma = type; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + pCoexDm->bPrePsTdmaOn, pCoexDm->bCurPsTdmaOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + pCoexDm->prePsTdma, pCoexDm->curPsTdma)); + + if( (pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && + (pCoexDm->prePsTdma == pCoexDm->curPsTdma) ) + return; + } + if(bTurnOn) + { + switch(type) + { + default: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x53, 0x2c, 0x03, 0x10, 0x50); + break; + case 1: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x53, 0x2c, 0x03, 0x10, 0x50); + rssiAdjustVal = 11; + break; + case 2: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x53, 0x25, 0x03, 0x10, 0x50); + rssiAdjustVal = 14; + break; + case 3: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x40); + break; + case 4: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x14, 0x0); + rssiAdjustVal = 17; + break; + case 5: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x61, 0x15, 0x3, 0x31, 0x0); + break; + case 6: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0x3, 0x0, 0x0); + break; + case 7: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x13, 0xc, 0x5, 0x0, 0x0); + break; + case 8: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x0); + break; + case 9: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x53, 0x1e, 0x03, 0x10, 0x50); + rssiAdjustVal = 18; + break; + case 10: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0xa, 0x0, 0x40); + break; + case 11: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x53, 0x12, 0x03, 0x10, 0x50); + rssiAdjustVal = 20; + break; + case 12: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xeb, 0xa, 0x3, 0x31, 0x18); + break; + + case 15: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0x3, 0x8, 0x0); + break; + case 16: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x10, 0x0); + rssiAdjustVal = 18; + break; + + case 18: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x0); + rssiAdjustVal = 14; + break; + + case 20: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x13, 0x25, 0x25, 0x0, 0x0); + break; + case 21: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x20, 0x3, 0x10, 0x40); + break; + case 22: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x13, 0x8, 0x8, 0x0, 0x40); + break; + case 23: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 24: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x15, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 25: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 26: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 27: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x3, 0x31, 0x98); + rssiAdjustVal = 22; + break; + case 28: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x69, 0x25, 0x3, 0x31, 0x0); + break; + case 29: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xab, 0x1a, 0x1a, 0x1, 0x10); + break; + case 30: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x14, 0x0); + break; + case 31: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x1a, 0x1a, 0, 0x58); + break; + case 32: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xab, 0xa, 0x3, 0x31, 0x90); + break; + case 33: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xa3, 0x25, 0x3, 0x30, 0x90); + break; + case 34: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x1a, 0x1a, 0x0, 0x10); + break; + case 35: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x0, 0x10); + break; + case 36: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x12, 0x3, 0x14, 0x50); + break; + case 37: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x53, 0x25, 0x3, 0x10, 0x50); + break; + case 38: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x90); + break; + } + } + else + { + // disable PS tdma + switch(type) + { + case 8: //0x778 = 1, ant2PTA + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x8, 0x0, 0x0, 0x0, 0x0); + halbtc8192e1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_PTA, FALSE, FALSE); + break; + case 0: //0x778 = 1, ant2BT + default: + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + delay_ms(5); + halbtc8192e1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, FALSE); + break; + case 9: //0x778 = 1, ant2WIFI + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + halbtc8192e1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_WIFI, FALSE, FALSE); + break; + case 10: //0x778 = 3, ant2BT + halbtc8192e1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x8, 0x0); + delay_ms(5); + halbtc8192e1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, FALSE); + break; + } + } + rssiAdjustVal =0; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssiAdjustVal); + + // update pre state + pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; + pCoexDm->prePsTdma = pCoexDm->curPsTdma; +} + +VOID +halbtc8192e1ant_SetSwitchSsType( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte ssType + ) +{ + u1Byte mimoPs=BTC_MIMO_PS_DYNAMIC; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], REAL set SS Type = %d\n", ssType)); + + if(ssType == 1) + { + halbtc8192e1ant_UpdateRaMask(pBtCoexist, FORCE_EXEC, BTC_RATE_DISABLE, 0xfff00000); // disable 2ss + halbtc8192e1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 0); + // switch ofdm path + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xc04, 0x11); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xd04, 0x1); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x90c, 0x81111111); + // switch cck patch + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xe77, 0x4, 0x1); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xa07, 0x81); + mimoPs=BTC_MIMO_PS_STATIC; + } + else if(ssType == 2) + { + halbtc8192e1ant_UpdateRaMask(pBtCoexist, FORCE_EXEC, BTC_RATE_ENABLE, 0xfff00000); // enable 2ss + halbtc8192e1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 8); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xc04, 0x33); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xd04, 0x3); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x90c, 0x81121313); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xe77, 0x4, 0x0); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xa07, 0x41); + mimoPs=BTC_MIMO_PS_DYNAMIC; + } + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_SEND_MIMO_PS, &mimoPs); // set rx 1ss or 2ss +} + +VOID +halbtc8192e1ant_SwitchSsType( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte newSsType + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], %s Switch SS Type = %d\n", + (bForceExec? "force to":""), newSsType)); + pCoexDm->curSsType = newSsType; + + if(!bForceExec) + { + if(pCoexDm->preSsType == pCoexDm->curSsType) + return; + } + halbtc8192e1ant_SetSwitchSsType(pBtCoexist, pCoexDm->curSsType); + + pCoexDm->preSsType = pCoexDm->curSsType; +} + +VOID +halbtc8192e1ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + // hw all off + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +BOOLEAN +halbtc8192e1ant_IsCommonAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bCommon=FALSE, bWifiConnected=FALSE, bWifiBusy=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + + if(!bWifiConnected && + BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n")); + bCommon = TRUE; + } + else if(bWifiConnected && + (BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT non connected-idle!!\n")); + + bCommon = TRUE; + } + else if(!bWifiConnected && + (BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT connected-idle!!\n")); + + bCommon = TRUE; + } + else if(bWifiConnected && + (BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT connected-idle!!\n")); + + bCommon = TRUE; + } + else if(!bWifiConnected && + (BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE != pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT Busy!!\n")); + + bCommon = TRUE; + } + else + { + bCommon = FALSE; + } + + return bCommon; +} + + +VOID +halbtc8192e1ant_TdmaDurationAdjustForAcl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0, btInfoExt; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjustForAcl()\n")); + + if( (BT_8192E_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) || + (BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifiStatus) || + (BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifiStatus) ) + { + if( pCoexDm->curPsTdma != 1 && + pCoexDm->curPsTdma != 2 && + pCoexDm->curPsTdma != 3 && + pCoexDm->curPsTdma != 9 ) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + return; + } + + if(!pCoexDm->bAutoTdmaAdjust) + { + pCoexDm->bAutoTdmaAdjust = TRUE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + btInfoExt = pCoexSta->btInfoExt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n", + up, dn, m, n, WaitCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if �s�� n ��2�� retry count��0, �h�ռeWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration + { + if (WaitCount <= 2) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration + { + if (WaitCount == 1) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + if(result == -1) + { + if( (BT_INFO_8192E_1ANT_A2DP_BASIC_RATE(btInfoExt)) && + ((pCoexDm->curPsTdma == 1) ||(pCoexDm->curPsTdma == 2)) ) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + else if(result == 1) + { + if( (BT_INFO_8192E_1ANT_A2DP_BASIC_RATE(btInfoExt)) && + ((pCoexDm->curPsTdma == 1) ||(pCoexDm->curPsTdma == 2)) ) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + } + + if( pCoexDm->curPsTdma != 1 && + pCoexDm->curPsTdma != 2 && + pCoexDm->curPsTdma != 9 && + pCoexDm->curPsTdma != 11 ) + { + // recover to previous adjust type + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, pCoexDm->psTdmaDuAdjType); + } + } +} + +u1Byte +halbtc8192e1ant_PsTdmaTypeByWifiRssi( + IN s4Byte wifiRssi, + IN s4Byte preWifiRssi, + IN u1Byte wifiRssiThresh + ) +{ + u1Byte psTdmaType=0; + + if(wifiRssi > preWifiRssi) + { + if(wifiRssi > (wifiRssiThresh+5)) + { + psTdmaType = 26; + } + else + { + psTdmaType = 25; + } + } + else + { + if(wifiRssi > wifiRssiThresh) + { + psTdmaType = 26; + } + else + { + psTdmaType = 25; + } + } + + return psTdmaType; +} + +VOID +halbtc8192e1ant_PsTdmaCheckForPowerSaveState( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bNewPsState + ) +{ + u1Byte lpsMode=0x0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_LPS_MODE, &lpsMode); + + if(lpsMode) // already under LPS state + { + if(bNewPsState) + { + // keep state under LPS, do nothing. + } + else + { + // will leave LPS state, turn off psTdma first + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + } + else // NO PS state + { + if(bNewPsState) + { + // will enter LPS state, turn off psTdma first + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + // keep state under NO PS state, do nothing. + } + } +} + +VOID +halbtc8192e1ant_PowerSaveState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte psType, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + BOOLEAN bLowPwrDisable=FALSE; + + switch(psType) + { + case BTC_PS_WIFI_NATIVE: + // recover to original 32k low power setting + bLowPwrDisable = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + break; + case BTC_PS_LPS_ON: + halbtc8192e1ant_PsTdmaCheckForPowerSaveState(pBtCoexist, TRUE); + halbtc8192e1ant_LpsRpwm(pBtCoexist, NORMAL_EXEC, lpsVal, rpwmVal); + // when coex force to enter LPS, do not enter 32k low power. + bLowPwrDisable = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + // power save must executed before psTdma. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_ENTER_LPS, NULL); + break; + case BTC_PS_LPS_OFF: + halbtc8192e1ant_PsTdmaCheckForPowerSaveState(pBtCoexist, FALSE); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + break; + default: + break; + } +} + + +VOID +halbtc8192e1ant_ActionWifiOnly( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); +} + +VOID +halbtc8192e1ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtActive=TRUE, bBtDisabled=FALSE; + + // This function check if bt is disabled + + if( pCoexSta->highPriorityTx == 0 && + pCoexSta->highPriorityRx == 0 && + pCoexSta->lowPriorityTx == 0 && + pCoexSta->lowPriorityRx == 0) + { + bBtActive = FALSE; + } + if( pCoexSta->highPriorityTx == 0xffff && + pCoexSta->highPriorityRx == 0xffff && + pCoexSta->lowPriorityTx == 0xffff && + pCoexSta->lowPriorityRx == 0xffff) + { + bBtActive = FALSE; + } + if(bBtActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + halbtc8192e1ant_ActionWifiOnly(pBtCoexist); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + bPreBtDisabled = bBtDisabled; + if(!bBtDisabled) + { + } + else + { + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + } + } +} + +//============================================= +// +// Software Coex Mechanism start +// +//============================================= + +// SCO only or SCO+PAN(HS) +VOID +halbtc8192e1ant_ActionSco( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +VOID +halbtc8192e1ant_ActionHid( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +//A2DP only / PAN(EDR) only/ A2DP+PAN(HS) +VOID +halbtc8192e1ant_ActionA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +VOID +halbtc8192e1ant_ActionA2dpPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +VOID +halbtc8192e1ant_ActionPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +//PAN(HS) only +VOID +halbtc8192e1ant_ActionPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +//PAN(EDR)+A2DP +VOID +halbtc8192e1ant_ActionPanEdrA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +VOID +halbtc8192e1ant_ActionPanEdrHid( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +// HID+A2DP+PAN(EDR) +VOID +halbtc8192e1ant_ActionHidA2dpPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +VOID +halbtc8192e1ant_ActionHidA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +//============================================= +// +// Non-Software Coex Mechanism start +// +//============================================= +VOID +halbtc8192e1ant_ActionBtInquiry( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + // Note: + // Do not do DacSwing here, use original setting. + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(bBtHsOn) + return; + + if(!bWifiConnected) + { + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } + else if( (pBtLinkInfo->bScoExist) || + (pBtLinkInfo->bHidOnly) ) + { + // SCO/HID-only busy + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 32); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + else + { + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x0); + + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 30); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } +} + +VOID +halbtc8192e1ant_ActionBtScoHidOnlyBusy( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + u1Byte btRssiState=BTC_RSSI_STATE_HIGH; + + if(BT_8192E_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } + else + { + if(pBtLinkInfo->bHidOnly) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + else + { + // dec bt power for diff level + btRssiState = halbtc8192e1ant_BtRssiState(3, 34, 42); + if( (btRssiState == BTC_RSSI_STATE_LOW) || + (btRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + } + else if( (btRssiState == BTC_RSSI_STATE_MEDIUM) || + (btRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 6); + } + + // sw dacSwing + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 0xc); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); + } + } +} + +VOID +halbtc8192e1ant_ActionHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action for HS!!!\n")); + + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + if(BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) + { + // error, should not be here + pCoexDm->errorCondition = 1; + } + else if(BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 6); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 10); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } + else if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && + !pBtCoexist->btLinkInfo.bHidOnly) + { + if(pCoexDm->curSsType == 1) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, TRUE, 6); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 10); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } + } + else + { + halbtc8192e1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } +} + +VOID +halbtc8192e1ant_ActionWifiConnectedBtAclBusy( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + + if(pBtLinkInfo->bHidOnly) + { + halbtc8192e1ant_ActionBtScoHidOnlyBusy(pBtCoexist, wifiStatus); + pCoexDm->bAutoTdmaAdjust = FALSE; + return; + } + + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + if( (pBtLinkInfo->bA2dpOnly) || + (pBtLinkInfo->bHidExist&&pBtLinkInfo->bA2dpExist) ) + { + halbtc8192e1ant_TdmaDurationAdjustForAcl(pBtCoexist, wifiStatus); + } + else if( (pBtLinkInfo->bPanOnly) || + (pBtLinkInfo->bHidExist&&pBtLinkInfo->bPanExist) ) + { + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + else + { + if( (BT_8192E_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) || + (BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifiStatus) || + (BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifiStatus) ) + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + else + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); +} + + +VOID +halbtc8192e1ant_ActionWifiNotConnected( + IN PBTC_COEXIST pBtCoexist + ) +{ + // power save state + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +VOID +halbtc8192e1ant_ActionWifiNotConnectedAssoAuthScan( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +VOID +halbtc8192e1ant_ActionWifiConnectedScan( + IN PBTC_COEXIST pBtCoexist + ) +{ + // power save state + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && !pBtCoexist->btLinkInfo.bHidOnly) + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x0); + else + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8192e1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } + else if( (BT_8192E_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8192e1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } + else + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } +} + + +VOID +halbtc8192e1ant_ActionWifiConnectedSpecialPacket( + IN PBTC_COEXIST pBtCoexist + ) +{ + // power save state + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && !pBtCoexist->btLinkInfo.bHidOnly) + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x0); + else + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8192e1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT); + } + else + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } +} + +VOID +halbtc8192e1ant_ActionWifiConnected( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiConnected=FALSE, bWifiBusy=FALSE; + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + BOOLEAN bUnder4way=FALSE; + u4Byte wifiBw; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect()===>\n")); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(!bWifiConnected) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi not connected<===\n")); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); + if(bUnder4way) + { + halbtc8192e1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n")); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + if(bScan || bLink || bRoam) + { + halbtc8192e1ant_ActionWifiConnectedScan(pBtCoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n")); + return; + } + + // power save state + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && !pBtCoexist->btLinkInfo.bHidOnly) + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x0); + else + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + if(!bWifiBusy) + { + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8192e1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } + else if( (BT_8192E_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8192e1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } + else + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + } + else + { + if(BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + else if(BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + else if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8192e1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } + else if( (BT_8192E_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8192e1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } + else + { + halbtc8192e1ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + } +} + +VOID +halbtc8192e1ant_RunSwCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiUnder5G=FALSE, bWifiBusy=FALSE, bWifiConnected=FALSE; + u1Byte btInfoOriginal=0, btRetryCnt=0; + u1Byte algorithm=0; + + return; + + algorithm = halbtc8192e1ant_ActionAlgorithm(pBtCoexist); + pCoexDm->curAlgorithm = algorithm; + + if(halbtc8192e1ant_IsCommonAction(pBtCoexist)) + { + } + else + { + switch(pCoexDm->curAlgorithm) + { + case BT_8192E_1ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = SCO.\n")); + halbtc8192e1ant_ActionSco(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID.\n")); + halbtc8192e1ant_ActionHid(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP.\n")); + halbtc8192e1ant_ActionA2dp(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP+PAN(HS).\n")); + halbtc8192e1ant_ActionA2dpPanHs(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR).\n")); + halbtc8192e1ant_ActionPanEdr(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HS mode.\n")); + halbtc8192e1ant_ActionPanHs(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN+A2DP.\n")); + halbtc8192e1ant_ActionPanEdrA2dp(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR)+HID.\n")); + halbtc8192e1ant_ActionPanEdrHid(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP+PAN.\n")); + halbtc8192e1ant_ActionHidA2dpPanEdr(pBtCoexist); + break; + case BT_8192E_1ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP.\n")); + halbtc8192e1ant_ActionHidA2dp(pBtCoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = coexist All Off!!\n")); + halbtc8192e1ant_CoexAllOff(pBtCoexist); + break; + } + pCoexDm->preAlgorithm = pCoexDm->curAlgorithm; + } +} + +VOID +halbtc8192e1ant_RunCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism()===>\n")); + + if(pBtCoexist->bManualControl) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n")); + return; + } + + if(pBtCoexist->bStopCoexDm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n")); + return; + } + + if(pCoexSta->bUnderIps) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under IPS !!!\n")); + return; + } + + halbtc8192e1ant_RunSwCoexistMechanism(pBtCoexist); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8192e1ant_ActionBtInquiry(pBtCoexist); + return; + } + + // 1ss or 2ss + if(pBtLinkInfo->bScoExist) + { + halbtc8192e1ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + } + else if(bBtHsOn) + { + if(pBtLinkInfo->bHidOnly) + halbtc8192e1ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8192e1ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + } + else + halbtc8192e1ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 2); + + if(bBtHsOn) + { + halbtc8192e1ant_ActionHs(pBtCoexist); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(!bWifiConnected) + { + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is non connected-idle !!!\n")); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if(bScan || bLink || bRoam) + halbtc8192e1ant_ActionWifiNotConnectedAssoAuthScan(pBtCoexist); + else + halbtc8192e1ant_ActionWifiNotConnected(pBtCoexist); + } + else + { + halbtc8192e1ant_ActionWifiConnected(pBtCoexist); + } +} + +VOID +halbtc8192e1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + // force to reset coex mechanism + halbtc8192e1ant_FwDacSwingLvl(pBtCoexist, FORCE_EXEC, 6); + halbtc8192e1ant_DecBtPwr(pBtCoexist, FORCE_EXEC, 0); + + halbtc8192e1ant_SwitchSsType(pBtCoexist, FORCE_EXEC, 2); + + halbtc8192e1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 8); + halbtc8192e1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); +} + +//============================================================ +// work around function start with wa_halbtc8192e1ant_ +//============================================================ +//============================================================ +// extern function start with EXhalbtc8192e1ant_ +//============================================================ +VOID +EXhalbtc8192e1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte u4Tmp=0; + u2Byte u2Tmp=0; + u1Byte u1Tmp=0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 1Ant Init HW Config!!\n")); + + // antenna sw ctrl to bt + halbtc8192e1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, TRUE, FALSE); + + halbtc8192e1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); + + // antenna switch control parameter + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x858, 0x55555555); + + // coex parameters + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x778, 0x1); + // 0x790[5:0]=0x5 + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x790); + u1Tmp &= 0xc0; + u1Tmp |= 0x5; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x790, u1Tmp); + + // enable counter statistics + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); + + // enable PTA + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x20); + // enable mailbox interface + u2Tmp = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x40); + u2Tmp |= BIT9; + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x40, u2Tmp); + + // enable PTA I2C mailbox + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x101); + u1Tmp |= BIT4; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x101, u1Tmp); + + // enable bt clock when wifi is disabled. + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x93); + u1Tmp |= BIT0; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x93, u1Tmp); + // enable bt clock when suspend. + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x7); + u1Tmp |= BIT0; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x7, u1Tmp); +} + +VOID +EXhalbtc8192e1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + pBtCoexist->bStopCoexDm = FALSE; + + halbtc8192e1ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8192e1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + pu1Byte cliBuf=pBtCoexist->cliBuf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir; + u1Byte wifiDot11Chnl, wifiHsChnl; + u4Byte fwVer=0, btPatchVer=0; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(pBtCoexist->bManualControl) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cliBuf); + } + if(pBtCoexist->bStopCoexDm) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cliBuf); + } + + if(!pBoardInfo->bBtExist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", \ + GLCoexVerDate8192e1Ant, GLCoexVer8192e1Ant, fwVer, btPatchVer, btPatchVer); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ + wifiDot11Chnl, wifiHsChnl, bBtHsOn); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], + pCoexDm->wifiChnlInfo[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((pBtCoexist->btInfo.bBtDisabled)? ("disabled"): ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus)? "non-connected idle": + ( (BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy")))), + pCoexSta->btRssi, pCoexSta->btRetryCnt); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pBtLinkInfo->bScoExist, pBtLinkInfo->bHidExist, pBtLinkInfo->bPanExist, pBtLinkInfo->bA2dpExist); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + + btInfoExt = pCoexSta->btInfoExt; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (btInfoExt&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cliBuf); + + for(i=0; i<BT_INFO_SRC_8192E_1ANT_MAX; i++) + { + if(pCoexSta->btInfoC2hCnt[i]) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8192e1Ant[i], \ + pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], + pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], + pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], + pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); + CL_PRINTF(cliBuf); + } + } + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s, (0x%x/0x%x)", "PS state, IPS/LPS, (lps/rpwm)", \ + ((pCoexSta->bUnderIps? "IPS ON":"IPS OFF")), + ((pCoexSta->bUnderLps? "LPS ON":"LPS OFF")), + pBtCoexist->btInfo.lpsVal, + pBtCoexist->btInfo.rpwmVal); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "SS Type", \ + pCoexDm->curSsType); + CL_PRINTF(cliBuf); + + if(!pBtCoexist->bManualControl) + { + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d(0x%x) ", "SM[SwDacSwing(lvl)]", \ + pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %d ", "DelBA/ BtCtrlAgg/ AggSize", \ + (pBtCoexist->btInfo.bRejectAggPkt? "Yes":"No"), (pBtCoexist->btInfo.bBtCtrlAggBufSize? "Yes":"No"), + pBtCoexist->btInfo.aggBufSize); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask", \ + pBtCoexist->btInfo.raMask); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + psTdmaCase = pCoexDm->curPsTdma; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA", \ + pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], + pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], + pCoexDm->psTdmaPara[4], psTdmaCase, pCoexDm->bAutoTdmaAdjust); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Latest error condition(should be 0)", \ + pCoexDm->errorCondition); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "DecBtPwrLvl/ IgnWlanAct", \ + pCoexDm->curBtDecPwrLvl, pCoexDm->bCurIgnoreWlanAct); + CL_PRINTF(cliBuf); + } + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc04); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xd04); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x90c); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0xc04/ 0xd04/ 0x90c", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x778); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x778", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x92c); + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x930); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x92c/ 0x930", \ + (u1Tmp[0]), u4Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x4f); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x40/ 0x4f", \ + u1Tmp[0], u1Tmp[1]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x550); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x522); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp[0]); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770(hp rx[31:16]/tx[15:0])", \ + pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(lp rx[31:16]/tx[15:0])", \ + pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); + CL_PRINTF(cliBuf); +#if(BT_AUTO_REPORT_ONLY_8192E_1ANT == 1) + halbtc8192e1ant_MonitorBtCtr(pBtCoexist); +#endif + + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8192e1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u4Byte u4Tmp=0; + + if(pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm) + return; + + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + pCoexSta->bUnderIps = TRUE; + halbtc8192e1ant_CoexAllOff(pBtCoexist); + halbtc8192e1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, TRUE); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + pCoexSta->bUnderIps = FALSE; + } +} + +VOID +EXhalbtc8192e1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm) + return; + + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + pCoexSta->bUnderLps = TRUE; + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + pCoexSta->bUnderLps = FALSE; + } +} + +VOID +EXhalbtc8192e1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8192e1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8192e1ant_ActionHs(pBtCoexist); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + if(!bWifiConnected) // non-connected scan + { + halbtc8192e1ant_ActionWifiNotConnectedAssoAuthScan(pBtCoexist); + } + else // wifi is connected + { + halbtc8192e1ant_ActionWifiConnectedScan(pBtCoexist); + } + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + if(!bWifiConnected) // non-connected scan + { + halbtc8192e1ant_ActionWifiNotConnected(pBtCoexist); + } + else + { + halbtc8192e1ant_ActionWifiConnected(pBtCoexist); + } + } +} + +VOID +EXhalbtc8192e1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8192e1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8192e1ant_ActionHs(pBtCoexist); + return; + } + + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + halbtc8192e1ant_ActionWifiNotConnectedAssoAuthScan(pBtCoexist); + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(!bWifiConnected) // non-connected scan + { + halbtc8192e1ant_ActionWifiNotConnected(pBtCoexist); + } + else + { + halbtc8192e1ant_ActionWifiConnected(pBtCoexist); + } + } +} + +VOID +EXhalbtc8192e1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u1Byte H2C_Parameter[3] ={0}; + u4Byte wifiBw; + u1Byte wifiCentralChnl; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } + + // only 2.4G we need to inform bt the chnl mask + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); + if( (BTC_MEDIA_CONNECT == type) && + (wifiCentralChnl <= 14) ) + { + H2C_Parameter[0] = 0x1; + H2C_Parameter[1] = wifiCentralChnl; + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + H2C_Parameter[2] = 0x30; + else + H2C_Parameter[2] = 0x20; + } + + pCoexDm->wifiChnlInfo[0] = H2C_Parameter[0]; + pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1]; + pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x66=0x%x\n", + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x66, 3, H2C_Parameter); +} + +VOID +EXhalbtc8192e1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bBtHsOn=FALSE; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8192e1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8192e1ant_ActionHs(pBtCoexist); + return; + } + + if( BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type ) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], special Packet(%d) notify\n", type)); + halbtc8192e1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); + } +} + +VOID +EXhalbtc8192e1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + u1Byte btInfo=0; + u1Byte i, rspSource=0; + static u4Byte setBtPsdMode=0; + BOOLEAN bBtBusy=FALSE; + BOOLEAN bWifiConnected=FALSE; + BOOLEAN bBtCtrlAggBufSize=FALSE; + + pCoexSta->bC2hBtInfoReqSent = FALSE; + + rspSource = tmpBuf[0]&0xf; + if(rspSource >= BT_INFO_SRC_8192E_1ANT_MAX) + rspSource = BT_INFO_SRC_8192E_1ANT_WIFI_FW; + pCoexSta->btInfoC2hCnt[rspSource]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rspSource, length)); + for(i=0; i<length; i++) + { + pCoexSta->btInfoC2h[rspSource][i] = tmpBuf[i]; + if(i == 1) + btInfo = tmpBuf[i]; + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); + } + } + + if(pBtCoexist->btInfo.bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for BT is disabled <===\n")); + return; + } + + if(pBtCoexist->bManualControl) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for Manual CTRL<===\n")); + return; + } + if(pBtCoexist->bStopCoexDm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for Coex STOPPED!!<===\n")); + return; + } + + if(BT_INFO_SRC_8192E_1ANT_WIFI_FW != rspSource) + { + pCoexSta->btRetryCnt = // [3:0] + pCoexSta->btInfoC2h[rspSource][2]&0xf; + + pCoexSta->btRssi = + pCoexSta->btInfoC2h[rspSource][3]*2+10; + + pCoexSta->btInfoExt = + pCoexSta->btInfoC2h[rspSource][4]; + + // Here we need to resend some wifi info to BT + // because bt is reset and loss of the info. + if( (pCoexSta->btInfoExt & BIT1) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n")); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(bWifiConnected) + { + EXhalbtc8192e1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_CONNECT); + } + else + { + EXhalbtc8192e1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); + } + + setBtPsdMode = 0; + } + + // test-chip bt patch only rsp the status for BT_RSP, + // so temporary we consider the following only under BT_RSP + if(BT_INFO_SRC_8192E_1ANT_BT_RSP == rspSource) + { + if( (pCoexSta->btInfoExt & BIT3) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n")); + halbtc8192e1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); + } + else + { + // BT already NOT ignore Wlan active, do nothing here. + } +#if(BT_AUTO_REPORT_ONLY_8192E_1ANT == 0) + if( (pCoexSta->btInfoExt & BIT4) ) + { + // BT auto report already enabled, do nothing + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit4 check, set BT to enable Auto Report!!\n")); + halbtc8192e1ant_BtAutoReport(pBtCoexist, FORCE_EXEC, TRUE); + } +#endif + } + } + + // check BIT2 first ==> check if bt is under inquiry or page scan + if(btInfo & BT_INFO_8192E_1ANT_B_INQ_PAGE) + pCoexSta->bC2hBtInquiryPage = TRUE; + else + pCoexSta->bC2hBtInquiryPage = FALSE; + + // set link exist status + if(!(btInfo&BT_INFO_8192E_1ANT_B_CONNECTION)) + { + pCoexSta->bBtLinkExist = FALSE; + pCoexSta->bPanExist = FALSE; + pCoexSta->bA2dpExist = FALSE; + pCoexSta->bHidExist = FALSE; + pCoexSta->bScoExist = FALSE; + } + else // connection exists + { + pCoexSta->bBtLinkExist = TRUE; + if(btInfo & BT_INFO_8192E_1ANT_B_FTP) + pCoexSta->bPanExist = TRUE; + else + pCoexSta->bPanExist = FALSE; + if(btInfo & BT_INFO_8192E_1ANT_B_A2DP) + pCoexSta->bA2dpExist = TRUE; + else + pCoexSta->bA2dpExist = FALSE; + if(btInfo & BT_INFO_8192E_1ANT_B_HID) + pCoexSta->bHidExist = TRUE; + else + pCoexSta->bHidExist = FALSE; + if(btInfo & BT_INFO_8192E_1ANT_B_SCO_ESCO) + pCoexSta->bScoExist = TRUE; + else + pCoexSta->bScoExist = FALSE; + } + + halbtc8192e1ant_UpdateBtLinkInfo(pBtCoexist); + + if(!(btInfo&BT_INFO_8192E_1ANT_B_CONNECTION)) + { + pCoexDm->btStatus = BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt non-connected idle!!!\n")); + } + else if(btInfo == BT_INFO_8192E_1ANT_B_CONNECTION) // connection exists but no busy + { + pCoexDm->btStatus = BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt connected-idle!!!\n")); + } + else if((btInfo&BT_INFO_8192E_1ANT_B_SCO_ESCO) || + (btInfo&BT_INFO_8192E_1ANT_B_SCO_BUSY)) + { + pCoexDm->btStatus = BT_8192E_1ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt sco busy!!!\n")); + } + else if( (btInfo&BT_INFO_8192E_1ANT_B_ACL_BUSY) || + (btInfo&BT_INFO_8192E_1ANT_B_A2DP) || + (btInfo&BT_INFO_8192E_1ANT_B_FTP) ) + { + if(BT_8192E_1ANT_BT_STATUS_ACL_BUSY != pCoexDm->btStatus) + pCoexDm->bAutoTdmaAdjust = FALSE; + pCoexDm->btStatus = BT_8192E_1ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt acl busy!!!\n")); + } + else + { + pCoexDm->btStatus = BT_8192E_1ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt non-defined state!!!\n")); + } + + // ra mask check + if(pBtLinkInfo->bScoExist || pBtLinkInfo->bHidExist) + { + halbtc8192e1ant_UpdateRaMask(pBtCoexist, NORMAL_EXEC, BTC_RATE_DISABLE, 0x00000003); // disable tx cck 1M/2M + } + else + { + halbtc8192e1ant_UpdateRaMask(pBtCoexist, NORMAL_EXEC, BTC_RATE_ENABLE, 0x00000003); // enable tx cck 1M/2M + } + + if( (BT_8192E_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || + (BT_8192E_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + bBtBusy = TRUE; + if(pBtLinkInfo->bHidExist) + bBtCtrlAggBufSize = TRUE; + } + else + { + bBtBusy = FALSE; + } + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + + //============================================ + // Aggregation related setting + //============================================ + // if sco, reject AddBA + //pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &bRejApAggPkt); + + // decide BT control aggregation buf size or not + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, &bBtCtrlAggBufSize); + // real update aggregation setting + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + //============================================ + + halbtc8192e1ant_RunCoexistMechanism(pBtCoexist); +} + +VOID +EXhalbtc8192e1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + pBtCoexist->bStopCoexDm = TRUE; + halbtc8192e1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8192e1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, TRUE); + + EXhalbtc8192e1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8192e1ant_PnpNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pnpState + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify\n")); + + if(BTC_WIFI_PNP_SLEEP == pnpState) + { + pBtCoexist->bStopCoexDm = TRUE; + halbtc8192e1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + } + else if(BTC_WIFI_PNP_WAKE_UP == pnpState) + { + + } +} + +VOID +EXhalbtc8192e1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + static u1Byte disVerInfoCnt=0; + u4Byte fwVer=0, btPatchVer=0; + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ==========================Periodical===========================\n")); + + if(disVerInfoCnt <= 5) + { + disVerInfoCnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum, pBoardInfo->btdmAntPos)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], BT stack/ hci ext ver = %s / %d\n", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion)); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", \ + GLCoexVerDate8192e1Ant, GLCoexVer8192e1Ant, fwVer, btPatchVer, btPatchVer)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + } +#if(BT_AUTO_REPORT_ONLY_8192E_1ANT == 0) + halbtc8192e1ant_QueryBtInfo(pBtCoexist); + halbtc8192e1ant_MonitorBtCtr(pBtCoexist); + halbtc8192e1ant_MonitorBtEnableDisable(pBtCoexist); +#else + if( halbtc8192e1ant_IsWifiStatusChanged(pBtCoexist) || + pCoexDm->bAutoTdmaAdjust) + { + halbtc8192e1ant_RunCoexistMechanism(pBtCoexist); + } +#endif +} + +VOID +EXhalbtc8192e1ant_DbgControl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte opCode, + IN u1Byte opLen, + IN pu1Byte pData + ) +{ + switch(opCode) + { + case BTC_DBG_SET_COEX_NORMAL: + pBtCoexist->bManualControl = FALSE; + halbtc8192e1ant_InitCoexDm(pBtCoexist); + break; + case BTC_DBG_SET_COEX_WIFI_ONLY: + pBtCoexist->bManualControl = TRUE; + halbtc8192e1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8192e1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + break; + case BTC_DBG_SET_COEX_BT_ONLY: + // todo + break; + default: + break; + } +} +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e1Ant.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e1Ant.h new file mode 100644 index 0000000..9dde00d --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e1Ant.h @@ -0,0 +1,209 @@ +//=========================================== +// The following is for 8192E_1ANT BT Co-exist definition +//=========================================== +#define BT_AUTO_REPORT_ONLY_8192E_1ANT 0 + +#define BT_INFO_8192E_1ANT_B_FTP BIT7 +#define BT_INFO_8192E_1ANT_B_A2DP BIT6 +#define BT_INFO_8192E_1ANT_B_HID BIT5 +#define BT_INFO_8192E_1ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8192E_1ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8192E_1ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8192E_1ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8192E_1ANT_B_CONNECTION BIT0 + +#define BT_INFO_8192E_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT0))? TRUE:FALSE) + +#define BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT 2 + +typedef enum _BT_INFO_SRC_8192E_1ANT{ + BT_INFO_SRC_8192E_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8192E_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8192E_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8192E_1ANT_MAX +}BT_INFO_SRC_8192E_1ANT,*PBT_INFO_SRC_8192E_1ANT; + +typedef enum _BT_8192E_1ANT_BT_STATUS{ + BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8192E_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8192E_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8192E_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8192E_1ANT_BT_STATUS_MAX +}BT_8192E_1ANT_BT_STATUS,*PBT_8192E_1ANT_BT_STATUS; + +typedef enum _BT_8192E_1ANT_WIFI_STATUS{ + BT_8192E_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8192E_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT = 0x3, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8192E_1ANT_WIFI_STATUS_MAX +}BT_8192E_1ANT_WIFI_STATUS,*PBT_8192E_1ANT_WIFI_STATUS; + +typedef enum _BT_8192E_1ANT_COEX_ALGO{ + BT_8192E_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8192E_1ANT_COEX_ALGO_SCO = 0x1, + BT_8192E_1ANT_COEX_ALGO_HID = 0x2, + BT_8192E_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8192E_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8192E_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8192E_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8192E_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8192E_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8192E_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8192E_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8192E_1ANT_COEX_ALGO_MAX = 0xb, +}BT_8192E_1ANT_COEX_ALGO,*PBT_8192E_1ANT_COEX_ALGO; + +typedef struct _COEX_DM_8192E_1ANT{ + // fw mechanism + u1Byte preBtDecPwrLvl; + u1Byte curBtDecPwrLvl; + u1Byte preFwDacSwingLvl; + u1Byte curFwDacSwingLvl; + BOOLEAN bCurIgnoreWlanAct; + BOOLEAN bPreIgnoreWlanAct; + u1Byte prePsTdma; + u1Byte curPsTdma; + u1Byte psTdmaPara[5]; + u1Byte psTdmaDuAdjType; + BOOLEAN bAutoTdmaAdjust; + BOOLEAN bPrePsTdmaOn; + BOOLEAN bCurPsTdmaOn; + BOOLEAN bPreBtAutoReport; + BOOLEAN bCurBtAutoReport; + u1Byte preLps; + u1Byte curLps; + u1Byte preRpwm; + u1Byte curRpwm; + + // sw mechanism + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + BOOLEAN bPreDacSwingOn; + u4Byte preDacSwingLvl; + BOOLEAN bCurDacSwingOn; + u4Byte curDacSwingLvl; + u4Byte preVal0x6c0; + u4Byte curVal0x6c0; + u4Byte preVal0x6c4; + u4Byte curVal0x6c4; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u1Byte preVal0x6cc; + u1Byte curVal0x6cc; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + u1Byte btStatus; + u1Byte wifiChnlInfo[3]; + + u1Byte preSsType; + u1Byte curSsType; + + u4Byte preRaMask; + u4Byte curRaMask; + + u1Byte errorCondition; +} COEX_DM_8192E_1ANT, *PCOEX_DM_8192E_1ANT; + +typedef struct _COEX_STA_8192E_1ANT{ + BOOLEAN bBtLinkExist; + BOOLEAN bScoExist; + BOOLEAN bA2dpExist; + BOOLEAN bHidExist; + BOOLEAN bPanExist; + + BOOLEAN bUnderLps; + BOOLEAN bUnderIps; + u4Byte highPriorityTx; + u4Byte highPriorityRx; + u4Byte lowPriorityTx; + u4Byte lowPriorityRx; + u1Byte btRssi; + u1Byte preBtRssiState; + u1Byte preWifiRssiState[4]; + BOOLEAN bC2hBtInfoReqSent; + u1Byte btInfoC2h[BT_INFO_SRC_8192E_1ANT_MAX][10]; + u4Byte btInfoC2hCnt[BT_INFO_SRC_8192E_1ANT_MAX]; + BOOLEAN bC2hBtInquiryPage; + u1Byte btRetryCnt; + u1Byte btInfoExt; +}COEX_STA_8192E_1ANT, *PCOEX_STA_8192E_1ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8192e1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8192e1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e1ant_PnpNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pnpState + ); +VOID +EXhalbtc8192e1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e1ant_DbgControl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte opCode, + IN u1Byte opLen, + IN pu1Byte pData + ); diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e2Ant.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e2Ant.c new file mode 100644 index 0000000..d4e5378 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e2Ant.c @@ -0,0 +1,4398 @@ +//============================================================ +// Description: +// +// This file is for RTL8192E Co-exist mechanism +// +// History +// 2012/11/15 Cosa first check in. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8192E_2ANT GLCoexDm8192e2Ant; +static PCOEX_DM_8192E_2ANT pCoexDm=&GLCoexDm8192e2Ant; +static COEX_STA_8192E_2ANT GLCoexSta8192e2Ant; +static PCOEX_STA_8192E_2ANT pCoexSta=&GLCoexSta8192e2Ant; + +const char *const GLBtInfoSrc8192e2Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u4Byte GLCoexVerDate8192e2Ant=20130912; +u4Byte GLCoexVer8192e2Ant=0x35; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8192e2ant_ +//============================================================ +u1Byte +halbtc8192e2ant_BtRssiState( + u1Byte levelNum, + u1Byte rssiThresh, + u1Byte rssiThresh1 + ) +{ + s4Byte btRssi=0; + u1Byte btRssiState=pCoexSta->preBtRssiState; + + btRssi = pCoexSta->btRssi; + + if(levelNum == 2) + { + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi pre state=LOW\n")); + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi pre state=HIGH\n")); + if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); + return pCoexSta->preBtRssiState; + } + + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi pre state=LOW\n")); + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi pre state=MEDIUM\n")); + if(btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi pre state=HIGH\n")); + if(btRssi < rssiThresh1) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + + pCoexSta->preBtRssiState = btRssiState; + + return btRssiState; +} + +u1Byte +halbtc8192e2ant_WifiRssiState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte index, + IN u1Byte levelNum, + IN u1Byte rssiThresh, + IN u1Byte rssiThresh1 + ) +{ + s4Byte wifiRssi=0; + u1Byte wifiRssiState=pCoexSta->preWifiRssiState[index]; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(levelNum == 2) + { + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return pCoexSta->preWifiRssiState[index]; + } + + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifiRssi < rssiThresh1) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + pCoexSta->preWifiRssiState[index] = wifiRssiState; + + return wifiRssiState; +} + +VOID +halbtc8192e2ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtActive=TRUE, bBtDisabled=FALSE; + + // This function check if bt is disabled + + if( pCoexSta->highPriorityTx == 0 && + pCoexSta->highPriorityRx == 0 && + pCoexSta->lowPriorityTx == 0 && + pCoexSta->lowPriorityRx == 0) + { + bBtActive = FALSE; + } + if( pCoexSta->highPriorityTx == 0xffff && + pCoexSta->highPriorityRx == 0xffff && + pCoexSta->lowPriorityTx == 0xffff && + pCoexSta->lowPriorityRx == 0xffff) + { + bBtActive = FALSE; + } + if(bBtActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + bPreBtDisabled = bBtDisabled; + if(!bBtDisabled) + { + } + else + { + } + } +} + +u4Byte +halbtc8192e2ant_DecideRaMask( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte ssType, + IN u4Byte raMaskType + ) +{ + u4Byte disRaMask=0x0; + + switch(raMaskType) + { + case 0: // normal mode + if(ssType == 2) + disRaMask = 0x0; // enable 2ss + else + disRaMask = 0xfff00000; // disable 2ss + break; + case 1: // disable cck 1/2 + if(ssType == 2) + disRaMask = 0x00000003; // enable 2ss + else + disRaMask = 0xfff00003; // disable 2ss + break; + case 2: // disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 + if(ssType == 2) + disRaMask = 0x0001f1f7; // enable 2ss + else + disRaMask = 0xfff1f1f7; // disable 2ss + break; + default: + break; + } + + return disRaMask; +} + +VOID +halbtc8192e2ant_UpdateRaMask( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte disRateMask + ) +{ + pCoexDm->curRaMask = disRateMask; + + if( bForceExec || (pCoexDm->preRaMask != pCoexDm->curRaMask)) + { + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_UPDATE_RAMASK, &pCoexDm->curRaMask); + } + pCoexDm->preRaMask = pCoexDm->curRaMask; +} + +VOID +halbtc8192e2ant_AutoRateFallbackRetry( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + BOOLEAN bWifiUnderBMode=FALSE; + + pCoexDm->curArfrType = type; + + if( bForceExec || (pCoexDm->preArfrType != pCoexDm->curArfrType)) + { + switch(pCoexDm->curArfrType) + { + case 0: // normal mode + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, pCoexDm->backupArfrCnt1); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, pCoexDm->backupArfrCnt2); + break; + case 1: + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, &bWifiUnderBMode); + if(bWifiUnderBMode) + { + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, 0x0); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, 0x01010101); + } + else + { + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, 0x0); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, 0x04030201); + } + break; + default: + break; + } + } + + pCoexDm->preArfrType = pCoexDm->curArfrType; +} + +VOID +halbtc8192e2ant_RetryLimit( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + pCoexDm->curRetryLimitType = type; + + if( bForceExec || (pCoexDm->preRetryLimitType != pCoexDm->curRetryLimitType)) + { + switch(pCoexDm->curRetryLimitType) + { + case 0: // normal mode + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x42a, pCoexDm->backupRetryLimit); + break; + case 1: // retry limit=8 + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x42a, 0x0808); + break; + default: + break; + } + } + + pCoexDm->preRetryLimitType = pCoexDm->curRetryLimitType; +} + +VOID +halbtc8192e2ant_AmpduMaxTime( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + pCoexDm->curAmpduTimeType = type; + + if( bForceExec || (pCoexDm->preAmpduTimeType != pCoexDm->curAmpduTimeType)) + { + switch(pCoexDm->curAmpduTimeType) + { + case 0: // normal mode + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x456, pCoexDm->backupAmpduMaxTime); + break; + case 1: // AMPDU timw = 0x38 * 32us + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x456, 0x38); + break; + default: + break; + } + } + + pCoexDm->preAmpduTimeType = pCoexDm->curAmpduTimeType; +} + +VOID +halbtc8192e2ant_LimitedTx( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte raMaskType, + IN u1Byte arfrType, + IN u1Byte retryLimitType, + IN u1Byte ampduTimeType + ) +{ + u4Byte disRaMask=0x0; + + pCoexDm->curRaMaskType = raMaskType; + disRaMask = halbtc8192e2ant_DecideRaMask(pBtCoexist, pCoexDm->curSsType, raMaskType); + halbtc8192e2ant_UpdateRaMask(pBtCoexist, bForceExec, disRaMask); + + halbtc8192e2ant_AutoRateFallbackRetry(pBtCoexist, bForceExec, arfrType); + halbtc8192e2ant_RetryLimit(pBtCoexist, bForceExec, retryLimitType); + halbtc8192e2ant_AmpduMaxTime(pBtCoexist, bForceExec, ampduTimeType); +} + +VOID +halbtc8192e2ant_LimitedRx( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRejApAggPkt, + IN BOOLEAN bBtCtrlAggBufSize, + IN u1Byte aggBufSize + ) +{ + BOOLEAN bRejectRxAgg=bRejApAggPkt; + BOOLEAN bBtCtrlRxAggSize=bBtCtrlAggBufSize; + u1Byte rxAggSize=aggBufSize; + + //============================================ + // Rx Aggregation related setting + //============================================ + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &bRejectRxAgg); + // decide BT control aggregation buf size or not + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, &bBtCtrlRxAggSize); + // aggregation buf size, only work when BT control Rx aggregation size. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_AGG_BUF_SIZE, &rxAggSize); + // real update aggregation setting + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +VOID +halbtc8192e2ant_MonitorBtCtr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte regHPTxRx, regLPTxRx, u4Tmp; + u4Byte regHPTx=0, regHPRx=0, regLPTx=0, regLPRx=0; + u1Byte u1Tmp; + + regHPTxRx = 0x770; + regLPTxRx = 0x774; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); + regHPTx = u4Tmp & bMaskLWord; + regHPRx = (u4Tmp & bMaskHWord)>>16; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); + regLPTx = u4Tmp & bMaskLWord; + regLPRx = (u4Tmp & bMaskHWord)>>16; + + pCoexSta->highPriorityTx = regHPTx; + pCoexSta->highPriorityRx = regHPRx; + pCoexSta->lowPriorityTx = regLPTx; + pCoexSta->lowPriorityRx = regLPRx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regHPTxRx, regHPTx, regHPTx, regHPRx, regHPRx)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regLPTxRx, regLPTx, regLPTx, regLPRx, regLPRx)); + + // reset counter + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); +} + +VOID +halbtc8192e2ant_QueryBtInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + pCoexSta->bC2hBtInfoReqSent = TRUE; + + H2C_Parameter[0] |= BIT0; // trigger + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Query Bt Info, FW write 0x61=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x61, 1, H2C_Parameter); +} + +BOOLEAN +halbtc8192e2ant_IsWifiStatusChanged( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreWifiBusy=FALSE, bPreUnder4way=FALSE, bPreBtHsOn=FALSE; + BOOLEAN bWifiBusy=FALSE, bUnder4way=FALSE, bBtHsOn=FALSE; + BOOLEAN bWifiConnected=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); + + if(bWifiConnected) + { + if(bWifiBusy != bPreWifiBusy) + { + bPreWifiBusy = bWifiBusy; + return TRUE; + } + if(bUnder4way != bPreUnder4way) + { + bPreUnder4way = bUnder4way; + return TRUE; + } + if(bBtHsOn != bPreBtHsOn) + { + bPreBtHsOn = bBtHsOn; + return TRUE; + } + } + + return FALSE; +} + +VOID +halbtc8192e2ant_UpdateBtLinkInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bBtHsOn=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + pBtLinkInfo->bBtLinkExist = pCoexSta->bBtLinkExist; + pBtLinkInfo->bScoExist = pCoexSta->bScoExist; + pBtLinkInfo->bA2dpExist = pCoexSta->bA2dpExist; + pBtLinkInfo->bPanExist = pCoexSta->bPanExist; + pBtLinkInfo->bHidExist = pCoexSta->bHidExist; + + // work around for HS mode. + if(bBtHsOn) + { + pBtLinkInfo->bPanExist = TRUE; + pBtLinkInfo->bBtLinkExist = TRUE; + } + + // check if Sco only + if( pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bScoOnly = TRUE; + else + pBtLinkInfo->bScoOnly = FALSE; + + // check if A2dp only + if( !pBtLinkInfo->bScoExist && + pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bA2dpOnly = TRUE; + else + pBtLinkInfo->bA2dpOnly = FALSE; + + // check if Pan only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bPanOnly = TRUE; + else + pBtLinkInfo->bPanOnly = FALSE; + + // check if Hid only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + pBtLinkInfo->bHidExist ) + pBtLinkInfo->bHidOnly = TRUE; + else + pBtLinkInfo->bHidOnly = FALSE; +} + +u1Byte +halbtc8192e2ant_ActionAlgorithm( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + BOOLEAN bBtHsOn=FALSE; + u1Byte algorithm=BT_8192E_2ANT_COEX_ALGO_UNDEFINED; + u1Byte numOfDiffProfile=0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(!pBtLinkInfo->bBtLinkExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No BT link exists!!!\n")); + return algorithm; + } + + if(pBtLinkInfo->bScoExist) + numOfDiffProfile++; + if(pBtLinkInfo->bHidExist) + numOfDiffProfile++; + if(pBtLinkInfo->bPanExist) + numOfDiffProfile++; + if(pBtLinkInfo->bA2dpExist) + numOfDiffProfile++; + + if(numOfDiffProfile == 1) + { + if(pBtLinkInfo->bScoExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO only\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } + else + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_A2DP; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(HS) only\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(EDR) only\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR; + } + } + } + } + else if(numOfDiffProfile == 2) + { + if(pBtLinkInfo->bScoExist) + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP ==> SCO\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(HS)\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(EDR)\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO_PAN; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + if(pStackInfo->numOfHid >= 2) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID*2 + A2DP\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_HID_A2DP; + } + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(HS)\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_HID; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } + else if(numOfDiffProfile == 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP ==> HID\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(HS)\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(EDR)\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO_PAN; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(HS)\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + else if(numOfDiffProfile >= 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n")); + + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n")); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +VOID +halbtc8192e2ant_SetFwDacSwingLevel( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte dacSwingLvl + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + // There are several type of dacswing + // 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 + H2C_Parameter[0] = dacSwingLvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Set Dac Swing Level=0x%x\n", dacSwingLvl)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x64=0x%x\n", H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x64, 1, H2C_Parameter); +} + +VOID +halbtc8192e2ant_SetFwDecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte decBtPwrLvl + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = decBtPwrLvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], decrease Bt Power level = %d, FW write 0x62=0x%x\n", + decBtPwrLvl, H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x62, 1, H2C_Parameter); +} + +VOID +halbtc8192e2ant_DecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte decBtPwrLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s Dec BT power level = %d\n", + (bForceExec? "force to":""), decBtPwrLvl)); + pCoexDm->curBtDecPwrLvl = decBtPwrLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preBtDecPwrLvl=%d, curBtDecPwrLvl=%d\n", + pCoexDm->preBtDecPwrLvl, pCoexDm->curBtDecPwrLvl)); +#if 0 // work around, avoid h2c command fail. + if(pCoexDm->preBtDecPwrLvl == pCoexDm->curBtDecPwrLvl) + return; +#endif + } + halbtc8192e2ant_SetFwDecBtPwr(pBtCoexist, pCoexDm->curBtDecPwrLvl); + + pCoexDm->preBtDecPwrLvl = pCoexDm->curBtDecPwrLvl; +} + +VOID +halbtc8192e2ant_SetBtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnableAutoReport + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = 0; + + if(bEnableAutoReport) + { + H2C_Parameter[0] |= BIT0; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], BT FW auto report : %s, FW write 0x68=0x%x\n", + (bEnableAutoReport? "Enabled!!":"Disabled!!"), H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x68, 1, H2C_Parameter); +} + +VOID +halbtc8192e2ant_BtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnableAutoReport + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT Auto report = %s\n", + (bForceExec? "force to":""), ((bEnableAutoReport)? "Enabled":"Disabled"))); + pCoexDm->bCurBtAutoReport = bEnableAutoReport; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtAutoReport=%d, bCurBtAutoReport=%d\n", + pCoexDm->bPreBtAutoReport, pCoexDm->bCurBtAutoReport)); + + if(pCoexDm->bPreBtAutoReport == pCoexDm->bCurBtAutoReport) + return; + } + halbtc8192e2ant_SetBtAutoReport(pBtCoexist, pCoexDm->bCurBtAutoReport); + + pCoexDm->bPreBtAutoReport = pCoexDm->bCurBtAutoReport; +} + +VOID +halbtc8192e2ant_FwDacSwingLvl( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte fwDacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set FW Dac Swing level = %d\n", + (bForceExec? "force to":""), fwDacSwingLvl)); + pCoexDm->curFwDacSwingLvl = fwDacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preFwDacSwingLvl=%d, curFwDacSwingLvl=%d\n", + pCoexDm->preFwDacSwingLvl, pCoexDm->curFwDacSwingLvl)); + + if(pCoexDm->preFwDacSwingLvl == pCoexDm->curFwDacSwingLvl) + return; + } + + halbtc8192e2ant_SetFwDacSwingLevel(pBtCoexist, pCoexDm->curFwDacSwingLvl); + + pCoexDm->preFwDacSwingLvl = pCoexDm->curFwDacSwingLvl; +} + +VOID +halbtc8192e2ant_SetSwRfRxLpfCorner( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bRxRfShrinkOn + ) +{ + if(bRxRfShrinkOn) + { + //Shrink RF Rx LPF corner + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Shrink RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, 0xffffc); + } + else + { + //Resume RF Rx LPF corner + // After initialized, we can use pCoexDm->btRf0x1eBackup + if(pBtCoexist->bInitilized) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, pCoexDm->btRf0x1eBackup); + } + } +} + +VOID +halbtc8192e2ant_RfShrink( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRxRfShrinkOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn Rx RF Shrink = %s\n", + (bForceExec? "force to":""), ((bRxRfShrinkOn)? "ON":"OFF"))); + pCoexDm->bCurRfRxLpfShrink = bRxRfShrinkOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreRfRxLpfShrink=%d, bCurRfRxLpfShrink=%d\n", + pCoexDm->bPreRfRxLpfShrink, pCoexDm->bCurRfRxLpfShrink)); + + if(pCoexDm->bPreRfRxLpfShrink == pCoexDm->bCurRfRxLpfShrink) + return; + } + halbtc8192e2ant_SetSwRfRxLpfCorner(pBtCoexist, pCoexDm->bCurRfRxLpfShrink); + + pCoexDm->bPreRfRxLpfShrink = pCoexDm->bCurRfRxLpfShrink; +} + +VOID +halbtc8192e2ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte H2C_Parameter[6] ={0}; + + H2C_Parameter[0] = 0x6; // opCode, 0x6= Retry_Penalty + + if(bLowPenaltyRa) + { + H2C_Parameter[1] |= BIT0; + H2C_Parameter[2] = 0x00; //normal rate except MCS7/6/5, OFDM54/48/36 + H2C_Parameter[3] = 0xf7; //MCS7 or OFDM54 + H2C_Parameter[4] = 0xf8; //MCS6 or OFDM48 + H2C_Parameter[5] = 0xf9; //MCS5 or OFDM36 + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set WiFi Low-Penalty Retry: %s", + (bLowPenaltyRa? "ON!!":"OFF!!")) ); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x69, 6, H2C_Parameter); +} + +VOID +halbtc8192e2ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + //return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); + + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8192e2ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8192e2ant_SetDacSwingReg( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte level + ) +{ + u1Byte val=(u1Byte)level; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Write SwDacSwing = 0x%x\n", level)); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x883, 0x3e, val); +} + +VOID +halbtc8192e2ant_SetSwFullTimeDacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bSwDacSwingOn, + IN u4Byte swDacSwingLvl + ) +{ + if(bSwDacSwingOn) + { + halbtc8192e2ant_SetDacSwingReg(pBtCoexist, swDacSwingLvl); + } + else + { + halbtc8192e2ant_SetDacSwingReg(pBtCoexist, 0x18); + } +} + + +VOID +halbtc8192e2ant_DacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDacSwingOn, + IN u4Byte dacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn DacSwing=%s, dacSwingLvl=0x%x\n", + (bForceExec? "force to":""), ((bDacSwingOn)? "ON":"OFF"), dacSwingLvl)); + pCoexDm->bCurDacSwingOn = bDacSwingOn; + pCoexDm->curDacSwingLvl = dacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x, bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + pCoexDm->bPreDacSwingOn, pCoexDm->preDacSwingLvl, + pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl)); + + if( (pCoexDm->bPreDacSwingOn == pCoexDm->bCurDacSwingOn) && + (pCoexDm->preDacSwingLvl == pCoexDm->curDacSwingLvl) ) + return; + } + delay_ms(30); + halbtc8192e2ant_SetSwFullTimeDacSwing(pBtCoexist, bDacSwingOn, dacSwingLvl); + + pCoexDm->bPreDacSwingOn = pCoexDm->bCurDacSwingOn; + pCoexDm->preDacSwingLvl = pCoexDm->curDacSwingLvl; +} + +VOID +halbtc8192e2ant_SetAdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAdcBackOff + ) +{ + if(bAdcBackOff) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level On!\n")); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xc05, 0x30, 0x3); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level Off!\n")); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xc05, 0x30, 0x1); + } +} + +VOID +halbtc8192e2ant_AdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAdcBackOff + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn AdcBackOff = %s\n", + (bForceExec? "force to":""), ((bAdcBackOff)? "ON":"OFF"))); + pCoexDm->bCurAdcBackOff = bAdcBackOff; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAdcBackOff=%d, bCurAdcBackOff=%d\n", + pCoexDm->bPreAdcBackOff, pCoexDm->bCurAdcBackOff)); + + if(pCoexDm->bPreAdcBackOff == pCoexDm->bCurAdcBackOff) + return; + } + halbtc8192e2ant_SetAdcBackOff(pBtCoexist, pCoexDm->bCurAdcBackOff); + + pCoexDm->bPreAdcBackOff = pCoexDm->bCurAdcBackOff; +} + +VOID +halbtc8192e2ant_SetAgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAgcTableEn + ) +{ + u1Byte rssiAdjustVal=0; + + //=================BB AGC Gain Table + if(bAgcTableEn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB Agc Table On!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x0a1A0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x091B0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x081C0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x071D0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x061E0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x051F0001); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB Agc Table Off!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xaa1A0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa91B0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa81C0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa71D0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa61E0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa51F0001); + } + +#if 0 + //=================RF Gain + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); + if(bAgcTableEn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x38fff); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x38ffe); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x380c3); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x28ce6); + } + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xed, 0xfffff, 0x1); + if(bAgcTableEn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x38fff); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x38ffe); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x380c3); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x28ce6); + } + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xed, 0xfffff, 0x0); + + // set rssiAdjustVal for wifi module. + if(bAgcTableEn) + { + rssiAdjustVal = 8; + } + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, &rssiAdjustVal); +#endif + +} + +VOID +halbtc8192e2ant_AgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAgcTableEn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s %s Agc Table\n", + (bForceExec? "force to":""), ((bAgcTableEn)? "Enable":"Disable"))); + pCoexDm->bCurAgcTableEn = bAgcTableEn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + pCoexDm->bPreAgcTableEn, pCoexDm->bCurAgcTableEn)); + + if(pCoexDm->bPreAgcTableEn == pCoexDm->bCurAgcTableEn) + return; + } + halbtc8192e2ant_SetAgcTable(pBtCoexist, bAgcTableEn); + + pCoexDm->bPreAgcTableEn = pCoexDm->bCurAgcTableEn; +} + +VOID +halbtc8192e2ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8192e2ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c0, val0x6c4, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c0 = val0x6c0; + pCoexDm->curVal0x6c4 = val0x6c4; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c0=0x%x, preVal0x6c4=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + pCoexDm->preVal0x6c0, pCoexDm->preVal0x6c4, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c0=0x%x, curVal0x6c4=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + pCoexDm->curVal0x6c0, pCoexDm->curVal0x6c4, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && + (pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8192e2ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c4, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; + pCoexDm->preVal0x6c4 = pCoexDm->curVal0x6c4; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8192e2ant_CoexTableWithType( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + switch(type) + { + case 0: + halbtc8192e2ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 1: + halbtc8192e2ant_CoexTable(pBtCoexist, bForceExec, 0x5a5a5a5a, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8192e2ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x5ffb5ffb, 0xffffff, 0x3); + break; + case 3: + halbtc8192e2ant_CoexTable(pBtCoexist, bForceExec, 0x5fdf5fdf, 0x5fdb5fdb, 0xffffff, 0x3); + break; + case 4: + halbtc8192e2ant_CoexTable(pBtCoexist, bForceExec, 0xdfffdfff, 0x5ffb5ffb, 0xffffff, 0x3); + break; + + default: + break; + } +} + +VOID +halbtc8192e2ant_SetFwIgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnable + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + if(bEnable) + { + H2C_Parameter[0] |= BIT0; // function enable + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x63, 1, H2C_Parameter); +} + +VOID +halbtc8192e2ant_IgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); + pCoexDm->bCurIgnoreWlanAct = bEnable; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); + + if(pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) + return; + } + halbtc8192e2ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); + + pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; +} + +VOID +halbtc8192e2ant_SetFwPstdma( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte byte1, + IN u1Byte byte2, + IN u1Byte byte3, + IN u1Byte byte4, + IN u1Byte byte5 + ) +{ + u1Byte H2C_Parameter[5] ={0}; + + H2C_Parameter[0] = byte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = byte5; + + pCoexDm->psTdmaPara[0] = byte1; + pCoexDm->psTdmaPara[1] = byte2; + pCoexDm->psTdmaPara[2] = byte3; + pCoexDm->psTdmaPara[3] = byte4; + pCoexDm->psTdmaPara[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x60(5bytes)=0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x60, 5, H2C_Parameter); +} + +VOID +halbtc8192e2ant_SwMechanism1( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bShrinkRxLPF, + IN BOOLEAN bLowPenaltyRA, + IN BOOLEAN bLimitedDIG, + IN BOOLEAN bBTLNAConstrain + ) +{ + /* + u4Byte wifiBw; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 != wifiBw) //only shrink RF Rx LPF for HT40 + { + if (bShrinkRxLPF) + bShrinkRxLPF = FALSE; + } + */ + + halbtc8192e2ant_RfShrink(pBtCoexist, NORMAL_EXEC, bShrinkRxLPF); + //halbtc8192e2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, bLowPenaltyRA); +} + +VOID +halbtc8192e2ant_SwMechanism2( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAGCTableShift, + IN BOOLEAN bADCBackOff, + IN BOOLEAN bSWDACSwing, + IN u4Byte dacSwingLvl + ) +{ + halbtc8192e2ant_AgcTable(pBtCoexist, NORMAL_EXEC, bAGCTableShift); + //halbtc8192e2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, bADCBackOff); + halbtc8192e2ant_DacSwing(pBtCoexist, NORMAL_EXEC, bSWDACSwing, dacSwingLvl); +} + +VOID +halbtc8192e2ant_SetAntPath( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte antPosType, + IN BOOLEAN bInitHwCfg, + IN BOOLEAN bWifiOff + ) +{ + u4Byte u4Tmp=0; + + if(bInitHwCfg) + { + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x944, 0x24); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x930, 0x700700); + if(pBtCoexist->chipInterface == BTC_INTF_USB) + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x64, 0x30430004); + else + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x64, 0x30030004); + + // 0x4c[27][24]='00', Set Antenna to BB + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u4Tmp &= ~BIT24; + u4Tmp &= ~BIT27; + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); + } + else if(bWifiOff) + { + if(pBtCoexist->chipInterface == BTC_INTF_USB) + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x64, 0x30430004); + else + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x64, 0x30030004); + + // 0x4c[27][24]='11', Set Antenna to BT, 0x64[8:7]=0, 0x64[2]=1 + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u4Tmp |= BIT24; + u4Tmp |= BIT27; + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); + } + + // ext switch setting + switch(antPosType) + { + case BTC_ANT_PATH_WIFI: + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x92c, 0x4); + break; + case BTC_ANT_PATH_BT: + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x92c, 0x20); + break; + default: + case BTC_ANT_PATH_PTA: + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x92c, 0x4); + break; + } +} + +VOID +halbtc8192e2ant_PsTdma( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bTurnOn, + IN u1Byte type + ) +{ + BOOLEAN bTurnOnByCnt=FALSE; + u1Byte psTdmaTypeByCnt=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type=%d\n", + (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); + pCoexDm->bCurPsTdmaOn = bTurnOn; + pCoexDm->curPsTdma = type; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + pCoexDm->bPrePsTdmaOn, pCoexDm->bCurPsTdmaOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + pCoexDm->prePsTdma, pCoexDm->curPsTdma)); + + if( (pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && + (pCoexDm->prePsTdma == pCoexDm->curPsTdma) ) + return; + } + if(bTurnOn) + { + switch(type) + { + case 1: + default: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); + break; + case 2: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x90); + break; + case 3: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x3, 0xf1, 0x90); + break; + case 4: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x10, 0x3, 0xf1, 0x90); + break; + case 5: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x90); + break; + case 6: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0x60, 0x90); + break; + case 7: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x3, 0x70, 0x90); + break; + case 8: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xa3, 0x10, 0x3, 0x70, 0x90); + break; + case 9: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x10); + break; + case 10: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x10); + break; + case 11: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x3, 0xf1, 0x10); + break; + case 12: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x10, 0x3, 0xf1, 0x10); + break; + case 13: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe0, 0x10); + break; + case 14: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe0, 0x10); + break; + case 15: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x3, 0xf0, 0x10); + break; + case 16: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x3, 0xf0, 0x10); + break; + case 17: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0x61, 0x20, 0x03, 0x10, 0x10); + break; + case 18: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0xe1, 0x90); + break; + case 19: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0xe1, 0x90); + break; + case 20: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0x60, 0x90); + break; + case 21: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x15, 0x03, 0x70, 0x90); + break; + case 71: + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); + break; + } + } + else + { + // disable PS tdma + switch(type) + { + default: + case 0: //ANT2PTA, 0x778=1 + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0x8, 0x0, 0x0, 0x0, 0x0); + halbtc8192e2ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_PTA, FALSE, FALSE); + break; + case 1: //ANT2BT, 0x778=3 + halbtc8192e2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x8, 0x0); + delay_ms(5); + halbtc8192e2ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, FALSE); + break; + + } + } + + // update pre state + pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; + pCoexDm->prePsTdma = pCoexDm->curPsTdma; +} + +VOID +halbtc8192e2ant_SetSwitchSsType( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte ssType + ) +{ + u1Byte mimoPs=BTC_MIMO_PS_DYNAMIC; + u4Byte disRaMask=0x0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], REAL set SS Type = %d\n", ssType)); + + disRaMask = halbtc8192e2ant_DecideRaMask(pBtCoexist, ssType, pCoexDm->curRaMaskType); + halbtc8192e2ant_UpdateRaMask(pBtCoexist, FORCE_EXEC, disRaMask); + + if(ssType == 1) + { + halbtc8192e2ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 1); + // switch ofdm path + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xc04, 0x11); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xd04, 0x1); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x90c, 0x81111111); + // switch cck patch + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xe77, 0x4, 0x1); + //pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xa07, 0x81); + mimoPs=BTC_MIMO_PS_STATIC; + } + else if(ssType == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 0); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xc04, 0x33); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xd04, 0x3); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x90c, 0x81121313); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xe77, 0x4, 0x0); + //pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xa07, 0x41); + mimoPs=BTC_MIMO_PS_DYNAMIC; + } + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_SEND_MIMO_PS, &mimoPs); // set rx 1ss or 2ss +} + +VOID +halbtc8192e2ant_SwitchSsType( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte newSsType + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], %s Switch SS Type = %d\n", + (bForceExec? "force to":""), newSsType)); + pCoexDm->curSsType = newSsType; + + if(!bForceExec) + { + if(pCoexDm->preSsType == pCoexDm->curSsType) + return; + } + halbtc8192e2ant_SetSwitchSsType(pBtCoexist, pCoexDm->curSsType); + + pCoexDm->preSsType = pCoexDm->curSsType; +} + +VOID +halbtc8192e2ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + // fw all off + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + // sw all off + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + // hw all off + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +VOID +halbtc8192e2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + // force to reset coex mechanism + + halbtc8192e2ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 1); + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, FORCE_EXEC, 6); + halbtc8192e2ant_DecBtPwr(pBtCoexist, FORCE_EXEC, 0); + + halbtc8192e2ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); + halbtc8192e2ant_SwitchSsType(pBtCoexist, FORCE_EXEC, 2); + + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); +} + +VOID +halbtc8192e2ant_ActionBtInquiry( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bLowPwrDisable=TRUE; + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); +} + +BOOLEAN +halbtc8192e2ant_IsCommonAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bCommon=FALSE, bWifiConnected=FALSE, bWifiBusy=FALSE; + BOOLEAN bBtHsOn=FALSE, bLowPwrDisable=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + + if(pBtLinkInfo->bScoExist || pBtLinkInfo->bHidExist) + { + halbtc8192e2ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 1, 0, 0, 0); + } + else + { + halbtc8192e2ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); + } + + if(!bWifiConnected) + { + bLowPwrDisable = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non-connected idle!!\n")); + + if( (BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) || + (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + } + + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else + { + if(BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) + { + bLowPwrDisable = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT non connected-idle!!\n")); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else if(BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) + { + bLowPwrDisable = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + if(bBtHsOn) + return FALSE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT connected-idle!!\n")); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else + { + bLowPwrDisable = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + if(bWifiBusy) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Busy + BT Busy!!\n")); + bCommon = FALSE; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Idle + BT Busy!!\n")); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 21); + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + bCommon = TRUE; + } + } + } + + return bCommon; +} +VOID +halbtc8192e2ant_TdmaDurationAdjust( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bScoHid, + IN BOOLEAN bTxPause, + IN u1Byte maxInterval + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjust()\n")); + + if(!pCoexDm->bAutoTdmaAdjust) + { + pCoexDm->bAutoTdmaAdjust = TRUE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); + { + if(bScoHid) + { + if(bTxPause) + { + if(maxInterval == 1) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + else if(maxInterval == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(maxInterval == 3) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + } + else + { + if(maxInterval == 1) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(maxInterval == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(maxInterval == 3) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + } + else + { + if(bTxPause) + { + if(maxInterval == 1) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(maxInterval == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(maxInterval == 3) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + } + else + { + if(maxInterval == 1) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(maxInterval == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(maxInterval == 3) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + } + } + } + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n", + up, dn, m, n, WaitCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if �s�� n ��2�� retry count��0, �h�ռeWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration + { + if (WaitCount <= 2) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration + { + if (WaitCount == 1) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], max Interval = %d\n", maxInterval)); + if(maxInterval == 1) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + + if(pCoexDm->curPsTdma == 71) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 71); + pCoexDm->psTdmaDuAdjType = 71; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + + if(result == -1) + { + if(pCoexDm->curPsTdma == 71) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 71); + pCoexDm->psTdmaDuAdjType = 71; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + } + } + } + else if(maxInterval == 2) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + if(pCoexDm->curPsTdma == 1) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + } + } + } + else if(maxInterval == 3) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + if(pCoexDm->curPsTdma == 1) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + } + } + } + + // if current PsTdma not match with the recorded one (when scan, dhcp...), + // then we have to adjust it back to the previous record one. + if(pCoexDm->curPsTdma != pCoexDm->psTdmaDuAdjType) + { + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], PsTdma type dismatch!!!, curPsTdma=%d, recordPsTdma=%d\n", + pCoexDm->curPsTdma, pCoexDm->psTdmaDuAdjType)); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if( !bScan && !bLink && !bRoam) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, pCoexDm->psTdmaDuAdjType); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n")); + } + } +} + +// SCO only or SCO+PAN(HS) +VOID +halbtc8192e2ant_ActionSco( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState=BTC_RSSI_STATE_STAY_LOW; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); + + btRssiState = halbtc8192e2ant_BtRssiState(3, 34, 42); + + if( (btRssiState == BTC_RSSI_STATE_LOW) || + (btRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + } + else if( (btRssiState == BTC_RSSI_STATE_MEDIUM) || + (btRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x6); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x6); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x6); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x6); + } + } +} + +VOID +halbtc8192e2ant_ActionScoPan( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState=BTC_RSSI_STATE_STAY_LOW; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); + + btRssiState = halbtc8192e2ant_BtRssiState(3, 34, 42); + + if( (btRssiState == BTC_RSSI_STATE_LOW) || + (btRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + } + else if( (btRssiState == BTC_RSSI_STATE_MEDIUM) || + (btRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x6); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x6); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x6); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x6); + } + } +} + +VOID +halbtc8192e2ant_ActionHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8192e2ant_BtRssiState(3, 34, 42); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 3); + + if( (btRssiState == BTC_RSSI_STATE_LOW) || + (btRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + } + else if( (btRssiState == BTC_RSSI_STATE_MEDIUM) || + (btRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + } + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +//A2DP only / PAN(EDR) only/ A2DP+PAN(HS) +VOID +halbtc8192e2ant_ActionA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + BOOLEAN bLongDist=FALSE; + + wifiRssiState = halbtc8192e2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8192e2ant_BtRssiState(3, 34, 42); + + if( (btRssiState == BTC_RSSI_STATE_LOW||btRssiState == BTC_RSSI_STATE_STAY_LOW) && + (wifiRssiState == BTC_RSSI_STATE_LOW||wifiRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2dp, wifi/bt rssi both LOW!!\n")); + bLongDist = TRUE; + } + if(bLongDist) + { + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, TRUE, 0x4); + } + else + { + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + } + + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if(bLongDist) + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + else + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + + + if(bLongDist) + { + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 17); + pCoexDm->bAutoTdmaAdjust = FALSE; + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + } + else + { + if( (btRssiState == BTC_RSSI_STATE_LOW) || + (btRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 1); + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + } + else if( (btRssiState == BTC_RSSI_STATE_MEDIUM) || + (btRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 1); + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 1); + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + } + } + + // sw mechanism + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8192e2ant_ActionA2dpPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8192e2ant_BtRssiState(3, 34, 42); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + + if( (btRssiState == BTC_RSSI_STATE_LOW) || + (btRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 2); + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + } + else if( (btRssiState == BTC_RSSI_STATE_MEDIUM) || + (btRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 2); + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 2); + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + } + + // sw mechanism + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,TRUE,0x6); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,TRUE,0x6); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,TRUE,0x6); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,TRUE,0x6); + } + } +} + +VOID +halbtc8192e2ant_ActionPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8192e2ant_BtRssiState(3, 34, 42); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + + if( (btRssiState == BTC_RSSI_STATE_LOW) || + (btRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + } + else if( (btRssiState == BTC_RSSI_STATE_MEDIUM) || + (btRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + } + + // sw mechanism + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +//PAN(HS) only +VOID +halbtc8192e2ant_ActionPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8192e2ant_BtRssiState(3, 34, 42); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + + if( (btRssiState == BTC_RSSI_STATE_LOW) || + (btRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + } + else if( (btRssiState == BTC_RSSI_STATE_MEDIUM) || + (btRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + } + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +//PAN(EDR)+A2DP +VOID +halbtc8192e2ant_ActionPanEdrA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8192e2ant_BtRssiState(3, 34, 42); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if( (btRssiState == BTC_RSSI_STATE_LOW) || + (btRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 3); + } + else if( (btRssiState == BTC_RSSI_STATE_MEDIUM) || + (btRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 3); + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 3); + } + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8192e2ant_ActionPanEdrHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8192e2ant_BtRssiState(3, 34, 42); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 3); + + if( (btRssiState == BTC_RSSI_STATE_LOW) || + (btRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + } + else if( (btRssiState == BTC_RSSI_STATE_MEDIUM) || + (btRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + } + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +// HID+A2DP+PAN(EDR) +VOID +halbtc8192e2ant_ActionHidA2dpPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8192e2ant_BtRssiState(3, 34, 42); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + halbtc8192e2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 3); + + if( (btRssiState == BTC_RSSI_STATE_LOW) || + (btRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 3); + } + else if( (btRssiState == BTC_RSSI_STATE_MEDIUM) || + (btRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 3); + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 3); + } + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8192e2ant_ActionHidA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8192e2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8192e2ant_BtRssiState(3, 34, 42); + + halbtc8192e2ant_SwitchSsType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8192e2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + halbtc8192e2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 3); + + if( (btRssiState == BTC_RSSI_STATE_LOW) || + (btRssiState == BTC_RSSI_STATE_STAY_LOW) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + } + else if( (btRssiState == BTC_RSSI_STATE_MEDIUM) || + (btRssiState == BTC_RSSI_STATE_STAY_MEDIUM) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 2); + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 2); + } + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8192e2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8192e2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8192e2ant_RunCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiUnder5G=FALSE; + u1Byte btInfoOriginal=0, btRetryCnt=0; + u1Byte algorithm=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism()===>\n")); + + if(pBtCoexist->bManualControl) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n")); + return; + } + + if(pCoexSta->bUnderIps) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under IPS !!!\n")); + return; + } + + algorithm = halbtc8192e2ant_ActionAlgorithm(pBtCoexist); + if(pCoexSta->bC2hBtInquiryPage && (BT_8192E_2ANT_COEX_ALGO_PANHS!=algorithm)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT is under inquiry/page scan !!\n")); + halbtc8192e2ant_ActionBtInquiry(pBtCoexist); + return; + } + + pCoexDm->curAlgorithm = algorithm; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Algorithm = %d \n", pCoexDm->curAlgorithm)); + + if(halbtc8192e2ant_IsCommonAction(pBtCoexist)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant common.\n")); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + else + { + if(pCoexDm->curAlgorithm != pCoexDm->preAlgorithm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], preAlgorithm=%d, curAlgorithm=%d\n", + pCoexDm->preAlgorithm, pCoexDm->curAlgorithm)); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + switch(pCoexDm->curAlgorithm) + { + case BT_8192E_2ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = SCO.\n")); + halbtc8192e2ant_ActionSco(pBtCoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_SCO_PAN: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = SCO+PAN(EDR).\n")); + halbtc8192e2ant_ActionScoPan(pBtCoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID.\n")); + halbtc8192e2ant_ActionHid(pBtCoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP.\n")); + halbtc8192e2ant_ActionA2dp(pBtCoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n")); + halbtc8192e2ant_ActionA2dpPanHs(pBtCoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n")); + halbtc8192e2ant_ActionPanEdr(pBtCoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HS mode.\n")); + halbtc8192e2ant_ActionPanHs(pBtCoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n")); + halbtc8192e2ant_ActionPanEdrA2dp(pBtCoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n")); + halbtc8192e2ant_ActionPanEdrHid(pBtCoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n")); + halbtc8192e2ant_ActionHidA2dpPanEdr(pBtCoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n")); + halbtc8192e2ant_ActionHidA2dp(pBtCoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = unknown!!\n")); + //halbtc8192e2ant_CoexAllOff(pBtCoexist); + break; + } + pCoexDm->preAlgorithm = pCoexDm->curAlgorithm; + } +} + +VOID +halbtc8192e2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bBackUp + ) +{ + u4Byte u4Tmp=0; + u2Byte u2Tmp=0; + u1Byte u1Tmp=0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 2Ant Init HW Config!!\n")); + + if(bBackUp) + { + // backup rf 0x1e value + pCoexDm->btRf0x1eBackup = + pBtCoexist->fBtcGetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff); + + pCoexDm->backupArfrCnt1 = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x430); + pCoexDm->backupArfrCnt2 = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x434); + pCoexDm->backupRetryLimit = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x42a); + pCoexDm->backupAmpduMaxTime = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x456); + } + + // antenna sw ctrl to bt + halbtc8192e2ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, TRUE, FALSE); + + halbtc8192e2ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); + + // antenna switch control parameter + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x858, 0x55555555); + + // coex parameters + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x778, 0x3); + // 0x790[5:0]=0x5 + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x790); + u1Tmp &= 0xc0; + u1Tmp |= 0x5; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x790, u1Tmp); + + // enable counter statistics + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); + + // enable PTA + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x20); + // enable mailbox interface + u2Tmp = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x40); + u2Tmp |= BIT9; + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x40, u2Tmp); + + // enable PTA I2C mailbox + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x101); + u1Tmp |= BIT4; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x101, u1Tmp); + + // enable bt clock when wifi is disabled. + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x93); + u1Tmp |= BIT0; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x93, u1Tmp); + // enable bt clock when suspend. + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x7); + u1Tmp |= BIT0; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x7, u1Tmp); +} + +//============================================================ +// work around function start with wa_halbtc8192e2ant_ +//============================================================ +//============================================================ +// extern function start with EXhalbtc8192e2ant_ +//============================================================ +VOID +EXhalbtc8192e2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8192e2ant_InitHwConfig(pBtCoexist, TRUE); +} + +VOID +EXhalbtc8192e2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + halbtc8192e2ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8192e2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + pu1Byte cliBuf=pBtCoexist->cliBuf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u2Byte u2Tmp[4]; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir, faOfdm, faCck; + u1Byte wifiDot11Chnl, wifiHsChnl; + u4Byte fwVer=0, btPatchVer=0; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(pBtCoexist->bManualControl) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cliBuf); + } + + if(!pBoardInfo->bBtExist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", \ + GLCoexVerDate8192e2Ant, GLCoexVer8192e2Ant, fwVer, btPatchVer, btPatchVer); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsMode(HsChnl)", \ + wifiDot11Chnl, bBtHsOn, wifiHsChnl); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], + pCoexDm->wifiChnlInfo[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((pBtCoexist->btInfo.bBtDisabled)? ("disabled"): ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus)? "non-connected idle": + ( (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy")))), + pCoexSta->btRssi, pCoexSta->btRetryCnt); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pStackInfo->bScoExist, pStackInfo->bHidExist, pStackInfo->bPanExist, pStackInfo->bA2dpExist); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + + btInfoExt = pCoexSta->btInfoExt; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (btInfoExt&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cliBuf); + + for(i=0; i<BT_INFO_SRC_8192E_2ANT_MAX; i++) + { + if(pCoexSta->btInfoC2hCnt[i]) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8192e2Ant[i], \ + pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], + pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], + pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], + pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); + CL_PRINTF(cliBuf); + } + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", "PS state, IPS/LPS", \ + ((pCoexSta->bUnderIps? "IPS ON":"IPS OFF")), + ((pCoexSta->bUnderLps? "LPS ON":"LPS OFF"))); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "SS Type", \ + pCoexDm->curSsType); + CL_PRINTF(cliBuf); + + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "SM1[ShRf/ LpRA/ LimDig]", \ + pCoexDm->bCurRfRxLpfShrink, pCoexDm->bCurLowPenaltyRa, pCoexDm->bLimitedDig); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", \ + pCoexDm->bCurAgcTableEn, pCoexDm->bCurAdcBackOff, pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask", \ + pBtCoexist->btInfo.raMask); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + psTdmaCase = pCoexDm->curPsTdma; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA", \ + pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], + pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], + pCoexDm->psTdmaPara[4], psTdmaCase, pCoexDm->bAutoTdmaAdjust); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", \ + pCoexDm->curBtDecPwrLvl, pCoexDm->bCurIgnoreWlanAct); + CL_PRINTF(cliBuf); + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", \ + pCoexDm->btRf0x1eBackup); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "backup ARFR1/ARFR2/RL/AMaxTime", \ + pCoexDm->backupArfrCnt1, pCoexDm->backupArfrCnt2, pCoexDm->backupRetryLimit, pCoexDm->backupAmpduMaxTime); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x430); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x434); + u2Tmp[0] = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x42a); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x456); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "0x430/0x434/0x42a/0x456", \ + u4Tmp[0], u4Tmp[1], u2Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc04); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xd04); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x90c); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0xc04/ 0xd04/ 0x90c", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x778); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x778", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x92c); + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x930); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x92c/ 0x930", \ + (u1Tmp[0]), u4Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x4f); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x40/ 0x4f", \ + u1Tmp[0], u1Tmp[1]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x550); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x522); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp[0]); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770(hp rx[31:16]/tx[15:0])", \ + pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(lp rx[31:16]/tx[15:0])", \ + pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); + CL_PRINTF(cliBuf); +#if(BT_AUTO_REPORT_ONLY_8192E_2ANT == 1) + halbtc8192e2ant_MonitorBtCtr(pBtCoexist); +#endif + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8192e2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + pCoexSta->bUnderIps = TRUE; + halbtc8192e2ant_CoexAllOff(pBtCoexist); + halbtc8192e2ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, TRUE); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + pCoexSta->bUnderIps = FALSE; + } +} + +VOID +EXhalbtc8192e2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + pCoexSta->bUnderLps = TRUE; + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + pCoexSta->bUnderLps = FALSE; + } +} + +VOID +EXhalbtc8192e2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + } +} + +VOID +EXhalbtc8192e2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + } +} + +VOID +EXhalbtc8192e2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u1Byte H2C_Parameter[3] ={0}; + u4Byte wifiBw; + u1Byte wifiCentralChnl; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } + + // only 2.4G we need to inform bt the chnl mask + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); + if( (BTC_MEDIA_CONNECT == type) && + (wifiCentralChnl <= 14) ) + { + H2C_Parameter[0] = 0x1; + H2C_Parameter[1] = wifiCentralChnl; + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + H2C_Parameter[2] = 0x30; + else + H2C_Parameter[2] = 0x20; + } + + pCoexDm->wifiChnlInfo[0] = H2C_Parameter[0]; + pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1]; + pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x66=0x%x\n", + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x66, 3, H2C_Parameter); +} + +VOID +EXhalbtc8192e2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(type == BTC_PACKET_DHCP) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], DHCP Packet notify\n")); + } +} + +VOID +EXhalbtc8192e2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + u1Byte btInfo=0; + u1Byte i, rspSource=0; + BOOLEAN bBtBusy=FALSE, bLimitedDig=FALSE; + BOOLEAN bWifiConnected=FALSE; + + pCoexSta->bC2hBtInfoReqSent = FALSE; + + rspSource = tmpBuf[0]&0xf; + if(rspSource >= BT_INFO_SRC_8192E_2ANT_MAX) + rspSource = BT_INFO_SRC_8192E_2ANT_WIFI_FW; + pCoexSta->btInfoC2hCnt[rspSource]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rspSource, length)); + for(i=0; i<length; i++) + { + pCoexSta->btInfoC2h[rspSource][i] = tmpBuf[i]; + if(i == 1) + btInfo = tmpBuf[i]; + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); + } + } + + if(BT_INFO_SRC_8192E_2ANT_WIFI_FW != rspSource) + { + pCoexSta->btRetryCnt = // [3:0] + pCoexSta->btInfoC2h[rspSource][2]&0xf; + + pCoexSta->btRssi = + pCoexSta->btInfoC2h[rspSource][3]*2+10; + + pCoexSta->btInfoExt = + pCoexSta->btInfoC2h[rspSource][4]; + + // Here we need to resend some wifi info to BT + // because bt is reset and loss of the info. + if( (pCoexSta->btInfoExt & BIT1) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n")); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(bWifiConnected) + { + EXhalbtc8192e2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_CONNECT); + } + else + { + EXhalbtc8192e2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); + } + } + + if( (pCoexSta->btInfoExt & BIT3) ) + { + if(!pBtCoexist->bManualControl && !pBtCoexist->bStopCoexDm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n")); + halbtc8192e2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); + } + } + else + { + // BT already NOT ignore Wlan active, do nothing here. + } + +#if(BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) + if( (pCoexSta->btInfoExt & BIT4) ) + { + // BT auto report already enabled, do nothing + } + else + { + halbtc8192e2ant_BtAutoReport(pBtCoexist, FORCE_EXEC, TRUE); + } +#endif + } + + // check BIT2 first ==> check if bt is under inquiry or page scan + if(btInfo & BT_INFO_8192E_2ANT_B_INQ_PAGE) + pCoexSta->bC2hBtInquiryPage = TRUE; + else + pCoexSta->bC2hBtInquiryPage = FALSE; + + // set link exist status + if(!(btInfo&BT_INFO_8192E_2ANT_B_CONNECTION)) + { + pCoexSta->bBtLinkExist = FALSE; + pCoexSta->bPanExist = FALSE; + pCoexSta->bA2dpExist = FALSE; + pCoexSta->bHidExist = FALSE; + pCoexSta->bScoExist = FALSE; + } + else // connection exists + { + pCoexSta->bBtLinkExist = TRUE; + if(btInfo & BT_INFO_8192E_2ANT_B_FTP) + pCoexSta->bPanExist = TRUE; + else + pCoexSta->bPanExist = FALSE; + if(btInfo & BT_INFO_8192E_2ANT_B_A2DP) + pCoexSta->bA2dpExist = TRUE; + else + pCoexSta->bA2dpExist = FALSE; + if(btInfo & BT_INFO_8192E_2ANT_B_HID) + pCoexSta->bHidExist = TRUE; + else + pCoexSta->bHidExist = FALSE; + if(btInfo & BT_INFO_8192E_2ANT_B_SCO_ESCO) + pCoexSta->bScoExist = TRUE; + else + pCoexSta->bScoExist = FALSE; + } + + halbtc8192e2ant_UpdateBtLinkInfo(pBtCoexist); + + if(!(btInfo&BT_INFO_8192E_2ANT_B_CONNECTION)) + { + pCoexDm->btStatus = BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n")); + } + else if(btInfo == BT_INFO_8192E_2ANT_B_CONNECTION) // connection exists but no busy + { + pCoexDm->btStatus = BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n")); + } + else if((btInfo&BT_INFO_8192E_2ANT_B_SCO_ESCO) || + (btInfo&BT_INFO_8192E_2ANT_B_SCO_BUSY)) + { + pCoexDm->btStatus = BT_8192E_2ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT SCO busy!!!\n")); + } + else if(btInfo&BT_INFO_8192E_2ANT_B_ACL_BUSY) + { + pCoexDm->btStatus = BT_8192E_2ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT ACL busy!!!\n")); + } + else + { + pCoexDm->btStatus = BT_8192E_2ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n")); + } + + if( (BT_8192E_2ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || + (BT_8192E_2ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + bBtBusy = TRUE; + bLimitedDig = TRUE; + } + else + { + bBtBusy = FALSE; + bLimitedDig = FALSE; + } + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + + pCoexDm->bLimitedDig = bLimitedDig; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_LIMITED_DIG, &bLimitedDig); + + halbtc8192e2ant_RunCoexistMechanism(pBtCoexist); +} + +VOID +EXhalbtc8192e2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + halbtc8192e2ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, TRUE); + halbtc8192e2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + EXhalbtc8192e2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8192e2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + static u1Byte disVerInfoCnt=0; + u4Byte fwVer=0, btPatchVer=0; + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ==========================Periodical===========================\n")); + + if(disVerInfoCnt <= 5) + { + disVerInfoCnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum, pBoardInfo->btdmAntPos)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], BT stack/ hci ext ver = %s / %d\n", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion)); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", \ + GLCoexVerDate8192e2Ant, GLCoexVer8192e2Ant, fwVer, btPatchVer, btPatchVer)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + } + +#if(BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) + halbtc8192e2ant_QueryBtInfo(pBtCoexist); + halbtc8192e2ant_MonitorBtCtr(pBtCoexist); + halbtc8192e2ant_MonitorBtEnableDisable(pBtCoexist); +#else + if( halbtc8192e2ant_IsWifiStatusChanged(pBtCoexist) || + pCoexDm->bAutoTdmaAdjust) + { + halbtc8192e2ant_RunCoexistMechanism(pBtCoexist); + } +#endif +} + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e2Ant.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e2Ant.h new file mode 100644 index 0000000..e986006 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8192e2Ant.h @@ -0,0 +1,201 @@ +//=========================================== +// The following is for 8192E 2Ant BT Co-exist definition +//=========================================== +#define BT_AUTO_REPORT_ONLY_8192E_2ANT 0 + +#define BT_INFO_8192E_2ANT_B_FTP BIT7 +#define BT_INFO_8192E_2ANT_B_A2DP BIT6 +#define BT_INFO_8192E_2ANT_B_HID BIT5 +#define BT_INFO_8192E_2ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8192E_2ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8192E_2ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8192E_2ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8192E_2ANT_B_CONNECTION BIT0 + +#define BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT 2 + +typedef enum _BT_INFO_SRC_8192E_2ANT{ + BT_INFO_SRC_8192E_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8192E_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8192E_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8192E_2ANT_MAX +}BT_INFO_SRC_8192E_2ANT,*PBT_INFO_SRC_8192E_2ANT; + +typedef enum _BT_8192E_2ANT_BT_STATUS{ + BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8192E_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8192E_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8192E_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8192E_2ANT_BT_STATUS_MAX +}BT_8192E_2ANT_BT_STATUS,*PBT_8192E_2ANT_BT_STATUS; + +typedef enum _BT_8192E_2ANT_COEX_ALGO{ + BT_8192E_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8192E_2ANT_COEX_ALGO_SCO = 0x1, + BT_8192E_2ANT_COEX_ALGO_SCO_PAN = 0x2, + BT_8192E_2ANT_COEX_ALGO_HID = 0x3, + BT_8192E_2ANT_COEX_ALGO_A2DP = 0x4, + BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS = 0x5, + BT_8192E_2ANT_COEX_ALGO_PANEDR = 0x6, + BT_8192E_2ANT_COEX_ALGO_PANHS = 0x7, + BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP = 0x8, + BT_8192E_2ANT_COEX_ALGO_PANEDR_HID = 0x9, + BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0xa, + BT_8192E_2ANT_COEX_ALGO_HID_A2DP = 0xb, + BT_8192E_2ANT_COEX_ALGO_MAX = 0xc +}BT_8192E_2ANT_COEX_ALGO,*PBT_8192E_2ANT_COEX_ALGO; + +typedef struct _COEX_DM_8192E_2ANT{ + // fw mechanism + u1Byte preBtDecPwrLvl; + u1Byte curBtDecPwrLvl; + u1Byte preFwDacSwingLvl; + u1Byte curFwDacSwingLvl; + BOOLEAN bCurIgnoreWlanAct; + BOOLEAN bPreIgnoreWlanAct; + u1Byte prePsTdma; + u1Byte curPsTdma; + u1Byte psTdmaPara[5]; + u1Byte psTdmaDuAdjType; + BOOLEAN bResetTdmaAdjust; + BOOLEAN bAutoTdmaAdjust; + BOOLEAN bPrePsTdmaOn; + BOOLEAN bCurPsTdmaOn; + BOOLEAN bPreBtAutoReport; + BOOLEAN bCurBtAutoReport; + + // sw mechanism + BOOLEAN bPreRfRxLpfShrink; + BOOLEAN bCurRfRxLpfShrink; + u4Byte btRf0x1eBackup; + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + BOOLEAN bPreDacSwingOn; + u4Byte preDacSwingLvl; + BOOLEAN bCurDacSwingOn; + u4Byte curDacSwingLvl; + BOOLEAN bPreAdcBackOff; + BOOLEAN bCurAdcBackOff; + BOOLEAN bPreAgcTableEn; + BOOLEAN bCurAgcTableEn; + u4Byte preVal0x6c0; + u4Byte curVal0x6c0; + u4Byte preVal0x6c4; + u4Byte curVal0x6c4; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u1Byte preVal0x6cc; + u1Byte curVal0x6cc; + BOOLEAN bLimitedDig; + + u4Byte backupArfrCnt1; // Auto Rate Fallback Retry cnt + u4Byte backupArfrCnt2; // Auto Rate Fallback Retry cnt + u2Byte backupRetryLimit; + u1Byte backupAmpduMaxTime; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + u1Byte btStatus; + u1Byte wifiChnlInfo[3]; + + u1Byte preSsType; + u1Byte curSsType; + + u4Byte preRaMask; + u4Byte curRaMask; + u1Byte curRaMaskType; + u1Byte preArfrType; + u1Byte curArfrType; + u1Byte preRetryLimitType; + u1Byte curRetryLimitType; + u1Byte preAmpduTimeType; + u1Byte curAmpduTimeType; +} COEX_DM_8192E_2ANT, *PCOEX_DM_8192E_2ANT; + +typedef struct _COEX_STA_8192E_2ANT{ + BOOLEAN bBtLinkExist; + BOOLEAN bScoExist; + BOOLEAN bA2dpExist; + BOOLEAN bHidExist; + BOOLEAN bPanExist; + + BOOLEAN bUnderLps; + BOOLEAN bUnderIps; + u4Byte highPriorityTx; + u4Byte highPriorityRx; + u4Byte lowPriorityTx; + u4Byte lowPriorityRx; + u1Byte btRssi; + u1Byte preBtRssiState; + u1Byte preWifiRssiState[4]; + BOOLEAN bC2hBtInfoReqSent; + u1Byte btInfoC2h[BT_INFO_SRC_8192E_2ANT_MAX][10]; + u4Byte btInfoC2hCnt[BT_INFO_SRC_8192E_2ANT_MAX]; + BOOLEAN bC2hBtInquiryPage; + u1Byte btRetryCnt; + u1Byte btInfoExt; +}COEX_STA_8192E_2ANT, *PCOEX_STA_8192E_2ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8192e2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8192e2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8192e2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8192e2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a1Ant.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a1Ant.c new file mode 100644 index 0000000..1e80e8d --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a1Ant.c @@ -0,0 +1,1598 @@ +//============================================================ +// Description: +// +// This file is for RTL8723A Co-exist mechanism +// +// History +// 2012/08/22 Cosa first check in. +// 2012/11/14 Cosa Revise for 8723A 1Ant out sourcing. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8723A_1ANT GLCoexDm8723a1Ant; +static PCOEX_DM_8723A_1ANT pCoexDm=&GLCoexDm8723a1Ant; +static COEX_STA_8723A_1ANT GLCoexSta8723a1Ant; +static PCOEX_STA_8723A_1ANT pCoexSta=&GLCoexSta8723a1Ant; + +const char *const GLBtInfoSrc8723a1Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8723a1ant_ +//============================================================ +VOID +halbtc8723a1ant_Reg0x550Bit3( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bSet + ) +{ + u1Byte u1tmp=0; + + u1tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x550); + if(bSet) + { + u1tmp |= BIT3; + } + else + { + u1tmp &= ~BIT3; + } + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x550, u1tmp); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], set 0x550[3]=%d\n", (bSet? 1:0))); +} + +VOID +halbtc8723a1ant_NotifyFwScan( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte scanType + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + if(BTC_SCAN_START == scanType) + H2C_Parameter[0] = 0x1; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Notify FW for wifi scan, write 0x3b=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x3b, 1, H2C_Parameter); +} + +VOID +halbtc8723a1ant_QueryBtInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + pCoexSta->bC2hBtInfoReqSent = TRUE; + + H2C_Parameter[0] |= BIT0; // trigger + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Query Bt Info, FW write 0x38=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x38, 1, H2C_Parameter); +} + +VOID +halbtc8723a1ant_SetSwRfRxLpfCorner( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bRxRfShrinkOn + ) +{ + if(bRxRfShrinkOn) + { + //Shrink RF Rx LPF corner + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Shrink RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, 0xf0ff7); + } + else + { + //Resume RF Rx LPF corner + // After initialized, we can use pCoexDm->btRf0x1eBackup + if(pBtCoexist->bInitilized) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, pCoexDm->btRf0x1eBackup); + } + } +} + +VOID +halbtc8723a1ant_RfShrink( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRxRfShrinkOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn Rx RF Shrink = %s\n", + (bForceExec? "force to":""), ((bRxRfShrinkOn)? "ON":"OFF"))); + pCoexDm->bCurRfRxLpfShrink = bRxRfShrinkOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreRfRxLpfShrink=%d, bCurRfRxLpfShrink=%d\n", + pCoexDm->bPreRfRxLpfShrink, pCoexDm->bCurRfRxLpfShrink)); + + if(pCoexDm->bPreRfRxLpfShrink == pCoexDm->bCurRfRxLpfShrink) + return; + } + halbtc8723a1ant_SetSwRfRxLpfCorner(pBtCoexist, pCoexDm->bCurRfRxLpfShrink); + + pCoexDm->bPreRfRxLpfShrink = pCoexDm->bCurRfRxLpfShrink; +} + +VOID +halbtc8723a1ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte tmpU1; + + tmpU1 = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x4fd); + tmpU1 |= BIT0; + if(bLowPenaltyRa) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set low penalty!!\n")); + tmpU1 &= ~BIT2; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set normal!!\n")); + tmpU1 |= BIT2; + } + + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x4fd, tmpU1); +} + +VOID +halbtc8723a1ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); + + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8723a1ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8723a1ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c0, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8723a1ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c0, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c0, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c0 = val0x6c0; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c0=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + pCoexDm->preVal0x6c0, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c0=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + pCoexDm->curVal0x6c0, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8723a1ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8723a1ant_SetFwIgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnable + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + if(bEnable) + { + H2C_Parameter[0] |= BIT0; // function enable + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x25=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x25, 1, H2C_Parameter); +} + +VOID +halbtc8723a1ant_IgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); + pCoexDm->bCurIgnoreWlanAct = bEnable; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); + + if(pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) + return; + } + halbtc8723a1ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); + + pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; +} + +VOID +halbtc8723a1ant_SetFwPstdma( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type, + IN u1Byte byte1, + IN u1Byte byte2, + IN u1Byte byte3, + IN u1Byte byte4, + IN u1Byte byte5 + ) +{ + u1Byte H2C_Parameter[5] ={0}; + u1Byte realByte1=byte1, realByte5=byte5; + BOOLEAN bApEnable=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, &bApEnable); + + // byte1[1:0] != 0 means enable pstdma + // for 2Ant bt coexist, if byte1 != 0 means enable pstdma + if(byte1) + { + if(bApEnable) + { + if(type != 5 && type != 12) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], FW for 1Ant AP mode\n")); + realByte1 &= ~BIT4; + realByte1 |= BIT5; + + realByte5 |= BIT5; + realByte5 &= ~BIT6; + } + } + } + H2C_Parameter[0] = realByte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = realByte5; + + pCoexDm->psTdmaPara[0] = realByte1; + pCoexDm->psTdmaPara[1] = byte2; + pCoexDm->psTdmaPara[2] = byte3; + pCoexDm->psTdmaPara[3] = byte4; + pCoexDm->psTdmaPara[4] = realByte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x3a(5bytes)=0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x3a, 5, H2C_Parameter); +} + +VOID +halbtc8723a1ant_PsTdma( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bTurnOn, + IN u1Byte type + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type=%d\n", + (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); + pCoexDm->bCurPsTdmaOn = bTurnOn; + pCoexDm->curPsTdma = type; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + pCoexDm->bPrePsTdmaOn, pCoexDm->bCurPsTdmaOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + pCoexDm->prePsTdma, pCoexDm->curPsTdma)); + + if( (pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && + (pCoexDm->prePsTdma == pCoexDm->curPsTdma) ) + return; + } + if(pCoexDm->bCurPsTdmaOn) + { + switch(pCoexDm->curPsTdma) + { + case 1: + default: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x1a, 0x1a, 0x0, 0x40); + break; + case 2: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x12, 0x12, 0x0, 0x40); + break; + case 3: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x93, 0x3f, 0x3, 0x10, 0x40); + break; + case 4: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x93, 0x15, 0x3, 0x10, 0x0); + break; + case 5: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0xa9, 0x15, 0x3, 0x35, 0xc0); + break; + + case 8: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x93, 0x25, 0x3, 0x10, 0x0); + break; + case 9: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0xa, 0xa, 0x0, 0x40); + break; + case 10: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0xa, 0xa, 0x0, 0x40); + break; + case 11: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x5, 0x5, 0x0, 0x40); + break; + case 12: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0xa9, 0xa, 0x3, 0x15, 0xc0); + break; + + case 18: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x93, 0x25, 0x3, 0x10, 0x0); + break; + + case 20: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x2a, 0x2a, 0x0, 0x0); + break; + case 21: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x93, 0x20, 0x3, 0x10, 0x40); + break; + case 22: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x1a, 0x1a, 0x2, 0x40); + break; + case 23: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x12, 0x12, 0x2, 0x40); + break; + case 24: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0xa, 0xa, 0x2, 0x40); + break; + case 25: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x5, 0x5, 0x2, 0x40); + break; + case 26: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x93, 0x25, 0x3, 0x10, 0x0); + break; + case 27: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x13, 0x5, 0x5, 0x2, 0x40); + break; + case 28: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x3, 0x2f, 0x2f, 0x0, 0x0); + break; + + } + } + else + { + // disable PS tdma + switch(pCoexDm->curPsTdma) + { + case 8: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x8, 0x0, 0x0, 0x0, 0x0); + break; + case 0: + default: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x0, 0x0, 0x0, 0x0, 0x0); + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x860, 0x210); + break; + case 9: + halbtc8723a1ant_SetFwPstdma(pBtCoexist, type, 0x0, 0x0, 0x0, 0x0, 0x0); + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x860, 0x110); + break; + + } + } + + // update pre state + pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; + pCoexDm->prePsTdma = pCoexDm->curPsTdma; +} + + +VOID +halbtc8723a1ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + // fw all off + halbtc8723a1ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + // sw all off + halbtc8723a1ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a1ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + + // hw all off + halbtc8723a1ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); +} + +VOID +halbtc8723a1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + // force to reset coex mechanism + halbtc8723a1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); +} + +VOID +halbtc8723a1ant_BtEnableAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723a1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); +} + +VOID +halbtc8723a1ant_MonitorBtCtr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte regHPTxRx, regLPTxRx, u4Tmp; + u4Byte regHPTx=0, regHPRx=0, regLPTx=0, regLPRx=0; + u1Byte u1Tmp; + + regHPTxRx = 0x770; + regLPTxRx = 0x774; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); + regHPTx = u4Tmp & bMaskLWord; + regHPRx = (u4Tmp & bMaskHWord)>>16; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); + regLPTx = u4Tmp & bMaskLWord; + regLPRx = (u4Tmp & bMaskHWord)>>16; + + pCoexSta->highPriorityTx = regHPTx; + pCoexSta->highPriorityRx = regHPRx; + pCoexSta->lowPriorityTx = regLPTx; + pCoexSta->lowPriorityRx = regLPRx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regHPTxRx, regHPTx, regHPTx, regHPRx, regHPRx)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regLPTxRx, regLPTx, regLPTx, regLPRx, regLPRx)); + + // reset counter + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); +} + +VOID +halbtc8723a1ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtActive=TRUE, bBtDisabled=FALSE; + + // This function check if bt is disabled + + if( pCoexSta->highPriorityTx == 0 && + pCoexSta->highPriorityRx == 0 && + pCoexSta->lowPriorityTx == 0 && + pCoexSta->lowPriorityRx == 0) + { + bBtActive = FALSE; + } + if( pCoexSta->highPriorityTx == 0xffff && + pCoexSta->highPriorityRx == 0xffff && + pCoexSta->lowPriorityTx == 0xffff && + pCoexSta->lowPriorityRx == 0xffff) + { + bBtActive = FALSE; + } + if(bBtActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + bPreBtDisabled = bBtDisabled; + if(!bBtDisabled) + { + halbtc8723a1ant_BtEnableAction(pBtCoexist); + } + else + { + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + } + } +} + +VOID +halbtc8723a1ant_TdmaDurationAdjust( + IN PBTC_COEXIST pBtCoexist + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0; + u1Byte btState; + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + u4Byte wifiBw; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + btState = pCoexDm->btStatus; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], TdmaDurationAdjust()\n")); + if(pCoexDm->psTdmaGlobalCnt != pCoexDm->psTdmaMonitorCnt) + { + pCoexDm->psTdmaMonitorCnt = 0; + pCoexDm->psTdmaGlobalCnt = 0; + } + if(pCoexDm->psTdmaMonitorCnt == 0) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], first run BT A2DP + WiFi busy state!!\n")); + if(btState == BT_STATE_8723A_1ANT_ACL_ONLY_BUSY) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 22); + pCoexDm->psTdmaDuAdjType = 22; + } + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], retryCount = %d\n", retryCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if �s�� n ��2�� retry count��0, �h�ռeWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration + { + if (WaitCount <= 2) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration + { + if (WaitCount == 1) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT TxRx counter H+L <= 1200\n")); + if(btState != BT_STATE_8723A_1ANT_ACL_ONLY_BUSY) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], NOT ACL only busy!\n")); + if(BTC_WIFI_BW_HT40 != wifiBw) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], 20MHz\n")); + if(result == -1) + { + if(pCoexDm->curPsTdma == 22) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 23); + pCoexDm->psTdmaDuAdjType = 23; + } + else if(pCoexDm->curPsTdma == 23) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 24); + pCoexDm->psTdmaDuAdjType = 24; + } + else if(pCoexDm->curPsTdma == 24) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 25); + pCoexDm->psTdmaDuAdjType = 25; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 25) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 24); + pCoexDm->psTdmaDuAdjType = 24; + } + else if(pCoexDm->curPsTdma == 24) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 23); + pCoexDm->psTdmaDuAdjType = 23; + } + else if(pCoexDm->curPsTdma == 23) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 22); + pCoexDm->psTdmaDuAdjType = 22; + } + } + // error handle, if not in the following state, + // set psTdma again. + if( (pCoexDm->psTdmaDuAdjType != 22) && + (pCoexDm->psTdmaDuAdjType != 23) && + (pCoexDm->psTdmaDuAdjType != 24) && + (pCoexDm->psTdmaDuAdjType != 25) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], duration case out of handle!!\n")); + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 23); + pCoexDm->psTdmaDuAdjType = 23; + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], 40MHz\n")); + if(result == -1) + { + if(pCoexDm->curPsTdma == 23) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 24); + pCoexDm->psTdmaDuAdjType = 24; + } + else if(pCoexDm->curPsTdma == 24) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 25); + pCoexDm->psTdmaDuAdjType = 25; + } + else if(pCoexDm->curPsTdma == 25) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 27); + pCoexDm->psTdmaDuAdjType = 27; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 27) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 25); + pCoexDm->psTdmaDuAdjType = 25; + } + else if(pCoexDm->curPsTdma == 25) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 24); + pCoexDm->psTdmaDuAdjType = 24; + } + else if(pCoexDm->curPsTdma == 24) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 23); + pCoexDm->psTdmaDuAdjType = 23; + } + } + // error handle, if not in the following state, + // set psTdma again. + if( (pCoexDm->psTdmaDuAdjType != 23) && + (pCoexDm->psTdmaDuAdjType != 24) && + (pCoexDm->psTdmaDuAdjType != 25) && + (pCoexDm->psTdmaDuAdjType != 27) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], duration case out of handle!!\n")); + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 24); + pCoexDm->psTdmaDuAdjType = 24; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ACL only busy\n")); + if (result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 11) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + } + + // error handle, if not in the following state, + // set psTdma again. + if( (pCoexDm->psTdmaDuAdjType != 1) && + (pCoexDm->psTdmaDuAdjType != 2) && + (pCoexDm->psTdmaDuAdjType != 9) && + (pCoexDm->psTdmaDuAdjType != 11) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], duration case out of handle!!\n")); + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + } + } + } + + // if current PsTdma not match with the recorded one (when scan, dhcp...), + // then we have to adjust it back to the previous record one. + if(pCoexDm->curPsTdma != pCoexDm->psTdmaDuAdjType) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PsTdma type dismatch!!!, curPsTdma=%d, recordPsTdma=%d\n", + pCoexDm->curPsTdma, pCoexDm->psTdmaDuAdjType)); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if( !bScan && !bLink && !bRoam) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, pCoexDm->psTdmaDuAdjType); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n")); + } + } + pCoexDm->psTdmaMonitorCnt++; +} + + +VOID +halbtc8723a1ant_CoexForWifiConnect( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiConnected=FALSE, bWifiBusy=FALSE; + u1Byte btState, btInfoOriginal=0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + btState = pCoexDm->btStatus; + btInfoOriginal = pCoexSta->btInfoC2h[BT_INFO_SRC_8723A_1ANT_BT_RSP][0]; + + if(bWifiConnected) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi connected!!\n")); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + + if( !bWifiBusy && + ((BT_STATE_8723A_1ANT_NO_CONNECTION == btState) || + (BT_STATE_8723A_1ANT_CONNECT_IDLE == btState)) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], [Wifi is idle] or [Bt is non connected idle or Bt is connected idle]!!\n")); + + if(BT_STATE_8723A_1ANT_NO_CONNECTION == btState) + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + else if(BT_STATE_8723A_1ANT_CONNECT_IDLE == btState) + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + pBtCoexist->fBtcSetBbReg(pBtCoexist, 0x880, 0xff000000, 0xc0); + } + else + { + if( (BT_STATE_8723A_1ANT_SCO_ONLY_BUSY == btState) || + (BT_STATE_8723A_1ANT_ACL_SCO_BUSY == btState) || + (BT_STATE_8723A_1ANT_HID_BUSY == btState) || + (BT_STATE_8723A_1ANT_HID_SCO_BUSY == btState) ) + { + pBtCoexist->fBtcSetBbReg(pBtCoexist, 0x880, 0xff000000, 0x60); + } + else + { + pBtCoexist->fBtcSetBbReg(pBtCoexist, 0x880, 0xff000000, 0xc0); + } + switch(btState) + { + case BT_STATE_8723A_1ANT_NO_CONNECTION: + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + break; + case BT_STATE_8723A_1ANT_CONNECT_IDLE: + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + break; + case BT_STATE_8723A_1ANT_INQ_OR_PAG: + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + break; + case BT_STATE_8723A_1ANT_SCO_ONLY_BUSY: + case BT_STATE_8723A_1ANT_ACL_SCO_BUSY: + case BT_STATE_8723A_1ANT_HID_BUSY: + case BT_STATE_8723A_1ANT_HID_SCO_BUSY: + halbtc8723a1ant_TdmaDurationAdjust(pBtCoexist); + break; + case BT_STATE_8723A_1ANT_ACL_ONLY_BUSY: + if (btInfoOriginal&BT_INFO_8723A_1ANT_B_A2DP) + { + halbtc8723a1ant_TdmaDurationAdjust(pBtCoexist); + } + else if(btInfoOriginal&BT_INFO_8723A_1ANT_B_FTP) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + } + else if( (btInfoOriginal&BT_INFO_8723A_1ANT_B_A2DP) && + (btInfoOriginal&BT_INFO_8723A_1ANT_B_FTP) ) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + } + else + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + } + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], error!!!, undefined case in halbtc8723a1ant_CoexForWifiConnect()!!\n")); + break; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is disconnected!!\n")); + } + + pCoexDm->psTdmaGlobalCnt++; +} + +//============================================================ +// work around function start with wa_halbtc8723a1ant_ +//============================================================ +VOID +wa_halbtc8723a1ant_MonitorC2h( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte tmp1b=0x0; + u4Byte curC2hTotalCnt=0x0; + static u4Byte preC2hTotalCnt=0x0, sameCntPollingTime=0x0; + + curC2hTotalCnt+=pCoexSta->btInfoC2hCnt[BT_INFO_SRC_8723A_1ANT_BT_RSP]; + + if(curC2hTotalCnt == preC2hTotalCnt) + { + sameCntPollingTime++; + } + else + { + preC2hTotalCnt = curC2hTotalCnt; + sameCntPollingTime = 0; + } + + if(sameCntPollingTime >= 2) + { + tmp1b = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x1af); + if(tmp1b != 0x0) + { + pCoexSta->c2hHangDetectCnt++; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x1af, 0x0); + } + } +} + +//============================================================ +// extern function start with EXhalbtc8723a1ant_ +//============================================================ +VOID +EXhalbtc8723a1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 1Ant Init HW Config!!\n")); + + // backup rf 0x1e value + pCoexDm->btRf0x1eBackup = + pBtCoexist->fBtcGetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff); + + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x20); + + // enable counter statistics + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); + + // coex table + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, 0x0); // 1-Ant coex + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, 0xffff); // wifi break table + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, 0x55555555); //coex table + + // antenna switch control parameter + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x858, 0xaaaaaaaa); + + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x860, 0x210); //set antenna at wifi side if ANTSW is software control + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x870, 0x300); //SPDT(connected with TRSW) control by hardware PTA + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x874, 0x22804000); //ANTSW keep by GNT_BT + + // coexistence parameters + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x778, 0x1); // enable RTK mode PTA +} + +VOID +EXhalbtc8723a1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + halbtc8723a1ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8723a1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + pu1Byte cliBuf=pBtCoexist->cliBuf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir; + u1Byte wifiDot11Chnl, wifiHsChnl; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(!pBoardInfo->bBtExist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum); + CL_PRINTF(cliBuf); + + if(pBtCoexist->bManualControl) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "[Action Manual control]!!"); + CL_PRINTF(cliBuf); + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ + wifiDot11Chnl, wifiHsChnl, bBtHsOn); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], + pCoexDm->wifiChnlInfo[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8723A_1ANT_BT_STATUS_IDLE == pCoexDm->btStatus)? "idle":( (BT_8723A_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy"))), + pCoexSta->btRssi, pCoexSta->btRetryCnt); + CL_PRINTF(cliBuf); + + if(pStackInfo->bProfileNotified) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pStackInfo->bScoExist, pStackInfo->bHidExist, pStackInfo->bPanExist, pStackInfo->bA2dpExist); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + } + + btInfoExt = pCoexSta->btInfoExt; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (btInfoExt&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cliBuf); + + for(i=0; i<BT_INFO_SRC_8723A_1ANT_MAX; i++) + { + if(pCoexSta->btInfoC2hCnt[i]) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8723a1Ant[i], \ + pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], + pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], + pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], + pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); + CL_PRINTF(cliBuf); + } + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "write 0x1af=0x0 num", \ + pCoexSta->c2hHangDetectCnt); + CL_PRINTF(cliBuf); + + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", "SM1[ShRf/ LpRA/ LimDig]", \ + pCoexDm->bCurRfRxLpfShrink, pCoexDm->bCurLowPenaltyRa, pCoexDm->bLimitedDig); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + if(!pBtCoexist->bManualControl) + { + psTdmaCase = pCoexDm->curPsTdma; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d", "PS TDMA", \ + pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], + pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], + pCoexDm->psTdmaPara[4], psTdmaCase); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "IgnWlanAct", \ + pCoexDm->bCurIgnoreWlanAct); + CL_PRINTF(cliBuf); + } + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", \ + pCoexDm->btRf0x1eBackup); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x778); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x783); + u1Tmp[2] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x796); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x778/ 0x783/ 0x796", \ + u1Tmp[0], u1Tmp[1], u1Tmp[2]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x880); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x880", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x40", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x550); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x522); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x484); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x484(rate adaptive)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda8); + u4Tmp[3] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xdac); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0xda0/0xda4/0xda8/0xdac(FA cnt)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u4Tmp[3]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp[0]); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770 (hp rx[31:16]/tx[15:0])", \ + pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(lp rx[31:16]/tx[15:0])", \ + pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); + CL_PRINTF(cliBuf); + + // Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x41b); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x41b (mgntQ hang chk == 0xf)", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8723a1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + halbtc8723a1ant_CoexAllOff(pBtCoexist); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + //halbtc8723a1ant_InitCoexDm(pBtCoexist); + } +} + +VOID +EXhalbtc8723a1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + } +} + +VOID +EXhalbtc8723a1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE; + + halbtc8723a1ant_NotifyFwScan(pBtCoexist, type); + + if(pBtCoexist->btInfo.bBtDisabled) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + } + else + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + if(!bWifiConnected) // non-connected scan + { + //set 0x550[3]=1 before PsTdma + halbtc8723a1ant_Reg0x550Bit3(pBtCoexist, TRUE); + } + + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + if(!bWifiConnected) // non-connected scan + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + halbtc8723a1ant_CoexForWifiConnect(pBtCoexist); + } + } + } +} + +VOID +EXhalbtc8723a1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE; + + if(pBtCoexist->btInfo.bBtDisabled) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + } + else + { + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + //set 0x550[3]=1 before PsTdma + halbtc8723a1ant_Reg0x550Bit3(pBtCoexist, TRUE); + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); // extend wifi slot + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(!bWifiConnected) // non-connected scan + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + halbtc8723a1ant_CoexForWifiConnect(pBtCoexist); + } + } + } +} + +VOID +EXhalbtc8723a1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } +} + +VOID +EXhalbtc8723a1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(type == BTC_PACKET_DHCP) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], DHCP Packet notify\n")); + if(pBtCoexist->btInfo.bBtDisabled) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + } + else + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 18); + } + } +} + +VOID +EXhalbtc8723a1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ + u1Byte btInfo=0; + u1Byte i, rspSource=0; + BOOLEAN bBtHsOn=FALSE, bBtBusy=FALSE, bForceLps=FALSE; + + pCoexSta->bC2hBtInfoReqSent = FALSE; + + rspSource = BT_INFO_SRC_8723A_1ANT_BT_RSP; + pCoexSta->btInfoC2hCnt[rspSource]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rspSource, length)); + for(i=0; i<length; i++) + { + pCoexSta->btInfoC2h[rspSource][i] = tmpBuf[i]; + if(i == 0) + btInfo = tmpBuf[i]; + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); + } + } + + if(BT_INFO_SRC_8723A_1ANT_WIFI_FW != rspSource) + { + pCoexSta->btRetryCnt = + pCoexSta->btInfoC2h[rspSource][1]; + + pCoexSta->btRssi = + pCoexSta->btInfoC2h[rspSource][2]*2+10; + + pCoexSta->btInfoExt = + pCoexSta->btInfoC2h[rspSource][3]; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + // check BIT2 first ==> check if bt is under inquiry or page scan + if(btInfo & BT_INFO_8723A_1ANT_B_INQ_PAGE) + { + pCoexSta->bC2hBtInquiryPage = TRUE; + } + else + { + pCoexSta->bC2hBtInquiryPage = FALSE; + } + btInfo &= ~BIT2; + if(!(btInfo & BIT0)) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_NO_CONNECTION; + bForceLps = FALSE; + } + else + { + bForceLps = TRUE; + if(btInfo == 0x1) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_CONNECT_IDLE; + } + else if(btInfo == 0x9) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_ACL_ONLY_BUSY; + bBtBusy = TRUE; + } + else if(btInfo == 0x13) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_SCO_ONLY_BUSY; + bBtBusy = TRUE; + } + else if(btInfo == 0x1b) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_ACL_SCO_BUSY; + bBtBusy = TRUE; + } + else if(btInfo == 0x29) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_HID_BUSY; + bBtBusy = TRUE; + } + else if(btInfo == 0x3b) + { + pCoexDm->btStatus = BT_STATE_8723A_1ANT_HID_SCO_BUSY; + bBtBusy = TRUE; + } + } + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_LIMITED_DIG, &bBtBusy); + if(bForceLps) + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_ENTER_LPS, NULL); + else + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + + if( (BT_STATE_8723A_1ANT_NO_CONNECTION == pCoexDm->btStatus) || + (BT_STATE_8723A_1ANT_CONNECT_IDLE == pCoexDm->btStatus) ) + { + if(pCoexSta->bC2hBtInquiryPage) + pCoexDm->btStatus = BT_STATE_8723A_1ANT_INQ_OR_PAG; + } +} + +VOID +EXhalbtc8723a1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723a1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 0); + + halbtc8723a1ant_LowPenaltyRa(pBtCoexist, FORCE_EXEC, FALSE); + halbtc8723a1ant_RfShrink(pBtCoexist, FORCE_EXEC, FALSE); + + halbtc8723a1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + EXhalbtc8723a1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8723a1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE, bWifiConnected=FALSE; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], 1Ant Periodical!!\n")); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + // work around for c2h hang + wa_halbtc8723a1ant_MonitorC2h(pBtCoexist); + + halbtc8723a1ant_QueryBtInfo(pBtCoexist); + halbtc8723a1ant_MonitorBtCtr(pBtCoexist); + halbtc8723a1ant_MonitorBtEnableDisable(pBtCoexist); + + + if(bScan) + return; + if(bLink) + return; + + if(bWifiConnected) + { + if(pBtCoexist->btInfo.bBtDisabled) + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + + halbtc8723a1ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a1ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + } + else + { + halbtc8723a1ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a1ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a1ant_CoexForWifiConnect(pBtCoexist); + } + } + else + { + halbtc8723a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + halbtc8723a1ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a1ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + } +} + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a1Ant.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a1Ant.h new file mode 100644 index 0000000..6d4e1b4 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a1Ant.h @@ -0,0 +1,171 @@ +//=========================================== +// The following is for 8723A 1Ant BT Co-exist definition +//=========================================== +#define BT_INFO_8723A_1ANT_B_FTP BIT7 +#define BT_INFO_8723A_1ANT_B_A2DP BIT6 +#define BT_INFO_8723A_1ANT_B_HID BIT5 +#define BT_INFO_8723A_1ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8723A_1ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8723A_1ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8723A_1ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8723A_1ANT_B_CONNECTION BIT0 + +typedef enum _BT_STATE_8723A_1ANT{ + BT_STATE_8723A_1ANT_DISABLED = 0, + BT_STATE_8723A_1ANT_NO_CONNECTION = 1, + BT_STATE_8723A_1ANT_CONNECT_IDLE = 2, + BT_STATE_8723A_1ANT_INQ_OR_PAG = 3, + BT_STATE_8723A_1ANT_ACL_ONLY_BUSY = 4, + BT_STATE_8723A_1ANT_SCO_ONLY_BUSY = 5, + BT_STATE_8723A_1ANT_ACL_SCO_BUSY = 6, + BT_STATE_8723A_1ANT_HID_BUSY = 7, + BT_STATE_8723A_1ANT_HID_SCO_BUSY = 8, + BT_STATE_8723A_1ANT_MAX +}BT_STATE_8723A_1ANT, *PBT_STATE_8723A_1ANT; + +#define BTC_RSSI_COEX_THRESH_TOL_8723A_1ANT 2 + +typedef enum _BT_INFO_SRC_8723A_1ANT{ + BT_INFO_SRC_8723A_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723A_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723A_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723A_1ANT_MAX +}BT_INFO_SRC_8723A_1ANT,*PBT_INFO_SRC_8723A_1ANT; + +typedef enum _BT_8723A_1ANT_BT_STATUS{ + BT_8723A_1ANT_BT_STATUS_IDLE = 0x0, + BT_8723A_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723A_1ANT_BT_STATUS_NON_IDLE = 0x2, + BT_8723A_1ANT_BT_STATUS_MAX +}BT_8723A_1ANT_BT_STATUS,*PBT_8723A_1ANT_BT_STATUS; + +typedef enum _BT_8723A_1ANT_COEX_ALGO{ + BT_8723A_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723A_1ANT_COEX_ALGO_SCO = 0x1, + BT_8723A_1ANT_COEX_ALGO_HID = 0x2, + BT_8723A_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8723A_1ANT_COEX_ALGO_PANEDR = 0x4, + BT_8723A_1ANT_COEX_ALGO_PANHS = 0x5, + BT_8723A_1ANT_COEX_ALGO_PANEDR_A2DP = 0x6, + BT_8723A_1ANT_COEX_ALGO_PANEDR_HID = 0x7, + BT_8723A_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x8, + BT_8723A_1ANT_COEX_ALGO_HID_A2DP = 0x9, + BT_8723A_1ANT_COEX_ALGO_MAX +}BT_8723A_1ANT_COEX_ALGO,*PBT_8723A_1ANT_COEX_ALGO; + +typedef struct _COEX_DM_8723A_1ANT{ + // fw mechanism + BOOLEAN bCurIgnoreWlanAct; + BOOLEAN bPreIgnoreWlanAct; + u1Byte prePsTdma; + u1Byte curPsTdma; + u1Byte psTdmaPara[5]; + u1Byte psTdmaDuAdjType; + u4Byte psTdmaMonitorCnt; + u4Byte psTdmaGlobalCnt; + BOOLEAN bResetTdmaAdjust; + BOOLEAN bPrePsTdmaOn; + BOOLEAN bCurPsTdmaOn; + + // sw mechanism + BOOLEAN bPreRfRxLpfShrink; + BOOLEAN bCurRfRxLpfShrink; + u4Byte btRf0x1eBackup; + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + u4Byte preVal0x6c0; + u4Byte curVal0x6c0; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u1Byte preVal0x6cc; + u1Byte curVal0x6cc; + BOOLEAN bLimitedDig; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + u1Byte btStatus; + u1Byte wifiChnlInfo[3]; +} COEX_DM_8723A_1ANT, *PCOEX_DM_8723A_1ANT; + +typedef struct _COEX_STA_8723A_1ANT{ + u4Byte highPriorityTx; + u4Byte highPriorityRx; + u4Byte lowPriorityTx; + u4Byte lowPriorityRx; + u1Byte btRssi; + u1Byte preBtRssiState; + u1Byte preBtRssiState1; + u1Byte preWifiRssiState[4]; + BOOLEAN bC2hBtInfoReqSent; + u1Byte btInfoC2h[BT_INFO_SRC_8723A_1ANT_MAX][10]; + u4Byte btInfoC2hCnt[BT_INFO_SRC_8723A_1ANT_MAX]; + BOOLEAN bC2hBtInquiryPage; + u1Byte btRetryCnt; + u1Byte btInfoExt; + //BOOLEAN bHoldForStackOperation; + //u1Byte bHoldPeriodCnt; + // this is for c2h hang work-around + u4Byte c2hHangDetectCnt; +}COEX_STA_8723A_1ANT, *PCOEX_STA_8723A_1ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8723a1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8723a1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a2Ant.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a2Ant.c new file mode 100644 index 0000000..9e2c184 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a2Ant.c @@ -0,0 +1,3780 @@ +//============================================================ +// Description: +// +// This file is for RTL8723A Co-exist mechanism +// +// History +// 2012/08/22 Cosa first check in. +// 2012/11/14 Cosa Revise for 8723A 2Ant out sourcing. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8723A_2ANT GLCoexDm8723a2Ant; +static PCOEX_DM_8723A_2ANT pCoexDm=&GLCoexDm8723a2Ant; +static COEX_STA_8723A_2ANT GLCoexSta8723a2Ant; +static PCOEX_STA_8723A_2ANT pCoexSta=&GLCoexSta8723a2Ant; + +const char *const GLBtInfoSrc8723a2Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8723a2ant_ +//============================================================ +BOOLEAN +halbtc8723a2ant_IsWifiIdle( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiConnected=FALSE, bScan=FALSE, bLink=FALSE, bRoam=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if(bWifiConnected) + return FALSE; + if(bScan) + return FALSE; + if(bLink) + return FALSE; + if(bRoam) + return FALSE; + + return TRUE; +} + +u1Byte +halbtc8723a2ant_BtRssiState( + u1Byte levelNum, + u1Byte rssiThresh, + u1Byte rssiThresh1 + ) +{ + s4Byte btRssi=0; + u1Byte btRssiState=pCoexSta->preBtRssiState; + + btRssi = pCoexSta->btRssi; + + if(levelNum == 2) + { + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else + { + if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); + return pCoexSta->preBtRssiState; + } + + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT)) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); + } + } + else + { + if(btRssi < rssiThresh1) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + + pCoexSta->preBtRssiState = btRssiState; + + return btRssiState; +} + +u1Byte +halbtc8723a2ant_WifiRssiState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte index, + IN u1Byte levelNum, + IN u1Byte rssiThresh, + IN u1Byte rssiThresh1 + ) +{ + s4Byte wifiRssi=0; + u1Byte wifiRssiState=pCoexSta->preWifiRssiState[index]; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(levelNum == 2) + { + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return pCoexSta->preWifiRssiState[index]; + } + + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifiRssi < rssiThresh1) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + pCoexSta->preWifiRssiState[index] = wifiRssiState; + + return wifiRssiState; +} + +VOID +halbtc8723a2ant_IndicateWifiChnlBwInfo( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u1Byte H2C_Parameter[3] ={0}; + u4Byte wifiBw; + u1Byte wifiCentralChnl; + + // only 2.4G we need to inform bt the chnl mask + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); + if( (BTC_MEDIA_CONNECT == type) && + (wifiCentralChnl <= 14) ) + { + H2C_Parameter[0] = 0x1; + H2C_Parameter[1] = wifiCentralChnl; + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + H2C_Parameter[2] = 0x30; + else + H2C_Parameter[2] = 0x20; + } + + pCoexDm->wifiChnlInfo[0] = H2C_Parameter[0]; + pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1]; + pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x19=0x%x\n", + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x19, 3, H2C_Parameter); +} + +VOID +halbtc8723a2ant_QueryBtInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + pCoexSta->bC2hBtInfoReqSent = TRUE; + + H2C_Parameter[0] |= BIT0; // trigger + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Query Bt Info, FW write 0x38=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x38, 1, H2C_Parameter); +} +u1Byte +halbtc8723a2ant_ActionAlgorithm( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + BOOLEAN bBtHsOn=FALSE, bBtBusy=FALSE, bLimitedDig=FALSE; + u1Byte algorithm=BT_8723A_2ANT_COEX_ALGO_UNDEFINED; + u1Byte numOfDiffProfile=0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + //====================== + // here we get BT status first + //====================== + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_IDLE; + + if((pStackInfo->bScoExist) ||(bBtHsOn) ||(pStackInfo->bHidExist)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO or HID or HS exists, set BT non-idle !!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_NON_IDLE; + } + else + { + // A2dp profile + if( (pBtCoexist->stackInfo.numOfLink == 1) && + (pStackInfo->bA2dpExist) ) + { + if( (pCoexSta->lowPriorityTx+ pCoexSta->lowPriorityRx) < 100) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP, low priority tx+rx < 100, set BT connected-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP, low priority tx+rx >= 100, set BT non-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_NON_IDLE; + } + } + // Pan profile + if( (pBtCoexist->stackInfo.numOfLink == 1) && + (pStackInfo->bPanExist) ) + { + if((pCoexSta->lowPriorityTx+ pCoexSta->lowPriorityRx) < 600) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN, low priority tx+rx < 600, set BT connected-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE; + } + else + { + if(pCoexSta->lowPriorityTx) + { + if((pCoexSta->lowPriorityRx /pCoexSta->lowPriorityTx)>9 ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN, low priority rx/tx > 9, set BT connected-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE; + } + } + } + if(BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE != pCoexDm->btStatus) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN, set BT non-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_NON_IDLE; + } + } + // Pan+A2dp profile + if( (pBtCoexist->stackInfo.numOfLink == 2) && + (pStackInfo->bA2dpExist) && + (pStackInfo->bPanExist) ) + { + if((pCoexSta->lowPriorityTx+ pCoexSta->lowPriorityRx) < 600) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN+A2DP, low priority tx+rx < 600, set BT connected-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE; + } + else + { + if(pCoexSta->lowPriorityTx) + { + if((pCoexSta->lowPriorityRx /pCoexSta->lowPriorityTx)>9 ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN+A2DP, low priority rx/tx > 9, set BT connected-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE; + } + } + } + if(BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE != pCoexDm->btStatus) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN+A2DP, set BT non-idle!!!\n")); + pCoexDm->btStatus = BT_8723A_2ANT_BT_STATUS_NON_IDLE; + } + } + } + if(BT_8723A_2ANT_BT_STATUS_IDLE != pCoexDm->btStatus) + { + bBtBusy = TRUE; + bLimitedDig = TRUE; + } + else + { + bBtBusy = FALSE; + bLimitedDig = FALSE; + } + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_LIMITED_DIG, &bLimitedDig); + //====================== + + if(!pStackInfo->bBtLinkExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No profile exists!!!\n")); + return algorithm; + } + + if(pStackInfo->bScoExist) + numOfDiffProfile++; + if(pStackInfo->bHidExist) + numOfDiffProfile++; + if(pStackInfo->bPanExist) + numOfDiffProfile++; + if(pStackInfo->bA2dpExist) + numOfDiffProfile++; + + if(numOfDiffProfile == 1) + { + if(pStackInfo->bScoExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO only\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_SCO; + } + else + { + if(pStackInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID; + } + else if(pStackInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_A2DP; + } + else if(pStackInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(HS) only\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(EDR) only\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR; + } + } + } + } + else if(numOfDiffProfile == 2) + { + if(pStackInfo->bScoExist) + { + if(pStackInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID; + } + else if(pStackInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP ==> SCO\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_SCO; + } + else if(pStackInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(HS)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(EDR)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pStackInfo->bHidExist && + pStackInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID_A2DP; + } + else if( pStackInfo->bHidExist && + pStackInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(HS)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } + else if(numOfDiffProfile == 3) + { + if(pStackInfo->bScoExist) + { + if( pStackInfo->bHidExist && + pStackInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP ==> HID\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID; + } + else if( pStackInfo->bHidExist && + pStackInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(HS)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(EDR)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(HS)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pStackInfo->bHidExist && + pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + else if(numOfDiffProfile >= 3) + { + if(pStackInfo->bScoExist) + { + if( pStackInfo->bHidExist && + pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n")); + + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n")); + algorithm = BT_8723A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +BOOLEAN +halbtc8723a2ant_NeedToDecBtPwr( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bRet=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiConnected=FALSE; + s4Byte btHsRssi=0; + + if(!pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn)) + return FALSE; + if(!pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected)) + return FALSE; + if(!pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi)) + return FALSE; + + if(bWifiConnected) + { + if(bBtHsOn) + { + if(btHsRssi > 37) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], Need to decrease bt power for HS mode!!\n")); + bRet = TRUE; + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], Need to decrease bt power for Wifi is connected!!\n")); + bRet = TRUE; + } + } + + return bRet; +} + +VOID +halbtc8723a2ant_SetFwDacSwingLevel( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte dacSwingLvl + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + // There are several type of dacswing + // 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 + H2C_Parameter[0] = dacSwingLvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Set Dac Swing Level=0x%x\n", dacSwingLvl)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x29=0x%x\n", H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x29, 1, H2C_Parameter); +} + +VOID +halbtc8723a2ant_SetFwDecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bDecBtPwr + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = 0; + + if(bDecBtPwr) + { + H2C_Parameter[0] |= BIT1; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], decrease Bt Power : %s, FW write 0x21=0x%x\n", + (bDecBtPwr? "Yes!!":"No!!"), H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x21, 1, H2C_Parameter); +} + +VOID +halbtc8723a2ant_DecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDecBtPwr + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s Dec BT power = %s\n", + (bForceExec? "force to":""), ((bDecBtPwr)? "ON":"OFF"))); + pCoexDm->bCurDecBtPwr = bDecBtPwr; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreDecBtPwr=%d, bCurDecBtPwr=%d\n", + pCoexDm->bPreDecBtPwr, pCoexDm->bCurDecBtPwr)); + + if(pCoexDm->bPreDecBtPwr == pCoexDm->bCurDecBtPwr) + return; + } + halbtc8723a2ant_SetFwDecBtPwr(pBtCoexist, pCoexDm->bCurDecBtPwr); + + pCoexDm->bPreDecBtPwr = pCoexDm->bCurDecBtPwr; +} + +VOID +halbtc8723a2ant_FwDacSwingLvl( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte fwDacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set FW Dac Swing level = %d\n", + (bForceExec? "force to":""), fwDacSwingLvl)); + pCoexDm->curFwDacSwingLvl = fwDacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preFwDacSwingLvl=%d, curFwDacSwingLvl=%d\n", + pCoexDm->preFwDacSwingLvl, pCoexDm->curFwDacSwingLvl)); + + if(pCoexDm->preFwDacSwingLvl == pCoexDm->curFwDacSwingLvl) + return; + } + + halbtc8723a2ant_SetFwDacSwingLevel(pBtCoexist, pCoexDm->curFwDacSwingLvl); + + pCoexDm->preFwDacSwingLvl = pCoexDm->curFwDacSwingLvl; +} + +VOID +halbtc8723a2ant_SetSwRfRxLpfCorner( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bRxRfShrinkOn + ) +{ + if(bRxRfShrinkOn) + { + //Shrink RF Rx LPF corner + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Shrink RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, 0xf0ff7); + } + else + { + //Resume RF Rx LPF corner + // After initialized, we can use pCoexDm->btRf0x1eBackup + if(pBtCoexist->bInitilized) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, pCoexDm->btRf0x1eBackup); + } + } +} + +VOID +halbtc8723a2ant_RfShrink( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRxRfShrinkOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn Rx RF Shrink = %s\n", + (bForceExec? "force to":""), ((bRxRfShrinkOn)? "ON":"OFF"))); + pCoexDm->bCurRfRxLpfShrink = bRxRfShrinkOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreRfRxLpfShrink=%d, bCurRfRxLpfShrink=%d\n", + pCoexDm->bPreRfRxLpfShrink, pCoexDm->bCurRfRxLpfShrink)); + + if(pCoexDm->bPreRfRxLpfShrink == pCoexDm->bCurRfRxLpfShrink) + return; + } + halbtc8723a2ant_SetSwRfRxLpfCorner(pBtCoexist, pCoexDm->bCurRfRxLpfShrink); + + pCoexDm->bPreRfRxLpfShrink = pCoexDm->bCurRfRxLpfShrink; +} + +VOID +halbtc8723a2ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte tmpU1; + + tmpU1 = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x4fd); + tmpU1 |= BIT0; + if(bLowPenaltyRa) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set low penalty!!\n")); + tmpU1 &= ~BIT2; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set normal!!\n")); + tmpU1 |= BIT2; + } + + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x4fd, tmpU1); +} + +VOID +halbtc8723a2ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); + + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8723a2ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8723a2ant_SetSwFullTimeDacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bSwDacSwingOn, + IN u4Byte swDacSwingLvl + ) +{ + if(bSwDacSwingOn) + { + pBtCoexist->fBtcSetBbReg(pBtCoexist, 0x880, 0xff000000, swDacSwingLvl); + } + else + { + pBtCoexist->fBtcSetBbReg(pBtCoexist, 0x880, 0xff000000, 0xc0); + } +} + + +VOID +halbtc8723a2ant_DacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDacSwingOn, + IN u4Byte dacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn DacSwing=%s, dacSwingLvl=0x%x\n", + (bForceExec? "force to":""), ((bDacSwingOn)? "ON":"OFF"), dacSwingLvl)); + pCoexDm->bCurDacSwingOn = bDacSwingOn; + pCoexDm->curDacSwingLvl = dacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x, bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + pCoexDm->bPreDacSwingOn, pCoexDm->preDacSwingLvl, + pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl)); + + if( (pCoexDm->bPreDacSwingOn == pCoexDm->bCurDacSwingOn) && + (pCoexDm->preDacSwingLvl == pCoexDm->curDacSwingLvl) ) + return; + } + delay_ms(30); + halbtc8723a2ant_SetSwFullTimeDacSwing(pBtCoexist, bDacSwingOn, dacSwingLvl); + + pCoexDm->bPreDacSwingOn = pCoexDm->bCurDacSwingOn; + pCoexDm->preDacSwingLvl = pCoexDm->curDacSwingLvl; +} + +VOID +halbtc8723a2ant_SetAdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAdcBackOff + ) +{ + if(bAdcBackOff) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level On!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc04,0x3a07611); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level Off!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc04,0x3a05611); + } +} + +VOID +halbtc8723a2ant_AdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAdcBackOff + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn AdcBackOff = %s\n", + (bForceExec? "force to":""), ((bAdcBackOff)? "ON":"OFF"))); + pCoexDm->bCurAdcBackOff = bAdcBackOff; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAdcBackOff=%d, bCurAdcBackOff=%d\n", + pCoexDm->bPreAdcBackOff, pCoexDm->bCurAdcBackOff)); + + if(pCoexDm->bPreAdcBackOff == pCoexDm->bCurAdcBackOff) + return; + } + halbtc8723a2ant_SetAdcBackOff(pBtCoexist, pCoexDm->bCurAdcBackOff); + + pCoexDm->bPreAdcBackOff = pCoexDm->bCurAdcBackOff; +} + +VOID +halbtc8723a2ant_SetAgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAgcTableEn + ) +{ + u1Byte rssiAdjustVal=0; + + if(bAgcTableEn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x4e1c0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x4d1d0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x4c1e0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x4b1f0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x4a200001); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0xdc000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x90000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x51000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x12000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1a, 0xfffff, 0x00355); + + rssiAdjustVal = 6; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x641c0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x631d0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x621e0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x611f0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78,0x60200001); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x32000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0x71000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0xb0000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x12, 0xfffff, 0xfc000); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1a, 0xfffff, 0x30355); + } + + // set rssiAdjustVal for wifi module. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, &rssiAdjustVal); +} + + +VOID +halbtc8723a2ant_AgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAgcTableEn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s %s Agc Table\n", + (bForceExec? "force to":""), ((bAgcTableEn)? "Enable":"Disable"))); + pCoexDm->bCurAgcTableEn = bAgcTableEn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + pCoexDm->bPreAgcTableEn, pCoexDm->bCurAgcTableEn)); + + if(pCoexDm->bPreAgcTableEn == pCoexDm->bCurAgcTableEn) + return; + } + halbtc8723a2ant_SetAgcTable(pBtCoexist, bAgcTableEn); + + pCoexDm->bPreAgcTableEn = pCoexDm->bCurAgcTableEn; +} + +VOID +halbtc8723a2ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c0, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8723a2ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c0, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c0, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c0 = val0x6c0; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c0=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + pCoexDm->preVal0x6c0, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c0=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + pCoexDm->curVal0x6c0, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8723a2ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8723a2ant_SetFwIgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnable + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + if(bEnable) + { + H2C_Parameter[0] |= BIT0; // function enable + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x25=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x25, 1, H2C_Parameter); +} + +VOID +halbtc8723a2ant_IgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); + pCoexDm->bCurIgnoreWlanAct = bEnable; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); + + if(pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) + return; + } + halbtc8723a2ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); + + pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; +} + +VOID +halbtc8723a2ant_SetFwPstdma( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte byte1, + IN u1Byte byte2, + IN u1Byte byte3, + IN u1Byte byte4, + IN u1Byte byte5 + ) +{ + u1Byte H2C_Parameter[5] ={0}; + + H2C_Parameter[0] = byte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = byte5; + + pCoexDm->psTdmaPara[0] = byte1; + pCoexDm->psTdmaPara[1] = byte2; + pCoexDm->psTdmaPara[2] = byte3; + pCoexDm->psTdmaPara[3] = byte4; + pCoexDm->psTdmaPara[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x3a(5bytes)=0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x3a, 5, H2C_Parameter); +} + +VOID +halbtc8723a2ant_PsTdma( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bTurnOn, + IN u1Byte type + ) +{ + u4Byte btTxRxCnt=0; + + btTxRxCnt = pCoexSta->highPriorityTx+pCoexSta->highPriorityRx+ + pCoexSta->lowPriorityTx+pCoexSta->lowPriorityRx; + + if(btTxRxCnt > 3000) + { + pCoexDm->bCurPsTdmaOn = TRUE; + pCoexDm->curPsTdma = 8; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], turn ON PS TDMA, type=%d for BT tx/rx counters=%d(>3000)\n", + pCoexDm->curPsTdma, btTxRxCnt)); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type=%d\n", + (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); + pCoexDm->bCurPsTdmaOn = bTurnOn; + pCoexDm->curPsTdma = type; + } + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + pCoexDm->bPrePsTdmaOn, pCoexDm->bCurPsTdmaOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + pCoexDm->prePsTdma, pCoexDm->curPsTdma)); + + if( (pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && + (pCoexDm->prePsTdma == pCoexDm->curPsTdma) ) + return; + } + if(pCoexDm->bCurPsTdmaOn) + { + switch(pCoexDm->curPsTdma) + { + case 1: + default: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x98); + break; + case 2: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x98); + break; + case 3: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0xe1, 0x98); + break; + case 4: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xa3, 0x5, 0x5, 0xe1, 0x80); + break; + case 5: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x98); + break; + case 6: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0x60, 0x98); + break; + case 7: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0x60, 0x98); + break; + case 8: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xa3, 0x5, 0x5, 0x60, 0x80); + break; + case 9: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x98); + break; + case 10: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x98); + break; + case 11: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0xe1, 0x98); + break; + case 12: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0xe1, 0x98); + break; + case 13: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x98); + break; + case 14: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0x60, 0x98); + break; + case 15: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0x60, 0x98); + break; + case 16: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0x60, 0x98); + break; + case 17: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xa3, 0x2f, 0x2f, 0x60, 0x80); + break; + case 18: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0xe1, 0x98); + break; + case 19: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0xe1, 0x98); + break; + case 20: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0x60, 0x98); + break; + } + } + else + { + // disable PS tdma + switch(pCoexDm->curPsTdma) + { + case 0: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x8, 0x0); + break; + case 1: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + break; + default: + halbtc8723a2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x8, 0x0); + break; + } + } + + // update pre state + pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; + pCoexDm->prePsTdma = pCoexDm->curPsTdma; +} + + +VOID +halbtc8723a2ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + // fw all off + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + // sw all off + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + + // hw all off + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); +} + +VOID +halbtc8723a2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + // force to reset coex mechanism + halbtc8723a2ant_CoexTable(pBtCoexist, FORCE_EXEC, 0x55555555, 0xffff, 0x3); + halbtc8723a2ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, FORCE_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, FORCE_EXEC, FALSE); + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); + + halbtc8723a2ant_AgcTable(pBtCoexist, FORCE_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, FORCE_EXEC, FALSE); + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, FORCE_EXEC, FALSE); + halbtc8723a2ant_RfShrink(pBtCoexist, FORCE_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, FORCE_EXEC, FALSE, 0xc0); +} + +VOID +halbtc8723a2ant_BtInquiryPage( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bLowPwrDisable=TRUE; + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); +} + +VOID +halbtc8723a2ant_BtEnableAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiConnected=FALSE; + + // Here we need to resend some wifi info to BT + // because bt is reset and loss of the info. + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(bWifiConnected) + { + halbtc8723a2ant_IndicateWifiChnlBwInfo(pBtCoexist, BTC_MEDIA_CONNECT); + } + else + { + halbtc8723a2ant_IndicateWifiChnlBwInfo(pBtCoexist, BTC_MEDIA_DISCONNECT); + } + + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); +} + +VOID +halbtc8723a2ant_MonitorBtCtr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte regHPTxRx, regLPTxRx, u4Tmp; + u4Byte regHPTx=0, regHPRx=0, regLPTx=0, regLPRx=0; + u1Byte u1Tmp; + + regHPTxRx = 0x770; + regLPTxRx = 0x774; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); + regHPTx = u4Tmp & bMaskLWord; + regHPRx = (u4Tmp & bMaskHWord)>>16; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); + regLPTx = u4Tmp & bMaskLWord; + regLPRx = (u4Tmp & bMaskHWord)>>16; + + pCoexSta->highPriorityTx = regHPTx; + pCoexSta->highPriorityRx = regHPRx; + pCoexSta->lowPriorityTx = regLPTx; + pCoexSta->lowPriorityRx = regLPRx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regHPTxRx, regHPTx, regHPTx, regHPRx, regHPRx)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regLPTxRx, regLPTx, regLPTx, regLPRx, regLPRx)); + + // reset counter + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); +} + +VOID +halbtc8723a2ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtActive=TRUE, bBtDisabled=FALSE; + + // This function check if bt is disabled + + if( pCoexSta->highPriorityTx == 0 && + pCoexSta->highPriorityRx == 0 && + pCoexSta->lowPriorityTx == 0 && + pCoexSta->lowPriorityRx == 0) + { + bBtActive = FALSE; + } + if( pCoexSta->highPriorityTx == 0xffff && + pCoexSta->highPriorityRx == 0xffff && + pCoexSta->lowPriorityTx == 0xffff && + pCoexSta->lowPriorityRx == 0xffff) + { + bBtActive = FALSE; + } + if(bBtActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + bPreBtDisabled = bBtDisabled; + if(!bBtDisabled) + { + halbtc8723a2ant_BtEnableAction(pBtCoexist); + } + } +} + +BOOLEAN +halbtc8723a2ant_IsCommonAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + BOOLEAN bCommon=FALSE, bWifiConnected=FALSE; + BOOLEAN bLowPwrDisable=FALSE; + + if(!pStackInfo->bBtLinkExist) + { + bLowPwrDisable = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + } + else + { + bLowPwrDisable = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + if(halbtc8723a2ant_IsWifiIdle(pBtCoexist) && + BT_8723A_2ANT_BT_STATUS_IDLE == pCoexDm->btStatus) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi idle + Bt idle!!\n")); + + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + + bCommon = TRUE; + } + else if(!halbtc8723a2ant_IsWifiIdle(pBtCoexist) && + (BT_8723A_2ANT_BT_STATUS_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non-idle + BT idle!!\n")); + + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + + bCommon = TRUE; + } + else if(halbtc8723a2ant_IsWifiIdle(pBtCoexist) && + (BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi idle + Bt connected idle!!\n")); + + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + + bCommon = TRUE; + } + else if(!halbtc8723a2ant_IsWifiIdle(pBtCoexist) && + (BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non-idle + Bt connected idle!!\n")); + + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + + bCommon = TRUE; + } + else if(halbtc8723a2ant_IsWifiIdle(pBtCoexist) && + (BT_8723A_2ANT_BT_STATUS_NON_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi idle + BT non-idle!!\n")); + + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + + bCommon = TRUE; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non-idle + BT non-idle!!\n")); + halbtc8723a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x20); + + bCommon = FALSE; + } + + return bCommon; +} +VOID +halbtc8723a2ant_TdmaDurationAdjust( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bScoHid, + IN BOOLEAN bTxPause, + IN u1Byte maxInterval + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjust()\n")); + + if(pCoexDm->bResetTdmaAdjust) + { + pCoexDm->bResetTdmaAdjust = FALSE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); + { + if(bScoHid) + { + if(bTxPause) + { + if(maxInterval == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + else if(maxInterval == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(maxInterval == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + } + else + { + if(maxInterval == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(maxInterval == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(maxInterval == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + } + else + { + if(bTxPause) + { + if(maxInterval == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(maxInterval == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(maxInterval == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + } + else + { + if(maxInterval == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(maxInterval == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(maxInterval == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + } + } + } + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n", + up, dn, m, n, WaitCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if �s�� n ��2�� retry count��0, �h�ռeWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration + { + if (WaitCount <= 2) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration + { + if (WaitCount == 1) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], max Interval = %d\n", maxInterval)); + if(maxInterval == 1) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + } + } + } + else if(maxInterval == 2) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + } + } + } + else if(maxInterval == 3) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + } + } + } + + // if current PsTdma not match with the recorded one (when scan, dhcp...), + // then we have to adjust it back to the previous record one. + if(pCoexDm->curPsTdma != pCoexDm->psTdmaDuAdjType) + { + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], PsTdma type dismatch!!!, curPsTdma=%d, recordPsTdma=%d\n", + pCoexDm->curPsTdma, pCoexDm->psTdmaDuAdjType)); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if( !bScan && !bLink && !bRoam) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, pCoexDm->psTdmaDuAdjType); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n")); + } + } +} + +// SCO only or SCO+PAN(HS) +VOID +halbtc8723a2ant_ActionSco( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1; + u4Byte wifiBw; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + + +VOID +halbtc8723a2ant_ActionHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1; + u4Byte wifiBw; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +//A2DP only / PAN(EDR) only/ A2DP+PAN(HS) +VOID +halbtc8723a2ant_ActionA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp rate, 1:basic /0:edr + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 3); + } + else + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 1); + } + } + else + { + if(btInfoExt&BIT0) //a2dp rate, 1:basic /0:edr + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 3); + } + else + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 1); + } + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp rate, 1:basic /0:edr + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 3); + } + else + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 1); + } + } + else + { + if(btInfoExt&BIT0) //a2dp rate, 1:basic /0:edr + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 3); + } + else + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 1); + } + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +VOID +halbtc8723a2ant_ActionPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + + +//PAN(HS) only +VOID +halbtc8723a2ant_ActionPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + } + else + { + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + } + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +//PAN(EDR)+A2DP +VOID +halbtc8723a2ant_ActionPanEdrA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + } + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + } + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +VOID +halbtc8723a2ant_ActionPanEdrHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1; + u4Byte wifiBw; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + } + else + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +// HID+A2DP+PAN(EDR) +VOID +halbtc8723a2ant_ActionHidA2dpPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + } + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + } + else //a2dp edr rate + { + halbtc8723a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + } + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +VOID +halbtc8723a2ant_ActionHidA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + + if(halbtc8723a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0xffff, 0x3); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 37, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 3); + } + else //a2dp edr rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 1); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 3); + } + else //a2dp edr rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 1); + } + } + + // sw mechanism + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + wifiRssiState = halbtc8723a2ant_WifiRssiState(pBtCoexist, 0, 2, 27, 0); + wifiRssiState1 = halbtc8723a2ant_WifiRssiState(pBtCoexist, 1, 2, 47, 0); + + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 3); + } + else //a2dp edr rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 1); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 3); + } + else //a2dp edr rate + { + halbtc8723a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 1); + } + } + + // sw mechanism + if( (wifiRssiState1 == BTC_RSSI_STATE_HIGH) || + (wifiRssiState1 == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, TRUE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + else + { + halbtc8723a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, FALSE, 0xc0); + } + } +} + +VOID +halbtc8723a2ant_RunCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + u1Byte btInfoOriginal=0, btRetryCnt=0; + u1Byte algorithm=0; + + if(pBtCoexist->bManualControl) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Manual control!!!\n")); + return; + } + + if(pStackInfo->bProfileNotified) + { + if(pCoexSta->bHoldForStackOperation) + { + // if bt inquiry/page/pair, do not execute. + return; + } + + algorithm = halbtc8723a2ant_ActionAlgorithm(pBtCoexist); + if(pCoexSta->bHoldPeriodCnt && (BT_8723A_2ANT_COEX_ALGO_PANHS!=algorithm)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex],Hold BT inquiry/page scan setting (cnt = %d)!!\n", + pCoexSta->bHoldPeriodCnt)); + if(pCoexSta->bHoldPeriodCnt >= 6) + { + pCoexSta->bHoldPeriodCnt = 0; + // next time the coexist parameters should be reset again. + } + else + pCoexSta->bHoldPeriodCnt++; + return; + } + + pCoexDm->curAlgorithm = algorithm; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Algorithm = %d \n", pCoexDm->curAlgorithm)); + if(halbtc8723a2ant_IsCommonAction(pBtCoexist)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant common.\n")); + pCoexDm->bResetTdmaAdjust = TRUE; + } + else + { + if(pCoexDm->curAlgorithm != pCoexDm->preAlgorithm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], preAlgorithm=%d, curAlgorithm=%d\n", + pCoexDm->preAlgorithm, pCoexDm->curAlgorithm)); + pCoexDm->bResetTdmaAdjust = TRUE; + } + switch(pCoexDm->curAlgorithm) + { + case BT_8723A_2ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = SCO.\n")); + halbtc8723a2ant_ActionSco(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID.\n")); + halbtc8723a2ant_ActionHid(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP.\n")); + halbtc8723a2ant_ActionA2dp(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n")); + halbtc8723a2ant_ActionPanEdr(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HS mode.\n")); + halbtc8723a2ant_ActionPanHs(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n")); + halbtc8723a2ant_ActionPanEdrA2dp(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n")); + halbtc8723a2ant_ActionPanEdrHid(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n")); + halbtc8723a2ant_ActionHidA2dpPanEdr(pBtCoexist); + break; + case BT_8723A_2ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n")); + halbtc8723a2ant_ActionHidA2dp(pBtCoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n")); + halbtc8723a2ant_CoexAllOff(pBtCoexist); + break; + } + pCoexDm->preAlgorithm = pCoexDm->curAlgorithm; + } + } +} + +//============================================================ +// work around function start with wa_halbtc8723a2ant_ +//============================================================ +VOID +wa_halbtc8723a2ant_MonitorC2h( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte tmp1b=0x0; + u4Byte curC2hTotalCnt=0x0; + static u4Byte preC2hTotalCnt=0x0, sameCntPollingTime=0x0; + + curC2hTotalCnt+=pCoexSta->btInfoC2hCnt[BT_INFO_SRC_8723A_2ANT_BT_RSP]; + + if(curC2hTotalCnt == preC2hTotalCnt) + { + sameCntPollingTime++; + } + else + { + preC2hTotalCnt = curC2hTotalCnt; + sameCntPollingTime = 0; + } + + if(sameCntPollingTime >= 2) + { + tmp1b = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x1af); + if(tmp1b != 0x0) + { + pCoexSta->c2hHangDetectCnt++; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x1af, 0x0); + } + } +} + +//============================================================ +// extern function start with EXhalbtc8723a2ant_ +//============================================================ +VOID +EXhalbtc8723a2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte u4Tmp=0; + u1Byte u1Tmp=0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 2Ant Init HW Config!!\n")); + + // backup rf 0x1e value + pCoexDm->btRf0x1eBackup = + pBtCoexist->fBtcGetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff); + + // Enable counter statistics + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x778, 0x3); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x20); +} + +VOID +EXhalbtc8723a2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + halbtc8723a2ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8723a2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + pu1Byte cliBuf=pBtCoexist->cliBuf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir; + u1Byte wifiDot11Chnl, wifiHsChnl; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(!pBoardInfo->bBtExist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum); + CL_PRINTF(cliBuf); + + if(pBtCoexist->bManualControl) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "[Action Manual control]!!"); + CL_PRINTF(cliBuf); + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ + wifiDot11Chnl, wifiHsChnl, bBtHsOn); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], + pCoexDm->wifiChnlInfo[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8723A_2ANT_BT_STATUS_IDLE == pCoexDm->btStatus)? "idle":( (BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy"))), + pCoexSta->btRssi, pCoexSta->btRetryCnt); + CL_PRINTF(cliBuf); + + if(pStackInfo->bProfileNotified) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pStackInfo->bScoExist, pStackInfo->bHidExist, pStackInfo->bPanExist, pStackInfo->bA2dpExist); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + } + + btInfoExt = pCoexSta->btInfoExt; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (btInfoExt&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cliBuf); + + for(i=0; i<BT_INFO_SRC_8723A_2ANT_MAX; i++) + { + if(pCoexSta->btInfoC2hCnt[i]) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8723a2Ant[i], \ + pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], + pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], + pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], + pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); + CL_PRINTF(cliBuf); + } + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "write 0x1af=0x0 num", \ + pCoexSta->c2hHangDetectCnt); + CL_PRINTF(cliBuf); + + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", "SM1[ShRf/ LpRA/ LimDig]", \ + pCoexDm->bCurRfRxLpfShrink, pCoexDm->bCurLowPenaltyRa, pCoexDm->bLimitedDig); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", \ + pCoexDm->bCurAgcTableEn, pCoexDm->bCurAdcBackOff, pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + if(!pBtCoexist->bManualControl) + { + psTdmaCase = pCoexDm->curPsTdma; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d", "PS TDMA", \ + pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], + pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], + pCoexDm->psTdmaPara[4], psTdmaCase); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", \ + pCoexDm->bCurDecBtPwr, pCoexDm->bCurIgnoreWlanAct); + CL_PRINTF(cliBuf); + } + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", \ + pCoexDm->btRf0x1eBackup); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x778); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x783); + u1Tmp[2] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x796); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x778/ 0x783/ 0x796", \ + u1Tmp[0], u1Tmp[1], u1Tmp[2]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x880); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x880", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x40", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x550); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x522); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x484); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x484(rate adaptive)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda8); + u4Tmp[3] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xdac); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0xda0/0xda4/0xda8/0xdac(FA cnt)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u4Tmp[3]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp[0]); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770 (hp rx[31:16]/tx[15:0])", \ + pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(lp rx[31:16]/tx[15:0])", \ + pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); + CL_PRINTF(cliBuf); + + // Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x41b); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x41b (mgntQ hang chk == 0xf)", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8723a2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + halbtc8723a2ant_CoexAllOff(pBtCoexist); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + //halbtc8723a2ant_InitCoexDm(pBtCoexist); + } +} + +VOID +EXhalbtc8723a2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + } +} + +VOID +EXhalbtc8723a2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + } +} + +VOID +EXhalbtc8723a2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + } +} + +VOID +EXhalbtc8723a2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } + + halbtc8723a2ant_IndicateWifiChnlBwInfo(pBtCoexist, type); +} + +VOID +EXhalbtc8723a2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(type == BTC_PACKET_DHCP) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], DHCP Packet notify\n")); + } +} + +VOID +EXhalbtc8723a2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ + u1Byte btInfo=0; + u1Byte i, rspSource=0; + BOOLEAN bBtBusy=FALSE, bLimitedDig=FALSE; + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + pCoexSta->bC2hBtInfoReqSent = FALSE; + + rspSource = BT_INFO_SRC_8723A_2ANT_BT_RSP; + pCoexSta->btInfoC2hCnt[rspSource]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rspSource, length)); + for(i=0; i<length; i++) + { + pCoexSta->btInfoC2h[rspSource][i] = tmpBuf[i]; + if(i == 0) + btInfo = tmpBuf[i]; + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); + } + } + + if(BT_INFO_SRC_8723A_2ANT_WIFI_FW != rspSource) + { + pCoexSta->btRetryCnt = + pCoexSta->btInfoC2h[rspSource][1]; + + pCoexSta->btRssi = + pCoexSta->btInfoC2h[rspSource][2]*2+10; + + pCoexSta->btInfoExt = + pCoexSta->btInfoC2h[rspSource][3]; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + // check BIT2 first ==> check if bt is under inquiry or page scan + if(btInfo & BT_INFO_8723A_2ANT_B_INQ_PAGE) + { + pCoexSta->bC2hBtInquiryPage = TRUE; + } + else + { + pCoexSta->bC2hBtInquiryPage = FALSE; + } +} + +VOID +EXhalbtc8723a2ant_StackOperationNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_STACK_OP_INQ_PAGE_PAIR_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], StackOP Inquiry/page/pair start notify\n")); + pCoexSta->bHoldForStackOperation = TRUE; + pCoexSta->bHoldPeriodCnt = 1; + halbtc8723a2ant_BtInquiryPage(pBtCoexist); + } + else if(BTC_STACK_OP_INQ_PAGE_PAIR_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], StackOP Inquiry/page/pair finish notify\n")); + pCoexSta->bHoldForStackOperation = FALSE; + } +} + +VOID +EXhalbtc8723a2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + halbtc8723a2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + EXhalbtc8723a2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8723a2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], 2Ant Periodical!!\n")); + + // work around for c2h hang + wa_halbtc8723a2ant_MonitorC2h(pBtCoexist); + + halbtc8723a2ant_QueryBtInfo(pBtCoexist); + halbtc8723a2ant_MonitorBtCtr(pBtCoexist); + halbtc8723a2ant_MonitorBtEnableDisable(pBtCoexist); + + halbtc8723a2ant_RunCoexistMechanism(pBtCoexist); +} + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a2Ant.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a2Ant.h new file mode 100644 index 0000000..584c95f --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723a2Ant.h @@ -0,0 +1,179 @@ +//=========================================== +// The following is for 8723A 2Ant BT Co-exist definition +//=========================================== +#define BT_INFO_8723A_2ANT_B_FTP BIT7 +#define BT_INFO_8723A_2ANT_B_A2DP BIT6 +#define BT_INFO_8723A_2ANT_B_HID BIT5 +#define BT_INFO_8723A_2ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8723A_2ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8723A_2ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8723A_2ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8723A_2ANT_B_CONNECTION BIT0 + +#define BTC_RSSI_COEX_THRESH_TOL_8723A_2ANT 2 + +typedef enum _BT_INFO_SRC_8723A_2ANT{ + BT_INFO_SRC_8723A_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723A_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723A_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723A_2ANT_MAX +}BT_INFO_SRC_8723A_2ANT,*PBT_INFO_SRC_8723A_2ANT; + +typedef enum _BT_8723A_2ANT_BT_STATUS{ + BT_8723A_2ANT_BT_STATUS_IDLE = 0x0, + BT_8723A_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723A_2ANT_BT_STATUS_NON_IDLE = 0x2, + BT_8723A_2ANT_BT_STATUS_MAX +}BT_8723A_2ANT_BT_STATUS,*PBT_8723A_2ANT_BT_STATUS; + +typedef enum _BT_8723A_2ANT_COEX_ALGO{ + BT_8723A_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723A_2ANT_COEX_ALGO_SCO = 0x1, + BT_8723A_2ANT_COEX_ALGO_HID = 0x2, + BT_8723A_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8723A_2ANT_COEX_ALGO_PANEDR = 0x4, + BT_8723A_2ANT_COEX_ALGO_PANHS = 0x5, + BT_8723A_2ANT_COEX_ALGO_PANEDR_A2DP = 0x6, + BT_8723A_2ANT_COEX_ALGO_PANEDR_HID = 0x7, + BT_8723A_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x8, + BT_8723A_2ANT_COEX_ALGO_HID_A2DP = 0x9, + BT_8723A_2ANT_COEX_ALGO_MAX +}BT_8723A_2ANT_COEX_ALGO,*PBT_8723A_2ANT_COEX_ALGO; + +typedef struct _COEX_DM_8723A_2ANT{ + // fw mechanism + BOOLEAN bPreDecBtPwr; + BOOLEAN bCurDecBtPwr; + //BOOLEAN bPreBtLnaConstrain; + //BOOLEAN bCurBtLnaConstrain; + //u1Byte bPreBtPsdMode; + //u1Byte bCurBtPsdMode; + u1Byte preFwDacSwingLvl; + u1Byte curFwDacSwingLvl; + BOOLEAN bCurIgnoreWlanAct; + BOOLEAN bPreIgnoreWlanAct; + u1Byte prePsTdma; + u1Byte curPsTdma; + u1Byte psTdmaPara[5]; + u1Byte psTdmaDuAdjType; + BOOLEAN bResetTdmaAdjust; + BOOLEAN bPrePsTdmaOn; + BOOLEAN bCurPsTdmaOn; + //BOOLEAN bPreBtAutoReport; + //BOOLEAN bCurBtAutoReport; + + // sw mechanism + BOOLEAN bPreRfRxLpfShrink; + BOOLEAN bCurRfRxLpfShrink; + u4Byte btRf0x1eBackup; + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + BOOLEAN bPreDacSwingOn; + u4Byte preDacSwingLvl; + BOOLEAN bCurDacSwingOn; + u4Byte curDacSwingLvl; + BOOLEAN bPreAdcBackOff; + BOOLEAN bCurAdcBackOff; + BOOLEAN bPreAgcTableEn; + BOOLEAN bCurAgcTableEn; + u4Byte preVal0x6c0; + u4Byte curVal0x6c0; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u1Byte preVal0x6cc; + u1Byte curVal0x6cc; + BOOLEAN bLimitedDig; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + u1Byte btStatus; + u1Byte wifiChnlInfo[3]; +} COEX_DM_8723A_2ANT, *PCOEX_DM_8723A_2ANT; + +typedef struct _COEX_STA_8723A_2ANT{ + u4Byte highPriorityTx; + u4Byte highPriorityRx; + u4Byte lowPriorityTx; + u4Byte lowPriorityRx; + u1Byte btRssi; + u1Byte preBtRssiState; + u1Byte preBtRssiState1; + u1Byte preWifiRssiState[4]; + BOOLEAN bC2hBtInfoReqSent; + u1Byte btInfoC2h[BT_INFO_SRC_8723A_2ANT_MAX][10]; + u4Byte btInfoC2hCnt[BT_INFO_SRC_8723A_2ANT_MAX]; + BOOLEAN bC2hBtInquiryPage; + u1Byte btRetryCnt; + u1Byte btInfoExt; + BOOLEAN bHoldForStackOperation; + u1Byte bHoldPeriodCnt; + // this is for c2h hang work-around + u4Byte c2hHangDetectCnt; +}COEX_STA_8723A_2ANT, *PCOEX_STA_8723A_2ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8723a2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723a2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8723a2ant_StackOperationNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723a2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b1Ant.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b1Ant.c new file mode 100644 index 0000000..04115b8 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b1Ant.c @@ -0,0 +1,3669 @@ +//============================================================ +// Description: +// +// This file is for RTL8723B Co-exist mechanism +// +// History +// 2012/11/15 Cosa first check in. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8723B_1ANT GLCoexDm8723b1Ant; +static PCOEX_DM_8723B_1ANT pCoexDm=&GLCoexDm8723b1Ant; +static COEX_STA_8723B_1ANT GLCoexSta8723b1Ant; +static PCOEX_STA_8723B_1ANT pCoexSta=&GLCoexSta8723b1Ant; + +const char *const GLBtInfoSrc8723b1Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u4Byte GLCoexVerDate8723b1Ant=20140110; +u4Byte GLCoexVer8723b1Ant=0x49; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8723b1ant_ +//============================================================ +u1Byte +halbtc8723b1ant_BtRssiState( + u1Byte levelNum, + u1Byte rssiThresh, + u1Byte rssiThresh1 + ) +{ + s4Byte btRssi=0; + u1Byte btRssiState=pCoexSta->preBtRssiState; + + btRssi = pCoexSta->btRssi; + + if(levelNum == 2) + { + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else + { + if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); + return pCoexSta->preBtRssiState; + } + + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); + } + } + else + { + if(btRssi < rssiThresh1) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + + pCoexSta->preBtRssiState = btRssiState; + + return btRssiState; +} + +u1Byte +halbtc8723b1ant_WifiRssiState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte index, + IN u1Byte levelNum, + IN u1Byte rssiThresh, + IN u1Byte rssiThresh1 + ) +{ + s4Byte wifiRssi=0; + u1Byte wifiRssiState=pCoexSta->preWifiRssiState[index]; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(levelNum == 2) + { + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return pCoexSta->preWifiRssiState[index]; + } + + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifiRssi < rssiThresh1) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + pCoexSta->preWifiRssiState[index] = wifiRssiState; + + return wifiRssiState; +} + +VOID +halbtc8723b1ant_UpdateRaMask( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte disRateMask + ) +{ + pCoexDm->curRaMask = disRateMask; + + if( bForceExec || (pCoexDm->preRaMask != pCoexDm->curRaMask)) + { + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_UPDATE_RAMASK, &pCoexDm->curRaMask); + } + pCoexDm->preRaMask = pCoexDm->curRaMask; +} + +VOID +halbtc8723b1ant_AutoRateFallbackRetry( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + BOOLEAN bWifiUnderBMode=FALSE; + + pCoexDm->curArfrType = type; + + if( bForceExec || (pCoexDm->preArfrType != pCoexDm->curArfrType)) + { + switch(pCoexDm->curArfrType) + { + case 0: // normal mode + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, pCoexDm->backupArfrCnt1); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, pCoexDm->backupArfrCnt2); + break; + case 1: + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, &bWifiUnderBMode); + if(bWifiUnderBMode) + { + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, 0x0); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, 0x01010101); + } + else + { + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, 0x0); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, 0x04030201); + } + break; + default: + break; + } + } + + pCoexDm->preArfrType = pCoexDm->curArfrType; +} + +VOID +halbtc8723b1ant_RetryLimit( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + pCoexDm->curRetryLimitType = type; + + if( bForceExec || (pCoexDm->preRetryLimitType != pCoexDm->curRetryLimitType)) + { + switch(pCoexDm->curRetryLimitType) + { + case 0: // normal mode + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x42a, pCoexDm->backupRetryLimit); + break; + case 1: // retry limit=8 + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x42a, 0x0808); + break; + default: + break; + } + } + + pCoexDm->preRetryLimitType = pCoexDm->curRetryLimitType; +} + +VOID +halbtc8723b1ant_AmpduMaxTime( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + pCoexDm->curAmpduTimeType = type; + + if( bForceExec || (pCoexDm->preAmpduTimeType != pCoexDm->curAmpduTimeType)) + { + switch(pCoexDm->curAmpduTimeType) + { + case 0: // normal mode + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x456, pCoexDm->backupAmpduMaxTime); + break; + case 1: // AMPDU timw = 0x38 * 32us + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x456, 0x38); + break; + default: + break; + } + } + + pCoexDm->preAmpduTimeType = pCoexDm->curAmpduTimeType; +} + +VOID +halbtc8723b1ant_LimitedTx( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte raMaskType, + IN u1Byte arfrType, + IN u1Byte retryLimitType, + IN u1Byte ampduTimeType + ) +{ + switch(raMaskType) + { + case 0: // normal mode + halbtc8723b1ant_UpdateRaMask(pBtCoexist, bForceExec, 0x0); + break; + case 1: // disable cck 1/2 + halbtc8723b1ant_UpdateRaMask(pBtCoexist, bForceExec, 0x00000003); + break; + case 2: // disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 + halbtc8723b1ant_UpdateRaMask(pBtCoexist, bForceExec, 0x0001f1f7); + break; + default: + break; + } + + halbtc8723b1ant_AutoRateFallbackRetry(pBtCoexist, bForceExec, arfrType); + halbtc8723b1ant_RetryLimit(pBtCoexist, bForceExec, retryLimitType); + halbtc8723b1ant_AmpduMaxTime(pBtCoexist, bForceExec, ampduTimeType); +} + +VOID +halbtc8723b1ant_LimitedRx( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRejApAggPkt, + IN BOOLEAN bBtCtrlAggBufSize, + IN u1Byte aggBufSize + ) +{ + BOOLEAN bRejectRxAgg=bRejApAggPkt; + BOOLEAN bBtCtrlRxAggSize=bBtCtrlAggBufSize; + u1Byte rxAggSize=aggBufSize; + + //============================================ + // Rx Aggregation related setting + //============================================ + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &bRejectRxAgg); + // decide BT control aggregation buf size or not + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, &bBtCtrlRxAggSize); + // aggregation buf size, only work when BT control Rx aggregation size. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_AGG_BUF_SIZE, &rxAggSize); + // real update aggregation setting + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +VOID +halbtc8723b1ant_MonitorBtCtr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte regHPTxRx, regLPTxRx, u4Tmp, u4Tmp1; + u4Byte regHPTx=0, regHPRx=0, regLPTx=0, regLPRx=0; + u1Byte u1Tmp, u1Tmp1; + s4Byte wifiRssi; + + regHPTxRx = 0x770; + regLPTxRx = 0x774; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); + regHPTx = u4Tmp & bMaskLWord; + regHPRx = (u4Tmp & bMaskHWord)>>16; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); + regLPTx = u4Tmp & bMaskLWord; + regLPRx = (u4Tmp & bMaskHWord)>>16; + + pCoexSta->highPriorityTx = regHPTx; + pCoexSta->highPriorityRx = regHPRx; + pCoexSta->lowPriorityTx = regLPTx; + pCoexSta->lowPriorityRx = regLPRx; + + // reset counter + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); +} + +VOID +halbtc8723b1ant_QueryBtInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + pCoexSta->bC2hBtInfoReqSent = TRUE; + + H2C_Parameter[0] |= BIT0; // trigger + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Query Bt Info, FW write 0x61=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x61, 1, H2C_Parameter); +} + +BOOLEAN +halbtc8723b1ant_IsWifiStatusChanged( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreWifiBusy=FALSE, bPreUnder4way=FALSE, bPreBtHsOn=FALSE; + BOOLEAN bWifiBusy=FALSE, bUnder4way=FALSE, bBtHsOn=FALSE; + BOOLEAN bWifiConnected=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); + + if(bWifiConnected) + { + if(bWifiBusy != bPreWifiBusy) + { + bPreWifiBusy = bWifiBusy; + return TRUE; + } + if(bUnder4way != bPreUnder4way) + { + bPreUnder4way = bUnder4way; + return TRUE; + } + if(bBtHsOn != bPreBtHsOn) + { + bPreBtHsOn = bBtHsOn; + return TRUE; + } + } + + return FALSE; +} + +VOID +halbtc8723b1ant_UpdateBtLinkInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bBtHsOn=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + pBtLinkInfo->bBtLinkExist = pCoexSta->bBtLinkExist; + pBtLinkInfo->bScoExist = pCoexSta->bScoExist; + pBtLinkInfo->bA2dpExist = pCoexSta->bA2dpExist; + pBtLinkInfo->bPanExist = pCoexSta->bPanExist; + pBtLinkInfo->bHidExist = pCoexSta->bHidExist; + + // work around for HS mode. + if(bBtHsOn) + { + pBtLinkInfo->bPanExist = TRUE; + pBtLinkInfo->bBtLinkExist = TRUE; + } + + // check if Sco only + if( pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bScoOnly = TRUE; + else + pBtLinkInfo->bScoOnly = FALSE; + + // check if A2dp only + if( !pBtLinkInfo->bScoExist && + pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bA2dpOnly = TRUE; + else + pBtLinkInfo->bA2dpOnly = FALSE; + + // check if Pan only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bPanOnly = TRUE; + else + pBtLinkInfo->bPanOnly = FALSE; + + // check if Hid only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + pBtLinkInfo->bHidExist ) + pBtLinkInfo->bHidOnly = TRUE; + else + pBtLinkInfo->bHidOnly = FALSE; +} + +u1Byte +halbtc8723b1ant_ActionAlgorithm( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bBtHsOn=FALSE; + u1Byte algorithm=BT_8723B_1ANT_COEX_ALGO_UNDEFINED; + u1Byte numOfDiffProfile=0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(!pBtLinkInfo->bBtLinkExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No BT link exists!!!\n")); + return algorithm; + } + + if(pBtLinkInfo->bScoExist) + numOfDiffProfile++; + if(pBtLinkInfo->bHidExist) + numOfDiffProfile++; + if(pBtLinkInfo->bPanExist) + numOfDiffProfile++; + if(pBtLinkInfo->bA2dpExist) + numOfDiffProfile++; + + if(numOfDiffProfile == 1) + { + if(pBtLinkInfo->bScoExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO only\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; + } + else + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID only\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = A2DP only\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_A2DP; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = PAN(HS) only\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = PAN(EDR) only\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR; + } + } + } + } + else if(numOfDiffProfile == 2) + { + if(pBtLinkInfo->bScoExist) + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + A2DP ==> SCO\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + PAN(HS)\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + PAN(EDR)\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + A2DP\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP; + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + PAN(HS)\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + PAN(EDR)\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = A2DP + PAN(HS)\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = A2DP + PAN(EDR)\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } + else if(numOfDiffProfile == 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID; + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + PAN(HS)\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + else if(numOfDiffProfile >= 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n")); + + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n")); + algorithm = BT_8723B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +VOID +halbtc8723b1ant_SetBtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnableAutoReport + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = 0; + + if(bEnableAutoReport) + { + H2C_Parameter[0] |= BIT0; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], BT FW auto report : %s, FW write 0x68=0x%x\n", + (bEnableAutoReport? "Enabled!!":"Disabled!!"), H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x68, 1, H2C_Parameter); +} + +VOID +halbtc8723b1ant_BtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnableAutoReport + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT Auto report = %s\n", + (bForceExec? "force to":""), ((bEnableAutoReport)? "Enabled":"Disabled"))); + pCoexDm->bCurBtAutoReport = bEnableAutoReport; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtAutoReport=%d, bCurBtAutoReport=%d\n", + pCoexDm->bPreBtAutoReport, pCoexDm->bCurBtAutoReport)); + + if(pCoexDm->bPreBtAutoReport == pCoexDm->bCurBtAutoReport) + return; + } + halbtc8723b1ant_SetBtAutoReport(pBtCoexist, pCoexDm->bCurBtAutoReport); + + pCoexDm->bPreBtAutoReport = pCoexDm->bCurBtAutoReport; +} + +VOID +halbtc8723b1ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte H2C_Parameter[6] ={0}; + + H2C_Parameter[0] = 0x6; // opCode, 0x6= Retry_Penalty + + if(bLowPenaltyRa) + { + H2C_Parameter[1] |= BIT0; + H2C_Parameter[2] = 0x00; //normal rate except MCS7/6/5, OFDM54/48/36 + H2C_Parameter[3] = 0xf7; //MCS7 or OFDM54 + H2C_Parameter[4] = 0xf8; //MCS6 or OFDM48 + H2C_Parameter[5] = 0xf9; //MCS5 or OFDM36 + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set WiFi Low-Penalty Retry: %s", + (bLowPenaltyRa? "ON!!":"OFF!!") )); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x69, 6, H2C_Parameter); +} + +VOID +halbtc8723b1ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8723b1ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8723b1ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8723b1ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c4=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c0, val0x6c4, val0x6cc)); + pCoexDm->curVal0x6c0 = val0x6c0; + pCoexDm->curVal0x6c4 = val0x6c4; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + //BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c0=0x%x, preVal0x6c4=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + // pCoexDm->preVal0x6c0, pCoexDm->preVal0x6c4, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + //BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c0=0x%x, curVal0x6c4=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + // pCoexDm->curVal0x6c0, pCoexDm->curVal0x6c4, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && + (pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8723b1ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c4, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; + pCoexDm->preVal0x6c4 = pCoexDm->curVal0x6c4; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8723b1ant_CoexTableWithType( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], ********** CoexTable(%d) **********\n", + type)); + + switch(type) + { + case 0: + halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x55555555, 0xffffff, 0x3); + break; + case 1: + halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0x5a5a5a5a, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 3: + halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0x5a5a5a5a, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 4: + halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 5: + halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0x5a5a5a5a, 0xaaaa5a5a, 0xffffff, 0x3); + break; + case 6: + halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0xaaaa5a5a, 0xffffff, 0x3); + break; + case 7: + halbtc8723b1ant_CoexTable(pBtCoexist, bForceExec, 0xaaaaaaaa, 0xaaaaaaaa, 0xffffff, 0x3); + break; + default: + break; + } +} + +VOID +halbtc8723b1ant_SetFwIgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnable + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + if(bEnable) + { + H2C_Parameter[0] |= BIT0; // function enable + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x63, 1, H2C_Parameter); +} + +VOID +halbtc8723b1ant_IgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); + pCoexDm->bCurIgnoreWlanAct = bEnable; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); + + if(pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) + return; + } + halbtc8723b1ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); + + pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; +} + +VOID +halbtc8723b1ant_SetFwPstdma( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte byte1, + IN u1Byte byte2, + IN u1Byte byte3, + IN u1Byte byte4, + IN u1Byte byte5 + ) +{ + u1Byte H2C_Parameter[5] ={0}; + u1Byte realByte1=byte1, realByte5=byte5; + BOOLEAN bApEnable=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, &bApEnable); + + if(bApEnable) + { + if(byte1&BIT4 && !(byte1&BIT5)) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], FW for 1Ant AP mode\n")); + realByte1 &= ~BIT4; + realByte1 |= BIT5; + + realByte5 |= BIT5; + realByte5 &= ~BIT6; + } + } + + H2C_Parameter[0] = realByte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = realByte5; + + pCoexDm->psTdmaPara[0] = realByte1; + pCoexDm->psTdmaPara[1] = byte2; + pCoexDm->psTdmaPara[2] = byte3; + pCoexDm->psTdmaPara[3] = byte4; + pCoexDm->psTdmaPara[4] = realByte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], PS-TDMA H2C cmd =0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x60, 5, H2C_Parameter); +} + +VOID +halbtc8723b1ant_SetLpsRpwm( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + u1Byte lps=lpsVal; + u1Byte rpwm=rpwmVal; + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_LPS_VAL, &lps); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +VOID +halbtc8723b1ant_LpsRpwm( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + BOOLEAN bForceExecPwrCmd=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set lps/rpwm=0x%x/0x%x \n", + (bForceExec? "force to":""), lpsVal, rpwmVal)); + pCoexDm->curLps = lpsVal; + pCoexDm->curRpwm = rpwmVal; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], LPS-RxBeaconMode=0x%x , LPS-RPWM=0x%x!!\n", + pCoexDm->curLps, pCoexDm->curRpwm)); + + if( (pCoexDm->preLps == pCoexDm->curLps) && + (pCoexDm->preRpwm == pCoexDm->curRpwm) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], LPS-RPWM_Last=0x%x , LPS-RPWM_Now=0x%x!!\n", + pCoexDm->preRpwm, pCoexDm->curRpwm)); + + return; + } + } + halbtc8723b1ant_SetLpsRpwm(pBtCoexist, lpsVal, rpwmVal); + + pCoexDm->preLps = pCoexDm->curLps; + pCoexDm->preRpwm = pCoexDm->curRpwm; +} + +VOID +halbtc8723b1ant_SwMechanism( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRA + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], SM[LpRA] = %d\n", + bLowPenaltyRA)); + + halbtc8723b1ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, bLowPenaltyRA); +} + +VOID +halbtc8723b1ant_SetAntPath( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte antPosType, + IN BOOLEAN bInitHwCfg, + IN BOOLEAN bWifiOff + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + u4Byte fwVer=0, u4Tmp=0; + BOOLEAN bPgExtSwitch=FALSE; + BOOLEAN bUseExtSwitch=FALSE; + u1Byte H2C_Parameter[2] ={0}; + PADAPTER padapter=pBtCoexist->Adapter; + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_EXT_SWITCH, &bPgExtSwitch); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); // [31:16]=fw ver, [15:0]=fw sub ver + + + if((fwVer<0xc0000) || bPgExtSwitch) + bUseExtSwitch = TRUE; + + if(bInitHwCfg) + { + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x1); //BT select s0/s1 is controlled by WiFi + + //Force GNT_BT to Normal + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x765, 0x18, 0x0); + + //set wlan_act control by PTA + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); + + //pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); + } + else if(bWifiOff) + { + //Force GNT_BT to High + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x765, 0x18, 0x3); + + //set wlan_act to always low + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); + + if(padapter->registrypriv.mp_mode ==0) + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x0); //BT select s0/s1 is controlled by BT + else + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x1); //BT select s0/s1 is controlled by WiFi + + // 0x4c[24:23]=00, Set Antenna control by BT_RFE_CTRL BT Vendor 0xac=0xf002 + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u4Tmp &= ~BIT23; + u4Tmp &= ~BIT24; + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); + } + + if(bUseExtSwitch) + { + if(bInitHwCfg) + { + // 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u4Tmp &=~BIT23; + u4Tmp |= BIT24; + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); + + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + { + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x64, 0x1, 0x1); //Main Ant to BT for IPS case 0x4c[23]=1 + + //tell firmware "no antenna inverse" + H2C_Parameter[0] = 0; + H2C_Parameter[1] = 1; //ext switch type + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); + } + else + { + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x64, 0x1, 0x0); //Aux Ant to BT for IPS case 0x4c[23]=1 + + //tell firmware "antenna inverse" + H2C_Parameter[0] = 1; + H2C_Parameter[1] = 1; //ext switch type + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); + } + } + + // fixed internal switch first + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); // fixed internal switch S1->WiFi, S0->BT + else + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x280); // fixed internal switch S0->WiFi, S1->BT + + // ext switch setting + switch(antPosType) + { + case BTC_ANT_PATH_WIFI: + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x1); + else + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x2); + break; + case BTC_ANT_PATH_BT: + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x2); + else + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x1); + break; + default: + case BTC_ANT_PATH_PTA: + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x1); + else + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x2); + break; + } + + } + else + { + if(bInitHwCfg) + { + // 0x4c[23]=1, 0x4c[24]=0 Antenna control by 0x64 + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u4Tmp |= BIT23; + u4Tmp &=~BIT24; + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); + + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + { + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x64, 0x1, 0x0); //Main Ant to WiFi for IPS case 0x4c[23]=1 + + //tell firmware "no antenna inverse" + H2C_Parameter[0] = 0; + H2C_Parameter[1] = 0; //internal switch type + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); + } + else + { + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x64, 0x1, 0x1); //Aux Ant to BT for IPS case 0x4c[23]=1 + + //tell firmware "antenna inverse" + H2C_Parameter[0] = 1; + H2C_Parameter[1] = 0; //internal switch type + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); + } + } + + // fixed external switch first + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x1); //Main->WiFi, Aux->BT + else + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x2); //Main->BT, Aux->WiFi + + // internal switch setting + switch(antPosType) + { + case BTC_ANT_PATH_WIFI: + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); + else + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x280); + break; + case BTC_ANT_PATH_BT: + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x280); + else + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); + break; + default: + case BTC_ANT_PATH_PTA: + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x200); + else + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x80); + break; + } + } +} + +VOID +halbtc8723b1ant_PsTdma( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bTurnOn, + IN u1Byte type + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + BOOLEAN bTurnOnByCnt=FALSE, bWifiBusy=FALSE; + u1Byte psTdmaTypeByCnt=0, rssiAdjustVal=0; + //u4Byte fwVer=0; + + //BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type=%d\n", + // (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); + pCoexDm->bCurPsTdmaOn = bTurnOn; + pCoexDm->curPsTdma = type; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + + if (pCoexDm->bCurPsTdmaOn) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], ********** TDMA(on, %d) **********\n", + pCoexDm->curPsTdma)); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], ********** TDMA(off, %d) **********\n", + pCoexDm->curPsTdma)); + } + + if(!bForceExec) + { + if( (pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && + (pCoexDm->prePsTdma == pCoexDm->curPsTdma) ) + return; + } + if(bTurnOn) + { + switch(type) + { + default: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x1a, 0x1a, 0x0, 0x50); + break; + case 1: + //if(bWifiBusy) + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x3a, 0x03, 0x10, 0x50); + //else + // halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x3a, 0x03, 0x10, 0x51); + + rssiAdjustVal = 11; + break; + case 2: + //if(bWifiBusy) + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x2b, 0x03, 0x10, 0x50); + //else + // halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x2b, 0x03, 0x10, 0x51); + rssiAdjustVal = 14; + break; + case 3: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x1d, 0x1d, 0x0, 0x52); + break; + case 4: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x14, 0x0); + rssiAdjustVal = 17; + break; + case 5: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x61, 0x15, 0x3, 0x11, 0x10); + break; + case 6: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x61, 0x20, 0x3, 0x11, 0x13); + break; + case 7: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x13, 0xc, 0x5, 0x0, 0x0); + break; + case 8: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x0); + break; + case 9: + //if(bWifiBusy) + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x21, 0x3, 0x10, 0x50); + //else + // halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x21, 0x3, 0x10, 0x50); + rssiAdjustVal = 18; + break; + case 10: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0xa, 0x0, 0x40); + break; + case 11: + //if(bWifiBusy) + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x15, 0x03, 0x10, 0x50); + //else + // halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x15, 0x03, 0x10, 0x50); + rssiAdjustVal = 20; + break; + case 12: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x0a, 0x0a, 0x0, 0x50); + break; + case 13: + //halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x15, 0x15, 0x0, 0x50); + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x12, 0x12, 0x0, 0x50); + break; + case 14: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x21, 0x3, 0x10, 0x52); + break; + case 15: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0x3, 0x8, 0x0); + break; + case 16: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x10, 0x0); + rssiAdjustVal = 18; + break; + case 18: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x0); + rssiAdjustVal = 14; + break; + case 20: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x61, 0x35, 0x03, 0x11, 0x10); + break; + case 21: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x61, 0x25, 0x03, 0x11, 0x11); + break; + case 22: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x61, 0x25, 0x03, 0x11, 0x10); + break; + case 23: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 24: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x15, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 25: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 26: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 27: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x3, 0x31, 0x98); + rssiAdjustVal = 22; + break; + case 28: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x69, 0x25, 0x3, 0x31, 0x0); + break; + case 29: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xab, 0x1a, 0x1a, 0x1, 0x10); + break; + case 30: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x51, 0x30, 0x3, 0x10, 0x10); + break; + case 31: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x1a, 0x1a, 0, 0x58); + break; + case 32: + //halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x61, 0xa, 0x3, 0x10, 0x0); + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x61, 0x35, 0x3, 0x11, 0x11); + break; + case 33: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xa3, 0x25, 0x3, 0x30, 0x90); + break; + case 34: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x53, 0x1a, 0x1a, 0x0, 0x10); + break; + case 35: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x63, 0x1a, 0x1a, 0x0, 0x10); + break; + case 36: + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x12, 0x3, 0x14, 0x50); + break; + case 40: // SoftAP only with no sta associated,BT disable ,TDMA mode for power saving + /* here softap mode screen off will cost 70-80mA for phone */ + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x23, 0x18, 0x00, 0x10, 0x24); + break; + } + } + else + { + //pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); // [31:16]=fw ver, [15:0]=fw sub ver + + // disable PS tdma + switch(type) + { + case 8: //PTA Control + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x8, 0x0, 0x0, 0x0, 0x0); + halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_PTA, FALSE, FALSE); + break; + case 0: + default: //Software control, Antenna at BT side + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, FALSE); + break; + case 9: //Software control, Antenna at WiFi side + halbtc8723b1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_WIFI, FALSE, FALSE); + break; + } + } + rssiAdjustVal =0; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssiAdjustVal); + + // update pre state + pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; + pCoexDm->prePsTdma = pCoexDm->curPsTdma; +} + +VOID +halbtc8723b1ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + // sw all off + halbtc8723b1ant_SwMechanism(pBtCoexist, FALSE); + + // hw all off + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +BOOLEAN +halbtc8723b1ant_IsCommonAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bCommon=FALSE, bWifiConnected=FALSE, bWifiBusy=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + + if(!bWifiConnected && + BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n")); + + halbtc8723b1ant_SwMechanism(pBtCoexist, FALSE); + + bCommon = TRUE; + } + else if(bWifiConnected && + (BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT non connected-idle!!\n")); + + halbtc8723b1ant_SwMechanism(pBtCoexist, FALSE); + + bCommon = TRUE; + } + else if(!bWifiConnected && + (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT connected-idle!!\n")); + + halbtc8723b1ant_SwMechanism(pBtCoexist, FALSE); + + bCommon = TRUE; + } + else if(bWifiConnected && + (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT connected-idle!!\n")); + + halbtc8723b1ant_SwMechanism(pBtCoexist, FALSE); + + bCommon = TRUE; + } + else if(!bWifiConnected && + (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE != pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT Busy!!\n")); + + halbtc8723b1ant_SwMechanism(pBtCoexist, FALSE); + + bCommon = TRUE; + } + else + { + if (bWifiBusy) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Busy + BT Busy!!\n")); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Idle + BT Busy!!\n")); + } + + bCommon = FALSE; + } + + return bCommon; +} + + +VOID +halbtc8723b1ant_TdmaDurationAdjustForAcl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0, btInfoExt; + static BOOLEAN bPreWifiBusy=FALSE; + BOOLEAN bWifiBusy = FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjustForAcl()\n")); + + if(BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY == wifiStatus) + bWifiBusy = TRUE; + else + bWifiBusy = FALSE; + + if( (BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) || + (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifiStatus) || + (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifiStatus) ) + { + if( pCoexDm->curPsTdma != 1 && + pCoexDm->curPsTdma != 2 && + pCoexDm->curPsTdma != 3 && + pCoexDm->curPsTdma != 9 ) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + return; + } + + if(!pCoexDm->bAutoTdmaAdjust) + { + pCoexDm->bAutoTdmaAdjust = TRUE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); + + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + btInfoExt = pCoexSta->btInfoExt; + //BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); + //BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n", + // up, dn, m, n, WaitCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if �s�� n ��2�� retry count��0, �h�ռeWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration + { + if (WaitCount <= 2) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration + { + if (WaitCount == 1) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + if(result == -1) + { + if( (BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(btInfoExt)) && + ((pCoexDm->curPsTdma == 1) ||(pCoexDm->curPsTdma == 2)) ) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + else if(result == 1) + { + if( (BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(btInfoExt)) && + ((pCoexDm->curPsTdma == 1) ||(pCoexDm->curPsTdma == 2)) ) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + } + else //no change + { + /* Bryant Modify + if(bWifiBusy != bPreWifiBusy) //if busy / idle change + { + bPreWifiBusy = bWifiBusy; + halbtc8723b1ant_PsTdma(pBtCoexist, FORCE_EXEC, TRUE, pCoexDm->curPsTdma); + } + */ + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], ********** TDMA(on, %d) **********\n", + pCoexDm->curPsTdma)); + } + + if( pCoexDm->curPsTdma != 1 && + pCoexDm->curPsTdma != 2 && + pCoexDm->curPsTdma != 9 && + pCoexDm->curPsTdma != 11 ) + { + // recover to previous adjust type + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, pCoexDm->psTdmaDuAdjType); + } + } +} + +VOID +halbtc8723b1ant_PsTdmaCheckForPowerSaveState( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bNewPsState + ) +{ + u1Byte lpsMode=0x0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_LPS_MODE, &lpsMode); + + if(lpsMode) // already under LPS state + { + if(bNewPsState) + { + // keep state under LPS, do nothing. + } + else + { + // will leave LPS state, turn off psTdma first + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + } + else // NO PS state + { + if(bNewPsState) + { + // will enter LPS state, turn off psTdma first + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + // keep state under NO PS state, do nothing. + } + } +} + +VOID +halbtc8723b1ant_PowerSaveState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte psType, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + BOOLEAN bLowPwrDisable=FALSE; + + switch(psType) + { + case BTC_PS_WIFI_NATIVE: + // recover to original 32k low power setting + bLowPwrDisable = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + break; + case BTC_PS_LPS_ON: + halbtc8723b1ant_PsTdmaCheckForPowerSaveState(pBtCoexist, TRUE); + halbtc8723b1ant_LpsRpwm(pBtCoexist, NORMAL_EXEC, lpsVal, rpwmVal); + // when coex force to enter LPS, do not enter 32k low power. + bLowPwrDisable = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + // power save must executed before psTdma. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_ENTER_LPS, NULL); + break; + case BTC_PS_LPS_OFF: + halbtc8723b1ant_PsTdmaCheckForPowerSaveState(pBtCoexist, FALSE); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + break; + default: + break; + } +} + +VOID +halbtc8723b1ant_ActionWifiOnly( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); +} + +VOID +halbtc8723b1ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtActive=TRUE, bBtDisabled=FALSE; + + // This function check if bt is disabled + + if( pCoexSta->highPriorityTx == 0 && + pCoexSta->highPriorityRx == 0 && + pCoexSta->lowPriorityTx == 0 && + pCoexSta->lowPriorityRx == 0) + { + bBtActive = FALSE; + } + if( pCoexSta->highPriorityTx == 0xffff && + pCoexSta->highPriorityRx == 0xffff && + pCoexSta->lowPriorityTx == 0xffff && + pCoexSta->lowPriorityRx == 0xffff) + { + bBtActive = FALSE; + } + if(bBtActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + halbtc8723b1ant_ActionWifiOnly(pBtCoexist); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + bPreBtDisabled = bBtDisabled; + if(!bBtDisabled) + { + } + else + { + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + } + } +} + +//============================================= +// +// Software Coex Mechanism start +// +//============================================= + +// SCO only or SCO+PAN(HS) +VOID +halbtc8723b1ant_ActionSco( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_SwMechanism(pBtCoexist, TRUE); +} + + +VOID +halbtc8723b1ant_ActionHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_SwMechanism(pBtCoexist, TRUE); +} + +//A2DP only / PAN(EDR) only/ A2DP+PAN(HS) +VOID +halbtc8723b1ant_ActionA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_SwMechanism(pBtCoexist, FALSE); +} + +VOID +halbtc8723b1ant_ActionA2dpPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_SwMechanism(pBtCoexist, FALSE); +} + +VOID +halbtc8723b1ant_ActionPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_SwMechanism(pBtCoexist, FALSE); +} + +//PAN(HS) only +VOID +halbtc8723b1ant_ActionPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_SwMechanism(pBtCoexist, FALSE); +} + +//PAN(EDR)+A2DP +VOID +halbtc8723b1ant_ActionPanEdrA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_SwMechanism(pBtCoexist, FALSE); +} + +VOID +halbtc8723b1ant_ActionPanEdrHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_SwMechanism(pBtCoexist, TRUE); +} + +// HID+A2DP+PAN(EDR) +VOID +halbtc8723b1ant_ActionHidA2dpPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_SwMechanism(pBtCoexist, TRUE); +} + +VOID +halbtc8723b1ant_ActionHidA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_SwMechanism(pBtCoexist, TRUE); +} + +//============================================= +// +// Non-Software Coex Mechanism start +// +//============================================= +VOID +halbtc8723b1ant_ActionWifiMultiPort( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); +} + +VOID +halbtc8723b1ant_ActionHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); +} + +VOID +halbtc8723b1ant_ActionBtInquiry( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bWifiConnected=FALSE, bApEnable=FALSE, bWifiBusy=FALSE, bBtBusy=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, &bApEnable); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + + + if ( (!bWifiConnected) && (!pCoexSta->bWiFiIsHighPriTask) ) + { + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } + else if( (pBtLinkInfo->bScoExist) || + (pBtLinkInfo->bHidExist) ) + { + // SCO/HID-only busy + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 32); + + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 3); + } + else if ( (pBtLinkInfo->bA2dpExist) || (pBtLinkInfo->bPanExist) || (bWifiBusy) ) + { + + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 20); + + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); + } + else + { + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); + } + +} + +VOID +halbtc8723b1ant_ActionBtScoHidOnlyBusy( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bWifiConnected=FALSE; + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + // tdma and coex table + + if(pBtLinkInfo->bScoExist) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + else //HID + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 5); + } +/* + if(pBtLinkInfo->bScoExist || pBtLinkInfo->bHidExist) + { + if(bWifiConnected) + { + wifiRssiState = halbtc8723b1ant_WifiRssiState(pBtCoexist, 0, 2, 30, 0); + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 2, 1, 1, 1); + } + else + { + halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 1, 1, 1, 1); + } + } + else + { + halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); + } + } +*/ +} + +VOID +halbtc8723b1ant_ActionWifiConnectedBtAclBusy( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + u1Byte btRssiState; + + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + btRssiState = halbtc8723b1ant_BtRssiState(2, 28, 0); + + if(pBtLinkInfo->bHidOnly) //HID + { + halbtc8723b1ant_ActionBtScoHidOnlyBusy(pBtCoexist, wifiStatus); + pCoexDm->bAutoTdmaAdjust = FALSE; + return; + } + else if(pBtLinkInfo->bA2dpOnly) //A2DP + { + if(BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifiStatus) + { + //halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + //halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 32); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + else if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b1ant_TdmaDurationAdjustForAcl(pBtCoexist, wifiStatus); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + else //for low BT RSSI + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + } + else if(pBtLinkInfo->bHidExist&&pBtLinkInfo->bA2dpExist) //HID+A2DP + { + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + else //for low BT RSSI + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 6); + } + else if( (pBtLinkInfo->bPanOnly) || (pBtLinkInfo->bHidExist&&pBtLinkInfo->bPanExist) ) //PAN(OPP,FTP), HID+PAN(OPP,FTP) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 6); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + else if ( ((pBtLinkInfo->bA2dpExist) && (pBtLinkInfo->bPanExist)) || + (pBtLinkInfo->bHidExist&&pBtLinkInfo->bA2dpExist&&pBtLinkInfo->bPanExist) ) //A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + else + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + pCoexDm->bAutoTdmaAdjust = FALSE; + } +} + +VOID +halbtc8723b1ant_ActionWifiNotConnected( + IN PBTC_COEXIST pBtCoexist + ) +{ + // power save state + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +VOID +halbtc8723b1ant_ActionWifiNotConnectedScan( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8723b1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 8); + + // tdma and coex table + if(BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + if(pBtLinkInfo->bA2dpExist && pBtLinkInfo->bPanExist) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 22); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + else if(pBtLinkInfo->bPanOnly) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 20); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + else + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 20); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + } + else if( (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8723b1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } + else + { + //halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 20); + //halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + + //Bryant Add + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } +} + +VOID +halbtc8723b1ant_ActionWifiNotConnectedAssoAuth( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + if( (pBtLinkInfo->bScoExist) || (pBtLinkInfo->bHidExist) ) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 32); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 3); + } + else if( (pBtLinkInfo->bA2dpExist) || (pBtLinkInfo->bPanExist) ) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 20); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); + } + else + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + +} + +VOID +halbtc8723b1ant_ActionWifiConnectedScan( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + if(BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + if(pBtLinkInfo->bA2dpExist && pBtLinkInfo->bPanExist) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 22); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + else if(pBtLinkInfo->bPanOnly) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 20); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + else + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 20); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + } + else if( (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8723b1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } + else + { + //halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 20); + //halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + + //Bryant Add + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } +} + +VOID +halbtc8723b1ant_ActionWifiConnectedSpecialPacket( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + if( (pBtLinkInfo->bScoExist) || (pBtLinkInfo->bHidExist) ) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 32); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 3); + } + else if( (pBtLinkInfo->bA2dpExist) || (pBtLinkInfo->bPanExist) ) + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 20); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); + } + else + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } +} + +VOID +halbtc8723b1ant_ActionWifiConnected( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiBusy=FALSE; + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + BOOLEAN bUnder4way=FALSE, bApEnable=FALSE; + u4Byte wifiBw; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect()===>\n")); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); + if(bUnder4way) + { + halbtc8723b1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n")); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + if(bScan || bLink || bRoam) + { + if(bScan) + halbtc8723b1ant_ActionWifiConnectedScan(pBtCoexist); + else + halbtc8723b1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n")); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, &bApEnable); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + // power save state + if(!bApEnable && BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && !pBtCoexist->btLinkInfo.bHidOnly) + { + if(!bWifiBusy && pBtCoexist->btLinkInfo.bA2dpOnly) //A2DP + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + else + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x4); + } + else + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + if(!bWifiBusy) + { + if(BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8723b1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } + else if( (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8723b1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } + else + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + } + else + { + if(BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8723b1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } + else if( (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8723b1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } + else + { + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + } +} + +VOID +halbtc8723b1ant_RunSwCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte algorithm=0; + + algorithm = halbtc8723b1ant_ActionAlgorithm(pBtCoexist); + pCoexDm->curAlgorithm = algorithm; + + if(halbtc8723b1ant_IsCommonAction(pBtCoexist)) + { + + } + else + { + switch(pCoexDm->curAlgorithm) + { + case BT_8723B_1ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = SCO.\n")); + halbtc8723b1ant_ActionSco(pBtCoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID.\n")); + halbtc8723b1ant_ActionHid(pBtCoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP.\n")); + halbtc8723b1ant_ActionA2dp(pBtCoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP+PAN(HS).\n")); + halbtc8723b1ant_ActionA2dpPanHs(pBtCoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR).\n")); + halbtc8723b1ant_ActionPanEdr(pBtCoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HS mode.\n")); + halbtc8723b1ant_ActionPanHs(pBtCoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN+A2DP.\n")); + halbtc8723b1ant_ActionPanEdrA2dp(pBtCoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR)+HID.\n")); + halbtc8723b1ant_ActionPanEdrHid(pBtCoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP+PAN.\n")); + halbtc8723b1ant_ActionHidA2dpPanEdr(pBtCoexist); + break; + case BT_8723B_1ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP.\n")); + halbtc8723b1ant_ActionHidA2dp(pBtCoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = coexist All Off!!\n")); + //halbtc8723b1ant_CoexAllOff(pBtCoexist); + break; + } + pCoexDm->preAlgorithm = pCoexDm->curAlgorithm; + } +} + +VOID +halbtc8723b1ant_RunCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + BOOLEAN bIncreaseScanDevNum=FALSE; + BOOLEAN bBtCtrlAggBufSize=FALSE; + u1Byte aggBufSize=5; + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiLinkStatus=0; + u4Byte numOfWifiLink=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism()===>\n")); + + if(pBtCoexist->bManualControl) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n")); + return; + } + + if(pBtCoexist->bStopCoexDm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n")); + return; + } + + if(pCoexSta->bUnderIps) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under IPS !!!\n")); + return; + } + + if( (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || + (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + bIncreaseScanDevNum = TRUE; + } + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, &bIncreaseScanDevNum); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus); + numOfWifiLink = wifiLinkStatus>>16; + if(numOfWifiLink >= 2) + { + halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, bBtCtrlAggBufSize, aggBufSize); + halbtc8723b1ant_ActionWifiMultiPort(pBtCoexist); + return; + } + + if(!pBtLinkInfo->bScoExist && !pBtLinkInfo->bHidExist) + { + halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); + } + else + { + if(bWifiConnected) + { + wifiRssiState = halbtc8723b1ant_WifiRssiState(pBtCoexist, 1, 2, 30, 0); + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 1, 1, 1, 1); + } + else + { + halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 1, 1, 1, 1); + } + } + else + { + halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); + } + + } + + if(pBtLinkInfo->bScoExist) + { + bBtCtrlAggBufSize = TRUE; + aggBufSize = 0x3; + } + else if(pBtLinkInfo->bHidExist) + { + bBtCtrlAggBufSize = TRUE; + aggBufSize = 0x5; + } + else if(pBtLinkInfo->bA2dpExist || pBtLinkInfo->bPanExist) + { + bBtCtrlAggBufSize = TRUE; + aggBufSize = 0x8; + } + halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, bBtCtrlAggBufSize, aggBufSize); + + halbtc8723b1ant_RunSwCoexistMechanism(pBtCoexist); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8723b1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8723b1ant_ActionHs(pBtCoexist); + return; + } + + + if(!bWifiConnected) + { + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is non connected-idle !!!\n")); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if(bScan || bLink || bRoam) + { + if (bScan) + halbtc8723b1ant_ActionWifiNotConnectedScan(pBtCoexist); + else + halbtc8723b1ant_ActionWifiNotConnectedAssoAuth(pBtCoexist); + } + else + halbtc8723b1ant_ActionWifiNotConnected(pBtCoexist); + } + else // wifi LPS/Busy + { + halbtc8723b1ant_ActionWifiConnected(pBtCoexist); + } +} + +VOID +halbtc8723b1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + // force to reset coex mechanism + + // sw all off + halbtc8723b1ant_SwMechanism(pBtCoexist, FALSE); + + //halbtc8723b1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 8); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); +} + +VOID +halbtc8723b1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bBackUp + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + u4Byte u4Tmp=0;//, fwVer; + u2Byte u2Tmp=0; + u1Byte u1Tmp=0; + u1Byte H2C_Parameter[2] ={0}; + u4Byte cntBtCalChk=0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 1Ant Init HW Config!!\n")); + + if(bBackUp) + { + pCoexDm->backupArfrCnt1 = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x430); + pCoexDm->backupArfrCnt2 = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x434); + pCoexDm->backupRetryLimit = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x42a); + pCoexDm->backupAmpduMaxTime = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x456); + } + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); //WiFi goto standby while GNT_BT 0-->1 + //pBtCoexist->fBtcSetBtReg(pBtCoexist, 0, 0x3c, 0x15); //BT goto standby while GNT_BT 1-->0 + + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x974, 0xff); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x944, 0x3, 0x3); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x930, 0x77); + + //pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x1); //BT select s0/s1 is controlled by WiFi + + // BT calibration check + while(cntBtCalChk <= 20) + { + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x49d); + cntBtCalChk++; + if(u4Tmp & BIT0) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ########### BT calibration(cnt=%d) ###########\n", cntBtCalChk)); + delay_ms(50); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ********** BT NOT calibration (cnt=%d)**********\n", cntBtCalChk)); + break; + } + } + + // 0x790[5:0]=0x5 + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x790); + u1Tmp &= 0xc0; + u1Tmp |= 0x5; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x790, u1Tmp); + + // Enable counter statistics + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); //0x76e[3] =1, WLAN_Act control by PTA + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x778, 0x1); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x40, 0x20, 0x1); + + //Antenna config + //halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_PTA, TRUE, FALSE); + halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, TRUE, FALSE); + + // PTA parameter + halbtc8723b1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); +} + +VOID +halbtc8723b1ant_WifiOffHwCfg( + IN PBTC_COEXIST pBtCoexist + ) +{ + // set wlan_act to low + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); +} + +//============================================================ +// work around function start with wa_halbtc8723b1ant_ +//============================================================ +//============================================================ +// extern function start with EXhalbtc8723b1ant_ +//============================================================ +VOID +EXhalbtc8723b1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8723b1ant_InitHwConfig(pBtCoexist, TRUE); +} + +VOID +EXhalbtc8723b1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + pBtCoexist->bStopCoexDm = FALSE; + + halbtc8723b1ant_InitCoexDm(pBtCoexist); + + halbtc8723b1ant_QueryBtInfo(pBtCoexist); +} + +VOID +EXhalbtc8723b1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + pu1Byte cliBuf=pBtCoexist->cliBuf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u2Byte u2Tmp[4]; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir, faOfdm, faCck, wifiLinkStatus; + u1Byte wifiDot11Chnl, wifiHsChnl; + u4Byte fwVer=0, btPatchVer=0; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(pBtCoexist->bManualControl) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cliBuf); + } + if(pBtCoexist->bStopCoexDm) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cliBuf); + } + + if(!pBoardInfo->bBtExist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", "Ant PG Num/ Ant Mech/ Ant Pos:", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum, pBoardInfo->btdmAntPos); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", \ + GLCoexVerDate8723b1Ant, GLCoexVer8723b1Ant, fwVer, btPatchVer, btPatchVer); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ + wifiDot11Chnl, wifiHsChnl, bBtHsOn); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], + pCoexDm->wifiChnlInfo[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", "sta/vwifi/hs/p2pGo/p2pGc", \ + ((wifiLinkStatus&WIFI_STA_CONNECTED)? 1:0), ((wifiLinkStatus&WIFI_AP_CONNECTED)? 1:0), + ((wifiLinkStatus&WIFI_HS_CONNECTED)? 1:0), ((wifiLinkStatus&WIFI_P2P_GO_CONNECTED)? 1:0), + ((wifiLinkStatus&WIFI_P2P_GC_CONNECTED)? 1:0) ); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((pBtCoexist->btInfo.bBtDisabled)? ("disabled"): ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus)? "non-connected idle": + ( (BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy")))), + pCoexSta->btRssi, pCoexSta->btRetryCnt); + CL_PRINTF(cliBuf); + + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pBtLinkInfo->bScoExist, pBtLinkInfo->bHidExist, pBtLinkInfo->bPanExist, pBtLinkInfo->bA2dpExist); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + + btInfoExt = pCoexSta->btInfoExt; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (btInfoExt&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cliBuf); + + for(i=0; i<BT_INFO_SRC_8723B_1ANT_MAX; i++) + { + if(pCoexSta->btInfoC2hCnt[i]) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8723b1Ant[i], \ + pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], + pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], + pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], + pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); + CL_PRINTF(cliBuf); + } + } + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s, (0x%x/0x%x)", "PS state, IPS/LPS, (lps/rpwm)", \ + ((pCoexSta->bUnderIps? "IPS ON":"IPS OFF")), + ((pCoexSta->bUnderLps? "LPS ON":"LPS OFF")), + pBtCoexist->btInfo.lpsVal, + pBtCoexist->btInfo.rpwmVal); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + if(!pBtCoexist->bManualControl) + { + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "SM[LowPenaltyRA]", \ + pCoexDm->bCurLowPenaltyRa); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %d ", "DelBA/ BtCtrlAgg/ AggSize", \ + (pBtCoexist->btInfo.bRejectAggPkt? "Yes":"No"), (pBtCoexist->btInfo.bBtCtrlAggBufSize? "Yes":"No"), + pBtCoexist->btInfo.aggBufSize); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask", \ + pBtCoexist->btInfo.raMask); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + psTdmaCase = pCoexDm->curPsTdma; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA", \ + pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], + pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], + pCoexDm->psTdmaPara[4], psTdmaCase, pCoexDm->bAutoTdmaAdjust); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "IgnWlanAct", \ + pCoexDm->bCurIgnoreWlanAct); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Latest error condition(should be 0)", \ + pCoexDm->errorCondition); + CL_PRINTF(cliBuf); + } + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "backup ARFR1/ARFR2/RL/AMaxTime", \ + pCoexDm->backupArfrCnt1, pCoexDm->backupArfrCnt2, pCoexDm->backupRetryLimit, pCoexDm->backupAmpduMaxTime); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x430); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x434); + u2Tmp[0] = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x42a); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x456); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "0x430/0x434/0x42a/0x456", \ + u4Tmp[0], u4Tmp[1], u2Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x778); + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6cc); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x880); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x778/0x6cc/0x880[29:25]", \ + u1Tmp[0], u4Tmp[0], (u4Tmp[1]&0x3e000000) >> 25); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x948); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x67); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x765); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x948/ 0x67[5] / 0x765", \ + u4Tmp[0], ((u1Tmp[0]&0x20)>> 5), u1Tmp[1]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x92c); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x930); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x944); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", \ + u4Tmp[0]&0x3, u4Tmp[1]&0xff, u4Tmp[2]&0x3); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x39); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u1Tmp[2] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x64); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x38[11]/0x40/0x4c[24:23]/0x64[0]", \ + ((u1Tmp[0] & 0x8)>>3), u1Tmp[1], ((u4Tmp[0]&0x01800000)>>23), u1Tmp[2]&0x1); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x550); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x522); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x49c); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0xc50(dig)/0x49c(null-drop)", \ + u4Tmp[0]&0xff, u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda8); + u4Tmp[3] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xcf0); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5b); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5c); + + faOfdm = ((u4Tmp[0]&0xffff0000) >> 16) + ((u4Tmp[1]&0xffff0000) >> 16) + (u4Tmp[1] & 0xffff) + (u4Tmp[2] & 0xffff) + \ + ((u4Tmp[3]&0xffff0000) >> 16) + (u4Tmp[3] & 0xffff) ; + faCck = (u1Tmp[0] << 8) + u1Tmp[1]; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "OFDM-CCA/OFDM-FA/CCK-FA", \ + u4Tmp[0]&0xffff, faOfdm, faCck); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2]); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)", \ + pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", \ + pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); + CL_PRINTF(cliBuf); +#if(BT_AUTO_REPORT_ONLY_8723B_1ANT == 1) + halbtc8723b1ant_MonitorBtCtr(pBtCoexist); +#endif + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8723b1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u4Byte u4Tmp=0; + + if(pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm) + return; + + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + pCoexSta->bUnderIps = TRUE; + halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, TRUE); + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8723b1ant_WifiOffHwCfg(pBtCoexist); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + pCoexSta->bUnderIps = FALSE; + //halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_PTA, TRUE, FALSE); + //halbtc8723b1ant_RunCoexistMechanism(pBtCoexist); + + halbtc8723b1ant_InitHwConfig(pBtCoexist, FALSE); + halbtc8723b1ant_InitCoexDm(pBtCoexist); + halbtc8723b1ant_QueryBtInfo(pBtCoexist); + } +} + +VOID +EXhalbtc8723b1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm) + return; + + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + pCoexSta->bUnderLps = TRUE; + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + pCoexSta->bUnderLps = FALSE; + } +} + +VOID +EXhalbtc8723b1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + u4Byte wifiLinkStatus=0; + u4Byte numOfWifiLink=0; + BOOLEAN bBtCtrlAggBufSize=FALSE; + u1Byte aggBufSize=5; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + if(BTC_SCAN_START == type) + { + pCoexSta->bWiFiIsHighPriTask = TRUE; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + } + else + { + pCoexSta->bWiFiIsHighPriTask = FALSE; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + } + + halbtc8723b1ant_QueryBtInfo(pBtCoexist); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus); + numOfWifiLink = wifiLinkStatus>>16; + if(numOfWifiLink >= 2) + { + halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, bBtCtrlAggBufSize, aggBufSize); + halbtc8723b1ant_ActionWifiMultiPort(pBtCoexist); + return; + } + + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8723b1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8723b1ant_ActionHs(pBtCoexist); + return; + } + + if(BTC_SCAN_START == type) + { + //BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + if(!bWifiConnected) // non-connected scan + { + halbtc8723b1ant_ActionWifiNotConnectedScan(pBtCoexist); + } + else // wifi is connected + { + halbtc8723b1ant_ActionWifiConnectedScan(pBtCoexist); + } + } + else if(BTC_SCAN_FINISH == type) + { + //BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + if(!bWifiConnected) // non-connected scan + { + halbtc8723b1ant_ActionWifiNotConnected(pBtCoexist); + } + else + { + halbtc8723b1ant_ActionWifiConnected(pBtCoexist); + } + } +} + +VOID +EXhalbtc8723b1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + u4Byte wifiLinkStatus=0; + u4Byte numOfWifiLink=0; + BOOLEAN bBtCtrlAggBufSize=FALSE; + u1Byte aggBufSize=5; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + if(BTC_ASSOCIATE_START == type) + { + pCoexSta->bWiFiIsHighPriTask = TRUE; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + } + else + { + pCoexSta->bWiFiIsHighPriTask = FALSE; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus); + numOfWifiLink = wifiLinkStatus>>16; + if(numOfWifiLink >= 2) + { + halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, bBtCtrlAggBufSize, aggBufSize); + halbtc8723b1ant_ActionWifiMultiPort(pBtCoexist); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8723b1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8723b1ant_ActionHs(pBtCoexist); + return; + } + + if(BTC_ASSOCIATE_START == type) + { + //BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + halbtc8723b1ant_ActionWifiNotConnectedAssoAuth(pBtCoexist); + } + else if(BTC_ASSOCIATE_FINISH == type) + { + //BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(!bWifiConnected) // non-connected scan + { + halbtc8723b1ant_ActionWifiNotConnected(pBtCoexist); + } + else + { + halbtc8723b1ant_ActionWifiConnected(pBtCoexist); + } + } +} + +VOID +EXhalbtc8723b1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u1Byte H2C_Parameter[3] ={0}; + u4Byte wifiBw; + u1Byte wifiCentralChnl; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } + + // only 2.4G we need to inform bt the chnl mask + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); + if( (BTC_MEDIA_CONNECT == type) && + (wifiCentralChnl <= 14) ) + { + //H2C_Parameter[0] = 0x1; + H2C_Parameter[0] = 0x0; + H2C_Parameter[1] = wifiCentralChnl; + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + H2C_Parameter[2] = 0x30; + else + H2C_Parameter[2] = 0x20; + } + + pCoexDm->wifiChnlInfo[0] = H2C_Parameter[0]; + pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1]; + pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x66=0x%x\n", + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x66, 3, H2C_Parameter); +} + +VOID +EXhalbtc8723b1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bBtHsOn=FALSE; + u4Byte wifiLinkStatus=0; + u4Byte numOfWifiLink=0; + BOOLEAN bBtCtrlAggBufSize=FALSE; + u1Byte aggBufSize=5; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + if( BTC_PACKET_DHCP == type || BTC_PACKET_EAPOL == type ||BTC_PACKET_ARP == type) + { + pCoexSta->bWiFiIsHighPriTask = TRUE; + + if (BTC_PACKET_ARP == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], special Packet ARP notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], special Packet DHCP or EAPOL notify\n")); + } + } + else + { + pCoexSta->bWiFiIsHighPriTask = FALSE; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], special Packet [Type = %d] notify\n", type)); + } + + pCoexSta->specialPktPeriodCnt = 0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_LINK_STATUS, &wifiLinkStatus); + numOfWifiLink = wifiLinkStatus>>16; + if(numOfWifiLink >= 2) + { + halbtc8723b1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8723b1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, bBtCtrlAggBufSize, aggBufSize); + halbtc8723b1ant_ActionWifiMultiPort(pBtCoexist); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8723b1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8723b1ant_ActionHs(pBtCoexist); + return; + } + + if( BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type || BTC_PACKET_ARP == type) + { + //BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], special Packet(%d) notify\n", type)); + halbtc8723b1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); + } +} + +VOID +EXhalbtc8723b1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + u1Byte btInfo=0; + u1Byte i, rspSource=0; + BOOLEAN bWifiConnected=FALSE; + BOOLEAN bBtBusy=FALSE; + + pCoexSta->bC2hBtInfoReqSent = FALSE; + + rspSource = tmpBuf[0]&0xf; + if(rspSource >= BT_INFO_SRC_8723B_1ANT_MAX) + rspSource = BT_INFO_SRC_8723B_1ANT_WIFI_FW; + pCoexSta->btInfoC2hCnt[rspSource]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rspSource, length)); + for(i=0; i<length; i++) + { + pCoexSta->btInfoC2h[rspSource][i] = tmpBuf[i]; + if(i == 1) + btInfo = tmpBuf[i]; + + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); + } + + } + + if(BT_INFO_SRC_8723B_1ANT_WIFI_FW != rspSource) + { + pCoexSta->btRetryCnt = // [3:0] + pCoexSta->btInfoC2h[rspSource][2]&0xf; + + if (pCoexSta->btInfoC2h[rspSource][2]&0x20) + pCoexSta->bC2hBtPage = TRUE; + else + pCoexSta->bC2hBtPage = FALSE; + + pCoexSta->btRssi = + pCoexSta->btInfoC2h[rspSource][3]*2+10; + + pCoexSta->btInfoExt = + pCoexSta->btInfoC2h[rspSource][4]; + + if (!(pCoexSta->btInfoC2h[rspSource][2] & 0x40)) + { + /* BT into is responded by BT FW and BT RF REG 0x3C != 0x15 => Need to switch GNT_BT */ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Switch GNT_BT since BT RF REG 0x3C != 0x15\n")); + pBtCoexist->fBtcSetBtReg(pBtCoexist, 0, 0x3c, 0x15); + } + + // Here we need to resend some wifi info to BT + // because bt is reset and loss of the info. + if(pCoexSta->btInfoExt & BIT1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n")); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(bWifiConnected) + { + EXhalbtc8723b1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_CONNECT); + } + else + { + EXhalbtc8723b1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); + } + } + + if(pCoexSta->btInfoExt & BIT3) + { + if(!pBtCoexist->bManualControl && !pBtCoexist->bStopCoexDm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n")); + halbtc8723b1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); + } + } + else + { + // BT already NOT ignore Wlan active, do nothing here. + } +#if(BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) + if( (pCoexSta->btInfoExt & BIT4) ) + { + // BT auto report already enabled, do nothing + } + else + { + halbtc8723b1ant_BtAutoReport(pBtCoexist, FORCE_EXEC, TRUE); + } +#endif + } + + // check BIT2 first ==> check if bt is under inquiry or page scan + if(btInfo & BT_INFO_8723B_1ANT_B_INQ_PAGE) + pCoexSta->bC2hBtInquiryPage = TRUE; + else + pCoexSta->bC2hBtInquiryPage = FALSE; + + // set link exist status + if(!(btInfo&BT_INFO_8723B_1ANT_B_CONNECTION)) + { + pCoexSta->bBtLinkExist = FALSE; + pCoexSta->bPanExist = FALSE; + pCoexSta->bA2dpExist = FALSE; + pCoexSta->bHidExist = FALSE; + pCoexSta->bScoExist = FALSE; + } + else // connection exists + { + pCoexSta->bBtLinkExist = TRUE; + if(btInfo & BT_INFO_8723B_1ANT_B_FTP) + pCoexSta->bPanExist = TRUE; + else + pCoexSta->bPanExist = FALSE; + if(btInfo & BT_INFO_8723B_1ANT_B_A2DP) + pCoexSta->bA2dpExist = TRUE; + else + pCoexSta->bA2dpExist = FALSE; + if(btInfo & BT_INFO_8723B_1ANT_B_HID) + pCoexSta->bHidExist = TRUE; + else + pCoexSta->bHidExist = FALSE; + if(btInfo & BT_INFO_8723B_1ANT_B_SCO_ESCO) + pCoexSta->bScoExist = TRUE; + else + pCoexSta->bScoExist = FALSE; + } + + halbtc8723b1ant_UpdateBtLinkInfo(pBtCoexist); + + if(!(btInfo&BT_INFO_8723B_1ANT_B_CONNECTION)) + { + pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n")); + } + else if(btInfo == BT_INFO_8723B_1ANT_B_CONNECTION) // connection exists but no busy + { + pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n")); + } + else if((btInfo&BT_INFO_8723B_1ANT_B_SCO_ESCO) || + (btInfo&BT_INFO_8723B_1ANT_B_SCO_BUSY)) + { + pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT SCO busy!!!\n")); + } + else if(btInfo&BT_INFO_8723B_1ANT_B_ACL_BUSY) + { + if(BT_8723B_1ANT_BT_STATUS_ACL_BUSY != pCoexDm->btStatus) + pCoexDm->bAutoTdmaAdjust = FALSE; + pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT ACL busy!!!\n")); + } + else + { + pCoexDm->btStatus = BT_8723B_1ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n")); + } + + if( (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || + (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + bBtBusy = TRUE; + else + bBtBusy = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + + halbtc8723b1ant_RunCoexistMechanism(pBtCoexist); +} + +VOID +EXhalbtc8723b1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte u4Tmp; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + pBtCoexist->bStopCoexDm = TRUE; + + halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, TRUE); + halbtc8723b1ant_WifiOffHwCfg(pBtCoexist); + halbtc8723b1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8723b1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 0); + + EXhalbtc8723b1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8723b1ant_PnpNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pnpState + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify\n")); + + if(BTC_WIFI_PNP_SLEEP == pnpState) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify to SLEEP\n")); + pBtCoexist->bStopCoexDm = TRUE; + /* + halbtc8723b1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + */ + + halbtc8723b1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, TRUE); + halbtc8723b1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8723b1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8723b1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + halbtc8723b1ant_WifiOffHwCfg(pBtCoexist); + } + else if(BTC_WIFI_PNP_WAKE_UP == pnpState) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify to WAKE UP\n")); + pBtCoexist->bStopCoexDm = FALSE; + halbtc8723b1ant_InitHwConfig(pBtCoexist, FALSE); + halbtc8723b1ant_InitCoexDm(pBtCoexist); + halbtc8723b1ant_QueryBtInfo(pBtCoexist); + } +} + +VOID +EXhalbtc8723b1ant_CoexDmReset( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], *****************Coex DM Reset*****************\n")); + + halbtc8723b1ant_InitHwConfig(pBtCoexist, FALSE); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x2, 0xfffff, 0x0); + halbtc8723b1ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8723b1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + static u1Byte disVerInfoCnt=0; + u4Byte fwVer=0, btPatchVer=0; + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ==========================Periodical===========================\n")); + + if(disVerInfoCnt <= 5) + { + disVerInfoCnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum, pBoardInfo->btdmAntPos)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], BT stack/ hci ext ver = %s / %d\n", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion)); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", \ + GLCoexVerDate8723b1Ant, GLCoexVer8723b1Ant, fwVer, btPatchVer, btPatchVer)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + } + +#if(BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) + halbtc8723b1ant_QueryBtInfo(pBtCoexist); + halbtc8723b1ant_MonitorBtCtr(pBtCoexist); + halbtc8723b1ant_MonitorBtEnableDisable(pBtCoexist); +#else + if( halbtc8723b1ant_IsWifiStatusChanged(pBtCoexist) || + pCoexDm->bAutoTdmaAdjust ) + { + //if(pCoexSta->specialPktPeriodCnt > 2) + //{ + halbtc8723b1ant_RunCoexistMechanism(pBtCoexist); + //} + } + + pCoexSta->specialPktPeriodCnt++; +#endif +} + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b1Ant.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b1Ant.h new file mode 100644 index 0000000..179ab10 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b1Ant.h @@ -0,0 +1,211 @@ +//=========================================== +// The following is for 8723B 1ANT BT Co-exist definition +//=========================================== +#define BT_AUTO_REPORT_ONLY_8723B_1ANT 1 + +#define BT_INFO_8723B_1ANT_B_FTP BIT7 +#define BT_INFO_8723B_1ANT_B_A2DP BIT6 +#define BT_INFO_8723B_1ANT_B_HID BIT5 +#define BT_INFO_8723B_1ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8723B_1ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8723B_1ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8723B_1ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8723B_1ANT_B_CONNECTION BIT0 + +#define BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT0))? TRUE:FALSE) + +#define BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT 2 + +typedef enum _BT_INFO_SRC_8723B_1ANT{ + BT_INFO_SRC_8723B_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723B_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723B_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723B_1ANT_MAX +}BT_INFO_SRC_8723B_1ANT,*PBT_INFO_SRC_8723B_1ANT; + +typedef enum _BT_8723B_1ANT_BT_STATUS{ + BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723B_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8723B_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8723B_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8723B_1ANT_BT_STATUS_MAX +}BT_8723B_1ANT_BT_STATUS,*PBT_8723B_1ANT_BT_STATUS; + +typedef enum _BT_8723B_1ANT_WIFI_STATUS{ + BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT = 0x3, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8723B_1ANT_WIFI_STATUS_MAX +}BT_8723B_1ANT_WIFI_STATUS,*PBT_8723B_1ANT_WIFI_STATUS; + +typedef enum _BT_8723B_1ANT_COEX_ALGO{ + BT_8723B_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723B_1ANT_COEX_ALGO_SCO = 0x1, + BT_8723B_1ANT_COEX_ALGO_HID = 0x2, + BT_8723B_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8723B_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8723B_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8723B_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8723B_1ANT_COEX_ALGO_MAX = 0xb, +}BT_8723B_1ANT_COEX_ALGO,*PBT_8723B_1ANT_COEX_ALGO; + +typedef struct _COEX_DM_8723B_1ANT{ + // fw mechanism + BOOLEAN bCurIgnoreWlanAct; + BOOLEAN bPreIgnoreWlanAct; + u1Byte prePsTdma; + u1Byte curPsTdma; + u1Byte psTdmaPara[5]; + u1Byte psTdmaDuAdjType; + BOOLEAN bAutoTdmaAdjust; + BOOLEAN bPrePsTdmaOn; + BOOLEAN bCurPsTdmaOn; + BOOLEAN bPreBtAutoReport; + BOOLEAN bCurBtAutoReport; + u1Byte preLps; + u1Byte curLps; + u1Byte preRpwm; + u1Byte curRpwm; + + // sw mechanism + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + u4Byte preVal0x6c0; + u4Byte curVal0x6c0; + u4Byte preVal0x6c4; + u4Byte curVal0x6c4; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u1Byte preVal0x6cc; + u1Byte curVal0x6cc; + BOOLEAN bLimitedDig; + + u4Byte backupArfrCnt1; // Auto Rate Fallback Retry cnt + u4Byte backupArfrCnt2; // Auto Rate Fallback Retry cnt + u2Byte backupRetryLimit; + u1Byte backupAmpduMaxTime; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + u1Byte btStatus; + u1Byte wifiChnlInfo[3]; + + u4Byte preRaMask; + u4Byte curRaMask; + u1Byte preArfrType; + u1Byte curArfrType; + u1Byte preRetryLimitType; + u1Byte curRetryLimitType; + u1Byte preAmpduTimeType; + u1Byte curAmpduTimeType; + + u1Byte errorCondition; +} COEX_DM_8723B_1ANT, *PCOEX_DM_8723B_1ANT; + +typedef struct _COEX_STA_8723B_1ANT{ + BOOLEAN bBtLinkExist; + BOOLEAN bScoExist; + BOOLEAN bA2dpExist; + BOOLEAN bHidExist; + BOOLEAN bPanExist; + + BOOLEAN bUnderLps; + BOOLEAN bUnderIps; + u4Byte specialPktPeriodCnt; + u4Byte highPriorityTx; + u4Byte highPriorityRx; + u4Byte lowPriorityTx; + u4Byte lowPriorityRx; + u1Byte btRssi; + u1Byte preBtRssiState; + u1Byte preWifiRssiState[4]; + BOOLEAN bC2hBtInfoReqSent; + u1Byte btInfoC2h[BT_INFO_SRC_8723B_1ANT_MAX][10]; + u4Byte btInfoC2hCnt[BT_INFO_SRC_8723B_1ANT_MAX]; + BOOLEAN bC2hBtInquiryPage; + u1Byte btRetryCnt; + u1Byte btInfoExt; + BOOLEAN bWiFiIsHighPriTask; + BOOLEAN bC2hBtPage; +}COEX_STA_8723B_1ANT, *PCOEX_STA_8723B_1ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8723b1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723b1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723b1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723b1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723b1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723b1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723b1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723b1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723b1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8723b1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723b1ant_PnpNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pnpState + ); +VOID +EXhalbtc8723b1ant_CoexDmReset( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723b1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723b1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b2Ant.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b2Ant.c new file mode 100644 index 0000000..fc2b904 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b2Ant.c @@ -0,0 +1,4155 @@ +//============================================================ +// Description: +// +// This file is for RTL8723B Co-exist mechanism +// +// History +// 2012/11/15 Cosa first check in. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8723B_2ANT GLCoexDm8723b2Ant; +static PCOEX_DM_8723B_2ANT pCoexDm=&GLCoexDm8723b2Ant; +static COEX_STA_8723B_2ANT GLCoexSta8723b2Ant; +static PCOEX_STA_8723B_2ANT pCoexSta=&GLCoexSta8723b2Ant; + +const char *const GLBtInfoSrc8723b2Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u4Byte GLCoexVerDate8723b2Ant=20131113; +u4Byte GLCoexVer8723b2Ant=0x3f; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8723b2ant_ +//============================================================ +u1Byte +halbtc8723b2ant_BtRssiState( + u1Byte levelNum, + u1Byte rssiThresh, + u1Byte rssiThresh1 + ) +{ + s4Byte btRssi=0; + u1Byte btRssiState=pCoexSta->preBtRssiState; + + btRssi = pCoexSta->btRssi; + + if(levelNum == 2) + { + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else + { + if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); + return pCoexSta->preBtRssiState; + } + + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); + } + } + else + { + if(btRssi < rssiThresh1) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + + pCoexSta->preBtRssiState = btRssiState; + + return btRssiState; +} + +u1Byte +halbtc8723b2ant_WifiRssiState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte index, + IN u1Byte levelNum, + IN u1Byte rssiThresh, + IN u1Byte rssiThresh1 + ) +{ + s4Byte wifiRssi=0; + u1Byte wifiRssiState=pCoexSta->preWifiRssiState[index]; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(levelNum == 2) + { + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return pCoexSta->preWifiRssiState[index]; + } + + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifiRssi < rssiThresh1) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + pCoexSta->preWifiRssiState[index] = wifiRssiState; + + return wifiRssiState; +} + +VOID +halbtc8723b2ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtActive=TRUE, bBtDisabled=FALSE; + + // This function check if bt is disabled + + if( pCoexSta->highPriorityTx == 0 && + pCoexSta->highPriorityRx == 0 && + pCoexSta->lowPriorityTx == 0 && + pCoexSta->lowPriorityRx == 0) + { + bBtActive = FALSE; + } + if( pCoexSta->highPriorityTx == 0xffff && + pCoexSta->highPriorityRx == 0xffff && + pCoexSta->lowPriorityTx == 0xffff && + pCoexSta->lowPriorityRx == 0xffff) + { + bBtActive = FALSE; + } + if(bBtActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + bPreBtDisabled = bBtDisabled; + if(!bBtDisabled) + { + } + else + { + } + } +} + +VOID +halbtc8723b2ant_MonitorBtCtr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte regHPTxRx, regLPTxRx, u4Tmp; + u4Byte regHPTx=0, regHPRx=0, regLPTx=0, regLPRx=0; + u1Byte u1Tmp; + + regHPTxRx = 0x770; + regLPTxRx = 0x774; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); + regHPTx = u4Tmp & bMaskLWord; + regHPRx = (u4Tmp & bMaskHWord)>>16; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); + regLPTx = u4Tmp & bMaskLWord; + regLPRx = (u4Tmp & bMaskHWord)>>16; + + pCoexSta->highPriorityTx = regHPTx; + pCoexSta->highPriorityRx = regHPRx; + pCoexSta->lowPriorityTx = regLPTx; + pCoexSta->lowPriorityRx = regLPRx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regHPTxRx, regHPTx, regHPTx, regHPRx, regHPRx)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regLPTxRx, regLPTx, regLPTx, regLPRx, regLPRx)); + + // reset counter + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); +} + +VOID +halbtc8723b2ant_QueryBtInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + pCoexSta->bC2hBtInfoReqSent = TRUE; + + H2C_Parameter[0] |= BIT0; // trigger + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Query Bt Info, FW write 0x61=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x61, 1, H2C_Parameter); +} + +BOOLEAN +halbtc8723b2ant_IsWifiStatusChanged( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreWifiBusy=FALSE, bPreUnder4way=FALSE, bPreBtHsOn=FALSE; + BOOLEAN bWifiBusy=FALSE, bUnder4way=FALSE, bBtHsOn=FALSE; + BOOLEAN bWifiConnected=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); + + if(bWifiConnected) + { + if(bWifiBusy != bPreWifiBusy) + { + bPreWifiBusy = bWifiBusy; + return TRUE; + } + if(bUnder4way != bPreUnder4way) + { + bPreUnder4way = bUnder4way; + return TRUE; + } + if(bBtHsOn != bPreBtHsOn) + { + bPreBtHsOn = bBtHsOn; + return TRUE; + } + } + + return FALSE; +} + +VOID +halbtc8723b2ant_UpdateBtLinkInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bBtHsOn=FALSE; + +#if(BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) // profile from bt patch + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + pBtLinkInfo->bBtLinkExist = pCoexSta->bBtLinkExist; + pBtLinkInfo->bScoExist = pCoexSta->bScoExist; + pBtLinkInfo->bA2dpExist = pCoexSta->bA2dpExist; + pBtLinkInfo->bPanExist = pCoexSta->bPanExist; + pBtLinkInfo->bHidExist = pCoexSta->bHidExist; + + // work around for HS mode. + if(bBtHsOn) + { + pBtLinkInfo->bPanExist = TRUE; + pBtLinkInfo->bBtLinkExist = TRUE; + } +#else // profile from bt stack + pBtLinkInfo->bBtLinkExist = pStackInfo->bBtLinkExist; + pBtLinkInfo->bScoExist = pStackInfo->bScoExist; + pBtLinkInfo->bA2dpExist = pStackInfo->bA2dpExist; + pBtLinkInfo->bPanExist = pStackInfo->bPanExist; + pBtLinkInfo->bHidExist = pStackInfo->bHidExist; + + //for win-8 stack HID report error + if(!pStackInfo->bHidExist) + pStackInfo->bHidExist = pCoexSta->bHidExist; //sync BTInfo with BT firmware and stack + // when stack HID report error, here we use the info from bt fw. + if(!pStackInfo->bBtLinkExist) + pStackInfo->bBtLinkExist = pCoexSta->bBtLinkExist; +#endif + // check if Sco only + if( pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bScoOnly = TRUE; + else + pBtLinkInfo->bScoOnly = FALSE; + + // check if A2dp only + if( !pBtLinkInfo->bScoExist && + pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bA2dpOnly = TRUE; + else + pBtLinkInfo->bA2dpOnly = FALSE; + + // check if Pan only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bPanOnly = TRUE; + else + pBtLinkInfo->bPanOnly = FALSE; + + // check if Hid only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + pBtLinkInfo->bHidExist ) + pBtLinkInfo->bHidOnly = TRUE; + else + pBtLinkInfo->bHidOnly = FALSE; +} + +u1Byte +halbtc8723b2ant_ActionAlgorithm( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bBtHsOn=FALSE; + u1Byte algorithm=BT_8723B_2ANT_COEX_ALGO_UNDEFINED; + u1Byte numOfDiffProfile=0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(!pBtLinkInfo->bBtLinkExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No BT link exists!!!\n")); + return algorithm; + } + + if(pBtLinkInfo->bScoExist) + numOfDiffProfile++; + if(pBtLinkInfo->bHidExist) + numOfDiffProfile++; + if(pBtLinkInfo->bPanExist) + numOfDiffProfile++; + if(pBtLinkInfo->bA2dpExist) + numOfDiffProfile++; + + if(numOfDiffProfile == 1) + { + if(pBtLinkInfo->bScoExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO only\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_SCO; + } + else + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_A2DP; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(HS) only\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(EDR) only\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR; + } + } + } + } + else if(numOfDiffProfile == 2) + { + if(pBtLinkInfo->bScoExist) + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP ==> SCO\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(HS)\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(EDR)\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { +#if 0 + if(pStackInfo->numOfHid >= 2) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID*2 + A2DP\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + else +#endif + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP; + } + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(HS)\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } + else if(numOfDiffProfile == 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP ==> HID\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(HS)\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(EDR)\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(HS)\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + else if(numOfDiffProfile >= 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n")); + + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n")); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +BOOLEAN +halbtc8723b2ant_NeedToDecBtPwr( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bRet=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiConnected=FALSE; + s4Byte btHsRssi=0; + u1Byte btRssiState; + + if(!pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn)) + return FALSE; + if(!pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected)) + return FALSE; + if(!pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi)) + return FALSE; + + btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); + + if(bWifiConnected) + { + if(bBtHsOn) + { + if(btHsRssi > 37) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], Need to decrease bt power for HS mode!!\n")); + bRet = TRUE; + } + } + else + { + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], Need to decrease bt power for Wifi is connected!!\n")); + bRet = TRUE; + } + } + } + + return bRet; +} + +VOID +halbtc8723b2ant_SetFwDacSwingLevel( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte dacSwingLvl + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + // There are several type of dacswing + // 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 + H2C_Parameter[0] = dacSwingLvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Set Dac Swing Level=0x%x\n", dacSwingLvl)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x64=0x%x\n", H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x64, 1, H2C_Parameter); +} + +VOID +halbtc8723b2ant_SetFwDecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bDecBtPwr + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = 0; + + if(bDecBtPwr) + { + H2C_Parameter[0] |= BIT1; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], decrease Bt Power : %s, FW write 0x62=0x%x\n", + (bDecBtPwr? "Yes!!":"No!!"), H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x62, 1, H2C_Parameter); +} + +VOID +halbtc8723b2ant_DecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDecBtPwr + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s Dec BT power = %s\n", + (bForceExec? "force to":""), ((bDecBtPwr)? "ON":"OFF"))); + pCoexDm->bCurDecBtPwr = bDecBtPwr; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreDecBtPwr=%d, bCurDecBtPwr=%d\n", + pCoexDm->bPreDecBtPwr, pCoexDm->bCurDecBtPwr)); + + if(pCoexDm->bPreDecBtPwr == pCoexDm->bCurDecBtPwr) + return; + } + halbtc8723b2ant_SetFwDecBtPwr(pBtCoexist, pCoexDm->bCurDecBtPwr); + + pCoexDm->bPreDecBtPwr = pCoexDm->bCurDecBtPwr; +} + +VOID +halbtc8723b2ant_SetBtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnableAutoReport + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = 0; + + if(bEnableAutoReport) + { + H2C_Parameter[0] |= BIT0; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], BT FW auto report : %s, FW write 0x68=0x%x\n", + (bEnableAutoReport? "Enabled!!":"Disabled!!"), H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x68, 1, H2C_Parameter); +} + +VOID +halbtc8723b2ant_BtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnableAutoReport + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT Auto report = %s\n", + (bForceExec? "force to":""), ((bEnableAutoReport)? "Enabled":"Disabled"))); + pCoexDm->bCurBtAutoReport = bEnableAutoReport; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtAutoReport=%d, bCurBtAutoReport=%d\n", + pCoexDm->bPreBtAutoReport, pCoexDm->bCurBtAutoReport)); + + if(pCoexDm->bPreBtAutoReport == pCoexDm->bCurBtAutoReport) + return; + } + halbtc8723b2ant_SetBtAutoReport(pBtCoexist, pCoexDm->bCurBtAutoReport); + + pCoexDm->bPreBtAutoReport = pCoexDm->bCurBtAutoReport; +} + +VOID +halbtc8723b2ant_FwDacSwingLvl( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte fwDacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set FW Dac Swing level = %d\n", + (bForceExec? "force to":""), fwDacSwingLvl)); + pCoexDm->curFwDacSwingLvl = fwDacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preFwDacSwingLvl=%d, curFwDacSwingLvl=%d\n", + pCoexDm->preFwDacSwingLvl, pCoexDm->curFwDacSwingLvl)); + + if(pCoexDm->preFwDacSwingLvl == pCoexDm->curFwDacSwingLvl) + return; + } + + halbtc8723b2ant_SetFwDacSwingLevel(pBtCoexist, pCoexDm->curFwDacSwingLvl); + + pCoexDm->preFwDacSwingLvl = pCoexDm->curFwDacSwingLvl; +} + +VOID +halbtc8723b2ant_SetSwRfRxLpfCorner( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bRxRfShrinkOn + ) +{ + if(bRxRfShrinkOn) + { + //Shrink RF Rx LPF corner + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Shrink RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, 0xffffc); + } + else + { + //Resume RF Rx LPF corner + // After initialized, we can use pCoexDm->btRf0x1eBackup + if(pBtCoexist->bInitilized) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, pCoexDm->btRf0x1eBackup); + } + } +} + +VOID +halbtc8723b2ant_RfShrink( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRxRfShrinkOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn Rx RF Shrink = %s\n", + (bForceExec? "force to":""), ((bRxRfShrinkOn)? "ON":"OFF"))); + pCoexDm->bCurRfRxLpfShrink = bRxRfShrinkOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreRfRxLpfShrink=%d, bCurRfRxLpfShrink=%d\n", + pCoexDm->bPreRfRxLpfShrink, pCoexDm->bCurRfRxLpfShrink)); + + if(pCoexDm->bPreRfRxLpfShrink == pCoexDm->bCurRfRxLpfShrink) + return; + } + halbtc8723b2ant_SetSwRfRxLpfCorner(pBtCoexist, pCoexDm->bCurRfRxLpfShrink); + + pCoexDm->bPreRfRxLpfShrink = pCoexDm->bCurRfRxLpfShrink; +} + +VOID +halbtc8723b2ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte H2C_Parameter[6] ={0}; + + H2C_Parameter[0] = 0x6; // opCode, 0x6= Retry_Penalty + + if(bLowPenaltyRa) + { + H2C_Parameter[1] |= BIT0; + H2C_Parameter[2] = 0x00; //normal rate except MCS7/6/5, OFDM54/48/36 + H2C_Parameter[3] = 0xf7; //MCS7 or OFDM54 + H2C_Parameter[4] = 0xf8; //MCS6 or OFDM48 + H2C_Parameter[5] = 0xf9; //MCS5 or OFDM36 + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set WiFi Low-Penalty Retry: %s", + (bLowPenaltyRa? "ON!!":"OFF!!")) ); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x69, 6, H2C_Parameter); +} + +VOID +halbtc8723b2ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + //return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); + + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8723b2ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8723b2ant_SetDacSwingReg( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte level + ) +{ + u1Byte val=(u1Byte)level; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Write SwDacSwing = 0x%x\n", level)); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x883, 0x3e, val); +} + +VOID +halbtc8723b2ant_SetSwFullTimeDacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bSwDacSwingOn, + IN u4Byte swDacSwingLvl + ) +{ + if(bSwDacSwingOn) + { + halbtc8723b2ant_SetDacSwingReg(pBtCoexist, swDacSwingLvl); + } + else + { + halbtc8723b2ant_SetDacSwingReg(pBtCoexist, 0x18); + } +} + + +VOID +halbtc8723b2ant_DacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDacSwingOn, + IN u4Byte dacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn DacSwing=%s, dacSwingLvl=0x%x\n", + (bForceExec? "force to":""), ((bDacSwingOn)? "ON":"OFF"), dacSwingLvl)); + pCoexDm->bCurDacSwingOn = bDacSwingOn; + pCoexDm->curDacSwingLvl = dacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x, bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + pCoexDm->bPreDacSwingOn, pCoexDm->preDacSwingLvl, + pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl)); + + if( (pCoexDm->bPreDacSwingOn == pCoexDm->bCurDacSwingOn) && + (pCoexDm->preDacSwingLvl == pCoexDm->curDacSwingLvl) ) + return; + } + delay_ms(30); + halbtc8723b2ant_SetSwFullTimeDacSwing(pBtCoexist, bDacSwingOn, dacSwingLvl); + + pCoexDm->bPreDacSwingOn = pCoexDm->bCurDacSwingOn; + pCoexDm->preDacSwingLvl = pCoexDm->curDacSwingLvl; +} + +VOID +halbtc8723b2ant_SetAdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAdcBackOff + ) +{ + if(bAdcBackOff) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level On!\n")); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xc05, 0x30, 0x3); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level Off!\n")); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xc05, 0x30, 0x1); + } +} + +VOID +halbtc8723b2ant_AdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAdcBackOff + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn AdcBackOff = %s\n", + (bForceExec? "force to":""), ((bAdcBackOff)? "ON":"OFF"))); + pCoexDm->bCurAdcBackOff = bAdcBackOff; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAdcBackOff=%d, bCurAdcBackOff=%d\n", + pCoexDm->bPreAdcBackOff, pCoexDm->bCurAdcBackOff)); + + if(pCoexDm->bPreAdcBackOff == pCoexDm->bCurAdcBackOff) + return; + } + halbtc8723b2ant_SetAdcBackOff(pBtCoexist, pCoexDm->bCurAdcBackOff); + + pCoexDm->bPreAdcBackOff = pCoexDm->bCurAdcBackOff; +} + +VOID +halbtc8723b2ant_SetAgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAgcTableEn + ) +{ + u1Byte rssiAdjustVal=0; + + //=================BB AGC Gain Table + if(bAgcTableEn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB Agc Table On!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6e1A0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6d1B0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6c1C0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6b1D0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x6a1E0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x691F0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0x68200001); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB Agc Table Off!\n")); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xaa1A0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa91B0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa81C0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa71D0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa61E0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa51F0001); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0xc78, 0xa4200001); + } + + + //=================RF Gain + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); + if(bAgcTableEn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x38fff); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x38ffe); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x380c3); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x28ce6); + } + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xed, 0xfffff, 0x1); + if(bAgcTableEn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x38fff); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x38ffe); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x380c3); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x40, 0xfffff, 0x28ce6); + } + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xed, 0xfffff, 0x0); + + // set rssiAdjustVal for wifi module. + if(bAgcTableEn) + { + rssiAdjustVal = 8; + } + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, &rssiAdjustVal); +} + +VOID +halbtc8723b2ant_AgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAgcTableEn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s %s Agc Table\n", + (bForceExec? "force to":""), ((bAgcTableEn)? "Enable":"Disable"))); + pCoexDm->bCurAgcTableEn = bAgcTableEn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + pCoexDm->bPreAgcTableEn, pCoexDm->bCurAgcTableEn)); + + if(pCoexDm->bPreAgcTableEn == pCoexDm->bCurAgcTableEn) + return; + } + halbtc8723b2ant_SetAgcTable(pBtCoexist, bAgcTableEn); + + pCoexDm->bPreAgcTableEn = pCoexDm->bCurAgcTableEn; +} + +VOID +halbtc8723b2ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8723b2ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c0, val0x6c4, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c0 = val0x6c0; + pCoexDm->curVal0x6c4 = val0x6c4; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c0=0x%x, preVal0x6c4=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + pCoexDm->preVal0x6c0, pCoexDm->preVal0x6c4, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c0=0x%x, curVal0x6c4=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + pCoexDm->curVal0x6c0, pCoexDm->curVal0x6c4, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && + (pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8723b2ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c4, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; + pCoexDm->preVal0x6c4 = pCoexDm->curVal0x6c4; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8723b2ant_CoexTableWithType( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + switch(type) + { + case 0: + halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x55555555, 0xffff, 0x3); + break; + case 1: + halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x5afa5afa, 0xffff, 0x3); + break; + case 2: + halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x5a5a5a5a, 0x5a5a5a5a, 0xffff, 0x3); + break; + case 3: + halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0xaaaaaaaa, 0xaaaaaaaa, 0xffff, 0x3); + break; + case 4: + halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0xffffffff, 0xffffffff, 0xffff, 0x3); + break; + case 5: + halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x5fff5fff, 0x5fff5fff, 0xffff, 0x3); + break; + case 6: + halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5a5a5a5a, 0xffff, 0x3); + break; + case 7: + halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5afa5afa, 0xffff, 0x3); + break; + case 8: + halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x5aea5aea, 0x5aea5aea, 0xffff, 0x3); + break; + case 9: + halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5aea5aea, 0xffff, 0x3); + break; + case 10: + halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5aff5aff, 0xffff, 0x3); + break; + case 11: + halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5a5f5a5f, 0xffff, 0x3); + break; + case 12: + halbtc8723b2ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5f5f5f5f, 0xffff, 0x3); + break; + default: + break; + } +} + +VOID +halbtc8723b2ant_SetFwIgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnable + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + if(bEnable) + { + H2C_Parameter[0] |= BIT0; // function enable + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x63, 1, H2C_Parameter); +} + +VOID +halbtc8723b2ant_IgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); + pCoexDm->bCurIgnoreWlanAct = bEnable; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); + + if(pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) + return; + } + halbtc8723b2ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); + + pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; +} + +VOID +halbtc8723b2ant_SetFwPstdma( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte byte1, + IN u1Byte byte2, + IN u1Byte byte3, + IN u1Byte byte4, + IN u1Byte byte5 + ) +{ + u1Byte H2C_Parameter[5] ={0}; + + H2C_Parameter[0] = byte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = byte5; + + pCoexDm->psTdmaPara[0] = byte1; + pCoexDm->psTdmaPara[1] = byte2; + pCoexDm->psTdmaPara[2] = byte3; + pCoexDm->psTdmaPara[3] = byte4; + pCoexDm->psTdmaPara[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x60(5bytes)=0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x60, 5, H2C_Parameter); +} + +VOID +halbtc8723b2ant_SwMechanism1( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bShrinkRxLPF, + IN BOOLEAN bLowPenaltyRA, + IN BOOLEAN bLimitedDIG, + IN BOOLEAN bBTLNAConstrain + ) +{ + /* + u4Byte wifiBw; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 != wifiBw) //only shrink RF Rx LPF for HT40 + { + if (bShrinkRxLPF) + bShrinkRxLPF = FALSE; + } + */ + + halbtc8723b2ant_RfShrink(pBtCoexist, NORMAL_EXEC, bShrinkRxLPF); + halbtc8723b2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, bLowPenaltyRA); +} + +VOID +halbtc8723b2ant_SwMechanism2( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAGCTableShift, + IN BOOLEAN bADCBackOff, + IN BOOLEAN bSWDACSwing, + IN u4Byte dacSwingLvl + ) +{ + halbtc8723b2ant_AgcTable(pBtCoexist, NORMAL_EXEC, bAGCTableShift); + //halbtc8723b2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, bADCBackOff); + halbtc8723b2ant_DacSwing(pBtCoexist, NORMAL_EXEC, bSWDACSwing, dacSwingLvl); +} + +VOID +halbtc8723b2ant_SetAntPath( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte antPosType, + IN BOOLEAN bInitHwCfg, + IN BOOLEAN bWifiOff + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + u4Byte fwVer=0, u4Tmp=0; + BOOLEAN bPgExtSwitch=FALSE; + BOOLEAN bUseExtSwitch=FALSE; + u1Byte H2C_Parameter[2] ={0}; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_EXT_SWITCH, &bPgExtSwitch); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); // [31:16]=fw ver, [15:0]=fw sub ver + + if((fwVer<0xc0000) || bPgExtSwitch) + bUseExtSwitch = TRUE; + + if(bInitHwCfg) + { + // 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u4Tmp &=~BIT23; + u4Tmp |= BIT24; + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); + + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x974, 0xff); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x944, 0x3, 0x3); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x930, 0x77); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x1); + + //Force GNT_BT to low + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x765, 0x18, 0x0); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); + + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + { + //tell firmware "no antenna inverse" + H2C_Parameter[0] = 0; + } + else + { + //tell firmware "antenna inverse" + H2C_Parameter[0] = 1; + } + + if (bUseExtSwitch) + { + //ext switch type + H2C_Parameter[1] = 1; + } + else + { + //int switch type + H2C_Parameter[1] = 0; + } + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); + } + + + // ext switch setting + if(bUseExtSwitch) + { + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); // fixed internal switch S1->WiFi, S0->BT + switch(antPosType) + { + case BTC_ANT_WIFI_AT_MAIN: + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x1); // ext switch main at wifi + break; + case BTC_ANT_WIFI_AT_AUX: + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x2); // ext switch aux at wifi + break; + } + } + else // internal switch + { + // fixed ext switch + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x92c, 0x3, 0x1); + switch(antPosType) + { + case BTC_ANT_WIFI_AT_MAIN: + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x0); // fixed internal switch S1->WiFi, S0->BT + break; + case BTC_ANT_WIFI_AT_AUX: + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, 0x280); // fixed internal switch S0->WiFi, S1->BT + break; + } + } +} + +VOID +halbtc8723b2ant_PsTdma( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bTurnOn, + IN u1Byte type + ) +{ + BOOLEAN bTurnOnByCnt=FALSE; + u1Byte psTdmaTypeByCnt=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type=%d\n", + (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); + pCoexDm->bCurPsTdmaOn = bTurnOn; + pCoexDm->curPsTdma = type; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + pCoexDm->bPrePsTdmaOn, pCoexDm->bCurPsTdmaOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + pCoexDm->prePsTdma, pCoexDm->curPsTdma)); + + if( (pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && + (pCoexDm->prePsTdma == pCoexDm->curPsTdma) ) + return; + } + if(bTurnOn) + { + switch(type) + { + case 1: + default: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); + break; + case 2: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x90); + break; + case 3: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x3, 0xf1, 0x90); + break; + case 4: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x10, 0x03, 0xf1, 0x90); + break; + case 5: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x90); + break; + case 6: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0x60, 0x90); + break; + case 7: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x3, 0x70, 0x90); + break; + case 8: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xa3, 0x10, 0x3, 0x70, 0x90); + break; + case 9: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); + break; + case 10: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x90); + break; + case 11: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0xe1, 0x90); + break; + case 12: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0xe1, 0x90); + break; + case 13: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x90); + break; + case 14: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0x60, 0x90); + break; + case 15: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0x60, 0x90); + break; + case 16: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0x60, 0x90); + break; + case 17: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xa3, 0x2f, 0x2f, 0x60, 0x90); + break; + case 18: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0xe1, 0x90); + break; + case 19: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0xe1, 0x90); + break; + case 20: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0x60, 0x90); + break; + case 21: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x15, 0x03, 0x70, 0x90); + break; + case 71: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); + break; + } + } + else + { + // disable PS tdma + switch(type) + { + case 0: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x40, 0x0); + break; + case 1: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x48, 0x0); + break; + default: + halbtc8723b2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x40, 0x0); + break; + } + } + + // update pre state + pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; + pCoexDm->prePsTdma = pCoexDm->curPsTdma; +} + +VOID +halbtc8723b2ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + // fw all off + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + // sw all off + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + // hw all off + //pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +VOID +halbtc8723b2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + // force to reset coex mechanism + + halbtc8723b2ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 1); + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, FORCE_EXEC, 6); + halbtc8723b2ant_DecBtPwr(pBtCoexist, FORCE_EXEC, FALSE); + + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); +} + +VOID +halbtc8723b2ant_ActionBtInquiry( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiConnected=FALSE; + BOOLEAN bLowPwrDisable=TRUE; + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + if(bWifiConnected) + { + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + } + else + { + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + } + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, FORCE_EXEC, 6); + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + pCoexDm->bNeedRecover0x948 = TRUE; + pCoexDm->backup0x948 = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x948); + + halbtc8723b2ant_SetAntPath(pBtCoexist, BTC_ANT_WIFI_AT_AUX, FALSE, FALSE); +} +BOOLEAN +halbtc8723b2ant_IsCommonAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bCommon=FALSE, bWifiConnected=FALSE, bWifiBusy=FALSE; + BOOLEAN bBtHsOn=FALSE, bLowPwrDisable=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + + if(!bWifiConnected) + { + bLowPwrDisable = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non-connected idle!!\n")); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else + { + if(BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) + { + bLowPwrDisable = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT non connected-idle!!\n")); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0xb); + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else if(BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) + { + bLowPwrDisable = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + if(bBtHsOn) + return FALSE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT connected-idle!!\n")); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0xb); + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else + { + bLowPwrDisable = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + if(bWifiBusy) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Busy + BT Busy!!\n")); + bCommon = FALSE; + } + else + { + if(bBtHsOn) + return FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Idle + BT Busy!!\n")); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 21); + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0xb); + if(halbtc8723b2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + bCommon = TRUE; + } + } + } + + return bCommon; +} +VOID +halbtc8723b2ant_TdmaDurationAdjust( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bScoHid, + IN BOOLEAN bTxPause, + IN u1Byte maxInterval + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjust()\n")); + + if(!pCoexDm->bAutoTdmaAdjust) + { + pCoexDm->bAutoTdmaAdjust = TRUE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); + { + if(bScoHid) + { + if(bTxPause) + { + if(maxInterval == 1) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + else if(maxInterval == 2) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(maxInterval == 3) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + } + else + { + if(maxInterval == 1) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(maxInterval == 2) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(maxInterval == 3) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + } + else + { + if(bTxPause) + { + if(maxInterval == 1) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(maxInterval == 2) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(maxInterval == 3) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + } + else + { + if(maxInterval == 1) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(maxInterval == 2) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(maxInterval == 3) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + } + } + } + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n", + up, dn, m, n, WaitCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if �s�� n ��2�� retry count��0, �h�ռeWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration + { + if (WaitCount <= 2) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration + { + if (WaitCount == 1) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], max Interval = %d\n", maxInterval)); + if(maxInterval == 1) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + + if(pCoexDm->curPsTdma == 71) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 71); + pCoexDm->psTdmaDuAdjType = 71; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + + if(result == -1) + { + if(pCoexDm->curPsTdma == 71) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 71); + pCoexDm->psTdmaDuAdjType = 71; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + } + } + } + else if(maxInterval == 2) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + if(pCoexDm->curPsTdma == 1) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + } + } + } + else if(maxInterval == 3) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + if(pCoexDm->curPsTdma == 1) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + } + } + } + + // if current PsTdma not match with the recorded one (when scan, dhcp...), + // then we have to adjust it back to the previous record one. + if(pCoexDm->curPsTdma != pCoexDm->psTdmaDuAdjType) + { + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], PsTdma type dismatch!!!, curPsTdma=%d, recordPsTdma=%d\n", + pCoexDm->curPsTdma, pCoexDm->psTdmaDuAdjType)); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if( !bScan && !bLink && !bRoam) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, pCoexDm->psTdmaDuAdjType); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n")); + } + } +} + +// SCO only or SCO+PAN(HS) +VOID +halbtc8723b2ant_ActionSco( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 4); + + if(halbtc8723b2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if (BTC_WIFI_BW_LEGACY == wifiBw) //for SCO quality at 11b/g mode + { + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + else //for SCO quality & wifi performance balance at 11n mode + { + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 8); + } + + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); //for voice quality + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,TRUE,0x4); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,TRUE,0x4); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,TRUE,0x4); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,TRUE,0x4); + } + } +} + + +VOID +halbtc8723b2ant_ActionHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if(halbtc8723b2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if (BTC_WIFI_BW_LEGACY == wifiBw) //for HID at 11b/g mode + { + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); + } + else //for HID quality & wifi performance balance at 11n mode + { + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 9); + } + + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + } + else + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + } + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +//A2DP only / PAN(EDR) only/ A2DP+PAN(HS) +VOID +halbtc8723b2ant_ActionA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, wifiRssiState1, btRssiState; + u4Byte wifiBw; + u1Byte apNum=0; + + wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + wifiRssiState1 = halbtc8723b2ant_WifiRssiState(pBtCoexist, 1, 2, 40, 0); + btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_AP_NUM, &apNum); + + // define the office environment + if(apNum >= 10 && BTC_RSSI_HIGH(wifiRssiState1)) + { + //DbgPrint(" AP#>10(%d)\n", apNum); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + + // sw mechanism + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,TRUE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,TRUE,0x18); + } + return; + } + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if(halbtc8723b2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); + + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 1); + } + else + { + halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 1); + } + + // sw mechanism + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8723b2ant_ActionA2dpPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if(halbtc8723b2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); + + halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 2); + + // sw mechanism + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8723b2ant_ActionPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if(halbtc8723b2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 10); + + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + } + else + { + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + } + + // sw mechanism + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + + +//PAN(HS) only +VOID +halbtc8723b2ant_ActionPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + } + else + { + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + } + + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); + + halbtc8723b2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +//PAN(EDR)+A2DP +VOID +halbtc8723b2ant_ActionPanEdrA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if(halbtc8723b2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 12); + if(BTC_WIFI_BW_HT40 == wifiBw) + halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 3); + else + halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 3); + } + else + { + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); + halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 3); + } + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8723b2ant_ActionPanEdrHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(halbtc8723b2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(BTC_WIFI_BW_HT40 == wifiBw) + { + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 3); + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 11); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); + } + else + { + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + } + halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 2); + } + else + { + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 11); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + } + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +// HID+A2DP+PAN(EDR) +VOID +halbtc8723b2ant_ActionHidA2dpPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if(halbtc8723b2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); + + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(BTC_WIFI_BW_HT40 == wifiBw) + halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + else + halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 3); + } + else + { + halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 3); + } + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8723b2ant_ActionHidA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8723b2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8723b2ant_BtRssiState(2, 29, 0); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if(halbtc8723b2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8723b2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + halbtc8723b2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 7); + + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 2); + } + else + { + halbtc8723b2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + } + + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8723b2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8723b2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8723b2ant_RunCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiUnder5G=FALSE, bBtHsOn=FALSE; + u1Byte btInfoOriginal=0, btRetryCnt=0; + u1Byte algorithm=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism()===>\n")); + + if(pBtCoexist->bManualControl) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n")); + return; + } + + if(pCoexSta->bUnderIps) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under IPS !!!\n")); + return; + } + + algorithm = halbtc8723b2ant_ActionAlgorithm(pBtCoexist); + if(pCoexSta->bC2hBtInquiryPage && (BT_8723B_2ANT_COEX_ALGO_PANHS!=algorithm)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT is under inquiry/page scan !!\n")); + halbtc8723b2ant_ActionBtInquiry(pBtCoexist); + return; + } + else + { + if(pCoexDm->bNeedRecover0x948) + { + pCoexDm->bNeedRecover0x948 = FALSE; + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x948, pCoexDm->backup0x948); + } + } + + pCoexDm->curAlgorithm = algorithm; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Algorithm = %d \n", pCoexDm->curAlgorithm)); + + if(halbtc8723b2ant_IsCommonAction(pBtCoexist)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant common.\n")); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + else + { + if(pCoexDm->curAlgorithm != pCoexDm->preAlgorithm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], preAlgorithm=%d, curAlgorithm=%d\n", + pCoexDm->preAlgorithm, pCoexDm->curAlgorithm)); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + switch(pCoexDm->curAlgorithm) + { + case BT_8723B_2ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = SCO.\n")); + halbtc8723b2ant_ActionSco(pBtCoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID.\n")); + halbtc8723b2ant_ActionHid(pBtCoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP.\n")); + halbtc8723b2ant_ActionA2dp(pBtCoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n")); + halbtc8723b2ant_ActionA2dpPanHs(pBtCoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n")); + halbtc8723b2ant_ActionPanEdr(pBtCoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HS mode.\n")); + halbtc8723b2ant_ActionPanHs(pBtCoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n")); + halbtc8723b2ant_ActionPanEdrA2dp(pBtCoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n")); + halbtc8723b2ant_ActionPanEdrHid(pBtCoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n")); + halbtc8723b2ant_ActionHidA2dpPanEdr(pBtCoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n")); + halbtc8723b2ant_ActionHidA2dp(pBtCoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n")); + halbtc8723b2ant_CoexAllOff(pBtCoexist); + break; + } + pCoexDm->preAlgorithm = pCoexDm->curAlgorithm; + } +} + +VOID +halbtc8723b2ant_WifiOffHwCfg( + IN PBTC_COEXIST pBtCoexist + ) +{ + PADAPTER padapter=pBtCoexist->Adapter; + // set wlan_act to low + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x780); //WiFi goto standby while GNT_BT 0-->1 + + //Force GNT_BT to High + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x765, 0x18, 0x3); + if(padapter->registrypriv.mp_mode ==0) + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x0); //BT select s0/s1 is controlled by BT + else + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x67, 0x20, 0x1); //BT select s0/s1 is controlled by WiFi +} + +//============================================================ +// work around function start with wa_halbtc8723b2ant_ +//============================================================ +//============================================================ +// extern function start with EXhalbtc8723b2ant_ +//============================================================ +VOID +EXhalbtc8723b2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + u4Byte u4Tmp=0, fwVer; + u2Byte u2Tmp=0; + u1Byte u1Tmp=0; + u1Byte H2C_Parameter[2] ={0}; + + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 2Ant Init HW Config!!\n")); + + //pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); //WiFi goto standby while GNT_BT 0-->1 + //pBtCoexist->fBtcSetBtReg(pBtCoexist, 0, 0x3c, 0x1); //BT goto standby while GNT_BT 1-->0 + + // backup rf 0x1e value + pCoexDm->btRf0x1eBackup = + pBtCoexist->fBtcGetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff); + + // 0x790[5:0]=0x5 + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x790); + u1Tmp &= 0xc0; + u1Tmp |= 0x5; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x790, u1Tmp); + + //Antenna config + halbtc8723b2ant_SetAntPath(pBtCoexist, BTC_ANT_WIFI_AT_MAIN, TRUE, FALSE); + + // PTA parameter + halbtc8723b2ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); + + // Enable counter statistics + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); //0x76e[3] =1, WLAN_Act control by PTA + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x778, 0x3); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x40, 0x20, 0x1); + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); //WiFi goto standby while GNT_BT 0-->1 +} + +VOID +EXhalbtc8723b2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + halbtc8723b2ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8723b2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + pu1Byte cliBuf=pBtCoexist->cliBuf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir, faOfdm, faCck; + u1Byte wifiDot11Chnl, wifiHsChnl; + u4Byte fwVer=0, btPatchVer=0; + u1Byte apNum=0; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(pBtCoexist->bManualControl) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cliBuf); + } + + if(!pBoardInfo->bBtExist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", \ + GLCoexVerDate8723b2Ant, GLCoexVer8723b2Ant, fwVer, btPatchVer, btPatchVer); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ + wifiDot11Chnl, wifiHsChnl, bBtHsOn); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], + pCoexDm->wifiChnlInfo[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_AP_NUM, &apNum); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", "Wifi rssi/ HS rssi/ AP#", \ + wifiRssi, btHsRssi, apNum); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((pBtCoexist->btInfo.bBtDisabled)? ("disabled"): ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus)? "non-connected idle": + ( (BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy")))), + pCoexSta->btRssi, pCoexSta->btRetryCnt); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pBtLinkInfo->bScoExist, pBtLinkInfo->bHidExist, pBtLinkInfo->bPanExist, pBtLinkInfo->bA2dpExist); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + + btInfoExt = pCoexSta->btInfoExt; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (btInfoExt&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cliBuf); + + for(i=0; i<BT_INFO_SRC_8723B_2ANT_MAX; i++) + { + if(pCoexSta->btInfoC2hCnt[i]) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8723b2Ant[i], \ + pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], + pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], + pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], + pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); + CL_PRINTF(cliBuf); + } + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", "PS state, IPS/LPS", \ + ((pCoexSta->bUnderIps? "IPS ON":"IPS OFF")), + ((pCoexSta->bUnderLps? "LPS ON":"LPS OFF"))); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "SM1[ShRf/ LpRA/ LimDig]", \ + pCoexDm->bCurRfRxLpfShrink, pCoexDm->bCurLowPenaltyRa, pCoexDm->bLimitedDig); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", \ + pCoexDm->bCurAgcTableEn, pCoexDm->bCurAdcBackOff, pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + psTdmaCase = pCoexDm->curPsTdma; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA", \ + pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], + pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], + pCoexDm->psTdmaPara[4], psTdmaCase, pCoexDm->bAutoTdmaAdjust); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", \ + pCoexDm->bCurDecBtPwr, pCoexDm->bCurIgnoreWlanAct); + CL_PRINTF(cliBuf); + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", \ + pCoexDm->btRf0x1eBackup); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x778); + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x880); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x778/0x880[29:25]", \ + u1Tmp[0], (u4Tmp[0]&0x3e000000) >> 25); + CL_PRINTF(cliBuf); + + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x948); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x67); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x765); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x948/ 0x67[5] / 0x765", \ + u4Tmp[0], ((u1Tmp[0]&0x20)>> 5), u1Tmp[1]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x92c); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x930); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x944); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", \ + u4Tmp[0]&0x3, u4Tmp[1]&0xff, u4Tmp[2]&0x3); + CL_PRINTF(cliBuf); + + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x39); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u1Tmp[2] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x64); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x38[11]/0x40/0x4c[24:23]/0x64[0]", \ + ((u1Tmp[0] & 0x8)>>3), u1Tmp[1], ((u4Tmp[0]&0x01800000)>>23), u1Tmp[2]&0x1); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x550); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x522); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x49c); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0xc50(dig)/0x49c(null-drop)", \ + u4Tmp[0]&0xff, u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xda8); + u4Tmp[3] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xcf0); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5b); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5c); + + faOfdm = ((u4Tmp[0]&0xffff0000) >> 16) + ((u4Tmp[1]&0xffff0000) >> 16) + (u4Tmp[1] & 0xffff) + (u4Tmp[2] & 0xffff) + \ + ((u4Tmp[3]&0xffff0000) >> 16) + (u4Tmp[3] & 0xffff) ; + faCck = (u1Tmp[0] << 8) + u1Tmp[1]; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "OFDM-CCA/OFDM-FA/CCK-FA", \ + u4Tmp[0]&0xffff, faOfdm, faCck); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp[0]); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)", \ + pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", \ + pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); + CL_PRINTF(cliBuf); +#if(BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) + halbtc8723b2ant_MonitorBtCtr(pBtCoexist); +#endif + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8723b2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + pCoexSta->bUnderIps = TRUE; + halbtc8723b2ant_WifiOffHwCfg(pBtCoexist); + halbtc8723b2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + halbtc8723b2ant_CoexAllOff(pBtCoexist); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + pCoexSta->bUnderIps = FALSE; + EXhalbtc8723b2ant_InitHwConfig(pBtCoexist); + halbtc8723b2ant_InitCoexDm(pBtCoexist); + halbtc8723b2ant_QueryBtInfo(pBtCoexist); + } +} + +VOID +EXhalbtc8723b2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + pCoexSta->bUnderLps = TRUE; + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + pCoexSta->bUnderLps = FALSE; + } +} + +VOID +EXhalbtc8723b2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + } +} + +VOID +EXhalbtc8723b2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + } +} + +VOID +EXhalbtc8723b2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u1Byte H2C_Parameter[3] ={0}; + u4Byte wifiBw; + u1Byte wifiCentralChnl; + + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } + + // only 2.4G we need to inform bt the chnl mask + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); + if( (BTC_MEDIA_CONNECT == type) && + (wifiCentralChnl <= 14) ) + { + H2C_Parameter[0] = 0x1; + H2C_Parameter[1] = wifiCentralChnl; + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + H2C_Parameter[2] = 0x30; + else + H2C_Parameter[2] = 0x20; + } + + pCoexDm->wifiChnlInfo[0] = H2C_Parameter[0]; + pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1]; + pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x66=0x%x\n", + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x66, 3, H2C_Parameter); +} + +VOID +EXhalbtc8723b2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(type == BTC_PACKET_DHCP) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], DHCP Packet notify\n")); + } +} + +VOID +EXhalbtc8723b2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + u1Byte btInfo=0; + u1Byte i, rspSource=0; + BOOLEAN bBtBusy=FALSE, bLimitedDig=FALSE; + BOOLEAN bWifiConnected=FALSE; + static BOOLEAN bPreScoExist=FALSE; + u4Byte raMask=0x0; + + pCoexSta->bC2hBtInfoReqSent = FALSE; + + rspSource = tmpBuf[0]&0xf; + if(rspSource >= BT_INFO_SRC_8723B_2ANT_MAX) + rspSource = BT_INFO_SRC_8723B_2ANT_WIFI_FW; + pCoexSta->btInfoC2hCnt[rspSource]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rspSource, length)); + for(i=0; i<length; i++) + { + pCoexSta->btInfoC2h[rspSource][i] = tmpBuf[i]; + if(i == 1) + btInfo = tmpBuf[i]; + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); + } + } + + if(pBtCoexist->bManualControl) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for Manual CTRL<===\n")); + return; + } + + if(BT_INFO_SRC_8723B_2ANT_WIFI_FW != rspSource) + { + pCoexSta->btRetryCnt = // [3:0] + pCoexSta->btInfoC2h[rspSource][2]&0xf; + + pCoexSta->btRssi = + pCoexSta->btInfoC2h[rspSource][3]*2+10; + + pCoexSta->btInfoExt = + pCoexSta->btInfoC2h[rspSource][4]; + + if (pCoexSta->btInfoC2h[rspSource][2] & 0x40) + { + /* BT into is responded by BT FW and BT RF REG 0x3C != 0x01 => Need to switch GNT_BT */ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Switch GNT_BT since BT RF REG 0x3C != 0x01\n")); + pBtCoexist->fBtcSetBtReg(pBtCoexist, 0, 0x3c, 0x01); + } + + // Here we need to resend some wifi info to BT + // because bt is reset and loss of the info. + if( (pCoexSta->btInfoExt & BIT1) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n")); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(bWifiConnected) + { + EXhalbtc8723b2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_CONNECT); + } + else + { + EXhalbtc8723b2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); + } + } + + if( (pCoexSta->btInfoExt & BIT3) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n")); + halbtc8723b2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); + } + else + { + // BT already NOT ignore Wlan active, do nothing here. + } +#if(BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) + if( (pCoexSta->btInfoExt & BIT4) ) + { + // BT auto report already enabled, do nothing + } + else + { + halbtc8723b2ant_BtAutoReport(pBtCoexist, FORCE_EXEC, TRUE); + } +#endif + } + + // check BIT2 first ==> check if bt is under inquiry or page scan + if(btInfo & BT_INFO_8723B_2ANT_B_INQ_PAGE) + pCoexSta->bC2hBtInquiryPage = TRUE; + else + pCoexSta->bC2hBtInquiryPage = FALSE; + + // set link exist status + if(!(btInfo&BT_INFO_8723B_2ANT_B_CONNECTION)) + { + pCoexSta->bBtLinkExist = FALSE; + pCoexSta->bPanExist = FALSE; + pCoexSta->bA2dpExist = FALSE; + pCoexSta->bHidExist = FALSE; + pCoexSta->bScoExist = FALSE; + } + else // connection exists + { + pCoexSta->bBtLinkExist = TRUE; + if(btInfo & BT_INFO_8723B_2ANT_B_FTP) + pCoexSta->bPanExist = TRUE; + else + pCoexSta->bPanExist = FALSE; + if(btInfo & BT_INFO_8723B_2ANT_B_A2DP) + pCoexSta->bA2dpExist = TRUE; + else + pCoexSta->bA2dpExist = FALSE; + if(btInfo & BT_INFO_8723B_2ANT_B_HID) + pCoexSta->bHidExist = TRUE; + else + pCoexSta->bHidExist = FALSE; + if(btInfo & BT_INFO_8723B_2ANT_B_SCO_ESCO) + pCoexSta->bScoExist = TRUE; + else + pCoexSta->bScoExist = FALSE; + } + + halbtc8723b2ant_UpdateBtLinkInfo(pBtCoexist); + + if(!(btInfo&BT_INFO_8723B_2ANT_B_CONNECTION)) + { + pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n")); + } + else if(btInfo == BT_INFO_8723B_2ANT_B_CONNECTION) // connection exists but no busy + { + pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n")); + } + else if((btInfo&BT_INFO_8723B_2ANT_B_SCO_ESCO) || + (btInfo&BT_INFO_8723B_2ANT_B_SCO_BUSY)) + { + pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT SCO busy!!!\n")); + } + else if(btInfo&BT_INFO_8723B_2ANT_B_ACL_BUSY) + { + pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT ACL busy!!!\n")); + } + else + { + pCoexDm->btStatus = BT_8723B_2ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n")); + } + + if( (BT_8723B_2ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || + (BT_8723B_2ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + bBtBusy = TRUE; + bLimitedDig = TRUE; + } + else + { + bBtBusy = FALSE; + bLimitedDig = FALSE; + } + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + + pCoexDm->bLimitedDig = bLimitedDig; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_LIMITED_DIG, &bLimitedDig); + + halbtc8723b2ant_RunCoexistMechanism(pBtCoexist); +} + +VOID +EXhalbtc8723b2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + halbtc8723b2ant_WifiOffHwCfg(pBtCoexist); + pBtCoexist->fBtcSetBtReg(pBtCoexist, 0, 0x3c, 0x15); //BT goto standby while GNT_BT 1-->0 + halbtc8723b2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + + EXhalbtc8723b2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8723b2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + static u1Byte disVerInfoCnt=0; + u4Byte fwVer=0, btPatchVer=0; + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ==========================Periodical===========================\n")); + + if(disVerInfoCnt <= 5) + { + disVerInfoCnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum, pBoardInfo->btdmAntPos)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], BT stack/ hci ext ver = %s / %d\n", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion)); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", \ + GLCoexVerDate8723b2Ant, GLCoexVer8723b2Ant, fwVer, btPatchVer, btPatchVer)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + } + +#if(BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) + halbtc8723b2ant_QueryBtInfo(pBtCoexist); + halbtc8723b2ant_MonitorBtCtr(pBtCoexist); + halbtc8723b2ant_MonitorBtEnableDisable(pBtCoexist); +#else + if( halbtc8723b2ant_IsWifiStatusChanged(pBtCoexist) || + pCoexDm->bAutoTdmaAdjust) + { + halbtc8723b2ant_RunCoexistMechanism(pBtCoexist); + } +#endif +} + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b2Ant.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b2Ant.h new file mode 100644 index 0000000..e758414 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8723b2Ant.h @@ -0,0 +1,186 @@ +//=========================================== +// The following is for 8723B 2Ant BT Co-exist definition +//=========================================== +#define BT_AUTO_REPORT_ONLY_8723B_2ANT 1 + + +#define BT_INFO_8723B_2ANT_B_FTP BIT7 +#define BT_INFO_8723B_2ANT_B_A2DP BIT6 +#define BT_INFO_8723B_2ANT_B_HID BIT5 +#define BT_INFO_8723B_2ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8723B_2ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8723B_2ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8723B_2ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8723B_2ANT_B_CONNECTION BIT0 + +#define BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT 2 + +typedef enum _BT_INFO_SRC_8723B_2ANT{ + BT_INFO_SRC_8723B_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723B_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723B_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723B_2ANT_MAX +}BT_INFO_SRC_8723B_2ANT,*PBT_INFO_SRC_8723B_2ANT; + +typedef enum _BT_8723B_2ANT_BT_STATUS{ + BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723B_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8723B_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8723B_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8723B_2ANT_BT_STATUS_MAX +}BT_8723B_2ANT_BT_STATUS,*PBT_8723B_2ANT_BT_STATUS; + +typedef enum _BT_8723B_2ANT_COEX_ALGO{ + BT_8723B_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723B_2ANT_COEX_ALGO_SCO = 0x1, + BT_8723B_2ANT_COEX_ALGO_HID = 0x2, + BT_8723B_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8723B_2ANT_COEX_ALGO_PANEDR = 0x5, + BT_8723B_2ANT_COEX_ALGO_PANHS = 0x6, + BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8723B_2ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8723B_2ANT_COEX_ALGO_MAX = 0xb, +}BT_8723B_2ANT_COEX_ALGO,*PBT_8723B_2ANT_COEX_ALGO; + +typedef struct _COEX_DM_8723B_2ANT{ + // fw mechanism + BOOLEAN bPreDecBtPwr; + BOOLEAN bCurDecBtPwr; + u1Byte preFwDacSwingLvl; + u1Byte curFwDacSwingLvl; + BOOLEAN bCurIgnoreWlanAct; + BOOLEAN bPreIgnoreWlanAct; + u1Byte prePsTdma; + u1Byte curPsTdma; + u1Byte psTdmaPara[5]; + u1Byte psTdmaDuAdjType; + BOOLEAN bResetTdmaAdjust; + BOOLEAN bAutoTdmaAdjust; + BOOLEAN bPrePsTdmaOn; + BOOLEAN bCurPsTdmaOn; + BOOLEAN bPreBtAutoReport; + BOOLEAN bCurBtAutoReport; + + // sw mechanism + BOOLEAN bPreRfRxLpfShrink; + BOOLEAN bCurRfRxLpfShrink; + u4Byte btRf0x1eBackup; + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + BOOLEAN bPreDacSwingOn; + u4Byte preDacSwingLvl; + BOOLEAN bCurDacSwingOn; + u4Byte curDacSwingLvl; + BOOLEAN bPreAdcBackOff; + BOOLEAN bCurAdcBackOff; + BOOLEAN bPreAgcTableEn; + BOOLEAN bCurAgcTableEn; + u4Byte preVal0x6c0; + u4Byte curVal0x6c0; + u4Byte preVal0x6c4; + u4Byte curVal0x6c4; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u1Byte preVal0x6cc; + u1Byte curVal0x6cc; + BOOLEAN bLimitedDig; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + u1Byte btStatus; + u1Byte wifiChnlInfo[3]; + + BOOLEAN bNeedRecover0x948; + u4Byte backup0x948; +} COEX_DM_8723B_2ANT, *PCOEX_DM_8723B_2ANT; + +typedef struct _COEX_STA_8723B_2ANT{ + BOOLEAN bBtLinkExist; + BOOLEAN bScoExist; + BOOLEAN bA2dpExist; + BOOLEAN bHidExist; + BOOLEAN bPanExist; + + BOOLEAN bUnderLps; + BOOLEAN bUnderIps; + u4Byte highPriorityTx; + u4Byte highPriorityRx; + u4Byte lowPriorityTx; + u4Byte lowPriorityRx; + u1Byte btRssi; + u1Byte preBtRssiState; + u1Byte preWifiRssiState[4]; + BOOLEAN bC2hBtInfoReqSent; + u1Byte btInfoC2h[BT_INFO_SRC_8723B_2ANT_MAX][10]; + u4Byte btInfoC2hCnt[BT_INFO_SRC_8723B_2ANT_MAX]; + BOOLEAN bC2hBtInquiryPage; + u1Byte btRetryCnt; + u1Byte btInfoExt; +}COEX_STA_8723B_2ANT, *PCOEX_STA_8723B_2ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8723b2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723b2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723b2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723b2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723b2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723b2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723b2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723b2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8723b2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8723b2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723b2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8723b2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a1Ant.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a1Ant.c new file mode 100644 index 0000000..3a21622 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a1Ant.c @@ -0,0 +1,2973 @@ +//============================================================ +// Description: +// +// This file is for 8812a1ant Co-exist mechanism +// +// History +// 2012/11/15 Cosa first check in. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8812A_1ANT GLCoexDm8812a1Ant; +static PCOEX_DM_8812A_1ANT pCoexDm=&GLCoexDm8812a1Ant; +static COEX_STA_8812A_1ANT GLCoexSta8812a1Ant; +static PCOEX_STA_8812A_1ANT pCoexSta=&GLCoexSta8812a1Ant; + +const char *const GLBtInfoSrc8812a1Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u4Byte GLCoexVerDate8812a1Ant=20130729; +u4Byte GLCoexVer8812a1Ant=0x10; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8812a1ant_ +//============================================================ +u1Byte +halbtc8812a1ant_BtRssiState( + u1Byte levelNum, + u1Byte rssiThresh, + u1Byte rssiThresh1 + ) +{ + s4Byte btRssi=0; + u1Byte btRssiState=pCoexSta->preBtRssiState; + + btRssi = pCoexSta->btRssi; + + if(levelNum == 2) + { + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else + { + if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); + return pCoexSta->preBtRssiState; + } + + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); + } + } + else + { + if(btRssi < rssiThresh1) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + + pCoexSta->preBtRssiState = btRssiState; + + return btRssiState; +} + +u1Byte +halbtc8812a1ant_WifiRssiState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte index, + IN u1Byte levelNum, + IN u1Byte rssiThresh, + IN u1Byte rssiThresh1 + ) +{ + s4Byte wifiRssi=0; + u1Byte wifiRssiState=pCoexSta->preWifiRssiState[index]; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(levelNum == 2) + { + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return pCoexSta->preWifiRssiState[index]; + } + + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifiRssi < rssiThresh1) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + pCoexSta->preWifiRssiState[index] = wifiRssiState; + + return wifiRssiState; +} + +VOID +halbtc8812a1ant_UpdateRaMask( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type, + IN u4Byte rateMask + ) +{ + if(BTC_RATE_DISABLE == type) + { + pCoexDm->curRaMask |= rateMask; // disable rate + } + else if(BTC_RATE_ENABLE == type) + { + pCoexDm->curRaMask &= ~rateMask; // enable rate + } + + if( bForceExec || (pCoexDm->preRaMask != pCoexDm->curRaMask)) + { + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_UPDATE_RAMASK, &pCoexDm->curRaMask); + } + pCoexDm->preRaMask = pCoexDm->curRaMask; +} + +VOID +halbtc8812a1ant_MonitorBtCtr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte regHPTxRx, regLPTxRx, u4Tmp; + u4Byte regHPTx=0, regHPRx=0, regLPTx=0, regLPRx=0; + u1Byte u1Tmp; + + regHPTxRx = 0x770; + regLPTxRx = 0x774; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); + regHPTx = u4Tmp & bMaskLWord; + regHPRx = (u4Tmp & bMaskHWord)>>16; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); + regLPTx = u4Tmp & bMaskLWord; + regLPRx = (u4Tmp & bMaskHWord)>>16; + + pCoexSta->highPriorityTx = regHPTx; + pCoexSta->highPriorityRx = regHPRx; + pCoexSta->lowPriorityTx = regLPTx; + pCoexSta->lowPriorityRx = regLPRx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regHPTxRx, regHPTx, regHPTx, regHPRx, regHPRx)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regLPTxRx, regLPTx, regLPTx, regLPRx, regLPRx)); + + // reset counter + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); +} + +VOID +halbtc8812a1ant_QueryBtInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte dataLen=3; + u1Byte buf[5] = {0}; + + if(!pBtCoexist->btInfo.bBtDisabled) + { + if(!pCoexSta->btInfoQueryCnt || + (pCoexSta->btInfoC2hCnt[BT_INFO_SRC_8812A_1ANT_BT_RSP]-pCoexSta->btInfoQueryCnt)>2) + { + buf[0] = dataLen; + buf[1] = 0x1; // polling enable, 1=enable, 0=disable + buf[2] = 0x2; // polling time in seconds + buf[3] = 0x1; // auto report enable, 1=enable, 0=disable + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_CTRL_BT_INFO, (PVOID)&buf[0]); + } + } + pCoexSta->btInfoQueryCnt++; +} + +VOID +halbtc8812a1ant_UpdateBtLinkInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + + pBtLinkInfo->bBtLinkExist = pCoexSta->bBtLinkExist; + pBtLinkInfo->bScoExist = pCoexSta->bScoExist; + pBtLinkInfo->bA2dpExist = pCoexSta->bA2dpExist; + pBtLinkInfo->bPanExist = pCoexSta->bPanExist; + pBtLinkInfo->bHidExist = pCoexSta->bHidExist; + + // check if Sco only + if( pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bScoOnly = TRUE; + else + pBtLinkInfo->bScoOnly = FALSE; + + // check if A2dp only + if( !pBtLinkInfo->bScoExist && + pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bA2dpOnly = TRUE; + else + pBtLinkInfo->bA2dpOnly = FALSE; + + // check if Pan only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bPanOnly = TRUE; + else + pBtLinkInfo->bPanOnly = FALSE; + + // check if Hid only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + pBtLinkInfo->bHidExist ) + pBtLinkInfo->bHidOnly = TRUE; + else + pBtLinkInfo->bHidOnly = FALSE; +} + +u1Byte +halbtc8812a1ant_ActionAlgorithm( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bBtHsOn=FALSE; + u1Byte algorithm=BT_8812A_1ANT_COEX_ALGO_UNDEFINED; + u1Byte numOfDiffProfile=0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(!pBtLinkInfo->bBtLinkExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No profile exists!!!\n")); + return algorithm; + } + + if(pBtLinkInfo->bScoExist) + numOfDiffProfile++; + if(pBtLinkInfo->bHidExist) + numOfDiffProfile++; + if(pBtLinkInfo->bPanExist) + numOfDiffProfile++; + if(pBtLinkInfo->bA2dpExist) + numOfDiffProfile++; + + if(numOfDiffProfile == 1) + { + if(pBtLinkInfo->bScoExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO only\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_SCO; + } + else + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_A2DP; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(HS) only\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(EDR) only\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR; + } + } + } + } + else if(numOfDiffProfile == 2) + { + if(pBtLinkInfo->bScoExist) + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP ==> SCO\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_SCO; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(HS)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(EDR)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID_A2DP; + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(HS)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_A2DP_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } + else if(numOfDiffProfile == 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP ==> HID\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID; + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(HS)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(EDR)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(HS)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + else if(numOfDiffProfile >= 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n")); + + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n")); + algorithm = BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +VOID +halbtc8812a1ant_SetBtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnableAutoReport + ) +{ +} + +VOID +halbtc8812a1ant_BtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnableAutoReport + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT Auto report = %s\n", + (bForceExec? "force to":""), ((bEnableAutoReport)? "Enabled":"Disabled"))); + pCoexDm->bCurBtAutoReport = bEnableAutoReport; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtAutoReport=%d, bCurBtAutoReport=%d\n", + pCoexDm->bPreBtAutoReport, pCoexDm->bCurBtAutoReport)); + + if(pCoexDm->bPreBtAutoReport == pCoexDm->bCurBtAutoReport) + return; + } + halbtc8812a1ant_SetBtAutoReport(pBtCoexist, pCoexDm->bCurBtAutoReport); + + pCoexDm->bPreBtAutoReport = pCoexDm->bCurBtAutoReport; +} + +VOID +halbtc8812a1ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte tmpU1; + + tmpU1 = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x4fd); + tmpU1 |= BIT0; + if(bLowPenaltyRa) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set low penalty!!\n")); + tmpU1 &= ~BIT2; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set normal!!\n")); + tmpU1 |= BIT2; + } + + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x4fd, tmpU1); +} + +VOID +halbtc8812a1ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); + + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8812a1ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8812a1ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8812a1ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c0, val0x6c4, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c0 = val0x6c0; + pCoexDm->curVal0x6c4 = val0x6c4; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c0=0x%x, preVal0x6c4=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + pCoexDm->preVal0x6c0, pCoexDm->preVal0x6c4, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c0=0x%x, curVal0x6c4=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + pCoexDm->curVal0x6c0, pCoexDm->curVal0x6c4, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && + (pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8812a1ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c4, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; + pCoexDm->preVal0x6c4 = pCoexDm->curVal0x6c4; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8812a1ant_CoexTableWithType( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + switch(type) + { + case 0: + halbtc8812a1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x55555555, 0xffff, 0x3); + break; + case 1: + halbtc8812a1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x5a5a5a5a, 0xffff, 0x3); + break; + case 2: + halbtc8812a1ant_CoexTable(pBtCoexist, bForceExec, 0x5a5a5a5a, 0x5a5a5a5a, 0xffff, 0x3); + break; + case 3: + halbtc8812a1ant_CoexTable(pBtCoexist, bForceExec, 0xaaaaaaaa, 0xaaaaaaaa, 0xffff, 0x3); + break; + case 4: + halbtc8812a1ant_CoexTable(pBtCoexist, bForceExec, 0xffffffff, 0xffffffff, 0xffff, 0x3); + break; + case 5: + halbtc8812a1ant_CoexTable(pBtCoexist, bForceExec, 0x5fff5fff, 0x5fff5fff, 0xffff, 0x3); + break; + case 6: + halbtc8812a1ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5a5a5a5a, 0xffff, 0x3); + break; + case 7: + halbtc8812a1ant_CoexTable(pBtCoexist, bForceExec, 0x5afa5afa, 0x5afa5afa, 0xffff, 0x3); + break; + default: + break; + } +} + +VOID +halbtc8812a1ant_SetFwIgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnable + ) +{ + u1Byte dataLen=3; + u1Byte buf[5] = {0}; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], %s BT Ignore Wlan_Act\n", + (bEnable? "Enable":"Disable"))); + + buf[0] = dataLen; + buf[1] = 0x1; // OP_Code + buf[2] = 0x1; // OP_Code_Length + if(bEnable) + buf[3] = 0x1; // OP_Code_Content + else + buf[3] = 0x0; + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); +} + +VOID +halbtc8812a1ant_IgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); + pCoexDm->bCurIgnoreWlanAct = bEnable; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); + + if(pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) + return; + } + halbtc8812a1ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); + + pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; +} + +VOID +halbtc8812a1ant_SetFwPstdma( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte byte1, + IN u1Byte byte2, + IN u1Byte byte3, + IN u1Byte byte4, + IN u1Byte byte5 + ) +{ + u1Byte H2C_Parameter[5] ={0}; + + H2C_Parameter[0] = byte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = byte5; + + pCoexDm->psTdmaPara[0] = byte1; + pCoexDm->psTdmaPara[1] = byte2; + pCoexDm->psTdmaPara[2] = byte3; + pCoexDm->psTdmaPara[3] = byte4; + pCoexDm->psTdmaPara[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x60(5bytes)=0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x60, 5, H2C_Parameter); +} + +VOID +halbtc8812a1ant_SetLpsRpwm( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + u1Byte lps=lpsVal; + u1Byte rpwm=rpwmVal; + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_LPS_VAL, &lps); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +VOID +halbtc8812a1ant_LpsRpwm( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + BOOLEAN bForceExecPwrCmd=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set lps/rpwm=0x%x/0x%x \n", + (bForceExec? "force to":""), lpsVal, rpwmVal)); + pCoexDm->curLps = lpsVal; + pCoexDm->curRpwm = rpwmVal; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preLps/curLps=0x%x/0x%x, preRpwm/curRpwm=0x%x/0x%x!!\n", + pCoexDm->preLps, pCoexDm->curLps, pCoexDm->preRpwm, pCoexDm->curRpwm)); + + if( (pCoexDm->preLps == pCoexDm->curLps) && + (pCoexDm->preRpwm == pCoexDm->curRpwm) ) + { + return; + } + } + halbtc8812a1ant_SetLpsRpwm(pBtCoexist, lpsVal, rpwmVal); + + pCoexDm->preLps = pCoexDm->curLps; + pCoexDm->preRpwm = pCoexDm->curRpwm; +} + +VOID +halbtc8812a1ant_SetAntPath( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte antPosType, + IN BOOLEAN bInitHwCfg, + IN BOOLEAN bWifiOff + ) +{ + u1Byte u1Tmp=0; + + if(bInitHwCfg) + { + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xcb3, 0x77); + + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x900, 0x00000400); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76d, 0x1); + } + else if(bWifiOff) + { + + } + + // ext switch setting + switch(antPosType) + { + case BTC_ANT_PATH_WIFI: + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xcb7); + u1Tmp |= BIT3; + u1Tmp &= ~BIT2; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xcb7, u1Tmp); + break; + case BTC_ANT_PATH_BT: + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xcb7); + u1Tmp &= ~BIT3; + u1Tmp |= BIT2; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xcb7, u1Tmp); + break; + default: + case BTC_ANT_PATH_PTA: + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xcb7); + u1Tmp |= BIT3; + u1Tmp &= ~BIT2; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xcb7, u1Tmp); + break; + } +} + +VOID +halbtc8812a1ant_PsTdma( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bTurnOn, + IN u1Byte type + ) +{ + BOOLEAN bTurnOnByCnt=FALSE; + u1Byte psTdmaTypeByCnt=0, rssiAdjustVal=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type=%d\n", + (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); + pCoexDm->bCurPsTdmaOn = bTurnOn; + pCoexDm->curPsTdma = type; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + pCoexDm->bPrePsTdmaOn, pCoexDm->bCurPsTdmaOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + pCoexDm->prePsTdma, pCoexDm->curPsTdma)); + + if( (pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && + (pCoexDm->prePsTdma == pCoexDm->curPsTdma) ) + return; + } + if(bTurnOn) + { + switch(type) + { + default: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x1a, 0x1a, 0x0, 0x50); + break; + case 1: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x1a, 0x1a, 0x0, 0x50); + rssiAdjustVal = 11; + break; + case 2: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x12, 0x12, 0x0, 0x50); + rssiAdjustVal = 14; + break; + case 3: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x40); + break; + case 4: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x14, 0x0); + rssiAdjustVal = 17; + break; + case 5: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x61, 0x15, 0x3, 0x31, 0x0); + break; + case 6: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0x3, 0x0, 0x0); + break; + case 7: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x13, 0xc, 0x5, 0x0, 0x0); + break; + case 8: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x0); + break; + case 9: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xd3, 0xa, 0xa, 0x0, 0x50); + rssiAdjustVal = 18; + break; + case 10: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0xa, 0x0, 0x40); + break; + case 11: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x5, 0x5, 0x0, 0x50); + rssiAdjustVal = 20; + break; + case 12: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xeb, 0xa, 0x3, 0x31, 0x18); + break; + + case 15: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0x3, 0x8, 0x0); + break; + case 16: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x10, 0x0); + rssiAdjustVal = 18; + break; + + case 18: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x0); + rssiAdjustVal = 14; + break; + + case 20: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x13, 0x25, 0x25, 0x0, 0x0); + break; + case 21: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x93, 0x20, 0x3, 0x10, 0x40); + break; + case 22: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x13, 0x8, 0x8, 0x0, 0x40); + break; + case 23: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 24: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x15, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 25: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 26: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 27: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x3, 0x31, 0x98); + rssiAdjustVal = 22; + break; + case 28: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x69, 0x25, 0x3, 0x31, 0x0); + break; + case 29: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xab, 0x1a, 0x1a, 0x1, 0x10); + break; + case 30: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x14, 0x0); + break; + case 31: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x1a, 0x1a, 0, 0x58); + break; + case 32: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xab, 0xa, 0x3, 0x31, 0x90); + break; + case 33: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xa3, 0x25, 0x3, 0x30, 0x90); + break; + case 34: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x1a, 0x1a, 0x0, 0x10); + break; + case 35: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x0, 0x10); + break; + case 36: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x12, 0x3, 0x14, 0x50); + break; + case 37: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x53, 0x25, 0x3, 0x10, 0x50); + break; + } + } + else + { + // disable PS tdma + switch(type) + { + case 8: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x8, 0x0, 0x0, 0x0, 0x0); + halbtc8812a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_PTA, FALSE, FALSE); + break; + case 0: + default: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + halbtc8812a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, FALSE); + break; + case 9: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + halbtc8812a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_WIFI, FALSE, FALSE); + break; + case 10: + halbtc8812a1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x8, 0x0); + halbtc8812a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, FALSE); + break; + } + } + rssiAdjustVal =0; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssiAdjustVal); + + // update pre state + pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; + pCoexDm->prePsTdma = pCoexDm->curPsTdma; +} + +VOID +halbtc8812a1ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + // hw all off + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +BOOLEAN +halbtc8812a1ant_IsCommonAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bCommon=FALSE, bWifiConnected=FALSE, bWifiBusy=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + + if(!bWifiConnected && + BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n")); + + bCommon = TRUE; + } + else if(bWifiConnected && + (BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT non connected-idle!!\n")); + + bCommon = TRUE; + } + else if(!bWifiConnected && + (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT connected-idle!!\n")); + + bCommon = TRUE; + } + else if(bWifiConnected && + (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT connected-idle!!\n")); + + bCommon = TRUE; + } + else if(!bWifiConnected && + (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE != pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT Busy!!\n")); + + bCommon = TRUE; + } + else + { + bCommon = FALSE; + } + + return bCommon; +} + + +VOID +halbtc8812a1ant_TdmaDurationAdjustForAcl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0, btInfoExt; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjustForAcl()\n")); + + if( (BT_8812A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) || + (BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifiStatus) || + (BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifiStatus) ) + { + if( pCoexDm->curPsTdma != 1 && + pCoexDm->curPsTdma != 2 && + pCoexDm->curPsTdma != 3 && + pCoexDm->curPsTdma != 9 ) + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + return; + } + + if(pCoexDm->bResetTdmaAdjust) + { + pCoexDm->bResetTdmaAdjust = FALSE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); + + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + btInfoExt = pCoexSta->btInfoExt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n", + up, dn, m, n, WaitCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if �s�� n ��2�� retry count��0, �h�ռeWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration + { + if (WaitCount <= 2) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration + { + if (WaitCount == 1) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + if(result == -1) + { + if( (BT_INFO_8812A_1ANT_A2DP_BASIC_RATE(btInfoExt)) && + ((pCoexDm->curPsTdma == 1) ||(pCoexDm->curPsTdma == 2)) ) + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + else if(result == 1) + { + if( (BT_INFO_8812A_1ANT_A2DP_BASIC_RATE(btInfoExt)) && + ((pCoexDm->curPsTdma == 1) ||(pCoexDm->curPsTdma == 2)) ) + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + } + + if( pCoexDm->curPsTdma != 1 && + pCoexDm->curPsTdma != 2 && + pCoexDm->curPsTdma != 9 && + pCoexDm->curPsTdma != 11 ) + { + // recover to previous adjust type + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, pCoexDm->psTdmaDuAdjType); + } + } +} + +u1Byte +halbtc8812a1ant_PsTdmaTypeByWifiRssi( + IN s4Byte wifiRssi, + IN s4Byte preWifiRssi, + IN u1Byte wifiRssiThresh + ) +{ + u1Byte psTdmaType=0; + + if(wifiRssi > preWifiRssi) + { + if(wifiRssi > (wifiRssiThresh+5)) + { + psTdmaType = 26; + } + else + { + psTdmaType = 25; + } + } + else + { + if(wifiRssi > wifiRssiThresh) + { + psTdmaType = 26; + } + else + { + psTdmaType = 25; + } + } + + return psTdmaType; +} + +VOID +halbtc8812a1ant_PsTdmaCheckForPowerSaveState( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bNewPsState + ) +{ + u1Byte lpsMode=0x0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_LPS_MODE, &lpsMode); + + if(lpsMode) // already under LPS state + { + if(bNewPsState) + { + // keep state under LPS, do nothing. + } + else + { + // will leave LPS state, turn off psTdma first + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + } + else // NO PS state + { + if(bNewPsState) + { + // will enter LPS state, turn off psTdma first + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + // keep state under NO PS state, do nothing. + } + } +} + +VOID +halbtc8812a1ant_PowerSaveState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte psType, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + BOOLEAN bLowPwrDisable=FALSE; + + switch(psType) + { + case BTC_PS_WIFI_NATIVE: + // recover to original 32k low power setting + bLowPwrDisable = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + break; + case BTC_PS_LPS_ON: + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(pBtCoexist, TRUE); + halbtc8812a1ant_LpsRpwm(pBtCoexist, NORMAL_EXEC, lpsVal, rpwmVal); + // when coex force to enter LPS, do not enter 32k low power. + bLowPwrDisable = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + // power save must executed before psTdma. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_ENTER_LPS, NULL); + break; + case BTC_PS_LPS_OFF: + halbtc8812a1ant_PsTdmaCheckForPowerSaveState(pBtCoexist, FALSE); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + break; + default: + break; + } +} + + +VOID +halbtc8812a1ant_CoexUnder5G( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 10); + + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +VOID +halbtc8812a1ant_ActionWifiOnly( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); +} + +VOID +halbtc8812a1ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtActive=TRUE, bBtDisabled=FALSE; + + // only 8812a need to consider if core stack is installed. + if(!pStackInfo->hciVersion) + { + bBtActive = FALSE; + } + + // This function check if bt is disabled + + if( pCoexSta->highPriorityTx == 0 && + pCoexSta->highPriorityRx == 0 && + pCoexSta->lowPriorityTx == 0 && + pCoexSta->lowPriorityRx == 0) + { + bBtActive = FALSE; + } + if( pCoexSta->highPriorityTx == 0xffff && + pCoexSta->highPriorityRx == 0xffff && + pCoexSta->lowPriorityTx == 0xffff && + pCoexSta->lowPriorityRx == 0xffff) + { + bBtActive = FALSE; + } + if(bBtActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + halbtc8812a1ant_ActionWifiOnly(pBtCoexist); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + bPreBtDisabled = bBtDisabled; + if(!bBtDisabled) + { + } + else + { + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + } + } +} + +//============================================= +// +// Software Coex Mechanism start +// +//============================================= + +// SCO only or SCO+PAN(HS) +VOID +halbtc8812a1ant_ActionSco( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +VOID +halbtc8812a1ant_ActionHid( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +//A2DP only / PAN(EDR) only/ A2DP+PAN(HS) +VOID +halbtc8812a1ant_ActionA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +VOID +halbtc8812a1ant_ActionA2dpPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +VOID +halbtc8812a1ant_ActionPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +//PAN(HS) only +VOID +halbtc8812a1ant_ActionPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +//PAN(EDR)+A2DP +VOID +halbtc8812a1ant_ActionPanEdrA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +VOID +halbtc8812a1ant_ActionPanEdrHid( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +// HID+A2DP+PAN(EDR) +VOID +halbtc8812a1ant_ActionHidA2dpPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +VOID +halbtc8812a1ant_ActionHidA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ +} + +//============================================= +// +// Non-Software Coex Mechanism start +// +//============================================= + +VOID +halbtc8812a1ant_ActionHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bHsConnecting=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_CONNECTING, &bHsConnecting); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action for HS, bHsConnecting=%d!!!\n", bHsConnecting)); + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + + if(bHsConnecting) + { + halbtc8812a1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 3); + } + else + { + if((pCoexSta->highPriorityTx+pCoexSta->highPriorityRx+ + pCoexSta->lowPriorityTx+pCoexSta->lowPriorityRx)<=1200) + halbtc8812a1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 3); + else + halbtc8812a1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 4); + } +} + +VOID +halbtc8812a1ant_ActionBtInquiry( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bWifiConnected=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + if(!bWifiConnected) + { + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } + else if( (pBtLinkInfo->bScoExist) || + (pBtLinkInfo->bHidOnly) ) + { + // SCO/HID-only busy + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 32); + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + else + { + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x0); + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 30); + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } +} + +VOID +halbtc8812a1ant_ActionBtScoHidOnlyBusy( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + // tdma and coex table + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + + if(BT_8812A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + else + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); +} + +VOID +halbtc8812a1ant_ActionWifiConnectedBtAclBusy( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + + if(pBtLinkInfo->bHidOnly) + { + halbtc8812a1ant_ActionBtScoHidOnlyBusy(pBtCoexist, wifiStatus); + pCoexDm->bResetTdmaAdjust = TRUE; + return; + } + else if( (pBtLinkInfo->bA2dpOnly) || + (pBtLinkInfo->bHidExist&&pBtLinkInfo->bA2dpExist) ) + { + halbtc8812a1ant_TdmaDurationAdjustForAcl(pBtCoexist, wifiStatus); + } + else if( (pBtLinkInfo->bPanOnly) || + (pBtLinkInfo->bHidExist&&pBtLinkInfo->bPanExist) ) + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->bResetTdmaAdjust = TRUE; + } + else + { + if( (BT_8812A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) || + (BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifiStatus) || + (BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifiStatus) ) + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + else + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->bResetTdmaAdjust = TRUE; + } + + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); +} + +VOID +halbtc8812a1ant_ActionWifiNotConnected( + IN PBTC_COEXIST pBtCoexist + ) +{ + // power save state + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +VOID +halbtc8812a1ant_ActionWifiNotConnectedAssoAuthScan( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); +} + +VOID +halbtc8812a1ant_ActionWifiConnectedScan( + IN PBTC_COEXIST pBtCoexist + ) +{ + // power save state + if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && !pBtCoexist->btLinkInfo.bHidOnly) + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x0); + else + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8812a1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } + else if( (BT_8812A_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8812a1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } + else + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } +} + +VOID +halbtc8812a1ant_ActionWifiConnectedSpecialPacket( + IN PBTC_COEXIST pBtCoexist + ) +{ + // power save state + if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && !pBtCoexist->btLinkInfo.bHidOnly) + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x0); + else + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8812a1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT); + } + else + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } +} + +VOID +halbtc8812a1ant_ActionWifiConnected( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiConnected=FALSE, bWifiBusy=FALSE; + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + BOOLEAN bUnder4way=FALSE; + u4Byte wifiBw; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect()===>\n")); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(!bWifiConnected) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi not connected<===\n")); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); + if(bUnder4way) + { + halbtc8812a1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n")); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + if(bScan || bLink || bRoam) + { + halbtc8812a1ant_ActionWifiConnectedScan(pBtCoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n")); + return; + } + + // power save state + if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && !pBtCoexist->btLinkInfo.bHidOnly) + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x0); + else + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + if(!bWifiBusy) + { + if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8812a1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } + else if( (BT_8812A_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8812a1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } + else + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + } + else + { + if(BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + else if(BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + else if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8812a1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } + else if( (BT_8812A_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8812a1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } + else + { + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8812a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + } +} + +VOID +halbtc8812a1ant_RunSwCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiUnder5G=FALSE, bWifiBusy=FALSE, bWifiConnected=FALSE; + u1Byte btInfoOriginal=0, btRetryCnt=0; + u1Byte algorithm=0; + + return; + + algorithm = halbtc8812a1ant_ActionAlgorithm(pBtCoexist); + pCoexDm->curAlgorithm = algorithm; + + if(halbtc8812a1ant_IsCommonAction(pBtCoexist)) + { + } + else + { + switch(pCoexDm->curAlgorithm) + { + case BT_8812A_1ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = SCO.\n")); + halbtc8812a1ant_ActionSco(pBtCoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID.\n")); + halbtc8812a1ant_ActionHid(pBtCoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP.\n")); + halbtc8812a1ant_ActionA2dp(pBtCoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP+PAN(HS).\n")); + halbtc8812a1ant_ActionA2dpPanHs(pBtCoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR).\n")); + halbtc8812a1ant_ActionPanEdr(pBtCoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HS mode.\n")); + halbtc8812a1ant_ActionPanHs(pBtCoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN+A2DP.\n")); + halbtc8812a1ant_ActionPanEdrA2dp(pBtCoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR)+HID.\n")); + halbtc8812a1ant_ActionPanEdrHid(pBtCoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP+PAN.\n")); + halbtc8812a1ant_ActionHidA2dpPanEdr(pBtCoexist); + break; + case BT_8812A_1ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP.\n")); + halbtc8812a1ant_ActionHidA2dp(pBtCoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = coexist All Off!!\n")); + halbtc8812a1ant_CoexAllOff(pBtCoexist); + break; + } + pCoexDm->preAlgorithm = pCoexDm->curAlgorithm; + } +} + +VOID +halbtc8812a1ant_RunCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiUnder5G=FALSE, bWifiBusy=FALSE, bWifiConnected=FALSE, bBtHsOn=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism()===>\n")); + + if(pBtCoexist->bManualControl) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n")); + return; + } + + if(pBtCoexist->bStopCoexDm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n")); + return; + } + + if(pCoexSta->bUnderIps) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under IPS !!!\n")); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + if(bWifiUnder5G) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), run 5G coex setting!!<===\n")); + halbtc8812a1ant_CoexUnder5G(pBtCoexist); + return; + } + + halbtc8812a1ant_RunSwCoexistMechanism(pBtCoexist); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8812a1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8812a1ant_ActionHs(pBtCoexist); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(!bWifiConnected) + { + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is non connected-idle !!!\n")); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if(bScan || bLink || bRoam) + halbtc8812a1ant_ActionWifiNotConnectedAssoAuthScan(pBtCoexist); + else + halbtc8812a1ant_ActionWifiNotConnected(pBtCoexist); + } + else // wifi LPS/Busy + { + halbtc8812a1ant_ActionWifiConnected(pBtCoexist); + } +} + +VOID +halbtc8812a1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + // force to reset coex mechanism + halbtc8812a1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 8); + halbtc8812a1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); +} + +//============================================================ +// work around function start with wa_halbtc8812a1ant_ +//============================================================ +//============================================================ +// extern function start with EXhalbtc8812a1ant_ +//============================================================ +VOID +EXhalbtc8812a1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte u4Tmp=0; + u2Byte u2Tmp=0; + u1Byte u1Tmp=0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 1Ant Init HW Config!!\n")); + + //ant sw control to BT + halbtc8812a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, TRUE, FALSE); + + // 0x790[5:0]=0x5 + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x790); + u1Tmp &= 0xc0; + u1Tmp |= 0x5; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x790, u1Tmp); + + // PTA parameter + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, 0x0); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, 0xffff); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, 0x55555555); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, 0x55555555); + + // coex parameters + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x778, 0x1); + + // enable counter statistics + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); + + // enable PTA + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x20); + + // bt clock related + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x4); + u1Tmp |= BIT7; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x4, u1Tmp); + + // bt clock related + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x7); + u1Tmp |= BIT1; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x7, u1Tmp); +} + +VOID +EXhalbtc8812a1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + pBtCoexist->bStopCoexDm = FALSE; + + halbtc8812a1ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8812a1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + pu1Byte cliBuf=pBtCoexist->cliBuf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir; + u1Byte wifiDot11Chnl, wifiHsChnl; + u4Byte fwVer=0, btPatchVer=0; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(pBtCoexist->bManualControl) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cliBuf); + } + if(pBtCoexist->bStopCoexDm) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cliBuf); + } + + if(!pBoardInfo->bBtExist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", \ + GLCoexVerDate8812a1Ant, GLCoexVer8812a1Ant, fwVer, btPatchVer, btPatchVer); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ + wifiDot11Chnl, wifiHsChnl, bBtHsOn); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], + pCoexDm->wifiChnlInfo[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((pBtCoexist->btInfo.bBtDisabled)? ("disabled"): ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus)? "non-connected idle": + ( (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy")))), + pCoexSta->btRssi, pCoexSta->btRetryCnt); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pBtLinkInfo->bScoExist, pBtLinkInfo->bHidExist, pBtLinkInfo->bPanExist, pBtLinkInfo->bA2dpExist); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + + btInfoExt = pCoexSta->btInfoExt; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (btInfoExt&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cliBuf); + + for(i=0; i<BT_INFO_SRC_8812A_1ANT_MAX; i++) + { + if(pCoexSta->btInfoC2hCnt[i]) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8812a1Ant[i], \ + pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], + pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], + pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], + pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); + CL_PRINTF(cliBuf); + } + } + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s, (0x%x/0x%x)", "PS state, IPS/LPS, (lps/rpwm)", \ + ((pCoexSta->bUnderIps? "IPS ON":"IPS OFF")), + ((pCoexSta->bUnderLps? "LPS ON":"LPS OFF")), + pBtCoexist->btInfo.lpsVal, + pBtCoexist->btInfo.rpwmVal); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + if(!pBtCoexist->bManualControl) + { + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %d ", "DelBA/ BtCtrlAgg/ AggSize", \ + (pBtCoexist->btInfo.bRejectAggPkt? "Yes":"No"), (pBtCoexist->btInfo.bBtCtrlAggBufSize? "Yes":"No"), + pBtCoexist->btInfo.aggBufSize); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask", \ + pBtCoexist->btInfo.raMask); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + psTdmaCase = pCoexDm->curPsTdma; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d", "PS TDMA", \ + pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], + pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], + pCoexDm->psTdmaPara[4], psTdmaCase); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Latest error condition(should be 0)", \ + pCoexDm->errorCondition); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "IgnWlanAct", \ + pCoexDm->bCurIgnoreWlanAct); + CL_PRINTF(cliBuf); + } + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x778); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x778", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xcb3); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xcb7); + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x900); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0xcb3/0xcb7/0x900", \ + u1Tmp[0], u1Tmp[1], u4Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x40", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x550); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x522); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \ + u4Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp[0]); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770(hp rx[31:16]/tx[15:0])", \ + pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(lp rx[31:16]/tx[15:0])", \ + pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8812a1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u4Byte u4Tmp=0; + + if(pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm) + return; + + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + pCoexSta->bUnderIps = TRUE; + halbtc8812a1ant_CoexAllOff(pBtCoexist); + halbtc8812a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, TRUE); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + pCoexSta->bUnderIps = FALSE; + } +} + +VOID +EXhalbtc8812a1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm) + return; + + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + pCoexSta->bUnderLps = TRUE; + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + pCoexSta->bUnderLps = FALSE; + } +} + +VOID +EXhalbtc8812a1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8812a1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8812a1ant_ActionHs(pBtCoexist); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + if(!bWifiConnected) // non-connected scan + { + halbtc8812a1ant_ActionWifiNotConnectedAssoAuthScan(pBtCoexist); + } + else // wifi is connected + { + halbtc8812a1ant_ActionWifiConnectedScan(pBtCoexist); + } + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + if(!bWifiConnected) // non-connected scan + { + halbtc8812a1ant_ActionWifiNotConnected(pBtCoexist); + } + else + { + halbtc8812a1ant_ActionWifiConnected(pBtCoexist); + } + } +} + +VOID +EXhalbtc8812a1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8812a1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8812a1ant_ActionHs(pBtCoexist); + return; + } + + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + halbtc8812a1ant_ActionWifiNotConnectedAssoAuthScan(pBtCoexist); + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(!bWifiConnected) // non-connected scan + { + halbtc8812a1ant_ActionWifiNotConnected(pBtCoexist); + } + else + { + halbtc8812a1ant_ActionWifiConnected(pBtCoexist); + } + } +} + +VOID +EXhalbtc8812a1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u1Byte dataLen=5; + u1Byte buf[6] = {0}; + u1Byte H2C_Parameter[3] ={0}; + u4Byte wifiBw; + u1Byte wifiCentralChnl; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } + + // only 2.4G we need to inform bt the chnl mask + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); + if( (BTC_MEDIA_CONNECT == type) && + (wifiCentralChnl <= 14) ) + { + H2C_Parameter[0] = 0x1; + H2C_Parameter[1] = wifiCentralChnl; + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + H2C_Parameter[2] = 0x30; + else + H2C_Parameter[2] = 0x20; + } + + pCoexDm->wifiChnlInfo[0] = H2C_Parameter[0]; + pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1]; + pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2]; + + buf[0] = dataLen; + buf[1] = 0x5; // OP_Code + buf[2] = 0x3; // OP_Code_Length + buf[3] = H2C_Parameter[0]; // OP_Code_Content + buf[4] = H2C_Parameter[1]; + buf[5] = H2C_Parameter[2]; + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); +} + +VOID +EXhalbtc8812a1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bBtHsOn=FALSE; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8812a1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8812a1ant_ActionHs(pBtCoexist); + return; + } + + if( BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type ) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], special Packet(%d) notify\n", type)); + halbtc8812a1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); + } +} + +VOID +EXhalbtc8812a1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + u1Byte btInfo=0; + u1Byte i, rspSource=0; + static u4Byte setBtPsdMode=0; + BOOLEAN bBtBusy=FALSE; + BOOLEAN bWifiConnected=FALSE; + BOOLEAN bBtCtrlAggBufSize=FALSE, bRejApAggPkt=FALSE; + + rspSource = tmpBuf[0]&0xf; + if(rspSource >= BT_INFO_SRC_8812A_1ANT_MAX) + rspSource = BT_INFO_SRC_8812A_1ANT_WIFI_FW; + pCoexSta->btInfoC2hCnt[rspSource]++; + + if(BT_INFO_SRC_8812A_1ANT_BT_RSP == rspSource) + pCoexSta->btInfoQueryCnt = pCoexSta->btInfoC2hCnt[BT_INFO_SRC_8812A_1ANT_BT_RSP]; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rspSource, length)); + for(i=0; i<length; i++) + { + pCoexSta->btInfoC2h[rspSource][i] = tmpBuf[i]; + if(i == 1) + btInfo = tmpBuf[i]; + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); + } + } + + if(pBtCoexist->btInfo.bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for BT is disabled <===\n")); + return; + } + + if(pBtCoexist->bManualControl) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for Manual CTRL<===\n")); + return; + } + if(pBtCoexist->bStopCoexDm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), return for Coex STOPPED!!<===\n")); + return; + } + + if(BT_INFO_SRC_8812A_1ANT_WIFI_FW != rspSource) + { + pCoexSta->btRetryCnt = // [3:0] + pCoexSta->btInfoC2h[rspSource][2]&0xf; + + pCoexSta->btRssi = + pCoexSta->btInfoC2h[rspSource][3]*2+10; + + pCoexSta->btInfoExt = + pCoexSta->btInfoC2h[rspSource][4]; + + // Here we need to resend some wifi info to BT + // because bt is reset and loss of the info. + if( (pCoexSta->btInfoExt & BIT1) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n")); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(bWifiConnected) + { + EXhalbtc8812a1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_CONNECT); + } + else + { + EXhalbtc8812a1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); + } + + setBtPsdMode = 0; + } + + // test-chip bt patch only rsp the status for BT_RSP, + // so temporary we consider the following only under BT_RSP + if(BT_INFO_SRC_8812A_1ANT_BT_RSP == rspSource) + { + if( (pCoexSta->btInfoExt & BIT3) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n")); + halbtc8812a1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); + } + else + { + // BT already NOT ignore Wlan active, do nothing here. + } + + if( (pCoexSta->btInfoExt & BIT4) ) + { + // BT auto report already enabled, do nothing + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit4 check, set BT to enable Auto Report!!\n")); + halbtc8812a1ant_BtAutoReport(pBtCoexist, FORCE_EXEC, TRUE); + } + } + } + + // check BIT2 first ==> check if bt is under inquiry or page scan + if(btInfo & BT_INFO_8812A_1ANT_B_INQ_PAGE) + pCoexSta->bC2hBtInquiryPage = TRUE; + else + pCoexSta->bC2hBtInquiryPage = FALSE; + + // set link exist status + if(!(btInfo&BT_INFO_8812A_1ANT_B_CONNECTION)) + { + pCoexSta->bBtLinkExist = FALSE; + pCoexSta->bPanExist = FALSE; + pCoexSta->bA2dpExist = FALSE; + pCoexSta->bHidExist = FALSE; + pCoexSta->bScoExist = FALSE; + } + else // connection exists + { + pCoexSta->bBtLinkExist = TRUE; + if(btInfo & BT_INFO_8812A_1ANT_B_FTP) + pCoexSta->bPanExist = TRUE; + else + pCoexSta->bPanExist = FALSE; + if(btInfo & BT_INFO_8812A_1ANT_B_A2DP) + pCoexSta->bA2dpExist = TRUE; + else + pCoexSta->bA2dpExist = FALSE; + if(btInfo & BT_INFO_8812A_1ANT_B_HID) + pCoexSta->bHidExist = TRUE; + else + pCoexSta->bHidExist = FALSE; + if(btInfo & BT_INFO_8812A_1ANT_B_SCO_ESCO) + pCoexSta->bScoExist = TRUE; + else + pCoexSta->bScoExist = FALSE; + } + + halbtc8812a1ant_UpdateBtLinkInfo(pBtCoexist); + + if(!(btInfo&BT_INFO_8812A_1ANT_B_CONNECTION)) + { + pCoexDm->btStatus = BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt non-connected idle!!!\n")); + } + else if(btInfo == BT_INFO_8812A_1ANT_B_CONNECTION) // connection exists but no busy + { + pCoexDm->btStatus = BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt connected-idle!!!\n")); + } + else if((btInfo&BT_INFO_8812A_1ANT_B_SCO_ESCO) || + (btInfo&BT_INFO_8812A_1ANT_B_SCO_BUSY)) + { + pCoexDm->btStatus = BT_8812A_1ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt sco busy!!!\n")); + } + else if(btInfo&BT_INFO_8812A_1ANT_B_ACL_BUSY) + { + if(BT_8812A_1ANT_BT_STATUS_ACL_BUSY != pCoexDm->btStatus) + pCoexDm->bResetTdmaAdjust = TRUE; + pCoexDm->btStatus = BT_8812A_1ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt acl busy!!!\n")); + } + else + { + pCoexDm->btStatus = BT_8812A_1ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), bt non-defined state!!!\n")); + } + + if(pBtLinkInfo->bScoExist) + { + bRejApAggPkt = TRUE; + halbtc8812a1ant_UpdateRaMask(pBtCoexist, NORMAL_EXEC, BTC_RATE_DISABLE, 0x00000003); // disable cck 1M2M. + } + else + { + halbtc8812a1ant_UpdateRaMask(pBtCoexist, NORMAL_EXEC, BTC_RATE_ENABLE, 0x00000003); // enable cck 1M2M. + } + + if( (BT_8812A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || + (BT_8812A_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + bBtBusy = TRUE; + if(pBtLinkInfo->bHidExist) + bBtCtrlAggBufSize = TRUE; + } + else + { + bBtBusy = FALSE; + } + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + + //============================================ + // Aggregation related setting + //============================================ + // if sco, reject AddBA + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &bRejApAggPkt); + // decide BT control aggregation buf size or not + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, &bBtCtrlAggBufSize); + // real update aggregation setting + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + //============================================ + + halbtc8812a1ant_RunCoexistMechanism(pBtCoexist); +} + +VOID +EXhalbtc8812a1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + halbtc8812a1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + halbtc8812a1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 0); + halbtc8812a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, TRUE); + EXhalbtc8812a1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8812a1ant_PnpNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pnpState + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify\n")); + + if(BTC_WIFI_PNP_SLEEP == pnpState) + { + pBtCoexist->bStopCoexDm = TRUE; + halbtc8812a1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + } + else if(BTC_WIFI_PNP_WAKE_UP == pnpState) + { + + } +} + +VOID +EXhalbtc8812a1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + static u1Byte disVerInfoCnt=0; + u4Byte fwVer=0, btPatchVer=0; + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ==========================Periodical===========================\n")); + + if(disVerInfoCnt <= 5) + { + disVerInfoCnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum, pBoardInfo->btdmAntPos)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], BT stack/ hci ext ver = %s / %d\n", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion)); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", \ + GLCoexVerDate8812a1Ant, GLCoexVer8812a1Ant, fwVer, btPatchVer, btPatchVer)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + } + + halbtc8812a1ant_QueryBtInfo(pBtCoexist); + halbtc8812a1ant_MonitorBtCtr(pBtCoexist); + halbtc8812a1ant_MonitorBtEnableDisable(pBtCoexist); +} + +VOID +EXhalbtc8812a1ant_DbgControl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte opCode, + IN u1Byte opLen, + IN pu1Byte pData + ) +{ + switch(opCode) + { + case BTC_DBG_SET_COEX_NORMAL: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set CoexMode to Normal\n")); + pBtCoexist->bManualControl = FALSE; + halbtc8812a1ant_InitCoexDm(pBtCoexist); + break; + case BTC_DBG_SET_COEX_WIFI_ONLY: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set CoexMode to Wifi Only\n")); + pBtCoexist->bManualControl = TRUE; + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + break; + case BTC_DBG_SET_COEX_BT_ONLY: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set CoexMode to BT only\n")); + pBtCoexist->bManualControl = TRUE; + halbtc8812a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + break; + case BTC_DBG_SET_COEX_DEC_BT_PWR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set Dec BT power\n")); + { + u1Byte dataLen=4; + u1Byte buf[6] = {0}; + u1Byte decBtPwr=0, pwrLevel=0; + if(opLen == 2) + { + decBtPwr = pData[0]; + pwrLevel = pData[1]; + + buf[0] = dataLen; + buf[1] = 0x3; // OP_Code + buf[2] = 0x2; // OP_Code_Length + + buf[3] = decBtPwr; // OP_Code_Content + buf[4] = pwrLevel; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set Dec BT power=%d, pwrLevel=%d\n", decBtPwr, pwrLevel)); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); + } + } + break; + + case BTC_DBG_SET_COEX_BT_AFH_MAP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set BT AFH Map\n")); + { + u1Byte dataLen=5; + u1Byte buf[6] = {0}; + if(opLen == 3) + { + buf[0] = dataLen; + buf[1] = 0x5; // OP_Code + buf[2] = 0x3; // OP_Code_Length + + buf[3] = pData[0]; // OP_Code_Content + buf[4] = pData[1]; + buf[5] = pData[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set BT AFH Map = %02x %02x %02x\n", + pData[0], pData[1], pData[2])); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); + } + } + break; + + case BTC_DBG_SET_COEX_BT_IGNORE_WLAN_ACT: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set BT Ignore Wlan Active\n")); + { + u1Byte dataLen=3; + u1Byte buf[6] = {0}; + if(opLen == 1) + { + buf[0] = dataLen; + buf[1] = 0x1; // OP_Code + buf[2] = 0x1; // OP_Code_Length + + buf[3] = pData[0]; // OP_Code_Content + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set BT Ignore Wlan Active = 0x%x\n", + pData[0])); + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); + } + } + break; + default: + break; + } +} +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a1Ant.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a1Ant.h new file mode 100644 index 0000000..8517c6f --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a1Ant.h @@ -0,0 +1,201 @@ +//=========================================== +// The following is for 8812A_1ANT BT Co-exist definition +//=========================================== +#define BT_INFO_8812A_1ANT_B_FTP BIT7 +#define BT_INFO_8812A_1ANT_B_A2DP BIT6 +#define BT_INFO_8812A_1ANT_B_HID BIT5 +#define BT_INFO_8812A_1ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8812A_1ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8812A_1ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8812A_1ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8812A_1ANT_B_CONNECTION BIT0 + +#define BT_INFO_8812A_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT0))? TRUE:FALSE) + +#define BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT 2 + +#define BTC_8812A_1ANT_SWITCH_TO_WIFI 0 +#define BTC_8812A_1ANT_SWITCH_TO_BT 1 + +typedef enum _BT_INFO_SRC_8812A_1ANT{ + BT_INFO_SRC_8812A_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8812A_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8812A_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8812A_1ANT_MAX +}BT_INFO_SRC_8812A_1ANT,*PBT_INFO_SRC_8812A_1ANT; + +typedef enum _BT_8812A_1ANT_BT_STATUS{ + BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8812A_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8812A_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8812A_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8812A_1ANT_BT_STATUS_MAX +}BT_8812A_1ANT_BT_STATUS,*PBT_8812A_1ANT_BT_STATUS; + +typedef enum _BT_8812A_1ANT_WIFI_STATUS{ + BT_8812A_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8812A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT = 0x3, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8812A_1ANT_WIFI_STATUS_MAX +}BT_8812A_1ANT_WIFI_STATUS,*PBT_8812A_1ANT_WIFI_STATUS; + +typedef enum _BT_8812A_1ANT_COEX_ALGO{ + BT_8812A_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8812A_1ANT_COEX_ALGO_SCO = 0x1, + BT_8812A_1ANT_COEX_ALGO_HID = 0x2, + BT_8812A_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8812A_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8812A_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8812A_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8812A_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8812A_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8812A_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8812A_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8812A_1ANT_COEX_ALGO_MAX = 0xb, +}BT_8812A_1ANT_COEX_ALGO,*PBT_8812A_1ANT_COEX_ALGO; + +typedef struct _COEX_DM_8812A_1ANT{ + // fw mechanism + BOOLEAN bCurIgnoreWlanAct; + BOOLEAN bPreIgnoreWlanAct; + u1Byte prePsTdma; + u1Byte curPsTdma; + u1Byte psTdmaPara[5]; + u1Byte psTdmaDuAdjType; + BOOLEAN bResetTdmaAdjust; + BOOLEAN bPrePsTdmaOn; + BOOLEAN bCurPsTdmaOn; + BOOLEAN bPreBtAutoReport; + BOOLEAN bCurBtAutoReport; + u1Byte preLps; + u1Byte curLps; + u1Byte preRpwm; + u1Byte curRpwm; + + // sw mechanism + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + BOOLEAN bPreDacSwingOn; + u4Byte preVal0x6c0; + u4Byte curVal0x6c0; + u4Byte preVal0x6c4; + u4Byte curVal0x6c4; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u1Byte preVal0x6cc; + u1Byte curVal0x6cc; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + u1Byte btStatus; + u1Byte wifiChnlInfo[3]; + + u4Byte preRaMask; + u4Byte curRaMask; + + u1Byte errorCondition; +} COEX_DM_8812A_1ANT, *PCOEX_DM_8812A_1ANT; + +typedef struct _COEX_STA_8812A_1ANT{ + BOOLEAN bBtLinkExist; + BOOLEAN bScoExist; + BOOLEAN bA2dpExist; + BOOLEAN bHidExist; + BOOLEAN bPanExist; + + BOOLEAN bUnderLps; + BOOLEAN bUnderIps; + u4Byte highPriorityTx; + u4Byte highPriorityRx; + u4Byte lowPriorityTx; + u4Byte lowPriorityRx; + u1Byte btRssi; + u1Byte preBtRssiState; + u1Byte preWifiRssiState[4]; + BOOLEAN bC2hBtInfoReqSent; + u1Byte btInfoC2h[BT_INFO_SRC_8812A_1ANT_MAX][10]; + u4Byte btInfoC2hCnt[BT_INFO_SRC_8812A_1ANT_MAX]; + u4Byte btInfoQueryCnt; + BOOLEAN bC2hBtInquiryPage; + u1Byte btRetryCnt; + u1Byte btInfoExt; +}COEX_STA_8812A_1ANT, *PCOEX_STA_8812A_1ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8812a1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8812a1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8812a1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8812a1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8812a1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8812a1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8812a1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8812a1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8812a1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8812a1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8812a1ant_PnpNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pnpState + ); +VOID +EXhalbtc8812a1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8812a1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8812a1ant_DbgControl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte opCode, + IN u1Byte opLen, + IN pu1Byte pData + ); diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a2Ant.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a2Ant.c new file mode 100644 index 0000000..adf7be7 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a2Ant.c @@ -0,0 +1,4826 @@ +//============================================================ +// Description: +// +// This file is for RTL8812A Co-exist mechanism +// +// History +// 2012/08/22 Cosa first check in. +// 2012/11/14 Cosa Revise for 8812A 2Ant out sourcing. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8812A_2ANT GLCoexDm8812a2Ant; +static PCOEX_DM_8812A_2ANT pCoexDm=&GLCoexDm8812a2Ant; +static COEX_STA_8812A_2ANT GLCoexSta8812a2Ant; +static PCOEX_STA_8812A_2ANT pCoexSta=&GLCoexSta8812a2Ant; + +const char *const GLBtInfoSrc8812a2Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u4Byte GLCoexVerDate8812a2Ant=20131017; +u4Byte GLCoexVer8812a2Ant=0x36; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8812a2ant_ +//============================================================ +u1Byte +halbtc8812a2ant_BtRssiState( + u1Byte levelNum, + u1Byte rssiThresh, + u1Byte rssiThresh1 + ) +{ + s4Byte btRssi=0; + u1Byte btRssiState=pCoexSta->preBtRssiState; + + btRssi = pCoexSta->btRssi; + + if(levelNum == 2) + { + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi pre state=LOW\n")); + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi pre state=HIGH\n")); + if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); + return pCoexSta->preBtRssiState; + } + + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi pre state=LOW\n")); + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT)) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi pre state=MEDIUM\n")); + if(btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi pre state=HIGH\n")); + if(btRssi < rssiThresh1) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + + pCoexSta->preBtRssiState = btRssiState; + + return btRssiState; +} + +u1Byte +halbtc8812a2ant_WifiRssiState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte index, + IN u1Byte levelNum, + IN u1Byte rssiThresh, + IN u1Byte rssiThresh1 + ) +{ + s4Byte wifiRssi=0; + u1Byte wifiRssiState=pCoexSta->preWifiRssiState[index]; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(levelNum == 2) + { + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return pCoexSta->preWifiRssiState[index]; + } + + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifiRssi < rssiThresh1) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + pCoexSta->preWifiRssiState[index] = wifiRssiState; + + return wifiRssiState; +} + +VOID +halbtc8812a2ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtActive=TRUE, bBtDisabled=FALSE; + + // This function check if bt is disabled + + // only 8812a need to consider if core stack is installed. + if(!pStackInfo->hciVersion) + { + bBtActive = FALSE; + } + + if( pCoexSta->highPriorityTx == 0 && + pCoexSta->highPriorityRx == 0 && + pCoexSta->lowPriorityTx == 0 && + pCoexSta->lowPriorityRx == 0) + { + bBtActive = FALSE; + } + if( pCoexSta->highPriorityTx == 0xffff && + pCoexSta->highPriorityRx == 0xffff && + pCoexSta->lowPriorityTx == 0xffff && + pCoexSta->lowPriorityRx == 0xffff) + { + bBtActive = FALSE; + } + if(bBtActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt is detected as disabled %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + bPreBtDisabled = bBtDisabled; + if(!bBtDisabled) + { + } + else + { + } + } +} + +u4Byte +halbtc8812a2ant_DecideRaMask( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte raMaskType + ) +{ + u4Byte disRaMask=0x0; + + switch(raMaskType) + { + case 0: // normal mode + disRaMask = 0x0; + break; + case 1: // disable cck 1/2 + disRaMask = 0x00000003; + break; + case 2: // disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 + disRaMask = 0x0001f1f7; + break; + default: + break; + } + + return disRaMask; +} + +VOID +halbtc8812a2ant_UpdateRaMask( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte disRateMask + ) +{ + pCoexDm->curRaMask = disRateMask; + + if( bForceExec || (pCoexDm->preRaMask != pCoexDm->curRaMask)) + { + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_UPDATE_RAMASK, &pCoexDm->curRaMask); + } + pCoexDm->preRaMask = pCoexDm->curRaMask; +} + +VOID +halbtc8812a2ant_AutoRateFallbackRetry( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + BOOLEAN bWifiUnderBMode=FALSE; + + pCoexDm->curArfrType = type; + + if( bForceExec || (pCoexDm->preArfrType != pCoexDm->curArfrType)) + { + switch(pCoexDm->curArfrType) + { + case 0: // normal mode + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, pCoexDm->backupArfrCnt1); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, pCoexDm->backupArfrCnt2); + break; + case 1: + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, &bWifiUnderBMode); + if(bWifiUnderBMode) + { + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, 0x0); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, 0x01010101); + } + else + { + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, 0x0); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, 0x04030201); + } + break; + default: + break; + } + } + + pCoexDm->preArfrType = pCoexDm->curArfrType; +} + +VOID +halbtc8812a2ant_RetryLimit( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + pCoexDm->curRetryLimitType = type; + + if( bForceExec || (pCoexDm->preRetryLimitType != pCoexDm->curRetryLimitType)) + { + switch(pCoexDm->curRetryLimitType) + { + case 0: // normal mode + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x42a, pCoexDm->backupRetryLimit); + break; + case 1: // retry limit=8 + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x42a, 0x0808); + break; + default: + break; + } + } + + pCoexDm->preRetryLimitType = pCoexDm->curRetryLimitType; +} + +VOID +halbtc8812a2ant_AmpduMaxTime( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + pCoexDm->curAmpduTimeType = type; + + if( bForceExec || (pCoexDm->preAmpduTimeType != pCoexDm->curAmpduTimeType)) + { + switch(pCoexDm->curAmpduTimeType) + { + case 0: // normal mode + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x456, pCoexDm->backupAmpduMaxTime); + break; + case 1: // AMPDU timw = 0x38 * 32us + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x456, 0x38); + break; + default: + break; + } + } + + pCoexDm->preAmpduTimeType = pCoexDm->curAmpduTimeType; +} + +VOID +halbtc8812a2ant_LimitedTx( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte raMaskType, + IN u1Byte arfrType, + IN u1Byte retryLimitType, + IN u1Byte ampduTimeType + ) +{ + u4Byte disRaMask=0x0; + + pCoexDm->curRaMaskType = raMaskType; + disRaMask = halbtc8812a2ant_DecideRaMask(pBtCoexist, raMaskType); + halbtc8812a2ant_UpdateRaMask(pBtCoexist, bForceExec, disRaMask); + + halbtc8812a2ant_AutoRateFallbackRetry(pBtCoexist, bForceExec, arfrType); + halbtc8812a2ant_RetryLimit(pBtCoexist, bForceExec, retryLimitType); + halbtc8812a2ant_AmpduMaxTime(pBtCoexist, bForceExec, ampduTimeType); +} + +VOID +halbtc8812a2ant_LimitedRx( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRejApAggPkt, + IN BOOLEAN bBtCtrlAggBufSize, + IN u1Byte aggBufSize + ) +{ + BOOLEAN bRejectRxAgg=bRejApAggPkt; + BOOLEAN bBtCtrlRxAggSize=bBtCtrlAggBufSize; + u1Byte rxAggSize=aggBufSize; + + //============================================ + // Rx Aggregation related setting + //============================================ + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &bRejectRxAgg); + // decide BT control aggregation buf size or not + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, &bBtCtrlRxAggSize); + // aggregation buf size, only work when BT control Rx aggregation size. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_AGG_BUF_SIZE, &rxAggSize); + // real update aggregation setting + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +VOID +halbtc8812a2ant_MonitorBtCtr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte regHPTxRx, regLPTxRx, u4Tmp; + u4Byte regHPTx=0, regHPRx=0, regLPTx=0, regLPRx=0; + u1Byte u1Tmp; + + regHPTxRx = 0x770; + regLPTxRx = 0x774; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); + regHPTx = u4Tmp & bMaskLWord; + regHPRx = (u4Tmp & bMaskHWord)>>16; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); + regLPTx = u4Tmp & bMaskLWord; + regLPRx = (u4Tmp & bMaskHWord)>>16; + + pCoexSta->highPriorityTx = regHPTx; + pCoexSta->highPriorityRx = regHPRx; + pCoexSta->lowPriorityTx = regLPTx; + pCoexSta->lowPriorityRx = regLPRx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regHPTxRx, regHPTx, regHPTx, regHPRx, regHPRx)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regLPTxRx, regLPTx, regLPTx, regLPRx, regLPRx)); + + // reset counter + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); +} + +VOID +halbtc8812a2ant_QueryBtInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte dataLen=3; + u1Byte buf[5] = {0}; + + if(!pBtCoexist->btInfo.bBtDisabled) + { + if(!pCoexSta->btInfoQueryCnt || + (pCoexSta->btInfoC2hCnt[BT_INFO_SRC_8812A_2ANT_BT_RSP]-pCoexSta->btInfoQueryCnt)>2) + { + buf[0] = dataLen; + buf[1] = 0x1; // polling enable, 1=enable, 0=disable + buf[2] = 0x2; // polling time in seconds + buf[3] = 0x1; // auto report enable, 1=enable, 0=disable + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_CTRL_BT_INFO, (PVOID)&buf[0]); + } + } + pCoexSta->btInfoQueryCnt++; +} + +BOOLEAN +halbtc8812a2ant_IsWifiStatusChanged( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreWifiBusy=FALSE, bPreUnder4way=FALSE, bPreBtHsOn=FALSE; + BOOLEAN bWifiBusy=FALSE, bUnder4way=FALSE, bBtHsOn=FALSE; + BOOLEAN bWifiConnected=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); + + if(bWifiConnected) + { + if(bWifiBusy != bPreWifiBusy) + { + bPreWifiBusy = bWifiBusy; + return TRUE; + } + if(bUnder4way != bPreUnder4way) + { + bPreUnder4way = bUnder4way; + return TRUE; + } + if(bBtHsOn != bPreBtHsOn) + { + bPreBtHsOn = bBtHsOn; + return TRUE; + } + } + + return FALSE; +} + +VOID +halbtc8812a2ant_UpdateBtLinkInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bBtHsOn=FALSE; + +#if 1//(BT_AUTO_REPORT_ONLY_8812A_2ANT == 1) // profile from bt patch + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + pBtLinkInfo->bBtLinkExist = pCoexSta->bBtLinkExist; + pBtLinkInfo->bScoExist = pCoexSta->bScoExist; + pBtLinkInfo->bA2dpExist = pCoexSta->bA2dpExist; + pBtLinkInfo->bPanExist = pCoexSta->bPanExist; + pBtLinkInfo->bHidExist = pCoexSta->bHidExist; + + // work around for HS mode. + if(bBtHsOn) + { + pBtLinkInfo->bPanExist = TRUE; + pBtLinkInfo->bBtLinkExist = TRUE; + } +#else // profile from bt stack + pBtLinkInfo->bBtLinkExist = pStackInfo->bBtLinkExist; + pBtLinkInfo->bScoExist = pStackInfo->bScoExist; + pBtLinkInfo->bA2dpExist = pStackInfo->bA2dpExist; + pBtLinkInfo->bPanExist = pStackInfo->bPanExist; + pBtLinkInfo->bHidExist = pStackInfo->bHidExist; + + //for win-8 stack HID report error + if(!pStackInfo->bHidExist) + pStackInfo->bHidExist = pCoexSta->bHidExist; //sync BTInfo with BT firmware and stack + // when stack HID report error, here we use the info from bt fw. + if(!pStackInfo->bBtLinkExist) + pStackInfo->bBtLinkExist = pCoexSta->bBtLinkExist; +#endif + // check if Sco only + if( pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bScoOnly = TRUE; + else + pBtLinkInfo->bScoOnly = FALSE; + + // check if A2dp only + if( !pBtLinkInfo->bScoExist && + pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bA2dpOnly = TRUE; + else + pBtLinkInfo->bA2dpOnly = FALSE; + + // check if Pan only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bPanOnly = TRUE; + else + pBtLinkInfo->bPanOnly = FALSE; + + // check if Hid only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + pBtLinkInfo->bHidExist ) + pBtLinkInfo->bHidOnly = TRUE; + else + pBtLinkInfo->bHidOnly = FALSE; +} + +u1Byte +halbtc8812a2ant_ActionAlgorithm( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + BOOLEAN bBtHsOn=FALSE; + u1Byte algorithm=BT_8812A_2ANT_COEX_ALGO_UNDEFINED; + u1Byte numOfDiffProfile=0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(!pBtLinkInfo->bBtLinkExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No BT link exists!!!\n")); + return algorithm; + } + + if(pBtLinkInfo->bScoExist) + numOfDiffProfile++; + if(pBtLinkInfo->bHidExist) + numOfDiffProfile++; + if(pBtLinkInfo->bPanExist) + numOfDiffProfile++; + if(pBtLinkInfo->bA2dpExist) + numOfDiffProfile++; + + if(numOfDiffProfile == 1) + { + if(pBtLinkInfo->bScoExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO only\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_SCO; + } + else + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_A2DP; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(HS) only\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(EDR) only\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_PANEDR; + } + } + } + } + else if(numOfDiffProfile == 2) + { + if(pBtLinkInfo->bScoExist) + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_SCO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP ==> SCO\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_PANEDR_HID; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(HS)\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(EDR)\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_SCO; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + if(pStackInfo->numOfHid >= 2) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID*2 + A2DP\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_HID_A2DP; + } + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(HS)\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_HID; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_A2DP_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } + else if(numOfDiffProfile == 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP ==> HID\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_PANEDR_HID; + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(HS)\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_SCO_HID; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(EDR)\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_SCO_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(HS)\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + else if(numOfDiffProfile >= 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n")); + + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n")); + algorithm = BT_8812A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +VOID +halbtc8812a2ant_SetFwDacSwingLevel( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte dacSwingLvl + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + // There are several type of dacswing + // 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 + H2C_Parameter[0] = dacSwingLvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Set Dac Swing Level=0x%x\n", dacSwingLvl)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x64=0x%x\n", H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x64, 1, H2C_Parameter); +} + +VOID +halbtc8812a2ant_SetFwDecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte decBtPwrLvl + ) +{ + u1Byte dataLen=4; + u1Byte buf[6] = {0}; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], decrease Bt Power level = %d\n", + decBtPwrLvl)); + + buf[0] = dataLen; + buf[1] = 0x3; // OP_Code + buf[2] = 0x2; // OP_Code_Length + if(decBtPwrLvl) + buf[3] = 0x1; // OP_Code_Content + else + buf[3] = 0x0; + buf[4] = decBtPwrLvl;// pwrLevel + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); +} + +VOID +halbtc8812a2ant_DecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte decBtPwrLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s Dec BT power level = %d\n", + (bForceExec? "force to":""), decBtPwrLvl)); + pCoexDm->curBtDecPwrLvl = decBtPwrLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preBtDecPwrLvl=%d, curBtDecPwrLvl=%d\n", + pCoexDm->preBtDecPwrLvl, pCoexDm->curBtDecPwrLvl)); + + if(pCoexDm->preBtDecPwrLvl == pCoexDm->curBtDecPwrLvl) + return; + } + halbtc8812a2ant_SetFwDecBtPwr(pBtCoexist, pCoexDm->curBtDecPwrLvl); + + pCoexDm->preBtDecPwrLvl = pCoexDm->curBtDecPwrLvl; +} + +VOID +halbtc8812a2ant_FwDacSwingLvl( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte fwDacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set FW Dac Swing level = %d\n", + (bForceExec? "force to":""), fwDacSwingLvl)); + pCoexDm->curFwDacSwingLvl = fwDacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preFwDacSwingLvl=%d, curFwDacSwingLvl=%d\n", + pCoexDm->preFwDacSwingLvl, pCoexDm->curFwDacSwingLvl)); + + if(pCoexDm->preFwDacSwingLvl == pCoexDm->curFwDacSwingLvl) + return; + } + + halbtc8812a2ant_SetFwDacSwingLevel(pBtCoexist, pCoexDm->curFwDacSwingLvl); + + pCoexDm->preFwDacSwingLvl = pCoexDm->curFwDacSwingLvl; +} + +VOID +halbtc8812a2ant_SetSwRfRxLpfCorner( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bRxRfShrinkOn + ) +{ + if(bRxRfShrinkOn) + { + //Shrink RF Rx LPF corner + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Shrink RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, 0xffffc); + } + else + { + //Resume RF Rx LPF corner + // After initialized, we can use pCoexDm->btRf0x1eBackup + if(pBtCoexist->bInitilized) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, pCoexDm->btRf0x1eBackup); + } + } +} + +VOID +halbtc8812a2ant_RfShrink( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRxRfShrinkOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn Rx RF Shrink = %s\n", + (bForceExec? "force to":""), ((bRxRfShrinkOn)? "ON":"OFF"))); + pCoexDm->bCurRfRxLpfShrink = bRxRfShrinkOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreRfRxLpfShrink=%d, bCurRfRxLpfShrink=%d\n", + pCoexDm->bPreRfRxLpfShrink, pCoexDm->bCurRfRxLpfShrink)); + + if(pCoexDm->bPreRfRxLpfShrink == pCoexDm->bCurRfRxLpfShrink) + return; + } + halbtc8812a2ant_SetSwRfRxLpfCorner(pBtCoexist, pCoexDm->bCurRfRxLpfShrink); + + pCoexDm->bPreRfRxLpfShrink = pCoexDm->bCurRfRxLpfShrink; +} + +VOID +halbtc8812a2ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte tmpU1; + + tmpU1 = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x4fd); + tmpU1 |= BIT0; + if(bLowPenaltyRa) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set low penalty!!\n")); + tmpU1 &= ~BIT2; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Tx rate adaptive, set normal!!\n")); + tmpU1 |= BIT2; + } + + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x4fd, tmpU1); +} + +VOID +halbtc8812a2ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); + + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8812a2ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8812a2ant_SetDacSwingReg( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte level + ) +{ + u1Byte val=(u1Byte)level; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Write SwDacSwing = 0x%x\n", level)); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xc5b, 0x3e, val); +} + +VOID +halbtc8812a2ant_SetSwFullTimeDacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bSwDacSwingOn, + IN u4Byte swDacSwingLvl + ) +{ + if(bSwDacSwingOn) + { + halbtc8812a2ant_SetDacSwingReg(pBtCoexist, swDacSwingLvl); + } + else + { + halbtc8812a2ant_SetDacSwingReg(pBtCoexist, 0x18); + } +} + + +VOID +halbtc8812a2ant_DacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDacSwingOn, + IN u4Byte dacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn DacSwing=%s, dacSwingLvl=0x%x\n", + (bForceExec? "force to":""), ((bDacSwingOn)? "ON":"OFF"), dacSwingLvl)); + pCoexDm->bCurDacSwingOn = bDacSwingOn; + pCoexDm->curDacSwingLvl = dacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x, bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + pCoexDm->bPreDacSwingOn, pCoexDm->preDacSwingLvl, + pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl)); + + if( (pCoexDm->bPreDacSwingOn == pCoexDm->bCurDacSwingOn) && + (pCoexDm->preDacSwingLvl == pCoexDm->curDacSwingLvl) ) + return; + } + delay_ms(30); + halbtc8812a2ant_SetSwFullTimeDacSwing(pBtCoexist, bDacSwingOn, dacSwingLvl); + + pCoexDm->bPreDacSwingOn = pCoexDm->bCurDacSwingOn; + pCoexDm->preDacSwingLvl = pCoexDm->curDacSwingLvl; +} + +VOID +halbtc8812a2ant_SetAdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAdcBackOff + ) +{ + if(bAdcBackOff) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level On!\n")); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x8db, 0x60, 0x3); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level Off!\n")); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x8db, 0x60, 0x1); + } +} + +VOID +halbtc8812a2ant_AdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAdcBackOff + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn AdcBackOff = %s\n", + (bForceExec? "force to":""), ((bAdcBackOff)? "ON":"OFF"))); + pCoexDm->bCurAdcBackOff = bAdcBackOff; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAdcBackOff=%d, bCurAdcBackOff=%d\n", + pCoexDm->bPreAdcBackOff, pCoexDm->bCurAdcBackOff)); + + if(pCoexDm->bPreAdcBackOff == pCoexDm->bCurAdcBackOff) + return; + } + halbtc8812a2ant_SetAdcBackOff(pBtCoexist, pCoexDm->bCurAdcBackOff); + + pCoexDm->bPreAdcBackOff = pCoexDm->bCurAdcBackOff; +} + +VOID +halbtc8812a2ant_SetAgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAgcTableEn + ) +{ + u1Byte rssiAdjustVal=0; + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); + if(bAgcTableEn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x28F4B); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x10AB2); + rssiAdjustVal = 8; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x2884B); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x104B2); + } + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); + + // set rssiAdjustVal for wifi module. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, &rssiAdjustVal); +} + +VOID +halbtc8812a2ant_AgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAgcTableEn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s %s Agc Table\n", + (bForceExec? "force to":""), ((bAgcTableEn)? "Enable":"Disable"))); + pCoexDm->bCurAgcTableEn = bAgcTableEn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + pCoexDm->bPreAgcTableEn, pCoexDm->bCurAgcTableEn)); + + if(pCoexDm->bPreAgcTableEn == pCoexDm->bCurAgcTableEn) + return; + } + halbtc8812a2ant_SetAgcTable(pBtCoexist, bAgcTableEn); + + pCoexDm->bPreAgcTableEn = pCoexDm->bCurAgcTableEn; +} + +VOID +halbtc8812a2ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8812a2ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c0, val0x6c4, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c0 = val0x6c0; + pCoexDm->curVal0x6c4 = val0x6c4; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c0=0x%x, preVal0x6c4=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + pCoexDm->preVal0x6c0, pCoexDm->preVal0x6c4, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c0=0x%x, curVal0x6c4=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + pCoexDm->curVal0x6c0, pCoexDm->curVal0x6c4, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && + (pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8812a2ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c4, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; + pCoexDm->preVal0x6c4 = pCoexDm->curVal0x6c4; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8812a2ant_CoexTableWithType( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + switch(type) + { + case 0: + halbtc8812a2ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 1: + halbtc8812a2ant_CoexTable(pBtCoexist, bForceExec, 0x5a5a5a5a, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8812a2ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x5ffb5ffb, 0xffffff, 0x3); + break; + case 3: + halbtc8812a2ant_CoexTable(pBtCoexist, bForceExec, 0x5fdf5fdf, 0x5fdb5fdb, 0xffffff, 0x3); + break; + case 4: + halbtc8812a2ant_CoexTable(pBtCoexist, bForceExec, 0xdfffdfff, 0x5fdb5fdb, 0xffffff, 0x3); + break; + case 5: + halbtc8812a2ant_CoexTable(pBtCoexist, bForceExec, 0x5ddd5ddd, 0x5fdb5fdb, 0xffffff, 0x3); + break; + + default: + break; + } +} + +VOID +halbtc8812a2ant_SetFwIgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnable + ) +{ + u1Byte dataLen=3; + u1Byte buf[5] = {0}; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], %s BT Ignore Wlan_Act\n", + (bEnable? "Enable":"Disable"))); + + buf[0] = dataLen; + buf[1] = 0x1; // OP_Code + buf[2] = 0x1; // OP_Code_Length + if(bEnable) + buf[3] = 0x1; // OP_Code_Content + else + buf[3] = 0x0; + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); +} + +VOID +halbtc8812a2ant_IgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); + pCoexDm->bCurIgnoreWlanAct = bEnable; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); + + if(pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) + return; + } + halbtc8812a2ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); + + pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; +} + +VOID +halbtc8812a2ant_SetFwPstdma( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte byte1, + IN u1Byte byte2, + IN u1Byte byte3, + IN u1Byte byte4, + IN u1Byte byte5 + ) +{ + u1Byte H2C_Parameter[5] ={0}; + + H2C_Parameter[0] = byte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = byte5; + + pCoexDm->psTdmaPara[0] = byte1; + pCoexDm->psTdmaPara[1] = byte2; + pCoexDm->psTdmaPara[2] = byte3; + pCoexDm->psTdmaPara[3] = byte4; + pCoexDm->psTdmaPara[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x60(5bytes)=0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x60, 5, H2C_Parameter); +} + +VOID +halbtc8812a2ant_SetLpsRpwm( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + u1Byte lps=lpsVal; + u1Byte rpwm=rpwmVal; + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_LPS_VAL, &lps); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +VOID +halbtc8812a2ant_LpsRpwm( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + BOOLEAN bForceExecPwrCmd=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set lps/rpwm=0x%x/0x%x \n", + (bForceExec? "force to":""), lpsVal, rpwmVal)); + pCoexDm->curLps = lpsVal; + pCoexDm->curRpwm = rpwmVal; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preLps/curLps=0x%x/0x%x, preRpwm/curRpwm=0x%x/0x%x!!\n", + pCoexDm->preLps, pCoexDm->curLps, pCoexDm->preRpwm, pCoexDm->curRpwm)); + + if( (pCoexDm->preLps == pCoexDm->curLps) && + (pCoexDm->preRpwm == pCoexDm->curRpwm) ) + { + return; + } + } + halbtc8812a2ant_SetLpsRpwm(pBtCoexist, lpsVal, rpwmVal); + + pCoexDm->preLps = pCoexDm->curLps; + pCoexDm->preRpwm = pCoexDm->curRpwm; +} + +VOID +halbtc8812a2ant_SwMechanism1( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bShrinkRxLPF, + IN BOOLEAN bLowPenaltyRA, + IN BOOLEAN bLimitedDIG, + IN BOOLEAN bBTLNAConstrain + ) +{ + /* + u4Byte wifiBw; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 != wifiBw) //only shrink RF Rx LPF for HT40 + { + if (bShrinkRxLPF) + bShrinkRxLPF = FALSE; + } + */ + + halbtc8812a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, bShrinkRxLPF); + //halbtc8812a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, bLowPenaltyRA); +} + +VOID +halbtc8812a2ant_SwMechanism2( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAGCTableShift, + IN BOOLEAN bADCBackOff, + IN BOOLEAN bSWDACSwing, + IN u4Byte dacSwingLvl + ) +{ + //halbtc8812a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, bAGCTableShift); + halbtc8812a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, bADCBackOff); + halbtc8812a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, bSWDACSwing, dacSwingLvl); +} + +VOID +halbtc8812a2ant_SetAntPath( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte antPosType, + IN BOOLEAN bInitHwCfg, + IN BOOLEAN bWifiOff + ) +{ + u1Byte u1Tmp=0; + + if(bInitHwCfg) + { + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x900, 0x00000400); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76d, 0x1); + } + else if(bWifiOff) + { + + } + + // ext switch setting + switch(antPosType) + { + case BTC_ANT_WIFI_AT_CPL_MAIN: + break; + case BTC_ANT_WIFI_AT_CPL_AUX: + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xcb7); + u1Tmp &= ~BIT3; + u1Tmp |= BIT2; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xcb7, u1Tmp); + break; + default: + break; + } +} + +VOID +halbtc8812a2ant_PsTdma( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bTurnOn, + IN u1Byte type + ) +{ + BOOLEAN bTurnOnByCnt=FALSE; + u1Byte psTdmaTypeByCnt=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type=%d\n", + (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); + pCoexDm->bCurPsTdmaOn = bTurnOn; + pCoexDm->curPsTdma = type; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + pCoexDm->bPrePsTdmaOn, pCoexDm->bCurPsTdmaOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + pCoexDm->prePsTdma, pCoexDm->curPsTdma)); + + if( (pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && + (pCoexDm->prePsTdma == pCoexDm->curPsTdma) ) + return; + } + if(bTurnOn) + { + switch(type) + { + case 1: + default: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xa1, 0x90); + break; + case 2: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xa1, 0x90); + break; + case 3: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x3, 0xb1, 0x90); + break; + case 4: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x10, 0x03, 0xb1, 0x90); + break; + case 5: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x21, 0x10); + break; + case 6: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0x21, 0x10); + break; + case 7: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x3, 0x21, 0x10); + break; + case 8: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x10, 0x3, 0x21, 0x10); + break; + case 9: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xa1, 0x10); + break; + case 10: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xa1, 0x10); + break; + case 11: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x03, 0xb1, 0x10); + break; + case 12: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x10, 0x03, 0xb1, 0x10); + break; + case 13: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x21, 0x10); + break; + case 14: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0x21, 0x10); + break; + case 15: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x03, 0x21, 0x10); + break; + case 16: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x10, 0x03, 0x21, 0x10); + break; + case 17: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x15, 0x03, 0xb1, 0x10); + break; + case 18: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0xe1, 0x90); + break; + case 19: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0xe1, 0x90); + break; + case 20: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0x60, 0x90); + break; + case 21: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x15, 0x03, 0x70, 0x90); + break; + case 71: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); + break; + + // following cases is for wifi rssi low, started from 81 + case 81: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xd3, 0x3a, 0x3, 0x90, 0x50); + break; + case 82: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xd3, 0x2b, 0x3, 0x90, 0x50); + break; + case 83: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xd3, 0x21, 0x3, 0x90, 0x50); + break; + case 84: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xd3, 0x15, 0x3, 0x90, 0x50); + break; + case 85: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xd3, 0x1d, 0x1d, 0x80, 0x50); + break; + case 86: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0xd3, 0x15, 0x15, 0x80, 0x50); + break; + } + } + else + { + // disable PS tdma + switch(type) + { + case 0: //ANT2PTA, 0x778=0x1 + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0x8, 0x0, 0x0, 0x0, 0x0); + break; + case 1: //ANT2BT, 0x778=3 + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x08, 0x0); + delay_ms(5); + halbtc8812a2ant_SetAntPath(pBtCoexist, BTC_ANT_WIFI_AT_CPL_AUX, FALSE, FALSE); + break; + default: + halbtc8812a2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x00, 0x0); + break; + } + } + + // update pre state + pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; + pCoexDm->prePsTdma = pCoexDm->curPsTdma; +} + +VOID +halbtc8812a2ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + // fw all off + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + // sw all off + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + // hw all off + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +VOID +halbtc8812a2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + // force to reset coex mechanism + + halbtc8812a2ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 1); + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, FORCE_EXEC, 6); + halbtc8812a2ant_DecBtPwr(pBtCoexist, FORCE_EXEC, 0); + + halbtc8812a2ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); + + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); +} + +VOID +halbtc8812a2ant_PsTdmaCheckForPowerSaveState( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bNewPsState + ) +{ + u1Byte lpsMode=0x0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_LPS_MODE, &lpsMode); + + if(lpsMode) // already under LPS state + { + if(bNewPsState) + { + // keep state under LPS, do nothing. + } + else + { + // will leave LPS state, turn off psTdma first + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + } + else // NO PS state + { + if(bNewPsState) + { + // will enter LPS state, turn off psTdma first + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + // keep state under NO PS state, do nothing. + } + } +} + +VOID +halbtc8812a2ant_PowerSaveState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte psType, + IN BOOLEAN bLowPwrDisable, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + switch(psType) + { + case BTC_PS_WIFI_NATIVE: + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + break; + case BTC_PS_LPS_ON: + halbtc8812a2ant_PsTdmaCheckForPowerSaveState(pBtCoexist, TRUE); + halbtc8812a2ant_LpsRpwm(pBtCoexist, NORMAL_EXEC, lpsVal, rpwmVal); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + // power save must executed before psTdma. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_ENTER_LPS, NULL); + break; + default: + break; + } +} + +VOID +halbtc8812a2ant_ActionBtInquiry( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); +} + +BOOLEAN +halbtc8812a2ant_IsCommonAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH; + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bCommon=FALSE, bWifiConnected=FALSE, bWifiBusy=FALSE; + BOOLEAN bBtHsOn=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + + if(pBtLinkInfo->bScoExist || pBtLinkInfo->bHidExist) + { + halbtc8812a2ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 1, 0, 0, 0); + } + else + { + halbtc8812a2ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); + } + + if(!bWifiConnected) + { + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, FALSE, 0x0, 0x0); + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non-connected idle!!\n")); + + if( (BT_8812A_2ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) || + (BT_8812A_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + } + + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else + { + if(BT_8812A_2ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT non connected-idle!!\n")); + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, FALSE, 0x0, 0x0); + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else if(BT_8812A_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) + { + if(bBtHsOn) + return FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT connected-idle!!\n")); + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else + { + if(bWifiBusy) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Busy + BT Busy!!\n")); + bCommon = FALSE; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Idle + BT Busy!!\n")); + wifiRssiState = halbtc8812a2ant_WifiRssiState(pBtCoexist, 0, 2, 34, 0); + + if(BTC_RSSI_HIGH(wifiRssiState)) + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + else + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, TRUE, 0x50, 0x4); + + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + if(BTC_RSSI_HIGH(wifiRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); + else + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + + if(BTC_RSSI_HIGH(wifiRssiState)) + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 17); + else + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 83); + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + bCommon = TRUE; + } + } + } + + return bCommon; +} + +VOID +halbtc8812a2ant_TdmaDurationAdjust( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bScoHid, + IN BOOLEAN bTxPause, + IN u1Byte maxInterval + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjust()\n")); + + pCoexDm->bAutoTdmaAdjustLowRssi = FALSE; + + if(!pCoexDm->bAutoTdmaAdjust) + { + pCoexDm->bAutoTdmaAdjust = TRUE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); + { + if(bScoHid) + { + if(bTxPause) + { + if(maxInterval == 1) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + else if(maxInterval == 2) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(maxInterval == 3) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + } + else + { + if(maxInterval == 1) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(maxInterval == 2) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(maxInterval == 3) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + } + else + { + if(bTxPause) + { + if(maxInterval == 1) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(maxInterval == 2) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(maxInterval == 3) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + } + else + { + if(maxInterval == 1) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(maxInterval == 2) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(maxInterval == 3) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + } + } + } + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n", + up, dn, m, n, WaitCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if �s�� n ��2�� retry count��0, �h�ռeWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration + { + if (WaitCount <= 2) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration + { + if (WaitCount == 1) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], max Interval = %d\n", maxInterval)); + if(maxInterval == 1) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + + if(pCoexDm->curPsTdma == 71) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 71); + pCoexDm->psTdmaDuAdjType = 71; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + + if(result == -1) + { + if(pCoexDm->curPsTdma == 71) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 71); + pCoexDm->psTdmaDuAdjType = 71; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + } + } + } + else if(maxInterval == 2) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + if(pCoexDm->curPsTdma == 1) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + } + } + } + else if(maxInterval == 3) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + if(pCoexDm->curPsTdma == 1) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + } + } + } + + // if current PsTdma not match with the recorded one (when scan, dhcp...), + // then we have to adjust it back to the previous record one. + if(pCoexDm->curPsTdma != pCoexDm->psTdmaDuAdjType) + { + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], PsTdma type dismatch!!!, curPsTdma=%d, recordPsTdma=%d\n", + pCoexDm->curPsTdma, pCoexDm->psTdmaDuAdjType)); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if( !bScan && !bLink && !bRoam) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, pCoexDm->psTdmaDuAdjType); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n")); + } + } +} + +//================== +// pstdma for wifi rssi low +//================== +VOID +halbtc8812a2ant_TdmaDurationAdjustForWifiRssiLow( + IN PBTC_COEXIST pBtCoexist//, + //IN u1Byte wifiStatus + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0, btInfoExt; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], halbtc8812a2ant_TdmaDurationAdjustForWifiRssiLow()\n")); +#if 0 + if( (BT_8812A_2ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) || + (BT_8812A_2ANT_WIFI_STATUS_CONNECTED_SCAN == wifiStatus) || + (BT_8812A_2ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifiStatus) ) + { + if( pCoexDm->curPsTdma != 81 && + pCoexDm->curPsTdma != 82 && + pCoexDm->curPsTdma != 83 && + pCoexDm->curPsTdma != 84 ) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 82); + pCoexDm->psTdmaDuAdjType = 82; + + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + return; + } +#endif + pCoexDm->bAutoTdmaAdjust = FALSE; + + if(!pCoexDm->bAutoTdmaAdjustLowRssi) + { + pCoexDm->bAutoTdmaAdjustLowRssi = TRUE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjustForWifiRssiLow()!!\n")); + + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 82); + pCoexDm->psTdmaDuAdjType = 82; + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + btInfoExt = pCoexSta->btInfoExt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n", + up, dn, m, n, WaitCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if �s�� n ��2�� retry count��0, �h�ռeWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration + { + if (WaitCount <= 2) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration + { + if (WaitCount == 1) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + if(result == -1) + { + if( (BT_INFO_8812A_2ANT_A2DP_BASIC_RATE(btInfoExt)) && + ((pCoexDm->curPsTdma == 81) ||(pCoexDm->curPsTdma == 82)) ) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 83); + pCoexDm->psTdmaDuAdjType = 83; + } + else if(pCoexDm->curPsTdma == 81) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 82); + pCoexDm->psTdmaDuAdjType = 82; + } + else if(pCoexDm->curPsTdma == 82) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 83); + pCoexDm->psTdmaDuAdjType = 83; + } + else if(pCoexDm->curPsTdma == 83) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 84); + pCoexDm->psTdmaDuAdjType = 84; + } + } + else if(result == 1) + { + if( (BT_INFO_8812A_2ANT_A2DP_BASIC_RATE(btInfoExt)) && + ((pCoexDm->curPsTdma == 81) ||(pCoexDm->curPsTdma == 82)) ) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 83); + pCoexDm->psTdmaDuAdjType = 83; + } + else if(pCoexDm->curPsTdma == 84) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 83); + pCoexDm->psTdmaDuAdjType = 83; + } + else if(pCoexDm->curPsTdma == 83) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 82); + pCoexDm->psTdmaDuAdjType = 82; + } + else if(pCoexDm->curPsTdma == 82) + { + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 81); + pCoexDm->psTdmaDuAdjType = 81; + } + } + + if( pCoexDm->curPsTdma != 81 && + pCoexDm->curPsTdma != 82 && + pCoexDm->curPsTdma != 83 && + pCoexDm->curPsTdma != 84 ) + { + // recover to previous adjust type + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, pCoexDm->psTdmaDuAdjType); + } + } +} + +VOID +halbtc8812a2ant_ActionSco( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8812a2ant_WifiRssiState(pBtCoexist, 0, 2, 34, 0); + btRssiState = halbtc8812a2ant_BtRssiState(3, 34, 42); + + // power save state + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + + // coex table + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 5); + else + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); + + // pstdma + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + else + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + + // decrease BT power + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + + // limited Rx + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + // fw dac swing level + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,TRUE,0x6); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,TRUE,0x6); + } + } + else + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,TRUE,0x6); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,TRUE,0x6); + } + } +} + +VOID +halbtc8812a2ant_ActionScoHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8812a2ant_WifiRssiState(pBtCoexist, 0, 2, 34, 0); + btRssiState = halbtc8812a2ant_BtRssiState(3, 34, 42); + + // power save state + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + + // coex table + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 4); + + // pstdma + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + else + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + + // decrease BT power + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + + // limited Rx + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, TRUE, 0x8); + + // fw dac swing level + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x6); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x6); + } + } + else + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x6); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x6); + } + } +} + +VOID +halbtc8812a2ant_ActionHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8812a2ant_WifiRssiState(pBtCoexist, 0, 2, 34, 0); + btRssiState = halbtc8812a2ant_BtRssiState(3, 34, 42); + + // power save state + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + + // coex table + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 3); + else + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 5); + + // pstdma + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + else + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + + // decrease BT power + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + + // limited Rx + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + else + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, TRUE, 0x8); + + + // fw dac swing level + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +//A2DP only / PAN(EDR) only/ A2DP+PAN(HS) +VOID +halbtc8812a2ant_ActionA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8812a2ant_WifiRssiState(pBtCoexist, 0, 2, 34, 0); + btRssiState = halbtc8812a2ant_BtRssiState(3, 34, 42); + + // power save state + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + else + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, TRUE, 0x50, 0x4); + + // coex table + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + + // pstdma + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 1); + else + halbtc8812a2ant_TdmaDurationAdjustForWifiRssiLow(pBtCoexist); + + // decrease BT power + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + + // limited Rx + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + // fw dac swing level + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + + // sw mechanism + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8812a2ant_ActionA2dpPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8812a2ant_WifiRssiState(pBtCoexist, 0, 2, 34, 0); + btRssiState = halbtc8812a2ant_BtRssiState(3, 34, 42); + + // power save state + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + + // coex table + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 5); + + // pstdma + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 2); + else + halbtc8812a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 2); + + // decrease BT power + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + + // limited Rx + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + // fw dac swing level + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + + // sw mechanism + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,TRUE,0x6); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,TRUE,0x6); + } + } + else + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,TRUE,0x6); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,TRUE,0x6); + } + } +} + +VOID +halbtc8812a2ant_ActionPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8812a2ant_WifiRssiState(pBtCoexist, 0, 2, 34, 0); + btRssiState = halbtc8812a2ant_BtRssiState(3, 34, 42); + + // power save state + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + else + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, TRUE, 0x50, 0x4); + + // coex table + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + + // pstdma + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + else + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 85); + + // decrease BT power + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + + // limited Rx + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + // fw dac swing level + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + + // sw mechanism + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +//PAN(HS) only +VOID +halbtc8812a2ant_ActionPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8812a2ant_WifiRssiState(pBtCoexist, 0, 2, 34, 0); + btRssiState = halbtc8812a2ant_BtRssiState(3, 34, 42); + + // power save state + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + + // coex table + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + + // pstdma + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + + // decrease BT power + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + + // limited Rx + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + // fw dac swing level + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +//PAN(EDR)+A2DP +VOID +halbtc8812a2ant_ActionPanEdrA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8812a2ant_WifiRssiState(pBtCoexist, 0, 2, 34, 0); + btRssiState = halbtc8812a2ant_BtRssiState(3, 34, 42); + + // power save state + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + else + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, TRUE, 0x50, 0x4); + + // coex table + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 5); + else + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + + // pstdma + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 3); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 3); + else + { + pCoexDm->bAutoTdmaAdjust = FALSE; + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 86); + } + + // decrease BT power + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + + // limited Rx + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + + // fw dac swing level + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8812a2ant_ActionPanEdrHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8812a2ant_WifiRssiState(pBtCoexist, 0, 2, 34, 0); + btRssiState = halbtc8812a2ant_BtRssiState(3, 34, 42); + + // power save state + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + else + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, TRUE, 0x50, 0x4); + + // coex table + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 3); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 5); + else + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + + // pstdma + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + else + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 85); + + // decrease BT power + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + + // limited Rx + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + else + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, TRUE, 0x8); + + // fw dac swing level + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +// HID+A2DP+PAN(EDR) +VOID +halbtc8812a2ant_ActionHidA2dpPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8812a2ant_WifiRssiState(pBtCoexist, 0, 2, 34, 0); + btRssiState = halbtc8812a2ant_BtRssiState(3, 34, 42); + + // power save state + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + else + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, TRUE, 0x50, 0x4); + + // coex table + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 3); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 5); + else + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + + // pstdma + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 3); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 3); + else + { + pCoexDm->bAutoTdmaAdjust = FALSE; + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 86); + } + + // decrease BT power + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + + // limited Rx + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + else + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, TRUE, 0x8); + + + // fw dac swing level + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8812a2ant_ActionHidA2dpPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8812a2ant_WifiRssiState(pBtCoexist, 0, 2, 34, 0); + btRssiState = halbtc8812a2ant_BtRssiState(3, 34, 42); + + // power save state + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + + // coex table + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 3); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 5); + else + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 5); + + // pstdma + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 2); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + else + halbtc8812a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + + // decrease BT power + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + + // limited Rx + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + else + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, TRUE, 0x8); + + // fw dac swing level + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8812a2ant_ActionHidA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH, btRssiState=BTC_RSSI_STATE_HIGH; + u4Byte wifiBw; + + wifiRssiState = halbtc8812a2ant_WifiRssiState(pBtCoexist, 0, 2, 34, 0); + btRssiState = halbtc8812a2ant_BtRssiState(3, 34, 42); + + // power save state + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, TRUE, 0x0, 0x0); + else + halbtc8812a2ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, TRUE, 0x50, 0x4); + + // coex table + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 3); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 5); + else + halbtc8812a2ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + + // pstdma + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 2); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + else + { + pCoexDm->bAutoTdmaAdjust = FALSE; + halbtc8812a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 82); + } + + // decrease BT power + if(BTC_RSSI_LOW(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(btRssiState)) + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, 4); + + // limited Rx + if(BTC_RSSI_HIGH(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + else if(BTC_RSSI_LOW(wifiRssiState) && BTC_RSSI_HIGH(btRssiState)) + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 0x8); + else + halbtc8812a2ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, TRUE, 0x8); + + // fw dac swing level + halbtc8812a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + // sw mechanism + if(BTC_WIFI_BW_HT40 == wifiBw) + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + if(BTC_RSSI_HIGH(wifiRssiState)) + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8812a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8812a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + + +VOID +halbtc8812a2ant_CoexUnder5G( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8812a2ant_CoexAllOff(pBtCoexist); + + halbtc8812a2ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, TRUE); +} +//==================================================== +VOID +halbtc8812a2ant_RunCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiUnder5G=FALSE, bBtHsOn=FALSE; + u1Byte btInfoOriginal=0, btRetryCnt=0; + u1Byte algorithm=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism()===>\n")); + + if(pBtCoexist->bManualControl) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n")); + return; + } + + if(pCoexSta->bUnderIps) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under IPS !!!\n")); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + if(bWifiUnder5G) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), run 5G coex setting!!<===\n")); + halbtc8812a2ant_CoexUnder5G(pBtCoexist); + return; + } + + algorithm = halbtc8812a2ant_ActionAlgorithm(pBtCoexist); + if(pCoexSta->bC2hBtInquiryPage && (BT_8812A_2ANT_COEX_ALGO_PANHS!=algorithm)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT is under inquiry/page scan !!\n")); + halbtc8812a2ant_ActionBtInquiry(pBtCoexist); + return; + } + + pCoexDm->curAlgorithm = algorithm; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Algorithm = %d \n", pCoexDm->curAlgorithm)); + + if(halbtc8812a2ant_IsCommonAction(pBtCoexist)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant common.\n")); + pCoexDm->bAutoTdmaAdjust = FALSE; + pCoexDm->bAutoTdmaAdjustLowRssi = FALSE; + } + else + { + if(pCoexDm->curAlgorithm != pCoexDm->preAlgorithm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], preAlgorithm=%d, curAlgorithm=%d\n", + pCoexDm->preAlgorithm, pCoexDm->curAlgorithm)); + pCoexDm->bAutoTdmaAdjust = FALSE; + pCoexDm->bAutoTdmaAdjustLowRssi = FALSE; + } + switch(pCoexDm->curAlgorithm) + { + case BT_8812A_2ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = SCO.\n")); + halbtc8812a2ant_ActionSco(pBtCoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_SCO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = SCO+HID.\n")); + halbtc8812a2ant_ActionScoHid(pBtCoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID.\n")); + halbtc8812a2ant_ActionHid(pBtCoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP.\n")); + halbtc8812a2ant_ActionA2dp(pBtCoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n")); + halbtc8812a2ant_ActionA2dpPanHs(pBtCoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n")); + halbtc8812a2ant_ActionPanEdr(pBtCoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HS mode.\n")); + halbtc8812a2ant_ActionPanHs(pBtCoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n")); + halbtc8812a2ant_ActionPanEdrA2dp(pBtCoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n")); + halbtc8812a2ant_ActionPanEdrHid(pBtCoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n")); + halbtc8812a2ant_ActionHidA2dpPanEdr(pBtCoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN(HS).\n")); + halbtc8812a2ant_ActionHidA2dpPanHs(pBtCoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n")); + halbtc8812a2ant_ActionHidA2dp(pBtCoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n")); + halbtc8812a2ant_CoexAllOff(pBtCoexist); + break; + } + pCoexDm->preAlgorithm = pCoexDm->curAlgorithm; + } +} + +VOID +halbtc8812a2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bBackUp + ) +{ + u4Byte u4Tmp=0; + u2Byte u2Tmp=0; + u1Byte u1Tmp=0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 2Ant Init HW Config!!\n")); + + if(bBackUp) + { + // backup rf 0x1e value + pCoexDm->btRf0x1eBackup = + pBtCoexist->fBtcGetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff); + + pCoexDm->backupArfrCnt1 = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x430); + pCoexDm->backupArfrCnt2 = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x434); + pCoexDm->backupRetryLimit = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x42a); + pCoexDm->backupAmpduMaxTime = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x456); + } + + //ant sw control to BT + halbtc8812a2ant_SetAntPath(pBtCoexist, BTC_ANT_WIFI_AT_CPL_AUX, TRUE, FALSE); + + // 0x790[5:0]=0x5 + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x790); + u1Tmp &= 0xc0; + u1Tmp |= 0x5; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x790, u1Tmp); + + // PTA parameter + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, 0x0); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, 0xffff); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, 0x55555555); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, 0x55555555); + + // coex parameters + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x778, 0x1); + + // enable counter statistics + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0x4); + + // enable PTA + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x40, 0x20); + + // bt clock related + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x4); + u1Tmp |= BIT7; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x4, u1Tmp); + + // bt clock related + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x7); + u1Tmp |= BIT1; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x7, u1Tmp); +} + +//============================================================ +// work around function start with wa_halbtc8812a2ant_ +//============================================================ +//============================================================ +// extern function start with EXhalbtc8812a2ant_ +//============================================================ +VOID +EXhalbtc8812a2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8812a2ant_InitHwConfig(pBtCoexist, TRUE); +} + +VOID +EXhalbtc8812a2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + halbtc8812a2ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8812a2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + pu1Byte cliBuf=pBtCoexist->cliBuf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u2Byte u2Tmp[4]; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir; + u1Byte wifiDot11Chnl, wifiHsChnl; + u4Byte fwVer=0, btPatchVer=0; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(pBtCoexist->bManualControl) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cliBuf); + } + + if(!pBoardInfo->bBtExist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", \ + GLCoexVerDate8812a2Ant, GLCoexVer8812a2Ant, fwVer, btPatchVer, btPatchVer); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsMode(HsChnl)", \ + wifiDot11Chnl, bBtHsOn, wifiHsChnl); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], + pCoexDm->wifiChnlInfo[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((pBtCoexist->btInfo.bBtDisabled)? ("disabled"): ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8812A_2ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus)? "non-connected idle": + ( (BT_8812A_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy")))), + pCoexSta->btRssi, pCoexSta->btRetryCnt); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pBtLinkInfo->bScoExist, pBtLinkInfo->bHidExist, pBtLinkInfo->bPanExist, pBtLinkInfo->bA2dpExist); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + + btInfoExt = pCoexSta->btInfoExt; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (btInfoExt&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cliBuf); + + for(i=0; i<BT_INFO_SRC_8812A_2ANT_MAX; i++) + { + if(pCoexSta->btInfoC2hCnt[i]) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8812a2Ant[i], \ + pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], + pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], + pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], + pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); + CL_PRINTF(cliBuf); + } + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s, (0x%x/0x%x)", "PS state, IPS/LPS, (lps/rpwm)", \ + ((pCoexSta->bUnderIps? "IPS ON":"IPS OFF")), + ((pCoexSta->bUnderLps? "LPS ON":"LPS OFF")), + pBtCoexist->btInfo.lpsVal, + pBtCoexist->btInfo.rpwmVal); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "SM1[ShRf/ LpRA/ LimDig]", \ + pCoexDm->bCurRfRxLpfShrink, pCoexDm->bCurLowPenaltyRa, pCoexDm->bLimitedDig); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", \ + pCoexDm->bCurAgcTableEn, pCoexDm->bCurAdcBackOff, pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask", \ + pBtCoexist->btInfo.raMask); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + psTdmaCase = pCoexDm->curPsTdma; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d/%d)", "PS TDMA", \ + pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], + pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], + pCoexDm->psTdmaPara[4], psTdmaCase, pCoexDm->bAutoTdmaAdjust, pCoexDm->bAutoTdmaAdjustLowRssi); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", \ + pCoexDm->curBtDecPwrLvl, pCoexDm->bCurIgnoreWlanAct); + CL_PRINTF(cliBuf); + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", \ + pCoexDm->btRf0x1eBackup); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "backup ARFR1/ARFR2/RL/AMaxTime", \ + pCoexDm->backupArfrCnt1, pCoexDm->backupArfrCnt2, pCoexDm->backupRetryLimit, pCoexDm->backupAmpduMaxTime); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x430); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x434); + u2Tmp[0] = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x42a); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x456); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "0x430/0x434/0x42a/0x456", \ + u4Tmp[0], u4Tmp[1], u2Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x778); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x ", "0x778 (W_Act)/ 0x6cc (CoTab Sel)", \ + u1Tmp[0], u1Tmp[1]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x8db); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xc5b); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x8db(ADC)/0xc5b[29:25](DAC)", \ + ((u1Tmp[0]&0x60)>>5), ((u1Tmp[1]&0x3e)>>1)); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xcb3); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xcb7); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0xcb3/ 0xcb7", \ + u1Tmp[0], u1Tmp[1]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x974); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x40/ 0x4c[24:23]/ 0x974", \ + u1Tmp[0], ((u4Tmp[0]&0x01800000)>>23), u4Tmp[1]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x550); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x522); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa0a); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0xc50(DIG)/0xa0a(CCK-TH)", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xf48); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5b); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5c); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0xf48/ 0xa5b (FA cnt-- OFDM : CCK)", \ + u4Tmp[0], (u1Tmp[0]<<8) + u1Tmp[1] ); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp[0]); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)", \ + pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", \ + pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); + CL_PRINTF(cliBuf); +#if(BT_AUTO_REPORT_ONLY_8812A_2ANT == 1) + halbtc8812a2ant_MonitorBtCtr(pBtCoexist); +#endif + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8812a2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + pCoexSta->bUnderIps = TRUE; + halbtc8812a2ant_CoexAllOff(pBtCoexist); + halbtc8812a2ant_SetAntPath(pBtCoexist, BTC_ANT_WIFI_AT_CPL_AUX, FALSE, TRUE); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + pCoexSta->bUnderIps = FALSE; + } +} + +VOID +EXhalbtc8812a2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + pCoexSta->bUnderLps = TRUE; + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + pCoexSta->bUnderLps = FALSE; + } +} + +VOID +EXhalbtc8812a2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + } +} + +VOID +EXhalbtc8812a2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + } +} + +VOID +EXhalbtc8812a2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u1Byte dataLen=5; + u1Byte buf[6] = {0}; + u1Byte H2C_Parameter[3] ={0}; + u4Byte wifiBw; + u1Byte wifiCentralChnl; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } + + // only 2.4G we need to inform bt the chnl mask + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); + if( (BTC_MEDIA_CONNECT == type) && + (wifiCentralChnl <= 14) ) + { + H2C_Parameter[0] = 0x1; + H2C_Parameter[1] = wifiCentralChnl; + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + H2C_Parameter[2] = 0x30; + else + H2C_Parameter[2] = 0x20; + } + + pCoexDm->wifiChnlInfo[0] = H2C_Parameter[0]; + pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1]; + pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2]; + + buf[0] = dataLen; + buf[1] = 0x5; // OP_Code + buf[2] = 0x3; // OP_Code_Length + buf[3] = H2C_Parameter[0]; // OP_Code_Content + buf[4] = H2C_Parameter[1]; + buf[5] = H2C_Parameter[2]; + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); +} + +VOID +EXhalbtc8812a2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(type == BTC_PACKET_DHCP) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], DHCP Packet notify\n")); + } +} + +VOID +EXhalbtc8812a2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + u1Byte btInfo=0; + u1Byte i, rspSource=0; + BOOLEAN bBtBusy=FALSE, bLimitedDig=FALSE; + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE, bWifiUnder5G=FALSE; + + pCoexSta->bC2hBtInfoReqSent = FALSE; + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + + rspSource = tmpBuf[0]&0xf; + if(rspSource >= BT_INFO_SRC_8812A_2ANT_MAX) + rspSource = BT_INFO_SRC_8812A_2ANT_WIFI_FW; + pCoexSta->btInfoC2hCnt[rspSource]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rspSource, length)); + for(i=0; i<length; i++) + { + pCoexSta->btInfoC2h[rspSource][i] = tmpBuf[i]; + if(i == 1) + btInfo = tmpBuf[i]; + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); + } + } + + if(BT_INFO_SRC_8812A_2ANT_WIFI_FW != rspSource) + { + pCoexSta->btRetryCnt = // [3:0] + pCoexSta->btInfoC2h[rspSource][2]&0xf; + + pCoexSta->btRssi = + pCoexSta->btInfoC2h[rspSource][3]*2+10; + + pCoexSta->btInfoExt = + pCoexSta->btInfoC2h[rspSource][4]; + + // Here we need to resend some wifi info to BT + // because bt is reset and loss of the info. + if( (pCoexSta->btInfoExt & BIT1) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n")); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(bWifiConnected) + { + EXhalbtc8812a2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_CONNECT); + } + else + { + EXhalbtc8812a2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); + } + } + + if( (pCoexSta->btInfoExt&BIT3) && !bWifiUnder5G) + { + if(!pBtCoexist->bManualControl && !pBtCoexist->bStopCoexDm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n")); + halbtc8812a2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); + } + } + else + { + // BT already NOT ignore Wlan active, do nothing here. + } + } + + // check BIT2 first ==> check if bt is under inquiry or page scan + if(btInfo & BT_INFO_8812A_2ANT_B_INQ_PAGE) + pCoexSta->bC2hBtInquiryPage = TRUE; + else + pCoexSta->bC2hBtInquiryPage = FALSE; + + // set link exist status + if(!(btInfo&BT_INFO_8812A_2ANT_B_CONNECTION)) + { + pCoexSta->bBtLinkExist = FALSE; + pCoexSta->bPanExist = FALSE; + pCoexSta->bA2dpExist = FALSE; + pCoexSta->bHidExist = FALSE; + pCoexSta->bScoExist = FALSE; + } + else // connection exists + { + pCoexSta->bBtLinkExist = TRUE; + if(btInfo & BT_INFO_8812A_2ANT_B_FTP) + pCoexSta->bPanExist = TRUE; + else + pCoexSta->bPanExist = FALSE; + if(btInfo & BT_INFO_8812A_2ANT_B_A2DP) + pCoexSta->bA2dpExist = TRUE; + else + pCoexSta->bA2dpExist = FALSE; + if(btInfo & BT_INFO_8812A_2ANT_B_HID) + pCoexSta->bHidExist = TRUE; + else + pCoexSta->bHidExist = FALSE; + if(btInfo & BT_INFO_8812A_2ANT_B_SCO_ESCO) + pCoexSta->bScoExist = TRUE; + else + pCoexSta->bScoExist = FALSE; + } + + halbtc8812a2ant_UpdateBtLinkInfo(pBtCoexist); + + if(!(btInfo&BT_INFO_8812A_2ANT_B_CONNECTION)) + { + pCoexDm->btStatus = BT_8812A_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n")); + } + else if(btInfo == BT_INFO_8812A_2ANT_B_CONNECTION) // connection exists but no busy + { + pCoexDm->btStatus = BT_8812A_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n")); + } + else if((btInfo&BT_INFO_8812A_2ANT_B_SCO_ESCO) || + (btInfo&BT_INFO_8812A_2ANT_B_SCO_BUSY)) + { + pCoexDm->btStatus = BT_8812A_2ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT SCO busy!!!\n")); + } + else if(btInfo&BT_INFO_8812A_2ANT_B_ACL_BUSY) + { + pCoexDm->btStatus = BT_8812A_2ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT ACL busy!!!\n")); + } + else + { + pCoexDm->btStatus = BT_8812A_2ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n")); + } + + if( (BT_8812A_2ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || + (BT_8812A_2ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8812A_2ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + bBtBusy = TRUE; + if(!bWifiUnder5G) + bLimitedDig = TRUE; + } + else + { + bBtBusy = FALSE; + bLimitedDig = FALSE; + } + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + + pCoexDm->bLimitedDig = bLimitedDig; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_LIMITED_DIG, &bLimitedDig); + + halbtc8812a2ant_RunCoexistMechanism(pBtCoexist); +} + +VOID +EXhalbtc8812a2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte u1Tmp=0; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + halbtc8812a2ant_SetAntPath(pBtCoexist, BTC_ANT_WIFI_AT_CPL_AUX, FALSE, TRUE); + halbtc8812a2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + EXhalbtc8812a2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); + + // 0x522=0xff, pause tx + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x522, 0xff); + // 0x40[7:6]=2'b01, modify BT mode. + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x40, 0xc0, 0x2); +} + +VOID +EXhalbtc8812a2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + static u1Byte disVerInfoCnt=0; + u4Byte fwVer=0, btPatchVer=0; + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ==========================Periodical===========================\n")); + + if(disVerInfoCnt <= 5) + { + disVerInfoCnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum, pBoardInfo->btdmAntPos)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], BT stack/ hci ext ver = %s / %d\n", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion)); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", \ + GLCoexVerDate8812a2Ant, GLCoexVer8812a2Ant, fwVer, btPatchVer, btPatchVer)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + } + +#if(BT_AUTO_REPORT_ONLY_8812A_2ANT == 0) + halbtc8812a2ant_QueryBtInfo(pBtCoexist); + halbtc8812a2ant_MonitorBtCtr(pBtCoexist); + halbtc8812a2ant_MonitorBtEnableDisable(pBtCoexist); +#else + if( halbtc8812a2ant_IsWifiStatusChanged(pBtCoexist) || + pCoexDm->bAutoTdmaAdjust || + pCoexDm->bAutoTdmaAdjustLowRssi) + { + halbtc8812a2ant_RunCoexistMechanism(pBtCoexist); + } +#endif +} + +VOID +EXhalbtc8812a2ant_DbgControl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte opCode, + IN u1Byte opLen, + IN pu1Byte pData + ) +{ + switch(opCode) + { + case BTC_DBG_SET_COEX_DEC_BT_PWR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set Dec BT power\n")); + { + u1Byte dataLen=4; + u1Byte buf[6] = {0}; + u1Byte decBtPwr=0, pwrLevel=0; + if(opLen == 2) + { + decBtPwr = pData[0]; + pwrLevel = pData[1]; + + buf[0] = dataLen; + buf[1] = 0x3; // OP_Code + buf[2] = 0x2; // OP_Code_Length + + buf[3] = decBtPwr; // OP_Code_Content + buf[4] = pwrLevel; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set Dec BT power=%d, pwrLevel=%d\n", decBtPwr, pwrLevel)); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); + } + } + break; + + case BTC_DBG_SET_COEX_BT_AFH_MAP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set BT AFH Map\n")); + { + u1Byte dataLen=5; + u1Byte buf[6] = {0}; + if(opLen == 3) + { + buf[0] = dataLen; + buf[1] = 0x5; // OP_Code + buf[2] = 0x3; // OP_Code_Length + + buf[3] = pData[0]; // OP_Code_Content + buf[4] = pData[1]; + buf[5] = pData[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set BT AFH Map = %02x %02x %02x\n", + pData[0], pData[1], pData[2])); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); + } + } + break; + + case BTC_DBG_SET_COEX_BT_IGNORE_WLAN_ACT: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set BT Ignore Wlan Active\n")); + { + u1Byte dataLen=3; + u1Byte buf[6] = {0}; + if(opLen == 1) + { + buf[0] = dataLen; + buf[1] = 0x1; // OP_Code + buf[2] = 0x1; // OP_Code_Length + + buf[3] = pData[0]; // OP_Code_Content + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Set BT Ignore Wlan Active = 0x%x\n", + pData[0])); + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_CTRL_BT_COEX, (PVOID)&buf[0]); + } + } + break; + + default: + break; + } +} + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a2Ant.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a2Ant.h new file mode 100644 index 0000000..c46ee74 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8812a2Ant.h @@ -0,0 +1,213 @@ +//=========================================== +// The following is for 8812A 2Ant BT Co-exist definition +//=========================================== +#define BT_AUTO_REPORT_ONLY_8812A_2ANT 0 + +#define BT_INFO_8812A_2ANT_B_FTP BIT7 +#define BT_INFO_8812A_2ANT_B_A2DP BIT6 +#define BT_INFO_8812A_2ANT_B_HID BIT5 +#define BT_INFO_8812A_2ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8812A_2ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8812A_2ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8812A_2ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8812A_2ANT_B_CONNECTION BIT0 + +#define BT_INFO_8812A_2ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT0))? TRUE:FALSE) + +#define BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT 2 + +typedef enum _BT_INFO_SRC_8812A_2ANT{ + BT_INFO_SRC_8812A_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8812A_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8812A_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8812A_2ANT_MAX +}BT_INFO_SRC_8812A_2ANT,*PBT_INFO_SRC_8812A_2ANT; + +typedef enum _BT_8812A_2ANT_BT_STATUS{ + BT_8812A_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8812A_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8812A_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8812A_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8812A_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8812A_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8812A_2ANT_BT_STATUS_MAX +}BT_8812A_2ANT_BT_STATUS,*PBT_8812A_2ANT_BT_STATUS; + +typedef enum _BT_8812A_2ANT_COEX_ALGO{ + BT_8812A_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8812A_2ANT_COEX_ALGO_SCO = 0x1, + BT_8812A_2ANT_COEX_ALGO_SCO_HID = 0x2, + BT_8812A_2ANT_COEX_ALGO_HID = 0x3, + BT_8812A_2ANT_COEX_ALGO_A2DP = 0x4, + BT_8812A_2ANT_COEX_ALGO_A2DP_PANHS = 0x5, + BT_8812A_2ANT_COEX_ALGO_PANEDR = 0x6, + BT_8812A_2ANT_COEX_ALGO_PANHS = 0x7, + BT_8812A_2ANT_COEX_ALGO_PANEDR_A2DP = 0x8, + BT_8812A_2ANT_COEX_ALGO_PANEDR_HID = 0x9, + BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0xa, + BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANHS = 0xb, + BT_8812A_2ANT_COEX_ALGO_HID_A2DP = 0xc, + BT_8812A_2ANT_COEX_ALGO_MAX = 0xd +}BT_8812A_2ANT_COEX_ALGO,*PBT_8812A_2ANT_COEX_ALGO; + +typedef struct _COEX_DM_8812A_2ANT{ + // fw mechanism + u1Byte preBtDecPwrLvl; + u1Byte curBtDecPwrLvl; + u1Byte preFwDacSwingLvl; + u1Byte curFwDacSwingLvl; + BOOLEAN bCurIgnoreWlanAct; + BOOLEAN bPreIgnoreWlanAct; + u1Byte prePsTdma; + u1Byte curPsTdma; + u1Byte psTdmaPara[5]; + u1Byte psTdmaDuAdjType; + BOOLEAN bAutoTdmaAdjust; + BOOLEAN bAutoTdmaAdjustLowRssi; + BOOLEAN bPrePsTdmaOn; + BOOLEAN bCurPsTdmaOn; + BOOLEAN bPreBtAutoReport; + BOOLEAN bCurBtAutoReport; + u1Byte preLps; + u1Byte curLps; + u1Byte preRpwm; + u1Byte curRpwm; + + // sw mechanism + BOOLEAN bPreRfRxLpfShrink; + BOOLEAN bCurRfRxLpfShrink; + u4Byte btRf0x1eBackup; + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + BOOLEAN bPreDacSwingOn; + u4Byte preDacSwingLvl; + BOOLEAN bCurDacSwingOn; + u4Byte curDacSwingLvl; + BOOLEAN bPreAdcBackOff; + BOOLEAN bCurAdcBackOff; + BOOLEAN bPreAgcTableEn; + BOOLEAN bCurAgcTableEn; + u4Byte preVal0x6c0; + u4Byte curVal0x6c0; + u4Byte preVal0x6c4; + u4Byte curVal0x6c4; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u1Byte preVal0x6cc; + u1Byte curVal0x6cc; + BOOLEAN bLimitedDig; + u4Byte backupArfrCnt1; // Auto Rate Fallback Retry cnt + u4Byte backupArfrCnt2; // Auto Rate Fallback Retry cnt + u2Byte backupRetryLimit; + u1Byte backupAmpduMaxTime; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + u1Byte btStatus; + u1Byte wifiChnlInfo[3]; + + u4Byte preRaMask; + u4Byte curRaMask; + u1Byte curRaMaskType; + u1Byte preArfrType; + u1Byte curArfrType; + u1Byte preRetryLimitType; + u1Byte curRetryLimitType; + u1Byte preAmpduTimeType; + u1Byte curAmpduTimeType; +} COEX_DM_8812A_2ANT, *PCOEX_DM_8812A_2ANT; + +typedef struct _COEX_STA_8812A_2ANT{ + BOOLEAN bBtLinkExist; + BOOLEAN bScoExist; + BOOLEAN bA2dpExist; + BOOLEAN bHidExist; + BOOLEAN bPanExist; + + BOOLEAN bUnderLps; + BOOLEAN bUnderIps; + u4Byte highPriorityTx; + u4Byte highPriorityRx; + u4Byte lowPriorityTx; + u4Byte lowPriorityRx; + u1Byte btRssi; + u1Byte preBtRssiState; + u1Byte preWifiRssiState[4]; + BOOLEAN bC2hBtInfoReqSent; + u1Byte btInfoC2h[BT_INFO_SRC_8812A_2ANT_MAX][10]; + u4Byte btInfoC2hCnt[BT_INFO_SRC_8812A_2ANT_MAX]; + u4Byte btInfoQueryCnt; + BOOLEAN bC2hBtInquiryPage; + u1Byte btRetryCnt; + u1Byte btInfoExt; +}COEX_STA_8812A_2ANT, *PCOEX_STA_8812A_2ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8812a2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8812a2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8812a2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8812a2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8812a2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8812a2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8812a2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8812a2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8812a2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8812a2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8812a2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8812a2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8812a2ant_DbgControl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte opCode, + IN u1Byte opLen, + IN pu1Byte pData + ); + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a1Ant.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a1Ant.c new file mode 100644 index 0000000..77934a6 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a1Ant.c @@ -0,0 +1,3223 @@ +//============================================================ +// Description: +// +// This file is for RTL8821A Co-exist mechanism +// +// History +// 2012/11/15 Cosa first check in. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8821A_1ANT GLCoexDm8821a1Ant; +static PCOEX_DM_8821A_1ANT pCoexDm=&GLCoexDm8821a1Ant; +static COEX_STA_8821A_1ANT GLCoexSta8821a1Ant; +static PCOEX_STA_8821A_1ANT pCoexSta=&GLCoexSta8821a1Ant; + +const char *const GLBtInfoSrc8821a1Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u4Byte GLCoexVerDate8821a1Ant=20130816; +u4Byte GLCoexVer8821a1Ant=0x41; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8821a1ant_ +//============================================================ +u1Byte +halbtc8821a1ant_BtRssiState( + u1Byte levelNum, + u1Byte rssiThresh, + u1Byte rssiThresh1 + ) +{ + s4Byte btRssi=0; + u1Byte btRssiState=pCoexSta->preBtRssiState; + + btRssi = pCoexSta->btRssi; + + if(levelNum == 2) + { + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else + { + if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); + return pCoexSta->preBtRssiState; + } + + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); + } + } + else + { + if(btRssi < rssiThresh1) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + + pCoexSta->preBtRssiState = btRssiState; + + return btRssiState; +} + +u1Byte +halbtc8821a1ant_WifiRssiState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte index, + IN u1Byte levelNum, + IN u1Byte rssiThresh, + IN u1Byte rssiThresh1 + ) +{ + s4Byte wifiRssi=0; + u1Byte wifiRssiState=pCoexSta->preWifiRssiState[index]; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(levelNum == 2) + { + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return pCoexSta->preWifiRssiState[index]; + } + + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifiRssi < rssiThresh1) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + pCoexSta->preWifiRssiState[index] = wifiRssiState; + + return wifiRssiState; +} + +VOID +halbtc8821a1ant_UpdateRaMask( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte disRateMask + ) +{ + pCoexDm->curRaMask = disRateMask; + + if( bForceExec || (pCoexDm->preRaMask != pCoexDm->curRaMask)) + { + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_UPDATE_RAMASK, &pCoexDm->curRaMask); + } + pCoexDm->preRaMask = pCoexDm->curRaMask; +} + +VOID +halbtc8821a1ant_AutoRateFallbackRetry( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + BOOLEAN bWifiUnderBMode=FALSE; + + pCoexDm->curArfrType = type; + + if( bForceExec || (pCoexDm->preArfrType != pCoexDm->curArfrType)) + { + switch(pCoexDm->curArfrType) + { + case 0: // normal mode + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, pCoexDm->backupArfrCnt1); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, pCoexDm->backupArfrCnt2); + break; + case 1: + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, &bWifiUnderBMode); + if(bWifiUnderBMode) + { + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, 0x0); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, 0x01010101); + } + else + { + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x430, 0x0); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x434, 0x04030201); + } + break; + default: + break; + } + } + + pCoexDm->preArfrType = pCoexDm->curArfrType; +} + +VOID +halbtc8821a1ant_RetryLimit( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + pCoexDm->curRetryLimitType = type; + + if( bForceExec || (pCoexDm->preRetryLimitType != pCoexDm->curRetryLimitType)) + { + switch(pCoexDm->curRetryLimitType) + { + case 0: // normal mode + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x42a, pCoexDm->backupRetryLimit); + break; + case 1: // retry limit=8 + pBtCoexist->fBtcWrite2Byte(pBtCoexist, 0x42a, 0x0808); + break; + default: + break; + } + } + + pCoexDm->preRetryLimitType = pCoexDm->curRetryLimitType; +} + +VOID +halbtc8821a1ant_AmpduMaxTime( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + pCoexDm->curAmpduTimeType = type; + + if( bForceExec || (pCoexDm->preAmpduTimeType != pCoexDm->curAmpduTimeType)) + { + switch(pCoexDm->curAmpduTimeType) + { + case 0: // normal mode + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x456, pCoexDm->backupAmpduMaxTime); + break; + case 1: // AMPDU timw = 0x38 * 32us + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x456, 0x38); + break; + default: + break; + } + } + + pCoexDm->preAmpduTimeType = pCoexDm->curAmpduTimeType; +} + +VOID +halbtc8821a1ant_LimitedTx( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte raMaskType, + IN u1Byte arfrType, + IN u1Byte retryLimitType, + IN u1Byte ampduTimeType + ) +{ + switch(raMaskType) + { + case 0: // normal mode + halbtc8821a1ant_UpdateRaMask(pBtCoexist, bForceExec, 0x0); + break; + case 1: // disable cck 1/2 + halbtc8821a1ant_UpdateRaMask(pBtCoexist, bForceExec, 0x00000003); + break; + case 2: // disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 + halbtc8821a1ant_UpdateRaMask(pBtCoexist, bForceExec, 0x0001f1f7); + break; + default: + break; + } + + halbtc8821a1ant_AutoRateFallbackRetry(pBtCoexist, bForceExec, arfrType); + halbtc8821a1ant_RetryLimit(pBtCoexist, bForceExec, retryLimitType); + halbtc8821a1ant_AmpduMaxTime(pBtCoexist, bForceExec, ampduTimeType); +} + +VOID +halbtc8821a1ant_LimitedRx( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRejApAggPkt, + IN BOOLEAN bBtCtrlAggBufSize, + IN u1Byte aggBufSize + ) +{ + BOOLEAN bRejectRxAgg=bRejApAggPkt; + BOOLEAN bBtCtrlRxAggSize=bBtCtrlAggBufSize; + u1Byte rxAggSize=aggBufSize; + + //============================================ + // Rx Aggregation related setting + //============================================ + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, &bRejectRxAgg); + // decide BT control aggregation buf size or not + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, &bBtCtrlRxAggSize); + // aggregation buf size, only work when BT control Rx aggregation size. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_AGG_BUF_SIZE, &rxAggSize); + // real update aggregation setting + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +VOID +halbtc8821a1ant_MonitorBtCtr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte regHPTxRx, regLPTxRx, u4Tmp, u4Tmp1; + u4Byte regHPTx=0, regHPRx=0, regLPTx=0, regLPRx=0; + u1Byte u1Tmp, u1Tmp1; + s4Byte wifiRssi; + + regHPTxRx = 0x770; + regLPTxRx = 0x774; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); + regHPTx = u4Tmp & bMaskLWord; + regHPRx = (u4Tmp & bMaskHWord)>>16; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); + regLPTx = u4Tmp & bMaskLWord; + regLPRx = (u4Tmp & bMaskHWord)>>16; + + pCoexSta->highPriorityTx = regHPTx; + pCoexSta->highPriorityRx = regHPRx; + pCoexSta->lowPriorityTx = regLPTx; + pCoexSta->lowPriorityRx = regLPRx; + + // reset counter + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); +} + +VOID +halbtc8821a1ant_QueryBtInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + pCoexSta->bC2hBtInfoReqSent = TRUE; + + H2C_Parameter[0] |= BIT0; // trigger + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Query Bt Info, FW write 0x61=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x61, 1, H2C_Parameter); +} + +BOOLEAN +halbtc8821a1ant_IsWifiStatusChanged( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreWifiBusy=FALSE, bPreUnder4way=FALSE, bPreBtHsOn=FALSE; + BOOLEAN bWifiBusy=FALSE, bUnder4way=FALSE, bBtHsOn=FALSE; + BOOLEAN bWifiConnected=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); + + if(bWifiConnected) + { + if(bWifiBusy != bPreWifiBusy) + { + bPreWifiBusy = bWifiBusy; + return TRUE; + } + if(bUnder4way != bPreUnder4way) + { + bPreUnder4way = bUnder4way; + return TRUE; + } + if(bBtHsOn != bPreBtHsOn) + { + bPreBtHsOn = bBtHsOn; + return TRUE; + } + } + + return FALSE; +} + +VOID +halbtc8821a1ant_UpdateBtLinkInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bBtHsOn=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + pBtLinkInfo->bBtLinkExist = pCoexSta->bBtLinkExist; + pBtLinkInfo->bScoExist = pCoexSta->bScoExist; + pBtLinkInfo->bA2dpExist = pCoexSta->bA2dpExist; + pBtLinkInfo->bPanExist = pCoexSta->bPanExist; + pBtLinkInfo->bHidExist = pCoexSta->bHidExist; + + // work around for HS mode. + if(bBtHsOn) + { + pBtLinkInfo->bPanExist = TRUE; + pBtLinkInfo->bBtLinkExist = TRUE; + } + + // check if Sco only + if( pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bScoOnly = TRUE; + else + pBtLinkInfo->bScoOnly = FALSE; + + // check if A2dp only + if( !pBtLinkInfo->bScoExist && + pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bA2dpOnly = TRUE; + else + pBtLinkInfo->bA2dpOnly = FALSE; + + // check if Pan only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + pBtLinkInfo->bPanExist && + !pBtLinkInfo->bHidExist ) + pBtLinkInfo->bPanOnly = TRUE; + else + pBtLinkInfo->bPanOnly = FALSE; + + // check if Hid only + if( !pBtLinkInfo->bScoExist && + !pBtLinkInfo->bA2dpExist && + !pBtLinkInfo->bPanExist && + pBtLinkInfo->bHidExist ) + pBtLinkInfo->bHidOnly = TRUE; + else + pBtLinkInfo->bHidOnly = FALSE; +} + +u1Byte +halbtc8821a1ant_ActionAlgorithm( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bBtHsOn=FALSE; + u1Byte algorithm=BT_8821A_1ANT_COEX_ALGO_UNDEFINED; + u1Byte numOfDiffProfile=0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + if(!pBtLinkInfo->bBtLinkExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No BT link exists!!!\n")); + return algorithm; + } + + if(pBtLinkInfo->bScoExist) + numOfDiffProfile++; + if(pBtLinkInfo->bHidExist) + numOfDiffProfile++; + if(pBtLinkInfo->bPanExist) + numOfDiffProfile++; + if(pBtLinkInfo->bA2dpExist) + numOfDiffProfile++; + + if(numOfDiffProfile == 1) + { + if(pBtLinkInfo->bScoExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO only\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; + } + else + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID only\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = A2DP only\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_A2DP; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = PAN(HS) only\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = PAN(EDR) only\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR; + } + } + } + } + else if(numOfDiffProfile == 2) + { + if(pBtLinkInfo->bScoExist) + { + if(pBtLinkInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID; + } + else if(pBtLinkInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + A2DP ==> SCO\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; + } + else if(pBtLinkInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + PAN(HS)\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + PAN(EDR)\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + A2DP\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP; + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + PAN(HS)\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + PAN(EDR)\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = A2DP + PAN(HS)\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = A2DP + PAN(EDR)\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } + else if(numOfDiffProfile == 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID; + } + else if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + PAN(HS)\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + else if(numOfDiffProfile >= 3) + { + if(pBtLinkInfo->bScoExist) + { + if( pBtLinkInfo->bHidExist && + pBtLinkInfo->bPanExist && + pBtLinkInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n")); + + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n")); + algorithm = BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +VOID +halbtc8821a1ant_SetBtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnableAutoReport + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = 0; + + if(bEnableAutoReport) + { + H2C_Parameter[0] |= BIT0; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], BT FW auto report : %s, FW write 0x68=0x%x\n", + (bEnableAutoReport? "Enabled!!":"Disabled!!"), H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x68, 1, H2C_Parameter); +} + +VOID +halbtc8821a1ant_BtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnableAutoReport + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT Auto report = %s\n", + (bForceExec? "force to":""), ((bEnableAutoReport)? "Enabled":"Disabled"))); + pCoexDm->bCurBtAutoReport = bEnableAutoReport; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtAutoReport=%d, bCurBtAutoReport=%d\n", + pCoexDm->bPreBtAutoReport, pCoexDm->bCurBtAutoReport)); + + if(pCoexDm->bPreBtAutoReport == pCoexDm->bCurBtAutoReport) + return; + } + halbtc8821a1ant_SetBtAutoReport(pBtCoexist, pCoexDm->bCurBtAutoReport); + + pCoexDm->bPreBtAutoReport = pCoexDm->bCurBtAutoReport; +} + +VOID +halbtc8821a1ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte H2C_Parameter[6] ={0}; + + H2C_Parameter[0] = 0x6; // opCode, 0x6= Retry_Penalty + + if(bLowPenaltyRa) + { + H2C_Parameter[1] |= BIT0; + H2C_Parameter[2] = 0x00; //normal rate except MCS7/6/5, OFDM54/48/36 + H2C_Parameter[3] = 0xf7; //MCS7 or OFDM54 + H2C_Parameter[4] = 0xf8; //MCS6 or OFDM48 + H2C_Parameter[5] = 0xf9; //MCS5 or OFDM36 + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set WiFi Low-Penalty Retry: %s", + (bLowPenaltyRa? "ON!!":"OFF!!") )); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x69, 6, H2C_Parameter); +} + +VOID +halbtc8821a1ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8821a1ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8821a1ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8821a1ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c0, val0x6c4, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c0 = val0x6c0; + pCoexDm->curVal0x6c4 = val0x6c4; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + if( (pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && + (pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8821a1ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c4, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; + pCoexDm->preVal0x6c4 = pCoexDm->curVal0x6c4; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8821a1ant_CoexTableWithType( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte type + ) +{ + switch(type) + { + case 0: + halbtc8821a1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x55555555, 0xffffff, 0x3); + break; + case 1: + halbtc8821a1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8821a1ant_CoexTable(pBtCoexist, bForceExec, 0x5a5a5a5a, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 3: + halbtc8821a1ant_CoexTable(pBtCoexist, bForceExec, 0x55555555, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 4: + halbtc8821a1ant_CoexTable(pBtCoexist, bForceExec, 0xffffffff, 0xffffffff, 0xffffff, 0x3); + break; + case 5: + halbtc8821a1ant_CoexTable(pBtCoexist, bForceExec, 0x5fff5fff, 0x5fff5fff, 0xffffff, 0x3); + break; + case 6: + halbtc8821a1ant_CoexTable(pBtCoexist, bForceExec, 0x55ff55ff, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 7: + halbtc8821a1ant_CoexTable(pBtCoexist, bForceExec, 0x5afa5afa, 0x5afa5afa, 0xffffff, 0x3); + break; + default: + break; + } +} + +VOID +halbtc8821a1ant_SetFwIgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnable + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + if(bEnable) + { + H2C_Parameter[0] |= BIT0; // function enable + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x63, 1, H2C_Parameter); +} + +VOID +halbtc8821a1ant_IgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); + pCoexDm->bCurIgnoreWlanAct = bEnable; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); + + if(pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) + return; + } + halbtc8821a1ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); + + pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; +} + +VOID +halbtc8821a1ant_SetFwPstdma( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte byte1, + IN u1Byte byte2, + IN u1Byte byte3, + IN u1Byte byte4, + IN u1Byte byte5 + ) +{ + u1Byte H2C_Parameter[5] ={0}; + + H2C_Parameter[0] = byte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = byte5; + + pCoexDm->psTdmaPara[0] = byte1; + pCoexDm->psTdmaPara[1] = byte2; + pCoexDm->psTdmaPara[2] = byte3; + pCoexDm->psTdmaPara[3] = byte4; + pCoexDm->psTdmaPara[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], PS-TDMA H2C cmd =0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x60, 5, H2C_Parameter); +} + +VOID +halbtc8821a1ant_SetLpsRpwm( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + u1Byte lps=lpsVal; + u1Byte rpwm=rpwmVal; + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_LPS_VAL, &lps); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +VOID +halbtc8821a1ant_LpsRpwm( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + BOOLEAN bForceExecPwrCmd=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set lps/rpwm=0x%x/0x%x \n", + (bForceExec? "force to":""), lpsVal, rpwmVal)); + pCoexDm->curLps = lpsVal; + pCoexDm->curRpwm = rpwmVal; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], LPS-RxBeaconMode=0x%x , LPS-RPWM=0x%x!!\n", + pCoexDm->curLps, pCoexDm->curRpwm)); + + if( (pCoexDm->preLps == pCoexDm->curLps) && + (pCoexDm->preRpwm == pCoexDm->curRpwm) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], LPS-RPWM_Last=0x%x , LPS-RPWM_Now=0x%x!!\n", + pCoexDm->preRpwm, pCoexDm->curRpwm)); + + return; + } + } + halbtc8821a1ant_SetLpsRpwm(pBtCoexist, lpsVal, rpwmVal); + + pCoexDm->preLps = pCoexDm->curLps; + pCoexDm->preRpwm = pCoexDm->curRpwm; +} + +VOID +halbtc8821a1ant_SwMechanism( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRA + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], SM[LpRA] = %d \n", bLowPenaltyRA)); + + halbtc8821a1ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, bLowPenaltyRA); +} + +VOID +halbtc8821a1ant_SetAntPath( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte antPosType, + IN BOOLEAN bInitHwCfg, + IN BOOLEAN bWifiOff + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + u4Byte fwVer=0, u4Tmp=0; + u1Byte H2C_Parameter[2] ={0}; + + if(bInitHwCfg) + { + // 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u4Tmp &=~BIT23; + u4Tmp |= BIT24; + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); + + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x975, 0x3, 0x3); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xcb4, 0x77); + + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + { + //tell firmware "antenna inverse" ==> WRONG firmware antenna control code.==>need fw to fix + H2C_Parameter[0] = 1; + H2C_Parameter[1] = 1; + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); + + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x64, 0x1, 0x1); //Main Ant to BT for IPS case 0x4c[23]=1 + } + else + { + //tell firmware "no antenna inverse" ==> WRONG firmware antenna control code.==>need fw to fix + H2C_Parameter[0] = 0; + H2C_Parameter[1] = 1; + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); + + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x64, 0x1, 0x0); //Aux Ant to BT for IPS case 0x4c[23]=1 + } + } + else if(bWifiOff) + { + // 0x4c[24:23]=00, Set Antenna control by BT_RFE_CTRL BT Vendor 0xac=0xf002 + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u4Tmp &= ~BIT23; + u4Tmp &= ~BIT24; + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); + } + + // ext switch setting + switch(antPosType) + { + case BTC_ANT_PATH_WIFI: + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xcb7, 0x30, 0x1); + else + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xcb7, 0x30, 0x2); + break; + case BTC_ANT_PATH_BT: + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xcb7, 0x30, 0x2); + else + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xcb7, 0x30, 0x1); + break; + default: + case BTC_ANT_PATH_PTA: + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xcb7, 0x30, 0x1); + else + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xcb7, 0x30, 0x2); + break; + } +} + +VOID +halbtc8821a1ant_PsTdma( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bTurnOn, + IN u1Byte type + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + BOOLEAN bTurnOnByCnt=FALSE; + u1Byte psTdmaTypeByCnt=0, rssiAdjustVal=0; + u4Byte fwVer=0; + + pCoexDm->bCurPsTdmaOn = bTurnOn; + pCoexDm->curPsTdma = type; + + if(!bForceExec) + { + if (pCoexDm->bCurPsTdmaOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], ********** TDMA(on, %d) **********\n", + pCoexDm->curPsTdma)); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], ********** TDMA(off, %d) **********\n", + pCoexDm->curPsTdma)); + } + + + if( (pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && + (pCoexDm->prePsTdma == pCoexDm->curPsTdma) ) + return; + } + if(bTurnOn) + { + switch(type) + { + default: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x51, 0x1a, 0x1a, 0x0, 0x50); + break; + case 1: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x51, 0x3a, 0x03, 0x10, 0x50); + rssiAdjustVal = 11; + break; + case 2: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x51, 0x2b, 0x03, 0x10, 0x50); + rssiAdjustVal = 14; + break; + case 3: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x51, 0x1d, 0x1d, 0x0, 0x10); + break; + case 4: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x14, 0x0); + rssiAdjustVal = 17; + break; + case 5: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x61, 0x15, 0x3, 0x11, 0x10); + break; + case 6: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0x3, 0x0, 0x0); + break; + case 7: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x13, 0xc, 0x5, 0x0, 0x0); + break; + case 8: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x0); + break; + case 9: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x51, 0x21, 0x3, 0x10, 0x50); + rssiAdjustVal = 18; + break; + case 10: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0xa, 0x0, 0x40); + break; + case 11: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x51, 0x14, 0x03, 0x10, 0x10); + rssiAdjustVal = 20; + break; + case 12: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x51, 0x0a, 0x0a, 0x0, 0x50); + break; + case 13: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x51, 0x18, 0x18, 0x0, 0x10); + break; + case 14: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x51, 0x21, 0x3, 0x10, 0x10); + break; + case 15: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x13, 0xa, 0x3, 0x8, 0x0); + break; + case 16: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x93, 0x15, 0x3, 0x10, 0x0); + rssiAdjustVal = 18; + break; + case 18: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x93, 0x25, 0x3, 0x10, 0x0); + rssiAdjustVal = 14; + break; + case 20: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x61, 0x35, 0x03, 0x11, 0x10); + break; + case 21: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x61, 0x15, 0x03, 0x11, 0x10); + break; + case 22: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x61, 0x25, 0x03, 0x11, 0x10); + break; + case 23: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 24: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x15, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 25: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 26: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0x3, 0x31, 0x18); + rssiAdjustVal = 22; + break; + case 27: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x3, 0x31, 0x98); + rssiAdjustVal = 22; + break; + case 28: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x69, 0x25, 0x3, 0x31, 0x0); + break; + case 29: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0xab, 0x1a, 0x1a, 0x1, 0x10); + break; + case 30: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x51, 0x14, 0x3, 0x10, 0x50); + break; + case 31: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x1a, 0x1a, 0, 0x58); + break; + case 32: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x61, 0xa, 0x3, 0x10, 0x0); + break; + case 33: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0xa3, 0x25, 0x3, 0x30, 0x90); + break; + case 34: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x53, 0x1a, 0x1a, 0x0, 0x10); + break; + case 35: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x63, 0x1a, 0x1a, 0x0, 0x10); + break; + case 36: + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0xd3, 0x12, 0x3, 0x14, 0x50); + break; + } + } + else + { + // disable PS tdma + switch(type) + { + case 8: //PTA Control + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x8, 0x0, 0x0, 0x0, 0x0); + halbtc8821a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_PTA, FALSE, FALSE); + break; + case 0: + default: //Software control, Antenna at BT side + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + halbtc8821a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, FALSE); + break; + case 9: //Software control, Antenna at WiFi side + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x0, 0x0); + halbtc8821a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_WIFI, FALSE, FALSE); + break; + case 10: // under 5G + halbtc8821a1ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x8, 0x0); + halbtc8821a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, FALSE); + break; + } + } + rssiAdjustVal =0; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssiAdjustVal); + + // update pre state + pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; + pCoexDm->prePsTdma = pCoexDm->curPsTdma; +} + +VOID +halbtc8821a1ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + // sw all off + halbtc8821a1ant_SwMechanism(pBtCoexist, FALSE); + + // hw all off + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +BOOLEAN +halbtc8821a1ant_IsCommonAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bCommon=FALSE, bWifiConnected=FALSE, bWifiBusy=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + + if(!bWifiConnected && + BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n")); + halbtc8821a1ant_SwMechanism(pBtCoexist, FALSE); + + bCommon = TRUE; + } + else if(bWifiConnected && + (BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT non connected-idle!!\n")); + halbtc8821a1ant_SwMechanism(pBtCoexist, FALSE); + + bCommon = TRUE; + } + else if(!bWifiConnected && + (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT connected-idle!!\n")); + halbtc8821a1ant_SwMechanism(pBtCoexist, FALSE); + + bCommon = TRUE; + } + else if(bWifiConnected && + (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi connected + BT connected-idle!!\n")); + halbtc8821a1ant_SwMechanism(pBtCoexist, FALSE); + + bCommon = TRUE; + } + else if(!bWifiConnected && + (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE != pCoexDm->btStatus) ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi non connected-idle + BT Busy!!\n")); + halbtc8821a1ant_SwMechanism(pBtCoexist, FALSE); + + bCommon = TRUE; + } + else + { + if (bWifiBusy) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Busy + BT Busy!!\n")); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Connected-Idle + BT Busy!!\n")); + } + + bCommon = FALSE; + } + + return bCommon; +} + + +VOID +halbtc8821a1ant_TdmaDurationAdjustForAcl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0, btInfoExt; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjustForAcl()\n")); + + if( (BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) || + (BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifiStatus) || + (BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == wifiStatus) ) + { + if( pCoexDm->curPsTdma != 1 && + pCoexDm->curPsTdma != 2 && + pCoexDm->curPsTdma != 3 && + pCoexDm->curPsTdma != 9 ) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + return; + } + + if(!pCoexDm->bAutoTdmaAdjust) + { + pCoexDm->bAutoTdmaAdjust = TRUE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); + + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + btInfoExt = pCoexSta->btInfoExt; + //BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); + //BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n", + // up, dn, m, n, WaitCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if �s�� n ��2�� retry count��0, �h�ռeWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration + { + if (WaitCount <= 2) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration + { + if (WaitCount == 1) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + if(result == -1) + { + if( (BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(btInfoExt)) && + ((pCoexDm->curPsTdma == 1) ||(pCoexDm->curPsTdma == 2)) ) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + else if(result == 1) + { + if( (BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(btInfoExt)) && + ((pCoexDm->curPsTdma == 1) ||(pCoexDm->curPsTdma == 2)) ) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + } + else //no change + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], ********** TDMA(on, %d) **********\n", + pCoexDm->curPsTdma)); + } + + if( pCoexDm->curPsTdma != 1 && + pCoexDm->curPsTdma != 2 && + pCoexDm->curPsTdma != 9 && + pCoexDm->curPsTdma != 11 ) + { + // recover to previous adjust type + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, pCoexDm->psTdmaDuAdjType); + } + } +} + +VOID +halbtc8821a1ant_PsTdmaCheckForPowerSaveState( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bNewPsState + ) +{ + u1Byte lpsMode=0x0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_LPS_MODE, &lpsMode); + + if(lpsMode) // already under LPS state + { + if(bNewPsState) + { + // keep state under LPS, do nothing. + } + else + { + // will leave LPS state, turn off psTdma first + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + } + else // NO PS state + { + if(bNewPsState) + { + // will enter LPS state, turn off psTdma first + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); + } + else + { + // keep state under NO PS state, do nothing. + } + } +} + +VOID +halbtc8821a1ant_PowerSaveState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte psType, + IN u1Byte lpsVal, + IN u1Byte rpwmVal + ) +{ + BOOLEAN bLowPwrDisable=FALSE; + + switch(psType) + { + case BTC_PS_WIFI_NATIVE: + // recover to original 32k low power setting + bLowPwrDisable = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + break; + case BTC_PS_LPS_ON: + halbtc8821a1ant_PsTdmaCheckForPowerSaveState(pBtCoexist, TRUE); + halbtc8821a1ant_LpsRpwm(pBtCoexist, NORMAL_EXEC, lpsVal, rpwmVal); + // when coex force to enter LPS, do not enter 32k low power. + bLowPwrDisable = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + // power save must executed before psTdma. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_ENTER_LPS, NULL); + break; + case BTC_PS_LPS_OFF: + halbtc8821a1ant_PsTdmaCheckForPowerSaveState(pBtCoexist, FALSE); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + break; + default: + break; + } +} + +VOID +halbtc8821a1ant_CoexUnder5G( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8821a1ant_IgnoreWlanAct(pBtCoexist, NORMAL_EXEC, TRUE); + + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 10); + + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + + halbtc8821a1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); + + halbtc8821a1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, FALSE, 5); +} + +#define WIFI_ONLY_CHECK_UNDER_5G +#ifdef WIFI_ONLY_CHECK_UNDER_5G +VOID +halbtc8821a1ant_ActionWifiOnly( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiUnder5G=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + + if (bWifiUnder5G) + { + halbtc8821a1ant_CoexUnder5G(pBtCoexist); + return; + } + else + { + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + } +} +#else +VOID +halbtc8821a1ant_ActionWifiOnly( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); +} +#endif + +VOID +halbtc8821a1ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtActive=TRUE, bBtDisabled=FALSE; + + // This function check if bt is disabled + + if( pCoexSta->highPriorityTx == 0 && + pCoexSta->highPriorityRx == 0 && + pCoexSta->lowPriorityTx == 0 && + pCoexSta->lowPriorityRx == 0) + { + bBtActive = FALSE; + } + if( pCoexSta->highPriorityTx == 0xffff && + pCoexSta->highPriorityRx == 0xffff && + pCoexSta->lowPriorityTx == 0xffff && + pCoexSta->lowPriorityRx == 0xffff) + { + bBtActive = FALSE; + } + if(bBtActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + halbtc8821a1ant_ActionWifiOnly(pBtCoexist); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + bPreBtDisabled = bBtDisabled; + if(!bBtDisabled) + { + } + else + { + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_LEAVE_LPS, NULL); + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_NORMAL_LPS, NULL); + } + } +} + +//============================================= +// +// Software Coex Mechanism start +// +//============================================= + +// SCO only or SCO+PAN(HS) +VOID +halbtc8821a1ant_ActionSco( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_SwMechanism(pBtCoexist, TRUE); +} + +VOID +halbtc8821a1ant_ActionHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_SwMechanism(pBtCoexist, TRUE); +} + +//A2DP only / PAN(EDR) only/ A2DP+PAN(HS) +VOID +halbtc8821a1ant_ActionA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_SwMechanism(pBtCoexist, FALSE); +} + +VOID +halbtc8821a1ant_ActionA2dpPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_SwMechanism(pBtCoexist, FALSE); +} + +VOID +halbtc8821a1ant_ActionPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_SwMechanism(pBtCoexist, FALSE); +} + +//PAN(HS) only +VOID +halbtc8821a1ant_ActionPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_SwMechanism(pBtCoexist, FALSE); +} + +//PAN(EDR)+A2DP +VOID +halbtc8821a1ant_ActionPanEdrA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_SwMechanism(pBtCoexist, FALSE); +} + +VOID +halbtc8821a1ant_ActionPanEdrHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_SwMechanism(pBtCoexist, TRUE); +} + +// HID+A2DP+PAN(EDR) +VOID +halbtc8821a1ant_ActionHidA2dpPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_SwMechanism(pBtCoexist, TRUE); +} + +VOID +halbtc8821a1ant_ActionHidA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_SwMechanism(pBtCoexist, TRUE); +} + +//============================================= +// +// Non-Software Coex Mechanism start +// +//============================================= + +VOID +halbtc8821a1ant_ActionHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 2); +} + +VOID +halbtc8821a1ant_ActionBtInquiry( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bWifiConnected=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + if(!bWifiConnected) + { + halbtc8821a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + else if( (pBtLinkInfo->bScoExist) || + (pBtLinkInfo->bHidOnly) ) + { + // SCO/HID-only busy + halbtc8821a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 32); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + else + { + halbtc8821a1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 30); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } +} + +VOID +halbtc8821a1ant_ActionBtScoHidOnlyBusy( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + // tdma and coex table + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + + if(BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == wifiStatus) + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + else + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); +} + +VOID +halbtc8821a1ant_ActionWifiConnectedBtAclBusy( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte wifiStatus + ) +{ + u1Byte btRssiState; + + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + btRssiState = halbtc8821a1ant_BtRssiState(2, 28, 0); + + if(pBtLinkInfo->bHidOnly) //HID + { + halbtc8821a1ant_ActionBtScoHidOnlyBusy(pBtCoexist, wifiStatus); + pCoexDm->bAutoTdmaAdjust = FALSE; + return; + } + else if(pBtLinkInfo->bA2dpOnly) //A2DP + { + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a1ant_TdmaDurationAdjustForAcl(pBtCoexist, wifiStatus); + } + else //for low BT RSSI + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + else if(pBtLinkInfo->bHidExist&&pBtLinkInfo->bA2dpExist) //HID+A2DP + { + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + else //for low BT RSSI + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + else if( (pBtLinkInfo->bPanOnly) || (pBtLinkInfo->bHidExist&&pBtLinkInfo->bPanExist) ) //PAN(OPP,FTP), HID+PAN(OPP,FTP) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + else if ( ((pBtLinkInfo->bA2dpExist) && (pBtLinkInfo->bPanExist)) || + (pBtLinkInfo->bHidExist&&pBtLinkInfo->bA2dpExist&&pBtLinkInfo->bPanExist) ) //A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + pCoexDm->bAutoTdmaAdjust = FALSE; + } + else + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + pCoexDm->bAutoTdmaAdjust = FALSE; + } +} + +VOID +halbtc8821a1ant_ActionWifiNotConnected( + IN PBTC_COEXIST pBtCoexist + ) +{ + // power save state + halbtc8821a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); +} + +VOID +halbtc8821a1ant_ActionWifiNotConnectedAssoAuthScan( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 22); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); +} + +VOID +halbtc8821a1ant_ActionWifiConnectedScan( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + + // power save state + halbtc8821a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + if(BT_8821A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + if(pBtLinkInfo->bA2dpExist && pBtLinkInfo->bPanExist) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 22); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + else + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 20); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + } + else if( (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8821a1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } + else + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 20); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } +} + +VOID +halbtc8821a1ant_ActionWifiConnectedSpecialPacket( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bHsConnecting=FALSE; + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_CONNECTING, &bHsConnecting); + + halbtc8821a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + if(BT_8821A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + if(pBtLinkInfo->bA2dpExist && pBtLinkInfo->bPanExist) + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 22); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + else + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 20); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } + } + else + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 20); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 1); + } +} + +VOID +halbtc8821a1ant_ActionWifiConnected( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bWifiBusy=FALSE; + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + BOOLEAN bUnder4way=FALSE; + u4Byte wifiBw; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect()===>\n")); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, &bUnder4way); + if(bUnder4way) + { + halbtc8821a1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n")); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + if(bScan || bLink || bRoam) + { + halbtc8821a1ant_ActionWifiConnectedScan(pBtCoexist); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n")); + return; + } + + // power save state + if(BT_8821A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus && !pBtCoexist->btLinkInfo.bHidOnly) + halbtc8821a1ant_PowerSaveState(pBtCoexist, BTC_PS_LPS_ON, 0x50, 0x4); + else + halbtc8821a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + // tdma and coex table + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + if(!bWifiBusy) + { + if(BT_8821A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8821a1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } + else if( (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8821a1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } + else + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + } + else + { + if(BT_8821A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) + { + halbtc8821a1ant_ActionWifiConnectedBtAclBusy(pBtCoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } + else if( (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + halbtc8821a1ant_ActionBtScoHidOnlyBusy(pBtCoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } + else + { + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 2); + } + } +} + +VOID +halbtc8821a1ant_RunSwCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte algorithm=0; + + algorithm = halbtc8821a1ant_ActionAlgorithm(pBtCoexist); + pCoexDm->curAlgorithm = algorithm; + + if(halbtc8821a1ant_IsCommonAction(pBtCoexist)) + { + + } + else + { + switch(pCoexDm->curAlgorithm) + { + case BT_8821A_1ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = SCO.\n")); + halbtc8821a1ant_ActionSco(pBtCoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID.\n")); + halbtc8821a1ant_ActionHid(pBtCoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP.\n")); + halbtc8821a1ant_ActionA2dp(pBtCoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = A2DP+PAN(HS).\n")); + halbtc8821a1ant_ActionA2dpPanHs(pBtCoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR).\n")); + halbtc8821a1ant_ActionPanEdr(pBtCoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HS mode.\n")); + halbtc8821a1ant_ActionPanHs(pBtCoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN+A2DP.\n")); + halbtc8821a1ant_ActionPanEdrA2dp(pBtCoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = PAN(EDR)+HID.\n")); + halbtc8821a1ant_ActionPanEdrHid(pBtCoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP+PAN.\n")); + halbtc8821a1ant_ActionHidA2dpPanEdr(pBtCoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = HID+A2DP.\n")); + halbtc8821a1ant_ActionHidA2dp(pBtCoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action algorithm = coexist All Off!!\n")); + //halbtc8821a1ant_CoexAllOff(pBtCoexist); + break; + } + pCoexDm->preAlgorithm = pCoexDm->curAlgorithm; + } +} + +VOID +halbtc8821a1ant_RunCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + BOOLEAN bIncreaseScanDevNum=FALSE; + BOOLEAN bBtCtrlAggBufSize=FALSE; + u1Byte aggBufSize=5; + u1Byte wifiRssiState=BTC_RSSI_STATE_HIGH; + BOOLEAN bWifiUnder5G=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism()===>\n")); + + if(pBtCoexist->bManualControl) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n")); + return; + } + + if(pBtCoexist->bStopCoexDm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n")); + return; + } + + if(pCoexSta->bUnderIps) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is under IPS !!!\n")); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + if(bWifiUnder5G) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), return for 5G <===\n")); + halbtc8821a1ant_CoexUnder5G(pBtCoexist); + return; + } + + if( (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || + (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + { + bIncreaseScanDevNum = TRUE; + } + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, &bIncreaseScanDevNum); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + if(!pBtLinkInfo->bScoExist && !pBtLinkInfo->bHidExist) + { + halbtc8821a1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); + } + else + { + if(bWifiConnected) + { + wifiRssiState = halbtc8821a1ant_WifiRssiState(pBtCoexist, 1, 2, 30, 0); + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 1, 1, 1, 1); + } + else + { + halbtc8821a1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 1, 1, 1, 1); + } + } + else + { + halbtc8821a1ant_LimitedTx(pBtCoexist, NORMAL_EXEC, 0, 0, 0, 0); + } + + } + + if(pBtLinkInfo->bScoExist) + { + bBtCtrlAggBufSize = TRUE; + aggBufSize = 0x3; + } + else if(pBtLinkInfo->bHidExist) + { + bBtCtrlAggBufSize = TRUE; + aggBufSize = 0x5; + } + else if(pBtLinkInfo->bA2dpExist || pBtLinkInfo->bPanExist) + { + bBtCtrlAggBufSize = TRUE; + aggBufSize = 0x8; + } + halbtc8821a1ant_LimitedRx(pBtCoexist, NORMAL_EXEC, FALSE, bBtCtrlAggBufSize, aggBufSize); + + halbtc8821a1ant_RunSwCoexistMechanism(pBtCoexist); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8821a1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8821a1ant_ActionHs(pBtCoexist); + return; + } + + + if(!bWifiConnected) + { + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], wifi is non connected-idle !!!\n")); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if(bScan || bLink || bRoam) + halbtc8821a1ant_ActionWifiNotConnectedAssoAuthScan(pBtCoexist); + else + halbtc8821a1ant_ActionWifiNotConnected(pBtCoexist); + } + else // wifi LPS/Busy + { + halbtc8821a1ant_ActionWifiConnected(pBtCoexist); + } +} + +VOID +halbtc8821a1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + // force to reset coex mechanism + // sw all off + halbtc8821a1ant_SwMechanism(pBtCoexist, FALSE); + + halbtc8821a1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 8); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); +} + +VOID +halbtc8821a1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bBackUp + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + u4Byte u4Tmp=0; + u2Byte u2Tmp=0; + u1Byte u1Tmp=0; + u1Byte H2C_Parameter[2] ={0}; + BOOLEAN bWifiUnder5G=FALSE; + + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 1Ant Init HW Config!!\n")); + + if(bBackUp) + { + pCoexDm->backupArfrCnt1 = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x430); + pCoexDm->backupArfrCnt2 = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x434); + pCoexDm->backupRetryLimit = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x42a); + pCoexDm->backupAmpduMaxTime = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x456); + } + + // 0x790[5:0]=0x5 + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x790); + u1Tmp &= 0xc0; + u1Tmp |= 0x5; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x790, u1Tmp); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + + //Antenna config + if(bWifiUnder5G) + halbtc8821a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, TRUE, FALSE); + else + halbtc8821a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_PTA, TRUE, FALSE); + // PTA parameter + halbtc8821a1ant_CoexTableWithType(pBtCoexist, FORCE_EXEC, 0); + + // Enable counter statistics + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); //0x76e[3] =1, WLAN_Act control by PTA + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x778, 0x3); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x40, 0x20, 0x1); +} + +//============================================================ +// work around function start with wa_halbtc8821a1ant_ +//============================================================ +//============================================================ +// extern function start with EXhalbtc8821a1ant_ +//============================================================ +VOID +EXhalbtc8821a1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a1ant_InitHwConfig(pBtCoexist, TRUE); +} + +VOID +EXhalbtc8821a1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + pBtCoexist->bStopCoexDm = FALSE; + + halbtc8821a1ant_InitCoexDm(pBtCoexist); + + halbtc8821a1ant_QueryBtInfo(pBtCoexist); +} + +VOID +EXhalbtc8821a1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + pu1Byte cliBuf=pBtCoexist->cliBuf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u2Byte u2Tmp[4]; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir; + u1Byte wifiDot11Chnl, wifiHsChnl; + u4Byte fwVer=0, btPatchVer=0; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(pBtCoexist->bManualControl) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cliBuf); + } + if(pBtCoexist->bStopCoexDm) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n =========================================="); + CL_PRINTF(cliBuf); + } + + if(!pBoardInfo->bBtExist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", "Ant PG Num/ Ant Mech/ Ant Pos:", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum, pBoardInfo->btdmAntPos); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", \ + GLCoexVerDate8821a1Ant, GLCoexVer8821a1Ant, fwVer, btPatchVer, btPatchVer); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsChnl(HsMode)", \ + wifiDot11Chnl, wifiHsChnl, bBtHsOn); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], + pCoexDm->wifiChnlInfo[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((pBtCoexist->btInfo.bBtDisabled)? ("disabled"): ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == pCoexDm->btStatus)? "non-connected idle": + ( (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy")))), + pCoexSta->btRssi, pCoexSta->btRetryCnt); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pBtLinkInfo->bScoExist, pBtLinkInfo->bHidExist, pBtLinkInfo->bPanExist, pBtLinkInfo->bA2dpExist); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + + btInfoExt = pCoexSta->btInfoExt; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (btInfoExt&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cliBuf); + + for(i=0; i<BT_INFO_SRC_8821A_1ANT_MAX; i++) + { + if(pCoexSta->btInfoC2hCnt[i]) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8821a1Ant[i], \ + pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], + pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], + pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], + pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); + CL_PRINTF(cliBuf); + } + } + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s, (0x%x/0x%x)", "PS state, IPS/LPS, (lps/rpwm)", \ + ((pCoexSta->bUnderIps? "IPS ON":"IPS OFF")), + ((pCoexSta->bUnderLps? "LPS ON":"LPS OFF")), + pBtCoexist->btInfo.lpsVal, + pBtCoexist->btInfo.rpwmVal); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + if(!pBtCoexist->bManualControl) + { + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "SM[LowPenaltyRA]", \ + pCoexDm->bCurLowPenaltyRa); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %d ", "DelBA/ BtCtrlAgg/ AggSize", \ + (pBtCoexist->btInfo.bRejectAggPkt? "Yes":"No"), (pBtCoexist->btInfo.bBtCtrlAggBufSize? "Yes":"No"), + pBtCoexist->btInfo.aggBufSize); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask", \ + pBtCoexist->btInfo.raMask); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + psTdmaCase = pCoexDm->curPsTdma; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", "PS TDMA", \ + pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], + pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], + pCoexDm->psTdmaPara[4], psTdmaCase, pCoexDm->bAutoTdmaAdjust); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Latest error condition(should be 0)", \ + pCoexDm->errorCondition); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "IgnWlanAct", \ + pCoexDm->bCurIgnoreWlanAct); + CL_PRINTF(cliBuf); + } + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "backup ARFR1/ARFR2/RL/AMaxTime", \ + pCoexDm->backupArfrCnt1, pCoexDm->backupArfrCnt2, pCoexDm->backupRetryLimit, pCoexDm->backupAmpduMaxTime); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x430); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x434); + u2Tmp[0] = pBtCoexist->fBtcRead2Byte(pBtCoexist, 0x42a); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x456); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", "0x430/0x434/0x42a/0x456", \ + u4Tmp[0], u4Tmp[1], u2Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x778); + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc58); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x778/ 0xc58[29:25]", \ + u1Tmp[0], (u4Tmp[0]&0x3e000000) >> 25); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x8db); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x8db[6:5]", \ + ((u1Tmp[0]&0x60)>>5)); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x975); + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xcb4); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0xcb4[29:28]/0xcb4[7:0]/0x974[9:8]", \ + (u4Tmp[0]&0x30000000)>>28, u4Tmp[0]&0xff, u1Tmp[0]& 0x3); + CL_PRINTF(cliBuf); + + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x64); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x40/0x4c[24:23]/0x64[0]", \ + u1Tmp[0], ((u4Tmp[0]&0x01800000)>>23), u1Tmp[1]&0x1); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x550); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x522); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \ + u4Tmp[0]&0xff); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xf48); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5d); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5c); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "OFDM-FA/ CCK-FA", \ + u4Tmp[0], (u1Tmp[0]<<8) + u1Tmp[1] ); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp[0]); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770(high-pri rx/tx)", \ + pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(low-pri rx/tx)", \ + pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); + CL_PRINTF(cliBuf); +#if(BT_AUTO_REPORT_ONLY_8821A_1ANT == 1) + halbtc8821a1ant_MonitorBtCtr(pBtCoexist); +#endif + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8821a1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u4Byte u4Tmp=0; + + if(pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm) + return; + + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + pCoexSta->bUnderIps = TRUE; + halbtc8821a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, TRUE); + //set PTA control + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 8); + halbtc8821a1ant_CoexTableWithType(pBtCoexist, NORMAL_EXEC, 0); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + pCoexSta->bUnderIps = FALSE; + + halbtc8821a1ant_RunCoexistMechanism(pBtCoexist); + } +} + +VOID +EXhalbtc8821a1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(pBtCoexist->bManualControl || pBtCoexist->bStopCoexDm) + return; + + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + pCoexSta->bUnderLps = TRUE; + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + pCoexSta->bUnderLps = FALSE; + } +} + +VOID +EXhalbtc8821a1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + + halbtc8821a1ant_QueryBtInfo(pBtCoexist); + + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8821a1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8821a1ant_ActionHs(pBtCoexist); + return; + } + + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + if(!bWifiConnected) // non-connected scan + { + halbtc8821a1ant_ActionWifiNotConnectedAssoAuthScan(pBtCoexist); + } + else // wifi is connected + { + halbtc8821a1ant_ActionWifiConnectedScan(pBtCoexist); + } + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + if(!bWifiConnected) // non-connected scan + { + halbtc8821a1ant_ActionWifiNotConnected(pBtCoexist); + } + else + { + halbtc8821a1ant_ActionWifiConnected(pBtCoexist); + } + } +} + +VOID +EXhalbtc8821a1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8821a1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8821a1ant_ActionHs(pBtCoexist); + return; + } + + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + halbtc8821a1ant_ActionWifiNotConnectedAssoAuthScan(pBtCoexist); + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(!bWifiConnected) // non-connected scan + { + halbtc8821a1ant_ActionWifiNotConnected(pBtCoexist); + } + else + { + halbtc8821a1ant_ActionWifiConnected(pBtCoexist); + } + } +} + +VOID +EXhalbtc8821a1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u1Byte H2C_Parameter[3] ={0}; + u4Byte wifiBw; + u1Byte wifiCentralChnl; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } + + // only 2.4G we need to inform bt the chnl mask + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); + if( (BTC_MEDIA_CONNECT == type) && + (wifiCentralChnl <= 14) ) + { + //H2C_Parameter[0] = 0x1; + H2C_Parameter[0] = 0x0; + H2C_Parameter[1] = wifiCentralChnl; + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + H2C_Parameter[2] = 0x30; + else + H2C_Parameter[2] = 0x20; + } + + pCoexDm->wifiChnlInfo[0] = H2C_Parameter[0]; + pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1]; + pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x66=0x%x\n", + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x66, 3, H2C_Parameter); +} + +VOID +EXhalbtc8821a1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + BOOLEAN bBtHsOn=FALSE; + + if(pBtCoexist->bManualControl || + pBtCoexist->bStopCoexDm || + pBtCoexist->btInfo.bBtDisabled ) + return; + + pCoexSta->specialPktPeriodCnt = 0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + if(pCoexSta->bC2hBtInquiryPage) + { + halbtc8821a1ant_ActionBtInquiry(pBtCoexist); + return; + } + else if(bBtHsOn) + { + halbtc8821a1ant_ActionHs(pBtCoexist); + return; + } + + if( BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type ) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], special Packet(%d) notify\n", type)); + halbtc8821a1ant_ActionWifiConnectedSpecialPacket(pBtCoexist); + } +} + +VOID +EXhalbtc8821a1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ + PBTC_BT_LINK_INFO pBtLinkInfo=&pBtCoexist->btLinkInfo; + u1Byte btInfo=0; + u1Byte i, rspSource=0; + BOOLEAN bWifiConnected=FALSE; + BOOLEAN bBtBusy=FALSE; + BOOLEAN bWifiUnder5G=FALSE; + + pCoexSta->bC2hBtInfoReqSent = FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + + rspSource = tmpBuf[0]&0xf; + if(rspSource >= BT_INFO_SRC_8821A_1ANT_MAX) + rspSource = BT_INFO_SRC_8821A_1ANT_WIFI_FW; + pCoexSta->btInfoC2hCnt[rspSource]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rspSource, length)); + for(i=0; i<length; i++) + { + pCoexSta->btInfoC2h[rspSource][i] = tmpBuf[i]; + if(i == 1) + btInfo = tmpBuf[i]; + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); + } + } + + if(BT_INFO_SRC_8821A_1ANT_WIFI_FW != rspSource) + { + pCoexSta->btRetryCnt = // [3:0] + pCoexSta->btInfoC2h[rspSource][2]&0xf; + + pCoexSta->btRssi = + pCoexSta->btInfoC2h[rspSource][3]*2+10; + + pCoexSta->btInfoExt = + pCoexSta->btInfoC2h[rspSource][4]; + + // Here we need to resend some wifi info to BT + // because bt is reset and loss of the info. + if(pCoexSta->btInfoExt & BIT1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n")); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(bWifiConnected) + { + EXhalbtc8821a1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_CONNECT); + } + else + { + EXhalbtc8821a1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); + } + } + + if( (pCoexSta->btInfoExt & BIT3) && !bWifiUnder5G) + { + if(!pBtCoexist->bManualControl && !pBtCoexist->bStopCoexDm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n")); + halbtc8821a1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); + } + } + else + { + // BT already NOT ignore Wlan active, do nothing here. + } +#if(BT_AUTO_REPORT_ONLY_8821A_1ANT == 0) + if( (pCoexSta->btInfoExt & BIT4) ) + { + // BT auto report already enabled, do nothing + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT ext info bit4 check, set BT to enable Auto Report!!\n")); + halbtc8821a1ant_BtAutoReport(pBtCoexist, FORCE_EXEC, TRUE); + } +#endif + } + + // check BIT2 first ==> check if bt is under inquiry or page scan + if(btInfo & BT_INFO_8821A_1ANT_B_INQ_PAGE) + pCoexSta->bC2hBtInquiryPage = TRUE; + else + pCoexSta->bC2hBtInquiryPage = FALSE; + + // set link exist status + if(!(btInfo&BT_INFO_8821A_1ANT_B_CONNECTION)) + { + pCoexSta->bBtLinkExist = FALSE; + pCoexSta->bPanExist = FALSE; + pCoexSta->bA2dpExist = FALSE; + pCoexSta->bHidExist = FALSE; + pCoexSta->bScoExist = FALSE; + } + else // connection exists + { + pCoexSta->bBtLinkExist = TRUE; + if(btInfo & BT_INFO_8821A_1ANT_B_FTP) + pCoexSta->bPanExist = TRUE; + else + pCoexSta->bPanExist = FALSE; + if(btInfo & BT_INFO_8821A_1ANT_B_A2DP) + pCoexSta->bA2dpExist = TRUE; + else + pCoexSta->bA2dpExist = FALSE; + if(btInfo & BT_INFO_8821A_1ANT_B_HID) + pCoexSta->bHidExist = TRUE; + else + pCoexSta->bHidExist = FALSE; + if(btInfo & BT_INFO_8821A_1ANT_B_SCO_ESCO) + pCoexSta->bScoExist = TRUE; + else + pCoexSta->bScoExist = FALSE; + } + + halbtc8821a1ant_UpdateBtLinkInfo(pBtCoexist); + + if(!(btInfo&BT_INFO_8821A_1ANT_B_CONNECTION)) + { + pCoexDm->btStatus = BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n")); + } + else if(btInfo == BT_INFO_8821A_1ANT_B_CONNECTION) // connection exists but no busy + { + pCoexDm->btStatus = BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n")); + } + else if((btInfo&BT_INFO_8821A_1ANT_B_SCO_ESCO) || + (btInfo&BT_INFO_8821A_1ANT_B_SCO_BUSY)) + { + pCoexDm->btStatus = BT_8821A_1ANT_BT_STATUS_SCO_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT SCO busy!!!\n")); + } + else if(btInfo&BT_INFO_8821A_1ANT_B_ACL_BUSY) + { + if(BT_8821A_1ANT_BT_STATUS_ACL_BUSY != pCoexDm->btStatus) + pCoexDm->bAutoTdmaAdjust = FALSE; + pCoexDm->btStatus = BT_8821A_1ANT_BT_STATUS_ACL_BUSY; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT ACL busy!!!\n")); + } + else + { + pCoexDm->btStatus = BT_8821A_1ANT_BT_STATUS_MAX; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n")); + } + + if( (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == pCoexDm->btStatus) || + (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == pCoexDm->btStatus) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == pCoexDm->btStatus) ) + bBtBusy = TRUE; + else + bBtBusy = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + + halbtc8821a1ant_RunCoexistMechanism(pBtCoexist); +} + +VOID +EXhalbtc8821a1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte u4Tmp; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + pBtCoexist->bStopCoexDm = TRUE; + + halbtc8821a1ant_SetAntPath(pBtCoexist, BTC_ANT_PATH_BT, FALSE, TRUE); + halbtc8821a1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + + halbtc8821a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8821a1ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 0); + + EXhalbtc8821a1ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8821a1ant_PnpNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pnpState + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify\n")); + + if(BTC_WIFI_PNP_SLEEP == pnpState) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify to SLEEP\n")); + pBtCoexist->bStopCoexDm = TRUE; + halbtc8821a1ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + halbtc8821a1ant_PowerSaveState(pBtCoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8821a1ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 9); + } + else if(BTC_WIFI_PNP_WAKE_UP == pnpState) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Pnp notify to WAKE UP\n")); + pBtCoexist->bStopCoexDm = FALSE; + halbtc8821a1ant_InitHwConfig(pBtCoexist, FALSE); + halbtc8821a1ant_InitCoexDm(pBtCoexist); + halbtc8821a1ant_QueryBtInfo(pBtCoexist); + } +} + +VOID +EXhalbtc8821a1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + static u1Byte disVerInfoCnt=0; + u4Byte fwVer=0, btPatchVer=0; + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ==========================Periodical===========================\n")); + + if(disVerInfoCnt <= 5) + { + disVerInfoCnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum, pBoardInfo->btdmAntPos)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], BT stack/ hci ext ver = %s / %d\n", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion)); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", \ + GLCoexVerDate8821a1Ant, GLCoexVer8821a1Ant, fwVer, btPatchVer, btPatchVer)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + } + +#if(BT_AUTO_REPORT_ONLY_8821A_1ANT == 0) + halbtc8821a1ant_QueryBtInfo(pBtCoexist); + halbtc8821a1ant_MonitorBtCtr(pBtCoexist); + halbtc8821a1ant_MonitorBtEnableDisable(pBtCoexist); +#else + if( halbtc8821a1ant_IsWifiStatusChanged(pBtCoexist) || + pCoexDm->bAutoTdmaAdjust ) + { + if(pCoexSta->specialPktPeriodCnt > 2) + { + halbtc8821a1ant_RunCoexistMechanism(pBtCoexist); + } + } + + pCoexSta->specialPktPeriodCnt++; +#endif +} + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a1Ant.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a1Ant.h new file mode 100644 index 0000000..aa0caa4 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a1Ant.h @@ -0,0 +1,210 @@ +//=========================================== +// The following is for 8821A 1ANT BT Co-exist definition +//=========================================== +#define BT_AUTO_REPORT_ONLY_8821A_1ANT 0 + +#define BT_INFO_8821A_1ANT_B_FTP BIT7 +#define BT_INFO_8821A_1ANT_B_A2DP BIT6 +#define BT_INFO_8821A_1ANT_B_HID BIT5 +#define BT_INFO_8821A_1ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8821A_1ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8821A_1ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8821A_1ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8821A_1ANT_B_CONNECTION BIT0 + +#define BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT0))? TRUE:FALSE) + +#define BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT 2 + +typedef enum _BT_INFO_SRC_8821A_1ANT{ + BT_INFO_SRC_8821A_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8821A_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8821A_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8821A_1ANT_MAX +}BT_INFO_SRC_8821A_1ANT,*PBT_INFO_SRC_8821A_1ANT; + +typedef enum _BT_8821A_1ANT_BT_STATUS{ + BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8821A_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8821A_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8821A_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8821A_1ANT_BT_STATUS_MAX +}BT_8821A_1ANT_BT_STATUS,*PBT_8821A_1ANT_BT_STATUS; + +typedef enum _BT_8821A_1ANT_WIFI_STATUS{ + BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT = 0x3, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8821A_1ANT_WIFI_STATUS_MAX +}BT_8821A_1ANT_WIFI_STATUS,*PBT_8821A_1ANT_WIFI_STATUS; + +typedef enum _BT_8821A_1ANT_COEX_ALGO{ + BT_8821A_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8821A_1ANT_COEX_ALGO_SCO = 0x1, + BT_8821A_1ANT_COEX_ALGO_HID = 0x2, + BT_8821A_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8821A_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8821A_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8821A_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8821A_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8821A_1ANT_COEX_ALGO_MAX = 0xb, +}BT_8821A_1ANT_COEX_ALGO,*PBT_8821A_1ANT_COEX_ALGO; + +typedef struct _COEX_DM_8821A_1ANT{ + // fw mechanism + BOOLEAN bCurIgnoreWlanAct; + BOOLEAN bPreIgnoreWlanAct; + u1Byte prePsTdma; + u1Byte curPsTdma; + u1Byte psTdmaPara[5]; + u1Byte psTdmaDuAdjType; + BOOLEAN bAutoTdmaAdjust; + BOOLEAN bPrePsTdmaOn; + BOOLEAN bCurPsTdmaOn; + BOOLEAN bPreBtAutoReport; + BOOLEAN bCurBtAutoReport; + u1Byte preLps; + u1Byte curLps; + u1Byte preRpwm; + u1Byte curRpwm; + + // sw mechanism + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + u4Byte preVal0x6c0; + u4Byte curVal0x6c0; + u4Byte preVal0x6c4; + u4Byte curVal0x6c4; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u1Byte preVal0x6cc; + u1Byte curVal0x6cc; + + u4Byte backupArfrCnt1; // Auto Rate Fallback Retry cnt + u4Byte backupArfrCnt2; // Auto Rate Fallback Retry cnt + u2Byte backupRetryLimit; + u1Byte backupAmpduMaxTime; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + u1Byte btStatus; + u1Byte wifiChnlInfo[3]; + + u4Byte preRaMask; + u4Byte curRaMask; + u1Byte preArfrType; + u1Byte curArfrType; + u1Byte preRetryLimitType; + u1Byte curRetryLimitType; + u1Byte preAmpduTimeType; + u1Byte curAmpduTimeType; + + u1Byte errorCondition; +} COEX_DM_8821A_1ANT, *PCOEX_DM_8821A_1ANT; + +typedef struct _COEX_STA_8821A_1ANT{ + BOOLEAN bBtLinkExist; + BOOLEAN bScoExist; + BOOLEAN bA2dpExist; + BOOLEAN bHidExist; + BOOLEAN bPanExist; + + BOOLEAN bUnderLps; + BOOLEAN bUnderIps; + u4Byte specialPktPeriodCnt; + u4Byte highPriorityTx; + u4Byte highPriorityRx; + u4Byte lowPriorityTx; + u4Byte lowPriorityRx; + u1Byte btRssi; + u1Byte preBtRssiState; + u1Byte preWifiRssiState[4]; + BOOLEAN bC2hBtInfoReqSent; + u1Byte btInfoC2h[BT_INFO_SRC_8821A_1ANT_MAX][10]; + u4Byte btInfoC2hCnt[BT_INFO_SRC_8821A_1ANT_MAX]; + BOOLEAN bC2hBtInquiryPage; + u1Byte btRetryCnt; + u1Byte btInfoExt; +}COEX_STA_8821A_1ANT, *PCOEX_STA_8821A_1ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8821a1ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8821a1ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8821a1ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8821a1ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8821a1ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8821a1ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8821a1ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8821a1ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8821a1ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8821a1ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8821a1ant_PnpNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pnpState + ); +VOID +EXhalbtc8821a1ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8821a1ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8821a1ant_DbgControl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte opCode, + IN u1Byte opLen, + IN pu1Byte pData + ); diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a2Ant.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a2Ant.c new file mode 100644 index 0000000..a76b7ac --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a2Ant.c @@ -0,0 +1,4222 @@ +//============================================================ +// Description: +// +// This file is for RTL8821A Co-exist mechanism +// +// History +// 2012/08/22 Cosa first check in. +// 2012/11/14 Cosa Revise for 8821A 2Ant out sourcing. +// +//============================================================ + +//============================================================ +// include files +//============================================================ +#include "Mp_Precomp.h" +#if(BT_30_SUPPORT == 1) +//============================================================ +// Global variables, these are static variables +//============================================================ +static COEX_DM_8821A_2ANT GLCoexDm8821a2Ant; +static PCOEX_DM_8821A_2ANT pCoexDm=&GLCoexDm8821a2Ant; +static COEX_STA_8821A_2ANT GLCoexSta8821a2Ant; +static PCOEX_STA_8821A_2ANT pCoexSta=&GLCoexSta8821a2Ant; + +const char *const GLBtInfoSrc8821a2Ant[]={ + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u4Byte GLCoexVerDate8821a2Ant=20130618; +u4Byte GLCoexVer8821a2Ant=0x5050; + +//============================================================ +// local function proto type if needed +//============================================================ +//============================================================ +// local function start with halbtc8821a2ant_ +//============================================================ +u1Byte +halbtc8821a2ant_BtRssiState( + u1Byte levelNum, + u1Byte rssiThresh, + u1Byte rssiThresh1 + ) +{ + s4Byte btRssi=0; + u1Byte btRssiState=pCoexSta->preBtRssiState; + + btRssi = pCoexSta->btRssi; + + if(levelNum == 2) + { + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else + { + if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi thresh error!!\n")); + return pCoexSta->preBtRssiState; + } + + if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_LOW) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_LOW)) + { + if(btRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Low\n")); + } + } + else if( (pCoexSta->preBtRssiState == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preBtRssiState == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(btRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) + { + btRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to High\n")); + } + else if(btRssi < rssiThresh) + { + btRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Low\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at Medium\n")); + } + } + else + { + if(btRssi < rssiThresh1) + { + btRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state switch to Medium\n")); + } + else + { + btRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_RSSI_STATE, ("[BTCoex], BT Rssi state stay at High\n")); + } + } + } + + pCoexSta->preBtRssiState = btRssiState; + + return btRssiState; +} + +u1Byte +halbtc8821a2ant_WifiRssiState( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte index, + IN u1Byte levelNum, + IN u1Byte rssiThresh, + IN u1Byte rssiThresh1 + ) +{ + s4Byte wifiRssi=0; + u1Byte wifiRssiState=pCoexSta->preWifiRssiState[index]; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + + if(levelNum == 2) + { + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else + { + if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + else if(levelNum == 3) + { + if(rssiThresh > rssiThresh1) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI thresh error!!\n")); + return pCoexSta->preWifiRssiState[index]; + } + + if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_LOW) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_LOW)) + { + if(wifiRssi >= (rssiThresh+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Low\n")); + } + } + else if( (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_MEDIUM) || + (pCoexSta->preWifiRssiState[index] == BTC_RSSI_STATE_STAY_MEDIUM)) + { + if(wifiRssi >= (rssiThresh1+BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) + { + wifiRssiState = BTC_RSSI_STATE_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to High\n")); + } + else if(wifiRssi < rssiThresh) + { + wifiRssiState = BTC_RSSI_STATE_LOW; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Low\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at Medium\n")); + } + } + else + { + if(wifiRssi < rssiThresh1) + { + wifiRssiState = BTC_RSSI_STATE_MEDIUM; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state switch to Medium\n")); + } + else + { + wifiRssiState = BTC_RSSI_STATE_STAY_HIGH; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_WIFI_RSSI_STATE, ("[BTCoex], wifi RSSI state stay at High\n")); + } + } + } + + pCoexSta->preWifiRssiState[index] = wifiRssiState; + + return wifiRssiState; +} + +VOID +halbtc8821a2ant_MonitorBtEnableDisable( + IN PBTC_COEXIST pBtCoexist + ) +{ + static BOOLEAN bPreBtDisabled=FALSE; + static u4Byte btDisableCnt=0; + BOOLEAN bBtActive=TRUE, bBtDisabled=FALSE; + + // This function check if bt is disabled + + if( pCoexSta->highPriorityTx == 0 && + pCoexSta->highPriorityRx == 0 && + pCoexSta->lowPriorityTx == 0 && + pCoexSta->lowPriorityRx == 0) + { + bBtActive = FALSE; + } + if( pCoexSta->highPriorityTx == 0xffff && + pCoexSta->highPriorityRx == 0xffff && + pCoexSta->lowPriorityTx == 0xffff && + pCoexSta->lowPriorityRx == 0xffff) + { + bBtActive = FALSE; + } + if(bBtActive) + { + btDisableCnt = 0; + bBtDisabled = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is enabled !!\n")); + } + else + { + btDisableCnt++; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], bt all counters=0, %d times!!\n", + btDisableCnt)); + if(btDisableCnt >= 2) + { + bBtDisabled = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_DISABLE, &bBtDisabled); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is disabled !!\n")); + } + } + if(bPreBtDisabled != bBtDisabled) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], BT is from %s to %s!!\n", + (bPreBtDisabled ? "disabled":"enabled"), + (bBtDisabled ? "disabled":"enabled"))); + bPreBtDisabled = bBtDisabled; + if(!bBtDisabled) + { + } + else + { + } + } +} + +VOID +halbtc8821a2ant_MonitorBtCtr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u4Byte regHPTxRx, regLPTxRx, u4Tmp; + u4Byte regHPTx=0, regHPRx=0, regLPTx=0, regLPRx=0; + u1Byte u1Tmp; + + regHPTxRx = 0x770; + regLPTxRx = 0x774; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regHPTxRx); + regHPTx = u4Tmp & bMaskLWord; + regHPRx = (u4Tmp & bMaskHWord)>>16; + + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, regLPTxRx); + regLPTx = u4Tmp & bMaskLWord; + regLPRx = (u4Tmp & bMaskHWord)>>16; + + pCoexSta->highPriorityTx = regHPTx; + pCoexSta->highPriorityRx = regHPRx; + pCoexSta->lowPriorityTx = regLPTx; + pCoexSta->lowPriorityRx = regLPRx; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regHPTxRx, regHPTx, regHPTx, regHPRx, regHPRx)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_BT_MONITOR, ("[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + regLPTxRx, regLPTx, regLPTx, regLPRx, regLPRx)); + + // reset counter + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); +} + +VOID +halbtc8821a2ant_QueryBtInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + pCoexSta->bC2hBtInfoReqSent = TRUE; + + H2C_Parameter[0] |= BIT0; // trigger + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Query Bt Info, FW write 0x61=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x61, 1, H2C_Parameter); +} +u1Byte +halbtc8821a2ant_ActionAlgorithm( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + BOOLEAN bBtHsOn=FALSE; + u1Byte algorithm=BT_8821A_2ANT_COEX_ALGO_UNDEFINED; + u1Byte numOfDiffProfile=0; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + + //for win-8 stack HID report error + if(!pStackInfo->bHidExist) + pStackInfo->bHidExist = pCoexSta->bHidExist; //sync BTInfo with BT firmware and stack + // when stack HID report error, here we use the info from bt fw. + if(!pStackInfo->bBtLinkExist) + pStackInfo->bBtLinkExist = pCoexSta->bBtLinkExist; + + if(!pStackInfo->bBtLinkExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], No profile exists!!!\n")); + return algorithm; + } + + if(pStackInfo->bScoExist) + numOfDiffProfile++; + if(pStackInfo->bHidExist) + numOfDiffProfile++; + if(pStackInfo->bPanExist) + numOfDiffProfile++; + if(pStackInfo->bA2dpExist) + numOfDiffProfile++; + + if(numOfDiffProfile == 1) + { + if(pStackInfo->bScoExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO only\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } + else + { + if(pStackInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID only\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_HID; + } + else if(pStackInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP only\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP; + } + else if(pStackInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(HS) only\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], PAN(EDR) only\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR; + } + } + } + } + else if(numOfDiffProfile == 2) + { + if(pStackInfo->bScoExist) + { + if(pStackInfo->bHidExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + else if(pStackInfo->bA2dpExist) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP ==> SCO\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + else if(pStackInfo->bPanExist) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(HS)\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + PAN(EDR)\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pStackInfo->bHidExist && + pStackInfo->bA2dpExist ) + { + if(pStackInfo->numOfHid >= 2) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID*2 + A2DP\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP; + } + } + else if( pStackInfo->bHidExist && + pStackInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(HS)\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_HID; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + PAN(EDR)\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(HS)\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } + else if(numOfDiffProfile == 3) + { + if(pStackInfo->bScoExist) + { + if( pStackInfo->bHidExist && + pStackInfo->bA2dpExist ) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP ==> HID\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + else if( pStackInfo->bHidExist && + pStackInfo->bPanExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(HS)\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + PAN(EDR)\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + else if( pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(HS)\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + else + { + if( pStackInfo->bHidExist && + pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + else if(numOfDiffProfile >= 3) + { + if(pStackInfo->bScoExist) + { + if( pStackInfo->bHidExist && + pStackInfo->bPanExist && + pStackInfo->bA2dpExist ) + { + if(bBtHsOn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n")); + + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n")); + algorithm = BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +BOOLEAN +halbtc8821a2ant_NeedToDecBtPwr( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bRet=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiConnected=FALSE; + s4Byte btHsRssi=0; + u1Byte btRssiState; + + if(!pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn)) + return FALSE; + if(!pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected)) + return FALSE; + if(!pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi)) + return FALSE; + + btRssiState = halbtc8821a2ant_BtRssiState(2, 35, 0); + + if(bWifiConnected) + { + if(bBtHsOn) + { + if(btHsRssi > 37) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], Need to decrease bt power for HS mode!!\n")); + bRet = TRUE; + } + } + else + { + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], Need to decrease bt power for Wifi is connected!!\n")); + bRet = TRUE; + } + } + } + + return bRet; +} + +VOID +halbtc8821a2ant_SetFwDacSwingLevel( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte dacSwingLvl + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + // There are several type of dacswing + // 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 + H2C_Parameter[0] = dacSwingLvl; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], Set Dac Swing Level=0x%x\n", dacSwingLvl)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x64=0x%x\n", H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x64, 1, H2C_Parameter); +} + +VOID +halbtc8821a2ant_SetFwDecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bDecBtPwr + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = 0; + + if(bDecBtPwr) + { + H2C_Parameter[0] |= BIT1; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], decrease Bt Power : %s, FW write 0x62=0x%x\n", + (bDecBtPwr? "Yes!!":"No!!"), H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x62, 1, H2C_Parameter); +} + +VOID +halbtc8821a2ant_DecBtPwr( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDecBtPwr + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s Dec BT power = %s\n", + (bForceExec? "force to":""), ((bDecBtPwr)? "ON":"OFF"))); + pCoexDm->bCurDecBtPwr = bDecBtPwr; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreDecBtPwr=%d, bCurDecBtPwr=%d\n", + pCoexDm->bPreDecBtPwr, pCoexDm->bCurDecBtPwr)); + + if(pCoexDm->bPreDecBtPwr == pCoexDm->bCurDecBtPwr) + return; + } + halbtc8821a2ant_SetFwDecBtPwr(pBtCoexist, pCoexDm->bCurDecBtPwr); + + pCoexDm->bPreDecBtPwr = pCoexDm->bCurDecBtPwr; +} + +VOID +halbtc8821a2ant_SetFwBtLnaConstrain( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bBtLnaConsOn + ) +{ + u1Byte H2C_Parameter[2] ={0}; + + H2C_Parameter[0] = 0x3; // opCode, 0x3=BT_SET_LNA_CONSTRAIN + + if(bBtLnaConsOn) + { + H2C_Parameter[1] |= BIT0; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set BT LNA Constrain: %s, FW write 0x69=0x%x\n", + (bBtLnaConsOn? "ON!!":"OFF!!"), + H2C_Parameter[0]<<8|H2C_Parameter[1])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x69, 2, H2C_Parameter); +} + +VOID +halbtc8821a2ant_SetBtLnaConstrain( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bBtLnaConsOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT Constrain = %s\n", + (bForceExec? "force":""), ((bBtLnaConsOn)? "ON":"OFF"))); + pCoexDm->bCurBtLnaConstrain = bBtLnaConsOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtLnaConstrain=%d, bCurBtLnaConstrain=%d\n", + pCoexDm->bPreBtLnaConstrain, pCoexDm->bCurBtLnaConstrain)); + + if(pCoexDm->bPreBtLnaConstrain == pCoexDm->bCurBtLnaConstrain) + return; + } + halbtc8821a2ant_SetFwBtLnaConstrain(pBtCoexist, pCoexDm->bCurBtLnaConstrain); + + pCoexDm->bPreBtLnaConstrain = pCoexDm->bCurBtLnaConstrain; +} + +VOID +halbtc8821a2ant_SetFwBtPsdMode( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte btPsdMode + ) +{ + u1Byte H2C_Parameter[2] ={0}; + + H2C_Parameter[0] = 0x2; // opCode, 0x2=BT_SET_PSD_MODE + + H2C_Parameter[1] = btPsdMode; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set BT PSD mode=0x%x, FW write 0x69=0x%x\n", + H2C_Parameter[1], + H2C_Parameter[0]<<8|H2C_Parameter[1])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x69, 2, H2C_Parameter); +} + + +VOID +halbtc8821a2ant_SetBtPsdMode( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte btPsdMode + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT PSD mode = 0x%x\n", + (bForceExec? "force":""), btPsdMode)); + pCoexDm->bCurBtPsdMode = btPsdMode; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtPsdMode=0x%x, bCurBtPsdMode=0x%x\n", + pCoexDm->bPreBtPsdMode, pCoexDm->bCurBtPsdMode)); + + if(pCoexDm->bPreBtPsdMode == pCoexDm->bCurBtPsdMode) + return; + } + halbtc8821a2ant_SetFwBtPsdMode(pBtCoexist, pCoexDm->bCurBtPsdMode); + + pCoexDm->bPreBtPsdMode = pCoexDm->bCurBtPsdMode; +} + + +VOID +halbtc8821a2ant_SetBtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnableAutoReport + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + H2C_Parameter[0] = 0; + + if(bEnableAutoReport) + { + H2C_Parameter[0] |= BIT0; + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], BT FW auto report : %s, FW write 0x68=0x%x\n", + (bEnableAutoReport? "Enabled!!":"Disabled!!"), H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x68, 1, H2C_Parameter); +} + +VOID +halbtc8821a2ant_BtAutoReport( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnableAutoReport + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s BT Auto report = %s\n", + (bForceExec? "force to":""), ((bEnableAutoReport)? "Enabled":"Disabled"))); + pCoexDm->bCurBtAutoReport = bEnableAutoReport; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreBtAutoReport=%d, bCurBtAutoReport=%d\n", + pCoexDm->bPreBtAutoReport, pCoexDm->bCurBtAutoReport)); + + if(pCoexDm->bPreBtAutoReport == pCoexDm->bCurBtAutoReport) + return; + } + halbtc8821a2ant_SetBtAutoReport(pBtCoexist, pCoexDm->bCurBtAutoReport); + + pCoexDm->bPreBtAutoReport = pCoexDm->bCurBtAutoReport; +} + +VOID +halbtc8821a2ant_FwDacSwingLvl( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u1Byte fwDacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s set FW Dac Swing level = %d\n", + (bForceExec? "force to":""), fwDacSwingLvl)); + pCoexDm->curFwDacSwingLvl = fwDacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], preFwDacSwingLvl=%d, curFwDacSwingLvl=%d\n", + pCoexDm->preFwDacSwingLvl, pCoexDm->curFwDacSwingLvl)); + + if(pCoexDm->preFwDacSwingLvl == pCoexDm->curFwDacSwingLvl) + return; + } + + halbtc8821a2ant_SetFwDacSwingLevel(pBtCoexist, pCoexDm->curFwDacSwingLvl); + + pCoexDm->preFwDacSwingLvl = pCoexDm->curFwDacSwingLvl; +} + +VOID +halbtc8821a2ant_SetSwRfRxLpfCorner( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bRxRfShrinkOn + ) +{ + if(bRxRfShrinkOn) + { + //Shrink RF Rx LPF corner + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Shrink RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, 0xffffc); + } + else + { + //Resume RF Rx LPF corner + // After initialized, we can use pCoexDm->btRf0x1eBackup + if(pBtCoexist->bInitilized) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Resume RF Rx LPF corner!!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff, pCoexDm->btRf0x1eBackup); + } + } +} + +VOID +halbtc8821a2ant_RfShrink( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bRxRfShrinkOn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn Rx RF Shrink = %s\n", + (bForceExec? "force to":""), ((bRxRfShrinkOn)? "ON":"OFF"))); + pCoexDm->bCurRfRxLpfShrink = bRxRfShrinkOn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreRfRxLpfShrink=%d, bCurRfRxLpfShrink=%d\n", + pCoexDm->bPreRfRxLpfShrink, pCoexDm->bCurRfRxLpfShrink)); + + if(pCoexDm->bPreRfRxLpfShrink == pCoexDm->bCurRfRxLpfShrink) + return; + } + halbtc8821a2ant_SetSwRfRxLpfCorner(pBtCoexist, pCoexDm->bCurRfRxLpfShrink); + + pCoexDm->bPreRfRxLpfShrink = pCoexDm->bCurRfRxLpfShrink; +} + +VOID +halbtc8821a2ant_SetSwPenaltyTxRateAdaptive( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bLowPenaltyRa + ) +{ + u1Byte H2C_Parameter[6] ={0}; + + H2C_Parameter[0] = 0x6; // opCode, 0x6= Retry_Penalty + + if(bLowPenaltyRa) + { + H2C_Parameter[1] |= BIT0; + H2C_Parameter[2] = 0x00; //normal rate except MCS7/6/5, OFDM54/48/36 + H2C_Parameter[3] = 0xf7; //MCS7 or OFDM54 + H2C_Parameter[4] = 0xf8; //MCS6 or OFDM48 + H2C_Parameter[5] = 0xf9; //MCS5 or OFDM36 + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set WiFi Low-Penalty Retry: %s", + (bLowPenaltyRa? "ON!!":"OFF!!") )); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x69, 6, H2C_Parameter); +} + +VOID +halbtc8821a2ant_LowPenaltyRa( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bLowPenaltyRa + ) +{ + //return; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn LowPenaltyRA = %s\n", + (bForceExec? "force to":""), ((bLowPenaltyRa)? "ON":"OFF"))); + pCoexDm->bCurLowPenaltyRa = bLowPenaltyRa; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreLowPenaltyRa=%d, bCurLowPenaltyRa=%d\n", + pCoexDm->bPreLowPenaltyRa, pCoexDm->bCurLowPenaltyRa)); + + if(pCoexDm->bPreLowPenaltyRa == pCoexDm->bCurLowPenaltyRa) + return; + } + halbtc8821a2ant_SetSwPenaltyTxRateAdaptive(pBtCoexist, pCoexDm->bCurLowPenaltyRa); + + pCoexDm->bPreLowPenaltyRa = pCoexDm->bCurLowPenaltyRa; +} + +VOID +halbtc8821a2ant_SetDacSwingReg( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte level + ) +{ + u1Byte val=(u1Byte)level; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Write SwDacSwing = 0x%x\n", level)); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xc5b, 0x3e, val); +} + +VOID +halbtc8821a2ant_SetSwFullTimeDacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bSwDacSwingOn, + IN u4Byte swDacSwingLvl + ) +{ + if(bSwDacSwingOn) + { + halbtc8821a2ant_SetDacSwingReg(pBtCoexist, swDacSwingLvl); + } + else + { + halbtc8821a2ant_SetDacSwingReg(pBtCoexist, 0x18); + } +} + + +VOID +halbtc8821a2ant_DacSwing( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bDacSwingOn, + IN u4Byte dacSwingLvl + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn DacSwing=%s, dacSwingLvl=0x%x\n", + (bForceExec? "force to":""), ((bDacSwingOn)? "ON":"OFF"), dacSwingLvl)); + pCoexDm->bCurDacSwingOn = bDacSwingOn; + pCoexDm->curDacSwingLvl = dacSwingLvl; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreDacSwingOn=%d, preDacSwingLvl=0x%x, bCurDacSwingOn=%d, curDacSwingLvl=0x%x\n", + pCoexDm->bPreDacSwingOn, pCoexDm->preDacSwingLvl, + pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl)); + + if( (pCoexDm->bPreDacSwingOn == pCoexDm->bCurDacSwingOn) && + (pCoexDm->preDacSwingLvl == pCoexDm->curDacSwingLvl) ) + return; + } + delay_ms(30); + halbtc8821a2ant_SetSwFullTimeDacSwing(pBtCoexist, bDacSwingOn, dacSwingLvl); + + pCoexDm->bPreDacSwingOn = pCoexDm->bCurDacSwingOn; + pCoexDm->preDacSwingLvl = pCoexDm->curDacSwingLvl; +} + +VOID +halbtc8821a2ant_SetAdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAdcBackOff + ) +{ + if(bAdcBackOff) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level On!\n")); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x8db, 0x60, 0x3); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], BB BackOff Level Off!\n")); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x8db, 0x60, 0x1); + } +} + +VOID +halbtc8821a2ant_AdcBackOff( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAdcBackOff + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s turn AdcBackOff = %s\n", + (bForceExec? "force to":""), ((bAdcBackOff)? "ON":"OFF"))); + pCoexDm->bCurAdcBackOff = bAdcBackOff; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAdcBackOff=%d, bCurAdcBackOff=%d\n", + pCoexDm->bPreAdcBackOff, pCoexDm->bCurAdcBackOff)); + + if(pCoexDm->bPreAdcBackOff == pCoexDm->bCurAdcBackOff) + return; + } + halbtc8821a2ant_SetAdcBackOff(pBtCoexist, pCoexDm->bCurAdcBackOff); + + pCoexDm->bPreAdcBackOff = pCoexDm->bCurAdcBackOff; +} + +VOID +halbtc8821a2ant_SetAgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAgcTableEn + ) +{ + u1Byte rssiAdjustVal=0; + + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); + if(bAgcTableEn) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table On!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x28F4B); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x10AB2); + rssiAdjustVal = 8; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], Agc Table Off!\n")); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x2884B); + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0x3b, 0xfffff, 0x104B2); + } + pBtCoexist->fBtcSetRfReg(pBtCoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); + + // set rssiAdjustVal for wifi module. + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, &rssiAdjustVal); +} + +VOID +halbtc8821a2ant_AgcTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bAgcTableEn + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s %s Agc Table\n", + (bForceExec? "force to":""), ((bAgcTableEn)? "Enable":"Disable"))); + pCoexDm->bCurAgcTableEn = bAgcTableEn; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], bPreAgcTableEn=%d, bCurAgcTableEn=%d\n", + pCoexDm->bPreAgcTableEn, pCoexDm->bCurAgcTableEn)); + + if(pCoexDm->bPreAgcTableEn == pCoexDm->bCurAgcTableEn) + return; + } + halbtc8821a2ant_SetAgcTable(pBtCoexist, bAgcTableEn); + + pCoexDm->bPreAgcTableEn = pCoexDm->bCurAgcTableEn; +} + +VOID +halbtc8821a2ant_SetCoexTable( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c0, val0x6c0); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c4, val0x6c4); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8)); + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x6c8, val0x6c8); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_EXEC, ("[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc)); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x6cc, val0x6cc); +} + +VOID +halbtc8821a2ant_CoexTable( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN u4Byte val0x6c0, + IN u4Byte val0x6c4, + IN u4Byte val0x6c8, + IN u1Byte val0x6cc + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW, ("[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (bForceExec? "force to":""), val0x6c0, val0x6c4, val0x6c8, val0x6cc)); + pCoexDm->curVal0x6c0 = val0x6c0; + pCoexDm->curVal0x6c4 = val0x6c4; + pCoexDm->curVal0x6c8 = val0x6c8; + pCoexDm->curVal0x6cc = val0x6cc; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], preVal0x6c0=0x%x, preVal0x6c4=0x%x, preVal0x6c8=0x%x, preVal0x6cc=0x%x !!\n", + pCoexDm->preVal0x6c0, pCoexDm->preVal0x6c4, pCoexDm->preVal0x6c8, pCoexDm->preVal0x6cc)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_SW_DETAIL, ("[BTCoex], curVal0x6c0=0x%x, curVal0x6c4=0x%x, curVal0x6c8=0x%x, curVal0x6cc=0x%x !!\n", + pCoexDm->curVal0x6c0, pCoexDm->curVal0x6c4, pCoexDm->curVal0x6c8, pCoexDm->curVal0x6cc)); + + if( (pCoexDm->preVal0x6c0 == pCoexDm->curVal0x6c0) && + (pCoexDm->preVal0x6c4 == pCoexDm->curVal0x6c4) && + (pCoexDm->preVal0x6c8 == pCoexDm->curVal0x6c8) && + (pCoexDm->preVal0x6cc == pCoexDm->curVal0x6cc) ) + return; + } + halbtc8821a2ant_SetCoexTable(pBtCoexist, val0x6c0, val0x6c4, val0x6c8, val0x6cc); + + pCoexDm->preVal0x6c0 = pCoexDm->curVal0x6c0; + pCoexDm->preVal0x6c4 = pCoexDm->curVal0x6c4; + pCoexDm->preVal0x6c8 = pCoexDm->curVal0x6c8; + pCoexDm->preVal0x6cc = pCoexDm->curVal0x6cc; +} + +VOID +halbtc8821a2ant_SetFwIgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bEnable + ) +{ + u1Byte H2C_Parameter[1] ={0}; + + if(bEnable) + { + H2C_Parameter[0] |= BIT0; // function enable + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], set FW for BT Ignore Wlan_Act, FW write 0x63=0x%x\n", + H2C_Parameter[0])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x63, 1, H2C_Parameter); +} + +VOID +halbtc8821a2ant_IgnoreWlanAct( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bEnable + ) +{ + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn Ignore WlanAct %s\n", + (bForceExec? "force to":""), (bEnable? "ON":"OFF"))); + pCoexDm->bCurIgnoreWlanAct = bEnable; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPreIgnoreWlanAct = %d, bCurIgnoreWlanAct = %d!!\n", + pCoexDm->bPreIgnoreWlanAct, pCoexDm->bCurIgnoreWlanAct)); + + if(pCoexDm->bPreIgnoreWlanAct == pCoexDm->bCurIgnoreWlanAct) + return; + } + halbtc8821a2ant_SetFwIgnoreWlanAct(pBtCoexist, bEnable); + + pCoexDm->bPreIgnoreWlanAct = pCoexDm->bCurIgnoreWlanAct; +} + +VOID +halbtc8821a2ant_SetFwPstdma( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte byte1, + IN u1Byte byte2, + IN u1Byte byte3, + IN u1Byte byte4, + IN u1Byte byte5 + ) +{ + u1Byte H2C_Parameter[5] ={0}; + + H2C_Parameter[0] = byte1; + H2C_Parameter[1] = byte2; + H2C_Parameter[2] = byte3; + H2C_Parameter[3] = byte4; + H2C_Parameter[4] = byte5; + + pCoexDm->psTdmaPara[0] = byte1; + pCoexDm->psTdmaPara[1] = byte2; + pCoexDm->psTdmaPara[2] = byte3; + pCoexDm->psTdmaPara[3] = byte4; + pCoexDm->psTdmaPara[4] = byte5; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x60(5bytes)=0x%x%08x\n", + H2C_Parameter[0], + H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x60, 5, H2C_Parameter); +} + +VOID +halbtc8821a2ant_SwMechanism1( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bShrinkRxLPF, + IN BOOLEAN bLowPenaltyRA, + IN BOOLEAN bLimitedDIG, + IN BOOLEAN bBTLNAConstrain + ) +{ + u4Byte wifiBw; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 != wifiBw) //only shrink RF Rx LPF for HT40 + { + if (bShrinkRxLPF) + bShrinkRxLPF = FALSE; + } + + halbtc8821a2ant_RfShrink(pBtCoexist, NORMAL_EXEC, bShrinkRxLPF); + halbtc8821a2ant_LowPenaltyRa(pBtCoexist, NORMAL_EXEC, bLowPenaltyRA); + + //no limited DIG + //halbtc8821a2ant_SetBtLnaConstrain(pBtCoexist, NORMAL_EXEC, bBTLNAConstrain); +} + +VOID +halbtc8821a2ant_SwMechanism2( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bAGCTableShift, + IN BOOLEAN bADCBackOff, + IN BOOLEAN bSWDACSwing, + IN u4Byte dacSwingLvl + ) +{ + //halbtc8821a2ant_AgcTable(pBtCoexist, NORMAL_EXEC, bAGCTableShift); + halbtc8821a2ant_AdcBackOff(pBtCoexist, NORMAL_EXEC, bADCBackOff); + halbtc8821a2ant_DacSwing(pBtCoexist, NORMAL_EXEC, bSWDACSwing, dacSwingLvl); +} + +VOID +halbtc8821a2ant_SetAntPath( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte antPosType, + IN BOOLEAN bInitHwCfg, + IN BOOLEAN bWifiOff + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + u4Byte u4Tmp=0; + u1Byte H2C_Parameter[2] ={0}; + + if(bInitHwCfg) + { + // 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT + u4Tmp = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u4Tmp &=~BIT23; + u4Tmp |= BIT24; + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x4c, u4Tmp); + + pBtCoexist->fBtcWrite4Byte(pBtCoexist, 0x974, 0x3ff); + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0xcb4, 0x77); + + if(pBoardInfo->btdmAntPos == BTC_ANTENNA_AT_MAIN_PORT) + { + //tell firmware "antenna inverse" ==> WRONG firmware antenna control code.==>need fw to fix + H2C_Parameter[0] = 1; + H2C_Parameter[1] = 1; + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); + } + else + { + //tell firmware "no antenna inverse" ==> WRONG firmware antenna control code.==>need fw to fix + H2C_Parameter[0] = 0; + H2C_Parameter[1] = 1; + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x65, 2, H2C_Parameter); + } + } + + // ext switch setting + switch(antPosType) + { + case BTC_ANT_WIFI_AT_MAIN: + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xcb7, 0x30, 0x1); + break; + case BTC_ANT_WIFI_AT_AUX: + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0xcb7, 0x30, 0x2); + break; + } +} + +VOID +halbtc8821a2ant_PsTdma( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bForceExec, + IN BOOLEAN bTurnOn, + IN u1Byte type + ) +{ + BOOLEAN bTurnOnByCnt=FALSE; + u1Byte psTdmaTypeByCnt=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], %s turn %s PS TDMA, type=%d\n", + (bForceExec? "force to":""), (bTurnOn? "ON":"OFF"), type)); + pCoexDm->bCurPsTdmaOn = bTurnOn; + pCoexDm->curPsTdma = type; + + if(!bForceExec) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], bPrePsTdmaOn = %d, bCurPsTdmaOn = %d!!\n", + pCoexDm->bPrePsTdmaOn, pCoexDm->bCurPsTdmaOn)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], prePsTdma = %d, curPsTdma = %d!!\n", + pCoexDm->prePsTdma, pCoexDm->curPsTdma)); + + if( (pCoexDm->bPrePsTdmaOn == pCoexDm->bCurPsTdmaOn) && + (pCoexDm->prePsTdma == pCoexDm->curPsTdma) ) + return; + } + if(bTurnOn) + { + switch(type) + { + case 1: + default: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); + break; + case 2: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x90); + break; + case 3: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x3, 0xf1, 0x90); + break; + case 4: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x10, 0x03, 0xf1, 0x90); + break; + case 5: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x90); + break; + case 6: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0x60, 0x90); + break; + case 7: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1c, 0x3, 0x70, 0x90); + break; + case 8: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xa3, 0x10, 0x3, 0x70, 0x90); + break; + case 9: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); + break; + case 10: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0xe1, 0x90); + break; + case 11: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0xe1, 0x90); + break; + case 12: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0xe1, 0x90); + break; + case 13: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x90); + break; + case 14: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x12, 0x12, 0x60, 0x90); + break; + case 15: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0xa, 0xa, 0x60, 0x90); + break; + case 16: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0x60, 0x90); + break; + case 17: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xa3, 0x2f, 0x2f, 0x60, 0x90); + break; + case 18: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x5, 0x5, 0xe1, 0x90); + break; + case 19: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0xe1, 0x90); + break; + case 20: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x25, 0x25, 0x60, 0x90); + break; + case 21: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x15, 0x03, 0x70, 0x90); + break; + case 71: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); + break; + } + } + else + { + // disable PS tdma + switch(type) + { + case 0: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x40, 0x0); + break; + case 1: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x48, 0x0); + break; + default: + halbtc8821a2ant_SetFwPstdma(pBtCoexist, 0x0, 0x0, 0x0, 0x40, 0x0); + break; + } + } + + // update pre state + pCoexDm->bPrePsTdmaOn = pCoexDm->bCurPsTdmaOn; + pCoexDm->prePsTdma = pCoexDm->curPsTdma; +} + +VOID +halbtc8821a2ant_CoexAllOff( + IN PBTC_COEXIST pBtCoexist + ) +{ + // fw all off + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + // sw all off + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + // hw all off + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); +} + +VOID +halbtc8821a2ant_CoexUnder5G( + IN PBTC_COEXIST pBtCoexist + ) +{ + halbtc8821a2ant_CoexAllOff(pBtCoexist); +} + +VOID +halbtc8821a2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + // force to reset coex mechanism + halbtc8821a2ant_CoexTable(pBtCoexist, FORCE_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + + halbtc8821a2ant_PsTdma(pBtCoexist, FORCE_EXEC, FALSE, 1); + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, FORCE_EXEC, 6); + halbtc8821a2ant_DecBtPwr(pBtCoexist, FORCE_EXEC, FALSE); + + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); +} + +VOID +halbtc8821a2ant_BtInquiryPage( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bLowPwrDisable=TRUE; + + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5afa5afa, 0xffff, 0x3); + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); +} +BOOLEAN +halbtc8821a2ant_IsCommonAction( + IN PBTC_COEXIST pBtCoexist + ) +{ + BOOLEAN bCommon=FALSE, bWifiConnected=FALSE, bWifiBusy=FALSE; + BOOLEAN bLowPwrDisable=FALSE; + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5afa5afa, 0xffff, 0x3); + + if(!bWifiConnected && + BT_8821A_2ANT_BT_STATUS_IDLE == pCoexDm->btStatus) + { + bLowPwrDisable = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi IPS + BT IPS!!\n")); + + + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else if(bWifiConnected && + (BT_8821A_2ANT_BT_STATUS_IDLE == pCoexDm->btStatus) ) + { + bLowPwrDisable = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + if(bWifiBusy) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Busy + BT IPS!!\n")); + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi LPS + BT IPS!!\n")); + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + } + + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else if(!bWifiConnected && + (BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + bLowPwrDisable = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi IPS + BT LPS!!\n")); + + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else if(bWifiConnected && + (BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus) ) + { + bLowPwrDisable = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + if(bWifiBusy) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Busy + BT LPS!!\n")); + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi LPS + BT LPS!!\n")); + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + } + + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,TRUE,TRUE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else if(!bWifiConnected && + (BT_8821A_2ANT_BT_STATUS_NON_IDLE == pCoexDm->btStatus) ) + { + bLowPwrDisable = FALSE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi IPS + BT Busy!!\n")); + + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + + bCommon = TRUE; + } + else + { + bLowPwrDisable = TRUE; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_ACT_DISABLE_LOW_POWER, &bLowPwrDisable); + + if(bWifiBusy) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi Busy + BT Busy!!\n")); + bCommon = FALSE; + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Wifi LPS + BT Busy!!\n")); + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 21); + + if(halbtc8821a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + bCommon = TRUE; + } + + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,TRUE,TRUE); + } + + return bCommon; +} +VOID +halbtc8821a2ant_TdmaDurationAdjust( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bScoHid, + IN BOOLEAN bTxPause, + IN u1Byte maxInterval + ) +{ + static s4Byte up,dn,m,n,WaitCount; + s4Byte result; //0: no change, +1: increase WiFi duration, -1: decrease WiFi duration + u1Byte retryCount=0; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW, ("[BTCoex], TdmaDurationAdjust()\n")); + + if(pCoexDm->bResetTdmaAdjust) + { + pCoexDm->bResetTdmaAdjust = FALSE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], first run TdmaDurationAdjust()!!\n")); + { + if(bScoHid) + { + if(bTxPause) + { + if(maxInterval == 1) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + else if(maxInterval == 2) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(maxInterval == 3) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + } + else + { + if(maxInterval == 1) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(maxInterval == 2) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(maxInterval == 3) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + } + else + { + if(bTxPause) + { + if(maxInterval == 1) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(maxInterval == 2) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(maxInterval == 3) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + } + else + { + if(maxInterval == 1) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(maxInterval == 2) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(maxInterval == 3) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + } + } + } + //============ + up = 0; + dn = 0; + m = 1; + n= 3; + result = 0; + WaitCount = 0; + } + else + { + //accquire the BT TRx retry count from BT_Info byte2 + retryCount = pCoexSta->btRetryCnt; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n", + up, dn, m, n, WaitCount)); + result = 0; + WaitCount++; + + if(retryCount == 0) // no retry in the last 2-second duration + { + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if(up >= n) // if �s�� n ��2�� retry count��0, �h�ռeWiFi duration + { + WaitCount = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Increase wifi duration!!\n")); + } + } + else if (retryCount <= 3) // <=3 retry in the last 2-second duration + { + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) // if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration + { + if (WaitCount <= 2) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n")); + } + } + else //retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration + { + if (WaitCount == 1) + m++; // �קK�@���b���level���Ӧ^ + else + m = 1; + + if ( m >= 20) //m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. + m = 20; + + n = 3*m; + up = 0; + dn = 0; + WaitCount = 0; + result = -1; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n")); + } + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], max Interval = %d\n", maxInterval)); + if(maxInterval == 1) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + + if(pCoexDm->curPsTdma == 71) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + pCoexDm->psTdmaDuAdjType = 5; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + pCoexDm->psTdmaDuAdjType = 13; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 71); + pCoexDm->psTdmaDuAdjType = 71; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + + if(result == -1) + { + if(pCoexDm->curPsTdma == 71) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + pCoexDm->psTdmaDuAdjType = 1; + } + else if(pCoexDm->curPsTdma == 1) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 71); + pCoexDm->psTdmaDuAdjType = 71; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + pCoexDm->psTdmaDuAdjType = 9; + } + } + } + } + else if(maxInterval == 2) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + if(pCoexDm->curPsTdma == 1) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 6); + pCoexDm->psTdmaDuAdjType = 6; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + pCoexDm->psTdmaDuAdjType = 14; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 2); + pCoexDm->psTdmaDuAdjType = 2; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + pCoexDm->psTdmaDuAdjType = 10; + } + } + } + } + else if(maxInterval == 3) + { + if(bTxPause) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 1\n")); + if(pCoexDm->curPsTdma == 1) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 4) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + if(pCoexDm->curPsTdma == 9) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 5) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 8); + pCoexDm->psTdmaDuAdjType = 8; + } + else if(pCoexDm->curPsTdma == 13) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 16); + pCoexDm->psTdmaDuAdjType = 16; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 8) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 7); + pCoexDm->psTdmaDuAdjType = 7; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 15); + pCoexDm->psTdmaDuAdjType = 15; + } + } + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], TxPause = 0\n")); + if(pCoexDm->curPsTdma == 5) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 6) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 7) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 8) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + if(pCoexDm->curPsTdma == 13) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 14) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 15) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 16) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + if(result == -1) + { + if(pCoexDm->curPsTdma == 1) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 4); + pCoexDm->psTdmaDuAdjType = 4; + } + else if(pCoexDm->curPsTdma == 9) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 12); + pCoexDm->psTdmaDuAdjType = 12; + } + } + else if (result == 1) + { + if(pCoexDm->curPsTdma == 4) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 3) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 2) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 3); + pCoexDm->psTdmaDuAdjType = 3; + } + else if(pCoexDm->curPsTdma == 12) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 11) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + else if(pCoexDm->curPsTdma == 10) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 11); + pCoexDm->psTdmaDuAdjType = 11; + } + } + } + } + } + + // if current PsTdma not match with the recorded one (when scan, dhcp...), + // then we have to adjust it back to the previous record one. + if(pCoexDm->curPsTdma != pCoexDm->psTdmaDuAdjType) + { + BOOLEAN bScan=FALSE, bLink=FALSE, bRoam=FALSE; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], PsTdma type dismatch!!!, curPsTdma=%d, recordPsTdma=%d\n", + pCoexDm->curPsTdma, pCoexDm->psTdmaDuAdjType)); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + + if( !bScan && !bLink && !bRoam) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, pCoexDm->psTdmaDuAdjType); + } + else + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n")); + } + } + + // when halbtc8821a2ant_TdmaDurationAdjust() is called, fw dac swing is included in the function. + //if(pCoexDm->psTdmaDuAdjType == 71) + // halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0xc); //Skip because A2DP get worse at HT40 + //else + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 0x6); +} + +// SCO only or SCO+PAN(HS) +VOID +halbtc8821a2ant_ActionSco( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState,btRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8821a2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8821a2ant_BtRssiState(2, 35, 0); + + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 4); + + if(halbtc8821a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if (BTC_WIFI_BW_LEGACY == wifiBw) //for SCO quality at 11b/g mode + { + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x5a5a5a5a, 0x5a5a5a5a, 0xffff, 0x3); + } + else //for SCO quality & wifi performance balance at 11n mode + { + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x5aea5aea, 0x5aea5aea, 0xffff, 0x3); + } + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + + // fw mechanism + //halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); //for voice quality + } + else + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); //for voice quality + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + // fw mechanism + //halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); //for voice quality + } + else + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 0); //for voice quality + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + + +VOID +halbtc8821a2ant_ActionHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8821a2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8821a2ant_BtRssiState(2, 35, 0); + + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if(halbtc8821a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if (BTC_WIFI_BW_LEGACY == wifiBw) //for HID at 11b/g mode + { + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5a5a5a5a, 0xffff, 0x3); + } + else //for HID quality & wifi performance balance at 11n mode + { + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5aea5aea, 0xffff, 0x3); + } + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + } + else + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 9); + } + else + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 13); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +//A2DP only / PAN(EDR) only/ A2DP+PAN(HS) +VOID +halbtc8821a2ant_ActionA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8821a2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8821a2ant_BtRssiState(2, 35, 0); + + //fw dac swing is called in halbtc8821a2ant_TdmaDurationAdjust() + //halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + + if(halbtc8821a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 1); + } + else + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 1); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 1); + } + else + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 1); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8821a2ant_ActionA2dpPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + wifiRssiState = halbtc8821a2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8821a2ant_BtRssiState(2,35, 0); + + //fw dac swing is called in halbtc8821a2ant_TdmaDurationAdjust() + //halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + + if(halbtc8821a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 2); + } + else //a2dp edr rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 1); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + // fw mechanism + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 2); + } + else //a2dp edr rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 1); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8821a2ant_ActionPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8821a2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8821a2ant_BtRssiState(2, 35, 0); + + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if(halbtc8821a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if (BTC_WIFI_BW_LEGACY == wifiBw) //for HID at 11b/g mode + { + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5aff5aff, 0xffff, 0x3); + } + else //for HID quality & wifi performance balance at 11n mode + { + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5aff5aff, 0xffff, 0x3); + } + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + } + else + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 1); + } + else + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 5); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + + +//PAN(HS) only +VOID +halbtc8821a2ant_ActionPanHs( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8821a2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8821a2ant_BtRssiState(2, 35, 0); + + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + } + else + { + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + } + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + // fw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + } + else + { + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + } + + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + } + else + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, FALSE, 1); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +//PAN(EDR)+A2DP +VOID +halbtc8821a2ant_ActionPanEdrA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + wifiRssiState = halbtc8821a2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8821a2ant_BtRssiState(2, 35, 0); + + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if(halbtc8821a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if (BTC_WIFI_BW_LEGACY == wifiBw) //for HID at 11b/g mode + { + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5afa5afa, 0xffff, 0x3); + } + else //for HID quality & wifi performance balance at 11n mode + { + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5afa5afa, 0xffff, 0x3); + } + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 3); + } + else //a2dp edr rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 3); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 3); + } + else //a2dp edr rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 3); + } + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + }; + } + else + { + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 3); + } + else //a2dp edr rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, FALSE, 3); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 3); + } + else //a2dp edr rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, FALSE, TRUE, 3); + } + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,FALSE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8821a2ant_ActionPanEdrHid( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState; + u4Byte wifiBw; + + wifiRssiState = halbtc8821a2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8821a2ant_BtRssiState(2, 35, 0); + + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if(halbtc8821a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if (BTC_WIFI_BW_LEGACY == wifiBw) //for HID at 11b/g mode + { + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5a5f5a5f, 0xffff, 0x3); + } + else //for HID quality & wifi performance balance at 11n mode + { + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5a5f5a5f, 0xffff, 0x3); + } + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 3); + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + } + else + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 10); + } + else + { + halbtc8821a2ant_PsTdma(pBtCoexist, NORMAL_EXEC, TRUE, 14); + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +// HID+A2DP+PAN(EDR) +VOID +halbtc8821a2ant_ActionHidA2dpPanEdr( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + wifiRssiState = halbtc8821a2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8821a2ant_BtRssiState(2, 35, 0); + + halbtc8821a2ant_FwDacSwingLvl(pBtCoexist, NORMAL_EXEC, 6); + + if(halbtc8821a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if (BTC_WIFI_BW_LEGACY == wifiBw) //for HID at 11b/g mode + { + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5a5a5a5a, 0xffff, 0x3); + } + else //for HID quality & wifi performance balance at 11n mode + { + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5a5a5a5a, 0xffff, 0x3); + } + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 3); + } + else //a2dp edr rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 3); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 3); + } + else //a2dp edr rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 3); + } + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 3); + } + else //a2dp edr rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 3); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 3); + } + else //a2dp edr rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 3); + } + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8821a2ant_ActionHidA2dp( + IN PBTC_COEXIST pBtCoexist + ) +{ + u1Byte wifiRssiState, btRssiState, btInfoExt; + u4Byte wifiBw; + + btInfoExt = pCoexSta->btInfoExt; + wifiRssiState = halbtc8821a2ant_WifiRssiState(pBtCoexist, 0, 2, 15, 0); + btRssiState = halbtc8821a2ant_BtRssiState(2, 35, 0); + + if(halbtc8821a2ant_NeedToDecBtPwr(pBtCoexist)) + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, TRUE); + else + halbtc8821a2ant_DecBtPwr(pBtCoexist, NORMAL_EXEC, FALSE); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + + if (BTC_WIFI_BW_LEGACY == wifiBw) //for HID at 11b/g mode + { +//Allen halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5a5a5a5a, 0xffff, 0x3); + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5f5b5f5b, 0xffffff, 0x3); + } + else //for HID quality & wifi performance balance at 11n mode + { +//Allen halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5a5a5a5a, 0xffff, 0x3); + halbtc8821a2ant_CoexTable(pBtCoexist, NORMAL_EXEC, 0x55ff55ff, 0x5f5b5f5b, 0xffffff, 0x3); + + } + + if(BTC_WIFI_BW_HT40 == wifiBw) + { + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + } + else //a2dp edr rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + } + else //a2dp edr rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + } + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,TRUE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } + else + { + // fw mechanism + if( (btRssiState == BTC_RSSI_STATE_HIGH) || + (btRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + if(btInfoExt&BIT0) //a2dp basic rate + { +// halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 2); + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + + } + else //a2dp edr rate + { +//Allen halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, FALSE, 2); + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + } + } + else + { + if(btInfoExt&BIT0) //a2dp basic rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + } + else //a2dp edr rate + { + halbtc8821a2ant_TdmaDurationAdjust(pBtCoexist, TRUE, TRUE, 2); + } + } + + // sw mechanism + if( (wifiRssiState == BTC_RSSI_STATE_HIGH) || + (wifiRssiState == BTC_RSSI_STATE_STAY_HIGH) ) + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,TRUE,FALSE,FALSE,0x18); + } + else + { + halbtc8821a2ant_SwMechanism1(pBtCoexist,FALSE,TRUE,FALSE,FALSE); + halbtc8821a2ant_SwMechanism2(pBtCoexist,FALSE,FALSE,FALSE,0x18); + } + } +} + +VOID +halbtc8821a2ant_RunCoexistMechanism( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + BOOLEAN bWifiUnder5G=FALSE; + u1Byte btInfoOriginal=0, btRetryCnt=0; + u1Byte algorithm=0; + + if(pBtCoexist->bManualControl) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Manual control!!!\n")); + return; + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + + if(bWifiUnder5G) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], RunCoexistMechanism(), run 5G coex setting!!<===\n")); + halbtc8821a2ant_CoexUnder5G(pBtCoexist); + return; + } + + if(pStackInfo->bProfileNotified) + { + algorithm = halbtc8821a2ant_ActionAlgorithm(pBtCoexist); + if(pCoexSta->bC2hBtInquiryPage && (BT_8821A_2ANT_COEX_ALGO_PANHS!=algorithm)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], BT is under inquiry/page scan !!\n")); + halbtc8821a2ant_BtInquiryPage(pBtCoexist); + return; + } + + pCoexDm->curAlgorithm = algorithm; + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Algorithm = %d \n", pCoexDm->curAlgorithm)); + + if(halbtc8821a2ant_IsCommonAction(pBtCoexist)) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant common.\n")); + pCoexDm->bResetTdmaAdjust = TRUE; + } + else + { + if(pCoexDm->curAlgorithm != pCoexDm->preAlgorithm) + { + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], preAlgorithm=%d, curAlgorithm=%d\n", + pCoexDm->preAlgorithm, pCoexDm->curAlgorithm)); + pCoexDm->bResetTdmaAdjust = TRUE; + } + switch(pCoexDm->curAlgorithm) + { + case BT_8821A_2ANT_COEX_ALGO_SCO: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = SCO.\n")); + halbtc8821a2ant_ActionSco(pBtCoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID.\n")); + halbtc8821a2ant_ActionHid(pBtCoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP.\n")); + halbtc8821a2ant_ActionA2dp(pBtCoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n")); + halbtc8821a2ant_ActionA2dpPanHs(pBtCoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n")); + halbtc8821a2ant_ActionPanEdr(pBtCoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_PANHS: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HS mode.\n")); + halbtc8821a2ant_ActionPanHs(pBtCoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n")); + halbtc8821a2ant_ActionPanEdrA2dp(pBtCoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_PANEDR_HID: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n")); + halbtc8821a2ant_ActionPanEdrHid(pBtCoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n")); + halbtc8821a2ant_ActionHidA2dpPanEdr(pBtCoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_HID_A2DP: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n")); + halbtc8821a2ant_ActionHidA2dp(pBtCoexist); + break; + default: + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n")); + halbtc8821a2ant_CoexAllOff(pBtCoexist); + break; + } + pCoexDm->preAlgorithm = pCoexDm->curAlgorithm; + } + } + else + { // stack doesn't notify profile info. + // use the following profile info from bt fw. + //pCoexSta->bBtLinkExist + //pCoexSta->bScoExist + //pCoexSta->bA2dpExist + //pCoexSta->bHidExist + //pCoexSta->bPanExist +} +} + + + +//============================================================ +// work around function start with wa_halbtc8821a2ant_ +//============================================================ +//============================================================ +// extern function start with EXhalbtc8821a2ant_ +//============================================================ +VOID +EXhalbtc8821a2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + u4Byte u4Tmp=0; + u2Byte u2Tmp=0; + u1Byte u1Tmp=0; + u1Byte H2C_Parameter[2] ={0}; + + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], 2Ant Init HW Config!!\n")); + + // backup rf 0x1e value + pCoexDm->btRf0x1eBackup = + pBtCoexist->fBtcGetRfReg(pBtCoexist, BTC_RF_A, 0x1e, 0xfffff); + + // 0x790[5:0]=0x5 + u1Tmp = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x790); + u1Tmp &= 0xc0; + u1Tmp |= 0x5; + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x790, u1Tmp); + + //Antenna config + halbtc8821a2ant_SetAntPath(pBtCoexist, BTC_ANT_WIFI_AT_MAIN, TRUE, FALSE); + + // PTA parameter + halbtc8821a2ant_CoexTable(pBtCoexist, FORCE_EXEC, 0x55555555, 0x55555555, 0xffff, 0x3); + + // Enable counter statistics + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x76e, 0xc); //0x76e[3] =1, WLAN_Act control by PTA + pBtCoexist->fBtcWrite1Byte(pBtCoexist, 0x778, 0x3); + pBtCoexist->fBtcWrite1ByteBitMask(pBtCoexist, 0x40, 0x20, 0x1); +} + +VOID +EXhalbtc8821a2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Coex Mechanism Init!!\n")); + + halbtc8821a2ant_InitCoexDm(pBtCoexist); +} + +VOID +EXhalbtc8821a2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ) +{ + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + pu1Byte cliBuf=pBtCoexist->cliBuf; + u1Byte u1Tmp[4], i, btInfoExt, psTdmaCase=0; + u4Byte u4Tmp[4]; + BOOLEAN bRoam=FALSE, bScan=FALSE, bLink=FALSE, bWifiUnder5G=FALSE; + BOOLEAN bBtHsOn=FALSE, bWifiBusy=FALSE; + s4Byte wifiRssi=0, btHsRssi=0; + u4Byte wifiBw, wifiTrafficDir; + u1Byte wifiDot11Chnl, wifiHsChnl; + u4Byte fwVer=0, btPatchVer=0; + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cliBuf); + + if(!pBoardInfo->bBtExist) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!"); + CL_PRINTF(cliBuf); + return; + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "Ant PG number/ Ant mechanism:", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum); + CL_PRINTF(cliBuf); + + if(pBtCoexist->bManualControl) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "[Action Manual control]!!"); + CL_PRINTF(cliBuf); + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", "CoexVer/ FwVer/ PatchVer", \ + GLCoexVerDate8821a2Ant, GLCoexVer8821a2Ant, fwVer, btPatchVer, btPatchVer); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiDot11Chnl); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_HS_CHNL, &wifiHsChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d(%d)", "Dot11 channel / HsMode(HsChnl)", \ + wifiDot11Chnl, bBtHsOn, wifiHsChnl); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", "H2C Wifi inform bt chnl Info", \ + pCoexDm->wifiChnlInfo[0], pCoexDm->wifiChnlInfo[1], + pCoexDm->wifiChnlInfo[2]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_S4_HS_RSSI, &btHsRssi); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Wifi rssi/ HS rssi", \ + wifiRssi, btHsRssi); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Wifi bLink/ bRoam/ bScan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &bWifiUnder5G); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s ", "Wifi status", \ + (bWifiUnder5G? "5G":"2.4G"), + ((BTC_WIFI_BW_LEGACY==wifiBw)? "Legacy": (((BTC_WIFI_BW_HT40==wifiBw)? "HT40":"HT20"))), + ((!bWifiBusy)? "idle": ((BTC_WIFI_TRAFFIC_TX==wifiTrafficDir)? "uplink":"downlink"))); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", "BT [status/ rssi/ retryCnt]", \ + ((pCoexSta->bC2hBtInquiryPage)?("inquiry/page scan"):((BT_8821A_2ANT_BT_STATUS_IDLE == pCoexDm->btStatus)? "idle":( (BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE == pCoexDm->btStatus)? "connected-idle":"busy"))), + pCoexSta->btRssi, pCoexSta->btRetryCnt); + CL_PRINTF(cliBuf); + + if(pStackInfo->bProfileNotified) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP", \ + pStackInfo->bScoExist, pStackInfo->bHidExist, pStackInfo->bPanExist, pStackInfo->bA2dpExist); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_BT_LINK_INFO); + } + + btInfoExt = pCoexSta->btInfoExt; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Info A2DP rate", \ + (btInfoExt&BIT0)? "Basic rate":"EDR rate"); + CL_PRINTF(cliBuf); + + for(i=0; i<BT_INFO_SRC_8821A_2ANT_MAX; i++) + { + if(pCoexSta->btInfoC2hCnt[i]) + { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", GLBtInfoSrc8821a2Ant[i], \ + pCoexSta->btInfoC2h[i][0], pCoexSta->btInfoC2h[i][1], + pCoexSta->btInfoC2h[i][2], pCoexSta->btInfoC2h[i][3], + pCoexSta->btInfoC2h[i][4], pCoexSta->btInfoC2h[i][5], + pCoexSta->btInfoC2h[i][6], pCoexSta->btInfoC2hCnt[i]); + CL_PRINTF(cliBuf); + } + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/%s", "PS state, IPS/LPS", \ + ((pCoexSta->bUnderIps? "IPS ON":"IPS OFF")), + ((pCoexSta->bUnderLps? "LPS ON":"LPS OFF"))); + CL_PRINTF(cliBuf); + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_FW_PWR_MODE_CMD); + + // Sw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw mechanism]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d ", "SM1[ShRf/ LpRA/ LimDig/ btLna]", \ + pCoexDm->bCurRfRxLpfShrink, pCoexDm->bCurLowPenaltyRa, pCoexDm->bLimitedDig, pCoexDm->bCurBtLnaConstrain); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", \ + pCoexDm->bCurAgcTableEn, pCoexDm->bCurAdcBackOff, pCoexDm->bCurDacSwingOn, pCoexDm->curDacSwingLvl); + CL_PRINTF(cliBuf); + + // Fw mechanism + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw mechanism]============"); + CL_PRINTF(cliBuf); + + if(!pBtCoexist->bManualControl) + { + psTdmaCase = pCoexDm->curPsTdma; + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d", "PS TDMA", \ + pCoexDm->psTdmaPara[0], pCoexDm->psTdmaPara[1], + pCoexDm->psTdmaPara[2], pCoexDm->psTdmaPara[3], + pCoexDm->psTdmaPara[4], psTdmaCase); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", "DecBtPwr/ IgnWlanAct", \ + pCoexDm->bCurDecBtPwr, pCoexDm->bCurIgnoreWlanAct); + CL_PRINTF(cliBuf); + } + + // Hw setting + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw setting]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "RF-A, 0x1e initVal", \ + pCoexDm->btRf0x1eBackup); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x778); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x6cc); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x ", "0x778 (W_Act)/ 0x6cc (CoTab Sel)", \ + u1Tmp[0], u1Tmp[1]); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x8db); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xc5b); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x8db(ADC)/0xc5b[29:25](DAC)", \ + ((u1Tmp[0]&0x60)>>5), ((u1Tmp[1]&0x3e)>>1)); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xcb4); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0xcb4[7:0](ctrl)/ 0xcb4[29:28](val)", \ + u4Tmp[0]&0xff, ((u4Tmp[0]&0x30000000)>>28)); + CL_PRINTF(cliBuf); + + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x40); + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x4c); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x974); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x40/ 0x4c[24:23]/ 0x974", \ + u1Tmp[0], ((u4Tmp[0]&0x01800000)>>23), u4Tmp[1]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x550); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x522); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0x550(bcn ctrl)/0x522", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xc50); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa0a); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "0xc50(DIG)/0xa0a(CCK-TH)", \ + u4Tmp[0], u1Tmp[0]); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0xf48); + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5b); + u1Tmp[1] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0xa5c); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "OFDM-FA/ CCK-FA", \ + u4Tmp[0], (u1Tmp[0]<<8) + u1Tmp[1] ); + CL_PRINTF(cliBuf); + + u4Tmp[0] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c0); + u4Tmp[1] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c4); + u4Tmp[2] = pBtCoexist->fBtcRead4Byte(pBtCoexist, 0x6c8); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8", \ + u4Tmp[0], u4Tmp[1], u4Tmp[2]); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x770 (hi-pri Rx/Tx)", \ + pCoexSta->highPriorityRx, pCoexSta->highPriorityTx); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "0x774(low-pri Rx/Tx)", \ + pCoexSta->lowPriorityRx, pCoexSta->lowPriorityTx); + CL_PRINTF(cliBuf); + + // Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang + u1Tmp[0] = pBtCoexist->fBtcRead1Byte(pBtCoexist, 0x41b); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x41b (mgntQ hang chk == 0xf)", \ + u1Tmp[0]); + CL_PRINTF(cliBuf); + + pBtCoexist->fBtcDispDbgMsg(pBtCoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +VOID +EXhalbtc8821a2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_IPS_ENTER == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS ENTER notify\n")); + pCoexSta->bUnderIps = TRUE; + halbtc8821a2ant_CoexAllOff(pBtCoexist); + } + else if(BTC_IPS_LEAVE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], IPS LEAVE notify\n")); + pCoexSta->bUnderIps = FALSE; + //halbtc8821a2ant_InitCoexDm(pBtCoexist); + } +} + +VOID +EXhalbtc8821a2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_LPS_ENABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS ENABLE notify\n")); + pCoexSta->bUnderLps = TRUE; + } + else if(BTC_LPS_DISABLE == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], LPS DISABLE notify\n")); + pCoexSta->bUnderLps = FALSE; + } +} + +VOID +EXhalbtc8821a2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_SCAN_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN START notify\n")); + } + else if(BTC_SCAN_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], SCAN FINISH notify\n")); + } +} + +VOID +EXhalbtc8821a2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(BTC_ASSOCIATE_START == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT START notify\n")); + } + else if(BTC_ASSOCIATE_FINISH == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], CONNECT FINISH notify\n")); + } +} + +VOID +EXhalbtc8821a2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + u1Byte H2C_Parameter[3] ={0}; + u4Byte wifiBw; + u1Byte wifiCentralChnl; + + if(BTC_MEDIA_CONNECT == type) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA connect notify\n")); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], MEDIA disconnect notify\n")); + } + + // only 2.4G we need to inform bt the chnl mask + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, &wifiCentralChnl); + if( (BTC_MEDIA_CONNECT == type) && + (wifiCentralChnl <= 14) ) + { + H2C_Parameter[0] = 0x1; + H2C_Parameter[1] = wifiCentralChnl; + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + if(BTC_WIFI_BW_HT40 == wifiBw) + H2C_Parameter[2] = 0x30; + else + H2C_Parameter[2] = 0x20; + } + + pCoexDm->wifiChnlInfo[0] = H2C_Parameter[0]; + pCoexDm->wifiChnlInfo[1] = H2C_Parameter[1]; + pCoexDm->wifiChnlInfo[2] = H2C_Parameter[2]; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_EXEC, ("[BTCoex], FW write 0x66=0x%x\n", + H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2])); + + pBtCoexist->fBtcFillH2c(pBtCoexist, 0x66, 3, H2C_Parameter); +} + +VOID +EXhalbtc8821a2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ) +{ + if(type == BTC_PACKET_DHCP) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], DHCP Packet notify\n")); + } +} + +VOID +EXhalbtc8821a2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ) +{ + u1Byte btInfo=0; + u1Byte i, rspSource=0; + static u4Byte setBtLnaCnt=0, setBtPsdMode=0; + BOOLEAN bBtBusy=FALSE, bLimitedDig=FALSE; + BOOLEAN bWifiConnected=FALSE, bBtHsOn=FALSE; + + pCoexSta->bC2hBtInfoReqSent = FALSE; + + rspSource = tmpBuf[0]&0xf; + if(rspSource >= BT_INFO_SRC_8821A_2ANT_MAX) + rspSource = BT_INFO_SRC_8821A_2ANT_WIFI_FW; + pCoexSta->btInfoC2hCnt[rspSource]++; + + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Bt info[%d], length=%d, hex data=[", rspSource, length)); + for(i=0; i<length; i++) + { + pCoexSta->btInfoC2h[rspSource][i] = tmpBuf[i]; + if(i == 1) + btInfo = tmpBuf[i]; + if(i == length-1) + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x]\n", tmpBuf[i])); + } + else + { + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("0x%02x, ", tmpBuf[i])); + } + } + + if(BT_INFO_SRC_8821A_2ANT_WIFI_FW != rspSource) + { + pCoexSta->btRetryCnt = // [3:0] + pCoexSta->btInfoC2h[rspSource][2]&0xf; + + pCoexSta->btRssi = + pCoexSta->btInfoC2h[rspSource][3]*2+10; + + pCoexSta->btInfoExt = + pCoexSta->btInfoC2h[rspSource][4]; + + // Here we need to resend some wifi info to BT + // because bt is reset and loss of the info. + if( (pCoexSta->btInfoExt & BIT1) ) + { + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_WIFI_CONNECTED, &bWifiConnected); + if(bWifiConnected) + { + EXhalbtc8821a2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_CONNECT); + } + else + { + EXhalbtc8821a2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); + } + + setBtPsdMode = 0; + } + if(setBtPsdMode <= 3) + { + halbtc8821a2ant_SetBtPsdMode(pBtCoexist, FORCE_EXEC, 0x0); //fix CH-BW mode + setBtPsdMode++; + } + + if(pCoexDm->bCurBtLnaConstrain) + { + if( (pCoexSta->btInfoExt & BIT2) ) + { + } + else + { + if(setBtLnaCnt <= 3) + { + halbtc8821a2ant_SetBtLnaConstrain(pBtCoexist, FORCE_EXEC, TRUE); + setBtLnaCnt++; + } + } + } + else + { + setBtLnaCnt = 0; + } + + if( (pCoexSta->btInfoExt & BIT3) ) + { + halbtc8821a2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, FALSE); + } + else + { + // BT already NOT ignore Wlan active, do nothing here. + } + + if( (pCoexSta->btInfoExt & BIT4) ) + { + // BT auto report already enabled, do nothing + } + else + { + halbtc8821a2ant_BtAutoReport(pBtCoexist, FORCE_EXEC, TRUE); + } + } + + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_BL_HS_OPERATION, &bBtHsOn); + // check BIT2 first ==> check if bt is under inquiry or page scan + if(btInfo & BT_INFO_8821A_2ANT_B_INQ_PAGE) + { + pCoexSta->bC2hBtInquiryPage = TRUE; + pCoexDm->btStatus = BT_8821A_2ANT_BT_STATUS_NON_IDLE; + } + else + { + pCoexSta->bC2hBtInquiryPage = FALSE; + if(btInfo == 0x1) // connection exists but no busy + { + pCoexSta->bBtLinkExist = TRUE; + pCoexDm->btStatus = BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE; + } + else if(btInfo & BT_INFO_8821A_2ANT_B_CONNECTION) // connection exists and some link is busy + { + pCoexSta->bBtLinkExist = TRUE; + if(btInfo & BT_INFO_8821A_2ANT_B_FTP) + pCoexSta->bPanExist = TRUE; + else + pCoexSta->bPanExist = FALSE; + if(btInfo & BT_INFO_8821A_2ANT_B_A2DP) + pCoexSta->bA2dpExist = TRUE; + else + pCoexSta->bA2dpExist = FALSE; + if(btInfo & BT_INFO_8821A_2ANT_B_HID) + pCoexSta->bHidExist = TRUE; + else + pCoexSta->bHidExist = FALSE; + if(btInfo & BT_INFO_8821A_2ANT_B_SCO_ESCO) + pCoexSta->bScoExist = TRUE; + else + pCoexSta->bScoExist = FALSE; + pCoexDm->btStatus = BT_8821A_2ANT_BT_STATUS_NON_IDLE; + } + else + { + pCoexSta->bBtLinkExist = FALSE; + pCoexSta->bPanExist = FALSE; + pCoexSta->bA2dpExist = FALSE; + pCoexSta->bHidExist = FALSE; + pCoexSta->bScoExist = FALSE; + pCoexDm->btStatus = BT_8821A_2ANT_BT_STATUS_IDLE; + } + + if(bBtHsOn) + { + pCoexDm->btStatus = BT_8821A_2ANT_BT_STATUS_NON_IDLE; + } + } + + if(BT_8821A_2ANT_BT_STATUS_NON_IDLE == pCoexDm->btStatus) + { + bBtBusy = TRUE; + } + else + { + bBtBusy = FALSE; + } + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bBtBusy); + + if(BT_8821A_2ANT_BT_STATUS_IDLE != pCoexDm->btStatus) + { + bLimitedDig = TRUE; + } + else + { + bLimitedDig = FALSE; + } + pCoexDm->bLimitedDig = bLimitedDig; + pBtCoexist->fBtcSet(pBtCoexist, BTC_SET_BL_BT_LIMITED_DIG, &bLimitedDig); + + halbtc8821a2ant_RunCoexistMechanism(pBtCoexist); +} + +VOID +EXhalbtc8821a2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ) +{ + BTC_PRINT(BTC_MSG_INTERFACE, INTF_NOTIFY, ("[BTCoex], Halt notify\n")); + + halbtc8821a2ant_IgnoreWlanAct(pBtCoexist, FORCE_EXEC, TRUE); + EXhalbtc8821a2ant_MediaStatusNotify(pBtCoexist, BTC_MEDIA_DISCONNECT); +} + +VOID +EXhalbtc8821a2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ) +{ + static u1Byte disVerInfoCnt=0; + u4Byte fwVer=0, btPatchVer=0; + PBTC_BOARD_INFO pBoardInfo=&pBtCoexist->boardInfo; + PBTC_STACK_INFO pStackInfo=&pBtCoexist->stackInfo; + + BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], ==========================Periodical===========================\n")); + + if(disVerInfoCnt <= 5) + { + disVerInfoCnt += 1; + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", \ + pBoardInfo->pgAntNum, pBoardInfo->btdmAntNum, pBoardInfo->btdmAntPos)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], BT stack/ hci ext ver = %s / %d\n", \ + ((pStackInfo->bProfileNotified)? "Yes":"No"), pStackInfo->hciVersion)); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_BT_PATCH_VER, &btPatchVer); + pBtCoexist->fBtcGet(pBtCoexist, BTC_GET_U4_WIFI_FW_VER, &fwVer); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", \ + GLCoexVerDate8821a2Ant, GLCoexVer8821a2Ant, fwVer, btPatchVer, btPatchVer)); + BTC_PRINT(BTC_MSG_INTERFACE, INTF_INIT, ("[BTCoex], ****************************************************************\n")); + } + + halbtc8821a2ant_QueryBtInfo(pBtCoexist); + halbtc8821a2ant_MonitorBtCtr(pBtCoexist); + halbtc8821a2ant_MonitorBtEnableDisable(pBtCoexist); +} + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a2Ant.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a2Ant.h new file mode 100644 index 0000000..46b87ee --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtc8821a2Ant.h @@ -0,0 +1,180 @@ +//=========================================== +// The following is for 8821A 2Ant BT Co-exist definition +//=========================================== +#define BT_INFO_8821A_2ANT_B_FTP BIT7 +#define BT_INFO_8821A_2ANT_B_A2DP BIT6 +#define BT_INFO_8821A_2ANT_B_HID BIT5 +#define BT_INFO_8821A_2ANT_B_SCO_BUSY BIT4 +#define BT_INFO_8821A_2ANT_B_ACL_BUSY BIT3 +#define BT_INFO_8821A_2ANT_B_INQ_PAGE BIT2 +#define BT_INFO_8821A_2ANT_B_SCO_ESCO BIT1 +#define BT_INFO_8821A_2ANT_B_CONNECTION BIT0 + +#define BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT 2 + +typedef enum _BT_INFO_SRC_8821A_2ANT{ + BT_INFO_SRC_8821A_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8821A_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8821A_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8821A_2ANT_MAX +}BT_INFO_SRC_8821A_2ANT,*PBT_INFO_SRC_8821A_2ANT; + +typedef enum _BT_8821A_2ANT_BT_STATUS{ + BT_8821A_2ANT_BT_STATUS_IDLE = 0x0, + BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8821A_2ANT_BT_STATUS_NON_IDLE = 0x2, + BT_8821A_2ANT_BT_STATUS_MAX +}BT_8821A_2ANT_BT_STATUS,*PBT_8821A_2ANT_BT_STATUS; + +typedef enum _BT_8821A_2ANT_COEX_ALGO{ + BT_8821A_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8821A_2ANT_COEX_ALGO_SCO = 0x1, + BT_8821A_2ANT_COEX_ALGO_HID = 0x2, + BT_8821A_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8821A_2ANT_COEX_ALGO_PANEDR = 0x5, + BT_8821A_2ANT_COEX_ALGO_PANHS = 0x6, + BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8821A_2ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8821A_2ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8821A_2ANT_COEX_ALGO_MAX = 0xb, +}BT_8821A_2ANT_COEX_ALGO,*PBT_8821A_2ANT_COEX_ALGO; + +typedef struct _COEX_DM_8821A_2ANT{ + // fw mechanism + BOOLEAN bPreDecBtPwr; + BOOLEAN bCurDecBtPwr; + BOOLEAN bPreBtLnaConstrain; + BOOLEAN bCurBtLnaConstrain; + u1Byte bPreBtPsdMode; + u1Byte bCurBtPsdMode; + u1Byte preFwDacSwingLvl; + u1Byte curFwDacSwingLvl; + BOOLEAN bCurIgnoreWlanAct; + BOOLEAN bPreIgnoreWlanAct; + u1Byte prePsTdma; + u1Byte curPsTdma; + u1Byte psTdmaPara[5]; + u1Byte psTdmaDuAdjType; + BOOLEAN bResetTdmaAdjust; + BOOLEAN bPrePsTdmaOn; + BOOLEAN bCurPsTdmaOn; + BOOLEAN bPreBtAutoReport; + BOOLEAN bCurBtAutoReport; + + // sw mechanism + BOOLEAN bPreRfRxLpfShrink; + BOOLEAN bCurRfRxLpfShrink; + u4Byte btRf0x1eBackup; + BOOLEAN bPreLowPenaltyRa; + BOOLEAN bCurLowPenaltyRa; + BOOLEAN bPreDacSwingOn; + u4Byte preDacSwingLvl; + BOOLEAN bCurDacSwingOn; + u4Byte curDacSwingLvl; + BOOLEAN bPreAdcBackOff; + BOOLEAN bCurAdcBackOff; + BOOLEAN bPreAgcTableEn; + BOOLEAN bCurAgcTableEn; + u4Byte preVal0x6c0; + u4Byte curVal0x6c0; + u4Byte preVal0x6c4; + u4Byte curVal0x6c4; + u4Byte preVal0x6c8; + u4Byte curVal0x6c8; + u1Byte preVal0x6cc; + u1Byte curVal0x6cc; + BOOLEAN bLimitedDig; + + // algorithm related + u1Byte preAlgorithm; + u1Byte curAlgorithm; + u1Byte btStatus; + u1Byte wifiChnlInfo[3]; +} COEX_DM_8821A_2ANT, *PCOEX_DM_8821A_2ANT; + +typedef struct _COEX_STA_8821A_2ANT{ + BOOLEAN bBtLinkExist; + BOOLEAN bScoExist; + BOOLEAN bA2dpExist; + BOOLEAN bHidExist; + BOOLEAN bPanExist; + + BOOLEAN bUnderLps; + BOOLEAN bUnderIps; + u4Byte highPriorityTx; + u4Byte highPriorityRx; + u4Byte lowPriorityTx; + u4Byte lowPriorityRx; + u1Byte btRssi; + u1Byte preBtRssiState; + u1Byte preWifiRssiState[4]; + BOOLEAN bC2hBtInfoReqSent; + u1Byte btInfoC2h[BT_INFO_SRC_8821A_2ANT_MAX][10]; + u4Byte btInfoC2hCnt[BT_INFO_SRC_8821A_2ANT_MAX]; + BOOLEAN bC2hBtInquiryPage; + u1Byte btRetryCnt; + u1Byte btInfoExt; +}COEX_STA_8821A_2ANT, *PCOEX_STA_8821A_2ANT; + +//=========================================== +// The following is interface which will notify coex module. +//=========================================== +VOID +EXhalbtc8821a2ant_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8821a2ant_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8821a2ant_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8821a2ant_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8821a2ant_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8821a2ant_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8821a2ant_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8821a2ant_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtc8821a2ant_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtc8821a2ant_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8821a2ant_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtc8821a2ant_DisplayCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtcOutSrc.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtcOutSrc.h new file mode 100644 index 0000000..8345925 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/HalBtcOutSrc.h @@ -0,0 +1,681 @@ +#ifndef __HALBTC_OUT_SRC_H__ +#define __HALBTC_OUT_SRC_H__ + +#define NORMAL_EXEC FALSE +#define FORCE_EXEC TRUE + +#define BTC_RF_A 0x0 +#define BTC_RF_B 0x1 +#define BTC_RF_C 0x2 +#define BTC_RF_D 0x3 + +#define BTC_SMSP SINGLEMAC_SINGLEPHY +#define BTC_DMDP DUALMAC_DUALPHY +#define BTC_DMSP DUALMAC_SINGLEPHY +#define BTC_MP_UNKNOWN 0xff + +#define BT_COEX_ANT_TYPE_PG 0 +#define BT_COEX_ANT_TYPE_ANTDIV 1 +#define BT_COEX_ANT_TYPE_DETECTED 2 + +#define BTC_MIMO_PS_STATIC 0 // 1ss +#define BTC_MIMO_PS_DYNAMIC 1 // 2ss + +#define BTC_RATE_DISABLE 0 +#define BTC_RATE_ENABLE 1 + +// single Antenna definition +#define BTC_ANT_PATH_WIFI 0 +#define BTC_ANT_PATH_BT 1 +#define BTC_ANT_PATH_PTA 2 +// dual Antenna definition +#define BTC_ANT_WIFI_AT_MAIN 0 +#define BTC_ANT_WIFI_AT_AUX 1 +// coupler Antenna definition +#define BTC_ANT_WIFI_AT_CPL_MAIN 0 +#define BTC_ANT_WIFI_AT_CPL_AUX 1 + +typedef enum _BTC_POWERSAVE_TYPE{ + BTC_PS_WIFI_NATIVE = 0, // wifi original power save behavior + BTC_PS_LPS_ON = 1, + BTC_PS_LPS_OFF = 2, + BTC_PS_MAX +} BTC_POWERSAVE_TYPE, *PBTC_POWERSAVE_TYPE; + +typedef enum _BTC_CHIP_INTERFACE{ + BTC_INTF_UNKNOWN = 0, + BTC_INTF_PCI = 1, + BTC_INTF_USB = 2, + BTC_INTF_SDIO = 3, + BTC_INTF_MAX +} BTC_CHIP_INTERFACE, *PBTC_CHIP_INTERFACE; + +typedef enum _BTC_CHIP_TYPE{ + BTC_CHIP_UNDEF = 0, + BTC_CHIP_CSR_BC4 = 1, + BTC_CHIP_CSR_BC8 = 2, + BTC_CHIP_RTL8723A = 3, + BTC_CHIP_RTL8821 = 4, + BTC_CHIP_RTL8723B = 5, + BTC_CHIP_MAX +} BTC_CHIP_TYPE, *PBTC_CHIP_TYPE; + +typedef enum _BTC_MSG_TYPE{ + BTC_MSG_INTERFACE = 0x0, + BTC_MSG_ALGORITHM = 0x1, + BTC_MSG_MAX +}BTC_MSG_TYPE; +extern u4Byte GLBtcDbgType[]; + +// following is for BTC_MSG_INTERFACE +#define INTF_INIT BIT0 +#define INTF_NOTIFY BIT2 + +// following is for BTC_ALGORITHM +#define ALGO_BT_RSSI_STATE BIT0 +#define ALGO_WIFI_RSSI_STATE BIT1 +#define ALGO_BT_MONITOR BIT2 +#define ALGO_TRACE BIT3 +#define ALGO_TRACE_FW BIT4 +#define ALGO_TRACE_FW_DETAIL BIT5 +#define ALGO_TRACE_FW_EXEC BIT6 +#define ALGO_TRACE_SW BIT7 +#define ALGO_TRACE_SW_DETAIL BIT8 +#define ALGO_TRACE_SW_EXEC BIT9 + +// following is for wifi link status +#define WIFI_STA_CONNECTED BIT0 +#define WIFI_AP_CONNECTED BIT1 +#define WIFI_HS_CONNECTED BIT2 +#define WIFI_P2P_GO_CONNECTED BIT3 +#define WIFI_P2P_GC_CONNECTED BIT4 + +// following is for command line utility +#define CL_SPRINTF rsprintf +#define CL_PRINTF DCMD_Printf + +// The following is for dbgview print +#if DBG +#define BTC_PRINT(dbgtype, dbgflag, printstr)\ +{\ + if (GLBtcDbgType[dbgtype] & dbgflag)\ + {\ + DbgPrint printstr;\ + }\ +} + +#define BTC_PRINT_F(dbgtype, dbgflag, printstr)\ +{\ + if (GLBtcDbgType[dbgtype] & dbgflag)\ + {\ + DbgPrint("%s(): ", __FUNCTION__);\ + DbgPrint printstr;\ + }\ +} + +#define BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _Ptr)\ +{\ + if (GLBtcDbgType[dbgtype] & dbgflag)\ + {\ + int __i; \ + pu1Byte ptr = (pu1Byte)_Ptr; \ + DbgPrint printstr; \ + DbgPrint(" "); \ + for( __i=0; __i<6; __i++ ) \ + DbgPrint("%02X%s", ptr[__i], (__i==5)?"":"-"); \ + DbgPrint("\n"); \ + }\ +} + +#define BTC_PRINT_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen)\ +{\ + if (GLBtcDbgType[dbgtype] & dbgflag)\ + {\ + int __i; \ + pu1Byte ptr = (pu1Byte)_HexData; \ + DbgPrint(_TitleString); \ + for( __i=0; __i<(int)_HexDataLen; __i++ ) \ + { \ + DbgPrint("%02X%s", ptr[__i], (((__i + 1) % 4) == 0)?" ":" ");\ + if (((__i + 1) % 16) == 0) DbgPrint("\n");\ + } \ + DbgPrint("\n"); \ + }\ +} + +#else +#define BTC_PRINT(dbgtype, dbgflag, printstr) +#define BTC_PRINT_F(dbgtype, dbgflag, printstr) +#define BTC_PRINT_ADDR(dbgtype, dbgflag, printstr, _Ptr) +#define BTC_PRINT_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen) +#endif + +typedef struct _BTC_BOARD_INFO{ + // The following is some board information + u1Byte btChipType; + u1Byte pgAntNum; // pg ant number + u1Byte btdmAntNum; // ant number for btdm + u1Byte btdmAntPos; //Bryant Add to indicate Antenna Position for (pgAntNum = 2) && (btdmAntNum =1) (DPDT+1Ant case) + BOOLEAN bBtExist; +} BTC_BOARD_INFO, *PBTC_BOARD_INFO; + +typedef enum _BTC_DBG_OPCODE{ + BTC_DBG_SET_COEX_NORMAL = 0x0, + BTC_DBG_SET_COEX_WIFI_ONLY = 0x1, + BTC_DBG_SET_COEX_BT_ONLY = 0x2, + BTC_DBG_SET_COEX_DEC_BT_PWR = 0x3, + BTC_DBG_SET_COEX_BT_AFH_MAP = 0x4, + BTC_DBG_SET_COEX_BT_IGNORE_WLAN_ACT = 0x5, + BTC_DBG_MAX +}BTC_DBG_OPCODE,*PBTC_DBG_OPCODE; + +typedef enum _BTC_RSSI_STATE{ + BTC_RSSI_STATE_HIGH = 0x0, + BTC_RSSI_STATE_MEDIUM = 0x1, + BTC_RSSI_STATE_LOW = 0x2, + BTC_RSSI_STATE_STAY_HIGH = 0x3, + BTC_RSSI_STATE_STAY_MEDIUM = 0x4, + BTC_RSSI_STATE_STAY_LOW = 0x5, + BTC_RSSI_MAX +}BTC_RSSI_STATE,*PBTC_RSSI_STATE; +#define BTC_RSSI_HIGH(_rssi_) ((_rssi_==BTC_RSSI_STATE_HIGH||_rssi_==BTC_RSSI_STATE_STAY_HIGH)? TRUE:FALSE) +#define BTC_RSSI_MEDIUM(_rssi_) ((_rssi_==BTC_RSSI_STATE_MEDIUM||_rssi_==BTC_RSSI_STATE_STAY_MEDIUM)? TRUE:FALSE) +#define BTC_RSSI_LOW(_rssi_) ((_rssi_==BTC_RSSI_STATE_LOW||_rssi_==BTC_RSSI_STATE_STAY_LOW)? TRUE:FALSE) + +typedef enum _BTC_WIFI_ROLE{ + BTC_ROLE_STATION = 0x0, + BTC_ROLE_AP = 0x1, + BTC_ROLE_IBSS = 0x2, + BTC_ROLE_HS_MODE = 0x3, + BTC_ROLE_MAX +}BTC_WIFI_ROLE,*PBTC_WIFI_ROLE; + +typedef enum _BTC_WIFI_BW_MODE{ + BTC_WIFI_BW_LEGACY = 0x0, + BTC_WIFI_BW_HT20 = 0x1, + BTC_WIFI_BW_HT40 = 0x2, + BTC_WIFI_BW_MAX +}BTC_WIFI_BW_MODE,*PBTC_WIFI_BW_MODE; + +typedef enum _BTC_WIFI_TRAFFIC_DIR{ + BTC_WIFI_TRAFFIC_TX = 0x0, + BTC_WIFI_TRAFFIC_RX = 0x1, + BTC_WIFI_TRAFFIC_MAX +}BTC_WIFI_TRAFFIC_DIR,*PBTC_WIFI_TRAFFIC_DIR; + +typedef enum _BTC_WIFI_PNP{ + BTC_WIFI_PNP_WAKE_UP = 0x0, + BTC_WIFI_PNP_SLEEP = 0x1, + BTC_WIFI_PNP_MAX +}BTC_WIFI_PNP,*PBTC_WIFI_PNP; + +// defined for BFP_BTC_GET +typedef enum _BTC_GET_TYPE{ + // type BOOLEAN + BTC_GET_BL_HS_OPERATION, + BTC_GET_BL_HS_CONNECTING, + BTC_GET_BL_WIFI_CONNECTED, + BTC_GET_BL_WIFI_BUSY, + BTC_GET_BL_WIFI_SCAN, + BTC_GET_BL_WIFI_LINK, + BTC_GET_BL_WIFI_ROAM, + BTC_GET_BL_WIFI_4_WAY_PROGRESS, + BTC_GET_BL_WIFI_UNDER_5G, + BTC_GET_BL_WIFI_AP_MODE_ENABLE, + BTC_GET_BL_WIFI_ENABLE_ENCRYPTION, + BTC_GET_BL_WIFI_UNDER_B_MODE, + BTC_GET_BL_EXT_SWITCH, + + // type s4Byte + BTC_GET_S4_WIFI_RSSI, + BTC_GET_S4_HS_RSSI, + + // type u4Byte + BTC_GET_U4_WIFI_BW, + BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, + BTC_GET_U4_WIFI_FW_VER, + BTC_GET_U4_WIFI_LINK_STATUS, + BTC_GET_U4_BT_PATCH_VER, + + // type u1Byte + BTC_GET_U1_WIFI_DOT11_CHNL, + BTC_GET_U1_WIFI_CENTRAL_CHNL, + BTC_GET_U1_WIFI_HS_CHNL, + BTC_GET_U1_MAC_PHY_MODE, + BTC_GET_U1_AP_NUM, + + //===== for 1Ant ====== + BTC_GET_U1_LPS_MODE, + + BTC_GET_MAX +}BTC_GET_TYPE,*PBTC_GET_TYPE; + +// defined for BFP_BTC_SET +typedef enum _BTC_SET_TYPE{ + // type BOOLEAN + BTC_SET_BL_BT_DISABLE, + BTC_SET_BL_BT_TRAFFIC_BUSY, + BTC_SET_BL_BT_LIMITED_DIG, + BTC_SET_BL_FORCE_TO_ROAM, + BTC_SET_BL_TO_REJ_AP_AGG_PKT, + BTC_SET_BL_BT_CTRL_AGG_SIZE, + BTC_SET_BL_INC_SCAN_DEV_NUM, + + // type u1Byte + BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, + BTC_SET_U1_AGG_BUF_SIZE, + + // type trigger some action + BTC_SET_ACT_GET_BT_RSSI, + BTC_SET_ACT_AGGREGATE_CTRL, + //===== for 1Ant ====== + // type BOOLEAN + + // type u1Byte + BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, + BTC_SET_U1_LPS_VAL, + BTC_SET_U1_RPWM_VAL, + // type trigger some action + BTC_SET_ACT_LEAVE_LPS, + BTC_SET_ACT_ENTER_LPS, + BTC_SET_ACT_NORMAL_LPS, + BTC_SET_ACT_DISABLE_LOW_POWER, + BTC_SET_ACT_UPDATE_RAMASK, + BTC_SET_ACT_SEND_MIMO_PS, + // BT Coex related + BTC_SET_ACT_CTRL_BT_INFO, + BTC_SET_ACT_CTRL_BT_COEX, + //================= + BTC_SET_MAX +}BTC_SET_TYPE,*PBTC_SET_TYPE; + +typedef enum _BTC_DBG_DISP_TYPE{ + BTC_DBG_DISP_COEX_STATISTICS = 0x0, + BTC_DBG_DISP_BT_LINK_INFO = 0x1, + BTC_DBG_DISP_FW_PWR_MODE_CMD = 0x2, + BTC_DBG_DISP_MAX +}BTC_DBG_DISP_TYPE,*PBTC_DBG_DISP_TYPE; + +typedef enum _BTC_NOTIFY_TYPE_IPS{ + BTC_IPS_LEAVE = 0x0, + BTC_IPS_ENTER = 0x1, + BTC_IPS_MAX +}BTC_NOTIFY_TYPE_IPS,*PBTC_NOTIFY_TYPE_IPS; +typedef enum _BTC_NOTIFY_TYPE_LPS{ + BTC_LPS_DISABLE = 0x0, + BTC_LPS_ENABLE = 0x1, + BTC_LPS_MAX +}BTC_NOTIFY_TYPE_LPS,*PBTC_NOTIFY_TYPE_LPS; +typedef enum _BTC_NOTIFY_TYPE_SCAN{ + BTC_SCAN_FINISH = 0x0, + BTC_SCAN_START = 0x1, + BTC_SCAN_MAX +}BTC_NOTIFY_TYPE_SCAN,*PBTC_NOTIFY_TYPE_SCAN; +typedef enum _BTC_NOTIFY_TYPE_ASSOCIATE{ + BTC_ASSOCIATE_FINISH = 0x0, + BTC_ASSOCIATE_START = 0x1, + BTC_ASSOCIATE_MAX +}BTC_NOTIFY_TYPE_ASSOCIATE,*PBTC_NOTIFY_TYPE_ASSOCIATE; +typedef enum _BTC_NOTIFY_TYPE_MEDIA_STATUS{ + BTC_MEDIA_DISCONNECT = 0x0, + BTC_MEDIA_CONNECT = 0x1, + BTC_MEDIA_MAX +}BTC_NOTIFY_TYPE_MEDIA_STATUS,*PBTC_NOTIFY_TYPE_MEDIA_STATUS; +typedef enum _BTC_NOTIFY_TYPE_SPECIAL_PACKET{ + BTC_PACKET_UNKNOWN = 0x0, + BTC_PACKET_DHCP = 0x1, + BTC_PACKET_ARP = 0x2, + BTC_PACKET_EAPOL = 0x3, + BTC_PACKET_MAX +}BTC_NOTIFY_TYPE_SPECIAL_PACKET,*PBTC_NOTIFY_TYPE_SPECIAL_PACKET; +typedef enum _BTC_NOTIFY_TYPE_STACK_OPERATION{ + BTC_STACK_OP_NONE = 0x0, + BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1, + BTC_STACK_OP_INQ_PAGE_PAIR_FINISH = 0x2, + BTC_STACK_OP_MAX +}BTC_NOTIFY_TYPE_STACK_OPERATION,*PBTC_NOTIFY_TYPE_STACK_OPERATION; + +//Bryant Add +typedef enum _BTC_ANTENNA_POS{ + BTC_ANTENNA_AT_MAIN_PORT = 0x1, + BTC_ANTENNA_AT_AUX_PORT = 0x2, +}BTC_ANTENNA_POS,*PBTC_ANTENNA_POS; + +typedef u1Byte +(*BFP_BTC_R1)( + IN PVOID pBtcContext, + IN u4Byte RegAddr + ); +typedef u2Byte +(*BFP_BTC_R2)( + IN PVOID pBtcContext, + IN u4Byte RegAddr + ); +typedef u4Byte +(*BFP_BTC_R4)( + IN PVOID pBtcContext, + IN u4Byte RegAddr + ); +typedef VOID +(*BFP_BTC_W1)( + IN PVOID pBtcContext, + IN u4Byte RegAddr, + IN u1Byte Data + ); +typedef VOID +(*BFP_BTC_W1_BIT_MASK)( + IN PVOID pBtcContext, + IN u4Byte regAddr, + IN u1Byte bitMask, + IN u1Byte data1b + ); +typedef VOID +(*BFP_BTC_W2)( + IN PVOID pBtcContext, + IN u4Byte RegAddr, + IN u2Byte Data + ); +typedef VOID +(*BFP_BTC_W4)( + IN PVOID pBtcContext, + IN u4Byte RegAddr, + IN u4Byte Data + ); +typedef VOID +(*BFP_BTC_SET_BB_REG)( + IN PVOID pBtcContext, + IN u4Byte RegAddr, + IN u4Byte BitMask, + IN u4Byte Data + ); +typedef u4Byte +(*BFP_BTC_GET_BB_REG)( + IN PVOID pBtcContext, + IN u4Byte RegAddr, + IN u4Byte BitMask + ); +typedef VOID +(*BFP_BTC_SET_RF_REG)( + IN PVOID pBtcContext, + IN u1Byte eRFPath, + IN u4Byte RegAddr, + IN u4Byte BitMask, + IN u4Byte Data + ); +typedef u4Byte +(*BFP_BTC_GET_RF_REG)( + IN PVOID pBtcContext, + IN u1Byte eRFPath, + IN u4Byte RegAddr, + IN u4Byte BitMask + ); +typedef VOID +(*BFP_BTC_SET_BT_REG)( + IN PVOID pBtcContext, + IN u1Byte RegType, + IN u4Byte RegAddr, + IN u4Byte Data + ); +typedef VOID +(*BFP_BTC_FILL_H2C)( + IN PVOID pBtcContext, + IN u1Byte elementId, + IN u4Byte cmdLen, + IN pu1Byte pCmdBuffer + ); + +typedef BOOLEAN +(*BFP_BTC_GET)( + IN PVOID pBtCoexist, + IN u1Byte getType, + OUT PVOID pOutBuf + ); + +typedef BOOLEAN +(*BFP_BTC_SET)( + IN PVOID pBtCoexist, + IN u1Byte setType, + OUT PVOID pInBuf + ); +typedef VOID +(*BFP_BTC_DISP_DBG_MSG)( + IN PVOID pBtCoexist, + IN u1Byte dispType + ); + +typedef struct _BTC_BT_INFO{ + BOOLEAN bBtDisabled; + u1Byte rssiAdjustForAgcTableOn; + u1Byte rssiAdjustFor1AntCoexType; + BOOLEAN bPreBtCtrlAggBufSize; + BOOLEAN bBtCtrlAggBufSize; + BOOLEAN bRejectAggPkt; + BOOLEAN bIncreaseScanDevNum; + u1Byte preAggBufSize; + u1Byte aggBufSize; + BOOLEAN bBtBusy; + BOOLEAN bLimitedDig; + u2Byte btHciVer; + u2Byte btRealFwVer; + u1Byte btFwVer; + + BOOLEAN bBtDisableLowPwr; + + BOOLEAN bBtCtrlLps; + BOOLEAN bBtLpsOn; + BOOLEAN bForceToRoam; // for 1Ant solution + u1Byte lpsVal; + u1Byte rpwmVal; + u4Byte raMask; +} BTC_BT_INFO, *PBTC_BT_INFO; + +typedef struct _BTC_STACK_INFO{ + BOOLEAN bProfileNotified; + u2Byte hciVersion; // stack hci version + u1Byte numOfLink; + BOOLEAN bBtLinkExist; + BOOLEAN bScoExist; + BOOLEAN bAclExist; + BOOLEAN bA2dpExist; + BOOLEAN bHidExist; + u1Byte numOfHid; + BOOLEAN bPanExist; + BOOLEAN bUnknownAclExist; + s1Byte minBtRssi; +} BTC_STACK_INFO, *PBTC_STACK_INFO; + +typedef struct _BTC_BT_LINK_INFO{ + BOOLEAN bBtLinkExist; + BOOLEAN bScoExist; + BOOLEAN bScoOnly; + BOOLEAN bA2dpExist; + BOOLEAN bA2dpOnly; + BOOLEAN bHidExist; + BOOLEAN bHidOnly; + BOOLEAN bPanExist; + BOOLEAN bPanOnly; +} BTC_BT_LINK_INFO, *PBTC_BT_LINK_INFO; + +typedef struct _BTC_STATISTICS{ + u4Byte cntBind; + u4Byte cntInitHwConfig; + u4Byte cntInitCoexDm; + u4Byte cntIpsNotify; + u4Byte cntLpsNotify; + u4Byte cntScanNotify; + u4Byte cntConnectNotify; + u4Byte cntMediaStatusNotify; + u4Byte cntSpecialPacketNotify; + u4Byte cntBtInfoNotify; + u4Byte cntPeriodical; + u4Byte cntCoexDmSwitch; + u4Byte cntStackOperationNotify; + u4Byte cntDbgCtrl; +} BTC_STATISTICS, *PBTC_STATISTICS; + +typedef struct _BTC_COEXIST{ + BOOLEAN bBinded; // make sure only one adapter can bind the data context + PVOID Adapter; // default adapter + BTC_BOARD_INFO boardInfo; + BTC_BT_INFO btInfo; // some bt info referenced by non-bt module + BTC_STACK_INFO stackInfo; + BTC_BT_LINK_INFO btLinkInfo; + BTC_CHIP_INTERFACE chipInterface; + + BOOLEAN bInitilized; + BOOLEAN bStopCoexDm; + BOOLEAN bManualControl; + pu1Byte cliBuf; + BTC_STATISTICS statistics; + u1Byte pwrModeVal[10]; + + // function pointers + // io related + BFP_BTC_R1 fBtcRead1Byte; + BFP_BTC_W1 fBtcWrite1Byte; + BFP_BTC_W1_BIT_MASK fBtcWrite1ByteBitMask; + BFP_BTC_R2 fBtcRead2Byte; + BFP_BTC_W2 fBtcWrite2Byte; + BFP_BTC_R4 fBtcRead4Byte; + BFP_BTC_W4 fBtcWrite4Byte; + // read/write bb related + BFP_BTC_SET_BB_REG fBtcSetBbReg; + BFP_BTC_GET_BB_REG fBtcGetBbReg; + + // read/write rf related + BFP_BTC_SET_RF_REG fBtcSetRfReg; + BFP_BTC_GET_RF_REG fBtcGetRfReg; + + //write bt reg related + BFP_BTC_SET_BT_REG fBtcSetBtReg; + + // fill h2c related + BFP_BTC_FILL_H2C fBtcFillH2c; + // other + BFP_BTC_DISP_DBG_MSG fBtcDispDbgMsg; + // normal get/set related + BFP_BTC_GET fBtcGet; + BFP_BTC_SET fBtcSet; +} BTC_COEXIST, *PBTC_COEXIST; + +extern BTC_COEXIST GLBtCoexist; + +BOOLEAN +EXhalbtcoutsrc_InitlizeVariables( + IN PVOID Adapter + ); +VOID +EXhalbtcoutsrc_InitHwConfig( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtcoutsrc_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtcoutsrc_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtcoutsrc_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtcoutsrc_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtcoutsrc_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte action + ); +VOID +EXhalbtcoutsrc_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN RT_MEDIA_STATUS mediaStatus + ); +VOID +EXhalbtcoutsrc_SpecialPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pktType + ); +VOID +EXhalbtcoutsrc_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtcoutsrc_StackOperationNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtcoutsrc_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtcoutsrc_SwitchGntBt( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtcoutsrc_PnpNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pnpState + ); +VOID +EXhalbtcoutsrc_CoexDmSwitch( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN antInverse + ); +VOID +EXhalbtcoutsrc_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtcoutsrc_DbgControl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte opCode, + IN u1Byte opLen, + IN pu1Byte pData + ); +VOID +EXhalbtcoutsrc_StackUpdateProfileInfo( + VOID + ); +VOID +EXhalbtcoutsrc_SetHciVersion( + IN u2Byte hciVersion + ); +VOID +EXhalbtcoutsrc_SetBtPatchVersion( + IN u2Byte btHciVersion, + IN u2Byte btPatchVersion + ); +VOID +EXhalbtcoutsrc_UpdateMinBtRssi( + IN s1Byte btRssi + ); +VOID +EXhalbtcoutsrc_SetBtExist( + IN BOOLEAN bBtExist + ); +VOID +EXhalbtcoutsrc_SetChipType( + IN u1Byte chipType + ); +VOID +EXhalbtcoutsrc_SetAntNum( + IN u1Byte type, + IN u1Byte antNum, + IN BOOLEAN antInverse + ); +VOID +EXhalbtcoutsrc_DisplayBtCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); + +#endif diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/Mp_Precomp.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/Mp_Precomp.h new file mode 100644 index 0000000..fdd9406 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC-BTCoexist/Mp_Precomp.h @@ -0,0 +1,56 @@ +/****************************************************************************** + * + * Copyright(c) 2013 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __MP_PRECOMP_H__ +#define __MP_PRECOMP_H__ + +#include <drv_types.h> +#include <hal_data.h> + +#define BT_TMP_BUF_SIZE 100 + +#ifdef PLATFORM_LINUX +#define rsprintf snprintf +#elif defined(PLATFORM_WINDOWS) +#define rsprintf sprintf_s +#endif + +#define DCMD_Printf DBG_BT_INFO + +#define delay_ms(ms) rtw_mdelay_os(ms) + +#ifdef bEnable +#undef bEnable +#endif + +#include "HalBtcOutSrc.h" +#include "HalBtc8188c2Ant.h" +#include "HalBtc8192d2Ant.h" +#include "HalBtc8192e1Ant.h" +#include "HalBtc8192e2Ant.h" +#include "HalBtc8723a1Ant.h" +#include "HalBtc8723a2Ant.h" +#include "HalBtc8723b1Ant.h" +#include "HalBtc8723b2Ant.h" +#include "HalBtc8812a1Ant.h" +#include "HalBtc8812a2Ant.h" +#include "HalBtc8821a1Ant.h" +#include "HalBtc8821a2Ant.h" + +#endif // __MP_PRECOMP_H__ diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/HalPhyRf.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/HalPhyRf.c new file mode 100644 index 0000000..88c9787 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/HalPhyRf.c @@ -0,0 +1,530 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +//#include "Mp_Precomp.h" +#include "odm_precomp.h" + + +#define CALCULATE_SWINGTALBE_OFFSET(_offset, _direction, _size, _deltaThermal) \ + do {\ + for(_offset = 0; _offset < _size; _offset++)\ + {\ + if(_deltaThermal < thermalThreshold[_direction][_offset])\ + {\ + if(_offset != 0)\ + _offset--;\ + break;\ + }\ + } \ + if(_offset >= _size)\ + _offset = _size-1;\ + } while(0) + + +void ConfigureTxpowerTrack( + IN PDM_ODM_T pDM_Odm, + OUT PTXPWRTRACK_CFG pConfig + ) +{ +#if RTL8192E_SUPPORT + if(pDM_Odm->SupportICType==ODM_RTL8192E) + ConfigureTxpowerTrack_8192E(pConfig); +#endif +#if RTL8821A_SUPPORT + if(pDM_Odm->SupportICType==ODM_RTL8821) + ConfigureTxpowerTrack_8821A(pConfig); +#endif +#if RTL8812A_SUPPORT + if(pDM_Odm->SupportICType==ODM_RTL8812) + ConfigureTxpowerTrack_8812A(pConfig); +#endif +#if RTL8188E_SUPPORT + if(pDM_Odm->SupportICType==ODM_RTL8188E) + ConfigureTxpowerTrack_8188E(pConfig); +#endif + +#if RTL8723B_SUPPORT + if(pDM_Odm->SupportICType==ODM_RTL8723B) + ConfigureTxpowerTrack_8723B(pConfig); +#endif + +} + +//====================================================================== +// <20121113, Kordan> This function should be called when TxAGC changed. +// Otherwise the previous compensation is gone, because we record the +// delta of temperature between two TxPowerTracking watch dogs. +// +// NOTE: If Tx BB swing or Tx scaling is varified during run-time, still +// need to call this function. +//====================================================================== +VOID +ODM_ClearTxPowerTrackingState( + IN PDM_ODM_T pDM_Odm + ) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pDM_Odm->Adapter); + u1Byte p = 0; + + pDM_Odm->BbSwingIdxCckBase = pDM_Odm->DefaultCckIndex; + pDM_Odm->BbSwingIdxCck = pDM_Odm->DefaultCckIndex; + pDM_Odm->RFCalibrateInfo.CCK_index = 0; + + for (p = ODM_RF_PATH_A; p < MAX_RF_PATH; ++p) + { + pDM_Odm->BbSwingIdxOfdmBase[p] = pDM_Odm->DefaultOfdmIndex; + pDM_Odm->BbSwingIdxOfdm[p] = pDM_Odm->DefaultOfdmIndex; + pDM_Odm->RFCalibrateInfo.OFDM_index[p] = pDM_Odm->DefaultOfdmIndex; + + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0; + pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] = 0; + pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p] = 0; + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0; + + pDM_Odm->Absolute_OFDMSwingIdx[p] = 0; // Initial Mix mode power tracking + pDM_Odm->Remnant_OFDMSwingIdx[p] = 0; + } + + pDM_Odm->Modify_TxAGC_Flag_PathA= FALSE; //Initial at Modify Tx Scaling Mode + pDM_Odm->Modify_TxAGC_Flag_PathB= FALSE; //Initial at Modify Tx Scaling Mode + pDM_Odm->Remnant_CCKSwingIdx= 0; + pDM_Odm->RFCalibrateInfo.ThermalValue = pHalData->EEPROMThermalMeter; + pDM_Odm->RFCalibrateInfo.ThermalValue_IQK = pHalData->EEPROMThermalMeter; + pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = pHalData->EEPROMThermalMeter; +} + +VOID +ODM_TXPowerTrackingCallback_ThermalMeter( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm +#else + IN PADAPTER Adapter +#endif + ) +{ + +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif +#endif + + u1Byte ThermalValue = 0, delta, delta_LCK, delta_IQK, p = 0, i = 0; + u1Byte ThermalValue_AVG_count = 0; + u4Byte ThermalValue_AVG = 0; + + u1Byte OFDM_min_index = 0; // OFDM BB Swing should be less than +3.0dB, which is required by Arthur + u1Byte Indexforchannel = 0; // GetRightChnlPlaceforIQK(pHalData->CurrentChannel) + + TXPWRTRACK_CFG c; + + + //4 1. The following TWO tables decide the final index of OFDM/CCK swing table. + pu1Byte deltaSwingTableIdx_TUP_A; + pu1Byte deltaSwingTableIdx_TDOWN_A; + pu1Byte deltaSwingTableIdx_TUP_B; + pu1Byte deltaSwingTableIdx_TDOWN_B; + + //4 2. Initilization ( 7 steps in total ) + + ConfigureTxpowerTrack(pDM_Odm, &c); + + (*c.GetDeltaSwingTable)(pDM_Odm, (pu1Byte*)&deltaSwingTableIdx_TUP_A, (pu1Byte*)&deltaSwingTableIdx_TDOWN_A, + (pu1Byte*)&deltaSwingTableIdx_TUP_B, (pu1Byte*)&deltaSwingTableIdx_TDOWN_B); + + pDM_Odm->RFCalibrateInfo.TXPowerTrackingCallbackCnt++; //cosa add for debug + pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = TRUE; + +#if (MP_DRIVER == 1) +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = pHalData->TxPowerTrackControl; // <Kordan> We should keep updating the control variable according to HalData. +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) + if ( *(pDM_Odm->mp_mode) == 1) +#endif + // <Kordan> RFCalibrateInfo.RegA24 will be initialized when ODM HW configuring, but MP configures with para files. + pDM_Odm->RFCalibrateInfo.RegA24 = 0x090e1317; +#endif + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("===>ODM_TXPowerTrackingCallback_ThermalMeter, \ + \n pDM_Odm->BbSwingIdxCckBase: %d, pDM_Odm->BbSwingIdxOfdmBase[A]: %d, pDM_Odm->DefaultOfdmIndex: %d\n", + pDM_Odm->BbSwingIdxCckBase, pDM_Odm->BbSwingIdxOfdmBase[ODM_RF_PATH_A], pDM_Odm->DefaultOfdmIndex)); + + ThermalValue = (u1Byte)ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, c.ThermalRegAddr, 0xfc00); //0x42: RF Reg[15:10] 88E + if( ! pDM_Odm->RFCalibrateInfo.TxPowerTrackControl || pHalData->EEPROMThermalMeter == 0 || + pHalData->EEPROMThermalMeter == 0xFF) + return; + + + //4 3. Initialize ThermalValues of RFCalibrateInfo + + if(pDM_Odm->RFCalibrateInfo.bReloadtxpowerindex) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("reload ofdm index for band switch\n")); + } + + //4 4. Calculate average thermal meter + + pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index] = ThermalValue; + pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index++; + if(pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index == c.AverageThermalNum) //Average times = c.AverageThermalNum + pDM_Odm->RFCalibrateInfo.ThermalValue_AVG_index = 0; + + for(i = 0; i < c.AverageThermalNum; i++) + { + if(pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[i]) + { + ThermalValue_AVG += pDM_Odm->RFCalibrateInfo.ThermalValue_AVG[i]; + ThermalValue_AVG_count++; + } + } + + if(ThermalValue_AVG_count) //Calculate Average ThermalValue after average enough times + { + ThermalValue = (u1Byte)(ThermalValue_AVG / ThermalValue_AVG_count); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("AVG Thermal Meter = 0x%X, EFUSE Thermal Base = 0x%X\n", ThermalValue, pHalData->EEPROMThermalMeter)); + } + + //4 5. Calculate delta, delta_LCK, delta_IQK. + + //"delta" here is used to determine whether thermal value changes or not. + delta = (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue)?(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue):(pDM_Odm->RFCalibrateInfo.ThermalValue - ThermalValue); + delta_LCK = (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue_LCK)?(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue_LCK):(pDM_Odm->RFCalibrateInfo.ThermalValue_LCK - ThermalValue); + delta_IQK = (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue_IQK)?(ThermalValue - pDM_Odm->RFCalibrateInfo.ThermalValue_IQK):(pDM_Odm->RFCalibrateInfo.ThermalValue_IQK - ThermalValue); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("(delta, delta_LCK, delta_IQK) = (%d, %d, %d)\n", delta, delta_LCK, delta_IQK)); + + //4 6. If necessary, do LCK. + + if ((delta_LCK >= c.Threshold_IQK)) // Delta temperature is equal to or larger than 20 centigrade. + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("delta_LCK(%d) >= Threshold_IQK(%d)\n", delta_LCK, c.Threshold_IQK)); + pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = ThermalValue; + if(c.PHY_LCCalibrate) + (*c.PHY_LCCalibrate)(pDM_Odm); + } + + //3 7. If necessary, move the index of swing table to adjust Tx power. + + if (delta > 0 && pDM_Odm->RFCalibrateInfo.TxPowerTrackControl) + { + //"delta" here is used to record the absolute value of differrence. +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + delta = ThermalValue > pHalData->EEPROMThermalMeter?(ThermalValue - pHalData->EEPROMThermalMeter):(pHalData->EEPROMThermalMeter - ThermalValue); +#else + delta = (ThermalValue > pDM_Odm->priv->pmib->dot11RFEntry.ther)?(ThermalValue - pDM_Odm->priv->pmib->dot11RFEntry.ther):(pDM_Odm->priv->pmib->dot11RFEntry.ther - ThermalValue); +#endif + if (delta >= TXPWR_TRACK_TABLE_SIZE) + delta = TXPWR_TRACK_TABLE_SIZE - 1; + + //4 7.1 The Final Power Index = BaseIndex + PowerIndexOffset + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + if(ThermalValue > pHalData->EEPROMThermalMeter) { +#else + if(ThermalValue > pDM_Odm->priv->pmib->dot11RFEntry.ther) { +#endif + ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("deltaSwingTableIdx_TUP_A[%d] = %d\n", delta, deltaSwingTableIdx_TUP_A[delta])); + pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_A] = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A]; + pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A] = deltaSwingTableIdx_TUP_A[delta]; + + pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = deltaSwingTableIdx_TUP_A[delta]; // Record delta swing for mix mode power tracking + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A])); + + if(c.RfPathCount > 1) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("deltaSwingTableIdx_TUP_B[%d] = %d\n", delta, deltaSwingTableIdx_TUP_B[delta])); + pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_B] = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B]; + pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B] = deltaSwingTableIdx_TUP_B[delta]; + + pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = deltaSwingTableIdx_TUP_B[delta]; // Record delta swing for mix mode power tracking + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n", pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B])); + } + + } + else { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("deltaSwingTableIdx_TDOWN_A[%d] = %d\n", delta, deltaSwingTableIdx_TDOWN_A[delta])); + + pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_A] = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A]; + pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_A] = -1 * deltaSwingTableIdx_TDOWN_A[delta]; + + pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = -1 * deltaSwingTableIdx_TDOWN_A[delta]; // Record delta swing for mix mode power tracking + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A])); + + if(c.RfPathCount > 1) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("deltaSwingTableIdx_TDOWN_B[%d] = %d\n", delta, deltaSwingTableIdx_TDOWN_B[delta])); + + pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[ODM_RF_PATH_B] = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B]; + pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[ODM_RF_PATH_B] = -1 * deltaSwingTableIdx_TDOWN_B[delta]; + + pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = -1 * deltaSwingTableIdx_TDOWN_B[delta]; // Record delta swing for mix mode power tracking + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n", pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B])); + } + } + + for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("\n\n================================ [Path-%c] Calculating PowerIndexOffset ================================\n", (p == ODM_RF_PATH_A ? 'A' : 'B'))); + + if (pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] == pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p]) // If Thermal value changes but lookup table value still the same + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0; + else + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] - pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p]; // Power Index Diff between 2 times Power Tracking + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("[Path-%c] PowerIndexOffset(%d) = DeltaPowerIndex(%d) - DeltaPowerIndexLast(%d)\n", + (p == ODM_RF_PATH_A ? 'A' : 'B'), pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p], pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p], + pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p])); + + pDM_Odm->RFCalibrateInfo.OFDM_index[p] = pDM_Odm->BbSwingIdxOfdmBase[p] + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p]; + pDM_Odm->RFCalibrateInfo.CCK_index = pDM_Odm->BbSwingIdxCckBase + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p]; + + pDM_Odm->BbSwingIdxCck = pDM_Odm->RFCalibrateInfo.CCK_index; + pDM_Odm->BbSwingIdxOfdm[p] = pDM_Odm->RFCalibrateInfo.OFDM_index[p]; + + // *************Print BB Swing Base and Index Offset************* + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("The 'CCK' final index(%d) = BaseIndex(%d) + PowerIndexOffset(%d)\n", + pDM_Odm->BbSwingIdxCck, pDM_Odm->BbSwingIdxCckBase, pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p])); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("The 'OFDM' final index(%d) = BaseIndex[%c](%d) + PowerIndexOffset(%d)\n", + pDM_Odm->BbSwingIdxOfdm[p], (p == ODM_RF_PATH_A ? 'A' : 'B'), pDM_Odm->BbSwingIdxOfdmBase[p], pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p])); + + //4 7.1 Handle boundary conditions of index. + + + if(pDM_Odm->RFCalibrateInfo.OFDM_index[p] > c.SwingTableSize_OFDM-1) + { + pDM_Odm->RFCalibrateInfo.OFDM_index[p] = c.SwingTableSize_OFDM-1; + } + else if (pDM_Odm->RFCalibrateInfo.OFDM_index[p] < OFDM_min_index) + { + pDM_Odm->RFCalibrateInfo.OFDM_index[p] = OFDM_min_index; + } + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("\n\n========================================================================================================\n")); + if(pDM_Odm->RFCalibrateInfo.CCK_index > c.SwingTableSize_CCK-1) + pDM_Odm->RFCalibrateInfo.CCK_index = c.SwingTableSize_CCK-1; + //else if (pDM_Odm->RFCalibrateInfo.CCK_index < 0) + //pDM_Odm->RFCalibrateInfo.CCK_index = 0; + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("The thermal meter is unchanged or TxPowerTracking OFF(%d): ThermalValue: %d , pDM_Odm->RFCalibrateInfo.ThermalValue: %d\n", + pDM_Odm->RFCalibrateInfo.TxPowerTrackControl, ThermalValue, pDM_Odm->RFCalibrateInfo.ThermalValue)); + + for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0; + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("TxPowerTracking: [CCK] Swing Current Index: %d, Swing Base Index: %d\n", + pDM_Odm->RFCalibrateInfo.CCK_index, pDM_Odm->BbSwingIdxCckBase)); //Print Swing base & current + for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("TxPowerTracking: [OFDM] Swing Current Index: %d, Swing Base Index[%c]: %d\n", + pDM_Odm->RFCalibrateInfo.OFDM_index[p], (p == ODM_RF_PATH_A ? 'A' : 'B'), pDM_Odm->BbSwingIdxOfdmBase[p])); + } + + if ((pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_A] != 0 || + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_B] != 0 ) && + pDM_Odm->RFCalibrateInfo.TxPowerTrackControl) + { + //4 7.2 Configure the Swing Table to adjust Tx Power. + + pDM_Odm->RFCalibrateInfo.bTxPowerChanged = TRUE; // Always TRUE after Tx Power is adjusted by power tracking. + // + // 2012/04/23 MH According to Luke's suggestion, we can not write BB digital + // to increase TX power. Otherwise, EVM will be bad. + // + // 2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. + if (ThermalValue > pDM_Odm->RFCalibrateInfo.ThermalValue) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature Increasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_A], delta, ThermalValue, pHalData->EEPROMThermalMeter, pDM_Odm->RFCalibrateInfo.ThermalValue)); + + if(c.RfPathCount > 1) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature Increasing(B): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_B], delta, ThermalValue, pHalData->EEPROMThermalMeter, pDM_Odm->RFCalibrateInfo.ThermalValue)); + + } + else if (ThermalValue < pDM_Odm->RFCalibrateInfo.ThermalValue)// Low temperature + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature Decreasing(A): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_A], delta, ThermalValue, pHalData->EEPROMThermalMeter, pDM_Odm->RFCalibrateInfo.ThermalValue)); + + if(c.RfPathCount > 1) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature Decreasing(B): delta_pi: %d , delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_B], delta, ThermalValue, pHalData->EEPROMThermalMeter, pDM_Odm->RFCalibrateInfo.ThermalValue)); + + } +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + if (ThermalValue > pHalData->EEPROMThermalMeter) +#else + if (ThermalValue > pDM_Odm->priv->pmib->dot11RFEntry.ther) +#endif + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature(%d) higher than PG value(%d)\n", ThermalValue, pHalData->EEPROMThermalMeter)); + + if (pDM_Odm->SupportICType == ODM_RTL8188E || pDM_Odm->SupportICType == ODM_RTL8192E || + pDM_Odm->SupportICType == ODM_RTL8821 || pDM_Odm->SupportICType == ODM_RTL8812 || pDM_Odm->SupportICType == ODM_RTL8723B) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("**********Enter POWER Tracking MIX_MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) + (*c.ODM_TxPwrTrackSetPwr)(pDM_Odm, MIX_MODE, p, 0); + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("**********Enter POWER Tracking BBSWING_MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) + (*c.ODM_TxPwrTrackSetPwr)(pDM_Odm, BBSWING, p, Indexforchannel); + } + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature(%d) lower than PG value(%d)\n", ThermalValue, pHalData->EEPROMThermalMeter)); + + if (pDM_Odm->SupportICType == ODM_RTL8188E || pDM_Odm->SupportICType == ODM_RTL8192E || + pDM_Odm->SupportICType == ODM_RTL8821 || pDM_Odm->SupportICType == ODM_RTL8812 || pDM_Odm->SupportICType == ODM_RTL8723B) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("**********Enter POWER Tracking MIX_MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) + (*c.ODM_TxPwrTrackSetPwr)(pDM_Odm, MIX_MODE, p, Indexforchannel); + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("**********Enter POWER Tracking BBSWING_MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) + (*c.ODM_TxPwrTrackSetPwr)(pDM_Odm, BBSWING, p, Indexforchannel); + } + + } + + pDM_Odm->BbSwingIdxCckBase = pDM_Odm->BbSwingIdxCck; // Record last time Power Tracking result as base. + for (p = ODM_RF_PATH_A; p < c.RfPathCount; p++) + pDM_Odm->BbSwingIdxOfdmBase[p] = pDM_Odm->BbSwingIdxOfdm[p]; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("pDM_Odm->RFCalibrateInfo.ThermalValue = %d ThermalValue= %d\n", pDM_Odm->RFCalibrateInfo.ThermalValue, ThermalValue)); + + pDM_Odm->RFCalibrateInfo.ThermalValue = ThermalValue; //Record last Power Tracking Thermal Value + + } +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) +#if (RTL8723B_SUPPORT == 0) + // Delta temperature is equal to or larger than 20 centigrade (When threshold is 8). + if ((delta_IQK >= c.Threshold_IQK)) { + if ( ! pDM_Odm->RFCalibrateInfo.bIQKInProgress) + (*c.DoIQK)(pDM_Odm, delta_IQK, ThermalValue, 8); + } +#endif +#endif + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("<===ODM_TXPowerTrackingCallback_ThermalMeter\n")); + + pDM_Odm->RFCalibrateInfo.TXPowercount = 0; +} + + + + +//3============================================================ +//3 IQ Calibration +//3============================================================ + +VOID +ODM_ResetIQKResult( + IN PDM_ODM_T pDM_Odm +) +{ + u1Byte i; +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN || DM_ODM_SUPPORT_TYPE == ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + + if (!IS_HARDWARE_TYPE_8192D(Adapter)) + return; +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD,("PHY_ResetIQKResult:: settings regs %d default regs %d\n", (u4Byte)(sizeof(pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting)/sizeof(IQK_MATRIX_REGS_SETTING)), IQK_Matrix_Settings_NUM)); + //0xe94, 0xe9c, 0xea4, 0xeac, 0xeb4, 0xebc, 0xec4, 0xecc + + for(i = 0; i < IQK_Matrix_Settings_NUM; i++) + { + { + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][0] = + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][2] = + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][4] = + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][6] = 0x100; + + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][1] = + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][3] = + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][5] = + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].Value[0][7] = 0x0; + + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[i].bIQKDone = FALSE; + + } + } + +} +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) +u1Byte ODM_GetRightChnlPlaceforIQK(u1Byte chnl) +{ + u1Byte channel_all[ODM_TARGET_CHNL_NUM_2G_5G] = + {1,2,3,4,5,6,7,8,9,10,11,12,13,14,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,149,151,153,155,157,159,161,163,165}; + u1Byte place = chnl; + + + if(chnl > 14) + { + for(place = 14; place<sizeof(channel_all); place++) + { + if(channel_all[place] == chnl) + { + return place-13; + } + } + } + return 0; + +} +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/HalPhyRf.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/HalPhyRf.h new file mode 100644 index 0000000..d084e76 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/HalPhyRf.h @@ -0,0 +1,89 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + + #ifndef __HAL_PHY_RF_H__ + #define __HAL_PHY_RF_H__ + +typedef enum _SPUR_CAL_METHOD { + PLL_RESET, + AFE_PHASE_SEL +} SPUR_CAL_METHOD; + +typedef enum _PWRTRACK_CONTROL_METHOD { + BBSWING, + TXAGC, + MIX_MODE +} PWRTRACK_METHOD; + +typedef VOID (*FuncSetPwr)(PDM_ODM_T, PWRTRACK_METHOD, u1Byte, u1Byte); +typedef VOID (*FuncIQK)(PDM_ODM_T, u1Byte, u1Byte, u1Byte); +typedef VOID (*FuncLCK)(PDM_ODM_T); +typedef VOID (*FuncSwing)(PDM_ODM_T, pu1Byte*, pu1Byte*, pu1Byte*, pu1Byte*); + +typedef struct _TXPWRTRACK_CFG { + u1Byte SwingTableSize_CCK; + u1Byte SwingTableSize_OFDM; + u1Byte Threshold_IQK; + u1Byte AverageThermalNum; + u1Byte RfPathCount; + u4Byte ThermalRegAddr; + FuncSetPwr ODM_TxPwrTrackSetPwr; + FuncIQK DoIQK; + FuncLCK PHY_LCCalibrate; + FuncSwing GetDeltaSwingTable; +} TXPWRTRACK_CFG, *PTXPWRTRACK_CFG; + +void ConfigureTxpowerTrack( + IN PDM_ODM_T pDM_Odm, + OUT PTXPWRTRACK_CFG pConfig + ); + + +VOID +ODM_ClearTxPowerTrackingState( + IN PDM_ODM_T pDM_Odm + ); + +VOID +ODM_TXPowerTrackingCallback_ThermalMeter( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm +#else + IN PADAPTER Adapter +#endif + ); + + + +#define ODM_TARGET_CHNL_NUM_2G_5G 59 + + +VOID +ODM_ResetIQKResult( + IN PDM_ODM_T pDM_Odm +); +u1Byte +ODM_GetRightChnlPlaceforIQK( + IN u1Byte chnl +); + + +#endif // #ifndef __HAL_PHY_RF_H__ + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/PhyDM_Adaptivity.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/PhyDM_Adaptivity.c new file mode 100644 index 0000000..ec9240f --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/PhyDM_Adaptivity.c @@ -0,0 +1,873 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +//============================================================ +// include files +//============================================================ +//#include "Mp_Precomp.h" +#include "odm_precomp.h" + +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) +#if WPP_SOFTWARE_TRACE +#include "PhyDM_Adaptivity.tmh" +#endif +#endif + + +VOID +Phydm_CheckAdaptivity( + IN PVOID pDM_VOID +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + PADAPTIVITY_STATISTICS Adaptivity = (PADAPTIVITY_STATISTICS)PhyDM_Get_Structure(pDM_Odm, PHYDM_ADAPTIVITY); + + if (pDM_Odm->SupportAbility & ODM_BB_ADAPTIVITY) { +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + if (pDM_Odm->APTotalNum > Adaptivity->APNumTH) { + pDM_Odm->Adaptivity_enable = FALSE; + pDM_Odm->adaptivity_flag = FALSE; + Phydm_SetEDCCAThreshold(pDM_Odm, 0x7f, 0x7f); + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("AP total num > %d!!, disable adaptivity\n", Adaptivity->APNumTH)); + } else +#endif + { + if (Adaptivity->DynamicLinkAdaptivity == TRUE) { + if (pDM_Odm->bLinked && Adaptivity->bCheck == FALSE) { + Phydm_NHMCounterStatistics(pDM_Odm); + Phydm_CheckEnvironment(pDM_Odm); + } else if (!pDM_Odm->bLinked) + Adaptivity->bCheck = FALSE; + } else { + pDM_Odm->Adaptivity_enable = TRUE; + + if (pDM_Odm->SupportICType & (ODM_RTL8814A|ODM_RTL8195A)) + pDM_Odm->adaptivity_flag = FALSE; + else + pDM_Odm->adaptivity_flag = TRUE; + } + } + } else { + pDM_Odm->Adaptivity_enable = FALSE; + pDM_Odm->adaptivity_flag = FALSE; + } + + + +} + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +BOOLEAN +Phydm_CheckChannelPlan( + IN PVOID pDM_VOID +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + PADAPTER pAdapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMGNT_INFO pMgntInfo = &(pAdapter->MgntInfo); + + if (pMgntInfo->RegEnableAdaptivity == 2) { + if (pDM_Odm->Carrier_Sense_enable == FALSE) { /*check domain Code for Adaptivity or CarrierSense*/ + if ((*pDM_Odm->pBandType == ODM_BAND_5G) && + !(pDM_Odm->odm_Regulation5G == REGULATION_ETSI || pDM_Odm->odm_Regulation5G == REGULATION_WW)) { + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("Adaptivity skip 5G domain code : %d\n", pDM_Odm->odm_Regulation5G)); + return TRUE; + } else if ((*pDM_Odm->pBandType == ODM_BAND_2_4G) && + !(pDM_Odm->odm_Regulation2_4G == REGULATION_ETSI || pDM_Odm->odm_Regulation2_4G == REGULATION_WW)) { + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("Adaptivity skip 2.4G domain code : %d\n", pDM_Odm->odm_Regulation2_4G)); + return TRUE; + + } else if ((*pDM_Odm->pBandType != ODM_BAND_2_4G) && (*pDM_Odm->pBandType != ODM_BAND_5G)) { + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("Adaptivity neither 2G nor 5G band, return\n")); + return TRUE; + } + } else { + if ((*pDM_Odm->pBandType == ODM_BAND_5G) && + !(pDM_Odm->odm_Regulation5G == REGULATION_MKK || pDM_Odm->odm_Regulation5G == REGULATION_WW)) { + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("CarrierSense skip 5G domain code : %d\n", pDM_Odm->odm_Regulation5G)); + return TRUE; + } + + else if ((*pDM_Odm->pBandType == ODM_BAND_2_4G) && + !(pDM_Odm->odm_Regulation2_4G == REGULATION_MKK || pDM_Odm->odm_Regulation2_4G == REGULATION_WW)) { + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("CarrierSense skip 2.4G domain code : %d\n", pDM_Odm->odm_Regulation2_4G)); + return TRUE; + + } else if ((*pDM_Odm->pBandType != ODM_BAND_2_4G) && (*pDM_Odm->pBandType != ODM_BAND_5G)) { + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("CarrierSense neither 2G nor 5G band, return\n")); + return TRUE; + } + } + } + + return FALSE; + +} +#endif + +VOID +Phydm_NHMCounterStatisticsInit( + IN PVOID pDM_VOID +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + + if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) { + /*PHY parameters initialize for n series*/ + ODM_Write2Byte(pDM_Odm, ODM_REG_NHM_TIMER_11N + 2, 0xC350); /*0x894[31:16]=0x0xC350 Time duration for NHM unit: us, 0xc350=200ms*/ + ODM_Write2Byte(pDM_Odm, ODM_REG_NHM_TH9_TH10_11N + 2, 0xffff); /*0x890[31:16]=0xffff th_9, th_10*/ + ODM_Write4Byte(pDM_Odm, ODM_REG_NHM_TH3_TO_TH0_11N, 0xffffff50); /*0x898=0xffffff52 th_3, th_2, th_1, th_0*/ + ODM_Write4Byte(pDM_Odm, ODM_REG_NHM_TH7_TO_TH4_11N, 0xffffffff); /*0x89c=0xffffffff th_7, th_6, th_5, th_4*/ + ODM_SetBBReg(pDM_Odm, ODM_REG_FPGA0_IQK_11N, bMaskByte0, 0xff); /*0xe28[7:0]=0xff th_8*/ + ODM_SetBBReg(pDM_Odm, ODM_REG_NHM_TH9_TH10_11N, BIT10 | BIT9 | BIT8, 0x1); /*0x890[10:8]=1 ignoreCCA ignore PHYTXON enable CCX*/ + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT7, 0x1); /*0xc0c[7]=1 max power among all RX ants*/ + } +#if (RTL8195A_SUPPORT == 0) + else if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) { + /*PHY parameters initialize for ac series*/ + ODM_Write2Byte(pDM_Odm, ODM_REG_NHM_TIMER_11AC + 2, 0xC350); /*0x990[31:16]=0xC350 Time duration for NHM unit: us, 0xc350=200ms*/ + ODM_Write2Byte(pDM_Odm, ODM_REG_NHM_TH9_TH10_11AC + 2, 0xffff); /*0x994[31:16]=0xffff th_9, th_10*/ + ODM_Write4Byte(pDM_Odm, ODM_REG_NHM_TH3_TO_TH0_11AC, 0xffffff50); /*0x998=0xffffff52 th_3, th_2, th_1, th_0*/ + ODM_Write4Byte(pDM_Odm, ODM_REG_NHM_TH7_TO_TH4_11AC, 0xffffffff); /*0x99c=0xffffffff th_7, th_6, th_5, th_4*/ + ODM_SetBBReg(pDM_Odm, ODM_REG_NHM_TH8_11AC, bMaskByte0, 0xff); /*0x9a0[7:0]=0xff th_8*/ + ODM_SetBBReg(pDM_Odm, ODM_REG_NHM_TH9_TH10_11AC, BIT8 | BIT9 | BIT10, 0x1); /*0x994[10:8]=1 ignoreCCA ignore PHYTXON enable CCX*/ + ODM_SetBBReg(pDM_Odm, ODM_REG_NHM_9E8_11AC, BIT0, 0x1); /*0x9e8[7]=1 max power among all RX ants*/ + + } +#endif +} + +VOID +Phydm_NHMCounterStatistics( + IN PVOID pDM_VOID +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + + if (!(pDM_Odm->SupportAbility & ODM_BB_NHM_CNT)) + return; + + /*Get NHM report*/ + Phydm_GetNHMCounterStatistics(pDM_Odm); + + /*Reset NHM counter*/ + Phydm_NHMCounterStatisticsReset(pDM_Odm); +} + +VOID +Phydm_GetNHMCounterStatistics( + IN PVOID pDM_VOID +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + u4Byte value32 = 0; +#if (RTL8195A_SUPPORT == 0) + if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) + value32 = ODM_GetBBReg(pDM_Odm, ODM_REG_NHM_CNT_11AC, bMaskDWord); + else if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) +#endif + value32 = ODM_GetBBReg(pDM_Odm, ODM_REG_NHM_CNT_11N, bMaskDWord); + + pDM_Odm->NHM_cnt_0 = (u1Byte)(value32 & bMaskByte0); + pDM_Odm->NHM_cnt_1 = (u1Byte)((value32 & bMaskByte1) >> 8); + +} + +VOID +Phydm_NHMCounterStatisticsReset( + IN PVOID pDM_VOID +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + + if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) { + ODM_SetBBReg(pDM_Odm, ODM_REG_NHM_TH9_TH10_11N, BIT1, 0); + ODM_SetBBReg(pDM_Odm, ODM_REG_NHM_TH9_TH10_11N, BIT1, 1); + } +#if (RTL8195A_SUPPORT == 0) + else if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) { + ODM_SetBBReg(pDM_Odm, ODM_REG_NHM_TH9_TH10_11AC, BIT1, 0); + ODM_SetBBReg(pDM_Odm, ODM_REG_NHM_TH9_TH10_11AC, BIT1, 1); + } + +#endif + +} + +VOID +Phydm_SetEDCCAThreshold( + IN PVOID pDM_VOID, + IN s1Byte H2L, + IN s1Byte L2H +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + + if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) { + ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, bMaskByte0, (u1Byte)L2H); + ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, bMaskByte2, (u1Byte)H2L); + } +#if (RTL8195A_SUPPORT == 0) + else if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) { + ODM_SetBBReg(pDM_Odm, rFPGA0_XB_LSSIReadBack, bMaskByte0, (u1Byte)L2H); + ODM_SetBBReg(pDM_Odm, rFPGA0_XB_LSSIReadBack, bMaskByte1, (u1Byte)H2L); + } +#endif + +} + +VOID +Phydm_SetTRxMux( + IN PVOID pDM_VOID, + IN PhyDM_Trx_MUX_Type txMode, + IN PhyDM_Trx_MUX_Type rxMode +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + + if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) { + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_RPT_FORMAT_11N, BIT3 | BIT2 | BIT1, txMode); /*set TXmod to standby mode to remove outside noise affect*/ + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_RPT_FORMAT_11N, BIT22 | BIT21 | BIT20, rxMode); /*set RXmod to standby mode to remove outside noise affect*/ + if (pDM_Odm->RFType > ODM_1T1R) { + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_RPT_FORMAT_11N_B, BIT3 | BIT2 | BIT1, txMode); /*set TXmod to standby mode to remove outside noise affect*/ + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_RPT_FORMAT_11N_B, BIT22 | BIT21 | BIT20, rxMode); /*set RXmod to standby mode to remove outside noise affect*/ + } + } +#if (RTL8195A_SUPPORT == 0) + else if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) { + ODM_SetBBReg(pDM_Odm, ODM_REG_TRMUX_11AC, BIT11 | BIT10 | BIT9 | BIT8, txMode); /*set TXmod to standby mode to remove outside noise affect*/ + ODM_SetBBReg(pDM_Odm, ODM_REG_TRMUX_11AC, BIT7 | BIT6 | BIT5 | BIT4, rxMode); /*set RXmod to standby mode to remove outside noise affect*/ + if (pDM_Odm->RFType > ODM_1T1R) { + ODM_SetBBReg(pDM_Odm, ODM_REG_TRMUX_11AC_B, BIT11 | BIT10 | BIT9 | BIT8, txMode); /*set TXmod to standby mode to remove outside noise affect*/ + ODM_SetBBReg(pDM_Odm, ODM_REG_TRMUX_11AC_B, BIT7 | BIT6 | BIT5 | BIT4, rxMode); /*set RXmod to standby mode to remove outside noise affect*/ + } + } +#endif + +} + +VOID +Phydm_MACEDCCAState( + IN PVOID pDM_VOID, + IN PhyDM_MACEDCCA_Type State +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + if (State == PhyDM_IGNORE_EDCCA) { + ODM_SetMACReg(pDM_Odm, REG_TX_PTCL_CTRL, BIT15, 1); /*ignore EDCCA reg520[15]=1*/ + ODM_SetMACReg(pDM_Odm, REG_RD_CTRL, BIT11, 0); /*reg524[11]=0*/ + } else { /*don't set MAC ignore EDCCA signal*/ + ODM_SetMACReg(pDM_Odm, REG_TX_PTCL_CTRL, BIT15, 0); /*don't ignore EDCCA reg520[15]=0*/ + ODM_SetMACReg(pDM_Odm, REG_RD_CTRL, BIT11, 1); /*reg524[11]=1 */ + } + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("EDCCA enable State = %d\n", State)); + +} + +BOOLEAN +Phydm_CalNHMcnt( + IN PVOID pDM_VOID +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + u2Byte Base = 0; + + Base = pDM_Odm->NHM_cnt_0 + pDM_Odm->NHM_cnt_1; + + if (Base != 0) { + pDM_Odm->NHM_cnt_0 = ((pDM_Odm->NHM_cnt_0) << 8) / Base; + pDM_Odm->NHM_cnt_1 = ((pDM_Odm->NHM_cnt_1) << 8) / Base; + } + if ((pDM_Odm->NHM_cnt_0 - pDM_Odm->NHM_cnt_1) >= 100) + return TRUE; /*clean environment*/ + else + return FALSE; /*noisy environment*/ + +} + + +VOID +Phydm_CheckEnvironment( + IN PVOID pDM_VOID +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + PADAPTIVITY_STATISTICS Adaptivity = (PADAPTIVITY_STATISTICS)PhyDM_Get_Structure(pDM_Odm, PHYDM_ADAPTIVITY); + BOOLEAN isCleanEnvironment = FALSE; + + if (Adaptivity->bFirstLink == TRUE) { + if (pDM_Odm->SupportICType & (ODM_RTL8814A|ODM_RTL8195A)) + pDM_Odm->adaptivity_flag = FALSE; + else + pDM_Odm->adaptivity_flag = TRUE; + + Adaptivity->bFirstLink = FALSE; + return; + } else { + if (Adaptivity->NHMWait < 3) { /*Start enter NHM after 4 NHMWait*/ + Adaptivity->NHMWait++; + Phydm_NHMCounterStatistics(pDM_Odm); + return; + } else { + Phydm_NHMCounterStatistics(pDM_Odm); + isCleanEnvironment = Phydm_CalNHMcnt(pDM_Odm); + if (isCleanEnvironment == TRUE) { +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + pDM_Odm->TH_L2H_ini = pDM_Odm->TH_L2H_ini_backup; /*mode 1*/ + pDM_Odm->TH_EDCCA_HL_diff = Adaptivity->TH_EDCCA_HL_diff_backup; +#endif + pDM_Odm->Adaptivity_enable = TRUE; + + if (pDM_Odm->SupportICType & (ODM_RTL8814A|ODM_RTL8195A)) + pDM_Odm->adaptivity_flag = FALSE; + else + pDM_Odm->adaptivity_flag = TRUE; + } else { +#if(DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + Phydm_SetEDCCAThreshold(pDM_Odm, 0x7f, 0x7f); +#else + pDM_Odm->TH_L2H_ini = Adaptivity->TH_L2H_ini_mode2; /*for AP mode 2*/ + pDM_Odm->TH_EDCCA_HL_diff = Adaptivity->TH_EDCCA_HL_diff_mode2; +#endif + pDM_Odm->adaptivity_flag = FALSE; + pDM_Odm->Adaptivity_enable = FALSE; + } + Adaptivity->NHMWait = 0; + Adaptivity->bFirstLink = TRUE; + Adaptivity->bCheck = TRUE; + } + + } + + +} + +VOID +Phydm_SearchPwdBLowerBound( + IN PVOID pDM_VOID +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + PADAPTIVITY_STATISTICS Adaptivity = (PADAPTIVITY_STATISTICS)PhyDM_Get_Structure(pDM_Odm, PHYDM_ADAPTIVITY); + u4Byte value32 = 0; + u1Byte cnt, IGI_Pause = 0x7f, IGI_Resume = 0x20, IGI = 0x45; /*IGI = 0x50 for cal EDCCA lower bound*/ + u1Byte txEdcca1 = 0, txEdcca0 = 0; + BOOLEAN bAdjust = TRUE; + s1Byte TH_L2H_dmc, TH_H2L_dmc, IGI_target = 0x32; + s1Byte Diff; + + Phydm_SetTRxMux(pDM_Odm, PhyDM_STANDBY_MODE, PhyDM_STANDBY_MODE); + ODM_Write_DIG(pDM_Odm, IGI_Pause); + + Diff = IGI_target - (s1Byte)IGI; + TH_L2H_dmc = pDM_Odm->TH_L2H_ini + Diff; + if (TH_L2H_dmc > 10) + TH_L2H_dmc = 10; + TH_H2L_dmc = TH_L2H_dmc - pDM_Odm->TH_EDCCA_HL_diff; + + Phydm_SetEDCCAThreshold(pDM_Odm, TH_H2L_dmc, TH_L2H_dmc); + ODM_delay_ms(5); + + while (bAdjust) { + for (cnt = 0; cnt < 20; cnt++) { + if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) + value32 = ODM_GetBBReg(pDM_Odm, ODM_REG_RPT_11N, bMaskDWord); +#if (RTL8195A_SUPPORT == 0) + else if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) + value32 = ODM_GetBBReg(pDM_Odm, ODM_REG_RPT_11AC, bMaskDWord); +#endif + if (value32 & BIT30 && (pDM_Odm->SupportICType & (ODM_RTL8723A | ODM_RTL8723B | ODM_RTL8188E))) + txEdcca1 = txEdcca1 + 1; + else if (value32 & BIT29) + txEdcca1 = txEdcca1 + 1; + else + txEdcca0 = txEdcca0 + 1; + } + + if (txEdcca1 > 1) { + IGI = IGI - 1; + TH_L2H_dmc = TH_L2H_dmc + 1; + if (TH_L2H_dmc > 10) + TH_L2H_dmc = 10; + TH_H2L_dmc = TH_L2H_dmc - pDM_Odm->TH_EDCCA_HL_diff; + + Phydm_SetEDCCAThreshold(pDM_Odm, TH_H2L_dmc, TH_L2H_dmc); + if (TH_L2H_dmc == 10) { + bAdjust = FALSE; + Adaptivity->H2L_lb = TH_H2L_dmc; + Adaptivity->L2H_lb = TH_L2H_dmc; + pDM_Odm->Adaptivity_IGI_upper = IGI; + } + + txEdcca1 = 0; + txEdcca0 = 0; + + } else { + bAdjust = FALSE; + Adaptivity->H2L_lb = TH_H2L_dmc; + Adaptivity->L2H_lb = TH_L2H_dmc; + pDM_Odm->Adaptivity_IGI_upper = IGI; + txEdcca1 = 0; + txEdcca0 = 0; + } + } + + pDM_Odm->Adaptivity_IGI_upper = pDM_Odm->Adaptivity_IGI_upper - pDM_Odm->DCbackoff; + Adaptivity->H2L_lb = Adaptivity->H2L_lb + pDM_Odm->DCbackoff; + Adaptivity->L2H_lb = Adaptivity->L2H_lb + pDM_Odm->DCbackoff; + + Phydm_SetTRxMux(pDM_Odm, PhyDM_TX_MODE, PhyDM_RX_MODE); + ODM_Write_DIG(pDM_Odm, IGI_Resume); + Phydm_SetEDCCAThreshold(pDM_Odm, 0x7f, 0x7f); /*resume to no link state*/ +} + +VOID +Phydm_AdaptivityInit( + IN PVOID pDM_VOID +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + PADAPTIVITY_STATISTICS Adaptivity = (PADAPTIVITY_STATISTICS)PhyDM_Get_Structure(pDM_Odm, PHYDM_ADAPTIVITY); +#if(DM_ODM_SUPPORT_TYPE == ODM_WIN) + PADAPTER pAdapter = pDM_Odm->Adapter; + PMGNT_INFO pMgntInfo = &(pAdapter->MgntInfo); + pDM_Odm->Carrier_Sense_enable = (BOOLEAN)pMgntInfo->RegEnableCarrierSense; + pDM_Odm->DCbackoff = (u1Byte)pMgntInfo->RegDCbackoff; + Adaptivity->DynamicLinkAdaptivity = (BOOLEAN)pMgntInfo->RegDmLinkAdaptivity; + Adaptivity->APNumTH = (u1Byte)pMgntInfo->RegAPNumTH; +#elif(DM_ODM_SUPPORT_TYPE == ODM_CE) + pDM_Odm->Carrier_Sense_enable = (pDM_Odm->Adapter->registrypriv.adaptivity_mode != 0) ? TRUE : FALSE; + pDM_Odm->DCbackoff = pDM_Odm->Adapter->registrypriv.adaptivity_dc_backoff; + Adaptivity->DynamicLinkAdaptivity = (pDM_Odm->Adapter->registrypriv.adaptivity_dml != 0) ? TRUE : FALSE; +#endif + +#if(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_WIN)) + + if (pDM_Odm->Carrier_Sense_enable == FALSE) { +#if(DM_ODM_SUPPORT_TYPE == ODM_WIN) + if (pMgntInfo->RegL2HForAdaptivity != 0) + pDM_Odm->TH_L2H_ini = pMgntInfo->RegL2HForAdaptivity; + else +#endif + { + pDM_Odm->TH_L2H_ini = 0xf5; + } + } else { +#if(DM_ODM_SUPPORT_TYPE == ODM_WIN) + if (pMgntInfo->RegL2HForAdaptivity != 0) + pDM_Odm->TH_L2H_ini = pMgntInfo->RegL2HForAdaptivity; + else +#endif + pDM_Odm->TH_L2H_ini = 0xa; + } + +#if(DM_ODM_SUPPORT_TYPE == ODM_WIN) + if (pMgntInfo->RegHLDiffForAdaptivity != 0) + pDM_Odm->TH_EDCCA_HL_diff = pMgntInfo->RegHLDiffForAdaptivity; + else +#endif + pDM_Odm->TH_EDCCA_HL_diff = 7; + + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("TH_L2H_ini = 0x%x, TH_EDCCA_HL_diff = 0x%x\n", pDM_Odm->TH_L2H_ini, pDM_Odm->TH_EDCCA_HL_diff)); + +#elif (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + prtl8192cd_priv priv = pDM_Odm->priv; + + if (pDM_Odm->Carrier_Sense_enable) { + pDM_Odm->TH_L2H_ini = 0xa; + pDM_Odm->TH_EDCCA_HL_diff = 7; + } else { + pDM_Odm->TH_L2H_ini = pDM_Odm->TH_L2H_ini_backup; /*set by mib*/ + pDM_Odm->TH_EDCCA_HL_diff = 7; + } + + Adaptivity->TH_L2H_ini_mode2 = 20; + Adaptivity->TH_EDCCA_HL_diff_mode2 = 8; + Adaptivity->TH_EDCCA_HL_diff_backup = pDM_Odm->TH_EDCCA_HL_diff; + if (priv->pshare->rf_ft_var.adaptivity_enable == 2) + Adaptivity->DynamicLinkAdaptivity = TRUE; + else + Adaptivity->DynamicLinkAdaptivity = FALSE; + +#endif + + pDM_Odm->Adaptivity_IGI_upper = 0; + pDM_Odm->Adaptivity_enable = FALSE; /*use this flag to decide enable or disable*/ + + Adaptivity->IGI_Base = 0x32; + Adaptivity->IGI_target = 0x1c; + Adaptivity->H2L_lb = 0; + Adaptivity->L2H_lb = 0; + Adaptivity->NHMWait = 0; + Adaptivity->bCheck = FALSE; + Adaptivity->bFirstLink = TRUE; + + Phydm_MACEDCCAState(pDM_Odm, PhyDM_DONT_IGNORE_EDCCA); + + /*Search pwdB lower bound*/ + if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) + ODM_SetBBReg(pDM_Odm, ODM_REG_DBG_RPT_11N, bMaskDWord, 0x208); +#if (RTL8195A_SUPPORT == 0) + else if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) + ODM_SetBBReg(pDM_Odm, ODM_REG_DBG_RPT_11AC, bMaskDWord, 0x209); +#endif + +#if (RTL8195A_SUPPORT == 1) + if (pDM_Odm->SupportICType & ODM_RTL8195A) { + ODM_SetBBReg(pDM_Odm, ODM_REG_EDCCA_DOWN_OPT_11N, BIT12 | BIT11 | BIT10, 0x7); /*interfernce need > 2^x us, and then EDCCA will be 1*/ + ODM_SetBBReg(pDM_Odm, DOM_REG_EDCCA_DCNF_11N, BIT21 | BIT20, 0x1); /*0:rx_dfir, 1: dcnf_out, 2 :rx_iq, 3: rx_nbi_nf_out*/ + } +#else + if (pDM_Odm->SupportICType & ODM_RTL8814A) { /*8814a no need to find pwdB lower bound, maybe*/ + ODM_SetBBReg(pDM_Odm, ODM_REG_EDCCA_DOWN_OPT, BIT30 | BIT29 | BIT28, 0x7); /*interfernce need > 2^x us, and then EDCCA will be 1*/ + ODM_SetBBReg(pDM_Odm, ODM_REG_ACBB_EDCCA_ENHANCE, BIT29 | BIT28, 0x1); /*0:rx_dfir, 1: dcnf_out, 2 :rx_iq, 3: rx_nbi_nf_out*/ + } else + Phydm_SearchPwdBLowerBound(pDM_Odm); +#endif + +} + + +VOID +Phydm_Adaptivity( + IN PVOID pDM_VOID, + IN u1Byte IGI +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + s1Byte TH_L2H_dmc, TH_H2L_dmc; + s1Byte Diff, IGI_target; + PADAPTIVITY_STATISTICS Adaptivity = (PADAPTIVITY_STATISTICS)PhyDM_Get_Structure(pDM_Odm, PHYDM_ADAPTIVITY); +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PADAPTER pAdapter = pDM_Odm->Adapter; + BOOLEAN bFwCurrentInPSMode = FALSE; + PMGNT_INFO pMgntInfo = &(pAdapter->MgntInfo); + + pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_FW_PSMODE_STATUS, (pu1Byte)(&bFwCurrentInPSMode)); + + /*Disable EDCCA mode while under LPS mode, added by Roger, 2012.09.14.*/ + if (bFwCurrentInPSMode) + return; +#endif + + if (!(pDM_Odm->SupportAbility & ODM_BB_ADAPTIVITY)) { + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("Go to odm_DynamicEDCCA()\n")); + /*Add by Neil Chen to enable edcca to MP Platform */ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + /*Adjust EDCCA.*/ + if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) + Phydm_DynamicEDCCA(pDM_Odm); +#endif + return; + } + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + if (Phydm_CheckChannelPlan(pDM_Odm)) + return; + if (pDM_Odm->APTotalNum > Adaptivity->APNumTH) + return; +#endif + + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("odm_Adaptivity() =====>\n")); + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("IGI_Base=0x%x, TH_L2H_ini = %d, TH_EDCCA_HL_diff = %d\n", + Adaptivity->IGI_Base, pDM_Odm->TH_L2H_ini, pDM_Odm->TH_EDCCA_HL_diff)); +#if (RTL8195A_SUPPORT == 0) + if (pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) { + /*fix AC series when enable EDCCA hang issue*/ + ODM_SetBBReg(pDM_Odm, 0x800, BIT10, 1); /*ADC_mask disable*/ + ODM_SetBBReg(pDM_Odm, 0x800, BIT10, 0); /*ADC_mask enable*/ + } +#endif + if (*pDM_Odm->pBandWidth == ODM_BW20M) /*CHANNEL_WIDTH_20*/ + IGI_target = Adaptivity->IGI_Base; + else if (*pDM_Odm->pBandWidth == ODM_BW40M) + IGI_target = Adaptivity->IGI_Base + 2; +#if (RTL8195A_SUPPORT == 0) + else if (*pDM_Odm->pBandWidth == ODM_BW80M) + IGI_target = Adaptivity->IGI_Base + 2; +#endif + else + IGI_target = Adaptivity->IGI_Base; + Adaptivity->IGI_target = (u1Byte) IGI_target; + + if (*pDM_Odm->pChannel >= 149) { /*Band4 -> for AP : mode2*/ +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + s1Byte L2H_nolink_Band4 = 0x7f, H2L_nolink_Band4 = 0x7f; + if (pDM_Odm->bLinked) { + if (pDM_Odm->SupportICType & ODM_RTL8814A) { + L2H_nolink_Band4 = (s1Byte)Adaptivity->TH_L2H_ini_mode2 + IGI_target; + H2L_nolink_Band4 = L2H_nolink_Band4 - Adaptivity->TH_EDCCA_HL_diff_mode2; + } else { + Diff = IGI_target - (s1Byte)IGI; + L2H_nolink_Band4 = Adaptivity->TH_L2H_ini_mode2 + Diff; + if (L2H_nolink_Band4 > 10) + L2H_nolink_Band4 = 10; + H2L_nolink_Band4 = L2H_nolink_Band4 - Adaptivity->TH_EDCCA_HL_diff_mode2; + } + } else { + L2H_nolink_Band4 = 0x7f; + H2L_nolink_Band4 = 0x7f; + } + Phydm_SetEDCCAThreshold(pDM_Odm, H2L_nolink_Band4, L2H_nolink_Band4); + return; +#endif + } + + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("BandWidth=%s, IGI_target=0x%x, DynamicLinkAdaptivity = %d\n", + (*pDM_Odm->pBandWidth == ODM_BW80M) ? "80M" : ((*pDM_Odm->pBandWidth == ODM_BW40M) ? "40M" : "20M"), IGI_target, Adaptivity->DynamicLinkAdaptivity)); + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("RSSI_min = %d, AdapIGIUpper= 0x%x, adaptivity_flag = %d, Adaptivity_enable = %d\n", + pDM_Odm->RSSI_Min, pDM_Odm->Adaptivity_IGI_upper, pDM_Odm->adaptivity_flag, pDM_Odm->Adaptivity_enable)); + + if ((Adaptivity->DynamicLinkAdaptivity == TRUE) && (!pDM_Odm->bLinked) && (pDM_Odm->Adaptivity_enable == FALSE)) { + Phydm_SetEDCCAThreshold(pDM_Odm, 0x7f, 0x7f); + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("In DynamicLink mode(noisy) and No link, Turn off EDCCA!!\n")); + return; + } +#if (!(DM_ODM_SUPPORT_TYPE & ODM_AP)) + else if ((Adaptivity->DynamicLinkAdaptivity == TRUE) && (pDM_Odm->Adaptivity_enable == FALSE)) { + Phydm_SetEDCCAThreshold(pDM_Odm, 0x7f, 0x7f); + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("In DynamicLink mode(noisy) disable EDCCA, return!!\n")); + return; + } +#endif + + if (pDM_Odm->SupportICType & (ODM_RTL8814A|ODM_RTL8195A)) { + TH_L2H_dmc = (s1Byte)pDM_Odm->TH_L2H_ini + IGI_target; + TH_H2L_dmc = TH_L2H_dmc - pDM_Odm->TH_EDCCA_HL_diff; + } +#if (RTL8195A_SUPPORT == 0) + else { + Diff = IGI_target - (s1Byte)IGI; + TH_L2H_dmc = pDM_Odm->TH_L2H_ini + Diff; + if (TH_L2H_dmc > 10) + TH_L2H_dmc = 10; + + TH_H2L_dmc = TH_L2H_dmc - pDM_Odm->TH_EDCCA_HL_diff; + + /*replace lower bound to prevent EDCCA always equal 1*/ + if (TH_H2L_dmc < Adaptivity->H2L_lb) + TH_H2L_dmc = Adaptivity->H2L_lb; + if (TH_L2H_dmc < Adaptivity->L2H_lb) + TH_L2H_dmc = Adaptivity->L2H_lb; + } +#endif + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("IGI=0x%x, TH_L2H_dmc = %d, TH_H2L_dmc = %d\n", IGI, TH_L2H_dmc, TH_H2L_dmc)); + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("Adaptivity_IGI_upper=0x%x, H2L_lb = 0x%x, L2H_lb = 0x%x\n", pDM_Odm->Adaptivity_IGI_upper, Adaptivity->H2L_lb, Adaptivity->L2H_lb)); + + Phydm_SetEDCCAThreshold(pDM_Odm, TH_H2L_dmc, TH_L2H_dmc); + return; +} + + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +VOID +Phydm_AdaptivityBSOD( + IN PVOID pDM_VOID +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + PADAPTER pAdapter = pDM_Odm->Adapter; + PMGNT_INFO pMgntInfo = &(pAdapter->MgntInfo); + u1Byte count = 0; + u4Byte u4Value; + + /* + 1. turn off RF (TRX Mux in standby mode) + 2. H2C mac id drop + 3. ignore EDCCA + 4. wait for clear FIFO + 5. don't ignore EDCCA + 6. turn on RF (TRX Mux in TRx mdoe) + 7. H2C mac id resume + */ + + RT_TRACE(COMP_MLME, DBG_WARNING, ("MAC id drop packet!!!!!\n")); + + pAdapter->dropPktByMacIdCnt++; + pMgntInfo->bDropPktInProgress = TRUE; + + pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_MAX_Q_PAGE_NUM, (pu1Byte)(&u4Value)); + RT_TRACE(COMP_INIT, DBG_LOUD, ("Queue Reserved Page Number = 0x%08x\n", u4Value)); + pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_AVBL_Q_PAGE_NUM, (pu1Byte)(&u4Value)); + RT_TRACE(COMP_INIT, DBG_LOUD, ("Available Queue Page Number = 0x%08x\n", u4Value)); + +#if 1 + + /*Standby mode*/ + Phydm_SetTRxMux(pDM_Odm, PhyDM_STANDBY_MODE, PhyDM_STANDBY_MODE); + ODM_Write_DIG(pDM_Odm, 0x20); + + /*H2C mac id drop*/ + MacIdIndicateDisconnect(pAdapter); + + /*Ignore EDCCA*/ + Phydm_MACEDCCAState(pDM_Odm, PhyDM_IGNORE_EDCCA); + + delay_ms(50); + count = 5; + +#else + + do { + + u8Byte diffTime, curTime, oldestTime; + u1Byte queueIdx + + //3 Standby mode + Phydm_SetTRxMux(pDM_Odm, PhyDM_STANDBY_MODE, PhyDM_STANDBY_MODE); + ODM_Write_DIG(pDM_Odm, 0x20); + + //3 H2C mac id drop + MacIdIndicateDisconnect(pAdapter); + + //3 Ignore EDCCA + Phydm_MACEDCCAState(pDM_Odm, PhyDM_IGNORE_EDCCA); + + count++; + delay_ms(10); + + // Check latest packet + curTime = PlatformGetCurrentTime(); + oldestTime = 0xFFFFFFFFFFFFFFFF; + + for (queueIdx = 0; queueIdx < MAX_TX_QUEUE; queueIdx++) { + if (!IS_DATA_QUEUE(queueIdx)) + continue; + + if (!pAdapter->bTcbBusyQEmpty[queueIdx]) { + RT_TRACE(COMP_MLME, DBG_WARNING, ("oldestTime = %llu\n", oldestTime)); + RT_TRACE(COMP_MLME, DBG_WARNING, ("Q[%d] = %llu\n", queueIdx, pAdapter->firstTcbSysTime[queueIdx])); + if (pAdapter->firstTcbSysTime[queueIdx] < oldestTime) + oldestTime = pAdapter->firstTcbSysTime[queueIdx]; + } + } + + diffTime = curTime - oldestTime; + + RT_TRACE(COMP_MLME, DBG_WARNING, ("diff s = %llu\n", (diffTime / 1000000))); + + } while (((diffTime / 1000000) >= 4) && (oldestTime != 0xFFFFFFFFFFFFFFFF)); +#endif + + /*Resume EDCCA*/ + Phydm_MACEDCCAState(pDM_Odm, PhyDM_DONT_IGNORE_EDCCA); + + /*Turn on TRx mode*/ + Phydm_SetTRxMux(pDM_Odm, PhyDM_TX_MODE, PhyDM_RX_MODE); + ODM_Write_DIG(pDM_Odm, 0x20); + + /*Resume H2C macid*/ + MacIdRecoverMediaStatus(pAdapter); + + pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_AVBL_Q_PAGE_NUM, (pu1Byte)(&u4Value)); + RT_TRACE(COMP_INIT, DBG_LOUD, ("Available Queue Page Number = 0x%08x\n", u4Value)); + + pMgntInfo->bDropPktInProgress = FALSE; + RT_TRACE(COMP_MLME, DBG_WARNING, ("End of MAC id drop packet, spent %dms\n", count * 10)); + +} + +VOID +Phydm_EnableEDCCA( + IN PVOID pDM_VOID +) +{ + + /*This should be moved out of OUTSRC*/ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + PADAPTER pAdapter = pDM_Odm->Adapter; + /*Enable EDCCA. The value is suggested by SD3 Wilson.*/ + + /*Revised for ASUS 11b/g performance issues, suggested by BB Neil, 2012.04.13.*/ + if ((pDM_Odm->SupportICType == ODM_RTL8723A) && (IS_WIRELESS_MODE_G(pAdapter))) { + ODM_Write1Byte(pDM_Odm, rOFDM0_ECCAThreshold, 0x00); + ODM_Write1Byte(pDM_Odm, rOFDM0_ECCAThreshold + 2, 0xFD); + } else { + ODM_Write1Byte(pDM_Odm, rOFDM0_ECCAThreshold, 0x03); + ODM_Write1Byte(pDM_Odm, rOFDM0_ECCAThreshold + 2, 0x00); + } +} + +VOID +Phydm_DisableEDCCA( + IN PVOID pDM_VOID +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + ODM_Write1Byte(pDM_Odm, rOFDM0_ECCAThreshold, 0x7f); + ODM_Write1Byte(pDM_Odm, rOFDM0_ECCAThreshold + 2, 0x7f); +} + +VOID +Phydm_DynamicEDCCA( + IN PVOID pDM_VOID +) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID; + PADAPTER pAdapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + u1Byte RegC50, RegC58; + +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) + BOOLEAN bFwCurrentInPSMode = FALSE; + + pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_FW_PSMODE_STATUS, (pu1Byte)(&bFwCurrentInPSMode)); + + /*Disable EDCCA mode while under LPS mode, added by Roger, 2012.09.14.*/ + if (bFwCurrentInPSMode) + return; +#endif + + /*2013/11/14 Ken According to BB team Jame's suggestion, we need to disable soft AP mode EDCCA.*/ + /*2014/01/08 MH For Miracst AP mode test. We need to disable EDCCA. Otherwise, we may stop*/ + /*to send beacon in noisy environment or platform.*/ + + if (ACTING_AS_AP(pAdapter) || ACTING_AS_AP(GetFirstAPAdapter(pAdapter))) { + ODM_RT_TRACE(pDM_Odm, PHYDM_COMP_ADAPTIVITY, ODM_DBG_LOUD, ("At least One Port as AP disable EDCCA\n")); + Phydm_DisableEDCCA(pDM_Odm); + if (pHalData->bPreEdccaEnable) + Phydm_DisableEDCCA(pDM_Odm); + pHalData->bPreEdccaEnable = FALSE; + return; + } + + RegC50 = (u1Byte)ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskByte0); + RegC58 = (u1Byte)ODM_GetBBReg(pDM_Odm, rOFDM0_XBAGCCore1, bMaskByte0); + + + if ((RegC50 > 0x28 && RegC58 > 0x28) || + ((pDM_Odm->SupportICType == ODM_RTL8723A && IS_WIRELESS_MODE_G(pAdapter) && RegC50 > 0x26)) || + (pDM_Odm->SupportICType == ODM_RTL8188E && RegC50 > 0x28)) { + if (!pHalData->bPreEdccaEnable) { + Phydm_EnableEDCCA(pDM_Odm); + pHalData->bPreEdccaEnable = TRUE; + } + + } else if ((RegC50 < 0x25 && RegC58 < 0x25) || (pDM_Odm->SupportICType == ODM_RTL8188E && RegC50 < 0x25)) { + if (pHalData->bPreEdccaEnable) { + Phydm_DisableEDCCA(pDM_Odm); + pHalData->bPreEdccaEnable = FALSE; + } + } +} + +#endif diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/PhyDM_Adaptivity.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/PhyDM_Adaptivity.h new file mode 100644 index 0000000..0787d5d --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/PhyDM_Adaptivity.h @@ -0,0 +1,157 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#ifndef __PHYDMADAPTIVITY_H__ +#define __PHYDMADAPTIVITY_H__ + +#define ADAPTIVITY_VERSION "8.5.1" + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) +typedef enum _tag_PhyDM_REGULATION_Type { + REGULATION_FCC = 0, + REGULATION_MKK = 1, + REGULATION_ETSI = 2, + REGULATION_WW = 3, + + MAX_REGULATION_NUM = 4 +} PhyDM_REGULATION_TYPE; +#endif + + +typedef enum tag_PhyDM_TRx_MUX_Type +{ + PhyDM_SHUTDOWN = 0, + PhyDM_STANDBY_MODE = 1, + PhyDM_TX_MODE = 2, + PhyDM_RX_MODE = 3 +}PhyDM_Trx_MUX_Type; + +typedef enum tag_PhyDM_MACEDCCA_Type +{ + PhyDM_IGNORE_EDCCA = 0, + PhyDM_DONT_IGNORE_EDCCA = 1 +}PhyDM_MACEDCCA_Type; + +typedef struct _ADAPTIVITY_STATISTICS { + s1Byte TH_L2H_ini_mode2; + s1Byte TH_EDCCA_HL_diff_mode2; + s1Byte TH_EDCCA_HL_diff_backup; + s1Byte IGI_Base; + u1Byte IGI_target; + u1Byte NHMWait; + s1Byte H2L_lb; + s1Byte L2H_lb; + BOOLEAN bFirstLink; + BOOLEAN bCheck; + BOOLEAN DynamicLinkAdaptivity; + u1Byte APNumTH; +} ADAPTIVITY_STATISTICS, *PADAPTIVITY_STATISTICS; + +VOID +Phydm_CheckAdaptivity( + IN PVOID pDM_VOID + ); + +VOID +Phydm_CheckEnvironment( + IN PVOID pDM_VOID + ); + +VOID +Phydm_NHMCounterStatisticsInit( + IN PVOID pDM_VOID + ); + +VOID +Phydm_NHMCounterStatistics( + IN PVOID pDM_VOID + ); + +VOID +Phydm_NHMCounterStatisticsReset( + IN PVOID pDM_VOID +); + +VOID +Phydm_GetNHMCounterStatistics( + IN PVOID pDM_VOID +); + +VOID +Phydm_MACEDCCAState( + IN PVOID pDM_VOID, + IN PhyDM_MACEDCCA_Type State +); + +VOID +Phydm_SetEDCCAThreshold( + IN PVOID pDM_VOID, + IN s1Byte H2L, + IN s1Byte L2H +); + +VOID +Phydm_SetTRxMux( + IN PVOID pDM_VOID, + IN PhyDM_Trx_MUX_Type txMode, + IN PhyDM_Trx_MUX_Type rxMode +); + +BOOLEAN +Phydm_CalNHMcnt( + IN PVOID pDM_VOID +); + +VOID +Phydm_SearchPwdBLowerBound( + IN PVOID pDM_VOID +); + +VOID +Phydm_AdaptivityInit( + IN PVOID pDM_VOID + ); + +VOID +Phydm_Adaptivity( + IN PVOID pDM_VOID, + IN u1Byte IGI + ); + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +VOID +Phydm_DisableEDCCA( + IN PVOID pDM_VOID +); + +VOID +Phydm_DynamicEDCCA( + IN PVOID pDM_VOID +); + +VOID +Phydm_AdaptivityBSOD( + IN PVOID pDM_VOID +); + +#endif + + +#endif diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm.c new file mode 100644 index 0000000..9b0e698 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm.c @@ -0,0 +1,14017 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +//============================================================ +// include files +//============================================================ + +#include "odm_precomp.h" + + +const u2Byte dB_Invert_Table[8][12] = { + { 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4}, + { 4, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16}, + { 18, 20, 22, 25, 28, 32, 35, 40, 45, 50, 56, 63}, + { 71, 79, 89, 100, 112, 126, 141, 158, 178, 200, 224, 251}, + { 282, 316, 355, 398, 447, 501, 562, 631, 708, 794, 891, 1000}, + { 1122, 1259, 1413, 1585, 1778, 1995, 2239, 2512, 2818, 3162, 3548, 3981}, + { 4467, 5012, 5623, 6310, 7079, 7943, 8913, 10000, 11220, 12589, 14125, 15849}, + { 17783, 19953, 22387, 25119, 28184, 31623, 35481, 39811, 44668, 50119, 56234, 65535}}; + + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) +static u4Byte edca_setting_UL[HT_IOT_PEER_MAX] = +// UNKNOWN REALTEK_90 REALTEK_92SE BROADCOM RALINK ATHEROS CISCO MERU MARVELL 92U_AP SELF_AP(DownLink/Tx) +{ 0x5e4322, 0xa44f, 0x5e4322, 0x5ea32b, 0x5ea422, 0x5ea322, 0x3ea430, 0x5ea42b, 0x5ea44f, 0x5e4322, 0x5e4322}; + + +static u4Byte edca_setting_DL[HT_IOT_PEER_MAX] = +// UNKNOWN REALTEK_90 REALTEK_92SE BROADCOM RALINK ATHEROS CISCO MERU, MARVELL 92U_AP SELF_AP(UpLink/Rx) +{ 0xa44f, 0x5ea44f, 0x5e4322, 0x5ea42b, 0xa44f, 0xa630, 0x5ea630, 0x5ea42b, 0xa44f, 0xa42b, 0xa42b}; + +static u4Byte edca_setting_DL_GMode[HT_IOT_PEER_MAX] = +// UNKNOWN REALTEK_90 REALTEK_92SE BROADCOM RALINK ATHEROS CISCO MERU, MARVELL 92U_AP SELF_AP +{ 0x4322, 0xa44f, 0x5e4322, 0xa42b, 0x5e4322, 0x4322, 0xa42b, 0x5ea42b, 0xa44f, 0x5e4322, 0x5ea42b}; + + +//============================================================ +// EDCA Paramter for AP/ADSL by Mingzhi 2011-11-22 +//============================================================ +#elif (DM_ODM_SUPPORT_TYPE &ODM_ADSL) +enum qos_prio { BK, BE, VI, VO, VI_AG, VO_AG }; + +static const struct ParaRecord rtl_ap_EDCA[] = +{ +//ACM,AIFSN, ECWmin, ECWmax, TXOplimit + {0, 7, 4, 10, 0}, //BK + {0, 3, 4, 6, 0}, //BE + {0, 1, 3, 4, 188}, //VI + {0, 1, 2, 3, 102}, //VO + {0, 1, 3, 4, 94}, //VI_AG + {0, 1, 2, 3, 47}, //VO_AG +}; + +static const struct ParaRecord rtl_sta_EDCA[] = +{ +//ACM,AIFSN, ECWmin, ECWmax, TXOplimit + {0, 7, 4, 10, 0}, + {0, 3, 4, 10, 0}, + {0, 2, 3, 4, 188}, + {0, 2, 2, 3, 102}, + {0, 2, 3, 4, 94}, + {0, 2, 2, 3, 47}, +}; +#endif + +//============================================================ +// Global var +//============================================================ + +u4Byte OFDMSwingTable[OFDM_TABLE_SIZE] = { + 0x7f8001fe, // 0, +6.0dB + 0x788001e2, // 1, +5.5dB + 0x71c001c7, // 2, +5.0dB + 0x6b8001ae, // 3, +4.5dB + 0x65400195, // 4, +4.0dB + 0x5fc0017f, // 5, +3.5dB + 0x5a400169, // 6, +3.0dB + 0x55400155, // 7, +2.5dB + 0x50800142, // 8, +2.0dB + 0x4c000130, // 9, +1.5dB + 0x47c0011f, // 10, +1.0dB + 0x43c0010f, // 11, +0.5dB + 0x40000100, // 12, +0dB + 0x3c8000f2, // 13, -0.5dB + 0x390000e4, // 14, -1.0dB + 0x35c000d7, // 15, -1.5dB + 0x32c000cb, // 16, -2.0dB + 0x300000c0, // 17, -2.5dB + 0x2d4000b5, // 18, -3.0dB + 0x2ac000ab, // 19, -3.5dB + 0x288000a2, // 20, -4.0dB + 0x26000098, // 21, -4.5dB + 0x24000090, // 22, -5.0dB + 0x22000088, // 23, -5.5dB + 0x20000080, // 24, -6.0dB + 0x1e400079, // 25, -6.5dB + 0x1c800072, // 26, -7.0dB + 0x1b00006c, // 27. -7.5dB + 0x19800066, // 28, -8.0dB + 0x18000060, // 29, -8.5dB + 0x16c0005b, // 30, -9.0dB + 0x15800056, // 31, -9.5dB + 0x14400051, // 32, -10.0dB + 0x1300004c, // 33, -10.5dB + 0x12000048, // 34, -11.0dB + 0x11000044, // 35, -11.5dB + 0x10000040, // 36, -12.0dB +}; + +u1Byte CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8] = { + {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, // 0, +0dB + {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, // 1, -0.5dB + {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, // 2, -1.0dB + {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, // 3, -1.5dB + {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, // 4, -2.0dB + {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, // 5, -2.5dB + {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, // 6, -3.0dB + {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, // 7, -3.5dB + {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, // 8, -4.0dB + {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, // 9, -4.5dB + {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, // 10, -5.0dB + {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, // 11, -5.5dB + {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, // 12, -6.0dB <== default + {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, // 13, -6.5dB + {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, // 14, -7.0dB + {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, // 15, -7.5dB + {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, // 16, -8.0dB + {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, // 17, -8.5dB + {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, // 18, -9.0dB + {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 19, -9.5dB + {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 20, -10.0dB + {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, // 21, -10.5dB + {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, // 22, -11.0dB + {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, // 23, -11.5dB + {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, // 24, -12.0dB + {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, // 25, -12.5dB + {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, // 26, -13.0dB + {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, // 27, -13.5dB + {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, // 28, -14.0dB + {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, // 29, -14.5dB + {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, // 30, -15.0dB + {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, // 31, -15.5dB + {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} // 32, -16.0dB +}; + + +u1Byte CCKSwingTable_Ch14[CCK_TABLE_SIZE][8] = { + {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, // 0, +0dB + {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, // 1, -0.5dB + {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, // 2, -1.0dB + {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, // 3, -1.5dB + {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, // 4, -2.0dB + {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, // 5, -2.5dB + {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, // 6, -3.0dB + {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, // 7, -3.5dB + {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, // 8, -4.0dB + {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, // 9, -4.5dB + {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, // 10, -5.0dB + {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 11, -5.5dB + {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 12, -6.0dB <== default + {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, // 13, -6.5dB + {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, // 14, -7.0dB + {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 15, -7.5dB + {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 16, -8.0dB + {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 17, -8.5dB + {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 18, -9.0dB + {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 19, -9.5dB + {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 20, -10.0dB + {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, // 21, -10.5dB + {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, // 22, -11.0dB + {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, // 23, -11.5dB + {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, // 24, -12.0dB + {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, // 25, -12.5dB + {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, // 26, -13.0dB + {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, // 27, -13.5dB + {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, // 28, -14.0dB + {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, // 29, -14.5dB + {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, // 30, -15.0dB + {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, // 31, -15.5dB + {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} // 32, -16.0dB +}; + + +u4Byte OFDMSwingTable_New[OFDM_TABLE_SIZE] = { + 0x0b40002d, // 0, -15.0dB + 0x0c000030, // 1, -14.5dB + 0x0cc00033, // 2, -14.0dB + 0x0d800036, // 3, -13.5dB + 0x0e400039, // 4, -13.0dB + 0x0f00003c, // 5, -12.5dB + 0x10000040, // 6, -12.0dB + 0x11000044, // 7, -11.5dB + 0x12000048, // 8, -11.0dB + 0x1300004c, // 9, -10.5dB + 0x14400051, // 10, -10.0dB + 0x15800056, // 11, -9.5dB + 0x16c0005b, // 12, -9.0dB + 0x18000060, // 13, -8.5dB + 0x19800066, // 14, -8.0dB + 0x1b00006c, // 15, -7.5dB + 0x1c800072, // 16, -7.0dB + 0x1e400079, // 17, -6.5dB + 0x20000080, // 18, -6.0dB + 0x22000088, // 19, -5.5dB + 0x24000090, // 20, -5.0dB + 0x26000098, // 21, -4.5dB + 0x288000a2, // 22, -4.0dB + 0x2ac000ab, // 23, -3.5dB + 0x2d4000b5, // 24, -3.0dB + 0x300000c0, // 25, -2.5dB + 0x32c000cb, // 26, -2.0dB + 0x35c000d7, // 27, -1.5dB + 0x390000e4, // 28, -1.0dB + 0x3c8000f2, // 29, -0.5dB + 0x40000100, // 30, +0dB + 0x43c0010f, // 31, +0.5dB + 0x47c0011f, // 32, +1.0dB + 0x4c000130, // 33, +1.5dB + 0x50800142, // 34, +2.0dB + 0x55400155, // 35, +2.5dB + 0x5a400169, // 36, +3.0dB + 0x5fc0017f, // 37, +3.5dB + 0x65400195, // 38, +4.0dB + 0x6b8001ae, // 39, +4.5dB + 0x71c001c7, // 40, +5.0dB + 0x788001e2, // 41, +5.5dB + 0x7f8001fe // 42, +6.0dB +}; + + +u1Byte CCKSwingTable_Ch1_Ch13_New[CCK_TABLE_SIZE][8] = { + {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}, // 0, -16.0dB + {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, // 1, -15.5dB + {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, // 2, -15.0dB + {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, // 3, -14.5dB + {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, // 4, -14.0dB + {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, // 5, -13.5dB + {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, // 6, -13.0dB + {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, // 7, -12.5dB + {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, // 8, -12.0dB + {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, // 9, -11.5dB + {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, // 10, -11.0dB + {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, // 11, -10.5dB + {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 12, -10.0dB + {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 13, -9.5dB + {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, // 14, -9.0dB + {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, // 15, -8.5dB + {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, // 16, -8.0dB + {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, // 17, -7.5dB + {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, // 18, -7.0dB + {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, // 19, -6.5dB + {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, // 20, -6.0dB + {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, // 21, -5.5dB + {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, // 22, -5.0dB + {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, // 23, -4.5dB + {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, // 24, -4.0dB + {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, // 25, -3.5dB + {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, // 26, -3.0dB + {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, // 27, -2.5dB + {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, // 28, -2.0dB + {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, // 29, -1.5dB + {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, // 30, -1.0dB + {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, // 31, -0.5dB + {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04} // 32, +0dB +}; + + +u1Byte CCKSwingTable_Ch14_New[CCK_TABLE_SIZE][8]= { + {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}, // 0, -16.0dB + {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, // 1, -15.5dB + {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, // 2, -15.0dB + {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, // 3, -14.5dB + {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, // 4, -14.0dB + {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, // 5, -13.5dB + {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, // 6, -13.0dB + {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, // 7, -12.5dB + {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, // 8, -12.0dB + {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, // 9, -11.5dB + {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, // 10, -11.0dB + {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, // 11, -10.5dB + {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 12, -10.0dB + {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 13, -9.5dB + {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 14, -9.0dB + {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 15, -8.5dB + {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 16, -8.0dB + {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 17, -7.5dB + {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, // 18, -7.0dB + {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, // 19, -6.5dB + {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 20, -6.0dB + {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 21, -5.5dB + {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, // 22, -5.0dB + {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, // 23, -4.5dB + {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, // 24, -4.0dB + {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, // 25, -3.5dB + {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, // 26, -3.0dB + {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, // 27, -2.5dB + {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, // 28, -2.0dB + {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, // 29, -1.5dB + {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, // 30, -1.0dB + {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, // 31, -0.5dB + {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00} // 32, +0dB +}; + +u4Byte TxScalingTable_Jaguar[TXSCALE_TABLE_SIZE] = +{ + 0x081, // 0, -12.0dB + 0x088, // 1, -11.5dB + 0x090, // 2, -11.0dB + 0x099, // 3, -10.5dB + 0x0A2, // 4, -10.0dB + 0x0AC, // 5, -9.5dB + 0x0B6, // 6, -9.0dB + 0x0C0, // 7, -8.5dB + 0x0CC, // 8, -8.0dB + 0x0D8, // 9, -7.5dB + 0x0E5, // 10, -7.0dB + 0x0F2, // 11, -6.5dB + 0x101, // 12, -6.0dB + 0x110, // 13, -5.5dB + 0x120, // 14, -5.0dB + 0x131, // 15, -4.5dB + 0x143, // 16, -4.0dB + 0x156, // 17, -3.5dB + 0x16A, // 18, -3.0dB + 0x180, // 19, -2.5dB + 0x197, // 20, -2.0dB + 0x1AF, // 21, -1.5dB + 0x1C8, // 22, -1.0dB + 0x1E3, // 23, -0.5dB + 0x200, // 24, +0 dB + 0x21E, // 25, +0.5dB + 0x23E, // 26, +1.0dB + 0x261, // 27, +1.5dB + 0x285, // 28, +2.0dB + 0x2AB, // 29, +2.5dB + 0x2D3, // 30, +3.0dB + 0x2FE, // 31, +3.5dB + 0x32B, // 32, +4.0dB + 0x35C, // 33, +4.5dB + 0x38E, // 34, +5.0dB + 0x3C4, // 35, +5.5dB + 0x3FE // 36, +6.0dB +}; + +#ifdef AP_BUILD_WORKAROUND + +unsigned int TxPwrTrk_OFDM_SwingTbl[TxPwrTrk_OFDM_SwingTbl_Len] = { + /* +6.0dB */ 0x7f8001fe, + /* +5.5dB */ 0x788001e2, + /* +5.0dB */ 0x71c001c7, + /* +4.5dB */ 0x6b8001ae, + /* +4.0dB */ 0x65400195, + /* +3.5dB */ 0x5fc0017f, + /* +3.0dB */ 0x5a400169, + /* +2.5dB */ 0x55400155, + /* +2.0dB */ 0x50800142, + /* +1.5dB */ 0x4c000130, + /* +1.0dB */ 0x47c0011f, + /* +0.5dB */ 0x43c0010f, + /* 0.0dB */ 0x40000100, + /* -0.5dB */ 0x3c8000f2, + /* -1.0dB */ 0x390000e4, + /* -1.5dB */ 0x35c000d7, + /* -2.0dB */ 0x32c000cb, + /* -2.5dB */ 0x300000c0, + /* -3.0dB */ 0x2d4000b5, + /* -3.5dB */ 0x2ac000ab, + /* -4.0dB */ 0x288000a2, + /* -4.5dB */ 0x26000098, + /* -5.0dB */ 0x24000090, + /* -5.5dB */ 0x22000088, + /* -6.0dB */ 0x20000080, + /* -6.5dB */ 0x1a00006c, + /* -7.0dB */ 0x1c800072, + /* -7.5dB */ 0x18000060, + /* -8.0dB */ 0x19800066, + /* -8.5dB */ 0x15800056, + /* -9.0dB */ 0x26c0005b, + /* -9.5dB */ 0x14400051, + /* -10.0dB */ 0x24400051, + /* -10.5dB */ 0x1300004c, + /* -11.0dB */ 0x12000048, + /* -11.5dB */ 0x11000044, + /* -12.0dB */ 0x10000040 +}; +#endif + +//============================================================ +// Local Function predefine. +//============================================================ + +//START------------COMMON INFO RELATED---------------// +VOID +odm_CommonInfoSelfInit( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_CommonInfoSelfUpdate( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_CmnInfoInit_Debug( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_CmnInfoHook_Debug( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_CmnInfoUpdate_Debug( + IN PDM_ODM_T pDM_Odm + ); +VOID +odm_BasicDbgMessage +( + IN PDM_ODM_T pDM_Odm + ); + +//END------------COMMON INFO RELATED---------------// + +//START---------------DIG---------------------------// +VOID +odm_FalseAlarmCounterStatistics( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_DIGInit( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_DIG( + IN PDM_ODM_T pDM_Odm + ); + +BOOLEAN +odm_DigAbort( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_CCKPacketDetectionThresh( + IN PDM_ODM_T pDM_Odm + ); + +//END---------------DIG---------------------------// + +//START-------BB POWER SAVE-----------------------// +VOID +odm_DynamicBBPowerSavingInit( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_DynamicBBPowerSaving( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_1R_CCA( + IN PDM_ODM_T pDM_Odm + ); +//END---------BB POWER SAVE-----------------------// + +//START-----------------PSD-----------------------// +#if(DM_ODM_SUPPORT_TYPE & (ODM_WIN)) +//============================================================ +// Function predefine. +//============================================================ +VOID odm_PathDiversityInit_92C( IN PADAPTER Adapter); +VOID odm_2TPathDiversityInit_92C( IN PADAPTER Adapter); +VOID odm_1TPathDiversityInit_92C( IN PADAPTER Adapter); +BOOLEAN odm_IsConnected_92C(IN PADAPTER Adapter); +VOID odm_PathDiversityAfterLink_92C( IN PADAPTER Adapter); + +VOID +odm_CCKTXPathDiversityCallback( + PRT_TIMER pTimer + ); + +VOID +odm_CCKTXPathDiversityWorkItemCallback( + IN PVOID pContext + ); + +VOID +odm_PathDivChkAntSwitchCallback( + PRT_TIMER pTimer + ); + +VOID +odm_PathDivChkAntSwitchWorkitemCallback( + IN PVOID pContext + ); + +VOID odm_SetRespPath_92C( IN PADAPTER Adapter, IN u1Byte DefaultRespPath); +VOID odm_OFDMTXPathDiversity_92C( IN PADAPTER Adapter); +VOID odm_CCKTXPathDiversity_92C( IN PADAPTER Adapter); +VOID odm_ResetPathDiversity_92C( IN PADAPTER Adapter); + +//Start-------------------- RX High Power------------------------// +VOID odm_RXHPInit( IN PDM_ODM_T pDM_Odm); +VOID odm_RXHP( IN PDM_ODM_T pDM_Odm); +VOID odm_Write_RXHP( IN PDM_ODM_T pDM_Odm); + +VOID odm_PSD_RXHP( IN PDM_ODM_T pDM_Odm); +VOID odm_PSD_RXHPCallback( PRT_TIMER pTimer); +VOID odm_PSD_RXHPWorkitemCallback( IN PVOID pContext); +//End--------------------- RX High Power -----------------------// + +VOID odm_PathDivInit_92D( IN PDM_ODM_T pDM_Odm); + +VOID +odm_SetRespPath_92C( + IN PADAPTER Adapter, + IN u1Byte DefaultRespPath + ); + +#endif +//END-------------------PSD-----------------------// + +VOID +odm_RefreshRateAdaptiveMaskMP( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_RefreshRateAdaptiveMaskCE( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_RefreshRateAdaptiveMaskAPADSL( + IN PDM_ODM_T pDM_Odm + ); + +VOID +ODM_DynamicATCSwitch_init( + IN PDM_ODM_T pDM_Odm + ); + +VOID +ODM_DynamicATCSwitch( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_Write_CrystalCap( + IN PDM_ODM_T pDM_Odm, + IN u1Byte CrystalCap +); + +VOID +odm_DynamicTxPowerInit( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_DynamicTxPowerRestorePowerIndex( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_DynamicTxPowerNIC( + IN PDM_ODM_T pDM_Odm + ); + +#if(DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) +VOID +odm_DynamicTxPowerSavePowerIndex( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_DynamicTxPowerWritePowerIndex( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Value); + +VOID +odm_DynamicTxPower_92C( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_DynamicTxPower_92D( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_MPT_DIGCallback( + PRT_TIMER pTimer +); + +VOID +odm_MPT_DIGWorkItemCallback( + IN PVOID pContext + ); +#endif + + +VOID +odm_RSSIMonitorInit( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_RSSIMonitorCheckMP( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_RSSIMonitorCheckCE( + IN PDM_ODM_T pDM_Odm + ); +VOID +odm_RSSIMonitorCheckAP( + IN PDM_ODM_T pDM_Odm + ); + + + +VOID +odm_RSSIMonitorCheck( + IN PDM_ODM_T pDM_Odm + ); +VOID +odm_DynamicTxPower( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_DynamicTxPowerAP( + IN PDM_ODM_T pDM_Odm + ); + + +VOID +odm_SwAntDivInit( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_SwAntDivInit_NIC( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_SwAntDetectInit( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_SwAntDivChkAntSwitch( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Step + ); + +VOID +odm_SwAntDivChkAntSwitchNIC( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Step + ); + + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +VOID +odm_SwAntDivChkAntSwitchCallback( + PRT_TIMER pTimer +); +VOID +odm_SwAntDivChkAntSwitchWorkitemCallback( + IN PVOID pContext + ); +VOID +ODM_UpdateInitRateWorkItemCallback( + IN PVOID pContext + ); +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + VOID odm_SwAntDivChkAntSwitchCallback(void *FunctionContext); +#elif (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + VOID odm_SwAntDivChkAntSwitchCallback(void *FunctionContext); +#endif + + + +VOID +odm_GlobalAdapterCheck( + IN VOID + ); + +VOID +odm_RefreshBasicRateMask( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_RefreshRateAdaptiveMask( + IN PDM_ODM_T pDM_Odm + ); + +VOID +ODM_TXPowerTrackingCheck( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_TXPowerTrackingCheckAP( + IN PDM_ODM_T pDM_Odm + ); + + + + + + + +VOID +odm_RateAdaptiveMaskInit( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_TXPowerTrackingThermalMeterInit( + IN PDM_ODM_T pDM_Odm + ); + + +VOID +odm_IQCalibrate( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_TXPowerTrackingInit( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_TXPowerTrackingCheckMP( + IN PDM_ODM_T pDM_Odm + ); + + +VOID +odm_TXPowerTrackingCheckCE( + IN PDM_ODM_T pDM_Odm + ); + +#if(DM_ODM_SUPPORT_TYPE & (ODM_WIN)) + +VOID +ODM_RateAdaptiveStateApInit( + IN PADAPTER Adapter , + IN PRT_WLAN_STA pEntry + ); + +VOID +odm_TXPowerTrackingCallbackThermalMeter92C( + IN PADAPTER Adapter + ); + +VOID +odm_TXPowerTrackingCallbackRXGainThermalMeter92D( + IN PADAPTER Adapter + ); + +VOID +odm_TXPowerTrackingCallbackThermalMeter92D( + IN PADAPTER Adapter + ); + +VOID +odm_TXPowerTrackingDirectCall92C( + IN PADAPTER Adapter + ); + +VOID +odm_TXPowerTrackingThermalMeterCheck( + IN PADAPTER Adapter + ); + +#endif + +VOID +odm_EdcaTurboCheck( + IN PDM_ODM_T pDM_Odm + ); +VOID +ODM_EdcaTurboInit( + IN PDM_ODM_T pDM_Odm +); + +#if(DM_ODM_SUPPORT_TYPE==ODM_WIN) +VOID +odm_EdcaTurboCheckMP( + IN PDM_ODM_T pDM_Odm + ); + +//check if edca turbo is disabled +BOOLEAN +odm_IsEdcaTurboDisable( + IN PDM_ODM_T pDM_Odm +); +//choose edca paramter for special IOT case +VOID +ODM_EdcaParaSelByIot( + IN PDM_ODM_T pDM_Odm, + OUT u4Byte *EDCA_BE_UL, + OUT u4Byte *EDCA_BE_DL + ); +//check if it is UL or DL +VOID +odm_EdcaChooseTrafficIdx( + IN PDM_ODM_T pDM_Odm, + IN u8Byte cur_tx_bytes, + IN u8Byte cur_rx_bytes, + IN BOOLEAN bBiasOnRx, + OUT BOOLEAN *pbIsCurRDLState + ); + +#elif (DM_ODM_SUPPORT_TYPE==ODM_CE) +VOID +odm_EdcaTurboCheckCE( + IN PDM_ODM_T pDM_Odm + ); +#else +VOID +odm_IotEngine( + IN PDM_ODM_T pDM_Odm + ); + +VOID +odm_EdcaParaInit( + IN PDM_ODM_T pDM_Odm + ); +#endif + + + +#define RxDefaultAnt1 0x65a9 +#define RxDefaultAnt2 0x569a + +VOID +odm_InitHybridAntDiv( + IN PDM_ODM_T pDM_Odm + ); + +BOOLEAN +odm_StaDefAntSel( + IN PDM_ODM_T pDM_Odm, + IN u4Byte OFDM_Ant1_Cnt, + IN u4Byte OFDM_Ant2_Cnt, + IN u4Byte CCK_Ant1_Cnt, + IN u4Byte CCK_Ant2_Cnt, + OUT u1Byte *pDefAnt + ); + +VOID +odm_SetRxIdleAnt( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Ant, + IN BOOLEAN bDualPath +); + + + +VOID +odm_HwAntDiv( + IN PDM_ODM_T pDM_Odm +); + +VOID odm_PathDiversityInit(IN PDM_ODM_T pDM_Odm); +VOID odm_PathDiversity( IN PDM_ODM_T pDM_Odm); + + + +//============================================================ +//3 Export Interface +//============================================================ + +// +// 2011/09/21 MH Add to describe different team necessary resource allocate?? +// +VOID +ODM_DMInit( + IN PDM_ODM_T pDM_Odm + ) +{ + + //2012.05.03 Luke: For all IC series + odm_CommonInfoSelfInit(pDM_Odm); + odm_CmnInfoInit_Debug(pDM_Odm); + odm_DIGInit(pDM_Odm); + Phydm_AdaptivityInit(pDM_Odm); + odm_RateAdaptiveMaskInit(pDM_Odm); + odm_RSSIMonitorInit(pDM_Odm); + +#if (RTL8192E_SUPPORT == 1) + if(pDM_Odm->SupportICType==ODM_RTL8192E) + { + odm_PrimaryCCA_Check_Init(pDM_Odm); + } +#endif + +//#if (MP_DRIVER != 1) + if ( *(pDM_Odm->mp_mode) != 1) + odm_PathDiversityInit(pDM_Odm); +//#endif + ODM_EdcaTurboInit(pDM_Odm); + + if(pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) + { + odm_TXPowerTrackingInit(pDM_Odm); +//#if (MP_DRIVER != 1) + if ( *(pDM_Odm->mp_mode) != 1) + ODM_AntDivInit(pDM_Odm); +//#endif + } + else if(pDM_Odm->SupportICType & ODM_IC_11N_SERIES) + { + odm_DynamicBBPowerSavingInit(pDM_Odm); + odm_DynamicTxPowerInit(pDM_Odm); + odm_TXPowerTrackingInit(pDM_Odm); + //ODM_EdcaTurboInit(pDM_Odm); +//#if (MP_DRIVER != 1) + if ( *(pDM_Odm->mp_mode) != 1) { + if(pDM_Odm->SupportICType==ODM_RTL8723A) + odm_SwAntDivInit(pDM_Odm); + else if(pDM_Odm->SupportICType & (ODM_RTL8192C|ODM_RTL8192D)) + { + if(pDM_Odm->AntDivType == HW_ANTDIV) + odm_InitHybridAntDiv(pDM_Odm); + else + odm_SwAntDivInit(pDM_Odm); + } + else + ODM_AntDivInit(pDM_Odm); + + if(pDM_Odm->SupportICType == ODM_RTL8723B) + odm_SwAntDetectInit(pDM_Odm); + } +//#endif + +//2010.05.30 LukeLee: For CE platform, files in IC subfolders may not be included to be compiled, +// so compile flags must be left here to prevent from compile errors +#if (RTL8188E_SUPPORT == 1) + if(pDM_Odm->SupportICType==ODM_RTL8188E) + { + odm_PrimaryCCA_Init(pDM_Odm); // Gary + ODM_RAInfo_Init_all(pDM_Odm); + } +#endif + +//2010.05.30 LukeLee: Following are not incorporated into ODM structure yet. +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + if(pDM_Odm->SupportICType&ODM_RTL8723A) + odm_PSDMonitorInit(pDM_Odm); + + if(!(pDM_Odm->SupportICType & (ODM_RTL8723A|ODM_RTL8188E))) + { + odm_RXHPInit(pDM_Odm); + } + if(pDM_Odm->SupportICType==ODM_RTL8192D) + { + odm_PathDivInit_92D(pDM_Odm); //92D Path Div Init //Neil Chen + } +#endif + } + + ODM_DynamicATCSwitch_init(pDM_Odm); + ODM_ClearTxPowerTrackingState(pDM_Odm); + +} + +// +// 2011/09/20 MH This is the entry pointer for all team to execute HW out source DM. +// You can not add any dummy function here, be care, you can only use DM structure +// to perform any new ODM_DM. +// +VOID +ODM_DMWatchdog( + IN PDM_ODM_T pDM_Odm + ) +{ + if((pDM_Odm->SupportICType == ODM_RTL8821) && (pDM_Odm->SupportInterface == ODM_ITRF_USB)) + { + if(pDM_Odm->RSSI_Min > 25) + ODM_Write1Byte(pDM_Odm, 0x4CF, 0x02); + else if(pDM_Odm->RSSI_Min < 20) + ODM_Write1Byte(pDM_Odm, 0x4CF, 0x00); + } + + + odm_CommonInfoSelfUpdate(pDM_Odm); + odm_BasicDbgMessage(pDM_Odm); + odm_FalseAlarmCounterStatistics(pDM_Odm); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): RSSI=0x%x\n",pDM_Odm->RSSI_Min)); + + odm_RSSIMonitorCheck(pDM_Odm); + +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) +//#ifdef CONFIG_PLATFORM_SPRD + //For CE Platform(SPRD or Tablet) + //8723A or 8189ES platform + //NeilChen--2012--08--24-- + //Fix Leave LPS issue + if( (adapter_to_pwrctl(pDM_Odm->Adapter)->pwr_mode != PS_MODE_ACTIVE) // in LPS mode + //&&( + // (pDM_Odm->SupportICType & (ODM_RTL8723A ) )|| + // (pDM_Odm->SupportICType & (ODM_RTL8188E) &&((pDM_Odm->SupportInterface == ODM_ITRF_SDIO)) ) + //) + ) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("----Step1: odm_DIG is in LPS mode\n")); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("---Step2: 8723AS is in LPS mode\n")); + odm_DIGbyRSSI_LPS(pDM_Odm); + { + pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + Phydm_Adaptivity(pDM_Odm, pDM_DigTable->CurIGValue); + } + + } + else +//#endif +#endif + + Phydm_CheckAdaptivity(pDM_Odm); + + { + odm_DIG(pDM_Odm); + } + + { + pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + Phydm_Adaptivity(pDM_Odm, pDM_DigTable->CurIGValue); + } + odm_CCKPacketDetectionThresh(pDM_Odm); + + if(*(pDM_Odm->pbPowerSaving)==TRUE) + return; + + + odm_RefreshRateAdaptiveMask(pDM_Odm); + odm_RefreshBasicRateMask(pDM_Odm); + odm_DynamicBBPowerSaving(pDM_Odm); + odm_EdcaTurboCheck(pDM_Odm); + odm_PathDiversity(pDM_Odm); + ODM_DynamicATCSwitch(pDM_Odm); + odm_DynamicTxPower(pDM_Odm); + +#if (RTL8192E_SUPPORT == 1) + if(pDM_Odm->SupportICType==ODM_RTL8192E) + odm_DynamicPrimaryCCA_Check(pDM_Odm); +#endif + //if(pDM_Odm->SupportICType == ODM_RTL8192E) + // return; + + +//#if (MP_DRIVER != 1) +if ( *(pDM_Odm->mp_mode) != 1) { + if(pDM_Odm->SupportICType==ODM_RTL8723A) + { + odm_SwAntDivChkAntSwitch(pDM_Odm, SWAW_STEP_PEAK); + } + else if(pDM_Odm->SupportICType & (ODM_RTL8192C|ODM_RTL8192D)) + { + if(pDM_Odm->AntDivType == HW_ANTDIV) + odm_HwAntDiv(pDM_Odm); + else + odm_SwAntDivChkAntSwitch(pDM_Odm, SWAW_STEP_PEAK); + } + else + ODM_AntDiv(pDM_Odm); +} +//#endif + + if(pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) + { + ODM_TXPowerTrackingCheck(pDM_Odm); + + odm_IQCalibrate(pDM_Odm); + } + else if(pDM_Odm->SupportICType & ODM_IC_11N_SERIES) + { + ODM_TXPowerTrackingCheck(pDM_Odm); + + //odm_EdcaTurboCheck(pDM_Odm); + + #if( DM_ODM_SUPPORT_TYPE & (ODM_WIN)) + if(!(pDM_Odm->SupportICType & (ODM_RTL8723A|ODM_RTL8188E))) + odm_RXHP(pDM_Odm); + #endif + + //2010.05.30 LukeLee: For CE platform, files in IC subfolders may not be included to be compiled, + // so compile flags must be left here to prevent from compile errors +#if (RTL8192D_SUPPORT == 1) + if(pDM_Odm->SupportICType==ODM_RTL8192D) + ODM_DynamicEarlyMode(pDM_Odm); +#endif + odm_DynamicBBPowerSaving(pDM_Odm); +#if (RTL8188E_SUPPORT == 1) + if(pDM_Odm->SupportICType==ODM_RTL8188E) + odm_DynamicPrimaryCCA(pDM_Odm); +#endif + + } + pDM_Odm->PhyDbgInfo.NumQryBeaconPkt = 0; + +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) + odm_dtc(pDM_Odm); +#endif +} + + +// +// Init /.. Fixed HW value. Only init time. +// +VOID +ODM_CmnInfoInit( + IN PDM_ODM_T pDM_Odm, + IN ODM_CMNINFO_E CmnInfo, + IN u4Byte Value + ) +{ + // + // This section is used for init value + // + switch (CmnInfo) + { + // + // Fixed ODM value. + // + case ODM_CMNINFO_ABILITY: + pDM_Odm->SupportAbility = (u4Byte)Value; + break; + + case ODM_CMNINFO_RF_TYPE: + pDM_Odm->RFType = (u1Byte)Value; + break; + + case ODM_CMNINFO_PLATFORM: + pDM_Odm->SupportPlatform = (u1Byte)Value; + break; + + case ODM_CMNINFO_INTERFACE: + pDM_Odm->SupportInterface = (u1Byte)Value; + break; + + case ODM_CMNINFO_MP_TEST_CHIP: + pDM_Odm->bIsMPChip= (u1Byte)Value; + break; + + case ODM_CMNINFO_IC_TYPE: + pDM_Odm->SupportICType = Value; + break; + + case ODM_CMNINFO_CUT_VER: + pDM_Odm->CutVersion = (u1Byte)Value; + break; + + case ODM_CMNINFO_FAB_VER: + pDM_Odm->FabVersion = (u1Byte)Value; + break; + + case ODM_CMNINFO_RFE_TYPE: + pDM_Odm->RFEType = (u1Byte)Value; + break; + + case ODM_CMNINFO_RF_ANTENNA_TYPE: + pDM_Odm->AntDivType= (u1Byte)Value; + break; + + case ODM_CMNINFO_BOARD_TYPE: + pDM_Odm->BoardType = (u1Byte)Value; + break; + + case ODM_CMNINFO_PACKAGE_TYPE: + pDM_Odm->PackageType = (u1Byte)Value; + break; + + case ODM_CMNINFO_EXT_LNA: + pDM_Odm->ExtLNA = (u1Byte)Value; + break; + + case ODM_CMNINFO_5G_EXT_LNA: + pDM_Odm->ExtLNA5G = (u1Byte)Value; + break; + + case ODM_CMNINFO_EXT_PA: + pDM_Odm->ExtPA = (u1Byte)Value; + break; + + case ODM_CMNINFO_5G_EXT_PA: + pDM_Odm->ExtPA5G = (u1Byte)Value; + break; + + case ODM_CMNINFO_GPA: + pDM_Odm->TypeGPA= (ODM_TYPE_GPA_E)Value; + break; + case ODM_CMNINFO_APA: + pDM_Odm->TypeAPA= (ODM_TYPE_APA_E)Value; + break; + case ODM_CMNINFO_GLNA: + pDM_Odm->TypeGLNA= (ODM_TYPE_GLNA_E)Value; + break; + case ODM_CMNINFO_ALNA: + pDM_Odm->TypeALNA= (ODM_TYPE_ALNA_E)Value; + break; + + case ODM_CMNINFO_EXT_TRSW: + pDM_Odm->ExtTRSW = (u1Byte)Value; + break; + case ODM_CMNINFO_PATCH_ID: + pDM_Odm->PatchID = (u1Byte)Value; + break; + case ODM_CMNINFO_BINHCT_TEST: + pDM_Odm->bInHctTest = (BOOLEAN)Value; + break; + case ODM_CMNINFO_BWIFI_TEST: + pDM_Odm->bWIFITest = (BOOLEAN)Value; + break; + + case ODM_CMNINFO_SMART_CONCURRENT: + pDM_Odm->bDualMacSmartConcurrent = (BOOLEAN )Value; + break; + + //To remove the compiler warning, must add an empty default statement to handle the other values. + default: + //do nothing + break; + + } + +} + + +VOID +ODM_CmnInfoHook( + IN PDM_ODM_T pDM_Odm, + IN ODM_CMNINFO_E CmnInfo, + IN PVOID pValue + ) +{ + // + // Hook call by reference pointer. + // + switch (CmnInfo) + { + // + // Dynamic call by reference pointer. + // + case ODM_CMNINFO_MAC_PHY_MODE: + pDM_Odm->pMacPhyMode = (u1Byte *)pValue; + break; + + case ODM_CMNINFO_TX_UNI: + pDM_Odm->pNumTxBytesUnicast = (u8Byte *)pValue; + break; + + case ODM_CMNINFO_RX_UNI: + pDM_Odm->pNumRxBytesUnicast = (u8Byte *)pValue; + break; + + case ODM_CMNINFO_WM_MODE: + pDM_Odm->pWirelessMode = (u1Byte *)pValue; + break; + + case ODM_CMNINFO_BAND: + pDM_Odm->pBandType = (u1Byte *)pValue; + break; + + case ODM_CMNINFO_SEC_CHNL_OFFSET: + pDM_Odm->pSecChOffset = (u1Byte *)pValue; + break; + + case ODM_CMNINFO_SEC_MODE: + pDM_Odm->pSecurity = (u1Byte *)pValue; + break; + + case ODM_CMNINFO_BW: + pDM_Odm->pBandWidth = (u1Byte *)pValue; + break; + + case ODM_CMNINFO_CHNL: + pDM_Odm->pChannel = (u1Byte *)pValue; + break; + + case ODM_CMNINFO_DMSP_GET_VALUE: + pDM_Odm->pbGetValueFromOtherMac = (BOOLEAN *)pValue; + break; + + case ODM_CMNINFO_BUDDY_ADAPTOR: + pDM_Odm->pBuddyAdapter = (PADAPTER *)pValue; + break; + + case ODM_CMNINFO_DMSP_IS_MASTER: + pDM_Odm->pbMasterOfDMSP = (BOOLEAN *)pValue; + break; + + case ODM_CMNINFO_SCAN: + pDM_Odm->pbScanInProcess = (BOOLEAN *)pValue; + break; + + case ODM_CMNINFO_POWER_SAVING: + pDM_Odm->pbPowerSaving = (BOOLEAN *)pValue; + break; + + case ODM_CMNINFO_ONE_PATH_CCA: + pDM_Odm->pOnePathCCA = (u1Byte *)pValue; + break; + + case ODM_CMNINFO_DRV_STOP: + pDM_Odm->pbDriverStopped = (BOOLEAN *)pValue; + break; + + case ODM_CMNINFO_PNP_IN: + pDM_Odm->pbDriverIsGoingToPnpSetPowerSleep = (BOOLEAN *)pValue; + break; + + case ODM_CMNINFO_INIT_ON: + pDM_Odm->pinit_adpt_in_progress = (BOOLEAN *)pValue; + break; + + case ODM_CMNINFO_ANT_TEST: + pDM_Odm->pAntennaTest = (u1Byte *)pValue; + break; + + case ODM_CMNINFO_NET_CLOSED: + pDM_Odm->pbNet_closed = (BOOLEAN *)pValue; + break; + + case ODM_CMNINFO_FORCED_RATE: + pDM_Odm->pForcedDataRate = (pu2Byte)pValue; + break; + + case ODM_CMNINFO_FORCED_IGI_LB: + pDM_Odm->pu1ForcedIgiLb = (u1Byte *)pValue; + break; + + case ODM_CMNINFO_MP_MODE: + pDM_Odm->mp_mode = (u1Byte *)pValue; + break; + + //case ODM_CMNINFO_RTSTA_AID: + // pDM_Odm->pAidMap = (u1Byte *)pValue; + // break; + + //case ODM_CMNINFO_BT_COEXIST: + // pDM_Odm->BTCoexist = (BOOLEAN *)pValue; + + //case ODM_CMNINFO_STA_STATUS: + //pDM_Odm->pODM_StaInfo[] = (PSTA_INFO_T)pValue; + //break; + + //case ODM_CMNINFO_PHY_STATUS: + // pDM_Odm->pPhyInfo = (ODM_PHY_INFO *)pValue; + // break; + + //case ODM_CMNINFO_MAC_STATUS: + // pDM_Odm->pMacInfo = (ODM_MAC_INFO *)pValue; + // break; + //To remove the compiler warning, must add an empty default statement to handle the other values. + default: + //do nothing + break; + + } + +} + + +VOID +ODM_CmnInfoPtrArrayHook( + IN PDM_ODM_T pDM_Odm, + IN ODM_CMNINFO_E CmnInfo, + IN u2Byte Index, + IN PVOID pValue + ) +{ + // + // Hook call by reference pointer. + // + switch (CmnInfo) + { + // + // Dynamic call by reference pointer. + // + case ODM_CMNINFO_STA_STATUS: + pDM_Odm->pODM_StaInfo[Index] = (PSTA_INFO_T)pValue; + break; + //To remove the compiler warning, must add an empty default statement to handle the other values. + default: + //do nothing + break; + } + +} + + +// +// Update Band/CHannel/.. The values are dynamic but non-per-packet. +// +VOID +ODM_CmnInfoUpdate( + IN PDM_ODM_T pDM_Odm, + IN u4Byte CmnInfo, + IN u8Byte Value + ) +{ + // + // This init variable may be changed in run time. + // + switch (CmnInfo) + { + case ODM_CMNINFO_LINK_IN_PROGRESS: + pDM_Odm->bLinkInProcess = (BOOLEAN)Value; + break; + + case ODM_CMNINFO_ABILITY: + pDM_Odm->SupportAbility = (u4Byte)Value; + break; + + case ODM_CMNINFO_RF_TYPE: + pDM_Odm->RFType = (u1Byte)Value; + break; + + case ODM_CMNINFO_WIFI_DIRECT: + pDM_Odm->bWIFI_Direct = (BOOLEAN)Value; + break; + + case ODM_CMNINFO_WIFI_DISPLAY: + pDM_Odm->bWIFI_Display = (BOOLEAN)Value; + break; + + case ODM_CMNINFO_LINK: + pDM_Odm->bLinked = (BOOLEAN)Value; + break; + + case ODM_CMNINFO_STATION_STATE: + pDM_Odm->bsta_state = (BOOLEAN)Value; + break; + + case ODM_CMNINFO_RSSI_MIN: + pDM_Odm->RSSI_Min= (u1Byte)Value; + break; + + case ODM_CMNINFO_DBG_COMP: + pDM_Odm->DebugComponents = Value; + break; + + case ODM_CMNINFO_DBG_LEVEL: + pDM_Odm->DebugLevel = (u4Byte)Value; + break; + case ODM_CMNINFO_RA_THRESHOLD_HIGH: + pDM_Odm->RateAdaptive.HighRSSIThresh = (u1Byte)Value; + break; + + case ODM_CMNINFO_RA_THRESHOLD_LOW: + pDM_Odm->RateAdaptive.LowRSSIThresh = (u1Byte)Value; + break; + // The following is for BT HS mode and BT coexist mechanism. + case ODM_CMNINFO_BT_DISABLED: + pDM_Odm->bBtDisabled = (BOOLEAN)Value; + break; + + case ODM_CMNINFO_BT_HS_CONNECT_PROCESS: + pDM_Odm->bBtConnectProcess = (BOOLEAN)Value; + break; + + case ODM_CMNINFO_BT_HS_RSSI: + pDM_Odm->btHsRssi = (u1Byte)Value; + break; + + case ODM_CMNINFO_BT_OPERATION: + pDM_Odm->bBtHsOperation = (BOOLEAN)Value; + break; + + case ODM_CMNINFO_BT_LIMITED_DIG: + pDM_Odm->bBtLimitedDig = (BOOLEAN)Value; + break; + + case ODM_CMNINFO_BT_DISABLE_EDCA: + pDM_Odm->bBtDisableEdcaTurbo = (BOOLEAN)Value; + break; + +/* + case ODM_CMNINFO_OP_MODE: + pDM_Odm->OPMode = (u1Byte)Value; + break; + + case ODM_CMNINFO_WM_MODE: + pDM_Odm->WirelessMode = (u1Byte)Value; + break; + + case ODM_CMNINFO_BAND: + pDM_Odm->BandType = (u1Byte)Value; + break; + + case ODM_CMNINFO_SEC_CHNL_OFFSET: + pDM_Odm->SecChOffset = (u1Byte)Value; + break; + + case ODM_CMNINFO_SEC_MODE: + pDM_Odm->Security = (u1Byte)Value; + break; + + case ODM_CMNINFO_BW: + pDM_Odm->BandWidth = (u1Byte)Value; + break; + + case ODM_CMNINFO_CHNL: + pDM_Odm->Channel = (u1Byte)Value; + break; +*/ + default: + //do nothing + break; + } + + +} + +VOID +odm_CommonInfoSelfInit( + IN PDM_ODM_T pDM_Odm + ) +{ + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + pDM_Odm->bCckHighPower = (BOOLEAN) ODM_GetBBReg(pDM_Odm, ODM_REG(CCK_RPT_FORMAT,pDM_Odm), ODM_BIT(CCK_RPT_FORMAT,pDM_Odm)); + pDM_Odm->RFPathRxEnable = (u1Byte) ODM_GetBBReg(pDM_Odm, ODM_REG(BB_RX_PATH,pDM_Odm), ODM_BIT(BB_RX_PATH,pDM_Odm)); +#if (DM_ODM_SUPPORT_TYPE != ODM_CE) + pDM_Odm->pbNet_closed = &pDM_Odm->BOOLEAN_temp; +#endif + + ODM_InitDebugSetting(pDM_Odm); + + if(pDM_Odm->SupportICType==ODM_RTL8723A) + { + pDM_Odm->AntDivType = SW_ANTDIV; + } + else if(pDM_Odm->SupportICType & (ODM_RTL8192C|ODM_RTL8192D)) + { + #if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) + pDM_Odm->AntDivType = HW_ANTDIV; + #elif (defined(CONFIG_SW_ANTENNA_DIVERSITY)) + pDM_Odm->AntDivType = SW_ANTDIV; + #endif + } + pDM_Odm->TxRate = 0xFF; +#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + + if(pDM_Odm->SupportICType==ODM_RTL8723B) + { + if((!pDM_Odm->DM_SWAT_Table.ANTA_ON || !pDM_Odm->DM_SWAT_Table.ANTB_ON)) + pDM_Odm->SupportAbility &= ~(ODM_BB_ANT_DIV); + } + +#elif (DM_ODM_SUPPORT_TYPE == ODM_AP) + + #if(defined(CONFIG_NOT_SUPPORT_ANTDIV)) + pDM_Odm->SupportAbility &= ~(ODM_BB_ANT_DIV); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ Disable AntDiv function] : Not Support 2.4G & 5G Antenna Diversity\n")); + #elif(defined(CONFIG_2G5G_SUPPORT_ANTDIV)) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ Enable AntDiv function] : 2.4G & 5G Support Antenna Diversity Simultaneously \n")); + pDM_FatTable->AntDiv_2G_5G = (ODM_ANTDIV_2G|ODM_ANTDIV_5G); + if(pDM_Odm->SupportICType & ODM_ANTDIV_SUPPORT) + pDM_Odm->SupportAbility |= ODM_BB_ANT_DIV; + if(*pDM_Odm->pBandType == ODM_BAND_5G ) + { + #if ( defined(CONFIG_5G_CGCS_RX_DIVERSITY) ) + pDM_Odm->AntDivType = CGCS_RX_HW_ANTDIV; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ 5G] : AntDiv Type = CGCS_RX_HW_ANTDIV\n")); + #elif( defined(CONFIG_5G_CG_TRX_DIVERSITY) ) + pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ 5G] : AntDiv Type = CG_TRX_HW_ANTDIV\n")); + #elif( defined(CONFIG_5G_CG_SMART_ANT_DIVERSITY) ) + pDM_Odm->AntDivType = CG_TRX_SMART_ANTDIV; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ 5G] : AntDiv Type = CG_SMART_ANTDIV\n")); + #endif + } + else if(*pDM_Odm->pBandType == ODM_BAND_2_4G ) + { + #if ( defined(CONFIG_2G_CGCS_RX_DIVERSITY) ) + pDM_Odm->AntDivType = CGCS_RX_HW_ANTDIV; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ 2.4G] : AntDiv Type = CGCS_RX_HW_ANTDIV\n")); + #elif( defined(CONFIG_2G_CG_TRX_DIVERSITY) ) + pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ 2.4G] : AntDiv Type = CG_TRX_HW_ANTDIV\n")); + #elif( defined(CONFIG_2G_CG_SMART_ANT_DIVERSITY) ) + pDM_Odm->AntDivType = CG_TRX_SMART_ANTDIV; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ 2.4G] : AntDiv Type = CG_SMART_ANTDIV\n")); + #endif + } + #elif(defined(CONFIG_5G_SUPPORT_ANTDIV)) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ Enable AntDiv function] : Only 5G Support Antenna Diversity\n")); + pDM_FatTable->AntDiv_2G_5G = (ODM_ANTDIV_5G); + if(*pDM_Odm->pBandType == ODM_BAND_5G ) + { + if(pDM_Odm->SupportICType & ODM_ANTDIV_5G_SUPPORT_IC) + pDM_Odm->SupportAbility |= ODM_BB_ANT_DIV; + #if ( defined(CONFIG_5G_CGCS_RX_DIVERSITY) ) + pDM_Odm->AntDivType = CGCS_RX_HW_ANTDIV; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ 5G] : AntDiv Type = CGCS_RX_HW_ANTDIV\n")); + #elif( defined(CONFIG_5G_CG_TRX_DIVERSITY) ) + pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ 5G] : AntDiv Type = CG_TRX_HW_ANTDIV\n")); + #elif( defined(CONFIG_5G_CG_SMART_ANT_DIVERSITY) ) + pDM_Odm->AntDivType = CG_TRX_SMART_ANTDIV; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ 5G] : AntDiv Type = CG_SMART_ANTDIV\n")); + #endif + } + else if(*pDM_Odm->pBandType == ODM_BAND_2_4G ) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("Not Support 2G AntDivType\n")); + pDM_Odm->SupportAbility &= ~(ODM_BB_ANT_DIV); + } + #elif(defined(CONFIG_2G_SUPPORT_ANTDIV)) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ Enable AntDiv function] : Only 2.4G Support Antenna Diversity\n")); + pDM_FatTable->AntDiv_2G_5G = (ODM_ANTDIV_2G); + if(*pDM_Odm->pBandType == ODM_BAND_2_4G ) + { + if(pDM_Odm->SupportICType & ODM_ANTDIV_2G_SUPPORT_IC) + pDM_Odm->SupportAbility |= ODM_BB_ANT_DIV; + #if ( defined(CONFIG_2G_CGCS_RX_DIVERSITY) ) + pDM_Odm->AntDivType = CGCS_RX_HW_ANTDIV; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ 2.4G] : AntDiv Type = CGCS_RX_HW_ANTDIV\n")); + #elif( defined(CONFIG_2G_CG_TRX_DIVERSITY) ) + pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ 2.4G] : AntDiv Type = CG_TRX_HW_ANTDIV\n")); + #elif( defined(CONFIG_2G_CG_SMART_ANT_DIVERSITY) ) + pDM_Odm->AntDivType = CG_TRX_SMART_ANTDIV; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ 2.4G] : AntDiv Type = CG_SMART_ANTDIV\n")); + #endif + } + else if(*pDM_Odm->pBandType == ODM_BAND_5G ) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("Not Support 5G AntDivType\n")); + pDM_Odm->SupportAbility &= ~(ODM_BB_ANT_DIV); + } + #endif +#endif //#if (DM_ODM_SUPPORT_TYPE == ODM_AP) +#endif //#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) + +} + +VOID +odm_CommonInfoSelfUpdate( + IN PDM_ODM_T pDM_Odm + ) +{ + u1Byte EntryCnt=0; + u1Byte i; + PSTA_INFO_T pEntry; + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + + PADAPTER Adapter = pDM_Odm->Adapter; + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + + pEntry = pDM_Odm->pODM_StaInfo[0]; + if(pMgntInfo->mAssoc) + { + pEntry->bUsed=TRUE; + for (i=0; i<6; i++) + pEntry->MacAddr[i] = pMgntInfo->Bssid[i]; + } + else + { + pEntry->bUsed=FALSE; + for (i=0; i<6; i++) + pEntry->MacAddr[i] = 0; + } +#endif + + + if(*(pDM_Odm->pBandWidth) == ODM_BW40M) + { + if(*(pDM_Odm->pSecChOffset) == 1) + pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) -2; + else if(*(pDM_Odm->pSecChOffset) == 2) + pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) +2; + } + else + pDM_Odm->ControlChannel = *(pDM_Odm->pChannel); + + for (i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++) + { + pEntry = pDM_Odm->pODM_StaInfo[i]; + if(IS_STA_VALID(pEntry)) + EntryCnt++; + } + if(EntryCnt == 1) + pDM_Odm->bOneEntryOnly = TRUE; + else + pDM_Odm->bOneEntryOnly = FALSE; +} + +VOID +odm_CmnInfoInit_Debug( + IN PDM_ODM_T pDM_Odm + ) +{ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoInit_Debug==>\n")); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportPlatform=%d\n",pDM_Odm->SupportPlatform) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportAbility=0x%x\n",pDM_Odm->SupportAbility) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportInterface=%d\n",pDM_Odm->SupportInterface) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportICType=0x%x\n",pDM_Odm->SupportICType) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("CutVersion=%d\n",pDM_Odm->CutVersion) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("FabVersion=%d\n",pDM_Odm->FabVersion) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("RFType=%d\n",pDM_Odm->RFType) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("BoardType=%d\n",pDM_Odm->BoardType) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtLNA=%d\n",pDM_Odm->ExtLNA) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtPA=%d\n",pDM_Odm->ExtPA) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtTRSW=%d\n",pDM_Odm->ExtTRSW) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("PatchID=%d\n",pDM_Odm->PatchID) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("bInHctTest=%d\n",pDM_Odm->bInHctTest) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFITest=%d\n",pDM_Odm->bWIFITest) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("bDualMacSmartConcurrent=%d\n",pDM_Odm->bDualMacSmartConcurrent) ); + +} + +VOID +odm_CmnInfoHook_Debug( + IN PDM_ODM_T pDM_Odm + ) +{ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoHook_Debug==>\n")); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumTxBytesUnicast=%llu\n",*(pDM_Odm->pNumTxBytesUnicast)) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumRxBytesUnicast=%llu\n",*(pDM_Odm->pNumRxBytesUnicast)) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pWirelessMode=0x%x\n",*(pDM_Odm->pWirelessMode)) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecChOffset=%d\n",*(pDM_Odm->pSecChOffset)) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecurity=%d\n",*(pDM_Odm->pSecurity)) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pBandWidth=%d\n",*(pDM_Odm->pBandWidth)) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pChannel=%d\n",*(pDM_Odm->pChannel)) ); + + if(pDM_Odm->SupportICType==ODM_RTL8192D) + { + if(pDM_Odm->pBandType) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pBandType=%d\n",*(pDM_Odm->pBandType)) ); + if(pDM_Odm->pMacPhyMode) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pMacPhyMode=%d\n",*(pDM_Odm->pMacPhyMode)) ); + if(pDM_Odm->pBuddyAdapter) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbGetValueFromOtherMac=%d\n",*(pDM_Odm->pbGetValueFromOtherMac)) ); + if(pDM_Odm->pBuddyAdapter) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pBuddyAdapter=%p\n",*(pDM_Odm->pBuddyAdapter)) ); + if(pDM_Odm->pbMasterOfDMSP) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbMasterOfDMSP=%d\n",*(pDM_Odm->pbMasterOfDMSP)) ); + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbScanInProcess=%d\n",*(pDM_Odm->pbScanInProcess)) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbPowerSaving=%d\n",*(pDM_Odm->pbPowerSaving)) ); + + if(pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("pOnePathCCA=%d\n",*(pDM_Odm->pOnePathCCA)) ); +} + +VOID +odm_CmnInfoUpdate_Debug( + IN PDM_ODM_T pDM_Odm + ) +{ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoUpdate_Debug==>\n")); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Direct=%d\n",pDM_Odm->bWIFI_Direct) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Display=%d\n",pDM_Odm->bWIFI_Display) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("bLinked=%d\n",pDM_Odm->bLinked) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("RSSI_Min=%d\n",pDM_Odm->RSSI_Min) ); +} + +VOID +odm_BasicDbgMessage +( + IN PDM_ODM_T pDM_Odm + ) +{ + PFALSE_ALARM_STATISTICS FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); + pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_BasicDbgMsg==>\n")); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("bLinked = %d, RSSI_Min = %d, CurrentIGI = 0x%x \n", + pDM_Odm->bLinked, pDM_Odm->RSSI_Min, pDM_DigTable->CurIGValue) ); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("Cnt_Cck_fail = %d, Cnt_Ofdm_fail = %d, Total False Alarm = %d\n", + FalseAlmCnt->Cnt_Cck_fail, FalseAlmCnt->Cnt_Ofdm_fail, FalseAlmCnt->Cnt_all)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("RxRate = 0x%x, RSSI_A = %d, RSSI_B = %d\n", + pDM_Odm->RxRate, pDM_Odm->RSSI_A, pDM_Odm->RSSI_B)); + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_COMMON, ODM_DBG_LOUD, ("RSSI_C = %d, RSSI_D = %d\n", pDM_Odm->RSSI_C, pDM_Odm->RSSI_D)); + +} + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +VOID +ODM_InitAllWorkItems(IN PDM_ODM_T pDM_Odm ) +{ +#if USE_WORKITEM + PADAPTER pAdapter = pDM_Odm->Adapter; + + ODM_InitializeWorkItem( pDM_Odm, + &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchWorkitem_8723B, + (RT_WORKITEM_CALL_BACK)ODM_SW_AntDiv_WorkitemCallback, + (PVOID)pAdapter, + "AntennaSwitchWorkitem"); + + ODM_InitializeWorkItem( pDM_Odm, + &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchWorkitem, + (RT_WORKITEM_CALL_BACK)odm_SwAntDivChkAntSwitchWorkitemCallback, + (PVOID)pAdapter, + "AntennaSwitchWorkitem"); + + + ODM_InitializeWorkItem( + pDM_Odm, + &(pDM_Odm->PathDivSwitchWorkitem), + (RT_WORKITEM_CALL_BACK)odm_PathDivChkAntSwitchWorkitemCallback, + (PVOID)pAdapter, + "SWAS_WorkItem"); + + ODM_InitializeWorkItem( + pDM_Odm, + &(pDM_Odm->CCKPathDiversityWorkitem), + (RT_WORKITEM_CALL_BACK)odm_CCKTXPathDiversityWorkItemCallback, + (PVOID)pAdapter, + "CCKTXPathDiversityWorkItem"); + + ODM_InitializeWorkItem( + pDM_Odm, + &(pDM_Odm->MPT_DIGWorkitem), + (RT_WORKITEM_CALL_BACK)odm_MPT_DIGWorkItemCallback, + (PVOID)pAdapter, + "MPT_DIGWorkitem"); + + ODM_InitializeWorkItem( + pDM_Odm, + &(pDM_Odm->RaRptWorkitem), + (RT_WORKITEM_CALL_BACK)ODM_UpdateInitRateWorkItemCallback, + (PVOID)pAdapter, + "RaRptWorkitem"); + +#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) +#if (RTL8188E_SUPPORT == 1) + ODM_InitializeWorkItem( + pDM_Odm, + &(pDM_Odm->FastAntTrainingWorkitem), + (RT_WORKITEM_CALL_BACK)odm_FastAntTrainingWorkItemCallback, + (PVOID)pAdapter, + "FastAntTrainingWorkitem"); +#endif +#endif + ODM_InitializeWorkItem( + pDM_Odm, + &(pDM_Odm->DM_RXHP_Table.PSDTimeWorkitem), + (RT_WORKITEM_CALL_BACK)odm_PSD_RXHPWorkitemCallback, + (PVOID)pAdapter, + "PSDRXHP_WorkItem"); +#endif +} + +VOID +ODM_FreeAllWorkItems(IN PDM_ODM_T pDM_Odm ) +{ +#if USE_WORKITEM + ODM_FreeWorkItem( &(pDM_Odm->DM_SWAT_Table.SwAntennaSwitchWorkitem_8723B)); + + ODM_FreeWorkItem( &(pDM_Odm->DM_SWAT_Table.SwAntennaSwitchWorkitem)); + + ODM_FreeWorkItem(&(pDM_Odm->PathDivSwitchWorkitem)); + + ODM_FreeWorkItem(&(pDM_Odm->CCKPathDiversityWorkitem)); + + ODM_FreeWorkItem(&(pDM_Odm->FastAntTrainingWorkitem)); + + ODM_FreeWorkItem(&(pDM_Odm->MPT_DIGWorkitem)); + + ODM_FreeWorkItem(&(pDM_Odm->RaRptWorkitem)); + + ODM_FreeWorkItem((&pDM_Odm->DM_RXHP_Table.PSDTimeWorkitem)); +#endif + +} +#endif + +/* +VOID +odm_FindMinimumRSSI( + IN PDM_ODM_T pDM_Odm + ) +{ + u4Byte i; + u1Byte RSSI_Min = 0xFF; + + for(i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++) + { +// if(pDM_Odm->pODM_StaInfo[i] != NULL) + if(IS_STA_VALID(pDM_Odm->pODM_StaInfo[i]) ) + { + if(pDM_Odm->pODM_StaInfo[i]->RSSI_Ave < RSSI_Min) + { + RSSI_Min = pDM_Odm->pODM_StaInfo[i]->RSSI_Ave; + } + } + } + + pDM_Odm->RSSI_Min = RSSI_Min; + +} + +VOID +odm_IsLinked( + IN PDM_ODM_T pDM_Odm + ) +{ + u4Byte i; + BOOLEAN Linked = FALSE; + + for(i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++) + { + if(IS_STA_VALID(pDM_Odm->pODM_StaInfo[i]) ) + { + Linked = TRUE; + break; + } + + } + + pDM_Odm->bLinked = Linked; +} +*/ + + +//3============================================================ +//3 DIG +//3============================================================ +/*----------------------------------------------------------------------------- + * Function: odm_DIGInit() + * + * Overview: Set DIG scheme init value. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * + *---------------------------------------------------------------------------*/ +VOID +ODM_ChangeDynamicInitGainThresh( + IN PDM_ODM_T pDM_Odm, + IN u4Byte DM_Type, + IN u4Byte DM_Value + ) +{ + pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + + if (DM_Type == DIG_TYPE_THRESH_HIGH) + { + pDM_DigTable->RssiHighThresh = DM_Value; + } + else if (DM_Type == DIG_TYPE_THRESH_LOW) + { + pDM_DigTable->RssiLowThresh = DM_Value; + } + else if (DM_Type == DIG_TYPE_ENABLE) + { + pDM_DigTable->Dig_Enable_Flag = TRUE; + } + else if (DM_Type == DIG_TYPE_DISABLE) + { + pDM_DigTable->Dig_Enable_Flag = FALSE; + } + else if (DM_Type == DIG_TYPE_BACKOFF) + { + if(DM_Value > 30) + DM_Value = 30; + pDM_DigTable->BackoffVal = (u1Byte)DM_Value; + } + else if(DM_Type == DIG_TYPE_RX_GAIN_MIN) + { + if(DM_Value == 0) + DM_Value = 0x1; + pDM_DigTable->rx_gain_range_min = (u1Byte)DM_Value; + } + else if(DM_Type == DIG_TYPE_RX_GAIN_MAX) + { + if(DM_Value > 0x50) + DM_Value = 0x50; + pDM_DigTable->rx_gain_range_max = (u1Byte)DM_Value; + } +} /* DM_ChangeDynamicInitGainThresh */ + +int getIGIForDiff(int value_IGI) +{ + #define ONERCCA_LOW_TH 0x30 + #define ONERCCA_LOW_DIFF 8 + + if (value_IGI < ONERCCA_LOW_TH) { + if ((ONERCCA_LOW_TH - value_IGI) < ONERCCA_LOW_DIFF) + return ONERCCA_LOW_TH; + else + return value_IGI + ONERCCA_LOW_DIFF; + } else { + return value_IGI; + } +} + +// Add by Neil Chen to enable edcca to MP Platform +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +VOID +odm_EnableEDCCA( + IN PDM_ODM_T pDM_Odm +) +{ + + // This should be moved out of OUTSRC + PADAPTER pAdapter = pDM_Odm->Adapter; + // Enable EDCCA. The value is suggested by SD3 Wilson. + + // + // Revised for ASUS 11b/g performance issues, suggested by BB Neil, 2012.04.13. + // + if((pDM_Odm->SupportICType == ODM_RTL8723A)&&(IS_WIRELESS_MODE_G(pAdapter))) + { + //PlatformEFIOWrite1Byte(Adapter, rOFDM0_ECCAThreshold, 0x00); + ODM_Write1Byte(pDM_Odm,rOFDM0_ECCAThreshold,0x00); + ODM_Write1Byte(pDM_Odm,rOFDM0_ECCAThreshold+2,0xFD); + + } + else + { + //PlatformEFIOWrite1Byte(Adapter, rOFDM0_ECCAThreshold, 0x03); + ODM_Write1Byte(pDM_Odm,rOFDM0_ECCAThreshold,0x03); + ODM_Write1Byte(pDM_Odm,rOFDM0_ECCAThreshold+2,0x00); + } + + //PlatformEFIOWrite1Byte(Adapter, rOFDM0_ECCAThreshold+2, 0x00); +} + +VOID +odm_DisableEDCCA( + IN PDM_ODM_T pDM_Odm +) +{ + // Disable EDCCA.. + ODM_Write1Byte(pDM_Odm, rOFDM0_ECCAThreshold, 0x7f); + ODM_Write1Byte(pDM_Odm, rOFDM0_ECCAThreshold+2, 0x7f); +} + +// +// Description: According to initial gain value to determine to enable or disable EDCCA. +// +// Suggested by SD3 Wilson. Added by tynli. 2011.11.25. +// +VOID +odm_DynamicEDCCA( + IN PDM_ODM_T pDM_Odm +) +{ + PADAPTER pAdapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + u1Byte RegC50, RegC58; + BOOLEAN bFwCurrentInPSMode=FALSE; + + pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_FW_PSMODE_STATUS, (pu1Byte)(&bFwCurrentInPSMode)); + + // Disable EDCCA mode while under LPS mode, added by Roger, 2012.09.14. + if(bFwCurrentInPSMode) + return; + + RegC50 = (u1Byte)ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskByte0); + RegC58 = (u1Byte)ODM_GetBBReg(pDM_Odm, rOFDM0_XBAGCCore1, bMaskByte0); + + + if((RegC50 > 0x28 && RegC58 > 0x28) || + ((pDM_Odm->SupportICType == ODM_RTL8723A && IS_WIRELESS_MODE_G(pAdapter) && RegC50>0x26)) || + (pDM_Odm->SupportICType == ODM_RTL8188E && RegC50 > 0x28)) + { + if(!pHalData->bPreEdccaEnable) + { + odm_EnableEDCCA(pDM_Odm); + pHalData->bPreEdccaEnable = TRUE; + } + + } + else if((RegC50 < 0x25 && RegC58 < 0x25) || (pDM_Odm->SupportICType == ODM_RTL8188E && RegC50 < 0x25)) + { + if(pHalData->bPreEdccaEnable) + { + odm_DisableEDCCA(pDM_Odm); + pHalData->bPreEdccaEnable = FALSE; + } + } +} + + +#endif // end MP platform support + +VOID +ODM_DynamicATCSwitch_init( + IN PDM_ODM_T pDM_Odm +) +{ + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN ) + + pDM_Odm->CrystalCap = pHalData->CrystalCap; + pDM_Odm->bATCStatus = (u1Byte)ODM_GetBBReg(pDM_Odm, rOFDM1_CFOTracking, BIT11); + pDM_Odm->CFOThreshold = CFO_Threshold_Xtal; + +#endif +} + +VOID +ODM_DynamicATCSwitch( + IN PDM_ODM_T pDM_Odm +) +{ + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + u1Byte CrystalCap,ATC_status_temp = 0; + u4Byte packet_count; + int CFO_kHz_A,CFO_kHz_B,CFO_ave = 0, Adjust_Xtal = 0; + int CFO_ave_diff; + +#if (MP_DRIVER == 1) + if ( *(pDM_Odm->mp_mode) == 1) + pDM_Odm->bLinked = TRUE; +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN ) + + if(!(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_ATC)) + return; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("=========> ODM_DynamicATCSwitch()\n")); + + //2 No link! + // + if(!pDM_Odm->bLinked) + { + //3 + //3 1.Enable ATC + if(pDM_Odm->bATCStatus == ATC_Status_Off) + { + if(pDM_Odm->SupportICType & ODM_IC_11N_SERIES) + ODM_SetBBReg(pDM_Odm, rOFDM1_CFOTracking, BIT11, ATC_Status_On); + + if(pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) + ODM_SetBBReg(pDM_Odm, rFc_area_Jaguar, BIT14, ATC_Status_On); + + pDM_Odm->bATCStatus = ATC_Status_On; + } + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): No link!!\n")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): ATCStatus = %d\n", pDM_Odm->bATCStatus)); + + //3 2.Disable CFO tracking for BT + if(!pDM_Odm->bBtDisabled) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): Disable CFO tracking for BT!!\n")); + return; + } + + //3 3.Reset Crystal Cap. + if(pDM_Odm->CrystalCap != pHalData->CrystalCap) + { + pDM_Odm->CrystalCap = pHalData->CrystalCap; + CrystalCap = pDM_Odm->CrystalCap & 0x3f; + odm_Write_CrystalCap(pDM_Odm,CrystalCap); + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): CrystalCap = 0x%x\n", pDM_Odm->CrystalCap)); + + } + else + { + + //2 Initialization + // + //3 1. Calculate CFO for path-A & path-B + CFO_kHz_A = (int)(pDM_Odm->CFO_tail[0] * 3125) / 1280; + CFO_kHz_B = (int)(pDM_Odm->CFO_tail[1] * 3125) / 1280; + packet_count = pDM_Odm->packetCount; + + //3 2.No new packet + if(packet_count == pDM_Odm->packetCount_pre) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): packet counter doesn't change\n")); + return; + } + pDM_Odm->packetCount_pre = packet_count; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): packet counter = %d\n", pDM_Odm->packetCount)); + + //3 3.Average CFO + if(pDM_Odm->RFType == ODM_1T1R) + CFO_ave = CFO_kHz_A; + else + CFO_ave = (int)(CFO_kHz_A + CFO_kHz_B) >> 1; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): CFO_kHz_A = %dkHz, CFO_kHz_B = %dkHz, CFO_ave = %dkHz\n", + CFO_kHz_A, CFO_kHz_B, CFO_ave)); + + //3 4.Avoid abnormal large CFO + CFO_ave_diff = (pDM_Odm->CFO_ave_pre >= CFO_ave)?(pDM_Odm->CFO_ave_pre - CFO_ave):(CFO_ave - pDM_Odm->CFO_ave_pre); + if(CFO_ave_diff > 20 && pDM_Odm->largeCFOHit == 0) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): first large CFO hit\n")); + pDM_Odm->largeCFOHit = 1; + return; + } + else + pDM_Odm->largeCFOHit = 0; + pDM_Odm->CFO_ave_pre = CFO_ave; + + //2 CFO tracking by adjusting Xtal cap. + // + if (pDM_Odm->bBtDisabled) + { + //3 1.Dynamic Xtal threshold + if(CFO_ave >= -pDM_Odm->CFOThreshold && CFO_ave <= pDM_Odm->CFOThreshold && pDM_Odm->bIsfreeze == 0) + { + if (pDM_Odm->CFOThreshold == CFO_Threshold_Xtal) + { + pDM_Odm->CFOThreshold = CFO_Threshold_Xtal + 10; + pDM_Odm->bIsfreeze = 1; + } + else + pDM_Odm->CFOThreshold = CFO_Threshold_Xtal; + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): Dynamic threshold = %d\n", pDM_Odm->CFOThreshold)); + + //3 2.Calculate Xtal offset + if(CFO_ave > pDM_Odm->CFOThreshold && pDM_Odm->CrystalCap < 0x3f) + Adjust_Xtal = ((CFO_ave - CFO_Threshold_Xtal) >> 2) + 1; + else if(CFO_ave < (-pDM_Odm->CFOThreshold) && pDM_Odm->CrystalCap > 0) + Adjust_Xtal = ((CFO_ave + CFO_Threshold_Xtal) >> 2) - 1; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): Crystal cap = 0x%x, Crystal cap offset = %d\n", pDM_Odm->CrystalCap, Adjust_Xtal)); + + //3 3.Adjudt Crystal Cap. + if(Adjust_Xtal != 0) + { + pDM_Odm->bIsfreeze = 0; + pDM_Odm->CrystalCap = pDM_Odm->CrystalCap + Adjust_Xtal; + + if(pDM_Odm->CrystalCap > 0x3f) + pDM_Odm->CrystalCap = 0x3f; + else if (pDM_Odm->CrystalCap < 0) + pDM_Odm->CrystalCap = 0; + + CrystalCap = pDM_Odm->CrystalCap & 0x3f; + odm_Write_CrystalCap(pDM_Odm,CrystalCap); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): New crystal cap = 0x%x \n", pDM_Odm->CrystalCap)); + } + } + else if(pDM_Odm->CrystalCap != pHalData->CrystalCap) + { + //3 Reset Xtal Cap when BT is enable + pDM_Odm->CrystalCap = pHalData->CrystalCap; + CrystalCap = pDM_Odm->CrystalCap & 0x3f; + odm_Write_CrystalCap(pDM_Odm,CrystalCap); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): Disable CFO tracking for BT!! (CrystalCap is reset)\n")); + } + else + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): Disable CFO tracking for BT!! (CrystalCap is unchanged)\n")); + if(pDM_Odm->SupportICType & ODM_IC_11N_SERIES){ + //2 Dynamic ATC switch + // + //3 1.Enable ATC when CFO is larger then 80kHz + if(CFO_ave < CFO_Threshold_ATC && CFO_ave > -CFO_Threshold_ATC) + { + if(pDM_Odm->bATCStatus == ATC_Status_On) + { + ODM_SetBBReg(pDM_Odm, rOFDM1_CFOTracking, BIT11, ATC_Status_Off); + pDM_Odm->bATCStatus = ATC_Status_Off; + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): Disable ATC!!\n")); + } + else + { + if(pDM_Odm->bATCStatus == ATC_Status_Off) + { + ODM_SetBBReg(pDM_Odm, rOFDM1_CFOTracking, BIT11, ATC_Status_On); + pDM_Odm->bATCStatus = ATC_Status_On; + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, ("ODM_DynamicATCSwitch(): Enable ATC!!\n")); + } + } + } +#endif +} + +VOID +odm_Write_CrystalCap( + IN PDM_ODM_T pDM_Odm, + IN u1Byte CrystalCap +) +{ + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + + if(IS_HARDWARE_TYPE_8192D(Adapter)) + { + PHY_SetBBReg(Adapter, 0x24, 0xF0, CrystalCap & 0x0F); + PHY_SetBBReg(Adapter, 0x28, 0xF0000000, ((CrystalCap & 0xF0) >> 4)); + } + + if(IS_HARDWARE_TYPE_8188E(Adapter)) + { + // write 0x24[16:11] = 0x24[22:17] = CrystalCap + PHY_SetBBReg(Adapter, REG_AFE_XTAL_CTRL, 0x7ff800, (CrystalCap | (CrystalCap << 6))); + } + + if(IS_HARDWARE_TYPE_8812(Adapter)) + { + // write 0x2C[30:25] = 0x2C[24:19] = CrystalCap + CrystalCap = CrystalCap & 0x3F; + PHY_SetBBReg(Adapter, REG_MAC_PHY_CTRL, 0x7FF80000, (CrystalCap | (CrystalCap << 6))); + } + + //only for B-cut + if ((IS_HARDWARE_TYPE_8723A(Adapter) && pHalData->EEPROMVersion >= 0x01) || + IS_HARDWARE_TYPE_8723B(Adapter) ||IS_HARDWARE_TYPE_8192E(Adapter) || IS_HARDWARE_TYPE_8821(Adapter)) + { + // 0x2C[23:18] = 0x2C[17:12] = CrystalCap + CrystalCap = CrystalCap & 0x3F; + PHY_SetBBReg(Adapter, REG_MAC_PHY_CTRL, 0xFFF000, (CrystalCap | (CrystalCap << 6))); + } + + if(IS_HARDWARE_TYPE_8723AE(Adapter)) + PHY_SetBBReg(Adapter, REG_LDOA15_CTRL, bMaskDWord, 0x01572505); + +} + + +VOID +ODM_Write_DIG( + IN PDM_ODM_T pDM_Odm, + IN u1Byte CurrentIGI + ) +{ + pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + + if(pDM_Odm->StopDIG) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("Stop Writing IGI\n")); + return; + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("ODM_REG(IGI_A,pDM_Odm)=0x%x, ODM_BIT(IGI,pDM_Odm)=0x%x \n", + ODM_REG(IGI_A,pDM_Odm),ODM_BIT(IGI,pDM_Odm))); + + //1 Check initial gain by upper bound + //if(!pDM_DigTable->bPSDInProgress) + { + if(CurrentIGI > pDM_DigTable->rx_gain_range_max) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_TRACE, ("CurrentIGI(0x%02x) is larger than upper bound !!\n",CurrentIGI)); + CurrentIGI = pDM_DigTable->rx_gain_range_max; + } + if(pDM_Odm->SupportAbility & ODM_BB_ADAPTIVITY && pDM_Odm->adaptivity_flag == TRUE) + { + if(CurrentIGI > pDM_Odm->Adaptivity_IGI_upper) + CurrentIGI = pDM_Odm->Adaptivity_IGI_upper; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_write_DIG(): Adaptivity case: Force upper bound to 0x%x !!!!!!\n", CurrentIGI)); + } + } + + if(pDM_DigTable->CurIGValue != CurrentIGI) + { + //1 Set IGI value + if(pDM_Odm->SupportPlatform & (ODM_WIN|ODM_CE)) + { + ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); + + if(pDM_Odm->RFType > ODM_1T1R) + ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); + + if((pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) && (pDM_Odm->RFType > ODM_2T2R)) + { + ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_C,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); + ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_D,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); + } + } + else if(pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) + { + switch(*(pDM_Odm->pOnePathCCA)) + { + case ODM_CCA_2R: + ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); + + if(pDM_Odm->RFType > ODM_1T1R) + ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); + + if((pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) && (pDM_Odm->RFType > ODM_2T2R)) + { + ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_C,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); + ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_D,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); + } + break; + case ODM_CCA_1R_A: + ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); + if(pDM_Odm->RFType != ODM_1T1R) + ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B,pDM_Odm), ODM_BIT(IGI,pDM_Odm), getIGIForDiff(CurrentIGI)); + break; + case ODM_CCA_1R_B: + ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A,pDM_Odm), ODM_BIT(IGI,pDM_Odm), getIGIForDiff(CurrentIGI)); + if(pDM_Odm->RFType != ODM_1T1R) + ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_B,pDM_Odm), ODM_BIT(IGI,pDM_Odm), CurrentIGI); + break; + } + } + pDM_DigTable->CurIGValue = CurrentIGI; + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("CurrentIGI(0x%02x). \n",CurrentIGI)); + +} + +VOID +odm_DIGbyRSSI_LPS( + IN PDM_ODM_T pDM_Odm + ) +{ + //PADAPTER pAdapter =pDM_Odm->Adapter; + //pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + PFALSE_ALARM_STATISTICS pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; + +#if 0 //and 2.3.5 coding rule + struct mlme_priv *pmlmepriv = &(pAdapter->mlmepriv); + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; +#endif + + u1Byte RSSI_Lower=DM_DIG_MIN_NIC; //0x1E or 0x1C + u1Byte CurrentIGI=pDM_Odm->RSSI_Min; + + CurrentIGI=CurrentIGI+RSSI_OFFSET_DIG; + + + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG_LPS, ODM_DBG_LOUD, ("odm_DIG()==>\n")); + + // Using FW PS mode to make IGI + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("---Neil---odm_DIG is in LPS mode\n")); + //Adjust by FA in LPS MODE + if(pFalseAlmCnt->Cnt_all> DM_DIG_FA_TH2_LPS) + CurrentIGI = CurrentIGI+2; + else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_LPS) + CurrentIGI = CurrentIGI+1; + else if(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_LPS) + CurrentIGI = CurrentIGI-1; + + + //Lower bound checking + + //RSSI Lower bound check + if((pDM_Odm->RSSI_Min-10) > DM_DIG_MIN_NIC) + RSSI_Lower =(pDM_Odm->RSSI_Min-10); + else + RSSI_Lower =DM_DIG_MIN_NIC; + + //Upper and Lower Bound checking + if(CurrentIGI > DM_DIG_MAX_NIC) + CurrentIGI=DM_DIG_MAX_NIC; + else if(CurrentIGI < RSSI_Lower) + CurrentIGI =RSSI_Lower; + + ODM_Write_DIG(pDM_Odm, CurrentIGI);//ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); + +} + +VOID +odm_DIGInit( + IN PDM_ODM_T pDM_Odm + ) +{ + pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + + //pDM_DigTable->Dig_Enable_Flag = TRUE; + //pDM_DigTable->Dig_Ext_Port_Stage = DIG_EXT_PORT_STAGE_MAX; + pDM_DigTable->CurIGValue = (u1Byte) ODM_GetBBReg(pDM_Odm, ODM_REG(IGI_A,pDM_Odm), ODM_BIT(IGI,pDM_Odm)); + //pDM_DigTable->PreIGValue = 0x0; + //pDM_DigTable->CurSTAConnectState = pDM_DigTable->PreSTAConnectState = DIG_STA_DISCONNECT; + //pDM_DigTable->CurMultiSTAConnectState = DIG_MultiSTA_DISCONNECT; + pDM_DigTable->RssiLowThresh = DM_DIG_THRESH_LOW; + pDM_DigTable->RssiHighThresh = DM_DIG_THRESH_HIGH; + pDM_DigTable->FALowThresh = DM_FALSEALARM_THRESH_LOW; + pDM_DigTable->FAHighThresh = DM_FALSEALARM_THRESH_HIGH; + if(pDM_Odm->BoardType & (ODM_BOARD_EXT_PA|ODM_BOARD_EXT_LNA)) + { + pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; + pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; + } + else + { + pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; + pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC; + } + pDM_DigTable->BackoffVal = DM_DIG_BACKOFF_DEFAULT; + pDM_DigTable->BackoffVal_range_max = DM_DIG_BACKOFF_MAX; + pDM_DigTable->BackoffVal_range_min = DM_DIG_BACKOFF_MIN; + pDM_DigTable->PreCCK_CCAThres = 0xFF; + pDM_DigTable->CurCCK_CCAThres = 0x83; + pDM_DigTable->ForbiddenIGI = DM_DIG_MIN_NIC; + pDM_DigTable->LargeFAHit = 0; + pDM_DigTable->Recover_cnt = 0; + pDM_DigTable->DIG_Dynamic_MIN_0 = DM_DIG_MIN_NIC; + pDM_DigTable->DIG_Dynamic_MIN_1 = DM_DIG_MIN_NIC; + pDM_DigTable->bMediaConnect_0 = FALSE; + pDM_DigTable->bMediaConnect_1 = FALSE; + + //To Initialize pDM_Odm->bDMInitialGainEnable == FALSE to avoid DIG error + pDM_Odm->bDMInitialGainEnable = TRUE; + + //To Initi BT30 IGI + pDM_DigTable->BT30_CurIGI=0x32; + +} + +VOID +odm_DigForBtHsMode( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + pDIG_T pDM_DigTable=&pDM_Odm->DM_DigTable; + u1Byte digForBtHs=0; + u1Byte digUpBound=0x5a; + + if(pDM_Odm->bBtConnectProcess) + { + if(pDM_Odm->SupportICType&(ODM_RTL8723A)) + digForBtHs = 0x28; + else + digForBtHs = 0x22; + } + else + { + // + // Decide DIG value by BT HS RSSI. + // + digForBtHs = pDM_Odm->btHsRssi+4; + + //DIG Bound + if(pDM_Odm->SupportICType&(ODM_RTL8723A)) + digUpBound = 0x3e; + + if(digForBtHs > digUpBound) + digForBtHs = digUpBound; + if(digForBtHs < 0x1c) + digForBtHs = 0x1c; + + // update Current IGI + pDM_DigTable->BT30_CurIGI = digForBtHs; + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DigForBtHsMode() : set DigValue=0x%x\n", digForBtHs)); +#endif +} + +VOID +odm_DIG( + IN PDM_ODM_T pDM_Odm + ) +{ + pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + PFALSE_ALARM_STATISTICS pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; + pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; + u1Byte DIG_Dynamic_MIN; + u1Byte DIG_MaxOfMin; + BOOLEAN FirstConnect, FirstDisConnect; + u1Byte dm_dig_max, dm_dig_min, offset; + u1Byte CurrentIGI = pDM_DigTable->CurIGValue; + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +// This should be moved out of OUTSRC + PADAPTER pAdapter = pDM_Odm->Adapter; +#if OS_WIN_FROM_WIN7(OS_VERSION) + if(IsAPModeExist( pAdapter) && pAdapter->bInHctTest) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: Is AP mode or In HCT Test \n")); + return; + } +#endif + + if(pDM_Odm->bBtHsOperation) + { + odm_DigForBtHsMode(pDM_Odm); + } + + if(!(pDM_Odm->SupportICType &(ODM_RTL8723A|ODM_RTL8188E))) + { + if(pRX_HP_Table->RXHP_flag == 1) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: In RXHP Operation \n")); + return; + } + } +#endif +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) +#ifdef CONFIG_SPECIAL_SETTING_FOR_FUNAI_TV + if((pDM_Odm->bLinked) && (pDM_Odm->Adapter->registrypriv.force_igi !=0)) + { + printk("pDM_Odm->RSSI_Min=%d \n",pDM_Odm->RSSI_Min); + ODM_Write_DIG(pDM_Odm,pDM_Odm->Adapter->registrypriv.force_igi); + return; + } +#endif +#endif +#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + prtl8192cd_priv priv = pDM_Odm->priv; + if (!((priv->up_time > 5) && (priv->up_time % 2)) ) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: Not In DIG Operation Period \n")); + return; + } +#endif + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG()==>\n")); + //if(!(pDM_Odm->SupportAbility & (ODM_BB_DIG|ODM_BB_FA_CNT))) + if((!(pDM_Odm->SupportAbility&ODM_BB_DIG)) ||(!(pDM_Odm->SupportAbility&ODM_BB_FA_CNT))) + { +#if 0 + if(pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) + { + if ((pDM_Odm->SupportICType == ODM_RTL8192C) && (pDM_Odm->ExtLNA == 1)) + CurrentIGI = 0x30; //pDM_DigTable->CurIGValue = 0x30; + else + CurrentIGI = 0x20; //pDM_DigTable->CurIGValue = 0x20; + ODM_Write_DIG(pDM_Odm, CurrentIGI);//ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); + } +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: SupportAbility ODM_BB_DIG or ODM_BB_FA_CNT is disabled\n")); + return; + } + + if(*(pDM_Odm->pbScanInProcess)) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: In Scan Progress \n")); + return; + } + + //add by Neil Chen to avoid PSD is processing + if(pDM_Odm->SupportICType==ODM_RTL8723A) + { + if(pDM_Odm->bDMInitialGainEnable == FALSE) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: PSD is Processing \n")); + return; + } + } + + //1 Update status +#if (RTL8192D_SUPPORT==1) + if(pDM_Odm->SupportICType == ODM_RTL8192D) + { + if(*(pDM_Odm->pMacPhyMode) == ODM_DMSP) + { + if(*(pDM_Odm->pbMasterOfDMSP)) + { + DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; + FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == FALSE); + FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == TRUE); + } + else + { + DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1; + FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1 == FALSE); + FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1 == TRUE); + } + } + else + { + if(*(pDM_Odm->pBandType) == ODM_BAND_5G) + { + DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; + FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == FALSE); + FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == TRUE); + } + else + { + DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_1; + FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1 == FALSE); + FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_1 == TRUE); + } + } + } + else +#endif + { + DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0; + FirstConnect = (pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == FALSE); + FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0 == TRUE); + } + + //1 Boundary Decision +#if (RTL8192C_SUPPORT==1) + if((pDM_Odm->SupportICType & ODM_RTL8192C) && (pDM_Odm->BoardType & (ODM_BOARD_EXT_LNA | ODM_BOARD_EXT_PA))) + { + //2 High power case + if(pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) + { + dm_dig_max = DM_DIG_MAX_AP_HP; + dm_dig_min = DM_DIG_MIN_AP_HP; + } + else + { + dm_dig_max = DM_DIG_MAX_NIC_HP; + dm_dig_min = DM_DIG_MIN_NIC_HP; + } + DIG_MaxOfMin = DM_DIG_MAX_AP_HP; + } + else +#endif + { + if(pDM_Odm->SupportPlatform & (ODM_AP|ODM_ADSL)) + { +#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) +#ifdef DFS + if (!priv->pmib->dot11DFSEntry.disable_DFS && + (OPMODE & WIFI_AP_STATE) && + (((pDM_Odm->ControlChannel >= 52) && + (pDM_Odm->ControlChannel <= 64)) || + ((pDM_Odm->ControlChannel >= 100) && + (pDM_Odm->ControlChannel <= 140)))) + dm_dig_max = 0x24; + else +#endif + if (priv->pmib->dot11RFEntry.tx2path) { + if (*(pDM_Odm->pWirelessMode) == ODM_WM_B)//(priv->pmib->dot11BssType.net_work_type == WIRELESS_11B) + dm_dig_max = 0x2A; + else + dm_dig_max = 0x32; + } + else +#endif + dm_dig_max = DM_DIG_MAX_AP; + dm_dig_min = DM_DIG_MIN_AP; + DIG_MaxOfMin = dm_dig_max; + } + else + { + if((pDM_Odm->SupportICType >= ODM_RTL8188E) && (pDM_Odm->SupportPlatform & (ODM_WIN|ODM_CE))) + dm_dig_max = 0x5A; + else + dm_dig_max = DM_DIG_MAX_NIC; + + if(pDM_Odm->SupportICType != ODM_RTL8821) + dm_dig_min = DM_DIG_MIN_NIC; + else + dm_dig_min = 0x1C; + + DIG_MaxOfMin = DM_DIG_MAX_AP; + } + } + + if(0 < *pDM_Odm->pu1ForcedIgiLb) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): force IGI lb to: %u\n", *pDM_Odm->pu1ForcedIgiLb)); + dm_dig_min = *pDM_Odm->pu1ForcedIgiLb; + dm_dig_max = (dm_dig_min <= dm_dig_max) ? (dm_dig_max) : (dm_dig_min + 1); + } + + if(pDM_Odm->bLinked) + { + if(pDM_Odm->SupportICType&(ODM_RTL8723A/*|ODM_RTL8821*/)) + { + //2 Upper Bound + if(( pDM_Odm->RSSI_Min + 10) > DM_DIG_MAX_NIC ) + pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC; + else if(( pDM_Odm->RSSI_Min + 10) < DM_DIG_MIN_NIC ) + pDM_DigTable->rx_gain_range_max = DM_DIG_MIN_NIC; + else + pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 10; + + //BT is Concurrent + + if(pDM_Odm->bBtLimitedDig) + { + if(pDM_Odm->RSSI_Min>10) + { + if((pDM_Odm->RSSI_Min - 10) > DM_DIG_MAX_NIC) + DIG_Dynamic_MIN = DM_DIG_MAX_NIC; + else if((pDM_Odm->RSSI_Min - 10) < DM_DIG_MIN_NIC) + DIG_Dynamic_MIN = DM_DIG_MIN_NIC; + else + DIG_Dynamic_MIN = pDM_Odm->RSSI_Min - 10; + } + else + DIG_Dynamic_MIN=DM_DIG_MIN_NIC; + } + else + { + if((pDM_Odm->RSSI_Min + 20) > dm_dig_max ) + pDM_DigTable->rx_gain_range_max = dm_dig_max; + else if((pDM_Odm->RSSI_Min + 20) < dm_dig_min ) + pDM_DigTable->rx_gain_range_max = dm_dig_min; + else + pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 20; + + } + } + else + { + if((pDM_Odm->SupportICType & (ODM_RTL8192E|ODM_RTL8723B|ODM_RTL8812|ODM_RTL8821)) && (pDM_Odm->bBtLimitedDig==1)){ + //2 Modify DIG upper bound for 92E, 8723B, 8821 & 8812 BT + if((pDM_Odm->RSSI_Min + 10) > dm_dig_max ) + pDM_DigTable->rx_gain_range_max = dm_dig_max; + else if((pDM_Odm->RSSI_Min + 10) < dm_dig_min ) + pDM_DigTable->rx_gain_range_max = dm_dig_min; + else + pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 10; + } + else{ + + //2 Modify DIG upper bound + //2013.03.19 Luke: Modified upper bound for Netgear rental house test + if(pDM_Odm->SupportICType != ODM_RTL8821 && pDM_Odm->SupportICType != ODM_RTL8192E) + offset = 20; + else + offset = 10; + + if((pDM_Odm->RSSI_Min + offset) > dm_dig_max ) + pDM_DigTable->rx_gain_range_max = dm_dig_max; + else if((pDM_Odm->RSSI_Min + offset) < dm_dig_min ) + pDM_DigTable->rx_gain_range_max = dm_dig_min; + else + pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + offset; + + } + + //2 Modify DIG lower bound + /* + if((pFalseAlmCnt->Cnt_all > 500)&&(DIG_Dynamic_MIN < 0x25)) + DIG_Dynamic_MIN++; + else if(((pFalseAlmCnt->Cnt_all < 500)||(pDM_Odm->RSSI_Min < 8))&&(DIG_Dynamic_MIN > dm_dig_min)) + DIG_Dynamic_MIN--; + */ + if(pDM_Odm->bOneEntryOnly) + { + if(pDM_Odm->SupportICType != ODM_RTL8723B) + offset = 0; + else + offset = 12; + + if(pDM_Odm->RSSI_Min - offset < dm_dig_min) + DIG_Dynamic_MIN = dm_dig_min; + else if (pDM_Odm->RSSI_Min - offset > DIG_MaxOfMin) + DIG_Dynamic_MIN = DIG_MaxOfMin; + else + DIG_Dynamic_MIN = pDM_Odm->RSSI_Min - offset; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() : bOneEntryOnly=TRUE, DIG_Dynamic_MIN=0x%x\n",DIG_Dynamic_MIN)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() : pDM_Odm->RSSI_Min=%d",pDM_Odm->RSSI_Min)); + } + //1 Lower Bound for 88E AntDiv +#if (defined(CONFIG_HW_ANTENNA_DIVERSITY)) + else if( (pDM_Odm->SupportICType & ODM_ANTDIV_SUPPORT) &&(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV) ) + //else if((pDM_Odm->SupportICType == ODM_RTL8188E)&&(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) + { + if((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV)||(pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) ||pDM_Odm->AntDivType == S0S1_SW_ANTDIV) + { + DIG_Dynamic_MIN = (u1Byte) pDM_DigTable->AntDiv_RSSI_max; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_DIG(): pDM_DigTable->AntDiv_RSSI_max=%d \n",pDM_DigTable->AntDiv_RSSI_max)); + } + } +#endif + else + { + DIG_Dynamic_MIN=dm_dig_min; + } + } + } + else + { + pDM_DigTable->rx_gain_range_max = dm_dig_max; + DIG_Dynamic_MIN = dm_dig_min; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() : No Link\n")); + } + + //1 Modify DIG lower bound, deal with abnorally large false alarm + if(pFalseAlmCnt->Cnt_all > 10000) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("dm_DIG(): Abnornally false alarm case. \n")); + + if(pDM_DigTable->LargeFAHit != 3) + pDM_DigTable->LargeFAHit++; + if(pDM_DigTable->ForbiddenIGI < CurrentIGI)//if(pDM_DigTable->ForbiddenIGI < pDM_DigTable->CurIGValue) + { + pDM_DigTable->ForbiddenIGI = (u1Byte)CurrentIGI;//pDM_DigTable->ForbiddenIGI = pDM_DigTable->CurIGValue; + pDM_DigTable->LargeFAHit = 1; + } + + if(pDM_DigTable->LargeFAHit >= 3) + { + if((pDM_DigTable->ForbiddenIGI+1) >pDM_DigTable->rx_gain_range_max) + pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max; + else + pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1); + pDM_DigTable->Recover_cnt = 3600; //3600=2hr + } + + } + else + { + //Recovery mechanism for IGI lower bound + if(pDM_DigTable->Recover_cnt != 0) + pDM_DigTable->Recover_cnt --; + else + { + if(pDM_DigTable->LargeFAHit < 3) + { + if((pDM_DigTable->ForbiddenIGI -1) < DIG_Dynamic_MIN) //DM_DIG_MIN) + { + pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; //DM_DIG_MIN; + pDM_DigTable->rx_gain_range_min = DIG_Dynamic_MIN; //DM_DIG_MIN; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: At Lower Bound\n")); + } + else + { + pDM_DigTable->ForbiddenIGI --; + pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: Approach Lower Bound\n")); + } + } + else + { + pDM_DigTable->LargeFAHit = 0; + } + } + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): pDM_DigTable->LargeFAHit=%d\n",pDM_DigTable->LargeFAHit)); + + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + if(IS_STA_VALID(pDM_Odm->pODM_StaInfo[0])) //STA mode is linked to AP + pDM_Odm->bsta_state = _TRUE; + #endif + + if((pDM_Odm->SupportPlatform&(ODM_WIN|ODM_CE))&&(pDM_Odm->PhyDbgInfo.NumQryBeaconPkt < 2) && (pDM_Odm->bsta_state) ) + { + pDM_DigTable->rx_gain_range_min = dm_dig_min; + } + + if(pDM_DigTable->rx_gain_range_min > pDM_DigTable->rx_gain_range_max) + pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max; + + //1 Adjust initial gain by false alarm + if(pDM_Odm->bLinked) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG AfterLink\n")); + if(FirstConnect) + { + if(pDM_Odm->RSSI_Min <= DIG_MaxOfMin) + CurrentIGI = pDM_Odm->RSSI_Min; + else + CurrentIGI = DIG_MaxOfMin; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("DIG: First Connect\n")); + + ODM_ConfigBBWithHeaderFile(pDM_Odm, CONFIG_BB_AGC_TAB_DIFF); + } + else + { + if(pDM_Odm->SupportICType == ODM_RTL8192D) + { + if(pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_92D) + CurrentIGI = CurrentIGI + 4;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; + else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_92D) + CurrentIGI = CurrentIGI + 2; //pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; + else if(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_92D) + CurrentIGI = CurrentIGI - 2;//pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; + } + else + { + //FA for Combo IC--NeilChen--2012--09--28 + if(pDM_Odm->SupportICType == ODM_RTL8723A) + { + //WLAN and BT ConCurrent + if(pDM_Odm->bBtLimitedDig) + { + if(pFalseAlmCnt->Cnt_all > 0x300) + CurrentIGI = CurrentIGI + 4; + else if (pFalseAlmCnt->Cnt_all > 0x250) + CurrentIGI = CurrentIGI + 2; + else if(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0) + CurrentIGI = CurrentIGI -2; + } + else //Not Concurrent + { + if(pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2) + CurrentIGI = CurrentIGI + 4;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; + else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1) + CurrentIGI = CurrentIGI + 2;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; + else if(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0) + CurrentIGI = CurrentIGI - 2;//pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; + } + } + else + { + if(pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2) + CurrentIGI = CurrentIGI + 4;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; + else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1) + CurrentIGI = CurrentIGI + 2;//pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; + else if(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0) + CurrentIGI = CurrentIGI - 2;//pDM_DigTable->CurIGValue =pDM_DigTable->PreIGValue-1; + + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + if(IS_STA_VALID(pDM_Odm->pODM_StaInfo[0])) //STA mode is linked to AP + pDM_Odm->bsta_state = _TRUE; + #endif + + if((pDM_Odm->SupportPlatform&(ODM_WIN|ODM_CE))&&(pDM_Odm->PhyDbgInfo.NumQryBeaconPkt < 2) + &&(pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH1) && (pDM_Odm->bsta_state)) + { + CurrentIGI = pDM_DigTable->rx_gain_range_min; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Beacon is less than 10 and FA is less than 768, IGI GOES TO 0x1E!!!!!!!!!!!!\n")); + } + /*{ + u2Byte value16; + value16 = (u2Byte) ODM_GetBBReg(pDM_Odm, 0x664, bMaskLWord); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): NumQryBeaconPkt = %d, OFDM_OK_Cnt = %d\n", + pDM_Odm->PhyDbgInfo.NumQryBeaconPkt, value16)); + }*/ + } + } + } + } + else + { + //CurrentIGI = pDM_DigTable->rx_gain_range_min;//pDM_DigTable->CurIGValue = pDM_DigTable->rx_gain_range_min + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG BeforeLink\n")); + if(FirstDisConnect) + { + CurrentIGI = pDM_DigTable->rx_gain_range_min; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): First DisConnect \n")); + } + else + { + //2012.03.30 LukeLee: enable DIG before link but with very high thresholds + if(pFalseAlmCnt->Cnt_all > 10000) + CurrentIGI = CurrentIGI + 4; + else if (pFalseAlmCnt->Cnt_all > 8000) + CurrentIGI = CurrentIGI + 2; + else if(pFalseAlmCnt->Cnt_all < 500) + CurrentIGI = CurrentIGI - 2; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): England DIG \n")); + } + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): DIG End Adjust IGI\n")); + + //1 Check initial gain by upper/lower bound + if(CurrentIGI < pDM_DigTable->rx_gain_range_min) + CurrentIGI = pDM_DigTable->rx_gain_range_min; + + if(CurrentIGI > pDM_DigTable->rx_gain_range_max) + CurrentIGI = pDM_DigTable->rx_gain_range_max; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): rx_gain_range_max=0x%x, rx_gain_range_min=0x%x\n", + pDM_DigTable->rx_gain_range_max, pDM_DigTable->rx_gain_range_min)); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): CurIGValue=0x%x, TotalFA=%d\n\n", CurrentIGI, pFalseAlmCnt->Cnt_all)); + + //1 High power RSSI threshold +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) + if((pDM_Odm->SupportICType == ODM_RTL8723A)&& (pHalData->UndecoratedSmoothedPWDB > DM_DIG_HIGH_PWR_THRESHOLD)) + { + // High power IGI lower bound + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): UndecoratedSmoothedPWDB(%#x)\n", pHalData->UndecoratedSmoothedPWDB)); + if(CurrentIGI < DM_DIG_HIGH_PWR_IGI_LOWER_BOUND) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): CurIGValue(%#x)\n", pDM_DigTable->CurIGValue)); + //pDM_DigTable->CurIGValue = DM_DIG_HIGH_PWR_IGI_LOWER_BOUND; + CurrentIGI=DM_DIG_HIGH_PWR_IGI_LOWER_BOUND; + } + } + if((pDM_Odm->SupportICType & ODM_RTL8723A) && IS_WIRELESS_MODE_G(pAdapter)) + { + if(pHalData->UndecoratedSmoothedPWDB > 0x28) + { + if(CurrentIGI < DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND) + { + //pDM_DigTable->CurIGValue = DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND; + CurrentIGI = DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND; + } + } + } +#endif + + //1 Update status +#if (RTL8192D_SUPPORT==1) + if(pDM_Odm->SupportICType == ODM_RTL8192D) + { + //sherry delete DualMacSmartConncurrent 20110517 + if(*(pDM_Odm->pMacPhyMode) == ODM_DMSP) + { + ODM_Write_DIG_DMSP(pDM_Odm, CurrentIGI);//ODM_Write_DIG_DMSP(pDM_Odm, pDM_DigTable->CurIGValue); + if(*(pDM_Odm->pbMasterOfDMSP)) + { + pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; + pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; + } + else + { + pDM_DigTable->bMediaConnect_1 = pDM_Odm->bLinked; + pDM_DigTable->DIG_Dynamic_MIN_1 = DIG_Dynamic_MIN; + } + } + else + { + ODM_Write_DIG(pDM_Odm, CurrentIGI);//ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); + if(*(pDM_Odm->pBandType) == ODM_BAND_5G) + { + pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; + pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; + } + else + { + pDM_DigTable->bMediaConnect_1 = pDM_Odm->bLinked; + pDM_DigTable->DIG_Dynamic_MIN_1 = DIG_Dynamic_MIN; + } + } + } + else +#endif + { +#if ((DM_ODM_SUPPORT_TYPE & ODM_WIN) || ((DM_ODM_SUPPORT_TYPE & ODM_CE) && (ODM_CONFIG_BT_COEXIST == 1))) + if(pDM_Odm->bBtHsOperation) + { + if(pDM_Odm->bLinked) + { + if(pDM_DigTable->BT30_CurIGI > (CurrentIGI)) + ODM_Write_DIG(pDM_Odm, CurrentIGI); + else + ODM_Write_DIG(pDM_Odm, pDM_DigTable->BT30_CurIGI); + + pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; + pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; + } + else + { + if(pDM_Odm->bLinkInProcess) + ODM_Write_DIG(pDM_Odm, 0x1c); + else if(pDM_Odm->bBtConnectProcess) + ODM_Write_DIG(pDM_Odm, 0x28); + else + ODM_Write_DIG(pDM_Odm, pDM_DigTable->BT30_CurIGI);//ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); + } + } + else // BT is not using +#endif + { + ODM_Write_DIG(pDM_Odm, CurrentIGI);//ODM_Write_DIG(pDM_Odm, pDM_DigTable->CurIGValue); + pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked; + pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN; + } + } +} + +BOOLEAN +odm_DigAbort( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +// This should be moved out of OUTSRC + PADAPTER pAdapter = pDM_Odm->Adapter; + pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; + +#if OS_WIN_FROM_WIN7(OS_VERSION) + if(IsAPModeExist( pAdapter) && pAdapter->bInHctTest) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: Is AP mode or In HCT Test \n")); + return TRUE; + } +#endif + + if(pRX_HP_Table->RXHP_flag == 1) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG() Return: In RXHP Operation \n")); + return TRUE; + } + + return FALSE; +#else // For Other team any special case for DIG? + return FALSE; +#endif + + +} + +//3============================================================ +//3 FASLE ALARM CHECK +//3============================================================ + +VOID +odm_FalseAlarmCounterStatistics( + IN PDM_ODM_T pDM_Odm + ) +{ + u4Byte ret_value; + PFALSE_ALARM_STATISTICS FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); + +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) + prtl8192cd_priv priv = pDM_Odm->priv; + if( (priv->auto_channel != 0) && (priv->auto_channel != 2) ) + return; +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + if((pDM_Odm->SupportICType == ODM_RTL8192D) && + (*(pDM_Odm->pMacPhyMode)==ODM_DMSP)&& ////modify by Guo.Mingzhi 2011-12-29 + (!(*(pDM_Odm->pbMasterOfDMSP)))) + { + odm_FalseAlarmCounterStatistics_ForSlaveOfDMSP(pDM_Odm); + return; + } +#endif + + if(!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT)) + return; + + if(pDM_Odm->SupportICType & ODM_IC_11N_SERIES) + { + + //hold ofdm counter + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 1); //hold page C counter + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 1); //hold page D counter + + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE1_11N, bMaskDWord); + FalseAlmCnt->Cnt_Fast_Fsync = (ret_value&0xffff); + FalseAlmCnt->Cnt_SB_Search_fail = ((ret_value&0xffff0000)>>16); + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE2_11N, bMaskDWord); + FalseAlmCnt->Cnt_OFDM_CCA = (ret_value&0xffff); + FalseAlmCnt->Cnt_Parity_Fail = ((ret_value&0xffff0000)>>16); + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE3_11N, bMaskDWord); + FalseAlmCnt->Cnt_Rate_Illegal = (ret_value&0xffff); + FalseAlmCnt->Cnt_Crc8_fail = ((ret_value&0xffff0000)>>16); + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE4_11N, bMaskDWord); + FalseAlmCnt->Cnt_Mcs_fail = (ret_value&0xffff); + + FalseAlmCnt->Cnt_Ofdm_fail = FalseAlmCnt->Cnt_Parity_Fail + FalseAlmCnt->Cnt_Rate_Illegal + + FalseAlmCnt->Cnt_Crc8_fail + FalseAlmCnt->Cnt_Mcs_fail + + FalseAlmCnt->Cnt_Fast_Fsync + FalseAlmCnt->Cnt_SB_Search_fail; + +#if (RTL8188E_SUPPORT==1) + if((pDM_Odm->SupportICType == ODM_RTL8188E)||(pDM_Odm->SupportICType == ODM_RTL8192E)) + { + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_SC_CNT_11N, bMaskDWord); + FalseAlmCnt->Cnt_BW_LSC = (ret_value&0xffff); + FalseAlmCnt->Cnt_BW_USC = ((ret_value&0xffff0000)>>16); + } +#endif + +#if (RTL8192D_SUPPORT==1) + if(pDM_Odm->SupportICType == ODM_RTL8192D) + { + odm_GetCCKFalseAlarm_92D(pDM_Odm); + } + else +#endif + { + //hold cck counter + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT12, 1); + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT14, 1); + + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_LSB_11N, bMaskByte0); + FalseAlmCnt->Cnt_Cck_fail = ret_value; + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_MSB_11N, bMaskByte3); + FalseAlmCnt->Cnt_Cck_fail += (ret_value& 0xff)<<8; + + ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_CCA_CNT_11N, bMaskDWord); + FalseAlmCnt->Cnt_CCK_CCA = ((ret_value&0xFF)<<8) |((ret_value&0xFF00)>>8); + } + + FalseAlmCnt->Cnt_all = ( FalseAlmCnt->Cnt_Fast_Fsync + + FalseAlmCnt->Cnt_SB_Search_fail + + FalseAlmCnt->Cnt_Parity_Fail + + FalseAlmCnt->Cnt_Rate_Illegal + + FalseAlmCnt->Cnt_Crc8_fail + + FalseAlmCnt->Cnt_Mcs_fail + + FalseAlmCnt->Cnt_Cck_fail); + + FalseAlmCnt->Cnt_CCA_all = FalseAlmCnt->Cnt_OFDM_CCA + FalseAlmCnt->Cnt_CCK_CCA; + +#if (RTL8192C_SUPPORT==1) + if(pDM_Odm->SupportICType == ODM_RTL8192C) + odm_ResetFACounter_92C(pDM_Odm); +#endif + +#if (RTL8192D_SUPPORT==1) + if(pDM_Odm->SupportICType == ODM_RTL8192D) + odm_ResetFACounter_92D(pDM_Odm); +#endif + + if(pDM_Odm->SupportICType >=ODM_RTL8723A) + { + //reset false alarm counter registers + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 1); + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 0); + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 1); + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 0); + //update ofdm counter + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 0); //update page C counter + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 0); //update page D counter + + //reset CCK CCA counter + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 0); + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 2); + //reset CCK FA counter + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 0); + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 2); + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Enter odm_FalseAlarmCounterStatistics\n")); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Fast_Fsync=%d, Cnt_SB_Search_fail=%d\n", + FalseAlmCnt->Cnt_Fast_Fsync, FalseAlmCnt->Cnt_SB_Search_fail)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Parity_Fail=%d, Cnt_Rate_Illegal=%d\n", + FalseAlmCnt->Cnt_Parity_Fail, FalseAlmCnt->Cnt_Rate_Illegal)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Crc8_fail=%d, Cnt_Mcs_fail=%d\n", + FalseAlmCnt->Cnt_Crc8_fail, FalseAlmCnt->Cnt_Mcs_fail)); + } + else if(pDM_Odm->SupportICType & ODM_IC_11AC_SERIES) + { + u4Byte CCKenable; + //read OFDM FA counter + FalseAlmCnt->Cnt_Ofdm_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_11AC, bMaskLWord); + FalseAlmCnt->Cnt_Cck_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_11AC, bMaskLWord); + + CCKenable = ODM_GetBBReg(pDM_Odm, ODM_REG_BB_RX_PATH_11AC, BIT28); + if(CCKenable)//if(*pDM_Odm->pBandType == ODM_BAND_2_4G) + FalseAlmCnt->Cnt_all = FalseAlmCnt->Cnt_Ofdm_fail + FalseAlmCnt->Cnt_Cck_fail; + else + FalseAlmCnt->Cnt_all = FalseAlmCnt->Cnt_Ofdm_fail; + + // reset OFDM FA coutner + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 1); + ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 0); + // reset CCK FA counter + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 0); + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 1); + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Cck_fail=%d\n", FalseAlmCnt->Cnt_Cck_fail)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Ofdm_fail=%d\n", FalseAlmCnt->Cnt_Ofdm_fail)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Total False Alarm=%d\n", FalseAlmCnt->Cnt_all)); +} + +//3============================================================ +//3 CCK Packet Detect Threshold +//3============================================================ + +VOID +odm_CCKPacketDetectionThresh( + IN PDM_ODM_T pDM_Odm + ) +{ + + u1Byte CurCCK_CCAThres; + PFALSE_ALARM_STATISTICS FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +//modify by Guo.Mingzhi 2011-12-29 + if (pDM_Odm->bDualMacSmartConcurrent == TRUE) +// if (pDM_Odm->bDualMacSmartConcurrent == FALSE) + return; + + if(pDM_Odm->bBtHsOperation) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_CCKPacketDetectionThresh() write 0xcd for BT HS mode!!\n")); + ODM_Write_CCK_CCA_Thres(pDM_Odm, 0xcd); + return; + } + +#endif + + if(!(pDM_Odm->SupportAbility & (ODM_BB_CCK_PD|ODM_BB_FA_CNT))) + return; + + if(pDM_Odm->ExtLNA) + return; + + if(pDM_Odm->bLinked) + { + if(pDM_Odm->RSSI_Min > 25) + CurCCK_CCAThres = 0xcd; + else if((pDM_Odm->RSSI_Min <= 25) && (pDM_Odm->RSSI_Min > 10)) + CurCCK_CCAThres = 0x83; + else + { + if(FalseAlmCnt->Cnt_Cck_fail > 1000) + CurCCK_CCAThres = 0x83; + else + CurCCK_CCAThres = 0x40; + } + } + else + { + if(FalseAlmCnt->Cnt_Cck_fail > 1000) + CurCCK_CCAThres = 0x83; + else + CurCCK_CCAThres = 0x40; + } + +#if (RTL8192D_SUPPORT==1) + if((pDM_Odm->SupportICType == ODM_RTL8192D)&&(*pDM_Odm->pBandType == ODM_BAND_2_4G)) + ODM_Write_CCK_CCA_Thres_92D(pDM_Odm, CurCCK_CCAThres); + else +#endif + ODM_Write_CCK_CCA_Thres(pDM_Odm, CurCCK_CCAThres); +} + +VOID +ODM_Write_CCK_CCA_Thres( + IN PDM_ODM_T pDM_Odm, + IN u1Byte CurCCK_CCAThres + ) +{ + pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + + if(pDM_DigTable->CurCCK_CCAThres!=CurCCK_CCAThres) //modify by Guo.Mingzhi 2012-01-03 + { + ODM_Write1Byte(pDM_Odm, ODM_REG(CCK_CCA,pDM_Odm), CurCCK_CCAThres); + } + pDM_DigTable->PreCCK_CCAThres = pDM_DigTable->CurCCK_CCAThres; + pDM_DigTable->CurCCK_CCAThres = CurCCK_CCAThres; + +} + +//3============================================================ +//3 BB Power Save +//3============================================================ +VOID +odm_DynamicBBPowerSavingInit( + IN PDM_ODM_T pDM_Odm + ) +{ + pPS_T pDM_PSTable = &pDM_Odm->DM_PSTable; + + pDM_PSTable->PreCCAState = CCA_MAX; + pDM_PSTable->CurCCAState = CCA_MAX; + pDM_PSTable->PreRFState = RF_MAX; + pDM_PSTable->CurRFState = RF_MAX; + pDM_PSTable->Rssi_val_min = 0; + pDM_PSTable->initialize = 0; +} + + +VOID +odm_DynamicBBPowerSaving( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + + if (pDM_Odm->SupportICType != ODM_RTL8723A) + return; + if(!(pDM_Odm->SupportAbility & ODM_BB_PWR_SAVE)) + return; + if(!(pDM_Odm->SupportPlatform & (ODM_WIN|ODM_CE))) + return; + + //1 2.Power Saving for 92C + if((pDM_Odm->SupportICType == ODM_RTL8192C) &&(pDM_Odm->RFType == ODM_2T2R)) + { + odm_1R_CCA(pDM_Odm); + } + + // 20100628 Joseph: Turn off BB power save for 88CE because it makesthroughput unstable. + // 20100831 Joseph: Turn ON BB power save again after modifying AGC delay from 900ns ot 600ns. + //1 3.Power Saving for 88C + else + { + ODM_RF_Saving(pDM_Odm, FALSE); + } +#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +} + +VOID +odm_1R_CCA( + IN PDM_ODM_T pDM_Odm + ) +{ + pPS_T pDM_PSTable = &pDM_Odm->DM_PSTable; + + if(pDM_Odm->RSSI_Min!= 0xFF) + { + + if(pDM_PSTable->PreCCAState == CCA_2R) + { + if(pDM_Odm->RSSI_Min >= 35) + pDM_PSTable->CurCCAState = CCA_1R; + else + pDM_PSTable->CurCCAState = CCA_2R; + + } + else{ + if(pDM_Odm->RSSI_Min <= 30) + pDM_PSTable->CurCCAState = CCA_2R; + else + pDM_PSTable->CurCCAState = CCA_1R; + } + } + else{ + pDM_PSTable->CurCCAState=CCA_MAX; + } + + if(pDM_PSTable->PreCCAState != pDM_PSTable->CurCCAState) + { + if(pDM_PSTable->CurCCAState == CCA_1R) + { + if( pDM_Odm->RFType ==ODM_2T2R ) + { + ODM_SetBBReg(pDM_Odm, 0xc04 , bMaskByte0, 0x13); + //PHY_SetBBReg(pAdapter, 0xe70, bMaskByte3, 0x20); + } + else + { + ODM_SetBBReg(pDM_Odm, 0xc04 , bMaskByte0, 0x23); + //PHY_SetBBReg(pAdapter, 0xe70, 0x7fc00000, 0x10c); // Set RegE70[30:22] = 9b'100001100 + } + } + else + { + ODM_SetBBReg(pDM_Odm, 0xc04 , bMaskByte0, 0x33); + //PHY_SetBBReg(pAdapter,0xe70, bMaskByte3, 0x63); + } + pDM_PSTable->PreCCAState = pDM_PSTable->CurCCAState; + } + //ODM_RT_TRACE(pDM_Odm, COMP_BB_POWERSAVING, DBG_LOUD, ("CCAStage = %s\n",(pDM_PSTable->CurCCAState==0)?"1RCCA":"2RCCA")); +} + +void +ODM_RF_Saving( + IN PDM_ODM_T pDM_Odm, + IN u1Byte bForceInNormal + ) +{ +#if (DM_ODM_SUPPORT_TYPE != ODM_AP) + pPS_T pDM_PSTable = &pDM_Odm->DM_PSTable; + u1Byte Rssi_Up_bound = 30 ; + u1Byte Rssi_Low_bound = 25; + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + if(pDM_Odm->PatchID == 40 ) //RT_CID_819x_FUNAI_TV + { + Rssi_Up_bound = 50 ; + Rssi_Low_bound = 45; + } + #endif + if(pDM_PSTable->initialize == 0){ + + pDM_PSTable->Reg874 = (ODM_GetBBReg(pDM_Odm, 0x874, bMaskDWord)&0x1CC000)>>14; + pDM_PSTable->RegC70 = (ODM_GetBBReg(pDM_Odm, 0xc70, bMaskDWord)&BIT3)>>3; + pDM_PSTable->Reg85C = (ODM_GetBBReg(pDM_Odm, 0x85c, bMaskDWord)&0xFF000000)>>24; + pDM_PSTable->RegA74 = (ODM_GetBBReg(pDM_Odm, 0xa74, bMaskDWord)&0xF000)>>12; + //Reg818 = PHY_QueryBBReg(pAdapter, 0x818, bMaskDWord); + pDM_PSTable->initialize = 1; + } + + if(!bForceInNormal) + { + if(pDM_Odm->RSSI_Min != 0xFF) + { + if(pDM_PSTable->PreRFState == RF_Normal) + { + if(pDM_Odm->RSSI_Min >= Rssi_Up_bound) + pDM_PSTable->CurRFState = RF_Save; + else + pDM_PSTable->CurRFState = RF_Normal; + } + else{ + if(pDM_Odm->RSSI_Min <= Rssi_Low_bound) + pDM_PSTable->CurRFState = RF_Normal; + else + pDM_PSTable->CurRFState = RF_Save; + } + } + else + pDM_PSTable->CurRFState=RF_MAX; + } + else + { + pDM_PSTable->CurRFState = RF_Normal; + } + + if(pDM_PSTable->PreRFState != pDM_PSTable->CurRFState) + { + if(pDM_PSTable->CurRFState == RF_Save) + { + // <tynli_note> 8723 RSSI report will be wrong. Set 0x874[5]=1 when enter BB power saving mode. + // Suggested by SD3 Yu-Nan. 2011.01.20. + if(pDM_Odm->SupportICType == ODM_RTL8723A) + { + ODM_SetBBReg(pDM_Odm, 0x874 , BIT5, 0x1); //Reg874[5]=1b'1 + } + ODM_SetBBReg(pDM_Odm, 0x874 , 0x1C0000, 0x2); //Reg874[20:18]=3'b010 + ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, 0); //RegC70[3]=1'b0 + ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, 0x63); //Reg85C[31:24]=0x63 + ODM_SetBBReg(pDM_Odm, 0x874, 0xC000, 0x2); //Reg874[15:14]=2'b10 + ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, 0x3); //RegA75[7:4]=0x3 + ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0); //Reg818[28]=1'b0 + ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x1); //Reg818[28]=1'b1 + //ODM_RT_TRACE(pDM_Odm, COMP_BB_POWERSAVING, DBG_LOUD, (" RF_Save")); + } + else + { + ODM_SetBBReg(pDM_Odm, 0x874 , 0x1CC000, pDM_PSTable->Reg874); + ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, pDM_PSTable->RegC70); + ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, pDM_PSTable->Reg85C); + ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, pDM_PSTable->RegA74); + ODM_SetBBReg(pDM_Odm,0x818, BIT28, 0x0); + + if(pDM_Odm->SupportICType == ODM_RTL8723A) + { + ODM_SetBBReg(pDM_Odm,0x874 , BIT5, 0x0); //Reg874[5]=1b'0 + } + //ODM_RT_TRACE(pDM_Odm, COMP_BB_POWERSAVING, DBG_LOUD, (" RF_Normal")); + } + pDM_PSTable->PreRFState =pDM_PSTable->CurRFState; + } +#endif +} + + +//3============================================================ +//3 RATR MASK +//3============================================================ +//3============================================================ +//3 Rate Adaptive +//3============================================================ + +VOID +odm_RateAdaptiveMaskInit( + IN PDM_ODM_T pDM_Odm + ) +{ + PODM_RATE_ADAPTIVE pOdmRA = &pDM_Odm->RateAdaptive; + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PMGNT_INFO pMgntInfo = &pDM_Odm->Adapter->MgntInfo; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pDM_Odm->Adapter); + + pMgntInfo->Ratr_State = DM_RATR_STA_INIT; + + if (pMgntInfo->DM_Type == DM_Type_ByDriver) + pHalData->bUseRAMask = TRUE; + else + pHalData->bUseRAMask = FALSE; + +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + pOdmRA->Type = DM_Type_ByDriver; + if (pOdmRA->Type == DM_Type_ByDriver) + pDM_Odm->bUseRAMask = _TRUE; + else + pDM_Odm->bUseRAMask = _FALSE; +#endif + + pOdmRA->RATRState = DM_RATR_STA_INIT; + pOdmRA->LdpcThres = 35; + pOdmRA->bUseLdpc = FALSE; + pOdmRA->HighRSSIThresh = 50; + pOdmRA->LowRSSIThresh = 20; +} + +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) +VOID +ODM_RateAdaptiveStateApInit( + IN PADAPTER Adapter , + IN PRT_WLAN_STA pEntry + ) +{ + pEntry->Ratr_State = DM_RATR_STA_INIT; +} +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) +u4Byte ODM_Get_Rate_Bitmap( + IN PDM_ODM_T pDM_Odm, + IN u4Byte macid, + IN u4Byte ra_mask, + IN u1Byte rssi_level) +{ + PSTA_INFO_T pEntry; + u4Byte rate_bitmap = 0; + u1Byte WirelessMode; + //u1Byte WirelessMode =*(pDM_Odm->pWirelessMode); + + + pEntry = pDM_Odm->pODM_StaInfo[macid]; + if(!IS_STA_VALID(pEntry)) + return ra_mask; + + WirelessMode = pEntry->wireless_mode; + + switch(WirelessMode) + { + case ODM_WM_B: + if(ra_mask & 0x0000000c) //11M or 5.5M enable + rate_bitmap = 0x0000000d; + else + rate_bitmap = 0x0000000f; + break; + + case (ODM_WM_G): + case (ODM_WM_A): + if(rssi_level == DM_RATR_STA_HIGH) + rate_bitmap = 0x00000f00; + else + rate_bitmap = 0x00000ff0; + break; + + case (ODM_WM_B|ODM_WM_G): + if(rssi_level == DM_RATR_STA_HIGH) + rate_bitmap = 0x00000f00; + else if(rssi_level == DM_RATR_STA_MIDDLE) + rate_bitmap = 0x00000ff0; + else + rate_bitmap = 0x00000ff5; + break; + + case (ODM_WM_B|ODM_WM_G|ODM_WM_N24G) : + case (ODM_WM_B|ODM_WM_N24G) : + case (ODM_WM_G|ODM_WM_N24G) : + case (ODM_WM_A|ODM_WM_N5G) : + { + if ( pDM_Odm->RFType == ODM_1T2R ||pDM_Odm->RFType == ODM_1T1R) + { + if(rssi_level == DM_RATR_STA_HIGH) + { + rate_bitmap = 0x000f0000; + } + else if(rssi_level == DM_RATR_STA_MIDDLE) + { + rate_bitmap = 0x000ff000; + } + else{ + if (*(pDM_Odm->pBandWidth) == ODM_BW40M) + rate_bitmap = 0x000ff015; + else + rate_bitmap = 0x000ff005; + } + } + else + { + if(rssi_level == DM_RATR_STA_HIGH) + { + rate_bitmap = 0x0f8f0000; + } + else if(rssi_level == DM_RATR_STA_MIDDLE) + { + rate_bitmap = 0x0f8ff000; + } + else + { + if (*(pDM_Odm->pBandWidth) == ODM_BW40M) + rate_bitmap = 0x0f8ff015; + else + rate_bitmap = 0x0f8ff005; + } + } + } + break; + + case (ODM_WM_AC|ODM_WM_G): + if(rssi_level == 1) + rate_bitmap = 0xfc3f0000; + else if(rssi_level == 2) + rate_bitmap = 0xfffff000; + else + rate_bitmap = 0xffffffff; + break; + + case (ODM_WM_AC|ODM_WM_A): + + if (pDM_Odm->RFType == RF_1T1R) + { + if(rssi_level == 1) // add by Gary for ac-series + rate_bitmap = 0x003f8000; + else if (rssi_level == 2) + rate_bitmap = 0x003ff000; + else + rate_bitmap = 0x003ff010; + } + else + { + if(rssi_level == 1) // add by Gary for ac-series + rate_bitmap = 0xfe3f8000; // VHT 2SS MCS3~9 + else if (rssi_level == 2) + rate_bitmap = 0xfffff000; // VHT 2SS MCS0~9 + else + rate_bitmap = 0xfffff010; // All + } + break; + + default: + if(pDM_Odm->RFType == RF_1T2R) + rate_bitmap = 0x000fffff; + else + rate_bitmap = 0x0fffffff; + break; + + } + + //printk("%s ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x \n",__FUNCTION__,rssi_level,WirelessMode,rate_bitmap); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, (" ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x \n",rssi_level,WirelessMode,rate_bitmap)); + + return (ra_mask&rate_bitmap); + +} +#endif + + +VOID +odm_RefreshBasicRateMask( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + static u1Byte Stage = 0; + u1Byte CurStage = 0; + OCTET_STRING osRateSet; + PMGNT_INFO pMgntInfo = GetDefaultMgntInfo(Adapter); + u1Byte RateSet[5] = {MGN_1M, MGN_2M, MGN_5_5M, MGN_11M, MGN_6M}; + + if(pDM_Odm->SupportICType != ODM_RTL8812 && pDM_Odm->SupportICType != ODM_RTL8821 ) + return; + + if(pDM_Odm->bLinked == FALSE) // unlink Default port information + CurStage = 0; + else if(pDM_Odm->RSSI_Min < 40) // link RSSI < 40% + CurStage = 1; + else if(pDM_Odm->RSSI_Min > 45) // link RSSI > 45% + CurStage = 3; + else + CurStage = 2; // link 25% <= RSSI <= 30% + + if(CurStage != Stage) + { + if(CurStage == 1) + { + FillOctetString(osRateSet, RateSet, 5); + FilterSupportRate(pMgntInfo->mBrates, &osRateSet, FALSE); + Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_BASIC_RATE, (pu1Byte)&osRateSet); + } + else if(CurStage == 3 && (Stage == 1 || Stage == 2)) + { + Adapter->HalFunc.SetHwRegHandler( Adapter, HW_VAR_BASIC_RATE, (pu1Byte)(&pMgntInfo->mBrates) ); + } + } + + Stage = CurStage; +#endif +} + +/*----------------------------------------------------------------------------- + * Function: odm_RefreshRateAdaptiveMask() + * + * Overview: Update rate table mask according to rssi + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 05/27/2009 hpfan Create Version 0. + * + *---------------------------------------------------------------------------*/ +VOID +odm_RefreshRateAdaptiveMask( + IN PDM_ODM_T pDM_Odm + ) +{ + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("odm_RefreshRateAdaptiveMask()---------->\n")); + if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("odm_RefreshRateAdaptiveMask(): Return cos not supported\n")); + return; + } + // + // 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate + // at the same time. In the stage2/3, we need to prive universal interface and merge all + // HW dynamic mechanism. + // + switch (pDM_Odm->SupportPlatform) + { + case ODM_WIN: + odm_RefreshRateAdaptiveMaskMP(pDM_Odm); + break; + + case ODM_CE: + odm_RefreshRateAdaptiveMaskCE(pDM_Odm); + break; + + case ODM_AP: + case ODM_ADSL: + odm_RefreshRateAdaptiveMaskAPADSL(pDM_Odm); + break; + } + +} + +VOID +odm_RefreshRateAdaptiveMaskMP( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PADAPTER pAdapter = pDM_Odm->Adapter; + PADAPTER pTargetAdapter = NULL; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMGNT_INFO pMgntInfo = GetDefaultMgntInfo(pAdapter); + PODM_RATE_ADAPTIVE pRA = &pDM_Odm->RateAdaptive; + + if(pAdapter->bDriverStopped) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("<---- odm_RefreshRateAdaptiveMask(): driver is going to unload\n")); + return; + } + + if(!pHalData->bUseRAMask) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("<---- odm_RefreshRateAdaptiveMask(): driver does not control rate adaptive mask\n")); + return; + } + + // if default port is connected, update RA table for default port (infrastructure mode only) + if(pMgntInfo->mAssoc && (!ACTING_AS_AP(pAdapter))) + { + + if(pHalData->UndecoratedSmoothedPWDB < pRA->LdpcThres) + { + pRA->bUseLdpc = TRUE; + pRA->bLowerRtsRate = TRUE; + if((pDM_Odm->SupportICType == ODM_RTL8821) && (pDM_Odm->CutVersion == ODM_CUT_A)) + MgntSet_TX_LDPC(pAdapter,0,TRUE); + //DbgPrint("RSSI=%d, bUseLdpc = TRUE\n", pHalData->UndecoratedSmoothedPWDB); + } + else if(pHalData->UndecoratedSmoothedPWDB > (pRA->LdpcThres-5)) + { + pRA->bUseLdpc = FALSE; + pRA->bLowerRtsRate = FALSE; + if((pDM_Odm->SupportICType == ODM_RTL8821) && (pDM_Odm->CutVersion == ODM_CUT_A)) + MgntSet_TX_LDPC(pAdapter,0,FALSE); + //DbgPrint("RSSI=%d, bUseLdpc = FALSE\n", pHalData->UndecoratedSmoothedPWDB); + } + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("odm_RefreshRateAdaptiveMask(): Infrasture Mode\n")); + if( ODM_RAStateCheck(pDM_Odm, pHalData->UndecoratedSmoothedPWDB, pMgntInfo->bSetTXPowerTrainingByOid, &pMgntInfo->Ratr_State) ) + { + ODM_PRINT_ADDR(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("Target AP addr : "), pMgntInfo->Bssid); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI:%d, RSSI_LEVEL:%d\n", pHalData->UndecoratedSmoothedPWDB, pMgntInfo->Ratr_State)); + pAdapter->HalFunc.UpdateHalRAMaskHandler(pAdapter, pMgntInfo->mMacId, NULL, pMgntInfo->Ratr_State); + } + } + + // + // The following part configure AP/VWifi/IBSS rate adaptive mask. + // + + if(pMgntInfo->mIbss) // Target: AP/IBSS peer. + pTargetAdapter = GetDefaultAdapter(pAdapter); + else + pTargetAdapter = GetFirstAPAdapter(pAdapter); + + // if extension port (softap) is started, updaet RA table for more than one clients associate + if(pTargetAdapter != NULL) + { + int i; + PRT_WLAN_STA pEntry; + + for(i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) + { + pEntry = AsocEntry_EnumStation(pTargetAdapter, i); + if(NULL != pEntry) + { + if(pEntry->bAssociated) + { + if(ODM_RAStateCheck(pDM_Odm, pEntry->rssi_stat.UndecoratedSmoothedPWDB, pMgntInfo->bSetTXPowerTrainingByOid, &pEntry->Ratr_State) ) + { + ODM_PRINT_ADDR(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("Target STA addr : "), pEntry->MacAddr); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI:%d, RSSI_LEVEL:%d\n", pEntry->rssi_stat.UndecoratedSmoothedPWDB, pEntry->Ratr_State)); + pAdapter->HalFunc.UpdateHalRAMaskHandler(pTargetAdapter, pEntry->AssociatedMacId, pEntry, pEntry->Ratr_State); + } + } + } + } + } + + if(pMgntInfo->bSetTXPowerTrainingByOid) + pMgntInfo->bSetTXPowerTrainingByOid = FALSE; +#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +} + + +VOID +odm_RefreshRateAdaptiveMaskCE( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) + u1Byte i; + PADAPTER pAdapter = pDM_Odm->Adapter; + PODM_RATE_ADAPTIVE pRA = &pDM_Odm->RateAdaptive; + + if(pAdapter->bDriverStopped) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE, ("<---- odm_RefreshRateAdaptiveMask(): driver is going to unload\n")); + return; + } + + if(!pDM_Odm->bUseRAMask) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("<---- odm_RefreshRateAdaptiveMask(): driver does not control rate adaptive mask\n")); + return; + } + + //printk("==> %s \n",__FUNCTION__); + + for(i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++){ + PSTA_INFO_T pstat = pDM_Odm->pODM_StaInfo[i]; + if(IS_STA_VALID(pstat) ) { + if(IS_MCAST( pstat->hwaddr)) //if(psta->mac_id ==1) + continue; + if(IS_MCAST( pstat->hwaddr)) + continue; + + #if((RTL8812A_SUPPORT==1)||(RTL8821A_SUPPORT==1)) + if((pDM_Odm->SupportICType == ODM_RTL8812)||(pDM_Odm->SupportICType == ODM_RTL8821)) + { + if(pstat->rssi_stat.UndecoratedSmoothedPWDB < pRA->LdpcThres) + { + pRA->bUseLdpc = TRUE; + pRA->bLowerRtsRate = TRUE; + if((pDM_Odm->SupportICType == ODM_RTL8821) && (pDM_Odm->CutVersion == ODM_CUT_A)) + Set_RA_LDPC_8812(pstat, TRUE); + //DbgPrint("RSSI=%d, bUseLdpc = TRUE\n", pHalData->UndecoratedSmoothedPWDB); + } + else if(pstat->rssi_stat.UndecoratedSmoothedPWDB > (pRA->LdpcThres-5)) + { + pRA->bUseLdpc = FALSE; + pRA->bLowerRtsRate = FALSE; + if((pDM_Odm->SupportICType == ODM_RTL8821) && (pDM_Odm->CutVersion == ODM_CUT_A)) + Set_RA_LDPC_8812(pstat, FALSE); + //DbgPrint("RSSI=%d, bUseLdpc = FALSE\n", pHalData->UndecoratedSmoothedPWDB); + } + } + #endif + + if( TRUE == ODM_RAStateCheck(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, FALSE , &pstat->rssi_level) ) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI:%d, RSSI_LEVEL:%d\n", pstat->rssi_stat.UndecoratedSmoothedPWDB, pstat->rssi_level)); + //printk("RSSI:%d, RSSI_LEVEL:%d\n", pstat->rssi_stat.UndecoratedSmoothedPWDB, pstat->rssi_level); + rtw_hal_update_ra_mask(pstat, pstat->rssi_level); + } + + } + } + +#endif +} + +VOID +odm_RefreshRateAdaptiveMaskAPADSL( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + struct rtl8192cd_priv *priv = pDM_Odm->priv; + struct stat_info *pstat; + + if (!priv->pmib->dot11StationConfigEntry.autoRate) + return; + + if (list_empty(&priv->asoc_list)) + return; + + list_for_each_entry(pstat, &priv->asoc_list, asoc_list) { + if(ODM_RAStateCheck(pDM_Odm, (s4Byte)pstat->rssi, FALSE, &pstat->rssi_level) ) { + ODM_PRINT_ADDR(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("Target STA addr : "), pstat->hwaddr); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI:%d, RSSI_LEVEL:%d\n", pstat->rssi, pstat->rssi_level)); + +#ifdef CONFIG_RTL_88E_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8188E) { +#ifdef TXREPORT + add_RATid(priv, pstat); +#endif + } else +#endif + { +#if defined(CONFIG_RTL_92D_SUPPORT) || defined(CONFIG_RTL_92C_SUPPORT) + add_update_RATid(priv, pstat); +#endif + } + } + } +#endif +} + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +VOID +ODM_DynamicARFBSelect( + IN PDM_ODM_T pDM_Odm, + IN u1Byte rate, + IN BOOLEAN Collision_State +) +{ + + if(pDM_Odm->SupportICType != ODM_RTL8192E) + return; + + if (rate >= DESC_RATEMCS8 && rate <= DESC_RATEMCS12){ + if (Collision_State == 1){ + if(rate == DESC_RATEMCS12){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x0); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x07060501); + } + else if(rate == DESC_RATEMCS11){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x0); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x07070605); + } + else if(rate == DESC_RATEMCS10){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x0); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x08080706); + } + else if(rate == DESC_RATEMCS9){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x0); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x08080707); + } + else{ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x0); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x09090808); + } + } + else{ // Collision_State == 0 + if(rate == DESC_RATEMCS12){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x05010000); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x09080706); + } + else if(rate == DESC_RATEMCS11){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x06050000); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x09080807); + } + else if(rate == DESC_RATEMCS10){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x07060000); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x0a090908); + } + else if(rate == DESC_RATEMCS9){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x07070000); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x0a090808); + } + else{ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x08080000); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x0b0a0909); + } + } + } + else{ // MCS13~MCS15, 1SS, G-mode + if (Collision_State == 1){ + if(rate == DESC_RATEMCS15){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x00000000); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x05040302); + } + else if(rate == DESC_RATEMCS14){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x00000000); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x06050302); + } + else if(rate == DESC_RATEMCS13){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x00000000); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x07060502); + } + else{ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x00000000); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x06050402); + } + } + else{ // Collision_State == 0 + if(rate == DESC_RATEMCS15){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x03020000); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x07060504); + } + else if(rate == DESC_RATEMCS14){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x03020000); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x08070605); + } + else if(rate == DESC_RATEMCS13){ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x05020000); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x09080706); + } + else{ + + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E, 0x04020000); + ODM_Write4Byte(pDM_Odm, REG_DARFRC_8192E+4, 0x08070605); + } + + + } + + } + +} + +#endif + +// Return Value: BOOLEAN +// - TRUE: RATRState is changed. +BOOLEAN +ODM_RAStateCheck( + IN PDM_ODM_T pDM_Odm, + IN s4Byte RSSI, + IN BOOLEAN bForceUpdate, + OUT pu1Byte pRATRState + ) +{ + PODM_RATE_ADAPTIVE pRA = &pDM_Odm->RateAdaptive; + const u1Byte GoUpGap = 5; + u1Byte HighRSSIThreshForRA = pRA->HighRSSIThresh; + u1Byte LowRSSIThreshForRA = pRA->LowRSSIThresh; + u1Byte RATRState; + + // Threshold Adjustment: + // when RSSI state trends to go up one or two levels, make sure RSSI is high enough. + // Here GoUpGap is added to solve the boundary's level alternation issue. + switch (*pRATRState) + { + case DM_RATR_STA_INIT: + case DM_RATR_STA_HIGH: + break; + + case DM_RATR_STA_MIDDLE: + HighRSSIThreshForRA += GoUpGap; + break; + + case DM_RATR_STA_LOW: + HighRSSIThreshForRA += GoUpGap; + LowRSSIThreshForRA += GoUpGap; + break; + + default: + ODM_RT_ASSERT(pDM_Odm, FALSE, ("wrong rssi level setting %d !", *pRATRState) ); + break; + } + + // Decide RATRState by RSSI. + if(RSSI > HighRSSIThreshForRA) + RATRState = DM_RATR_STA_HIGH; + else if(RSSI > LowRSSIThreshForRA) + RATRState = DM_RATR_STA_MIDDLE; + else + RATRState = DM_RATR_STA_LOW; + //printk("==>%s,RATRState:0x%02x ,RSSI:%d \n",__FUNCTION__,RATRState,RSSI); + + if( *pRATRState!=RATRState || bForceUpdate) + { + ODM_RT_TRACE( pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, ("RSSI Level %d -> %d\n", *pRATRState, RATRState) ); + *pRATRState = RATRState; + return TRUE; + } + + return FALSE; +} + + +//============================================================ + +//3============================================================ +//3 Dynamic Tx Power +//3============================================================ + +VOID +odm_DynamicTxPowerInit( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + + #if DEV_BUS_TYPE==RT_USB_INTERFACE + if(RT_GetInterfaceSelection(Adapter) == INTF_SEL1_USB_High_Power) + { + odm_DynamicTxPowerSavePowerIndex(pDM_Odm); + pMgntInfo->bDynamicTxPowerEnable = TRUE; + } + else + #else + //so 92c pci do not need dynamic tx power? vivi check it later + if(IS_HARDWARE_TYPE_8192D(Adapter)) + pMgntInfo->bDynamicTxPowerEnable = TRUE; + else + pMgntInfo->bDynamicTxPowerEnable = FALSE; + #endif + + + pHalData->LastDTPLvl = TxHighPwrLevel_Normal; + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + pdmpriv->bDynamicTxPowerEnable = _FALSE; + + #if (RTL8192C_SUPPORT==1) + #ifdef CONFIG_USB_HCI + + #ifdef CONFIG_INTEL_PROXIM + if((pHalData->BoardType == BOARD_USB_High_PA)||(Adapter->proximity.proxim_support==_TRUE)) + #else + if(pHalData->BoardType == BOARD_USB_High_PA) + #endif + + { + //odm_SavePowerIndex(Adapter); + odm_DynamicTxPowerSavePowerIndex(pDM_Odm); + pdmpriv->bDynamicTxPowerEnable = _TRUE; + } + else + #else + pdmpriv->bDynamicTxPowerEnable = _FALSE; + #endif + #endif + + pdmpriv->LastDTPLvl = TxHighPwrLevel_Normal; + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + +#endif + +} + +VOID +odm_DynamicTxPowerSavePowerIndex( + IN PDM_ODM_T pDM_Odm + ) +{ + u1Byte index; + u4Byte Power_Index_REG[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a}; + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + for(index = 0; index< 6; index++) + pHalData->PowerIndex_backup[index] = PlatformEFIORead1Byte(Adapter, Power_Index_REG[index]); +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + for(index = 0; index< 6; index++) + pdmpriv->PowerIndex_backup[index] = rtw_read8(Adapter, Power_Index_REG[index]); +#endif +} + +VOID +odm_DynamicTxPowerRestorePowerIndex( + IN PDM_ODM_T pDM_Odm + ) +{ + u1Byte index; + PADAPTER Adapter = pDM_Odm->Adapter; + +#if (DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_WIN)) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + u4Byte Power_Index_REG[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a}; +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + for(index = 0; index< 6; index++) + PlatformEFIOWrite1Byte(Adapter, Power_Index_REG[index], pHalData->PowerIndex_backup[index]); +#elif(DM_ODM_SUPPORT_TYPE == ODM_CE) + struct dm_priv *pdmpriv = &pHalData->dmpriv; + for(index = 0; index< 6; index++) + rtw_write8(Adapter, Power_Index_REG[index], pdmpriv->PowerIndex_backup[index]); +#endif +#endif +} + +VOID +odm_DynamicTxPowerWritePowerIndex( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Value) +{ + + u1Byte index; + u4Byte Power_Index_REG[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a}; + + for(index = 0; index< 6; index++) + //PlatformEFIOWrite1Byte(Adapter, Power_Index_REG[index], Value); + ODM_Write1Byte(pDM_Odm, Power_Index_REG[index], Value); + +} + + +VOID +odm_DynamicTxPower( + IN PDM_ODM_T pDM_Odm + ) +{ + // + // For AP/ADSL use prtl8192cd_priv + // For CE/NIC use PADAPTER + // + //PADAPTER pAdapter = pDM_Odm->Adapter; +// prtl8192cd_priv priv = pDM_Odm->priv; + + if (!(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_TXPWR)) + return; + + // + // 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate + // at the same time. In the stage2/3, we need to prive universal interface and merge all + // HW dynamic mechanism. + // + switch (pDM_Odm->SupportPlatform) + { + case ODM_WIN: + case ODM_CE: + odm_DynamicTxPowerNIC(pDM_Odm); + break; + case ODM_AP: + odm_DynamicTxPowerAP(pDM_Odm); + break; + + case ODM_ADSL: + //odm_DIGAP(pDM_Odm); + break; + } + + +} + + +VOID +odm_DynamicTxPowerNIC( + IN PDM_ODM_T pDM_Odm + ) +{ + if (!(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_TXPWR)) + return; + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + + if(pDM_Odm->SupportICType == ODM_RTL8192C) + { + odm_DynamicTxPower_92C(pDM_Odm); + } + else if(pDM_Odm->SupportICType == ODM_RTL8192D) + { + odm_DynamicTxPower_92D(pDM_Odm); + } + else if (pDM_Odm->SupportICType == ODM_RTL8821) + { +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) + PADAPTER Adapter = pDM_Odm->Adapter; + PMGNT_INFO pMgntInfo = GetDefaultMgntInfo(Adapter); + + if (pMgntInfo->RegRspPwr == 1) + { + if(pDM_Odm->RSSI_Min > 60) + { + ODM_SetMACReg(pDM_Odm, ODM_REG_RESP_TX_11AC, BIT20|BIT19|BIT18, 1); // Resp TXAGC offset = -3dB + + } + else if(pDM_Odm->RSSI_Min < 55) + { + ODM_SetMACReg(pDM_Odm, ODM_REG_RESP_TX_11AC, BIT20|BIT19|BIT18, 0); // Resp TXAGC offset = 0dB + } + } +#endif + } +#endif +} + +VOID +odm_DynamicTxPowerAP( + IN PDM_ODM_T pDM_Odm + + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) + prtl8192cd_priv priv = pDM_Odm->priv; + s4Byte i; + + if(!priv->pshare->rf_ft_var.tx_pwr_ctrl) + return; + +#ifdef HIGH_POWER_EXT_PA + if(pDM_Odm->ExtPA) + tx_power_control(priv); +#endif + + /* + * Check if station is near by to use lower tx power + */ + + if ((priv->up_time % 3) == 0 ) { + for(i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++){ + PSTA_INFO_T pstat = pDM_Odm->pODM_StaInfo[i]; + if(IS_STA_VALID(pstat) ) { + if ((pstat->hp_level == 0) && (pstat->rssi > TX_POWER_NEAR_FIELD_THRESH_AP+4)) + pstat->hp_level = 1; + else if ((pstat->hp_level == 1) && (pstat->rssi < TX_POWER_NEAR_FIELD_THRESH_AP)) + pstat->hp_level = 0; + } + } + } + +#endif +} + + +VOID +odm_DynamicTxPower_92C( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + s4Byte UndecoratedSmoothedPWDB; + + // 2012/01/12 MH According to Luke's suggestion, only high power will support the feature. + if (pDM_Odm->ExtPA == FALSE) + return; + + // STA not connected and AP not connected + if((!pMgntInfo->bMediaConnect) && + (pHalData->EntryMinUndecoratedSmoothedPWDB == 0)) + { + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("Not connected to any \n")); + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + + //the LastDTPlvl should reset when disconnect, + //otherwise the tx power level wouldn't change when disconnect and connect again. + // Maddest 20091220. + pHalData->LastDTPLvl=TxHighPwrLevel_Normal; + return; + } + +#if (INTEL_PROXIMITY_SUPPORT == 1) + // Intel set fixed tx power + if(pMgntInfo->IntelProximityModeInfo.PowerOutput > 0) + { + switch(pMgntInfo->IntelProximityModeInfo.PowerOutput){ + case 1: + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_100; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_100\n")); + break; + case 2: + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_70; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_70\n")); + break; + case 3: + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_50; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_50\n")); + break; + case 4: + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_35; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_35\n")); + break; + case 5: + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_15; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_15\n")); + break; + default: + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_100; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_100\n")); + break; + } + } + else +#endif + { + if( (pMgntInfo->bDynamicTxPowerEnable != TRUE) || + (pHalData->DMFlag & HAL_DM_HIPWR_DISABLE) || + pMgntInfo->IOTAction & HT_IOT_ACT_DISABLE_HIGH_POWER) + { + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + } + else + { + if(pMgntInfo->bMediaConnect) // Default port + { + if(ACTING_AS_AP(Adapter) || ACTING_AS_IBSS(Adapter)) + { + UndecoratedSmoothedPWDB = pHalData->EntryMinUndecoratedSmoothedPWDB; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Client PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); + } + else + { + UndecoratedSmoothedPWDB = pHalData->UndecoratedSmoothedPWDB; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("STA Default Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); + } + } + else // associated entry pwdb + { + UndecoratedSmoothedPWDB = pHalData->EntryMinUndecoratedSmoothedPWDB; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Ext Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); + } + + if(UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL2) + { + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Level2; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x0)\n")); + } + else if((UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL2-3)) && + (UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL1) ) + { + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x10)\n")); + } + else if(UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL1-5)) + { + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Normal\n")); + } + } + } + if( pHalData->DynamicTxHighPowerLvl != pHalData->LastDTPLvl ) + { + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("PHY_SetTxPowerLevel8192C() Channel = %d \n" , pHalData->CurrentChannel)); + PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); + if( (pHalData->DynamicTxHighPowerLvl == TxHighPwrLevel_Normal) && + (pHalData->LastDTPLvl == TxHighPwrLevel_Level1 || pHalData->LastDTPLvl == TxHighPwrLevel_Level2)) //TxHighPwrLevel_Normal + odm_DynamicTxPowerRestorePowerIndex(pDM_Odm); + else if(pHalData->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) + odm_DynamicTxPowerWritePowerIndex(pDM_Odm, 0x14); + else if(pHalData->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) + odm_DynamicTxPowerWritePowerIndex(pDM_Odm, 0x10); + } + pHalData->LastDTPLvl = pHalData->DynamicTxHighPowerLvl; + + +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + + #if (RTL8192C_SUPPORT==1) + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; + int UndecoratedSmoothedPWDB; + + if(!pdmpriv->bDynamicTxPowerEnable) + return; + +#ifdef CONFIG_INTEL_PROXIM + if(Adapter->proximity.proxim_on== _TRUE){ + struct proximity_priv *prox_priv=Adapter->proximity.proximity_priv; + // Intel set fixed tx power + printk("\n %s Adapter->proximity.proxim_on=%d prox_priv->proxim_modeinfo->power_output=%d \n",__FUNCTION__,Adapter->proximity.proxim_on,prox_priv->proxim_modeinfo->power_output); + if(prox_priv!=NULL){ + if(prox_priv->proxim_modeinfo->power_output> 0) + { + switch(prox_priv->proxim_modeinfo->power_output) + { + case 1: + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_100; + printk("TxHighPwrLevel_100\n"); + break; + case 2: + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_70; + printk("TxHighPwrLevel_70\n"); + break; + case 3: + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_50; + printk("TxHighPwrLevel_50\n"); + break; + case 4: + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_35; + printk("TxHighPwrLevel_35\n"); + break; + case 5: + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_15; + printk("TxHighPwrLevel_15\n"); + break; + default: + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_100; + printk("TxHighPwrLevel_100\n"); + break; + } + } + } + } + else +#endif + { + // STA not connected and AP not connected + if((check_fwstate(pmlmepriv, _FW_LINKED) != _TRUE) && + (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0)) + { + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("Not connected to any \n")); + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + + //the LastDTPlvl should reset when disconnect, + //otherwise the tx power level wouldn't change when disconnect and connect again. + // Maddest 20091220. + pdmpriv->LastDTPLvl=TxHighPwrLevel_Normal; + return; + } + + if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) // Default port + { + #if 0 + //todo: AP Mode + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)) + { + UndecoratedSmoothedPWDB = pdmpriv->EntryMinUndecoratedSmoothedPWDB; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Client PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); + } + else + { + UndecoratedSmoothedPWDB = pdmpriv->UndecoratedSmoothedPWDB; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("STA Default Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); + } + #else + UndecoratedSmoothedPWDB = pdmpriv->EntryMinUndecoratedSmoothedPWDB; + #endif + } + else // associated entry pwdb + { + UndecoratedSmoothedPWDB = pdmpriv->EntryMinUndecoratedSmoothedPWDB; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Ext Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); + } + + if(UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL2) + { + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Level2; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x0)\n")); + } + else if((UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL2-3)) && + (UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL1) ) + { + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x10)\n")); + } + else if(UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL1-5)) + { + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Normal\n")); + } + } + if( (pdmpriv->DynamicTxHighPowerLvl != pdmpriv->LastDTPLvl) ) + { + PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); + if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Normal) // HP1 -> Normal or HP2 -> Normal + odm_DynamicTxPowerRestorePowerIndex(pDM_Odm); + else if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) + odm_DynamicTxPowerWritePowerIndex(pDM_Odm, 0x14); + else if(pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) + odm_DynamicTxPowerWritePowerIndex(pDM_Odm, 0x10); + } + pdmpriv->LastDTPLvl = pdmpriv->DynamicTxHighPowerLvl; + #endif +#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +} + + +VOID +odm_DynamicTxPower_92D( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + s4Byte UndecoratedSmoothedPWDB; + + PADAPTER BuddyAdapter = Adapter->BuddyAdapter; + BOOLEAN bGetValueFromBuddyAdapter = dm_DualMacGetParameterFromBuddyAdapter(Adapter); + u1Byte HighPowerLvlBackForMac0 = TxHighPwrLevel_Level1; + + // 2012/01/12 MH According to Luke's suggestion, only high power will support the feature. + if (pDM_Odm->ExtPA == FALSE) + return; + + // If dynamic high power is disabled. + if( (pMgntInfo->bDynamicTxPowerEnable != TRUE) || + (pHalData->DMFlag & HAL_DM_HIPWR_DISABLE) || + pMgntInfo->IOTAction & HT_IOT_ACT_DISABLE_HIGH_POWER) + { + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + return; + } + + // STA not connected and AP not connected + if((!pMgntInfo->bMediaConnect) && + (pHalData->EntryMinUndecoratedSmoothedPWDB == 0)) + { + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("Not connected to any \n")); + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + + //the LastDTPlvl should reset when disconnect, + //otherwise the tx power level wouldn't change when disconnect and connect again. + // Maddest 20091220. + pHalData->LastDTPLvl=TxHighPwrLevel_Normal; + return; + } + + if(pMgntInfo->bMediaConnect) // Default port + { + if(ACTING_AS_AP(Adapter) || pMgntInfo->mIbss) + { + UndecoratedSmoothedPWDB = pHalData->EntryMinUndecoratedSmoothedPWDB; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Client PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); + } + else + { + UndecoratedSmoothedPWDB = pHalData->UndecoratedSmoothedPWDB; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("STA Default Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); + } + } + else // associated entry pwdb + { + UndecoratedSmoothedPWDB = pHalData->EntryMinUndecoratedSmoothedPWDB; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Ext Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); + } + + if(IS_HARDWARE_TYPE_8192D(Adapter) && GET_HAL_DATA(Adapter)->CurrentBandType == 1){ + if(UndecoratedSmoothedPWDB >= 0x33) + { + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Level2; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("5G:TxHighPwrLevel_Level2 (TxPwr=0x0)\n")); + } + else if((UndecoratedSmoothedPWDB <0x33) && + (UndecoratedSmoothedPWDB >= 0x2b) ) + { + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("5G:TxHighPwrLevel_Level1 (TxPwr=0x10)\n")); + } + else if(UndecoratedSmoothedPWDB < 0x2b) + { + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("5G:TxHighPwrLevel_Normal\n")); + } + + } + else + + { + if(UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL2) + { + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x0)\n")); + } + else if((UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL2-3)) && + (UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL1) ) + { + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x10)\n")); + } + else if(UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL1-5)) + { + pHalData->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Normal\n")); + } + + } + +//sherry delete flag 20110517 + if(bGetValueFromBuddyAdapter) + { + ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() mac 0 for mac 1 \n")); + if(Adapter->DualMacDMSPControl.bChangeTxHighPowerLvlForAnotherMacOfDMSP) + { + ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() change value \n")); + HighPowerLvlBackForMac0 = pHalData->DynamicTxHighPowerLvl; + pHalData->DynamicTxHighPowerLvl = Adapter->DualMacDMSPControl.CurTxHighLvlForAnotherMacOfDMSP; + PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); + pHalData->DynamicTxHighPowerLvl = HighPowerLvlBackForMac0; + Adapter->DualMacDMSPControl.bChangeTxHighPowerLvlForAnotherMacOfDMSP = FALSE; + } + } + + if( (pHalData->DynamicTxHighPowerLvl != pHalData->LastDTPLvl) ) + { + ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("PHY_SetTxPowerLevel8192S() Channel = %d \n" , pHalData->CurrentChannel)); + if(Adapter->DualMacSmartConcurrent == TRUE) + { + if(BuddyAdapter == NULL) + { + ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() BuddyAdapter == NULL case \n")); + if(!Adapter->bSlaveOfDMSP) + { + PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); + } + } + else + { + if(pHalData->MacPhyMode92D == DUALMAC_SINGLEPHY) + { + ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() BuddyAdapter DMSP \n")); + if(Adapter->bSlaveOfDMSP) + { + ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() bslave case \n")); + BuddyAdapter->DualMacDMSPControl.bChangeTxHighPowerLvlForAnotherMacOfDMSP = TRUE; + BuddyAdapter->DualMacDMSPControl.CurTxHighLvlForAnotherMacOfDMSP = pHalData->DynamicTxHighPowerLvl; + } + else + { + ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() master case \n")); + if(!bGetValueFromBuddyAdapter) + { + ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() mac 0 for mac 0 \n")); + PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); + } + } + } + else + { + ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() BuddyAdapter DMDP\n")); + PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); + } + } + } + else + { + PHY_SetTxPowerLevel8192C(Adapter, pHalData->CurrentChannel); + } + + } + pHalData->LastDTPLvl = pHalData->DynamicTxHighPowerLvl; +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) +#if (RTL8192D_SUPPORT==1) + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + + struct dm_priv *pdmpriv = &pHalData->dmpriv; + DM_ODM_T *podmpriv = &pHalData->odmpriv; + int UndecoratedSmoothedPWDB; + #if (RTL8192D_EASY_SMART_CONCURRENT == 1) + PADAPTER BuddyAdapter = Adapter->BuddyAdapter; + BOOLEAN bGetValueFromBuddyAdapter = DualMacGetParameterFromBuddyAdapter(Adapter); + u8 HighPowerLvlBackForMac0 = TxHighPwrLevel_Level1; + #endif + + // If dynamic high power is disabled. + if( (pdmpriv->bDynamicTxPowerEnable != _TRUE) || + (!(podmpriv->SupportAbility& ODM_BB_DYNAMIC_TXPWR)) ) + { + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + return; + } + + // STA not connected and AP not connected + if((check_fwstate(pmlmepriv, _FW_LINKED) != _TRUE) && + (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0)) + { + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("Not connected to any \n")); + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + //the LastDTPlvl should reset when disconnect, + //otherwise the tx power level wouldn't change when disconnect and connect again. + // Maddest 20091220. + pdmpriv->LastDTPLvl=TxHighPwrLevel_Normal; + return; + } + + if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) // Default port + { + #if 0 + //todo: AP Mode + if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) || + (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)) + { + UndecoratedSmoothedPWDB = pdmpriv->EntryMinUndecoratedSmoothedPWDB; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Client PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); + } + else + { + UndecoratedSmoothedPWDB = pdmpriv->UndecoratedSmoothedPWDB; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("STA Default Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); + } + #else + UndecoratedSmoothedPWDB = pdmpriv->EntryMinUndecoratedSmoothedPWDB; + #endif + } + else // associated entry pwdb + { + UndecoratedSmoothedPWDB = pdmpriv->EntryMinUndecoratedSmoothedPWDB; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("AP Ext Port PWDB = 0x%x \n", UndecoratedSmoothedPWDB)); + } +#if TX_POWER_FOR_5G_BAND == 1 + if(pHalData->CurrentBandType92D == BAND_ON_5G){ + if(UndecoratedSmoothedPWDB >= 0x33) + { + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Level2; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("5G:TxHighPwrLevel_Level2 (TxPwr=0x0)\n")); + } + else if((UndecoratedSmoothedPWDB <0x33) && + (UndecoratedSmoothedPWDB >= 0x2b) ) + { + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("5G:TxHighPwrLevel_Level1 (TxPwr=0x10)\n")); + } + else if(UndecoratedSmoothedPWDB < 0x2b) + { + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("5G:TxHighPwrLevel_Normal\n")); + } + } + else +#endif + { + if(UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL2) + { + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Level2; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x0)\n")); + } + else if((UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL2-3)) && + (UndecoratedSmoothedPWDB >= TX_POWER_NEAR_FIELD_THRESH_LVL1) ) + { + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Level1; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Level1 (TxPwr=0x10)\n")); + } + else if(UndecoratedSmoothedPWDB < (TX_POWER_NEAR_FIELD_THRESH_LVL1-5)) + { + pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal; + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("TxHighPwrLevel_Normal\n")); + } + } +#if (RTL8192D_EASY_SMART_CONCURRENT == 1) + if(bGetValueFromBuddyAdapter) + { + //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() mac 0 for mac 1 \n")); + if(Adapter->DualMacDMSPControl.bChangeTxHighPowerLvlForAnotherMacOfDMSP) + { + //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() change value \n")); + HighPowerLvlBackForMac0 = pHalData->DynamicTxHighPowerLvl; + pHalData->DynamicTxHighPowerLvl = Adapter->DualMacDMSPControl.CurTxHighLvlForAnotherMacOfDMSP; + PHY_SetTxPowerLevel8192D(Adapter, pHalData->CurrentChannel); + pHalData->DynamicTxHighPowerLvl = HighPowerLvlBackForMac0; + Adapter->DualMacDMSPControl.bChangeTxHighPowerLvlForAnotherMacOfDMSP = _FALSE; + } + } +#endif + + if( (pdmpriv->DynamicTxHighPowerLvl != pdmpriv->LastDTPLvl) ) + { + //ODM_RT_TRACE(pDM_Odm,COMP_HIPWR, DBG_LOUD, ("PHY_SetTxPowerLevel8192S() Channel = %d \n" , pHalData->CurrentChannel)); +#if (RTL8192D_EASY_SMART_CONCURRENT == 1) + if(BuddyAdapter == NULL) + { + //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() BuddyAdapter == NULL case \n")); + if(!Adapter->bSlaveOfDMSP) + { + PHY_SetTxPowerLevel8192D(Adapter, pHalData->CurrentChannel); + } + } + else + { + if(pHalData->MacPhyMode92D == DUALMAC_SINGLEPHY) + { + //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() BuddyAdapter DMSP \n")); + if(Adapter->bSlaveOfDMSP) + { + //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() bslave case \n")); + BuddyAdapter->DualMacDMSPControl.bChangeTxHighPowerLvlForAnotherMacOfDMSP = _TRUE; + BuddyAdapter->DualMacDMSPControl.CurTxHighLvlForAnotherMacOfDMSP = pHalData->DynamicTxHighPowerLvl; + } + else + { + //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() master case \n")); + if(!bGetValueFromBuddyAdapter) + { + //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() mac 0 for mac 0 \n")); + PHY_SetTxPowerLevel8192D(Adapter, pHalData->CurrentChannel); + } + } + } + else + { + //ODM_RT_TRACE(pDM_Odm,COMP_MLME,DBG_LOUD,("dm_DynamicTxPower() BuddyAdapter DMDP\n")); + PHY_SetTxPowerLevel8192D(Adapter, pHalData->CurrentChannel); + } + } +#else + PHY_SetTxPowerLevel8192D(Adapter, pHalData->CurrentChannel); +#endif + } + pdmpriv->LastDTPLvl = pdmpriv->DynamicTxHighPowerLvl; +#endif +#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +} + + +//3============================================================ +//3 RSSI Monitor +//3============================================================ + +VOID +odm_RSSIDumpToRegister( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + + if(pDM_Odm->SupportICType == ODM_RTL8812) + { + PlatformEFIOWrite1Byte(Adapter, rA_RSSIDump_Jaguar, Adapter->RxStats.RxRSSIPercentage[0]); + PlatformEFIOWrite1Byte(Adapter, rB_RSSIDump_Jaguar, Adapter->RxStats.RxRSSIPercentage[1]); + + // Rx EVM + PlatformEFIOWrite1Byte(Adapter, rS1_RXevmDump_Jaguar, Adapter->RxStats.RxEVMdbm[0]); + PlatformEFIOWrite1Byte(Adapter, rS2_RXevmDump_Jaguar, Adapter->RxStats.RxEVMdbm[1]); + + // Rx SNR + PlatformEFIOWrite1Byte(Adapter, rA_RXsnrDump_Jaguar, (u1Byte)(Adapter->RxStats.RxSNRdB[0])); + PlatformEFIOWrite1Byte(Adapter, rB_RXsnrDump_Jaguar, (u1Byte)(Adapter->RxStats.RxSNRdB[1])); + + // Rx Cfo_Short + PlatformEFIOWrite2Byte(Adapter, rA_CfoShortDump_Jaguar, Adapter->RxStats.RxCfoShort[0]); + PlatformEFIOWrite2Byte(Adapter, rB_CfoShortDump_Jaguar, Adapter->RxStats.RxCfoShort[1]); + + // Rx Cfo_Tail + PlatformEFIOWrite2Byte(Adapter, rA_CfoLongDump_Jaguar, Adapter->RxStats.RxCfoTail[0]); + PlatformEFIOWrite2Byte(Adapter, rB_CfoLongDump_Jaguar, Adapter->RxStats.RxCfoTail[1]); + } + else if(pDM_Odm->SupportICType == ODM_RTL8192E) + { + PlatformEFIOWrite1Byte(Adapter, rA_RSSIDump_92E, Adapter->RxStats.RxRSSIPercentage[0]); + PlatformEFIOWrite1Byte(Adapter, rB_RSSIDump_92E, Adapter->RxStats.RxRSSIPercentage[1]); + // Rx EVM + PlatformEFIOWrite1Byte(Adapter, rS1_RXevmDump_92E, Adapter->RxStats.RxEVMdbm[0]); + PlatformEFIOWrite1Byte(Adapter, rS2_RXevmDump_92E, Adapter->RxStats.RxEVMdbm[1]); + // Rx SNR + PlatformEFIOWrite1Byte(Adapter, rA_RXsnrDump_92E, (u1Byte)(Adapter->RxStats.RxSNRdB[0])); + PlatformEFIOWrite1Byte(Adapter, rB_RXsnrDump_92E, (u1Byte)(Adapter->RxStats.RxSNRdB[1])); + // Rx Cfo_Short + PlatformEFIOWrite2Byte(Adapter, rA_CfoShortDump_92E, Adapter->RxStats.RxCfoShort[0]); + PlatformEFIOWrite2Byte(Adapter, rB_CfoShortDump_92E, Adapter->RxStats.RxCfoShort[1]); + // Rx Cfo_Tail + PlatformEFIOWrite2Byte(Adapter, rA_CfoLongDump_92E, Adapter->RxStats.RxCfoTail[0]); + PlatformEFIOWrite2Byte(Adapter, rB_CfoLongDump_92E, Adapter->RxStats.RxCfoTail[1]); + } +#endif +} + + +VOID +odm_RSSIMonitorInit( + IN PDM_ODM_T pDM_Odm + ) +{ + pRA_T pRA_Table = &pDM_Odm->DM_RA_Table; + + pRA_Table->firstconnect = FALSE; + +} + +VOID +odm_RSSIMonitorCheck( + IN PDM_ODM_T pDM_Odm + ) +{ + // + // For AP/ADSL use prtl8192cd_priv + // For CE/NIC use PADAPTER + // + + if (!(pDM_Odm->SupportAbility & ODM_BB_RSSI_MONITOR)) + return; + + // + // 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate + // at the same time. In the stage2/3, we need to prive universal interface and merge all + // HW dynamic mechanism. + // + switch (pDM_Odm->SupportPlatform) + { + case ODM_WIN: + odm_RSSIMonitorCheckMP(pDM_Odm); + break; + + case ODM_CE: + odm_RSSIMonitorCheckCE(pDM_Odm); + break; + + case ODM_AP: + odm_RSSIMonitorCheckAP(pDM_Odm); + break; + + case ODM_ADSL: + //odm_DIGAP(pDM_Odm); + break; + } + +} // odm_RSSIMonitorCheck + + +VOID +odm_RSSIMonitorCheckMP( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PRT_WLAN_STA pEntry; + u1Byte i; + s4Byte tmpEntryMaxPWDB=0, tmpEntryMinPWDB=0xff; + u1Byte H2C_Parameter[4] ={0}; + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + u8Byte curTxOkCnt = 0, curRxOkCnt = 0; + u1Byte STBC_TX = 0; + BOOLEAN FirstConnect; + pRA_T pRA_Table = &pDM_Odm->DM_RA_Table; +#if (BEAMFORMING_SUPPORT == 1) + BEAMFORMING_CAP Beamform_cap = BEAMFORMING_CAP_NONE; + u1Byte TxBF_EN = 0; +#endif + + RT_DISP(FDM, DM_PWDB, ("pHalData->UndecoratedSmoothedPWDB = 0x%x( %d)\n", + pHalData->UndecoratedSmoothedPWDB, + pHalData->UndecoratedSmoothedPWDB)); + + curTxOkCnt = Adapter->TxStats.NumTxBytesUnicast - pMgntInfo->lastTxOkCnt; + curRxOkCnt = Adapter->RxStats.NumRxBytesUnicast - pMgntInfo->lastRxOkCnt; + pMgntInfo->lastTxOkCnt = curTxOkCnt; + pMgntInfo->lastRxOkCnt = curRxOkCnt; + + RT_DISP(FDM, DM_PWDB, ("Tx = %d Rx = %d\n", curTxOkCnt, curRxOkCnt)); + + FirstConnect = (pHalData->bLinked) && (pRA_Table->firstconnect == FALSE); + pRA_Table->firstconnect = pHalData->bLinked; + H2C_Parameter[3] |= FirstConnect << 5; + + if(pDM_Odm->SupportICType == ODM_RTL8188E && (pMgntInfo->CustomerID==RT_CID_819x_HP)) + { + if(curRxOkCnt >(curTxOkCnt*6)) + PlatformEFIOWrite4Byte(Adapter, REG_ARFR0, 0x8f015); + else + PlatformEFIOWrite4Byte(Adapter, REG_ARFR0, 0xff015); + } + + if(pDM_Odm->SupportICType == ODM_RTL8812 || pDM_Odm->SupportICType == ODM_RTL8821) + { + if(curRxOkCnt >(curTxOkCnt*6)) + H2C_Parameter[3]=0x01; + else + H2C_Parameter[3]=0x00; + } + + for(i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) + { + if(IsAPModeExist(Adapter) && GetFirstExtAdapter(Adapter) != NULL) + { + pEntry = AsocEntry_EnumStation(GetFirstExtAdapter(Adapter), i); + } + else + { + pEntry = AsocEntry_EnumStation(GetDefaultAdapter(Adapter), i); + } + + if(pEntry != NULL) + { + if(pEntry->bAssociated) + { + + RT_DISP_ADDR(FDM, DM_PWDB, ("pEntry->MacAddr ="), pEntry->MacAddr); + RT_DISP(FDM, DM_PWDB, ("pEntry->rssi = 0x%x(%d)\n", + pEntry->rssi_stat.UndecoratedSmoothedPWDB, pEntry->rssi_stat.UndecoratedSmoothedPWDB)); + + if(pDM_Odm->SupportICType == ODM_RTL8192E || pDM_Odm->SupportICType == ODM_RTL8812) + { + +#if (BEAMFORMING_SUPPORT == 1) + Beamform_cap = Beamforming_GetEntryBeamCapByMacId(pMgntInfo, pEntry->AssociatedMacId); + if(Beamform_cap & (BEAMFORMER_CAP_HT_EXPLICIT |BEAMFORMER_CAP_VHT_SU)) + TxBF_EN = 1; + else + TxBF_EN = 0; + + H2C_Parameter[3] |= TxBF_EN << 6; + + if(TxBF_EN) + STBC_TX = 0; + else +#endif + { + if(IS_WIRELESS_MODE_AC(Adapter)) + STBC_TX = TEST_FLAG(pEntry->VHTInfo.STBC, STBC_VHT_ENABLE_TX); + else + STBC_TX = TEST_FLAG(pEntry->HTInfo.STBC, STBC_HT_ENABLE_TX); + } + + H2C_Parameter[3] |= STBC_TX << 1; + } + + if(pEntry->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB) + tmpEntryMinPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB; + if(pEntry->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB) + tmpEntryMaxPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB; + + H2C_Parameter[2] = (u1Byte)(pEntry->rssi_stat.UndecoratedSmoothedPWDB & 0xFF); + H2C_Parameter[1] = 0x20; // fw v12 cmdid 5:use max macid ,for nic ,default macid is 0 ,max macid is 1 + H2C_Parameter[0] = (pEntry->AssociatedMacId); + if(pDM_Odm->SupportICType == ODM_RTL8812) + ODM_FillH2CCmd(Adapter, ODM_H2C_RSSI_REPORT, 4, H2C_Parameter); + else if(pDM_Odm->SupportICType == ODM_RTL8192E) + ODM_FillH2CCmd(Adapter, ODM_H2C_RSSI_REPORT, 4, H2C_Parameter); + else + ODM_FillH2CCmd(Adapter, ODM_H2C_RSSI_REPORT, 3, H2C_Parameter); + } + } + else + { + break; + } + } + + if(tmpEntryMaxPWDB != 0) // If associated entry is found + { + pHalData->EntryMaxUndecoratedSmoothedPWDB = tmpEntryMaxPWDB; + RT_DISP(FDM, DM_PWDB, ("EntryMaxPWDB = 0x%x(%d)\n", tmpEntryMaxPWDB, tmpEntryMaxPWDB)); + } + else + { + pHalData->EntryMaxUndecoratedSmoothedPWDB = 0; + } + + if(tmpEntryMinPWDB != 0xff) // If associated entry is found + { + pHalData->EntryMinUndecoratedSmoothedPWDB = tmpEntryMinPWDB; + RT_DISP(FDM, DM_PWDB, ("EntryMinPWDB = 0x%x(%d)\n", tmpEntryMinPWDB, tmpEntryMinPWDB)); + + } + else + { + pHalData->EntryMinUndecoratedSmoothedPWDB = 0; + } + + // Indicate Rx signal strength to FW. + if(pHalData->bUseRAMask) + { + if(pDM_Odm->SupportICType == ODM_RTL8192E || pDM_Odm->SupportICType == ODM_RTL8812) + { + PRT_HIGH_THROUGHPUT pHTInfo = GET_HT_INFO(pMgntInfo); + PRT_VERY_HIGH_THROUGHPUT pVHTInfo = GET_VHT_INFO(pMgntInfo); + +#if (BEAMFORMING_SUPPORT == 1) + + Beamform_cap = Beamforming_GetEntryBeamCapByMacId(pMgntInfo, pMgntInfo->mMacId); + + if(Beamform_cap & (BEAMFORMER_CAP_HT_EXPLICIT |BEAMFORMER_CAP_VHT_SU)) + TxBF_EN = 1; + else + TxBF_EN = 0; + + H2C_Parameter[3] |= TxBF_EN << 6; + + if(TxBF_EN) + STBC_TX = 0; + else +#endif + { + if(IS_WIRELESS_MODE_AC(Adapter)) + STBC_TX = TEST_FLAG(pVHTInfo->VhtCurStbc, STBC_VHT_ENABLE_TX); + else + STBC_TX = TEST_FLAG(pHTInfo->HtCurStbc, STBC_HT_ENABLE_TX); + } + + H2C_Parameter[3] |= STBC_TX << 1; + } + + H2C_Parameter[2] = (u1Byte)(pHalData->UndecoratedSmoothedPWDB & 0xFF); + H2C_Parameter[1] = 0x20; // fw v12 cmdid 5:use max macid ,for nic ,default macid is 0 ,max macid is 1 + H2C_Parameter[0] = 0; // fw v12 cmdid 5:use max macid ,for nic ,default macid is 0 ,max macid is 1 + if(pDM_Odm->SupportICType == ODM_RTL8812) + ODM_FillH2CCmd(Adapter, ODM_H2C_RSSI_REPORT, 4, H2C_Parameter); + else if(pDM_Odm->SupportICType == ODM_RTL8192E) + ODM_FillH2CCmd(Adapter, ODM_H2C_RSSI_REPORT, 4, H2C_Parameter); + else + ODM_FillH2CCmd(Adapter, ODM_H2C_RSSI_REPORT, 3, H2C_Parameter); + } + else + { + PlatformEFIOWrite1Byte(Adapter, 0x4fe, (u1Byte)pHalData->UndecoratedSmoothedPWDB); + } + + if((pDM_Odm->SupportICType == ODM_RTL8812)||(pDM_Odm->SupportICType == ODM_RTL8192E)) + odm_RSSIDumpToRegister(pDM_Odm); + + odm_FindMinimumRSSI(Adapter); + ODM_CmnInfoUpdate(&pHalData->DM_OutSrc ,ODM_CMNINFO_LINK, (u8Byte)pHalData->bLinked); + ODM_CmnInfoUpdate(&pHalData->DM_OutSrc ,ODM_CMNINFO_RSSI_MIN, (u8Byte)pHalData->MinUndecoratedPWDBForDM); +#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +} + +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) +// +//sherry move from DUSC to here 20110517 +// +static VOID +FindMinimumRSSI_Dmsp( + IN PADAPTER pAdapter +) +{ +#if 0 + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + s32 Rssi_val_min_back_for_mac0; + BOOLEAN bGetValueFromBuddyAdapter = dm_DualMacGetParameterFromBuddyAdapter(pAdapter); + BOOLEAN bRestoreRssi = _FALSE; + PADAPTER BuddyAdapter = pAdapter->BuddyAdapter; + + if(pHalData->MacPhyMode92D == DUALMAC_SINGLEPHY) + { + if(BuddyAdapter!= NULL) + { + if(pHalData->bSlaveOfDMSP) + { + //ODM_RT_TRACE(pDM_Odm,COMP_EASY_CONCURRENT,DBG_LOUD,("bSlavecase of dmsp\n")); + BuddyAdapter->DualMacDMSPControl.RssiValMinForAnotherMacOfDMSP = pdmpriv->MinUndecoratedPWDBForDM; + } + else + { + if(bGetValueFromBuddyAdapter) + { + //ODM_RT_TRACE(pDM_Odm,COMP_EASY_CONCURRENT,DBG_LOUD,("get new RSSI\n")); + bRestoreRssi = _TRUE; + Rssi_val_min_back_for_mac0 = pdmpriv->MinUndecoratedPWDBForDM; + pdmpriv->MinUndecoratedPWDBForDM = pAdapter->DualMacDMSPControl.RssiValMinForAnotherMacOfDMSP; + } + } + } + + } + + if(bRestoreRssi) + { + bRestoreRssi = _FALSE; + pdmpriv->MinUndecoratedPWDBForDM = Rssi_val_min_back_for_mac0; + } +#endif +} + +static void +FindMinimumRSSI( +IN PADAPTER pAdapter + ) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + PDM_ODM_T pDM_Odm = &(pHalData->odmpriv); + + //1 1.Determine the minimum RSSI + + if((pDM_Odm->bLinked != _TRUE) && + (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0)) + { + pdmpriv->MinUndecoratedPWDBForDM = 0; + //ODM_RT_TRACE(pDM_Odm,COMP_BB_POWERSAVING, DBG_LOUD, ("Not connected to any \n")); + } + else + { + pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB; + } + + //DBG_8192C("%s=>MinUndecoratedPWDBForDM(%d)\n",__FUNCTION__,pdmpriv->MinUndecoratedPWDBForDM); + //ODM_RT_TRACE(pDM_Odm,COMP_DIG, DBG_LOUD, ("MinUndecoratedPWDBForDM =%d\n",pHalData->MinUndecoratedPWDBForDM)); +} +#endif + +VOID +odm_RSSIMonitorCheckCE( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter); + int i; + int tmpEntryMaxPWDB=0, tmpEntryMinPWDB=0xff; + u8 sta_cnt=0; + u32 UL_DL_STATE = 0, STBC_TX = 0, TxBF_EN = 0; + u32 PWDB_rssi[NUM_STA]={0};//[0~15]:MACID, [16~31]:PWDB_rssi + BOOLEAN FirstConnect = FALSE; + pRA_T pRA_Table = &pDM_Odm->DM_RA_Table; + + if(pDM_Odm->bLinked != _TRUE) + return; + + #if((RTL8812A_SUPPORT==1)||(RTL8821A_SUPPORT==1)) + if((pDM_Odm->SupportICType == ODM_RTL8812)||(pDM_Odm->SupportICType == ODM_RTL8821)) + { + u64 curTxOkCnt = pdvobjpriv->traffic_stat.cur_tx_bytes; + u64 curRxOkCnt = pdvobjpriv->traffic_stat.cur_rx_bytes; + + if(curRxOkCnt >(curTxOkCnt*6)) + UL_DL_STATE = 1; + else + UL_DL_STATE = 0; + } + #endif + + FirstConnect = (pDM_Odm->bLinked) && (pRA_Table->firstconnect == FALSE); + pRA_Table->firstconnect = pDM_Odm->bLinked; + + //if(check_fwstate(&Adapter->mlmepriv, WIFI_AP_STATE|WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) == _TRUE) + { + #if 1 + struct sta_info *psta; + + for(i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++) { + if (IS_STA_VALID(psta = pDM_Odm->pODM_StaInfo[i])) + { + if(IS_MCAST( psta->hwaddr)) //if(psta->mac_id ==1) + continue; + + if(psta->rssi_stat.UndecoratedSmoothedPWDB == (-1)) + continue; + + if(psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB) + tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; + + if(psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB) + tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; + + #if 0 + DBG_871X("%s mac_id:%u, mac:"MAC_FMT", rssi:%d\n", __func__, + psta->mac_id, MAC_ARG(psta->hwaddr), psta->rssi_stat.UndecoratedSmoothedPWDB); + #endif + + if(psta->rssi_stat.UndecoratedSmoothedPWDB != (-1)) { + +#ifdef CONFIG_80211N_HT + if(pDM_Odm->SupportICType == ODM_RTL8192E || pDM_Odm->SupportICType == ODM_RTL8812) + { +#ifdef CONFIG_BEAMFORMING + BEAMFORMING_CAP Beamform_cap = beamforming_get_entry_beam_cap_by_mac_id(&Adapter->mlmepriv, psta->mac_id); + + if(Beamform_cap & (BEAMFORMER_CAP_HT_EXPLICIT |BEAMFORMER_CAP_VHT_SU)) + TxBF_EN = 1; + else + TxBF_EN = 0; + + if (TxBF_EN) { + STBC_TX = 0; + } + else +#endif + { +#ifdef CONFIG_80211AC_VHT + if(IsSupportedVHT(psta->wireless_mode)) + STBC_TX = TEST_FLAG(psta->vhtpriv.stbc_cap, STBC_VHT_ENABLE_TX); + else +#endif + STBC_TX = TEST_FLAG(psta->htpriv.stbc_cap, STBC_HT_ENABLE_TX); + } + } +#endif + + if(pDM_Odm->SupportICType == ODM_RTL8192D) + PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16) | ((Adapter->stapriv.asoc_sta_count+1) << 8)); + else if ((pDM_Odm->SupportICType == ODM_RTL8192E)||(pDM_Odm->SupportICType == ODM_RTL8812)||(pDM_Odm->SupportICType == ODM_RTL8821)) + PWDB_rssi[sta_cnt++] = (((u8)(psta->mac_id&0xFF)) | ((psta->rssi_stat.UndecoratedSmoothedPWDB&0x7F)<<16) |(STBC_TX << 25) | (FirstConnect << 29) | (TxBF_EN << 30)); + else + PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16) ); + } + } + } + #else + _irqL irqL; + _list *plist, *phead; + struct sta_info *psta; + struct sta_priv *pstapriv = &Adapter->stapriv; + u8 bcast_addr[ETH_ALEN]= {0xff,0xff,0xff,0xff,0xff,0xff}; + + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + for(i=0; i< NUM_STA; i++) + { + phead = &(pstapriv->sta_hash[i]); + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) + { + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + + plist = get_next(plist); + + if(_rtw_memcmp(psta->hwaddr, bcast_addr, ETH_ALEN) || + _rtw_memcmp(psta->hwaddr, myid(&Adapter->eeprompriv), ETH_ALEN)) + continue; + + if(psta->state & WIFI_ASOC_STATE) + { + + if(psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB) + tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; + + if(psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB) + tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB; + + if(psta->rssi_stat.UndecoratedSmoothedPWDB != (-1)){ + //printk("%s==> mac_id(%d),rssi(%d)\n",__FUNCTION__,psta->mac_id,psta->rssi_stat.UndecoratedSmoothedPWDB); + #if(RTL8192D_SUPPORT==1) + PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16) | ((Adapter->stapriv.asoc_sta_count+1) << 8)); + #else + PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16) ); + #endif + } + } + + } + + } + + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + #endif + + //printk("%s==> sta_cnt(%d)\n",__FUNCTION__,sta_cnt); + + for(i=0; i< sta_cnt; i++) + { + if(PWDB_rssi[i] != (0)){ + if(pHalData->fw_ractrl == _TRUE)// Report every sta's RSSI to FW + { + #if(RTL8192D_SUPPORT==1) + if(pDM_Odm->SupportICType == ODM_RTL8192D){ + FillH2CCmd92D(Adapter, H2C_RSSI_REPORT, 3, (u8 *)(&PWDB_rssi[i])); + } + #endif + + #if((RTL8192C_SUPPORT==1)||(RTL8723A_SUPPORT==1)) + if((pDM_Odm->SupportICType == ODM_RTL8192C)||(pDM_Odm->SupportICType == ODM_RTL8723A)){ + rtl8192c_set_rssi_cmd(Adapter, (u8*)&PWDB_rssi[i]); + } + #endif + + #if((RTL8812A_SUPPORT==1)||(RTL8821A_SUPPORT==1)) + if((pDM_Odm->SupportICType == ODM_RTL8812)||(pDM_Odm->SupportICType == ODM_RTL8821)){ + PWDB_rssi[i] |= (UL_DL_STATE << 24); + rtl8812_set_rssi_cmd(Adapter, (u8 *)(&PWDB_rssi[i])); + } + #endif + #if(RTL8192E_SUPPORT==1) + if(pDM_Odm->SupportICType == ODM_RTL8192E){ + rtl8192e_set_rssi_cmd(Adapter, (u8 *)(&PWDB_rssi[i])); + } + #endif + #if(RTL8723B_SUPPORT==1) + if(pDM_Odm->SupportICType == ODM_RTL8723B){ + rtl8723b_set_rssi_cmd(Adapter, (u8 *)(&PWDB_rssi[i])); + } + #endif + } + else{ + #if((RTL8188E_SUPPORT==1)&&(RATE_ADAPTIVE_SUPPORT == 1)) + if(pDM_Odm->SupportICType == ODM_RTL8188E){ + ODM_RA_SetRSSI_8188E( + &(pHalData->odmpriv), (PWDB_rssi[i]&0xFF), (u8)((PWDB_rssi[i]>>16) & 0xFF)); + } + #endif + } + } + } + } + + + + if(tmpEntryMaxPWDB != 0) // If associated entry is found + { + pdmpriv->EntryMaxUndecoratedSmoothedPWDB = tmpEntryMaxPWDB; + } + else + { + pdmpriv->EntryMaxUndecoratedSmoothedPWDB = 0; + } + + if(tmpEntryMinPWDB != 0xff) // If associated entry is found + { + pdmpriv->EntryMinUndecoratedSmoothedPWDB = tmpEntryMinPWDB; + } + else + { + pdmpriv->EntryMinUndecoratedSmoothedPWDB = 0; + } + + FindMinimumRSSI(Adapter);//get pdmpriv->MinUndecoratedPWDBForDM + + #if(RTL8192D_SUPPORT==1) + FindMinimumRSSI_Dmsp(Adapter); + #endif + pDM_Odm->RSSI_Min = pdmpriv->MinUndecoratedPWDBForDM; + //ODM_CmnInfoUpdate(&pHalData->odmpriv ,ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM); +#endif//if (DM_ODM_SUPPORT_TYPE == ODM_CE) +} +VOID +odm_RSSIMonitorCheckAP( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) +#ifdef CONFIG_RTL_92C_SUPPORT || defined(CONFIG_RTL_92D_SUPPORT) + + u4Byte i; + PSTA_INFO_T pstat; + + for(i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++) + { + pstat = pDM_Odm->pODM_StaInfo[i]; + if(IS_STA_VALID(pstat) ) + { +#ifdef STA_EXT + if (REMAP_AID(pstat) < (FW_NUM_STAT - 1)) +#endif + add_update_rssi(pDM_Odm->priv, pstat); + + } + } +#endif +#endif + +} + + + +VOID +ODM_InitAllTimers( + IN PDM_ODM_T pDM_Odm + ) +{ +#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) +#if (RTL8723B_SUPPORT == 1)||(RTL8821A_SUPPORT == 1) + ODM_InitializeTimer(pDM_Odm,&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer_8723B, + (RT_TIMER_CALL_BACK)ODM_SW_AntDiv_Callback, NULL, "SwAntennaSwitchTimer_8723B"); +#endif +#endif + +#if(defined(CONFIG_SW_ANTENNA_DIVERSITY)) + ODM_InitializeTimer(pDM_Odm,&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer, + (RT_TIMER_CALL_BACK)odm_SwAntDivChkAntSwitchCallback, NULL, "SwAntennaSwitchTimer"); +#endif + +#if (!(DM_ODM_SUPPORT_TYPE == ODM_CE)) +#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) +#if (RTL8188E_SUPPORT == 1) + ODM_InitializeTimer(pDM_Odm,&pDM_Odm->FastAntTrainingTimer, + (RT_TIMER_CALL_BACK)odm_FastAntTrainingCallback, NULL, "FastAntTrainingTimer"); +#endif +#endif +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + ODM_InitializeTimer(pDM_Odm, &pDM_Odm->PSDTimer, + (RT_TIMER_CALL_BACK)dm_PSDMonitorCallback, NULL, "PSDTimer"); + // + //Path Diversity + //Neil Chen--2011--06--16-- / 2012/02/23 MH Revise Arch. + // + ODM_InitializeTimer(pDM_Odm, &pDM_Odm->PathDivSwitchTimer, + (RT_TIMER_CALL_BACK)odm_PathDivChkAntSwitchCallback, NULL, "PathDivTimer"); + + ODM_InitializeTimer(pDM_Odm, &pDM_Odm->CCKPathDiversityTimer, + (RT_TIMER_CALL_BACK)odm_CCKTXPathDiversityCallback, NULL, "CCKPathDiversityTimer"); + + ODM_InitializeTimer(pDM_Odm, &pDM_Odm->MPT_DIGTimer, + (RT_TIMER_CALL_BACK)odm_MPT_DIGCallback, NULL, "MPT_DIGTimer"); + + ODM_InitializeTimer(pDM_Odm, &pDM_Odm->DM_RXHP_Table.PSDTimer, + (RT_TIMER_CALL_BACK)odm_PSD_RXHPCallback, NULL, "PSDRXHPTimer"); +#endif +} + +VOID +ODM_CancelAllTimers( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + // + // 2012/01/12 MH Temp BSOD fix. We need to find NIC allocate mem fail reason in + // win7 platform. + // + HAL_ADAPTER_STS_CHK(pDM_Odm) +#endif +#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) +#if (RTL8723B_SUPPORT == 1)||(RTL8821A_SUPPORT == 1) + ODM_CancelTimer(pDM_Odm,&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer_8723B); +#endif +#endif + +#if(defined(CONFIG_SW_ANTENNA_DIVERSITY)) + ODM_CancelTimer(pDM_Odm,&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer); +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +#if (RTL8188E_SUPPORT == 1) + ODM_CancelTimer(pDM_Odm,&pDM_Odm->FastAntTrainingTimer); +#endif + ODM_CancelTimer(pDM_Odm, &pDM_Odm->PSDTimer); + // + //Path Diversity + //Neil Chen--2011--06--16-- / 2012/02/23 MH Revise Arch. + // + ODM_CancelTimer(pDM_Odm, &pDM_Odm->PathDivSwitchTimer); + + ODM_CancelTimer(pDM_Odm, &pDM_Odm->CCKPathDiversityTimer); + + ODM_CancelTimer(pDM_Odm, &pDM_Odm->MPT_DIGTimer); + + ODM_CancelTimer(pDM_Odm, &pDM_Odm->DM_RXHP_Table.PSDTimer); +#endif +} + + +VOID +ODM_ReleaseAllTimers( + IN PDM_ODM_T pDM_Odm + ) +{ +#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) +#if (RTL8723B_SUPPORT == 1)||(RTL8821A_SUPPORT == 1) + ODM_ReleaseTimer(pDM_Odm,&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer_8723B); +#endif +#endif + +#if(defined(CONFIG_SW_ANTENNA_DIVERSITY)) + ODM_ReleaseTimer(pDM_Odm,&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer); +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +#if (RTL8188E_SUPPORT == 1) + ODM_ReleaseTimer(pDM_Odm,&pDM_Odm->FastAntTrainingTimer); +#endif + + ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->PSDTimer); + // + //Path Diversity + //Neil Chen--2011--06--16-- / 2012/02/23 MH Revise Arch. + // + ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->PathDivSwitchTimer); + + ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->CCKPathDiversityTimer); + + ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->MPT_DIGTimer); + + ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->DM_RXHP_Table.PSDTimer); +#endif +} + + +//3============================================================ +//3 Tx Power Tracking +//3============================================================ + +VOID +odm_IQCalibrate( + IN PDM_ODM_T pDM_Odm + ) +{ + PADAPTER Adapter = pDM_Odm->Adapter; + + if(!IS_HARDWARE_TYPE_JAGUAR(Adapter)) + return; + else if(IS_HARDWARE_TYPE_8812AU(Adapter)) + return; +#if (RTL8821A_SUPPORT == 1) + if(pDM_Odm->bLinked) + { + if((*pDM_Odm->pChannel != pDM_Odm->preChannel) && (!*pDM_Odm->pbScanInProcess)) + { + pDM_Odm->preChannel = *pDM_Odm->pChannel; + pDM_Odm->LinkedInterval = 0; + } + + if(pDM_Odm->LinkedInterval < 3) + pDM_Odm->LinkedInterval++; + + if(pDM_Odm->LinkedInterval == 2) + { + // Mark out IQK flow to prevent tx stuck. by Maddest 20130306 + // Open it verified by James 20130715 + PHY_IQCalibrate_8821A(Adapter, FALSE); + } + } + else + pDM_Odm->LinkedInterval = 0; +#endif +} + + +VOID +odm_TXPowerTrackingInit( + IN PDM_ODM_T pDM_Odm + ) +{ + odm_TXPowerTrackingThermalMeterInit(pDM_Odm); +} + +u1Byte +getSwingIndex( + IN PDM_ODM_T pDM_Odm + ) +{ + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + u1Byte i = 0; + u4Byte bbSwing; + u4Byte swingTableSize; + pu4Byte pSwingTable; + + if (pDM_Odm->SupportICType == ODM_RTL8188E || pDM_Odm->SupportICType == ODM_RTL8723B || + pDM_Odm->SupportICType == ODM_RTL8192E) + { + bbSwing = PHY_QueryBBReg(Adapter, rOFDM0_XATxIQImbalance, 0xFFC00000); + + pSwingTable = OFDMSwingTable_New; + swingTableSize = OFDM_TABLE_SIZE; + } else { +#if ((RTL8812A_SUPPORT==1)||(RTL8821A_SUPPORT==1)) + if (pDM_Odm->SupportICType == ODM_RTL8812 || pDM_Odm->SupportICType == ODM_RTL8821) + { + bbSwing = PHY_GetTxBBSwing_8812A(Adapter, pHalData->CurrentBandType, ODM_RF_PATH_A); + pSwingTable = TxScalingTable_Jaguar; + swingTableSize = TXSCALE_TABLE_SIZE; + } + else +#endif + { + bbSwing = 0; + pSwingTable = OFDMSwingTable; + swingTableSize = OFDM_TABLE_SIZE; + } + } + + for (i = 0; i < swingTableSize; ++i) { + u4Byte tableValue = pSwingTable[i]; + + if (tableValue >= 0x100000 ) + tableValue >>= 22; + if (bbSwing == tableValue) + break; + } + return i; +} + +VOID +odm_TXPowerTrackingThermalMeterInit( + IN PDM_ODM_T pDM_Odm + ) +{ + u1Byte defaultSwingIndex = getSwingIndex(pDM_Odm); + u1Byte p = 0; +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + + #if MP_DRIVER != 1 //for mp driver, turn off txpwrtracking as default + pHalData->TxPowerTrackControl = TRUE; + #endif +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + + + if (pDM_Odm->SupportICType >= ODM_RTL8188E) + { + pDM_Odm->RFCalibrateInfo.bTXPowerTracking = _TRUE; + pDM_Odm->RFCalibrateInfo.TXPowercount = 0; + pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = _FALSE; + //#if (MP_DRIVER != 1) //for mp driver, turn off txpwrtracking as default + if ( *(pDM_Odm->mp_mode) != 1) + pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = _TRUE; + //#endif//#if (MP_DRIVER != 1) + MSG_8192C("pDM_Odm TxPowerTrackControl = %d\n", pDM_Odm->RFCalibrateInfo.TxPowerTrackControl); + } + else + { + struct dm_priv *pdmpriv = &pHalData->dmpriv; + + pdmpriv->bTXPowerTracking = _TRUE; + pdmpriv->TXPowercount = 0; + pdmpriv->bTXPowerTrackingInit = _FALSE; + //#if (MP_DRIVER != 1) //for mp driver, turn off txpwrtracking as default + + if (*(pDM_Odm->mp_mode) != 1) + pdmpriv->TxPowerTrackControl = _TRUE; + //#endif//#if (MP_DRIVER != 1) + + //MSG_8192C("pdmpriv->TxPowerTrackControl = %d\n", pdmpriv->TxPowerTrackControl); + } + +#elif (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + #ifdef RTL8188E_SUPPORT + { + pDM_Odm->RFCalibrateInfo.bTXPowerTracking = _TRUE; + pDM_Odm->RFCalibrateInfo.TXPowercount = 0; + pDM_Odm->RFCalibrateInfo.bTXPowerTrackingInit = _FALSE; + pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = _TRUE; + } + #endif +#endif + + pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = TRUE; + pDM_Odm->RFCalibrateInfo.ThermalValue = pHalData->EEPROMThermalMeter; + pDM_Odm->RFCalibrateInfo.ThermalValue_IQK = pHalData->EEPROMThermalMeter; + pDM_Odm->RFCalibrateInfo.ThermalValue_LCK = pHalData->EEPROMThermalMeter; + + // The index of "0 dB" in SwingTable. + if (pDM_Odm->SupportICType == ODM_RTL8188E || pDM_Odm->SupportICType == ODM_RTL8723B || + pDM_Odm->SupportICType == ODM_RTL8192E) + { + pDM_Odm->DefaultOfdmIndex = (defaultSwingIndex >= OFDM_TABLE_SIZE) ? 30 : defaultSwingIndex; + pDM_Odm->DefaultCckIndex = 20; + } + else + { + pDM_Odm->DefaultOfdmIndex = (defaultSwingIndex >= TXSCALE_TABLE_SIZE) ? 24 : defaultSwingIndex; + pDM_Odm->DefaultCckIndex = 24; + } + + pDM_Odm->BbSwingIdxCckBase = pDM_Odm->DefaultCckIndex; + pDM_Odm->RFCalibrateInfo.CCK_index = pDM_Odm->DefaultCckIndex; + + for (p = ODM_RF_PATH_A; p < MAX_RF_PATH; ++p) + { + pDM_Odm->BbSwingIdxOfdmBase[p] = pDM_Odm->DefaultOfdmIndex; + pDM_Odm->RFCalibrateInfo.OFDM_index[p] = pDM_Odm->DefaultOfdmIndex; + pDM_Odm->RFCalibrateInfo.DeltaPowerIndex[p] = 0; + pDM_Odm->RFCalibrateInfo.DeltaPowerIndexLast[p] = 0; + pDM_Odm->RFCalibrateInfo.PowerIndexOffset[p] = 0; + } + +} + + +VOID +ODM_TXPowerTrackingCheck( + IN PDM_ODM_T pDM_Odm + ) +{ + // + // 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate + // at the same time. In the stage2/3, we need to prive universal interface and merge all + // HW dynamic mechanism. + // + switch (pDM_Odm->SupportPlatform) + { + case ODM_WIN: + odm_TXPowerTrackingCheckMP(pDM_Odm); + break; + + case ODM_CE: + odm_TXPowerTrackingCheckCE(pDM_Odm); + break; + + case ODM_AP: + odm_TXPowerTrackingCheckAP(pDM_Odm); + break; + + case ODM_ADSL: + //odm_DIGAP(pDM_Odm); + break; + } + +} + +VOID +odm_TXPowerTrackingCheckCE( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + #if( (RTL8192C_SUPPORT==1) || (RTL8723A_SUPPORT==1) ) + if(IS_HARDWARE_TYPE_8192C(Adapter)){ + rtl8192c_odm_CheckTXPowerTracking(Adapter); + return; + } + #endif + + #if (RTL8192D_SUPPORT==1) + if(IS_HARDWARE_TYPE_8192D(Adapter)){ + #if (RTL8192D_EASY_SMART_CONCURRENT == 1) + if(!Adapter->bSlaveOfDMSP) + #endif + rtl8192d_odm_CheckTXPowerTracking(Adapter); + return; + } + #endif + + #if(((RTL8188E_SUPPORT==1) || (RTL8812A_SUPPORT==1) || (RTL8821A_SUPPORT==1) || (RTL8192E_SUPPORT==1) || (RTL8723B_SUPPORT==1) )) + if(!(pDM_Odm->SupportAbility & ODM_RF_TX_PWR_TRACK)) + { + return; + } + + if(!pDM_Odm->RFCalibrateInfo.TM_Trigger) //at least delay 1 sec + { + //pHalData->TxPowerCheckCnt++; //cosa add for debug + if(IS_HARDWARE_TYPE_8188E(Adapter) || IS_HARDWARE_TYPE_JAGUAR(Adapter) || IS_HARDWARE_TYPE_8192E(Adapter)||IS_HARDWARE_TYPE_8723B(Adapter)) + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_T_METER_NEW, (BIT17 | BIT16), 0x03); + else + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_T_METER_OLD, bRFRegOffsetMask, 0x60); + + //DBG_871X("Trigger Thermal Meter!!\n"); + + pDM_Odm->RFCalibrateInfo.TM_Trigger = 1; + return; + } + else + { + //DBG_871X("Schedule TxPowerTracking direct call!!\n"); + ODM_TXPowerTrackingCallback_ThermalMeter(Adapter); + pDM_Odm->RFCalibrateInfo.TM_Trigger = 0; + } + #endif +#endif +} + +VOID +odm_TXPowerTrackingCheckMP( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + + if (ODM_CheckPowerStatus(Adapter) == FALSE) + { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, ("===>ODM_CheckPowerStatus() return FALSE\n")); + return; + } + + if(IS_HARDWARE_TYPE_8723A(Adapter)) + return; + + if(!Adapter->bSlaveOfDMSP || Adapter->DualMacSmartConcurrent == FALSE) + odm_TXPowerTrackingThermalMeterCheck(Adapter); + else { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, ("!Adapter->bSlaveOfDMSP || Adapter->DualMacSmartConcurrent == FALSE\n")); + } +#endif + +} + + +VOID +odm_TXPowerTrackingCheckAP( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) + prtl8192cd_priv priv = pDM_Odm->priv; + + if ( (priv->pmib->dot11RFEntry.ther) && ((priv->up_time % priv->pshare->rf_ft_var.tpt_period) == 0)){ +#ifdef CONFIG_RTL_92D_SUPPORT + if (GET_CHIP_VER(priv)==VERSION_8192D){ + tx_power_tracking_92D(priv); + } else +#endif + { +#ifdef CONFIG_RTL_92C_SUPPORT + tx_power_tracking(priv); +#endif + } + } +#endif + +} + + + +//antenna mapping info +// 1: right-side antenna +// 2/0: left-side antenna +//PDM_SWAT_Table->CCK_Ant1_Cnt /OFDM_Ant1_Cnt: for right-side antenna: Ant:1 RxDefaultAnt1 +//PDM_SWAT_Table->CCK_Ant2_Cnt /OFDM_Ant2_Cnt: for left-side antenna: Ant:0 RxDefaultAnt2 +// We select left antenna as default antenna in initial process, modify it as needed +// + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +VOID +odm_TXPowerTrackingThermalMeterCheck( + IN PADAPTER Adapter + ) +{ +#ifndef AP_BUILD_WORKAROUND + static u1Byte TM_Trigger = 0; + + if(!(GET_HAL_DATA(Adapter)->DM_OutSrc.SupportAbility & ODM_RF_TX_PWR_TRACK)) + { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, + ("===>odm_TXPowerTrackingThermalMeterCheck(),pMgntInfo->bTXPowerTracking is FALSE, return!!\n")); + return; + } + + if(!TM_Trigger) //at least delay 1 sec + { + if(IS_HARDWARE_TYPE_8192D(Adapter)) + PHY_SetRFReg(Adapter, ODM_RF_PATH_A, RF_T_METER_92D, BIT17 | BIT16, 0x03); + else if(IS_HARDWARE_TYPE_8188E(Adapter) || IS_HARDWARE_TYPE_JAGUAR(Adapter) || IS_HARDWARE_TYPE_8192E(Adapter) || + IS_HARDWARE_TYPE_8723B(Adapter)) + PHY_SetRFReg(Adapter, ODM_RF_PATH_A, RF_T_METER_88E, BIT17 | BIT16, 0x03); + else + PHY_SetRFReg(Adapter, ODM_RF_PATH_A, RF_T_METER, bRFRegOffsetMask, 0x60); + + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD,("Trigger Thermal Meter!!\n")); + + TM_Trigger = 1; + return; + } + else + { + RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD,("Schedule TxPowerTracking direct call!!\n")); + odm_TXPowerTrackingDirectCall(Adapter); //Using direct call is instead, added by Roger, 2009.06.18. + TM_Trigger = 0; + } +#endif +} + +// Only for 8723A SW ANT DIV INIT--2012--07--17 +VOID +odm_SwAntDivInit_NIC_8723A( + IN PDM_ODM_T pDM_Odm) +{ + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + PADAPTER Adapter = pDM_Odm->Adapter; + + u1Byte btAntNum=BT_GetPgAntNum(Adapter); + + if(IS_HARDWARE_TYPE_8723A(Adapter)) + { + pDM_SWAT_Table->ANTA_ON =TRUE; + + // Set default antenna B status by PG + if(btAntNum == 2) + pDM_SWAT_Table->ANTB_ON = TRUE; + else if(btAntNum == 1) + pDM_SWAT_Table->ANTB_ON = FALSE; + else + pDM_SWAT_Table->ANTB_ON = TRUE; + } + +} + +#endif //end #ifMP + + + +//3============================================================ +//3 SW Antenna Diversity +//3============================================================ +#if(defined(CONFIG_SW_ANTENNA_DIVERSITY)) +VOID +odm_SwAntDivInit( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + odm_SwAntDivInit_NIC(pDM_Odm); +#elif(DM_ODM_SUPPORT_TYPE == ODM_AP) + dm_SW_AntennaSwitchInit(pDM_Odm->priv); +#endif +} + +VOID +odm_SwAntDivInit_NIC( + IN PDM_ODM_T pDM_Odm + ) +{ + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + + +// Init SW ANT DIV mechanism for 8723AE/AU/AS +// Neil Chen--2012--07--17--- +// CE/AP/ADSL no using SW ANT DIV for 8723A Series IC +//#if (DM_ODM_SUPPORT_TYPE==ODM_WIN) +#if (RTL8723A_SUPPORT==1) + if(pDM_Odm->SupportICType == ODM_RTL8723A) + { + odm_SwAntDivInit_NIC_8723A(pDM_Odm); + } +#endif + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS:Init SW Antenna Switch\n")); + pDM_SWAT_Table->RSSI_sum_A = 0; + pDM_SWAT_Table->RSSI_cnt_A = 0; + pDM_SWAT_Table->RSSI_sum_B = 0; + pDM_SWAT_Table->RSSI_cnt_B = 0; + pDM_SWAT_Table->CurAntenna = MAIN_ANT; + pDM_SWAT_Table->PreAntenna = MAIN_ANT; + pDM_SWAT_Table->try_flag = 0xff; + pDM_SWAT_Table->PreRSSI = 0; + pDM_SWAT_Table->SWAS_NoLink_State = 0; + pDM_SWAT_Table->bTriggerAntennaSwitch = 0; + pDM_SWAT_Table->SelectAntennaMap=0xAA; + pDM_SWAT_Table->lastTxOkCnt = 0; + pDM_SWAT_Table->lastRxOkCnt = 0; + pDM_SWAT_Table->TXByteCnt_A = 0; + pDM_SWAT_Table->TXByteCnt_B = 0; + pDM_SWAT_Table->RXByteCnt_A = 0; + pDM_SWAT_Table->RXByteCnt_B = 0; + pDM_SWAT_Table->TrafficLoad = TRAFFIC_LOW; + pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 = ODM_Read4Byte(pDM_Odm, 0x860); + +} + +// +// 20100514 Joseph: +// Add new function to reset the state of antenna diversity before link. +// +VOID +ODM_SwAntDivResetBeforeLink( + IN PDM_ODM_T pDM_Odm + ) +{ + + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + + pDM_SWAT_Table->SWAS_NoLink_State = 0; + +} + +// +// 20100514 Luke/Joseph: +// Add new function to reset antenna diversity state after link. +// +VOID +ODM_SwAntDivRestAfterLink( + IN PDM_ODM_T pDM_Odm + ) +{ + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + u4Byte i; + + if(pDM_Odm->SupportICType == ODM_RTL8723A) + { + pDM_SWAT_Table->RSSI_cnt_A = 0; + pDM_SWAT_Table->RSSI_cnt_B = 0; + pDM_Odm->RSSI_test = FALSE; + pDM_SWAT_Table->try_flag = 0xff; + pDM_SWAT_Table->RSSI_Trying = 0; + pDM_SWAT_Table->SelectAntennaMap=0xAA; + + } + else if(pDM_Odm->SupportICType & (ODM_RTL8723B|ODM_RTL8821)) + { + pDM_Odm->RSSI_test = FALSE; + pDM_SWAT_Table->try_flag = 0xff; + pDM_SWAT_Table->RSSI_Trying = 0; + pDM_SWAT_Table->Double_chk_flag= 0; + + pDM_FatTable->RxIdleAnt=MAIN_ANT; + + for (i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++) + { + pDM_FatTable->MainAnt_Sum[i] = 0; + pDM_FatTable->AuxAnt_Sum[i] = 0; + pDM_FatTable->MainAnt_Cnt[i] = 0; + pDM_FatTable->AuxAnt_Cnt[i] = 0; + } + + } +} + +void +odm_SwAntDetectInit( + IN PDM_ODM_T pDM_Odm + ) +{ + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; +#if (RTL8723B_SUPPORT == 1) + pDM_SWAT_Table->SWAS_NoLink_BK_Reg92c = ODM_Read4Byte(pDM_Odm, rDPDT_control); +#endif + pDM_SWAT_Table->PreAntenna = MAIN_ANT; + pDM_SWAT_Table->CurAntenna = MAIN_ANT; + pDM_SWAT_Table->SWAS_NoLink_State = 0; +} + +VOID +ODM_SwAntDivChkPerPktRssi( + IN PDM_ODM_T pDM_Odm, + IN u1Byte StationID, + IN PODM_PHY_INFO_T pPhyInfo + ) +{ + SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + + if(!(pDM_Odm->SupportAbility & (ODM_BB_ANT_DIV))) + return; + +// temporary Fix 8723A MP SW ANT DIV Bug --NeilChen--2012--07--11 +#if (DM_ODM_SUPPORT_TYPE==ODM_WIN) + if(pDM_Odm->SupportICType == ODM_RTL8723A) + { + //if(StationID == pDM_SWAT_Table->RSSI_target) + //{ + //1 RSSI for SW Antenna Switch + if(pDM_SWAT_Table->CurAntenna == MAIN_ANT) + { + pDM_SWAT_Table->RSSI_sum_A += pPhyInfo->RxPWDBAll; + pDM_SWAT_Table->RSSI_cnt_A++; + } + else + { + pDM_SWAT_Table->RSSI_sum_B += pPhyInfo->RxPWDBAll; + pDM_SWAT_Table->RSSI_cnt_B++; + + } + //} + } + else + { + if(StationID == pDM_SWAT_Table->RSSI_target) + { + //1 RSSI for SW Antenna Switch + if(pDM_SWAT_Table->CurAntenna == MAIN_ANT) + { + pDM_SWAT_Table->RSSI_sum_A += pPhyInfo->RxPWDBAll; + pDM_SWAT_Table->RSSI_cnt_A++; + } + else + { + pDM_SWAT_Table->RSSI_sum_B += pPhyInfo->RxPWDBAll; + pDM_SWAT_Table->RSSI_cnt_B++; + + } + } + } +#else + if(StationID == pDM_SWAT_Table->RSSI_target) + { + //1 RSSI for SW Antenna Switch + if(pDM_SWAT_Table->CurAntenna == MAIN_ANT) + { + pDM_SWAT_Table->RSSI_sum_A += pPhyInfo->RxPWDBAll; + pDM_SWAT_Table->RSSI_cnt_A++; + } + else + { + pDM_SWAT_Table->RSSI_sum_B += pPhyInfo->RxPWDBAll; + pDM_SWAT_Table->RSSI_cnt_B++; + + } + } +#endif +} + +// +VOID +odm_SwAntDivChkAntSwitch( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Step + ) +{ + // + // For AP/ADSL use prtl8192cd_priv + // For CE/NIC use PADAPTER + // + prtl8192cd_priv priv = pDM_Odm->priv; + + // + // 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate + // at the same time. In the stage2/3, we need to prive universal interface and merge all + // HW dynamic mechanism. + // + switch (pDM_Odm->SupportPlatform) + { + case ODM_WIN: + odm_SwAntDivChkAntSwitchNIC(pDM_Odm, Step); + break; + case ODM_CE: + odm_SwAntDivChkAntSwitchNIC(pDM_Odm, Step); + break; + + case ODM_AP: + case ODM_ADSL: +#if (DM_ODM_SUPPORT_TYPE & (ODM_AP |ODM_ADSL)) + if (priv->pshare->rf_ft_var.antSw_enable && (priv->up_time % 4==1)) + dm_SW_AntennaSwitch(priv, SWAW_STEP_PEAK); +#endif + break; + } + +} + +// +// 20100514 Luke/Joseph: +// Add new function for antenna diversity after link. +// This is the main function of antenna diversity after link. +// This function is called in HalDmWatchDog() and ODM_SwAntDivChkAntSwitchCallback(). +// HalDmWatchDog() calls this function with SWAW_STEP_PEAK to initialize the antenna test. +// In SWAW_STEP_PEAK, another antenna and a 500ms timer will be set for testing. +// After 500ms, ODM_SwAntDivChkAntSwitchCallback() calls this function to compare the signal just +// listened on the air with the RSSI of original antenna. +// It chooses the antenna with better RSSI. +// There is also a aged policy for error trying. Each error trying will cost more 5 seconds waiting +// penalty to get next try. + + +VOID +ODM_SetAntenna( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Antenna) +{ + ODM_SetBBReg(pDM_Odm, 0x860, BIT8|BIT9, Antenna); +} + +VOID +odm_SwAntDivChkAntSwitchNIC( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Step + ) +{ +#if ((RTL8192C_SUPPORT==1)||(RTL8723A_SUPPORT==1)) + //PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + +#if (DM_ODM_SUPPORT_TYPE==ODM_WIN) + PADAPTER Adapter=pDM_Odm->Adapter; +#endif + + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + s4Byte curRSSI=100, RSSI_A, RSSI_B; + u1Byte nextAntenna=AUX_ANT; + //static u8Byte lastTxOkCnt=0, lastRxOkCnt=0; + u8Byte curTxOkCnt=0, curRxOkCnt=0; + //static u8Byte TXByteCnt_A=0, TXByteCnt_B=0, RXByteCnt_A=0, RXByteCnt_B=0; + u8Byte CurByteCnt=0, PreByteCnt=0; + //static u1Byte TrafficLoad = TRAFFIC_LOW; + u1Byte Score_A=0, Score_B=0; //A: Main; B: AUX + u1Byte i; + + if(!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) + return; + + if (pDM_Odm->SupportICType & (ODM_RTL8192D|ODM_RTL8188E)) + return; + + if((pDM_Odm->SupportICType == ODM_RTL8192C) &&(pDM_Odm->RFType == ODM_2T2R)) + return; + + if(pDM_Odm->SupportPlatform & ODM_WIN) + { + if(*(pDM_Odm->pAntennaTest)) + return; + } + + if((pDM_SWAT_Table->ANTA_ON == FALSE) ||(pDM_SWAT_Table->ANTB_ON == FALSE)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, + ("odm_SwAntDivChkAntSwitch(): No AntDiv Mechanism, Antenna A or B is off\n")); + return; + } + + // Radio off: Status reset to default and return. + if(*(pDM_Odm->pbPowerSaving)==TRUE) //pHalData->eRFPowerState==eRfOff + { + ODM_SwAntDivRestAfterLink(pDM_Odm); + return; + } + + + // Handling step mismatch condition. + // Peak step is not finished at last time. Recover the variable and check again. + if( Step != pDM_SWAT_Table->try_flag ) + { + ODM_SwAntDivRestAfterLink(pDM_Odm); + } + +#if (DM_ODM_SUPPORT_TYPE &( ODM_WIN| ODM_CE )) + + if(pDM_SWAT_Table->try_flag == 0xff) + { + pDM_SWAT_Table->RSSI_target = 0xff; + + #if(DM_ODM_SUPPORT_TYPE & ODM_CE) + { + u1Byte index = 0; + PSTA_INFO_T pEntry = NULL; + + + for(index=0; index<ODM_ASSOCIATE_ENTRY_NUM; index++) + { + pEntry = pDM_Odm->pODM_StaInfo[index]; + if(IS_STA_VALID(pEntry) ) { + break; + } + } + if(pEntry == NULL) + { + ODM_SwAntDivRestAfterLink(pDM_Odm); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): No Link.\n")); + return; + } + else + { + pDM_SWAT_Table->RSSI_target = index; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): RSSI_target is PEER STA\n")); + } + } + #elif (DM_ODM_SUPPORT_TYPE & ODM_WIN) + { + PADAPTER pAdapter = pDM_Odm->Adapter; + PMGNT_INFO pMgntInfo=&pAdapter->MgntInfo; + + // Select RSSI checking target + if(pMgntInfo->mAssoc && !ACTING_AS_AP(pAdapter)) + { + // Target: Infrastructure mode AP. + //pDM_SWAT_Table->RSSI_target = NULL; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("odm_SwAntDivChkAntSwitch(): RSSI_target is DEF AP!\n")); + } + else + { + u1Byte index = 0; + PSTA_INFO_T pEntry = NULL; + PADAPTER pTargetAdapter = NULL; + + if(pMgntInfo->mIbss ) + { + // Target: AP/IBSS peer. + pTargetAdapter = pAdapter; + } + else + { + pTargetAdapter = GetFirstAPAdapter(pAdapter); + } + + if(pTargetAdapter != NULL) + { + for(index=0; index<ODM_ASSOCIATE_ENTRY_NUM; index++) + { + + pEntry = AsocEntry_EnumStation(pTargetAdapter, index); + if(pEntry != NULL) + { + if(pEntry->bAssociated) + break; + } + + } + + } + + if(pEntry == NULL) + { + ODM_SwAntDivRestAfterLink(pDM_Odm); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): No Link.\n")); + return; + } + else + { + //pDM_SWAT_Table->RSSI_target = pEntry; + pDM_SWAT_Table->RSSI_target = index; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): RSSI_target is PEER STA\n")); + } + }//end if(pMgntInfo->mAssoc && !ACTING_AS_AP(Adapter)) + + } + #endif + + pDM_SWAT_Table->RSSI_cnt_A = 0; + pDM_SWAT_Table->RSSI_cnt_B = 0; + pDM_SWAT_Table->try_flag = 0; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("odm_SwAntDivChkAntSwitch(): Set try_flag to 0 prepare for peak!\n")); + return; + } + else + { + +// To Fix 8723A SW ANT DIV Bug issue +#if (DM_ODM_SUPPORT_TYPE==ODM_WIN) + if (pDM_Odm->SupportICType & ODM_RTL8723A) + { + curTxOkCnt = Adapter->TxStats.NumTxBytesUnicast - pDM_SWAT_Table->lastTxOkCnt; + curRxOkCnt =Adapter->RxStats.NumRxBytesUnicast - pDM_SWAT_Table->lastRxOkCnt; + pDM_SWAT_Table->lastTxOkCnt = Adapter->TxStats.NumTxBytesUnicast; + pDM_SWAT_Table->lastRxOkCnt = Adapter->RxStats.NumRxBytesUnicast; + } +#else + curTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast) - pDM_SWAT_Table->lastTxOkCnt; + curRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast) - pDM_SWAT_Table->lastRxOkCnt; + pDM_SWAT_Table->lastTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast); + pDM_SWAT_Table->lastRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast); +#endif + if(pDM_SWAT_Table->try_flag == 1) + { + if(pDM_SWAT_Table->CurAntenna == MAIN_ANT) + { + pDM_SWAT_Table->TXByteCnt_A += curTxOkCnt; + pDM_SWAT_Table->RXByteCnt_A += curRxOkCnt; + } + else + { + pDM_SWAT_Table->TXByteCnt_B += curTxOkCnt; + pDM_SWAT_Table->RXByteCnt_B += curRxOkCnt; + } + + nextAntenna = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? AUX_ANT : MAIN_ANT; + pDM_SWAT_Table->RSSI_Trying--; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("RSSI_Trying = %d\n",pDM_SWAT_Table->RSSI_Trying)); + if(pDM_SWAT_Table->RSSI_Trying == 0) + { + CurByteCnt = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? (pDM_SWAT_Table->TXByteCnt_A+pDM_SWAT_Table->RXByteCnt_A) : (pDM_SWAT_Table->TXByteCnt_B+pDM_SWAT_Table->RXByteCnt_B); + PreByteCnt = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? (pDM_SWAT_Table->TXByteCnt_B+pDM_SWAT_Table->RXByteCnt_B) : (pDM_SWAT_Table->TXByteCnt_A+pDM_SWAT_Table->RXByteCnt_A); + + if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_HIGH) + //CurByteCnt = PlatformDivision64(CurByteCnt, 9); + PreByteCnt = PreByteCnt*9; + else if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_LOW) + //CurByteCnt = PlatformDivision64(CurByteCnt, 2); + PreByteCnt = PreByteCnt*2; + + if(pDM_SWAT_Table->RSSI_cnt_A > 0) + RSSI_A = pDM_SWAT_Table->RSSI_sum_A/pDM_SWAT_Table->RSSI_cnt_A; + else + RSSI_A = 0; + if(pDM_SWAT_Table->RSSI_cnt_B > 0) + RSSI_B = pDM_SWAT_Table->RSSI_sum_B/pDM_SWAT_Table->RSSI_cnt_B; + else + RSSI_B = 0; + curRSSI = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? RSSI_A : RSSI_B; + pDM_SWAT_Table->PreRSSI = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? RSSI_B : RSSI_A; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Luke:PreRSSI = %d, CurRSSI = %d\n",pDM_SWAT_Table->PreRSSI, curRSSI)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: preAntenna= %s, curAntenna= %s \n", + (pDM_SWAT_Table->PreAntenna == MAIN_ANT?"MAIN":"AUX"), (pDM_SWAT_Table->CurAntenna == MAIN_ANT?"MAIN":"AUX"))); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Luke:RSSI_A= %d, RSSI_cnt_A = %d, RSSI_B= %d, RSSI_cnt_B = %d\n", + RSSI_A, pDM_SWAT_Table->RSSI_cnt_A, RSSI_B, pDM_SWAT_Table->RSSI_cnt_B)); + } + + } + else + { + + if(pDM_SWAT_Table->RSSI_cnt_A > 0) + RSSI_A = pDM_SWAT_Table->RSSI_sum_A/pDM_SWAT_Table->RSSI_cnt_A; + else + RSSI_A = 0; + if(pDM_SWAT_Table->RSSI_cnt_B > 0) + RSSI_B = pDM_SWAT_Table->RSSI_sum_B/pDM_SWAT_Table->RSSI_cnt_B; + else + RSSI_B = 0; + curRSSI = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? RSSI_A : RSSI_B; + pDM_SWAT_Table->PreRSSI = (pDM_SWAT_Table->PreAntenna == MAIN_ANT)? RSSI_A : RSSI_B; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ekul:PreRSSI = %d, CurRSSI = %d\n", pDM_SWAT_Table->PreRSSI, curRSSI)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: preAntenna= %s, curAntenna= %s \n", + (pDM_SWAT_Table->PreAntenna == MAIN_ANT?"MAIN":"AUX"), (pDM_SWAT_Table->CurAntenna == MAIN_ANT?"MAIN":"AUX"))); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ekul:RSSI_A= %d, RSSI_cnt_A = %d, RSSI_B= %d, RSSI_cnt_B = %d\n", + RSSI_A, pDM_SWAT_Table->RSSI_cnt_A, RSSI_B, pDM_SWAT_Table->RSSI_cnt_B)); + //RT_TRACE(COMP_SWAS, DBG_LOUD, ("Ekul:curTxOkCnt = %d\n", curTxOkCnt)); + //RT_TRACE(COMP_SWAS, DBG_LOUD, ("Ekul:curRxOkCnt = %d\n", curRxOkCnt)); + } + + //1 Trying State + if((pDM_SWAT_Table->try_flag == 1)&&(pDM_SWAT_Table->RSSI_Trying == 0)) + { + + if(pDM_SWAT_Table->TestMode == TP_MODE) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: TestMode = TP_MODE")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("TRY:CurByteCnt = %lld,", CurByteCnt)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("TRY:PreByteCnt = %lld\n",PreByteCnt)); + if(CurByteCnt < PreByteCnt) + { + if(pDM_SWAT_Table->CurAntenna == MAIN_ANT) + pDM_SWAT_Table->SelectAntennaMap=pDM_SWAT_Table->SelectAntennaMap<<1; + else + pDM_SWAT_Table->SelectAntennaMap=(pDM_SWAT_Table->SelectAntennaMap<<1)+1; + } + else + { + if(pDM_SWAT_Table->CurAntenna == MAIN_ANT) + pDM_SWAT_Table->SelectAntennaMap=(pDM_SWAT_Table->SelectAntennaMap<<1)+1; + else + pDM_SWAT_Table->SelectAntennaMap=pDM_SWAT_Table->SelectAntennaMap<<1; + } + for (i= 0; i<8; i++) + { + if(((pDM_SWAT_Table->SelectAntennaMap>>i)&BIT0) == 1) + Score_A++; + else + Score_B++; + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SelectAntennaMap=%x\n ",pDM_SWAT_Table->SelectAntennaMap)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Score_A=%d, Score_B=%d\n", Score_A, Score_B)); + + if(pDM_SWAT_Table->CurAntenna == MAIN_ANT) + { + nextAntenna = (Score_A > Score_B)?MAIN_ANT:AUX_ANT; + } + else + { + nextAntenna = (Score_B > Score_A)?AUX_ANT:MAIN_ANT; + } + //RT_TRACE(COMP_SWAS, DBG_LOUD, ("nextAntenna=%s\n",(nextAntenna==Antenna_A)?"A":"B")); + //RT_TRACE(COMP_SWAS, DBG_LOUD, ("preAntenna= %s, curAntenna= %s \n", + //(DM_SWAT_Table.PreAntenna == Antenna_A?"A":"B"), (DM_SWAT_Table.CurAntenna == Antenna_A?"A":"B"))); + + if(nextAntenna != pDM_SWAT_Table->CurAntenna) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: Switch back to another antenna")); + } + else + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: current anntena is good\n")); + } + } + + if(pDM_SWAT_Table->TestMode == RSSI_MODE) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: TestMode = RSSI_MODE")); + pDM_SWAT_Table->SelectAntennaMap=0xAA; + if(curRSSI < pDM_SWAT_Table->PreRSSI) //Current antenna is worse than previous antenna + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: Switch back to another antenna")); + nextAntenna = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? AUX_ANT : MAIN_ANT; + } + else // current anntena is good + { + nextAntenna =pDM_SWAT_Table->CurAntenna; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: current anntena is good\n")); + } + } + pDM_SWAT_Table->try_flag = 0; + pDM_Odm->RSSI_test = FALSE; + pDM_SWAT_Table->RSSI_sum_A = 0; + pDM_SWAT_Table->RSSI_cnt_A = 0; + pDM_SWAT_Table->RSSI_sum_B = 0; + pDM_SWAT_Table->RSSI_cnt_B = 0; + pDM_SWAT_Table->TXByteCnt_A = 0; + pDM_SWAT_Table->TXByteCnt_B = 0; + pDM_SWAT_Table->RXByteCnt_A = 0; + pDM_SWAT_Table->RXByteCnt_B = 0; + + } + + //1 Normal State + else if(pDM_SWAT_Table->try_flag == 0) + { + if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_HIGH) + { + if ((curTxOkCnt+curRxOkCnt) > 3750000)//if(PlatformDivision64(curTxOkCnt+curRxOkCnt, 2) > 1875000) + pDM_SWAT_Table->TrafficLoad = TRAFFIC_HIGH; + else + pDM_SWAT_Table->TrafficLoad = TRAFFIC_LOW; + } + else if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_LOW) + { + if ((curTxOkCnt+curRxOkCnt) > 3750000) //if(PlatformDivision64(curTxOkCnt+curRxOkCnt, 2) > 1875000) + pDM_SWAT_Table->TrafficLoad = TRAFFIC_HIGH; + else + pDM_SWAT_Table->TrafficLoad = TRAFFIC_LOW; + } + if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_HIGH) + pDM_SWAT_Table->bTriggerAntennaSwitch = 0; + //RT_TRACE(COMP_SWAS, DBG_LOUD, ("Normal:TrafficLoad = %llu\n", curTxOkCnt+curRxOkCnt)); + + //Prepare To Try Antenna + nextAntenna = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? AUX_ANT : MAIN_ANT; + pDM_SWAT_Table->try_flag = 1; + pDM_Odm->RSSI_test = TRUE; + if((curRxOkCnt+curTxOkCnt) > 1000) + { + pDM_SWAT_Table->RSSI_Trying = 4; + pDM_SWAT_Table->TestMode = TP_MODE; + } + else + { + pDM_SWAT_Table->RSSI_Trying = 2; + pDM_SWAT_Table->TestMode = RSSI_MODE; + + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: Normal State -> Begin Trying!\n")); + + + pDM_SWAT_Table->RSSI_sum_A = 0; + pDM_SWAT_Table->RSSI_cnt_A = 0; + pDM_SWAT_Table->RSSI_sum_B = 0; + pDM_SWAT_Table->RSSI_cnt_B = 0; + } + } + + //1 4.Change TRX antenna + if(nextAntenna != pDM_SWAT_Table->CurAntenna) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("SWAS: Change TX Antenna!\n ")); + //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, nextAntenna); + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + ODM_SetAntenna(pDM_Odm,nextAntenna); + #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + { + BOOLEAN bEnqueue; + bEnqueue = (pDM_Odm->SupportInterface == ODM_ITRF_PCIE)?FALSE :TRUE; + rtw_antenna_select_cmd(pDM_Odm->Adapter, nextAntenna, bEnqueue); + } + #endif + + } + + //1 5.Reset Statistics + pDM_SWAT_Table->PreAntenna = pDM_SWAT_Table->CurAntenna; + pDM_SWAT_Table->CurAntenna = nextAntenna; + pDM_SWAT_Table->PreRSSI = curRSSI; + + //1 6.Set next timer + { + //PADAPTER pAdapter = pDM_Odm->Adapter; + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + + if(pDM_SWAT_Table->RSSI_Trying == 0) + return; + + if(pDM_SWAT_Table->RSSI_Trying%2 == 0) + { + if(pDM_SWAT_Table->TestMode == TP_MODE) + { + if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_HIGH) + { + ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer, 10 ); //ms + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("dm_SW_AntennaSwitch(): Test another antenna for 10 ms\n")); + } + else if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_LOW) + { + ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer, 50 ); //ms + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("dm_SW_AntennaSwitch(): Test another antenna for 50 ms\n")); + } + } + else + { + ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer, 500 ); //ms + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("dm_SW_AntennaSwitch(): Test another antenna for 500 ms\n")); + } + } + else + { + if(pDM_SWAT_Table->TestMode == TP_MODE) + { + if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_HIGH) + ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer, 90 ); //ms + else if(pDM_SWAT_Table->TrafficLoad == TRAFFIC_LOW) + ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer, 100 ); //ms + } + else + ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer, 500 ); //ms + } + } +#endif // #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) +#endif // #if (RTL8192C_SUPPORT==1) +} + + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +u1Byte +odm_SwAntDivSelectScanChnl( + IN PADAPTER Adapter + ) +{ +#if (RT_MEM_SIZE_LEVEL != RT_MEM_SIZE_MINIMUM) + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); + PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + u1Byte i, j, ScanChannel = 0, ChannelNum = 0; + PRT_CHANNEL_LIST pChannelList = GET_RT_CHANNEL_LIST(pMgntInfo); + u1Byte EachChannelSTAs[MAX_SCAN_CHANNEL_NUM] = {0}; + + if(pMgntInfo->tmpNumBssDesc == 0) + return 0; + + for(i = 0; i < pMgntInfo->tmpNumBssDesc; i++) + { + ChannelNum = pMgntInfo->tmpbssDesc[i].ChannelNumber; + for(j = 0; j < pChannelList->ChannelLen; j++) + { + if(pChannelList->ChnlListEntry[j].ChannelNum == ChannelNum) + { + EachChannelSTAs[j]++; + break; + } + } + } + + for(i = 0; i < MAX_SCAN_CHANNEL_NUM; i++) + { + if(EachChannelSTAs[i] > EachChannelSTAs[ScanChannel]) + ScanChannel = i; + } + + if(EachChannelSTAs[ScanChannel] == 0) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, DBG_LOUD, ("odm_SwAntDivSelectScanChnl(): Scan List is empty.\n")); + return 0; + } + + ScanChannel = pChannelList->ChnlListEntry[ScanChannel].ChannelNum; + + + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, DBG_LOUD, + ("odm_SwAntDivSelectScanChnl(): Channel %d is select as scan channel.\n", ScanChannel)); + + return ScanChannel; +#else + return 0; +#endif +} + + +VOID +odm_SwAntDivConstructScanChnl( + IN PADAPTER Adapter, + IN u1Byte ScanChnl + ) +{ + + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + + if(ScanChnl == 0) + { + u1Byte i; + PRT_CHANNEL_LIST pChannelList = GET_RT_CHANNEL_LIST(pMgntInfo); + + // 20100519 Joseph: Original antenna scanned nothing. + // Test antenna shall scan all channel with half period in this condition. + RtActChannelList(Adapter, RT_CHNL_LIST_ACTION_CONSTRUCT_SCAN_LIST, NULL, NULL); + for(i = 0; i < pChannelList->ChannelLen; i++) + pChannelList->ChnlListEntry[i].ScanPeriod /= 2; + } + else + { + // The using of this CustomizedScanRequest is a trick to rescan the two channels + // under the NORMAL scanning process. It will not affect MGNT_INFO.CustomizedScanRequest. + CUSTOMIZED_SCAN_REQUEST CustomScanReq; + + CustomScanReq.bEnabled = TRUE; + CustomScanReq.Channels[0] = ScanChnl; + CustomScanReq.Channels[1] = pMgntInfo->dot11CurrentChannelNumber; + CustomScanReq.nChannels = 2; + CustomScanReq.ScanType = SCAN_ACTIVE; + CustomScanReq.Duration = DEFAULT_PASSIVE_SCAN_PERIOD; + + RtActChannelList(Adapter, RT_CHNL_LIST_ACTION_CONSTRUCT_SCAN_LIST, &CustomScanReq, NULL); + } + +} +#endif //#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +// +// 20100514 Luke/Joseph: +// Callback function for 500ms antenna test trying. +// +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +VOID +odm_SwAntDivChkAntSwitchCallback( + PRT_TIMER pTimer +) +{ + PADAPTER Adapter = (PADAPTER)pTimer->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + pSWAT_T pDM_SWAT_Table = &pHalData->DM_OutSrc.DM_SWAT_Table; + + #if DEV_BUS_TYPE==RT_PCI_INTERFACE + #if USE_WORKITEM + ODM_ScheduleWorkItem(&pDM_SWAT_Table->SwAntennaSwitchWorkitem); + #else + odm_SwAntDivChkAntSwitch(&pHalData->DM_OutSrc, SWAW_STEP_DETERMINE); + #endif + #else + ODM_ScheduleWorkItem(&pDM_SWAT_Table->SwAntennaSwitchWorkitem); + #endif + +} +VOID +odm_SwAntDivChkAntSwitchWorkitemCallback( + IN PVOID pContext + ) +{ + + PADAPTER pAdapter = (PADAPTER)pContext; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + odm_SwAntDivChkAntSwitch(&pHalData->DM_OutSrc, SWAW_STEP_DETERMINE); + +} +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) +VOID odm_SwAntDivChkAntSwitchCallback(void *FunctionContext) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)FunctionContext; + PADAPTER padapter = pDM_Odm->Adapter; + if(padapter->net_closed == _TRUE) + return; + odm_SwAntDivChkAntSwitch(pDM_Odm, SWAW_STEP_DETERMINE); +} +#elif (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) +VOID odm_SwAntDivChkAntSwitchCallback(void *FunctionContext) +{ + PDM_ODM_T pDM_Odm = (PDM_ODM_T)FunctionContext; + odm_SwAntDivChkAntSwitch(pDM_Odm, SWAW_STEP_DETERMINE); +} +#endif + +#else //#if(defined(CONFIG_SW_ANTENNA_DIVERSITY)) + +VOID odm_SwAntDivInit( IN PDM_ODM_T pDM_Odm ) {} +VOID ODM_SwAntDivChkPerPktRssi( + IN PDM_ODM_T pDM_Odm, + IN u1Byte StationID, + IN PODM_PHY_INFO_T pPhyInfo + ) {} +VOID odm_SwAntDivChkAntSwitch( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Step + ) {} +VOID ODM_SwAntDivResetBeforeLink( IN PDM_ODM_T pDM_Odm ){} +VOID ODM_SwAntDivRestAfterLink( IN PDM_ODM_T pDM_Odm ){} +VOID odm_SwAntDetectInit( IN PDM_ODM_T pDM_Odm){} +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +VOID odm_SwAntDivChkAntSwitchCallback( PRT_TIMER pTimer){} +VOID odm_SwAntDivChkAntSwitchWorkitemCallback( IN PVOID pContext ){} +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) +VOID odm_SwAntDivChkAntSwitchCallback(void *FunctionContext){} +#elif (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) +VOID odm_SwAntDivChkAntSwitchCallback(void *FunctionContext){} +#endif + +#endif //#if(defined(CONFIG_SW_ANTENNA_DIVERSITY)) + + + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +BOOLEAN +ODM_SwAntDivCheckBeforeLink( + IN PDM_ODM_T pDM_Odm + ) +{ + +#if (RT_MEM_SIZE_LEVEL != RT_MEM_SIZE_MINIMUM) + + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE* pHalData = GET_HAL_DATA(Adapter); + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + s1Byte Score = 0; + PRT_WLAN_BSS pTmpBssDesc, pTestBssDesc; + s4Byte power_diff = 0, power_target = 10; + u1Byte index, counter = 0; + static u1Byte ScanChannel; + u8Byte tStamp_diff = 0; + + + if (pDM_Odm->Adapter == NULL) //For BSOD when plug/unplug fast. //By YJ,120413 + { // The ODM structure is not initialized. + return FALSE; + } + + // Retrieve antenna detection registry info, added by Roger, 2012.11.27. + if(!IS_ANT_DETECT_SUPPORT_RSSI(Adapter)) + return FALSE; + + // Since driver is going to set BB register, it shall check if there is another thread controlling BB/RF. + PlatformAcquireSpinLock(Adapter, RT_RF_STATE_SPINLOCK); + if(pHalData->eRFPowerState!=eRfOn || pMgntInfo->RFChangeInProgress || pMgntInfo->bMediaConnect) + { + PlatformReleaseSpinLock(Adapter, RT_RF_STATE_SPINLOCK); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, + ("ODM_SwAntDivCheckBeforeLink(): RFChangeInProgress(%x), eRFPowerState(%x)\n", + pMgntInfo->RFChangeInProgress, pHalData->eRFPowerState)); + + pDM_SWAT_Table->SWAS_NoLink_State = 0; + + return FALSE; + } + else + { + PlatformReleaseSpinLock(Adapter, RT_RF_STATE_SPINLOCK); + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("pDM_SWAT_Table->SWAS_NoLink_State = %d\n", pDM_SWAT_Table->SWAS_NoLink_State)); + //1 Run AntDiv mechanism "Before Link" part. + if(pDM_SWAT_Table->SWAS_NoLink_State == 0) + { + //1 Prepare to do Scan again to check current antenna state. + + // Set check state to next step. + pDM_SWAT_Table->SWAS_NoLink_State = 1; + + // Copy Current Scan list. + pMgntInfo->tmpNumBssDesc = pMgntInfo->NumBssDesc; + PlatformMoveMemory((PVOID)Adapter->MgntInfo.tmpbssDesc, (PVOID)pMgntInfo->bssDesc, sizeof(RT_WLAN_BSS)*MAX_BSS_DESC); + + // Go back to scan function again. + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SwAntDivCheckBeforeLink: Scan one more time\n")); + pMgntInfo->ScanStep=0; + pMgntInfo->bScanAntDetect = TRUE; + ScanChannel = odm_SwAntDivSelectScanChnl(Adapter); + + + if(pDM_Odm->SupportICType & (ODM_RTL8188E|ODM_RTL8821)) + { + if(pDM_FatTable->RxIdleAnt == MAIN_ANT) + ODM_UpdateRxIdleAnt(pDM_Odm, AUX_ANT); + else + ODM_UpdateRxIdleAnt(pDM_Odm, MAIN_ANT); + if(ScanChannel == 0) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, + ("ODM_SwAntDivCheckBeforeLink(): No AP List Avaiable, Using Ant(%s)\n", (pDM_FatTable->RxIdleAnt==MAIN_ANT)?"AUX_ANT":"MAIN_ANT")); + + if(IS_5G_WIRELESS_MODE(pMgntInfo->dot11CurrentWirelessMode)) + { + pDM_SWAT_Table->Ant5G = pDM_FatTable->RxIdleAnt; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("pDM_SWAT_Table->Ant5G=%s\n", (pDM_FatTable->RxIdleAnt==MAIN_ANT)?"MAIN_ANT":"AUX_ANT")); + } + else + { + pDM_SWAT_Table->Ant2G = pDM_FatTable->RxIdleAnt; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("pDM_SWAT_Table->Ant2G=%s\n", (pDM_FatTable->RxIdleAnt==MAIN_ANT)?"MAIN_ANT":"AUX_ANT")); + } + return FALSE; + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, + ("ODM_SwAntDivCheckBeforeLink: Change to %s for testing.\n", ((pDM_FatTable->RxIdleAnt == MAIN_ANT)?"MAIN_ANT":"AUX_ANT"))); + } + else if(pDM_Odm->SupportICType & (ODM_RTL8192C|ODM_RTL8723B)) + { + // Switch Antenna to another one. + pDM_SWAT_Table->PreAntenna = pDM_SWAT_Table->CurAntenna; + pDM_SWAT_Table->CurAntenna = (pDM_SWAT_Table->CurAntenna==MAIN_ANT)?AUX_ANT:MAIN_ANT; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, + ("ODM_SwAntDivCheckBeforeLink: Change to Ant(%s) for testing.\n", (pDM_SWAT_Table->CurAntenna==MAIN_ANT)?"MAIN":"AUX")); + //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, DM_SWAT_Table.CurAntenna); + if(pDM_Odm->SupportICType == ODM_RTL8192C) + { + pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 = ((pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 & 0xfffffcff) | (pDM_SWAT_Table->CurAntenna<<8)); + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, bMaskDWord, pDM_SWAT_Table->SWAS_NoLink_BK_Reg860); + } + else if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + pDM_SWAT_Table->SWAS_NoLink_BK_Reg92c = ((pDM_SWAT_Table->SWAS_NoLink_BK_Reg92c & 0xfffffffc) | (pDM_SWAT_Table->CurAntenna)); + ODM_SetBBReg(pDM_Odm, rfe_ctrl_anta_src, 0xff, 0x77); + ODM_SetBBReg(pDM_Odm, rDPDT_control, bMaskDWord, pDM_SWAT_Table->SWAS_NoLink_BK_Reg92c); + } + } + + odm_SwAntDivConstructScanChnl(Adapter, ScanChannel); + PlatformSetTimer(Adapter, &pMgntInfo->ScanTimer, 5); + + return TRUE; + } + else + { + //1 ScanComple() is called after antenna swiched. + //1 Check scan result and determine which antenna is going + //1 to be used. + + for(index = 0; index < pMgntInfo->tmpNumBssDesc; index++) + { + pTmpBssDesc = &(pMgntInfo->tmpbssDesc[index]); // Antenna 1 + pTestBssDesc = &(pMgntInfo->bssDesc[index]); // Antenna 2 + + if(PlatformCompareMemory(pTestBssDesc->bdBssIdBuf, pTmpBssDesc->bdBssIdBuf, 6)!=0) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SwAntDivCheckBeforeLink(): ERROR!! This shall not happen.\n")); + continue; + } + + if(pDM_Odm->SupportICType != ODM_RTL8723B) + { + if(pTmpBssDesc->ChannelNumber == ScanChannel) + { + if(pTmpBssDesc->RecvSignalPower > pTestBssDesc->RecvSignalPower) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SwAntDivCheckBeforeLink: Compare scan entry: Score++\n")); + RT_PRINT_STR(COMP_SCAN, DBG_WARNING, "GetScanInfo(): new Bss SSID:", pTmpBssDesc->bdSsIdBuf, pTmpBssDesc->bdSsIdLen); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("at ch %d, Original: %d, Test: %d\n\n", pTmpBssDesc->ChannelNumber, pTmpBssDesc->RecvSignalPower, pTestBssDesc->RecvSignalPower)); + + Score++; + PlatformMoveMemory(pTestBssDesc, pTmpBssDesc, sizeof(RT_WLAN_BSS)); + } + else if(pTmpBssDesc->RecvSignalPower < pTestBssDesc->RecvSignalPower) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SwAntDivCheckBeforeLink: Compare scan entry: Score--\n")); + RT_PRINT_STR(COMP_SCAN, DBG_WARNING, "GetScanInfo(): new Bss SSID:", pTmpBssDesc->bdSsIdBuf, pTmpBssDesc->bdSsIdLen); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("at ch %d, Original: %d, Test: %d\n\n", pTmpBssDesc->ChannelNumber, pTmpBssDesc->RecvSignalPower, pTestBssDesc->RecvSignalPower)); + Score--; + } + else + { + if(pTestBssDesc->bdTstamp - pTmpBssDesc->bdTstamp < 5000) + { + RT_PRINT_STR(COMP_SCAN, DBG_WARNING, "GetScanInfo(): new Bss SSID:", pTmpBssDesc->bdSsIdBuf, pTmpBssDesc->bdSsIdLen); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("at ch %d, Original: %d, Test: %d\n", pTmpBssDesc->ChannelNumber, pTmpBssDesc->RecvSignalPower, pTestBssDesc->RecvSignalPower)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("The 2nd Antenna didn't get this AP\n\n")); + } + } + } + } + else + { + if(pTmpBssDesc->ChannelNumber == ScanChannel) + { + if(pTmpBssDesc->RecvSignalPower > pTestBssDesc->RecvSignalPower) + { + counter++; + power_diff = power_diff + (pTmpBssDesc->RecvSignalPower - pTestBssDesc->RecvSignalPower); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Original: %d, Test: %d\n", pTmpBssDesc->RecvSignalPower, pTestBssDesc->RecvSignalPower)); + ODM_PRINT_ADDR(pDM_Odm,ODM_COMP_ANT_DIV, DBG_LOUD, ("SSID:"), pTmpBssDesc->bdSsIdBuf); + ODM_PRINT_ADDR(pDM_Odm,ODM_COMP_ANT_DIV, DBG_LOUD, ("BSSID:"), pTmpBssDesc->bdBssIdBuf); + PlatformMoveMemory(pTestBssDesc, pTmpBssDesc, sizeof(RT_WLAN_BSS)); + } + else if(pTestBssDesc->RecvSignalPower > pTmpBssDesc->RecvSignalPower) + { + counter++; + power_diff = power_diff + (pTestBssDesc->RecvSignalPower - pTmpBssDesc->RecvSignalPower); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Original: %d, Test: %d\n", pTmpBssDesc->RecvSignalPower, pTestBssDesc->RecvSignalPower)); + ODM_PRINT_ADDR(pDM_Odm,ODM_COMP_ANT_DIV, DBG_LOUD, ("SSID:"), pTmpBssDesc->bdSsIdBuf); + ODM_PRINT_ADDR(pDM_Odm,ODM_COMP_ANT_DIV, DBG_LOUD, ("BSSID:"), pTmpBssDesc->bdBssIdBuf) + } + else if(pTestBssDesc->bdTstamp > pTmpBssDesc->bdTstamp) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("time_diff: %lld\n", (pTestBssDesc->bdTstamp-pTmpBssDesc->bdTstamp)/1000)); + if(pTestBssDesc->bdTstamp - pTmpBssDesc->bdTstamp > 5000) + { + counter++; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Original: %d, Test: %d\n", pTmpBssDesc->RecvSignalPower, pTestBssDesc->RecvSignalPower)); + ODM_PRINT_ADDR(pDM_Odm,ODM_COMP_ANT_DIV, DBG_LOUD, ("SSID:"), pTmpBssDesc->bdSsIdBuf); + ODM_PRINT_ADDR(pDM_Odm,ODM_COMP_ANT_DIV, DBG_LOUD, ("BSSID:"), pTmpBssDesc->bdBssIdBuf) + } + } + } + } + } + + if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("counter: %d power_diff: %d\n", counter, power_diff)); + + if(counter != 0) + power_diff = power_diff / counter; + + if(power_diff <= power_target && counter != 0) + Score++; + } + + if(pDM_Odm->SupportICType & (ODM_RTL8188E|ODM_RTL8821)) + { + if(pMgntInfo->NumBssDesc!=0 && Score<0) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, + ("ODM_SwAntDivCheckBeforeLink(): Using Ant(%s)\n", (pDM_FatTable->RxIdleAnt==MAIN_ANT)?"MAIN_ANT":"AUX_ANT")); + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, + ("ODM_SwAntDivCheckBeforeLink(): Remain Ant(%s)\n", (pDM_FatTable->RxIdleAnt==MAIN_ANT)?"AUX_ANT":"MAIN_ANT")); + + if(pDM_FatTable->RxIdleAnt == MAIN_ANT) + ODM_UpdateRxIdleAnt(pDM_Odm, AUX_ANT); + else + ODM_UpdateRxIdleAnt(pDM_Odm, MAIN_ANT); + } + + if(IS_5G_WIRELESS_MODE(pMgntInfo->dot11CurrentWirelessMode)) + { + pDM_SWAT_Table->Ant5G = pDM_FatTable->RxIdleAnt; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("pDM_SWAT_Table->Ant5G=%s\n", (pDM_FatTable->RxIdleAnt==MAIN_ANT)?"MAIN_ANT":"AUX_ANT")); + } + else + { + pDM_SWAT_Table->Ant2G = pDM_FatTable->RxIdleAnt; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("pDM_SWAT_Table->Ant2G=%s\n", (pDM_FatTable->RxIdleAnt==MAIN_ANT)?"MAIN_ANT":"AUX_ANT")); + } + } + else if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + pDM_SWAT_Table->CurAntenna = pDM_SWAT_Table->PreAntenna; + pDM_SWAT_Table->SWAS_NoLink_BK_Reg92c = ((pDM_SWAT_Table->SWAS_NoLink_BK_Reg92c & 0xfffffffc) | (pDM_SWAT_Table->CurAntenna)); + ODM_SetBBReg(pDM_Odm, rfe_ctrl_anta_src, 0xff, 0x77); + ODM_SetBBReg(pDM_Odm, rDPDT_control,bMaskDWord, pDM_SWAT_Table->SWAS_NoLink_BK_Reg92c); + + if(counter != 0) + { + if(pMgntInfo->NumBssDesc != 0 && Score > 0) + { + if(pDM_Odm->DM_SWAT_Table.ANTB_ON == FALSE) + { + pDM_Odm->DM_SWAT_Table.ANTA_ON = TRUE; + pDM_Odm->DM_SWAT_Table.ANTB_ON = TRUE; + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("ODM_SwAntDivCheckBeforeLink(): Dual antenna\n")); + } + else + { + if(pDM_Odm->DM_SWAT_Table.ANTB_ON == TRUE) + { + pDM_Odm->DM_SWAT_Table.ANTA_ON = TRUE; + pDM_Odm->DM_SWAT_Table.ANTB_ON = FALSE; + BT_SetBtCoexAntNum(Adapter, BT_COEX_ANT_TYPE_DETECTED, 1); + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SwAntDivCheckBeforeLink(): Single antenna\n")); + } + } + else + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("ODM_SwAntDivCheckBeforeLink(): Igone result\n")); + } + else if(pDM_Odm->SupportICType == ODM_RTL8192C) + { + if(pMgntInfo->NumBssDesc!=0 && Score<=0) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, + ("ODM_SwAntDivCheckBeforeLink(): Using Ant(%s)\n", (pDM_SWAT_Table->CurAntenna==MAIN_ANT)?"MAIN":"AUX")); + + pDM_SWAT_Table->PreAntenna = pDM_SWAT_Table->CurAntenna; + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, + ("ODM_SwAntDivCheckBeforeLink(): Remain Ant(%s)\n", (pDM_SWAT_Table->CurAntenna==MAIN_ANT)?"AUX":"MAIN")); + + pDM_SWAT_Table->CurAntenna = pDM_SWAT_Table->PreAntenna; + + //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, DM_SWAT_Table.CurAntenna); + pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 = ((pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 & 0xfffffcff) | (pDM_SWAT_Table->CurAntenna<<8)); + PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, bMaskDWord, pDM_SWAT_Table->SWAS_NoLink_BK_Reg860); + } + } + + // Check state reset to default and wait for next time. + pDM_SWAT_Table->SWAS_NoLink_State = 0; + pMgntInfo->bScanAntDetect = FALSE; + + return FALSE; + } + +#else + return FALSE; +#endif + +return FALSE; +} + +#endif //#if(DM_ODM_SUPPORT_TYPE==ODM_WIN) + + +//3============================================================ +//3 SW Antenna Diversity +//3============================================================ + +#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) +VOID +odm_InitHybridAntDiv_88C_92D( + IN PDM_ODM_T pDM_Odm + ) +{ + +#if((DM_ODM_SUPPORT_TYPE==ODM_AP)||(DM_ODM_SUPPORT_TYPE==ODM_ADSL)) + struct rtl8192cd_priv *priv=pDM_Odm->priv; +#endif + SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + u1Byte bTxPathSel=0; //0:Path-A 1:Path-B + u1Byte i; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_InitHybridAntDiv==============>\n")); + + //whether to do antenna diversity or not +#if(DM_ODM_SUPPORT_TYPE==ODM_AP) + if(priv==NULL) return; + if(!priv->pshare->rf_ft_var.antHw_enable) + return; + + #ifdef SW_ANT_SWITCH + priv->pshare->rf_ft_var.antSw_enable =0; + #endif +#endif + + if((pDM_Odm->SupportICType != ODM_RTL8192C) && (pDM_Odm->SupportICType != ODM_RTL8192D)) + return; + + + bTxPathSel=(pDM_Odm->RFType==ODM_1T1R)?FALSE:TRUE; + + ODM_SetBBReg(pDM_Odm,ODM_REG_BB_PWR_SAV1_11N, BIT23, 0); //No update ANTSEL during GNT_BT=1 + ODM_SetBBReg(pDM_Odm,ODM_REG_TX_ANT_CTRL_11N, BIT21, 1); //TX atenna selection from tx_info + ODM_SetBBReg(pDM_Odm,ODM_REG_ANTSEL_PIN_11N, BIT23, 1); //enable LED[1:0] pin as ANTSEL + ODM_SetBBReg(pDM_Odm,ODM_REG_ANTSEL_CTRL_11N, BIT8|BIT9, 0x01); // 0x01: left antenna, 0x02: right antenna + // check HW setting: ANTSEL pin connection + #if(DM_ODM_SUPPORT_TYPE==ODM_AP) + ODM_Write2Byte(pDM_Odm,ODM_REG_RF_PIN_11N, (ODM_Read2Byte(pDM_Odm,0x804)&0xf0ff )| BIT(8) ); // b11-b8=0001,update RFPin setting + #endif + + // only AP support different path selection temperarly + if(!bTxPathSel){ //PATH-A + ODM_SetBBReg(pDM_Odm,ODM_REG_PIN_CTRL_11N, BIT8|BIT9, 0 ); // ANTSEL as HW control + ODM_SetBBReg(pDM_Odm,ODM_REG_ANTSEL_PATH_11N, BIT13, 1); //select TX ANTESEL from path A + } + else { + ODM_SetBBReg(pDM_Odm,ODM_REG_PIN_CTRL_11N, BIT24|BIT25, 0 ); // ANTSEL as HW control + ODM_SetBBReg(pDM_Odm,ODM_REG_ANTSEL_PATH_11N, BIT13, 0); //select ANTESEL from path B + } + + //Set OFDM HW RX Antenna Diversity + ODM_SetBBReg(pDM_Odm,ODM_REG_ANTDIV_PARA1_11N, 0x7FF, 0x0c0); //Pwdb threshold=8dB + ODM_SetBBReg(pDM_Odm,ODM_REG_ANTDIV_PARA1_11N, BIT11, 0); //Switch to another antenna by checking pwdb threshold + ODM_SetBBReg(pDM_Odm,ODM_REG_ANTDIV_PARA3_11N, BIT23, 1); // Decide final antenna by comparing 2 antennas' pwdb + + //Set CCK HW RX Antenna Diversity + ODM_SetBBReg(pDM_Odm,ODM_REG_CCK_ANTDIV_PARA2_11N, BIT4, 0); //Antenna diversity decision period = 32 sample + ODM_SetBBReg(pDM_Odm,ODM_REG_CCK_ANTDIV_PARA2_11N, 0xf, 0xf); //Threshold for antenna diversity. Check another antenna power if input power < ANT_lim*4 + ODM_SetBBReg(pDM_Odm,ODM_REG_CCK_ANTDIV_PARA3_11N, BIT13, 1); //polarity ana_A=1 and ana_B=0 + ODM_SetBBReg(pDM_Odm,ODM_REG_CCK_ANTDIV_PARA4_11N, 0x1f, 0x8); //default antenna power = inpwr*(0.5 + r_ant_step/16) + + + //Enable HW Antenna Diversity + if(!bTxPathSel) //PATH-A + ODM_SetBBReg(pDM_Odm,ODM_REG_IGI_A_11N, BIT7,1); // Enable Hardware antenna switch + else + ODM_SetBBReg(pDM_Odm,ODM_REG_IGI_B_11N, BIT7,1); // Enable Hardware antenna switch + ODM_SetBBReg(pDM_Odm,ODM_REG_CCK_ANTDIV_PARA1_11N, BIT15, 1);//Enable antenna diversity + + pDM_SWAT_Table->CurAntenna=0; //choose left antenna as default antenna + pDM_SWAT_Table->PreAntenna=0; + for(i=0; i<ASSOCIATE_ENTRY_NUM ; i++) + { + pDM_SWAT_Table->CCK_Ant1_Cnt[i] = 0; + pDM_SWAT_Table->CCK_Ant2_Cnt[i] = 0; + pDM_SWAT_Table->OFDM_Ant1_Cnt[i] = 0; + pDM_SWAT_Table->OFDM_Ant2_Cnt[i] = 0; + pDM_SWAT_Table->RSSI_Ant1_Sum[i] = 0; + pDM_SWAT_Table->RSSI_Ant2_Sum[i] = 0; + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("<==============odm_InitHybridAntDiv\n")); +} + + +VOID +odm_InitHybridAntDiv( + IN PDM_ODM_T pDM_Odm + ) +{ + if(!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("Return: Not Support HW AntDiv\n")); + return; + } + + if(pDM_Odm->SupportICType & (ODM_RTL8192C | ODM_RTL8192D)) + { +#if ((RTL8192C_SUPPORT == 1)||(RTL8192D_SUPPORT == 1)) + odm_InitHybridAntDiv_88C_92D(pDM_Odm); +#endif + } +} + + +BOOLEAN +odm_StaDefAntSel( + IN PDM_ODM_T pDM_Odm, + IN u4Byte OFDM_Ant1_Cnt, + IN u4Byte OFDM_Ant2_Cnt, + IN u4Byte CCK_Ant1_Cnt, + IN u4Byte CCK_Ant2_Cnt, + OUT u1Byte *pDefAnt + + ) +{ +#if 1 + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_StaDefAntSelect==============>\n")); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("OFDM_Ant1_Cnt:%d, OFDM_Ant2_Cnt:%d\n",OFDM_Ant1_Cnt,OFDM_Ant2_Cnt)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("CCK_Ant1_Cnt:%d, CCK_Ant2_Cnt:%d\n",CCK_Ant1_Cnt,CCK_Ant2_Cnt)); + + + if(((OFDM_Ant1_Cnt+OFDM_Ant2_Cnt)==0)&&((CCK_Ant1_Cnt + CCK_Ant2_Cnt) <10)){ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_StaDefAntSelect Fail: No enough packet info!\n")); + return FALSE; + } + + if(OFDM_Ant1_Cnt || OFDM_Ant2_Cnt ) { + //if RX OFDM packet number larger than 0 + if(OFDM_Ant1_Cnt > OFDM_Ant2_Cnt) + (*pDefAnt)=1; + else + (*pDefAnt)=0; + } + // else if RX CCK packet number larger than 10 + else if((CCK_Ant1_Cnt + CCK_Ant2_Cnt) >=10 ) + { + if(CCK_Ant1_Cnt > (5*CCK_Ant2_Cnt)) + (*pDefAnt)=1; + else if(CCK_Ant2_Cnt > (5*CCK_Ant1_Cnt)) + (*pDefAnt)=0; + else if(CCK_Ant1_Cnt > CCK_Ant2_Cnt) + (*pDefAnt)=0; + else + (*pDefAnt)=1; + + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("TxAnt = %s\n",((*pDefAnt)==1)?"Ant1":"Ant2")); + +#endif + //u4Byte antsel = ODM_GetBBReg(pDM_Odm, 0xc88, bMaskByte0); + //(*pDefAnt)= (u1Byte) antsel; + + + + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("<==============odm_StaDefAntSelect\n")); + + return TRUE; + + +} + + +VOID +odm_SetRxIdleAnt( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Ant, + IN BOOLEAN bDualPath +) +{ + SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + + //ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_SetRxIdleAnt==============>\n")); + + if(Ant != pDM_SWAT_Table->RxIdleAnt) + { + //for path-A + if(Ant==1) + ODM_SetBBReg(pDM_Odm,ODM_REG_RX_DEFUALT_A_11N, 0xFFFF, 0x65a9); //right-side antenna + else + ODM_SetBBReg(pDM_Odm,ODM_REG_RX_DEFUALT_A_11N, 0xFFFF, 0x569a); //left-side antenna + + //for path-B + if(bDualPath){ + if(Ant==0) + ODM_SetBBReg(pDM_Odm,ODM_REG_RX_DEFUALT_A_11N, 0xFFFF0000, 0x65a9); //right-side antenna + else + ODM_SetBBReg(pDM_Odm,ODM_REG_RX_DEFUALT_A_11N, 0xFFFF0000, 0x569a); //left-side antenna + } + } + pDM_SWAT_Table->RxIdleAnt = Ant; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("RxIdleAnt: %s Reg858=0x%x\n",(Ant==1)?"Ant1":"Ant2",(Ant==1)?0x65a9:0x569a)); + + //ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("<==============odm_SetRxIdleAnt\n")); + + } + +VOID +ODM_AntselStatistics_88C( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacId, + IN u4Byte PWDBAll, + IN BOOLEAN isCCKrate +) +{ + SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + + if(pDM_SWAT_Table->antsel == 1) + { + if(isCCKrate) + pDM_SWAT_Table->CCK_Ant1_Cnt[MacId]++; + else + { + pDM_SWAT_Table->OFDM_Ant1_Cnt[MacId]++; + pDM_SWAT_Table->RSSI_Ant1_Sum[MacId] += PWDBAll; + } + } + else + { + if(isCCKrate) + pDM_SWAT_Table->CCK_Ant2_Cnt[MacId]++; + else + { + pDM_SWAT_Table->OFDM_Ant2_Cnt[MacId]++; + pDM_SWAT_Table->RSSI_Ant2_Sum[MacId] += PWDBAll; + } + } + +} + + + + +#if(DM_ODM_SUPPORT_TYPE==ODM_WIN) +VOID +ODM_SetTxAntByTxInfo_88C_92D( + IN PDM_ODM_T pDM_Odm, + IN pu1Byte pDesc, + IN u1Byte macId +) +{ + SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + u1Byte antsel; + + if(!(pDM_Odm->SupportAbility&ODM_BB_ANT_DIV)) + return; + + if(pDM_SWAT_Table->RxIdleAnt == 1) + antsel=(pDM_SWAT_Table->TxAnt[macId] == 1)?0:1; + else + antsel=(pDM_SWAT_Table->TxAnt[macId] == 1)?1:0; + + SET_TX_DESC_ANTSEL_A_92C(pDesc, antsel); + //SET_TX_DESC_ANTSEL_B_92C(pDesc, antsel); + //ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("SET_TX_DESC_ANTSEL_A_92C=%d\n", pDM_SWAT_Table->TxAnt[macId])); +} +#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) +VOID +ODM_SetTxAntByTxInfo_88C_92D( + IN PDM_ODM_T pDM_Odm +) +{ + +} +#elif(DM_ODM_SUPPORT_TYPE==ODM_AP) +VOID +ODM_SetTxAntByTxInfo_88C_92D( + IN PDM_ODM_T pDM_Odm +) +{ + +} +#endif + +VOID +odm_HwAntDiv_92C_92D( + IN PDM_ODM_T pDM_Odm +) +{ + SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + u4Byte RSSI_Min=0xFF, RSSI, RSSI_Ant1, RSSI_Ant2; + u1Byte RxIdleAnt, i; + BOOLEAN bRet=FALSE; + PSTA_INFO_T pEntry; + +#if (DM_ODM_SUPPORT_TYPE==ODM_AP) + struct rtl8192cd_priv *priv=pDM_Odm->priv; + //if test, return + if(priv->pshare->rf_ft_var.CurAntenna & 0x80) + return; +#endif + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_HwAntDiv==============>\n")); + + if(!(pDM_Odm->SupportAbility&ODM_BB_ANT_DIV)) //if don't support antenna diveristy + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_HwAntDiv: Not supported!\n")); + return; + } + + if((pDM_Odm->SupportICType != ODM_RTL8192C) && (pDM_Odm->SupportICType != ODM_RTL8192D)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("Return: IC Type is not 92C or 92D\n")); + return; + } + +#if (DM_ODM_SUPPORT_TYPE&(ODM_WIN|ODM_CE)) + if(!pDM_Odm->bLinked) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("Return: bLinked is FALSE\n")); + return; + } +#endif + + for (i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++) + { + pEntry = pDM_Odm->pODM_StaInfo[i]; + if(IS_STA_VALID(pEntry)) + { + + RSSI_Ant1 = (pDM_SWAT_Table->OFDM_Ant1_Cnt[i] == 0)?0:(pDM_SWAT_Table->RSSI_Ant1_Sum[i]/pDM_SWAT_Table->OFDM_Ant1_Cnt[i]); + RSSI_Ant2 = (pDM_SWAT_Table->OFDM_Ant2_Cnt[i] == 0)?0:(pDM_SWAT_Table->RSSI_Ant2_Sum[i]/pDM_SWAT_Table->OFDM_Ant2_Cnt[i]); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("RSSI_Ant1=%d, RSSI_Ant2=%d\n", RSSI_Ant1, RSSI_Ant2)); + + if(RSSI_Ant1 ||RSSI_Ant2) + { +#if (DM_ODM_SUPPORT_TYPE==ODM_AP) + if(pDM_Odm->pODM_StaInfo[i]->expire_to) +#endif + { + RSSI = (RSSI_Ant1 < RSSI_Ant2) ? RSSI_Ant1 : RSSI_Ant2; + if((!RSSI) || ( RSSI < RSSI_Min) ) { + pDM_SWAT_Table->TargetSTA = i; + RSSI_Min = RSSI; + } + } + } + ///STA: found out default antenna + bRet=odm_StaDefAntSel(pDM_Odm, + pDM_SWAT_Table->OFDM_Ant1_Cnt[i], + pDM_SWAT_Table->OFDM_Ant2_Cnt[i], + pDM_SWAT_Table->CCK_Ant1_Cnt[i], + pDM_SWAT_Table->CCK_Ant2_Cnt[i], + &pDM_SWAT_Table->TxAnt[i]); + + //if Tx antenna selection: successful + if(bRet){ + pDM_SWAT_Table->RSSI_Ant1_Sum[i] = 0; + pDM_SWAT_Table->RSSI_Ant2_Sum[i] = 0; + pDM_SWAT_Table->OFDM_Ant1_Cnt[i] = 0; + pDM_SWAT_Table->OFDM_Ant2_Cnt[i] = 0; + pDM_SWAT_Table->CCK_Ant1_Cnt[i] = 0; + pDM_SWAT_Table->CCK_Ant2_Cnt[i] = 0; + } + } + } + + //set RX Idle Ant + RxIdleAnt = pDM_SWAT_Table->TxAnt[pDM_SWAT_Table->TargetSTA]; + odm_SetRxIdleAnt(pDM_Odm, RxIdleAnt, FALSE); + +#if (DM_ODM_SUPPORT_TYPE==ODM_AP) +#ifdef TX_SHORTCUT + if (!priv->pmib->dot11OperationEntry.disable_txsc) { + plist = phead->next; + while(plist != phead) { + pstat = list_entry(plist, struct stat_info, asoc_list); + if(pstat->expire_to) { + for (i=0; i<TX_SC_ENTRY_NUM; i++) { + struct tx_desc *pdesc= &(pstat->tx_sc_ent[i].hwdesc1); + pdesc->Dword2 &= set_desc(~ (BIT(24)|BIT(25))); + if((pstat->CurAntenna^priv->pshare->rf_ft_var.CurAntenna)&1) + pdesc->Dword2 |= set_desc(BIT(24)|BIT(25)); + pdesc= &(pstat->tx_sc_ent[i].hwdesc2); + pdesc->Dword2 &= set_desc(~ (BIT(24)|BIT(25))); + if((pstat->CurAntenna^priv->pshare->rf_ft_var.CurAntenna)&1) + pdesc->Dword2 |= set_desc(BIT(24)|BIT(25)); + } + } + + if (plist == plist->next) + break; + plist = plist->next; + }; + } +#endif +#endif + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("<==============odm_HwAntDiv\n")); + +} + +VOID +odm_HwAntDiv( + IN PDM_ODM_T pDM_Odm +) +{ + + PADAPTER pAdapter = pDM_Odm->Adapter; + +#if(DM_ODM_SUPPORT_TYPE==ODM_WIN) + if(pAdapter->MgntInfo.AntennaTest) + return; +#endif + if(!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("Return: Not Support HW AntDiv\n")); + return; + } + + if(pDM_Odm->SupportICType & (ODM_RTL8192C | ODM_RTL8192D)) + { +#if ((RTL8192C_SUPPORT == 1)||(RTL8192D_SUPPORT == 1)) + odm_HwAntDiv_92C_92D(pDM_Odm); +#endif + } +} + + +#if(DM_ODM_SUPPORT_TYPE==ODM_AP) +#if 0 +VOID +odm_HwAntDiv( + IN PDM_ODM_T pDM_Odm +) +{ + struct rtl8192cd_priv *priv=pDM_Odm->priv; + struct stat_info *pstat, *pstat_min=NULL; + struct list_head *phead, *plist; + int rssi_min= 0xff, i; + u1Byte idleAnt=priv->pshare->rf_ft_var.CurAntenna; + u1Byte nextAnt; + BOOLEAN bRet=FALSE; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("odm_HwAntDiv==============>\n")); + + if((!priv->pshare->rf_ft_var.antHw_enable) ||(!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV))) + return; + + //if test, return + if(priv->pshare->rf_ft_var.CurAntenna & 0x80) + return; + + phead = &priv->asoc_list; + plist = phead->next; + ////========================= + //find mimum rssi sta + ////========================= + while(plist != phead) { + pstat = list_entry(plist, struct stat_info, asoc_list); + if((pstat->expire_to) && (pstat->AntRSSI[0] || pstat->AntRSSI[1])) { + int rssi = (pstat->AntRSSI[0] < pstat->AntRSSI[1]) ? pstat->AntRSSI[0] : pstat->AntRSSI[1]; + if((!pstat_min) || ( rssi < rssi_min) ) { + pstat_min = pstat; + rssi_min = rssi; + } + } + ///STA: found out default antenna + bRet=odm_StaDefAntSel(pDM_Odm, + pstat->hwRxAntSel[1], + pstat->hwRxAntSel[0], + pstat->cckPktCount[1], + pstat->cckPktCount[0], + &nextAnt + ); + + //if default antenna selection: successful + if(bRet){ + pstat->CurAntenna = nextAnt; + //update rssi + for(i=0; i<2; i++) { + if(pstat->cckPktCount[i]==0 && pstat->hwRxAntSel[i]==0) + pstat->AntRSSI[i] = 0; + } + if(pstat->AntRSSI[idleAnt]==0) + pstat->AntRSSI[idleAnt] = pstat->AntRSSI[idleAnt^1]; + // reset variables + pstat->hwRxAntSel[1] = pstat->hwRxAntSel[0] =0; + pstat->cckPktCount[1]= pstat->cckPktCount[0] =0; + } + + if (plist == plist->next) + break; + plist = plist->next; + + }; + ////========================= + //Choose RX Idle antenna according to minmum rssi + ////========================= + if(pstat_min) { + if(priv->pshare->rf_ft_var.CurAntenna!=pstat_min->CurAntenna) + odm_SetRxIdleAnt(pDM_Odm,pstat_min->CurAntenna,TRUE); + priv->pshare->rf_ft_var.CurAntenna = pstat_min->CurAntenna; + } + + +#ifdef TX_SHORTCUT + if (!priv->pmib->dot11OperationEntry.disable_txsc) { + plist = phead->next; + while(plist != phead) { + pstat = list_entry(plist, struct stat_info, asoc_list); + if(pstat->expire_to) { + for (i=0; i<TX_SC_ENTRY_NUM; i++) { + struct tx_desc *pdesc= &(pstat->tx_sc_ent[i].hwdesc1); + pdesc->Dword2 &= set_desc(~ (BIT(24)|BIT(25))); + if((pstat->CurAntenna^priv->pshare->rf_ft_var.CurAntenna)&1) + pdesc->Dword2 |= set_desc(BIT(24)|BIT(25)); + pdesc= &(pstat->tx_sc_ent[i].hwdesc2); + pdesc->Dword2 &= set_desc(~ (BIT(24)|BIT(25))); + if((pstat->CurAntenna^priv->pshare->rf_ft_var.CurAntenna)&1) + pdesc->Dword2 |= set_desc(BIT(24)|BIT(25)); + } + } + + if (plist == plist->next) + break; + plist = plist->next; + }; + } +#endif + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,"<==============odm_HwAntDiv\n"); +} +#endif + +u1Byte +ODM_Diversity_AntennaSelect( + IN PDM_ODM_T pDM_Odm, + IN u1Byte *data +) +{ + struct rtl8192cd_priv *priv=pDM_Odm->priv; + + int ant = _atoi(data, 16); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("ODM_Diversity_AntennaSelect==============>\n")); + + #ifdef PCIE_POWER_SAVING + PCIeWakeUp(priv, POWER_DOWN_T0); + #endif + + if (ant==AUX_ANT || ant==MAIN_ANT) + { + if ( !priv->pshare->rf_ft_var.antSw_select) { + ODM_Write4Byte(pDM_Odm,0x870, ODM_Read4Byte(pDM_Odm,0x870) | BIT(8)| BIT(9) ); // ANTSEL A as SW control + ODM_Write1Byte(pDM_Odm,0xc50, ODM_Read1Byte(pDM_Odm,0xc50) & (~ BIT(7))); // rx OFDM SW control + PHY_SetBBReg(priv, 0x860, 0x300, ant); + } else { + ODM_Write4Byte(pDM_Odm,0x870, ODM_Read4Byte(pDM_Odm,0x870) | BIT(24)| BIT(25) ); // ANTSEL B as HW control + PHY_SetBBReg(priv, 0x864, 0x300, ant); + ODM_Write1Byte(pDM_Odm,0xc58, ODM_Read1Byte(pDM_Odm,0xc58) & (~ BIT(7))); // rx OFDM SW control + } + + ODM_Write1Byte(pDM_Odm,0xa01, ODM_Read1Byte(pDM_Odm,0xa01) & (~ BIT(7))); // rx CCK SW control + ODM_Write4Byte(pDM_Odm,0x80c, ODM_Read4Byte(pDM_Odm,0x80c) & (~ BIT(21))); // select ant by tx desc + ODM_Write4Byte(pDM_Odm,0x858, 0x569a569a); + + priv->pshare->rf_ft_var.antHw_enable = 0; + priv->pshare->rf_ft_var.CurAntenna = (ant%2); + + #ifdef SW_ANT_SWITCH + priv->pshare->rf_ft_var.antSw_enable = 0; + priv->pshare->DM_SWAT_Table.CurAntenna = ant; + priv->pshare->RSSI_test =0; + #endif + } + else if(ant==0){ + + if ( !priv->pshare->rf_ft_var.antSw_select) { + ODM_Write4Byte(pDM_Odm,0x870, ODM_Read4Byte(pDM_Odm,0x870) & ~(BIT(8)| BIT(9)) ); + ODM_Write1Byte(pDM_Odm,0xc50, ODM_Read1Byte(pDM_Odm,0xc50) | BIT(7)); // OFDM HW control + } else { + ODM_Write4Byte(pDM_Odm,0x870, ODM_Read4Byte(pDM_Odm,0x870) & ~(BIT(24)| BIT(25)) ); + ODM_Write1Byte(pDM_Odm,0xc58, ODM_Read1Byte(pDM_Odm,0xc58) | BIT(7)); // OFDM HW control + } + + ODM_Write1Byte(pDM_Odm,0xa01, ODM_Read1Byte(pDM_Odm,0xa01) | BIT(7)); // CCK HW control + ODM_Write4Byte(pDM_Odm,0x80c, ODM_Read4Byte(pDM_Odm,0x80c) | BIT(21) ); // by tx desc + priv->pshare->rf_ft_var.CurAntenna = 0; + ODM_Write4Byte(pDM_Odm,0x858, 0x569a569a); + priv->pshare->rf_ft_var.antHw_enable = 1; +#ifdef SW_ANT_SWITCH + priv->pshare->rf_ft_var.antSw_enable = 0; + priv->pshare->RSSI_test =0; +#endif + } +#ifdef SW_ANT_SWITCH + else if(ant==3) { + if(!priv->pshare->rf_ft_var.antSw_enable) { + + dm_SW_AntennaSwitchInit(priv); + ODM_Write4Byte(pDM_Odm,0x858, 0x569a569a); + priv->pshare->lastTxOkCnt = priv->net_stats.tx_bytes; + priv->pshare->lastRxOkCnt = priv->net_stats.rx_bytes; + } + if ( !priv->pshare->rf_ft_var.antSw_select) + ODM_Write1Byte(pDM_Odm,0xc50, ODM_Read1Byte(pDM_Odm,0xc50) & (~ BIT(7))); // rx OFDM SW control + else + ODM_Write1Byte(pDM_Odm,0xc58, ODM_Read1Byte(pDM_Odm,0xc58) & (~ BIT(7))); // rx OFDM SW control + + ODM_Write1Byte(pDM_Odm,0xa01, ODM_Read1Byte(pDM_Odm,0xa01) & (~ BIT(7))); // rx CCK SW control + ODM_Write4Byte(pDM_Odm,0x80c, ODM_Read4Byte(pDM_Odm,0x80c) & (~ BIT(21))); // select ant by tx desc + priv->pshare->rf_ft_var.antHw_enable = 0; + priv->pshare->rf_ft_var.antSw_enable = 1; + + } +#endif + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("<==============ODM_Diversity_AntennaSelect\n")); + + return 1; +} +#endif + +#else //#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) + +VOID odm_InitHybridAntDiv( IN PDM_ODM_T pDM_Odm ){} +VOID odm_HwAntDiv( IN PDM_ODM_T pDM_Odm){} +#if(DM_ODM_SUPPORT_TYPE==ODM_WIN) +VOID ODM_SetTxAntByTxInfo_88C_92D( + IN PDM_ODM_T pDM_Odm, + IN pu1Byte pDesc, + IN u1Byte macId +){} +#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) +VOID ODM_SetTxAntByTxInfo_88C_92D( IN PDM_ODM_T pDM_Odm){ } +#elif(DM_ODM_SUPPORT_TYPE==ODM_AP) +VOID ODM_SetTxAntByTxInfo_88C_92D( IN PDM_ODM_T pDM_Odm){ } +#endif + +#endif //#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) + + + +//============================================================ +//EDCA Turbo +//============================================================ +VOID +ODM_EdcaTurboInit( + IN PDM_ODM_T pDM_Odm) +{ + +#if ((DM_ODM_SUPPORT_TYPE == ODM_AP)||(DM_ODM_SUPPORT_TYPE==ODM_ADSL)) + odm_EdcaParaInit(pDM_Odm); +#elif (DM_ODM_SUPPORT_TYPE==ODM_WIN) + PADAPTER Adapter = NULL; + HAL_DATA_TYPE *pHalData = NULL; + + if(pDM_Odm->Adapter==NULL) { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("EdcaTurboInit fail!!!\n")); + return; + } + + Adapter=pDM_Odm->Adapter; + pHalData=GET_HAL_DATA(Adapter); + + pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = FALSE; + pDM_Odm->DM_EDCA_Table.bIsCurRDLState = FALSE; + pHalData->bIsAnyNonBEPkts = FALSE; + +#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = FALSE; + pDM_Odm->DM_EDCA_Table.bIsCurRDLState = FALSE; + Adapter->recvpriv.bIsAnyNonBEPkts =FALSE; + +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Orginial VO PARAM: 0x%x\n",ODM_Read4Byte(pDM_Odm,ODM_EDCA_VO_PARAM))); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Orginial VI PARAM: 0x%x\n",ODM_Read4Byte(pDM_Odm,ODM_EDCA_VI_PARAM))); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Orginial BE PARAM: 0x%x\n",ODM_Read4Byte(pDM_Odm,ODM_EDCA_BE_PARAM))); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Orginial BK PARAM: 0x%x\n",ODM_Read4Byte(pDM_Odm,ODM_EDCA_BK_PARAM))); + + +} // ODM_InitEdcaTurbo + +VOID +odm_EdcaTurboCheck( + IN PDM_ODM_T pDM_Odm + ) +{ + // + // For AP/ADSL use prtl8192cd_priv + // For CE/NIC use PADAPTER + // + + // + // 2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate + // at the same time. In the stage2/3, we need to prive universal interface and merge all + // HW dynamic mechanism. + // + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("odm_EdcaTurboCheck========================>\n")); + + if(!(pDM_Odm->SupportAbility& ODM_MAC_EDCA_TURBO )) + return; + + switch (pDM_Odm->SupportPlatform) + { + case ODM_WIN: + +#if(DM_ODM_SUPPORT_TYPE==ODM_WIN) + odm_EdcaTurboCheckMP(pDM_Odm); +#endif + break; + + case ODM_CE: +#if(DM_ODM_SUPPORT_TYPE==ODM_CE) + odm_EdcaTurboCheckCE(pDM_Odm); +#endif + break; + + case ODM_AP: + case ODM_ADSL: + +#if ((DM_ODM_SUPPORT_TYPE == ODM_AP)||(DM_ODM_SUPPORT_TYPE==ODM_ADSL)) + odm_IotEngine(pDM_Odm); +#endif + break; + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("<========================odm_EdcaTurboCheck\n")); + +} // odm_CheckEdcaTurbo + +#if(DM_ODM_SUPPORT_TYPE==ODM_CE) + + +VOID +odm_EdcaTurboCheckCE( + IN PDM_ODM_T pDM_Odm + ) +{ + +#if(DM_ODM_SUPPORT_TYPE==ODM_CE) + + PADAPTER Adapter = pDM_Odm->Adapter; + u32 EDCA_BE_UL = 0x5ea42b;//Parameter suggested by Scott //edca_setting_UL[pMgntInfo->IOTPeer]; + u32 EDCA_BE_DL = 0x5ea42b;//Parameter suggested by Scott //edca_setting_DL[pMgntInfo->IOTPeer]; + u32 ICType=pDM_Odm->SupportICType; + u32 IOTPeer=0; + u8 WirelessMode=0xFF; //invalid value + u32 trafficIndex; + u32 edca_param; + u64 cur_tx_bytes = 0; + u64 cur_rx_bytes = 0; + u8 bbtchange = _FALSE; + u8 bBiasOnRx = _FALSE; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(Adapter); + struct xmit_priv *pxmitpriv = &(Adapter->xmitpriv); + struct recv_priv *precvpriv = &(Adapter->recvpriv); + struct registry_priv *pregpriv = &Adapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &(Adapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + if(pDM_Odm->bLinked != _TRUE) + goto dm_CheckEdcaTurbo_EXIT; + + if(pregpriv->wifi_spec == 1) //|| (pmlmeinfo->HT_enable == 0)) + { + goto dm_CheckEdcaTurbo_EXIT; + } + + if(pDM_Odm->pWirelessMode!=NULL) + WirelessMode=*(pDM_Odm->pWirelessMode); + + IOTPeer = pmlmeinfo->assoc_AP_vendor; + + if (IOTPeer >= HT_IOT_PEER_MAX) + { + goto dm_CheckEdcaTurbo_EXIT; + } + + if( (pDM_Odm->SupportICType == ODM_RTL8192C) || + (pDM_Odm->SupportICType == ODM_RTL8723A) || + (pDM_Odm->SupportICType == ODM_RTL8188E)) + { + if((IOTPeer == HT_IOT_PEER_RALINK)||(IOTPeer == HT_IOT_PEER_ATHEROS)) + bBiasOnRx = _TRUE; + } + + // Check if the status needs to be changed. + if((bbtchange) || (!precvpriv->bIsAnyNonBEPkts) ) + { + cur_tx_bytes = pdvobjpriv->traffic_stat.cur_tx_bytes; + cur_rx_bytes = pdvobjpriv->traffic_stat.cur_rx_bytes; + + //traffic, TX or RX + if(bBiasOnRx) + { + if (cur_tx_bytes > (cur_rx_bytes << 2)) + { // Uplink TP is present. + trafficIndex = UP_LINK; + } + else + { // Balance TP is present. + trafficIndex = DOWN_LINK; + } + } + else + { + if (cur_rx_bytes > (cur_tx_bytes << 2)) + { // Downlink TP is present. + trafficIndex = DOWN_LINK; + } + else + { // Balance TP is present. + trafficIndex = UP_LINK; + } + } + + //if ((pDM_Odm->DM_EDCA_Table.prv_traffic_idx != trafficIndex) || (!pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA)) + { + if(ICType==ODM_RTL8192D) + { + // Single PHY + if(pDM_Odm->RFType==ODM_2T2R) + { + EDCA_BE_UL = 0x60a42b; //0x5ea42b; + EDCA_BE_DL = 0x60a42b; //0x5ea42b; + } + else + { + EDCA_BE_UL = 0x6ea42b; + EDCA_BE_DL = 0x6ea42b; + } + } + else + { + if(pDM_Odm->SupportInterface==ODM_ITRF_PCIE) { + if((ICType==ODM_RTL8192C)&&(pDM_Odm->RFType==ODM_2T2R)) { + EDCA_BE_UL = 0x60a42b; + EDCA_BE_DL = 0x60a42b; + } + else + { + EDCA_BE_UL = 0x6ea42b; + EDCA_BE_DL = 0x6ea42b; + } + } + } + + //92D txop can't be set to 0x3e for cisco1250 + if((ICType!=ODM_RTL8192D) && (IOTPeer== HT_IOT_PEER_CISCO) &&(WirelessMode==ODM_WM_N24G)) + { + EDCA_BE_DL = edca_setting_DL[IOTPeer]; + EDCA_BE_UL = edca_setting_UL[IOTPeer]; + } + //merge from 92s_92c_merge temp brunch v2445 20120215 + else if((IOTPeer == HT_IOT_PEER_CISCO) &&((WirelessMode==ODM_WM_G)||(WirelessMode==(ODM_WM_B|ODM_WM_G))||(WirelessMode==ODM_WM_A)||(WirelessMode==ODM_WM_B))) + { + EDCA_BE_DL = edca_setting_DL_GMode[IOTPeer]; + } + else if((IOTPeer== HT_IOT_PEER_AIRGO )&& ((WirelessMode==ODM_WM_G)||(WirelessMode==ODM_WM_A))) + { + EDCA_BE_DL = 0xa630; + } + else if(IOTPeer == HT_IOT_PEER_MARVELL) + { + EDCA_BE_DL = edca_setting_DL[IOTPeer]; + EDCA_BE_UL = edca_setting_UL[IOTPeer]; + } + else if(IOTPeer == HT_IOT_PEER_ATHEROS) + { + // Set DL EDCA for Atheros peer to 0x3ea42b. Suggested by SD3 Wilson for ASUS TP issue. + EDCA_BE_DL = edca_setting_DL[IOTPeer]; + } + + if((ICType==ODM_RTL8812)||(ICType==ODM_RTL8821)||(ICType==ODM_RTL8192E)) //add 8812AU/8812AE + { + EDCA_BE_UL = 0x5ea42b; + EDCA_BE_DL = 0x5ea42b; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("8812A: EDCA_BE_UL=0x%x EDCA_BE_DL =0x%x",EDCA_BE_UL,EDCA_BE_DL)); + } + + if (trafficIndex == DOWN_LINK) + edca_param = EDCA_BE_DL; + else + edca_param = EDCA_BE_UL; + + rtw_write32(Adapter, REG_EDCA_BE_PARAM, edca_param); + + pDM_Odm->DM_EDCA_Table.prv_traffic_idx = trafficIndex; + } + + pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = _TRUE; + } + else + { + // + // Turn Off EDCA turbo here. + // Restore original EDCA according to the declaration of AP. + // + if(pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA) + { + rtw_write32(Adapter, REG_EDCA_BE_PARAM, pHalData->AcParam_BE); + pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = _FALSE; + } + } + +dm_CheckEdcaTurbo_EXIT: + // Set variables for next time. + precvpriv->bIsAnyNonBEPkts = _FALSE; +#endif +} + + +#elif(DM_ODM_SUPPORT_TYPE==ODM_WIN) +VOID +odm_EdcaTurboCheckMP( + IN PDM_ODM_T pDM_Odm + ) +{ + + + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + + PADAPTER pDefaultAdapter = GetDefaultAdapter(Adapter); + PADAPTER pExtAdapter = GetFirstExtAdapter(Adapter);//NULL; + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + PSTA_QOS pStaQos = Adapter->MgntInfo.pStaQos; + //[Win7 Count Tx/Rx statistic for Extension Port] odm_CheckEdcaTurbo's Adapter is always Default. 2009.08.20, by Bohn + u8Byte Ext_curTxOkCnt = 0; + u8Byte Ext_curRxOkCnt = 0; + //For future Win7 Enable Default Port to modify AMPDU size dynamically, 2009.08.20, Bohn. + u1Byte TwoPortStatus = (u1Byte)TWO_PORT_STATUS__WITHOUT_ANY_ASSOCIATE; + + // Keep past Tx/Rx packet count for RT-to-RT EDCA turbo. + u8Byte curTxOkCnt = 0; + u8Byte curRxOkCnt = 0; + u4Byte EDCA_BE_UL = 0x5ea42b;//Parameter suggested by Scott //edca_setting_UL[pMgntInfo->IOTPeer]; + u4Byte EDCA_BE_DL = 0x5ea42b;//Parameter suggested by Scott //edca_setting_DL[pMgntInfo->IOTPeer]; + u4Byte EDCA_BE = 0x5ea42b; + u1Byte IOTPeer=0; + BOOLEAN *pbIsCurRDLState=NULL; + BOOLEAN bLastIsCurRDLState=FALSE; + BOOLEAN bBiasOnRx=FALSE; + BOOLEAN bEdcaTurboOn=FALSE; + u1Byte TxRate = 0xFF; + u8Byte value64; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("odm_EdcaTurboCheckMP========================>")); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Orginial BE PARAM: 0x%x\n",ODM_Read4Byte(pDM_Odm,ODM_EDCA_BE_PARAM))); + +////=============================== +////list paramter for different platform +////=============================== + bLastIsCurRDLState=pDM_Odm->DM_EDCA_Table.bIsCurRDLState; + pbIsCurRDLState=&(pDM_Odm->DM_EDCA_Table.bIsCurRDLState); + + //2012/09/14 MH Add + if (pMgntInfo->NumNonBePkt > pMgntInfo->RegEdcaThresh && !Adapter->MgntInfo.bWiFiConfg) + pHalData->bIsAnyNonBEPkts = TRUE; + + pMgntInfo->NumNonBePkt = 0; + + // Caculate TX/RX TP: + //curTxOkCnt = Adapter->TxStats.NumTxBytesUnicast - pMgntInfo->lastTxOkCnt; + //curRxOkCnt = Adapter->RxStats.NumRxBytesUnicast - pMgntInfo->lastRxOkCnt; + curTxOkCnt = Adapter->TxStats.NumTxBytesUnicast - pDM_Odm->lastTxOkCnt; + curRxOkCnt = Adapter->RxStats.NumRxBytesUnicast - pDM_Odm->lastRxOkCnt; + pDM_Odm->lastTxOkCnt = Adapter->TxStats.NumTxBytesUnicast; + pDM_Odm->lastRxOkCnt = Adapter->RxStats.NumRxBytesUnicast; + + if(pExtAdapter == NULL) + pExtAdapter = pDefaultAdapter; + + Ext_curTxOkCnt = pExtAdapter->TxStats.NumTxBytesUnicast - pMgntInfo->Ext_lastTxOkCnt; + Ext_curRxOkCnt = pExtAdapter->RxStats.NumRxBytesUnicast - pMgntInfo->Ext_lastRxOkCnt; + GetTwoPortSharedResource(Adapter,TWO_PORT_SHARED_OBJECT__STATUS,NULL,&TwoPortStatus); + //For future Win7 Enable Default Port to modify AMPDU size dynamically, 2009.08.20, Bohn. + if(TwoPortStatus == TWO_PORT_STATUS__EXTENSION_ONLY) + { + curTxOkCnt = Ext_curTxOkCnt ; + curRxOkCnt = Ext_curRxOkCnt ; + } + // + IOTPeer=pMgntInfo->IOTPeer; + bBiasOnRx=(pMgntInfo->IOTAction & HT_IOT_ACT_EDCA_BIAS_ON_RX)?TRUE:FALSE; + bEdcaTurboOn=((!pHalData->bIsAnyNonBEPkts) && (!pMgntInfo->bDisableFrameBursting))?TRUE:FALSE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("bIsAnyNonBEPkts : 0x%lx bDisableFrameBursting : 0x%lx \n",pHalData->bIsAnyNonBEPkts,pMgntInfo->bDisableFrameBursting)); + + +////=============================== +////check if edca turbo is disabled +////=============================== + if(odm_IsEdcaTurboDisable(pDM_Odm)) + goto dm_CheckEdcaTurbo_EXIT; + + +////=============================== +////remove iot case out +////=============================== + ODM_EdcaParaSelByIot(pDM_Odm, &EDCA_BE_UL, &EDCA_BE_DL); + + +////=============================== +////Check if the status needs to be changed. +////=============================== + if(bEdcaTurboOn) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("bEdcaTurboOn : 0x%x bBiasOnRx : 0x%x\n",bEdcaTurboOn,bBiasOnRx)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("curTxOkCnt : 0x%lx \n",curTxOkCnt)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("curRxOkCnt : 0x%lx \n",curRxOkCnt)); + if(bBiasOnRx) + odm_EdcaChooseTrafficIdx(pDM_Odm,curTxOkCnt, curRxOkCnt, TRUE, pbIsCurRDLState); + else + odm_EdcaChooseTrafficIdx(pDM_Odm,curTxOkCnt, curRxOkCnt, FALSE, pbIsCurRDLState); + +//modify by Guo.Mingzhi 2011-12-29 + EDCA_BE=((*pbIsCurRDLState)==TRUE)?EDCA_BE_DL:EDCA_BE_UL; + if(IS_HARDWARE_TYPE_8821U(Adapter)) + { + if(pMgntInfo->RegTxDutyEnable) + { + //2013.01.23 LukeLee: debug for 8811AU thermal issue (reduce Tx duty cycle) + if(!pMgntInfo->ForcedDataRate) //auto rate + { + if(pDM_Odm->TxRate != 0xFF) + TxRate = Adapter->HalFunc.GetHwRateFromMRateHandler(pDM_Odm->TxRate); + } + else //force rate + { + TxRate = (u1Byte) pMgntInfo->ForcedDataRate; + } + + value64 = (curRxOkCnt<<2); + if(curTxOkCnt < value64) //Downlink + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,EDCA_BE); + else //Uplink + { + //DbgPrint("pDM_Odm->RFCalibrateInfo.ThermalValue = 0x%X\n", pDM_Odm->RFCalibrateInfo.ThermalValue); + //if(pDM_Odm->RFCalibrateInfo.ThermalValue < pHalData->EEPROMThermalMeter) + if((pDM_Odm->RFCalibrateInfo.ThermalValue < 0x2c) || (*pDM_Odm->pBandType == BAND_ON_2_4G)) + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,EDCA_BE); + else + { + switch (TxRate) + { + case MGN_VHT1SS_MCS6: + case MGN_VHT1SS_MCS5: + case MGN_MCS6: + case MGN_MCS5: + case MGN_48M: + case MGN_54M: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,0x1ea42b); + break; + case MGN_VHT1SS_MCS4: + case MGN_MCS4: + case MGN_36M: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,0xa42b); + break; + case MGN_VHT1SS_MCS3: + case MGN_MCS3: + case MGN_24M: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,0xa47f); + break; + case MGN_VHT1SS_MCS2: + case MGN_MCS2: + case MGN_18M: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,0xa57f); + break; + case MGN_VHT1SS_MCS1: + case MGN_MCS1: + case MGN_9M: + case MGN_12M: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,0xa77f); + break; + case MGN_VHT1SS_MCS0: + case MGN_MCS0: + case MGN_6M: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,0xa87f); + break; + default: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,EDCA_BE); + break; + } + } + } + } + else + { + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,EDCA_BE); + } + + } + else if (IS_HARDWARE_TYPE_8812AU(Adapter)){ + if(pMgntInfo->RegTxDutyEnable) + { + //2013.07.26 Wilson: debug for 8812AU thermal issue (reduce Tx duty cycle) + // it;s the same issue as 8811AU + if(!pMgntInfo->ForcedDataRate) //auto rate + { + if(pDM_Odm->TxRate != 0xFF) + TxRate = Adapter->HalFunc.GetHwRateFromMRateHandler(pDM_Odm->TxRate); + } + else //force rate + { + TxRate = (u1Byte) pMgntInfo->ForcedDataRate; + } + + value64 = (curRxOkCnt<<2); + if(curTxOkCnt < value64) //Downlink + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,EDCA_BE); + else //Uplink + { + //DbgPrint("pDM_Odm->RFCalibrateInfo.ThermalValue = 0x%X\n", pDM_Odm->RFCalibrateInfo.ThermalValue); + //if(pDM_Odm->RFCalibrateInfo.ThermalValue < pHalData->EEPROMThermalMeter) + if((pDM_Odm->RFCalibrateInfo.ThermalValue < 0x2c) || (*pDM_Odm->pBandType == BAND_ON_2_4G)) + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,EDCA_BE); + else + { + switch (TxRate) + { + case MGN_VHT2SS_MCS9: + case MGN_VHT1SS_MCS9: + case MGN_VHT1SS_MCS8: + case MGN_MCS15: + case MGN_MCS7: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,0x1ea44f); + case MGN_VHT2SS_MCS8: + case MGN_VHT1SS_MCS7: + case MGN_MCS14: + case MGN_MCS6: + case MGN_54M: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,0xa44f); + case MGN_VHT2SS_MCS7: + case MGN_VHT2SS_MCS6: + case MGN_VHT1SS_MCS6: + case MGN_VHT1SS_MCS5: + case MGN_MCS13: + case MGN_MCS5: + case MGN_48M: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,0xa630); + break; + case MGN_VHT2SS_MCS5: + case MGN_VHT2SS_MCS4: + case MGN_VHT1SS_MCS4: + case MGN_VHT1SS_MCS3: + case MGN_MCS12: + case MGN_MCS4: + case MGN_MCS3: + case MGN_36M: + case MGN_24M: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,0xa730); + break; + case MGN_VHT2SS_MCS3: + case MGN_VHT2SS_MCS2: + case MGN_VHT2SS_MCS1: + case MGN_VHT1SS_MCS2: + case MGN_VHT1SS_MCS1: + case MGN_MCS11: + case MGN_MCS10: + case MGN_MCS9: + case MGN_MCS2: + case MGN_MCS1: + case MGN_18M: + case MGN_12M: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,0xa830); + break; + case MGN_VHT2SS_MCS0: + case MGN_VHT1SS_MCS0: + case MGN_MCS0: + case MGN_MCS8: + case MGN_9M: + case MGN_6M: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,0xa87f); + break; + default: + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,EDCA_BE); + break; + } + } + } + } + else + { + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,EDCA_BE); + } + } + else + ODM_Write4Byte(pDM_Odm,ODM_EDCA_BE_PARAM,EDCA_BE); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("EDCA Turbo on: EDCA_BE:0x%lx\n",EDCA_BE)); + + pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = TRUE; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("EDCA_BE_DL : 0x%lx EDCA_BE_UL : 0x%lx EDCA_BE : 0x%lx \n",EDCA_BE_DL,EDCA_BE_UL,EDCA_BE)); + + } + else + { + // Turn Off EDCA turbo here. + // Restore original EDCA according to the declaration of AP. + if(pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA) + { + Adapter->HalFunc.SetHwRegHandler(Adapter, HW_VAR_AC_PARAM, GET_WMM_PARAM_ELE_SINGLE_AC_PARAM(pStaQos->WMMParamEle, AC0_BE) ); + + pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = FALSE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Restore EDCA BE: 0x%lx \n",pDM_Odm->WMMEDCA_BE)); + + } + } + +////=============================== +////Set variables for next time. +////=============================== +dm_CheckEdcaTurbo_EXIT: +#if (DM_ODM_SUPPORT_TYPE==ODM_WIN) + pHalData->bIsAnyNonBEPkts = FALSE; + pMgntInfo->lastTxOkCnt = Adapter->TxStats.NumTxBytesUnicast; + pMgntInfo->lastRxOkCnt = Adapter->RxStats.NumRxBytesUnicast; + pMgntInfo->Ext_lastTxOkCnt = pExtAdapter->TxStats.NumTxBytesUnicast; + pMgntInfo->Ext_lastRxOkCnt = pExtAdapter->RxStats.NumRxBytesUnicast; +#elif (DM_ODM_SUPPORT_TYPE==ODM_CE) + precvpriv->bIsAnyNonBEPkts = FALSE; + pxmitpriv->last_tx_bytes = pxmitpriv->tx_bytes; + precvpriv->last_rx_bytes = precvpriv->rx_bytes; +#endif + +} + + +//check if edca turbo is disabled +BOOLEAN +odm_IsEdcaTurboDisable( + IN PDM_ODM_T pDM_Odm +) +{ + PADAPTER Adapter = pDM_Odm->Adapter; + +#if(DM_ODM_SUPPORT_TYPE==ODM_WIN) + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + u4Byte IOTPeer=pMgntInfo->IOTPeer; +#elif (DM_ODM_SUPPORT_TYPE==ODM_CE) + struct registry_priv *pregpriv = &Adapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &(Adapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + u4Byte IOTPeer=pmlmeinfo->assoc_AP_vendor; + u1Byte WirelessMode=0xFF; //invalid value + + if(pDM_Odm->pWirelessMode!=NULL) + WirelessMode=*(pDM_Odm->pWirelessMode); + +#endif + + if(pDM_Odm->bBtDisableEdcaTurbo) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD, ("EdcaTurboDisable for BT!!\n")); + return TRUE; + } + + if((!(pDM_Odm->SupportAbility& ODM_MAC_EDCA_TURBO ))|| + (pDM_Odm->bWIFITest)|| + (IOTPeer>= HT_IOT_PEER_MAX)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD, ("EdcaTurboDisable\n")); + return TRUE; + } + + +#if (DM_ODM_SUPPORT_TYPE ==ODM_WIN) + // 1. We do not turn on EDCA turbo mode for some AP that has IOT issue + // 2. User may disable EDCA Turbo mode with OID settings. + if(pMgntInfo->IOTAction & HT_IOT_ACT_DISABLE_EDCA_TURBO){ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD, ("IOTAction:EdcaTurboDisable\n")); + return TRUE; + } + +#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) + //suggested by Jr.Luke: open TXOP for B/G/BG/A mode 2012-0215 + if((WirelessMode==ODM_WM_B)||(WirelessMode==(ODM_WM_B|ODM_WM_G)||(WirelessMode==ODM_WM_G)||(WirelessMode=ODM_WM_A)) + ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, ODM_Read4Byte(pDM_Odm, ODM_EDCA_BE_PARAM)|0x5E0000); + + if(pDM_Odm->SupportICType==ODM_RTL8192D) { + if ((pregpriv->wifi_spec == 1) || (pmlmeext->cur_wireless_mode == WIRELESS_11B)) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD, ("92D:EdcaTurboDisable\n")); + return TRUE; + } + } + else + { + if((pregpriv->wifi_spec == 1) || (pmlmeinfo->HT_enable == 0)){ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD, ("Others:EdcaTurboDisable\n")); + return TRUE; + } + } + +#endif + + return FALSE; + + +} + +//add iot case here: for MP/CE +VOID +ODM_EdcaParaSelByIot( + IN PDM_ODM_T pDM_Odm, + OUT u4Byte *EDCA_BE_UL, + OUT u4Byte *EDCA_BE_DL + ) +{ + + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + u4Byte IOTPeer=0; + u4Byte ICType=pDM_Odm->SupportICType; + u1Byte WirelessMode=0xFF; //invalid value + u4Byte RFType=pDM_Odm->RFType; + u4Byte IOTPeerSubType=0; + +#if(DM_ODM_SUPPORT_TYPE==ODM_WIN) + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + u1Byte TwoPortStatus = (u1Byte)TWO_PORT_STATUS__WITHOUT_ANY_ASSOCIATE; + +#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + #ifdef CONFIG_BT_COEXIST + struct btcoexist_priv *pbtpriv = &(pHalData->bt_coexist); + #endif + u1Byte bbtchange =FALSE; +#endif + + if(pDM_Odm->pWirelessMode!=NULL) + WirelessMode=*(pDM_Odm->pWirelessMode); + +/////////////////////////////////////////////////////////// +////list paramter for different platform +#if (DM_ODM_SUPPORT_TYPE==ODM_WIN) + IOTPeer=pMgntInfo->IOTPeer; + IOTPeerSubType=pMgntInfo->IOTPeerSubtype; + GetTwoPortSharedResource(Adapter,TWO_PORT_SHARED_OBJECT__STATUS,NULL,&TwoPortStatus); + +#elif(DM_ODM_SUPPORT_TYPE==ODM_CE) + IOTPeer=pmlmeinfo->assoc_AP_vendor; + #ifdef CONFIG_BT_COEXIST + if(pbtpriv->BT_Coexist) + { + if( (pbtpriv->BT_EDCA[UP_LINK]!=0) || (pbtpriv->BT_EDCA[DOWN_LINK]!=0)) + bbtchange = TRUE; + } + #endif + +#endif + + if(ICType==ODM_RTL8192D) + { + // Single PHY + if(pDM_Odm->RFType==ODM_2T2R) + { + (*EDCA_BE_UL) = 0x60a42b; //0x5ea42b; + (*EDCA_BE_DL) = 0x60a42b; //0x5ea42b; + + } + else + { + (*EDCA_BE_UL) = 0x6ea42b; + (*EDCA_BE_DL) = 0x6ea42b; + } + + } +////============================ +/// IOT case for MP +////============================ +#if (DM_ODM_SUPPORT_TYPE==ODM_WIN) + else + { + + if(pDM_Odm->SupportInterface==ODM_ITRF_PCIE){ + if((ICType==ODM_RTL8192C)&&(pDM_Odm->RFType==ODM_2T2R)) { + (*EDCA_BE_UL) = 0x60a42b; + (*EDCA_BE_DL) = 0x60a42b; + } + else + { + (*EDCA_BE_UL) = 0x6ea42b; + (*EDCA_BE_DL) = 0x6ea42b; + } + } + } + + if(TwoPortStatus == TWO_PORT_STATUS__EXTENSION_ONLY) + { + (*EDCA_BE_UL) = 0x5ea42b;//Parameter suggested by Scott //edca_setting_UL[ExtAdapter->MgntInfo.IOTPeer]; + (*EDCA_BE_DL) = 0x5ea42b;//Parameter suggested by Scott //edca_setting_DL[ExtAdapter->MgntInfo.IOTPeer]; + } + + #if (INTEL_PROXIMITY_SUPPORT == 1) + if(pMgntInfo->IntelClassModeInfo.bEnableCA == TRUE) + { + (*EDCA_BE_UL) = (*EDCA_BE_DL) = 0xa44f; + } + else + #endif + { + if((!pMgntInfo->bDisableFrameBursting) && + (pMgntInfo->IOTAction & (HT_IOT_ACT_FORCED_ENABLE_BE_TXOP|HT_IOT_ACT_AMSDU_ENABLE))) + {// To check whether we shall force turn on TXOP configuration. + if(!((*EDCA_BE_UL) & 0xffff0000)) + (*EDCA_BE_UL) |= 0x005e0000; // Force TxOP limit to 0x005e for UL. + if(!((*EDCA_BE_DL) & 0xffff0000)) + (*EDCA_BE_DL) |= 0x005e0000; // Force TxOP limit to 0x005e for DL. + } + + //92D txop can't be set to 0x3e for cisco1250 + if((ICType!=ODM_RTL8192D) && (IOTPeer== HT_IOT_PEER_CISCO) &&(WirelessMode==ODM_WM_N24G)) + { + (*EDCA_BE_DL) = edca_setting_DL[IOTPeer]; + (*EDCA_BE_UL) = edca_setting_UL[IOTPeer]; + } + //merge from 92s_92c_merge temp brunch v2445 20120215 + else if((IOTPeer == HT_IOT_PEER_CISCO) &&((WirelessMode==ODM_WM_G)||(WirelessMode==(ODM_WM_B|ODM_WM_G))||(WirelessMode==ODM_WM_A)||(WirelessMode==ODM_WM_B))) + { + (*EDCA_BE_DL) = edca_setting_DL_GMode[IOTPeer]; + } + else if((IOTPeer== HT_IOT_PEER_AIRGO )&& ((WirelessMode==ODM_WM_G)||(WirelessMode==ODM_WM_A))) + { + (*EDCA_BE_DL) = 0xa630; + } + + else if(IOTPeer == HT_IOT_PEER_MARVELL) + { + (*EDCA_BE_DL) = edca_setting_DL[IOTPeer]; + (*EDCA_BE_UL) = edca_setting_UL[IOTPeer]; + } + else if(IOTPeer == HT_IOT_PEER_ATHEROS) + { + // Set DL EDCA for Atheros peer to 0x3ea42b. Suggested by SD3 Wilson for ASUS TP issue. + (*EDCA_BE_DL) = edca_setting_DL[IOTPeer]; + + if(ICType == ODM_RTL8821) + (*EDCA_BE_DL) = 0x5ea630; + + } + } + + if((ICType == ODM_RTL8192D)&&(IOTPeerSubType == HT_IOT_PEER_LINKSYS_E4200_V1)&&((WirelessMode==ODM_WM_N5G))) + { + (*EDCA_BE_DL) = 0x432b; + (*EDCA_BE_UL) = 0x432b; + } + + + + if((ICType==ODM_RTL8812)||(ICType==ODM_RTL8192E)) //add 8812AU/8812AE + { + (*EDCA_BE_UL) = 0x5ea42b; + (*EDCA_BE_DL) = 0x5ea42b; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("8812A: EDCA_BE_UL=0x%lx EDCA_BE_DL =0x%lx",(*EDCA_BE_UL),(*EDCA_BE_DL))); + } + + // Revised for Atheros DIR-655 IOT issue to improve down link TP, added by Roger, 2013.03.22. + if((ICType == ODM_RTL8723A) && (IOTPeerSubType== HT_IOT_PEER_ATHEROS_DIR655) && + (pMgntInfo->dot11CurrentChannelNumber == 6)) + { + (*EDCA_BE_DL) = 0xa92b; + } + +////============================ +/// IOT case for CE +////============================ +#elif (DM_ODM_SUPPORT_TYPE==ODM_CE) + + if(RFType==ODM_RTL8192D) + { + if((IOTPeer == HT_IOT_PEER_CISCO) &&(WirelessMode==ODM_WM_N24G)) + { + (*EDCA_BE_UL) = EDCAParam[IOTPeer][UP_LINK]; + (*EDCA_BE_DL)=EDCAParam[IOTPeer][DOWN_LINK]; + } + else if((IOTPeer == HT_IOT_PEER_AIRGO) && + ((WirelessMode==ODM_WM_B)||(WirelessMode==(ODM_WM_B|ODM_WM_G)))) + (*EDCA_BE_DL)=0x00a630; + + else if((IOTPeer== HT_IOT_PEER_ATHEROS) && + (WirelessMode&ODM_WM_N5G) && + (Adapter->securitypriv.dot11PrivacyAlgrthm == _AES_ )) + (*EDCA_BE_DL)=0xa42b; + + } + //92C IOT case: + else + { + #ifdef CONFIG_BT_COEXIST + if(bbtchange) + { + (*EDCA_BE_UL) = pbtpriv->BT_EDCA[UP_LINK]; + (*EDCA_BE_DL) = pbtpriv->BT_EDCA[DOWN_LINK]; + } + else + #endif + { + if((IOTPeer == HT_IOT_PEER_CISCO) &&(WirelessMode==ODM_WM_N24G)) + { + (*EDCA_BE_UL) = EDCAParam[IOTPeer][UP_LINK]; + (*EDCA_BE_DL)=EDCAParam[IOTPeer][DOWN_LINK]; + } + else + { + (*EDCA_BE_UL)=EDCAParam[HT_IOT_PEER_UNKNOWN][UP_LINK]; + (*EDCA_BE_DL)=EDCAParam[HT_IOT_PEER_UNKNOWN][DOWN_LINK]; + } + } + if(pDM_Odm->SupportInterface==ODM_ITRF_PCIE){ + if((ICType==ODM_RTL8192C)&&(pDM_Odm->RFType==ODM_2T2R)) + { + (*EDCA_BE_UL) = 0x60a42b; + (*EDCA_BE_DL) = 0x60a42b; + } + else + { + (*EDCA_BE_UL) = 0x6ea42b; + (*EDCA_BE_DL) = 0x6ea42b; + } + } + + } +#endif + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Special: EDCA_BE_UL=0x%lx EDCA_BE_DL =0x%lx",(*EDCA_BE_UL),(*EDCA_BE_DL))); + +} + + +VOID +odm_EdcaChooseTrafficIdx( + IN PDM_ODM_T pDM_Odm, + IN u8Byte cur_tx_bytes, + IN u8Byte cur_rx_bytes, + IN BOOLEAN bBiasOnRx, + OUT BOOLEAN *pbIsCurRDLState + ) +{ + + + if(bBiasOnRx) + { + + if(cur_tx_bytes>(cur_rx_bytes*4)) + { + *pbIsCurRDLState=FALSE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Uplink Traffic\n ")); + + } + else + { + *pbIsCurRDLState=TRUE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Balance Traffic\n")); + + } + } + else + { + if(cur_rx_bytes>(cur_tx_bytes*4)) + { + *pbIsCurRDLState=TRUE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Downlink Traffic\n")); + + } + else + { + *pbIsCurRDLState=FALSE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_EDCA_TURBO,ODM_DBG_LOUD,("Balance Traffic\n")); + } + } + + return ; +} + +#endif + +#if((DM_ODM_SUPPORT_TYPE==ODM_AP)||(DM_ODM_SUPPORT_TYPE==ODM_ADSL)) + +void odm_EdcaParaInit( + IN PDM_ODM_T pDM_Odm + ) +{ + prtl8192cd_priv priv = pDM_Odm->priv; + int mode=priv->pmib->dot11BssType.net_work_type; + + static unsigned int slot_time, VO_TXOP, VI_TXOP, sifs_time; + struct ParaRecord EDCA[4]; + + memset(EDCA, 0, 4*sizeof(struct ParaRecord)); + + sifs_time = 10; + slot_time = 20; + + if (mode & (ODM_WM_N24G|ODM_WM_N5G)) + sifs_time = 16; + + if (mode & (ODM_WM_N24G|ODM_WM_N5G| ODM_WM_G|ODM_WM_A)) + slot_time = 9; + + +#if((defined(RTL_MANUAL_EDCA))&&(DM_ODM_SUPPORT_TYPE==ODM_AP)) + if( priv->pmib->dot11QosEntry.ManualEDCA ) { + if( OPMODE & WIFI_AP_STATE ) + memcpy(EDCA, priv->pmib->dot11QosEntry.AP_manualEDCA, 4*sizeof(struct ParaRecord)); + else + memcpy(EDCA, priv->pmib->dot11QosEntry.STA_manualEDCA, 4*sizeof(struct ParaRecord)); + + #ifdef WIFI_WMM + if (QOS_ENABLE) + ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, (EDCA[VI].TXOPlimit<< 16) | (EDCA[VI].ECWmax<< 12) | (EDCA[VI].ECWmin<< 8) | (sifs_time + EDCA[VI].AIFSN* slot_time)); + else + #endif + ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, (EDCA[BE].TXOPlimit<< 16) | (EDCA[BE].ECWmax<< 12) | (EDCA[BE].ECWmin<< 8) | (sifs_time + EDCA[VI].AIFSN* slot_time)); + + }else + #endif //RTL_MANUAL_EDCA + { + + if(OPMODE & WIFI_AP_STATE) + { + memcpy(EDCA, rtl_ap_EDCA, 2*sizeof(struct ParaRecord)); + + if(mode & (ODM_WM_A|ODM_WM_G|ODM_WM_N24G|ODM_WM_N5G)) + memcpy(&EDCA[VI], &rtl_ap_EDCA[VI_AG], 2*sizeof(struct ParaRecord)); + else + memcpy(&EDCA[VI], &rtl_ap_EDCA[VI], 2*sizeof(struct ParaRecord)); + } + else + { + memcpy(EDCA, rtl_sta_EDCA, 2*sizeof(struct ParaRecord)); + + if(mode & (ODM_WM_A|ODM_WM_G|ODM_WM_N24G|ODM_WM_N5G)) + memcpy(&EDCA[VI], &rtl_sta_EDCA[VI_AG], 2*sizeof(struct ParaRecord)); + else + memcpy(&EDCA[VI], &rtl_sta_EDCA[VI], 2*sizeof(struct ParaRecord)); + } + + #ifdef WIFI_WMM + if (QOS_ENABLE) + ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, (EDCA[VI].TXOPlimit<< 16) | (EDCA[VI].ECWmax<< 12) | (EDCA[VI].ECWmin<< 8) | (sifs_time + EDCA[VI].AIFSN* slot_time)); + else + #endif + +#if (DM_ODM_SUPPORT_TYPE==ODM_AP) + ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, (EDCA[BK].ECWmax<< 12) | (EDCA[BK].ECWmin<< 8) | (sifs_time + EDCA[VI].AIFSN* slot_time)); +#elif(DM_ODM_SUPPORT_TYPE==ODM_ADSL) + ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, (EDCA[BK].ECWmax<< 12) | (EDCA[BK].ECWmin<< 8) | (sifs_time + 2* slot_time)); +#endif + + + } + + ODM_Write4Byte(pDM_Odm, ODM_EDCA_VO_PARAM, (EDCA[VO].TXOPlimit<< 16) | (EDCA[VO].ECWmax<< 12) | (EDCA[VO].ECWmin<< 8) | (sifs_time + EDCA[VO].AIFSN* slot_time)); + ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (EDCA[BE].TXOPlimit<< 16) | (EDCA[BE].ECWmax<< 12) | (EDCA[BE].ECWmin<< 8) | (sifs_time + EDCA[BE].AIFSN* slot_time)); + ODM_Write4Byte(pDM_Odm, ODM_EDCA_BK_PARAM, (EDCA[BK].TXOPlimit<< 16) | (EDCA[BK].ECWmax<< 12) | (EDCA[BK].ECWmin<< 8) | (sifs_time + EDCA[BK].AIFSN* slot_time)); +// ODM_Write1Byte(pDM_Odm,ACMHWCTRL, 0x00); + + priv->pshare->iot_mode_enable = 0; +#if(DM_ODM_SUPPORT_TYPE==ODM_AP) + if (priv->pshare->rf_ft_var.wifi_beq_iot) + priv->pshare->iot_mode_VI_exist = 0; + + #ifdef WMM_VIBE_PRI + priv->pshare->iot_mode_BE_exist = 0; + #endif + + #ifdef LOW_TP_TXOP + priv->pshare->BE_cwmax_enhance = 0; + #endif + +#elif (DM_ODM_SUPPORT_TYPE==ODM_ADSL) + priv->pshare->iot_mode_BE_exist = 0; +#endif + priv->pshare->iot_mode_VO_exist = 0; +} + +BOOLEAN +ODM_ChooseIotMainSTA( + IN PDM_ODM_T pDM_Odm, + IN PSTA_INFO_T pstat + ) +{ + prtl8192cd_priv priv = pDM_Odm->priv; + BOOLEAN bhighTP_found_pstat=FALSE; + + if ((GET_ROOT(priv)->up_time % 2) == 0) { + unsigned int tx_2s_avg = 0; + unsigned int rx_2s_avg = 0; + int i=0, aggReady=0; + unsigned long total_sum = (priv->pshare->current_tx_bytes+priv->pshare->current_rx_bytes); + + pstat->current_tx_bytes += pstat->tx_byte_cnt; + pstat->current_rx_bytes += pstat->rx_byte_cnt; + + if (total_sum != 0) { + if (total_sum <= 100) { + tx_2s_avg = (unsigned int)((pstat->current_tx_bytes*100) / total_sum); + rx_2s_avg = (unsigned int)((pstat->current_rx_bytes*100) / total_sum); + } else { + tx_2s_avg = (unsigned int)(pstat->current_tx_bytes / (total_sum / 100)); + rx_2s_avg = (unsigned int)(pstat->current_rx_bytes / (total_sum / 100)); + } + + } + +#if(DM_ODM_SUPPORT_TYPE==ODM_ADSL) + if (pstat->ht_cap_len) { + if ((tx_2s_avg + rx_2s_avg) >=25 /*50*/) { + + priv->pshare->highTP_found_pstat = pstat; + bhighTP_found_pstat=TRUE; + } + } +#elif(DM_ODM_SUPPORT_TYPE==ODM_AP) + for(i=0; i<8; i++) + aggReady += (pstat->ADDBA_ready[i]); + if (pstat->ht_cap_len && aggReady) + { + if ((tx_2s_avg + rx_2s_avg >= 25)) { + priv->pshare->highTP_found_pstat = pstat; + } + + #ifdef CLIENT_MODE + if (OPMODE & WIFI_STATION_STATE) { +#if (DM_ODM_SUPPORT_TYPE &ODM_AP) && defined(USE_OUT_SRC) + if ((pstat->IOTPeer==HT_IOT_PEER_RALINK) && ((tx_2s_avg + rx_2s_avg) >= 45)) +#else + if(pstat->is_ralink_sta && ((tx_2s_avg + rx_2s_avg) >= 45)) +#endif + priv->pshare->highTP_found_pstat = pstat; + } + #endif + } +#endif + } else { + pstat->current_tx_bytes = pstat->tx_byte_cnt; + pstat->current_rx_bytes = pstat->rx_byte_cnt; + } + + return bhighTP_found_pstat; +} + + +#ifdef WIFI_WMM +VOID +ODM_IotEdcaSwitch( + IN PDM_ODM_T pDM_Odm, + IN unsigned char enable + ) +{ + prtl8192cd_priv priv = pDM_Odm->priv; + int mode=priv->pmib->dot11BssType.net_work_type; + unsigned int slot_time = 20, sifs_time = 10, BE_TXOP = 47, VI_TXOP = 94; + unsigned int vi_cw_max = 4, vi_cw_min = 3, vi_aifs; + +#if (DM_ODM_SUPPORT_TYPE==ODM_AP) + if (!(!priv->pmib->dot11OperationEntry.wifi_specific || + ((OPMODE & WIFI_AP_STATE) && (priv->pmib->dot11OperationEntry.wifi_specific == 2)) + #ifdef CLIENT_MODE + || ((OPMODE & WIFI_STATION_STATE) && (priv->pmib->dot11OperationEntry.wifi_specific == 2)) + #endif + )) + return; +#endif + + if ((mode & (ODM_WM_N24G|ODM_WM_N5G)) && (priv->pshare->ht_sta_num + #ifdef WDS + || ((OPMODE & WIFI_AP_STATE) && priv->pmib->dot11WdsInfo.wdsEnabled && priv->pmib->dot11WdsInfo.wdsNum) + #endif + )) + sifs_time = 16; + + if (mode & (ODM_WM_N24G|ODM_WM_N5G|ODM_WM_G|ODM_WM_A)) { + slot_time = 9; + } + else + { + BE_TXOP = 94; + VI_TXOP = 188; + } + +#if (DM_ODM_SUPPORT_TYPE==ODM_ADSL) + if (priv->pshare->iot_mode_VO_exist) { + // to separate AC_VI and AC_BE to avoid using the same EDCA settings + if (priv->pshare->iot_mode_BE_exist) { + vi_cw_max = 5; + vi_cw_min = 3; + } else { + vi_cw_max = 6; + vi_cw_min = 4; + } + } + vi_aifs = (sifs_time + ((OPMODE & WIFI_AP_STATE)?1:2) * slot_time); + + ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, ((VI_TXOP*(1-priv->pshare->iot_mode_VO_exist)) << 16)| (vi_cw_max << 12) | (vi_cw_min << 8) | vi_aifs); + + +#elif (DM_ODM_SUPPORT_TYPE==ODM_AP) + if ((OPMODE & WIFI_AP_STATE) && priv->pmib->dot11OperationEntry.wifi_specific) { + if (priv->pshare->iot_mode_VO_exist) { + #ifdef WMM_VIBE_PRI + if (priv->pshare->iot_mode_BE_exist) + { + vi_cw_max = 5; + vi_cw_min = 3; + vi_aifs = (sifs_time + ((OPMODE & WIFI_AP_STATE)?1:2) * slot_time); + } + else + #endif + { + vi_cw_max = 6; + vi_cw_min = 4; + vi_aifs = 0x2b; + } + } + else { + vi_aifs = (sifs_time + ((OPMODE & WIFI_AP_STATE)?1:2) * slot_time); + } + + ODM_Write4Byte(pDM_Odm, ODM_EDCA_VI_PARAM, ((VI_TXOP*(1-priv->pshare->iot_mode_VO_exist)) << 16) + | (vi_cw_max << 12) | (vi_cw_min << 8) | vi_aifs); + } +#endif + + + +#if (DM_ODM_SUPPORT_TYPE==ODM_AP) + if (priv->pshare->rf_ft_var.wifi_beq_iot && priv->pshare->iot_mode_VI_exist) + ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (10 << 12) | (4 << 8) | 0x4f); + else if(!enable) +#elif(DM_ODM_SUPPORT_TYPE==ODM_ADSL) + if(!enable) //if iot is disable ,maintain original BEQ PARAM +#endif + ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (((OPMODE & WIFI_AP_STATE)?6:10) << 12) | (4 << 8) + | (sifs_time + 3 * slot_time)); + else + { + int txop_enlarge; + int txop; + unsigned int cw_max; + unsigned int txop_close; + + #if((DM_ODM_SUPPORT_TYPE==ODM_AP)&&(defined LOW_TP_TXOP)) + cw_max = ((priv->pshare->BE_cwmax_enhance) ? 10 : 6); + txop_close = ((priv->pshare->rf_ft_var.low_tp_txop && priv->pshare->rf_ft_var.low_tp_txop_close) ? 1 : 0); + + if(priv->pshare->txop_enlarge == 0xe) //if intel case + txop = (txop_close ? 0 : (BE_TXOP*2)); + else //if other case + txop = (txop_close ? 0: (BE_TXOP*priv->pshare->txop_enlarge)); + #else + cw_max=6; + if((priv->pshare->txop_enlarge==0xe)||(priv->pshare->txop_enlarge==0xd)) + txop=BE_TXOP*2; + else + txop=BE_TXOP*priv->pshare->txop_enlarge; + + #endif + + if (priv->pshare->ht_sta_num + #ifdef WDS + || ((OPMODE & WIFI_AP_STATE) && (mode & (ODM_WM_N24G|ODM_WM_N5G)) && + priv->pmib->dot11WdsInfo.wdsEnabled && priv->pmib->dot11WdsInfo.wdsNum) + #endif + ) + { + + if (priv->pshare->txop_enlarge == 0xe) { + // is intel client, use a different edca value + ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (txop<< 16) | (cw_max<< 12) | (4 << 8) | 0x1f); + priv->pshare->txop_enlarge = 2; + } +#if(DM_ODM_SUPPORT_TYPE==ODM_AP) + #ifndef LOW_TP_TXOP + else if (priv->pshare->txop_enlarge == 0xd) { + // is intel ralink, use a different edca value + ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (txop << 16) | (4 << 12) | (3 << 8) | 0x19); + priv->pshare->txop_enlarge = 2; + } + #endif +#endif + else + { + if (pDM_Odm->RFType==ODM_2T2R) + ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (txop << 16) | + (cw_max << 12) | (4 << 8) | (sifs_time + 3 * slot_time)); + else + #if(DM_ODM_SUPPORT_TYPE==ODM_AP)&&(defined LOW_TP_TXOP) + ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (txop << 16) | + (((priv->pshare->BE_cwmax_enhance) ? 10 : 5) << 12) | (3 << 8) | (sifs_time + 2 * slot_time)); + #else + ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (txop << 16) | + (5 << 12) | (3 << 8) | (sifs_time + 2 * slot_time)); + + #endif + } + } + else + { + #if((DM_ODM_SUPPORT_TYPE==ODM_AP)&&(defined LOW_TP_TXOP)) + ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (BE_TXOP << 16) | (cw_max << 12) | (4 << 8) | (sifs_time + 3 * slot_time)); + #else + #if defined(CONFIG_RTL_8196D) || defined(CONFIG_RTL_8196E) || (defined(CONFIG_RTL_8197D) && !defined(CONFIG_PORT0_EXT_GIGA)) + ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (BE_TXOP*2 << 16) | (cw_max << 12) | (5 << 8) | (sifs_time + 3 * slot_time)); + #else + ODM_Write4Byte(pDM_Odm, ODM_EDCA_BE_PARAM, (BE_TXOP*2 << 16) | (cw_max << 12) | (4 << 8) | (sifs_time + 3 * slot_time)); + #endif + + #endif + } + + } +} +#endif + +VOID +odm_IotEngine( + IN PDM_ODM_T pDM_Odm + ) +{ + + struct rtl8192cd_priv *priv=pDM_Odm->priv; + PSTA_INFO_T pstat = NULL; + u4Byte i; + +#ifdef WIFI_WMM + unsigned int switch_turbo = 0; +#endif +//////////////////////////////////////////////////////// +// if EDCA Turbo function is not supported or Manual EDCA Setting +// then return +//////////////////////////////////////////////////////// + if(!(pDM_Odm->SupportAbility&ODM_MAC_EDCA_TURBO)){ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("ODM_MAC_EDCA_TURBO NOT SUPPORTED\n")); + return; + } + +#if((DM_ODM_SUPPORT_TYPE==ODM_AP)&& defined(RTL_MANUAL_EDCA) && defined(WIFI_WMM)) + if(priv->pmib->dot11QosEntry.ManualEDCA){ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("ODM_MAC_EDCA_TURBO OFF: MANUAL SETTING\n")); + return ; + } +#endif + +#if !(DM_ODM_SUPPORT_TYPE &ODM_AP) + ////////////////////////////////////////////////////// + //find high TP STA every 2s +////////////////////////////////////////////////////// + if ((GET_ROOT(priv)->up_time % 2) == 0) + priv->pshare->highTP_found_pstat==NULL; + +#if 0 + phead = &priv->asoc_list; + plist = phead->next; + while(plist != phead) { + pstat = list_entry(plist, struct stat_info, asoc_list); + + if(ODM_ChooseIotMainSTA(pDM_Odm, pstat)); //find the correct station + break; + if (plist == plist->next) //the last plist + break; + plist = plist->next; + }; +#endif + + //find highTP STA + for(i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++) { + pstat = pDM_Odm->pODM_StaInfo[i]; + if(IS_STA_VALID(pstat) && (ODM_ChooseIotMainSTA(pDM_Odm, pstat))) //find the correct station + break; + } + + ////////////////////////////////////////////////////// + //if highTP STA is not found, then return + ////////////////////////////////////////////////////// + if(priv->pshare->highTP_found_pstat==NULL) { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("ODM_MAC_EDCA_TURBO OFF: NO HT STA FOUND\n")); + return; + } +#endif + + pstat=priv->pshare->highTP_found_pstat; + + +#ifdef WIFI_WMM + if (QOS_ENABLE) { + if (!priv->pmib->dot11OperationEntry.wifi_specific + #if(DM_ODM_SUPPORT_TYPE==ODM_AP) + ||((OPMODE & WIFI_AP_STATE) && (priv->pmib->dot11OperationEntry.wifi_specific == 2)) + #elif(DM_ODM_SUPPORT_TYPE==ODM_ADSL) + || (priv->pmib->dot11OperationEntry.wifi_specific == 2) + #endif + ) { + if (priv->pshare->iot_mode_enable && + ((priv->pshare->phw->VO_pkt_count > 50) || + (priv->pshare->phw->VI_pkt_count > 50) || + (priv->pshare->phw->BK_pkt_count > 50))) { + priv->pshare->iot_mode_enable = 0; + switch_turbo++; + } else if ((!priv->pshare->iot_mode_enable) && + ((priv->pshare->phw->VO_pkt_count < 50) && + (priv->pshare->phw->VI_pkt_count < 50) && + (priv->pshare->phw->BK_pkt_count < 50))) { + priv->pshare->iot_mode_enable++; + switch_turbo++; + } + } + + + #if(DM_ODM_SUPPORT_TYPE==ODM_AP) + if ((OPMODE & WIFI_AP_STATE) && priv->pmib->dot11OperationEntry.wifi_specific) + #elif (DM_ODM_SUPPORT_TYPE==ODM_ADSL) + if (priv->pmib->dot11OperationEntry.wifi_specific) + #endif + { + if (!priv->pshare->iot_mode_VO_exist && (priv->pshare->phw->VO_pkt_count > 50)) { + priv->pshare->iot_mode_VO_exist++; + switch_turbo++; + } else if (priv->pshare->iot_mode_VO_exist && (priv->pshare->phw->VO_pkt_count < 50)) { + priv->pshare->iot_mode_VO_exist = 0; + switch_turbo++; + } +#if((DM_ODM_SUPPORT_TYPE==ODM_ADSL)||((DM_ODM_SUPPORT_TYPE==ODM_AP)&&(defined WMM_VIBE_PRI))) + if (priv->pshare->iot_mode_VO_exist) { + //printk("[%s %d] BE_pkt_count=%d\n", __FUNCTION__, __LINE__, priv->pshare->phw->BE_pkt_count); + if (!priv->pshare->iot_mode_BE_exist && (priv->pshare->phw->BE_pkt_count > 250)) { + priv->pshare->iot_mode_BE_exist++; + switch_turbo++; + } else if (priv->pshare->iot_mode_BE_exist && (priv->pshare->phw->BE_pkt_count < 250)) { + priv->pshare->iot_mode_BE_exist = 0; + switch_turbo++; + } + } +#endif + +#if (DM_ODM_SUPPORT_TYPE==ODM_AP) + if (priv->pshare->rf_ft_var.wifi_beq_iot) + { + if (!priv->pshare->iot_mode_VI_exist && (priv->pshare->phw->VI_rx_pkt_count > 50)) { + priv->pshare->iot_mode_VI_exist++; + switch_turbo++; + } else if (priv->pshare->iot_mode_VI_exist && (priv->pshare->phw->VI_rx_pkt_count < 50)) { + priv->pshare->iot_mode_VI_exist = 0; + switch_turbo++; + } + } +#endif + + } + else if (!pstat || pstat->rssi < priv->pshare->rf_ft_var.txop_enlarge_lower) { + if (priv->pshare->txop_enlarge) { + priv->pshare->txop_enlarge = 0; + if (priv->pshare->iot_mode_enable) + switch_turbo++; + } + } + +#if(defined(CLIENT_MODE) && (DM_ODM_SUPPORT_TYPE==ODM_AP)) + if ((OPMODE & WIFI_STATION_STATE) && (priv->pmib->dot11OperationEntry.wifi_specific == 2)) + { + if (priv->pshare->iot_mode_enable && + (((priv->pshare->phw->VO_pkt_count > 50) || + (priv->pshare->phw->VI_pkt_count > 50) || + (priv->pshare->phw->BK_pkt_count > 50)) || + (pstat && (!pstat->ADDBA_ready[0]) & (!pstat->ADDBA_ready[3])))) + { + priv->pshare->iot_mode_enable = 0; + switch_turbo++; + } + else if ((!priv->pshare->iot_mode_enable) && + (((priv->pshare->phw->VO_pkt_count < 50) && + (priv->pshare->phw->VI_pkt_count < 50) && + (priv->pshare->phw->BK_pkt_count < 50)) && + (pstat && (pstat->ADDBA_ready[0] | pstat->ADDBA_ready[3])))) + { + priv->pshare->iot_mode_enable++; + switch_turbo++; + } + } +#endif + + priv->pshare->phw->VO_pkt_count = 0; + priv->pshare->phw->VI_pkt_count = 0; + priv->pshare->phw->BK_pkt_count = 0; + + #if((DM_ODM_SUPPORT_TYPE==ODM_ADSL)||((DM_ODM_SUPPORT_TYPE==ODM_AP)&&(defined WMM_VIBE_PRI))) + priv->pshare->phw->BE_pkt_count = 0; + #endif + + #if(DM_ODM_SUPPORT_TYPE==ODM_AP) + if (priv->pshare->rf_ft_var.wifi_beq_iot) + priv->pshare->phw->VI_rx_pkt_count = 0; + #endif + + } +#endif + + if ((priv->up_time % 2) == 0) { + /* + * decide EDCA content for different chip vendor + */ +#ifdef WIFI_WMM + #if(DM_ODM_SUPPORT_TYPE==ODM_ADSL) + if (QOS_ENABLE && (!priv->pmib->dot11OperationEntry.wifi_specific || (priv->pmib->dot11OperationEntry.wifi_specific == 2) + + #elif(DM_ODM_SUPPORT_TYPE==ODM_AP) + if (QOS_ENABLE && (!priv->pmib->dot11OperationEntry.wifi_specific || + ((OPMODE & WIFI_AP_STATE) && (priv->pmib->dot11OperationEntry.wifi_specific == 2)) + #ifdef CLIENT_MODE + || ((OPMODE & WIFI_STATION_STATE) && (priv->pmib->dot11OperationEntry.wifi_specific == 2)) + #endif + #endif + )) + + { + + if (pstat && pstat->rssi >= priv->pshare->rf_ft_var.txop_enlarge_upper) { +#ifdef LOW_TP_TXOP +#if (DM_ODM_SUPPORT_TYPE &ODM_AP) && defined(USE_OUT_SRC) + if (pstat->IOTPeer==HT_IOT_PEER_INTEL) +#else + if (pstat->is_intel_sta) +#endif + { + if (priv->pshare->txop_enlarge != 0xe) + { + priv->pshare->txop_enlarge = 0xe; + + if (priv->pshare->iot_mode_enable) + switch_turbo++; + } + } + else if (priv->pshare->txop_enlarge != 2) + { + priv->pshare->txop_enlarge = 2; + if (priv->pshare->iot_mode_enable) + switch_turbo++; + } +#else + if (priv->pshare->txop_enlarge != 2) + { +#if (DM_ODM_SUPPORT_TYPE &ODM_AP) && defined(USE_OUT_SRC) + if (pstat->IOTPeer==HT_IOT_PEER_INTEL) +#else + if (pstat->is_intel_sta) +#endif + priv->pshare->txop_enlarge = 0xe; +#if (DM_ODM_SUPPORT_TYPE &ODM_AP) && defined(USE_OUT_SRC) + else if (pstat->IOTPeer==HT_IOT_PEER_RALINK) +#else + else if (pstat->is_ralink_sta) +#endif + priv->pshare->txop_enlarge = 0xd; + else + priv->pshare->txop_enlarge = 2; + + if (priv->pshare->iot_mode_enable) + switch_turbo++; + } +#endif +#if 0 + if (priv->pshare->txop_enlarge != 2) + { + #if(DM_ODM_SUPPORT_TYPE==ODM_AP) + if (pstat->IOTPeer==HT_IOT_PEER_INTEL) + #else + if (pstat->is_intel_sta) + #endif + priv->pshare->txop_enlarge = 0xe; + #if(DM_ODM_SUPPORT_TYPE==ODM_AP) + else if (pstat->IOTPeer==HT_IOT_PEER_RALINK) + priv->pshare->txop_enlarge = 0xd; + #endif + else + priv->pshare->txop_enlarge = 2; + if (priv->pshare->iot_mode_enable) + switch_turbo++; + } +#endif + } + else if (!pstat || pstat->rssi < priv->pshare->rf_ft_var.txop_enlarge_lower) + { + if (priv->pshare->txop_enlarge) { + priv->pshare->txop_enlarge = 0; + if (priv->pshare->iot_mode_enable) + switch_turbo++; + } + } + +#if((DM_ODM_SUPPORT_TYPE==ODM_AP)&&( defined LOW_TP_TXOP)) + // for Intel IOT, need to enlarge CW MAX from 6 to 10 + if (pstat && pstat->is_intel_sta && (((pstat->tx_avarage+pstat->rx_avarage)>>10) < + priv->pshare->rf_ft_var.cwmax_enhance_thd)) + { + if (!priv->pshare->BE_cwmax_enhance && priv->pshare->iot_mode_enable) + { + priv->pshare->BE_cwmax_enhance = 1; + switch_turbo++; + } + } else { + if (priv->pshare->BE_cwmax_enhance) { + priv->pshare->BE_cwmax_enhance = 0; + switch_turbo++; + } + } +#endif + } +#endif + priv->pshare->current_tx_bytes = 0; + priv->pshare->current_rx_bytes = 0; + } + +#if((DM_ODM_SUPPORT_TYPE==ODM_AP)&& defined( SW_TX_QUEUE)) + if ((priv->assoc_num > 1) && (AMPDU_ENABLE)) + { + if (priv->swq_txmac_chg >= priv->pshare->rf_ft_var.swq_en_highthd){ + if ((priv->swq_en == 0)){ + switch_turbo++; + if (priv->pshare->txop_enlarge == 0) + priv->pshare->txop_enlarge = 2; + priv->swq_en = 1; + } + else + { + if ((switch_turbo > 0) && (priv->pshare->txop_enlarge == 0) && (priv->pshare->iot_mode_enable != 0)) + { + priv->pshare->txop_enlarge = 2; + switch_turbo--; + } + } + } + else if(priv->swq_txmac_chg <= priv->pshare->rf_ft_var.swq_dis_lowthd){ + priv->swq_en = 0; + } + else if ((priv->swq_en == 1) && (switch_turbo > 0) && (priv->pshare->txop_enlarge == 0) && (priv->pshare->iot_mode_enable != 0)) { + priv->pshare->txop_enlarge = 2; + switch_turbo--; + } + } +#if ((DM_ODM_SUPPORT_TYPE==ODM_AP)&&(defined CONFIG_RTL_819XD)) + else if( (priv->assoc_num == 1) && (AMPDU_ENABLE)) { + if (pstat) { + int en_thd = 14417920>>(priv->up_time % 2); + if ((priv->swq_en == 0) && (pstat->current_tx_bytes > en_thd) && (pstat->current_rx_bytes > en_thd) ) { //50Mbps + priv->swq_en = 1; + priv->swqen_keeptime = priv->up_time; + } + else if ((priv->swq_en == 1) && ((pstat->tx_avarage < 4587520) || (pstat->rx_avarage < 4587520))) { //35Mbps + priv->swq_en = 0; + priv->swqen_keeptime = 0; + } + } + else { + priv->swq_en = 0; + priv->swqen_keeptime = 0; + } + } +#endif +#endif + +#ifdef WIFI_WMM +#ifdef LOW_TP_TXOP + if ((!priv->pmib->dot11OperationEntry.wifi_specific || (priv->pmib->dot11OperationEntry.wifi_specific == 2)) + && QOS_ENABLE) { + if (switch_turbo || priv->pshare->rf_ft_var.low_tp_txop) { + unsigned int thd_tp; + unsigned char under_thd; + unsigned int curr_tp; + + if (priv->pmib->dot11BssType.net_work_type & (ODM_WM_N24G|ODM_WM_N5G| ODM_WM_G)) + { + // Determine the upper bound throughput threshold. + if (priv->pmib->dot11BssType.net_work_type & (ODM_WM_N24G|ODM_WM_N5G)) { + if (priv->assoc_num && priv->assoc_num != priv->pshare->ht_sta_num) + thd_tp = priv->pshare->rf_ft_var.low_tp_txop_thd_g; + else + thd_tp = priv->pshare->rf_ft_var.low_tp_txop_thd_n; + } + else + thd_tp = priv->pshare->rf_ft_var.low_tp_txop_thd_g; + + // Determine to close txop. + curr_tp = (unsigned int)(priv->ext_stats.tx_avarage>>17) + (unsigned int)(priv->ext_stats.rx_avarage>>17); + if (curr_tp <= thd_tp && curr_tp >= priv->pshare->rf_ft_var.low_tp_txop_thd_low) + under_thd = 1; + else + under_thd = 0; + } + else + { + under_thd = 0; + } + + if (switch_turbo) + { + priv->pshare->rf_ft_var.low_tp_txop_close = under_thd; + priv->pshare->rf_ft_var.low_tp_txop_count = 0; + } + else if (priv->pshare->iot_mode_enable && (priv->pshare->rf_ft_var.low_tp_txop_close != under_thd)) { + priv->pshare->rf_ft_var.low_tp_txop_count++; + if (priv->pshare->rf_ft_var.low_tp_txop_close) { + priv->pshare->rf_ft_var.low_tp_txop_count = priv->pshare->rf_ft_var.low_tp_txop_delay; + } + if (priv->pshare->rf_ft_var.low_tp_txop_count ==priv->pshare->rf_ft_var.low_tp_txop_delay) + + { + priv->pshare->rf_ft_var.low_tp_txop_count = 0; + priv->pshare->rf_ft_var.low_tp_txop_close = under_thd; + switch_turbo++; + } + } + else + { + priv->pshare->rf_ft_var.low_tp_txop_count = 0; + } + } + } +#endif + + if (switch_turbo) + ODM_IotEdcaSwitch( pDM_Odm, priv->pshare->iot_mode_enable ); +#endif +} +#endif + + +#if( DM_ODM_SUPPORT_TYPE == ODM_WIN) +// +// 2011/07/26 MH Add an API for testing IQK fail case. +// +BOOLEAN +ODM_CheckPowerStatus( + IN PADAPTER Adapter) +{ + + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + RT_RF_POWER_STATE rtState; + PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); + + // 2011/07/27 MH We are not testing ready~~!! We may fail to get correct value when init sequence. + if (pMgntInfo->init_adpt_in_progress == TRUE) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("ODM_CheckPowerStatus Return TRUE, due to initadapter")); + return TRUE; + } + + // + // 2011/07/19 MH We can not execute tx pwoer tracking/ LLC calibrate or IQK. + // + Adapter->HalFunc.GetHwRegHandler(Adapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState)); + if(Adapter->bDriverStopped || Adapter->bDriverIsGoingToPnpSetPowerSleep || rtState == eRfOff) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("ODM_CheckPowerStatus Return FALSE, due to %d/%d/%d\n", + Adapter->bDriverStopped, Adapter->bDriverIsGoingToPnpSetPowerSleep, rtState)); + return FALSE; + } + return TRUE; +} +#endif + +// need to ODM CE Platform +//move to here for ANT detection mechanism using + +#if ((DM_ODM_SUPPORT_TYPE == ODM_WIN)||(DM_ODM_SUPPORT_TYPE == ODM_CE)) +u4Byte +GetPSDData( + IN PDM_ODM_T pDM_Odm, + unsigned int point, + u1Byte initial_gain_psd) +{ + //unsigned int val, rfval; + //int psd_report; + u4Byte psd_report; + + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + //Debug Message + //val = PHY_QueryBBReg(Adapter,0x908, bMaskDWord); + //DbgPrint("Reg908 = 0x%x\n",val); + //val = PHY_QueryBBReg(Adapter,0xDF4, bMaskDWord); + //rfval = PHY_QueryRFReg(Adapter, ODM_RF_PATH_A, 0x00, bRFRegOffsetMask); + //DbgPrint("RegDF4 = 0x%x, RFReg00 = 0x%x\n",val, rfval); + //DbgPrint("PHYTXON = %x, OFDMCCA_PP = %x, CCKCCA_PP = %x, RFReg00 = %x\n", + //(val&BIT25)>>25, (val&BIT14)>>14, (val&BIT15)>>15, rfval); + + //Set DCO frequency index, offset=(40MHz/SamplePts)*point + ODM_SetBBReg(pDM_Odm, 0x808, 0x3FF, point); + + //Start PSD calculation, Reg808[22]=0->1 + ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 1); + //Need to wait for HW PSD report + ODM_StallExecution(1000); + ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 0); + //Read PSD report, Reg8B4[15:0] + psd_report = ODM_GetBBReg(pDM_Odm,0x8B4, bMaskDWord) & 0x0000FFFF; + +#if 1//(DEV_BUS_TYPE == RT_PCI_INTERFACE) && ( (RT_PLATFORM == PLATFORM_LINUX) || (RT_PLATFORM == PLATFORM_MACOSX)) + psd_report = (u4Byte) (ConvertTo_dB(psd_report))+(u4Byte)(initial_gain_psd-0x1c); +#else + psd_report = (int) (20*log10((double)psd_report))+(int)(initial_gain_psd-0x1c); +#endif + + return psd_report; + +} + +u4Byte +ConvertTo_dB( + u4Byte Value) +{ + u1Byte i; + u1Byte j; + u4Byte dB; + + Value = Value & 0xFFFF; + + for (i=0;i<8;i++) + { + if (Value <= dB_Invert_Table[i][11]) + { + break; + } + } + + if (i >= 8) + { + return (96); // maximum 96 dB + } + + for (j=0;j<12;j++) + { + if (Value <= dB_Invert_Table[i][j]) + { + break; + } + } + + dB = i*12 + j + 1; + + return (dB); +} + +#endif + +// +// LukeLee: +// PSD function will be moved to FW in future IC, but now is only implemented in MP platform +// So PSD function will not be incorporated to common ODM +// +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +#define AFH_PSD 1 //0:normal PSD scan, 1: only do 20 pts PSD +#define MODE_40M 0 //0:20M, 1:40M +#define PSD_TH2 3 +#define PSD_CHMIN 20 // Minimum channel number for BT AFH +#define SIR_STEP_SIZE 3 +#define Smooth_Size_1 5 +#define Smooth_TH_1 3 +#define Smooth_Size_2 10 +#define Smooth_TH_2 4 +#define Smooth_Size_3 20 +#define Smooth_TH_3 4 +#define Smooth_Step_Size 5 +#define Adaptive_SIR 1 +//#if(RTL8723_FPGA_VERIFICATION == 1) +//#define PSD_RESCAN 1 +//#else +//#define PSD_RESCAN 4 +//#endif +#define SCAN_INTERVAL 1500 //ms +#define SYN_Length 5 // for 92D + +#define LNA_Low_Gain_1 0x64 +#define LNA_Low_Gain_2 0x5A +#define LNA_Low_Gain_3 0x58 + +#define pw_th_10dB 0x0 +#define pw_th_16dB 0x3 + +#define FA_RXHP_TH1 5000 +#define FA_RXHP_TH2 1500 +#define FA_RXHP_TH3 800 +#define FA_RXHP_TH4 600 +#define FA_RXHP_TH5 500 + +#define Idle_Mode 0 +#define High_TP_Mode 1 +#define Low_TP_Mode 2 + + +VOID +odm_PSDMonitorInit( + IN PDM_ODM_T pDM_Odm) +{ +#if (DEV_BUS_TYPE == RT_PCI_INTERFACE)|(DEV_BUS_TYPE == RT_USB_INTERFACE) + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + //PSD Monitor Setting + //Which path in ADC/DAC is turnned on for PSD: both I/Q + ODM_SetBBReg(pDM_Odm, ODM_PSDREG, BIT10|BIT11, 0x3); + //Ageraged number: 8 + ODM_SetBBReg(pDM_Odm, ODM_PSDREG, BIT12|BIT13, 0x1); + pDM_Odm->bPSDinProcess = FALSE; + pDM_Odm->bUserAssignLevel = FALSE; + pDM_Odm->bPSDactive = FALSE; + //pDM_Odm->bDMInitialGainEnable=TRUE; //change the initialization to DIGinit + //Set Debug Port + //PHY_SetBBReg(Adapter, 0x908, bMaskDWord, 0x803); + //PHY_SetBBReg(Adapter, 0xB34, bMaskByte0, 0x00); // pause PSD + //PHY_SetBBReg(Adapter, 0xB38, bMaskByte0, 10); //rescan + //PHY_SetBBReg(Adapter, 0xB38, bMaskByte2|bMaskByte3, 100); //interval + + //PlatformSetTimer( Adapter, &pHalData->PSDTriggerTimer, 0); //ms +#endif +} + +VOID +PatchDCTone( + IN PDM_ODM_T pDM_Odm, + pu4Byte PSD_report, + u1Byte initial_gain_psd +) +{ + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + //PADAPTER pAdapter; + + u4Byte psd_report; + + //2 Switch to CH11 to patch CH9 and CH13 DC tone + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, 0x3FF, 11); + + if(pDM_Odm->SupportICType== ODM_RTL8192D) + { + if((*(pDM_Odm->pMacPhyMode) == ODM_SMSP)||(*(pDM_Odm->pMacPhyMode) == ODM_DMSP)) + { + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, RF_CHNLBW, 0x3FF, 11); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x25, 0xfffff, 0x643BC); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x26, 0xfffff, 0xFC038); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x27, 0xfffff, 0x77C1A); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x2B, 0xfffff, 0x41289); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x2C, 0xfffff, 0x01840); + } + else + { + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x25, 0xfffff, 0x643BC); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x26, 0xfffff, 0xFC038); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x27, 0xfffff, 0x77C1A); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x2B, 0xfffff, 0x41289); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x2C, 0xfffff, 0x01840); + } + } + + //Ch9 DC tone patch + psd_report = GetPSDData(pDM_Odm, 96, initial_gain_psd); + PSD_report[50] = psd_report; + //Ch13 DC tone patch + psd_report = GetPSDData(pDM_Odm, 32, initial_gain_psd); + PSD_report[70] = psd_report; + + //2 Switch to CH3 to patch CH1 and CH5 DC tone + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, 0x3FF, 3); + + + if(pDM_Odm->SupportICType==ODM_RTL8192D) + { + if((*(pDM_Odm->pMacPhyMode) == ODM_SMSP)||(*(pDM_Odm->pMacPhyMode) == ODM_DMSP)) + { + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, RF_CHNLBW, 0x3FF, 3); + //PHY_SetRFReg(Adapter, ODM_RF_PATH_B, 0x25, 0xfffff, 0x643BC); + //PHY_SetRFReg(Adapter, ODM_RF_PATH_B, 0x26, 0xfffff, 0xFC038); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x27, 0xfffff, 0x07C1A); + //PHY_SetRFReg(Adapter, ODM_RF_PATH_B, 0x2B, 0xfffff, 0x61289); + //PHY_SetRFReg(Adapter, ODM_RF_PATH_B, 0x2C, 0xfffff, 0x01C41); + } + else + { + //PHY_SetRFReg(Adapter, ODM_RF_PATH_A, 0x25, 0xfffff, 0x643BC); + //PHY_SetRFReg(Adapter, ODM_RF_PATH_A, 0x26, 0xfffff, 0xFC038); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x27, 0xfffff, 0x07C1A); + //PHY_SetRFReg(Adapter, ODM_RF_PATH_A, 0x2B, 0xfffff, 0x61289); + //PHY_SetRFReg(Adapter, ODM_RF_PATH_A, 0x2C, 0xfffff, 0x01C41); + } + } + + //Ch1 DC tone patch + psd_report = GetPSDData(pDM_Odm, 96, initial_gain_psd); + PSD_report[10] = psd_report; + //Ch5 DC tone patch + psd_report = GetPSDData(pDM_Odm, 32, initial_gain_psd); + PSD_report[30] = psd_report; + +} + + +VOID +GoodChannelDecision( + PDM_ODM_T pDM_Odm, + pu4Byte PSD_report, + pu1Byte PSD_bitmap, + u1Byte RSSI_BT, + pu1Byte PSD_bitmap_memory) +{ + pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; + //s4Byte TH1 = SSBT-0x15; // modify TH by Neil Chen + s4Byte TH1= RSSI_BT+0x14; + s4Byte TH2 = RSSI_BT+85; + //u2Byte TH3; +// s4Byte RegB34; + u1Byte bitmap, Smooth_size[3], Smooth_TH[3]; + //u1Byte psd_bit; + u4Byte i,n,j, byte_idx, bit_idx, good_cnt, good_cnt_smoothing, Smooth_Interval[3]; + int start_byte_idx,start_bit_idx,cur_byte_idx, cur_bit_idx,NOW_byte_idx ; + +// RegB34 = PHY_QueryBBReg(Adapter,0xB34, bMaskDWord)&0xFF; + + if((pDM_Odm->SupportICType == ODM_RTL8192C)||(pDM_Odm->SupportICType == ODM_RTL8192D)) + { + TH1 = RSSI_BT + 0x14; + } + + Smooth_size[0]=Smooth_Size_1; + Smooth_size[1]=Smooth_Size_2; + Smooth_size[2]=Smooth_Size_3; + Smooth_TH[0]=Smooth_TH_1; + Smooth_TH[1]=Smooth_TH_2; + Smooth_TH[2]=Smooth_TH_3; + Smooth_Interval[0]=16; + Smooth_Interval[1]=15; + Smooth_Interval[2]=13; + good_cnt = 0; + if(pDM_Odm->SupportICType==ODM_RTL8723A) + { + //2 Threshold + + if(RSSI_BT >=41) + TH1 = 113; + else if(RSSI_BT >=38) // >= -15dBm + TH1 = 105; //0x69 + else if((RSSI_BT >=33)&(RSSI_BT <38)) + TH1 = 99+(RSSI_BT-33); //0x63 + else if((RSSI_BT >=26)&(RSSI_BT<33)) + TH1 = 99-(33-RSSI_BT)+2; //0x5e + else if((RSSI_BT >=24)&(RSSI_BT<26)) + TH1 = 88-((RSSI_BT-24)*3); //0x58 + else if((RSSI_BT >=18)&(RSSI_BT<24)) + TH1 = 77+((RSSI_BT-18)*2); + else if((RSSI_BT >=14)&(RSSI_BT<18)) + TH1 = 63+((RSSI_BT-14)*2); + else if((RSSI_BT >=8)&(RSSI_BT<14)) + TH1 = 58+((RSSI_BT-8)*2); + else if((RSSI_BT >=3)&(RSSI_BT<8)) + TH1 = 52+(RSSI_BT-3); + else + TH1 = 51; + } + + for (i = 0; i< 10; i++) + PSD_bitmap[i] = 0; + + + // Add By Gary + for (i=0; i<80; i++) + pRX_HP_Table->PSD_bitmap_RXHP[i] = 0; + // End + + + + if(pDM_Odm->SupportICType==ODM_RTL8723A) + { + TH1 =TH1-SIR_STEP_SIZE; + } + while (good_cnt < PSD_CHMIN) + { + good_cnt = 0; + if(pDM_Odm->SupportICType==ODM_RTL8723A) + { + if(TH1 ==TH2) + break; + if((TH1+SIR_STEP_SIZE) < TH2) + TH1 += SIR_STEP_SIZE; + else + TH1 = TH2; + } + else + { + if(TH1==(RSSI_BT+0x1E)) + break; + if((TH1+2) < (RSSI_BT+0x1E)) + TH1+=3; + else + TH1 = RSSI_BT+0x1E; + + } + ODM_RT_TRACE(pDM_Odm,COMP_PSD,DBG_LOUD,("PSD: decision threshold is: %d", TH1)); + + for (i = 0; i< 80; i++) + { + if((s4Byte)(PSD_report[i]) < TH1) + { + byte_idx = i / 8; + bit_idx = i -8*byte_idx; + bitmap = PSD_bitmap[byte_idx]; + PSD_bitmap[byte_idx] = bitmap | (u1Byte) (1 << bit_idx); + } + } + +#if DBG + ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD: before smoothing\n")); + for(n=0;n<10;n++) + { + //DbgPrint("PSD_bitmap[%u]=%x\n", n, PSD_bitmap[n]); + for (i = 0; i<8; i++) + ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD_bitmap[%u] = %d\n", 2402+n*8+i, (PSD_bitmap[n]&BIT(i))>>i)); + } +#endif + + //1 Start of smoothing function + + for (j=0;j<3;j++) + { + start_byte_idx=0; + start_bit_idx=0; + for(n=0; n<Smooth_Interval[j]; n++) + { + good_cnt_smoothing = 0; + cur_bit_idx = start_bit_idx; + cur_byte_idx = start_byte_idx; + for ( i=0; i < Smooth_size[j]; i++) + { + NOW_byte_idx = cur_byte_idx + (i+cur_bit_idx)/8; + if ( (PSD_bitmap[NOW_byte_idx]& BIT( (cur_bit_idx + i)%8)) != 0) + good_cnt_smoothing++; + + } + + if( good_cnt_smoothing < Smooth_TH[j] ) + { + cur_bit_idx = start_bit_idx; + cur_byte_idx = start_byte_idx; + for ( i=0; i< Smooth_size[j] ; i++) + { + NOW_byte_idx = cur_byte_idx + (i+cur_bit_idx)/8; + PSD_bitmap[NOW_byte_idx] = PSD_bitmap[NOW_byte_idx] & (~BIT( (cur_bit_idx + i)%8)); + } + } + start_bit_idx = start_bit_idx + Smooth_Step_Size; + while ( (start_bit_idx) > 7 ) + { + start_byte_idx= start_byte_idx+start_bit_idx/8; + start_bit_idx = start_bit_idx%8; + } + } + + ODM_RT_TRACE( pDM_Odm,COMP_PSD, DBG_LOUD,("PSD: after %u smoothing", j+1)); + for(n=0;n<10;n++) + { + for (i = 0; i<8; i++) + { + ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD_bitmap[%u] = %d\n", 2402+n*8+i, (PSD_bitmap[n]&BIT(i))>>i)); + + if ( ((PSD_bitmap[n]&BIT(i))>>i) ==1) //----- Add By Gary + { + pRX_HP_Table->PSD_bitmap_RXHP[8*n+i] = 1; + } // ------end by Gary + } + } + + } + + + good_cnt = 0; + for ( i = 0; i < 10; i++) + { + for (n = 0; n < 8; n++) + if((PSD_bitmap[i]& BIT(n)) != 0) + good_cnt++; + } + ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD: good channel cnt = %u",good_cnt)); + } + + //RT_TRACE(COMP_PSD, DBG_LOUD,("PSD: SSBT=%d, TH2=%d, TH1=%d",SSBT,TH2,TH1)); + for (i = 0; i <10; i++) + ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD: PSD_bitmap[%u]=%x",i,PSD_bitmap[i])); +/* + //Update bitmap memory + for(i = 0; i < 80; i++) + { + byte_idx = i / 8; + bit_idx = i -8*byte_idx; + psd_bit = (PSD_bitmap[byte_idx] & BIT(bit_idx)) >> bit_idx; + bitmap = PSD_bitmap_memory[i]; + PSD_bitmap_memory[i] = (bitmap << 1) |psd_bit; + } +*/ +} + + + +VOID +odm_PSD_Monitor( + PDM_ODM_T pDM_Odm +) +{ + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + //PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + + unsigned int pts, start_point, stop_point; + u1Byte initial_gain ; + static u1Byte PSD_bitmap_memory[80], init_memory = 0; + static u1Byte psd_cnt=0; + static u4Byte PSD_report[80], PSD_report_tmp; + static u8Byte lastTxOkCnt=0, lastRxOkCnt=0; + u1Byte H2C_PSD_DATA[5]={0,0,0,0,0}; + static u1Byte H2C_PSD_DATA_last[5] ={0,0,0,0,0}; + u1Byte idx[20]={96,99,102,106,109,112,115,118,122,125, + 0,3,6,10,13,16,19,22,26,29}; + u1Byte n, i, channel, BBReset,tone_idx; + u1Byte PSD_bitmap[10], SSBT=0,initial_gain_psd=0, RSSI_BT=0, initialGainUpper; + s4Byte PSD_skip_start, PSD_skip_stop; + u4Byte CurrentChannel, RXIQI, RxIdleLowPwr, wlan_channel; + u4Byte ReScan, Interval, Is40MHz; + u8Byte curTxOkCnt, curRxOkCnt; + int cur_byte_idx, cur_bit_idx; + PADAPTER Adapter = pDM_Odm->Adapter; + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + + if( (*(pDM_Odm->pbScanInProcess)) || + pDM_Odm->bLinkInProcess) + { + if((pDM_Odm->SupportICType==ODM_RTL8723A)&(pDM_Odm->SupportInterface==ODM_ITRF_PCIE)) + { + ODM_SetTimer( pDM_Odm, &pDM_Odm->PSDTimer, 1500); //ms + //psd_cnt=0; + } + return; + } + + if(pDM_Odm->bBtHsOperation) + { + ReScan = 1; + Interval = SCAN_INTERVAL; + } + else + { + ReScan = PSD_RESCAN; + Interval = SCAN_INTERVAL; + } + + //1 Initialization + if(init_memory == 0) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PSD, DBG_LOUD,("Init memory\n")); + for(i = 0; i < 80; i++) + PSD_bitmap_memory[i] = 0xFF; // channel is always good + init_memory = 1; + } + if(psd_cnt == 0) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PSD, DBG_LOUD,("Enter dm_PSD_Monitor\n")); + for(i = 0; i < 80; i++) + PSD_report[i] = 0; + } + + //1 Backup Current Settings + CurrentChannel = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask); +/* + if(pDM_Odm->SupportICType==ODM_RTL8192D) + { + //2 Record Current synthesizer parameters based on current channel + if((*pDM_Odm->MacPhyMode92D == SINGLEMAC_SINGLEPHY)||(*pDM_Odm->MacPhyMode92D == DUALMAC_SINGLEPHY)) + { + SYN_RF25 = ODM_GetRFReg(Adapter, ODM_RF_PATH_B, 0x25, bMaskDWord); + SYN_RF26 = ODM_GetRFReg(Adapter, ODM_RF_PATH_B, 0x26, bMaskDWord); + SYN_RF27 = ODM_GetRFReg(Adapter, ODM_RF_PATH_B, 0x27, bMaskDWord); + SYN_RF2B = ODM_GetRFReg(Adapter, ODM_RF_PATH_B, 0x2B, bMaskDWord); + SYN_RF2C = ODM_GetRFReg(Adapter, ODM_RF_PATH_B, 0x2C, bMaskDWord); + } + else // DualMAC_DualPHY 2G + { + SYN_RF25 = ODM_GetRFReg(Adapter, ODM_RF_PATH_A, 0x25, bMaskDWord); + SYN_RF26 = ODM_GetRFReg(Adapter, ODM_RF_PATH_A, 0x26, bMaskDWord); + SYN_RF27 = ODM_GetRFReg(Adapter, ODM_RF_PATH_A, 0x27, bMaskDWord); + SYN_RF2B = ODM_GetRFReg(Adapter, ODM_RF_PATH_A, 0x2B, bMaskDWord); + SYN_RF2C = ODM_GetRFReg(Adapter, ODM_RF_PATH_A, 0x2C, bMaskDWord); + } + } +*/ + //RXIQI = PHY_QueryBBReg(Adapter, 0xC14, bMaskDWord); + RXIQI = ODM_GetBBReg(pDM_Odm, 0xC14, bMaskDWord); + + //RxIdleLowPwr = (PHY_QueryBBReg(Adapter, 0x818, bMaskDWord)&BIT28)>>28; + RxIdleLowPwr = (ODM_GetBBReg(pDM_Odm, 0x818, bMaskDWord)&BIT28)>>28; + + //2??? + if(CHNL_RUN_ABOVE_40MHZ(pMgntInfo)) + Is40MHz = TRUE; + else + Is40MHz = FALSE; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_PSD, DBG_LOUD,("PSD Scan Start\n")); + //1 Turn off CCK + //PHY_SetBBReg(Adapter, rFPGA0_RFMOD, BIT24, 0); + ODM_SetBBReg(pDM_Odm, rFPGA0_RFMOD, BIT24, 0); + //1 Turn off TX + //Pause TX Queue + //PlatformEFIOWrite1Byte(Adapter, REG_TXPAUSE, 0xFF); + ODM_Write1Byte(pDM_Odm,REG_TXPAUSE, 0xFF); + + //Force RX to stop TX immediately + //PHY_SetRFReg(Adapter, ODM_RF_PATH_A, RF_AC, bRFRegOffsetMask, 0x32E13); + + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_AC, bRFRegOffsetMask, 0x32E13); + //1 Turn off RX + //Rx AGC off RegC70[0]=0, RegC7C[20]=0 + //PHY_SetBBReg(Adapter, 0xC70, BIT0, 0); + //PHY_SetBBReg(Adapter, 0xC7C, BIT20, 0); + + ODM_SetBBReg(pDM_Odm, 0xC70, BIT0, 0); + ODM_SetBBReg(pDM_Odm, 0xC7C, BIT20, 0); + + + //Turn off CCA + //PHY_SetBBReg(Adapter, 0xC14, bMaskDWord, 0x0); + ODM_SetBBReg(pDM_Odm, 0xC14, bMaskDWord, 0x0); + + //BB Reset + //BBReset = PlatformEFIORead1Byte(Adapter, 0x02); + BBReset = ODM_Read1Byte(pDM_Odm, 0x02); + + //PlatformEFIOWrite1Byte(Adapter, 0x02, BBReset&(~BIT0)); + //PlatformEFIOWrite1Byte(Adapter, 0x02, BBReset|BIT0); + ODM_SetBBReg(pDM_Odm, 0x87C, BIT31, 1); //clock gated to prevent from AGC table mess + ODM_Write1Byte(pDM_Odm, 0x02, BBReset&(~BIT0)); + ODM_Write1Byte(pDM_Odm, 0x02, BBReset|BIT0); + ODM_SetBBReg(pDM_Odm, 0x87C, BIT31, 0); + + //1 Leave RX idle low power + //PHY_SetBBReg(Adapter, 0x818, BIT28, 0x0); + + ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0); + //1 Fix initial gain + //if (IS_HARDWARE_TYPE_8723AE(Adapter)) + //RSSI_BT = pHalData->RSSI_BT; + //else if((IS_HARDWARE_TYPE_8192C(Adapter))||(IS_HARDWARE_TYPE_8192D(Adapter))) // Add by Gary + // RSSI_BT = RSSI_BT_new; + + if((pDM_Odm->SupportICType==ODM_RTL8723A)&(pDM_Odm->SupportInterface==ODM_ITRF_PCIE)) + RSSI_BT=pDM_Odm->RSSI_BT; //need to check C2H to pDM_Odm RSSI BT + + if(RSSI_BT>=47) + RSSI_BT=47; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PSD, DBG_LOUD,("PSD: RSSI_BT= %d\n", RSSI_BT)); + + if(pDM_Odm->SupportICType==ODM_RTL8723A) + { + //Neil add--2011--10--12 + //2 Initial Gain index + if(RSSI_BT >=35) // >= -15dBm + initial_gain_psd = RSSI_BT*2; + else if((RSSI_BT >=33)&(RSSI_BT<35)) + initial_gain_psd = RSSI_BT*2+6; + else if((RSSI_BT >=24)&(RSSI_BT<33)) + initial_gain_psd = 70-(33-RSSI_BT); + else if((RSSI_BT >=19)&(RSSI_BT<24)) + initial_gain_psd = 64-((24-RSSI_BT)*4); + else if((RSSI_BT >=14)&(RSSI_BT<19)) + initial_gain_psd = 44-((18-RSSI_BT)*2); + else if((RSSI_BT >=8)&(RSSI_BT<14)) + initial_gain_psd = 35-(14-RSSI_BT); + else + initial_gain_psd = 0x1B; + } + else + { + + //need to do + initial_gain_psd = pDM_Odm->RSSI_Min; // PSD report based on RSSI + //} + } + //if(RSSI_BT<0x17) + // RSSI_BT +=3; + //DbgPrint("PSD: RSSI_BT= %d\n", RSSI_BT); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PSD, DBG_LOUD,("PSD: RSSI_BT= %d\n", RSSI_BT)); + + //initialGainUpper = 0x5E; //Modify by neil chen + + if(pDM_Odm->bUserAssignLevel) + { + pDM_Odm->bUserAssignLevel = FALSE; + initialGainUpper = 0x7f; + } + else + { + initialGainUpper = 0x5E; + } + + /* + if (initial_gain_psd < 0x1a) + initial_gain_psd = 0x1a; + if (initial_gain_psd > initialGainUpper) + initial_gain_psd = initialGainUpper; + */ + + //if(pDM_Odm->SupportICType==ODM_RTL8723A) + SSBT = RSSI_BT * 2 +0x3E; + + + //if(IS_HARDWARE_TYPE_8723AE(Adapter)) + // SSBT = RSSI_BT * 2 +0x3E; + //else if((IS_HARDWARE_TYPE_8192C(Adapter))||(IS_HARDWARE_TYPE_8192D(Adapter))) // Add by Gary + //{ + // RSSI_BT = initial_gain_psd; + // SSBT = RSSI_BT; + //} + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PSD, DBG_LOUD,("PSD: SSBT= %d\n", SSBT)); + ODM_RT_TRACE( pDM_Odm,ODM_COMP_PSD, DBG_LOUD,("PSD: initial gain= 0x%x\n", initial_gain_psd)); + //DbgPrint("PSD: SSBT= %d", SSBT); + //need to do + //pMgntInfo->bDMInitialGainEnable = FALSE; + pDM_Odm->bDMInitialGainEnable = FALSE; + initial_gain =(u1Byte) (ODM_GetBBReg(pDM_Odm, 0xc50, bMaskDWord) & 0x7F); + + // make sure the initial gain is under the correct range. + //initial_gain_psd &= 0x7f; + ODM_Write_DIG(pDM_Odm, initial_gain_psd); + //1 Turn off 3-wire + ODM_SetBBReg(pDM_Odm, 0x88c, BIT20|BIT21|BIT22|BIT23, 0xF); + + //pts value = 128, 256, 512, 1024 + pts = 128; + + if(pts == 128) + { + ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x0); + start_point = 64; + stop_point = 192; + } + else if(pts == 256) + { + ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x1); + start_point = 128; + stop_point = 384; + } + else if(pts == 512) + { + ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x2); + start_point = 256; + stop_point = 768; + } + else + { + ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x3); + start_point = 512; + stop_point = 1536; + } + + +//3 Skip WLAN channels if WLAN busy + + curTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast) - lastTxOkCnt; + curRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast) - lastRxOkCnt; + lastTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast); + lastRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast); + + PSD_skip_start=80; + PSD_skip_stop = 0; + wlan_channel = CurrentChannel & 0x0f; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PSD,DBG_LOUD,("PSD: current channel: %x, BW:%d \n", wlan_channel, Is40MHz)); + if(pDM_Odm->SupportICType==ODM_RTL8723A) + { + if(pDM_Odm->bBtHsOperation) + { + if(pDM_Odm->bLinked) + { + if(Is40MHz) + { + PSD_skip_start = ((wlan_channel-1)*5 -Is40MHz*10)-2; // Modify by Neil to add 10 chs to mask + PSD_skip_stop = (PSD_skip_start + (1+Is40MHz)*20)+4; + } + else + { + PSD_skip_start = ((wlan_channel-1)*5 -Is40MHz*10)-10; // Modify by Neil to add 10 chs to mask + PSD_skip_stop = (PSD_skip_start + (1+Is40MHz)*20)+18; + } + } + else + { + // mask for 40MHz + PSD_skip_start = ((wlan_channel-1)*5 -Is40MHz*10)-2; // Modify by Neil to add 10 chs to mask + PSD_skip_stop = (PSD_skip_start + (1+Is40MHz)*20)+4; + } + if(PSD_skip_start < 0) + PSD_skip_start = 0; + if(PSD_skip_stop >80) + PSD_skip_stop = 80; + } + else + { + if((curRxOkCnt+curTxOkCnt) > 5) + { + if(Is40MHz) + { + PSD_skip_start = ((wlan_channel-1)*5 -Is40MHz*10)-2; // Modify by Neil to add 10 chs to mask + PSD_skip_stop = (PSD_skip_start + (1+Is40MHz)*20)+4; + } + else + { + PSD_skip_start = ((wlan_channel-1)*5 -Is40MHz*10)-10; // Modify by Neil to add 10 chs to mask + PSD_skip_stop = (PSD_skip_start + (1+Is40MHz)*20)+18; + } + + if(PSD_skip_start < 0) + PSD_skip_start = 0; + if(PSD_skip_stop >80) + PSD_skip_stop = 80; + } + } + } +#if 0 + else + { + if((curRxOkCnt+curTxOkCnt) > 1000) + { + PSD_skip_start = (wlan_channel-1)*5 -Is40MHz*10; + PSD_skip_stop = PSD_skip_start + (1+Is40MHz)*20; + } + } +#endif //Reove RXHP Issue + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PSD,DBG_LOUD,("PSD: Skip tone from %d to %d \n", PSD_skip_start, PSD_skip_stop)); + + for (n=0;n<80;n++) + { + if((n%20)==0) + { + channel = (n/20)*4 + 1; + + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, 0x3FF, channel); + } + tone_idx = n%20; + if ((n>=PSD_skip_start) && (n<PSD_skip_stop)) + { + PSD_report[n] = SSBT; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PSD,DBG_LOUD,("PSD:Tone %d skipped \n", n)); + } + else + { + PSD_report_tmp = GetPSDData(pDM_Odm, idx[tone_idx], initial_gain_psd); + + if ( PSD_report_tmp > PSD_report[n]) + PSD_report[n] = PSD_report_tmp; + + } + } + + PatchDCTone(pDM_Odm, PSD_report, initial_gain_psd); + + //----end + //1 Turn on RX + //Rx AGC on + ODM_SetBBReg(pDM_Odm, 0xC70, BIT0, 1); + ODM_SetBBReg(pDM_Odm, 0xC7C, BIT20, 1); + //CCK on + ODM_SetBBReg(pDM_Odm, rFPGA0_RFMOD, BIT24, 1); + //1 Turn on TX + //Resume TX Queue + + ODM_Write1Byte(pDM_Odm,REG_TXPAUSE, 0x00); + //Turn on 3-wire + ODM_SetBBReg(pDM_Odm, 0x88c, BIT20|BIT21|BIT22|BIT23, 0x0); + //1 Restore Current Settings + //Resume DIG + pDM_Odm->bDMInitialGainEnable = TRUE; + + ODM_Write_DIG(pDM_Odm, initial_gain); + + // restore originl center frequency + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, CurrentChannel); + + //Turn on CCA + ODM_SetBBReg(pDM_Odm, 0xC14, bMaskDWord, RXIQI); + //Restore RX idle low power + if(RxIdleLowPwr == TRUE) + ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 1); + + psd_cnt++; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PSD, DBG_LOUD,("PSD:psd_cnt = %d \n",psd_cnt)); + if (psd_cnt < ReScan) + ODM_SetTimer(pDM_Odm, &pDM_Odm->PSDTimer, Interval); + else + { + psd_cnt = 0; + for(i=0;i<80;i++) + //DbgPrint("psd_report[%d]= %d \n", 2402+i, PSD_report[i]); + RT_TRACE( COMP_PSD, DBG_LOUD,("psd_report[%d]= %d \n", 2402+i, PSD_report[i])); + + + GoodChannelDecision(pDM_Odm, PSD_report, PSD_bitmap,RSSI_BT, PSD_bitmap_memory); + + if(pDM_Odm->SupportICType==ODM_RTL8723A) + { + cur_byte_idx=0; + cur_bit_idx=0; + + //2 Restore H2C PSD Data to Last Data + H2C_PSD_DATA_last[0] = H2C_PSD_DATA[0]; + H2C_PSD_DATA_last[1] = H2C_PSD_DATA[1]; + H2C_PSD_DATA_last[2] = H2C_PSD_DATA[2]; + H2C_PSD_DATA_last[3] = H2C_PSD_DATA[3]; + H2C_PSD_DATA_last[4] = H2C_PSD_DATA[4]; + + + //2 Translate 80bit channel map to 40bit channel + for ( i=0;i<5;i++) + { + for(n=0;n<8;n++) + { + cur_byte_idx = i*2 + n/4; + cur_bit_idx = (n%4)*2; + if ( ((PSD_bitmap[cur_byte_idx]& BIT(cur_bit_idx)) != 0) && ((PSD_bitmap[cur_byte_idx]& BIT(cur_bit_idx+1)) != 0)) + H2C_PSD_DATA[i] = H2C_PSD_DATA[i] | (u1Byte) (1 << n); + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PSD, DBG_LOUD,("H2C_PSD_DATA[%d]=0x%x\n" ,i, H2C_PSD_DATA[i])); + } + + //3 To Compare the difference + for ( i=0;i<5;i++) + { + if(H2C_PSD_DATA[i] !=H2C_PSD_DATA_last[i]) + { + FillH2CCmd(Adapter, H2C_92C_PSD_RESULT, 5, H2C_PSD_DATA); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_PSD, DBG_LOUD,("Need to Update the AFH Map \n")); + break; + } + else + { + if(i==5) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PSD, DBG_LOUD,("Not need to Update\n")); + } + } + if(pDM_Odm->bBtHsOperation) + { + ODM_SetTimer(pDM_Odm, &pDM_Odm->PSDTimer, 10000); + ODM_RT_TRACE( pDM_Odm,ODM_COMP_PSD, DBG_LOUD,("Leave dm_PSD_Monitor\n")); + } + else + { + ODM_SetTimer(pDM_Odm, &pDM_Odm->PSDTimer, 1500); + ODM_RT_TRACE( pDM_Odm,ODM_COMP_PSD, DBG_LOUD,("Leave dm_PSD_Monitor\n")); + } + } + } +} +/* +//Neil for Get BT RSSI +// Be Triggered by BT C2H CMD +VOID +ODM_PSDGetRSSI( + IN u1Byte RSSI_BT) +{ + + +} + +*/ + +VOID +ODM_PSDMonitor( + IN PDM_ODM_T pDM_Odm + ) +{ + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + + //if(IS_HARDWARE_TYPE_8723AE(Adapter)) + + if(pDM_Odm->SupportICType == ODM_RTL8723A) //may need to add other IC type + { + if(pDM_Odm->SupportInterface==ODM_ITRF_PCIE) + { + if(pDM_Odm->bBtDisabled) //need to check upper layer connection + { + pDM_Odm->bPSDactive=FALSE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PSD, DBG_LOUD, ("odm_PSDMonitor, return for BT is disabled!!!\n")); + return; + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PSD, DBG_LOUD, ("odm_PSDMonitor\n")); + //{ + pDM_Odm->bPSDinProcess = TRUE; + pDM_Odm->bPSDactive=TRUE; + odm_PSD_Monitor(pDM_Odm); + pDM_Odm->bPSDinProcess = FALSE; + } + } + +} +VOID +odm_PSDMonitorCallback( + PRT_TIMER pTimer +) +{ + PADAPTER Adapter = (PADAPTER)pTimer->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + + PlatformScheduleWorkItem(&pHalData->PSDMonitorWorkitem); +} + +VOID +odm_PSDMonitorWorkItemCallback( + IN PVOID pContext + ) +{ + PADAPTER Adapter = (PADAPTER)pContext; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + + ODM_PSDMonitor(pDM_Odm); +} + +// <20130108, Kordan> E.g., With LNA used, we make the Rx power smaller to have a better EVM. (Asked by Willis) +VOID +odm_RFEControl( + IN PDM_ODM_T pDM_Odm, + IN u8Byte RSSIVal + ) +{ + PADAPTER Adapter = (PADAPTER)pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + static u1Byte TRSW_HighPwr = 0; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, DBG_LOUD, ("===> odm_RFEControl, RSSI = %d, TRSW_HighPwr = 0x%X, pHalData->RFEType = %d\n", + RSSIVal, TRSW_HighPwr, pHalData->RFEType )); + + if (pHalData->RFEType == 3) { + + pDM_Odm->RSSI_TRSW = RSSIVal; + + if (pDM_Odm->RSSI_TRSW >= pDM_Odm->RSSI_TRSW_H) + { + TRSW_HighPwr = 1; // Switch to + PHY_SetBBReg(Adapter, r_ANTSEL_SW_Jaguar, BIT1|BIT0, 0x1); // Set ANTSW=1/ANTSWB=0 for SW control + PHY_SetBBReg(Adapter, r_ANTSEL_SW_Jaguar, BIT9|BIT8, 0x3); // Set ANTSW=1/ANTSWB=0 for SW control + + } + else if (pDM_Odm->RSSI_TRSW <= pDM_Odm->RSSI_TRSW_L) + { + TRSW_HighPwr = 0; // Switched back + PHY_SetBBReg(Adapter, r_ANTSEL_SW_Jaguar, BIT1|BIT0, 0x1); // Set ANTSW=1/ANTSWB=0 for SW control + PHY_SetBBReg(Adapter, r_ANTSEL_SW_Jaguar, BIT9|BIT8, 0x0); // Set ANTSW=1/ANTSWB=0 for SW control + + } + } + + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, DBG_LOUD, ("(pDM_Odm->RSSI_TRSW_H, pDM_Odm->RSSI_TRSW_L) = (%d, %d)\n", pDM_Odm->RSSI_TRSW_H, pDM_Odm->RSSI_TRSW_L)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, DBG_LOUD, ("(RSSIVal, RSSIVal, pDM_Odm->RSSI_TRSW_iso) = (%d, %d, %d)\n", + RSSIVal, pDM_Odm->RSSI_TRSW_iso, pDM_Odm->RSSI_TRSW)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, DBG_LOUD, ("<=== odm_RFEControl, RSSI = %d, TRSW_HighPwr = 0x%X\n", RSSIVal, TRSW_HighPwr)); +} + +VOID +ODM_MPT_DIG( + IN PDM_ODM_T pDM_Odm + ) +{ + pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + PFALSE_ALARM_STATISTICS pFalseAlmCnt = &pDM_Odm->FalseAlmCnt; + u1Byte CurrentIGI = (u1Byte)pDM_DigTable->CurIGValue; + u1Byte DIG_Upper = 0x40, DIG_Lower = 0x20, C50, E50; + u8Byte RXOK_cal; + u1Byte IGI_A = 0x20, IGI_B = 0x20; + +#if ODM_FIX_2G_DIG + IGI_A = 0x22; + IGI_B = 0x24; +#endif + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_MP, DBG_LOUD, ("===> ODM_MPT_DIG, pBandType = %d\n", *pDM_Odm->pBandType)); + + odm_FalseAlarmCounterStatistics( pDM_Odm); + pDM_Odm->LastNumQryPhyStatusAll = pDM_Odm->NumQryPhyStatusAll; + pDM_Odm->NumQryPhyStatusAll = pDM_Odm->PhyDbgInfo.NumQryPhyStatusCCK + pDM_Odm->PhyDbgInfo.NumQryPhyStatusOFDM; + RXOK_cal = pDM_Odm->NumQryPhyStatusAll - pDM_Odm->LastNumQryPhyStatusAll; + + if (RXOK_cal == 0) + pDM_Odm->RxPWDBAve_final= 0; + else + pDM_Odm->RxPWDBAve_final= pDM_Odm->RxPWDBAve/RXOK_cal; + + pDM_Odm->RxPWDBAve = 0; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, DBG_LOUD, ("RX OK = %d\n", RXOK_cal)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, DBG_LOUD, ("pDM_Odm->RxPWDBAve_final = %d\n", pDM_Odm->RxPWDBAve_final)); + + // <20130315, Kordan> Except Cameo, we should always trun on 2.4G/5G DIG. + // (Cameo fixes the IGI of 2.4G, so only DIG on 5G. Asked by James.) +#if ODM_FIX_2G_DIG + if (*pDM_Odm->pBandType == BAND_ON_5G){ // for 5G +#else + if (1){ // for both 2G/5G +#endif + pDM_Odm->MPDIG_2G = FALSE; + pDM_Odm->Times_2G = 0; + + if (RXOK_cal >= 70 && pDM_Odm->RxPWDBAve_final<= 30) + { + if (CurrentIGI > 0x24){ + ODM_Write1Byte( pDM_Odm, rA_IGI_Jaguar, 0x24); + ODM_Write1Byte( pDM_Odm, rB_IGI_Jaguar, 0x24); + } + } + else + { + if(pFalseAlmCnt->Cnt_all > 1000){ + CurrentIGI = CurrentIGI + 8; + } + else if(pFalseAlmCnt->Cnt_all > 200){ + CurrentIGI = CurrentIGI + 4; + } + else if (pFalseAlmCnt->Cnt_all > 50){ + CurrentIGI = CurrentIGI + 2; + } + else if (pFalseAlmCnt->Cnt_all < 2){ + CurrentIGI = CurrentIGI - 2; + } + + if (CurrentIGI < DIG_Lower ){ + CurrentIGI = DIG_Lower; + } + else if(CurrentIGI > DIG_Upper){ + CurrentIGI = DIG_Upper; + } + + pDM_DigTable->CurIGValue = CurrentIGI; + + ODM_Write1Byte( pDM_Odm, rA_IGI_Jaguar, (u1Byte)CurrentIGI); + ODM_Write1Byte( pDM_Odm, rB_IGI_Jaguar, (u1Byte)CurrentIGI); + + C50 = ODM_Read1Byte( pDM_Odm, 0xc50); + E50 = ODM_Read1Byte( pDM_Odm, 0xe50); + //pDM_Odm->MPDIG_2G = FALSE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_MP, DBG_LOUD, ("DIG = (%x, %x), Cnt_all = %d, Cnt_Ofdm_fail = %d, Cnt_Cck_fail = %d\n", C50, E50, pFalseAlmCnt->Cnt_all, pFalseAlmCnt->Cnt_Ofdm_fail, pFalseAlmCnt->Cnt_Cck_fail)); + } + + } + else + { //2G + ODM_RT_TRACE(pDM_Odm,ODM_COMP_MP, DBG_LOUD, ("MPDIG_2G = %d,\n", pDM_Odm->MPDIG_2G)); + + if(pDM_Odm->MPDIG_2G == FALSE){ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_MP, DBG_LOUD, ("===> Fix IGI\n")); + ODM_Write1Byte( pDM_Odm, rA_IGI_Jaguar, (u1Byte)IGI_A); + ODM_Write1Byte( pDM_Odm, rB_IGI_Jaguar, (u1Byte)IGI_B); + } + if (pDM_Odm->Times_2G == 2) + pDM_Odm->MPDIG_2G = TRUE; + pDM_Odm->Times_2G++; + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DIG, DBG_LOUD, ("pDM_Odm->RxPWDBAve_final = %d\n", pDM_Odm->RxPWDBAve_final)); + + if (pDM_Odm->SupportICType == ODM_RTL8812) + odm_RFEControl(pDM_Odm, pDM_Odm->RxPWDBAve_final); + + ODM_SetTimer(pDM_Odm, &pDM_Odm->MPT_DIGTimer, 700); + +} + +VOID +odm_MPT_DIGCallback( + PRT_TIMER pTimer +) +{ + PADAPTER Adapter = (PADAPTER)pTimer->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + + + #if DEV_BUS_TYPE==RT_PCI_INTERFACE + #if USE_WORKITEM + PlatformScheduleWorkItem(&pDM_Odm->MPT_DIGWorkitem); + #else + ODM_MPT_DIG(pDM_Odm); + #endif + #else + PlatformScheduleWorkItem(&pDM_Odm->MPT_DIGWorkitem); + #endif + +} + +VOID +odm_MPT_DIGWorkItemCallback( + IN PVOID pContext + ) +{ + PADAPTER Adapter = (PADAPTER)pContext; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + + ODM_MPT_DIG(pDM_Odm); +} + + + + + //cosa debug tool need to modify + +VOID +ODM_PSDDbgControl( + IN PADAPTER Adapter, + IN u4Byte mode, + IN u4Byte btRssi + ) +{ +#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + + ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD, (" Monitor mode=%d, btRssi=%d\n", mode, btRssi)); + if(mode) + { + pDM_Odm->RSSI_BT = (u1Byte)btRssi; + pDM_Odm->bUserAssignLevel = TRUE; + ODM_SetTimer( pDM_Odm, &pDM_Odm->PSDTimer, 0); //ms + } + else + { + ODM_CancelTimer(pDM_Odm, &pDM_Odm->PSDTimer); + } +#endif +} + + +//#if(DEV_BUS_TYPE == RT_PCI_INTERFACE)|(DEV_BUS_TYPE == RT_USB_INTERFACE) + +void odm_RXHPInit( + IN PDM_ODM_T pDM_Odm) +{ +#if (DEV_BUS_TYPE == RT_PCI_INTERFACE)|(DEV_BUS_TYPE == RT_USB_INTERFACE) + pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; + u1Byte index; + + pRX_HP_Table->RXHP_enable = TRUE; + pRX_HP_Table->RXHP_flag = 0; + pRX_HP_Table->PSD_func_trigger = 0; + pRX_HP_Table->Pre_IGI = 0x20; + pRX_HP_Table->Cur_IGI = 0x20; + pRX_HP_Table->Cur_pw_th = pw_th_10dB; + pRX_HP_Table->Pre_pw_th = pw_th_10dB; + for(index=0; index<80; index++) + pRX_HP_Table->PSD_bitmap_RXHP[index] = 1; + +#if(DEV_BUS_TYPE == RT_USB_INTERFACE) + pRX_HP_Table->TP_Mode = Idle_Mode; +#endif +#endif +} + +void odm_RXHP( + IN PDM_ODM_T pDM_Odm) +{ +#if( DM_ODM_SUPPORT_TYPE & (ODM_WIN)) +#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) | (DEV_BUS_TYPE == RT_USB_INTERFACE) + PADAPTER Adapter = pDM_Odm->Adapter; + PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); + pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; + PFALSE_ALARM_STATISTICS FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); + + u1Byte i, j, sum; + u1Byte Is40MHz; + s1Byte Intf_diff_idx, MIN_Intf_diff_idx = 16; + s4Byte cur_channel; + u1Byte ch_map_intf_5M[17] = {0}; + static u4Byte FA_TH = 0; + static u1Byte psd_intf_flag = 0; + static s4Byte curRssi = 0; + static s4Byte preRssi = 0; + static u1Byte PSDTriggerCnt = 1; + + u1Byte RX_HP_enable = (u1Byte)(ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore2, bMaskDWord)>>31); // for debug!! + +#if(DEV_BUS_TYPE == RT_USB_INTERFACE) + static s8Byte lastTxOkCnt = 0, lastRxOkCnt = 0; + s8Byte curTxOkCnt, curRxOkCnt; + s8Byte curTPOkCnt; + s8Byte TP_Acc3, TP_Acc5; + static s8Byte TP_Buff[5] = {0}; + static u1Byte pre_state = 0, pre_state_flag = 0; + static u1Byte Intf_HighTP_flag = 0, De_counter = 16; + static u1Byte TP_Degrade_flag = 0; +#endif + static u1Byte LatchCnt = 0; + + if(pDM_Odm->SupportICType & (ODM_RTL8723A|ODM_RTL8188E)) + return; + //AGC RX High Power Mode is only applied on 2G band in 92D!!! + if(pDM_Odm->SupportICType == ODM_RTL8192D) + { + if(*(pDM_Odm->pBandType) != ODM_BAND_2_4G) + return; + } + + if(!(pDM_Odm->SupportAbility==ODM_BB_RXHP)) + return; + + + //RX HP ON/OFF + if(RX_HP_enable == 1) + pRX_HP_Table->RXHP_enable = FALSE; + else + pRX_HP_Table->RXHP_enable = TRUE; + + if(pRX_HP_Table->RXHP_enable == FALSE) + { + if(pRX_HP_Table->RXHP_flag == 1) + { + pRX_HP_Table->RXHP_flag = 0; + psd_intf_flag = 0; + } + return; + } + +#if(DEV_BUS_TYPE == RT_USB_INTERFACE) + //2 Record current TP for USB interface + curTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast)-lastTxOkCnt; + curRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast)-lastRxOkCnt; + lastTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast); + lastRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast); + + curTPOkCnt = curTxOkCnt+curRxOkCnt; + TP_Buff[0] = curTPOkCnt; // current TP + TP_Acc3 = PlatformDivision64((TP_Buff[1]+TP_Buff[2]+TP_Buff[3]), 3); + TP_Acc5 = PlatformDivision64((TP_Buff[0]+TP_Buff[1]+TP_Buff[2]+TP_Buff[3]+TP_Buff[4]), 5); + + if(TP_Acc5 < 1000) + pRX_HP_Table->TP_Mode = Idle_Mode; + else if((1000 < TP_Acc5)&&(TP_Acc5 < 3750000)) + pRX_HP_Table->TP_Mode = Low_TP_Mode; + else + pRX_HP_Table->TP_Mode = High_TP_Mode; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RX HP TP Mode = %d\n", pRX_HP_Table->TP_Mode)); + // Since TP result would be sampled every 2 sec, it needs to delay 4sec to wait PSD processing. + // When LatchCnt = 0, we would Get PSD result. + if(TP_Degrade_flag == 1) + { + LatchCnt--; + if(LatchCnt == 0) + { + TP_Degrade_flag = 0; + } + } + // When PSD function triggered by TP degrade 20%, and Interference Flag = 1 + // Set a De_counter to wait IGI = upper bound. If time is UP, the Interference flag will be pull down. + if(Intf_HighTP_flag == 1) + { + De_counter--; + if(De_counter == 0) + { + Intf_HighTP_flag = 0; + psd_intf_flag = 0; + } + } +#endif + + //2 AGC RX High Power Mode by PSD only applied to STA Mode + //3 NOT applied 1. Ad Hoc Mode. + //3 NOT applied 2. AP Mode + if ((pMgntInfo->mAssoc) && (!pMgntInfo->mIbss) && (!ACTING_AS_AP(Adapter))) + { + Is40MHz = *(pDM_Odm->pBandWidth); + curRssi = pDM_Odm->RSSI_Min; + cur_channel = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, 0x0fff) & 0x0f; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RXHP RX HP flag = %d\n", pRX_HP_Table->RXHP_flag)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RXHP FA = %d\n", FalseAlmCnt->Cnt_all)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RXHP cur RSSI = %d, pre RSSI=%d\n", curRssi, preRssi)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RXHP current CH = %d\n", cur_channel)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RXHP Is 40MHz = %d\n", Is40MHz)); + //2 PSD function would be triggered + //3 1. Every 4 sec for PCIE + //3 2. Before TP Mode (Idle TP<4kbps) for USB + //3 3. After TP Mode (High TP) for USB + if((curRssi > 68) && (pRX_HP_Table->RXHP_flag == 0)) // Only RSSI>TH and RX_HP_flag=0 will Do PSD process + { +#if (DEV_BUS_TYPE == RT_USB_INTERFACE) + //2 Before TP Mode ==> PSD would be trigger every 4 sec + if(pRX_HP_Table->TP_Mode == Idle_Mode) //2.1 less wlan traffic <4kbps + { +#endif + if(PSDTriggerCnt == 1) + { + odm_PSD_RXHP(pDM_Odm); + pRX_HP_Table->PSD_func_trigger = 1; + PSDTriggerCnt = 0; + } + else + { + PSDTriggerCnt++; + } +#if(DEV_BUS_TYPE == RT_USB_INTERFACE) + } + //2 After TP Mode ==> Check if TP degrade larger than 20% would trigger PSD function + if(pRX_HP_Table->TP_Mode == High_TP_Mode) + { + if((pre_state_flag == 0)&&(LatchCnt == 0)) + { + // TP var < 5% + if((((curTPOkCnt-TP_Acc3)*20)<(TP_Acc3))&&(((curTPOkCnt-TP_Acc3)*20)>(-TP_Acc3))) + { + pre_state++; + if(pre_state == 3) // hit pre_state condition => consecutive 3 times + { + pre_state_flag = 1; + pre_state = 0; + } + + } + else + { + pre_state = 0; + } + } + //3 If pre_state_flag=1 ==> start to monitor TP degrade 20% + if(pre_state_flag == 1) + { + if(((TP_Acc3-curTPOkCnt)*5)>(TP_Acc3)) // degrade 20% + { + odm_PSD_RXHP(pDM_Odm); + pRX_HP_Table->PSD_func_trigger = 1; + TP_Degrade_flag = 1; + LatchCnt = 2; + pre_state_flag = 0; + } + else if(((TP_Buff[2]-curTPOkCnt)*5)>TP_Buff[2]) + { + odm_PSD_RXHP(pDM_Odm); + pRX_HP_Table->PSD_func_trigger = 1; + TP_Degrade_flag = 1; + LatchCnt = 2; + pre_state_flag = 0; + } + else if(((TP_Buff[3]-curTPOkCnt)*5)>TP_Buff[3]) + { + odm_PSD_RXHP(pDM_Odm); + pRX_HP_Table->PSD_func_trigger = 1; + TP_Degrade_flag = 1; + LatchCnt = 2; + pre_state_flag = 0; + } + } + } +#endif +} + +#if (DEV_BUS_TYPE == RT_USB_INTERFACE) + for (i=0;i<4;i++) + { + TP_Buff[4-i] = TP_Buff[3-i]; + } +#endif + //2 Update PSD bitmap according to PSD report + if((pRX_HP_Table->PSD_func_trigger == 1)&&(LatchCnt == 0)) + { + //2 Separate 80M bandwidth into 16 group with smaller 5M BW. + for (i = 0 ; i < 16 ; i++) + { + sum = 0; + for(j = 0; j < 5 ; j++) + sum += pRX_HP_Table->PSD_bitmap_RXHP[5*i + j]; + + if(sum < 5) + { + ch_map_intf_5M[i] = 1; // interference flag + } + } + //=============just for debug========================= + //for(i=0;i<16;i++) + //DbgPrint("RX HP: ch_map_intf_5M[%d] = %d\n", i, ch_map_intf_5M[i]); + //=============================================== + //2 Mask target channel 5M index + for(i = 0; i < (4+4*Is40MHz) ; i++) + { + ch_map_intf_5M[cur_channel - (1+2*Is40MHz) + i] = 0; + } + + psd_intf_flag = 0; + for(i = 0; i < 16; i++) + { + if(ch_map_intf_5M[i] == 1) + { + psd_intf_flag = 1; // interference is detected!!! + break; + } + } + +#if (DEV_BUS_TYPE == RT_USB_INTERFACE) + if(pRX_HP_Table->TP_Mode!=Idle_Mode) + { + if(psd_intf_flag == 1) // to avoid psd_intf_flag always 1 + { + Intf_HighTP_flag = 1; + De_counter = 32; // 0x1E -> 0x3E needs 32 times by each IGI step =1 + } + } +#endif + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RX HP psd_intf_flag = %d\n", psd_intf_flag)); + //2 Distance between target channel and interference + for(i = 0; i < 16; i++) + { + if(ch_map_intf_5M[i] == 1) + { + Intf_diff_idx = ((cur_channel+Is40MHz-(i+1))>0) ? (s1Byte)(cur_channel-2*Is40MHz-(i-2)) : (s1Byte)((i+1)-(cur_channel+2*Is40MHz)); + if(Intf_diff_idx < MIN_Intf_diff_idx) + MIN_Intf_diff_idx = Intf_diff_idx; // the min difference index between interference and target + } + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RX HP MIN_Intf_diff_idx = %d\n", MIN_Intf_diff_idx)); + //2 Choose False Alarm Threshold + switch (MIN_Intf_diff_idx){ + case 0: + case 1: + case 2: + case 3: + FA_TH = FA_RXHP_TH1; + break; + case 4: // CH5 + case 5: // CH6 + FA_TH = FA_RXHP_TH2; + break; + case 6: // CH7 + case 7: // CH8 + FA_TH = FA_RXHP_TH3; + break; + case 8: // CH9 + case 9: //CH10 + FA_TH = FA_RXHP_TH4; + break; + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + FA_TH = FA_RXHP_TH5; + break; + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_RXHP, ODM_DBG_LOUD, ("RX HP FA_TH = %d\n", FA_TH)); + pRX_HP_Table->PSD_func_trigger = 0; + } + //1 Monitor RSSI variation to choose the suitable IGI or Exit AGC RX High Power Mode + if(pRX_HP_Table->RXHP_flag == 1) + { + if ((curRssi > 80)&&(preRssi < 80)) + { + pRX_HP_Table->Cur_IGI = LNA_Low_Gain_1; + } + else if ((curRssi < 80)&&(preRssi > 80)) + { + pRX_HP_Table->Cur_IGI = LNA_Low_Gain_2; + } + else if ((curRssi > 72)&&(preRssi < 72)) + { + pRX_HP_Table->Cur_IGI = LNA_Low_Gain_2; + } + else if ((curRssi < 72)&&( preRssi > 72)) + { + pRX_HP_Table->Cur_IGI = LNA_Low_Gain_3; + } + else if (curRssi < 68) //RSSI is NOT large enough!!==> Exit AGC RX High Power Mode + { + pRX_HP_Table->Cur_pw_th = pw_th_10dB; + pRX_HP_Table->RXHP_flag = 0; // Back to Normal DIG Mode + psd_intf_flag = 0; + } + } + else // pRX_HP_Table->RXHP_flag == 0 + { + //1 Decide whether to enter AGC RX High Power Mode + if ((curRssi > 70) && (psd_intf_flag == 1) && (FalseAlmCnt->Cnt_all > FA_TH) && + (pDM_DigTable->CurIGValue == pDM_DigTable->rx_gain_range_max)) + { + if (curRssi > 80) + { + pRX_HP_Table->Cur_IGI = LNA_Low_Gain_1; + } + else if (curRssi > 72) + { + pRX_HP_Table->Cur_IGI = LNA_Low_Gain_2; + } + else + { + pRX_HP_Table->Cur_IGI = LNA_Low_Gain_3; + } + pRX_HP_Table->Cur_pw_th = pw_th_16dB; //RegC54[9:8]=2'b11: to enter AGC Flow 3 + pRX_HP_Table->First_time_enter = TRUE; + pRX_HP_Table->RXHP_flag = 1; // RXHP_flag=1: AGC RX High Power Mode, RXHP_flag=0: Normal DIG Mode + } + } + preRssi = curRssi; + odm_Write_RXHP(pDM_Odm); + } +#endif //#if( DM_ODM_SUPPORT_TYPE & (ODM_WIN)) +#endif //#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) | (DEV_BUS_TYPE == RT_USB_INTERFACE) +} + +void odm_Write_RXHP( + IN PDM_ODM_T pDM_Odm) +{ + pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; + u4Byte currentIGI; + + if(pRX_HP_Table->Cur_IGI != pRX_HP_Table->Pre_IGI) + { + ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskByte0, pRX_HP_Table->Cur_IGI); + ODM_SetBBReg(pDM_Odm, rOFDM0_XBAGCCore1, bMaskByte0, pRX_HP_Table->Cur_IGI); + } + + if(pRX_HP_Table->Cur_pw_th != pRX_HP_Table->Pre_pw_th) +{ + ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore2, BIT8|BIT9, pRX_HP_Table->Cur_pw_th); // RegC54[9:8]=2'b11: AGC Flow 3 + } + + if(pRX_HP_Table->RXHP_flag == 0) + { + pRX_HP_Table->Cur_IGI = 0x20; + } + else + { + currentIGI = ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskByte0); + if(currentIGI<0x50) + { + ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskByte0, pRX_HP_Table->Cur_IGI); + ODM_SetBBReg(pDM_Odm, rOFDM0_XBAGCCore1, bMaskByte0, pRX_HP_Table->Cur_IGI); + } + } + pRX_HP_Table->Pre_IGI = pRX_HP_Table->Cur_IGI; + pRX_HP_Table->Pre_pw_th = pRX_HP_Table->Cur_pw_th; + +} + +VOID +odm_PSD_RXHP( + IN PDM_ODM_T pDM_Odm +) +{ + pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; + PADAPTER Adapter = pDM_Odm->Adapter; + PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); + unsigned int pts, start_point, stop_point, initial_gain ; + static u1Byte PSD_bitmap_memory[80], init_memory = 0; + static u1Byte psd_cnt=0; + static u4Byte PSD_report[80], PSD_report_tmp; + static u8Byte lastTxOkCnt=0, lastRxOkCnt=0; + u1Byte idx[20]={96,99,102,106,109,112,115,118,122,125, + 0,3,6,10,13,16,19,22,26,29}; + u1Byte n, i, channel, BBReset,tone_idx; + u1Byte PSD_bitmap[10]/*, SSBT=0*/,initial_gain_psd=0, RSSI_BT=0, initialGainUpper; + s4Byte PSD_skip_start, PSD_skip_stop; + u4Byte CurrentChannel, RXIQI, RxIdleLowPwr, wlan_channel; + u4Byte ReScan, Interval, Is40MHz; + u8Byte curTxOkCnt, curRxOkCnt; + //--------------2G band synthesizer for 92D switch RF channel using----------------- + u1Byte group_idx=0; + u4Byte SYN_RF25=0, SYN_RF26=0, SYN_RF27=0, SYN_RF2B=0, SYN_RF2C=0; + u4Byte SYN[5] = {0x25, 0x26, 0x27, 0x2B, 0x2C}; // synthesizer RF register for 2G channel + u4Byte SYN_group[3][5] = {{0x643BC, 0xFC038, 0x77C1A, 0x41289, 0x01840}, // For CH1,2,4,9,10.11.12 {0x643BC, 0xFC038, 0x77C1A, 0x41289, 0x01840} + {0x643BC, 0xFC038, 0x07C1A, 0x41289, 0x01840}, // For CH3,13,14 + {0x243BC, 0xFC438, 0x07C1A, 0x4128B, 0x0FC41}}; // For Ch5,6,7,8 + //--------------------- Add by Gary for Debug setting ---------------------- + u1Byte RSSI_BT_new = (u1Byte) ODM_GetBBReg(pDM_Odm, 0xB9C, 0xFF); + u1Byte rssi_ctrl = (u1Byte) ODM_GetBBReg(pDM_Odm, 0xB38, 0xFF); + //--------------------------------------------------------------------- + + if(pMgntInfo->bScanInProgress) + { + return; + } + + ReScan = PSD_RESCAN; + Interval = SCAN_INTERVAL; + + + //1 Initialization + if(init_memory == 0) + { + RT_TRACE( COMP_PSD, DBG_LOUD,("Init memory\n")); + for(i = 0; i < 80; i++) + PSD_bitmap_memory[i] = 0xFF; // channel is always good + init_memory = 1; + } + if(psd_cnt == 0) + { + RT_TRACE(COMP_PSD, DBG_LOUD,("Enter dm_PSD_Monitor\n")); + for(i = 0; i < 80; i++) + PSD_report[i] = 0; + } + + //1 Backup Current Settings + CurrentChannel = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask); + if(pDM_Odm->SupportICType == ODM_RTL8192D) + { + //2 Record Current synthesizer parameters based on current channel + if((*(pDM_Odm->pMacPhyMode)==ODM_SMSP)||(*(pDM_Odm->pMacPhyMode)==ODM_DMSP)) + { + SYN_RF25 = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x25, bMaskDWord); + SYN_RF26 = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x26, bMaskDWord); + SYN_RF27 = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x27, bMaskDWord); + SYN_RF2B = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x2B, bMaskDWord); + SYN_RF2C = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x2C, bMaskDWord); + } + else // DualMAC_DualPHY 2G + { + SYN_RF25 = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x25, bMaskDWord); + SYN_RF26 = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x26, bMaskDWord); + SYN_RF27 = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x27, bMaskDWord); + SYN_RF2B = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x2B, bMaskDWord); + SYN_RF2C = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x2C, bMaskDWord); + } + } + RXIQI = ODM_GetBBReg(pDM_Odm, 0xC14, bMaskDWord); + RxIdleLowPwr = (ODM_GetBBReg(pDM_Odm, 0x818, bMaskDWord)&BIT28)>>28; + Is40MHz = *(pDM_Odm->pBandWidth); + ODM_RT_TRACE(pDM_Odm, COMP_PSD, DBG_LOUD,("PSD Scan Start\n")); + //1 Turn off CCK + ODM_SetBBReg(pDM_Odm, rFPGA0_RFMOD, BIT24, 0); + //1 Turn off TX + //Pause TX Queue + ODM_Write1Byte(pDM_Odm, REG_TXPAUSE, 0xFF); + //Force RX to stop TX immediately + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_AC, bRFRegOffsetMask, 0x32E13); + //1 Turn off RX + //Rx AGC off RegC70[0]=0, RegC7C[20]=0 + ODM_SetBBReg(pDM_Odm, 0xC70, BIT0, 0); + ODM_SetBBReg(pDM_Odm, 0xC7C, BIT20, 0); + //Turn off CCA + ODM_SetBBReg(pDM_Odm, 0xC14, bMaskDWord, 0x0); + //BB Reset + ODM_SetBBReg(pDM_Odm, 0x87C, BIT31, 1); //clock gated to prevent from AGC table mess + BBReset = ODM_Read1Byte(pDM_Odm, 0x02); + ODM_Write1Byte(pDM_Odm, 0x02, BBReset&(~BIT0)); + ODM_Write1Byte(pDM_Odm, 0x02, BBReset|BIT0); + ODM_SetBBReg(pDM_Odm, 0x87C, BIT31, 0); + //1 Leave RX idle low power + ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0); + //1 Fix initial gain + RSSI_BT = RSSI_BT_new; + RT_TRACE(COMP_PSD, DBG_LOUD,("PSD: RSSI_BT= %d\n", RSSI_BT)); + + if(rssi_ctrl == 1) // just for debug!! + initial_gain_psd = RSSI_BT_new; + else + initial_gain_psd = pDM_Odm->RSSI_Min; // PSD report based on RSSI + + RT_TRACE(COMP_PSD, DBG_LOUD,("PSD: RSSI_BT= %d\n", RSSI_BT)); + + initialGainUpper = 0x54; + + RSSI_BT = initial_gain_psd; + //SSBT = RSSI_BT; + + //RT_TRACE( COMP_PSD, DBG_LOUD,("PSD: SSBT= %d\n", SSBT)); + RT_TRACE( COMP_PSD, DBG_LOUD,("PSD: initial gain= 0x%x\n", initial_gain_psd)); + + pDM_Odm->bDMInitialGainEnable = FALSE; + initial_gain = ODM_GetBBReg(pDM_Odm, 0xc50, bMaskDWord) & 0x7F; + //ODM_SetBBReg(pDM_Odm, 0xc50, 0x7F, initial_gain_psd); + ODM_Write_DIG(pDM_Odm, initial_gain_psd); + //1 Turn off 3-wire + ODM_SetBBReg(pDM_Odm, 0x88c, BIT20|BIT21|BIT22|BIT23, 0xF); + + //pts value = 128, 256, 512, 1024 + pts = 128; + + if(pts == 128) + { + ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x0); + start_point = 64; + stop_point = 192; + } + else if(pts == 256) + { + ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x1); + start_point = 128; + stop_point = 384; + } + else if(pts == 512) + { + ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x2); + start_point = 256; + stop_point = 768; + } + else + { + ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x3); + start_point = 512; + stop_point = 1536; + } + + +//3 Skip WLAN channels if WLAN busy + curTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast) - lastTxOkCnt; + curRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast) - lastRxOkCnt; + lastTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast); + lastRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast); + + PSD_skip_start=80; + PSD_skip_stop = 0; + wlan_channel = CurrentChannel & 0x0f; + + RT_TRACE(COMP_PSD,DBG_LOUD,("PSD: current channel: %x, BW:%d \n", wlan_channel, Is40MHz)); + + if((curRxOkCnt+curTxOkCnt) > 1000) + { + PSD_skip_start = (wlan_channel-1)*5 -Is40MHz*10; + PSD_skip_stop = PSD_skip_start + (1+Is40MHz)*20; + } + + RT_TRACE(COMP_PSD,DBG_LOUD,("PSD: Skip tone from %d to %d \n", PSD_skip_start, PSD_skip_stop)); + + for (n=0;n<80;n++) + { + if((n%20)==0) + { + channel = (n/20)*4 + 1; + if(pDM_Odm->SupportICType == ODM_RTL8192D) + { + switch(channel) + { + case 1: + case 9: + group_idx = 0; + break; + case 5: + group_idx = 2; + break; + case 13: + group_idx = 1; + break; + } + if((*(pDM_Odm->pMacPhyMode)==ODM_SMSP)||(*(pDM_Odm->pMacPhyMode)==ODM_DMSP)) + { + for(i = 0; i < SYN_Length; i++) + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, SYN[i], bMaskDWord, SYN_group[group_idx][i]); + + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, 0x3FF, channel); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, RF_CHNLBW, 0x3FF, channel); + } + else // DualMAC_DualPHY 2G + { + for(i = 0; i < SYN_Length; i++) + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, SYN[i], bMaskDWord, SYN_group[group_idx][i]); + + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, 0x3FF, channel); + } + } + else + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, 0x3FF, channel); + } + tone_idx = n%20; + if ((n>=PSD_skip_start) && (n<PSD_skip_stop)) + { + PSD_report[n] = initial_gain_psd;//SSBT; + ODM_RT_TRACE(pDM_Odm,COMP_PSD,DBG_LOUD,("PSD:Tone %d skipped \n", n)); + } + else + { + PSD_report_tmp = GetPSDData(pDM_Odm, idx[tone_idx], initial_gain_psd); + + if ( PSD_report_tmp > PSD_report[n]) + PSD_report[n] = PSD_report_tmp; + + } + } + + PatchDCTone(pDM_Odm, PSD_report, initial_gain_psd); + + //----end + //1 Turn on RX + //Rx AGC on + ODM_SetBBReg(pDM_Odm, 0xC70, BIT0, 1); + ODM_SetBBReg(pDM_Odm, 0xC7C, BIT20, 1); + //CCK on + ODM_SetBBReg(pDM_Odm, rFPGA0_RFMOD, BIT24, 1); + //1 Turn on TX + //Resume TX Queue + ODM_Write1Byte(pDM_Odm, REG_TXPAUSE, 0x00); + //Turn on 3-wire + ODM_SetBBReg(pDM_Odm, 0x88c, BIT20|BIT21|BIT22|BIT23, 0x0); + //1 Restore Current Settings + //Resume DIG + pDM_Odm->bDMInitialGainEnable= TRUE; + //ODM_SetBBReg(pDM_Odm, 0xc50, 0x7F, initial_gain); + ODM_Write_DIG(pDM_Odm,(u1Byte) initial_gain); + // restore originl center frequency + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, CurrentChannel); + if(pDM_Odm->SupportICType == ODM_RTL8192D) + { + if((*(pDM_Odm->pMacPhyMode)==ODM_SMSP)||(*(pDM_Odm->pMacPhyMode)==ODM_DMSP)) + { + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, RF_CHNLBW, bMaskDWord, CurrentChannel); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x25, bMaskDWord, SYN_RF25); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x26, bMaskDWord, SYN_RF26); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x27, bMaskDWord, SYN_RF27); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x2B, bMaskDWord, SYN_RF2B); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x2C, bMaskDWord, SYN_RF2C); + } + else // DualMAC_DualPHY + { + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x25, bMaskDWord, SYN_RF25); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x26, bMaskDWord, SYN_RF26); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x27, bMaskDWord, SYN_RF27); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x2B, bMaskDWord, SYN_RF2B); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x2C, bMaskDWord, SYN_RF2C); + } + } + //Turn on CCA + ODM_SetBBReg(pDM_Odm, 0xC14, bMaskDWord, RXIQI); + //Restore RX idle low power + if(RxIdleLowPwr == TRUE) + ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 1); + + psd_cnt++; + //gPrint("psd cnt=%d\n", psd_cnt); + ODM_RT_TRACE(pDM_Odm,COMP_PSD, DBG_LOUD,("PSD:psd_cnt = %d \n",psd_cnt)); + if (psd_cnt < ReScan) + { + ODM_SetTimer(pDM_Odm, &pRX_HP_Table->PSDTimer, Interval); //ms + } + else + { + psd_cnt = 0; + for(i=0;i<80;i++) + RT_TRACE( COMP_PSD, DBG_LOUD,("psd_report[%d]= %d \n", 2402+i, PSD_report[i])); + //DbgPrint("psd_report[%d]= %d \n", 2402+i, PSD_report[i]); + + GoodChannelDecision(pDM_Odm, PSD_report, PSD_bitmap,RSSI_BT, PSD_bitmap_memory); + + } + } + +VOID +odm_PSD_RXHPCallback( + PRT_TIMER pTimer +) +{ + PADAPTER Adapter = (PADAPTER)pTimer->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + pRXHP_T pRX_HP_Table = &pDM_Odm->DM_RXHP_Table; + +#if DEV_BUS_TYPE==RT_PCI_INTERFACE + #if USE_WORKITEM + ODM_ScheduleWorkItem(&pRX_HP_Table->PSDTimeWorkitem); + #else + odm_PSD_RXHP(pDM_Odm); + #endif +#else + ODM_ScheduleWorkItem(&pRX_HP_Table->PSDTimeWorkitem); +#endif + + } + +VOID +odm_PSD_RXHPWorkitemCallback( + IN PVOID pContext + ) +{ + PADAPTER pAdapter = (PADAPTER)pContext; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + + odm_PSD_RXHP(pDM_Odm); +} + +#endif //#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +VOID +odm_PathDiversityInit( + IN PDM_ODM_T pDM_Odm +) +{ + if(!(pDM_Odm->SupportAbility & ODM_BB_PATH_DIV)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_PATH_DIV,ODM_DBG_LOUD,("Return: Not Support PathDiv\n")); + return; + } + +#if RTL8812A_SUPPORT + + if(pDM_Odm->SupportICType & ODM_RTL8812) + ODM_PathDiversityInit_8812A(pDM_Odm); +#endif +} + + +VOID +odm_PathDiversity( + IN PDM_ODM_T pDM_Odm +) +{ + if(!(pDM_Odm->SupportAbility & ODM_BB_PATH_DIV)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_PATH_DIV,ODM_DBG_LOUD,("Return: Not Support PathDiv\n")); + return; + } + +#if RTL8812A_SUPPORT + + if(pDM_Odm->SupportICType & ODM_RTL8812) + ODM_PathDiversity_8812A(pDM_Odm); +#endif +} + + +// +// 2011/12/02 MH Copy from MP oursrc for temporarily test. +// +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +VOID +odm_OFDMTXPathDiversity_92C( + IN PADAPTER Adapter) +{ +// HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); + PRT_WLAN_STA pEntry; + u1Byte i, DefaultRespPath = 0; + s4Byte MinRSSI = 0xFF; + pPD_T pDM_PDTable = &Adapter->DM_PDTable; + pDM_PDTable->OFDMTXPath = 0; + + //1 Default Port + if(pMgntInfo->mAssoc) + { + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_OFDMTXPathDiversity_92C: Default port RSSI[0]=%d, RSSI[1]=%d\n", + Adapter->RxStats.RxRSSIPercentage[0], Adapter->RxStats.RxRSSIPercentage[1])); + if(Adapter->RxStats.RxRSSIPercentage[0] > Adapter->RxStats.RxRSSIPercentage[1]) + { + pDM_PDTable->OFDMTXPath = pDM_PDTable->OFDMTXPath & (~BIT0); + MinRSSI = Adapter->RxStats.RxRSSIPercentage[1]; + DefaultRespPath = 0; + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_OFDMTXPathDiversity_92C: Default port Select Path-0\n")); + } + else + { + pDM_PDTable->OFDMTXPath = pDM_PDTable->OFDMTXPath | BIT0; + MinRSSI = Adapter->RxStats.RxRSSIPercentage[0]; + DefaultRespPath = 1; + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_OFDMTXPathDiversity_92C: Default port Select Path-1\n")); + } + //RT_TRACE( COMP_SWAS, DBG_LOUD, ("pDM_PDTable->OFDMTXPath =0x%x\n",pDM_PDTable->OFDMTXPath)); + } + //1 Extension Port + for(i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) + { + if(IsAPModeExist(Adapter) && GetFirstExtAdapter(Adapter) != NULL) + pEntry = AsocEntry_EnumStation(GetFirstExtAdapter(Adapter), i); + else + pEntry = AsocEntry_EnumStation(GetDefaultAdapter(Adapter), i); + + if(pEntry!=NULL) + { + if(pEntry->bAssociated) + { + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_OFDMTXPathDiversity_92C: MACID=%d, RSSI_0=%d, RSSI_1=%d\n", + pEntry->AssociatedMacId, pEntry->rssi_stat.RxRSSIPercentage[0], pEntry->rssi_stat.RxRSSIPercentage[1])); + + if(pEntry->rssi_stat.RxRSSIPercentage[0] > pEntry->rssi_stat.RxRSSIPercentage[1]) + { + pDM_PDTable->OFDMTXPath = pDM_PDTable->OFDMTXPath & ~(BIT(pEntry->AssociatedMacId)); + //pHalData->TXPath = pHalData->TXPath & ~(1<<(pEntry->AssociatedMacId)); + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_OFDMTXPathDiversity_92C: MACID=%d Select Path-0\n", pEntry->AssociatedMacId)); + if(pEntry->rssi_stat.RxRSSIPercentage[1] < MinRSSI) + { + MinRSSI = pEntry->rssi_stat.RxRSSIPercentage[1]; + DefaultRespPath = 0; + } + } + else + { + pDM_PDTable->OFDMTXPath = pDM_PDTable->OFDMTXPath | BIT(pEntry->AssociatedMacId); + //pHalData->TXPath = pHalData->TXPath | (1 << (pEntry->AssociatedMacId)); + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_OFDMTXPathDiversity_92C: MACID=%d Select Path-1\n", pEntry->AssociatedMacId)); + if(pEntry->rssi_stat.RxRSSIPercentage[0] < MinRSSI) + { + MinRSSI = pEntry->rssi_stat.RxRSSIPercentage[0]; + DefaultRespPath = 1; + } + } + } + } + else + { + break; + } + } + + pDM_PDTable->OFDMDefaultRespPath = DefaultRespPath; +} + + +BOOLEAN +odm_IsConnected_92C( + IN PADAPTER Adapter +) +{ + PRT_WLAN_STA pEntry; + PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); + u4Byte i; + BOOLEAN bConnected=FALSE; + + if(pMgntInfo->mAssoc) + { + bConnected = TRUE; + } + else + { + for(i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) + { + if(IsAPModeExist(Adapter) && GetFirstExtAdapter(Adapter) != NULL) + pEntry = AsocEntry_EnumStation(GetFirstExtAdapter(Adapter), i); + else + pEntry = AsocEntry_EnumStation(GetDefaultAdapter(Adapter), i); + + if(pEntry!=NULL) + { + if(pEntry->bAssociated) + { + bConnected = TRUE; + break; + } + } + else + { + break; + } + } + } + return bConnected; +} + + +VOID +odm_ResetPathDiversity_92C( + IN PADAPTER Adapter +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + pPD_T pDM_PDTable = &Adapter->DM_PDTable; + PRT_WLAN_STA pEntry; + u4Byte i,j; + + pHalData->RSSI_test = FALSE; + pDM_PDTable->CCK_Pkt_Cnt = 0; + pDM_PDTable->OFDM_Pkt_Cnt = 0; + pHalData->CCK_Pkt_Cnt =0; + pHalData->OFDM_Pkt_Cnt =0; + + if(pDM_PDTable->CCKPathDivEnable == TRUE) + PHY_SetBBReg(Adapter, rCCK0_AFESetting , 0x0F000000, 0x01); //RX path = PathAB + + for(i=0; i<2; i++) + { + pDM_PDTable->RSSI_CCK_Path_cnt[i]=0; + pDM_PDTable->RSSI_CCK_Path[i] = 0; + } + for(i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) + { + if(IsAPModeExist(Adapter) && GetFirstExtAdapter(Adapter) != NULL) + pEntry = AsocEntry_EnumStation(GetFirstExtAdapter(Adapter), i); + else + pEntry = AsocEntry_EnumStation(GetDefaultAdapter(Adapter), i); + + if(pEntry!=NULL) + { + pEntry->rssi_stat.CCK_Pkt_Cnt = 0; + pEntry->rssi_stat.OFDM_Pkt_Cnt = 0; + for(j=0; j<2; j++) + { + pEntry->rssi_stat.RSSI_CCK_Path_cnt[j] = 0; + pEntry->rssi_stat.RSSI_CCK_Path[j] = 0; + } + } + else + break; + } +} + + +VOID +odm_CCKTXPathDiversity_92C( + IN PADAPTER Adapter +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); + PRT_WLAN_STA pEntry; + s4Byte MinRSSI = 0xFF; + u1Byte i, DefaultRespPath = 0; +// BOOLEAN bBModePathDiv = FALSE; + pPD_T pDM_PDTable = &Adapter->DM_PDTable; + + //1 Default Port + if(pMgntInfo->mAssoc) + { + if(pHalData->OFDM_Pkt_Cnt == 0) + { + for(i=0; i<2; i++) + { + if(pDM_PDTable->RSSI_CCK_Path_cnt[i] > 1) //Because the first packet is discarded + pDM_PDTable->RSSI_CCK_Path[i] = pDM_PDTable->RSSI_CCK_Path[i] / (pDM_PDTable->RSSI_CCK_Path_cnt[i]-1); + else + pDM_PDTable->RSSI_CCK_Path[i] = 0; + } + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: pDM_PDTable->RSSI_CCK_Path[0]=%d, pDM_PDTable->RSSI_CCK_Path[1]=%d\n", + pDM_PDTable->RSSI_CCK_Path[0], pDM_PDTable->RSSI_CCK_Path[1])); + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: pDM_PDTable->RSSI_CCK_Path_cnt[0]=%d, pDM_PDTable->RSSI_CCK_Path_cnt[1]=%d\n", + pDM_PDTable->RSSI_CCK_Path_cnt[0], pDM_PDTable->RSSI_CCK_Path_cnt[1])); + + if(pDM_PDTable->RSSI_CCK_Path[0] > pDM_PDTable->RSSI_CCK_Path[1]) + { + pDM_PDTable->CCKTXPath = pDM_PDTable->CCKTXPath & (~BIT0); + MinRSSI = pDM_PDTable->RSSI_CCK_Path[1]; + DefaultRespPath = 0; + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: Default port Select CCK Path-0\n")); + } + else if(pDM_PDTable->RSSI_CCK_Path[0] < pDM_PDTable->RSSI_CCK_Path[1]) + { + pDM_PDTable->CCKTXPath = pDM_PDTable->CCKTXPath | BIT0; + MinRSSI = pDM_PDTable->RSSI_CCK_Path[0]; + DefaultRespPath = 1; + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: Default port Select CCK Path-1\n")); + } + else + { + if((pDM_PDTable->RSSI_CCK_Path[0] != 0) && (pDM_PDTable->RSSI_CCK_Path[0] < MinRSSI)) + { + pDM_PDTable->CCKTXPath = pDM_PDTable->CCKTXPath & (~BIT0); + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: Default port Select CCK Path-0\n")); + MinRSSI = pDM_PDTable->RSSI_CCK_Path[1]; + DefaultRespPath = 0; + } + else + { + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: Default port unchange CCK Path\n")); + } + } + } + else //Follow OFDM decision + { + pDM_PDTable->CCKTXPath = (pDM_PDTable->CCKTXPath & (~BIT0)) | (pDM_PDTable->OFDMTXPath &BIT0); + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: Follow OFDM decision, Default port Select CCK Path-%d\n", + pDM_PDTable->CCKTXPath &BIT0)); + } + } + //1 Extension Port + for(i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) + { + if(IsAPModeExist(Adapter) && GetFirstExtAdapter(Adapter) != NULL) + pEntry = AsocEntry_EnumStation(GetFirstExtAdapter(Adapter), i); + else + pEntry = AsocEntry_EnumStation(GetDefaultAdapter(Adapter), i); + + if(pEntry!=NULL) + { + if(pEntry->bAssociated) + { + if(pEntry->rssi_stat.OFDM_Pkt_Cnt == 0) + { + u1Byte j=0; + for(j=0; j<2; j++) + { + if(pEntry->rssi_stat.RSSI_CCK_Path_cnt[j] > 1) + pEntry->rssi_stat.RSSI_CCK_Path[j] = pEntry->rssi_stat.RSSI_CCK_Path[j] / (pEntry->rssi_stat.RSSI_CCK_Path_cnt[j]-1); + else + pEntry->rssi_stat.RSSI_CCK_Path[j] = 0; + } + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: MACID=%d, RSSI_CCK0=%d, RSSI_CCK1=%d\n", + pEntry->AssociatedMacId, pEntry->rssi_stat.RSSI_CCK_Path[0], pEntry->rssi_stat.RSSI_CCK_Path[1])); + + if(pEntry->rssi_stat.RSSI_CCK_Path[0] >pEntry->rssi_stat.RSSI_CCK_Path[1]) + { + pDM_PDTable->CCKTXPath = pDM_PDTable->CCKTXPath & ~(BIT(pEntry->AssociatedMacId)); + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: MACID=%d Select CCK Path-0\n", pEntry->AssociatedMacId)); + if(pEntry->rssi_stat.RSSI_CCK_Path[1] < MinRSSI) + { + MinRSSI = pEntry->rssi_stat.RSSI_CCK_Path[1]; + DefaultRespPath = 0; + } + } + else if(pEntry->rssi_stat.RSSI_CCK_Path[0] <pEntry->rssi_stat.RSSI_CCK_Path[1]) + { + pDM_PDTable->CCKTXPath = pDM_PDTable->CCKTXPath | BIT(pEntry->AssociatedMacId); + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: MACID=%d Select CCK Path-1\n", pEntry->AssociatedMacId)); + if(pEntry->rssi_stat.RSSI_CCK_Path[0] < MinRSSI) + { + MinRSSI = pEntry->rssi_stat.RSSI_CCK_Path[0]; + DefaultRespPath = 1; + } + } + else + { + if((pEntry->rssi_stat.RSSI_CCK_Path[0] != 0) && (pEntry->rssi_stat.RSSI_CCK_Path[0] < MinRSSI)) + { + pDM_PDTable->CCKTXPath = pDM_PDTable->CCKTXPath & ~(BIT(pEntry->AssociatedMacId)); + MinRSSI = pEntry->rssi_stat.RSSI_CCK_Path[1]; + DefaultRespPath = 0; + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: MACID=%d Select CCK Path-0\n", pEntry->AssociatedMacId)); + } + else + { + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: MACID=%d unchange CCK Path\n", pEntry->AssociatedMacId)); + } + } + } + else //Follow OFDM decision + { + pDM_PDTable->CCKTXPath = (pDM_PDTable->CCKTXPath & (~(BIT(pEntry->AssociatedMacId)))) | (pDM_PDTable->OFDMTXPath & BIT(pEntry->AssociatedMacId)); + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: Follow OFDM decision, MACID=%d Select CCK Path-%d\n", + pEntry->AssociatedMacId, (pDM_PDTable->CCKTXPath & BIT(pEntry->AssociatedMacId))>>(pEntry->AssociatedMacId))); + } + } + } + else + { + break; + } + } + + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C:MinRSSI=%d\n",MinRSSI)); + + if(MinRSSI == 0xFF) + DefaultRespPath = pDM_PDTable->CCKDefaultRespPath; + + pDM_PDTable->CCKDefaultRespPath = DefaultRespPath; +} + + + +VOID +odm_PathDiversityAfterLink_92C( + IN PADAPTER Adapter +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + pPD_T pDM_PDTable = &Adapter->DM_PDTable; + u1Byte DefaultRespPath=0; + + if((!IS_92C_SERIAL(pHalData->VersionID)) || (pHalData->PathDivCfg != 1) || (pHalData->eRFPowerState == eRfOff)) + { + if(pHalData->PathDivCfg == 0) + { + RT_TRACE( COMP_SWAS, DBG_LOUD, ("No ODM_TXPathDiversity()\n")); + } + else + { + RT_TRACE( COMP_SWAS, DBG_LOUD, ("2T ODM_TXPathDiversity()\n")); + } + return; + } + if(!odm_IsConnected_92C(Adapter)) + { + RT_TRACE( COMP_SWAS, DBG_LOUD, ("ODM_TXPathDiversity(): No Connections\n")); + return; + } + + + if(pDM_PDTable->TrainingState == 0) + { + RT_TRACE( COMP_SWAS, DBG_LOUD, ("ODM_TXPathDiversity() ==>\n")); + odm_OFDMTXPathDiversity_92C(Adapter); + + if((pDM_PDTable->CCKPathDivEnable == TRUE) && (pDM_PDTable->OFDM_Pkt_Cnt < 100)) + { + //RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: TrainingState=0\n")); + + if(pDM_PDTable->CCK_Pkt_Cnt > 300) + pDM_PDTable->Timer = 20; + else if(pDM_PDTable->CCK_Pkt_Cnt > 100) + pDM_PDTable->Timer = 60; + else + pDM_PDTable->Timer = 250; + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: timer=%d\n",pDM_PDTable->Timer)); + + PHY_SetBBReg(Adapter, rCCK0_AFESetting , 0x0F000000, 0x00); // RX path = PathA + pDM_PDTable->TrainingState = 1; + pHalData->RSSI_test = TRUE; + ODM_SetTimer( pDM_Odm, &pDM_Odm->CCKPathDiversityTimer, pDM_PDTable->Timer); //ms + } + else + { + pDM_PDTable->CCKTXPath = pDM_PDTable->OFDMTXPath; + DefaultRespPath = pDM_PDTable->OFDMDefaultRespPath; + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_SetRespPath_92C: Skip odm_CCKTXPathDiversity_92C, DefaultRespPath is OFDM\n")); + odm_SetRespPath_92C(Adapter, DefaultRespPath); + odm_ResetPathDiversity_92C(Adapter); + RT_TRACE( COMP_SWAS, DBG_LOUD, ("ODM_TXPathDiversity() <==\n")); + } + } + else if(pDM_PDTable->TrainingState == 1) + { + //RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: TrainingState=1\n")); + PHY_SetBBReg(Adapter, rCCK0_AFESetting , 0x0F000000, 0x05); // RX path = PathB + pDM_PDTable->TrainingState = 2; + ODM_SetTimer( pDM_Odm, &pDM_Odm->CCKPathDiversityTimer, pDM_PDTable->Timer); //ms + } + else + { + //RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_CCKTXPathDiversity_92C: TrainingState=2\n")); + pDM_PDTable->TrainingState = 0; + odm_CCKTXPathDiversity_92C(Adapter); + if(pDM_PDTable->OFDM_Pkt_Cnt != 0) + { + DefaultRespPath = pDM_PDTable->OFDMDefaultRespPath; + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_SetRespPath_92C: DefaultRespPath is OFDM\n")); + } + else + { + DefaultRespPath = pDM_PDTable->CCKDefaultRespPath; + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_SetRespPath_92C: DefaultRespPath is CCK\n")); + } + odm_SetRespPath_92C(Adapter, DefaultRespPath); + odm_ResetPathDiversity_92C(Adapter); + RT_TRACE( COMP_SWAS, DBG_LOUD, ("ODM_TXPathDiversity() <==\n")); + } + +} + + + +VOID +odm_CCKTXPathDiversityCallback( + PRT_TIMER pTimer +) +{ +#if USE_WORKITEM + PADAPTER Adapter = (PADAPTER)pTimer->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; +#else + PADAPTER Adapter = (PADAPTER)pTimer->Adapter; +#endif + +#if DEV_BUS_TYPE==RT_PCI_INTERFACE +#if USE_WORKITEM + PlatformScheduleWorkItem(&pDM_Odm->CCKPathDiversityWorkitem); +#else + odm_PathDiversityAfterLink_92C(Adapter); +#endif +#else + PlatformScheduleWorkItem(&pDM_Odm->CCKPathDiversityWorkitem); +#endif + +} + + +VOID +odm_CCKTXPathDiversityWorkItemCallback( + IN PVOID pContext + ) +{ + PADAPTER Adapter = (PADAPTER)pContext; + + odm_CCKTXPathDiversity_92C(Adapter); +} + + +VOID +ODM_CCKPathDiversityChkPerPktRssi( + PADAPTER Adapter, + BOOLEAN bIsDefPort, + BOOLEAN bMatchBSSID, + PRT_WLAN_STA pEntry, + PRT_RFD pRfd, + pu1Byte pDesc + ) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + BOOLEAN bCount = FALSE; + pPD_T pDM_PDTable = &Adapter->DM_PDTable; + //BOOLEAN isCCKrate = RX_HAL_IS_CCK_RATE_92C(pDesc); +#if DEV_BUS_TYPE != RT_SDIO_INTERFACE + BOOLEAN isCCKrate = RX_HAL_IS_CCK_RATE(Adapter, pDesc); +#else //below code would be removed if we have verified SDIO + BOOLEAN isCCKrate = IS_HARDWARE_TYPE_8188E(Adapter) ? RX_HAL_IS_CCK_RATE_88E(pDesc) : RX_HAL_IS_CCK_RATE_92C(pDesc); +#endif + + if((pHalData->PathDivCfg != 1) || (pHalData->RSSI_test == FALSE)) + return; + + if(pHalData->RSSI_target==NULL && bIsDefPort && bMatchBSSID) + bCount = TRUE; + else if(pHalData->RSSI_target!=NULL && pEntry!=NULL && pHalData->RSSI_target==pEntry) + bCount = TRUE; + + if(bCount && isCCKrate) + { + if(pDM_PDTable->TrainingState == 1 ) + { + if(pEntry) + { + if(pEntry->rssi_stat.RSSI_CCK_Path_cnt[0] != 0) + pEntry->rssi_stat.RSSI_CCK_Path[0] += pRfd->Status.RxPWDBAll; + pEntry->rssi_stat.RSSI_CCK_Path_cnt[0]++; + } + else + { + if(pDM_PDTable->RSSI_CCK_Path_cnt[0] != 0) + pDM_PDTable->RSSI_CCK_Path[0] += pRfd->Status.RxPWDBAll; + pDM_PDTable->RSSI_CCK_Path_cnt[0]++; + } + } + else if(pDM_PDTable->TrainingState == 2 ) + { + if(pEntry) + { + if(pEntry->rssi_stat.RSSI_CCK_Path_cnt[1] != 0) + pEntry->rssi_stat.RSSI_CCK_Path[1] += pRfd->Status.RxPWDBAll; + pEntry->rssi_stat.RSSI_CCK_Path_cnt[1]++; + } + else + { + if(pDM_PDTable->RSSI_CCK_Path_cnt[1] != 0) + pDM_PDTable->RSSI_CCK_Path[1] += pRfd->Status.RxPWDBAll; + pDM_PDTable->RSSI_CCK_Path_cnt[1]++; + } + } + } +} + + +BOOLEAN +ODM_PathDiversityBeforeLink92C( + //IN PADAPTER Adapter + IN PDM_ODM_T pDM_Odm + ) +{ +#if (RT_MEM_SIZE_LEVEL != RT_MEM_SIZE_MINIMUM) + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE* pHalData = NULL; + PMGNT_INFO pMgntInfo = NULL; + //pSWAT_T pDM_SWAT_Table = &Adapter->DM_SWAT_Table; + pPD_T pDM_PDTable = NULL; + + s1Byte Score = 0; + PRT_WLAN_BSS pTmpBssDesc; + PRT_WLAN_BSS pTestBssDesc; + + u1Byte target_chnl = 0; + u1Byte index; + + if (pDM_Odm->Adapter == NULL) //For BSOD when plug/unplug fast. //By YJ,120413 + { // The ODM structure is not initialized. + return FALSE; + } + pHalData = GET_HAL_DATA(Adapter); + pMgntInfo = &Adapter->MgntInfo; + pDM_PDTable = &Adapter->DM_PDTable; + + // Condition that does not need to use path diversity. + if((!IS_92C_SERIAL(pHalData->VersionID)) || (pHalData->PathDivCfg!=1) || pMgntInfo->AntennaTest ) + { + RT_TRACE(COMP_SWAS, DBG_LOUD, + ("ODM_PathDiversityBeforeLink92C(): No PathDiv Mechanism before link.\n")); + return FALSE; + } + + // Since driver is going to set BB register, it shall check if there is another thread controlling BB/RF. + PlatformAcquireSpinLock(Adapter, RT_RF_STATE_SPINLOCK); + if(pHalData->eRFPowerState!=eRfOn || pMgntInfo->RFChangeInProgress || pMgntInfo->bMediaConnect) + { + PlatformReleaseSpinLock(Adapter, RT_RF_STATE_SPINLOCK); + + RT_TRACE(COMP_SWAS, DBG_LOUD, + ("ODM_PathDiversityBeforeLink92C(): RFChangeInProgress(%x), eRFPowerState(%x)\n", + pMgntInfo->RFChangeInProgress, + pHalData->eRFPowerState)); + + //pDM_SWAT_Table->SWAS_NoLink_State = 0; + pDM_PDTable->PathDiv_NoLink_State = 0; + + return FALSE; + } + else + { + PlatformReleaseSpinLock(Adapter, RT_RF_STATE_SPINLOCK); + } + + //1 Run AntDiv mechanism "Before Link" part. + //if(pDM_SWAT_Table->SWAS_NoLink_State == 0) + if(pDM_PDTable->PathDiv_NoLink_State == 0) + { + //1 Prepare to do Scan again to check current antenna state. + + // Set check state to next step. + //pDM_SWAT_Table->SWAS_NoLink_State = 1; + pDM_PDTable->PathDiv_NoLink_State = 1; + + // Copy Current Scan list. + Adapter->MgntInfo.tmpNumBssDesc = pMgntInfo->NumBssDesc; + PlatformMoveMemory((PVOID)Adapter->MgntInfo.tmpbssDesc, (PVOID)pMgntInfo->bssDesc, sizeof(RT_WLAN_BSS)*MAX_BSS_DESC); + + // Switch Antenna to another one. + if(pDM_PDTable->DefaultRespPath == 0) + { + PHY_SetBBReg(Adapter, rCCK0_AFESetting , 0x0F000000, 0x05); // TRX path = PathB + odm_SetRespPath_92C(Adapter, 1); + pDM_PDTable->OFDMTXPath = 0xFFFFFFFF; + pDM_PDTable->CCKTXPath = 0xFFFFFFFF; + } + else + { + PHY_SetBBReg(Adapter, rCCK0_AFESetting , 0x0F000000, 0x00); // TRX path = PathA + odm_SetRespPath_92C(Adapter, 0); + pDM_PDTable->OFDMTXPath = 0x0; + pDM_PDTable->CCKTXPath = 0x0; + } +#if 0 + + pDM_SWAT_Table->PreAntenna = pDM_SWAT_Table->CurAntenna; + pDM_SWAT_Table->CurAntenna = (pDM_SWAT_Table->CurAntenna==Antenna_A)?Antenna_B:Antenna_A; + + RT_TRACE(COMP_SWAS, DBG_LOUD, + ("ODM_SwAntDivCheckBeforeLink: Change to Ant(%s) for testing.\n", (pDM_SWAT_Table->CurAntenna==Antenna_A)?"A":"B")); + //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, DM_SWAT_Table.CurAntenna); + pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 = ((pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 & 0xfffffcff) | (pDM_SWAT_Table->CurAntenna<<8)); + PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, bMaskDWord, pDM_SWAT_Table->SWAS_NoLink_BK_Reg860); +#endif + + // Go back to scan function again. + RT_TRACE(COMP_SWAS, DBG_LOUD, ("ODM_PathDiversityBeforeLink92C: Scan one more time\n")); + pMgntInfo->ScanStep=0; + target_chnl = odm_SwAntDivSelectScanChnl(Adapter); + odm_SwAntDivConstructScanChnl(Adapter, target_chnl); + PlatformSetTimer(Adapter, &pMgntInfo->ScanTimer, 5); + + return TRUE; + } + else + { + //1 ScanComple() is called after antenna swiched. + //1 Check scan result and determine which antenna is going + //1 to be used. + + for(index=0; index<Adapter->MgntInfo.tmpNumBssDesc; index++) + { + pTmpBssDesc = &(Adapter->MgntInfo.tmpbssDesc[index]); + pTestBssDesc = &(pMgntInfo->bssDesc[index]); + + if(PlatformCompareMemory(pTestBssDesc->bdBssIdBuf, pTmpBssDesc->bdBssIdBuf, 6)!=0) + { + RT_TRACE(COMP_SWAS, DBG_LOUD, ("ODM_PathDiversityBeforeLink92C(): ERROR!! This shall not happen.\n")); + continue; + } + + if(pTmpBssDesc->RecvSignalPower > pTestBssDesc->RecvSignalPower) + { + RT_TRACE(COMP_SWAS, DBG_LOUD, ("ODM_PathDiversityBeforeLink92C: Compare scan entry: Score++\n")); + RT_PRINT_STR(COMP_SWAS, DBG_LOUD, "SSID: ", pTestBssDesc->bdSsIdBuf, pTestBssDesc->bdSsIdLen); + RT_TRACE(COMP_SWAS, DBG_LOUD, ("Original: %d, Test: %d\n", pTmpBssDesc->RecvSignalPower, pTestBssDesc->RecvSignalPower)); + + Score++; + PlatformMoveMemory(pTestBssDesc, pTmpBssDesc, sizeof(RT_WLAN_BSS)); + } + else if(pTmpBssDesc->RecvSignalPower < pTestBssDesc->RecvSignalPower) + { + RT_TRACE(COMP_SWAS, DBG_LOUD, ("ODM_PathDiversityBeforeLink92C: Compare scan entry: Score--\n")); + RT_PRINT_STR(COMP_SWAS, DBG_LOUD, "SSID: ", pTestBssDesc->bdSsIdBuf, pTestBssDesc->bdSsIdLen); + RT_TRACE(COMP_SWAS, DBG_LOUD, ("Original: %d, Test: %d\n", pTmpBssDesc->RecvSignalPower, pTestBssDesc->RecvSignalPower)); + Score--; + } + + } + + if(pMgntInfo->NumBssDesc!=0 && Score<=0) + { + RT_TRACE(COMP_SWAS, DBG_LOUD, + ("ODM_PathDiversityBeforeLink92C(): DefaultRespPath=%d\n", pDM_PDTable->DefaultRespPath)); + + //pDM_SWAT_Table->PreAntenna = pDM_SWAT_Table->CurAntenna; + } + else + { + RT_TRACE(COMP_SWAS, DBG_LOUD, + ("ODM_PathDiversityBeforeLink92C(): DefaultRespPath=%d\n", pDM_PDTable->DefaultRespPath)); + + if(pDM_PDTable->DefaultRespPath == 0) + { + pDM_PDTable->OFDMTXPath = 0xFFFFFFFF; + pDM_PDTable->CCKTXPath = 0xFFFFFFFF; + odm_SetRespPath_92C(Adapter, 1); + } + else + { + pDM_PDTable->OFDMTXPath = 0x0; + pDM_PDTable->CCKTXPath = 0x0; + odm_SetRespPath_92C(Adapter, 0); + } + PHY_SetBBReg(Adapter, rCCK0_AFESetting , 0x0F000000, 0x01); // RX path = PathAB + + //pDM_SWAT_Table->CurAntenna = pDM_SWAT_Table->PreAntenna; + + //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, DM_SWAT_Table.CurAntenna); + //pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 = ((pDM_SWAT_Table->SWAS_NoLink_BK_Reg860 & 0xfffffcff) | (pDM_SWAT_Table->CurAntenna<<8)); + //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, bMaskDWord, pDM_SWAT_Table->SWAS_NoLink_BK_Reg860); + } + + // Check state reset to default and wait for next time. + //pDM_SWAT_Table->SWAS_NoLink_State = 0; + pDM_PDTable->PathDiv_NoLink_State = 0; + + return FALSE; + } +#else + return FALSE; +#endif + +} + + +//Neil Chen---2011--06--22 +//----92D Path Diversity----// +//#ifdef PathDiv92D +//================================== +//3 Path Diversity +//================================== +// +// 20100514 Luke/Joseph: +// Add new function for antenna diversity after link. +// This is the main function of antenna diversity after link. +// This function is called in HalDmWatchDog() and ODM_SwAntDivChkAntSwitchCallback(). +// HalDmWatchDog() calls this function with SWAW_STEP_PEAK to initialize the antenna test. +// In SWAW_STEP_PEAK, another antenna and a 500ms timer will be set for testing. +// After 500ms, ODM_SwAntDivChkAntSwitchCallback() calls this function to compare the signal just +// listened on the air with the RSSI of original antenna. +// It chooses the antenna with better RSSI. +// There is also a aged policy for error trying. Each error trying will cost more 5 seconds waiting +// penalty to get next try. +// +// +// 20100503 Joseph: +// Add new function SwAntDivCheck8192C(). +// This is the main function of Antenna diversity function before link. +// Mainly, it just retains last scan result and scan again. +// After that, it compares the scan result to see which one gets better RSSI. +// It selects antenna with better receiving power and returns better scan result. +// + + +// +// 20100514 Luke/Joseph: +// This function is used to gather the RSSI information for antenna testing. +// It selects the RSSI of the peer STA that we want to know. +// +VOID +ODM_PathDivChkPerPktRssi( + PADAPTER Adapter, + BOOLEAN bIsDefPort, + BOOLEAN bMatchBSSID, + PRT_WLAN_STA pEntry, + PRT_RFD pRfd + ) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + BOOLEAN bCount = FALSE; + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + + if(pHalData->RSSI_target==NULL && bIsDefPort && bMatchBSSID) + bCount = TRUE; + else if(pHalData->RSSI_target!=NULL && pEntry!=NULL && pHalData->RSSI_target==pEntry) + bCount = TRUE; + + if(bCount) + { + //1 RSSI for SW Antenna Switch + if(pDM_SWAT_Table->CurAntenna == MAIN_ANT) + { + pHalData->RSSI_sum_A += pRfd->Status.RxPWDBAll; + pHalData->RSSI_cnt_A++; + } + else + { + pHalData->RSSI_sum_B += pRfd->Status.RxPWDBAll; + pHalData->RSSI_cnt_B++; + + } + } +} + + + +// +// 20100514 Luke/Joseph: +// Add new function to reset antenna diversity state after link. +// +VOID +ODM_PathDivRestAfterLink( + IN PDM_ODM_T pDM_Odm + ) +{ + PADAPTER Adapter=pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + + pHalData->RSSI_cnt_A = 0; + pHalData->RSSI_cnt_B = 0; + pHalData->RSSI_test = FALSE; + pDM_SWAT_Table->try_flag = 0x0; // NOT 0xff + pDM_SWAT_Table->RSSI_Trying = 0; + pDM_SWAT_Table->SelectAntennaMap=0xAA; + pDM_SWAT_Table->CurAntenna = MAIN_ANT; +} + + +// +// 20100514 Luke/Joseph: +// Callback function for 500ms antenna test trying. +// +VOID +odm_PathDivChkAntSwitchCallback( + PRT_TIMER pTimer +) +{ + PADAPTER Adapter = (PADAPTER)pTimer->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + +#if DEV_BUS_TYPE==RT_PCI_INTERFACE + +#if USE_WORKITEM + PlatformScheduleWorkItem(&pDM_Odm->PathDivSwitchWorkitem); +#else + odm_PathDivChkAntSwitch(pDM_Odm); +#endif +#else + PlatformScheduleWorkItem(&pDM_Odm->PathDivSwitchWorkitem); +#endif + +//odm_SwAntDivChkAntSwitch(Adapter, SWAW_STEP_DETERMINE); + +} + + +VOID +odm_PathDivChkAntSwitchWorkitemCallback( + IN PVOID pContext + ) +{ + PADAPTER pAdapter = (PADAPTER)pContext; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + + odm_PathDivChkAntSwitch(pDM_Odm); +} + + + //MAC0_ACCESS_PHY1 + +// 2011-06-22 Neil Chen & Gary Hsin +// Refer to Jr.Luke's SW ANT DIV +// 92D Path Diversity Main function +// refer to 88C software antenna diversity +// +VOID +odm_PathDivChkAntSwitch( + PDM_ODM_T pDM_Odm + //PADAPTER Adapter, + //u1Byte Step +) +{ + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + + + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + s4Byte curRSSI=100, RSSI_A, RSSI_B; + u1Byte nextAntenna=AUX_ANT; + static u8Byte lastTxOkCnt=0, lastRxOkCnt=0; + u8Byte curTxOkCnt, curRxOkCnt; + static u8Byte TXByteCnt_A=0, TXByteCnt_B=0, RXByteCnt_A=0, RXByteCnt_B=0; + u8Byte CurByteCnt=0, PreByteCnt=0; + static u1Byte TrafficLoad = TRAFFIC_LOW; + u1Byte Score_A=0, Score_B=0; + u1Byte i=0x0; + // Neil Chen + static u1Byte pathdiv_para=0x0; + static u1Byte switchfirsttime=0x00; + // u1Byte regB33 = (u1Byte) PHY_QueryBBReg(Adapter, 0xB30,BIT27); + u1Byte regB33 = (u1Byte)ODM_GetBBReg(pDM_Odm, PATHDIV_REG, BIT27); + + + //u1Byte reg637 =0x0; + static u1Byte fw_value=0x0; + //u8Byte curTxOkCnt_tmp, curRxOkCnt_tmp; + PADAPTER BuddyAdapter = Adapter->BuddyAdapter; // another adapter MAC + // Path Diversity //Neil Chen--2011--06--22 + + //u1Byte PathDiv_Trigger = (u1Byte) PHY_QueryBBReg(Adapter, 0xBA0,BIT31); + u1Byte PathDiv_Trigger = (u1Byte) ODM_GetBBReg(pDM_Odm, PATHDIV_TRI,BIT31); + u1Byte PathDiv_Enable = pHalData->bPathDiv_Enable; + + + //DbgPrint("Path Div PG Value:%x \n",PathDiv_Enable); + if((BuddyAdapter==NULL)||(!PathDiv_Enable)||(PathDiv_Trigger)||(pHalData->CurrentBandType == BAND_ON_2_4G)) + { + return; + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD,("===================>odm_PathDivChkAntSwitch()\n")); + + // The first time to switch path excluding 2nd, 3rd, ....etc.... + if(switchfirsttime==0) + { + if(regB33==0) + { + pDM_SWAT_Table->CurAntenna = MAIN_ANT; // Default MAC0_5G-->Path A (current antenna) + } + } + + // Condition that does not need to use antenna diversity. + if(pDM_Odm->SupportICType != ODM_RTL8192D) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("odm_PathDiversityMechanims(): No PathDiv Mechanism.\n")); + return; + } + + // Radio off: Status reset to default and return. + if(pHalData->eRFPowerState==eRfOff) + { + //ODM_SwAntDivRestAfterLink(Adapter); + return; + } + + /* + // Handling step mismatch condition. + // Peak step is not finished at last time. Recover the variable and check again. + if( Step != pDM_SWAT_Table->try_flag ) + { + ODM_SwAntDivRestAfterLink(Adapter); + } */ + + if(pDM_SWAT_Table->try_flag == 0xff) + { + // Select RSSI checking target + if(pMgntInfo->mAssoc && !ACTING_AS_AP(Adapter)) + { + // Target: Infrastructure mode AP. + pHalData->RSSI_target = NULL; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("odm_PathDivMechanism(): RSSI_target is DEF AP!\n")); + } + else + { + u1Byte index = 0; + PRT_WLAN_STA pEntry = NULL; + PADAPTER pTargetAdapter = NULL; + + if( pMgntInfo->mIbss || ACTING_AS_AP(Adapter) ) + { + // Target: AP/IBSS peer. + pTargetAdapter = Adapter; + } + else if(IsAPModeExist(Adapter) && GetFirstExtAdapter(Adapter) != NULL) + { + // Target: VWIFI peer. + pTargetAdapter = GetFirstExtAdapter(Adapter); + } + + if(pTargetAdapter != NULL) + { + for(index=0; index<ODM_ASSOCIATE_ENTRY_NUM; index++) + { + pEntry = AsocEntry_EnumStation(pTargetAdapter, index); + if(pEntry != NULL) + { + if(pEntry->bAssociated) + break; + } + } + } + + if(pEntry == NULL) + { + ODM_PathDivRestAfterLink(pDM_Odm); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): No Link.\n")); + return; + } + else + { + pHalData->RSSI_target = pEntry; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): RSSI_target is PEER STA\n")); + } + } + + pHalData->RSSI_cnt_A = 0; + pHalData->RSSI_cnt_B = 0; + pDM_SWAT_Table->try_flag = 0; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("odm_SwAntDivChkAntSwitch(): Set try_flag to 0 prepare for peak!\n")); + return; + } + else + { + // 1st step + curTxOkCnt = Adapter->TxStats.NumTxBytesUnicast - lastTxOkCnt; + curRxOkCnt = Adapter->RxStats.NumRxBytesUnicast - lastRxOkCnt; + lastTxOkCnt = Adapter->TxStats.NumTxBytesUnicast; + lastRxOkCnt = Adapter->RxStats.NumRxBytesUnicast; + + if(pDM_SWAT_Table->try_flag == 1) // Training State + { + if(pDM_SWAT_Table->CurAntenna == MAIN_ANT) + { + TXByteCnt_A += curTxOkCnt; + RXByteCnt_A += curRxOkCnt; + } + else + { + TXByteCnt_B += curTxOkCnt; + RXByteCnt_B += curRxOkCnt; + } + + nextAntenna = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? AUX_ANT : MAIN_ANT; + pDM_SWAT_Table->RSSI_Trying--; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: RSSI_Trying = %d\n",pDM_SWAT_Table->RSSI_Trying)); + if(pDM_SWAT_Table->RSSI_Trying == 0) + { + CurByteCnt = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? (TXByteCnt_A+RXByteCnt_A) : (TXByteCnt_B+RXByteCnt_B); + PreByteCnt = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? (TXByteCnt_B+RXByteCnt_B) : (TXByteCnt_A+RXByteCnt_A); + + if(TrafficLoad == TRAFFIC_HIGH) + { + //CurByteCnt = PlatformDivision64(CurByteCnt, 9); + PreByteCnt =PreByteCnt*9; + } + else if(TrafficLoad == TRAFFIC_LOW) + { + //CurByteCnt = PlatformDivision64(CurByteCnt, 2); + PreByteCnt =PreByteCnt*2; + } + if(pHalData->RSSI_cnt_A > 0) + RSSI_A = pHalData->RSSI_sum_A/pHalData->RSSI_cnt_A; + else + RSSI_A = 0; + if(pHalData->RSSI_cnt_B > 0) + RSSI_B = pHalData->RSSI_sum_B/pHalData->RSSI_cnt_B; + else + RSSI_B = 0; + curRSSI = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? RSSI_A : RSSI_B; + pDM_SWAT_Table->PreRSSI = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? RSSI_B : RSSI_A; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: PreRSSI = %d, CurRSSI = %d\n",pDM_SWAT_Table->PreRSSI, curRSSI)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: preAntenna= %s, curAntenna= %s \n", + (pDM_SWAT_Table->PreAntenna == MAIN_ANT?"MAIN":"AUX"), (pDM_SWAT_Table->CurAntenna == MAIN_ANT?"MAIN":"AUX"))); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: RSSI_A= %d, RSSI_cnt_A = %d, RSSI_B= %d, RSSI_cnt_B = %d\n", + RSSI_A, pHalData->RSSI_cnt_A, RSSI_B, pHalData->RSSI_cnt_B)); + } + + } + else // try_flag=0 + { + + if(pHalData->RSSI_cnt_A > 0) + RSSI_A = pHalData->RSSI_sum_A/pHalData->RSSI_cnt_A; + else + RSSI_A = 0; + if(pHalData->RSSI_cnt_B > 0) + RSSI_B = pHalData->RSSI_sum_B/pHalData->RSSI_cnt_B; + else + RSSI_B = 0; + curRSSI = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? RSSI_A : RSSI_B; + pDM_SWAT_Table->PreRSSI = (pDM_SWAT_Table->PreAntenna == MAIN_ANT)? RSSI_A : RSSI_B; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: PreRSSI = %d, CurRSSI = %d\n", pDM_SWAT_Table->PreRSSI, curRSSI)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: preAntenna= %s, curAntenna= %s \n", + (pDM_SWAT_Table->PreAntenna == MAIN_ANT?"MAIN":"AUX"), (pDM_SWAT_Table->CurAntenna == MAIN_ANT?"MAIN":"AUX"))); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH DIV=: RSSI_A= %d, RSSI_cnt_A = %d, RSSI_B= %d, RSSI_cnt_B = %d\n", + RSSI_A, pHalData->RSSI_cnt_A, RSSI_B, pHalData->RSSI_cnt_B)); + //RT_TRACE(COMP_SWAS, DBG_LOUD, ("Ekul:curTxOkCnt = %d\n", curTxOkCnt)); + //RT_TRACE(COMP_SWAS, DBG_LOUD, ("Ekul:curRxOkCnt = %d\n", curRxOkCnt)); + } + + //1 Trying State + if((pDM_SWAT_Table->try_flag == 1)&&(pDM_SWAT_Table->RSSI_Trying == 0)) + { + + if(pDM_SWAT_Table->TestMode == TP_MODE) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: TestMode = TP_MODE")); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH= TRY:CurByteCnt = %"i64fmt"d,", CurByteCnt)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH= TRY:PreByteCnt = %"i64fmt"d\n",PreByteCnt)); + if(CurByteCnt < PreByteCnt) + { + if(pDM_SWAT_Table->CurAntenna == MAIN_ANT) + pDM_SWAT_Table->SelectAntennaMap=pDM_SWAT_Table->SelectAntennaMap<<1; + else + pDM_SWAT_Table->SelectAntennaMap=(pDM_SWAT_Table->SelectAntennaMap<<1)+1; + } + else + { + if(pDM_SWAT_Table->CurAntenna == MAIN_ANT) + pDM_SWAT_Table->SelectAntennaMap=(pDM_SWAT_Table->SelectAntennaMap<<1)+1; + else + pDM_SWAT_Table->SelectAntennaMap=pDM_SWAT_Table->SelectAntennaMap<<1; + } + for (i= 0; i<8; i++) + { + if(((pDM_SWAT_Table->SelectAntennaMap>>i)&BIT0) == 1) + Score_A++; + else + Score_B++; + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("SelectAntennaMap=%x\n ",pDM_SWAT_Table->SelectAntennaMap)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Score_A=%d, Score_B=%d\n", Score_A, Score_B)); + + if(pDM_SWAT_Table->CurAntenna == MAIN_ANT) + { + nextAntenna = (Score_A >= Score_B)?MAIN_ANT:AUX_ANT; + } + else + { + nextAntenna = (Score_B >= Score_A)?AUX_ANT:MAIN_ANT; + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: nextAntenna=%s\n",(nextAntenna==MAIN_ANT)?"MAIN":"AUX")); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: preAntenna= %s, curAntenna= %s \n", + (pDM_SWAT_Table->PreAntenna == MAIN_ANT?"MAIN":"AUX"), (pDM_SWAT_Table->CurAntenna == MAIN_ANT?"MAIN":"AUX"))); + + if(nextAntenna != pDM_SWAT_Table->CurAntenna) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Switch back to another antenna")); + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: current anntena is good\n")); + } + } + + + if(pDM_SWAT_Table->TestMode == RSSI_MODE) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: TestMode = RSSI_MODE")); + pDM_SWAT_Table->SelectAntennaMap=0xAA; + if(curRSSI < pDM_SWAT_Table->PreRSSI) //Current antenna is worse than previous antenna + { + //RT_TRACE(COMP_SWAS, DBG_LOUD, ("SWAS: Switch back to another antenna")); + nextAntenna = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)?AUX_ANT : MAIN_ANT; + } + else // current anntena is good + { + nextAntenna =pDM_SWAT_Table->CurAntenna; + //RT_TRACE(COMP_SWAS, DBG_LOUD, ("SWAS: current anntena is good\n")); + } + } + + pDM_SWAT_Table->try_flag = 0; + pHalData->RSSI_test = FALSE; + pHalData->RSSI_sum_A = 0; + pHalData->RSSI_cnt_A = 0; + pHalData->RSSI_sum_B = 0; + pHalData->RSSI_cnt_B = 0; + TXByteCnt_A = 0; + TXByteCnt_B = 0; + RXByteCnt_A = 0; + RXByteCnt_B = 0; + + } + + //1 Normal State + else if(pDM_SWAT_Table->try_flag == 0) + { + if(TrafficLoad == TRAFFIC_HIGH) + { + if ((curTxOkCnt+curRxOkCnt) > 3750000)//if(PlatformDivision64(curTxOkCnt+curRxOkCnt, 2) > 1875000) + TrafficLoad = TRAFFIC_HIGH; + else + TrafficLoad = TRAFFIC_LOW; + } + else if(TrafficLoad == TRAFFIC_LOW) + { + if ((curTxOkCnt+curRxOkCnt) > 3750000)//if(PlatformDivision64(curTxOkCnt+curRxOkCnt, 2) > 1875000) + TrafficLoad = TRAFFIC_HIGH; + else + TrafficLoad = TRAFFIC_LOW; + } + if(TrafficLoad == TRAFFIC_HIGH) + pDM_SWAT_Table->bTriggerAntennaSwitch = 0; + //RT_TRACE(COMP_SWAS, DBG_LOUD, ("Normal:TrafficLoad = %llu\n", curTxOkCnt+curRxOkCnt)); + + //Prepare To Try Antenna + nextAntenna = (pDM_SWAT_Table->CurAntenna == MAIN_ANT)? AUX_ANT : MAIN_ANT; + pDM_SWAT_Table->try_flag = 1; + pHalData->RSSI_test = TRUE; + if((curRxOkCnt+curTxOkCnt) > 1000) + { +#if DEV_BUS_TYPE==RT_PCI_INTERFACE + pDM_SWAT_Table->RSSI_Trying = 4; +#else + pDM_SWAT_Table->RSSI_Trying = 2; +#endif + pDM_SWAT_Table->TestMode = TP_MODE; + } + else + { + pDM_SWAT_Table->RSSI_Trying = 2; + pDM_SWAT_Table->TestMode = RSSI_MODE; + + } + + //RT_TRACE(COMP_SWAS, DBG_LOUD, ("SWAS: Normal State -> Begin Trying!\n")); + pHalData->RSSI_sum_A = 0; + pHalData->RSSI_cnt_A = 0; + pHalData->RSSI_sum_B = 0; + pHalData->RSSI_cnt_B = 0; + } // end of try_flag=0 + } + + //1 4.Change TRX antenna + if(nextAntenna != pDM_SWAT_Table->CurAntenna) + { + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Change TX Antenna!\n ")); + //PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300, nextAntenna); for 88C + if(nextAntenna==MAIN_ANT) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Next Antenna is RF PATH A\n ")); + pathdiv_para = 0x02; //02 to switchback to RF path A + fw_value = 0x03; +#if DEV_BUS_TYPE==RT_PCI_INTERFACE + odm_PathDiversity_8192D(pDM_Odm, pathdiv_para); +#else + ODM_FillH2CCmd(Adapter, ODM_H2C_PathDiv,1,(pu1Byte)(&fw_value)); +#endif + } + else if(nextAntenna==AUX_ANT) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Next Antenna is RF PATH B\n ")); + if(switchfirsttime==0) // First Time To Enter Path Diversity + { + switchfirsttime=0x01; + pathdiv_para = 0x00; + fw_value=0x00; // to backup RF Path A Releated Registers + +#if DEV_BUS_TYPE==RT_PCI_INTERFACE + odm_PathDiversity_8192D(pDM_Odm, pathdiv_para); +#else + ODM_FillH2CCmd(Adapter, ODM_H2C_PathDiv,1,(pu1Byte)(&fw_value)); + //for(u1Byte n=0; n<80,n++) + //{ + //delay_us(500); + ODM_delay_ms(500); + odm_PathDiversity_8192D(pDM_Odm, pathdiv_para); + + fw_value=0x01; // to backup RF Path A Releated Registers + ODM_FillH2CCmd(Adapter, ODM_H2C_PathDiv,1,(pu1Byte)(&fw_value)); +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: FIRST TIME To DO PATH SWITCH!\n ")); + } + else + { + pathdiv_para = 0x01; + fw_value = 0x02; +#if DEV_BUS_TYPE==RT_PCI_INTERFACE + odm_PathDiversity_8192D(pDM_Odm, pathdiv_para); +#else + ODM_FillH2CCmd(Adapter, ODM_H2C_PathDiv,1,(pu1Byte)(&fw_value)); +#endif + } + } + // odm_PathDiversity_8192D(Adapter, pathdiv_para); + } + + //1 5.Reset Statistics + pDM_SWAT_Table->PreAntenna = pDM_SWAT_Table->CurAntenna; + pDM_SWAT_Table->CurAntenna = nextAntenna; + pDM_SWAT_Table->PreRSSI = curRSSI; + + //1 6.Set next timer + + if(pDM_SWAT_Table->RSSI_Trying == 0) + return; + + if(pDM_SWAT_Table->RSSI_Trying%2 == 0) + { + if(pDM_SWAT_Table->TestMode == TP_MODE) + { + if(TrafficLoad == TRAFFIC_HIGH) + { +#if DEV_BUS_TYPE==RT_PCI_INTERFACE + ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 10 ); //ms + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Test another antenna for 10 ms\n")); +#else + ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 20 ); //ms + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Test another antenna for 20 ms\n")); +#endif + } + else if(TrafficLoad == TRAFFIC_LOW) + { + ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 50 ); //ms + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Test another antenna for 50 ms\n")); + } + } + else // TestMode == RSSI_MODE + { + ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 500 ); //ms + ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Test another antenna for 500 ms\n")); + } + } + else + { + if(pDM_SWAT_Table->TestMode == TP_MODE) + { + if(TrafficLoad == TRAFFIC_HIGH) + +#if DEV_BUS_TYPE==RT_PCI_INTERFACE + ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 90 ); //ms + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_PATH_DIV, ODM_DBG_LOUD, ("=PATH=: Test another antenna for 90 ms\n")); +#else + ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 180); //ms +#endif + else if(TrafficLoad == TRAFFIC_LOW) + ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 100 ); //ms + } + else + ODM_SetTimer( pDM_Odm, &pDM_Odm->PathDivSwitchTimer, 500 ); //ms + } +} + +//================================================== +//3 PathDiv End +//================================================== + +VOID +odm_SetRespPath_92C( + IN PADAPTER Adapter, + IN u1Byte DefaultRespPath + ) +{ + pPD_T pDM_PDTable = &Adapter->DM_PDTable; + + RT_TRACE( COMP_SWAS, DBG_LOUD, ("odm_SetRespPath_92C: Select Response Path=%d\n",DefaultRespPath)); + if(DefaultRespPath != pDM_PDTable->DefaultRespPath) + { + if(DefaultRespPath == 0) + { + PlatformEFIOWrite1Byte(Adapter, 0x6D8, (PlatformEFIORead1Byte(Adapter, 0x6D8)&0xc0)|0x15); + } + else + { + PlatformEFIOWrite1Byte(Adapter, 0x6D8, (PlatformEFIORead1Byte(Adapter, 0x6D8)&0xc0)|0x2A); + } + } + pDM_PDTable->DefaultRespPath = DefaultRespPath; +} + + +VOID +ODM_FillTXPathInTXDESC( + IN PADAPTER Adapter, + IN PRT_TCB pTcb, + IN pu1Byte pDesc +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + u4Byte TXPath; + pPD_T pDM_PDTable = &Adapter->DM_PDTable; + + //2011.09.05 Add by Luke Lee for path diversity + if(pHalData->PathDivCfg == 1) + { + TXPath = (pDM_PDTable->OFDMTXPath >> pTcb->macId) & BIT0; + //RT_TRACE( COMP_SWAS, DBG_LOUD, ("Fill TXDESC: macID=%d, TXPath=%d\n", pTcb->macId, TXPath)); + //SET_TX_DESC_TX_ANT_CCK(pDesc,TXPath); + if(TXPath == 0) + { + SET_TX_DESC_TX_ANTL_92C(pDesc,1); + SET_TX_DESC_TX_ANT_HT_92C(pDesc,1); + } + else + { + SET_TX_DESC_TX_ANTL_92C(pDesc,2); + SET_TX_DESC_TX_ANT_HT_92C(pDesc,2); + } + TXPath = (pDM_PDTable->CCKTXPath >> pTcb->macId) & BIT0; + if(TXPath == 0) + { + SET_TX_DESC_TX_ANT_CCK_92C(pDesc,1); + } + else + { + SET_TX_DESC_TX_ANT_CCK_92C(pDesc,2); + } + } +} + +//Only for MP //Neil Chen--2012--0502-- +VOID +odm_PathDivInit_92D( +IN PDM_ODM_T pDM_Odm) +{ + pPATHDIV_PARA pathIQK = &pDM_Odm->pathIQK; + + pathIQK->org_2g_RegC14=0x0; + pathIQK->org_2g_RegC4C=0x0; + pathIQK->org_2g_RegC80=0x0; + pathIQK->org_2g_RegC94=0x0; + pathIQK->org_2g_RegCA0=0x0; + pathIQK->org_5g_RegC14=0x0; + pathIQK->org_5g_RegCA0=0x0; + pathIQK->org_5g_RegE30=0x0; + pathIQK->swt_2g_RegC14=0x0; + pathIQK->swt_2g_RegC4C=0x0; + pathIQK->swt_2g_RegC80=0x0; + pathIQK->swt_2g_RegC94=0x0; + pathIQK->swt_2g_RegCA0=0x0; + pathIQK->swt_5g_RegC14=0x0; + pathIQK->swt_5g_RegCA0=0x0; + pathIQK->swt_5g_RegE30=0x0; + +} + +#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN| ODM_CE)) + +// +// Description: +// Set Single/Dual Antenna default setting for products that do not do detection in advance. +// +// Added by Joseph, 2012.03.22 +// +VOID +ODM_SingleDualAntennaDefaultSetting( + IN PDM_ODM_T pDM_Odm + ) +{ + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + PADAPTER pAdapter = pDM_Odm->Adapter; + u1Byte btAntNum = 2; +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) + btAntNum=BT_GetPgAntNum(pAdapter); +#elif (DM_ODM_SUPPORT_TYPE & (ODM_CE)) +#ifdef CONFIG_BT_COEXIST + btAntNum = hal_btcoex_GetPgAntNum(pAdapter); +#endif +#endif + + // Set default antenna A and B status + if(btAntNum == 2) + { + pDM_SWAT_Table->ANTA_ON=TRUE; + pDM_SWAT_Table->ANTB_ON=TRUE; + //RT_TRACE(COMP_ANTENNA, DBG_LOUD, ("Dual antenna\n")); + } +#ifdef CONFIG_BT_COEXIST + else if(btAntNum == 1) + {// Set antenna A as default + pDM_SWAT_Table->ANTA_ON=TRUE; + pDM_SWAT_Table->ANTB_ON=FALSE; + //RT_TRACE(COMP_ANTENNA, DBG_LOUD, ("Single antenna\n")); + } + else + { + //RT_ASSERT(FALSE, ("Incorrect antenna number!!\n")); + } +#endif +} + + + +//2 8723A ANT DETECT +// +// Description: +// Implement IQK single tone for RF DPK loopback and BB PSD scanning. +// This function is cooperated with BB team Neil. +// +// Added by Roger, 2011.12.15 +// +BOOLEAN +ODM_SingleDualAntennaDetection( + IN PDM_ODM_T pDM_Odm, + IN u1Byte mode + ) +{ + PADAPTER pAdapter = pDM_Odm->Adapter; + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + u4Byte CurrentChannel,RfLoopReg; + u1Byte n; + u4Byte Reg88c, Regc08, Reg874, Regc50, Reg948=0, Regb2c=0, Reg92c=0, AFE_rRx_Wait_CCA=0; + u1Byte initial_gain = 0x5a; + u4Byte PSD_report_tmp; + u4Byte AntA_report = 0x0, AntB_report = 0x0,AntO_report=0x0; + BOOLEAN bResult = TRUE; + u4Byte AFE_Backup[16]; + u4Byte AFE_REG_8723A[16] = { + rRx_Wait_CCA, rTx_CCK_RFON, + rTx_CCK_BBON, rTx_OFDM_RFON, + rTx_OFDM_BBON, rTx_To_Rx, + rTx_To_Tx, rRx_CCK, + rRx_OFDM, rRx_Wait_RIFS, + rRx_TO_Rx, rStandby, + rSleep, rPMPD_ANAEN, + rFPGA0_XCD_SwitchControl, rBlue_Tooth}; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection()============> \n")); + + + if(!(pDM_Odm->SupportICType & (ODM_RTL8723A|ODM_RTL8192C|ODM_RTL8723B))) + return bResult; + + // Retrieve antenna detection registry info, added by Roger, 2012.11.27. + if(!IS_ANT_DETECT_SUPPORT_SINGLE_TONE(pAdapter)) + return bResult; + + if(pDM_Odm->SupportICType == ODM_RTL8192C) + { + //Which path in ADC/DAC is turnned on for PSD: both I/Q + ODM_SetBBReg(pDM_Odm, 0x808, BIT10|BIT11, 0x3); + //Ageraged number: 8 + ODM_SetBBReg(pDM_Odm, 0x808, BIT12|BIT13, 0x1); + //pts = 128; + ODM_SetBBReg(pDM_Odm, 0x808, BIT14|BIT15, 0x0); + } + + //1 Backup Current RF/BB Settings + + CurrentChannel = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask); + RfLoopReg = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x00, bRFRegOffsetMask); + if(!(pDM_Odm->SupportICType == ODM_RTL8723B)) + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, ODM_DPDT, Antenna_A); // change to Antenna A +#if (RTL8723B_SUPPORT == 1) + else + { + Reg92c = ODM_GetBBReg(pDM_Odm, 0x92c, bMaskDWord); + Reg948 = ODM_GetBBReg(pDM_Odm, rS0S1_PathSwitch, bMaskDWord); + Regb2c = ODM_GetBBReg(pDM_Odm, AGC_table_select, bMaskDWord); + ODM_SetBBReg(pDM_Odm, rDPDT_control, 0x3, 0x1); + ODM_SetBBReg(pDM_Odm, rfe_ctrl_anta_src, 0xff, 0x77); + ODM_SetBBReg(pDM_Odm, rS0S1_PathSwitch, 0x3ff, 0x000); + ODM_SetBBReg(pDM_Odm, AGC_table_select, BIT31, 0x0); + } +#endif + ODM_StallExecution(10); + + //Store A Path Register 88c, c08, 874, c50 + Reg88c = ODM_GetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord); + Regc08 = ODM_GetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord); + Reg874 = ODM_GetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord); + Regc50 = ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord); + + // Store AFE Registers + AFE_rRx_Wait_CCA = ODM_GetBBReg(pDM_Odm, rRx_Wait_CCA,bMaskDWord); + + //Set PSD 128 pts + ODM_SetBBReg(pDM_Odm, rFPGA0_PSDFunction, BIT14|BIT15, 0x0); //128 pts + + // To SET CH1 to do + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask, 0x7401); //Channel 1 + + // AFE all on step + if(pDM_Odm->SupportICType & (ODM_RTL8723A|ODM_RTL8192C)) + { + ODM_SetBBReg(pDM_Odm, rRx_Wait_CCA, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rTx_CCK_RFON, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rTx_CCK_BBON, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rTx_OFDM_RFON, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rTx_OFDM_BBON, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rTx_To_Rx, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rTx_To_Tx, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rRx_CCK, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rRx_OFDM, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rRx_Wait_RIFS, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rRx_TO_Rx, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rStandby, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rSleep, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rPMPD_ANAEN, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_SwitchControl, bMaskDWord, 0x6FDB25A4); + ODM_SetBBReg(pDM_Odm, rBlue_Tooth, bMaskDWord, 0x6FDB25A4); + } + else if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + ODM_SetBBReg(pDM_Odm, rRx_Wait_CCA, bMaskDWord, 0x01c00016); + } + + // 3 wire Disable + ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, 0xCCF000C0); + + //BB IQK Setting + ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800E4); + ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22208000); + + //IQK setting tone@ 4.34Mhz + ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008C1C); + ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, 0x01007c00); + + //Page B init + ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x00080000); + ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x0f600000); + ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x01004800); + ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x10008c1f); + ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x82150008); + ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28150008); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x001028d0); + + //RF loop Setting + if(pDM_Odm->SupportICType & (ODM_RTL8723A|ODM_RTL8192C)) + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x0, 0xFFFFF, 0x50008); + + //IQK Single tone start + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); + + ODM_StallExecution(10000); + + // PSD report of antenna A + PSD_report_tmp=0x0; + for (n=0;n<2;n++) + { + PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); + if(PSD_report_tmp >AntA_report) + AntA_report=PSD_report_tmp; + } + + // change to Antenna B + if(pDM_Odm->SupportICType & (ODM_RTL8723A|ODM_RTL8192C)) + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, ODM_DPDT, Antenna_B); +#if (RTL8723B_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8723B) + ODM_SetBBReg(pDM_Odm, rDPDT_control, 0x3, 0x2); +#endif + + ODM_StallExecution(10); + + // PSD report of antenna B + PSD_report_tmp=0x0; + for (n=0;n<2;n++) + { + PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); + if(PSD_report_tmp > AntB_report) + AntB_report=PSD_report_tmp; + } + + // change to open case + if(pDM_Odm->SupportICType & (ODM_RTL8723A|ODM_RTL8192C)) + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, ODM_DPDT, 0); // change to Antenna A +#if (RTL8723B_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8723B) + ODM_SetBBReg(pDM_Odm, rDPDT_control, 0x3, 0x0); +#endif + + ODM_StallExecution(10); + + // PSD report of open case + PSD_report_tmp=0x0; + for (n=0;n<2;n++) + { + PSD_report_tmp = GetPSDData(pDM_Odm, 14, initial_gain); + if(PSD_report_tmp > AntO_report) + AntO_report=PSD_report_tmp; + } + + //Close IQK Single Tone function + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); + + //1 Return to antanna A + if(pDM_Odm->SupportICType & (ODM_RTL8723A|ODM_RTL8192C)) + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, ODM_DPDT, Antenna_A); // change to Antenna A +#if (RTL8723B_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + // external DPDT + ODM_SetBBReg(pDM_Odm, rDPDT_control, bMaskDWord, Reg92c); + + //internal S0/S1 + ODM_SetBBReg(pDM_Odm, rS0S1_PathSwitch, bMaskDWord, Reg948); + ODM_SetBBReg(pDM_Odm, AGC_table_select, bMaskDWord, Regb2c); + } +#endif + ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, Reg88c); + ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, Regc08); + ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, Reg874); + ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, 0x7F, 0x40); + ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord, Regc50); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask,CurrentChannel); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x00, bRFRegOffsetMask,RfLoopReg); + + //Reload AFE Registers + ODM_SetBBReg(pDM_Odm, rRx_Wait_CCA, bMaskDWord, AFE_rRx_Wait_CCA); + + if(pDM_Odm->SupportICType == ODM_RTL8723A) + { + //2 Test Ant B based on Ant A is ON + if(mode==ANTTESTB) + { + if(AntA_report >= 100) + { + if(AntB_report > (AntA_report+1)) + { + pDM_SWAT_Table->ANTB_ON=FALSE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna A\n")); + } + else + { + pDM_SWAT_Table->ANTB_ON=TRUE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Dual Antenna is A and B\n")); + } + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n")); + pDM_SWAT_Table->ANTB_ON=FALSE; // Set Antenna B off as default + bResult = FALSE; + } + } + //2 Test Ant A and B based on DPDT Open + else if(mode==ANTTESTALL) + { + if((AntO_report >=100) && (AntO_report <=118)) + { + if(AntA_report > (AntO_report+1)) + { + pDM_SWAT_Table->ANTA_ON=FALSE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("Ant A is OFF\n")); + } + else + { + pDM_SWAT_Table->ANTA_ON=TRUE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("Ant A is ON\n")); + } + + if(AntB_report > (AntO_report+2)) + { + pDM_SWAT_Table->ANTB_ON=FALSE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("Ant B is OFF\n")); + } + else + { + pDM_SWAT_Table->ANTB_ON=TRUE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("Ant B is ON\n")); + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_A[%d]= %d \n", 2416, AntA_report)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_B[%d]= %d \n", 2416, AntB_report)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_O[%d]= %d \n", 2416, AntO_report)); + + pDM_Odm->AntDetectedInfo.bAntDetected= TRUE; + pDM_Odm->AntDetectedInfo.dBForAntA = AntA_report; + pDM_Odm->AntDetectedInfo.dBForAntB = AntB_report; + pDM_Odm->AntDetectedInfo.dBForAntO = AntO_report; + + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("return FALSE!!\n")); + bResult = FALSE; + } + } + } + else if(pDM_Odm->SupportICType == ODM_RTL8192C) + { + if(AntA_report >= 100) + { + if(AntB_report > (AntA_report+2)) + { + pDM_SWAT_Table->ANTA_ON=FALSE; + pDM_SWAT_Table->ANTB_ON=TRUE; + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_B); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna B\n")); + } + else if(AntA_report > (AntB_report+2)) + { + pDM_SWAT_Table->ANTA_ON=TRUE; + pDM_SWAT_Table->ANTB_ON=FALSE; + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_A); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna A\n")); + } + else + { + pDM_SWAT_Table->ANTA_ON=TRUE; + pDM_SWAT_Table->ANTB_ON=TRUE; + RT_TRACE(COMP_ANTENNA, DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Dual Antenna \n")); + } + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n")); + pDM_SWAT_Table->ANTA_ON=TRUE; // Set Antenna A on as default + pDM_SWAT_Table->ANTB_ON=FALSE; // Set Antenna B off as default + bResult = FALSE; + } + } + else if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_A[%d]= %d \n", 2416, AntA_report)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_B[%d]= %d \n", 2416, AntB_report)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_O[%d]= %d \n", 2416, AntO_report)); + + //2 Test Ant B based on Ant A is ON + if(mode==ANTTESTB) + { + if(AntA_report >=100 && AntA_report <= 116) + { + if(AntB_report >= (AntA_report+4) && AntB_report > 116) + { + pDM_SWAT_Table->ANTB_ON=FALSE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna A\n")); + } + else if(AntB_report >=100 && AntB_report <= 116) + { + pDM_SWAT_Table->ANTB_ON=TRUE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Dual Antenna is A and B\n")); + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n")); + pDM_SWAT_Table->ANTB_ON=FALSE; // Set Antenna B off as default + bResult = FALSE; + } + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n")); + pDM_SWAT_Table->ANTB_ON=FALSE; // Set Antenna B off as default + bResult = FALSE; + } + } + //2 Test Ant A and B based on DPDT Open + else if(mode==ANTTESTALL) + { + if((AntA_report >= 100) && (AntB_report >= 100) && (AntA_report <= 120) && (AntB_report <= 120)) + { + if((AntA_report - AntB_report < 2) || (AntB_report - AntA_report < 2)) + { + pDM_SWAT_Table->ANTA_ON=TRUE; + pDM_SWAT_Table->ANTB_ON=TRUE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("ODM_SingleDualAntennaDetection(): Dual Antenna\n")); + } + else if(((AntA_report - AntB_report >= 2) && (AntA_report - AntB_report <= 4)) || + ((AntB_report - AntA_report >= 2) && (AntB_report - AntA_report <= 4))) + { + pDM_SWAT_Table->ANTA_ON=FALSE; + pDM_SWAT_Table->ANTB_ON=FALSE; + bResult = FALSE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n")); + } + else + { + pDM_SWAT_Table->ANTA_ON = TRUE; + pDM_SWAT_Table->ANTB_ON=FALSE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("ODM_SingleDualAntennaDetection(): Single Antenna A\n")); + } + + pDM_Odm->AntDetectedInfo.bAntDetected= TRUE; + pDM_Odm->AntDetectedInfo.dBForAntA = AntA_report; + pDM_Odm->AntDetectedInfo.dBForAntB = AntB_report; + pDM_Odm->AntDetectedInfo.dBForAntO = AntO_report; + + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("return FALSE!!\n")); + bResult = FALSE; + } + } + } + + return bResult; + +} + + +#endif // end odm_CE + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN| ODM_CE)) + +VOID +odm_Set_RA_DM_ARFB_by_Noisy( + IN PDM_ODM_T pDM_Odm +) +{ + //DbgPrint("DM_ARFB ====> \n"); + if (pDM_Odm->bNoisyState){ + ODM_Write4Byte(pDM_Odm,0x430,0x00000000); + ODM_Write4Byte(pDM_Odm,0x434,0x05040200); + //DbgPrint("DM_ARFB ====> Noisy State\n"); + } + else{ + ODM_Write4Byte(pDM_Odm,0x430,0x02010000); + ODM_Write4Byte(pDM_Odm,0x434,0x07050403); + //DbgPrint("DM_ARFB ====> Clean State\n"); + } + +} + +VOID +ODM_UpdateNoisyState( + IN PDM_ODM_T pDM_Odm, + IN BOOLEAN bNoisyStateFromC2H + ) +{ + //DbgPrint("Get C2H Command! NoisyState=0x%x\n ", bNoisyStateFromC2H); + if(pDM_Odm->SupportICType == ODM_RTL8821 || pDM_Odm->SupportICType == ODM_RTL8812 || + pDM_Odm->SupportICType == ODM_RTL8723B || pDM_Odm->SupportICType == ODM_RTL8192E || pDM_Odm->SupportICType == ODM_RTL8188E) + { + pDM_Odm->bNoisyState = bNoisyStateFromC2H; + } + odm_Set_RA_DM_ARFB_by_Noisy(pDM_Odm); +}; + +u4Byte +Set_RA_DM_Ratrbitmap_by_Noisy( + IN PDM_ODM_T pDM_Odm, + IN WIRELESS_MODE WirelessMode, + IN u4Byte ratr_bitmap, + IN u1Byte rssi_level +) +{ + u4Byte ret_bitmap = ratr_bitmap; + switch (WirelessMode) + { + case WIRELESS_MODE_AC_24G : + case WIRELESS_MODE_AC_5G : + case WIRELESS_MODE_AC_ONLY: + if (pDM_Odm->bNoisyState){ // in Noisy State + if (rssi_level==1) + ret_bitmap&=0xfe3f0e08; + else if (rssi_level==2) + ret_bitmap&=0xff3f8f8c; + else if (rssi_level==3) + ret_bitmap&=0xffffffcc ; + else + ret_bitmap&=0xffffffff ; + } + else{ // in SNR State + if (rssi_level==1){ + ret_bitmap&=0xfc3e0c08; + } + else if (rssi_level==2){ + ret_bitmap&=0xfe3f0e08; + } + else if (rssi_level==3){ + ret_bitmap&=0xffbfefcc; + } + else{ + ret_bitmap&=0x0fffffff; + } + } + break; + case WIRELESS_MODE_B: + case WIRELESS_MODE_A: + case WIRELESS_MODE_G: + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + if (pDM_Odm->bNoisyState){ + if (rssi_level==1) + ret_bitmap&=0x0f0e0c08; + else if (rssi_level==2) + ret_bitmap&=0x0f8f0e0c; + else if (rssi_level==3) + ret_bitmap&=0x0fefefcc ; + else + ret_bitmap&=0xffffffff ; + } + else{ + if (rssi_level==1){ + ret_bitmap&=0x0f8f0e08; + } + else if (rssi_level==2){ + ret_bitmap&=0x0fcf8f8c; + } + else if (rssi_level==3){ + ret_bitmap&=0x0fffffcc; + } + else{ + ret_bitmap&=0x0fffffff; + } + } + break; + default: + break; + } + //DbgPrint("DM_RAMask ====> rssi_LV = %d, BITMAP = %x \n", rssi_level, ret_bitmap); + return ret_bitmap; + +} + + + +VOID +ODM_UpdateInitRate( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Rate + ) +{ + u1Byte p = 0; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("Get C2H Command! Rate=0x%x\n", Rate)); + + if(pDM_Odm->SupportICType == ODM_RTL8821 || pDM_Odm->SupportICType == ODM_RTL8812 || + pDM_Odm->SupportICType == ODM_RTL8723B || pDM_Odm->SupportICType == ODM_RTL8192E || pDM_Odm->SupportICType == ODM_RTL8188E) + { + pDM_Odm->TxRate = Rate; +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + #if DEV_BUS_TYPE==RT_PCI_INTERFACE + #if USE_WORKITEM + PlatformScheduleWorkItem(&pDM_Odm->RaRptWorkitem); + #else + if(pDM_Odm->SupportICType == ODM_RTL8821) + { + ODM_TxPwrTrackSetPwr8821A(pDM_Odm, MIX_MODE, ODM_RF_PATH_A, 0); + } + else if(pDM_Odm->SupportICType == ODM_RTL8812) + { + for (p = ODM_RF_PATH_A; p < MAX_PATH_NUM_8812A; p++) + { + ODM_TxPwrTrackSetPwr8812A(pDM_Odm, MIX_MODE, p, 0); + } + } + else if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + ODM_TxPwrTrackSetPwr_8723B(pDM_Odm, MIX_MODE, ODM_RF_PATH_A, 0); + } + else if(pDM_Odm->SupportICType == ODM_RTL8192E) + { + for (p = ODM_RF_PATH_A; p < MAX_PATH_NUM_8192E; p++) + { + ODM_TxPwrTrackSetPwr92E(pDM_Odm, MIX_MODE, p, 0); + } + } + else if(pDM_Odm->SupportICType == ODM_RTL8188E) + { + ODM_TxPwrTrackSetPwr88E(pDM_Odm, MIX_MODE, ODM_RF_PATH_A, 0); + } + #endif + #else + PlatformScheduleWorkItem(&pDM_Odm->RaRptWorkitem); + #endif +#endif + } + else + return; +} + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +VOID +ODM_UpdateInitRateWorkItemCallback( + IN PVOID pContext + ) +{ + PADAPTER Adapter = (PADAPTER)pContext; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + + u1Byte p = 0; + + if(pDM_Odm->SupportICType == ODM_RTL8821) + { + ODM_TxPwrTrackSetPwr8821A(pDM_Odm, MIX_MODE, ODM_RF_PATH_A, 0); + } + else if(pDM_Odm->SupportICType == ODM_RTL8812) + { + for (p = ODM_RF_PATH_A; p < MAX_PATH_NUM_8812A; p++) //DOn't know how to include &c + { + ODM_TxPwrTrackSetPwr8812A(pDM_Odm, MIX_MODE, p, 0); + } + } + else if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + ODM_TxPwrTrackSetPwr_8723B(pDM_Odm, MIX_MODE, ODM_RF_PATH_A, 0); + } + else if(pDM_Odm->SupportICType == ODM_RTL8192E) + { + for (p = ODM_RF_PATH_A; p < MAX_PATH_NUM_8192E; p++) //DOn't know how to include &c + { + ODM_TxPwrTrackSetPwr92E(pDM_Odm, MIX_MODE, p, 0); + } + } + else if(pDM_Odm->SupportICType == ODM_RTL8188E) + { + ODM_TxPwrTrackSetPwr88E(pDM_Odm, MIX_MODE, ODM_RF_PATH_A, 0); + } +} +#endif +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) +/* Justin: According to the current RRSI to adjust Response Frame TX power, 2012/11/05 */ +void odm_dtc(PDM_ODM_T pDM_Odm) +{ +#ifdef CONFIG_DM_RESP_TXAGC + #define DTC_BASE 35 /* RSSI higher than this value, start to decade TX power */ + #define DTC_DWN_BASE (DTC_BASE-5) /* RSSI lower than this value, start to increase TX power */ + + /* RSSI vs TX power step mapping: decade TX power */ + static const u8 dtc_table_down[]={ + DTC_BASE, + (DTC_BASE+5), + (DTC_BASE+10), + (DTC_BASE+15), + (DTC_BASE+20), + (DTC_BASE+25) + }; + + /* RSSI vs TX power step mapping: increase TX power */ + static const u8 dtc_table_up[]={ + DTC_DWN_BASE, + (DTC_DWN_BASE-5), + (DTC_DWN_BASE-10), + (DTC_DWN_BASE-15), + (DTC_DWN_BASE-15), + (DTC_DWN_BASE-20), + (DTC_DWN_BASE-20), + (DTC_DWN_BASE-25), + (DTC_DWN_BASE-25), + (DTC_DWN_BASE-30), + (DTC_DWN_BASE-35) + }; + + u8 i; + u8 dtc_steps=0; + u8 sign; + u8 resp_txagc=0; + + #if 0 + /* As DIG is disabled, DTC is also disable */ + if(!(pDM_Odm->SupportAbility & ODM_XXXXXX)) + return; + #endif + + if (DTC_BASE < pDM_Odm->RSSI_Min) { + /* need to decade the CTS TX power */ + sign = 1; + for (i=0;i<ARRAY_SIZE(dtc_table_down);i++) + { + if ((dtc_table_down[i] >= pDM_Odm->RSSI_Min) || (dtc_steps >= 6)) + break; + else + dtc_steps++; + } + } +#if 0 + else if (DTC_DWN_BASE > pDM_Odm->RSSI_Min) + { + /* needs to increase the CTS TX power */ + sign = 0; + dtc_steps = 1; + for (i=0;i<ARRAY_SIZE(dtc_table_up);i++) + { + if ((dtc_table_up[i] <= pDM_Odm->RSSI_Min) || (dtc_steps>=10)) + break; + else + dtc_steps++; + } + } +#endif + else + { + sign = 0; + dtc_steps = 0; + } + + resp_txagc = dtc_steps | (sign << 4); + resp_txagc = resp_txagc | (resp_txagc << 5); + ODM_Write1Byte(pDM_Odm, 0x06d9, resp_txagc); + + DBG_871X("%s RSSI_Min:%u, set RESP_TXAGC to %s %u\n", + __func__, pDM_Odm->RSSI_Min, sign?"minus":"plus", dtc_steps); +#endif /* CONFIG_RESP_TXAGC_ADJUST */ +} + +#endif /* #if (DM_ODM_SUPPORT_TYPE == ODM_CE) */ + +PVOID +PhyDM_Get_Structure( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Structure_Type +) + +{ + PVOID pStruct = NULL; +#if RTL8195A_SUPPORT + switch (Structure_Type){ + case PHYDM_FALSEALMCNT: + pStruct = &FalseAlmCnt; + break; + + case PHYDM_CFOTRACK: + pStruct = &DM_CfoTrack; + break; + + case PHYDM_ADAPTIVITY: + pStruct = &(pDM_Odm->Adaptivity); + break; + + default: + break; + } + +#else + switch (Structure_Type){ + case PHYDM_FALSEALMCNT: + pStruct = &(pDM_Odm->FalseAlmCnt); + break; + + //case PHYDM_CFOTRACK: + // pStruct = &(pDM_Odm->DM_CfoTrack); + //break; + + case PHYDM_ADAPTIVITY: + pStruct = &(pDM_Odm->Adaptivity); + break; + + default: + break; + } + +#endif + return pStruct; +} + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm.h new file mode 100644 index 0000000..e8003f3 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm.h @@ -0,0 +1,2409 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + + +#ifndef __HALDMOUTSRC_H__ +#define __HALDMOUTSRC_H__ + +#include "PhyDM_Adaptivity.h" + +//============================================================ +// Definition +//============================================================ +// +// 2011/09/22 MH Define all team supprt ability. +// + +// +// 2011/09/22 MH Define for all teams. Please Define the constan in your precomp header. +// +//#define DM_ODM_SUPPORT_AP 0 +//#define DM_ODM_SUPPORT_ADSL 0 +//#define DM_ODM_SUPPORT_CE 0 +//#define DM_ODM_SUPPORT_MP 1 + +// +// 2011/09/28 MH Define ODM SW team support flag. +// + + + +// +// Antenna Switch Relative Definition. +// + +// +// 20100503 Joseph: +// Add new function SwAntDivCheck8192C(). +// This is the main function of Antenna diversity function before link. +// Mainly, it just retains last scan result and scan again. +// After that, it compares the scan result to see which one gets better RSSI. +// It selects antenna with better receiving power and returns better scan result. +// +#define TP_MODE 0 +#define RSSI_MODE 1 +#define TRAFFIC_LOW 0 +#define TRAFFIC_HIGH 1 + + +//============================================================ +//3 Tx Power Tracking +//3============================================================ +#define DPK_DELTA_MAPPING_NUM 13 +#define index_mapping_HP_NUM 15 +#define OFDM_TABLE_SIZE 43 +#define CCK_TABLE_SIZE 33 +#define TXSCALE_TABLE_SIZE 37 +#define TXPWR_TRACK_TABLE_SIZE 30 +#define DELTA_SWINGIDX_SIZE 30 +#define BAND_NUM 4 + +//============================================================ +//3 PSD Handler +//3============================================================ + +#define AFH_PSD 1 //0:normal PSD scan, 1: only do 20 pts PSD +#define MODE_40M 0 //0:20M, 1:40M +#define PSD_TH2 3 +#define PSD_CHMIN 20 // Minimum channel number for BT AFH +#define SIR_STEP_SIZE 3 +#define Smooth_Size_1 5 +#define Smooth_TH_1 3 +#define Smooth_Size_2 10 +#define Smooth_TH_2 4 +#define Smooth_Size_3 20 +#define Smooth_TH_3 4 +#define Smooth_Step_Size 5 +#define Adaptive_SIR 1 +#if(RTL8723_FPGA_VERIFICATION == 1) +#define PSD_RESCAN 1 +#else +#define PSD_RESCAN 4 +#endif +#define PSD_SCAN_INTERVAL 700 //ms + + + +//8723A High Power IGI Setting +#define DM_DIG_HIGH_PWR_IGI_LOWER_BOUND 0x22 +#define DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND 0x28 +#define DM_DIG_HIGH_PWR_THRESHOLD 0x3a +#define DM_DIG_LOW_PWR_THRESHOLD 0x14 + +//ANT Test +#define ANTTESTALL 0x00 //Ant A or B will be Testing +#define ANTTESTA 0x01 //Ant A will be Testing +#define ANTTESTB 0x02 //Ant B will be testing + +// LPS define +#define DM_DIG_FA_TH0_LPS 4 //-> 4 in lps +#define DM_DIG_FA_TH1_LPS 15 //-> 15 lps +#define DM_DIG_FA_TH2_LPS 30 //-> 30 lps +#define RSSI_OFFSET_DIG 0x05; + + + +//for 8723A Ant Definition--2012--06--07 due to different IC may be different ANT define +#define MAIN_ANT 1 //Ant A or Ant Main +#define AUX_ANT 2 //AntB or Ant Aux +#define MAX_ANT 3 // 3 for AP using + + +//Antenna Diversity Type +#define SW_ANTDIV 0 +#define HW_ANTDIV 1 +//============================================================ +// structure and define +//============================================================ + +// +// 2011/09/20 MH Add for AP/ADSLpseudo DM structuer requirement. +// We need to remove to other position??? +// +#if(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_WIN)) +typedef struct rtl8192cd_priv { + u1Byte temp; + +}rtl8192cd_priv, *prtl8192cd_priv; +#endif + + +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) +typedef struct _ADAPTER{ + u1Byte temp; + #ifdef AP_BUILD_WORKAROUND + HAL_DATA_TYPE* temp2; + prtl8192cd_priv priv; + #endif +}ADAPTER, *PADAPTER; +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) + +typedef struct _WLAN_STA{ + u1Byte temp; +} WLAN_STA, *PRT_WLAN_STA; + +#endif + +typedef struct _Dynamic_Initial_Gain_Threshold_ +{ + u1Byte Dig_Enable_Flag; + u1Byte Dig_Ext_Port_Stage; + + int RssiLowThresh; + int RssiHighThresh; + + u4Byte FALowThresh; + u4Byte FAHighThresh; + + u1Byte CurSTAConnectState; + u1Byte PreSTAConnectState; + u1Byte CurMultiSTAConnectState; + + u1Byte PreIGValue; + u1Byte CurIGValue; + u1Byte BT30_CurIGI; + u1Byte BackupIGValue; + + s1Byte BackoffVal; + s1Byte BackoffVal_range_max; + s1Byte BackoffVal_range_min; + u1Byte rx_gain_range_max; + u1Byte rx_gain_range_min; + u1Byte Rssi_val_min; + + u1Byte PreCCK_CCAThres; + u1Byte CurCCK_CCAThres; + u1Byte PreCCKPDState; + u1Byte CurCCKPDState; + + u1Byte LargeFAHit; + u1Byte ForbiddenIGI; + u4Byte Recover_cnt; + + u1Byte DIG_Dynamic_MIN_0; + u1Byte DIG_Dynamic_MIN_1; + BOOLEAN bMediaConnect_0; + BOOLEAN bMediaConnect_1; + + u4Byte AntDiv_RSSI_max; + u4Byte RSSI_max; +}DIG_T,*pDIG_T; + +typedef struct _Dynamic_Power_Saving_ +{ + u1Byte PreCCAState; + u1Byte CurCCAState; + + u1Byte PreRFState; + u1Byte CurRFState; + + int Rssi_val_min; + + u1Byte initialize; + u4Byte Reg874,RegC70,Reg85C,RegA74; + +}PS_T,*pPS_T; + +typedef struct _FALSE_ALARM_STATISTICS{ + u4Byte Cnt_Parity_Fail; + u4Byte Cnt_Rate_Illegal; + u4Byte Cnt_Crc8_fail; + u4Byte Cnt_Mcs_fail; + u4Byte Cnt_Ofdm_fail; + u4Byte Cnt_Cck_fail; + u4Byte Cnt_all; + u4Byte Cnt_Fast_Fsync; + u4Byte Cnt_SB_Search_fail; + u4Byte Cnt_OFDM_CCA; + u4Byte Cnt_CCK_CCA; + u4Byte Cnt_CCA_all; + u4Byte Cnt_BW_USC; //Gary + u4Byte Cnt_BW_LSC; //Gary +}FALSE_ALARM_STATISTICS, *PFALSE_ALARM_STATISTICS; + +typedef struct _Dynamic_Primary_CCA{ + u1Byte PriCCA_flag; + u1Byte intf_flag; + u1Byte intf_type; + u1Byte DupRTS_flag; + u1Byte Monitor_flag; + u1Byte CH_offset; + u1Byte MF_state; +}Pri_CCA_T, *pPri_CCA_T; + +typedef struct _Rate_Adaptive_Table_{ + u1Byte firstconnect; +}RA_T, *pRA_T; + +typedef struct _RX_High_Power_ +{ + u1Byte RXHP_flag; + u1Byte PSD_func_trigger; + u1Byte PSD_bitmap_RXHP[80]; + u1Byte Pre_IGI; + u1Byte Cur_IGI; + u1Byte Pre_pw_th; + u1Byte Cur_pw_th; + BOOLEAN First_time_enter; + BOOLEAN RXHP_enable; + u1Byte TP_Mode; + RT_TIMER PSDTimer; +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + #if USE_WORKITEM + RT_WORK_ITEM PSDTimeWorkitem; + #endif +#endif + +}RXHP_T, *pRXHP_T; + +#if(DM_ODM_SUPPORT_TYPE & (ODM_CE)) +#define ASSOCIATE_ENTRY_NUM 32 // Max size of AsocEntry[]. +#define ODM_ASSOCIATE_ENTRY_NUM ASSOCIATE_ENTRY_NUM + +#elif(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) +#define ASSOCIATE_ENTRY_NUM NUM_STAT +#define ODM_ASSOCIATE_ENTRY_NUM ASSOCIATE_ENTRY_NUM+1 + +#else +// +// 2012/01/12 MH Revise for compatiable with other SW team. +// 0 is for STA 1-n is for AP clients. +// +#define ODM_ASSOCIATE_ENTRY_NUM ASSOCIATE_ENTRY_NUM+1// Default port only one +#endif + +//#ifdef CONFIG_ANTENNA_DIVERSITY +// This indicates two different the steps. +// In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the signal on the air. +// In SWAW_STEP_DETERMINE, driver just compares the signal captured in SWAW_STEP_PEAK +// with original RSSI to determine if it is necessary to switch antenna. +#define SWAW_STEP_PEAK 0 +#define SWAW_STEP_DETERMINE 1 + +#define TP_MODE 0 +#define RSSI_MODE 1 +#define TRAFFIC_LOW 0 +#define TRAFFIC_HIGH 1 +#define TRAFFIC_UltraLOW 2 + +typedef struct _SW_Antenna_Switch_ +{ + u1Byte Double_chk_flag; + u1Byte try_flag; + s4Byte PreRSSI; + u1Byte CurAntenna; + u1Byte PreAntenna; + u1Byte RSSI_Trying; + u1Byte TestMode; + u1Byte bTriggerAntennaSwitch; + u1Byte SelectAntennaMap; + u1Byte RSSI_target; + u1Byte reset_idx; + + // Before link Antenna Switch check + u1Byte SWAS_NoLink_State; + u4Byte SWAS_NoLink_BK_Reg860; + u4Byte SWAS_NoLink_BK_Reg92c; + BOOLEAN ANTA_ON; //To indicate Ant A is or not + BOOLEAN ANTB_ON; //To indicate Ant B is on or not + u1Byte Ant5G; + u1Byte Ant2G; + + s4Byte RSSI_sum_A; + s4Byte RSSI_sum_B; + s4Byte RSSI_cnt_A; + s4Byte RSSI_cnt_B; + + u8Byte lastTxOkCnt; + u8Byte lastRxOkCnt; + u8Byte TXByteCnt_A; + u8Byte TXByteCnt_B; + u8Byte RXByteCnt_A; + u8Byte RXByteCnt_B; + u1Byte TrafficLoad; + u1Byte Train_time; + u1Byte Train_time_flag; + RT_TIMER SwAntennaSwitchTimer; + RT_TIMER SwAntennaSwitchTimer_8723B; +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + #if USE_WORKITEM + RT_WORK_ITEM SwAntennaSwitchWorkitem; + RT_WORK_ITEM SwAntennaSwitchWorkitem_8723B; + #endif +#endif +/* CE Platform use +#ifdef CONFIG_SW_ANTENNA_DIVERSITY + _timer SwAntennaSwitchTimer; + u8Byte lastTxOkCnt; + u8Byte lastRxOkCnt; + u8Byte TXByteCnt_A; + u8Byte TXByteCnt_B; + u8Byte RXByteCnt_A; + u8Byte RXByteCnt_B; + u1Byte DoubleComfirm; + u1Byte TrafficLoad; + //SW Antenna Switch + + +#endif +*/ +#ifdef CONFIG_HW_ANTENNA_DIVERSITY + //Hybrid Antenna Diversity + u4Byte CCK_Ant1_Cnt[ASSOCIATE_ENTRY_NUM+1]; + u4Byte CCK_Ant2_Cnt[ASSOCIATE_ENTRY_NUM+1]; + u4Byte OFDM_Ant1_Cnt[ASSOCIATE_ENTRY_NUM+1]; + u4Byte OFDM_Ant2_Cnt[ASSOCIATE_ENTRY_NUM+1]; + u4Byte RSSI_Ant1_Sum[ASSOCIATE_ENTRY_NUM+1]; + u4Byte RSSI_Ant2_Sum[ASSOCIATE_ENTRY_NUM+1]; + u1Byte TxAnt[ASSOCIATE_ENTRY_NUM+1]; + u1Byte TargetSTA; + u1Byte antsel; + u1Byte RxIdleAnt; + +#endif + +}SWAT_T, *pSWAT_T; +//#endif + +typedef struct _EDCA_TURBO_ +{ + BOOLEAN bCurrentTurboEDCA; + BOOLEAN bIsCurRDLState; + + #if(DM_ODM_SUPPORT_TYPE == ODM_CE ) + u4Byte prv_traffic_idx; // edca turbo + #endif + +}EDCA_T,*pEDCA_T; + +typedef struct _ODM_RATE_ADAPTIVE +{ + u1Byte Type; // DM_Type_ByFW/DM_Type_ByDriver + u1Byte LdpcThres; // if RSSI > LdpcThres => switch from LPDC to BCC + BOOLEAN bUseLdpc; + BOOLEAN bLowerRtsRate; + u1Byte HighRSSIThresh; // if RSSI > HighRSSIThresh => RATRState is DM_RATR_STA_HIGH + u1Byte LowRSSIThresh; // if RSSI <= LowRSSIThresh => RATRState is DM_RATR_STA_LOW + u1Byte RATRState; // Current RSSI level, DM_RATR_STA_HIGH/DM_RATR_STA_MIDDLE/DM_RATR_STA_LOW + +} ODM_RATE_ADAPTIVE, *PODM_RATE_ADAPTIVE; + + +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + + +#ifdef ADSL_AP_BUILD_WORKAROUND +#define MAX_TOLERANCE 5 +#define IQK_DELAY_TIME 1 //ms +#endif + +// +// Indicate different AP vendor for IOT issue. +// +typedef enum _HT_IOT_PEER +{ + HT_IOT_PEER_UNKNOWN = 0, + HT_IOT_PEER_REALTEK = 1, + HT_IOT_PEER_REALTEK_92SE = 2, + HT_IOT_PEER_BROADCOM = 3, + HT_IOT_PEER_RALINK = 4, + HT_IOT_PEER_ATHEROS = 5, + HT_IOT_PEER_CISCO = 6, + HT_IOT_PEER_MERU = 7, + HT_IOT_PEER_MARVELL = 8, + HT_IOT_PEER_REALTEK_SOFTAP = 9,// peer is RealTek SOFT_AP, by Bohn, 2009.12.17 + HT_IOT_PEER_SELF_SOFTAP = 10, // Self is SoftAP + HT_IOT_PEER_AIRGO = 11, + HT_IOT_PEER_INTEL = 12, + HT_IOT_PEER_RTK_APCLIENT = 13, + HT_IOT_PEER_REALTEK_81XX = 14, + HT_IOT_PEER_REALTEK_WOW = 15, + HT_IOT_PEER_MAX = 16 +}HT_IOT_PEER_E, *PHTIOT_PEER_E; +#endif//#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + + + +#define IQK_MAC_REG_NUM 4 +#define IQK_ADDA_REG_NUM 16 +#define IQK_BB_REG_NUM_MAX 10 +#if (RTL8192D_SUPPORT==1) +#define IQK_BB_REG_NUM 10 +#else +#define IQK_BB_REG_NUM 9 +#endif +#define HP_THERMAL_NUM 8 + +#define AVG_THERMAL_NUM 8 +#define IQK_Matrix_REG_NUM 8 +#define IQK_Matrix_Settings_NUM 14+24+21 // Channels_2_4G_NUM + Channels_5G_20M_NUM + Channels_5G + +#define DM_Type_ByFW 0 +#define DM_Type_ByDriver 1 + +// +// Declare for common info +// +#define MAX_PATH_NUM_92CS 2 +#define MAX_PATH_NUM_8188E 1 +#define MAX_PATH_NUM_8192E 2 +#define MAX_PATH_NUM_8723B 1 +#define MAX_PATH_NUM_8812A 2 +#define MAX_PATH_NUM_8821A 1 + +#define IQK_THRESHOLD 8 + +typedef struct _ODM_Phy_Status_Info_ +{ + // + // Be care, if you want to add any element please insert between + // RxPWDBAll & SignalStrength. + // +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) + u4Byte RxPWDBAll; +#else + u1Byte RxPWDBAll; +#endif + + u1Byte SignalQuality; // in 0-100 index. + s1Byte RxMIMOSignalQuality[4]; //per-path's EVM + u1Byte RxMIMOEVMdbm[4]; //per-path's EVM dbm + + u1Byte RxMIMOSignalStrength[4];// in 0~100 index + + u2Byte Cfo_short[4]; // per-path's Cfo_short + u2Byte Cfo_tail[4]; // per-path's Cfo_tail + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + s1Byte RxPower; // in dBm Translate from PWdB + s1Byte RecvSignalPower; // Real power in dBm for this packet, no beautification and aggregation. Keep this raw info to be used for the other procedures. + u1Byte BTRxRSSIPercentage; + u1Byte SignalStrength; // in 0-100 index. + + s1Byte RxPwr[4]; //per-path's pwdb +#endif + u1Byte RxSNR[4]; //per-path's SNR + u1Byte BandWidth; + u1Byte btCoexPwrAdjust; +}ODM_PHY_INFO_T,*PODM_PHY_INFO_T; + + +typedef struct _ODM_Per_Pkt_Info_ +{ + //u1Byte Rate; + u1Byte DataRate; + u1Byte StationID; + BOOLEAN bPacketMatchBSSID; + BOOLEAN bPacketToSelf; + BOOLEAN bPacketBeacon; +}ODM_PACKET_INFO_T,*PODM_PACKET_INFO_T; + + +typedef struct _ODM_Phy_Dbg_Info_ +{ + //ODM Write,debug info + s1Byte RxSNRdB[4]; + u8Byte NumQryPhyStatus; + u8Byte NumQryPhyStatusCCK; + u8Byte NumQryPhyStatusOFDM; + u1Byte NumQryBeaconPkt; + //Others + s4Byte RxEVM[4]; + +}ODM_PHY_DBG_INFO_T; + + +typedef struct _ODM_Mac_Status_Info_ +{ + u1Byte test; + +}ODM_MAC_INFO; + + +typedef enum tag_Dynamic_ODM_Support_Ability_Type +{ + // BB Team + ODM_DIG = 0x00000001, + ODM_HIGH_POWER = 0x00000002, + ODM_CCK_CCA_TH = 0x00000004, + ODM_FA_STATISTICS = 0x00000008, + ODM_RAMASK = 0x00000010, + ODM_RSSI_MONITOR = 0x00000020, + ODM_SW_ANTDIV = 0x00000040, + ODM_HW_ANTDIV = 0x00000080, + ODM_BB_PWRSV = 0x00000100, + ODM_2TPATHDIV = 0x00000200, + ODM_1TPATHDIV = 0x00000400, + ODM_PSD2AFH = 0x00000800 +}ODM_Ability_E; + +// +// 2011/20/20 MH For MP driver RT_WLAN_STA = STA_INFO_T +// Please declare below ODM relative info in your STA info structure. +// +#if 1 +typedef struct _ODM_STA_INFO{ + // Driver Write + BOOLEAN bUsed; // record the sta status link or not? + //u1Byte WirelessMode; // + u1Byte IOTPeer; // Enum value. HT_IOT_PEER_E + + // ODM Write + //1 PHY_STATUS_INFO + u1Byte RSSI_Path[4]; // + u1Byte RSSI_Ave; + u1Byte RXEVM[4]; + u1Byte RXSNR[4]; + + // ODM Write + //1 TX_INFO (may changed by IC) + //TX_INFO_T pTxInfo; // Define in IC folder. Move lower layer. +#if 0 + u1Byte ANTSEL_A; //in Jagar: 4bit; others: 2bit + u1Byte ANTSEL_B; //in Jagar: 4bit; others: 2bit + u1Byte ANTSEL_C; //only in Jagar: 4bit + u1Byte ANTSEL_D; //only in Jagar: 4bit + u1Byte TX_ANTL; //not in Jagar: 2bit + u1Byte TX_ANT_HT; //not in Jagar: 2bit + u1Byte TX_ANT_CCK; //not in Jagar: 2bit + u1Byte TXAGC_A; //not in Jagar: 4bit + u1Byte TXAGC_B; //not in Jagar: 4bit + u1Byte TXPWR_OFFSET; //only in Jagar: 3bit + u1Byte TX_ANT; //only in Jagar: 4bit for TX_ANTL/TX_ANTHT/TX_ANT_CCK +#endif + + // + // Please use compile flag to disabe the strcutrue for other IC except 88E. + // Move To lower layer. + // + // ODM Write Wilson will handle this part(said by Luke.Lee) + //TX_RPT_T pTxRpt; // Define in IC folder. Move lower layer. +#if 0 + //1 For 88E RA (don't redefine the naming) + u1Byte rate_id; + u1Byte rate_SGI; + u1Byte rssi_sta_ra; + u1Byte SGI_enable; + u1Byte Decision_rate; + u1Byte Pre_rate; + u1Byte Active; + + // Driver write Wilson handle. + //1 TX_RPT (don't redefine the naming) + u2Byte RTY[4]; // ??? + u2Byte TOTAL; // ??? + u2Byte DROP; // ??? + // + // Please use compile flag to disabe the strcutrue for other IC except 88E. + // +#endif + +}ODM_STA_INFO_T, *PODM_STA_INFO_T; +#endif + +// +// 2011/10/20 MH Define Common info enum for all team. +// +typedef enum _ODM_Common_Info_Definition +{ +//-------------REMOVED CASE-----------// + //ODM_CMNINFO_CCK_HP, + //ODM_CMNINFO_RFPATH_ENABLE, // Define as ODM write??? + //ODM_CMNINFO_BT_COEXIST, // ODM_BT_COEXIST_E + //ODM_CMNINFO_OP_MODE, // ODM_OPERATION_MODE_E +//-------------REMOVED CASE-----------// + + // + // Fixed value: + // + + //-----------HOOK BEFORE REG INIT-----------// + ODM_CMNINFO_PLATFORM = 0, + ODM_CMNINFO_ABILITY, // ODM_ABILITY_E + ODM_CMNINFO_INTERFACE, // ODM_INTERFACE_E + ODM_CMNINFO_MP_TEST_CHIP, + ODM_CMNINFO_IC_TYPE, // ODM_IC_TYPE_E + ODM_CMNINFO_CUT_VER, // ODM_CUT_VERSION_E + ODM_CMNINFO_FAB_VER, // ODM_FAB_E + ODM_CMNINFO_RF_TYPE, // ODM_RF_PATH_E or ODM_RF_TYPE_E? + ODM_CMNINFO_RFE_TYPE, + ODM_CMNINFO_BOARD_TYPE, // ODM_BOARD_TYPE_E + ODM_CMNINFO_PACKAGE_TYPE, + ODM_CMNINFO_EXT_LNA, // TRUE + ODM_CMNINFO_5G_EXT_LNA, + ODM_CMNINFO_EXT_PA, + ODM_CMNINFO_5G_EXT_PA, + ODM_CMNINFO_GPA, + ODM_CMNINFO_APA, + ODM_CMNINFO_GLNA, + ODM_CMNINFO_ALNA, + ODM_CMNINFO_EXT_TRSW, + ODM_CMNINFO_PATCH_ID, //CUSTOMER ID + ODM_CMNINFO_BINHCT_TEST, + ODM_CMNINFO_BWIFI_TEST, + ODM_CMNINFO_SMART_CONCURRENT, + //-----------HOOK BEFORE REG INIT-----------// + + + // + // Dynamic value: + // +//--------- POINTER REFERENCE-----------// + ODM_CMNINFO_MAC_PHY_MODE, // ODM_MAC_PHY_MODE_E + ODM_CMNINFO_TX_UNI, + ODM_CMNINFO_RX_UNI, + ODM_CMNINFO_WM_MODE, // ODM_WIRELESS_MODE_E + ODM_CMNINFO_BAND, // ODM_BAND_TYPE_E + ODM_CMNINFO_SEC_CHNL_OFFSET, // ODM_SEC_CHNL_OFFSET_E + ODM_CMNINFO_SEC_MODE, // ODM_SECURITY_E + ODM_CMNINFO_BW, // ODM_BW_E + ODM_CMNINFO_CHNL, + ODM_CMNINFO_FORCED_RATE, + + ODM_CMNINFO_DMSP_GET_VALUE, + ODM_CMNINFO_BUDDY_ADAPTOR, + ODM_CMNINFO_DMSP_IS_MASTER, + ODM_CMNINFO_SCAN, + ODM_CMNINFO_POWER_SAVING, + ODM_CMNINFO_ONE_PATH_CCA, // ODM_CCA_PATH_E + ODM_CMNINFO_DRV_STOP, + ODM_CMNINFO_PNP_IN, + ODM_CMNINFO_INIT_ON, + ODM_CMNINFO_ANT_TEST, + ODM_CMNINFO_NET_CLOSED, + ODM_CMNINFO_MP_MODE, + //ODM_CMNINFO_RTSTA_AID, // For win driver only? + ODM_CMNINFO_FORCED_IGI_LB, +//--------- POINTER REFERENCE-----------// + +//------------CALL BY VALUE-------------// + ODM_CMNINFO_WIFI_DIRECT, + ODM_CMNINFO_WIFI_DISPLAY, + ODM_CMNINFO_LINK_IN_PROGRESS, + ODM_CMNINFO_LINK, + ODM_CMNINFO_STATION_STATE, + ODM_CMNINFO_RSSI_MIN, + ODM_CMNINFO_DBG_COMP, // u8Byte + ODM_CMNINFO_DBG_LEVEL, // u4Byte + ODM_CMNINFO_RA_THRESHOLD_HIGH, // u1Byte + ODM_CMNINFO_RA_THRESHOLD_LOW, // u1Byte + ODM_CMNINFO_RF_ANTENNA_TYPE, // u1Byte + ODM_CMNINFO_BT_DISABLED, + ODM_CMNINFO_BT_HS_CONNECT_PROCESS, + ODM_CMNINFO_BT_HS_RSSI, + ODM_CMNINFO_BT_OPERATION, + ODM_CMNINFO_BT_LIMITED_DIG, //Need to Limited Dig or not + ODM_CMNINFO_BT_DISABLE_EDCA, +//------------CALL BY VALUE-------------// + + // + // Dynamic ptr array hook itms. + // + ODM_CMNINFO_STA_STATUS, + ODM_CMNINFO_PHY_STATUS, + ODM_CMNINFO_MAC_STATUS, + + ODM_CMNINFO_MAX, + + +}ODM_CMNINFO_E; + +// +// 2011/10/20 MH Define ODM support ability. ODM_CMNINFO_ABILITY +// +typedef enum _ODM_Support_Ability_Definition +{ + // + // BB ODM section BIT 0-15 + // + ODM_BB_DIG = BIT0, + ODM_BB_RA_MASK = BIT1, + ODM_BB_DYNAMIC_TXPWR = BIT2, + ODM_BB_FA_CNT = BIT3, + ODM_BB_RSSI_MONITOR = BIT4, + ODM_BB_CCK_PD = BIT5, + ODM_BB_ANT_DIV = BIT6, + ODM_BB_PWR_SAVE = BIT7, + ODM_BB_PWR_TRAIN = BIT8, + ODM_BB_RATE_ADAPTIVE = BIT9, + ODM_BB_PATH_DIV = BIT10, + ODM_BB_PSD = BIT11, + ODM_BB_RXHP = BIT12, + ODM_BB_ADAPTIVITY = BIT13, + ODM_BB_DYNAMIC_ATC = BIT14, + ODM_BB_NHM_CNT = BIT15, + ODM_BB_PRIMARY_CCA = BIT16, + ODM_BB_TXBF = BIT17, + + // + // MAC DM section BIT 20-23 + // + ODM_MAC_EDCA_TURBO = BIT20, + ODM_MAC_EARLY_MODE = BIT21, + + // + // RF ODM section BIT 24-31 + // + ODM_RF_TX_PWR_TRACK = BIT24, + ODM_RF_RX_GAIN_TRACK = BIT25, + ODM_RF_CALIBRATION = BIT26, + +}ODM_ABILITY_E; + +// ODM_CMNINFO_INTERFACE +typedef enum tag_ODM_Support_Interface_Definition +{ + ODM_ITRF_PCIE = 0x1, + ODM_ITRF_USB = 0x2, + ODM_ITRF_SDIO = 0x4, + ODM_ITRF_ALL = 0x7, +}ODM_INTERFACE_E; + +// ODM_CMNINFO_IC_TYPE +typedef enum tag_ODM_Support_IC_Type_Definition +{ + ODM_RTL8192S = BIT0, + ODM_RTL8192C = BIT1, + ODM_RTL8192D = BIT2, + ODM_RTL8723A = BIT3, + ODM_RTL8188E = BIT4, + ODM_RTL8812 = BIT5, + ODM_RTL8821 = BIT6, + ODM_RTL8192E = BIT7, + ODM_RTL8723B = BIT8, + ODM_RTL8814A = BIT9, + ODM_RTL8881A = BIT10, + ODM_RTL8821B = BIT11, + ODM_RTL8822B = BIT12, + ODM_RTL8703B = BIT13, + ODM_RTL8195A = BIT14, + ODM_RTL8188F = BIT15 +}ODM_IC_TYPE_E; + +#define ODM_IC_11N_SERIES (ODM_RTL8192S|ODM_RTL8192C|ODM_RTL8192D|ODM_RTL8723A|ODM_RTL8188E|ODM_RTL8192E|ODM_RTL8723B) +#define ODM_IC_11AC_SERIES (ODM_RTL8812|ODM_RTL8821|ODM_RTL8814A|ODM_RTL8881A) + +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) +#ifdef RTK_AC_SUPPORT +#define ODM_IC_11AC_SERIES_SUPPORT 1 +#else +#define ODM_IC_11AC_SERIES_SUPPORT 0 +#endif +#else +#define ODM_IC_11AC_SERIES_SUPPORT 1 +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) +#ifdef CONFIG_BT_COEXIST +#define ODM_CONFIG_BT_COEXIST 1 +#else +#define ODM_CONFIG_BT_COEXIST 0 +#endif +#endif + +//ODM_CMNINFO_CUT_VER +typedef enum tag_ODM_Cut_Version_Definition +{ + ODM_CUT_A = 0, + ODM_CUT_B = 1, + ODM_CUT_C = 2, + ODM_CUT_D = 3, + ODM_CUT_E = 4, + ODM_CUT_F = 5, + + ODM_CUT_I = 8, + ODM_CUT_TEST = 15, +}ODM_CUT_VERSION_E; + +// ODM_CMNINFO_FAB_VER +typedef enum tag_ODM_Fab_Version_Definition +{ + ODM_TSMC = 0, + ODM_UMC = 1, +}ODM_FAB_E; + +// ODM_CMNINFO_RF_TYPE +// +// For example 1T2R (A+AB = BIT0|BIT4|BIT5) +// +typedef enum tag_ODM_RF_Path_Bit_Definition +{ + ODM_RF_TX_A = BIT0, + ODM_RF_TX_B = BIT1, + ODM_RF_TX_C = BIT2, + ODM_RF_TX_D = BIT3, + ODM_RF_RX_A = BIT4, + ODM_RF_RX_B = BIT5, + ODM_RF_RX_C = BIT6, + ODM_RF_RX_D = BIT7, +}ODM_RF_PATH_E; + + +typedef enum tag_ODM_RF_Type_Definition +{ + ODM_1T1R = 0, + ODM_1T2R = 1, + ODM_2T2R = 2, + ODM_2T3R = 3, + ODM_2T4R = 4, + ODM_3T3R = 5, + ODM_3T4R = 6, + ODM_4T4R = 7, +}ODM_RF_TYPE_E; + + +// +// ODM Dynamic common info value definition +// + +//typedef enum _MACPHY_MODE_8192D{ +// SINGLEMAC_SINGLEPHY, +// DUALMAC_DUALPHY, +// DUALMAC_SINGLEPHY, +//}MACPHY_MODE_8192D,*PMACPHY_MODE_8192D; +// Above is the original define in MP driver. Please use the same define. THX. +typedef enum tag_ODM_MAC_PHY_Mode_Definition +{ + ODM_SMSP = 0, + ODM_DMSP = 1, + ODM_DMDP = 2, +}ODM_MAC_PHY_MODE_E; + + +typedef enum tag_BT_Coexist_Definition +{ + ODM_BT_BUSY = 1, + ODM_BT_ON = 2, + ODM_BT_OFF = 3, + ODM_BT_NONE = 4, +}ODM_BT_COEXIST_E; + +// ODM_CMNINFO_OP_MODE +typedef enum tag_Operation_Mode_Definition +{ + ODM_NO_LINK = BIT0, + ODM_LINK = BIT1, + ODM_SCAN = BIT2, + ODM_POWERSAVE = BIT3, + ODM_AP_MODE = BIT4, + ODM_CLIENT_MODE = BIT5, + ODM_AD_HOC = BIT6, + ODM_WIFI_DIRECT = BIT7, + ODM_WIFI_DISPLAY = BIT8, +}ODM_OPERATION_MODE_E; + +// ODM_CMNINFO_WM_MODE +#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_CE)) +typedef enum tag_Wireless_Mode_Definition +{ + ODM_WM_UNKNOW = 0x0, + ODM_WM_B = BIT0, + ODM_WM_G = BIT1, + ODM_WM_A = BIT2, + ODM_WM_N24G = BIT3, + ODM_WM_N5G = BIT4, + ODM_WM_AUTO = BIT5, + ODM_WM_AC = BIT6, +}ODM_WIRELESS_MODE_E; +#else +typedef enum tag_Wireless_Mode_Definition +{ + ODM_WM_UNKNOWN = 0x00, + ODM_WM_A = BIT0, + ODM_WM_B = BIT1, + ODM_WM_G = BIT2, + ODM_WM_AUTO = BIT3, + ODM_WM_N24G = BIT4, + ODM_WM_N5G = BIT5, + ODM_WM_AC_5G = BIT6, + ODM_WM_AC_24G = BIT7, + ODM_WM_AC_ONLY = BIT8, + ODM_WM_MAX = BIT9 +}ODM_WIRELESS_MODE_E; +#endif + +// ODM_CMNINFO_BAND +typedef enum tag_Band_Type_Definition +{ + ODM_BAND_2_4G = 0, + ODM_BAND_5G, + ODM_BAND_ON_BOTH, + ODM_BANDMAX + +}ODM_BAND_TYPE_E; + +// ODM_CMNINFO_SEC_CHNL_OFFSET +typedef enum tag_Secondary_Channel_Offset_Definition +{ + ODM_DONT_CARE = 0, + ODM_BELOW = 1, + ODM_ABOVE = 2 +}ODM_SEC_CHNL_OFFSET_E; + +// ODM_CMNINFO_SEC_MODE +typedef enum tag_Security_Definition +{ + ODM_SEC_OPEN = 0, + ODM_SEC_WEP40 = 1, + ODM_SEC_TKIP = 2, + ODM_SEC_RESERVE = 3, + ODM_SEC_AESCCMP = 4, + ODM_SEC_WEP104 = 5, + ODM_WEP_WPA_MIXED = 6, // WEP + WPA + ODM_SEC_SMS4 = 7, +}ODM_SECURITY_E; + +// ODM_CMNINFO_BW +typedef enum tag_Bandwidth_Definition +{ + ODM_BW20M = 0, + ODM_BW40M = 1, + ODM_BW80M = 2, + ODM_BW160M = 3, + ODM_BW10M = 4, +}ODM_BW_E; + + +// ODM_CMNINFO_BOARD_TYPE +// For non-AC-series IC , ODM_BOARD_5G_EXT_PA and ODM_BOARD_5G_EXT_LNA are ignored +// For AC-series IC, external PA & LNA can be indivisuallly added on 2.4G and/or 5G +typedef enum tag_Board_Definition +{ + ODM_BOARD_DEFAULT = 0, // The DEFAULT case. + ODM_BOARD_MINICARD = BIT(0), // 0 = non-mini card, 1= mini card. + ODM_BOARD_SLIM = BIT(1), // 0 = non-slim card, 1 = slim card + ODM_BOARD_BT = BIT(2), // 0 = without BT card, 1 = with BT + ODM_BOARD_EXT_PA = BIT(3), // 0 = no 2G ext-PA, 1 = existing 2G ext-PA + ODM_BOARD_EXT_LNA = BIT(4), // 0 = no 2G ext-LNA, 1 = existing 2G ext-LNA + ODM_BOARD_EXT_TRSW = BIT(5), // 0 = no ext-TRSW, 1 = existing ext-TRSW + ODM_BOARD_EXT_PA_5G = BIT(6), // 0 = no 5G ext-PA, 1 = existing 5G ext-PA + ODM_BOARD_EXT_LNA_5G= BIT(7), // 0 = no 5G ext-LNA, 1 = existing 5G ext-LNA +}ODM_BOARD_TYPE_E; + +typedef enum tag_ODM_Package_Definition +{ + ODM_PACKAGE_DEFAULT = 0, + ODM_PACKAGE_QFN68 = BIT(0), + ODM_PACKAGE_TFBGA90 = BIT(1), + ODM_PACKAGE_TFBGA79 = BIT(2), +}ODM_Package_TYPE_E; + +typedef enum tag_ODM_TYPE_GPA_Definition +{ + TYPE_GPA0 = 0, + TYPE_GPA1 = BIT(1)|BIT(0) +}ODM_TYPE_GPA_E; + +typedef enum tag_ODM_TYPE_APA_Definition +{ + TYPE_APA0 = 0, + TYPE_APA1 = BIT(1)|BIT(0) +}ODM_TYPE_APA_E; + +typedef enum tag_ODM_TYPE_GLNA_Definition +{ + TYPE_GLNA0 = 0, + TYPE_GLNA1 = BIT(2)|BIT(0), + TYPE_GLNA2 = BIT(3)|BIT(1), + TYPE_GLNA3 = BIT(3)|BIT(2)|BIT(1)|BIT(0) +}ODM_TYPE_GLNA_E; + +typedef enum tag_ODM_TYPE_ALNA_Definition +{ + TYPE_ALNA0 = 0, + TYPE_ALNA1 = BIT(2)|BIT(0), + TYPE_ALNA2 = BIT(3)|BIT(1), + TYPE_ALNA3 = BIT(3)|BIT(2)|BIT(1)|BIT(0) +}ODM_TYPE_ALNA_E; + +// ODM_CMNINFO_ONE_PATH_CCA +typedef enum tag_CCA_Path +{ + ODM_CCA_2R = 0, + ODM_CCA_1R_A = 1, + ODM_CCA_1R_B = 2, +}ODM_CCA_PATH_E; + + +typedef struct _ODM_RA_Info_ +{ + u1Byte RateID; + u4Byte RateMask; + u4Byte RAUseRate; + u1Byte RateSGI; + u1Byte RssiStaRA; + u1Byte PreRssiStaRA; + u1Byte SGIEnable; + u1Byte DecisionRate; + u1Byte PreRate; + u1Byte HighestRate; + u1Byte LowestRate; + u4Byte NscUp; + u4Byte NscDown; + u2Byte RTY[5]; + u4Byte TOTAL; + u2Byte DROP; + u1Byte Active; + u2Byte RptTime; + u1Byte RAWaitingCounter; + u1Byte RAPendingCounter; +#if 1 //POWER_TRAINING_ACTIVE == 1 // For compile pass only~! + u1Byte PTActive; // on or off + u1Byte PTTryState; // 0 trying state, 1 for decision state + u1Byte PTStage; // 0~6 + u1Byte PTStopCount; //Stop PT counter + u1Byte PTPreRate; // if rate change do PT + u1Byte PTPreRssi; // if RSSI change 5% do PT + u1Byte PTModeSS; // decide whitch rate should do PT + u1Byte RAstage; // StageRA, decide how many times RA will be done between PT + u1Byte PTSmoothFactor; +#endif +} ODM_RA_INFO_T,*PODM_RA_INFO_T; + +typedef struct _IQK_MATRIX_REGS_SETTING{ + BOOLEAN bIQKDone; + s4Byte Value[3][IQK_Matrix_REG_NUM]; + BOOLEAN bBWIqkResultSaved[3]; +}IQK_MATRIX_REGS_SETTING,*PIQK_MATRIX_REGS_SETTING; + +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) +typedef struct _PathDiv_Parameter_define_ +{ + u4Byte org_5g_RegE30; + u4Byte org_5g_RegC14; + u4Byte org_5g_RegCA0; + u4Byte swt_5g_RegE30; + u4Byte swt_5g_RegC14; + u4Byte swt_5g_RegCA0; + //for 2G IQK information + u4Byte org_2g_RegC80; + u4Byte org_2g_RegC4C; + u4Byte org_2g_RegC94; + u4Byte org_2g_RegC14; + u4Byte org_2g_RegCA0; + + u4Byte swt_2g_RegC80; + u4Byte swt_2g_RegC4C; + u4Byte swt_2g_RegC94; + u4Byte swt_2g_RegC14; + u4Byte swt_2g_RegCA0; +}PATHDIV_PARA,*pPATHDIV_PARA; +#endif + + +typedef struct ODM_RF_Calibration_Structure +{ + //for tx power tracking + + u4Byte RegA24; // for TempCCK + s4Byte RegE94; + s4Byte RegE9C; + s4Byte RegEB4; + s4Byte RegEBC; + + u1Byte TXPowercount; + BOOLEAN bTXPowerTrackingInit; + BOOLEAN bTXPowerTracking; + u1Byte TxPowerTrackControl; //for mp mode, turn off txpwrtracking as default + u1Byte TM_Trigger; + u1Byte InternalPA5G[2]; //pathA / pathB + + u1Byte ThermalMeter[2]; // ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 + u1Byte ThermalValue; + u1Byte ThermalValue_LCK; + u1Byte ThermalValue_IQK; + u1Byte ThermalValue_DPK; + u1Byte ThermalValue_AVG[AVG_THERMAL_NUM]; + u1Byte ThermalValue_AVG_index; + u1Byte ThermalValue_RxGain; + u1Byte ThermalValue_Crystal; + u1Byte ThermalValue_DPKstore; + u1Byte ThermalValue_DPKtrack; + BOOLEAN TxPowerTrackingInProgress; + + BOOLEAN bReloadtxpowerindex; + u1Byte bRfPiEnable; + u4Byte TXPowerTrackingCallbackCnt; //cosa add for debug + + + //------------------------- Tx power Tracking -------------------------// + u1Byte bCCKinCH14; + u1Byte CCK_index; + u1Byte OFDM_index[MAX_RF_PATH]; + s1Byte PowerIndexOffset[MAX_RF_PATH]; + s1Byte DeltaPowerIndex[MAX_RF_PATH]; + s1Byte DeltaPowerIndexLast[MAX_RF_PATH]; + BOOLEAN bTxPowerChanged; + + u1Byte ThermalValue_HP[HP_THERMAL_NUM]; + u1Byte ThermalValue_HP_index; + IQK_MATRIX_REGS_SETTING IQKMatrixRegSetting[IQK_Matrix_Settings_NUM]; + BOOLEAN bNeedIQK; + BOOLEAN bIQKInProgress; + u1Byte Delta_IQK; + u1Byte Delta_LCK; + s1Byte BBSwingDiff2G, BBSwingDiff5G; // Unit: dB + u1Byte DeltaSwingTableIdx_2GCCKA_P[DELTA_SWINGIDX_SIZE]; + u1Byte DeltaSwingTableIdx_2GCCKA_N[DELTA_SWINGIDX_SIZE]; + u1Byte DeltaSwingTableIdx_2GCCKB_P[DELTA_SWINGIDX_SIZE]; + u1Byte DeltaSwingTableIdx_2GCCKB_N[DELTA_SWINGIDX_SIZE]; + u1Byte DeltaSwingTableIdx_2GA_P[DELTA_SWINGIDX_SIZE]; + u1Byte DeltaSwingTableIdx_2GA_N[DELTA_SWINGIDX_SIZE]; + u1Byte DeltaSwingTableIdx_2GB_P[DELTA_SWINGIDX_SIZE]; + u1Byte DeltaSwingTableIdx_2GB_N[DELTA_SWINGIDX_SIZE]; + u1Byte DeltaSwingTableIdx_5GA_P[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u1Byte DeltaSwingTableIdx_5GA_N[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u1Byte DeltaSwingTableIdx_5GB_P[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u1Byte DeltaSwingTableIdx_5GB_N[BAND_NUM][DELTA_SWINGIDX_SIZE]; + u1Byte DeltaSwingTableIdx_2GA_P_8188E[DELTA_SWINGIDX_SIZE]; + u1Byte DeltaSwingTableIdx_2GA_N_8188E[DELTA_SWINGIDX_SIZE]; + + //--------------------------------------------------------------------// + + //for IQK + u4Byte RegC04; + u4Byte Reg874; + u4Byte RegC08; + u4Byte RegB68; + u4Byte RegB6C; + u4Byte Reg870; + u4Byte Reg860; + u4Byte Reg864; + + BOOLEAN bIQKInitialized; + BOOLEAN bLCKInProgress; + BOOLEAN bAntennaDetected; + u4Byte ADDA_backup[IQK_ADDA_REG_NUM]; + u4Byte IQK_MAC_backup[IQK_MAC_REG_NUM]; + u4Byte IQK_BB_backup_recover[9]; + u4Byte IQK_BB_backup[IQK_BB_REG_NUM]; + + //for APK + u4Byte APKoutput[2][2]; //path A/B; output1_1a/output1_2a + u1Byte bAPKdone; + u1Byte bAPKThermalMeterIgnore; + u1Byte bDPdone; + u1Byte bDPPathAOK; + u1Byte bDPPathBOK; + + u4Byte TxIQC_8723B[2][3][2]; // { {S1: 0xc94, 0xc80, 0xc4c} , {S0: 0xc9c, 0xc88, 0xc4c}} + u4Byte RxIQC_8723B[2][2][2]; // { {S1: 0xc14, 0xca0} , {S0: 0xc14, 0xca0}} + u4Byte TxLOK[2]; + +}ODM_RF_CAL_T,*PODM_RF_CAL_T; +// +// ODM Dynamic common info value definition +// + +typedef struct _FAST_ANTENNA_TRAINNING_ +{ + u1Byte Bssid[6]; + u1Byte antsel_rx_keep_0; + u1Byte antsel_rx_keep_1; + u1Byte antsel_rx_keep_2; + u4Byte antSumRSSI[7]; + u4Byte antRSSIcnt[7]; + u4Byte antAveRSSI[7]; + u1Byte FAT_State; + u4Byte TrainIdx; + u1Byte antsel_a[ODM_ASSOCIATE_ENTRY_NUM]; + u1Byte antsel_b[ODM_ASSOCIATE_ENTRY_NUM]; + u1Byte antsel_c[ODM_ASSOCIATE_ENTRY_NUM]; + u4Byte MainAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM]; + u4Byte AuxAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM]; + u4Byte MainAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; + u4Byte AuxAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; + u1Byte RxIdleAnt; + BOOLEAN bBecomeLinked; + u4Byte MinMaxRSSI; + u1Byte idx_AntDiv_counter_2G; + u1Byte idx_AntDiv_counter_5G; + u4Byte AntDiv_2G_5G; + u4Byte CCK_counter_main; + u4Byte CCK_counter_aux; + u4Byte OFDM_counter_main; + u4Byte OFDM_counter_aux; + +}FAT_T,*pFAT_T; + +typedef enum _FAT_STATE +{ + FAT_NORMAL_STATE = 0, + FAT_TRAINING_STATE = 1, +}FAT_STATE_E, *PFAT_STATE_E; + +typedef enum _ANT_DIV_TYPE +{ + NO_ANTDIV = 0xFF, + CG_TRX_HW_ANTDIV = 0x01, + CGCS_RX_HW_ANTDIV = 0x02, + FIXED_HW_ANTDIV = 0x03, + CG_TRX_SMART_ANTDIV = 0x04, + CGCS_RX_SW_ANTDIV = 0x05, + S0S1_SW_ANTDIV = 0x06 //8723B intrnal switch S0 S1 +}ANT_DIV_TYPE_E, *PANT_DIV_TYPE_E; + +typedef struct _ODM_PATH_DIVERSITY_ +{ + u1Byte RespTxPath; + u1Byte PathSel[ODM_ASSOCIATE_ENTRY_NUM]; + u4Byte PathA_Sum[ODM_ASSOCIATE_ENTRY_NUM]; + u4Byte PathB_Sum[ODM_ASSOCIATE_ENTRY_NUM]; + u4Byte PathA_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; + u4Byte PathB_Cnt[ODM_ASSOCIATE_ENTRY_NUM]; +}PATHDIV_T, *pPATHDIV_T; + + +typedef enum _BASEBAND_CONFIG_PHY_REG_PG_VALUE_TYPE{ + PHY_REG_PG_RELATIVE_VALUE = 0, + PHY_REG_PG_EXACT_VALUE = 1 +} PHY_REG_PG_TYPE; + + +// +// Antenna detection information from single tone mechanism, added by Roger, 2012.11.27. +// +typedef struct _ANT_DETECTED_INFO{ + BOOLEAN bAntDetected; + u4Byte dBForAntA; + u4Byte dBForAntB; + u4Byte dBForAntO; +}ANT_DETECTED_INFO, *PANT_DETECTED_INFO; + +// +// 2011/09/22 MH Copy from SD4 defined structure. We use to support PHY DM integration. +// +#if(DM_ODM_SUPPORT_TYPE & ODM_WIN) +#if (RT_PLATFORM != PLATFORM_LINUX) +typedef +#endif +struct DM_Out_Source_Dynamic_Mechanism_Structure +#else// for AP,ADSL,CE Team +typedef struct DM_Out_Source_Dynamic_Mechanism_Structure +#endif +{ + //RT_TIMER FastAntTrainingTimer; + // + // Add for different team use temporarily + // + PADAPTER Adapter; // For CE/NIC team + prtl8192cd_priv priv; // For AP/ADSL team + // WHen you use Adapter or priv pointer, you must make sure the pointer is ready. + BOOLEAN odm_ready; + +#if(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_WIN)) + rtl8192cd_priv fake_priv; +#endif +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + // ADSL_AP_BUILD_WORKAROUND + ADAPTER fake_adapter; +#endif + + PHY_REG_PG_TYPE PhyRegPgValueType; + u1Byte PhyRegPgVersion; + + u8Byte DebugComponents; + u4Byte DebugLevel; + + u8Byte NumQryPhyStatusAll; //CCK + OFDM + u8Byte LastNumQryPhyStatusAll; + u8Byte RxPWDBAve; + u8Byte RxPWDBAve_final; + BOOLEAN MPDIG_2G; //off MPDIG + u1Byte Times_2G; + +//------ ODM HANDLE, DRIVER NEEDS NOT TO HOOK------// + BOOLEAN bCckHighPower; + u1Byte RFPathRxEnable; // ODM_CMNINFO_RFPATH_ENABLE + u1Byte ControlChannel; +//------ ODM HANDLE, DRIVER NEEDS NOT TO HOOK------// + +//--------REMOVED COMMON INFO----------// + //u1Byte PseudoMacPhyMode; + //BOOLEAN *BTCoexist; + //BOOLEAN PseudoBtCoexist; + //u1Byte OPMode; + //BOOLEAN bAPMode; + //BOOLEAN bClientMode; + //BOOLEAN bAdHocMode; + //BOOLEAN bSlaveOfDMSP; +//--------REMOVED COMMON INFO----------// + + +//1 COMMON INFORMATION + + // + // Init Value + // +//-----------HOOK BEFORE REG INIT-----------// + // ODM Platform info AP/ADSL/CE/MP = 1/2/3/4 + u1Byte SupportPlatform; + // ODM Support Ability DIG/RATR/TX_PWR_TRACK/ �K�K = 1/2/3/�K + u4Byte SupportAbility; + // ODM PCIE/USB/SDIO = 1/2/3 + u1Byte SupportInterface; + // ODM composite or independent. Bit oriented/ 92C+92D+ .... or any other type = 1/2/3/... + u4Byte SupportICType; + // Cut Version TestChip/A-cut/B-cut... = 0/1/2/3/... + u1Byte CutVersion; + // Fab Version TSMC/UMC = 0/1 + u1Byte FabVersion; + // RF Type 4T4R/3T3R/2T2R/1T2R/1T1R/... + u1Byte RFType; + u1Byte RFEType; + // Board Type Normal/HighPower/MiniCard/SLIM/Combo/... = 0/1/2/3/4/... + u1Byte BoardType; + u1Byte PackageType; + u1Byte TypeGLNA; + u1Byte TypeGPA; + u1Byte TypeALNA; + u1Byte TypeAPA; + // with external LNA NO/Yes = 0/1 + u1Byte ExtLNA; + u1Byte ExtLNA5G; + // with external PA NO/Yes = 0/1 + u1Byte ExtPA; + u1Byte ExtPA5G; + // with external TRSW NO/Yes = 0/1 + u1Byte ExtTRSW; + u1Byte PatchID; //Customer ID + BOOLEAN bInHctTest; + BOOLEAN bWIFITest; + + BOOLEAN bDualMacSmartConcurrent; + u4Byte BK_SupportAbility; + u1Byte AntDivType; +//-----------HOOK BEFORE REG INIT-----------// + + // + // Dynamic Value + // +//--------- POINTER REFERENCE-----------// + + u1Byte u1Byte_temp; + BOOLEAN BOOLEAN_temp; + PADAPTER PADAPTER_temp; + + // MAC PHY Mode SMSP/DMSP/DMDP = 0/1/2 + u1Byte *pMacPhyMode; + //TX Unicast byte count + u8Byte *pNumTxBytesUnicast; + //RX Unicast byte count + u8Byte *pNumRxBytesUnicast; + // Wireless mode B/G/A/N = BIT0/BIT1/BIT2/BIT3 + u1Byte *pWirelessMode; //ODM_WIRELESS_MODE_E + // Frequence band 2.4G/5G = 0/1 + u1Byte *pBandType; + // Secondary channel offset don't_care/below/above = 0/1/2 + u1Byte *pSecChOffset; + // Security mode Open/WEP/AES/TKIP = 0/1/2/3 + u1Byte *pSecurity; + // BW info 20M/40M/80M = 0/1/2 + u1Byte *pBandWidth; + // Central channel location Ch1/Ch2/.... + u1Byte *pChannel; //central channel number + BOOLEAN DPK_Done; + // Common info for 92D DMSP + + BOOLEAN *pbGetValueFromOtherMac; + PADAPTER *pBuddyAdapter; + BOOLEAN *pbMasterOfDMSP; //MAC0: master, MAC1: slave + // Common info for Status + BOOLEAN *pbScanInProcess; + BOOLEAN *pbPowerSaving; + // CCA Path 2-path/path-A/path-B = 0/1/2; using ODM_CCA_PATH_E. + u1Byte *pOnePathCCA; + //pMgntInfo->AntennaTest + u1Byte *pAntennaTest; + BOOLEAN *pbNet_closed; + u1Byte *mp_mode; + //u1Byte *pAidMap; + u1Byte *pu1ForcedIgiLb; +//--------- POINTER REFERENCE-----------// + pu2Byte pForcedDataRate; +//------------CALL BY VALUE-------------// + BOOLEAN bLinkInProcess; + BOOLEAN bWIFI_Direct; + BOOLEAN bWIFI_Display; + BOOLEAN bLinked; + + BOOLEAN bsta_state; + u1Byte RSSI_Min; + u1Byte InterfaceIndex; // Add for 92D dual MAC: 0--Mac0 1--Mac1 + BOOLEAN bIsMPChip; + BOOLEAN bOneEntryOnly; + // Common info for BTDM + BOOLEAN bBtDisabled; // BT is disabled + BOOLEAN bBtConnectProcess; // BT HS is under connection progress. + u1Byte btHsRssi; // BT HS mode wifi rssi value. + BOOLEAN bBtHsOperation; // BT HS mode is under progress + BOOLEAN bBtDisableEdcaTurbo; // Under some condition, don't enable the EDCA Turbo + BOOLEAN bBtLimitedDig; // BT is busy. +//------------CALL BY VALUE-------------// + u1Byte RSSI_A; + u1Byte RSSI_B; + u8Byte RSSI_TRSW; + u8Byte RSSI_TRSW_H; + u8Byte RSSI_TRSW_L; + u8Byte RSSI_TRSW_iso; + + u1Byte RxRate; + BOOLEAN StopDIG; + BOOLEAN bNoisyState; + u1Byte TxRate; + u1Byte LinkedInterval; + u1Byte preChannel; + u4Byte TxagcOffsetValueA; + BOOLEAN IsTxagcOffsetPositiveA; + u4Byte TxagcOffsetValueB; + BOOLEAN IsTxagcOffsetPositiveB; + u8Byte lastTxOkCnt; + u8Byte lastRxOkCnt; + u4Byte BbSwingOffsetA; + BOOLEAN IsBbSwingOffsetPositiveA; + u4Byte BbSwingOffsetB; + BOOLEAN IsBbSwingOffsetPositiveB; + + //For Adaptivtiy + u2Byte NHM_cnt_0; + u2Byte NHM_cnt_1; + s1Byte TH_L2H_ini; + s1Byte TH_EDCCA_HL_diff; + s1Byte TH_L2H_ini_backup; + BOOLEAN Carrier_Sense_enable; + u1Byte Adaptivity_IGI_upper; + BOOLEAN adaptivity_flag; + u1Byte DCbackoff; + BOOLEAN Adaptivity_enable; + u1Byte APTotalNum; + ADAPTIVITY_STATISTICS Adaptivity; + //For Adaptivtiy + + u1Byte antdiv_rssi; + u1Byte AntType; + u1Byte pre_AntType; + u1Byte antdiv_period; + u1Byte antdiv_select; + //2 Define STA info. + // _ODM_STA_INFO + // 2012/01/12 MH For MP, we need to reduce one array pointer for default port.?? + PSTA_INFO_T pODM_StaInfo[ODM_ASSOCIATE_ENTRY_NUM]; + +#if (RATE_ADAPTIVE_SUPPORT == 1) + u2Byte CurrminRptTime; + ODM_RA_INFO_T RAInfo[ODM_ASSOCIATE_ENTRY_NUM]; //See HalMacID support +#endif + // + // 2012/02/14 MH Add to share 88E ra with other SW team. + // We need to colelct all support abilit to a proper area. + // + BOOLEAN RaSupport88E; + + // Define ........... + + // Latest packet phy info (ODM write) + ODM_PHY_DBG_INFO_T PhyDbgInfo; + //PHY_INFO_88E PhyInfo; + + // Latest packet phy info (ODM write) + ODM_MAC_INFO *pMacInfo; + //MAC_INFO_88E MacInfo; + + // Different Team independt structure?? + + // + //TX_RTP_CMN TX_retrpo; + //TX_RTP_88E TX_retrpo; + //TX_RTP_8195 TX_retrpo; + + // + //ODM Structure + // + FAT_T DM_FatTable; + DIG_T DM_DigTable; + PS_T DM_PSTable; + Pri_CCA_T DM_PriCCA; + RXHP_T DM_RXHP_Table; + RA_T DM_RA_Table; + FALSE_ALARM_STATISTICS FalseAlmCnt; + FALSE_ALARM_STATISTICS FlaseAlmCntBuddyAdapter; + //#ifdef CONFIG_ANTENNA_DIVERSITY + SWAT_T DM_SWAT_Table; + BOOLEAN RSSI_test; + //#endif + +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) + //Path Div Struct + PATHDIV_PARA pathIQK; +#endif + + EDCA_T DM_EDCA_Table; + u4Byte WMMEDCA_BE; + PATHDIV_T DM_PathDiv; + // Copy from SD4 structure + // + // ================================================== + // + + //common + //u1Byte DM_Type; + //u1Byte PSD_Report_RXHP[80]; // Add By Gary + //u1Byte PSD_func_flag; // Add By Gary + //for DIG + //u1Byte bDMInitialGainEnable; + //u1Byte binitialized; // for dm_initial_gain_Multi_STA use. + //for Antenna diversity + //u8 AntDivCfg;// 0:OFF , 1:ON, 2:by efuse + //PSTA_INFO_T RSSI_target; + + BOOLEAN *pbDriverStopped; + BOOLEAN *pbDriverIsGoingToPnpSetPowerSleep; + BOOLEAN *pinit_adpt_in_progress; + + //PSD + BOOLEAN bUserAssignLevel; + RT_TIMER PSDTimer; + u1Byte RSSI_BT; //come from BT + BOOLEAN bPSDinProcess; + BOOLEAN bPSDactive; + BOOLEAN bDMInitialGainEnable; + + //MPT DIG + RT_TIMER MPT_DIGTimer; + + //for rate adaptive, in fact, 88c/92c fw will handle this + u1Byte bUseRAMask; + + ODM_RATE_ADAPTIVE RateAdaptive; + + ANT_DETECTED_INFO AntDetectedInfo; // Antenna detected information for RSSI tool + + ODM_RF_CAL_T RFCalibrateInfo; + + // + // TX power tracking + // + u1Byte BbSwingIdxOfdm[MAX_RF_PATH]; + u1Byte BbSwingIdxOfdmCurrent; + u1Byte BbSwingIdxOfdmBase[MAX_RF_PATH]; + BOOLEAN BbSwingFlagOfdm; + u1Byte BbSwingIdxCck; + u1Byte BbSwingIdxCckCurrent; + u1Byte BbSwingIdxCckBase; + u1Byte DefaultOfdmIndex; + u1Byte DefaultCckIndex; + BOOLEAN BbSwingFlagCck; + + s1Byte Absolute_OFDMSwingIdx[MAX_RF_PATH]; + s1Byte Remnant_OFDMSwingIdx[MAX_RF_PATH]; + s1Byte Remnant_CCKSwingIdx; + s1Byte Modify_TxAGC_Value; //Remnat compensate value at TxAGC + BOOLEAN Modify_TxAGC_Flag_PathA; + BOOLEAN Modify_TxAGC_Flag_PathB; + BOOLEAN Modify_TxAGC_Flag_PathA_CCK; + + // + // Dynamic ATC switch + // + BOOLEAN bATCStatus; + BOOLEAN largeCFOHit; + BOOLEAN bIsfreeze; + int CFO_tail[2]; + int CFO_ave_pre; + int CrystalCap; + u1Byte CFOThreshold; + u4Byte packetCount; + u4Byte packetCount_pre; + + // + // ODM system resource. + // + + // ODM relative time. + RT_TIMER PathDivSwitchTimer; + //2011.09.27 add for Path Diversity + RT_TIMER CCKPathDiversityTimer; + RT_TIMER FastAntTrainingTimer; + + // ODM relative workitem. +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + #if USE_WORKITEM + RT_WORK_ITEM PathDivSwitchWorkitem; + RT_WORK_ITEM CCKPathDiversityWorkitem; + RT_WORK_ITEM FastAntTrainingWorkitem; + RT_WORK_ITEM MPT_DIGWorkitem; + RT_WORK_ITEM RaRptWorkitem; + #endif +#endif + +#if(DM_ODM_SUPPORT_TYPE & ODM_WIN) + +#if (RT_PLATFORM != PLATFORM_LINUX) +} DM_ODM_T, *PDM_ODM_T; // DM_Dynamic_Mechanism_Structure +#else +}; +#endif + +#else// for AP,ADSL,CE Team +} DM_ODM_T, *PDM_ODM_T; // DM_Dynamic_Mechanism_Structure +#endif + + + +#if 1 //92c-series +#define ODM_RF_PATH_MAX 2 +#else //jaguar - series +#define ODM_RF_PATH_MAX 4 +#endif + +typedef enum _ODM_RF_RADIO_PATH { + ODM_RF_PATH_A = 0, //Radio Path A + ODM_RF_PATH_B = 1, //Radio Path B + ODM_RF_PATH_C = 2, //Radio Path C + ODM_RF_PATH_D = 3, //Radio Path D + ODM_RF_PATH_AB, + ODM_RF_PATH_AC, + ODM_RF_PATH_AD, + ODM_RF_PATH_BC, + ODM_RF_PATH_BD, + ODM_RF_PATH_CD, + ODM_RF_PATH_ABC, + ODM_RF_PATH_ACD, + ODM_RF_PATH_BCD, + ODM_RF_PATH_ABCD, + // ODM_RF_PATH_MAX, //Max RF number 90 support +} ODM_RF_RADIO_PATH_E, *PODM_RF_RADIO_PATH_E; + + typedef enum _ODM_RF_CONTENT{ + odm_radioa_txt = 0x1000, + odm_radiob_txt = 0x1001, + odm_radioc_txt = 0x1002, + odm_radiod_txt = 0x1003 +} ODM_RF_CONTENT; + +typedef enum _ODM_BB_Config_Type{ + CONFIG_BB_PHY_REG, + CONFIG_BB_AGC_TAB, + CONFIG_BB_AGC_TAB_2G, + CONFIG_BB_AGC_TAB_5G, + CONFIG_BB_PHY_REG_PG, + CONFIG_BB_PHY_REG_MP, + CONFIG_BB_AGC_TAB_DIFF, +} ODM_BB_Config_Type, *PODM_BB_Config_Type; + +typedef enum _ODM_RF_Config_Type{ + CONFIG_RF_RADIO, + CONFIG_RF_TXPWR_LMT, +} ODM_RF_Config_Type, *PODM_RF_Config_Type; + +typedef enum _ODM_FW_Config_Type{ + CONFIG_FW_NIC, + CONFIG_FW_NIC_2, + CONFIG_FW_AP, + CONFIG_FW_MP, + CONFIG_FW_WoWLAN, + CONFIG_FW_WoWLAN_2, + CONFIG_FW_AP_WoWLAN, + CONFIG_FW_BT, +} ODM_FW_Config_Type; + +// Status code +#if (DM_ODM_SUPPORT_TYPE != ODM_WIN) +typedef enum _RT_STATUS{ + RT_STATUS_SUCCESS, + RT_STATUS_FAILURE, + RT_STATUS_PENDING, + RT_STATUS_RESOURCE, + RT_STATUS_INVALID_CONTEXT, + RT_STATUS_INVALID_PARAMETER, + RT_STATUS_NOT_SUPPORT, + RT_STATUS_OS_API_FAILED, +}RT_STATUS,*PRT_STATUS; +#endif // end of RT_STATUS definition + +#ifdef REMOVE_PACK +#pragma pack() +#endif + +//#include "odm_function.h" + +//3=========================================================== +//3 DIG +//3=========================================================== + +typedef enum tag_Dynamic_Init_Gain_Operation_Type_Definition +{ + DIG_TYPE_THRESH_HIGH = 0, + DIG_TYPE_THRESH_LOW = 1, + DIG_TYPE_BACKOFF = 2, + DIG_TYPE_RX_GAIN_MIN = 3, + DIG_TYPE_RX_GAIN_MAX = 4, + DIG_TYPE_ENABLE = 5, + DIG_TYPE_DISABLE = 6, + DIG_OP_TYPE_MAX +}DM_DIG_OP_E; +/* +typedef enum tag_CCK_Packet_Detection_Threshold_Type_Definition +{ + CCK_PD_STAGE_LowRssi = 0, + CCK_PD_STAGE_HighRssi = 1, + CCK_PD_STAGE_MAX = 3, +}DM_CCK_PDTH_E; + +typedef enum tag_DIG_EXT_PORT_ALGO_Definition +{ + DIG_EXT_PORT_STAGE_0 = 0, + DIG_EXT_PORT_STAGE_1 = 1, + DIG_EXT_PORT_STAGE_2 = 2, + DIG_EXT_PORT_STAGE_3 = 3, + DIG_EXT_PORT_STAGE_MAX = 4, +}DM_DIG_EXT_PORT_ALG_E; + +typedef enum tag_DIG_Connect_Definition +{ + DIG_STA_DISCONNECT = 0, + DIG_STA_CONNECT = 1, + DIG_STA_BEFORE_CONNECT = 2, + DIG_MultiSTA_DISCONNECT = 3, + DIG_MultiSTA_CONNECT = 4, + DIG_CONNECT_MAX +}DM_DIG_CONNECT_E; + + +#define DM_MultiSTA_InitGainChangeNotify(Event) {DM_DigTable.CurMultiSTAConnectState = Event;} + +#define DM_MultiSTA_InitGainChangeNotify_CONNECT(_ADAPTER) \ + DM_MultiSTA_InitGainChangeNotify(DIG_MultiSTA_CONNECT) + +#define DM_MultiSTA_InitGainChangeNotify_DISCONNECT(_ADAPTER) \ + DM_MultiSTA_InitGainChangeNotify(DIG_MultiSTA_DISCONNECT) +*/ +#define DM_DIG_THRESH_HIGH 40 +#define DM_DIG_THRESH_LOW 35 + +#define DM_FALSEALARM_THRESH_LOW 400 +#define DM_FALSEALARM_THRESH_HIGH 1000 + +#define DM_DIG_MAX_NIC 0x3e +#define DM_DIG_MIN_NIC 0x1e //0x22//0x1c + +#define DM_DIG_MAX_AP 0x32 +#define DM_DIG_MIN_AP 0x20 + +#define DM_DIG_MAX_NIC_HP 0x46 +#define DM_DIG_MIN_NIC_HP 0x2e + +#define DM_DIG_MAX_AP_HP 0x42 +#define DM_DIG_MIN_AP_HP 0x30 + +//vivi 92c&92d has different definition, 20110504 +//this is for 92c +#ifdef CONFIG_SPECIAL_SETTING_FOR_FUNAI_TV +#define DM_DIG_FA_TH0 0x80//0x20 +#else +#define DM_DIG_FA_TH0 0x200//0x20 +#endif +#define DM_DIG_FA_TH1 0x300//0x100 +#define DM_DIG_FA_TH2 0x400//0x200 +//this is for 92d +#define DM_DIG_FA_TH0_92D 0x100 +#define DM_DIG_FA_TH1_92D 0x400 +#define DM_DIG_FA_TH2_92D 0x600 + +#define DM_DIG_BACKOFF_MAX 12 +#define DM_DIG_BACKOFF_MIN -4 +#define DM_DIG_BACKOFF_DEFAULT 10 + +//3=========================================================== +//3 AGC RX High Power Mode +//3=========================================================== +#define LNA_Low_Gain_1 0x64 +#define LNA_Low_Gain_2 0x5A +#define LNA_Low_Gain_3 0x58 + +#define FA_RXHP_TH1 5000 +#define FA_RXHP_TH2 1500 +#define FA_RXHP_TH3 800 +#define FA_RXHP_TH4 600 +#define FA_RXHP_TH5 500 + +//3=========================================================== +//3 EDCA +//3=========================================================== + +//3=========================================================== +//3 Dynamic Tx Power +//3=========================================================== +//Dynamic Tx Power Control Threshold +#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 +#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 +#define TX_POWER_NEAR_FIELD_THRESH_AP 0x3F + +#define TxHighPwrLevel_Normal 0 +#define TxHighPwrLevel_Level1 1 +#define TxHighPwrLevel_Level2 2 +#define TxHighPwrLevel_BT1 3 +#define TxHighPwrLevel_BT2 4 +#define TxHighPwrLevel_15 5 +#define TxHighPwrLevel_35 6 +#define TxHighPwrLevel_50 7 +#define TxHighPwrLevel_70 8 +#define TxHighPwrLevel_100 9 + +//3=========================================================== +//3 Tx Power Tracking +//3=========================================================== +#if 0 //mask this, since these have been defined in typdef.h, vivi +#define OFDM_TABLE_SIZE 43 +#define CCK_TABLE_SIZE 33 +#endif + + +//3=========================================================== +//3 Rate Adaptive +//3=========================================================== +#define DM_RATR_STA_INIT 0 +#define DM_RATR_STA_HIGH 1 +#define DM_RATR_STA_MIDDLE 2 +#define DM_RATR_STA_LOW 3 + +//3=========================================================== +//3 BB Power Save +//3=========================================================== + + +//3=========================================================== +//3 Dynamic ATC switch +//3=========================================================== +#define ATC_Status_Off 0x0 // enable +#define ATC_Status_On 0x1 // disable +#define CFO_Threshold_Xtal 10 // kHz +#define CFO_Threshold_ATC 80 // kHz + +typedef enum tag_1R_CCA_Type_Definition +{ + CCA_1R =0, + CCA_2R = 1, + CCA_MAX = 2, +}DM_1R_CCA_E; + +typedef enum tag_RF_Type_Definition +{ + RF_Save =0, + RF_Normal = 1, + RF_MAX = 2, +}DM_RF_E; + +//3=========================================================== +//3 Antenna Diversity +//3=========================================================== +typedef enum tag_SW_Antenna_Switch_Definition +{ + Antenna_A = 1, + Antenna_B = 2, + Antenna_MAX = 3, +}DM_SWAS_E; + + +// Maximal number of antenna detection mechanism needs to perform, added by Roger, 2011.12.28. +#define MAX_ANTENNA_DETECTION_CNT 10 + +// +// Extern Global Variables. +// +extern u4Byte OFDMSwingTable[OFDM_TABLE_SIZE]; +extern u1Byte CCKSwingTable_Ch1_Ch13[CCK_TABLE_SIZE][8]; +extern u1Byte CCKSwingTable_Ch14 [CCK_TABLE_SIZE][8]; + +extern u4Byte OFDMSwingTable_New[OFDM_TABLE_SIZE]; +extern u1Byte CCKSwingTable_Ch1_Ch13_New[CCK_TABLE_SIZE][8]; +extern u1Byte CCKSwingTable_Ch14_New [CCK_TABLE_SIZE][8]; + +extern u4Byte TxScalingTable_Jaguar[TXSCALE_TABLE_SIZE]; + +// <20121018, Kordan> In case fail to read TxPowerTrack.txt, we use the table of 88E as the default table. +static u1Byte DeltaSwingTableIdx_2GA_P_8188E[] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9}; +static u1Byte DeltaSwingTableIdx_2GA_N_8188E[] = {0, 0, 0, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11}; + +// +// check Sta pointer valid or not +// +#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) +#define IS_STA_VALID(pSta) (pSta && pSta->expire_to) +#elif (DM_ODM_SUPPORT_TYPE & ODM_WIN) +#define IS_STA_VALID(pSta) (pSta && pSta->bUsed) +#else +#define IS_STA_VALID(pSta) (pSta) +#endif +// 20100514 Joseph: Add definition for antenna switching test after link. +// This indicates two different the steps. +// In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the signal on the air. +// In SWAW_STEP_DETERMINE, driver just compares the signal captured in SWAW_STEP_PEAK +// with original RSSI to determine if it is necessary to switch antenna. +#define SWAW_STEP_PEAK 0 +#define SWAW_STEP_DETERMINE 1 + +VOID ODM_Write_DIG(IN PDM_ODM_T pDM_Odm, IN u1Byte CurrentIGI); +VOID ODM_Write_CCK_CCA_Thres(IN PDM_ODM_T pDM_Odm, IN u1Byte CurCCK_CCAThres); + +VOID +ODM_SetAntenna( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Antenna); + + +#define dm_RF_Saving ODM_RF_Saving +void ODM_RF_Saving( IN PDM_ODM_T pDM_Odm, + IN u1Byte bForceInNormal ); + +#define SwAntDivRestAfterLink ODM_SwAntDivRestAfterLink +VOID ODM_SwAntDivRestAfterLink( IN PDM_ODM_T pDM_Odm); + +#define dm_CheckTXPowerTracking ODM_TXPowerTrackingCheck +VOID +ODM_TXPowerTrackingCheck( + IN PDM_ODM_T pDM_Odm + ); + +BOOLEAN +ODM_RAStateCheck( + IN PDM_ODM_T pDM_Odm, + IN s4Byte RSSI, + IN BOOLEAN bForceUpdate, + OUT pu1Byte pRATRState + ); + +#if(DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_AP|ODM_ADSL)) +//============================================================ +// function prototype +//============================================================ +//#define DM_ChangeDynamicInitGainThresh ODM_ChangeDynamicInitGainThresh +//void ODM_ChangeDynamicInitGainThresh(IN PADAPTER pAdapter, +// IN INT32 DM_Type, +// IN INT32 DM_Value); +VOID +ODM_ChangeDynamicInitGainThresh( + IN PDM_ODM_T pDM_Odm, + IN u4Byte DM_Type, + IN u4Byte DM_Value + ); + +BOOLEAN +ODM_CheckPowerStatus( + IN PADAPTER Adapter + ); + + +#if (DM_ODM_SUPPORT_TYPE != ODM_ADSL) +VOID +ODM_RateAdaptiveStateApInit( + IN PADAPTER Adapter , + IN PRT_WLAN_STA pEntry + ); +#endif +#define AP_InitRateAdaptiveState ODM_RateAdaptiveStateApInit + + +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) +#ifdef WIFI_WMM +VOID +ODM_IotEdcaSwitch( + IN PDM_ODM_T pDM_Odm, + IN unsigned char enable + ); +#endif + +BOOLEAN +ODM_ChooseIotMainSTA( + IN PDM_ODM_T pDM_Odm, + IN PSTA_INFO_T pstat + ); +#endif + +#if(DM_ODM_SUPPORT_TYPE==ODM_AP) +#ifdef HW_ANT_SWITCH +u1Byte +ODM_Diversity_AntennaSelect( + IN PDM_ODM_T pDM_Odm, + IN u1Byte *data +); +#endif +#endif + +#define SwAntDivResetBeforeLink ODM_SwAntDivResetBeforeLink +VOID ODM_SwAntDivResetBeforeLink(IN PDM_ODM_T pDM_Odm); + +#define SwAntDivCheckBeforeLink ODM_SwAntDivCheckBeforeLink + +BOOLEAN +ODM_SwAntDivCheckBeforeLink( + IN PDM_ODM_T pDM_Odm + ); + + +#endif + +#define dm_SWAW_RSSI_Check ODM_SwAntDivChkPerPktRssi +VOID ODM_SwAntDivChkPerPktRssi( + IN PDM_ODM_T pDM_Odm, + IN u1Byte StationID, + IN PODM_PHY_INFO_T pPhyInfo + ); + +#if((DM_ODM_SUPPORT_TYPE==ODM_WIN)||(DM_ODM_SUPPORT_TYPE==ODM_CE)) + +u4Byte ConvertTo_dB(u4Byte Value); + +u4Byte +GetPSDData( + PDM_ODM_T pDM_Odm, + unsigned int point, + u1Byte initial_gain_psd); + +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) + +VOID +odm_DIGbyRSSI_LPS( + IN PDM_ODM_T pDM_Odm + ); + +u4Byte ODM_Get_Rate_Bitmap( + IN PDM_ODM_T pDM_Odm, + IN u4Byte macid, + IN u4Byte ra_mask, + IN u1Byte rssi_level); + +#endif + + +#if(DM_ODM_SUPPORT_TYPE & (ODM_WIN)) +#define dm_PSDMonitorCallback odm_PSDMonitorCallback +VOID odm_PSDMonitorCallback(PRT_TIMER pTimer); + +VOID +odm_PSDMonitorWorkItemCallback( + IN PVOID pContext + ); + +VOID +ODM_MPT_DIG( + IN PDM_ODM_T pDM_Odm +); + +VOID +PatchDCTone( + IN PDM_ODM_T pDM_Odm, + pu4Byte PSD_report, + u1Byte initial_gain_psd +); +VOID +ODM_PSDMonitor( + IN PDM_ODM_T pDM_Odm + ); +VOID odm_PSD_Monitor(PDM_ODM_T pDM_Odm); +VOID odm_PSDMonitorInit(PDM_ODM_T pDM_Odm); + +VOID +ODM_PSDDbgControl( + IN PADAPTER Adapter, + IN u4Byte mode, + IN u4Byte btRssi + ); + +#endif // DM_ODM_SUPPORT_TYPE + + +#if (BEAMFORMING_SUPPORT == 1) +BEAMFORMING_CAP +Beamforming_GetEntryBeamCapByMacId( + IN PMGNT_INFO pMgntInfo, + IN u1Byte MacId + ); +#endif + +VOID +odm_TXPowerTrackingInit( + IN PDM_ODM_T pDM_Odm + ); + + +VOID ODM_DMInit( IN PDM_ODM_T pDM_Odm); + +VOID +ODM_DMWatchdog( + IN PDM_ODM_T pDM_Odm // For common use in the future + ); + +VOID +ODM_CmnInfoInit( + IN PDM_ODM_T pDM_Odm, + IN ODM_CMNINFO_E CmnInfo, + IN u4Byte Value + ); + +VOID +ODM_CmnInfoHook( + IN PDM_ODM_T pDM_Odm, + IN ODM_CMNINFO_E CmnInfo, + IN PVOID pValue + ); + +VOID +ODM_CmnInfoPtrArrayHook( + IN PDM_ODM_T pDM_Odm, + IN ODM_CMNINFO_E CmnInfo, + IN u2Byte Index, + IN PVOID pValue + ); + +VOID +ODM_CmnInfoUpdate( + IN PDM_ODM_T pDM_Odm, + IN u4Byte CmnInfo, + IN u8Byte Value + ); + +VOID +ODM_InitAllTimers( + IN PDM_ODM_T pDM_Odm + ); + +VOID +ODM_CancelAllTimers( + IN PDM_ODM_T pDM_Odm + ); + +VOID +ODM_ReleaseAllTimers( + IN PDM_ODM_T pDM_Odm + ); + +VOID +ODM_ResetIQKResult( + IN PDM_ODM_T pDM_Odm + ); + + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +VOID ODM_InitAllWorkItems(IN PDM_ODM_T pDM_Odm ); +VOID ODM_FreeAllWorkItems(IN PDM_ODM_T pDM_Odm ); + +VOID odm_PathDivChkAntSwitch(PDM_ODM_T pDM_Odm); +VOID ODM_PathDivRestAfterLink( + IN PDM_ODM_T pDM_Odm + ); + + +//===========================================// +// Neil Chen----2011--06--15-- + +//3 Path Diversity +//=========================================================== + +#define TP_MODE 0 +#define RSSI_MODE 1 +#define TRAFFIC_LOW 0 +#define TRAFFIC_HIGH 1 + +//#define PATHDIV_ENABLE 1 + +//VOID odm_PathDivChkAntSwitch(PADAPTER Adapter,u1Byte Step); +VOID ODM_PathDivRestAfterLink( + IN PDM_ODM_T pDM_Odm + ); + +#define dm_PathDiv_RSSI_Check ODM_PathDivChkPerPktRssi +VOID ODM_PathDivChkPerPktRssi(PADAPTER Adapter, + BOOLEAN bIsDefPort, + BOOLEAN bMatchBSSID, + PRT_WLAN_STA pEntry, + PRT_RFD pRfd ); + +u8Byte +PlatformDivision64( + IN u8Byte x, + IN u8Byte y +); + + +// 20100514 Joseph: Add definition for antenna switching test after link. +// This indicates two different the steps. +// In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the signal on the air. +// In SWAW_STEP_DETERMINE, driver just compares the signal captured in SWAW_STEP_PEAK +// with original RSSI to determine if it is necessary to switch antenna. +#define SWAW_STEP_PEAK 0 +#define SWAW_STEP_DETERMINE 1 + +//==================================================== +//3 PathDiV End +//==================================================== + +#define PathDivCheckBeforeLink8192C ODM_PathDiversityBeforeLink92C +BOOLEAN +ODM_PathDiversityBeforeLink92C( + //IN PADAPTER Adapter + IN PDM_ODM_T pDM_Odm + ); + +#define DM_ChangeDynamicInitGainThresh ODM_ChangeDynamicInitGainThresh +//void ODM_ChangeDynamicInitGainThresh(IN PADAPTER pAdapter, +// IN INT32 DM_Type, +// IN INT32 DM_Value); +// + + +VOID +ODM_CCKPathDiversityChkPerPktRssi( + PADAPTER Adapter, + BOOLEAN bIsDefPort, + BOOLEAN bMatchBSSID, + PRT_WLAN_STA pEntry, + PRT_RFD pRfd, + pu1Byte pDesc + ); + + +typedef enum tag_DIG_Connect_Definition +{ + DIG_STA_DISCONNECT = 0, + DIG_STA_CONNECT = 1, + DIG_STA_BEFORE_CONNECT = 2, + DIG_MultiSTA_DISCONNECT = 3, + DIG_MultiSTA_CONNECT = 4, + DIG_CONNECT_MAX +}DM_DIG_CONNECT_E; + + +VOID +ODM_FillTXPathInTXDESC( + IN PADAPTER Adapter, + IN PRT_TCB pTcb, + IN pu1Byte pDesc +); + + +#define dm_SWAW_RSSI_Check ODM_SwAntDivChkPerPktRssi + +// +// 2012/01/12 MH Check afapter status. Temp fix BSOD. +// +#define HAL_ADAPTER_STS_CHK(pDM_Odm)\ + if (pDM_Odm->Adapter == NULL)\ + {\ + return;\ + }\ + + +// +// For new definition in MP temporarily fro power tracking, +// +#define odm_TXPowerTrackingDirectCall(_Adapter) \ + IS_HARDWARE_TYPE_8192D(_Adapter) ? odm_TXPowerTrackingCallback_ThermalMeter_92D(_Adapter) : \ + IS_HARDWARE_TYPE_8192C(_Adapter) ? odm_TXPowerTrackingCallback_ThermalMeter_92C(_Adapter) : \ + IS_HARDWARE_TYPE_8723A(_Adapter) ? odm_TXPowerTrackingCallback_ThermalMeter_8723A(_Adapter) :\ + ODM_TXPowerTrackingCallback_ThermalMeter(_Adapter) + +VOID +ODM_SetTxAntByTxInfo_88C_92D( + IN PDM_ODM_T pDM_Odm, + IN pu1Byte pDesc, + IN u1Byte macId + ); + +#endif // #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +VOID +ODM_AntselStatistics_88C( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacId, + IN u4Byte PWDBAll, + IN BOOLEAN isCCKrate +); + +#if( DM_ODM_SUPPORT_TYPE & (ODM_WIN |ODM_CE)) + +VOID +ODM_SingleDualAntennaDefaultSetting( + IN PDM_ODM_T pDM_Odm + ); + +BOOLEAN +ODM_SingleDualAntennaDetection( + IN PDM_ODM_T pDM_Odm, + IN u1Byte mode + ); + +VOID +ODM_DynamicATCSwitch( + IN PDM_ODM_T pDM_Odm +); + + +#endif // #if((DM_ODM_SUPPORT_TYPE==ODM_WIN)||(DM_ODM_SUPPORT_TYPE==ODM_CE)) +VOID +ODM_UpdateNoisyState( + IN PDM_ODM_T pDM_Odm, + IN BOOLEAN bNoisyStateFromC2H +); + +u4Byte +Set_RA_DM_Ratrbitmap_by_Noisy( + IN PDM_ODM_T pDM_Odm, + IN WIRELESS_MODE WirelessMode, + IN u4Byte ratr_bitmap, + IN u1Byte rssi_level +); + +VOID +ODM_UpdateInitRate( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Rate + ); + +VOID +ODM_DynamicARFBSelect( + IN PDM_ODM_T pDM_Odm, + IN u1Byte rate, + IN BOOLEAN Collision_State + ); + +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) +void odm_dtc(PDM_ODM_T pDM_Odm); +#endif /* #if (DM_ODM_SUPPORT_TYPE == ODM_CE) */ + +typedef enum _PHYDM_STRUCTURE_TYPE{ + PHYDM_FALSEALMCNT, + PHYDM_CFOTRACK, + PHYDM_ADAPTIVITY, + PHYDM_ROMINFO, + +}PHYDM_STRUCTURE_TYPE; + +PVOID +PhyDM_Get_Structure( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Structure_Type +); + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_AntDiv.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_AntDiv.c new file mode 100644 index 0000000..38b224b --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_AntDiv.c @@ -0,0 +1,2269 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +//============================================================ +// include files +//============================================================ + +#include "odm_precomp.h" + +#if (defined(CONFIG_HW_ANTENNA_DIVERSITY)) +VOID +odm_AntDiv_on_off( IN PDM_ODM_T pDM_Odm ,IN u1Byte swch) +{ + if(pDM_Odm->AntDivType==S0S1_SW_ANTDIV || pDM_Odm->AntDivType==CGCS_RX_SW_ANTDIV) + return; + + if(pDM_Odm->SupportICType & ODM_N_ANTDIV_SUPPORT) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("(( Turn %s )) N-Series AntDiv Function\n",(swch==ANTDIV_ON)?"ON" : "OFF")); + ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, swch); //OFDM AntDiv function block enable + ODM_SetBBReg(pDM_Odm, 0xa00 , BIT15, swch); //CCK AntDiv function block enable + } + else if(pDM_Odm->SupportICType & ODM_AC_ANTDIV_SUPPORT) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("(( Turn %s )) AC-Series AntDiv Function\n",(swch==ANTDIV_ON)?"ON" : "OFF")); + if(pDM_Odm->SupportICType == ODM_RTL8812) + { + ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, swch); //OFDM AntDiv function block enable + ODM_SetBBReg(pDM_Odm, 0xa00 , BIT15, swch); //CCK AntDiv function block enable + } + else + { + ODM_SetBBReg(pDM_Odm, 0x8D4 , BIT24, swch); //OFDM AntDiv function block enable + ODM_SetBBReg(pDM_Odm, 0x800 , BIT25, swch); //CCK AntDiv function block enable + } + } +} + +VOID +ODM_UpdateRxIdleAnt(IN PDM_ODM_T pDM_Odm, IN u1Byte Ant) +{ + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + u4Byte DefaultAnt, OptionalAnt,value32; + + #if (DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_WIN)) + PADAPTER pAdapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #endif + + if(pDM_FatTable->RxIdleAnt != Ant) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ Update Rx-Idle-Ant ] RxIdleAnt =%s\n",(Ant==MAIN_ANT)?"MAIN_ANT":"AUX_ANT")); + pDM_FatTable->RxIdleAnt = Ant; + + if(Ant == MAIN_ANT) + { + DefaultAnt = ANT1_2G; + OptionalAnt = ANT2_2G; + } + else + { + DefaultAnt = ANT2_2G; + OptionalAnt = ANT1_2G; + } + + if(pDM_Odm->SupportICType & ODM_N_ANTDIV_SUPPORT) + { + if(pDM_Odm->SupportICType==ODM_RTL8192E) + { + ODM_SetBBReg(pDM_Odm, 0xB38 , BIT5|BIT4|BIT3, DefaultAnt); //Default RX + ODM_SetBBReg(pDM_Odm, 0xB38 , BIT8|BIT7|BIT6, OptionalAnt);//Optional RX + } + else + { + ODM_SetBBReg(pDM_Odm, 0x864 , BIT5|BIT4|BIT3, DefaultAnt); //Default RX + ODM_SetBBReg(pDM_Odm, 0x864 , BIT8|BIT7|BIT6, OptionalAnt); //Optional RX + + if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + value32 = ODM_GetBBReg(pDM_Odm, 0x948, 0xFFF); + + if (value32 !=0x280) + ODM_SetBBReg(pDM_Odm, 0x948 , BIT9, DefaultAnt); + + rtw_hal_set_tx_power_level(pAdapter, pHalData->CurrentChannel); + } + + } + ODM_SetBBReg(pDM_Odm, 0x860, BIT14|BIT13|BIT12, DefaultAnt); //Default TX + } + else if(pDM_Odm->SupportICType & ODM_AC_ANTDIV_SUPPORT) + { + ODM_SetBBReg(pDM_Odm, 0xC08 , BIT21|BIT20|BIT19, DefaultAnt); //Default RX + ODM_SetBBReg(pDM_Odm, 0xC08 , BIT24|BIT23|BIT22, OptionalAnt);//Optional RX + ODM_SetBBReg(pDM_Odm, 0xC08 , BIT27|BIT26|BIT25, DefaultAnt); //Default TX + } + ODM_SetMACReg(pDM_Odm, 0x6D8 , BIT10|BIT9|BIT8, DefaultAnt); //PathA Resp Tx + } + else// pDM_FatTable->RxIdleAnt == Ant + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[ Stay in Ori-Ant ] RxIdleAnt =%s\n",(Ant==MAIN_ANT)?"MAIN_ANT":"AUX_ANT")); + pDM_FatTable->RxIdleAnt = Ant; + } +} + + +VOID +odm_UpdateTxAnt(IN PDM_ODM_T pDM_Odm, IN u1Byte Ant, IN u4Byte MacId) +{ + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + u1Byte TxAnt; + + if(Ant == MAIN_ANT) + TxAnt = ANT1_2G; + else + TxAnt = ANT2_2G; + + pDM_FatTable->antsel_a[MacId] = TxAnt&BIT0; + pDM_FatTable->antsel_b[MacId] = (TxAnt&BIT1)>>1; + pDM_FatTable->antsel_c[MacId] = (TxAnt&BIT2)>>2; + #if (DM_ODM_SUPPORT_TYPE == ODM_AP) + if (pDM_Odm->antdiv_rssi) + { + //panic_printk("[Tx from TxInfo]: MacID:(( %d )), TxAnt = (( %s ))\n",MacId,(Ant==MAIN_ANT)?"MAIN_ANT":"AUX_ANT"); + //panic_printk("antsel_tr_mux=(( 3'b%d%d%d ))\n", pDM_FatTable->antsel_c[MacId] , pDM_FatTable->antsel_b[MacId] , pDM_FatTable->antsel_a[MacId] ); + } + #endif + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[Tx from TxInfo]: MacID:(( %d )), TxAnt = (( %s ))\n", + // MacId,(Ant==MAIN_ANT)?"MAIN_ANT":"AUX_ANT")); + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("antsel_tr_mux=(( 3'b%d%d%d ))\n", + //pDM_FatTable->antsel_c[MacId] , pDM_FatTable->antsel_b[MacId] , pDM_FatTable->antsel_a[MacId] )); + +} + + + +#if (RTL8188E_SUPPORT == 1) + + +VOID +odm_RX_HWAntDiv_Init_88E( + IN PDM_ODM_T pDM_Odm +) +{ + u4Byte value32; + + pDM_Odm->AntType = ODM_AUTO_ANT; + + #if (MP_DRIVER == 1) + pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV; + ODM_SetBBReg(pDM_Odm, ODM_REG_IGI_A_11N , BIT7, 0); // disable HW AntDiv + ODM_SetBBReg(pDM_Odm, ODM_REG_LNA_SWITCH_11N , BIT31, 1); // 1:CG, 0:CS + return; + #endif + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("***8188E AntDiv_Init => AntDivType=[CGCS_RX_HW_ANTDIV]\n")); + + //MAC Setting + value32 = ODM_GetMACReg(pDM_Odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord); + ODM_SetMACReg(pDM_Odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord, value32|(BIT23|BIT25)); //Reg4C[25]=1, Reg4C[23]=1 for pin output + //Pin Settings + ODM_SetBBReg(pDM_Odm, ODM_REG_PIN_CTRL_11N , BIT9|BIT8, 0);//Reg870[8]=1'b0, Reg870[9]=1'b0 //antsel antselb by HW + ODM_SetBBReg(pDM_Odm, ODM_REG_RX_ANT_CTRL_11N , BIT10, 0); //Reg864[10]=1'b0 //antsel2 by HW + ODM_SetBBReg(pDM_Odm, ODM_REG_LNA_SWITCH_11N , BIT22, 1); //Regb2c[22]=1'b0 //disable CS/CG switch + ODM_SetBBReg(pDM_Odm, ODM_REG_LNA_SWITCH_11N , BIT31, 1); //Regb2c[31]=1'b1 //output at CG only + //OFDM Settings + ODM_SetBBReg(pDM_Odm, ODM_REG_ANTDIV_PARA1_11N , bMaskDWord, 0x000000a0); + //CCK Settings + ODM_SetBBReg(pDM_Odm, ODM_REG_BB_PWR_SAV4_11N , BIT7, 1); //Fix CCK PHY status report issue + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_ANTDIV_PARA2_11N , BIT4, 1); //CCK complete HW AntDiv within 64 samples + + ODM_SetBBReg(pDM_Odm, ODM_REG_ANT_MAPPING1_11N , 0xFFFF, 0x0102); //antenna mapping table + +} + +VOID +odm_TRX_HWAntDiv_Init_88E( + IN PDM_ODM_T pDM_Odm +) +{ + u4Byte value32; + + #if (MP_DRIVER == 1) + pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV; + ODM_SetBBReg(pDM_Odm, ODM_REG_IGI_A_11N , BIT7, 0); // disable HW AntDiv + ODM_SetBBReg(pDM_Odm, ODM_REG_RX_ANT_CTRL_11N , BIT5|BIT4|BIT3, 0); //Default RX (0/1) + return; + #endif + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("***8188E AntDiv_Init => AntDivType=[CG_TRX_HW_ANTDIV (SPDT)]\n")); + + //MAC Setting + value32 = ODM_GetMACReg(pDM_Odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord); + ODM_SetMACReg(pDM_Odm, ODM_REG_ANTSEL_PIN_11N, bMaskDWord, value32|(BIT23|BIT25)); //Reg4C[25]=1, Reg4C[23]=1 for pin output + //Pin Settings + ODM_SetBBReg(pDM_Odm, ODM_REG_PIN_CTRL_11N , BIT9|BIT8, 0);//Reg870[8]=1'b0, Reg870[9]=1'b0 //antsel antselb by HW + ODM_SetBBReg(pDM_Odm, ODM_REG_RX_ANT_CTRL_11N , BIT10, 0); //Reg864[10]=1'b0 //antsel2 by HW + ODM_SetBBReg(pDM_Odm, ODM_REG_LNA_SWITCH_11N , BIT22, 0); //Regb2c[22]=1'b0 //disable CS/CG switch + ODM_SetBBReg(pDM_Odm, ODM_REG_LNA_SWITCH_11N , BIT31, 1); //Regb2c[31]=1'b1 //output at CG only + //OFDM Settings + ODM_SetBBReg(pDM_Odm, ODM_REG_ANTDIV_PARA1_11N , bMaskDWord, 0x000000a0); + //CCK Settings + ODM_SetBBReg(pDM_Odm, ODM_REG_BB_PWR_SAV4_11N , BIT7, 1); //Fix CCK PHY status report issue + ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_ANTDIV_PARA2_11N , BIT4, 1); //CCK complete HW AntDiv within 64 samples + + //antenna mapping table + if(!pDM_Odm->bIsMPChip) //testchip + { + ODM_SetBBReg(pDM_Odm, ODM_REG_RX_DEFUALT_A_11N , BIT10|BIT9|BIT8, 1); //Reg858[10:8]=3'b001 + ODM_SetBBReg(pDM_Odm, ODM_REG_RX_DEFUALT_A_11N , BIT13|BIT12|BIT11, 2); //Reg858[13:11]=3'b010 + } + else //MPchip + ODM_SetBBReg(pDM_Odm, ODM_REG_ANT_MAPPING1_11N , bMaskDWord, 0x0201); //Reg914=3'b010, Reg915=3'b001 +} + +VOID +odm_Smart_HWAntDiv_Init_88E( + IN PDM_ODM_T pDM_Odm +) +{ + u4Byte value32, i; + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + u4Byte AntCombination = 2; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("***8188E AntDiv_Init => AntDivType=[CG_TRX_SMART_ANTDIV]\n")); + +#if (MP_DRIVER == 1) + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("pDM_Odm->AntDivType: %d\n", pDM_Odm->AntDivType)); + return; +#endif + + for(i=0; i<6; i++) + { + pDM_FatTable->Bssid[i] = 0; + pDM_FatTable->antSumRSSI[i] = 0; + pDM_FatTable->antRSSIcnt[i] = 0; + pDM_FatTable->antAveRSSI[i] = 0; + } + pDM_FatTable->TrainIdx = 0; + pDM_FatTable->FAT_State = FAT_NORMAL_STATE; + + //MAC Setting + value32 = ODM_GetMACReg(pDM_Odm, 0x4c, bMaskDWord); + ODM_SetMACReg(pDM_Odm, 0x4c, bMaskDWord, value32|(BIT23|BIT25)); //Reg4C[25]=1, Reg4C[23]=1 for pin output + value32 = ODM_GetMACReg(pDM_Odm, 0x7B4, bMaskDWord); + ODM_SetMACReg(pDM_Odm, 0x7b4, bMaskDWord, value32|(BIT16|BIT17)); //Reg7B4[16]=1 enable antenna training, Reg7B4[17]=1 enable A2 match + //value32 = PlatformEFIORead4Byte(Adapter, 0x7B4); + //PlatformEFIOWrite4Byte(Adapter, 0x7b4, value32|BIT18); //append MACID in reponse packet + + //Match MAC ADDR + ODM_SetMACReg(pDM_Odm, 0x7b4, 0xFFFF, 0); + ODM_SetMACReg(pDM_Odm, 0x7b0, bMaskDWord, 0); + + ODM_SetBBReg(pDM_Odm, 0x870 , BIT9|BIT8, 0);//Reg870[8]=1'b0, Reg870[9]=1'b0 //antsel antselb by HW + ODM_SetBBReg(pDM_Odm, 0x864 , BIT10, 0); //Reg864[10]=1'b0 //antsel2 by HW + ODM_SetBBReg(pDM_Odm, 0xb2c , BIT22, 0); //Regb2c[22]=1'b0 //disable CS/CG switch + ODM_SetBBReg(pDM_Odm, 0xb2c , BIT31, 1); //Regb2c[31]=1'b1 //output at CG only + ODM_SetBBReg(pDM_Odm, 0xca4 , bMaskDWord, 0x000000a0); + + //antenna mapping table + if(AntCombination == 2) + { + if(!pDM_Odm->bIsMPChip) //testchip + { + ODM_SetBBReg(pDM_Odm, 0x858 , BIT10|BIT9|BIT8, 1); //Reg858[10:8]=3'b001 + ODM_SetBBReg(pDM_Odm, 0x858 , BIT13|BIT12|BIT11, 2); //Reg858[13:11]=3'b010 + } + else //MPchip + { + ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte0, 1); + ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte1, 2); + } + } + else if(AntCombination == 7) + { + if(!pDM_Odm->bIsMPChip) //testchip + { + ODM_SetBBReg(pDM_Odm, 0x858 , BIT10|BIT9|BIT8, 0); //Reg858[10:8]=3'b000 + ODM_SetBBReg(pDM_Odm, 0x858 , BIT13|BIT12|BIT11, 1); //Reg858[13:11]=3'b001 + ODM_SetBBReg(pDM_Odm, 0x878 , BIT16, 0); + ODM_SetBBReg(pDM_Odm, 0x858 , BIT15|BIT14, 2); //(Reg878[0],Reg858[14:15])=3'b010 + ODM_SetBBReg(pDM_Odm, 0x878 , BIT19|BIT18|BIT17, 3);//Reg878[3:1]=3b'011 + ODM_SetBBReg(pDM_Odm, 0x878 , BIT22|BIT21|BIT20, 4);//Reg878[6:4]=3b'100 + ODM_SetBBReg(pDM_Odm, 0x878 , BIT25|BIT24|BIT23, 5);//Reg878[9:7]=3b'101 + ODM_SetBBReg(pDM_Odm, 0x878 , BIT28|BIT27|BIT26, 6);//Reg878[12:10]=3b'110 + ODM_SetBBReg(pDM_Odm, 0x878 , BIT31|BIT30|BIT29, 7);//Reg878[15:13]=3b'111 + } + else //MPchip + { + ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte0, 0); + ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte1, 1); + ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte2, 2); + ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte3, 3); + ODM_SetBBReg(pDM_Odm, 0x918 , bMaskByte0, 4); + ODM_SetBBReg(pDM_Odm, 0x918 , bMaskByte1, 5); + ODM_SetBBReg(pDM_Odm, 0x918 , bMaskByte2, 6); + ODM_SetBBReg(pDM_Odm, 0x918 , bMaskByte3, 7); + } + } + + //Default Ant Setting when no fast training + ODM_SetBBReg(pDM_Odm, 0x80c , BIT21, 1); //Reg80c[21]=1'b1 //from TX Info + ODM_SetBBReg(pDM_Odm, 0x864 , BIT5|BIT4|BIT3, 0); //Default RX + ODM_SetBBReg(pDM_Odm, 0x864 , BIT8|BIT7|BIT6, 1); //Optional RX + //ODM_SetBBReg(pDM_Odm, 0x860 , BIT14|BIT13|BIT12, 1); //Default TX + + //Enter Traing state + ODM_SetBBReg(pDM_Odm, 0x864 , BIT2|BIT1|BIT0, (AntCombination-1)); //Reg864[2:0]=3'd6 //ant combination=reg864[2:0]+1 + //ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 0); //RegC50[7]=1'b0 //disable HW AntDiv + //ODM_SetBBReg(pDM_Odm, 0xe08 , BIT16, 0); //RegE08[16]=1'b0 //disable fast training + //ODM_SetBBReg(pDM_Odm, 0xe08 , BIT16, 1); //RegE08[16]=1'b1 //enable fast training + ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 1); //RegC50[7]=1'b1 //enable HW AntDiv + + //SW Control + //PHY_SetBBReg(Adapter, 0x864 , BIT10, 1); + //PHY_SetBBReg(Adapter, 0x870 , BIT9, 1); + //PHY_SetBBReg(Adapter, 0x870 , BIT8, 1); + //PHY_SetBBReg(Adapter, 0x864 , BIT11, 1); + //PHY_SetBBReg(Adapter, 0x860 , BIT9, 0); + //PHY_SetBBReg(Adapter, 0x860 , BIT8, 0); +} +#endif //#if (RTL8188E_SUPPORT == 1) + + +#if (RTL8192E_SUPPORT == 1) +VOID +odm_RX_HWAntDiv_Init_92E( + IN PDM_ODM_T pDM_Odm +) +{ + +#if (MP_DRIVER == 1) + //pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV; + odm_AntDiv_on_off(pDM_Odm, ANTDIV_OFF); + ODM_SetBBReg(pDM_Odm, 0xc50 , BIT8, 0); //r_rxdiv_enable_anta Regc50[8]=1'b0 0: control by c50[9] + ODM_SetBBReg(pDM_Odm, 0xc50 , BIT9, 1); // 1:CG, 0:CS + return; +#endif + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("***8192E AntDiv_Init => AntDivType=[CGCS_RX_HW_ANTDIV]\n")); + + //Pin Settings + ODM_SetBBReg(pDM_Odm, 0x870 , BIT8, 0);//Reg870[8]=1'b0, // "antsel" is controled by HWs + ODM_SetBBReg(pDM_Odm, 0xc50 , BIT8, 1); //Regc50[8]=1'b1 //" CS/CG switching" is controled by HWs + + //Mapping table + ODM_SetBBReg(pDM_Odm, 0x914 , 0xFFFF, 0x0100); //antenna mapping table + + //OFDM Settings + ODM_SetBBReg(pDM_Odm, 0xca4 , 0x7FF, 0xA0); //thershold + ODM_SetBBReg(pDM_Odm, 0xca4 , 0x7FF000, 0x0); //bias + + //CCK Settings + ODM_SetBBReg(pDM_Odm, 0xa04 , 0xF000000, 0); //Select which path to receive for CCK_1 & CCK_2 + ODM_SetBBReg(pDM_Odm, 0xb34 , BIT30, 1); //(92E) ANTSEL_CCK_opt = r_en_antsel_cck? ANTSEL_CCK: 1'b0 + ODM_SetBBReg(pDM_Odm, 0xa74 , BIT7, 1); //Fix CCK PHY status report issue + ODM_SetBBReg(pDM_Odm, 0xa0c , BIT4, 1); //CCK complete HW AntDiv within 64 samples +} + +VOID +odm_TRX_HWAntDiv_Init_92E( + IN PDM_ODM_T pDM_Odm +) +{ + +#if (MP_DRIVER == 1) + //pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV; + odm_AntDiv_on_off(pDM_Odm, ANTDIV_OFF); + ODM_SetBBReg(pDM_Odm, 0xc50 , BIT8, 0); //r_rxdiv_enable_anta Regc50[8]=1'b0 0: control by c50[9] + ODM_SetBBReg(pDM_Odm, 0xc50 , BIT9, 1); // 1:CG, 0:CS + return; +#endif + +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + pDM_Odm->antdiv_rssi=0; +#endif + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("***8192E AntDiv_Init => AntDivType=[CG_TRX_HW_ANTDIV]\n")); + + //3 --RFE pin setting--------- + //[MAC] + ODM_SetMACReg(pDM_Odm, 0x38, BIT11, 1); //DBG PAD Driving control (GPIO 8) + ODM_SetMACReg(pDM_Odm, 0x4c, BIT23, 0); //path-A , RFE_CTRL_3 & RFE_CTRL_4 + //[BB] + ODM_SetBBReg(pDM_Odm, 0x944 , BIT4|BIT3, 0x3); //RFE_buffer + ODM_SetBBReg(pDM_Odm, 0x940 , BIT7|BIT6, 0x0); // r_rfe_path_sel_ (RFE_CTRL_3) + ODM_SetBBReg(pDM_Odm, 0x940 , BIT9|BIT8, 0x0); // r_rfe_path_sel_ (RFE_CTRL_4) + ODM_SetBBReg(pDM_Odm, 0x944 , BIT31, 0); //RFE_buffer + ODM_SetBBReg(pDM_Odm, 0x92C , BIT3, 0); //rfe_inv (RFE_CTRL_3) + ODM_SetBBReg(pDM_Odm, 0x92C , BIT4, 1); //rfe_inv (RFE_CTRL_4) + ODM_SetBBReg(pDM_Odm, 0x930 , 0xFF000, 0x88); //path-A , RFE_CTRL_3 & 4=> ANTSEL[0] + //3 ------------------------- + + //Pin Settings + ODM_SetBBReg(pDM_Odm, 0xC50 , BIT8, 0); //path-A //disable CS/CG switch + ODM_SetBBReg(pDM_Odm, 0xC50 , BIT9, 1); //path-A //output at CG only + ODM_SetBBReg(pDM_Odm, 0x870 , BIT9|BIT8, 0); //path-A //antsel antselb by HW + ODM_SetBBReg(pDM_Odm, 0xB38 , BIT10, 0); //path-A //antsel2 by HW + + //Mapping table + ODM_SetBBReg(pDM_Odm, 0x914 , 0xFFFF, 0x0100); //antenna mapping table + + //OFDM Settings + ODM_SetBBReg(pDM_Odm, 0xca4 , 0x7FF, 0xA0); //thershold + ODM_SetBBReg(pDM_Odm, 0xca4 , 0x7FF000, 0x0); //bias + + //CCK Settings + ODM_SetBBReg(pDM_Odm, 0xa04 , 0xF000000, 0); //Select which path to receive for CCK_1 & CCK_2 + ODM_SetBBReg(pDM_Odm, 0xb34 , BIT30, 1); //(92E) ANTSEL_CCK_opt = r_en_antsel_cck? ANTSEL_CCK: 1'b0 + ODM_SetBBReg(pDM_Odm, 0xa74 , BIT7, 1); //Fix CCK PHY status report issue + ODM_SetBBReg(pDM_Odm, 0xa0c , BIT4, 1); //CCK complete HW AntDiv within 64 samples + + //Timming issue + ODM_SetBBReg(pDM_Odm, 0xE20 , BIT23|BIT22|BIT21|BIT20, 8); //keep antidx after tx for ACK ( unit x 32 mu sec) +} + +VOID +odm_Smart_HWAntDiv_Init_92E( + IN PDM_ODM_T pDM_Odm +) +{ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("***8188E AntDiv_Init => AntDivType=[CG_TRX_SMART_ANTDIV]\n")); +} +#endif //#if (RTL8192E_SUPPORT == 1) + + +#if (RTL8723B_SUPPORT == 1) +VOID +odm_TRX_HWAntDiv_Init_8723B( + IN PDM_ODM_T pDM_Odm +) +{ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("***8723B AntDiv_Init => AntDivType=[CG_TRX_HW_ANTDIV(DPDT)]\n")); + + //Mapping Table + ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte0, 0); + ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte1, 1); + + //OFDM HW AntDiv Parameters + ODM_SetBBReg(pDM_Odm, 0xCA4 , 0x7FF, 0xa0); //thershold + ODM_SetBBReg(pDM_Odm, 0xCA4 , 0x7FF000, 0x00); //bias + + //CCK HW AntDiv Parameters + ODM_SetBBReg(pDM_Odm, 0xA74 , BIT7, 1); //patch for clk from 88M to 80M + ODM_SetBBReg(pDM_Odm, 0xA0C , BIT4, 1); //do 64 samples + + //BT Coexistence + ODM_SetBBReg(pDM_Odm, 0x864, BIT12, 0); //keep antsel_map when GNT_BT = 1 + ODM_SetBBReg(pDM_Odm, 0x874 , BIT23, 0); //Disable hw antsw & fast_train.antsw when GNT_BT=1 + + //Output Pin Settings + ODM_SetBBReg(pDM_Odm, 0x870 , BIT8, 0); // + + ODM_SetBBReg(pDM_Odm, 0x948 , BIT6, 0); //WL_BB_SEL_BTG_TRXG_anta, (1: HW CTRL 0: SW CTRL) + ODM_SetBBReg(pDM_Odm, 0x948 , BIT7, 0); + + ODM_SetMACReg(pDM_Odm, 0x40 , BIT3, 1); + ODM_SetMACReg(pDM_Odm, 0x38 , BIT11, 1); + ODM_SetMACReg(pDM_Odm, 0x4C , BIT24|BIT23, 2); //select DPDT_P and DPDT_N as output pin + + ODM_SetBBReg(pDM_Odm, 0x944 , BIT0|BIT1, 3); //in/out + ODM_SetBBReg(pDM_Odm, 0x944 , BIT31, 0); // + + ODM_SetBBReg(pDM_Odm, 0x92C , BIT1, 0); //DPDT_P non-inverse + ODM_SetBBReg(pDM_Odm, 0x92C , BIT0, 1); //DPDT_N inverse + + ODM_SetBBReg(pDM_Odm, 0x930 , 0xF0, 8); // DPDT_P = ANTSEL[0] + ODM_SetBBReg(pDM_Odm, 0x930 , 0xF, 8); // DPDT_N = ANTSEL[0] + + //Timming issue + ODM_SetBBReg(pDM_Odm, 0xE20 , BIT23|BIT22|BIT21|BIT20, 8); //keep antidx after tx for ACK ( unit x 32 mu sec) + + //2 [--For HW Bug Setting] + if(pDM_Odm->AntType == ODM_AUTO_ANT) + ODM_SetBBReg(pDM_Odm, 0xA00 , BIT15, 0); //CCK AntDiv function block enable + + //ODM_SetBBReg(pDM_Odm, 0x80C , BIT21, 0); //TX Ant by Reg + + +} + + + +VOID +odm_S0S1_SWAntDiv_Init_8723B( + IN PDM_ODM_T pDM_Odm +) +{ + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("***8723B AntDiv_Init => AntDivType=[ S0S1_SW_AntDiv] \n")); + + //Mapping Table + ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte0, 0); + ODM_SetBBReg(pDM_Odm, 0x914 , bMaskByte1, 1); + + //Output Pin Settings + //ODM_SetBBReg(pDM_Odm, 0x948 , BIT6, 0x1); + ODM_SetBBReg(pDM_Odm, 0x870 , BIT9|BIT8, 0); + + pDM_FatTable->bBecomeLinked =FALSE; + pDM_SWAT_Table->try_flag = 0xff; + pDM_SWAT_Table->Double_chk_flag = 0; + pDM_SWAT_Table->TrafficLoad = TRAFFIC_LOW; + + //Timming issue + ODM_SetBBReg(pDM_Odm, 0xE20 , BIT23|BIT22|BIT21|BIT20, 8); //keep antidx after tx for ACK ( unit x 32 mu sec) + + //2 [--For HW Bug Setting] + ODM_SetBBReg(pDM_Odm, 0x80C , BIT21, 0); //TX Ant by Reg + +} +#endif //#if (RTL8723B_SUPPORT == 1) + + +#if (RTL8821A_SUPPORT == 1) +VOID +odm_TRX_HWAntDiv_Init_8821A( + IN PDM_ODM_T pDM_Odm +) +{ + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + + PADAPTER pAdapter = pDM_Odm->Adapter; + pAdapter->HalFunc.GetHalDefVarHandler(pAdapter, HAL_DEF_5G_ANT_SELECT, (pu1Byte)(&pDM_Odm->AntType)); +#else + pDM_Odm->AntType = ODM_AUTO_ANT; +#endif + pAdapter->HalFunc.GetHalDefVarHandler(pAdapter, HAL_DEF_5G_ANT_SELECT, (pu1Byte)(&pDM_Odm->AntType)); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("***8821A AntDiv_Init => AntDivType=[ CG_TRX_HW_ANTDIV (DPDT)] \n")); + + //Output Pin Settings + ODM_SetMACReg(pDM_Odm, 0x4C , BIT25, 0); + + ODM_SetMACReg(pDM_Odm, 0x64 , BIT29, 1); //PAPE by WLAN control + ODM_SetMACReg(pDM_Odm, 0x64 , BIT28, 1); //LNAON by WLAN control + + ODM_SetBBReg(pDM_Odm, 0xCB0 , bMaskDWord, 0x77775745); + ODM_SetBBReg(pDM_Odm, 0xCB8 , BIT16, 0); + + ODM_SetMACReg(pDM_Odm, 0x4C , BIT23, 0); //select DPDT_P and DPDT_N as output pin + ODM_SetMACReg(pDM_Odm, 0x4C , BIT24, 1); //by WLAN control + ODM_SetBBReg(pDM_Odm, 0xCB4 , 0xF, 8); // DPDT_P = ANTSEL[0] + ODM_SetBBReg(pDM_Odm, 0xCB4 , 0xF0, 8); // DPDT_N = ANTSEL[0] + ODM_SetBBReg(pDM_Odm, 0xCB4 , BIT29, 0); //DPDT_P non-inverse + ODM_SetBBReg(pDM_Odm, 0xCB4 , BIT28, 1); //DPDT_N inverse + + //Mapping Table + ODM_SetBBReg(pDM_Odm, 0xCA4 , bMaskByte0, 0); + ODM_SetBBReg(pDM_Odm, 0xCA4 , bMaskByte1, 1); + + //Set ANT1_8821A as MAIN_ANT + if((pDM_Odm->AntType == ODM_FIX_MAIN_ANT) || (pDM_Odm->AntType == ODM_AUTO_ANT)) + ODM_UpdateRxIdleAnt(pDM_Odm, MAIN_ANT); + else + ODM_UpdateRxIdleAnt(pDM_Odm, AUX_ANT); + + //OFDM HW AntDiv Parameters + ODM_SetBBReg(pDM_Odm, 0x8D4 , 0x7FF, 0xA0); //thershold + ODM_SetBBReg(pDM_Odm, 0x8D4 , 0x7FF000, 0x10); //bias + + //CCK HW AntDiv Parameters + ODM_SetBBReg(pDM_Odm, 0xA74 , BIT7, 1); //patch for clk from 88M to 80M + ODM_SetBBReg(pDM_Odm, 0xA0C , BIT4, 1); //do 64 samples + + ODM_SetBBReg(pDM_Odm, 0x800 , BIT25, 0); //CCK AntDiv function block enable + + //BT Coexistence + ODM_SetBBReg(pDM_Odm, 0xCAC , BIT9, 1); //keep antsel_map when GNT_BT = 1 + ODM_SetBBReg(pDM_Odm, 0x804 , BIT4, 1); //Disable hw antsw & fast_train.antsw when GNT_BT=1 + + //Timming issue + ODM_SetBBReg(pDM_Odm, 0x818 , BIT23|BIT22|BIT21|BIT20, 8); //keep antidx after tx for ACK ( unit x 32 mu sec) + ODM_SetBBReg(pDM_Odm, 0x8CC , BIT20|BIT19|BIT18, 3); //settling time of antdiv by RF LNA = 100ns + + //response TX ant by RX ant + ODM_SetMACReg(pDM_Odm, 0x668 , BIT3, 1); + + //2 [--For HW Bug Setting] + if(pDM_Odm->AntType == ODM_AUTO_ANT) + ODM_SetBBReg(pDM_Odm, 0x800 , BIT25, 0); //CCK AntDiv function block enable + +} + +VOID +odm_S0S1_SWAntDiv_Init_8821A( + IN PDM_ODM_T pDM_Odm +) +{ + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + + + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + + PADAPTER pAdapter = pDM_Odm->Adapter; + pAdapter->HalFunc.GetHalDefVarHandler(pAdapter, HAL_DEF_5G_ANT_SELECT, (pu1Byte)(&pDM_Odm->AntType)); +#else + pDM_Odm->AntType = ODM_AUTO_ANT; +#endif + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("***8821A AntDiv_Init => AntDivType=[ S0S1_SW_AntDiv] \n")); + + //Output Pin Settings + ODM_SetMACReg(pDM_Odm, 0x4C , BIT25, 0); + + ODM_SetMACReg(pDM_Odm, 0x64 , BIT29, 1); //PAPE by WLAN control + ODM_SetMACReg(pDM_Odm, 0x64 , BIT28, 1); //LNAON by WLAN control + + ODM_SetBBReg(pDM_Odm, 0xCB0 , bMaskDWord, 0x77775745); + ODM_SetBBReg(pDM_Odm, 0xCB8 , BIT16, 0); + + ODM_SetMACReg(pDM_Odm, 0x4C , BIT23, 0); //select DPDT_P and DPDT_N as output pin + ODM_SetMACReg(pDM_Odm, 0x4C , BIT24, 1); //by WLAN control + ODM_SetBBReg(pDM_Odm, 0xCB4 , 0xF, 8); // DPDT_P = ANTSEL[0] + ODM_SetBBReg(pDM_Odm, 0xCB4 , 0xF0, 8); // DPDT_N = ANTSEL[0] + ODM_SetBBReg(pDM_Odm, 0xCB4 , BIT29, 0); //DPDT_P non-inverse + ODM_SetBBReg(pDM_Odm, 0xCB4 , BIT28, 1); //DPDT_N inverse + + //Mapping Table + ODM_SetBBReg(pDM_Odm, 0xCA4 , bMaskByte0, 0); + ODM_SetBBReg(pDM_Odm, 0xCA4 , bMaskByte1, 1); + + //Set ANT1_8821A as MAIN_ANT + if((pDM_Odm->AntType == ODM_FIX_MAIN_ANT) || (pDM_Odm->AntType == ODM_AUTO_ANT)) + ODM_UpdateRxIdleAnt(pDM_Odm, MAIN_ANT); + else + ODM_UpdateRxIdleAnt(pDM_Odm, AUX_ANT); + + //OFDM HW AntDiv Parameters + ODM_SetBBReg(pDM_Odm, 0x8D4 , 0x7FF, 0xA0); //thershold + ODM_SetBBReg(pDM_Odm, 0x8D4 , 0x7FF000, 0x10); //bias + + //CCK HW AntDiv Parameters + ODM_SetBBReg(pDM_Odm, 0xA74 , BIT7, 1); //patch for clk from 88M to 80M + ODM_SetBBReg(pDM_Odm, 0xA0C , BIT4, 1); //do 64 samples + + ODM_SetBBReg(pDM_Odm, 0x800 , BIT25, 0); //CCK AntDiv function block enable + + //BT Coexistence + ODM_SetBBReg(pDM_Odm, 0xCAC , BIT9, 1); //keep antsel_map when GNT_BT = 1 + ODM_SetBBReg(pDM_Odm, 0x804 , BIT4, 1); //Disable hw antsw & fast_train.antsw when GNT_BT=1 + + //Timming issue + ODM_SetBBReg(pDM_Odm, 0x818 , BIT23|BIT22|BIT21|BIT20, 8); //keep antidx after tx for ACK ( unit x 32 mu sec) + ODM_SetBBReg(pDM_Odm, 0x8CC , BIT20|BIT19|BIT18, 3); //settling time of antdiv by RF LNA = 100ns + + //response TX ant by RX ant + ODM_SetMACReg(pDM_Odm, 0x668 , BIT3, 1); + + //2 [--For HW Bug Setting] + if(pDM_Odm->AntType == ODM_AUTO_ANT) + ODM_SetBBReg(pDM_Odm, 0x800 , BIT25, 0); //CCK AntDiv function block enable + + + ODM_SetBBReg(pDM_Odm, 0x900 , BIT18, 0); + + pDM_SWAT_Table->try_flag = 0xff; + pDM_SWAT_Table->Double_chk_flag = 0; + pDM_SWAT_Table->TrafficLoad = TRAFFIC_LOW; + pDM_SWAT_Table->CurAntenna = MAIN_ANT; + pDM_SWAT_Table->PreAntenna = MAIN_ANT; + pDM_SWAT_Table->SWAS_NoLink_State = 0; + +} +#endif //#if (RTL8821A_SUPPORT == 1) + +#if (RTL8881A_SUPPORT == 1) +VOID +odm_RX_HWAntDiv_Init_8881A( + IN PDM_ODM_T pDM_Odm +) +{ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("***8881A AntDiv_Init => AntDivType=[ CGCS_RX_HW_ANTDIV] \n")); + +} + +VOID +odm_TRX_HWAntDiv_Init_8881A( + IN PDM_ODM_T pDM_Odm +) +{ + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("***8881A AntDiv_Init => AntDivType=[ CG_TRX_HW_ANTDIV (SPDT)] \n")); + + //Output Pin Settings + // [SPDT related] + ODM_SetMACReg(pDM_Odm, 0x4C , BIT25, 0); + ODM_SetMACReg(pDM_Odm, 0x4C , BIT26, 0); + ODM_SetBBReg(pDM_Odm, 0xCB4 , BIT31, 0); //delay buffer + ODM_SetBBReg(pDM_Odm, 0xCB4 , BIT22, 0); + ODM_SetBBReg(pDM_Odm, 0xCB4 , BIT24, 1); + ODM_SetBBReg(pDM_Odm, 0xCB0 , 0xF00, 8); // DPDT_P = ANTSEL[0] + ODM_SetBBReg(pDM_Odm, 0xCB0 , 0xF0000, 8); // DPDT_N = ANTSEL[0] + + //Mapping Table + ODM_SetBBReg(pDM_Odm, 0xCA4 , bMaskByte0, 0); + ODM_SetBBReg(pDM_Odm, 0xCA4 , bMaskByte1, 1); + + //OFDM HW AntDiv Parameters + ODM_SetBBReg(pDM_Odm, 0x8D4 , 0x7FF, 0xA0); //thershold + ODM_SetBBReg(pDM_Odm, 0x8D4 , 0x7FF000, 0x0); //bias + ODM_SetBBReg(pDM_Odm, 0x8CC , BIT20|BIT19|BIT18, 3); //settling time of antdiv by RF LNA = 100ns + + //CCK HW AntDiv Parameters + ODM_SetBBReg(pDM_Odm, 0xA74 , BIT7, 1); //patch for clk from 88M to 80M + ODM_SetBBReg(pDM_Odm, 0xA0C , BIT4, 1); //do 64 samples + + //Timming issue + ODM_SetBBReg(pDM_Odm, 0x818 , BIT23|BIT22|BIT21|BIT20, 8); //keep antidx after tx for ACK ( unit x 32 mu sec) + + //2 [--For HW Bug Setting] + + ODM_SetBBReg(pDM_Odm, 0x900 , BIT18, 0); //TX Ant by Reg // A-cut bug +} + +#endif //#if (RTL8881A_SUPPORT == 1) + + +#if (RTL8812A_SUPPORT == 1) +VOID +odm_TRX_HWAntDiv_Init_8812A( + IN PDM_ODM_T pDM_Odm +) +{ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("***8812A AntDiv_Init => AntDivType=[ CG_TRX_HW_ANTDIV (SPDT)] \n")); + + //3 //3 --RFE pin setting--------- + //[BB] + ODM_SetBBReg(pDM_Odm, 0x900 , BIT10|BIT9|BIT8, 0x0); //disable SW switch + ODM_SetBBReg(pDM_Odm, 0x900 , BIT17|BIT16, 0x0); + ODM_SetBBReg(pDM_Odm, 0x974 , BIT7|BIT6, 0x3); // in/out + ODM_SetBBReg(pDM_Odm, 0xCB4 , BIT31, 0); //delay buffer + ODM_SetBBReg(pDM_Odm, 0xCB4 , BIT26, 0); + ODM_SetBBReg(pDM_Odm, 0xCB4 , BIT27, 1); + ODM_SetBBReg(pDM_Odm, 0xCB0 , 0xF000000, 8); // DPDT_P = ANTSEL[0] + ODM_SetBBReg(pDM_Odm, 0xCB0 , 0xF0000000, 8); // DPDT_N = ANTSEL[0] + //3 ------------------------- + + //Mapping Table + ODM_SetBBReg(pDM_Odm, 0xCA4 , bMaskByte0, 0); + ODM_SetBBReg(pDM_Odm, 0xCA4 , bMaskByte1, 1); + + //OFDM HW AntDiv Parameters + ODM_SetBBReg(pDM_Odm, 0x8D4 , 0x7FF, 0xA0); //thershold + ODM_SetBBReg(pDM_Odm, 0x8D4 , 0x7FF000, 0x0); //bias + ODM_SetBBReg(pDM_Odm, 0x8CC , BIT20|BIT19|BIT18, 3); //settling time of antdiv by RF LNA = 100ns + + //CCK HW AntDiv Parameters + ODM_SetBBReg(pDM_Odm, 0xA74 , BIT7, 1); //patch for clk from 88M to 80M + ODM_SetBBReg(pDM_Odm, 0xA0C , BIT4, 1); //do 64 samples + + //Timming issue + ODM_SetBBReg(pDM_Odm, 0x818 , BIT23|BIT22|BIT21|BIT20, 8); //keep antidx after tx for ACK ( unit x 32 mu sec) + + //2 [--For HW Bug Setting] + + ODM_SetBBReg(pDM_Odm, 0x900 , BIT18, 0); //TX Ant by Reg // A-cut bug + +} + +#endif //#if (RTL8812A_SUPPORT == 1) + +VOID +odm_HW_AntDiv( + IN PDM_ODM_T pDM_Odm +) +{ + u4Byte i,MinMaxRSSI=0xFF, AntDivMaxRSSI=0, MaxRSSI=0, LocalMaxRSSI; + u4Byte Main_RSSI, Aux_RSSI, pkt_ratio_m=0, pkt_ratio_a=0,pkt_threshold=10; + u1Byte RxIdleAnt=0, TargetAnt=7; + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + PSTA_INFO_T pEntry; + + if(!pDM_Odm->bLinked) //bLinked==False + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[No Link!!!]\n")); + + #if(DM_ODM_SUPPORT_TYPE == ODM_AP) + if (pDM_Odm->antdiv_rssi) + panic_printk("[No Link!!!]\n"); + #endif + + if(pDM_FatTable->bBecomeLinked == TRUE) + { + odm_AntDiv_on_off(pDM_Odm, ANTDIV_OFF); + ODM_UpdateRxIdleAnt(pDM_Odm, MAIN_ANT); + + pDM_FatTable->bBecomeLinked = pDM_Odm->bLinked; + } + return; + } + else + { + if(pDM_FatTable->bBecomeLinked ==FALSE) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[Linked !!!]\n")); + odm_AntDiv_on_off(pDM_Odm, ANTDIV_ON); + if(pDM_Odm->SupportICType == ODM_RTL8821 ) + ODM_SetBBReg(pDM_Odm, 0x800 , BIT25, 0); //CCK AntDiv function disable + + #if(DM_ODM_SUPPORT_TYPE == ODM_AP) + else if(pDM_Odm->SupportICType == ODM_RTL8881 ) + ODM_SetBBReg(pDM_Odm, 0x800 , BIT25, 0); //CCK AntDiv function disable + #endif + + else if(pDM_Odm->SupportICType == ODM_RTL8723B ||pDM_Odm->SupportICType == ODM_RTL8812) + ODM_SetBBReg(pDM_Odm, 0xA00 , BIT15, 0); //CCK AntDiv function disable + + pDM_FatTable->bBecomeLinked = pDM_Odm->bLinked; + + if(pDM_Odm->SupportICType==ODM_RTL8723B && pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) + { + ODM_SetBBReg(pDM_Odm, 0x930 , 0xF0, 8); // DPDT_P = ANTSEL[0] // for 8723B AntDiv function patch. BB Dino 130412 + ODM_SetBBReg(pDM_Odm, 0x930 , 0xF, 8); // DPDT_N = ANTSEL[0] + } + } + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("\n[HW AntDiv] Start =>\n")); + + for (i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++) + { + pEntry = pDM_Odm->pODM_StaInfo[i]; + if(IS_STA_VALID(pEntry)) + { + //2 Caculate RSSI per Antenna + Main_RSSI = (pDM_FatTable->MainAnt_Cnt[i]!=0)?(pDM_FatTable->MainAnt_Sum[i]/pDM_FatTable->MainAnt_Cnt[i]):0; + Aux_RSSI = (pDM_FatTable->AuxAnt_Cnt[i]!=0)?(pDM_FatTable->AuxAnt_Sum[i]/pDM_FatTable->AuxAnt_Cnt[i]):0; + TargetAnt = (Main_RSSI==Aux_RSSI)?pDM_FatTable->RxIdleAnt:((Main_RSSI>=Aux_RSSI)?MAIN_ANT:AUX_ANT); + /* + if( pDM_FatTable->MainAnt_Cnt[i]!=0 && pDM_FatTable->AuxAnt_Cnt[i]!=0 ) + { + pkt_ratio_m=( pDM_FatTable->MainAnt_Cnt[i] / pDM_FatTable->AuxAnt_Cnt[i] ); + pkt_ratio_a=( pDM_FatTable->AuxAnt_Cnt[i] / pDM_FatTable->MainAnt_Cnt[i] ); + + if (pkt_ratio_m >= pkt_threshold) + TargetAnt=MAIN_ANT; + + else if(pkt_ratio_a >= pkt_threshold) + TargetAnt=AUX_ANT; + } + */ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("*** SupportICType=[%u] \n",pDM_Odm->SupportICType)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("*** Main_Cnt = (( %u )) , Main_RSSI= (( %u )) \n", pDM_FatTable->MainAnt_Cnt[i], Main_RSSI)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("*** Aux_Cnt = (( %u )) , Aux_RSSI = (( %u )) \n", pDM_FatTable->AuxAnt_Cnt[i] , Aux_RSSI )); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("*** MAC ID:[ %u ] , TargetAnt = (( %s )) \n", i ,( TargetAnt ==MAIN_ANT)?"MAIN_ANT":"AUX_ANT")); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("*** Phy_AntSel_A=[ %d, %d, %d] \n",((pDM_Odm->DM_FatTable.antsel_rx_keep_0)&BIT2)>>2, + ((pDM_Odm->DM_FatTable.antsel_rx_keep_0)&BIT1) >>1, ((pDM_Odm->DM_FatTable.antsel_rx_keep_0)&BIT0))); + #if(DM_ODM_SUPPORT_TYPE == ODM_AP) + if (pDM_Odm->antdiv_rssi) + { + panic_printk("*** SupportICType=[%lu] \n",pDM_Odm->SupportICType); + //panic_printk("*** Phy_AntSel_A=[ %d, %d, %d] \n",((pDM_Odm->DM_FatTable.antsel_rx_keep_0)&BIT2)>>2, + // ((pDM_Odm->DM_FatTable.antsel_rx_keep_0)&BIT1) >>1, ((pDM_Odm->DM_FatTable.antsel_rx_keep_0)&BIT0)); + //panic_printk("*** Phy_AntSel_B=[ %d, %d, %d] \n",((pDM_Odm->DM_FatTable.antsel_rx_keep_1)&BIT2)>>2, + // ((pDM_Odm->DM_FatTable.antsel_rx_keep_1)&BIT1) >>1, ((pDM_Odm->DM_FatTable.antsel_rx_keep_1)&BIT0)) + panic_printk("*** Client[ %lu ] , Main_Cnt = (( %lu )) , Main_RSSI= (( %lu )) \n",i, pDM_FatTable->MainAnt_Cnt[i], Main_RSSI); + panic_printk("*** Client[ %lu ] , Aux_Cnt = (( %lu )) , Aux_RSSI = (( %lu )) \n" ,i, pDM_FatTable->AuxAnt_Cnt[i] , Aux_RSSI); + } + #endif + + + LocalMaxRSSI = (Main_RSSI>Aux_RSSI)?Main_RSSI:Aux_RSSI; + //2 Select MaxRSSI for DIG + if((LocalMaxRSSI > AntDivMaxRSSI) && (LocalMaxRSSI < 40)) + AntDivMaxRSSI = LocalMaxRSSI; + if(LocalMaxRSSI > MaxRSSI) + MaxRSSI = LocalMaxRSSI; + + //2 Select RX Idle Antenna + if ( (LocalMaxRSSI != 0) && (LocalMaxRSSI < MinMaxRSSI) ) + { + RxIdleAnt = TargetAnt; + MinMaxRSSI = LocalMaxRSSI; + } + /* + if((pDM_FatTable->RxIdleAnt == MAIN_ANT) && (Main_RSSI == 0)) + Main_RSSI = Aux_RSSI; + else if((pDM_FatTable->RxIdleAnt == AUX_ANT) && (Aux_RSSI == 0)) + Aux_RSSI = Main_RSSI; + + LocalMinRSSI = (Main_RSSI>Aux_RSSI)?Aux_RSSI:Main_RSSI; + if(LocalMinRSSI < MinRSSI) + { + MinRSSI = LocalMinRSSI; + RxIdleAnt = TargetAnt; + } + */ + //2 Select TX Antenna + + #if TX_BY_REG + + #else + if(pDM_Odm->AntDivType != CGCS_RX_HW_ANTDIV) + odm_UpdateTxAnt(pDM_Odm, TargetAnt, i); + #endif + + } + pDM_FatTable->MainAnt_Sum[i] = 0; + pDM_FatTable->AuxAnt_Sum[i] = 0; + pDM_FatTable->MainAnt_Cnt[i] = 0; + pDM_FatTable->AuxAnt_Cnt[i] = 0; + } + + //2 Set RX Idle Antenna + ODM_UpdateRxIdleAnt(pDM_Odm, RxIdleAnt); + + #if(DM_ODM_SUPPORT_TYPE == ODM_AP) + if (pDM_Odm->antdiv_rssi) + panic_printk("*** RxIdleAnt = (( %s )) \n \n", ( RxIdleAnt ==MAIN_ANT)?"MAIN_ANT":"AUX_ANT"); + #endif + + pDM_DigTable->AntDiv_RSSI_max = AntDivMaxRSSI; + pDM_DigTable->RSSI_max = MaxRSSI; +} + + + +#if (RTL8723B_SUPPORT == 1)||(RTL8821A_SUPPORT == 1) +VOID +odm_S0S1_SwAntDiv( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Step + ) +{ + u4Byte i,MinMaxRSSI=0xFF, LocalMaxRSSI,LocalMinRSSI; + u4Byte Main_RSSI, Aux_RSSI; + u1Byte reset_period=10, SWAntDiv_threshold=35; + u1Byte HighTraffic_TrainTime_U=0x32,HighTraffic_TrainTime_L,Train_time_temp; + u1Byte LowTraffic_TrainTime_U=200,LowTraffic_TrainTime_L; + u1Byte RxIdleAnt, TargetAnt, nextAnt; + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + PSTA_INFO_T pEntry=NULL; + //static u1Byte reset_idx; + u4Byte value32; + PADAPTER Adapter = pDM_Odm->Adapter; + u8Byte curTxOkCnt=0, curRxOkCnt=0,TxCntOffset, RxCntOffset; + + if(!pDM_Odm->bLinked) //bLinked==False + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[No Link!!!]\n")); + if(pDM_FatTable->bBecomeLinked == TRUE) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Set REG 948[9:6]=0x0 \n")); + if(pDM_Odm->SupportICType == ODM_RTL8723B) + ODM_SetBBReg(pDM_Odm, 0x948 , BIT9|BIT8|BIT7|BIT6, 0x0); + + pDM_FatTable->bBecomeLinked = pDM_Odm->bLinked; + } + return; + } + else + { + if(pDM_FatTable->bBecomeLinked ==FALSE) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[Linked !!!]\n")); + + if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + value32 = ODM_GetBBReg(pDM_Odm, 0x864, BIT5|BIT4|BIT3); + + if (value32==0x0) + ODM_UpdateRxIdleAnt(pDM_Odm, MAIN_ANT); + else if (value32==0x1) + ODM_UpdateRxIdleAnt(pDM_Odm, AUX_ANT); + + ODM_SetBBReg(pDM_Odm, 0x948 , BIT6, 0x1); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Set REG 948[6]=0x1 , Set REG 864[5:3]=0x%x \n",value32 )); + } + + pDM_SWAT_Table->lastTxOkCnt = 0; + pDM_SWAT_Table->lastRxOkCnt =0; + TxCntOffset = Adapter->TxStats.NumTxBytesUnicast; + RxCntOffset = Adapter->RxStats.NumRxBytesUnicast; + + pDM_FatTable->bBecomeLinked = pDM_Odm->bLinked; + } + else + { + TxCntOffset = 0; + RxCntOffset = 0; + } + } + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[%d] { try_flag=(( %d )), Step=(( %d )), Double_chk_flag = (( %d )) }\n", + __LINE__,pDM_SWAT_Table->try_flag,Step,pDM_SWAT_Table->Double_chk_flag)); + + // Handling step mismatch condition. + // Peak step is not finished at last time. Recover the variable and check again. + if( Step != pDM_SWAT_Table->try_flag ) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[Step != try_flag] Need to Reset After Link\n")); + ODM_SwAntDivRestAfterLink(pDM_Odm); + } + + if(pDM_SWAT_Table->try_flag == 0xff) + { + pDM_SWAT_Table->try_flag = 0; + pDM_SWAT_Table->Train_time_flag=0; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("[set try_flag = 0] Prepare for peak!\n\n")); + return; + } + else//if( try_flag != 0xff ) + { + //1 Normal State (Begin Trying) + if(pDM_SWAT_Table->try_flag == 0) + { + + //---trafic decision--- + curTxOkCnt = Adapter->TxStats.NumTxBytesUnicast - pDM_SWAT_Table->lastTxOkCnt - TxCntOffset; + curRxOkCnt =Adapter->RxStats.NumRxBytesUnicast - pDM_SWAT_Table->lastRxOkCnt - RxCntOffset; + pDM_SWAT_Table->lastTxOkCnt = Adapter->TxStats.NumTxBytesUnicast; + pDM_SWAT_Table->lastRxOkCnt = Adapter->RxStats.NumRxBytesUnicast; + + if (curTxOkCnt > 1875000 || curRxOkCnt > 1875000)//if(PlatformDivision64(curTxOkCnt+curRxOkCnt, 2) > 1875000) ( 1.875M * 8bit ) / 2= 7.5M bits /sec ) + { + pDM_SWAT_Table->TrafficLoad = TRAFFIC_HIGH; + Train_time_temp=pDM_SWAT_Table->Train_time ; + + if(pDM_SWAT_Table->Train_time_flag==3) + { + HighTraffic_TrainTime_L=0xa; + + if(Train_time_temp<=16) + Train_time_temp=HighTraffic_TrainTime_L; + else + Train_time_temp-=16; + + } + else if(pDM_SWAT_Table->Train_time_flag==2) + { + Train_time_temp-=8; + HighTraffic_TrainTime_L=0xf; + } + else if(pDM_SWAT_Table->Train_time_flag==1) + { + Train_time_temp-=4; + HighTraffic_TrainTime_L=0x1e; + } + else if(pDM_SWAT_Table->Train_time_flag==0) + { + Train_time_temp+=8; + HighTraffic_TrainTime_L=0x28; + } + + + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("*** Train_time_temp = ((%d))\n",Train_time_temp)); + + //-- + if(Train_time_temp > HighTraffic_TrainTime_U) + Train_time_temp=HighTraffic_TrainTime_U; + + else if(Train_time_temp < HighTraffic_TrainTime_L) + Train_time_temp=HighTraffic_TrainTime_L; + + pDM_SWAT_Table->Train_time = Train_time_temp; //50ms~10ms + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,(" Train_time_flag=((%d)) , Train_time=((%d)) \n",pDM_SWAT_Table->Train_time_flag, pDM_SWAT_Table->Train_time)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, (" [HIGH Traffic] \n" )); + } + else if (curTxOkCnt > 125000 || curRxOkCnt > 125000) // ( 0.125M * 8bit ) / 2 = 0.5M bits /sec ) + { + pDM_SWAT_Table->TrafficLoad = TRAFFIC_LOW; + Train_time_temp=pDM_SWAT_Table->Train_time ; + + if(pDM_SWAT_Table->Train_time_flag==3) + { + LowTraffic_TrainTime_L=10; + if(Train_time_temp<50) + Train_time_temp=LowTraffic_TrainTime_L; + else + Train_time_temp-=50; + } + else if(pDM_SWAT_Table->Train_time_flag==2) + { + Train_time_temp-=30; + LowTraffic_TrainTime_L=36; + } + else if(pDM_SWAT_Table->Train_time_flag==1) + { + Train_time_temp-=10; + LowTraffic_TrainTime_L=40; + } + else + Train_time_temp+=10; + + //-- + if(Train_time_temp >= LowTraffic_TrainTime_U) + Train_time_temp=LowTraffic_TrainTime_U; + + else if(Train_time_temp <= LowTraffic_TrainTime_L) + Train_time_temp=LowTraffic_TrainTime_L; + + pDM_SWAT_Table->Train_time = Train_time_temp; //50ms~20ms + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,(" Train_time_flag=((%d)) , Train_time=((%d)) \n",pDM_SWAT_Table->Train_time_flag, pDM_SWAT_Table->Train_time)); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, (" [Low Traffic] \n" )); + } + else + { + pDM_SWAT_Table->TrafficLoad = TRAFFIC_UltraLOW; + pDM_SWAT_Table->Train_time = 0xc8; //200ms + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, (" [Ultra-Low Traffic] \n" )); + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("TxOkCnt=(( %llu )), RxOkCnt=(( %llu )) \n", + curTxOkCnt ,curRxOkCnt )); + + //----------------- + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,(" Current MinMaxRSSI is ((%d)) \n",pDM_FatTable->MinMaxRSSI)); + + //---reset index--- + if(pDM_SWAT_Table->reset_idx>=reset_period) + { + pDM_FatTable->MinMaxRSSI=0; // + pDM_SWAT_Table->reset_idx=0; + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("reset_idx = (( %d )) \n",pDM_SWAT_Table->reset_idx )); + //ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("reset_idx=%d\n",pDM_SWAT_Table->reset_idx)); + pDM_SWAT_Table->reset_idx++; + + //---double check flag--- + if(pDM_FatTable->MinMaxRSSI > SWAntDiv_threshold && pDM_SWAT_Table->Double_chk_flag== 0) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,(" MinMaxRSSI is ((%d)), and > %d \n", + pDM_FatTable->MinMaxRSSI,SWAntDiv_threshold)); + + pDM_SWAT_Table->Double_chk_flag =1; + pDM_SWAT_Table->try_flag = 1; + pDM_SWAT_Table->RSSI_Trying = 0; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, (" Test the current Ant for (( %d )) ms again \n", pDM_SWAT_Table->Train_time)); + ODM_UpdateRxIdleAnt(pDM_Odm, pDM_FatTable->RxIdleAnt); + ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer_8723B, pDM_SWAT_Table->Train_time ); //ms + return; + } + + nextAnt = (pDM_FatTable->RxIdleAnt == MAIN_ANT)? AUX_ANT : MAIN_ANT; + + pDM_SWAT_Table->try_flag = 1; + + if(pDM_SWAT_Table->reset_idx<=1) + pDM_SWAT_Table->RSSI_Trying = 2; + else + pDM_SWAT_Table->RSSI_Trying = 1; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("[set try_flag=1] Normal State: Begin Trying!! \n")); + + } + + else if(pDM_SWAT_Table->try_flag == 1 && pDM_SWAT_Table->Double_chk_flag== 0) + { + nextAnt = (pDM_FatTable->RxIdleAnt == MAIN_ANT)? AUX_ANT : MAIN_ANT; + pDM_SWAT_Table->RSSI_Trying--; + } + + //1 Decision State + if((pDM_SWAT_Table->try_flag == 1)&&(pDM_SWAT_Table->RSSI_Trying == 0) ) + { + + for (i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++) + { + pEntry = pDM_Odm->pODM_StaInfo[i]; + if(IS_STA_VALID(pEntry)) + { + //2 Caculate RSSI per Antenna + Main_RSSI = (pDM_FatTable->MainAnt_Cnt[i]!=0)?(pDM_FatTable->MainAnt_Sum[i]/pDM_FatTable->MainAnt_Cnt[i]):0; + Aux_RSSI = (pDM_FatTable->AuxAnt_Cnt[i]!=0)?(pDM_FatTable->AuxAnt_Sum[i]/pDM_FatTable->AuxAnt_Cnt[i]):0; + + if(pDM_FatTable->MainAnt_Cnt[i]<=1 && pDM_FatTable->CCK_counter_main>=1) + Main_RSSI=0; + + if(pDM_FatTable->AuxAnt_Cnt[i]<=1 && pDM_FatTable->CCK_counter_aux>=1) + Aux_RSSI=0; + + TargetAnt = (Main_RSSI==Aux_RSSI)?pDM_SWAT_Table->PreAntenna:((Main_RSSI>=Aux_RSSI)?MAIN_ANT:AUX_ANT); + LocalMaxRSSI = (Main_RSSI>=Aux_RSSI) ? Main_RSSI : Aux_RSSI; + LocalMinRSSI = (Main_RSSI>=Aux_RSSI) ? Aux_RSSI : Main_RSSI; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("*** CCK_counter_main = (( %d )) , CCK_counter_aux= (( %d )) \n", pDM_FatTable->CCK_counter_main, pDM_FatTable->CCK_counter_aux)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("*** OFDM_counter_main = (( %d )) , OFDM_counter_aux= (( %d )) \n", pDM_FatTable->OFDM_counter_main, pDM_FatTable->OFDM_counter_aux)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("*** Main_Cnt = (( %d )) , Main_RSSI= (( %d )) \n", pDM_FatTable->MainAnt_Cnt[i], Main_RSSI)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("*** Aux_Cnt = (( %d )) , Aux_RSSI = (( %d )) \n", pDM_FatTable->AuxAnt_Cnt[i] , Aux_RSSI )); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("*** MAC ID:[ %d ] , TargetAnt = (( %s )) \n", i ,( TargetAnt ==MAIN_ANT)?"MAIN_ANT":"AUX_ANT")); + + //2 Select RX Idle Antenna + + if (LocalMaxRSSI != 0 && LocalMaxRSSI < MinMaxRSSI) + { + RxIdleAnt = TargetAnt; + MinMaxRSSI = LocalMaxRSSI; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("*** LocalMaxRSSI-LocalMinRSSI = ((%d))\n",(LocalMaxRSSI-LocalMinRSSI))); + + if((LocalMaxRSSI-LocalMinRSSI)>8) + { + if(LocalMinRSSI != 0) + pDM_SWAT_Table->Train_time_flag=3; + else + { + if(MinMaxRSSI > SWAntDiv_threshold) + pDM_SWAT_Table->Train_time_flag=0; + else + pDM_SWAT_Table->Train_time_flag=3; + } + } + else if((LocalMaxRSSI-LocalMinRSSI)>5) + pDM_SWAT_Table->Train_time_flag=2; + else if((LocalMaxRSSI-LocalMinRSSI)>2) + pDM_SWAT_Table->Train_time_flag=1; + else + pDM_SWAT_Table->Train_time_flag=0; + + } + + //2 Select TX Antenna + if(TargetAnt == MAIN_ANT) + pDM_FatTable->antsel_a[i] = ANT1_2G; + else + pDM_FatTable->antsel_a[i] = ANT2_2G; + + } + pDM_FatTable->MainAnt_Sum[i] = 0; + pDM_FatTable->AuxAnt_Sum[i] = 0; + pDM_FatTable->MainAnt_Cnt[i] = 0; + pDM_FatTable->AuxAnt_Cnt[i] = 0; + pDM_FatTable->CCK_counter_main=0; + pDM_FatTable->CCK_counter_aux=0; + pDM_FatTable->OFDM_counter_main=0; + pDM_FatTable->OFDM_counter_aux=0; + + } + + + pDM_FatTable->MinMaxRSSI=MinMaxRSSI; + pDM_SWAT_Table->try_flag = 0; + + if( pDM_SWAT_Table->Double_chk_flag==1) + { + pDM_SWAT_Table->Double_chk_flag=0; + if(pDM_FatTable->MinMaxRSSI > SWAntDiv_threshold) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,(" [Double check] MinMaxRSSI ((%d)) > %d again!! \n", + pDM_FatTable->MinMaxRSSI,SWAntDiv_threshold)); + + ODM_UpdateRxIdleAnt(pDM_Odm, RxIdleAnt); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("[reset try_flag = 0] Training accomplished !!!] \n\n\n")); + return; + } + else + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,(" [Double check] MinMaxRSSI ((%d)) <= %d !! \n", + pDM_FatTable->MinMaxRSSI,SWAntDiv_threshold)); + + nextAnt = (pDM_FatTable->RxIdleAnt == MAIN_ANT)? AUX_ANT : MAIN_ANT; + pDM_SWAT_Table->try_flag = 0; + pDM_SWAT_Table->reset_idx=reset_period; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("[set try_flag=0] Normal State: Need to tryg again!! \n\n\n")); + return; + } + } + else + { + pDM_SWAT_Table->PreAntenna =RxIdleAnt; + ODM_UpdateRxIdleAnt(pDM_Odm, RxIdleAnt ); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("[reset try_flag = 0] Training accomplished !!!] \n\n\n")); + return; + } + + } + + } + + //1 4.Change TRX antenna + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("RSSI_Trying = (( %d )), Ant: (( %s )) >>> (( %s )) \n", + pDM_SWAT_Table->RSSI_Trying, (pDM_FatTable->RxIdleAnt == MAIN_ANT?"MAIN":"AUX"),(nextAnt == MAIN_ANT?"MAIN":"AUX"))); + + ODM_UpdateRxIdleAnt(pDM_Odm, nextAnt); + + //1 5.Reset Statistics + + pDM_FatTable->RxIdleAnt = nextAnt; + + //1 6.Set next timer (Trying State) + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, (" Test ((%s)) Ant for (( %d )) ms \n", (nextAnt == MAIN_ANT?"MAIN":"AUX"), pDM_SWAT_Table->Train_time)); + ODM_SetTimer(pDM_Odm,&pDM_SWAT_Table->SwAntennaSwitchTimer_8723B, pDM_SWAT_Table->Train_time ); //ms +} + + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +VOID +ODM_SW_AntDiv_Callback( + PRT_TIMER pTimer +) +{ + PADAPTER Adapter = (PADAPTER)pTimer->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + pSWAT_T pDM_SWAT_Table = &pHalData->DM_OutSrc.DM_SWAT_Table; + + #if DEV_BUS_TYPE==RT_PCI_INTERFACE + #if USE_WORKITEM + ODM_ScheduleWorkItem(&pDM_SWAT_Table->SwAntennaSwitchWorkitem_8723B); + #else + { + //DbgPrint("SW_antdiv_Callback"); + odm_S0S1_SwAntDiv(&pHalData->DM_OutSrc, SWAW_STEP_DETERMINE); + } + #endif + #else + ODM_ScheduleWorkItem(&pDM_SWAT_Table->SwAntennaSwitchWorkitem_8723B); + #endif +} +VOID +ODM_SW_AntDiv_WorkitemCallback( + IN PVOID pContext + ) +{ + PADAPTER pAdapter = (PADAPTER)pContext; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + //DbgPrint("SW_antdiv_Workitem_Callback"); + odm_S0S1_SwAntDiv(&pHalData->DM_OutSrc, SWAW_STEP_DETERMINE); +} +#endif //#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) +VOID +ODM_SW_AntDiv_Callback(void *FunctionContext) +{ + PDM_ODM_T pDM_Odm= (PDM_ODM_T)FunctionContext; + PADAPTER padapter = pDM_Odm->Adapter; + if(padapter->net_closed == _TRUE) + return; + //odm_S0S1_SwAntDiv(pDM_Odm, SWAW_STEP_DETERMINE); +} +#endif //#if (DM_ODM_SUPPORT_TYPE == ODM_CE) + +#endif //#if (RTL8723B_SUPPORT == 1) + + +#if(RTL8188E_SUPPORT == 1 || RTL8192E_SUPPORT == 1) +#if (!(DM_ODM_SUPPORT_TYPE == ODM_CE)) +VOID +odm_SetNextMACAddrTarget( + IN PDM_ODM_T pDM_Odm +) +{ + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + PSTA_INFO_T pEntry; + //u1Byte Bssid[6]; + u4Byte value32, i; + + // + //2012.03.26 LukeLee: The MAC address is changed according to MACID in turn + // + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("odm_SetNextMACAddrTarget() ==>\n")); + if(pDM_Odm->bLinked) + { + for (i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++) + { + if((pDM_FatTable->TrainIdx+1) == ODM_ASSOCIATE_ENTRY_NUM) + pDM_FatTable->TrainIdx = 0; + else + pDM_FatTable->TrainIdx++; + + pEntry = pDM_Odm->pODM_StaInfo[pDM_FatTable->TrainIdx]; + if(IS_STA_VALID(pEntry)) + { + //Match MAC ADDR +#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + value32 = (pEntry->hwaddr[5]<<8)|pEntry->hwaddr[4]; +#else + value32 = (pEntry->MacAddr[5]<<8)|pEntry->MacAddr[4]; +#endif + ODM_SetMACReg(pDM_Odm, 0x7b4, 0xFFFF, value32); +#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + value32 = (pEntry->hwaddr[3]<<24)|(pEntry->hwaddr[2]<<16) |(pEntry->hwaddr[1]<<8) |pEntry->hwaddr[0]; +#else + value32 = (pEntry->MacAddr[3]<<24)|(pEntry->MacAddr[2]<<16) |(pEntry->MacAddr[1]<<8) |pEntry->MacAddr[0]; +#endif + ODM_SetMACReg(pDM_Odm, 0x7b0, bMaskDWord, value32); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("pDM_FatTable->TrainIdx=%lu\n",pDM_FatTable->TrainIdx)); +#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Training MAC Addr = %x:%x:%x:%x:%x:%x\n", + pEntry->hwaddr[5],pEntry->hwaddr[4],pEntry->hwaddr[3],pEntry->hwaddr[2],pEntry->hwaddr[1],pEntry->hwaddr[0])); +#else + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Training MAC Addr = %x:%x:%x:%x:%x:%x\n", + pEntry->MacAddr[5],pEntry->MacAddr[4],pEntry->MacAddr[3],pEntry->MacAddr[2],pEntry->MacAddr[1],pEntry->MacAddr[0])); +#endif + + break; + } + } + + } + +#if 0 + // + //2012.03.26 LukeLee: This should be removed later, the MAC address is changed according to MACID in turn + // + #if( DM_ODM_SUPPORT_TYPE & ODM_WIN) + { + PADAPTER Adapter = pDM_Odm->Adapter; + PMGNT_INFO pMgntInfo = &Adapter->MgntInfo; + + for (i=0; i<6; i++) + { + Bssid[i] = pMgntInfo->Bssid[i]; + //DbgPrint("Bssid[%d]=%x\n", i, Bssid[i]); + } + } + #endif + + //odm_SetNextMACAddrTarget(pDM_Odm); + + //1 Select MAC Address Filter + for (i=0; i<6; i++) + { + if(Bssid[i] != pDM_FatTable->Bssid[i]) + { + bMatchBSSID = FALSE; + break; + } + } + if(bMatchBSSID == FALSE) + { + //Match MAC ADDR + value32 = (Bssid[5]<<8)|Bssid[4]; + ODM_SetMACReg(pDM_Odm, 0x7b4, 0xFFFF, value32); + value32 = (Bssid[3]<<24)|(Bssid[2]<<16) |(Bssid[1]<<8) |Bssid[0]; + ODM_SetMACReg(pDM_Odm, 0x7b0, bMaskDWord, value32); + } + + return bMatchBSSID; +#endif + +} + +VOID +odm_FastAntTraining( + IN PDM_ODM_T pDM_Odm +) +{ + u4Byte i, MaxRSSI=0; + u1Byte TargetAnt=2; + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + BOOLEAN bPktFilterMacth = FALSE; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("==>odm_FastAntTraining()\n")); + + //1 TRAINING STATE + if(pDM_FatTable->FAT_State == FAT_TRAINING_STATE) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Enter FAT_TRAINING_STATE\n")); + //2 Caculate RSSI per Antenna + for (i=0; i<7; i++) + { + if(pDM_FatTable->antRSSIcnt[i] == 0) + pDM_FatTable->antAveRSSI[i] = 0; + else + { + pDM_FatTable->antAveRSSI[i] = pDM_FatTable->antSumRSSI[i] /pDM_FatTable->antRSSIcnt[i]; + bPktFilterMacth = TRUE; + } + if(pDM_FatTable->antAveRSSI[i] > MaxRSSI) + { + MaxRSSI = pDM_FatTable->antAveRSSI[i]; + TargetAnt = (u1Byte) i; + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("pDM_FatTable->antAveRSSI[%lu] = %lu, pDM_FatTable->antRSSIcnt[%lu] = %lu\n", + i, pDM_FatTable->antAveRSSI[i], i, pDM_FatTable->antRSSIcnt[i])); + } + + //2 Select TRX Antenna + if(bPktFilterMacth == FALSE) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("None Packet is matched\n")); + + ODM_SetBBReg(pDM_Odm, 0xe08 , BIT16, 0); //RegE08[16]=1'b0 //disable fast training + ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 0); //RegC50[7]=1'b0 //disable HW AntDiv + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("TargetAnt=%d, MaxRSSI=%lu\n",TargetAnt,MaxRSSI)); + + ODM_SetBBReg(pDM_Odm, 0xe08 , BIT16, 0); //RegE08[16]=1'b0 //disable fast training + //ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 0); //RegC50[7]=1'b0 //disable HW AntDiv + ODM_SetBBReg(pDM_Odm, 0x864 , BIT8|BIT7|BIT6, TargetAnt); //Default RX is Omni, Optional RX is the best decision by FAT + //ODM_SetBBReg(pDM_Odm, 0x860 , BIT14|BIT13|BIT12, TargetAnt); //Default TX + ODM_SetBBReg(pDM_Odm, 0x80c , BIT21, 1); //Reg80c[21]=1'b1 //from TX Info + +#if 0 + pEntry = pDM_Odm->pODM_StaInfo[pDM_FatTable->TrainIdx]; + + if(IS_STA_VALID(pEntry)) + { + pEntry->antsel_a = TargetAnt&BIT0; + pEntry->antsel_b = (TargetAnt&BIT1)>>1; + pEntry->antsel_c = (TargetAnt&BIT2)>>2; + } +#else + pDM_FatTable->antsel_a[pDM_FatTable->TrainIdx] = TargetAnt&BIT0; + pDM_FatTable->antsel_b[pDM_FatTable->TrainIdx] = (TargetAnt&BIT1)>>1; + pDM_FatTable->antsel_c[pDM_FatTable->TrainIdx] = (TargetAnt&BIT2)>>2; +#endif + + + if(TargetAnt == 0) + ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 0); //RegC50[7]=1'b0 //disable HW AntDiv + + } + + //2 Reset Counter + for(i=0; i<7; i++) + { + pDM_FatTable->antSumRSSI[i] = 0; + pDM_FatTable->antRSSIcnt[i] = 0; + } + + pDM_FatTable->FAT_State = FAT_NORMAL_STATE; + return; + } + + //1 NORMAL STATE + if(pDM_FatTable->FAT_State == FAT_NORMAL_STATE) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Enter FAT_NORMAL_STATE\n")); + + odm_SetNextMACAddrTarget(pDM_Odm); + +#if 0 + pEntry = pDM_Odm->pODM_StaInfo[pDM_FatTable->TrainIdx]; + if(IS_STA_VALID(pEntry)) + { + pEntry->antsel_a = TargetAnt&BIT0; + pEntry->antsel_b = (TargetAnt&BIT1)>>1; + pEntry->antsel_c = (TargetAnt&BIT2)>>2; + } +#endif + + //2 Prepare Training + pDM_FatTable->FAT_State = FAT_TRAINING_STATE; + ODM_SetBBReg(pDM_Odm, 0xe08 , BIT16, 1); //RegE08[16]=1'b1 //enable fast training + ODM_SetBBReg(pDM_Odm, 0xc50 , BIT7, 1); //RegC50[7]=1'b1 //enable HW AntDiv + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Start FAT_TRAINING_STATE\n")); + ODM_SetTimer(pDM_Odm,&pDM_Odm->FastAntTrainingTimer, 500 ); //ms + + } + +} + +VOID +odm_FastAntTrainingCallback( + IN PDM_ODM_T pDM_Odm +) +{ + +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PADAPTER padapter = pDM_Odm->Adapter; + if(padapter->net_closed == _TRUE) + return; + //if(*pDM_Odm->pbNet_closed == TRUE) + // return; +#endif + +#if USE_WORKITEM + ODM_ScheduleWorkItem(&pDM_Odm->FastAntTrainingWorkitem); +#else + odm_FastAntTraining(pDM_Odm); +#endif +} + +VOID +odm_FastAntTrainingWorkItemCallback( + IN PDM_ODM_T pDM_Odm +) +{ + odm_FastAntTraining(pDM_Odm); +} +#endif + +#endif + + +VOID +ODM_AntDivInit( + IN PDM_ODM_T pDM_Odm + ) +{ + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + pSWAT_T pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + + + if(!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[Return!!!] Not Support Antenna Diversity Function\n")); + return; + } + //--- +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) + if(pDM_FatTable->AntDiv_2G_5G == ODM_ANTDIV_2G) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[2G AntDiv Init]: Only Support 2G Antenna Diversity Function\n")); + if(!(pDM_Odm->SupportICType & ODM_ANTDIV_2G_SUPPORT_IC)) + return; + } + else if(pDM_FatTable->AntDiv_2G_5G == ODM_ANTDIV_5G) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[5G AntDiv Init]: Only Support 5G Antenna Diversity Function\n")); + if(!(pDM_Odm->SupportICType & ODM_ANTDIV_5G_SUPPORT_IC)) + return; + } + else if(pDM_FatTable->AntDiv_2G_5G == (ODM_ANTDIV_2G|ODM_ANTDIV_5G)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[2G & 5G AntDiv Init]:Support Both 2G & 5G Antenna Diversity Function\n")); + } + + pDM_Odm->antdiv_rssi=0; + +#endif + //--- + + //2 [--General---] + pDM_Odm->antdiv_period=0; + pDM_Odm->antdiv_select=0; + pDM_SWAT_Table->Ant5G = MAIN_ANT; + pDM_SWAT_Table->Ant2G = MAIN_ANT; + pDM_FatTable->CCK_counter_main=0; + pDM_FatTable->CCK_counter_aux=0; + pDM_FatTable->OFDM_counter_main=0; + pDM_FatTable->OFDM_counter_aux=0; + + //3 [Set MAIN_ANT as default antenna if Auto-Ant enable] + if (pDM_Odm->antdiv_select==1) + pDM_Odm->AntType = ODM_FIX_MAIN_ANT; + else if (pDM_Odm->antdiv_select==2) + pDM_Odm->AntType = ODM_FIX_AUX_ANT; + else if(pDM_Odm->antdiv_select==0) + pDM_Odm->AntType = ODM_AUTO_ANT; + + if(pDM_Odm->AntType == ODM_AUTO_ANT) + { + odm_AntDiv_on_off(pDM_Odm, ANTDIV_OFF); + ODM_UpdateRxIdleAnt(pDM_Odm, MAIN_ANT); + } + else + { + odm_AntDiv_on_off(pDM_Odm, ANTDIV_OFF); + + if(pDM_Odm->AntType == ODM_FIX_MAIN_ANT) + { + ODM_UpdateRxIdleAnt(pDM_Odm, MAIN_ANT); + return; + } + else if(pDM_Odm->AntType == ODM_FIX_AUX_ANT) + { + ODM_UpdateRxIdleAnt(pDM_Odm, AUX_ANT); + return; + } + } + //--- + if(pDM_Odm->AntDivType != CGCS_RX_HW_ANTDIV) + { + if(pDM_Odm->SupportICType & ODM_N_ANTDIV_SUPPORT) + { + #if TX_BY_REG + ODM_SetBBReg(pDM_Odm, 0x80c , BIT21, 0); //Reg80c[21]=1'b0 //from Reg + #else + ODM_SetBBReg(pDM_Odm, 0x80c , BIT21, 1); + #endif + } + else if(pDM_Odm->SupportICType & ODM_AC_ANTDIV_SUPPORT) + { + #if TX_BY_REG + ODM_SetBBReg(pDM_Odm, 0x900 , BIT18, 0); + #else + ODM_SetBBReg(pDM_Odm, 0x900 , BIT18, 1); + #endif + } + } + + //2 [--88E---] + if(pDM_Odm->SupportICType == ODM_RTL8188E) + { + #if (RTL8188E_SUPPORT == 1) + //pDM_Odm->AntDivType = CGCS_RX_HW_ANTDIV; + //pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; + //pDM_Odm->AntDivType = CG_TRX_SMART_ANTDIV; + + if( (pDM_Odm->AntDivType != CGCS_RX_HW_ANTDIV) && (pDM_Odm->AntDivType != CG_TRX_HW_ANTDIV) && (pDM_Odm->AntDivType != CG_TRX_SMART_ANTDIV)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[Return!!!] 88E Not Supprrt This AntDiv Type\n")); + pDM_Odm->SupportAbility &= ~(ODM_BB_ANT_DIV); + return; + } + + if(pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) + odm_RX_HWAntDiv_Init_88E(pDM_Odm); + else if(pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) + odm_TRX_HWAntDiv_Init_88E(pDM_Odm); + else if(pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV) + odm_Smart_HWAntDiv_Init_88E(pDM_Odm); + #endif + } + + //2 [--92E---] + #if (RTL8192E_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8192E) + { + //pDM_Odm->AntDivType = CGCS_RX_HW_ANTDIV; + //pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; + //pDM_Odm->AntDivType = CG_TRX_SMART_ANTDIV; + + if( (pDM_Odm->AntDivType != CGCS_RX_HW_ANTDIV) && (pDM_Odm->AntDivType != CG_TRX_HW_ANTDIV) && (pDM_Odm->AntDivType != CG_TRX_SMART_ANTDIV)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[Return!!!] 8192E Not Supprrt This AntDiv Type\n")); + pDM_Odm->SupportAbility &= ~(ODM_BB_ANT_DIV); + return; + } + + if(pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) + odm_RX_HWAntDiv_Init_92E(pDM_Odm); + else if(pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) + odm_TRX_HWAntDiv_Init_92E(pDM_Odm); + else if(pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV) + odm_Smart_HWAntDiv_Init_92E(pDM_Odm); + + } + #endif + + //2 [--8723B---] + #if (RTL8723B_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + //pDM_Odm->AntDivType = S0S1_SW_ANTDIV; + //pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; + + if(pDM_Odm->AntDivType != S0S1_SW_ANTDIV && pDM_Odm->AntDivType != CG_TRX_HW_ANTDIV) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[Return!!!] 8723B Not Supprrt This AntDiv Type\n")); + pDM_Odm->SupportAbility &= ~(ODM_BB_ANT_DIV); + return; + } + + if( pDM_Odm->AntDivType==S0S1_SW_ANTDIV) + odm_S0S1_SWAntDiv_Init_8723B(pDM_Odm); + else if(pDM_Odm->AntDivType==CG_TRX_HW_ANTDIV) + odm_TRX_HWAntDiv_Init_8723B(pDM_Odm); + } + #endif + + //2 [--8811A 8821A---] + #if (RTL8821A_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8821) + { + //pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; + pDM_Odm->AntDivType = S0S1_SW_ANTDIV; + + if( pDM_Odm->AntDivType != CG_TRX_HW_ANTDIV && pDM_Odm->AntDivType != S0S1_SW_ANTDIV) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[Return!!!] 8821A & 8811A Not Supprrt This AntDiv Type\n")); + pDM_Odm->SupportAbility &= ~(ODM_BB_ANT_DIV); + return; + } + if(pDM_Odm->AntDivType==CG_TRX_HW_ANTDIV) + odm_TRX_HWAntDiv_Init_8821A(pDM_Odm); + else if( pDM_Odm->AntDivType==S0S1_SW_ANTDIV) + odm_S0S1_SWAntDiv_Init_8821A(pDM_Odm); + } + #endif + + //2 [--8881A---] + #if (RTL8881A_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8881A) + { + //pDM_Odm->AntDivType = CGCS_RX_HW_ANTDIV; + //pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; + + if(pDM_Odm->AntDivType != CGCS_RX_HW_ANTDIV && pDM_Odm->AntDivType != CG_TRX_HW_ANTDIV) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[Return!!!] 8881A Not Supprrt This AntDiv Type\n")); + pDM_Odm->SupportAbility &= ~(ODM_BB_ANT_DIV); + return; + } + if(pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) + odm_RX_HWAntDiv_Init_8881A(pDM_Odm); + else if(pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) + odm_TRX_HWAntDiv_Init_8881A(pDM_Odm); + } + #endif + + //2 [--8812---] + #if (RTL8812A_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8812) + { + //pDM_Odm->AntDivType = CG_TRX_HW_ANTDIV; + + if( pDM_Odm->AntDivType != CG_TRX_HW_ANTDIV) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[Return!!!] 8812A Not Supprrt This AntDiv Type\n")); + pDM_Odm->SupportAbility &= ~(ODM_BB_ANT_DIV); + return; + } + odm_TRX_HWAntDiv_Init_8812A(pDM_Odm); + } + #endif + //ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("*** SupportICType=[%lu] \n",pDM_Odm->SupportICType)); + //ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("*** AntDiv SupportAbility=[%lu] \n",(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)>>6)); + //ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("*** AntDiv Type=[%d] \n",pDM_Odm->AntDivType)); + +} + +VOID +ODM_AntDiv( + IN PDM_ODM_T pDM_Odm +) +{ + PADAPTER pAdapter = pDM_Odm->Adapter; + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + +//#if (DM_ODM_SUPPORT_TYPE == ODM_AP) + if(*pDM_Odm->pBandType == ODM_BAND_5G ) + { + if(pDM_FatTable->idx_AntDiv_counter_5G < pDM_Odm->antdiv_period ) + { + pDM_FatTable->idx_AntDiv_counter_5G++; + return; + } + else + pDM_FatTable->idx_AntDiv_counter_5G=0; + } + else if(*pDM_Odm->pBandType == ODM_BAND_2_4G ) + { + if(pDM_FatTable->idx_AntDiv_counter_2G < pDM_Odm->antdiv_period ) + { + pDM_FatTable->idx_AntDiv_counter_2G++; + return; + } + else + pDM_FatTable->idx_AntDiv_counter_2G=0; + } +//#endif + //---------- + if(!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[Return!!!] Not Support Antenna Diversity Function\n")); + return; + } + + //---------- +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + if(pAdapter->MgntInfo.AntennaTest) + return; + + { + #if (BEAMFORMING_SUPPORT == 1) + BEAMFORMING_CAP BeamformCap = (pAdapter->MgntInfo.BeamformingInfo.BeamformCap); + + if( BeamformCap & BEAMFORMEE_CAP ) // BFmee On && Div On -> Div Off + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[ AntDiv : OFF ] BFmee ==1 \n")); + if(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV) + { + odm_AntDiv_on_off(pDM_Odm, ANTDIV_OFF); + pDM_Odm->SupportAbility &= ~(ODM_BB_ANT_DIV); + return; + } + } + else // BFmee Off && Div Off -> Div On + #endif + { + if(!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV) && pDM_Odm->bLinked) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[ AntDiv : ON ] BFmee ==0 \n")); + if((pDM_Odm->AntDivType!=S0S1_SW_ANTDIV) ) + odm_AntDiv_on_off(pDM_Odm, ANTDIV_ON); + + pDM_Odm->SupportAbility |= (ODM_BB_ANT_DIV); + } + } + } +#endif + + //---------- +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) + if(pDM_FatTable->AntDiv_2G_5G == ODM_ANTDIV_2G) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[ 2G AntDiv Running ]\n")); + if(!(pDM_Odm->SupportICType & ODM_ANTDIV_2G_SUPPORT_IC)) + return; + } + else if(pDM_FatTable->AntDiv_2G_5G == ODM_ANTDIV_5G) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[ 5G AntDiv Running ]\n")); + if(!(pDM_Odm->SupportICType & ODM_ANTDIV_5G_SUPPORT_IC)) + return; + } + else if(pDM_FatTable->AntDiv_2G_5G == (ODM_ANTDIV_2G|ODM_ANTDIV_5G)) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("[ 2G & 5G AntDiv Running ]\n")); + } +#endif + + //---------- + + if (pDM_Odm->antdiv_select==1) + pDM_Odm->AntType = ODM_FIX_MAIN_ANT; + else if (pDM_Odm->antdiv_select==2) + pDM_Odm->AntType = ODM_FIX_AUX_ANT; + else if (pDM_Odm->antdiv_select==0) + pDM_Odm->AntType = ODM_AUTO_ANT; + + //ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV,ODM_DBG_LOUD,("AntType= (( %d )) , pre_AntType= (( %d )) \n",pDM_Odm->AntType,pDM_Odm->pre_AntType)); + + if(pDM_Odm->AntType != ODM_AUTO_ANT) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Fix Antenna at (( %s ))\n",(pDM_Odm->AntType == ODM_FIX_MAIN_ANT)?"MAIN":"AUX")); + + if(pDM_Odm->AntType != pDM_Odm->pre_AntType) + { + odm_AntDiv_on_off(pDM_Odm, ANTDIV_OFF); + + if(pDM_Odm->SupportICType & ODM_N_ANTDIV_SUPPORT) + ODM_SetBBReg(pDM_Odm, 0x80c , BIT21, 0); + else if(pDM_Odm->SupportICType & ODM_AC_ANTDIV_SUPPORT) + ODM_SetBBReg(pDM_Odm, 0x900 , BIT18, 0); + + if(pDM_Odm->AntType == ODM_FIX_MAIN_ANT) + ODM_UpdateRxIdleAnt(pDM_Odm, MAIN_ANT); + else if(pDM_Odm->AntType == ODM_FIX_AUX_ANT) + ODM_UpdateRxIdleAnt(pDM_Odm, AUX_ANT); + } + pDM_Odm->pre_AntType=pDM_Odm->AntType; + return; + } + else + { + if(pDM_Odm->AntType != pDM_Odm->pre_AntType) + { + odm_AntDiv_on_off(pDM_Odm, ANTDIV_ON); + if(pDM_Odm->SupportICType & ODM_N_ANTDIV_SUPPORT) + ODM_SetBBReg(pDM_Odm, 0x80c , BIT21, 1); + else if(pDM_Odm->SupportICType & ODM_AC_ANTDIV_SUPPORT) + ODM_SetBBReg(pDM_Odm, 0x900 , BIT18, 1); + } + pDM_Odm->pre_AntType=pDM_Odm->AntType; + } + + + //3 ----------------------------------------------------------------------------------------------------------- + //2 [--88E---] + if(pDM_Odm->SupportICType == ODM_RTL8188E) + { + #if (RTL8188E_SUPPORT == 1) + if(pDM_Odm->AntDivType==CG_TRX_HW_ANTDIV ||pDM_Odm->AntDivType==CGCS_RX_HW_ANTDIV) + odm_HW_AntDiv(pDM_Odm); + #if (!(DM_ODM_SUPPORT_TYPE == ODM_CE)) + else if (pDM_Odm->AntDivType==CG_TRX_SMART_ANTDIV) + odm_FastAntTraining(pDM_Odm); + #endif + #endif + } + //2 [--92E---] + #if (RTL8192E_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8192E) + { + if(pDM_Odm->AntDivType==CGCS_RX_HW_ANTDIV) + odm_HW_AntDiv(pDM_Odm); + #if (!(DM_ODM_SUPPORT_TYPE == ODM_CE)) + else if (pDM_Odm->AntDivType==CG_TRX_SMART_ANTDIV) + odm_FastAntTraining(pDM_Odm); + #endif + } + #endif + + #if (RTL8723B_SUPPORT == 1) + //2 [--8723B---] + else if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + if (pDM_Odm->AntDivType==S0S1_SW_ANTDIV) + odm_S0S1_SwAntDiv(pDM_Odm, SWAW_STEP_PEAK); + else if (pDM_Odm->AntDivType==CG_TRX_HW_ANTDIV) + odm_HW_AntDiv(pDM_Odm); + } + #endif + + //2 [--8821A---] + #if (RTL8821A_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8821) + { + if(pDM_Odm->bBtDisabled) //BT disabled + { + if(pDM_Odm->AntDivType == S0S1_SW_ANTDIV) + { + pDM_Odm->AntDivType=CG_TRX_HW_ANTDIV; + ODM_SetBBReg(pDM_Odm, 0x8D4 , BIT24, 1); + } + } + else //BT enabled + { + if(pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) + { + pDM_Odm->AntDivType=S0S1_SW_ANTDIV; + ODM_SetBBReg(pDM_Odm, 0x8D4 , BIT24, 0); + } + } + + if (pDM_Odm->AntDivType==S0S1_SW_ANTDIV) + odm_S0S1_SwAntDiv(pDM_Odm, SWAW_STEP_PEAK); + else if (pDM_Odm->AntDivType==CG_TRX_HW_ANTDIV) + odm_HW_AntDiv(pDM_Odm); + } + #endif + //2 [--8881A---] + #if (RTL8881A_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8881A) + odm_HW_AntDiv(pDM_Odm); + #endif + //2 [--8812A---] + #if (RTL8812A_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8812) + odm_HW_AntDiv(pDM_Odm); + #endif +} + + +VOID +odm_AntselStatistics( + IN PDM_ODM_T pDM_Odm, + IN u1Byte antsel_tr_mux, + IN u4Byte MacId, + IN u4Byte RxPWDBAll +) +{ + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + + if(antsel_tr_mux == ANT1_2G) + { + pDM_FatTable->MainAnt_Sum[MacId]+=RxPWDBAll; + pDM_FatTable->MainAnt_Cnt[MacId]++; + } + else + { + pDM_FatTable->AuxAnt_Sum[MacId]+=RxPWDBAll; + pDM_FatTable->AuxAnt_Cnt[MacId]++; + } +} + + +VOID +ODM_Process_RSSIForAntDiv( + IN OUT PDM_ODM_T pDM_Odm, + IN PODM_PHY_INFO_T pPhyInfo, + IN PODM_PACKET_INFO_T pPktinfo + ) +{ +u1Byte isCCKrate=0,CCKMaxRate=DESC_RATE11M; +pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) + u4Byte RxPower_Ant0, RxPower_Ant1; +#else + u1Byte RxPower_Ant0, RxPower_Ant1; +#endif + + if(pDM_Odm->SupportICType & ODM_N_ANTDIV_SUPPORT) + CCKMaxRate=DESC_RATE11M; + else if(pDM_Odm->SupportICType & ODM_AC_ANTDIV_SUPPORT) + CCKMaxRate=DESC_RATE11M; + isCCKrate = (pPktinfo->DataRate <= CCKMaxRate)?TRUE:FALSE; + +#if ((RTL8192C_SUPPORT == 1) ||(RTL8192D_SUPPORT == 1)) + if(pDM_Odm->SupportICType & ODM_RTL8192C|ODM_RTL8192D) + { + if(pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) + { + //if(pPktinfo->bPacketBeacon) + //{ + // DbgPrint("This is beacon, isCCKrate=%d\n", isCCKrate); + //} + ODM_AntselStatistics_88C(pDM_Odm, pPktinfo->StationID, pPhyInfo->RxPWDBAll, isCCKrate); + } + } +#endif + + if( (pDM_Odm->SupportICType == ODM_RTL8192E||pDM_Odm->SupportICType == ODM_RTL8812) && (pPktinfo->DataRate > CCKMaxRate) ) + { + RxPower_Ant0 = pPhyInfo->RxMIMOSignalStrength[0]; + RxPower_Ant1= pPhyInfo->RxMIMOSignalStrength[1]; + } + else + RxPower_Ant0=pPhyInfo->RxPWDBAll; + + if(pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV) + { + if( (pDM_Odm->SupportICType & ODM_SMART_ANT_SUPPORT) && pPktinfo->bPacketToSelf && pDM_FatTable->FAT_State == FAT_TRAINING_STATE )//(pPktinfo->bPacketMatchBSSID && (!pPktinfo->bPacketBeacon)) + { + u1Byte antsel_tr_mux; + antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2<<2) |(pDM_FatTable->antsel_rx_keep_1 <<1) |pDM_FatTable->antsel_rx_keep_0; + pDM_FatTable->antSumRSSI[antsel_tr_mux] += RxPower_Ant0; + pDM_FatTable->antRSSIcnt[antsel_tr_mux]++; + } + } + else //AntDivType != CG_TRX_SMART_ANTDIV + { + if( ( pDM_Odm->SupportICType & ODM_ANTDIV_SUPPORT ) && (pPktinfo->bPacketToSelf || pPktinfo->bPacketMatchBSSID) ) + { + if(pDM_Odm->SupportICType == ODM_RTL8188E || pDM_Odm->SupportICType == ODM_RTL8192E) + odm_AntselStatistics(pDM_Odm, pDM_FatTable->antsel_rx_keep_0, pPktinfo->StationID,RxPower_Ant0); + else// SupportICType == ODM_RTL8821 and ODM_RTL8723B and ODM_RTL8812) + { + if(isCCKrate && (pDM_Odm->AntDivType == S0S1_SW_ANTDIV)) + { + pDM_FatTable->antsel_rx_keep_0 = (pDM_FatTable->RxIdleAnt == MAIN_ANT) ? ANT1_2G : ANT2_2G; + + + if(pDM_FatTable->antsel_rx_keep_0==ANT1_2G) + pDM_FatTable->CCK_counter_main++; + else// if(pDM_FatTable->antsel_rx_keep_0==ANT2_2G) + pDM_FatTable->CCK_counter_aux++; + + odm_AntselStatistics(pDM_Odm, pDM_FatTable->antsel_rx_keep_0, pPktinfo->StationID, RxPower_Ant0); + } + else + { + + if(pDM_FatTable->antsel_rx_keep_0==ANT1_2G) + pDM_FatTable->OFDM_counter_main++; + else// if(pDM_FatTable->antsel_rx_keep_0==ANT2_2G) + pDM_FatTable->OFDM_counter_aux++; + odm_AntselStatistics(pDM_Odm, pDM_FatTable->antsel_rx_keep_0, pPktinfo->StationID, RxPower_Ant0); + } + } + } + } + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("isCCKrate=%d, PWDB_ALL=%d\n",isCCKrate, pPhyInfo->RxPWDBAll)); + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD,("antsel_tr_mux=3'b%d%d%d\n",pDM_FatTable->antsel_rx_keep_2, pDM_FatTable->antsel_rx_keep_1, pDM_FatTable->antsel_rx_keep_0)); +} + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) +VOID +ODM_SetTxAntByTxInfo( + IN PDM_ODM_T pDM_Odm, + IN pu1Byte pDesc, + IN u1Byte macId +) +{ + pFAT_T pDM_FatTable = &pDM_Odm->DM_FatTable; + + if(!(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV)) + return; + + if(pDM_Odm->AntDivType==CGCS_RX_HW_ANTDIV) + return; + + + if(pDM_Odm->SupportICType == ODM_RTL8723B) + { +#if (RTL8723B_SUPPORT == 1) + SET_TX_DESC_ANTSEL_A_8723B(pDesc, pDM_FatTable->antsel_a[macId]); + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[8723B] SetTxAntByTxInfo_WIN: MacID=%d, antsel_tr_mux=3'b%d%d%d\n", + //macId, pDM_FatTable->antsel_c[macId], pDM_FatTable->antsel_b[macId], pDM_FatTable->antsel_a[macId])); +#endif + } + else if(pDM_Odm->SupportICType == ODM_RTL8821) + { +#if (RTL8821A_SUPPORT == 1) + SET_TX_DESC_ANTSEL_A_8812(pDesc, pDM_FatTable->antsel_a[macId]); + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[8821A] SetTxAntByTxInfo_WIN: MacID=%d, antsel_tr_mux=3'b%d%d%d\n", + //macId, pDM_FatTable->antsel_c[macId], pDM_FatTable->antsel_b[macId], pDM_FatTable->antsel_a[macId])); +#endif + } + else if(pDM_Odm->SupportICType == ODM_RTL8188E) + { +#if (RTL8188E_SUPPORT == 1) + SET_TX_DESC_ANTSEL_A_88E(pDesc, pDM_FatTable->antsel_a[macId]); + SET_TX_DESC_ANTSEL_B_88E(pDesc, pDM_FatTable->antsel_b[macId]); + SET_TX_DESC_ANTSEL_C_88E(pDesc, pDM_FatTable->antsel_c[macId]); + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("[8188E] SetTxAntByTxInfo_WIN: MacID=%d, antsel_tr_mux=3'b%d%d%d\n", + //macId, pDM_FatTable->antsel_c[macId], pDM_FatTable->antsel_b[macId], pDM_FatTable->antsel_a[macId])); +#endif + } + else if(pDM_Odm->SupportICType == ODM_RTL8192E) + { + + + } +} +#else// (DM_ODM_SUPPORT_TYPE == ODM_AP) + +VOID +ODM_SetTxAntByTxInfo( + //IN PDM_ODM_T pDM_Odm, + struct rtl8192cd_priv *priv, + struct tx_desc *pdesc, + struct tx_insn *txcfg, + unsigned short aid +) +{ + pFAT_T pDM_FatTable = &priv->pshare->_dmODM.DM_FatTable; + u4Byte SupportICType=priv->pshare->_dmODM.SupportICType; + + if(SupportICType == ODM_RTL8881A) + { + //panic_printk("[%s] [%d] ******ODM_SetTxAntByTxInfo_8881E****** \n",__FUNCTION__,__LINE__); + pdesc->Dword6 &= set_desc(~ (BIT(18)|BIT(17)|BIT(16))); + pdesc->Dword6 |= set_desc(pDM_FatTable->antsel_a[aid]<<16); + } + else if(SupportICType == ODM_RTL8192E) + { + //panic_printk("[%s] [%d] ******ODM_SetTxAntByTxInfo_8192E****** \n",__FUNCTION__,__LINE__); + pdesc->Dword6 &= set_desc(~ (BIT(18)|BIT(17)|BIT(16))); + pdesc->Dword6 |= set_desc(pDM_FatTable->antsel_a[aid]<<16); + } + else if(SupportICType == ODM_RTL8812) + { + //3 [path-A] + //panic_printk("[%s] [%d] ******ODM_SetTxAntByTxInfo_8881E****** \n",__FUNCTION__,__LINE__); + + pdesc->Dword6 &= set_desc(~ BIT(16)); + pdesc->Dword6 &= set_desc(~ BIT(17)); + pdesc->Dword6 &= set_desc(~ BIT(18)); + if(txcfg->pstat) + { + pdesc->Dword6 |= set_desc(pDM_FatTable->antsel_a[aid]<<16); + pdesc->Dword6 |= set_desc(pDM_FatTable->antsel_b[aid]<<17); + pdesc->Dword6 |= set_desc(pDM_FatTable->antsel_c[aid]<<18); + } + } +} +#endif + +#else + +VOID ODM_AntDivInit( IN PDM_ODM_T pDM_Odm ){} +VOID ODM_AntDiv( IN PDM_ODM_T pDM_Odm){} + +#endif //#if (defined(CONFIG_HW_ANTENNA_DIVERSITY)) + + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_AntDiv.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_AntDiv.h new file mode 100644 index 0000000..86574a3 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_AntDiv.h @@ -0,0 +1,136 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#ifndef __ODMANTDIV_H__ +#define __ODMANTDIV_H__ + + + +#define ANT1_2G 0 // = ANT2_5G +#define ANT2_2G 1 // = ANT1_5G + +//Antenna Diversty Control Type +#define ODM_AUTO_ANT 0 +#define ODM_FIX_MAIN_ANT 1 +#define ODM_FIX_AUX_ANT 2 + +#define TX_BY_REG 0 + +#if (DM_ODM_SUPPORT_TYPE != ODM_AP) +#define ODM_RTL8881A 0 //Just for windows driver to jointly use ODM-driver +#endif + +#define ODM_ANTDIV_SUPPORT (ODM_RTL8188E|ODM_RTL8192E|ODM_RTL8723B|ODM_RTL8821|ODM_RTL8881A|ODM_RTL8812) +#define ODM_N_ANTDIV_SUPPORT (ODM_RTL8188E|ODM_RTL8192E|ODM_RTL8723B) +#define ODM_AC_ANTDIV_SUPPORT (ODM_RTL8821|ODM_RTL8881A|ODM_RTL8812) +#define ODM_SMART_ANT_SUPPORT (ODM_RTL8188E|ODM_RTL8192E) + +#define ODM_ANTDIV_2G_SUPPORT_IC (ODM_RTL8188E|ODM_RTL8192E|ODM_RTL8723B|ODM_RTL8881A) +#define ODM_ANTDIV_5G_SUPPORT_IC (ODM_RTL8821|ODM_RTL8881A|ODM_RTL8812) +#define ODM_ANTDIV_2G BIT0 +#define ODM_ANTDIV_5G BIT1 + +#define ANTDIV_ON 1 +#define ANTDIV_OFF 0 + +VOID +ODM_AntDivInit( + IN PDM_ODM_T pDM_Odm +); + +VOID +ODM_AntDiv( + IN PDM_ODM_T pDM_Odm +); + +#if (defined(CONFIG_HW_ANTENNA_DIVERSITY)) + +VOID +ODM_UpdateRxIdleAnt( + IN PDM_ODM_T pDM_Odm, + IN u1Byte Ant +); + +#if (RTL8723B_SUPPORT == 1)||(RTL8821A_SUPPORT == 1) +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +VOID +ODM_SW_AntDiv_Callback( + IN PRT_TIMER pTimer +); + +VOID +ODM_SW_AntDiv_WorkitemCallback( + IN PVOID pContext +); +#endif //#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) +VOID +ODM_SW_AntDiv_Callback(void *FunctionContext); +#endif //#if (DM_ODM_SUPPORT_TYPE == ODM_CE) +#endif + +#if(RTL8188E_SUPPORT == 1 || RTL8192E_SUPPORT == 1) +#if ( !(DM_ODM_SUPPORT_TYPE == ODM_CE)) +VOID +odm_FastAntTraining( + IN PDM_ODM_T pDM_Odm +); + +VOID +odm_FastAntTrainingCallback( + IN PDM_ODM_T pDM_Odm +); + +VOID +odm_FastAntTrainingWorkItemCallback( + IN PDM_ODM_T pDM_Odm +); +#endif +#endif + +VOID +ODM_Process_RSSIForAntDiv( + IN OUT PDM_ODM_T pDM_Odm, + IN PODM_PHY_INFO_T pPhyInfo, + IN PODM_PACKET_INFO_T pPktinfo +); + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) +VOID +ODM_SetTxAntByTxInfo( + IN PDM_ODM_T pDM_Odm, + IN pu1Byte pDesc, + IN u1Byte macId +); + +#else// (DM_ODM_SUPPORT_TYPE == ODM_AP) +VOID +ODM_SetTxAntByTxInfo( + //IN PDM_ODM_T pDM_Odm, + struct rtl8192cd_priv *priv, + struct tx_desc *pdesc, + struct tx_insn *txcfg, + unsigned short aid +); + +#endif + +#endif //#if (defined(CONFIG_HW_ANTENNA_DIVERSITY)) +#endif //#ifndef __ODMANTDIV_H__ diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_HWConfig.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_HWConfig.c new file mode 100644 index 0000000..5f96c94 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_HWConfig.c @@ -0,0 +1,2363 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +//============================================================ +// include files +//============================================================ + + +#include "odm_precomp.h" + +#define READ_AND_CONFIG_MP(ic, txt) (ODM_ReadAndConfig_MP_##ic##txt(pDM_Odm)) +#define READ_AND_CONFIG_TC(ic, txt) (ODM_ReadAndConfig_TC_##ic##txt(pDM_Odm)) + + +#if (TESTCHIP_SUPPORT == 1) +#define READ_AND_CONFIG(ic, txt) do {\ + if (pDM_Odm->bIsMPChip)\ + READ_AND_CONFIG_MP(ic,txt);\ + else\ + READ_AND_CONFIG_TC(ic,txt);\ + } while(0) +#else + #define READ_AND_CONFIG READ_AND_CONFIG_MP +#endif + + +#define READ_FIRMWARE_MP(ic, txt) (ODM_ReadFirmware_MP_##ic##txt(pDM_Odm, pFirmware, pSize)) +#define READ_FIRMWARE_TC(ic, txt) (ODM_ReadFirmware_TC_##ic##txt(pDM_Odm, pFirmware, pSize)) + +#if (TESTCHIP_SUPPORT == 1) +#define READ_FIRMWARE(ic, txt) do {\ + if (pDM_Odm->bIsMPChip)\ + READ_FIRMWARE_MP(ic,txt);\ + else\ + READ_FIRMWARE_TC(ic,txt);\ + } while(0) +#else +#define READ_FIRMWARE READ_FIRMWARE_MP +#endif + +#define GET_VERSION_MP(ic, txt) (ODM_GetVersion_MP_##ic##txt()) +#define GET_VERSION_TC(ic, txt) (ODM_GetVersion_TC_##ic##txt()) + +#define GET_VERSION(ic, txt) do {\ + if (pDM_Odm->bIsMPChip)\ + GET_VERSION_MP(ic,txt);\ + else\ + GET_VERSION_TC(ic,txt);\ + } while(0) + + +u1Byte +odm_QueryRxPwrPercentage( + IN s1Byte AntPower + ) +{ + if ((AntPower <= -100) || (AntPower >= 20)) + { + return 0; + } + else if (AntPower >= 0) + { + return 100; + } + else + { + return (100+AntPower); + } + +} + +#if (DM_ODM_SUPPORT_TYPE != ODM_WIN) +// +// 2012/01/12 MH MOve some signal strength smooth method to MP HAL layer. +// IF other SW team do not support the feature, remove this section.?? +// +s4Byte +odm_SignalScaleMapping_92CSeries_patch_RT_CID_819x_Lenovo( + IN OUT PDM_ODM_T pDM_Odm, + s4Byte CurrSig +) +{ + s4Byte RetSig = 0; +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + //if(pDM_Odm->SupportInterface == ODM_ITRF_PCIE) + { + // Step 1. Scale mapping. + // 20100611 Joseph: Re-tunning RSSI presentation for Lenovo. + // 20100426 Joseph: Modify Signal strength mapping. + // This modification makes the RSSI indication similar to Intel solution. + // 20100414 Joseph: Tunning RSSI for Lenovo according to RTL8191SE. + if(CurrSig >= 54 && CurrSig <= 100) + { + RetSig = 100; + } + else if(CurrSig>=42 && CurrSig <= 53 ) + { + RetSig = 95; + } + else if(CurrSig>=36 && CurrSig <= 41 ) + { + RetSig = 74 + ((CurrSig - 36) *20)/6; + } + else if(CurrSig>=33 && CurrSig <= 35 ) + { + RetSig = 65 + ((CurrSig - 33) *8)/2; + } + else if(CurrSig>=18 && CurrSig <= 32 ) + { + RetSig = 62 + ((CurrSig - 18) *2)/15; + } + else if(CurrSig>=15 && CurrSig <= 17 ) + { + RetSig = 33 + ((CurrSig - 15) *28)/2; + } + else if(CurrSig>=10 && CurrSig <= 14 ) + { + RetSig = 39; + } + else if(CurrSig>=8 && CurrSig <= 9 ) + { + RetSig = 33; + } + else if(CurrSig <= 8 ) + { + RetSig = 19; + } + } +#endif //ENDIF (DM_ODM_SUPPORT_TYPE == ODM_WIN) + return RetSig; +} + +s4Byte +odm_SignalScaleMapping_92CSeries_patch_RT_CID_819x_Netcore( + IN OUT PDM_ODM_T pDM_Odm, + s4Byte CurrSig +) +{ + s4Byte RetSig = 0; +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + //if(pDM_Odm->SupportInterface == ODM_ITRF_USB) + { + // Netcore request this modification because 2009.04.13 SU driver use it. + if(CurrSig >= 31 && CurrSig <= 100) + { + RetSig = 100; + } + else if(CurrSig >= 21 && CurrSig <= 30) + { + RetSig = 90 + ((CurrSig - 20) / 1); + } + else if(CurrSig >= 11 && CurrSig <= 20) + { + RetSig = 80 + ((CurrSig - 10) / 1); + } + else if(CurrSig >= 7 && CurrSig <= 10) + { + RetSig = 69 + (CurrSig - 7); + } + else if(CurrSig == 6) + { + RetSig = 54; + } + else if(CurrSig == 5) + { + RetSig = 45; + } + else if(CurrSig == 4) + { + RetSig = 36; + } + else if(CurrSig == 3) + { + RetSig = 27; + } + else if(CurrSig == 2) + { + RetSig = 18; + } + else if(CurrSig == 1) + { + RetSig = 9; + } + else + { + RetSig = CurrSig; + } + } +#endif //ENDIF (DM_ODM_SUPPORT_TYPE == ODM_WIN) + return RetSig; +} + + +s4Byte +odm_SignalScaleMapping_92CSeries( + IN OUT PDM_ODM_T pDM_Odm, + IN s4Byte CurrSig +) +{ + s4Byte RetSig = 0; +#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) + if(pDM_Odm->SupportInterface == ODM_ITRF_PCIE) + { + // Step 1. Scale mapping. + if(CurrSig >= 61 && CurrSig <= 100) + { + RetSig = 90 + ((CurrSig - 60) / 4); + } + else if(CurrSig >= 41 && CurrSig <= 60) + { + RetSig = 78 + ((CurrSig - 40) / 2); + } + else if(CurrSig >= 31 && CurrSig <= 40) + { + RetSig = 66 + (CurrSig - 30); + } + else if(CurrSig >= 21 && CurrSig <= 30) + { + RetSig = 54 + (CurrSig - 20); + } + else if(CurrSig >= 5 && CurrSig <= 20) + { + RetSig = 42 + (((CurrSig - 5) * 2) / 3); + } + else if(CurrSig == 4) + { + RetSig = 36; + } + else if(CurrSig == 3) + { + RetSig = 27; + } + else if(CurrSig == 2) + { + RetSig = 18; + } + else if(CurrSig == 1) + { + RetSig = 9; + } + else + { + RetSig = CurrSig; + } + } +#endif + +#if ((DEV_BUS_TYPE == RT_USB_INTERFACE) ||(DEV_BUS_TYPE == RT_SDIO_INTERFACE)) + if((pDM_Odm->SupportInterface == ODM_ITRF_USB) || (pDM_Odm->SupportInterface == ODM_ITRF_SDIO)) + { + if(CurrSig >= 51 && CurrSig <= 100) + { + RetSig = 100; + } + else if(CurrSig >= 41 && CurrSig <= 50) + { + RetSig = 80 + ((CurrSig - 40)*2); + } + else if(CurrSig >= 31 && CurrSig <= 40) + { + RetSig = 66 + (CurrSig - 30); + } + else if(CurrSig >= 21 && CurrSig <= 30) + { + RetSig = 54 + (CurrSig - 20); + } + else if(CurrSig >= 10 && CurrSig <= 20) + { + RetSig = 42 + (((CurrSig - 10) * 2) / 3); + } + else if(CurrSig >= 5 && CurrSig <= 9) + { + RetSig = 22 + (((CurrSig - 5) * 3) / 2); + } + else if(CurrSig >= 1 && CurrSig <= 4) + { + RetSig = 6 + (((CurrSig - 1) * 3) / 2); + } + else + { + RetSig = CurrSig; + } + } + +#endif + return RetSig; +} +s4Byte +odm_SignalScaleMapping( + IN OUT PDM_ODM_T pDM_Odm, + IN s4Byte CurrSig +) +{ + if( (pDM_Odm->SupportPlatform == ODM_WIN) && + (pDM_Odm->SupportInterface != ODM_ITRF_PCIE) && //USB & SDIO + (pDM_Odm->PatchID==10))//pMgntInfo->CustomerID == RT_CID_819x_Netcore + { + return odm_SignalScaleMapping_92CSeries_patch_RT_CID_819x_Netcore(pDM_Odm,CurrSig); + } + else if( (pDM_Odm->SupportPlatform == ODM_WIN) && + (pDM_Odm->SupportInterface == ODM_ITRF_PCIE) && + (pDM_Odm->PatchID==19))//pMgntInfo->CustomerID == RT_CID_819x_Lenovo) + { + return odm_SignalScaleMapping_92CSeries_patch_RT_CID_819x_Lenovo(pDM_Odm, CurrSig); + } + else{ + return odm_SignalScaleMapping_92CSeries(pDM_Odm,CurrSig); + } + +} +#endif + + +static u1Byte odm_SQ_process_patch_RT_CID_819x_Lenovo( + IN PDM_ODM_T pDM_Odm, + IN u1Byte isCCKrate, + IN u1Byte PWDB_ALL, + IN u1Byte path, + IN u1Byte RSSI +) +{ + u1Byte SQ = 0; +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) + + if(isCCKrate){ + + if(IS_HARDWARE_TYPE_8723AE(pDM_Odm->Adapter)) + { + + // + // <Roger_Notes> Expected signal strength and bars indication at Lenovo lab. 2013.04.11 + // 802.11n, 802.11b, 802.11g only at channel 6 + // + // Attenuation (dB) OS Signal Bars RSSI by Xirrus (dBm) + // 50 5 -52 + // 55 5 -54 + // 60 5 -55 + // 65 5 -59 + // 70 5 -63 + // 75 5 -66 + // 80 4 -72 + // 85 3 -75 + // 90 3 -80 + // 95 2 -85 + // 100 1 -89 + // 102 1 -90 + // 104 1 -91 + // + RT_TRACE(COMP_DBG, DBG_WARNING, ("odm_SQ_process_patch_RT_CID_819x_Lenovo\n")); + +#if OS_WIN_FROM_WIN8(OS_VERSION) + if(PWDB_ALL >= 50) + SQ = 100; + else if(PWDB_ALL >= 23 && PWDB_ALL < 50) + SQ = 80; + else if(PWDB_ALL >= 18 && PWDB_ALL < 23) + SQ = 60; + else if(PWDB_ALL >= 8 && PWDB_ALL < 18) + SQ = 40; + else + SQ = 10; +#else + if(PWDB_ALL >= 34) + SQ = 100; + else if(PWDB_ALL >= 23 && PWDB_ALL < 34) + SQ = 80; + else if(PWDB_ALL >= 18 && PWDB_ALL < 23) + SQ = 60; + else if(PWDB_ALL >= 8 && PWDB_ALL < 18) + SQ = 40; + else + SQ = 10; + + if(PWDB_ALL == 0)// Abnormal case, do not indicate the value above 20 on Win7 + SQ = 20; +#endif + + } + else if(IS_HARDWARE_TYPE_8192E(pDM_Odm->Adapter)){ + + // + // <Roger_Notes> Expected signal strength and bars indication at Lenovo lab. 2013.04.11 + // 802.11n, 802.11b, 802.11g only at channel 6 + // + // Attenuation (dB) OS Signal Bars RSSI by Xirrus (dBm) + // 50 5 -49 + // 55 5 -49 + // 60 5 -50 + // 65 5 -51 + // 70 5 -52 + // 75 5 -54 + // 80 5 -55 + // 85 4 -60 + // 90 3 -63 + // 95 3 -65 + // 100 2 -67 + // 102 2 -67 + // 104 1 -70 + // + + if(PWDB_ALL >= 50) + SQ = 100; + else if(PWDB_ALL >= 35 && PWDB_ALL < 50) + SQ = 80; + else if(PWDB_ALL >= 31 && PWDB_ALL < 35) + SQ = 60; + else if(PWDB_ALL >= 22 && PWDB_ALL < 31) + SQ = 40; + else if(PWDB_ALL >= 18 && PWDB_ALL < 22) + SQ = 20; + else + SQ = 10; + } + else + { + if(PWDB_ALL >= 50) + SQ = 100; + else if(PWDB_ALL >= 35 && PWDB_ALL < 50) + SQ = 80; + else if(PWDB_ALL >= 22 && PWDB_ALL < 35) + SQ = 60; + else if(PWDB_ALL >= 18 && PWDB_ALL < 22) + SQ = 40; + else + SQ = 10; + } + + } + else + {//OFDM rate + + if(IS_HARDWARE_TYPE_8723AE(pDM_Odm->Adapter) || + IS_HARDWARE_TYPE_8192E(pDM_Odm->Adapter)) + { + if(RSSI >= 45) + SQ = 100; + else if(RSSI >= 22 && RSSI < 45) + SQ = 80; + else if(RSSI >= 18 && RSSI < 22) + SQ = 40; + else + SQ = 20; + } + else + { + if(RSSI >= 45) + SQ = 100; + else if(RSSI >= 22 && RSSI < 45) + SQ = 80; + else if(RSSI >= 18 && RSSI < 22) + SQ = 40; + else + SQ = 20; + } + } + + RT_TRACE(COMP_DBG, DBG_TRACE, ("isCCKrate(%#d), PWDB_ALL(%#d), RSSI(%#d), SQ(%#d)\n", isCCKrate, PWDB_ALL, RSSI, SQ)); + +#endif + return SQ; +} + +static u1Byte odm_SQ_process_patch_RT_CID_819x_Acer( + IN PDM_ODM_T pDM_Odm, + IN u1Byte isCCKrate, + IN u1Byte PWDB_ALL, + IN u1Byte path, + IN u1Byte RSSI +) +{ + u1Byte SQ = 0; + +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) + + if(isCCKrate){ + + RT_TRACE(COMP_DBG, DBG_WARNING, ("odm_SQ_process_patch_RT_Acer\n")); + +#if OS_WIN_FROM_WIN8(OS_VERSION) + + if(PWDB_ALL >= 50) + SQ = 100; + else if(PWDB_ALL >= 35 && PWDB_ALL < 50) + SQ = 80; + else if(PWDB_ALL >= 30 && PWDB_ALL < 35) + SQ = 60; + else if(PWDB_ALL >= 25 && PWDB_ALL < 30) + SQ = 40; + else if(PWDB_ALL >= 20 && PWDB_ALL < 25) + SQ = 20; + else + SQ = 10; +#else + if(PWDB_ALL >= 50) + SQ = 100; + else if(PWDB_ALL >= 35 && PWDB_ALL < 50) + SQ = 80; + else if(PWDB_ALL >= 30 && PWDB_ALL < 35) + SQ = 60; + else if(PWDB_ALL >= 25 && PWDB_ALL < 30) + SQ = 40; + else if(PWDB_ALL >= 20 && PWDB_ALL < 25) + SQ = 20; + else + SQ = 10; + + if(PWDB_ALL == 0)// Abnormal case, do not indicate the value above 20 on Win7 + SQ = 20; +#endif + + + + } + else + {//OFDM rate + + if(IS_HARDWARE_TYPE_8723AE(pDM_Odm->Adapter) || + IS_HARDWARE_TYPE_8192E(pDM_Odm->Adapter)) + { + if(RSSI >= 45) + SQ = 100; + else if(RSSI >= 22 && RSSI < 45) + SQ = 80; + else if(RSSI >= 18 && RSSI < 22) + SQ = 40; + else + SQ = 20; + } + else + { + if(RSSI >= 35) + SQ = 100; + else if(RSSI >= 30 && RSSI < 35) + SQ = 80; + else if(RSSI >= 25 && RSSI < 30) + SQ = 40; + else + SQ = 20; + } + } + + RT_TRACE(COMP_DBG, DBG_LOUD, ("isCCKrate(%#d), PWDB_ALL(%#d), RSSI(%#d), SQ(%#d)\n", isCCKrate, PWDB_ALL, RSSI, SQ)); + +#endif + return SQ; +} + +static u1Byte +odm_EVMdbToPercentage( + IN s1Byte Value + ) +{ + // + // -33dB~0dB to 0%~99% + // + s1Byte ret_val; + + ret_val = Value; + ret_val /= 2; + + //DbgPrint("Value=%d\n", Value); + //ODM_RT_DISP(FRX, RX_PHY_SQ, ("EVMdbToPercentage92C Value=%d / %x \n", ret_val, ret_val)); + + if(ret_val >= 0) + ret_val = 0; + if(ret_val <= -33) + ret_val = -33; + + ret_val = 0 - ret_val; + ret_val*=3; + + if(ret_val == 99) + ret_val = 100; + + return(ret_val); +} + +static u1Byte +odm_EVMdbm_JaguarSeries( + IN s1Byte Value + ) +{ + s1Byte ret_val = Value; + + // -33dB~0dB to 33dB ~ 0dB + if(ret_val == -128) + ret_val = 127; + else if (ret_val < 0) + ret_val = 0 - ret_val; + + ret_val = ret_val >> 1; + return ret_val; +} + +static u2Byte +odm_Cfo( + IN s1Byte Value +) +{ + s2Byte ret_val; + + if (Value < 0) + { + ret_val = 0 - Value; + ret_val = (ret_val << 1) + (ret_val >> 1) ; // *2.5~=312.5/2^7 + ret_val = ret_val | BIT12; // set bit12 as 1 for negative cfo + } + else + { + ret_val = Value; + ret_val = (ret_val << 1) + (ret_val>>1) ; // *2.5~=312.5/2^7 + } + return ret_val; +} + + +VOID +odm_RxPhyStatus92CSeries_Parsing( + IN OUT PDM_ODM_T pDM_Odm, + OUT PODM_PHY_INFO_T pPhyInfo, + IN pu1Byte pPhyStatus, + IN PODM_PACKET_INFO_T pPktinfo + ) +{ + SWAT_T *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table; + u1Byte i, Max_spatial_stream; + s1Byte rx_pwr[4], rx_pwr_all=0; + u1Byte EVM, PWDB_ALL = 0, PWDB_ALL_BT; + u1Byte RSSI, total_rssi=0; + BOOLEAN isCCKrate=FALSE; + u1Byte rf_rx_num = 0; + u1Byte cck_highpwr = 0; + u1Byte LNA_idx, VGA_idx; + PPHY_STATUS_RPT_8192CD_T pPhyStaRpt = (PPHY_STATUS_RPT_8192CD_T)pPhyStatus; + + isCCKrate = (pPktinfo->DataRate <= DESC_RATE11M)?TRUE :FALSE; + pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = -1; + pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1; + + + if(isCCKrate) + { + u1Byte report; + u1Byte cck_agc_rpt; + + pDM_Odm->PhyDbgInfo.NumQryPhyStatusCCK++; + // + // (1)Hardware does not provide RSSI for CCK + // (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) + // + + //if(pHalData->eRFPowerState == eRfOn) + cck_highpwr = pDM_Odm->bCckHighPower; + //else + // cck_highpwr = FALSE; + + cck_agc_rpt = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a ; + + //2011.11.28 LukeLee: 88E use different LNA & VGA gain table + //The RSSI formula should be modified according to the gain table + //In 88E, cck_highpwr is always set to 1 + if(pDM_Odm->SupportICType & (ODM_RTL8188E|ODM_RTL8192E|ODM_RTL8723B)) + { + LNA_idx = ((cck_agc_rpt & 0xE0) >>5); + VGA_idx = (cck_agc_rpt & 0x1F); + if(pDM_Odm->SupportICType & (ODM_RTL8188E|ODM_RTL8192E)) + { + switch(LNA_idx) + { + case 7: + if(VGA_idx <= 27) + rx_pwr_all = -100 + 2*(27-VGA_idx); //VGA_idx = 27~2 + else + rx_pwr_all = -100; + break; + case 6: + rx_pwr_all = -48 + 2*(2-VGA_idx); //VGA_idx = 2~0 + break; + case 5: + rx_pwr_all = -42 + 2*(7-VGA_idx); //VGA_idx = 7~5 + break; + case 4: + rx_pwr_all = -36 + 2*(7-VGA_idx); //VGA_idx = 7~4 + break; + case 3: + //rx_pwr_all = -28 + 2*(7-VGA_idx); //VGA_idx = 7~0 + rx_pwr_all = -24 + 2*(7-VGA_idx); //VGA_idx = 7~0 + break; + case 2: + if(cck_highpwr) + rx_pwr_all = -12 + 2*(5-VGA_idx); //VGA_idx = 5~0 + else + rx_pwr_all = -6+ 2*(5-VGA_idx); + break; + case 1: + rx_pwr_all = 8-2*VGA_idx; + break; + case 0: + rx_pwr_all = 14-2*VGA_idx; + break; + default: + //DbgPrint("CCK Exception default\n"); + break; + } + rx_pwr_all += 6; + + //2012.10.08 LukeLee: Modify for 92E CCK RSSI + if(pDM_Odm->SupportICType == ODM_RTL8192E) + rx_pwr_all += 10; + + PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); + if(cck_highpwr == FALSE) + { + if(PWDB_ALL >= 80) + PWDB_ALL = ((PWDB_ALL-80)<<1)+((PWDB_ALL-80)>>1)+80; + else if((PWDB_ALL <= 78) && (PWDB_ALL >= 20)) + PWDB_ALL += 3; + if(PWDB_ALL>100) + PWDB_ALL = 100; + } + } + else if(pDM_Odm->SupportICType & (ODM_RTL8723B)) + { +#if (RTL8723B_SUPPORT == 1) + rx_pwr_all = odm_CCKRSSI_8723B(LNA_idx,VGA_idx); + PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); + if(PWDB_ALL>100) + PWDB_ALL = 100; +#endif + } + } + else + { + if(!cck_highpwr) + { + report =( cck_agc_rpt & 0xc0 )>>6; + switch(report) + { + // 03312009 modified by cosa + // Modify the RF RNA gain value to -40, -20, -2, 14 by Jenyu's suggestion + // Note: different RF with the different RNA gain. + case 0x3: + rx_pwr_all = -46 - (cck_agc_rpt & 0x3e); + break; + case 0x2: + rx_pwr_all = -26 - (cck_agc_rpt & 0x3e); + break; + case 0x1: + rx_pwr_all = -12 - (cck_agc_rpt & 0x3e); + break; + case 0x0: + rx_pwr_all = 16 - (cck_agc_rpt & 0x3e); + break; + } + } + else + { + //report = pDrvInfo->cfosho[0] & 0x60; + //report = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a& 0x60; + + report = (cck_agc_rpt & 0x60)>>5; + switch(report) + { + case 0x3: + rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f)<<1) ; + break; + case 0x2: + rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f)<<1); + break; + case 0x1: + rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f)<<1) ; + break; + case 0x0: + rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f)<<1) ; + break; + } + } + + PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); + + //Modification for ext-LNA board + if(pDM_Odm->BoardType & (ODM_BOARD_EXT_LNA | ODM_BOARD_EXT_PA)) + { + if((cck_agc_rpt>>7) == 0){ + PWDB_ALL = (PWDB_ALL>94)?100:(PWDB_ALL +6); + } + else + { + if(PWDB_ALL > 38) + PWDB_ALL -= 16; + else + PWDB_ALL = (PWDB_ALL<=16)?(PWDB_ALL>>2):(PWDB_ALL -12); + } + + //CCK modification + if(PWDB_ALL > 25 && PWDB_ALL <= 60) + PWDB_ALL += 6; + //else if (PWDB_ALL <= 25) + // PWDB_ALL += 8; + } + else//Modification for int-LNA board + { + if(PWDB_ALL > 99) + PWDB_ALL -= 8; + else if(PWDB_ALL > 50 && PWDB_ALL <= 68) + PWDB_ALL += 4; + } + } + + pPhyInfo->RxPWDBAll = PWDB_ALL; +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + pPhyInfo->BTRxRSSIPercentage = PWDB_ALL; + pPhyInfo->RecvSignalPower = rx_pwr_all; +#endif + // + // (3) Get Signal Quality (EVM) + // + //if(pPktinfo->bPacketMatchBSSID) + { + u1Byte SQ,SQ_rpt; + + if((pDM_Odm->SupportPlatform == ODM_WIN) && + (pDM_Odm->PatchID==RT_CID_819x_Lenovo)){ + SQ = odm_SQ_process_patch_RT_CID_819x_Lenovo(pDM_Odm,isCCKrate,PWDB_ALL,0,0); + } + else if((pDM_Odm->SupportPlatform == ODM_WIN) && + (pDM_Odm->PatchID==RT_CID_819x_Acer)) + { + SQ = odm_SQ_process_patch_RT_CID_819x_Acer(pDM_Odm,isCCKrate,PWDB_ALL,0,0); + } + else if(pPhyInfo->RxPWDBAll > 40 && !pDM_Odm->bInHctTest){ + SQ = 100; + } + else{ + SQ_rpt = pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all; + + if(SQ_rpt > 64) + SQ = 0; + else if (SQ_rpt < 20) + SQ = 100; + else + SQ = ((64-SQ_rpt) * 100) / 44; + + } + + //DbgPrint("cck SQ = %d\n", SQ); + pPhyInfo->SignalQuality = SQ; + pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = SQ; + pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1; + } + } + else //is OFDM rate + { + pDM_Odm->PhyDbgInfo.NumQryPhyStatusOFDM++; + + // + // (1)Get RSSI for HT rate + // + + for(i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX; i++) + { + // 2008/01/30 MH we will judge RF RX path now. + if (pDM_Odm->RFPathRxEnable & BIT(i)) + rf_rx_num++; + //else + //continue; + + rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain& 0x3F)*2) - 110; + + + #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + pPhyInfo->RxPwr[i] = rx_pwr[i]; + #endif + + /* Translate DBM to percentage. */ + RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]); + total_rssi += RSSI; + //RT_DISP(FRX, RX_PHY_SS, ("RF-%d RXPWR=%x RSSI=%d\n", i, rx_pwr[i], RSSI)); + + //Modification for ext-LNA board + if(pDM_Odm->SupportICType&ODM_RTL8192C) + { + if(pDM_Odm->BoardType & (ODM_BOARD_EXT_LNA | ODM_BOARD_EXT_PA)) + { + if((pPhyStaRpt->path_agc[i].trsw) == 1) + RSSI = (RSSI>94)?100:(RSSI +6); + else + RSSI = (RSSI<=16)?(RSSI>>3):(RSSI -16); + + if((RSSI <= 34) && (RSSI >=4)) + RSSI -= 4; + } + } + + pPhyInfo->RxMIMOSignalStrength[i] =(u1Byte) RSSI; + + #if (DM_ODM_SUPPORT_TYPE & (/*ODM_WIN|*/ODM_CE|ODM_AP|ODM_ADSL)) + //Get Rx snr value in DB + pPhyInfo->RxSNR[i] = pDM_Odm->PhyDbgInfo.RxSNRdB[i] = (s4Byte)(pPhyStaRpt->path_rxsnr[i]/2); + #endif + + /* Record Signal Strength for next packet */ + //if(pPktinfo->bPacketMatchBSSID) + { + if((pDM_Odm->SupportPlatform == ODM_WIN) && + (pDM_Odm->PatchID==RT_CID_819x_Lenovo)) + { + if(i==ODM_RF_PATH_A) + pPhyInfo->SignalQuality = odm_SQ_process_patch_RT_CID_819x_Lenovo(pDM_Odm,isCCKrate,PWDB_ALL,i,RSSI); + + } + else if((pDM_Odm->SupportPlatform == ODM_WIN) && + (pDM_Odm->PatchID==RT_CID_819x_Acer)) + { + pPhyInfo->SignalQuality = odm_SQ_process_patch_RT_CID_819x_Acer(pDM_Odm,isCCKrate,PWDB_ALL,0,RSSI); + } + + } + } + + + // + // (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) + // + rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1 )& 0x7f) -110; + + PWDB_ALL_BT = PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); + //RT_DISP(FRX, RX_PHY_SS, ("PWDB_ALL=%d\n",PWDB_ALL)); + + pPhyInfo->RxPWDBAll = PWDB_ALL; + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_RSSI_MONITOR, ODM_DBG_LOUD, ("ODM OFDM RSSI=%d\n",pPhyInfo->RxPWDBAll)); + #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + pPhyInfo->BTRxRSSIPercentage = PWDB_ALL_BT; + pPhyInfo->RxPower = rx_pwr_all; + pPhyInfo->RecvSignalPower = rx_pwr_all; + #endif + + if((pDM_Odm->SupportPlatform == ODM_WIN) &&(pDM_Odm->PatchID==19)){ + //do nothing + }else if((pDM_Odm->SupportPlatform == ODM_WIN) &&(pDM_Odm->PatchID==25)){ + //do nothing + } + else{//pMgntInfo->CustomerID != RT_CID_819x_Lenovo + // + // (3)EVM of HT rate + // + if(pPktinfo->DataRate >=DESC_RATEMCS8 && pPktinfo->DataRate <=DESC_RATEMCS15) + Max_spatial_stream = 2; //both spatial stream make sense + else + Max_spatial_stream = 1; //only spatial stream 1 makes sense + + for(i=0; i<Max_spatial_stream; i++) + { + // Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment + // fill most significant bit to "zero" when doing shifting operation which may change a negative + // value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. + EVM = odm_EVMdbToPercentage( (pPhyStaRpt->stream_rxevm[i] )); //dbm + + //RT_DISP(FRX, RX_PHY_SQ, ("RXRATE=%x RXEVM=%x EVM=%s%d\n", + //GET_RX_STATUS_DESC_RX_MCS(pDesc), pDrvInfo->rxevm[i], "%", EVM)); + + //if(pPktinfo->bPacketMatchBSSID) + { + if(i==ODM_RF_PATH_A) // Fill value in RFD, Get the first spatial stream only + { + pPhyInfo->SignalQuality = (u1Byte)(EVM & 0xff); + } + pPhyInfo->RxMIMOSignalQuality[i] = (u1Byte)(EVM & 0xff); + } + } + } + + //2 For dynamic ATC switch + if(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_ATC) + { + if(pPktinfo->bPacketMatchBSSID && ( *(pDM_Odm->mp_mode) == 0)) + { + // TODO: + + //3 Update CFO report for path-A & path-B + for(i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX; i++) + { + pDM_Odm->CFO_tail[i] = (int)pPhyStaRpt->path_cfotail[i]; + } + + //3 Update packet counter + if(pDM_Odm->packetCount == 0xffffffff) + pDM_Odm->packetCount = 0; + else + pDM_Odm->packetCount++; + + //ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, + //("pPhyStaRpt->path_cfotail[i] = 0x%x, pDM_Odm->CFO_tail[i] = 0x%x\n", pPhyStaRpt->path_cfotail[0], pDM_Odm->CFO_tail[1])); + } + } + + } +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + //UI BSS List signal strength(in percentage), make it good looking, from 0~100. + //It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). + if(isCCKrate) + { +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + // 2012/01/12 MH Use customeris signal strength from HalComRxdDesc.c/ + pPhyInfo->SignalStrength = (u1Byte)(SignalScaleMapping(pDM_Odm->Adapter, PWDB_ALL));//PWDB_ALL; +#else +#ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING + pPhyInfo->SignalStrength = (u1Byte)PWDB_ALL; +#else + pPhyInfo->SignalStrength = (u1Byte)(odm_SignalScaleMapping(pDM_Odm, PWDB_ALL));//PWDB_ALL; +#endif +#endif + } + else + { + if (rf_rx_num != 0) + { +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + // 2012/01/12 MH Use customeris signal strength from HalComRxdDesc.c/ + pPhyInfo->SignalStrength = (u1Byte)(SignalScaleMapping(pDM_Odm->Adapter, total_rssi/=rf_rx_num));//PWDB_ALL; +#else +#ifdef CONFIG_SKIP_SIGNAL_SCALE_MAPPING + total_rssi/=rf_rx_num; + pPhyInfo->SignalStrength = (u1Byte)total_rssi; +#else + pPhyInfo->SignalStrength = (u1Byte)(odm_SignalScaleMapping(pDM_Odm, total_rssi/=rf_rx_num)); +#endif +#endif + } + } +#endif + + //DbgPrint("isCCKrate = %d, pPhyInfo->RxPWDBAll = %d, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a = 0x%x\n", + //isCCKrate, pPhyInfo->RxPWDBAll, pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a); + + //For 92C/92D HW (Hybrid) Antenna Diversity +#if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) + pDM_SWAT_Table->antsel = pPhyStaRpt->ant_sel; + //For 88E HW Antenna Diversity + pDM_Odm->DM_FatTable.antsel_rx_keep_0 = pPhyStaRpt->ant_sel; + pDM_Odm->DM_FatTable.antsel_rx_keep_1 = pPhyStaRpt->ant_sel_b; + pDM_Odm->DM_FatTable.antsel_rx_keep_2 = pPhyStaRpt->antsel_rx_keep_2; +#endif +} + +#if ODM_IC_11AC_SERIES_SUPPORT + +VOID +odm_RxPhyStatusJaguarSeries_Parsing( + IN OUT PDM_ODM_T pDM_Odm, + OUT PODM_PHY_INFO_T pPhyInfo, + IN pu1Byte pPhyStatus, + IN PODM_PACKET_INFO_T pPktinfo + ) +{ + u1Byte i, Max_spatial_stream; + s1Byte rx_pwr[4], rx_pwr_all=0; + u1Byte EVM = 0, EVMdbm, PWDB_ALL = 0, PWDB_ALL_BT; + u1Byte RSSI, total_rssi=0; + u1Byte isCCKrate=0; + u1Byte rf_rx_num = 0; + u1Byte cck_highpwr = 0; + u1Byte LNA_idx, VGA_idx; + + + PPHY_STATUS_RPT_8812_T pPhyStaRpt = (PPHY_STATUS_RPT_8812_T)pPhyStatus; + + if(pPktinfo->DataRate <= DESC_RATE54M) + { + switch(pPhyStaRpt->r_RFMOD){ + case 1: + if(pPhyStaRpt->sub_chnl == 0) + pPhyInfo->BandWidth = 1; + else + pPhyInfo->BandWidth = 0; + break; + + case 2: + if(pPhyStaRpt->sub_chnl == 0) + pPhyInfo->BandWidth = 2; + else if(pPhyStaRpt->sub_chnl == 9 || pPhyStaRpt->sub_chnl == 10) + pPhyInfo->BandWidth = 1; + else + pPhyInfo->BandWidth = 0; + break; + + default: case 0: + pPhyInfo->BandWidth = 0; + break; + } + } + + if(pPktinfo->DataRate <= DESC_RATE11M) + isCCKrate = TRUE; + else + isCCKrate = FALSE; + + pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = -1; + pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1; + + + if(isCCKrate) + { + u1Byte cck_agc_rpt; + pDM_Odm->PhyDbgInfo.NumQryPhyStatusCCK++; + // + // (1)Hardware does not provide RSSI for CCK + // (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) + // + + //if(pHalData->eRFPowerState == eRfOn) + cck_highpwr = pDM_Odm->bCckHighPower; + //else + // cck_highpwr = FALSE; + + cck_agc_rpt = pPhyStaRpt->cfosho[0] ; + + LNA_idx = ((cck_agc_rpt & 0xE0) >>5); + VGA_idx = (cck_agc_rpt & 0x1F); + if(pDM_Odm->SupportICType == ODM_RTL8812) + { + switch(LNA_idx) + { + case 7: + if(VGA_idx <= 27) + rx_pwr_all = -100 + 2*(27-VGA_idx); //VGA_idx = 27~2 + else + rx_pwr_all = -100; + break; + case 6: + rx_pwr_all = -48 + 2*(2-VGA_idx); //VGA_idx = 2~0 + break; + case 5: + rx_pwr_all = -42 + 2*(7-VGA_idx); //VGA_idx = 7~5 + break; + case 4: + rx_pwr_all = -36 + 2*(7-VGA_idx); //VGA_idx = 7~4 + break; + case 3: + //rx_pwr_all = -28 + 2*(7-VGA_idx); //VGA_idx = 7~0 + rx_pwr_all = -24 + 2*(7-VGA_idx); //VGA_idx = 7~0 + break; + case 2: + if(cck_highpwr) + rx_pwr_all = -12 + 2*(5-VGA_idx); //VGA_idx = 5~0 + else + rx_pwr_all = -6+ 2*(5-VGA_idx); + break; + case 1: + rx_pwr_all = 8-2*VGA_idx; + break; + case 0: + rx_pwr_all = 14-2*VGA_idx; + break; + default: + //DbgPrint("CCK Exception default\n"); + break; + } + rx_pwr_all += 6; + PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); + if(cck_highpwr == FALSE) + { + if(PWDB_ALL >= 80) + PWDB_ALL = ((PWDB_ALL-80)<<1)+((PWDB_ALL-80)>>1)+80; + else if((PWDB_ALL <= 78) && (PWDB_ALL >= 20)) + PWDB_ALL += 3; + if(PWDB_ALL>100) + PWDB_ALL = 100; + } + } + else if(pDM_Odm->SupportICType == ODM_RTL8821) + { + s1Byte Pout = -6; + + switch(LNA_idx) + { + case 5: + rx_pwr_all = Pout -32 -(2*VGA_idx); + break; + case 4: + rx_pwr_all = Pout -24 -(2*VGA_idx); + break; + case 2: + rx_pwr_all = Pout -11 -(2*VGA_idx); + break; + case 1: + rx_pwr_all = Pout + 5 -(2*VGA_idx); + break; + case 0: + rx_pwr_all = Pout + 21 -(2*VGA_idx); + break; + } + PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); + } + + pPhyInfo->RxPWDBAll = PWDB_ALL; + //if(pPktinfo->StationID == 0) + //{ + // DbgPrint("CCK: LNA_idx = %d, VGA_idx = %d, pPhyInfo->RxPWDBAll = %d\n", + // LNA_idx, VGA_idx, pPhyInfo->RxPWDBAll); + //} +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + pPhyInfo->BTRxRSSIPercentage = PWDB_ALL; + pPhyInfo->RecvSignalPower = rx_pwr_all; +#endif + // + // (3) Get Signal Quality (EVM) + // + //if(pPktinfo->bPacketMatchBSSID) + { + u1Byte SQ,SQ_rpt; + + if((pDM_Odm->SupportPlatform == ODM_WIN) && + (pDM_Odm->PatchID==RT_CID_819x_Lenovo)){ + SQ = odm_SQ_process_patch_RT_CID_819x_Lenovo(pDM_Odm,isCCKrate,PWDB_ALL,0,0); + } + else if(pPhyInfo->RxPWDBAll > 40 && !pDM_Odm->bInHctTest){ + SQ = 100; + } + else{ + SQ_rpt = pPhyStaRpt->pwdb_all; + + if(SQ_rpt > 64) + SQ = 0; + else if (SQ_rpt < 20) + SQ = 100; + else + SQ = ((64-SQ_rpt) * 100) / 44; + + } + + //DbgPrint("cck SQ = %d\n", SQ); + pPhyInfo->SignalQuality = SQ; + pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_A] = SQ; + pPhyInfo->RxMIMOSignalQuality[ODM_RF_PATH_B] = -1; + } + } + else //is OFDM rate + { + pDM_Odm->PhyDbgInfo.NumQryPhyStatusOFDM++; + + // + // (1)Get RSSI for OFDM rate + // + + for(i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX; i++) + { + // 2008/01/30 MH we will judge RF RX path now. + //DbgPrint("pDM_Odm->RFPathRxEnable = %x\n", pDM_Odm->RFPathRxEnable); + if (pDM_Odm->RFPathRxEnable & BIT(i)) + { + rf_rx_num++; + } + //else + //continue; + //2012.05.25 LukeLee: Testchip AGC report is wrong, it should be restored back to old formula in MP chip + //if((pDM_Odm->SupportICType & (ODM_RTL8812|ODM_RTL8821)) && (!pDM_Odm->bIsMPChip)) + rx_pwr[i] = (pPhyStaRpt->gain_trsw[i]&0x7F) - 110; + //else + // rx_pwr[i] = ((pPhyStaRpt->gain_trsw[i]& 0x3F)*2) - 110; //OLD FORMULA + + #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + pPhyInfo->RxPwr[i] = rx_pwr[i]; + #endif + + /* Translate DBM to percentage. */ + RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]); + + total_rssi += RSSI; + //RT_DISP(FRX, RX_PHY_SS, ("RF-%d RXPWR=%x RSSI=%d\n", i, rx_pwr[i], RSSI)); + + + + pPhyInfo->RxMIMOSignalStrength[i] =(u1Byte) RSSI; + + #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE|ODM_AP|ODM_ADSL)) + //Get Rx snr value in DB + pPhyInfo->RxSNR[i] = pDM_Odm->PhyDbgInfo.RxSNRdB[i] = pPhyStaRpt->rxsnr[i]/2; + #endif + + // + // (2) CFO_short & CFO_tail + // + pPhyInfo->Cfo_short[i] = odm_Cfo( (pPhyStaRpt->cfosho[i]) ); + pPhyInfo->Cfo_tail[i] = odm_Cfo( (pPhyStaRpt->cfotail[i]) ); + + /* Record Signal Strength for next packet */ + //if(pPktinfo->bPacketMatchBSSID) + { + if((pDM_Odm->SupportPlatform == ODM_WIN) && + (pDM_Odm->PatchID==RT_CID_819x_Lenovo)) + { + if(i==ODM_RF_PATH_A) + pPhyInfo->SignalQuality = odm_SQ_process_patch_RT_CID_819x_Lenovo(pDM_Odm,isCCKrate,PWDB_ALL,i,RSSI); + + } + } + } + + + // + // (3)PWDB, Average PWDB cacluated by hardware (for rate adaptive) + // + //2012.05.25 LukeLee: Testchip AGC report is wrong, it should be restored back to old formula in MP chip + if((pDM_Odm->SupportICType & (ODM_RTL8812|ODM_RTL8821)) && (!pDM_Odm->bIsMPChip)) + rx_pwr_all = (pPhyStaRpt->pwdb_all& 0x7f) -110; + else + rx_pwr_all = (((pPhyStaRpt->pwdb_all) >> 1 )& 0x7f) -110; //OLD FORMULA + + + PWDB_ALL_BT = PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all); + + + pPhyInfo->RxPWDBAll = PWDB_ALL; + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_RSSI_MONITOR, ODM_DBG_LOUD, ("ODM OFDM RSSI=%d\n",pPhyInfo->RxPWDBAll)); + #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + pPhyInfo->BTRxRSSIPercentage = PWDB_ALL_BT; + pPhyInfo->RxPower = rx_pwr_all; + pPhyInfo->RecvSignalPower = rx_pwr_all; + #endif + + //DbgPrint("OFDM: pPhyInfo->RxPWDBAll = %d, pPhyInfo->RxMIMOSignalStrength[0] = %d, pPhyInfo->RxMIMOSignalStrength[1] = %d\n", + // pPhyInfo->RxPWDBAll, pPhyInfo->RxMIMOSignalStrength[0], pPhyInfo->RxMIMOSignalStrength[1]); + + + if((pDM_Odm->SupportPlatform == ODM_WIN) &&(pDM_Odm->PatchID==19)){ + //do nothing + } + else{//pMgntInfo->CustomerID != RT_CID_819x_Lenovo + // + // (4)EVM of OFDM rate + // + if( (pPktinfo->DataRate>=DESC_RATEMCS8) && + (pPktinfo->DataRate <=DESC_RATEMCS15)) + Max_spatial_stream = 2; + else if( (pPktinfo->DataRate>=DESC_RATEVHTSS2MCS0) && + (pPktinfo->DataRate <=DESC_RATEVHTSS2MCS9)) + Max_spatial_stream = 2; + else + Max_spatial_stream = 1; + + //if(pPktinfo->bPacketMatchBSSID) + { + //DbgPrint("pPktinfo->DataRate = %d\n", pPktinfo->DataRate); + + for(i=0; i<Max_spatial_stream; i++) + { + // Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment + // fill most significant bit to "zero" when doing shifting operation which may change a negative + // value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore. + // + // 2013/09/02 MH According to 8812AU test, when use RX evm the value sometimes + // will be incorrect and 1SS-MCS-0-7 always incorrect. Only use LSIG the evm value + // seems ok. This seems BB bug, we need use another way to display better SQ. + // + //if (pPktinfo->DataRate>=DESC8812_RATE6M && pPktinfo->DataRate<=DESC8812_RATE54M) + { + + if(i==ODM_RF_PATH_A ) + { + EVM = odm_EVMdbToPercentage( (pPhyStaRpt->sigevm )); //dbm + EVM += 20; + if (EVM > 100) + EVM = 100; + } + } +#if 0 + else + { + if (pPhyStaRpt->rxevm[i] == -128) + { + pPhyStaRpt->rxevm[i] = -25; + } + EVM = odm_EVMdbToPercentage( (pPhyStaRpt->rxevm[i] )); //dbm + } +#endif + EVMdbm = odm_EVMdbm_JaguarSeries(pPhyStaRpt->rxevm[i]); + //RT_DISP(FRX, RX_PHY_SQ, ("RXRATE=%x RXEVM=%x EVM=%s%d\n", + //pPktinfo->DataRate, pPhyStaRpt->rxevm[i], "%", EVM)); + + + { + if(i==ODM_RF_PATH_A) // Fill value in RFD, Get the first spatial stream only + { + pPhyInfo->SignalQuality = EVM; + } + pPhyInfo->RxMIMOSignalQuality[i] = EVM; + pPhyInfo->RxMIMOEVMdbm[i] = EVMdbm; + } + } + } + } + //2 For dynamic ATC switch + if(pDM_Odm->SupportAbility & ODM_BB_DYNAMIC_ATC) + { + if(pPktinfo->bPacketMatchBSSID && ( *(pDM_Odm->mp_mode) == 0) ) + { + //3 Update CFO report for path-A & path-B + for(i = ODM_RF_PATH_A; i < ODM_RF_PATH_MAX; i++) + { + pDM_Odm->CFO_tail[i] = (int)pPhyStaRpt->cfotail[i]; + } + + //3 Update packet counter + if(pDM_Odm->packetCount == 0xffffffff) + pDM_Odm->packetCount = 0; + else + pDM_Odm->packetCount++; + + //ODM_RT_TRACE(pDM_Odm, ODM_COMP_DYNAMIC_ATC, ODM_DBG_LOUD, + //("pPhyStaRpt->path_cfotail[i] = 0x%x, pDM_Odm->CFO_tail[i] = 0x%x\n", pPhyStaRpt->path_cfotail[0], pDM_Odm->CFO_tail[1])); + } + } + } + //DbgPrint("isCCKrate= %d, pPhyInfo->SignalStrength=%d % PWDB_AL=%d rf_rx_num=%d\n", isCCKrate, pPhyInfo->SignalStrength, PWDB_ALL, rf_rx_num); + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) + //UI BSS List signal strength(in percentage), make it good looking, from 0~100. + //It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). + if(isCCKrate) + { +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + // 2012/01/12 MH Use customeris signal strength from HalComRxdDesc.c/ + pPhyInfo->SignalStrength = (u1Byte)(SignalScaleMapping(pDM_Odm->Adapter, PWDB_ALL));//PWDB_ALL; +#else + pPhyInfo->SignalStrength = (u1Byte)(odm_SignalScaleMapping(pDM_Odm, PWDB_ALL));//PWDB_ALL; +#endif + } + else + { + if (rf_rx_num != 0) + { +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + // 2012/01/12 MH Use customeris signal strength from HalComRxdDesc.c/ + pPhyInfo->SignalStrength = (u1Byte)(SignalScaleMapping(pDM_Odm->Adapter, total_rssi/=rf_rx_num));//PWDB_ALL; +#else + pPhyInfo->SignalStrength = (u1Byte)(odm_SignalScaleMapping(pDM_Odm, total_rssi/=rf_rx_num)); +#endif + } + } +#endif + pDM_Odm->RxPWDBAve = pDM_Odm->RxPWDBAve + pPhyInfo->RxPWDBAll; + + pDM_Odm->DM_FatTable.antsel_rx_keep_0 = pPhyStaRpt->antidx_anta; + pDM_Odm->DM_FatTable.antsel_rx_keep_1 = pPhyStaRpt->antidx_antb; + + //DbgPrint("pPhyStaRpt->antidx_anta = %d, pPhyStaRpt->antidx_antb = %d, pPhyStaRpt->resvd_1 = %d", + // pPhyStaRpt->antidx_anta, pPhyStaRpt->antidx_antb, pPhyStaRpt->resvd_1); + + //DbgPrint("----------------------------\n"); + //DbgPrint("pPktinfo->StationID=%d, pPktinfo->DataRate=0x%x\n",pPktinfo->StationID, pPktinfo->DataRate); + //DbgPrint("pPhyStaRpt->gain_trsw[0]=0x%x, pPhyStaRpt->gain_trsw[1]=0x%x, pPhyStaRpt->pwdb_all=0x%x\n", + // pPhyStaRpt->gain_trsw[0],pPhyStaRpt->gain_trsw[1], pPhyStaRpt->pwdb_all); + //DbgPrint("pPhyInfo->RxMIMOSignalStrength[0]=%d, pPhyInfo->RxMIMOSignalStrength[1]=%d, RxPWDBAll=%d\n", + // pPhyInfo->RxMIMOSignalStrength[0], pPhyInfo->RxMIMOSignalStrength[1], pPhyInfo->RxPWDBAll); + +} + +#endif + +VOID +odm_Init_RSSIForDM( + IN OUT PDM_ODM_T pDM_Odm + ) +{ + +} + +VOID +odm_Process_RSSIForDM( + IN OUT PDM_ODM_T pDM_Odm, + IN PODM_PHY_INFO_T pPhyInfo, + IN PODM_PACKET_INFO_T pPktinfo + ) +{ + + s4Byte UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK, UndecoratedSmoothedOFDM, RSSI_Ave; + u1Byte isCCKrate=0; + u1Byte RSSI_max, RSSI_min, i; + u4Byte OFDM_pkt=0; + u4Byte Weighting=0; + PSTA_INFO_T pEntry; + + + if (pPktinfo->StationID >= ODM_ASSOCIATE_ENTRY_NUM) + return; + + // + // 2012/05/30 MH/Luke.Lee Add some description + // In windows driver: AP/IBSS mode STA + // + //if (pDM_Odm->SupportPlatform == ODM_WIN) + //{ + // pEntry = pDM_Odm->pODM_StaInfo[pDM_Odm->pAidMap[pPktinfo->StationID-1]]; + //} + //else + pEntry = pDM_Odm->pODM_StaInfo[pPktinfo->StationID]; + + if(!IS_STA_VALID(pEntry) ){ + return; + } + if((!pPktinfo->bPacketMatchBSSID) ) + { + return; + } + + if(pPktinfo->bPacketBeacon) + pDM_Odm->PhyDbgInfo.NumQryBeaconPkt++; + + isCCKrate = (pPktinfo->DataRate <= DESC_RATE11M)?TRUE :FALSE; + pDM_Odm->RxRate = pPktinfo->DataRate; + /* + if(!isCCKrate) + { + DbgPrint("OFDM: pPktinfo->StationID=%d, isCCKrate=%d, pPhyInfo->RxPWDBAll=%d\n", + pPktinfo->StationID, isCCKrate, pPhyInfo->RxPWDBAll); + } + */ + + //--------------Statistic for antenna/path diversity------------------ + if(pDM_Odm->SupportAbility & ODM_BB_ANT_DIV) + { + #if(defined(CONFIG_HW_ANTENNA_DIVERSITY)) + ODM_Process_RSSIForAntDiv(pDM_Odm,pPhyInfo,pPktinfo); + #endif + } + else if(pDM_Odm->SupportAbility & ODM_BB_PATH_DIV) + { + #if (RTL8812A_SUPPORT == 1) + if(pDM_Odm->SupportICType == ODM_RTL8812) + { + pPATHDIV_T pDM_PathDiv = &pDM_Odm->DM_PathDiv; + if(pPktinfo->bPacketToSelf || pPktinfo->bPacketMatchBSSID) + { + if(pPktinfo->DataRate > DESC_RATE11M) + ODM_PathStatistics_8812A(pDM_Odm, pPktinfo->StationID, pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A], + pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]); + } + } + #endif + } + + //-----------------Smart Antenna Debug Message------------------// + + UndecoratedSmoothedCCK = pEntry->rssi_stat.UndecoratedSmoothedCCK; + UndecoratedSmoothedOFDM = pEntry->rssi_stat.UndecoratedSmoothedOFDM; + UndecoratedSmoothedPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB; + + if(pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) + { + + if(!isCCKrate)//ofdm rate + { + if(pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B] == 0){ + RSSI_Ave = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; + pDM_Odm->RSSI_A = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; + pDM_Odm->RSSI_B = 0; + } + else + { + //DbgPrint("pRfd->Status.RxMIMOSignalStrength[0] = %d, pRfd->Status.RxMIMOSignalStrength[1] = %d \n", + //pRfd->Status.RxMIMOSignalStrength[0], pRfd->Status.RxMIMOSignalStrength[1]); + pDM_Odm->RSSI_A = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; + pDM_Odm->RSSI_B = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]; + + if(pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A] > pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]) + { + RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; + RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]; + } + else + { + RSSI_max = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_B]; + RSSI_min = pPhyInfo->RxMIMOSignalStrength[ODM_RF_PATH_A]; + } + if((RSSI_max -RSSI_min) < 3) + RSSI_Ave = RSSI_max; + else if((RSSI_max -RSSI_min) < 6) + RSSI_Ave = RSSI_max - 1; + else if((RSSI_max -RSSI_min) < 10) + RSSI_Ave = RSSI_max - 2; + else + RSSI_Ave = RSSI_max - 3; + } + + //1 Process OFDM RSSI + if(UndecoratedSmoothedOFDM <= 0) // initialize + { + UndecoratedSmoothedOFDM = pPhyInfo->RxPWDBAll; + } + else + { + if(pPhyInfo->RxPWDBAll > (u4Byte)UndecoratedSmoothedOFDM) + { + UndecoratedSmoothedOFDM = + ( ((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) + + (RSSI_Ave)) /(Rx_Smooth_Factor); + UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM + 1; + } + else + { + UndecoratedSmoothedOFDM = + ( ((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) + + (RSSI_Ave)) /(Rx_Smooth_Factor); + } + } + + pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap<<1) | BIT0; + + } + else + { + RSSI_Ave = pPhyInfo->RxPWDBAll; + pDM_Odm->RSSI_A = (u1Byte) pPhyInfo->RxPWDBAll; + pDM_Odm->RSSI_B = 0; + + //1 Process CCK RSSI + if(UndecoratedSmoothedCCK <= 0) // initialize + { + UndecoratedSmoothedCCK = pPhyInfo->RxPWDBAll; + } + else + { + if(pPhyInfo->RxPWDBAll > (u4Byte)UndecoratedSmoothedCCK) + { + UndecoratedSmoothedCCK = + ( ((UndecoratedSmoothedCCK)*(Rx_Smooth_Factor-1)) + + (pPhyInfo->RxPWDBAll)) /(Rx_Smooth_Factor); + UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1; + } + else + { + UndecoratedSmoothedCCK = + ( ((UndecoratedSmoothedCCK)*(Rx_Smooth_Factor-1)) + + (pPhyInfo->RxPWDBAll)) /(Rx_Smooth_Factor); + } + } + pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap<<1; + } + + //if(pEntry) + { + //2011.07.28 LukeLee: modified to prevent unstable CCK RSSI + if(pEntry->rssi_stat.ValidBit >= 64) + pEntry->rssi_stat.ValidBit = 64; + else + pEntry->rssi_stat.ValidBit++; + + for(i=0; i<pEntry->rssi_stat.ValidBit; i++) + OFDM_pkt += (u1Byte)(pEntry->rssi_stat.PacketMap>>i)&BIT0; + + if(pEntry->rssi_stat.ValidBit == 64) + { + Weighting = ((OFDM_pkt<<4) > 64)?64:(OFDM_pkt<<4); + UndecoratedSmoothedPWDB = (Weighting*UndecoratedSmoothedOFDM+(64-Weighting)*UndecoratedSmoothedCCK)>>6; + } + else + { + if(pEntry->rssi_stat.ValidBit != 0) + UndecoratedSmoothedPWDB = (OFDM_pkt*UndecoratedSmoothedOFDM+(pEntry->rssi_stat.ValidBit-OFDM_pkt)*UndecoratedSmoothedCCK)/pEntry->rssi_stat.ValidBit; + else + UndecoratedSmoothedPWDB = 0; + } + + pEntry->rssi_stat.UndecoratedSmoothedCCK = UndecoratedSmoothedCCK; + pEntry->rssi_stat.UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM; + pEntry->rssi_stat.UndecoratedSmoothedPWDB = UndecoratedSmoothedPWDB; + + //DbgPrint("OFDM_pkt=%d, Weighting=%d\n", OFDM_pkt, Weighting); + //DbgPrint("UndecoratedSmoothedOFDM=%d, UndecoratedSmoothedPWDB=%d, UndecoratedSmoothedCCK=%d\n", + // UndecoratedSmoothedOFDM, UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK); + + } + + } +} + + +// +// Endianness before calling this API +// +VOID +ODM_PhyStatusQuery_92CSeries( + IN OUT PDM_ODM_T pDM_Odm, + OUT PODM_PHY_INFO_T pPhyInfo, + IN pu1Byte pPhyStatus, + IN PODM_PACKET_INFO_T pPktinfo + ) +{ + + odm_RxPhyStatus92CSeries_Parsing( + pDM_Odm, + pPhyInfo, + pPhyStatus, + pPktinfo); + + if( pDM_Odm->RSSI_test == TRUE) + { + // Select the packets to do RSSI checking for antenna switching. + if(pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon ) + { + /* + #if 0//(DM_ODM_SUPPORT_TYPE == ODM_WIN) + dm_SWAW_RSSI_Check( + Adapter, + (tmppAdapter!=NULL)?(tmppAdapter==Adapter):TRUE, + bPacketMatchBSSID, + pEntry, + pRfd); + #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + // Select the packets to do RSSI checking for antenna switching. + //odm_SwAntDivRSSICheck8192C(padapter, precvframe->u.hdr.attrib.RxPWDBAll); + #endif + */ + ODM_SwAntDivChkPerPktRssi(pDM_Odm,pPktinfo->StationID,pPhyInfo); + } + } + else + { + odm_Process_RSSIForDM(pDM_Odm,pPhyInfo,pPktinfo); + } + +} + + + +// +// Endianness before calling this API +// +VOID +ODM_PhyStatusQuery_JaguarSeries( + IN OUT PDM_ODM_T pDM_Odm, + OUT PODM_PHY_INFO_T pPhyInfo, + IN pu1Byte pPhyStatus, + IN PODM_PACKET_INFO_T pPktinfo + ) +{ + odm_RxPhyStatusJaguarSeries_Parsing( + pDM_Odm, + pPhyInfo, + pPhyStatus, + pPktinfo); + + odm_Process_RSSIForDM(pDM_Odm,pPhyInfo,pPktinfo); +} + +VOID +ODM_PhyStatusQuery( + IN OUT PDM_ODM_T pDM_Odm, + OUT PODM_PHY_INFO_T pPhyInfo, + IN pu1Byte pPhyStatus, + IN PODM_PACKET_INFO_T pPktinfo + ) +{ + + if(pDM_Odm->SupportICType & ODM_IC_11AC_SERIES ) + { + ODM_PhyStatusQuery_JaguarSeries(pDM_Odm,pPhyInfo,pPhyStatus,pPktinfo); + } + else + { + ODM_PhyStatusQuery_92CSeries(pDM_Odm,pPhyInfo,pPhyStatus,pPktinfo); + } +} + +// For future use. +VOID +ODM_MacStatusQuery( + IN OUT PDM_ODM_T pDM_Odm, + IN pu1Byte pMacStatus, + IN u1Byte MacID, + IN BOOLEAN bPacketMatchBSSID, + IN BOOLEAN bPacketToSelf, + IN BOOLEAN bPacketBeacon + ) +{ + // 2011/10/19 Driver team will handle in the future. + +} + + +// +// If you want to add a new IC, Please follow below template and generate a new one. +// +// + +HAL_STATUS +ODM_ConfigRFWithHeaderFile( + IN PDM_ODM_T pDM_Odm, + IN ODM_RF_Config_Type ConfigType, + IN ODM_RF_RADIO_PATH_E eRFPath + ) +{ + PADAPTER Adapter = pDM_Odm->Adapter; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("===>ODM_ConfigRFWithHeaderFile (%s)\n", (pDM_Odm->bIsMPChip) ? "MPChip" : "TestChip")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("pDM_Odm->SupportPlatform: 0x%X, pDM_Odm->SupportInterface: 0x%X, pDM_Odm->BoardType: 0x%X\n", + pDM_Odm->SupportPlatform, pDM_Odm->SupportInterface, pDM_Odm->BoardType)); + +#if (RTL8723A_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8723A) + { + if(ConfigType == CONFIG_RF_RADIO) { + if(eRFPath == ODM_RF_PATH_A) + READ_AND_CONFIG_MP(8723A,_RadioA_1T); + } + } +#endif + +#if (RTL8188E_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8188E) + { + if(ConfigType == CONFIG_RF_RADIO) { + if(eRFPath == ODM_RF_PATH_A){ + if(IS_VENDOR_8188E_I_CUT_SERIES(Adapter)) + READ_AND_CONFIG(8188E,_RadioA_1T_ICUT); + else + READ_AND_CONFIG(8188E,_RadioA_1T); + } + } + else if(ConfigType == CONFIG_RF_TXPWR_LMT) { + READ_AND_CONFIG(8188E,_TXPWR_LMT); + } + } +#endif + +#if (RTL8812A_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8812) + { + if(ConfigType == CONFIG_RF_RADIO) { + if(eRFPath == ODM_RF_PATH_A) + { + READ_AND_CONFIG(8812A,_RadioA); + } + else if(eRFPath == ODM_RF_PATH_B) + { + READ_AND_CONFIG(8812A,_RadioB); + } + } + else if(ConfigType == CONFIG_RF_TXPWR_LMT) { + READ_AND_CONFIG(8812A,_TXPWR_LMT); + } + } +#endif + +#if (RTL8821A_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8821) + { + if(ConfigType == CONFIG_RF_RADIO) { + if(eRFPath == ODM_RF_PATH_A) + { + READ_AND_CONFIG(8821A,_RadioA); + } + } + else if(ConfigType == CONFIG_RF_TXPWR_LMT) { + + if (pDM_Odm->SupportInterface == ODM_ITRF_USB) { + if (pDM_Odm->ExtPA5G || pDM_Odm->ExtLNA5G) + READ_AND_CONFIG(8821A,_TXPWR_LMT_8811AU_FEM); + else + READ_AND_CONFIG(8821A,_TXPWR_LMT_8811AU_IPA); + } else { + READ_AND_CONFIG(8821A,_TXPWR_LMT_8821A); + } + } + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("<===8821_ODM_ConfigRFWithHeaderFile\n")); + } +#endif + +#if (RTL8723B_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8723B) + { + if(ConfigType == CONFIG_RF_RADIO) { + READ_AND_CONFIG(8723B,_RadioA); + } + else if(ConfigType == CONFIG_RF_TXPWR_LMT) { + READ_AND_CONFIG(8723B,_TXPWR_LMT); + } + } +#endif + +#if (RTL8192E_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8192E) + { + if(ConfigType == CONFIG_RF_RADIO) { + if(eRFPath == ODM_RF_PATH_A) + READ_AND_CONFIG(8192E,_RadioA); + else if(eRFPath == ODM_RF_PATH_B) + READ_AND_CONFIG(8192E,_RadioB); + } + else if(ConfigType == CONFIG_RF_TXPWR_LMT) { + READ_AND_CONFIG(8192E,_TXPWR_LMT); + } + } +#endif + +#if (RTL8813A_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8814A) + { + /* + if(ConfigType == CONFIG_RF_TXPWR_LMT) { + READ_AND_CONFIG(8813A,_TXPWR_LMT); + } + */ + } +#endif + + return HAL_STATUS_SUCCESS; +} + +HAL_STATUS +ODM_ConfigRFWithTxPwrTrackHeaderFile( + IN PDM_ODM_T pDM_Odm + ) +{ + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("===>ODM_ConfigRFWithTxPwrTrackHeaderFile (%s)\n", (pDM_Odm->bIsMPChip) ? "MPChip" : "TestChip")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("pDM_Odm->SupportPlatform: 0x%X, pDM_Odm->SupportInterface: 0x%X, pDM_Odm->BoardType: 0x%X\n", + pDM_Odm->SupportPlatform, pDM_Odm->SupportInterface, pDM_Odm->BoardType)); + + if(0) + { + } +#if (RTL8821A_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8821) + { + if (pDM_Odm->SupportInterface == ODM_ITRF_PCIE) + READ_AND_CONFIG(8821A,_TxPowerTrack_PCIE); + else if (pDM_Odm->SupportInterface == ODM_ITRF_USB) + READ_AND_CONFIG(8821A,_TxPowerTrack_USB); + else + READ_AND_CONFIG(8821A,_TxPowerTrack_PCIE); + } +#endif +#if (RTL8812A_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8812) + { + if (pDM_Odm->SupportInterface == ODM_ITRF_PCIE) + READ_AND_CONFIG(8812A,_TxPowerTrack_PCIE); + else if (pDM_Odm->SupportInterface == ODM_ITRF_USB) { + if (pDM_Odm->RFEType == 3 && pDM_Odm->bIsMPChip) + READ_AND_CONFIG_MP(8812A,_TxPowerTrack_RFE3); + else + READ_AND_CONFIG(8812A,_TxPowerTrack_USB); + } + + } +#endif +#if (RTL8192E_SUPPORT == 1) + else if(pDM_Odm->SupportICType == ODM_RTL8192E) + { + if (pDM_Odm->SupportInterface == ODM_ITRF_PCIE) + READ_AND_CONFIG(8192E,_TxPowerTrack_PCIE); + else if (pDM_Odm->SupportInterface == ODM_ITRF_USB) + READ_AND_CONFIG(8192E,_TxPowerTrack_USB); + } +#endif +#if RTL8723B_SUPPORT + else if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + if (pDM_Odm->SupportInterface == ODM_ITRF_PCIE) + READ_AND_CONFIG(8723B,_TxPowerTrack_PCIE); + else if (pDM_Odm->SupportInterface == ODM_ITRF_USB) + READ_AND_CONFIG(8723B,_TxPowerTrack_USB); + else if (pDM_Odm->SupportInterface == ODM_ITRF_SDIO) + READ_AND_CONFIG(8723B,_TxPowerTrack_SDIO); + } +#endif +#if RTL8188E_SUPPORT + else if(pDM_Odm->SupportICType == ODM_RTL8188E) + { + if (pDM_Odm->SupportInterface == ODM_ITRF_PCIE) + READ_AND_CONFIG(8188E,_TxPowerTrack_PCIE); + else if (pDM_Odm->SupportInterface == ODM_ITRF_USB) + READ_AND_CONFIG(8188E,_TxPowerTrack_USB); + } +#endif + + return HAL_STATUS_SUCCESS; +} + +HAL_STATUS +ODM_ConfigBBWithHeaderFile( + IN PDM_ODM_T pDM_Odm, + IN ODM_BB_Config_Type ConfigType + ) +{ +#if (DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_WIN)) + PADAPTER Adapter = pDM_Odm->Adapter; +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) + PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); +#endif +#endif + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("===>ODM_ConfigBBWithHeaderFile (%s)\n", (pDM_Odm->bIsMPChip) ? "MPChip" : "TestChip")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("pDM_Odm->SupportPlatform: 0x%X, pDM_Odm->SupportInterface: 0x%X, pDM_Odm->BoardType: 0x%X\n", + pDM_Odm->SupportPlatform, pDM_Odm->SupportInterface, pDM_Odm->BoardType)); + +#if (RTL8723A_SUPPORT == 1) + if(pDM_Odm->SupportICType == ODM_RTL8723A) + { + if(ConfigType == CONFIG_BB_PHY_REG) + { + READ_AND_CONFIG_MP(8723A,_PHY_REG_1T); + } + else if(ConfigType == CONFIG_BB_AGC_TAB) + { + READ_AND_CONFIG_MP(8723A,_AGC_TAB_1T); + } + } +#endif + +#if (RTL8188E_SUPPORT == 1) + if(pDM_Odm->SupportICType == ODM_RTL8188E) + { + if(ConfigType == CONFIG_BB_PHY_REG) + { + if(IS_VENDOR_8188E_I_CUT_SERIES(Adapter)) + READ_AND_CONFIG(8188E,_PHY_REG_1T_ICUT); + else + READ_AND_CONFIG(8188E,_PHY_REG_1T); + } + else if(ConfigType == CONFIG_BB_AGC_TAB) + { + if(IS_VENDOR_8188E_I_CUT_SERIES(Adapter)) + READ_AND_CONFIG(8188E,_AGC_TAB_1T_ICUT); + else + READ_AND_CONFIG(8188E,_AGC_TAB_1T); + } + else if(ConfigType == CONFIG_BB_PHY_REG_PG) + { + READ_AND_CONFIG(8188E,_PHY_REG_PG); + } + } +#endif + +#if (RTL8812A_SUPPORT == 1) + if(pDM_Odm->SupportICType == ODM_RTL8812) + { + if(ConfigType == CONFIG_BB_PHY_REG) + { + READ_AND_CONFIG(8812A,_PHY_REG); + } + else if(ConfigType == CONFIG_BB_AGC_TAB) + { + READ_AND_CONFIG(8812A,_AGC_TAB); + } + else if(ConfigType == CONFIG_BB_PHY_REG_PG) + { + if (pDM_Odm->RFEType == 3 && pDM_Odm->bIsMPChip) + READ_AND_CONFIG_MP(8812A,_PHY_REG_PG_ASUS); +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) + else if (pMgntInfo->CustomerID == RT_CID_WNC_NEC && pDM_Odm->bIsMPChip) + READ_AND_CONFIG_MP(8812A,_PHY_REG_PG_NEC); +#endif + else + READ_AND_CONFIG(8812A,_PHY_REG_PG); + } + else if(ConfigType == CONFIG_BB_PHY_REG_MP) + { + READ_AND_CONFIG_MP(8812A,_PHY_REG_MP); + } + else if(ConfigType == CONFIG_BB_AGC_TAB_DIFF) + { + if ((36 <= *pDM_Odm->pChannel) && (*pDM_Odm->pChannel <= 64)) + AGC_DIFF_CONFIG_MP(8812A,LB); + else if (100 <= *pDM_Odm->pChannel) + AGC_DIFF_CONFIG_MP(8812A,HB); + } + } +#endif + +#if (RTL8821A_SUPPORT == 1) + if(pDM_Odm->SupportICType == ODM_RTL8821) + { + if(ConfigType == CONFIG_BB_PHY_REG) + { + READ_AND_CONFIG(8821A,_PHY_REG); + } + else if(ConfigType == CONFIG_BB_AGC_TAB) + { + READ_AND_CONFIG(8821A,_AGC_TAB); + } + else if(ConfigType == CONFIG_BB_PHY_REG_PG) + { + READ_AND_CONFIG(8821A,_PHY_REG_PG); + } + } +#endif +#if (RTL8723B_SUPPORT == 1) + if(pDM_Odm->SupportICType == ODM_RTL8723B) + { + + if(ConfigType == CONFIG_BB_PHY_REG) + { + READ_AND_CONFIG(8723B,_PHY_REG); + } + else if(ConfigType == CONFIG_BB_AGC_TAB) + { + READ_AND_CONFIG(8723B,_AGC_TAB); + } + else if(ConfigType == CONFIG_BB_PHY_REG_PG) + { + READ_AND_CONFIG(8723B,_PHY_REG_PG); + } + } +#endif +#if (RTL8192E_SUPPORT == 1) + if(pDM_Odm->SupportICType == ODM_RTL8192E) + { + + if(ConfigType == CONFIG_BB_PHY_REG) + { + READ_AND_CONFIG(8192E,_PHY_REG); + } + else if(ConfigType == CONFIG_BB_AGC_TAB) + { + READ_AND_CONFIG(8192E,_AGC_TAB); + } + else if(ConfigType == CONFIG_BB_PHY_REG_PG) + { + READ_AND_CONFIG(8192E,_PHY_REG_PG); + } + } +#endif +#if (RTL8813A_SUPPORT == 1) + if(pDM_Odm->SupportICType == ODM_RTL8814A) + { + + if(ConfigType == CONFIG_BB_PHY_REG) + { + READ_AND_CONFIG(8813A,_PHY_REG); + } + else if(ConfigType == CONFIG_BB_AGC_TAB) + { + READ_AND_CONFIG(8813A,_AGC_TAB); + } + else if(ConfigType == CONFIG_BB_PHY_REG_PG) + { + //READ_AND_CONFIG(8813A,_PHY_REG_PG); + } + } +#endif + return HAL_STATUS_SUCCESS; +} + +HAL_STATUS +ODM_ConfigMACWithHeaderFile( + IN PDM_ODM_T pDM_Odm + ) +{ +#if (DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_WIN)) + PADAPTER Adapter = pDM_Odm->Adapter; +#endif + u1Byte result = HAL_STATUS_SUCCESS; + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("===>ODM_ConfigMACWithHeaderFile (%s)\n", (pDM_Odm->bIsMPChip) ? "MPChip" : "TestChip")); + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("pDM_Odm->SupportPlatform: 0x%X, pDM_Odm->SupportInterface: 0x%X, pDM_Odm->BoardType: 0x%X\n", + pDM_Odm->SupportPlatform, pDM_Odm->SupportInterface, pDM_Odm->BoardType)); + +#if (RTL8723A_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8723A) + { + READ_AND_CONFIG_MP(8723A,_MAC_REG); + } +#endif +#if (RTL8188E_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8188E) + { + if(IS_VENDOR_8188E_I_CUT_SERIES(Adapter)) + result = READ_AND_CONFIG(8188E,_MAC_REG_ICUT); + else + result = READ_AND_CONFIG(8188E,_MAC_REG); + } +#endif +#if (RTL8812A_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8812) + { + READ_AND_CONFIG(8812A,_MAC_REG); + } +#endif +#if (RTL8821A_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8821) + { + READ_AND_CONFIG(8821A,_MAC_REG); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("<===8821_ODM_ConfigMACwithHeaderFile\n")); + } +#endif +#if (RTL8723B_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8723B) + { + READ_AND_CONFIG(8723B,_MAC_REG); + } +#endif +#if (RTL8192E_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8192E) + { + READ_AND_CONFIG(8192E,_MAC_REG); + } +#endif + + return result; +} + +HAL_STATUS +ODM_ConfigFWWithHeaderFile( + IN PDM_ODM_T pDM_Odm, + IN ODM_FW_Config_Type ConfigType, + OUT u1Byte *pFirmware, + OUT u4Byte *pSize + ) +{ + +#if (RTL8188E_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8188E) + { + if (ConfigType == CONFIG_FW_NIC) + { + READ_FIRMWARE(8188E,_FW_NIC_T); + } + else if (ConfigType == CONFIG_FW_WoWLAN) + { + READ_FIRMWARE(8188E,_FW_WoWLAN_T); + } + else if(ConfigType == CONFIG_FW_NIC_2) + { + READ_FIRMWARE(8188E,_FW_NIC_S); + } + else if (ConfigType == CONFIG_FW_WoWLAN_2) + { + READ_FIRMWARE(8188E,_FW_WoWLAN_S); + } + } +#endif +#if (RTL8723B_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8723B) + { + if (ConfigType == CONFIG_FW_NIC) + { + READ_FIRMWARE(8723B,_FW_NIC); + } + else if (ConfigType == CONFIG_FW_WoWLAN) + { + READ_FIRMWARE(8723B,_FW_WoWLAN); + } +#ifdef CONFIG_AP_WOWLAN + else if (ConfigType == CONFIG_FW_AP_WoWLAN) + { + READ_FIRMWARE(8723B,_FW_AP_WoWLAN); + } +#endif + else if (ConfigType == CONFIG_FW_BT) + { + READ_FIRMWARE_MP(8723B,_FW_BT); + } + else if (ConfigType == CONFIG_FW_MP) + { + READ_FIRMWARE_MP(8723B,_FW_MP); + } + } +#endif +#if (RTL8812A_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8812) + { + if (ConfigType == CONFIG_FW_NIC) + { + READ_FIRMWARE(8812A,_FW_NIC); + } + else if (ConfigType == CONFIG_FW_WoWLAN) + { + READ_FIRMWARE(8812A,_FW_WoWLAN); + } + else if (ConfigType == CONFIG_FW_BT) + { + READ_FIRMWARE(8812A,_FW_NIC_BT); + } + + } +#endif +#if (RTL8821A_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8821) + { + if (ConfigType == CONFIG_FW_NIC) + { + READ_FIRMWARE_MP(8821A,_FW_NIC); + } + else if (ConfigType == CONFIG_FW_WoWLAN) + { + READ_FIRMWARE(8821A,_FW_WoWLAN); + } + else if (ConfigType == CONFIG_FW_BT) + { + READ_FIRMWARE_MP(8821A,_FW_NIC_BT); + } + } +#endif +#if (RTL8192E_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8192E) + { + if (ConfigType == CONFIG_FW_NIC) + { + READ_FIRMWARE(8192E,_FW_NIC); + } + else if (ConfigType == CONFIG_FW_WoWLAN) + { + READ_FIRMWARE(8192E,_FW_WoWLAN); + } +#ifdef CONFIG_AP_WOWLAN + else if (ConfigType == CONFIG_FW_AP_WoWLAN) + { + READ_FIRMWARE(8192E,_FW_AP_WoWLAN); + } +#endif + + } +#endif + return HAL_STATUS_SUCCESS; +} + + +u4Byte +ODM_GetHWImgVersion( + IN PDM_ODM_T pDM_Odm + ) +{ + +#if (RTL8812A_SUPPORT == 1) + if (pDM_Odm->SupportICType == ODM_RTL8812) + return GET_VERSION_MP(8812A,_MAC_REG); +#endif + + return 0; +} + + + + + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_HWConfig.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_HWConfig.h new file mode 100644 index 0000000..67aabcf --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_HWConfig.h @@ -0,0 +1,237 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + + +#ifndef __HALHWOUTSRC_H__ +#define __HALHWOUTSRC_H__ + + +/*--------------------------Define -------------------------------------------*/ +#define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) +#define AGC_DIFF_CONFIG_MP(ic, band) (ODM_ReadAndConfig_MP_##ic##_AGC_TAB_DIFF(pDM_Odm, Array_MP_##ic##_AGC_TAB_DIFF_##band, \ + sizeof(Array_MP_##ic##_AGC_TAB_DIFF_##band)/sizeof(u4Byte))) +#define AGC_DIFF_CONFIG_TC(ic, band) (ODM_ReadAndConfig_TC_##ic##_AGC_TAB_DIFF(pDM_Odm, Array_TC_##ic##_AGC_TAB_DIFF_##band, \ + sizeof(Array_TC_##ic##_AGC_TAB_DIFF_##band)/sizeof(u4Byte))) + +#define AGC_DIFF_CONFIG(ic, band) do {\ + if (pDM_Odm->bIsMPChip)\ + AGC_DIFF_CONFIG_MP(ic,band);\ + else\ + AGC_DIFF_CONFIG_TC(ic,band);\ + } while(0) + + +//============================================================ +// structure and define +//============================================================ + +typedef struct _Phy_Rx_AGC_Info +{ + #if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u1Byte gain:7,trsw:1; + #else + u1Byte trsw:1,gain:7; + #endif +} PHY_RX_AGC_INFO_T,*pPHY_RX_AGC_INFO_T; + +typedef struct _Phy_Status_Rpt_8192cd +{ + PHY_RX_AGC_INFO_T path_agc[2]; + u1Byte ch_corr[2]; + u1Byte cck_sig_qual_ofdm_pwdb_all; + u1Byte cck_agc_rpt_ofdm_cfosho_a; + u1Byte cck_rpt_b_ofdm_cfosho_b; + u1Byte rsvd_1;//ch_corr_msb; + u1Byte noise_power_db_msb; + s1Byte path_cfotail[2]; + u1Byte pcts_mask[2]; + s1Byte stream_rxevm[2]; + u1Byte path_rxsnr[2]; + u1Byte noise_power_db_lsb; + u1Byte rsvd_2[3]; + u1Byte stream_csi[2]; + u1Byte stream_target_csi[2]; + s1Byte sig_evm; + u1Byte rsvd_3; + +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u1Byte antsel_rx_keep_2:1; //ex_intf_flg:1; + u1Byte sgi_en:1; + u1Byte rxsc:2; + u1Byte idle_long:1; + u1Byte r_ant_train_en:1; + u1Byte ant_sel_b:1; + u1Byte ant_sel:1; +#else // _BIG_ENDIAN_ + u1Byte ant_sel:1; + u1Byte ant_sel_b:1; + u1Byte r_ant_train_en:1; + u1Byte idle_long:1; + u1Byte rxsc:2; + u1Byte sgi_en:1; + u1Byte antsel_rx_keep_2:1; //ex_intf_flg:1; +#endif +} PHY_STATUS_RPT_8192CD_T,*PPHY_STATUS_RPT_8192CD_T; + + +typedef struct _Phy_Status_Rpt_8812 +{ +#if 0 + PHY_RX_AGC_INFO_T path_agc[2]; + u1Byte ch_num[2]; + u1Byte cck_sig_qual_ofdm_pwdb_all; + u1Byte cck_agc_rpt_ofdm_cfosho_a; + u1Byte cck_bb_pwr_ofdm_cfosho_b; + u1Byte cck_rx_path; //CCK_RX_PATH [3:0] (with regA07[3:0] definition) + u1Byte rsvd_1; + u1Byte path_cfotail[2]; + u1Byte pcts_mask[2]; + s1Byte stream_rxevm[2]; + u1Byte path_rxsnr[2]; + u1Byte rsvd_2[2]; + u1Byte stream_snr[2]; + u1Byte stream_csi[2]; + u1Byte rsvd_3[2]; + s1Byte sig_evm; + u1Byte rsvd_4; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u1Byte antidx_anta:3; + u1Byte antidx_antb:3; + u1Byte rsvd_5:2; +#else // _BIG_ENDIAN_ + u1Byte rsvd_5:2; + u1Byte antidx_antb:3; + u1Byte antidx_anta:3; +#endif +#endif + + //2012.05.24 LukeLee: This structure should take big/little endian in consideration later..... + + //DWORD 0 + u1Byte gain_trsw[2]; +#if (ODM_ENDIAN_TYPE == ODM_ENDIAN_LITTLE) + u2Byte chl_num:10; + u2Byte sub_chnl:4; + u2Byte r_RFMOD:2; +#else // _BIG_ENDIAN_ + u2Byte r_RFMOD:2; + u2Byte sub_chnl:4; + u2Byte chl_num:10; +#endif + + //DWORD 1 + u1Byte pwdb_all; + u1Byte cfosho[4]; // DW 1 byte 1 DW 2 byte 0 + + //DWORD 2 + s1Byte cfotail[4]; // DW 2 byte 1 DW 3 byte 0 + + //DWORD 3 + s1Byte rxevm[2]; // DW 3 byte 1 DW 3 byte 2 + s1Byte rxsnr[2]; // DW 3 byte 3 DW 4 byte 0 + + //DWORD 4 + u1Byte PCTS_MSK_RPT[2]; + u1Byte pdsnr[2]; // DW 4 byte 3 DW 5 Byte 0 + + //DWORD 5 + u1Byte csi_current[2]; + u1Byte rx_gain_c; + + //DWORD 6 + u1Byte rx_gain_d; + s1Byte sigevm; + u1Byte resvd_0; + u1Byte antidx_anta:3; + u1Byte antidx_antb:3; + u1Byte resvd_1:2; +} PHY_STATUS_RPT_8812_T,*PPHY_STATUS_RPT_8812_T; + + +VOID +odm_Init_RSSIForDM( + IN OUT PDM_ODM_T pDM_Odm + ); + +VOID +ODM_PhyStatusQuery( + IN OUT PDM_ODM_T pDM_Odm, + OUT PODM_PHY_INFO_T pPhyInfo, + IN pu1Byte pPhyStatus, + IN PODM_PACKET_INFO_T pPktinfo + ); + +VOID +ODM_MacStatusQuery( + IN OUT PDM_ODM_T pDM_Odm, + IN pu1Byte pMacStatus, + IN u1Byte MacID, + IN BOOLEAN bPacketMatchBSSID, + IN BOOLEAN bPacketToSelf, + IN BOOLEAN bPacketBeacon + ); +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE|ODM_AP)) + +HAL_STATUS +ODM_ConfigRFWithTxPwrTrackHeaderFile( + IN PDM_ODM_T pDM_Odm + ); + +HAL_STATUS +ODM_ConfigRFWithHeaderFile( + IN PDM_ODM_T pDM_Odm, + IN ODM_RF_Config_Type ConfigType, + IN ODM_RF_RADIO_PATH_E eRFPath + ); + +HAL_STATUS +ODM_ConfigBBWithHeaderFile( + IN PDM_ODM_T pDM_Odm, + IN ODM_BB_Config_Type ConfigType + ); + +HAL_STATUS +ODM_ConfigMACWithHeaderFile( + IN PDM_ODM_T pDM_Odm + ); + +HAL_STATUS +ODM_ConfigFWWithHeaderFile( + IN PDM_ODM_T pDM_Odm, + IN ODM_FW_Config_Type ConfigType, + OUT u1Byte *pFirmware, + OUT u4Byte *pSize + ); + +u4Byte +ODM_GetHWImgVersion( + IN PDM_ODM_T pDM_Odm + ); + +s4Byte +odm_SignalScaleMapping( + IN OUT PDM_ODM_T pDM_Odm, + IN s4Byte CurrSig + ); + +#endif + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_RegDefine11AC.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_RegDefine11AC.h new file mode 100644 index 0000000..0619ccc --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_RegDefine11AC.h @@ -0,0 +1,81 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#ifndef __ODM_REGDEFINE11AC_H__ +#define __ODM_REGDEFINE11AC_H__ + +//2 RF REG LIST + + + +//2 BB REG LIST +//PAGE 8 +#define ODM_REG_CCK_RPT_FORMAT_11AC 0x804 +#define ODM_REG_BB_RX_PATH_11AC 0x808 +#define ODM_REG_BB_TX_PATH_11AC 0x80c +#define ODM_REG_BB_ATC_11AC 0x860 +#define ODM_REG_EDCCA_POWER_CAL 0x8dc +#define ODM_REG_DBG_RPT_11AC 0x8fc +//PAGE 9 +#define ODM_REG_EDCCA_DOWN_OPT 0x900 +#define ODM_REG_ACBB_EDCCA_ENHANCE 0x944 +#define ODM_REG_OFDM_FA_RST_11AC 0x9A4 +#define ODM_REG_NHM_TIMER_11AC 0x990 +#define ODM_REG_NHM_TH9_TH10_11AC 0x994 +#define ODM_REG_NHM_TH3_TO_TH0_11AC 0x998 +#define ODM_REG_NHM_TH7_TO_TH4_11AC 0x99c +#define ODM_REG_NHM_TH8_11AC 0x9a0 +#define ODM_REG_NHM_9E8_11AC 0x9e8 +//PAGE A +#define ODM_REG_CCK_CCA_11AC 0xA0A +#define ODM_REG_CCK_FA_RST_11AC 0xA2C +#define ODM_REG_CCK_FA_11AC 0xA5C +//PAGE B +#define ODM_REG_RST_RPT_11AC 0xB58 +//PAGE C +#define ODM_REG_TRMUX_11AC 0xC08 +#define ODM_REG_IGI_A_11AC 0xC50 +//PAGE E +#define ODM_REG_IGI_B_11AC 0xE50 +#define ODM_REG_TRMUX_11AC_B 0xE08 +//PAGE F +#define ODM_REG_CCK_CCA_CNT_11AC 0xF08 +#define ODM_REG_OFDM_FA_11AC 0xF48 +#define ODM_REG_RPT_11AC 0xfa0 +#define ODM_REG_NHM_CNT_11AC 0xfa8 +//PAGE 18 +#define ODM_REG_IGI_C_11AC 0x1850 +//PAGE 1A +#define ODM_REG_IGI_D_11AC 0x1A50 + +//2 MAC REG LIST +#define ODM_REG_RESP_TX_11AC 0x6D8 + + + +//DIG Related +#define ODM_BIT_IGI_11AC 0xFFFFFFFF +#define ODM_BIT_CCK_RPT_FORMAT_11AC BIT16 +#define ODM_BIT_BB_RX_PATH_11AC 0xF +#define ODM_BIT_BB_TX_PATH_11AC 0xF +#define ODM_BIT_BB_ATC_11AC BIT14 + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_RegDefine11N.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_RegDefine11N.h new file mode 100644 index 0000000..e10a4ec --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_RegDefine11N.h @@ -0,0 +1,187 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#ifndef __ODM_REGDEFINE11N_H__ +#define __ODM_REGDEFINE11N_H__ + + +//2 RF REG LIST +#define ODM_REG_RF_MODE_11N 0x00 +#define ODM_REG_RF_0B_11N 0x0B +#define ODM_REG_CHNBW_11N 0x18 +#define ODM_REG_T_METER_11N 0x24 +#define ODM_REG_RF_25_11N 0x25 +#define ODM_REG_RF_26_11N 0x26 +#define ODM_REG_RF_27_11N 0x27 +#define ODM_REG_RF_2B_11N 0x2B +#define ODM_REG_RF_2C_11N 0x2C +#define ODM_REG_RXRF_A3_11N 0x3C +#define ODM_REG_T_METER_92D_11N 0x42 +#define ODM_REG_T_METER_88E_11N 0x42 + + + +//2 BB REG LIST +//PAGE 8 +#define ODM_REG_BB_CTRL_11N 0x800 +#define ODM_REG_RF_PIN_11N 0x804 +#define ODM_REG_PSD_CTRL_11N 0x808 +#define ODM_REG_TX_ANT_CTRL_11N 0x80C +#define ODM_REG_BB_PWR_SAV5_11N 0x818 +#define ODM_REG_CCK_RPT_FORMAT_11N 0x824 +#define ODM_REG_CCK_RPT_FORMAT_11N_B 0x82C +#define ODM_REG_RX_DEFUALT_A_11N 0x858 +#define ODM_REG_RX_DEFUALT_B_11N 0x85A +#define ODM_REG_BB_PWR_SAV3_11N 0x85C +#define ODM_REG_ANTSEL_CTRL_11N 0x860 +#define ODM_REG_RX_ANT_CTRL_11N 0x864 +#define ODM_REG_PIN_CTRL_11N 0x870 +#define ODM_REG_BB_PWR_SAV1_11N 0x874 +#define ODM_REG_ANTSEL_PATH_11N 0x878 +#define ODM_REG_BB_3WIRE_11N 0x88C +#define ODM_REG_SC_CNT_11N 0x8C4 +#define ODM_REG_PSD_DATA_11N 0x8B4 +#define ODM_REG_PSD_DATA_11N 0x8B4 +#define ODM_REG_NHM_TIMER_11N 0x894 +#define ODM_REG_NHM_TH9_TH10_11N 0x890 +#define ODM_REG_NHM_TH3_TO_TH0_11N 0x898 +#define ODM_REG_NHM_TH7_TO_TH4_11N 0x89c +#define ODM_REG_NHM_CNT_11N 0x8d8 +//PAGE 9 +#define ODM_REG_DBG_RPT_11N 0x908 +#define ODM_REG_BB_TX_PATH_11N 0x90c +#define ODM_REG_ANT_MAPPING1_11N 0x914 +#define ODM_REG_ANT_MAPPING2_11N 0x918 +#define ODM_REG_EDCCA_DOWN_OPT_11N 0x948 + +//PAGE A +#define ODM_REG_CCK_ANTDIV_PARA1_11N 0xA00 +#define ODM_REG_CCK_CCA_11N 0xA0A +#define ODM_REG_CCK_ANTDIV_PARA2_11N 0xA0C +#define ODM_REG_CCK_ANTDIV_PARA3_11N 0xA10 +#define ODM_REG_CCK_ANTDIV_PARA4_11N 0xA14 +#define ODM_REG_CCK_FILTER_PARA1_11N 0xA22 +#define ODM_REG_CCK_FILTER_PARA2_11N 0xA23 +#define ODM_REG_CCK_FILTER_PARA3_11N 0xA24 +#define ODM_REG_CCK_FILTER_PARA4_11N 0xA25 +#define ODM_REG_CCK_FILTER_PARA5_11N 0xA26 +#define ODM_REG_CCK_FILTER_PARA6_11N 0xA27 +#define ODM_REG_CCK_FILTER_PARA7_11N 0xA28 +#define ODM_REG_CCK_FILTER_PARA8_11N 0xA29 +#define ODM_REG_CCK_FA_RST_11N 0xA2C +#define ODM_REG_CCK_FA_MSB_11N 0xA58 +#define ODM_REG_CCK_FA_LSB_11N 0xA5C +#define ODM_REG_CCK_CCA_CNT_11N 0xA60 +#define ODM_REG_BB_PWR_SAV4_11N 0xA74 +//PAGE B +#define ODM_REG_LNA_SWITCH_11N 0xB2C +#define ODM_REG_PATH_SWITCH_11N 0xB30 +#define ODM_REG_RSSI_CTRL_11N 0xB38 +#define ODM_REG_CONFIG_ANTA_11N 0xB68 +#define ODM_REG_RSSI_BT_11N 0xB9C +//PAGE C +#define ODM_REG_OFDM_FA_HOLDC_11N 0xC00 +#define ODM_REG_BB_RX_PATH_11N 0xC04 +#define ODM_REG_TRMUX_11N 0xC08 +#define ODM_REG_OFDM_FA_RSTC_11N 0xC0C +#define ODM_REG_RXIQI_MATRIX_11N 0xC14 +#define ODM_REG_TXIQK_MATRIX_LSB1_11N 0xC4C +#define ODM_REG_IGI_A_11N 0xC50 +#define ODM_REG_ANTDIV_PARA2_11N 0xC54 +#define ODM_REG_IGI_B_11N 0xC58 +#define ODM_REG_ANTDIV_PARA3_11N 0xC5C +#define ODM_REG_L1SBD_PD_CH_11N 0XC6C +#define ODM_REG_BB_PWR_SAV2_11N 0xC70 +#define ODM_REG_RX_OFF_11N 0xC7C +#define ODM_REG_TXIQK_MATRIXA_11N 0xC80 +#define ODM_REG_TXIQK_MATRIXB_11N 0xC88 +#define ODM_REG_TXIQK_MATRIXA_LSB2_11N 0xC94 +#define ODM_REG_TXIQK_MATRIXB_LSB2_11N 0xC9C +#define ODM_REG_RXIQK_MATRIX_LSB_11N 0xCA0 +#define ODM_REG_ANTDIV_PARA1_11N 0xCA4 +#define ODM_REG_OFDM_FA_TYPE1_11N 0xCF0 +//PAGE D +#define ODM_REG_OFDM_FA_RSTD_11N 0xD00 +#define ODM_REG_BB_ATC_11N 0xD2C +#define ODM_REG_OFDM_FA_TYPE2_11N 0xDA0 +#define ODM_REG_OFDM_FA_TYPE3_11N 0xDA4 +#define ODM_REG_OFDM_FA_TYPE4_11N 0xDA8 +#define ODM_REG_RPT_11N 0xDF4 +//PAGE E +#define ODM_REG_TXAGC_A_6_18_11N 0xE00 +#define ODM_REG_TXAGC_A_24_54_11N 0xE04 +#define ODM_REG_TXAGC_A_1_MCS32_11N 0xE08 +#define ODM_REG_TXAGC_A_MCS0_3_11N 0xE10 +#define ODM_REG_TXAGC_A_MCS4_7_11N 0xE14 +#define ODM_REG_TXAGC_A_MCS8_11_11N 0xE18 +#define ODM_REG_TXAGC_A_MCS12_15_11N 0xE1C +#define DOM_REG_EDCCA_DCNF_11N 0xE24 +#define ODM_REG_FPGA0_IQK_11N 0xE28 +#define ODM_REG_TXIQK_TONE_A_11N 0xE30 +#define ODM_REG_RXIQK_TONE_A_11N 0xE34 +#define ODM_REG_TXIQK_PI_A_11N 0xE38 +#define ODM_REG_RXIQK_PI_A_11N 0xE3C +#define ODM_REG_TXIQK_11N 0xE40 +#define ODM_REG_RXIQK_11N 0xE44 +#define ODM_REG_IQK_AGC_PTS_11N 0xE48 +#define ODM_REG_IQK_AGC_RSP_11N 0xE4C +#define ODM_REG_BLUETOOTH_11N 0xE6C +#define ODM_REG_RX_WAIT_CCA_11N 0xE70 +#define ODM_REG_TX_CCK_RFON_11N 0xE74 +#define ODM_REG_TX_CCK_BBON_11N 0xE78 +#define ODM_REG_OFDM_RFON_11N 0xE7C +#define ODM_REG_OFDM_BBON_11N 0xE80 +#define ODM_REG_TX2RX_11N 0xE84 +#define ODM_REG_TX2TX_11N 0xE88 +#define ODM_REG_RX_CCK_11N 0xE8C +#define ODM_REG_RX_OFDM_11N 0xED0 +#define ODM_REG_RX_WAIT_RIFS_11N 0xED4 +#define ODM_REG_RX2RX_11N 0xED8 +#define ODM_REG_STANDBY_11N 0xEDC +#define ODM_REG_SLEEP_11N 0xEE0 +#define ODM_REG_PMPD_ANAEN_11N 0xEEC +#define ODM_REG_IGI_C_11N 0xF84 +#define ODM_REG_IGI_D_11N 0xF88 + +//2 MAC REG LIST +#define ODM_REG_BB_RST_11N 0x02 +#define ODM_REG_ANTSEL_PIN_11N 0x4C +#define ODM_REG_EARLY_MODE_11N 0x4D0 +#define ODM_REG_RSSI_MONITOR_11N 0x4FE +#define ODM_REG_EDCA_VO_11N 0x500 +#define ODM_REG_EDCA_VI_11N 0x504 +#define ODM_REG_EDCA_BE_11N 0x508 +#define ODM_REG_EDCA_BK_11N 0x50C +#define ODM_REG_TXPAUSE_11N 0x522 +#define ODM_REG_RESP_TX_11N 0x6D8 +#define ODM_REG_ANT_TRAIN_PARA1_11N 0x7b0 +#define ODM_REG_ANT_TRAIN_PARA2_11N 0x7b4 + + +//DIG Related +#define ODM_BIT_IGI_11N 0x0000007F +#define ODM_BIT_CCK_RPT_FORMAT_11N BIT9 +#define ODM_BIT_BB_RX_PATH_11N 0xF +#define ODM_BIT_BB_TX_PATH_11N 0xF +#define ODM_BIT_BB_ATC_11N BIT11 + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_debug.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_debug.c new file mode 100644 index 0000000..61e7a86 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_debug.c @@ -0,0 +1,629 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +//============================================================ +// include files +//============================================================ + +#include "odm_precomp.h" + + +VOID +ODM_InitDebugSetting( + IN PDM_ODM_T pDM_Odm + ) +{ +pDM_Odm->DebugLevel = ODM_DBG_LOUD; + +pDM_Odm->DebugComponents = +\ +#if DBG +//BB Functions +// ODM_COMP_DIG | +// ODM_COMP_RA_MASK | +// ODM_COMP_DYNAMIC_TXPWR | +// ODM_COMP_FA_CNT | +// ODM_COMP_RSSI_MONITOR | +// ODM_COMP_CCK_PD | +// ODM_COMP_ANT_DIV | +// ODM_COMP_PWR_SAVE | +// ODM_COMP_PWR_TRAIN | +// ODM_COMP_RATE_ADAPTIVE | +// ODM_COMP_PATH_DIV | +// ODM_COMP_DYNAMIC_PRICCA | +// ODM_COMP_RXHP | +// ODM_COMP_MP | +// ODM_COMP_DYNAMIC_ATC | + +//MAC Functions +// ODM_COMP_EDCA_TURBO | +// ODM_COMP_EARLY_MODE | +//RF Functions +// ODM_COMP_TX_PWR_TRACK | +// ODM_COMP_RX_GAIN_TRACK | +// ODM_COMP_CALIBRATION | +//Common +// ODM_COMP_COMMON | +// ODM_COMP_INIT | +// ODM_COMP_PSD | +#endif + 0; +} + +#if 0 +/*------------------Declare variable----------------------- +// Define debug flag array for common debug print macro. */ +u4Byte ODM_DBGP_Type[ODM_DBGP_TYPE_MAX]; + +/* Define debug print header for every service module. */ +ODM_DBGP_HEAD_T ODM_DBGP_Head; + + +/*----------------------------------------------------------------------------- + * Function: DBGP_Flag_Init + * + * Overview: Refresh all debug print control flag content to zero. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 10/20/2006 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +extern void ODM_DBGP_Flag_Init(void) +{ + u1Byte i; + + for (i = 0; i < ODM_DBGP_TYPE_MAX; i++) + { + ODM_DBGP_Type[i] = 0; + } + +#ifndef ADSL_AP_BUILD_WORKAROUND +#if DBG + // 2010/06/02 MH Free build driver can not out any debug message!!! + // Init Debug flag enable condition + + ODM_DBGP_Type[FINIT] = \ +// INIT_EEPROM | +// INIT_TxPower | +// INIT_IQK | +// INIT_RF | + 0; + + ODM_DBGP_Type[FDM] = \ +// WA_IOT | +// DM_PWDB | +// DM_Monitor | +// DM_DIG | +// DM_EDCA_Turbo | +// DM_BT30 | + 0; + + ODM_DBGP_Type[FIOCTL] = \ +// IOCTL_IRP | +// IOCTL_IRP_DETAIL | +// IOCTL_IRP_STATISTICS | +// IOCTL_IRP_HANDLE | +// IOCTL_BT_HCICMD | +// IOCTL_BT_HCICMD_DETAIL | +// IOCTL_BT_HCICMD_EXT | +// IOCTL_BT_EVENT | +// IOCTL_BT_EVENT_DETAIL | +// IOCTL_BT_EVENT_PERIODICAL | +// IOCTL_BT_TX_ACLDATA | +// IOCTL_BT_TX_ACLDATA_DETAIL | +// IOCTL_BT_RX_ACLDATA | +// IOCTL_BT_RX_ACLDATA_DETAIL | +// IOCTL_BT_TP | +// IOCTL_STATE | +// IOCTL_BT_LOGO | +// IOCTL_CALLBACK_FUN | +// IOCTL_PARSE_BT_PKT | + 0; + + ODM_DBGP_Type[FBT] = \ +// BT_TRACE | + 0; + + ODM_DBGP_Type[FEEPROM] = \ +// EEPROM_W | +// EFUSE_PG | +// EFUSE_READ_ALL | +// EFUSE_ANALYSIS | +// EFUSE_PG_DETAIL | + 0; + + ODM_DBGP_Type[FDBG_CTRL] = \ +// DBG_CTRL_TRACE | +// DBG_CTRL_INBAND_NOISE | + 0; + + // 2011/07/20 MH Add for short cut + ODM_DBGP_Type[FSHORT_CUT] = \ +// SHCUT_TX | +// SHCUT_RX | + 0; + +#endif +#endif + /* Define debug header of every service module. */ + //ODM_DBGP_Head.pMANS = "\n\r[MANS] "; + //ODM_DBGP_Head.pRTOS = "\n\r[RTOS] "; + //ODM_DBGP_Head.pALM = "\n\r[ALM] "; + //ODM_DBGP_Head.pPEM = "\n\r[PEM] "; + //ODM_DBGP_Head.pCMPK = "\n\r[CMPK] "; + //ODM_DBGP_Head.pRAPD = "\n\r[RAPD] "; + //ODM_DBGP_Head.pTXPB = "\n\r[TXPB] "; + //ODM_DBGP_Head.pQUMG = "\n\r[QUMG] "; + +} /* DBGP_Flag_Init */ + +#endif + + +#if 0 +u4Byte GlobalDebugLevel = DBG_LOUD; +// +// 2009/06/22 MH Allow Fre build to print none debug info at init time. +// +#if DBG +u8Byte GlobalDebugComponents = \ +// COMP_TRACE | +// COMP_DBG | +// COMP_INIT | +// COMP_OID_QUERY | +// COMP_OID_SET | +// COMP_RECV | +// COMP_SEND | +// COMP_IO | +// COMP_POWER | +// COMP_MLME | +// COMP_SCAN | +// COMP_SYSTEM | +// COMP_SEC | +// COMP_AP | +// COMP_TURBO | +// COMP_QOS | +// COMP_AUTHENTICATOR | +// COMP_BEACON | +// COMP_ANTENNA | +// COMP_RATE | +// COMP_EVENTS | +// COMP_FPGA | +// COMP_RM | +// COMP_MP | +// COMP_RXDESC | +// COMP_CKIP | +// COMP_DIG | +// COMP_TXAGC | +// COMP_HIPWR | +// COMP_HALDM | +// COMP_RSNA | +// COMP_INDIC | +// COMP_LED | +// COMP_RF | +// COMP_DUALMACSWITCH | +// COMP_EASY_CONCURRENT | + +//1!!!!!!!!!!!!!!!!!!!!!!!!!!! +//1//1Attention Please!!!<11n or 8190 specific code should be put below this line> +//1!!!!!!!!!!!!!!!!!!!!!!!!!!! + +// COMP_HT | +// COMP_POWER_TRACKING | +// COMP_RX_REORDER | +// COMP_AMSDU | +// COMP_WPS | +// COMP_RATR | +// COMP_RESET | +// COMP_CMD | +// COMP_EFUSE | +// COMP_MESH_INTERWORKING | +// COMP_CCX | +// COMP_IOCTL | +// COMP_GP | +// COMP_TXAGG | +// COMP_BB_POWERSAVING | +// COMP_SWAS | +// COMP_P2P | +// COMP_MUX | +// COMP_FUNC | +// COMP_TDLS | +// COMP_OMNIPEEK | +// COMP_PSD | + 0; + + +#else +u8Byte GlobalDebugComponents = 0; +#endif + +#if (RT_PLATFORM==PLATFORM_LINUX) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) +EXPORT_SYMBOL(GlobalDebugComponents); +EXPORT_SYMBOL(GlobalDebugLevel); +#endif +#endif + +/*------------------Declare variable----------------------- +// Define debug flag array for common debug print macro. */ +u4Byte DBGP_Type[DBGP_TYPE_MAX]; + +/* Define debug print header for every service module. */ +DBGP_HEAD_T DBGP_Head; + + +/*----------------------------------------------------------------------------- + * Function: DBGP_Flag_Init + * + * Overview: Refresh all debug print control flag content to zero. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 10/20/2006 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +extern void DBGP_Flag_Init(void) +{ + u1Byte i; + + for (i = 0; i < DBGP_TYPE_MAX; i++) + { + DBGP_Type[i] = 0; + } + +#if DBG + // 2010/06/02 MH Free build driver can not out any debug message!!! + // Init Debug flag enable condition + + DBGP_Type[FINIT] = \ +// INIT_EEPROM | +// INIT_TxPower | +// INIT_IQK | +// INIT_RF | + 0; + + DBGP_Type[FDM] = \ +// WA_IOT | +// DM_PWDB | +// DM_Monitor | +// DM_DIG | +// DM_EDCA_Turbo | +// DM_BT30 | + 0; + + DBGP_Type[FIOCTL] = \ +// IOCTL_IRP | +// IOCTL_IRP_DETAIL | +// IOCTL_IRP_STATISTICS | +// IOCTL_IRP_HANDLE | +// IOCTL_BT_HCICMD | +// IOCTL_BT_HCICMD_DETAIL | +// IOCTL_BT_HCICMD_EXT | +// IOCTL_BT_EVENT | +// IOCTL_BT_EVENT_DETAIL | +// IOCTL_BT_EVENT_PERIODICAL | +// IOCTL_BT_TX_ACLDATA | +// IOCTL_BT_TX_ACLDATA_DETAIL | +// IOCTL_BT_RX_ACLDATA | +// IOCTL_BT_RX_ACLDATA_DETAIL | +// IOCTL_BT_TP | +// IOCTL_STATE | +// IOCTL_BT_LOGO | +// IOCTL_CALLBACK_FUN | +// IOCTL_PARSE_BT_PKT | + 0; + + DBGP_Type[FBT] = \ +// BT_TRACE | + 0; + + DBGP_Type[FEEPROM] = \ +// EEPROM_W | +// EFUSE_PG | +// EFUSE_READ_ALL | +// EFUSE_ANALYSIS | +// EFUSE_PG_DETAIL | + 0; + + DBGP_Type[FDBG_CTRL] = \ +// DBG_CTRL_TRACE | +// DBG_CTRL_INBAND_NOISE | + 0; + + // 2011/07/20 MH Add for short cut + DBGP_Type[FSHORT_CUT] = \ +// SHCUT_TX | +// SHCUT_RX | + 0; + +#endif + /* Define debug header of every service module. */ + DBGP_Head.pMANS = "\n\r[MANS] "; + DBGP_Head.pRTOS = "\n\r[RTOS] "; + DBGP_Head.pALM = "\n\r[ALM] "; + DBGP_Head.pPEM = "\n\r[PEM] "; + DBGP_Head.pCMPK = "\n\r[CMPK] "; + DBGP_Head.pRAPD = "\n\r[RAPD] "; + DBGP_Head.pTXPB = "\n\r[TXPB] "; + DBGP_Head.pQUMG = "\n\r[QUMG] "; + +} /* DBGP_Flag_Init */ + + +/*----------------------------------------------------------------------------- + * Function: DBG_PrintAllFlag + * + * Overview: Print All debug flag + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 12/10/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +extern void DBG_PrintAllFlag(void) +{ + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 0 FQoS\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 1 FTX\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 2 FRX\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 3 FSEC\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 4 FMGNT\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 5 FMLME\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 6 FRESOURCE\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 7 FBEACON\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 8 FISR\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 9 FPHY\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 11 FMP\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 12 FPWR\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 13 FDM\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 14 FDBG_CTRL\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 15 FC2H\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("DBGFLAG 16 FBT\n")); +} // DBG_PrintAllFlag + + +extern void DBG_PrintAllComp(void) +{ + u1Byte i; + + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("GlobalDebugComponents Definition\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT0 COMP_TRACE\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT1 COMP_DBG\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT2 COMP_INIT\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT3 COMP_OID_QUERY\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT4 COMP_OID_SET\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT5 COMP_RECV\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT6 COMP_SEND\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT7 COMP_IO\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT8 COMP_POWER\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT9 COMP_MLME\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT10 COMP_SCAN\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT11 COMP_SYSTEM\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT12 COMP_SEC\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT13 COMP_AP\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT14 COMP_TURBO\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT15 COMP_QOS\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT16 COMP_AUTHENTICATOR\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT17 COMP_BEACON\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT18 COMP_BEACON\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT19 COMP_RATE\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT20 COMP_EVENTS\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT21 COMP_FPGA\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT22 COMP_RM\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT23 COMP_MP\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT24 COMP_RXDESC\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT25 COMP_CKIP\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT26 COMP_DIG\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT27 COMP_TXAGC\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT28 COMP_HIPWR\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT29 COMP_HALDM\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT30 COMP_RSNA\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT31 COMP_INDIC\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT32 COMP_LED\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT33 COMP_RF\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT34 COMP_HT\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT35 COMP_POWER_TRACKING\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT36 COMP_POWER_TRACKING\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT37 COMP_AMSDU\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT38 COMP_WPS\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT39 COMP_RATR\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT40 COMP_RESET\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT41 COMP_CMD\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT42 COMP_EFUSE\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT43 COMP_MESH_INTERWORKING\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT43 COMP_CCX\n")); + + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("GlobalDebugComponents = %"i64fmt"x\n", GlobalDebugComponents)); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("Enable DBG COMP =")); + for (i = 0; i < 64; i++) + { + if (GlobalDebugComponents & ((u8Byte)0x1 << i) ) + { + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT%02d |\n", i)); + } + } + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("\n")); + +} // DBG_PrintAllComp + + +/*----------------------------------------------------------------------------- + * Function: DBG_PrintFlagEvent + * + * Overview: Print dedicated debug flag event + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 12/10/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +extern void DBG_PrintFlagEvent(u1Byte DbgFlag) +{ + switch(DbgFlag) + { + case FQoS: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 QoS_INIT\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 QoS_VISTA\n")); + break; + + case FTX: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 TX_DESC\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 TX_DESC_TID\n")); + break; + + case FRX: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 RX_DATA\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 RX_PHY_STS\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 2 RX_PHY_SS\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 3 RX_PHY_SQ\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 4 RX_PHY_ASTS\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 5 RX_ERR_LEN\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 6 RX_DEFRAG\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 7 RX_ERR_RATE\n")); + break; + + case FSEC: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("NA\n")); + break; + + case FMGNT: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("NA\n")); + break; + + case FMLME: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 MEDIA_STS\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 LINK_STS\n")); + break; + + case FRESOURCE: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 OS_CHK\n")); + break; + + case FBEACON: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 BCN_SHOW\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 BCN_PEER\n")); + break; + + case FISR: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 ISR_CHK\n")); + break; + + case FPHY: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 PHY_BBR\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 PHY_BBW\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 2 PHY_RFR\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 3 PHY_RFW\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 4 PHY_MACR\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 5 PHY_MACW\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 6 PHY_ALLR\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 7 PHY_ALLW\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 8 PHY_TXPWR\n")); + break; + + case FMP: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 MP_RX\n")); + break; + + case FEEPROM: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 EEPROM_W\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 EFUSE_PG\n")); + break; + + case FPWR: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 LPS\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 IPS\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 2 PWRSW\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 3 PWRHW\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 4 PWRHAL\n")); + break; + + case FDM: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 WA_IOT\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 DM_PWDB\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 2 DM_Monitor\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 3 DM_DIG\n")); + break; + + case FDBG_CTRL: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 DBG_CTRL_TRACE\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 DBG_CTRL_INBAND_NOISE\n")); + break; + + case FC2H: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 C2H_Summary\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 C2H_PacketData\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 2 C2H_ContentData\n")); + break; + + case FBT: + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 0 BT_TRACE\n")); + ODM_RT_TRACE(pDM_Odm,COMP_CMD, DBG_LOUD, ("BIT 1 BT_RFPoll\n")); + break; + + default: + break; + } + +} // DBG_PrintFlagEvent + + +extern void DBG_DumpMem(const u1Byte DbgComp, + const u1Byte DbgLevel, + pu1Byte pMem, + u2Byte Len) +{ + u2Byte i; + + for (i=0;i<((Len>>3) + 1);i++) + { + ODM_RT_TRACE(pDM_Odm,DbgComp, DbgLevel, ("%02X %02X %02X %02X %02X %02X %02X %02X\n", + *(pMem+(i*8)), *(pMem+(i*8+1)), *(pMem+(i*8+2)), *(pMem+(i*8+3)), + *(pMem+(i*8+4)), *(pMem+(i*8+5)), *(pMem+(i*8+6)), *(pMem+(i*8+7)))); + + } +} + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_debug.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_debug.h new file mode 100644 index 0000000..a4159eb --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_debug.h @@ -0,0 +1,898 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + + +#ifndef __ODM_DBG_H__ +#define __ODM_DBG_H__ + + +//----------------------------------------------------------------------------- +// Define the debug levels +// +// 1. DBG_TRACE and DBG_LOUD are used for normal cases. +// So that, they can help SW engineer to develope or trace states changed +// and also help HW enginner to trace every operation to and from HW, +// e.g IO, Tx, Rx. +// +// 2. DBG_WARNNING and DBG_SERIOUS are used for unusual or error cases, +// which help us to debug SW or HW. +// +//----------------------------------------------------------------------------- +// +// Never used in a call to ODM_RT_TRACE()! +// +#define ODM_DBG_OFF 1 + +// +// Fatal bug. +// For example, Tx/Rx/IO locked up, OS hangs, memory access violation, +// resource allocation failed, unexpected HW behavior, HW BUG and so on. +// +#define ODM_DBG_SERIOUS 2 + +// +// Abnormal, rare, or unexpeted cases. +// For example, IRP/Packet/OID canceled, device suprisely unremoved and so on. +// +#define ODM_DBG_WARNING 3 + +// +// Normal case with useful information about current SW or HW state. +// For example, Tx/Rx descriptor to fill, Tx/Rx descriptor completed status, +// SW protocol state change, dynamic mechanism state change and so on. +// +#define ODM_DBG_LOUD 4 + +// +// Normal case with detail execution flow or information. +// +#define ODM_DBG_TRACE 5 + +//----------------------------------------------------------------------------- +// Define the tracing components +// +//----------------------------------------------------------------------------- +//BB Functions +#define ODM_COMP_DIG BIT0 +#define ODM_COMP_RA_MASK BIT1 +#define ODM_COMP_DYNAMIC_TXPWR BIT2 +#define ODM_COMP_FA_CNT BIT3 +#define ODM_COMP_RSSI_MONITOR BIT4 +#define ODM_COMP_CCK_PD BIT5 +#define ODM_COMP_ANT_DIV BIT6 +#define ODM_COMP_PWR_SAVE BIT7 +#define ODM_COMP_PWR_TRAIN BIT8 +#define ODM_COMP_RATE_ADAPTIVE BIT9 +#define ODM_COMP_PATH_DIV BIT10 +#define ODM_COMP_PSD BIT11 +#define ODM_COMP_DYNAMIC_PRICCA BIT12 +#define ODM_COMP_RXHP BIT13 +#define ODM_COMP_MP BIT14 +#define ODM_COMP_DYNAMIC_ATC BIT15 +#define ODM_COMP_ACS BIT16 +#define PHYDM_COMP_ADAPTIVITY BIT17 +#define PHYDM_COMP_RA_DBG BIT18 +#define PHYDM_COMP_TXBF BIT19 +//MAC Functions +#define ODM_COMP_EDCA_TURBO BIT20 +#define ODM_COMP_EARLY_MODE BIT21 +#define ODM_FW_DEBUG_TRACE BIT22 +//RF Functions +#define ODM_COMP_TX_PWR_TRACK BIT24 +#define ODM_COMP_RX_GAIN_TRACK BIT25 +#define ODM_COMP_CALIBRATION BIT26 +//Common Functions +#define BEAMFORMING_DEBUG BIT29 +#define ODM_COMP_COMMON BIT30 +#define ODM_COMP_INIT BIT31 + +/*------------------------Export Marco Definition---------------------------*/ +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + #define RT_PRINTK DbgPrint +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + #define DbgPrint printk + #define RT_PRINTK(fmt, args...) DbgPrint( "%s(): " fmt, __FUNCTION__, ## args); + #define RT_DISP(dbgtype, dbgflag, printstr) +#else + #define DbgPrint panic_printk + #define RT_PRINTK(fmt, args...) DbgPrint( "%s(): " fmt, __FUNCTION__, ## args); +#endif + +#ifndef ASSERT + #define ASSERT(expr) +#endif + +#if DBG +#define ODM_RT_TRACE(pDM_Odm, comp, level, fmt) \ + if(((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel || level == ODM_DBG_SERIOUS)) \ + { \ + RT_PRINTK fmt; \ + } + +#define ODM_RT_TRACE_F(pDM_Odm, comp, level, fmt) \ + if(((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel)) \ + { \ + RT_PRINTK fmt; \ + } + +#define ODM_RT_ASSERT(pDM_Odm, expr, fmt) \ + if(!(expr)) { \ + DbgPrint( "Assertion failed! %s at ......\n", #expr); \ + DbgPrint( " ......%s,%s,line=%d\n",__FILE__,__FUNCTION__,__LINE__); \ + RT_PRINTK fmt; \ + ASSERT(FALSE); \ + } +#define ODM_dbg_enter() { DbgPrint("==> %s\n", __FUNCTION__); } +#define ODM_dbg_exit() { DbgPrint("<== %s\n", __FUNCTION__); } +#define ODM_dbg_trace(str) { DbgPrint("%s:%s\n", __FUNCTION__, str); } + +#define ODM_PRINT_ADDR(pDM_Odm, comp, level, title_str, ptr) \ + if(((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel)) \ + { \ + int __i; \ + pu1Byte __ptr = (pu1Byte)ptr; \ + DbgPrint("[ODM] "); \ + DbgPrint(title_str); \ + DbgPrint(" "); \ + for( __i=0; __i<6; __i++ ) \ + DbgPrint("%02X%s", __ptr[__i], (__i==5)?"":"-"); \ + DbgPrint("\n"); \ + } +#else +#define ODM_RT_TRACE(pDM_Odm, comp, level, fmt) +#define ODM_RT_TRACE_F(pDM_Odm, comp, level, fmt) +#define ODM_RT_ASSERT(pDM_Odm, expr, fmt) +#define ODM_dbg_enter() +#define ODM_dbg_exit() +#define ODM_dbg_trace(str) +#define ODM_PRINT_ADDR(pDM_Odm, comp, level, title_str, ptr) +#endif + + +VOID +ODM_InitDebugSetting( + IN PDM_ODM_T pDM_Odm + ); + + + +#if 0 +#if DBG +#define DbgPrint printk + +#define PRINT_DATA(_TitleString, _HexData, _HexDataLen) \ + { \ + char *szTitle = _TitleString; \ + pu1Byte pbtHexData = _HexData; \ + u4Byte u4bHexDataLen = _HexDataLen; \ + u4Byte __i; \ + DbgPrint("%s", szTitle); \ + for (__i=0;__i<u4bHexDataLen;__i++) \ + { \ + if ((__i & 15) == 0) \ + { \ + DbgPrint("\n"); \ + } \ + DbgPrint("%02X%s", pbtHexData[__i], ( ((__i&3)==3) ? " " : " ") ); \ + } \ + DbgPrint("\n"); \ + } + +// RT_PRINT_XXX macros: implemented for debugging purpose. +// Added by Annie, 2005-11-21. +#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) \ + if(((_Comp) & ODM_GlobalDebugComponents) && (_Level <= ODM_GlobalDebugLevel)) \ + { \ + int __i; \ + pu1Byte ptr = (pu1Byte)_HexData; \ + DbgPrint("Rtl819x: "); \ + DbgPrint(_TitleString); \ + for( __i=0; __i<(int)_HexDataLen; __i++ ) \ + { \ + DbgPrint("%02X%s", ptr[__i], (((__i + 1) % 4) == 0)?" ":" "); \ + if (((__i + 1) % 16) == 0) DbgPrint("\n"); \ + } \ + DbgPrint("\n"); \ + } + +#define RT_PRINT_ADDR(_Comp, _Level, _TitleString, _Ptr) \ + if(((_Comp) & ODM_GlobalDebugComponents) && (_Level <= ODM_GlobalDebugLevel)) \ + { \ + int __i; \ + pu1Byte ptr = (pu1Byte)_Ptr; \ + DbgPrint("Rtl819x: "); \ + DbgPrint(_TitleString); \ + DbgPrint(" "); \ + for( __i=0; __i<6; __i++ ) \ + DbgPrint("%02X%s", ptr[__i], (__i==5)?"":"-"); \ + DbgPrint("\n"); \ + } + +#define RT_PRINT_ADDRS(_Comp, _Level, _TitleString, _Ptr, _AddNum) \ + if(((_Comp) & ODM_GlobalDebugComponents) && (_Level <= ODM_GlobalDebugLevel)) \ + { \ + int __i, __j; \ + pu1Byte ptr = (pu1Byte)_Ptr; \ + DbgPrint("Rtl819x: "); \ + DbgPrint(_TitleString); \ + DbgPrint("\n"); \ + for( __i=0; __i<(int)_AddNum; __i++ ) \ + { \ + for( __j=0; __j<6; __j++ ) \ + DbgPrint("%02X%s", ptr[__i*6+__j], (__j==5)?"":"-"); \ + DbgPrint("\n"); \ + } \ + } + +// Added by Annie, 2005-11-22. +#define MAX_STR_LEN 64 +#define PRINTABLE(_ch) (_ch>=' ' &&_ch<='~' ) // I want to see ASCII 33 to 126 only. Otherwise, I print '?'. Annie, 2005-11-22. + +#define RT_PRINT_STR(_Comp, _Level, _TitleString, _Ptr, _Len) \ + if(((_Comp) & ODM_GlobalDebugComponents) && (_Level <= ODM_GlobalDebugLevel)) \ + { \ + int __i; \ + u1Byte buffer[MAX_STR_LEN]; \ + int length = (_Len<MAX_STR_LEN)? _Len : (MAX_STR_LEN-1) ; \ + PlatformZeroMemory( buffer, MAX_STR_LEN ); \ + PlatformMoveMemory( buffer, (pu1Byte)_Ptr, length ); \ + for( __i=0; __i<MAX_STR_LEN; __i++ ) \ + { \ + if( !PRINTABLE(buffer[__i]) ) buffer[__i] = '?'; \ + } \ + buffer[length] = '\0'; \ + DbgPrint("Rtl819x: "); \ + DbgPrint(_TitleString); \ + DbgPrint(": %d, <%s>\n", _Len, buffer); \ + } + +#else // of #if DBG +#define DbgPrint(...) +#define PRINT_DATA(_TitleString, _HexData, _HexDataLen) +#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) +#define RT_PRINT_ADDR(_Comp, _Level, _TitleString, _Ptr) +#define RT_PRINT_ADDRS(_Comp, _Level, _TitleString, _Ptr, _AddNum) +#define RT_PRINT_STR(_Comp, _Level, _TitleString, _Ptr, _Len) +#endif // of #if DBG + +#endif + + +#if 0 +/* Define debug print header for every service module.*/ +typedef struct tag_ODM_DBGP_Service_Module_Header_Name_Structure +{ + const char *pMANS; + const char *pRTOS; + const char *pALM; + const char *pPEM; + const char *pCMPK; + const char *pRAPD; + const char *pTXPB; + const char *pQUMG; +}ODM_DBGP_HEAD_T; + + +/* Define different debug flag for dedicated service modules in debug flag array. */ +// Each module has independt 32 bit debug flag you cnn define the flag as yout require. +typedef enum tag_ODM_DBGP_Flag_Type_Definition +{ + ODM_FTX = 0, + ODM_FRX , + ODM_FPHY , + ODM_FPWR , + ODM_FDM , + ODM_FC2H , + ODM_FBT , + ODM_DBGP_TYPE_MAX +}ODM_DBGP_FLAG_E; + + +// Define TX relative debug bit --> FTX +#define ODM_TX_DESC BIT0 +#define ODM_TX_DESC_TID BIT1 +#define ODM_TX_PATH BIT2 + +// Define RX relative debug bit --> FRX +#define ODM_RX_DATA BIT0 +#define ODM_RX_PHY_STS BIT1 +#define ODM_RX_PHY_SS BIT2 +#define ODM_RX_PHY_SQ BIT3 +#define ODM_RX_PHY_ASTS BIT4 +#define ODM_RX_ERR_LEN BIT5 +#define ODM_RX_DEFRAG BIT6 +#define ODM_RX_ERR_RATE BIT7 +#define ODM_RX_PATH BIT8 +#define ODM_RX_BEACON BIT9 + +// Define PHY-BB/RF/MAC check module bit --> FPHY +#define ODM_PHY_BBR BIT0 +#define ODM_PHY_BBW BIT1 +#define ODM_PHY_RFR BIT2 +#define ODM_PHY_RFW BIT3 +#define ODM_PHY_MACR BIT4 +#define ODM_PHY_MACW BIT5 +#define ODM_PHY_ALLR BIT6 +#define ODM_PHY_ALLW BIT7 +#define ODM_PHY_TXPWR BIT8 +#define ODM_PHY_PWRDIFF BIT9 +#define ODM_PHY_SICR BIT10 +#define ODM_PHY_SICW BIT11 + + + + +extern u4Byte ODM_GlobalDebugLevel; + + +#if DBG +extern u8Byte ODM_GlobalDebugComponents; +#endif +#endif +#if 0 + +//----------------------------------------------------------------------------- +// Define the debug levels +// +// 1. DBG_TRACE and DBG_LOUD are used for normal cases. +// So that, they can help SW engineer to develope or trace states changed +// and also help HW enginner to trace every operation to and from HW, +// e.g IO, Tx, Rx. +// +// 2. DBG_WARNNING and DBG_SERIOUS are used for unusual or error cases, +// which help us to debug SW or HW. +// +//----------------------------------------------------------------------------- +// +// Never used in a call to ODM_RT_TRACE(pDM_Odm,)! +// +#define DBG_OFF 0 + +// +// Deprecated! Don't use it! +// TODO: fix related debug message! +// +//#define DBG_SEC 1 + +// +// Fatal bug. +// For example, Tx/Rx/IO locked up, OS hangs, memory access violation, +// resource allocation failed, unexpected HW behavior, HW BUG and so on. +// +#define DBG_SERIOUS 2 + +// +// Abnormal, rare, or unexpeted cases. +// For example, IRP/Packet/OID canceled, device suprisely unremoved and so on. +// +#define DBG_WARNING 3 + +// +// Normal case with useful information about current SW or HW state. +// For example, Tx/Rx descriptor to fill, Tx/Rx descriptor completed status, +// SW protocol state change, dynamic mechanism state change and so on. +// +#define DBG_LOUD 4 + +// +// Normal case with detail execution flow or information. +// +#define DBG_TRACE 5 + + + +//----------------------------------------------------------------------------- +// Define the tracing components +// +//----------------------------------------------------------------------------- +#define COMP_TRACE BIT0 // For function call tracing. +#define COMP_DBG BIT1 // Only for temporary debug message. +#define COMP_INIT BIT2 // during driver initialization / halt / reset. +#define COMP_OID_QUERY BIT3 // Query OID. +#define COMP_OID_SET BIT4 // Set OID. +#define COMP_RECV BIT5 // Reveive part data path. +#define COMP_SEND BIT6 // Send part path. +#define COMP_IO BIT7 // I/O Related. Added by Annie, 2006-03-02. +#define COMP_POWER BIT8 // 802.11 Power Save mode or System/Device Power state related. +#define COMP_MLME BIT9 // 802.11 link related: join/start BSS, leave BSS. +#define COMP_SCAN BIT10 // For site survey. +#define COMP_SYSTEM BIT11 // For general platform function. +#define COMP_SEC BIT12 // For Security. +#define COMP_AP BIT13 // For AP mode related. +#define COMP_TURBO BIT14 // For Turbo Mode related. By Annie, 2005-10-21. +#define COMP_QOS BIT15 // For QoS. +#define COMP_AUTHENTICATOR BIT16 // For AP mode Authenticator. Added by Annie, 2006-01-30. +#define COMP_BEACON BIT17 // For Beacon related, by rcnjko. +#define COMP_ANTENNA BIT18 // For Antenna diversity related, by rcnjko. +#define COMP_RATE BIT19 // For Rate Adaptive mechanism, 2006.07.02, by rcnjko. #define COMP_EVENTS 0x00000080 // Event handling +#define COMP_EVENTS BIT20 // Event handling +#define COMP_FPGA BIT21 // For FPGA verfication +#define COMP_RM BIT22 // For Radio Measurement. +#define COMP_MP BIT23 // For mass production test, by shien chang, 2006.07.13 +#define COMP_RXDESC BIT24 // Show Rx desc information for SD3 debug. Added by Annie, 2006-07-15. +#define COMP_CKIP BIT25 // For CCX 1 S13: CKIP. Added by Annie, 2006-08-14. +#define COMP_DIG BIT26 // For DIG, 2006.09.25, by rcnjko. +#define COMP_TXAGC BIT27 // For Tx power, 060928, by rcnjko. +#define COMP_HIPWR BIT28 // For High Power Mechanism, 060928, by rcnjko. +#define COMP_HALDM BIT29 // For HW Dynamic Mechanism, 061010, by rcnjko. +#define COMP_RSNA BIT30 // For RSNA IBSS , 061201, by CCW. +#define COMP_INDIC BIT31 // For link indication +#define COMP_LED BIT32 // For LED. +#define COMP_RF BIT33 // For RF. +//1!!!!!!!!!!!!!!!!!!!!!!!!!!! +//1//1Attention Please!!!<11n or 8190 specific code should be put below this line> +//1!!!!!!!!!!!!!!!!!!!!!!!!!!! + +#define COMP_HT BIT34 // For 802.11n HT related information. by Emily 2006-8-11 +#define COMP_POWER_TRACKING BIT35 //FOR 8190 TX POWER TRACKING +#define COMP_RX_REORDER BIT36 // 8190 Rx Reorder +#define COMP_AMSDU BIT37 // For A-MSDU Debugging +#define COMP_WPS BIT38 //WPS Debug Message +#define COMP_RATR BIT39 +#define COMP_RESET BIT40 +// For debug command to print on dbgview!! +#define COMP_CMD BIT41 +#define COMP_EFUSE BIT42 +#define COMP_MESH_INTERWORKING BIT43 +#define COMP_CCX BIT44 //CCX Debug Flag +#define COMP_IOCTL BIT45 // IO Control +#define COMP_GP BIT46 // For generic parser. +#define COMP_TXAGG BIT47 +#define COMP_HVL BIT48 // For Ndis 6.2 Context Swirch and Hardware Virtualiztion Layer +#define COMP_TEST BIT49 +#define COMP_BB_POWERSAVING BIT50 +#define COMP_SWAS BIT51 // For SW Antenna Switch +#define COMP_P2P BIT52 +#define COMP_MUX BIT53 +#define COMP_FUNC BIT54 +#define COMP_TDLS BIT55 +#define COMP_OMNIPEEK BIT56 +#define COMP_DUALMACSWITCH BIT60 // 2010/12/27 Add for Dual mac mode debug +#define COMP_EASY_CONCURRENT BIT61 // 2010/12/27 Add for easy cncurrent mode debug +#define COMP_PSD BIT63 //2011/3/9 Add for WLAN PSD for BT AFH + +#define COMP_DFS BIT62 + +#define COMP_ALL UINT64_C(0xFFFFFFFFFFFFFFFF) // All components +// For debug print flag to use +/*------------------------------Define structure----------------------------*/ +/* 2007/07/13 MH *//*------For DeBuG Print modeue------*/ + +/* Defnie structure to store different debug flag variable. Every debug flag + is a UINT32 integer and you can assign 32 different events. */ +typedef struct tag_DBGP_Debug_Flag_Structure +{ + u4Byte Mans; /* Main Scheduler module. */ + u4Byte Rtos; /* RTOS module. */ + u4Byte Alarm; /* Alarm module. */ + u4Byte Pm; /* Performance monitor module. */ +}DBGP_FLAG_T; + +/* Define debug print header for every service module.*/ +typedef struct tag_DBGP_Service_Module_Header_Name_Structure +{ + const char *pMANS; + const char *pRTOS; + const char *pALM; + const char *pPEM; + const char *pCMPK; + const char *pRAPD; + const char *pTXPB; + const char *pQUMG; +}DBGP_HEAD_T; + + +/* Define different debug flag for dedicated service modules in debug flag array. */ +// Each module has independt 32 bit debug flag you cnn define the flag as yout require. +typedef enum tag_DBGP_Flag_Type_Definition +{ + FQoS = 0, + FTX = 1, + FRX = 2, + FSEC = 3, + FMGNT = 4, + FMLME = 5, + FRESOURCE = 6, + FBEACON = 7, + FISR = 8, + FPHY = 9, + FMP = 10, + FEEPROM = 11, + FPWR = 12, + FDM = 13, + FDBG_CTRL = 14, + FC2H = 15, + FBT = 16, + FINIT = 17, + FIOCTL = 18, + FSHORT_CUT = 19, + DBGP_TYPE_MAX +}DBGP_FLAG_E; + + +// Define Qos Relative debug flag bit --> FQoS +#define QoS_INIT BIT0 +#define QoS_VISTA BIT1 + +// Define TX relative debug bit --> FTX +#define TX_DESC BIT0 +#define TX_DESC_TID BIT1 +#define TX_PATH BIT2 + +// Define RX relative debug bit --> FRX +#define RX_DATA BIT0 +#define RX_PHY_STS BIT1 +#define RX_PHY_SS BIT2 +#define RX_PHY_SQ BIT3 +#define RX_PHY_ASTS BIT4 +#define RX_ERR_LEN BIT5 +#define RX_DEFRAG BIT6 +#define RX_ERR_RATE BIT7 +#define RX_PATH BIT8 +#define RX_BEACON BIT9 + +// Define Security relative debug bit --> FSEC + +// Define MGNT relative debug bit --> FMGNT + +// Define MLME relative debug bit --> FMLME +#define MEDIA_STS BIT0 +#define LINK_STS BIT1 + +// Define OS resource check module bit --> FRESOURCE +#define OS_CHK BIT0 + +// Define beacon content check module bit --> FBEACON +#define BCN_SHOW BIT0 +#define BCN_PEER BIT1 + +// Define ISR/IMR check module bit --> FISR +#define ISR_CHK BIT0 + +// Define PHY-BB/RF/MAC check module bit --> FPHY +#define PHY_BBR BIT0 +#define PHY_BBW BIT1 +#define PHY_RFR BIT2 +#define PHY_RFW BIT3 +#define PHY_MACR BIT4 +#define PHY_MACW BIT5 +#define PHY_ALLR BIT6 +#define PHY_ALLW BIT7 +#define PHY_TXPWR BIT8 +#define PHY_PWRDIFF BIT9 +#define PHY_SICR BIT10 +#define PHY_SICW BIT11 + +// Define MPT driver check module bit --> FMP +#define MP_RX BIT0 +#define MP_SWICH_CH BIT1 + +// Define EEPROM and EFUSE check module bit --> FEEPROM +#define EEPROM_W BIT0 +#define EFUSE_PG BIT1 +#define EFUSE_READ_ALL BIT2 +#define EFUSE_ANALYSIS BIT3 +#define EFUSE_PG_DETAIL BIT4 + +// Define power save check module bit --> FPWR +#define LPS BIT0 +#define IPS BIT1 +#define PWRSW BIT2 +#define PWRHW BIT3 +#define PWRHAL BIT4 + +// Define Dynamic Mechanism check module bit --> FDM +#define WA_IOT BIT0 +#define DM_PWDB BIT1 +#define DM_Monitor BIT2 +#define DM_DIG BIT3 +#define DM_EDCA_Turbo BIT4 +#define DM_BT30 BIT5 + +// Define Dbg Control module bit --> FDBG_CTRL +#define DBG_CTRL_TRACE BIT0 +#define DBG_CTRL_INBAND_NOISE BIT1 + +// Define FW C2H Cmd check module bit --> FC2H +#define C2H_Summary BIT0 +#define C2H_PacketData BIT1 +#define C2H_ContentData BIT2 +// Define BT Cmd check module bit --> FBT +#define BT_TRACE BIT0 +#define BT_RFPoll BIT1 + +// Define init check for module bit --> FINIT +#define INIT_EEPROM BIT0 +#define INIT_TxPower BIT1 +#define INIT_IQK BIT2 +#define INIT_RF BIT3 + +// Define IOCTL Cmd check module bit --> FIOCTL +// section 1 : IRP related +#define IOCTL_IRP BIT0 +#define IOCTL_IRP_DETAIL BIT1 +#define IOCTL_IRP_STATISTICS BIT2 +#define IOCTL_IRP_HANDLE BIT3 +// section 2 : HCI command/event +#define IOCTL_BT_HCICMD BIT8 +#define IOCTL_BT_HCICMD_DETAIL BIT9 +#define IOCTL_BT_HCICMD_EXT BIT10 +#define IOCTL_BT_EVENT BIT11 +#define IOCTL_BT_EVENT_DETAIL BIT12 +#define IOCTL_BT_EVENT_PERIODICAL BIT13 +// section 3 : BT tx/rx data and throughput +#define IOCTL_BT_TX_ACLDATA BIT16 +#define IOCTL_BT_TX_ACLDATA_DETAIL BIT17 +#define IOCTL_BT_RX_ACLDATA BIT18 +#define IOCTL_BT_RX_ACLDATA_DETAIL BIT19 +#define IOCTL_BT_TP BIT20 +// section 4 : BT connection state machine. +#define IOCTL_STATE BIT21 +#define IOCTL_BT_LOGO BIT22 +// section 5 : BT function trace +#define IOCTL_CALLBACK_FUN BIT24 +#define IOCTL_PARSE_BT_PKT BIT25 +#define IOCTL_BT_TX_PKT BIT26 +#define IOCTL_BT_FLAG_MON BIT27 + +// +// Define init check for module bit --> FSHORT_CUT +// 2011/07/20 MH Add for short but definition. +// +#define SHCUT_TX BIT0 +#define SHCUT_RX BIT1 + + +/* 2007/07/13 MH *//*------For DeBuG Print modeue------*/ +/*------------------------------Define structure----------------------------*/ + + +/*------------------------Export Marco Definition---------------------------*/ +#if (DM_ODM_SUPPORT_TYPE != ODM_WIN) +#define RT_PRINTK(fmt, args...) printk( "%s(): " fmt, __FUNCTION__, ## args); + +#if DBG +#define ODM_RT_TRACE(pDM_Odm,comp, level, fmt) \ + if(((comp) & GlobalDebugComponents) && (level <= GlobalDebugLevel)) \ + { \ + RT_PRINTK fmt; \ + } + +#define RT_TRACE_F(comp, level, fmt) \ + if(((comp) & GlobalDebugComponents) && (level <= GlobalDebugLevel)) \ + { \ + RT_PRINTK fmt; \ + } + +#define RT_ASSERT(expr,fmt) \ + if(!(expr)) { \ + printk( "Assertion failed! %s at ......\n", #expr); \ + printk( " ......%s,%s,line=%d\n",__FILE__,__FUNCTION__,__LINE__); \ + } +#define dbg_enter() { printk("==> %s\n", __FUNCTION__); } +#define dbg_exit() { printk("<== %s\n", __FUNCTION__); } +#define dbg_trace(str) { printk("%s:%s\n", __FUNCTION__, str); } +#else +#define ODM_RT_TRACE(pDM_Odm,comp, level, fmt) +#define RT_TRACE_F(comp, level, fmt) +#define RT_ASSERT(expr, fmt) +#define dbg_enter() +#define dbg_exit() +#define dbg_trace(str) +#endif + +#if DBG +#define DbgPrint printk + +#define PRINT_DATA(_TitleString, _HexData, _HexDataLen) \ + { \ + char *szTitle = _TitleString; \ + pu1Byte pbtHexData = _HexData; \ + u4Byte u4bHexDataLen = _HexDataLen; \ + u4Byte __i; \ + DbgPrint("%s", szTitle); \ + for (__i=0;__i<u4bHexDataLen;__i++) \ + { \ + if ((__i & 15) == 0) \ + { \ + DbgPrint("\n"); \ + } \ + DbgPrint("%02X%s", pbtHexData[__i], ( ((__i&3)==3) ? " " : " ") ); \ + } \ + DbgPrint("\n"); \ + } + +// RT_PRINT_XXX macros: implemented for debugging purpose. +// Added by Annie, 2005-11-21. +#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) \ + if(((_Comp) & GlobalDebugComponents) && (_Level <= GlobalDebugLevel)) \ + { \ + int __i; \ + pu1Byte ptr = (pu1Byte)_HexData; \ + DbgPrint("Rtl819x: "); \ + DbgPrint(_TitleString); \ + for( __i=0; __i<(int)_HexDataLen; __i++ ) \ + { \ + DbgPrint("%02X%s", ptr[__i], (((__i + 1) % 4) == 0)?" ":" "); \ + if (((__i + 1) % 16) == 0) DbgPrint("\n"); \ + } \ + DbgPrint("\n"); \ + } + +#define RT_PRINT_ADDR(_Comp, _Level, _TitleString, _Ptr) \ + if(((_Comp) & GlobalDebugComponents) && (_Level <= GlobalDebugLevel)) \ + { \ + int __i; \ + pu1Byte ptr = (pu1Byte)_Ptr; \ + DbgPrint("Rtl819x: "); \ + DbgPrint(_TitleString); \ + DbgPrint(" "); \ + for( __i=0; __i<6; __i++ ) \ + DbgPrint("%02X%s", ptr[__i], (__i==5)?"":"-"); \ + DbgPrint("\n"); \ + } + +#define RT_PRINT_ADDRS(_Comp, _Level, _TitleString, _Ptr, _AddNum) \ + if(((_Comp) & GlobalDebugComponents) && (_Level <= GlobalDebugLevel)) \ + { \ + int __i, __j; \ + pu1Byte ptr = (pu1Byte)_Ptr; \ + DbgPrint("Rtl819x: "); \ + DbgPrint(_TitleString); \ + DbgPrint("\n"); \ + for( __i=0; __i<(int)_AddNum; __i++ ) \ + { \ + for( __j=0; __j<6; __j++ ) \ + DbgPrint("%02X%s", ptr[__i*6+__j], (__j==5)?"":"-"); \ + DbgPrint("\n"); \ + } \ + } + +// Added by Annie, 2005-11-22. +#define MAX_STR_LEN 64 +#define PRINTABLE(_ch) (_ch>=' ' &&_ch<='~' ) // I want to see ASCII 33 to 126 only. Otherwise, I print '?'. Annie, 2005-11-22. + +#define RT_PRINT_STR(_Comp, _Level, _TitleString, _Ptr, _Len) \ + if(((_Comp) & GlobalDebugComponents) && (_Level <= GlobalDebugLevel)) \ + { \ + int __i; \ + u1Byte buffer[MAX_STR_LEN]; \ + int length = (_Len<MAX_STR_LEN)? _Len : (MAX_STR_LEN-1) ; \ + PlatformZeroMemory( buffer, MAX_STR_LEN ); \ + PlatformMoveMemory( buffer, (pu1Byte)_Ptr, length ); \ + for( __i=0; __i<MAX_STR_LEN; __i++ ) \ + { \ + if( !PRINTABLE(buffer[__i]) ) buffer[__i] = '?'; \ + } \ + buffer[length] = '\0'; \ + DbgPrint("Rtl819x: "); \ + DbgPrint(_TitleString); \ + DbgPrint(": %d, <%s>\n", _Len, buffer); \ + } + +#else // of #if DBG +#define DbgPrint(...) +#define PRINT_DATA(_TitleString, _HexData, _HexDataLen) +#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) +#define RT_PRINT_ADDR(_Comp, _Level, _TitleString, _Ptr) +#define RT_PRINT_ADDRS(_Comp, _Level, _TitleString, _Ptr, _AddNum) +#define RT_PRINT_STR(_Comp, _Level, _TitleString, _Ptr, _Len) +#endif // of #if DBG + + + +#endif // #if (DM_ODM_SUPPORT_TYPE != ODM_WIN) + +#define DEBUG_PRINT 1 + +// Please add new OS's print API by yourself + +//#if (RT_PLATFORM==PLATFORM_WINDOWS) +#if (DEBUG_PRINT == 1) && DBG +#define RT_DISP(dbgtype, dbgflag, printstr)\ +{\ + if (DBGP_Type[dbgtype] & dbgflag)\ + {\ + DbgPrint printstr;\ + }\ +} + +#define RT_DISP_ADDR(dbgtype, dbgflag, printstr, _Ptr)\ +{\ + if (DBGP_Type[dbgtype] & dbgflag)\ + {\ + int __i; \ + pu1Byte ptr = (pu1Byte)_Ptr; \ + DbgPrint printstr; \ + DbgPrint(" "); \ + for( __i=0; __i<6; __i++ ) \ + DbgPrint("%02X%s", ptr[__i], (__i==5)?"":"-"); \ + DbgPrint("\n"); \ + }\ +} + +#define RT_DISP_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen)\ +{\ + if (DBGP_Type[dbgtype] & dbgflag)\ + {\ + int __i; \ + pu1Byte ptr = (pu1Byte)_HexData; \ + DbgPrint(_TitleString); \ + for( __i=0; __i<(int)_HexDataLen; __i++ ) \ + { \ + DbgPrint("%02X%s", ptr[__i], (((__i + 1) % 4) == 0)?" ":" ");\ + if (((__i + 1) % 16) == 0) DbgPrint("\n");\ + } \ + DbgPrint("\n"); \ + }\ +} + +#define FunctionIn(_comp) ODM_RT_TRACE(pDM_Odm,(_comp), DBG_LOUD, ("==========> %s\n", __FUNCTION__)) +#define FunctionOut(_comp) ODM_RT_TRACE(pDM_Odm,(_comp), DBG_LOUD, ("<========== %s\n", __FUNCTION__)) + + +#else + +#define RT_DISP(dbgtype, dbgflag, printstr) +#define RT_DISP_ADDR(dbgtype, dbgflag, printstr, _Ptr) +#define RT_DISP_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen) + +#define FunctionIn(_comp) +#define FunctionOut(_comp) +#endif +/*------------------------Export Marco Definition---------------------------*/ + + +/*------------------------Export global variable----------------------------*/ +extern u4Byte DBGP_Type[DBGP_TYPE_MAX]; +extern DBGP_HEAD_T DBGP_Head; + +/*------------------------Export global variable----------------------------*/ + + +/*--------------------------Exported Function prototype---------------------*/ +extern void DBGP_Flag_Init(void); +extern void DBG_PrintAllFlag(void); +extern void DBG_PrintAllComp(void); +extern void DBG_PrintFlagEvent(u1Byte DbgFlag); +extern void DBG_DumpMem(const u1Byte DbgComp, + const u1Byte DbgLevel, + pu1Byte pMem, + u2Byte Len); + +/*--------------------------Exported Function prototype---------------------*/ + + + + + + + + + +extern u4Byte GlobalDebugLevel; +extern u8Byte GlobalDebugComponents; + + +#endif + + +#endif // __ODM_DBG_H__ + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_interface.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_interface.c new file mode 100644 index 0000000..8edf591 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_interface.c @@ -0,0 +1,751 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +//============================================================ +// include files +//============================================================ + + +#include "odm_precomp.h" + +// +// ODM IO Relative API. +// + +u1Byte +ODM_Read1Byte( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + prtl8192cd_priv priv = pDM_Odm->priv; + return RTL_R8(RegAddr); +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + return rtw_read8(Adapter,RegAddr); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + return PlatformEFIORead1Byte(Adapter, RegAddr); +#endif + +} + + +u2Byte +ODM_Read2Byte( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + prtl8192cd_priv priv = pDM_Odm->priv; + return RTL_R16(RegAddr); +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + return rtw_read16(Adapter,RegAddr); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + return PlatformEFIORead2Byte(Adapter, RegAddr); +#endif + +} + + +u4Byte +ODM_Read4Byte( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + prtl8192cd_priv priv = pDM_Odm->priv; + return RTL_R32(RegAddr); +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + return rtw_read32(Adapter,RegAddr); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + return PlatformEFIORead4Byte(Adapter, RegAddr); +#endif + +} + + +VOID +ODM_Write1Byte( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u1Byte Data + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + prtl8192cd_priv priv = pDM_Odm->priv; + RTL_W8(RegAddr, Data); +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + rtw_write8(Adapter,RegAddr, Data); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + PlatformEFIOWrite1Byte(Adapter, RegAddr, Data); +#endif + +} + + +VOID +ODM_Write2Byte( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u2Byte Data + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + prtl8192cd_priv priv = pDM_Odm->priv; + RTL_W16(RegAddr, Data); +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + rtw_write16(Adapter,RegAddr, Data); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + PlatformEFIOWrite2Byte(Adapter, RegAddr, Data); +#endif + +} + + +VOID +ODM_Write4Byte( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u4Byte Data + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + prtl8192cd_priv priv = pDM_Odm->priv; + RTL_W32(RegAddr, Data); +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + rtw_write32(Adapter,RegAddr, Data); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + PlatformEFIOWrite4Byte(Adapter, RegAddr, Data); +#endif + +} + + +VOID +ODM_SetMACReg( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u4Byte BitMask, + IN u4Byte Data + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + PHY_SetBBReg(pDM_Odm->priv, RegAddr, BitMask, Data); +#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_WIN)) + PADAPTER Adapter = pDM_Odm->Adapter; + PHY_SetBBReg(Adapter, RegAddr, BitMask, Data); +#endif +} + + +u4Byte +ODM_GetMACReg( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u4Byte BitMask + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + return PHY_QueryMacReg(pDM_Odm->priv, RegAddr, BitMask); +#elif(DM_ODM_SUPPORT_TYPE & (ODM_WIN)) + PADAPTER Adapter = pDM_Odm->Adapter; + return PHY_QueryMacReg(Adapter, RegAddr, BitMask); +#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE)) + return PHY_QueryBBReg(pDM_Odm->Adapter, RegAddr, BitMask); +#endif +} + + +VOID +ODM_SetBBReg( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u4Byte BitMask, + IN u4Byte Data + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + PHY_SetBBReg(pDM_Odm->priv, RegAddr, BitMask, Data); +#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_WIN)) + PADAPTER Adapter = pDM_Odm->Adapter; + PHY_SetBBReg(Adapter, RegAddr, BitMask, Data); +#endif +} + + +u4Byte +ODM_GetBBReg( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u4Byte BitMask + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + return PHY_QueryBBReg(pDM_Odm->priv, RegAddr, BitMask); +#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_WIN)) + PADAPTER Adapter = pDM_Odm->Adapter; + return PHY_QueryBBReg(Adapter, RegAddr, BitMask); +#endif +} + + +VOID +ODM_SetRFReg( + IN PDM_ODM_T pDM_Odm, + IN ODM_RF_RADIO_PATH_E eRFPath, + IN u4Byte RegAddr, + IN u4Byte BitMask, + IN u4Byte Data + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + PHY_SetRFReg(pDM_Odm->priv, eRFPath, RegAddr, BitMask, Data); +#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_WIN)) + PADAPTER Adapter = pDM_Odm->Adapter; + PHY_SetRFReg(Adapter, eRFPath, RegAddr, BitMask, Data); +#endif +} + + +u4Byte +ODM_GetRFReg( + IN PDM_ODM_T pDM_Odm, + IN ODM_RF_RADIO_PATH_E eRFPath, + IN u4Byte RegAddr, + IN u4Byte BitMask + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + return PHY_QueryRFReg(pDM_Odm->priv, eRFPath, RegAddr, BitMask, 1); +#elif(DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_WIN)) + PADAPTER Adapter = pDM_Odm->Adapter; + return PHY_QueryRFReg(Adapter, eRFPath, RegAddr, BitMask); +#endif +} + + + + +// +// ODM Memory relative API. +// +VOID +ODM_AllocateMemory( + IN PDM_ODM_T pDM_Odm, + OUT PVOID *pPtr, + IN u4Byte length + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + *pPtr = kmalloc(length, GFP_ATOMIC); +#elif (DM_ODM_SUPPORT_TYPE & ODM_CE ) + *pPtr = rtw_zvmalloc(length); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + PlatformAllocateMemory(Adapter, pPtr, length); +#endif +} + +// length could be ignored, used to detect memory leakage. +VOID +ODM_FreeMemory( + IN PDM_ODM_T pDM_Odm, + OUT PVOID pPtr, + IN u4Byte length + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + kfree(pPtr); +#elif (DM_ODM_SUPPORT_TYPE & ODM_CE ) + rtw_vmfree(pPtr, length); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + //PADAPTER Adapter = pDM_Odm->Adapter; + PlatformFreeMemory(pPtr, length); +#endif +} + +VOID +ODM_MoveMemory( + IN PDM_ODM_T pDM_Odm, + OUT PVOID pDest, + IN PVOID pSrc, + IN u4Byte Length + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif (DM_ODM_SUPPORT_TYPE & ODM_CE ) + _rtw_memcpy(pDest, pSrc, Length); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PlatformMoveMemory(pDest, pSrc, Length); +#endif +} + +s4Byte ODM_CompareMemory( + IN PDM_ODM_T pDM_Odm, + IN PVOID pBuf1, + IN PVOID pBuf2, + IN u4Byte length + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + return memcmp(pBuf1,pBuf2,length); +#elif (DM_ODM_SUPPORT_TYPE & ODM_CE ) + return _rtw_memcmp(pBuf1,pBuf2,length); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + return PlatformCompareMemory(pBuf1,pBuf2,length); +#endif +} + + + +// +// ODM MISC relative API. +// +VOID +ODM_AcquireSpinLock( + IN PDM_ODM_T pDM_Odm, + IN RT_SPINLOCK_TYPE type + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + PlatformAcquireSpinLock(Adapter, type); +#endif +} +VOID +ODM_ReleaseSpinLock( + IN PDM_ODM_T pDM_Odm, + IN RT_SPINLOCK_TYPE type + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif (DM_ODM_SUPPORT_TYPE & ODM_CE ) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + PlatformReleaseSpinLock(Adapter, type); +#endif +} + +// +// Work item relative API. FOr MP driver only~! +// +VOID +ODM_InitializeWorkItem( + IN PDM_ODM_T pDM_Odm, + IN PRT_WORK_ITEM pRtWorkItem, + IN RT_WORKITEM_CALL_BACK RtWorkItemCallback, + IN PVOID pContext, + IN const char* szID + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + PlatformInitializeWorkItem(Adapter, pRtWorkItem, RtWorkItemCallback, pContext, szID); +#endif +} + + +VOID +ODM_StartWorkItem( + IN PRT_WORK_ITEM pRtWorkItem + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PlatformStartWorkItem(pRtWorkItem); +#endif +} + + +VOID +ODM_StopWorkItem( + IN PRT_WORK_ITEM pRtWorkItem + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PlatformStopWorkItem(pRtWorkItem); +#endif +} + + +VOID +ODM_FreeWorkItem( + IN PRT_WORK_ITEM pRtWorkItem + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PlatformFreeWorkItem(pRtWorkItem); +#endif +} + + +VOID +ODM_ScheduleWorkItem( + IN PRT_WORK_ITEM pRtWorkItem + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PlatformScheduleWorkItem(pRtWorkItem); +#endif +} + + +VOID +ODM_IsWorkItemScheduled( + IN PRT_WORK_ITEM pRtWorkItem + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PlatformIsWorkItemScheduled(pRtWorkItem); +#endif +} + + + +// +// ODM Timer relative API. +// +VOID +ODM_StallExecution( + IN u4Byte usDelay + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + rtw_udelay_os(usDelay); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PlatformStallExecution(usDelay); +#endif +} + +VOID +ODM_delay_ms(IN u4Byte ms) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + delay_ms(ms); +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + rtw_mdelay_os(ms); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + delay_ms(ms); +#endif +} + +VOID +ODM_delay_us(IN u4Byte us) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + delay_us(us); +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + rtw_udelay_os(us); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PlatformStallExecution(us); +#endif +} + +VOID +ODM_sleep_ms(IN u4Byte ms) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + rtw_msleep_os(ms); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) +#endif +} + +VOID +ODM_sleep_us(IN u4Byte us) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + rtw_usleep_os(us); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) +#endif +} + +VOID +ODM_SetTimer( + IN PDM_ODM_T pDM_Odm, + IN PRT_TIMER pTimer, + IN u4Byte msDelay + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + mod_timer(pTimer, jiffies + (msDelay+9)/10); +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + _set_timer(pTimer, msDelay ); //ms +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + PlatformSetTimer(Adapter, pTimer, msDelay); +#endif + +} + +VOID +ODM_InitializeTimer( + IN PDM_ODM_T pDM_Odm, + IN PRT_TIMER pTimer, + IN RT_TIMER_CALL_BACK CallBackFunc, + IN PVOID pContext, + IN const char* szID + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + pTimer->function = CallBackFunc; + pTimer->data = (unsigned long)pDM_Odm; + init_timer(pTimer); +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + PADAPTER Adapter = pDM_Odm->Adapter; + _init_timer(pTimer, Adapter->pnetdev, CallBackFunc, pDM_Odm); + +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + PlatformInitializeTimer(Adapter, pTimer, CallBackFunc,pContext,szID); +#endif +} + + +VOID +ODM_CancelTimer( + IN PDM_ODM_T pDM_Odm, + IN PRT_TIMER pTimer + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + del_timer_sync(pTimer); +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + _cancel_timer_ex(pTimer); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + PADAPTER Adapter = pDM_Odm->Adapter; + PlatformCancelTimer(Adapter, pTimer); +#endif +} + + +VOID +ODM_ReleaseTimer( + IN PDM_ODM_T pDM_Odm, + IN PRT_TIMER pTimer + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + + PADAPTER Adapter = pDM_Odm->Adapter; + + // <20120301, Kordan> If the initilization fails, InitializeAdapterXxx will return regardless of InitHalDm. + // Hence, uninitialized timers cause BSOD when the driver releases resources since the init fail. + if (pTimer == 0) + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_SERIOUS, ("=====>ODM_ReleaseTimer(), The timer is NULL! Please check it!\n")); + return; + } + + PlatformReleaseTimer(Adapter, pTimer); +#endif +} + + +// +// ODM FW relative API. +// +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) +VOID +ODM_FillH2CCmd( + IN PADAPTER Adapter, + IN u1Byte ElementID, + IN u4Byte CmdLen, + IN pu1Byte pCmdBuffer +) +{ + if(IS_HARDWARE_TYPE_JAGUAR(Adapter)) + { + switch(ElementID) + { + case ODM_H2C_RSSI_REPORT: + FillH2CCmd8812(Adapter, H2C_8812_RSSI_REPORT, CmdLen, pCmdBuffer); + break; + default: + break; + } + + } + else if(IS_HARDWARE_TYPE_8192E(Adapter)) + { + switch(ElementID) + { + case ODM_H2C_RSSI_REPORT: + FillH2CCmd8812(Adapter, H2C_8812_RSSI_REPORT, CmdLen, pCmdBuffer); + break; + default: + break; + } + } + else if(IS_HARDWARE_TYPE_8723B(Adapter)) + { + // + // <Roger_TODO> We should take RTL8723B into consideration, 2012.10.08 + // + switch(ElementID) + { + case ODM_H2C_RSSI_REPORT: + FillH2CCmd8723B(Adapter, H2C_8723B_RSSI_REPORT, CmdLen, pCmdBuffer); + break; + + default: + break; + } + + } + else if(IS_HARDWARE_TYPE_8188E(Adapter)) + { + switch(ElementID) + { + case ODM_H2C_PSD_RESULT: + FillH2CCmd88E(Adapter, H2C_88E_PSD_RESULT, CmdLen, pCmdBuffer); + break; + case ODM_H2C_RSSI_REPORT: + if(IS_VENDOR_8188E_I_CUT_SERIES(Adapter)) + FillH2CCmd88E(Adapter, H2C_88E_RSSI_REPORT, CmdLen, pCmdBuffer); + break; + default: + break; + } + } + else + { + switch(ElementID) + { + case ODM_H2C_RSSI_REPORT: + FillH2CCmd92C(Adapter, H2C_RSSI_REPORT, CmdLen, pCmdBuffer); + break; + case ODM_H2C_PSD_RESULT: + FillH2CCmd92C(Adapter, H2C_92C_PSD_RESULT, CmdLen, pCmdBuffer); + break; + default: + break; + } + } +} +#else +u4Byte +ODM_FillH2CCmd( + IN pu1Byte pH2CBuffer, + IN u4Byte H2CBufferLen, + IN u4Byte CmdNum, + IN pu4Byte pElementID, + IN pu4Byte pCmdLen, + IN pu1Byte* pCmbBuffer, + IN pu1Byte CmdStartSeq + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + //FillH2CCmd(pH2CBuffer, H2CBufferLen, CmdNum, pElementID, pCmdLen, pCmbBuffer, CmdStartSeq); + return FALSE; +#endif + + return TRUE; +} +#endif + + +u4Byte +ODM_GetCurrentTime( + IN PDM_ODM_T pDM_Odm + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + return 0; +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + return rtw_get_current_time(); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + return 0; +#endif +} + +s4Byte +ODM_GetProgressingTime( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Start_Time + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) + return 0; +#elif(DM_ODM_SUPPORT_TYPE & ODM_CE) + return rtw_get_passing_time_ms(Start_Time); +#elif(DM_ODM_SUPPORT_TYPE & ODM_WIN) + return 0; +#endif +} + + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_interface.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_interface.h new file mode 100644 index 0000000..2400d4b --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_interface.h @@ -0,0 +1,394 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + + +#ifndef __ODM_INTERFACE_H__ +#define __ODM_INTERFACE_H__ + + + +// +// =========== Constant/Structure/Enum/... Define +// + + + +// +// =========== Macro Define +// + +#define _reg_all(_name) ODM_##_name +#define _reg_ic(_name, _ic) ODM_##_name##_ic +#define _bit_all(_name) BIT_##_name +#define _bit_ic(_name, _ic) BIT_##_name##_ic + +// _cat: implemented by Token-Pasting Operator. +#if 0 +#define _cat(_name, _ic_type, _func) \ + ( \ + _func##_all(_name) \ + ) +#endif + +/*=================================== + +#define ODM_REG_DIG_11N 0xC50 +#define ODM_REG_DIG_11AC 0xDDD + +ODM_REG(DIG,_pDM_Odm) +=====================================*/ + +#define _reg_11N(_name) ODM_REG_##_name##_11N +#define _reg_11AC(_name) ODM_REG_##_name##_11AC +#define _bit_11N(_name) ODM_BIT_##_name##_11N +#define _bit_11AC(_name) ODM_BIT_##_name##_11AC + +#if 1 //TODO: enable it if we need to support run-time to differentiate between 92C_SERIES and JAGUAR_SERIES. +#define _cat(_name, _ic_type, _func) \ + ( \ + ((_ic_type) & ODM_IC_11N_SERIES)? _func##_11N(_name): \ + _func##_11AC(_name) \ + ) +#endif +#if 0 // only sample code +#define _cat(_name, _ic_type, _func) \ + ( \ + ((_ic_type) & ODM_RTL8192C)? _func##_ic(_name, _8192C): \ + ((_ic_type) & ODM_RTL8192D)? _func##_ic(_name, _8192D): \ + ((_ic_type) & ODM_RTL8192S)? _func##_ic(_name, _8192S): \ + ((_ic_type) & ODM_RTL8723A)? _func##_ic(_name, _8723A): \ + ((_ic_type) & ODM_RTL8188E)? _func##_ic(_name, _8188E): \ + _func##_ic(_name, _8195) \ + ) +#endif + +// _name: name of register or bit. +// Example: "ODM_REG(R_A_AGC_CORE1, pDM_Odm)" +// gets "ODM_R_A_AGC_CORE1" or "ODM_R_A_AGC_CORE1_8192C", depends on SupportICType. +#define ODM_REG(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _reg) +#define ODM_BIT(_name, _pDM_Odm) _cat(_name, _pDM_Odm->SupportICType, _bit) + +typedef enum _ODM_H2C_CMD +{ + ODM_H2C_RSSI_REPORT = 0, + ODM_H2C_PSD_RESULT=1, + ODM_H2C_PathDiv = 2, + ODM_MAX_H2CCMD +}ODM_H2C_CMD; + + +// +// 2012/02/17 MH For non-MP compile pass only. Linux does not support workitem. +// Suggest HW team to use thread instead of workitem. Windows also support the feature. +// +#if (DM_ODM_SUPPORT_TYPE != ODM_WIN) +typedef void *PRT_WORK_ITEM ; +typedef void RT_WORKITEM_HANDLE,*PRT_WORKITEM_HANDLE; +typedef VOID (*RT_WORKITEM_CALL_BACK)(PVOID pContext); + +#if 0 +typedef struct tasklet_struct RT_WORKITEM_HANDLE, *PRT_WORKITEM_HANDLE; + +typedef struct _RT_WORK_ITEM +{ + + RT_WORKITEM_HANDLE Handle; // Platform-dependent handle for this workitem, e.g. Ndis Workitem object. + PVOID Adapter; // Pointer to Adapter object. + PVOID pContext; // Parameter to passed to CallBackFunc(). + RT_WORKITEM_CALL_BACK CallbackFunc; // Callback function of the workitem. + u1Byte RefCount; // 0: driver is going to unload, 1: No such workitem scheduled, 2: one workitem is schedueled. + PVOID pPlatformExt; // Pointer to platform-dependent extension. + BOOLEAN bFree; + char szID[36]; // An identity string of this workitem. +}RT_WORK_ITEM, *PRT_WORK_ITEM; + +#endif + + +#endif + +// +// =========== Extern Variable ??? It should be forbidden. +// + + +// +// =========== EXtern Function Prototype +// + + +u1Byte +ODM_Read1Byte( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr + ); + +u2Byte +ODM_Read2Byte( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr + ); + +u4Byte +ODM_Read4Byte( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr + ); + +VOID +ODM_Write1Byte( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u1Byte Data + ); + +VOID +ODM_Write2Byte( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u2Byte Data + ); + +VOID +ODM_Write4Byte( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u4Byte Data + ); + +VOID +ODM_SetMACReg( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u4Byte BitMask, + IN u4Byte Data + ); + +u4Byte +ODM_GetMACReg( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u4Byte BitMask + ); + +VOID +ODM_SetBBReg( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u4Byte BitMask, + IN u4Byte Data + ); + +u4Byte +ODM_GetBBReg( + IN PDM_ODM_T pDM_Odm, + IN u4Byte RegAddr, + IN u4Byte BitMask + ); + +VOID +ODM_SetRFReg( + IN PDM_ODM_T pDM_Odm, + IN ODM_RF_RADIO_PATH_E eRFPath, + IN u4Byte RegAddr, + IN u4Byte BitMask, + IN u4Byte Data + ); + +u4Byte +ODM_GetRFReg( + IN PDM_ODM_T pDM_Odm, + IN ODM_RF_RADIO_PATH_E eRFPath, + IN u4Byte RegAddr, + IN u4Byte BitMask + ); + + +// +// Memory Relative Function. +// +VOID +ODM_AllocateMemory( + IN PDM_ODM_T pDM_Odm, + OUT PVOID *pPtr, + IN u4Byte length + ); +VOID +ODM_FreeMemory( + IN PDM_ODM_T pDM_Odm, + OUT PVOID pPtr, + IN u4Byte length + ); + +VOID +ODM_MoveMemory( + IN PDM_ODM_T pDM_Odm, + OUT PVOID pDest, + IN PVOID pSrc, + IN u4Byte Length + ); + +s4Byte ODM_CompareMemory( + IN PDM_ODM_T pDM_Odm, + IN PVOID pBuf1, + IN PVOID pBuf2, + IN u4Byte length + ); + +// +// ODM MISC-spin lock relative API. +// +VOID +ODM_AcquireSpinLock( + IN PDM_ODM_T pDM_Odm, + IN RT_SPINLOCK_TYPE type + ); + +VOID +ODM_ReleaseSpinLock( + IN PDM_ODM_T pDM_Odm, + IN RT_SPINLOCK_TYPE type + ); + + +// +// ODM MISC-workitem relative API. +// +VOID +ODM_InitializeWorkItem( + IN PDM_ODM_T pDM_Odm, + IN PRT_WORK_ITEM pRtWorkItem, + IN RT_WORKITEM_CALL_BACK RtWorkItemCallback, + IN PVOID pContext, + IN const char* szID + ); + +VOID +ODM_StartWorkItem( + IN PRT_WORK_ITEM pRtWorkItem + ); + +VOID +ODM_StopWorkItem( + IN PRT_WORK_ITEM pRtWorkItem + ); + +VOID +ODM_FreeWorkItem( + IN PRT_WORK_ITEM pRtWorkItem + ); + +VOID +ODM_ScheduleWorkItem( + IN PRT_WORK_ITEM pRtWorkItem + ); + +VOID +ODM_IsWorkItemScheduled( + IN PRT_WORK_ITEM pRtWorkItem + ); + +// +// ODM Timer relative API. +// +VOID +ODM_StallExecution( + IN u4Byte usDelay + ); + +VOID +ODM_delay_ms(IN u4Byte ms); + + + +VOID +ODM_delay_us(IN u4Byte us); + +VOID +ODM_sleep_ms(IN u4Byte ms); + +VOID +ODM_sleep_us(IN u4Byte us); + +VOID +ODM_SetTimer( + IN PDM_ODM_T pDM_Odm, + IN PRT_TIMER pTimer, + IN u4Byte msDelay + ); + +VOID +ODM_InitializeTimer( + IN PDM_ODM_T pDM_Odm, + IN PRT_TIMER pTimer, + IN RT_TIMER_CALL_BACK CallBackFunc, + IN PVOID pContext, + IN const char* szID + ); + +VOID +ODM_CancelTimer( + IN PDM_ODM_T pDM_Odm, + IN PRT_TIMER pTimer + ); + +VOID +ODM_ReleaseTimer( + IN PDM_ODM_T pDM_Odm, + IN PRT_TIMER pTimer + ); + + +// +// ODM FW relative API. +// +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) +VOID +ODM_FillH2CCmd( + IN PADAPTER Adapter, + IN u1Byte ElementID, + IN u4Byte CmdLen, + IN pu1Byte pCmdBuffer +); +#else +u4Byte +ODM_FillH2CCmd( + IN pu1Byte pH2CBuffer, + IN u4Byte H2CBufferLen, + IN u4Byte CmdNum, + IN pu4Byte pElementID, + IN pu4Byte pCmdLen, + IN pu1Byte* pCmbBuffer, + IN pu1Byte CmdStartSeq + ); +#endif + +u4Byte +ODM_GetCurrentTime( + IN PDM_ODM_T pDM_Odm + ); +s4Byte +ODM_GetProgressingTime( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Start_Time + ); + +#endif // __ODM_INTERFACE_H__ + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_precomp.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_precomp.h new file mode 100644 index 0000000..e207dce --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_precomp.h @@ -0,0 +1,307 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#ifndef __ODM_PRECOMP_H__ +#define __ODM_PRECOMP_H__ + +#include "odm_types.h" + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +#include "Precomp.h" // We need to include mp_precomp.h due to batch file setting. + +#else + +#define TEST_FALG___ 1 + +#endif + +//2 Config Flags and Structs - defined by each ODM Type + +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) + #include "../8192cd_cfg.h" + #include "../odm_inc.h" + + #include "../8192cd.h" + #include "../8192cd_util.h" + #ifdef _BIG_ENDIAN_ + #define ODM_ENDIAN_TYPE ODM_ENDIAN_BIG + #else + #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE + #endif + + #ifdef AP_BUILD_WORKAROUND + #include "../8192cd_headers.h" + #include "../8192cd_debug.h" + #endif + +#elif (DM_ODM_SUPPORT_TYPE == ODM_ADSL) + // Flags + #include "../8192cd_cfg.h" // OUTSRC needs ADSL config flags. + #include "../odm_inc.h" // OUTSRC needs some extra flags. + // Data Structure + #include "../common_types.h" // OUTSRC and rtl8192cd both needs basic type such as UINT8 and BIT0. + #include "../8192cd.h" // OUTSRC needs basic ADSL struct definition. + #include "../8192cd_util.h" // OUTSRC needs basic I/O function. + #ifdef _BIG_ENDIAN_ + #define ODM_ENDIAN_TYPE ODM_ENDIAN_BIG + #else + #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE + #endif + + #ifdef ADSL_AP_BUILD_WORKAROUND + // NESTED_INC: Functions defined outside should not be included!! Marked by Annie, 2011-10-14. + #include "../8192cd_headers.h" + #include "../8192cd_debug.h" + #endif + +#elif (DM_ODM_SUPPORT_TYPE ==ODM_CE) + //#include <drv_conf.h> + //#include <basic_types.h> + //#include <osdep_service.h> + //#include <drv_types.h> + //#include <rtw_byteorder.h> + //#include <hal_intf.h> +#define BEAMFORMING_SUPPORT 0 +#elif (DM_ODM_SUPPORT_TYPE == ODM_WIN) + #include "Mp_Precomp.h" + #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE +#endif + + +//2 Hardware Parameter Files + + +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) +#if (RTL8192C_SUPPORT==1) + #include "rtl8192c/Hal8192CEFWImg_AP.h" + #include "rtl8192c/Hal8192CEPHYImg_AP.h" + #include "rtl8192c/Hal8192CEMACImg_AP.h" +#endif +#elif (DM_ODM_SUPPORT_TYPE == ODM_ADSL) + #include "rtl8192c/Hal8192CEFWImg_ADSL.h" + #include "rtl8192c/Hal8192CEPHYImg_ADSL.h" + #include "rtl8192c/Hal8192CEMACImg_ADSL.h" + +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + #if(RTL8192CE_SUPPORT ==1) + #include "rtl8192c/Hal8192CEFWImg_CE.h" + #include "rtl8192c/Hal8192CEPHYImg_CE.h" + #include "rtl8192c/Hal8192CEMACImg_CE.h" + #endif + + #if(RTL8192CU_SUPPORT ==1) + #include "rtl8192c/Hal8192CUFWImg_CE.h" + #include "rtl8192c/Hal8192CUPHYImg_CE.h" + #include "rtl8192c/Hal8192CUMACImg_CE.h" + #endif + + #if(RTL8192DE_SUPPORT ==1) + #include "rtl8192d/Hal8192DEFWImg_CE.h" + #include "rtl8192d/Hal8192DEPHYImg_CE.h" + #include "rtl8192d/Hal8192DEMACImg_CE.h" + #endif + + #if(RTL8192DU_SUPPORT ==1) + #include "rtl8192d/Hal8192DUFWImg_CE.h" + #include "rtl8192d/Hal8192DUPHYImg_CE.h" + #include "rtl8192d/Hal8192DUMACImg_CE.h" + #endif + + #if(RTL8723AS_SUPPORT==1) + #include "rtl8723a/Hal8723SHWImg_CE.h" + #endif + + #if(RTL8723AU_SUPPORT==1) + #include "rtl8723a/Hal8723UHWImg_CE.h" + #endif + +#elif (DM_ODM_SUPPORT_TYPE == ODM_WIN) + +#endif + + +//2 OutSrc Header Files + +#include "odm.h" +#include "odm_HWConfig.h" +#include "odm_debug.h" +#include "odm_RegDefine11AC.h" +#include "odm_RegDefine11N.h" +#include "odm_AntDiv.h" + +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) +#if (RTL8192C_SUPPORT==1) + #include "rtl8192c/HalDMOutSrc8192C_AP.h" +#endif +#if (RTL8188E_SUPPORT==1) + #include "rtl8188e/Hal8188ERateAdaptive.h"//for RA,Power training +#endif + +#elif (DM_ODM_SUPPORT_TYPE == ODM_ADSL) + #include "rtl8192c/HalDMOutSrc8192C_ADSL.h" + +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + //#include "hal_com.h" + #include "HalPhyRf.h" + #if (RTL8192C_SUPPORT==1) + #ifdef CONFIG_INTEL_PROXIM + #include "../proxim/intel_proxim.h" + #endif + #include "rtl8192c/HalDMOutSrc8192C_CE.h" + #include <rtl8192c_hal.h> + #endif + + #if (RTL8192D_SUPPORT==1) + #include "rtl8192d/HalDMOutSrc8192D_CE.h" + #include "rtl8192d_hal.h" + #endif + + #if (RTL8723A_SUPPORT==1) + #include "rtl8192c/HalDMOutSrc8192C_CE.h" //for IQK,LCK,Power-tracking + #include "rtl8723a_hal.h" + #endif + + #if (RTL8188E_SUPPORT==1) + #include "rtl8188e/HalPhyRf_8188e.h"//for IQK,LCK,Power-tracking + #include "rtl8188e/Hal8188ERateAdaptive.h"//for RA,Power training + #include "rtl8188e_hal.h" + #endif + + #if (RTL8192E_SUPPORT==1) + #include "rtl8192e/HalPhyRf_8192e.h"//for IQK,LCK,Power-tracking + #include "rtl8192e_hal.h" + #endif + + #if (RTL8812A_SUPPORT==1) + #include "rtl8812a/HalPhyRf_8812A.h"//for IQK,LCK,Power-tracking + #include "rtl8812a_hal.h" + #endif + + #if (RTL8821A_SUPPORT==1) + #include "rtl8821a/HalPhyRf_8821A.h"//for IQK,LCK,Power-tracking + #include "rtl8812a/HalPhyRf_8812A.h"//for IQK,LCK,Power-tracking + #include "rtl8812a_hal.h" + #endif + + #if (RTL8723B_SUPPORT==1) + #include "rtl8723b/HalPhyRf_8723B.h"//for IQK,LCK,Power-tracking + #include "rtl8723b_hal.h" + #endif +#endif + +#include "odm_interface.h" +#include "odm_reg.h" + +#if (RTL8192C_SUPPORT==1) +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) +#include "rtl8192c/Hal8192CHWImg_MAC.h" +#include "rtl8192c/Hal8192CHWImg_RF.h" +#include "rtl8192c/Hal8192CHWImg_BB.h" +#include "rtl8192c/Hal8192CHWImg_FW.h" +#endif +#include "rtl8192c/odm_RTL8192C.h" +#endif +#if (RTL8192D_SUPPORT==1) +#include "rtl8192d/odm_RTL8192D.h" +#endif + +#if (RTL8723A_SUPPORT==1) +#include "rtl8723a/HalHWImg8723A_MAC.h" +#include "rtl8723a/HalHWImg8723A_RF.h" +#include "rtl8723a/HalHWImg8723A_BB.h" +#include "rtl8723a/HalHWImg8723A_FW.h" +#include "rtl8723a/odm_RegConfig8723A.h" +#endif + +#if (RTL8188E_SUPPORT==1) +#include "rtl8188e/HalHWImg8188E_MAC.h" +#include "rtl8188e/HalHWImg8188E_RF.h" +#include "rtl8188e/HalHWImg8188E_BB.h" +#include "rtl8188e/HalHWImg8188E_FW.h" +#include "rtl8188e/Hal8188EReg.h" + +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) +#include "rtl8188e/HalPhyRf_8188e.h" +#endif + +#if (TESTCHIP_SUPPORT == 1) +#include "rtl8188e/HalHWImg8188E_TestChip_MAC.h" +#include "rtl8188e/HalHWImg8188E_TestChip_RF.h" +#include "rtl8188e/HalHWImg8188E_TestChip_BB.h" +#endif + + +#include "rtl8188e/odm_RegConfig8188E.h" +#include "rtl8188e/odm_RTL8188E.h" +#endif + +#if (RTL8192E_SUPPORT==1) +#include "rtl8192e/HalHWImg8192E_MAC.h" +#include "rtl8192e/HalHWImg8192E_RF.h" +#include "rtl8192e/HalHWImg8192E_BB.h" +#include "rtl8192e/HalHWImg8192E_FW.h" +#include "rtl8192e/Hal8192EReg.h" +#include "rtl8192e/odm_RegConfig8192E.h" +#include "rtl8192e/odm_RTL8192E.h" +#endif + +#if (RTL8723B_SUPPORT==1) +#include "rtl8723b/HalHWImg8723B_MAC.h" +#include "rtl8723b/HalHWImg8723B_RF.h" +#include "rtl8723b/HalHWImg8723B_BB.h" +#include "rtl8723b/HalHWImg8723B_FW.h" +#include "rtl8723b/HalHWImg8723B_MP.h" +#include "rtl8723b/Hal8723BReg.h" +#include "rtl8723b/odm_RTL8723B.h" +#include "rtl8723b/odm_RegConfig8723B.h" +#endif + +#if (RTL8812A_SUPPORT==1) +#include "rtl8812a/HalHWImg8812A_MAC.h" +#include "rtl8812a/HalHWImg8812A_RF.h" +#include "rtl8812a/HalHWImg8812A_BB.h" +#include "rtl8812a/HalHWImg8812A_FW.h" +#include "rtl8812a/odm_RegConfig8812A.h" +#include "rtl8812a/odm_RTL8812A.h" +#if (TESTCHIP_SUPPORT == 1) +#include "rtl8812a/HalHWImg8812A_TestChip_MAC.h" +#include "rtl8812a/HalHWImg8812A_TestChip_RF.h" +#include "rtl8812a/HalHWImg8812A_TestChip_BB.h" +#endif +#endif + + +#if (RTL8821A_SUPPORT==1) +#include "rtl8821a/HalHWImg8821A_MAC.h" +#include "rtl8821a/HalHWImg8821A_RF.h" +#include "rtl8821a/HalHWImg8821A_BB.h" +#include "rtl8821a/HalHWImg8821A_FW.h" +#include "rtl8821a/odm_RegConfig8821A.h" +#include "rtl8821a/odm_RTL8821A.h" +#if (TESTCHIP_SUPPORT == 1) +#include "rtl8821a/HalHWImg8821A_TestChip_MAC.h" +#include "rtl8821a/HalHWImg8821A_TestChip_RF.h" +#include "rtl8821a/HalHWImg8821A_TestChip_BB.h" +#include "rtl8821a/HalHWImg8821A_TestChip_FW.h" +#endif +#endif + +#endif // __ODM_PRECOMP_H__ + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_reg.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_reg.h new file mode 100644 index 0000000..dfdf467 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_reg.h @@ -0,0 +1,122 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +//============================================================ +// File Name: odm_reg.h +// +// Description: +// +// This file is for general register definition. +// +// +//============================================================ +#ifndef __HAL_ODM_REG_H__ +#define __HAL_ODM_REG_H__ + +// +// Register Definition +// + +//MAC REG +#define ODM_BB_RESET 0x002 +#define ODM_DUMMY 0x4fe +#define RF_T_METER_OLD 0x24 +#define RF_T_METER_NEW 0x42 + +#define ODM_EDCA_VO_PARAM 0x500 +#define ODM_EDCA_VI_PARAM 0x504 +#define ODM_EDCA_BE_PARAM 0x508 +#define ODM_EDCA_BK_PARAM 0x50C +#define ODM_TXPAUSE 0x522 + +//BB REG +#define ODM_FPGA_PHY0_PAGE8 0x800 +#define ODM_PSD_SETTING 0x808 +#define ODM_AFE_SETTING 0x818 +#define ODM_TXAGC_B_24_54 0x834 +#define ODM_TXAGC_B_MCS32_5 0x838 +#define ODM_TXAGC_B_MCS0_MCS3 0x83c +#define ODM_TXAGC_B_MCS4_MCS7 0x848 +#define ODM_TXAGC_B_MCS8_MCS11 0x84c +#define ODM_ANALOG_REGISTER 0x85c +#define ODM_RF_INTERFACE_OUTPUT 0x860 +#define ODM_TXAGC_B_MCS12_MCS15 0x868 +#define ODM_TXAGC_B_11_A_2_11 0x86c +#define ODM_AD_DA_LSB_MASK 0x874 +#define ODM_ENABLE_3_WIRE 0x88c +#define ODM_PSD_REPORT 0x8b4 +#define ODM_R_ANT_SELECT 0x90c +#define ODM_CCK_ANT_SELECT 0xa07 +#define ODM_CCK_PD_THRESH 0xa0a +#define ODM_CCK_RF_REG1 0xa11 +#define ODM_CCK_MATCH_FILTER 0xa20 +#define ODM_CCK_RAKE_MAC 0xa2e +#define ODM_CCK_CNT_RESET 0xa2d +#define ODM_CCK_TX_DIVERSITY 0xa2f +#define ODM_CCK_FA_CNT_MSB 0xa5b +#define ODM_CCK_FA_CNT_LSB 0xa5c +#define ODM_CCK_NEW_FUNCTION 0xa75 +#define ODM_OFDM_PHY0_PAGE_C 0xc00 +#define ODM_OFDM_RX_ANT 0xc04 +#define ODM_R_A_RXIQI 0xc14 +#define ODM_R_A_AGC_CORE1 0xc50 +#define ODM_R_A_AGC_CORE2 0xc54 +#define ODM_R_B_AGC_CORE1 0xc58 +#define ODM_R_AGC_PAR 0xc70 +#define ODM_R_HTSTF_AGC_PAR 0xc7c +#define ODM_TX_PWR_TRAINING_A 0xc90 +#define ODM_TX_PWR_TRAINING_B 0xc98 +#define ODM_OFDM_FA_CNT1 0xcf0 +#define ODM_OFDM_PHY0_PAGE_D 0xd00 +#define ODM_OFDM_FA_CNT2 0xda0 +#define ODM_OFDM_FA_CNT3 0xda4 +#define ODM_OFDM_FA_CNT4 0xda8 +#define ODM_TXAGC_A_6_18 0xe00 +#define ODM_TXAGC_A_24_54 0xe04 +#define ODM_TXAGC_A_1_MCS32 0xe08 +#define ODM_TXAGC_A_MCS0_MCS3 0xe10 +#define ODM_TXAGC_A_MCS4_MCS7 0xe14 +#define ODM_TXAGC_A_MCS8_MCS11 0xe18 +#define ODM_TXAGC_A_MCS12_MCS15 0xe1c + +//RF REG +#define ODM_GAIN_SETTING 0x00 +#define ODM_CHANNEL 0x18 + +//Ant Detect Reg +#define ODM_DPDT 0x300 + +//PSD Init +#define ODM_PSDREG 0x808 + +//92D Path Div +#define PATHDIV_REG 0xB30 +#define PATHDIV_TRI 0xBA0 + + +// +// Bitmap Definition +// + +#define BIT_FA_RESET BIT0 + + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_types.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_types.h new file mode 100644 index 0000000..ed9aebb --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/odm_types.h @@ -0,0 +1,282 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __ODM_TYPES_H__ +#define __ODM_TYPES_H__ + +// +// Define Different SW team support +// +#define ODM_AP 0x01 //BIT0 +#define ODM_ADSL 0x02 //BIT1 +#define ODM_CE 0x04 //BIT2 +#define ODM_WIN 0x08 //BIT3 + +#define DM_ODM_SUPPORT_TYPE ODM_CE + +// Deifne HW endian support +#define ODM_ENDIAN_BIG 0 +#define ODM_ENDIAN_LITTLE 1 + +#if (DM_ODM_SUPPORT_TYPE != ODM_WIN) +#define RT_PCI_INTERFACE 1 +#define RT_USB_INTERFACE 2 +#define RT_SDIO_INTERFACE 3 +#endif + +typedef enum _HAL_STATUS{ + HAL_STATUS_SUCCESS, + HAL_STATUS_FAILURE, + /*RT_STATUS_PENDING, + RT_STATUS_RESOURCE, + RT_STATUS_INVALID_CONTEXT, + RT_STATUS_INVALID_PARAMETER, + RT_STATUS_NOT_SUPPORT, + RT_STATUS_OS_API_FAILED,*/ +}HAL_STATUS,*PHAL_STATUS; + + +#if( (DM_ODM_SUPPORT_TYPE == ODM_AP) ||(DM_ODM_SUPPORT_TYPE == ODM_ADSL) || (DM_ODM_SUPPORT_TYPE == ODM_CE)) + +#define VISTA_USB_RX_REVISE 0 + +// +// Declare for ODM spin lock defintion temporarily fro compile pass. +// +typedef enum _RT_SPINLOCK_TYPE{ + RT_TX_SPINLOCK = 1, + RT_RX_SPINLOCK = 2, + RT_RM_SPINLOCK = 3, + RT_CAM_SPINLOCK = 4, + RT_SCAN_SPINLOCK = 5, + RT_LOG_SPINLOCK = 7, + RT_BW_SPINLOCK = 8, + RT_CHNLOP_SPINLOCK = 9, + RT_RF_OPERATE_SPINLOCK = 10, + RT_INITIAL_SPINLOCK = 11, + RT_RF_STATE_SPINLOCK = 12, // For RF state. Added by Bruce, 2007-10-30. +#if VISTA_USB_RX_REVISE + RT_USBRX_CONTEXT_SPINLOCK = 13, + RT_USBRX_POSTPROC_SPINLOCK = 14, // protect data of Adapter->IndicateW/ IndicateR +#endif + //Shall we define Ndis 6.2 SpinLock Here ? + RT_PORT_SPINLOCK=16, + RT_H2C_SPINLOCK = 20, // For H2C cmd. Added by tynli. 2009.11.09. + + RT_BTData_SPINLOCK=25, + + RT_WAPI_OPTION_SPINLOCK=26, + RT_WAPI_RX_SPINLOCK=27, + + // add for 92D CCK control issue + RT_CCK_PAGEA_SPINLOCK = 28, + RT_BUFFER_SPINLOCK = 29, + RT_CHANNEL_AND_BANDWIDTH_SPINLOCK = 30, + RT_GEN_TEMP_BUF_SPINLOCK = 31, + RT_AWB_SPINLOCK = 32, + RT_FW_PS_SPINLOCK = 33, + RT_HW_TIMER_SPIN_LOCK = 34, + RT_MPT_WI_SPINLOCK = 35, + RT_P2P_SPIN_LOCK = 36, // Protect P2P context + RT_DBG_SPIN_LOCK = 37, + RT_IQK_SPINLOCK = 38, + RT_PENDED_OID_SPINLOCK = 39, + RT_CHNLLIST_SPINLOCK = 40, + RT_INDIC_SPINLOCK = 41, //protect indication +}RT_SPINLOCK_TYPE; + +#endif + + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + #define STA_INFO_T RT_WLAN_STA + #define PSTA_INFO_T PRT_WLAN_STA + +// typedef unsigned long u4Byte,*pu4Byte; +#define CONFIG_HW_ANTENNA_DIVERSITY +#define CONFIG_SW_ANTENNA_DIVERSITY + +#elif (DM_ODM_SUPPORT_TYPE == ODM_AP) + + // To let ADSL/AP project compile ok; it should be removed after all conflict are solved. Added by Annie, 2011-10-07. + #define ADSL_AP_BUILD_WORKAROUND + #define AP_BUILD_WORKAROUND + // +#ifdef CONFIG_ANT_SWITCH + #define CONFIG_HW_ANTENNA_DIVERSITY + #if ( defined(CONFIG_NO_2G_DIVERSITY) && defined(CONFIG_NO_5G_DIVERSITY) ) + #define CONFIG_NOT_SUPPORT_ANTDIV + #elif( !defined(CONFIG_NO_2G_DIVERSITY) && defined(CONFIG_NO_5G_DIVERSITY) ) + #define CONFIG_2G_SUPPORT_ANTDIV + #elif( defined(CONFIG_NO_2G_DIVERSITY) && !defined(CONFIG_NO_5G_DIVERSITY) ) + #define CONFIG_5G_SUPPORT_ANTDIV + #elif( !defined(CONFIG_NO_2G_DIVERSITY) && !defined(CONFIG_NO_5G_DIVERSITY) ) + #define CONFIG_2G5G_SUPPORT_ANTDIV + #endif +#endif + + #ifdef AP_BUILD_WORKAROUND + #include "../typedef.h" + #else + typedef void VOID,*PVOID; + typedef unsigned char BOOLEAN,*PBOOLEAN; + typedef unsigned char u1Byte,*pu1Byte; + typedef unsigned short u2Byte,*pu2Byte; + typedef unsigned int u4Byte,*pu4Byte; + typedef unsigned long long u8Byte,*pu8Byte; + typedef char s1Byte,*ps1Byte; + typedef short s2Byte,*ps2Byte; + typedef long s4Byte,*ps4Byte; + typedef long long s8Byte,*ps8Byte; + #endif + + typedef struct rtl8192cd_priv *prtl8192cd_priv; + typedef struct stat_info STA_INFO_T,*PSTA_INFO_T; + + #if defined (LINUX_VERSION_CODE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) + typedef struct legacy_timer_emu RT_TIMER, *PRT_TIMER; + #else + typedef struct timer_list RT_TIMER, *PRT_TIMER; + #endif + + typedef void * RT_TIMER_CALL_BACK; + + #define DEV_BUS_TYPE RT_PCI_INTERFACE + + #define _TRUE 1 + #define _FALSE 0 + +#elif (DM_ODM_SUPPORT_TYPE == ODM_ADSL) + + // To let ADSL/AP project compile ok; it should be removed after all conflict are solved. Added by Annie, 2011-10-07. + #define ADSL_AP_BUILD_WORKAROUND + #define ADSL_BUILD_WORKAROUND + // + + typedef unsigned char BOOLEAN,*PBOOLEAN; + typedef unsigned char u1Byte,*pu1Byte; + typedef unsigned short u2Byte,*pu2Byte; + typedef unsigned int u4Byte,*pu4Byte; + typedef unsigned long long u8Byte,*pu8Byte; + typedef char s1Byte,*ps1Byte; + typedef short s2Byte,*ps2Byte; + typedef long s4Byte,*ps4Byte; + typedef long long s8Byte,*ps8Byte; + + typedef struct rtl8192cd_priv *prtl8192cd_priv; + typedef struct stat_info STA_INFO_T,*PSTA_INFO_T; + + #if defined (LINUX_VERSION_CODE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) + typedef struct legacy_timer_emu RT_TIMER, *PRT_TIMER; + #else + typedef struct timer_list RT_TIMER, *PRT_TIMER; + #endif + + typedef void * RT_TIMER_CALL_BACK; + + #define DEV_BUS_TYPE RT_PCI_INTERFACE + + #define _TRUE 1 + #define _FALSE 0 + +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + #include <drv_types.h> + +#if 0 + typedef u8 u1Byte, *pu1Byte; + typedef u16 u2Byte,*pu2Byte; + typedef u32 u4Byte,*pu4Byte; + typedef u64 u8Byte,*pu8Byte; + typedef s8 s1Byte,*ps1Byte; + typedef s16 s2Byte,*ps2Byte; + typedef s32 s4Byte,*ps4Byte; + typedef s64 s8Byte,*ps8Byte; +#else + #define u1Byte u8 + #define pu1Byte u8* + + #define u2Byte u16 + #define pu2Byte u16* + + #define u4Byte u32 + #define pu4Byte u32* + + #define u8Byte u64 + #define pu8Byte u64* + + #define s1Byte s8 + #define ps1Byte s8* + + #define s2Byte s16 + #define ps2Byte s16* + + #define s4Byte s32 + #define ps4Byte s32* + + #define s8Byte s64 + #define ps8Byte s64* + +#endif + #ifdef CONFIG_USB_HCI + #define DEV_BUS_TYPE RT_USB_INTERFACE + #elif defined(CONFIG_PCI_HCI) + #define DEV_BUS_TYPE RT_PCI_INTERFACE + #elif defined(CONFIG_SDIO_HCI) + #define DEV_BUS_TYPE RT_SDIO_INTERFACE + #elif defined(CONFIG_GSPI_HCI) + #define DEV_BUS_TYPE RT_SDIO_INTERFACE + #endif + + + #if defined(CONFIG_LITTLE_ENDIAN) + #define ODM_ENDIAN_TYPE ODM_ENDIAN_LITTLE + #elif defined (CONFIG_BIG_ENDIAN) + #define ODM_ENDIAN_TYPE ODM_ENDIAN_BIG + #endif + + #if defined (LINUX_VERSION_CODE) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) + typedef struct legacy_timer_emu RT_TIMER, *PRT_TIMER; + #else + typedef struct timer_list RT_TIMER, *PRT_TIMER; + #endif + + typedef void * RT_TIMER_CALL_BACK; + #define STA_INFO_T struct sta_info + #define PSTA_INFO_T struct sta_info * + + + + #define TRUE _TRUE + #define FALSE _FALSE + + + #define SET_TX_DESC_ANTSEL_A_88E(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 24, 1, __Value) + #define SET_TX_DESC_ANTSEL_B_88E(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 25, 1, __Value) + #define SET_TX_DESC_ANTSEL_C_88E(__pTxDesc, __Value) SET_BITS_TO_LE_4BYTE(__pTxDesc+28, 29, 1, __Value) + + //define useless flag to avoid compile warning + #define USE_WORKITEM 0 + #define FOR_BRAZIL_PRETEST 0 + #define FPGA_TWO_MAC_VERIFICATION 0 + #define RTL8881A_SUPPORT 0 +#endif + + +#endif // __ODM_TYPES_H__ + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.c new file mode 100644 index 0000000..bda8ad8 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.c @@ -0,0 +1,1250 @@ +/*++ +Copyright (c) Realtek Semiconductor Corp. All rights reserved. + +Module Name: + RateAdaptive.c + +Abstract: + Implement Rate Adaptive functions for common operations. + +Major Change History: + When Who What + ---------- --------------- ------------------------------- + 2011-08-12 Page Create. + +--*/ + + +#include "../odm_precomp.h" + + +#if (RATE_ADAPTIVE_SUPPORT == 1) +// Rate adaptive parameters +#define RA_RATE_LEVEL 2 + + +static u1Byte RETRY_PENALTY[PERENTRY][RETRYSIZE+1] = {{5,4,3,2,0,3},//92 , idx=0 + {6,5,4,3,0,4},//86 , idx=1 + {6,5,4,2,0,4},//81 , idx=2 + {8,7,6,4,0,6},//75 , idx=3 + {10,9,8,6,0,8},//71 , idx=4 + {10,9,8,4,0,8},//66 , idx=5 + {10,9,8,2,0,8},//62 , idx=6 + {10,9,8,0,0,8},//59 , idx=7 + {18,17,16,8,0,16},//53 , idx=8 + {26,25,24,16,0,24},//50 , idx=9 + {34,33,32,24,0,32},//47 , idx=0x0a + //{34,33,32,16,0,32},//43 , idx=0x0b + //{34,33,32,8,0,32},//40 , idx=0x0c + //{34,33,28,8,0,32},//37 , idx=0x0d + //{34,33,20,8,0,32},//32 , idx=0x0e + //{34,32,24,8,0,32},//26 , idx=0x0f + //{49,48,32,16,0,48},//20 , idx=0x10 + //{49,48,24,0,0,48},//17 , idx=0x11 + //{49,47,16,16,0,48},//15 , idx=0x12 + //{49,44,16,16,0,48},//12 , idx=0x13 + //{49,40,16,0,0,48},//9 , idx=0x14 + {34,31,28,20,0,32},//43 , idx=0x0b + {34,31,27,18,0,32},//40 , idx=0x0c + {34,31,26,16,0,32},//37 , idx=0x0d + {34,30,22,16,0,32},//32 , idx=0x0e + {34,30,24,16,0,32},//26 , idx=0x0f + {49,46,40,16,0,48},//20 , idx=0x10 + {49,45,32,0,0,48},//17 , idx=0x11 + {49,45,22,18,0,48},//15 , idx=0x12 +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) + {49,40,28,18,0,48},//12 , idx=0x13 + {49,34,20,16,0,48},//9 , idx=0x14 +#else + {49,40,24,16,0,48},//12 , idx=0x13 + {49,32,18,12,0,48},//9 , idx=0x14 +#endif + {49,22,18,14,0,48},//6 , idx=0x15 + {49,16,16,0,0,48}};//3 //3, idx=0x16 + +static u1Byte RETRY_PENALTY_UP[RETRYSIZE+1]={49,44,16,16,0,48}; // 12% for rate up + +static u1Byte PT_PENALTY[RETRYSIZE+1]={34,31,30,24,0,32}; + +#if 0 +static u1Byte RETRY_PENALTY_IDX[2][RATESIZE] = {{4,4,4,5,4,4,5,7,7,7,8,0x0a, // SS>TH + 4,4,4,4,6,0x0a,0x0b,0x0d, + 5,5,7,7,8,0x0b,0x0d,0x0f}, // 0329 R01 + {4,4,4,5,7,7,9,9,0x0c,0x0e,0x10,0x12, // SS<TH + 4,4,5,5,6,0x0a,0x11,0x13, + 9,9,9,9,0x0c,0x0e,0x11,0x13}}; +#endif + + +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) +static u1Byte RETRY_PENALTY_IDX[2][RATESIZE] = {{4,4,4,5,4,4,5,7,7,7,8,0x0a, // SS>TH + 4,4,4,4,6,0x0a,0x0b,0x0d, + 5,5,7,7,8,0x0b,0x0d,0x0f}, // 0329 R01 + {0x0a,0x0a,0x0a,0x0a,0x0c,0x0c,0x0e,0x10,0x11,0x12,0x12,0x13, // SS<TH + 0x0e,0x0f,0x10,0x10,0x11,0x14,0x14,0x15, + 9,9,9,9,0x0c,0x0e,0x11,0x13}}; + +static u1Byte RETRY_PENALTY_UP_IDX[RATESIZE] = {0x10,0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x14, // SS>TH + 0x13,0x13,0x14,0x14,0x15,0x15,0x15,0x15, + 0x11,0x11,0x12,0x13,0x13,0x13,0x14,0x15}; + +static u1Byte RSSI_THRESHOLD[RATESIZE] = {0,0,0,0, + 0,0,0,0,0,0x24,0x26,0x2a, + 0x13,0x15,0x17,0x18,0x1a,0x1c,0x1d,0x1f, + 0,0,0,0x1f,0x23,0x28,0x2a,0x2c}; +#else + +// wilson modify +/*static u1Byte RETRY_PENALTY_IDX[2][RATESIZE] = {{4,4,4,5,4,4,5,7,7,7,8,0x0a, // SS>TH + 4,4,4,4,6,0x0a,0x0b,0x0d, + 5,5,7,7,8,0x0b,0x0d,0x0f}, // 0329 R01 + {0x0a,0x0a,0x0b,0x0c,0x0a,0x0a,0x0b,0x0c,0x0d,0x10,0x13,0x14, // SS<TH + 0x0b,0x0c,0x0d,0x0e,0x0f,0x11,0x13,0x15, + 9,9,9,9,0x0c,0x0e,0x11,0x13}}; */ + +static u1Byte RETRY_PENALTY_IDX[2][RATESIZE] = {{4,4,4,5,4,4,5,7,7,7,8,0x0a, // SS>TH + 4,4,4,4,6,0x0a,0x0b,0x0d, + 5,5,7,7,8,0x0b,0x0d,0x0f}, // 0329 R01 + {0x0a,0x0a,0x0b,0x0c,0x0a,0x0a,0x0b,0x0c,0x0d,0x10,0x13,0x13, // SS<TH + 0x0b,0x0c,0x0d,0x0e,0x0f,0x11,0x13,0x13, + 9,9,9,9,0x0c,0x0e,0x11,0x13}}; +#if (RA_RATE_LEVEL == 0) +static u1Byte RETRY_PENALTY_UP_IDX[RATESIZE] = {0x0c,0x0d,0x0d,0x0f,0x0d,0x0e,0x0f,0x0f,0x10,0x12,0x13,0x14, // SS>TH + 0x0f,0x10,0x10,0x12,0x12,0x13,0x14,0x15, + 0x11,0x11,0x12,0x13,0x13,0x13,0x14,0x15}; +#elif (RA_RATE_LEVEL == 1) +static u1Byte RETRY_PENALTY_UP_IDX[RATESIZE] = {0x0c,0x0d,0x0d,0x0f,0x0d,0x0e,0x0f,0x0f,0x10,0x12,0x13,0x13, // SS>TH + 0x0f,0x10,0x10,0x12,0x12,0x13,0x13,0x14, + 0x11,0x11,0x12,0x13,0x13,0x13,0x13,0x14}; +#elif (RA_RATE_LEVEL == 2) +static u1Byte RETRY_PENALTY_UP_IDX[RATESIZE] = {0x0c,0x0d,0x0d,0x0f,0x0d,0x0e,0x0f,0x0f,0x10,0x12,0x13,0x13, // SS>TH + 0x0f,0x10,0x10,0x12,0x12,0x12,0x12,0x13, + 0x11,0x11,0x12,0x12,0x12,0x12,0x12,0x13}; +#endif + +static u1Byte RSSI_THRESHOLD[RATESIZE] = {0,0,0,0, + 0,0,0,0,0,0x24,0x26,0x2a, + 0x18,0x1a,0x1d,0x1f,0x21,0x27,0x29,0x2a, + 0,0,0,0x1f,0x23,0x28,0x2a,0x2c}; + +#endif + +/*static u1Byte RSSI_THRESHOLD[RATESIZE] = {0,0,0,0, + 0,0,0,0,0,0x24,0x26,0x2a, + 0x1a,0x1c,0x1e,0x21,0x24,0x2a,0x2b,0x2d, + 0,0,0,0x1f,0x23,0x28,0x2a,0x2c};*/ +/*static u2Byte N_THRESHOLD_HIGH[RATESIZE] = {4,4,8,16, + 24,36,48,72,96,144,192,216, + 60,80,100,160,240,400,560,640, + 300,320,480,720,1000,1200,1600,2000}; +static u2Byte N_THRESHOLD_LOW[RATESIZE] = {2,2,4,8, + 12,18,24,36,48,72,96,108, + 30,40,50,80,120,200,280,320, + 150,160,240,360,500,600,800,1000};*/ +static u2Byte N_THRESHOLD_HIGH[RATESIZE] = {4,4,8,16, + 24,36,48,72,96,144,192,216, + 60,80,100,160,240,400,600,800, + 300,320,480,720,1000,1200,1600,2000}; +static u2Byte N_THRESHOLD_LOW[RATESIZE] = {2,2,4,8, + 12,18,24,36,48,72,96,108, + 30,40,50,80,120,200,300,400, + 150,160,240,360,500,600,800,1000}; + +static u1Byte TRYING_NECESSARY[RATESIZE] = {2,2,2,2, + 2,2,3,3,4,4,5,7, + 4,4,7,10,10,12,12,18, + 5,7,7,8,11,18,36,60}; // 0329 // 1207 +#if 0 +static u1Byte POOL_RETRY_TH[RATESIZE] = {30,30,30,30, + 30,30,25,25,20,15,15,10, + 30,25,25,20,15,10,10,10, + 30,25,25,20,15,10,10,10}; +#endif + +static u1Byte DROPING_NECESSARY[RATESIZE] = {1,1,1,1, + 1,2,3,4,5,6,7,8, + 1,2,3,4,5,6,7,8, + 5,6,7,8,9,10,11,12}; + + +static u4Byte INIT_RATE_FALLBACK_TABLE[16]={0x0f8ff015, // 0: 40M BGN mode + 0x0f8ff010, // 1: 40M GN mode + 0x0f8ff005, // 2: BN mode/ 40M BGN mode + 0x0f8ff000, // 3: N mode + 0x00000ff5, // 4: BG mode + 0x00000ff0, // 5: G mode + 0x0000000d, // 6: B mode + 0, // 7: + 0, // 8: + 0, // 9: + 0, // 10: + 0, // 11: + 0, // 12: + 0, // 13: + 0, // 14: + 0, // 15: + + }; +static u1Byte PendingForRateUpFail[5]={2,10,24,36,48}; +static u2Byte DynamicTxRPTTiming[6]={0x186a, 0x30d4, 0x493e, 0x61a8, 0x7a12 ,0x927c}; // 200ms 400 / 600 / 8000 / 1000 -1200ms + +// End Rate adaptive parameters + +static void +odm_SetTxRPTTiming_8188E( + IN PDM_ODM_T pDM_Odm, + IN PODM_RA_INFO_T pRaInfo, + IN u1Byte extend + ) +{ + u1Byte idx = 0; + + for(idx=0; idx<5; idx++) + if(DynamicTxRPTTiming[idx] == pRaInfo->RptTime) + break; + + if (extend==0) // back to default timing + idx=0; //200ms + else if (extend==1) {// increase the timing + idx+=1; + if (idx>5) + idx=5; + } + else if (extend==2) {// decrease the timing + if(idx!=0) + idx-=1; + } + pRaInfo->RptTime=DynamicTxRPTTiming[idx]; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("pRaInfo->RptTime=0x%x\n", pRaInfo->RptTime)); +} + +static int +odm_RateDown_8188E( + IN PDM_ODM_T pDM_Odm, + IN PODM_RA_INFO_T pRaInfo + ) +{ + u1Byte RateID, LowestRate, HighestRate; + u1Byte i; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateDown_8188E()\n")); + if(NULL == pRaInfo) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateDown_8188E(): pRaInfo is NULL\n")); + return -1; + } + RateID = pRaInfo->PreRate; + LowestRate = pRaInfo->LowestRate; + HighestRate = pRaInfo->HighestRate; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, + (" RateID=%d LowestRate=%d HighestRate=%d RateSGI=%d\n", + RateID, LowestRate, HighestRate, pRaInfo->RateSGI)); + if (RateID > HighestRate) + { + RateID=HighestRate; + } + else if(pRaInfo->RateSGI) + { + pRaInfo->RateSGI=0; + } + else if (RateID > LowestRate) + { + if (RateID > 0) + { + for (i=RateID-1; i>LowestRate;i--) + { + if (pRaInfo->RAUseRate & BIT(i)) + { + RateID=i; + goto RateDownFinish; + + } + } + } + } + else if (RateID <= LowestRate) + { + RateID = LowestRate; + } +RateDownFinish: + if (pRaInfo->RAWaitingCounter==1){ + pRaInfo->RAWaitingCounter+=1; + pRaInfo->RAPendingCounter+=1; + } + else if(pRaInfo->RAWaitingCounter==0){ + } + else{ + pRaInfo->RAWaitingCounter=0; + pRaInfo->RAPendingCounter=0; + } + + if(pRaInfo->RAPendingCounter>=4) + pRaInfo->RAPendingCounter=4; + + pRaInfo->DecisionRate=RateID; + odm_SetTxRPTTiming_8188E(pDM_Odm,pRaInfo, 2); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate down, RPT Timing default\n")); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("RAWaitingCounter %d, RAPendingCounter %d",pRaInfo->RAWaitingCounter,pRaInfo->RAPendingCounter)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate down to RateID %d RateSGI %d\n", RateID, pRaInfo->RateSGI)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<=====odm_RateDown_8188E() \n")); + return 0; +} + +static int +odm_RateUp_8188E( + IN PDM_ODM_T pDM_Odm, + IN PODM_RA_INFO_T pRaInfo + ) +{ + u1Byte RateID, HighestRate; + u1Byte i; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateUp_8188E() \n")); + if(NULL == pRaInfo) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateUp_8188E(): pRaInfo is NULL\n")); + return -1; + } + RateID = pRaInfo->PreRate; + HighestRate = pRaInfo->HighestRate; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, + (" RateID=%d HighestRate=%d\n", + RateID, HighestRate)); + if (pRaInfo->RAWaitingCounter==1){ + pRaInfo->RAWaitingCounter=0; + pRaInfo->RAPendingCounter=0; + } + else if (pRaInfo->RAWaitingCounter>1){ + pRaInfo->PreRssiStaRA=pRaInfo->RssiStaRA; + goto RateUpfinish; + } + odm_SetTxRPTTiming_8188E(pDM_Odm,pRaInfo, 0); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("odm_RateUp_8188E():Decrease RPT Timing\n")); + + if (RateID < HighestRate) + { + for (i=RateID+1; i<=HighestRate; i++) + { + if (pRaInfo->RAUseRate & BIT(i)) + { + RateID=i; + goto RateUpfinish; + } + } + } + else if(RateID == HighestRate) + { + if (pRaInfo->SGIEnable && (pRaInfo->RateSGI != 1)) + pRaInfo->RateSGI = 1; + else if((pRaInfo->SGIEnable) !=1 ) + pRaInfo->RateSGI = 0; + } + else //if((sta_info_ra->Decision_rate) > (sta_info_ra->Highest_rate)) + { + RateID = HighestRate; + + } +RateUpfinish: + //if(pRaInfo->RAWaitingCounter==10) + if(pRaInfo->RAWaitingCounter==(4+PendingForRateUpFail[pRaInfo->RAPendingCounter])) + pRaInfo->RAWaitingCounter=0; + else + pRaInfo->RAWaitingCounter++; + + pRaInfo->DecisionRate=RateID; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("Rate up to RateID %d\n", RateID)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("RAWaitingCounter %d, RAPendingCounter %d",pRaInfo->RAWaitingCounter,pRaInfo->RAPendingCounter)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<=====odm_RateUp_8188E() \n")); + return 0; +} + +static void odm_ResetRaCounter_8188E( IN PODM_RA_INFO_T pRaInfo){ + u1Byte RateID; + RateID=pRaInfo->DecisionRate; + pRaInfo->NscUp=(N_THRESHOLD_HIGH[RateID]+N_THRESHOLD_LOW[RateID])>>1; + pRaInfo->NscDown=(N_THRESHOLD_HIGH[RateID]+N_THRESHOLD_LOW[RateID])>>1; +} + +static void +odm_RateDecision_8188E( + IN PDM_ODM_T pDM_Odm, + IN PODM_RA_INFO_T pRaInfo + ) +{ + u1Byte RateID = 0, RtyPtID = 0, PenaltyID1 = 0, PenaltyID2 = 0; + //u4Byte pool_retry; + static u1Byte DynamicTxRPTTimingCounter=0; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("=====>odm_RateDecision_8188E() \n")); + + if (pRaInfo->Active && (pRaInfo->TOTAL > 0)) // STA used and data packet exits + { + if ( (pRaInfo->RssiStaRA<(pRaInfo->PreRssiStaRA-3))|| (pRaInfo->RssiStaRA>(pRaInfo->PreRssiStaRA+3))){ + pRaInfo->RAWaitingCounter=0; + pRaInfo->RAPendingCounter=0; + } + // Start RA decision + if (pRaInfo->PreRate > pRaInfo->HighestRate) + RateID = pRaInfo->HighestRate; + else + RateID = pRaInfo->PreRate; + if (pRaInfo->RssiStaRA > RSSI_THRESHOLD[RateID]) + RtyPtID=0; + else + RtyPtID=1; + PenaltyID1 = RETRY_PENALTY_IDX[RtyPtID][RateID]; //TODO by page + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, + (" NscDown init is %d\n", pRaInfo->NscDown)); + //pool_retry=pRaInfo->RTY[2]+pRaInfo->RTY[3]+pRaInfo->RTY[4]+pRaInfo->DROP; + pRaInfo->NscDown += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID1][0]; + pRaInfo->NscDown += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID1][1]; + pRaInfo->NscDown += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID1][2]; + pRaInfo->NscDown += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID1][3]; + pRaInfo->NscDown += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID1][4]; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, + (" NscDown is %d, total*penalty[5] is %d\n", + pRaInfo->NscDown, (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5]))); + if (pRaInfo->NscDown > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5])) + pRaInfo->NscDown -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID1][5]; + else + pRaInfo->NscDown=0; + + // rate up + PenaltyID2 = RETRY_PENALTY_UP_IDX[RateID]; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, + (" NscUp init is %d\n", pRaInfo->NscUp)); + pRaInfo->NscUp += pRaInfo->RTY[0] * RETRY_PENALTY[PenaltyID2][0]; + pRaInfo->NscUp += pRaInfo->RTY[1] * RETRY_PENALTY[PenaltyID2][1]; + pRaInfo->NscUp += pRaInfo->RTY[2] * RETRY_PENALTY[PenaltyID2][2]; + pRaInfo->NscUp += pRaInfo->RTY[3] * RETRY_PENALTY[PenaltyID2][3]; + pRaInfo->NscUp += pRaInfo->RTY[4] * RETRY_PENALTY[PenaltyID2][4]; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, + ("NscUp is %d, total*up[5] is %d\n", + pRaInfo->NscUp, (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5]))); + if (pRaInfo->NscUp > (pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5])) + pRaInfo->NscUp -= pRaInfo->TOTAL * RETRY_PENALTY[PenaltyID2][5]; + else + pRaInfo->NscUp = 0; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE|ODM_COMP_INIT, ODM_DBG_LOUD, + (" RssiStaRa= %d RtyPtID=%d PenaltyID1=0x%x PenaltyID2=0x%x RateID=%d NscDown=%d NscUp=%d SGI=%d\n", + pRaInfo->RssiStaRA,RtyPtID, PenaltyID1,PenaltyID2, RateID, pRaInfo->NscDown, pRaInfo->NscUp, pRaInfo->RateSGI)); + if ((pRaInfo->NscDown < N_THRESHOLD_LOW[RateID]) ||(pRaInfo->DROP>DROPING_NECESSARY[RateID])) + odm_RateDown_8188E(pDM_Odm,pRaInfo); + //else if ((pRaInfo->NscUp > N_THRESHOLD_HIGH[RateID])&&(pool_retry<POOL_RETRY_TH[RateID])) + else if (pRaInfo->NscUp > N_THRESHOLD_HIGH[RateID]) + odm_RateUp_8188E(pDM_Odm,pRaInfo); + + if(pRaInfo->DecisionRate > pRaInfo->HighestRate) + pRaInfo->DecisionRate = pRaInfo->HighestRate; + + if ((pRaInfo->DecisionRate)==(pRaInfo->PreRate)) + DynamicTxRPTTimingCounter+=1; + else + DynamicTxRPTTimingCounter=0; + + if (DynamicTxRPTTimingCounter>=4) { + odm_SetTxRPTTiming_8188E(pDM_Odm,pRaInfo, 1); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("<=====Rate don't change 4 times, Extend RPT Timing\n")); + DynamicTxRPTTimingCounter=0; + } + + pRaInfo->PreRate = pRaInfo->DecisionRate; //YJ,add,120120 + + odm_ResetRaCounter_8188E( pRaInfo); + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, ("<=====odm_RateDecision_8188E() \n")); +} + +static int +odm_ARFBRefresh_8188E( + IN PDM_ODM_T pDM_Odm, + IN PODM_RA_INFO_T pRaInfo + ) +{ // Wilson 2011/10/26 + u4Byte MaskFromReg; + s1Byte i; + + switch(pRaInfo->RateID){ + case RATR_INX_WIRELESS_NGB: + pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0f8ff015; + break; + case RATR_INX_WIRELESS_NG: + pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0f8ff010; + break; + case RATR_INX_WIRELESS_NB: + pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0f8ff005; + break; + case RATR_INX_WIRELESS_N: + pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0f8ff000; + break; + case RATR_INX_WIRELESS_GB: + pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x00000ff5; + break; + case RATR_INX_WIRELESS_G: + pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x00000ff0; + break; + case RATR_INX_WIRELESS_B: + pRaInfo->RAUseRate=(pRaInfo->RateMask)&0x0000000d; + break; + case 12: + MaskFromReg=ODM_Read4Byte(pDM_Odm, REG_ARFR0); + pRaInfo->RAUseRate=(pRaInfo->RateMask)&MaskFromReg; + break; + case 13: + MaskFromReg=ODM_Read4Byte(pDM_Odm, REG_ARFR1); + pRaInfo->RAUseRate=(pRaInfo->RateMask)&MaskFromReg; + break; + case 14: + MaskFromReg=ODM_Read4Byte(pDM_Odm, REG_ARFR2); + pRaInfo->RAUseRate=(pRaInfo->RateMask)&MaskFromReg; + break; + case 15: + MaskFromReg=ODM_Read4Byte(pDM_Odm, REG_ARFR3); + pRaInfo->RAUseRate=(pRaInfo->RateMask)&MaskFromReg; + break; + + default: + pRaInfo->RAUseRate=(pRaInfo->RateMask); + break; + } + // Highest rate + if (pRaInfo->RAUseRate){ + for (i=RATESIZE;i>=0;i--) + { + if((pRaInfo->RAUseRate)&BIT(i)){ + pRaInfo->HighestRate=i; + break; + } + } + } + else{ + pRaInfo->HighestRate=0; + } + // Lowest rate + if (pRaInfo->RAUseRate){ + for (i=0;i<RATESIZE;i++) + { + if((pRaInfo->RAUseRate)&BIT(i)) + { + pRaInfo->LowestRate=i; + break; + } + } + } + else{ + pRaInfo->LowestRate=0; + } + +#if POWER_TRAINING_ACTIVE == 1 + if (pRaInfo->HighestRate >0x13) + pRaInfo->PTModeSS=3; + else if(pRaInfo->HighestRate >0x0b) + pRaInfo->PTModeSS=2; + else if(pRaInfo->HighestRate >0x0b) + pRaInfo->PTModeSS=1; + else + pRaInfo->PTModeSS=0; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, + ("ODM_ARFBRefresh_8188E(): PTModeSS=%d\n", pRaInfo->PTModeSS)); + +#endif + + if(pRaInfo->DecisionRate > pRaInfo->HighestRate) + pRaInfo->DecisionRate = pRaInfo->HighestRate; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, + ("ODM_ARFBRefresh_8188E(): RateID=%d RateMask=%8.8x RAUseRate=%8.8x HighestRate=%d,DecisionRate=%d \n", + pRaInfo->RateID, pRaInfo->RateMask, pRaInfo->RAUseRate, pRaInfo->HighestRate,pRaInfo->DecisionRate)); + return 0; +} + +#if POWER_TRAINING_ACTIVE == 1 +static void +odm_PTTryState_8188E( + IN PODM_RA_INFO_T pRaInfo + ) +{ + pRaInfo->PTTryState=0; + switch (pRaInfo->PTModeSS) + { + case 3: + if (pRaInfo->DecisionRate>=0x19) + pRaInfo->PTTryState=1; + break; + case 2: + if (pRaInfo->DecisionRate>=0x11) + pRaInfo->PTTryState=1; + break; + case 1: + if (pRaInfo->DecisionRate>=0x0a) + pRaInfo->PTTryState=1; + break; + case 0: + if (pRaInfo->DecisionRate>=0x03) + pRaInfo->PTTryState=1; + break; + default: + pRaInfo->PTTryState=0; + } + + if (pRaInfo->RssiStaRA<48) + { + pRaInfo->PTStage=0; + } + else if (pRaInfo->PTTryState==1) + { + if ((pRaInfo->PTStopCount>=10)||(pRaInfo->PTPreRssi>pRaInfo->RssiStaRA+5) + ||(pRaInfo->PTPreRssi<pRaInfo->RssiStaRA-5)||(pRaInfo->DecisionRate!=pRaInfo->PTPreRate)) + { + if (pRaInfo->PTStage==0) + pRaInfo->PTStage=1; + else if(pRaInfo->PTStage==1) + pRaInfo->PTStage=3; + else + pRaInfo->PTStage=5; + + pRaInfo->PTPreRssi=pRaInfo->RssiStaRA; + pRaInfo->PTStopCount=0; + + } + else{ + pRaInfo->RAstage=0; + pRaInfo->PTStopCount++; + } + } + else{ + pRaInfo->PTStage=0; + pRaInfo->RAstage=0; + } + pRaInfo->PTPreRate=pRaInfo->DecisionRate; +} + +static void +odm_PTDecision_8188E( + IN PODM_RA_INFO_T pRaInfo + ) +{ + u1Byte stage_BUF; + u1Byte j; + u1Byte temp_stage; + u4Byte numsc; + u4Byte num_total; + u1Byte stage_id; + + stage_BUF=pRaInfo->PTStage; + numsc = 0; + num_total= pRaInfo->TOTAL* PT_PENALTY[5]; + for(j=0;j<=4;j++) + { + numsc += pRaInfo->RTY[j] * PT_PENALTY[j]; + if(numsc>num_total) + break; + } + + j=j>>1; + temp_stage= (pRaInfo->PTStage +1)>>1; + if (temp_stage>j) + stage_id=temp_stage-j; + else + stage_id=0; + + pRaInfo->PTSmoothFactor=(pRaInfo->PTSmoothFactor>>1) + (pRaInfo->PTSmoothFactor>>2) + stage_id*16+2; + if (pRaInfo->PTSmoothFactor>192) + pRaInfo->PTSmoothFactor=192; + stage_id =pRaInfo->PTSmoothFactor>>6; + temp_stage=stage_id*2; + if (temp_stage!=0) + temp_stage-=1; + if (pRaInfo->DROP>3) + temp_stage=0; + pRaInfo->PTStage=temp_stage; + +} +#endif + +static VOID +odm_RATxRPTTimerSetting( + IN PDM_ODM_T pDM_Odm, + IN u2Byte minRptTime +) +{ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,(" =====>odm_RATxRPTTimerSetting()\n")); + + + if(pDM_Odm->CurrminRptTime != minRptTime){ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, + (" CurrminRptTime =0x%04x minRptTime=0x%04x\n", pDM_Odm->CurrminRptTime, minRptTime)); + #if(DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_AP)) + ODM_RA_Set_TxRPT_Time(pDM_Odm,minRptTime); + #else + rtw_rpt_timer_cfg_cmd(pDM_Odm->Adapter,minRptTime); + #endif + pDM_Odm->CurrminRptTime = minRptTime; + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE,(" <=====odm_RATxRPTTimerSetting()\n")); +} + + +VOID +ODM_RASupport_Init( + IN PDM_ODM_T pDM_Odm + ) +{ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>ODM_RASupport_Init()\n")); + + // 2012/02/14 MH Be noticed, the init must be after IC type is recognized!!!!! + if (pDM_Odm->SupportICType == ODM_RTL8188E) + { +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + //I Cut: FALSE(FW RA); Ohterwise: TRUE(Driver RA) + pDM_Odm->RaSupport88E = (pDM_Odm->Adapter->RASupport == TRUE); +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + if(pDM_Odm->CutVersion == ODM_CUT_I)//I Cut use FW RA + pDM_Odm->RaSupport88E = FALSE; + else + pDM_Odm->RaSupport88E = TRUE; +#endif + } +} + + + +int +ODM_RAInfo_Init( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID + ) +{ + PODM_RA_INFO_T pRaInfo = &pDM_Odm->RAInfo[MacID]; + #if 1 + u1Byte WirelessMode=0xFF; //invalid value + u1Byte max_rate_idx = 0x13; //MCS7 + if(pDM_Odm->pWirelessMode!=NULL){ + WirelessMode=*(pDM_Odm->pWirelessMode); + } + + if(WirelessMode != 0xFF ){ + if(WirelessMode & ODM_WM_N24G) + max_rate_idx = 0x13; + else if(WirelessMode & ODM_WM_G) + max_rate_idx = 0x0b; + else if(WirelessMode & ODM_WM_B) + max_rate_idx = 0x03; + } + + //printk("%s ==>WirelessMode:0x%08x ,max_raid_idx:0x%02x\n ",__FUNCTION__,WirelessMode,max_rate_idx); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, + ("ODM_RAInfo_Init(): WirelessMode:0x%08x ,max_raid_idx:0x%02x \n", + WirelessMode,max_rate_idx)); + + pRaInfo->DecisionRate = max_rate_idx; + pRaInfo->PreRate = max_rate_idx; + pRaInfo->HighestRate=max_rate_idx; + #else + pRaInfo->DecisionRate = 0x13; + pRaInfo->PreRate = 0x13; + pRaInfo->HighestRate=0x13; + #endif + pRaInfo->LowestRate=0; + pRaInfo->RateID=0; + pRaInfo->RateMask=0xffffffff; + pRaInfo->RssiStaRA=0; + pRaInfo->PreRssiStaRA=0; + pRaInfo->SGIEnable=0; + pRaInfo->RAUseRate=0xffffffff; + pRaInfo->NscDown=(N_THRESHOLD_HIGH[0x13]+N_THRESHOLD_LOW[0x13])/2; + pRaInfo->NscUp=(N_THRESHOLD_HIGH[0x13]+N_THRESHOLD_LOW[0x13])/2; + pRaInfo->RateSGI=0; + pRaInfo->Active=1; //Active is not used at present. by page, 110819 + pRaInfo->RptTime = 0x927c; + pRaInfo->DROP=0; + pRaInfo->RTY[0]=0; + pRaInfo->RTY[1]=0; + pRaInfo->RTY[2]=0; + pRaInfo->RTY[3]=0; + pRaInfo->RTY[4]=0; + pRaInfo->TOTAL=0; + pRaInfo->RAWaitingCounter=0; + pRaInfo->RAPendingCounter=0; +#if POWER_TRAINING_ACTIVE == 1 + pRaInfo->PTActive=1; // Active when this STA is use + pRaInfo->PTTryState=0; + pRaInfo->PTStage=5; // Need to fill into HW_PWR_STATUS + pRaInfo->PTSmoothFactor=192; + pRaInfo->PTStopCount=0; + pRaInfo->PTPreRate=0; + pRaInfo->PTPreRssi=0; + pRaInfo->PTModeSS=0; + pRaInfo->RAstage=0; +#endif + return 0; +} + +int +ODM_RAInfo_Init_all( + IN PDM_ODM_T pDM_Odm + ) +{ + u1Byte MacID = 0; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>\n")); + pDM_Odm->CurrminRptTime = 0; + + for(MacID=0; MacID<ODM_ASSOCIATE_ENTRY_NUM; MacID++) + ODM_RAInfo_Init(pDM_Odm,MacID); + + //Redifine arrays for I-cut NIC + if (pDM_Odm->CutVersion == ODM_CUT_I) + { +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + + u1Byte i; + u1Byte RETRY_PENALTY_IDX_S[2][RATESIZE] = {{4,4,4,5, + 4,4,5,7,7,7,8,0x0a, // SS>TH + 4,4,4,4,6,0x0a,0x0b,0x0d, + 5,5,7,7,8,0x0b,0x0d,0x0f}, // 0329 R01 + {0x0a,0x0a,0x0b,0x0c, + 0x0a,0x0a,0x0b,0x0c,0x0d,0x10,0x13,0x13, // SS<TH + 0x06,0x07,0x08,0x0d,0x0e,0x11,0x11,0x11, + 9,9,9,9,0x0c,0x0e,0x11,0x13}}; + + u1Byte RETRY_PENALTY_UP_IDX_S[RATESIZE] = {0x0c,0x0d,0x0d,0x0f, + 0x0d,0x0e,0x0f,0x0f,0x10,0x12,0x13,0x14, // SS>TH + 0x0b,0x0b,0x11,0x11,0x12,0x12,0x12,0x12, + 0x11,0x11,0x12,0x13,0x13,0x13,0x14,0x15}; + + for( i=0; i<RATESIZE; i++ ) + { + RETRY_PENALTY_IDX[0][i] = RETRY_PENALTY_IDX_S[0][i]; + RETRY_PENALTY_IDX[1][i] = RETRY_PENALTY_IDX_S[1][i]; + + RETRY_PENALTY_UP_IDX[i] = RETRY_PENALTY_UP_IDX_S[i]; + } + return 0; +#endif + } + + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN)//This is for non-I-cut +{ + PADAPTER Adapter = pDM_Odm->Adapter; + + //DbgPrint("Adapter->MgntInfo.RegRALvl = %d\n", Adapter->MgntInfo.RegRALvl); + + // + // 2012/09/14 MH Add for different Ra pattern init. For TPLINK case, we + // need to to adjust different RA pattern for middle range RA. 20-30dB degarde + // 88E rate adptve will raise too slow. + // + if (Adapter->MgntInfo.RegRALvl == 0) + { + RETRY_PENALTY_UP_IDX[11] = 0x14; + + RETRY_PENALTY_UP_IDX[17] = 0x13; + RETRY_PENALTY_UP_IDX[18] = 0x14; + RETRY_PENALTY_UP_IDX[19] = 0x15; + + RETRY_PENALTY_UP_IDX[23] = 0x13; + RETRY_PENALTY_UP_IDX[24] = 0x13; + RETRY_PENALTY_UP_IDX[25] = 0x13; + RETRY_PENALTY_UP_IDX[26] = 0x14; + RETRY_PENALTY_UP_IDX[27] = 0x15; + } + else if (Adapter->MgntInfo.RegRALvl == 1) + { + RETRY_PENALTY_UP_IDX[17] = 0x13; + RETRY_PENALTY_UP_IDX[18] = 0x13; + RETRY_PENALTY_UP_IDX[19] = 0x14; + + RETRY_PENALTY_UP_IDX[23] = 0x12; + RETRY_PENALTY_UP_IDX[24] = 0x13; + RETRY_PENALTY_UP_IDX[25] = 0x13; + RETRY_PENALTY_UP_IDX[26] = 0x13; + RETRY_PENALTY_UP_IDX[27] = 0x14; + } + else if (Adapter->MgntInfo.RegRALvl == 2) + { + // Compile flag default is lvl2, we need not to update. + } + else if (Adapter->MgntInfo.RegRALvl >= 0x80) + { + u1Byte index = 0, offset = Adapter->MgntInfo.RegRALvl - 0x80; + + // Reset to default rate adaptive value. + RETRY_PENALTY_UP_IDX[11] = 0x14; + + RETRY_PENALTY_UP_IDX[17] = 0x13; + RETRY_PENALTY_UP_IDX[18] = 0x14; + RETRY_PENALTY_UP_IDX[19] = 0x15; + + RETRY_PENALTY_UP_IDX[23] = 0x13; + RETRY_PENALTY_UP_IDX[24] = 0x13; + RETRY_PENALTY_UP_IDX[25] = 0x13; + RETRY_PENALTY_UP_IDX[26] = 0x14; + RETRY_PENALTY_UP_IDX[27] = 0x15; + + if (Adapter->MgntInfo.RegRALvl >= 0x90) + { + offset = Adapter->MgntInfo.RegRALvl - 0x90; + // Lazy mode. + for (index = 0; index < 28; index++) + { + RETRY_PENALTY_UP_IDX[index] += (offset); + } + } + else + { + // Aggrasive side. + for (index = 0; index < 28; index++) + { + RETRY_PENALTY_UP_IDX[index] -= (offset); + } + } + + } +} +#endif + + return 0; +} + + +u1Byte +ODM_RA_GetShortGI_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID +) +{ + if((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM)) + return 0; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, + ("MacID=%d SGI=%d\n", MacID, pDM_Odm->RAInfo[MacID].RateSGI)); + return pDM_Odm->RAInfo[MacID].RateSGI; +} + +u1Byte +ODM_RA_GetDecisionRate_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID + ) +{ + u1Byte DecisionRate = 0; + + if((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM)) + return 0; + DecisionRate = (pDM_Odm->RAInfo[MacID].DecisionRate); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, + (" MacID=%d DecisionRate=0x%x\n", MacID, DecisionRate)); + return DecisionRate; +} + +u1Byte +ODM_RA_GetHwPwrStatus_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID + ) +{ + u1Byte PTStage = 5; + if((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM)) + return 0; + PTStage = (pDM_Odm->RAInfo[MacID].PTStage); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, + ("MacID=%d PTStage=0x%x\n", MacID, PTStage)); + return PTStage; +} + +VOID +ODM_RA_UpdateRateInfo_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID, + IN u1Byte RateID, + IN u4Byte RateMask, + IN u1Byte SGIEnable + ) +{ + PODM_RA_INFO_T pRaInfo = NULL; + + if((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM)) + return; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, + ("MacID=%d RateID=0x%x RateMask=0x%x SGIEnable=%d\n", + MacID, RateID, RateMask, SGIEnable)); + + pRaInfo = &(pDM_Odm->RAInfo[MacID]); + pRaInfo->RateID = RateID; + pRaInfo->RateMask = RateMask; + pRaInfo->SGIEnable = SGIEnable; + odm_ARFBRefresh_8188E(pDM_Odm, pRaInfo); +} + +VOID +ODM_RA_SetRSSI_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID, + IN u1Byte Rssi + ) +{ + PODM_RA_INFO_T pRaInfo = NULL; + + if((NULL == pDM_Odm) || (MacID >= ASSOCIATE_ENTRY_NUM)) + return; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_TRACE, + (" MacID=%d Rssi=%d\n", MacID, Rssi)); + + pRaInfo = &(pDM_Odm->RAInfo[MacID]); + pRaInfo->RssiStaRA = Rssi; +} + +VOID +ODM_RA_Set_TxRPT_Time( + IN PDM_ODM_T pDM_Odm, + IN u2Byte minRptTime + ) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP)) + if (minRptTime != 0xffff) +#endif + ODM_Write2Byte(pDM_Odm, REG_TX_RPT_TIME, minRptTime); +} + + +VOID +ODM_RA_TxRPT2Handle_8188E( + IN PDM_ODM_T pDM_Odm, + IN pu1Byte TxRPT_Buf, + IN u2Byte TxRPT_Len, + IN u4Byte MacIDValidEntry0, + IN u4Byte MacIDValidEntry1 + ) +{ + PODM_RA_INFO_T pRAInfo = NULL; + u1Byte MacId = 0; + pu1Byte pBuffer = NULL; + u4Byte valid = 0, ItemNum = 0; + u2Byte minRptTime = 0x927c; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("=====>ODM_RA_TxRPT2Handle_8188E(): valid0=%d valid1=%d BufferLength=%d\n", + MacIDValidEntry0, MacIDValidEntry1, TxRPT_Len)); + + ItemNum = TxRPT_Len >> 3; + pBuffer = TxRPT_Buf; + + do + { + if(MacId >= ASSOCIATE_ENTRY_NUM) + valid = 0; + else if(MacId >= 32) + valid = (1<<(MacId-32)) & MacIDValidEntry1; + else + valid = (1<<MacId) & MacIDValidEntry0; + + if(valid) + { + pRAInfo = &(pDM_Odm->RAInfo[MacId]); + + pRAInfo->RTY[0] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_0(pBuffer); + pRAInfo->RTY[1] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_1(pBuffer); + pRAInfo->RTY[2] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_2(pBuffer); + pRAInfo->RTY[3] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_3(pBuffer); + pRAInfo->RTY[4] = (u2Byte)GET_TX_REPORT_TYPE1_RERTY_4(pBuffer); + pRAInfo->DROP = (u2Byte)GET_TX_REPORT_TYPE1_DROP_0(pBuffer); + + pRAInfo->TOTAL = pRAInfo->RTY[0] + \ + pRAInfo->RTY[1] + \ + pRAInfo->RTY[2] + \ + pRAInfo->RTY[3] + \ + pRAInfo->RTY[4] + \ + pRAInfo->DROP; + if(pRAInfo->TOTAL != 0) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, + ("macid=%d Total=%d R0=%d R1=%d R2=%d R3=%d R4=%d D0=%d valid0=%x valid1=%x\n", + MacId, + pRAInfo->TOTAL, + pRAInfo->RTY[0], + pRAInfo->RTY[1], + pRAInfo->RTY[2], + pRAInfo->RTY[3], + pRAInfo->RTY[4], + pRAInfo->DROP, + MacIDValidEntry0 , + MacIDValidEntry1)); +#if POWER_TRAINING_ACTIVE == 1 + if (pRAInfo->PTActive){ + if(pRAInfo->RAstage<5){ + odm_RateDecision_8188E(pDM_Odm,pRAInfo); + } + else if(pRAInfo->RAstage==5){ // Power training try state + odm_PTTryState_8188E(pRAInfo); + } + else {// RAstage==6 + odm_PTDecision_8188E(pRAInfo); + } + + // Stage_RA counter + if (pRAInfo->RAstage<=5) + pRAInfo->RAstage++; + else + pRAInfo->RAstage=0; + } + else{ + odm_RateDecision_8188E(pDM_Odm,pRAInfo); + } +#else + odm_RateDecision_8188E(pDM_Odm, pRAInfo); +#endif + +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + extern void RTL8188E_SetStationTxRateInfo(PDM_ODM_T, PODM_RA_INFO_T, int); + RTL8188E_SetStationTxRateInfo(pDM_Odm, pRAInfo, MacId); +#ifdef DETECT_STA_EXISTANCE + void RTL8188E_DetectSTAExistance(PDM_ODM_T pDM_Odm, PODM_RA_INFO_T pRAInfo, int MacID); + RTL8188E_DetectSTAExistance(pDM_Odm, pRAInfo, MacId); +#endif +#endif + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, + ("macid=%d R0=%d R1=%d R2=%d R3=%d R4=%d drop=%d valid0=%x RateID=%d SGI=%d\n", + MacId, + pRAInfo->RTY[0], + pRAInfo->RTY[1], + pRAInfo->RTY[2], + pRAInfo->RTY[3], + pRAInfo->RTY[4], + pRAInfo->DROP, + MacIDValidEntry0, + pRAInfo->DecisionRate, + pRAInfo->RateSGI)); + } + else + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, (" TOTAL=0!!!!\n")); + + if(minRptTime > pRAInfo->RptTime) + minRptTime = pRAInfo->RptTime; + } + + pBuffer += TX_RPT2_ITEM_SIZE; + MacId++; + }while(MacId < ItemNum); + + odm_RATxRPTTimerSetting(pDM_Odm,minRptTime); + + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_RATE_ADAPTIVE, ODM_DBG_LOUD, ("<===== ODM_RA_TxRPT2Handle_8188E()\n")); +} + +#else + +static VOID +odm_RATxRPTTimerSetting( + IN PDM_ODM_T pDM_Odm, + IN u2Byte minRptTime +) +{ + return; +} + + +VOID +ODM_RASupport_Init( + IN PDM_ODM_T pDM_Odm + ) +{ + return; +} + +int +ODM_RAInfo_Init( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID + ) +{ + return 0; +} + +int +ODM_RAInfo_Init_all( + IN PDM_ODM_T pDM_Odm + ) +{ + return 0; +} + +u1Byte +ODM_RA_GetShortGI_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID + ) +{ + return 0; +} + +u1Byte +ODM_RA_GetDecisionRate_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID + ) +{ + return 0; +} +u1Byte +ODM_RA_GetHwPwrStatus_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID + ) +{ + return 0; +} + +VOID +ODM_RA_UpdateRateInfo_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID, + IN u1Byte RateID, + IN u4Byte RateMask, + IN u1Byte SGIEnable + ) +{ + return; +} + +VOID +ODM_RA_SetRSSI_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID, + IN u1Byte Rssi + ) +{ + return; +} + +VOID +ODM_RA_Set_TxRPT_Time( + IN PDM_ODM_T pDM_Odm, + IN u2Byte minRptTime + ) +{ + return; +} + +VOID +ODM_RA_TxRPT2Handle_8188E( + IN PDM_ODM_T pDM_Odm, + IN pu1Byte TxRPT_Buf, + IN u2Byte TxRPT_Len, + IN u4Byte MacIDValidEntry0, + IN u4Byte MacIDValidEntry1 + ) +{ + return; +} + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.h new file mode 100644 index 0000000..172edf1 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188ERateAdaptive.h @@ -0,0 +1,108 @@ +#ifndef __INC_RA_H +#define __INC_RA_H +/*++ +Copyright (c) Realtek Semiconductor Corp. All rights reserved. + +Module Name: + RateAdaptive.h + +Abstract: + Prototype of RA and related data structure. + +Major Change History: + When Who What + ---------- --------------- ------------------------------- + 2011-08-12 Page Create. +--*/ + +// Rate adaptive define +#define PERENTRY 23 +#define RETRYSIZE 5 +#define RATESIZE 28 +#define TX_RPT2_ITEM_SIZE 8 + +#if (DM_ODM_SUPPORT_TYPE != ODM_WIN) +// +// TX report 2 format in Rx desc +// +#define GET_TX_RPT2_DESC_PKT_LEN_88E(__pRxStatusDesc) LE_BITS_TO_4BYTE( __pRxStatusDesc, 0, 9) +#define GET_TX_RPT2_DESC_MACID_VALID_1_88E(__pRxStatusDesc) LE_BITS_TO_4BYTE( __pRxStatusDesc+16, 0, 32) +#define GET_TX_RPT2_DESC_MACID_VALID_2_88E(__pRxStatusDesc) LE_BITS_TO_4BYTE( __pRxStatusDesc+20, 0, 32) + +#define GET_TX_REPORT_TYPE1_RERTY_0(__pAddr) LE_BITS_TO_4BYTE( __pAddr, 0, 16) +#define GET_TX_REPORT_TYPE1_RERTY_1(__pAddr) LE_BITS_TO_1BYTE( __pAddr+2, 0, 8) +#define GET_TX_REPORT_TYPE1_RERTY_2(__pAddr) LE_BITS_TO_1BYTE( __pAddr+3, 0, 8) +#define GET_TX_REPORT_TYPE1_RERTY_3(__pAddr) LE_BITS_TO_1BYTE( __pAddr+4, 0, 8) +#define GET_TX_REPORT_TYPE1_RERTY_4(__pAddr) LE_BITS_TO_1BYTE( __pAddr+4+1, 0, 8) +#define GET_TX_REPORT_TYPE1_DROP_0(__pAddr) LE_BITS_TO_1BYTE( __pAddr+4+2, 0, 8) +#define GET_TX_REPORT_TYPE1_DROP_1(__pAddr) LE_BITS_TO_1BYTE( __pAddr+4+3, 0, 8) +#endif + +// End rate adaptive define + +VOID +ODM_RASupport_Init( + IN PDM_ODM_T pDM_Odm + ); + +int +ODM_RAInfo_Init_all( + IN PDM_ODM_T pDM_Odm + ); + +int +ODM_RAInfo_Init( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID + ); + +u1Byte +ODM_RA_GetShortGI_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID + ); + +u1Byte +ODM_RA_GetDecisionRate_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID + ); + +u1Byte +ODM_RA_GetHwPwrStatus_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID + ); +VOID +ODM_RA_UpdateRateInfo_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID, + IN u1Byte RateID, + IN u4Byte RateMask, + IN u1Byte SGIEnable + ); + +VOID +ODM_RA_SetRSSI_8188E( + IN PDM_ODM_T pDM_Odm, + IN u1Byte MacID, + IN u1Byte Rssi + ); + +VOID +ODM_RA_TxRPT2Handle_8188E( + IN PDM_ODM_T pDM_Odm, + IN pu1Byte TxRPT_Buf, + IN u2Byte TxRPT_Len, + IN u4Byte MacIDValidEntry0, + IN u4Byte MacIDValidEntry1 + ); + + +VOID +ODM_RA_Set_TxRPT_Time( + IN PDM_ODM_T pDM_Odm, + IN u2Byte minRptTime + ); +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188EReg.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188EReg.h new file mode 100644 index 0000000..b31ae2d --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/Hal8188EReg.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +//============================================================ +// File Name: Hal8188EReg.h +// +// Description: +// +// This file is for RTL8188E register definition. +// +// +//============================================================ +#ifndef __HAL_8188E_REG_H__ +#define __HAL_8188E_REG_H__ + +// +// Register Definition +// +#define TRX_ANTDIV_PATH 0x860 +#define RX_ANTDIV_PATH 0xb2c +#define ODM_R_A_AGC_CORE1_8188E 0xc50 + + +// +// Bitmap Definition +// +#define BIT_FA_RESET_8188E BIT0 + +#define REG_DBI_WDATA_8188 0x0348 // DBI Write Data +#define REG_DBI_RDATA_8188 0x034C // DBI Read Data +#define REG_DBI_ADDR_8188 0x0350 // DBI Address +#define REG_DBI_FLAG_8188 0x0352 // DBI Read/Write Flag +#define REG_MDIO_WDATA_8188E 0x0354 // MDIO for Write PCIE PHY +#define REG_MDIO_RDATA_8188E 0x0356 // MDIO for Reads PCIE PHY +#define REG_MDIO_CTL_8188E 0x0358 // MDIO for Control + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.c new file mode 100644 index 0000000..0dedc46 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.c @@ -0,0 +1,1652 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + +#include "../odm_precomp.h" + +#ifdef CONFIG_IOL_IOREG_CFG +#include <rtw_iol.h> +#endif + +#if (RTL8188E_SUPPORT == 1) +static BOOLEAN +CheckCondition( + const u4Byte Condition, + const u4Byte Hex + ) +{ + u4Byte _board = (Hex & 0x000000FF); + u4Byte _interface = (Hex & 0x0000FF00) >> 8; + u4Byte _platform = (Hex & 0x00FF0000) >> 16; + u4Byte cond = Condition; + + if ( Condition == 0xCDCDCDCD ) + return TRUE; + + cond = Condition & 0x000000FF; + if ( (_board != cond) && (cond != 0xFF) ) + return FALSE; + + cond = Condition & 0x0000FF00; + cond = cond >> 8; + if ( ((_interface & cond) == 0) && (cond != 0x07) ) + return FALSE; + + cond = Condition & 0x00FF0000; + cond = cond >> 16; + if ( ((_platform & cond) == 0) && (cond != 0x0F) ) + return FALSE; + return TRUE; +} + + +/****************************************************************************** +* AGC_TAB_1T.TXT +******************************************************************************/ + +u4Byte Array_MP_8188E_AGC_TAB_1T[] = { + 0xFF0F0718, 0xABCD, + 0xC78, 0xF7000001, + 0xC78, 0xF6010001, + 0xC78, 0xF5020001, + 0xC78, 0xF4030001, + 0xC78, 0xF3040001, + 0xC78, 0xF2050001, + 0xC78, 0xF1060001, + 0xC78, 0xF0070001, + 0xC78, 0xEF080001, + 0xC78, 0xEE090001, + 0xC78, 0xED0A0001, + 0xC78, 0xEC0B0001, + 0xC78, 0xEB0C0001, + 0xC78, 0xEA0D0001, + 0xC78, 0xE90E0001, + 0xC78, 0xE80F0001, + 0xC78, 0xE7100001, + 0xC78, 0xE6110001, + 0xC78, 0xE5120001, + 0xC78, 0xE4130001, + 0xC78, 0xE3140001, + 0xC78, 0xE2150001, + 0xC78, 0xE1160001, + 0xC78, 0x89170001, + 0xC78, 0x88180001, + 0xC78, 0x87190001, + 0xC78, 0x861A0001, + 0xC78, 0x851B0001, + 0xC78, 0x841C0001, + 0xC78, 0x831D0001, + 0xC78, 0x821E0001, + 0xC78, 0x811F0001, + 0xC78, 0x6B200001, + 0xC78, 0x6A210001, + 0xC78, 0x69220001, + 0xC78, 0x68230001, + 0xC78, 0x67240001, + 0xC78, 0x66250001, + 0xC78, 0x65260001, + 0xC78, 0x64270001, + 0xC78, 0x63280001, + 0xC78, 0x62290001, + 0xC78, 0x612A0001, + 0xC78, 0x462B0001, + 0xC78, 0x452C0001, + 0xC78, 0x442D0001, + 0xC78, 0x432E0001, + 0xC78, 0x422F0001, + 0xC78, 0x41300001, + 0xC78, 0x40310001, + 0xC78, 0x40320001, + 0xC78, 0x40330001, + 0xC78, 0x40340001, + 0xC78, 0x40350001, + 0xC78, 0x40360001, + 0xC78, 0x40370001, + 0xC78, 0x40380001, + 0xC78, 0x40390001, + 0xC78, 0x403A0001, + 0xC78, 0x403B0001, + 0xC78, 0x403C0001, + 0xC78, 0x403D0001, + 0xC78, 0x403E0001, + 0xC78, 0x403F0001, + 0xCDCDCDCD, 0xCDCD, + 0xC78, 0xFB000001, + 0xC78, 0xFB010001, + 0xC78, 0xFB020001, + 0xC78, 0xFB030001, + 0xC78, 0xFB040001, + 0xC78, 0xFB050001, + 0xC78, 0xFA060001, + 0xC78, 0xF9070001, + 0xC78, 0xF8080001, + 0xC78, 0xF7090001, + 0xC78, 0xF60A0001, + 0xC78, 0xF50B0001, + 0xC78, 0xF40C0001, + 0xC78, 0xF30D0001, + 0xC78, 0xF20E0001, + 0xC78, 0xF10F0001, + 0xC78, 0xF0100001, + 0xC78, 0xEF110001, + 0xC78, 0xEE120001, + 0xC78, 0xED130001, + 0xC78, 0xEC140001, + 0xC78, 0xEB150001, + 0xC78, 0xEA160001, + 0xC78, 0xE9170001, + 0xC78, 0xE8180001, + 0xC78, 0xE7190001, + 0xC78, 0xE61A0001, + 0xC78, 0xE51B0001, + 0xC78, 0xE41C0001, + 0xC78, 0xE31D0001, + 0xC78, 0xE21E0001, + 0xC78, 0xE11F0001, + 0xC78, 0x8A200001, + 0xC78, 0x89210001, + 0xC78, 0x88220001, + 0xC78, 0x87230001, + 0xC78, 0x86240001, + 0xC78, 0x85250001, + 0xC78, 0x84260001, + 0xC78, 0x83270001, + 0xC78, 0x82280001, + 0xC78, 0x6B290001, + 0xC78, 0x6A2A0001, + 0xC78, 0x692B0001, + 0xC78, 0x682C0001, + 0xC78, 0x672D0001, + 0xC78, 0x662E0001, + 0xC78, 0x652F0001, + 0xC78, 0x64300001, + 0xC78, 0x63310001, + 0xC78, 0x62320001, + 0xC78, 0x61330001, + 0xC78, 0x46340001, + 0xC78, 0x45350001, + 0xC78, 0x44360001, + 0xC78, 0x43370001, + 0xC78, 0x42380001, + 0xC78, 0x41390001, + 0xC78, 0x403A0001, + 0xC78, 0x403B0001, + 0xC78, 0x403C0001, + 0xC78, 0x403D0001, + 0xC78, 0x403E0001, + 0xC78, 0x403F0001, + 0xFF0F0718, 0xDEAD, + 0xFF0F0718, 0xABCD, + 0xC78, 0xFB400001, + 0xC78, 0xFA410001, + 0xC78, 0xF9420001, + 0xC78, 0xF8430001, + 0xC78, 0xF7440001, + 0xC78, 0xF6450001, + 0xC78, 0xF5460001, + 0xC78, 0xF4470001, + 0xC78, 0xF3480001, + 0xC78, 0xF2490001, + 0xC78, 0xF14A0001, + 0xC78, 0xF04B0001, + 0xC78, 0xEF4C0001, + 0xC78, 0xEE4D0001, + 0xC78, 0xED4E0001, + 0xC78, 0xEC4F0001, + 0xC78, 0xEB500001, + 0xC78, 0xEA510001, + 0xC78, 0xE9520001, + 0xC78, 0xE8530001, + 0xC78, 0xE7540001, + 0xC78, 0xE6550001, + 0xC78, 0xE5560001, + 0xC78, 0xE4570001, + 0xC78, 0xE3580001, + 0xC78, 0xE2590001, + 0xC78, 0xC35A0001, + 0xC78, 0xC25B0001, + 0xC78, 0xC15C0001, + 0xC78, 0x8B5D0001, + 0xC78, 0x8A5E0001, + 0xC78, 0x895F0001, + 0xC78, 0x88600001, + 0xC78, 0x87610001, + 0xC78, 0x86620001, + 0xC78, 0x85630001, + 0xC78, 0x84640001, + 0xC78, 0x67650001, + 0xC78, 0x66660001, + 0xC78, 0x65670001, + 0xC78, 0x64680001, + 0xC78, 0x63690001, + 0xC78, 0x626A0001, + 0xC78, 0x616B0001, + 0xC78, 0x606C0001, + 0xC78, 0x466D0001, + 0xC78, 0x456E0001, + 0xC78, 0x446F0001, + 0xC78, 0x43700001, + 0xC78, 0x42710001, + 0xC78, 0x41720001, + 0xC78, 0x40730001, + 0xC78, 0x40740001, + 0xC78, 0x40750001, + 0xC78, 0x40760001, + 0xC78, 0x40770001, + 0xC78, 0x40780001, + 0xC78, 0x40790001, + 0xC78, 0x407A0001, + 0xC78, 0x407B0001, + 0xC78, 0x407C0001, + 0xC78, 0x407D0001, + 0xC78, 0x407E0001, + 0xC78, 0x407F0001, + 0xCDCDCDCD, 0xCDCD, + 0xC78, 0xFB400001, + 0xC78, 0xFB410001, + 0xC78, 0xFB420001, + 0xC78, 0xFB430001, + 0xC78, 0xFB440001, + 0xC78, 0xFB450001, + 0xC78, 0xFB460001, + 0xC78, 0xFB470001, + 0xC78, 0xFB480001, + 0xC78, 0xFA490001, + 0xC78, 0xF94A0001, + 0xC78, 0xF84B0001, + 0xC78, 0xF74C0001, + 0xC78, 0xF64D0001, + 0xC78, 0xF54E0001, + 0xC78, 0xF44F0001, + 0xC78, 0xF3500001, + 0xC78, 0xF2510001, + 0xC78, 0xF1520001, + 0xC78, 0xF0530001, + 0xC78, 0xEF540001, + 0xC78, 0xEE550001, + 0xC78, 0xED560001, + 0xC78, 0xEC570001, + 0xC78, 0xEB580001, + 0xC78, 0xEA590001, + 0xC78, 0xE95A0001, + 0xC78, 0xE85B0001, + 0xC78, 0xE75C0001, + 0xC78, 0xE65D0001, + 0xC78, 0xE55E0001, + 0xC78, 0xE45F0001, + 0xC78, 0xE3600001, + 0xC78, 0xE2610001, + 0xC78, 0xC3620001, + 0xC78, 0xC2630001, + 0xC78, 0xC1640001, + 0xC78, 0x8B650001, + 0xC78, 0x8A660001, + 0xC78, 0x89670001, + 0xC78, 0x88680001, + 0xC78, 0x87690001, + 0xC78, 0x866A0001, + 0xC78, 0x856B0001, + 0xC78, 0x846C0001, + 0xC78, 0x676D0001, + 0xC78, 0x666E0001, + 0xC78, 0x656F0001, + 0xC78, 0x64700001, + 0xC78, 0x63710001, + 0xC78, 0x62720001, + 0xC78, 0x61730001, + 0xC78, 0x60740001, + 0xC78, 0x46750001, + 0xC78, 0x45760001, + 0xC78, 0x44770001, + 0xC78, 0x43780001, + 0xC78, 0x42790001, + 0xC78, 0x417A0001, + 0xC78, 0x407B0001, + 0xC78, 0x407C0001, + 0xC78, 0x407D0001, + 0xC78, 0x407E0001, + 0xC78, 0x407F0001, + 0xFF0F0718, 0xDEAD, + 0xC50, 0x69553422, + 0xC50, 0x69553420, + +}; + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_AGC_TAB_1T( + IN PDM_ODM_T pDM_Odm + ) +{ + #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) + + u4Byte hex = 0; + u4Byte i = 0; + u2Byte count = 0; + pu4Byte ptr_array = NULL; + u1Byte platform = pDM_Odm->SupportPlatform; + u1Byte _interface = pDM_Odm->SupportInterface; + u1Byte board = pDM_Odm->BoardType; + u4Byte ArrayLen = sizeof(Array_MP_8188E_AGC_TAB_1T)/sizeof(u4Byte); + pu4Byte Array = Array_MP_8188E_AGC_TAB_1T; + BOOLEAN biol = FALSE; +#ifdef CONFIG_IOL_IOREG_CFG + PADAPTER Adapter = pDM_Odm->Adapter; + struct xmit_frame *pxmit_frame; + u8 bndy_cnt=1; +#endif//#ifdef CONFIG_IOL_IOREG_CFG + HAL_STATUS rst =HAL_STATUS_SUCCESS; + + hex += board; + hex += _interface << 8; + hex += platform << 16; + hex += 0xFF000000; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_8188E_AGC_TAB_1T, hex = 0x%X\n", hex)); +#ifdef CONFIG_IOL_IOREG_CFG + biol = rtw_IOL_applied(Adapter); + + if(biol){ + if((pxmit_frame= rtw_IOL_accquire_xmit_frame(Adapter)) == NULL){ + printk("rtw_IOL_accquire_xmit_frame failed\n"); + return HAL_STATUS_FAILURE; + } + } +#endif//#ifdef CONFIG_IOL_IOREG_CFG + + for (i = 0; i < ArrayLen; i += 2 ) + { + u4Byte v1 = Array[i]; + u4Byte v2 = Array[i+1]; + + // This (offset, data) pair meets the condition. + if ( v1 < 0xCDCDCDCD ) + { + #ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + rtw_IOL_append_WD_cmd(pxmit_frame,(u2Byte)v1, v2,bMaskDWord); + } + else + #endif //#ifdef CONFIG_IOL_IOREG_CFG + { + odm_ConfigBB_AGC_8188E(pDM_Odm, v1, bMaskDWord, v2); + } + continue; + } + else + { // This line is the start line of branch. + if ( !CheckCondition(Array[i], hex) ) + { // Discard the following (offset, data) pairs. + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + i -= 2; // prevent from for-loop += 2 + } + else // Configure matched pairs and skip to end of if-else. + { + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + #ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + rtw_IOL_append_WD_cmd(pxmit_frame,(u2Byte)v1, v2,bMaskDWord); + } + else + #endif //#ifdef CONFIG_IOL_IOREG_CFG + { + odm_ConfigBB_AGC_8188E(pDM_Odm, v1, bMaskDWord, v2); + } + READ_NEXT_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + + } + } + } +#ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + //printk("==> %s, pktlen = %d,bndy_cnt = %d\n",__FUNCTION__,pxmit_frame->attrib.pktlen+4+32,bndy_cnt); + if(rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) + { + #ifdef CONFIG_IOL_IOREG_CFG_DBG + printk("~~~ %s Success !!! \n",__FUNCTION__); + { + //dump data from TX packet buffer + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + + } + else{ + printk("~~~ %s IOL_exec_cmds Failed !!! \n",__FUNCTION__); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + { + //dump data from TX packet buffer + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + + rst = HAL_STATUS_FAILURE; + } + } +#endif //#ifdef CONFIG_IOL_IOREG_CFG + return rst; +} + +/****************************************************************************** +* AGC_TAB_1T_ICUT.TXT +******************************************************************************/ + +u4Byte Array_MP_8188E_AGC_TAB_1T_ICUT[] = { + 0xC78, 0xFB000001, + 0xC78, 0xFB010001, + 0xC78, 0xFB020001, + 0xC78, 0xFB030001, + 0xC78, 0xFB040001, + 0xC78, 0xFA050001, + 0xC78, 0xF9060001, + 0xC78, 0xF8070001, + 0xC78, 0xF7080001, + 0xC78, 0xF6090001, + 0xC78, 0xF50A0001, + 0xC78, 0xF40B0001, + 0xC78, 0xF30C0001, + 0xC78, 0xF20D0001, + 0xC78, 0xF10E0001, + 0xC78, 0xF00F0001, + 0xC78, 0xEF100001, + 0xC78, 0xEE110001, + 0xC78, 0xED120001, + 0xC78, 0xEC130001, + 0xC78, 0xEB140001, + 0xC78, 0xEA150001, + 0xC78, 0xE9160001, + 0xC78, 0xE8170001, + 0xC78, 0xE7180001, + 0xC78, 0xE6190001, + 0xC78, 0xE51A0001, + 0xC78, 0xE41B0001, + 0xC78, 0xC71C0001, + 0xC78, 0xC61D0001, + 0xC78, 0xC51E0001, + 0xC78, 0xC41F0001, + 0xC78, 0xC3200001, + 0xC78, 0xC2210001, + 0xC78, 0x88220001, + 0xC78, 0x87230001, + 0xC78, 0x86240001, + 0xC78, 0x85250001, + 0xC78, 0x84260001, + 0xC78, 0x83270001, + 0xC78, 0x82280001, + 0xC78, 0x81290001, + 0xC78, 0x242A0001, + 0xC78, 0x232B0001, + 0xC78, 0x222C0001, + 0xC78, 0x672D0001, + 0xC78, 0x662E0001, + 0xC78, 0x652F0001, + 0xC78, 0x64300001, + 0xC78, 0x63310001, + 0xC78, 0x62320001, + 0xC78, 0x61330001, + 0xC78, 0x60340001, + 0xC78, 0x4A350001, + 0xC78, 0x49360001, + 0xC78, 0x48370001, + 0xC78, 0x47380001, + 0xC78, 0x46390001, + 0xC78, 0x453A0001, + 0xC78, 0x443B0001, + 0xC78, 0x433C0001, + 0xC78, 0x423D0001, + 0xC78, 0x413E0001, + 0xC78, 0x403F0001, + 0xC78, 0xFB400001, + 0xC78, 0xFB410001, + 0xC78, 0xFB420001, + 0xC78, 0xFB430001, + 0xC78, 0xFB440001, + 0xC78, 0xFB450001, + 0xC78, 0xFB460001, + 0xC78, 0xFB470001, + 0xC78, 0xFA480001, + 0xC78, 0xF9490001, + 0xC78, 0xF84A0001, + 0xC78, 0xF74B0001, + 0xC78, 0xF64C0001, + 0xC78, 0xF54D0001, + 0xC78, 0xF44E0001, + 0xC78, 0xF34F0001, + 0xC78, 0xF2500001, + 0xC78, 0xF1510001, + 0xC78, 0xF0520001, + 0xC78, 0xEF530001, + 0xC78, 0xEE540001, + 0xC78, 0xED550001, + 0xC78, 0xEC560001, + 0xC78, 0xEB570001, + 0xC78, 0xEA580001, + 0xC78, 0xE9590001, + 0xC78, 0xE85A0001, + 0xC78, 0xE75B0001, + 0xC78, 0xE65C0001, + 0xC78, 0xE55D0001, + 0xC78, 0xC65E0001, + 0xC78, 0xC55F0001, + 0xC78, 0xC4600001, + 0xC78, 0xC3610001, + 0xC78, 0xC2620001, + 0xC78, 0xC1630001, + 0xC78, 0xC0640001, + 0xC78, 0xA3650001, + 0xC78, 0xA2660001, + 0xC78, 0xA1670001, + 0xC78, 0x88680001, + 0xC78, 0x87690001, + 0xC78, 0x866A0001, + 0xC78, 0x856B0001, + 0xC78, 0x846C0001, + 0xC78, 0x836D0001, + 0xC78, 0x826E0001, + 0xC78, 0x666F0001, + 0xC78, 0x65700001, + 0xC78, 0x64710001, + 0xC78, 0x63720001, + 0xC78, 0x62730001, + 0xC78, 0x61740001, + 0xC78, 0x48750001, + 0xC78, 0x47760001, + 0xC78, 0x46770001, + 0xC78, 0x45780001, + 0xC78, 0x44790001, + 0xC78, 0x437A0001, + 0xC78, 0x427B0001, + 0xC78, 0x417C0001, + 0xC78, 0x407D0001, + 0xC78, 0x407E0001, + 0xC78, 0x407F0001, + 0xC50, 0x69553422, + 0xC50, 0x69553420, + +}; + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_AGC_TAB_1T_ICUT( + IN PDM_ODM_T pDM_Odm + ) +{ + #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) + + u4Byte hex = 0; + u4Byte i = 0; + u2Byte count = 0; + pu4Byte ptr_array = NULL; + u1Byte platform = pDM_Odm->SupportPlatform; + u1Byte _interface = pDM_Odm->SupportInterface; + u1Byte board = pDM_Odm->BoardType; + u4Byte ArrayLen = sizeof(Array_MP_8188E_AGC_TAB_1T_ICUT)/sizeof(u4Byte); + pu4Byte Array = Array_MP_8188E_AGC_TAB_1T_ICUT; + BOOLEAN biol = FALSE; +#ifdef CONFIG_IOL_IOREG_CFG + PADAPTER Adapter = pDM_Odm->Adapter; + struct xmit_frame *pxmit_frame; + u8 bndy_cnt=1; +#endif//#ifdef CONFIG_IOL_IOREG_CFG + HAL_STATUS rst =HAL_STATUS_SUCCESS; + + hex += board; + hex += _interface << 8; + hex += platform << 16; + hex += 0xFF000000; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_8188E_AGC_TAB_1T_ICUT, hex = 0x%X\n", hex)); +#ifdef CONFIG_IOL_IOREG_CFG + biol = rtw_IOL_applied(Adapter); + + if(biol){ + if((pxmit_frame= rtw_IOL_accquire_xmit_frame(Adapter)) == NULL){ + printk("rtw_IOL_accquire_xmit_frame failed\n"); + return HAL_STATUS_FAILURE; + } + } +#endif//#ifdef CONFIG_IOL_IOREG_CFG + + for (i = 0; i < ArrayLen; i += 2 ) + { + u4Byte v1 = Array[i]; + u4Byte v2 = Array[i+1]; + + // This (offset, data) pair meets the condition. + if ( v1 < 0xCDCDCDCD ) + { + #ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + rtw_IOL_append_WD_cmd(pxmit_frame,(u2Byte)v1, v2,bMaskDWord); + } + else + #endif //#ifdef CONFIG_IOL_IOREG_CFG + { + odm_ConfigBB_AGC_8188E(pDM_Odm, v1, bMaskDWord, v2); + } + continue; + } + else + { // This line is the start line of branch. + if ( !CheckCondition(Array[i], hex) ) + { // Discard the following (offset, data) pairs. + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + i -= 2; // prevent from for-loop += 2 + } + else // Configure matched pairs and skip to end of if-else. + { + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + #ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + rtw_IOL_append_WD_cmd(pxmit_frame,(u2Byte)v1, v2,bMaskDWord); + } + else + #endif //#ifdef CONFIG_IOL_IOREG_CFG + { + odm_ConfigBB_AGC_8188E(pDM_Odm, v1, bMaskDWord, v2); + } + READ_NEXT_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + + } + } + } +#ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + //printk("==> %s, pktlen = %d,bndy_cnt = %d\n",__FUNCTION__,pxmit_frame->attrib.pktlen+4+32,bndy_cnt); + if(rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) + { + #ifdef CONFIG_IOL_IOREG_CFG_DBG + printk("~~~ %s Success !!! \n",__FUNCTION__); + { + //dump data from TX packet buffer + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + + } + else{ + printk("~~~ %s IOL_exec_cmds Failed !!! \n",__FUNCTION__); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + { + //dump data from TX packet buffer + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + + rst = HAL_STATUS_FAILURE; + } + } +#endif //#ifdef CONFIG_IOL_IOREG_CFG + return rst; +} + +/****************************************************************************** +* PHY_REG_1T.TXT +******************************************************************************/ + +u4Byte Array_MP_8188E_PHY_REG_1T[] = { + 0x800, 0x80040000, + 0x804, 0x00000003, + 0x808, 0x0000FC00, + 0x80C, 0x0000000A, + 0x810, 0x10001331, + 0x814, 0x020C3D10, + 0x818, 0x02200385, + 0x81C, 0x00000000, + 0x820, 0x01000100, + 0x824, 0x00390204, + 0x828, 0x00000000, + 0x82C, 0x00000000, + 0x830, 0x00000000, + 0x834, 0x00000000, + 0x838, 0x00000000, + 0x83C, 0x00000000, + 0x840, 0x00010000, + 0x844, 0x00000000, + 0x848, 0x00000000, + 0x84C, 0x00000000, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x569A11A9, + 0x85C, 0x01000014, + 0x860, 0x66F60110, + 0x864, 0x061F0649, + 0x868, 0x00000000, + 0x86C, 0x27272700, + 0xFF0F0718, 0xABCD, + 0x870, 0x07000300, + 0xCDCDCDCD, 0xCDCD, + 0x870, 0x07000760, + 0xFF0F0718, 0xDEAD, + 0x874, 0x25004000, + 0x878, 0x00000808, + 0x87C, 0x00000000, + 0x880, 0xB0000C1C, + 0x884, 0x00000001, + 0x888, 0x00000000, + 0x88C, 0xCCC000C0, + 0x890, 0x00000800, + 0x894, 0xFFFFFFFE, + 0x898, 0x40302010, + 0x89C, 0x00706050, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90C, 0x81121111, + 0x910, 0x00000002, + 0x914, 0x00000201, + 0xA00, 0x00D047C8, + 0xA04, 0x80FF000C, + 0xA08, 0x8C838300, + 0xA0C, 0x2E7F120F, + 0xA10, 0x9500BB78, + 0xA14, 0x1114D028, + 0xA18, 0x00881117, + 0xA1C, 0x89140F00, + 0xFF0F0718, 0xABCD, + 0xA20, 0x13130000, + 0xA24, 0x060A0D10, + 0xA28, 0x00000103, + 0xCDCDCDCD, 0xCDCD, + 0xA20, 0x1A1B0000, + 0xA24, 0x090E1317, + 0xA28, 0x00000204, + 0xFF0F0718, 0xDEAD, + 0xA2C, 0x00D30000, + 0xA70, 0x101FBF00, + 0xA74, 0x00000007, + 0xA78, 0x00000900, + 0xA7C, 0x225B0606, + 0xA80, 0x218075B1, + 0xFF0F0718, 0xABCD, + 0xB2C, 0x00000000, + 0xCDCDCDCD, 0xCDCD, + 0xB2C, 0x80000000, + 0xFF0F0718, 0xDEAD, + 0xC00, 0x48071D40, + 0xC04, 0x03A05611, + 0xC08, 0x000000E4, + 0xC0C, 0x6C6C6C6C, + 0xC10, 0x08800000, + 0xC14, 0x40000100, + 0xC18, 0x08800000, + 0xC1C, 0x40000100, + 0xC20, 0x00000000, + 0xC24, 0x00000000, + 0xC28, 0x00000000, + 0xC2C, 0x00000000, + 0xC30, 0x69E9AC47, + 0xC34, 0x469652AF, + 0xC38, 0x49795994, + 0xC3C, 0x0A97971C, + 0xC40, 0x1F7C403F, + 0xC44, 0x000100B7, + 0xC48, 0xEC020107, + 0xC4C, 0x007F037F, + 0xC50, 0x69553420, + 0xC54, 0x43BC0094, + 0xC58, 0x00013169, + 0xC5C, 0x00250492, + 0xC60, 0x00000000, + 0xC64, 0x7112848B, + 0xC68, 0x47C00BFF, + 0xC6C, 0x00000036, + 0xC70, 0x2C7F000D, + 0xC74, 0x020610DB, + 0xC78, 0x0000001F, + 0xC7C, 0x00B91612, + 0xFF0F0718, 0xABCD, + 0xC80, 0x2D4000B5, + 0xCDCDCDCD, 0xCDCD, + 0xC80, 0x390000E4, + 0xFF0F0718, 0xDEAD, + 0xC84, 0x20F60000, + 0xC88, 0x40000100, + 0xC8C, 0x20200000, + 0xC90, 0x00091521, + 0xC94, 0x00000000, + 0xC98, 0x00121820, + 0xC9C, 0x00007F7F, + 0xCA0, 0x00000000, + 0xCA4, 0x000300A0, + 0xCA8, 0x00000000, + 0xCAC, 0x00000000, + 0xCB0, 0x00000000, + 0xCB4, 0x00000000, + 0xCB8, 0x00000000, + 0xCBC, 0x28000000, + 0xCC0, 0x00000000, + 0xCC4, 0x00000000, + 0xCC8, 0x00000000, + 0xCCC, 0x00000000, + 0xCD0, 0x00000000, + 0xCD4, 0x00000000, + 0xCD8, 0x64B22427, + 0xCDC, 0x00766932, + 0xCE0, 0x00222222, + 0xCE4, 0x00000000, + 0xCE8, 0x37644302, + 0xCEC, 0x2F97D40C, + 0xD00, 0x00000740, + 0xD04, 0x00020401, + 0xD08, 0x0000907F, + 0xD0C, 0x20010201, + 0xD10, 0xA0633333, + 0xD14, 0x3333BC43, + 0xD18, 0x7A8F5B6F, + 0xD2C, 0xCC979975, + 0xD30, 0x00000000, + 0xD34, 0x80608000, + 0xD38, 0x00000000, + 0xD3C, 0x00127353, + 0xD40, 0x00000000, + 0xD44, 0x00000000, + 0xD48, 0x00000000, + 0xD4C, 0x00000000, + 0xD50, 0x6437140A, + 0xD54, 0x00000000, + 0xD58, 0x00000282, + 0xD5C, 0x30032064, + 0xD60, 0x4653DE68, + 0xD64, 0x04518A3C, + 0xD68, 0x00002101, + 0xD6C, 0x2A201C16, + 0xD70, 0x1812362E, + 0xD74, 0x322C2220, + 0xD78, 0x000E3C24, + 0xE00, 0x2D2D2D2D, + 0xE04, 0x2D2D2D2D, + 0xE08, 0x0390272D, + 0xE10, 0x2D2D2D2D, + 0xE14, 0x2D2D2D2D, + 0xE18, 0x2D2D2D2D, + 0xE1C, 0x2D2D2D2D, + 0xE28, 0x00000000, + 0xE30, 0x1000DC1F, + 0xE34, 0x10008C1F, + 0xE38, 0x02140102, + 0xE3C, 0x681604C2, + 0xE40, 0x01007C00, + 0xE44, 0x01004800, + 0xE48, 0xFB000000, + 0xE4C, 0x000028D1, + 0xE50, 0x1000DC1F, + 0xE54, 0x10008C1F, + 0xE58, 0x02140102, + 0xE5C, 0x28160D05, + 0xE60, 0x00000008, + 0xE68, 0x001B25A4, + 0xE6C, 0x00C00014, + 0xE70, 0x00C00014, + 0xE74, 0x01000014, + 0xE78, 0x01000014, + 0xE7C, 0x01000014, + 0xE80, 0x01000014, + 0xE84, 0x00C00014, + 0xE88, 0x01000014, + 0xE8C, 0x00C00014, + 0xED0, 0x00C00014, + 0xED4, 0x00C00014, + 0xED8, 0x00C00014, + 0xEDC, 0x00000014, + 0xEE0, 0x00000014, + 0xFF0F0718, 0xABCD, + 0xEE8, 0x32555448, + 0xCDCDCDCD, 0xCDCD, + 0xEE8, 0x21555448, + 0xFF0F0718, 0xDEAD, + 0xEEC, 0x01C00014, + 0xF14, 0x00000003, + 0xF4C, 0x00000000, + 0xF00, 0x00000300, + +}; + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_PHY_REG_1T( + IN PDM_ODM_T pDM_Odm + ) +{ + #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) + + u4Byte hex = 0; + u4Byte i = 0; + u2Byte count = 0; + pu4Byte ptr_array = NULL; + u1Byte platform = pDM_Odm->SupportPlatform; + u1Byte _interface = pDM_Odm->SupportInterface; + u1Byte board = pDM_Odm->BoardType; + u4Byte ArrayLen = sizeof(Array_MP_8188E_PHY_REG_1T)/sizeof(u4Byte); + pu4Byte Array = Array_MP_8188E_PHY_REG_1T; + BOOLEAN biol = FALSE; +#ifdef CONFIG_IOL_IOREG_CFG + PADAPTER Adapter = pDM_Odm->Adapter; + struct xmit_frame *pxmit_frame; + u8 bndy_cnt=1; + #ifdef CONFIG_IOL_IOREG_CFG_DBG + struct cmd_cmp cmpdata[ArrayLen]; + u4Byte cmpdata_idx=0; + #endif +#endif//#ifdef CONFIG_IOL_IOREG_CFG + HAL_STATUS rst =HAL_STATUS_SUCCESS; + + hex += board; + hex += _interface << 8; + hex += platform << 16; + hex += 0xFF000000; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_8188E_PHY_REG_1T, hex = 0x%X\n", hex)); +#ifdef CONFIG_IOL_IOREG_CFG + biol = rtw_IOL_applied(Adapter); + + if(biol){ + if((pxmit_frame=rtw_IOL_accquire_xmit_frame(Adapter)) == NULL) + { + printk("rtw_IOL_accquire_xmit_frame failed\n"); + return HAL_STATUS_FAILURE; + } + } +#endif//#ifdef CONFIG_IOL_IOREG_CFG + + for (i = 0; i < ArrayLen; i += 2 ) + { + u4Byte v1 = Array[i]; + u4Byte v2 = Array[i+1]; + + // This (offset, data) pair meets the condition. + if ( v1 < 0xCDCDCDCD ) + { + #ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + + + if (v1 == 0xfe){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,50); + } + else if (v1 == 0xfd){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,5); + } + else if (v1 == 0xfc){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,1); + } + else if (v1 == 0xfb){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,50); + } + else if (v1 == 0xfa){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5); + } + else if (v1 == 0xf9){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,1); + } + else{ + if (v1 == 0xa24) + pDM_Odm->RFCalibrateInfo.RegA24 = v2; + + rtw_IOL_append_WD_cmd(pxmit_frame,(u2Byte)v1, v2,bMaskDWord); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + cmpdata[cmpdata_idx].addr = v1; + cmpdata[cmpdata_idx].value= v2; + cmpdata_idx++; + #endif + } + } + else + #endif //#ifdef CONFIG_IOL_IOREG_CFG + { + odm_ConfigBB_PHY_8188E(pDM_Odm, v1, bMaskDWord, v2); + } + continue; + } + else + { // This line is the start line of branch. + if ( !CheckCondition(Array[i], hex) ) + { // Discard the following (offset, data) pairs. + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + i -= 2; // prevent from for-loop += 2 + } + else // Configure matched pairs and skip to end of if-else. + { + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + #ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + if (v1 == 0xfe){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,50); + } + else if (v1 == 0xfd){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,5); + } + else if (v1 == 0xfc){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,1); + } + else if (v1 == 0xfb){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,50); + } + else if (v1 == 0xfa){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,5); + } + else if (v1 == 0xf9){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,1); + } + else{ + if (v1 == 0xa24) + pDM_Odm->RFCalibrateInfo.RegA24 = v2; + + rtw_IOL_append_WD_cmd(pxmit_frame,(u2Byte)v1, v2,bMaskDWord); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + cmpdata[cmpdata_idx].addr = v1; + cmpdata[cmpdata_idx].value= v2; + cmpdata_idx++; + #endif + } + } + else + #endif //#ifdef CONFIG_IOL_IOREG_CFG + { + odm_ConfigBB_PHY_8188E(pDM_Odm, v1, bMaskDWord, v2); + } + READ_NEXT_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + + } + } + } +#ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + //printk("==> %s, pktlen = %d,bndy_cnt = %d\n",__FUNCTION__,pxmit_frame->attrib.pktlen+4+32,bndy_cnt); + if(rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) + { + #ifdef CONFIG_IOL_IOREG_CFG_DBG + printk("~~~ %s IOL_exec_cmds Success !!! \n",__FUNCTION__); + { + u4Byte idx; + u4Byte cdata; + printk(" %s data compare => array_len:%d \n",__FUNCTION__,cmpdata_idx); + printk("### %s data compared !!###\n",__FUNCTION__); + for(idx=0;idx< cmpdata_idx;idx++) + { + cdata = ODM_Read4Byte(pDM_Odm, cmpdata[idx].addr); + if(cdata != cmpdata[idx].value){ + printk(" addr:0x%04x, data:(0x%02x : 0x%02x) \n", + cmpdata[idx].addr,cmpdata[idx].value,cdata); + rst = HAL_STATUS_FAILURE; + } + } + printk("### %s data compared !!###\n",__FUNCTION__); + //if(rst == HAL_STATUS_FAILURE) + {//dump data from TX packet buffer + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + + } + else{ + rst = HAL_STATUS_FAILURE; + printk("~~~ IOL Config %s Failed !!! \n",__FUNCTION__); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + { + //dump data from TX packet buffer + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + } + } +#endif //#ifdef CONFIG_IOL_IOREG_CFG + return rst; +} + +/****************************************************************************** +* PHY_REG_1T_ICUT.TXT +******************************************************************************/ + +u4Byte Array_MP_8188E_PHY_REG_1T_ICUT[] = { + 0x800, 0x80040000, + 0x804, 0x00000003, + 0x808, 0x0000FC00, + 0x80C, 0x0000000A, + 0x810, 0x10001331, + 0x814, 0x020C3D10, + 0x818, 0x02200385, + 0x81C, 0x00000000, + 0x820, 0x01000100, + 0x824, 0x00390204, + 0x828, 0x00000000, + 0x82C, 0x00000000, + 0x830, 0x00000000, + 0x834, 0x00000000, + 0x838, 0x00000000, + 0x83C, 0x00000000, + 0x840, 0x00010000, + 0x844, 0x00000000, + 0x848, 0x00000000, + 0x84C, 0x00000000, + 0x850, 0x00000000, + 0x854, 0x00000000, + 0x858, 0x569A11A9, + 0x85C, 0x01000014, + 0x860, 0x66F60110, + 0x864, 0x061F0649, + 0x868, 0x00000000, + 0x86C, 0x27272700, + 0x870, 0x07000760, + 0x874, 0x25004000, + 0x878, 0x00000808, + 0x87C, 0x00000000, + 0x880, 0xB0000C1C, + 0x884, 0x00000001, + 0x888, 0x00000000, + 0x88C, 0xCCC000C0, + 0x890, 0x00000800, + 0x894, 0xFFFFFFFE, + 0x898, 0x40302010, + 0x89C, 0x00706050, + 0x900, 0x00000000, + 0x904, 0x00000023, + 0x908, 0x00000000, + 0x90C, 0x81121111, + 0x910, 0x00000002, + 0x914, 0x00000201, + 0xA00, 0x00D047C8, + 0xA04, 0x80FF000C, + 0xA08, 0x8C838300, + 0xA0C, 0x2E7F120F, + 0xA10, 0x9500BB78, + 0xA14, 0x1114D028, + 0xA18, 0x00881117, + 0xA1C, 0x89140F00, + 0xA20, 0x1A1B0000, + 0xA24, 0x090E1317, + 0xA28, 0x00000204, + 0xA2C, 0x00D30000, + 0xA70, 0x101FBF00, + 0xA74, 0x00000007, + 0xA78, 0x00000900, + 0xA7C, 0x225B0606, + 0xA80, 0x218075B1, + 0xB2C, 0x80000000, + 0xC00, 0x48071D40, + 0xC04, 0x03A05611, + 0xC08, 0x000000E4, + 0xC0C, 0x6C6C6C6C, + 0xC10, 0x08800000, + 0xC14, 0x40000100, + 0xC18, 0x08800000, + 0xC1C, 0x40000100, + 0xC20, 0x00000000, + 0xC24, 0x00000000, + 0xC28, 0x00000000, + 0xC2C, 0x00000000, + 0xC30, 0x69E9AC47, + 0xC34, 0x469652AF, + 0xC38, 0x49795994, + 0xC3C, 0x0A97971C, + 0xC40, 0x1F7C403F, + 0xC44, 0x000100B7, + 0xC48, 0xEC020107, + 0xC4C, 0x007F037F, + 0xC50, 0x69553420, + 0xC54, 0x43BC0094, + 0xC58, 0x00013159, + 0xC5C, 0x00250492, + 0xC60, 0x00000000, + 0xC64, 0x7112848B, + 0xC68, 0x47C00BFF, + 0xC6C, 0x00000036, + 0xC70, 0x2C7F000D, + 0xC74, 0x028610DB, + 0xC78, 0x0000001F, + 0xC7C, 0x00B91612, + 0xC80, 0x390000E4, + 0xC84, 0x20F60000, + 0xC88, 0x40000100, + 0xC8C, 0x20200000, + 0xC90, 0x00091521, + 0xC94, 0x00000000, + 0xC98, 0x00121820, + 0xC9C, 0x00007F7F, + 0xCA0, 0x00000000, + 0xCA4, 0x000300A0, + 0xCA8, 0xFFFF0000, + 0xCAC, 0x00000000, + 0xCB0, 0x00000000, + 0xCB4, 0x00000000, + 0xCB8, 0x00000000, + 0xCBC, 0x28000000, + 0xCC0, 0x00000000, + 0xCC4, 0x00000000, + 0xCC8, 0x00000000, + 0xCCC, 0x00000000, + 0xCD0, 0x00000000, + 0xCD4, 0x00000000, + 0xCD8, 0x64B22427, + 0xCDC, 0x00766932, + 0xCE0, 0x00222222, + 0xCE4, 0x00000000, + 0xCE8, 0x37644302, + 0xCEC, 0x2F97D40C, + 0xD00, 0x00000740, + 0xD04, 0x00020401, + 0xD08, 0x0000907F, + 0xD0C, 0x20010201, + 0xD10, 0xA0633333, + 0xD14, 0x3333BC43, + 0xD18, 0x7A8F5B6F, + 0xD2C, 0xCC979975, + 0xD30, 0x00000000, + 0xD34, 0x80608000, + 0xD38, 0x00000000, + 0xD3C, 0x00127353, + 0xD40, 0x00000000, + 0xD44, 0x00000000, + 0xD48, 0x00000000, + 0xD4C, 0x00000000, + 0xD50, 0x6437140A, + 0xD54, 0x00000000, + 0xD58, 0x00000282, + 0xD5C, 0x30032064, + 0xD60, 0x4653DE68, + 0xD64, 0x04518A3C, + 0xD68, 0x00002101, + 0xD6C, 0x2A201C16, + 0xD70, 0x1812362E, + 0xD74, 0x322C2220, + 0xD78, 0x000E3C24, + 0xE00, 0x2D2D2D2D, + 0xE04, 0x2D2D2D2D, + 0xE08, 0x0390272D, + 0xE10, 0x2D2D2D2D, + 0xE14, 0x2D2D2D2D, + 0xE18, 0x2D2D2D2D, + 0xE1C, 0x2D2D2D2D, + 0xE28, 0x00000000, + 0xE30, 0x1000DC1F, + 0xE34, 0x10008C1F, + 0xE38, 0x02140102, + 0xE3C, 0x681604C2, + 0xE40, 0x01007C00, + 0xE44, 0x01004800, + 0xE48, 0xFB000000, + 0xE4C, 0x000028D1, + 0xE50, 0x1000DC1F, + 0xE54, 0x10008C1F, + 0xE58, 0x02140102, + 0xE5C, 0x28160D05, + 0xE60, 0x00000008, + 0xE68, 0x001B25A4, + 0xE6C, 0x00C00014, + 0xE70, 0x00C00014, + 0xE74, 0x01000014, + 0xE78, 0x01000014, + 0xE7C, 0x01000014, + 0xE80, 0x01000014, + 0xE84, 0x00C00014, + 0xE88, 0x01000014, + 0xE8C, 0x00C00014, + 0xED0, 0x00C00014, + 0xED4, 0x00C00014, + 0xED8, 0x00C00014, + 0xEDC, 0x00000014, + 0xEE0, 0x00000014, + 0xEEC, 0x01C00014, + 0xF14, 0x00000003, + 0xF4C, 0x00000000, + 0xF00, 0x00000300, + +}; + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_PHY_REG_1T_ICUT( + IN PDM_ODM_T pDM_Odm + ) +{ + #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) + + u4Byte hex = 0; + u4Byte i = 0; + u2Byte count = 0; + pu4Byte ptr_array = NULL; + u1Byte platform = pDM_Odm->SupportPlatform; + u1Byte _interface = pDM_Odm->SupportInterface; + u1Byte board = pDM_Odm->BoardType; + u4Byte ArrayLen = sizeof(Array_MP_8188E_PHY_REG_1T_ICUT)/sizeof(u4Byte); + pu4Byte Array = Array_MP_8188E_PHY_REG_1T_ICUT; + BOOLEAN biol = FALSE; +#ifdef CONFIG_IOL_IOREG_CFG + PADAPTER Adapter = pDM_Odm->Adapter; + struct xmit_frame *pxmit_frame; + u8 bndy_cnt=1; + #ifdef CONFIG_IOL_IOREG_CFG_DBG + struct cmd_cmp cmpdata[ArrayLen]; + u4Byte cmpdata_idx=0; + #endif +#endif//#ifdef CONFIG_IOL_IOREG_CFG + HAL_STATUS rst =HAL_STATUS_SUCCESS; + + hex += board; + hex += _interface << 8; + hex += platform << 16; + hex += 0xFF000000; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_8188E_PHY_REG_1T_ICUT, hex = 0x%X\n", hex)); +#ifdef CONFIG_IOL_IOREG_CFG + biol = rtw_IOL_applied(Adapter); + + if(biol){ + if((pxmit_frame=rtw_IOL_accquire_xmit_frame(Adapter)) == NULL) + { + printk("rtw_IOL_accquire_xmit_frame failed\n"); + return HAL_STATUS_FAILURE; + } + } +#endif//#ifdef CONFIG_IOL_IOREG_CFG + + for (i = 0; i < ArrayLen; i += 2 ) + { + u4Byte v1 = Array[i]; + u4Byte v2 = Array[i+1]; + + // This (offset, data) pair meets the condition. + if ( v1 < 0xCDCDCDCD ) + { + #ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + + + if (v1 == 0xfe){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,50); + } + else if (v1 == 0xfd){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,5); + } + else if (v1 == 0xfc){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,1); + } + else if (v1 == 0xfb){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,50); + } + else if (v1 == 0xfa){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame, 5); + } + else if (v1 == 0xf9){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,1); + } + else{ + if (v1 == 0xa24) + pDM_Odm->RFCalibrateInfo.RegA24 = v2; + + rtw_IOL_append_WD_cmd(pxmit_frame,(u2Byte)v1, v2,bMaskDWord); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + cmpdata[cmpdata_idx].addr = v1; + cmpdata[cmpdata_idx].value= v2; + cmpdata_idx++; + #endif + } + } + else + #endif //#ifdef CONFIG_IOL_IOREG_CFG + { + odm_ConfigBB_PHY_8188E(pDM_Odm, v1, bMaskDWord, v2); + } + continue; + } + else + { // This line is the start line of branch. + if ( !CheckCondition(Array[i], hex) ) + { // Discard the following (offset, data) pairs. + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + i -= 2; // prevent from for-loop += 2 + } + else // Configure matched pairs and skip to end of if-else. + { + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + #ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + if (v1 == 0xfe){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,50); + } + else if (v1 == 0xfd){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,5); + } + else if (v1 == 0xfc){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,1); + } + else if (v1 == 0xfb){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,50); + } + else if (v1 == 0xfa){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,5); + } + else if (v1 == 0xf9){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,1); + } + else{ + if (v1 == 0xa24) + pDM_Odm->RFCalibrateInfo.RegA24 = v2; + + rtw_IOL_append_WD_cmd(pxmit_frame,(u2Byte)v1, v2,bMaskDWord); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + cmpdata[cmpdata_idx].addr = v1; + cmpdata[cmpdata_idx].value= v2; + cmpdata_idx++; + #endif + } + } + else + #endif //#ifdef CONFIG_IOL_IOREG_CFG + { + odm_ConfigBB_PHY_8188E(pDM_Odm, v1, bMaskDWord, v2); + } + READ_NEXT_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + + } + } + } +#ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + //printk("==> %s, pktlen = %d,bndy_cnt = %d\n",__FUNCTION__,pxmit_frame->attrib.pktlen+4+32,bndy_cnt); + if(rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) + { + #ifdef CONFIG_IOL_IOREG_CFG_DBG + printk("~~~ %s IOL_exec_cmds Success !!! \n",__FUNCTION__); + { + u4Byte idx; + u4Byte cdata; + printk(" %s data compare => array_len:%d \n",__FUNCTION__,cmpdata_idx); + printk("### %s data compared !!###\n",__FUNCTION__); + for(idx=0;idx< cmpdata_idx;idx++) + { + cdata = ODM_Read4Byte(pDM_Odm, cmpdata[idx].addr); + if(cdata != cmpdata[idx].value){ + printk(" addr:0x%04x, data:(0x%02x : 0x%02x) \n", + cmpdata[idx].addr,cmpdata[idx].value,cdata); + rst = HAL_STATUS_FAILURE; + } + } + printk("### %s data compared !!###\n",__FUNCTION__); + //if(rst == HAL_STATUS_FAILURE) + {//dump data from TX packet buffer + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + + } + else{ + rst = HAL_STATUS_FAILURE; + printk("~~~ IOL Config %s Failed !!! \n",__FUNCTION__); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + { + //dump data from TX packet buffer + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + } + } +#endif //#ifdef CONFIG_IOL_IOREG_CFG + return rst; +} + +/****************************************************************************** +* PHY_REG_PG.TXT +******************************************************************************/ + +u4Byte Array_MP_8188E_PHY_REG_PG[] = { + 0, 0, 0, 0x00000e08, 0x0000ff00, 0x00004000, + 0, 0, 0, 0x0000086c, 0xffffff00, 0x34363800, + 0, 0, 0, 0x00000e00, 0xffffffff, 0x42444646, + 0, 0, 0, 0x00000e04, 0xffffffff, 0x30343840, + 0, 0, 0, 0x00000e10, 0xffffffff, 0x38404244, + 0, 0, 0, 0x00000e14, 0xffffffff, 0x26303436 +}; + +void +ODM_ReadAndConfig_MP_8188E_PHY_REG_PG( + IN PDM_ODM_T pDM_Odm + ) +{ + u4Byte hex = 0; + u4Byte i = 0; + u2Byte count = 0; + pu4Byte ptr_array = NULL; + u1Byte platform = pDM_Odm->SupportPlatform; + u1Byte _interface = pDM_Odm->SupportInterface; + u1Byte board = pDM_Odm->BoardType; + u4Byte ArrayLen = sizeof(Array_MP_8188E_PHY_REG_PG)/sizeof(u4Byte); + pu4Byte Array = Array_MP_8188E_PHY_REG_PG; + + pDM_Odm->PhyRegPgVersion = 1; + pDM_Odm->PhyRegPgValueType = PHY_REG_PG_EXACT_VALUE; + hex += board; + hex += _interface << 8; + hex += platform << 16; + hex += 0xFF000000; + for (i = 0; i < ArrayLen; i += 6 ) + { + u4Byte v1 = Array[i]; + u4Byte v2 = Array[i+1]; + u4Byte v3 = Array[i+2]; + u4Byte v4 = Array[i+3]; + u4Byte v5 = Array[i+4]; + u4Byte v6 = Array[i+5]; + + // this line is a line of pure_body + if ( v1 < 0xCDCDCDCD ) + { + odm_ConfigBB_PHY_REG_PG_8188E(pDM_Odm, v1, v2, v3, v4, v5, v6); + continue; + } + else + { // this line is the start of branch + if ( !CheckCondition(Array[i], hex) ) + { // don't need the hw_body + i += 2; // skip the pair of expression + v1 = Array[i]; + v2 = Array[i+1]; + v3 = Array[i+2]; + while (v2 != 0xDEAD) + { + i += 3; + v1 = Array[i]; + v2 = Array[i+1]; + v3 = Array[i+1]; + } + } + } + } +} + + + +#endif // end of HWIMG_SUPPORT + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.h new file mode 100644 index 0000000..8f3e09b --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_BB.h @@ -0,0 +1,74 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + +#if (RTL8188E_SUPPORT == 1) +#ifndef __INC_MP_BB_HW_IMG_8188E_H +#define __INC_MP_BB_HW_IMG_8188E_H + +//static BOOLEAN CheckCondition(const u4Byte Condition, const u4Byte Hex); + +/****************************************************************************** +* AGC_TAB_1T.TXT +******************************************************************************/ + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_AGC_TAB_1T( // TC: Test Chip, MP: MP Chip + IN PDM_ODM_T pDM_Odm +); + +/****************************************************************************** +* AGC_TAB_1T_ICUT.TXT +******************************************************************************/ + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_AGC_TAB_1T_ICUT( // TC: Test Chip, MP: MP Chip + IN PDM_ODM_T pDM_Odm +); + +/****************************************************************************** +* PHY_REG_1T.TXT +******************************************************************************/ + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_PHY_REG_1T( // TC: Test Chip, MP: MP Chip + IN PDM_ODM_T pDM_Odm +); + +/****************************************************************************** +* PHY_REG_1T_ICUT.TXT +******************************************************************************/ + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_PHY_REG_1T_ICUT( // TC: Test Chip, MP: MP Chip + IN PDM_ODM_T pDM_Odm +); + +/****************************************************************************** +* PHY_REG_PG.TXT +******************************************************************************/ + +void +ODM_ReadAndConfig_MP_8188E_PHY_REG_PG( // TC: Test Chip, MP: MP Chip + IN PDM_ODM_T pDM_Odm +); + +#endif +#endif // end of HWIMG_SUPPORT + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.c new file mode 100644 index 0000000..5e23988 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.c @@ -0,0 +1,5010 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + + +#include "../odm_precomp.h" + +#if (RTL8188E_SUPPORT == 1) +#if(DM_ODM_SUPPORT_TYPE & (ODM_AP)) + + +u1Byte Array_MP_8188E_FW_AP[] = { +0x00, 0x95, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x18, 0x19, 0x12, 0x5A, 0x3B, 0x00, 0x00, +0x18, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x02, 0x49, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x02, 0x59, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x02, 0x59, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x5F, 0xDD, 0x00, 0x00, +0x0F, 0xF0, 0x8F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x05, 0xF0, +0x8F, 0x0F, 0x00, 0x00, 0x00, 0x05, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xF0, 0x8F, 0x0F, +0x00, 0x00, 0x00, 0x0A, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF5, 0x0F, 0x00, 0x00, 0x00, 0x00, +0x00, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, +0x04, 0x03, 0x02, 0x00, 0x03, 0x06, 0x05, 0x04, 0x03, 0x00, 0x04, 0x06, 0x05, 0x04, 0x02, 0x00, +0x04, 0x08, 0x07, 0x06, 0x04, 0x00, 0x06, 0x0A, 0x09, 0x08, 0x06, 0x00, 0x08, 0x0A, 0x09, 0x08, +0x04, 0x00, 0x08, 0x0A, 0x09, 0x08, 0x02, 0x00, 0x08, 0x0A, 0x09, 0x08, 0x00, 0x00, 0x08, 0x12, +0x11, 0x10, 0x08, 0x00, 0x10, 0x1A, 0x19, 0x18, 0x10, 0x00, 0x18, 0x22, 0x21, 0x20, 0x18, 0x00, +0x20, 0x22, 0x21, 0x20, 0x10, 0x00, 0x20, 0x22, 0x21, 0x20, 0x08, 0x00, 0x20, 0x22, 0x21, 0x1C, +0x08, 0x00, 0x20, 0x22, 0x21, 0x14, 0x08, 0x00, 0x20, 0x22, 0x20, 0x18, 0x08, 0x00, 0x20, 0x31, +0x30, 0x20, 0x10, 0x00, 0x30, 0x31, 0x30, 0x18, 0x00, 0x00, 0x30, 0x31, 0x2F, 0x10, 0x10, 0x00, +0x30, 0x31, 0x2C, 0x10, 0x10, 0x00, 0x30, 0x31, 0x28, 0x10, 0x00, 0x00, 0x30, 0x31, 0x20, 0x10, +0x00, 0x00, 0x30, 0x31, 0x10, 0x10, 0x00, 0x00, 0x30, 0x04, 0x04, 0x04, 0x05, 0x04, 0x04, 0x05, +0x07, 0x07, 0x07, 0x08, 0x0A, 0x04, 0x04, 0x04, 0x04, 0x06, 0x0A, 0x0B, 0x0D, 0x05, 0x05, 0x07, +0x07, 0x08, 0x0B, 0x0D, 0x0F, 0x05, 0x05, 0x07, 0x07, 0x08, 0x0B, 0x0D, 0x0F, 0x05, 0x05, 0x07, +0x07, 0x08, 0x0B, 0x0D, 0x0F, 0x05, 0x05, 0x07, 0x07, 0x08, 0x0B, 0x0D, 0x0F, 0x0F, 0x0F, 0x05, +0x05, 0x07, 0x07, 0x08, 0x0B, 0x0D, 0x0F, 0x0F, 0x0F, 0x05, 0x05, 0x07, 0x07, 0x08, 0x0B, 0x0D, +0x0F, 0x0F, 0x0F, 0x05, 0x05, 0x07, 0x07, 0x08, 0x0B, 0x0D, 0x0F, 0x0F, 0x0F, 0x04, 0x04, 0x04, +0x05, 0x07, 0x07, 0x09, 0x09, 0x0C, 0x0E, 0x10, 0x12, 0x04, 0x04, 0x05, 0x05, 0x06, 0x0A, 0x11, +0x13, 0x09, 0x09, 0x09, 0x09, 0x0C, 0x0E, 0x11, 0x13, 0x09, 0x09, 0x09, 0x09, 0x0C, 0x0E, 0x11, +0x13, 0x09, 0x09, 0x09, 0x09, 0x0C, 0x0E, 0x11, 0x13, 0x13, 0x13, 0x09, 0x09, 0x09, 0x09, 0x0C, +0x0E, 0x11, 0x13, 0x13, 0x13, 0x09, 0x09, 0x09, 0x09, 0x0C, 0x0E, 0x11, 0x13, 0x13, 0x13, 0x09, +0x09, 0x09, 0x09, 0x0C, 0x0E, 0x11, 0x13, 0x13, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x26, 0x2A, 0x18, 0x1A, 0x1D, +0x1F, 0x21, 0x27, 0x29, 0x2A, 0x00, 0x00, 0x00, 0x1F, 0x23, 0x28, 0x2A, 0x2C, 0x00, 0x00, 0x00, +0x1F, 0x23, 0x28, 0x2A, 0x2C, 0x00, 0x00, 0x00, 0x1F, 0x23, 0x28, 0x2A, 0x2C, 0x00, 0x00, 0x00, +0x1F, 0x23, 0x28, 0x2A, 0x2C, 0x2C, 0x2C, 0x00, 0x00, 0x00, 0x1F, 0x23, 0x28, 0x2A, 0x2C, 0x2C, +0x2C, 0x00, 0x00, 0x00, 0x1F, 0x23, 0x28, 0x2A, 0x2C, 0x2C, 0x2C, 0x00, 0x00, 0x00, 0x1F, 0x23, +0x28, 0x2A, 0x2C, 0x2C, 0x2C, 0x00, 0x04, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, +0x24, 0x00, 0x30, 0x00, 0x48, 0x00, 0x60, 0x00, 0x90, 0x00, 0xC0, 0x00, 0xD8, 0x00, 0x50, 0x00, +0x78, 0x00, 0xA0, 0x00, 0xC8, 0x01, 0x40, 0x01, 0x90, 0x01, 0xE0, 0x02, 0x30, 0x01, 0x2C, 0x01, +0x40, 0x01, 0xE0, 0x02, 0xD0, 0x03, 0xE8, 0x04, 0xB0, 0x06, 0x40, 0x07, 0xD0, 0x01, 0x2C, 0x01, +0x40, 0x01, 0xE0, 0x02, 0xD0, 0x03, 0xE8, 0x04, 0xB0, 0x06, 0x40, 0x07, 0xD0, 0x01, 0x2C, 0x01, +0x40, 0x01, 0xE0, 0x02, 0xD0, 0x03, 0xE8, 0x04, 0xB0, 0x06, 0x40, 0x07, 0xD0, 0x01, 0x2C, 0x01, +0x40, 0x01, 0xE0, 0x02, 0xD0, 0x03, 0xE8, 0x04, 0xB0, 0x06, 0x40, 0x07, 0xD0, 0x07, 0xD0, 0x07, +0xD0, 0x01, 0x2C, 0x01, 0x40, 0x01, 0xE0, 0x02, 0xD0, 0x03, 0xE8, 0x04, 0xB0, 0x06, 0x40, 0x07, +0xD0, 0x07, 0xD0, 0x07, 0xD0, 0x01, 0x2C, 0x01, 0x40, 0x01, 0xE0, 0x02, 0xD0, 0x03, 0xE8, 0x04, +0xB0, 0x06, 0x40, 0x07, 0xD0, 0x07, 0xD0, 0x07, 0xD0, 0x01, 0x2C, 0x01, 0x40, 0x01, 0xE0, 0x02, +0xD0, 0x03, 0xE8, 0x04, 0xB0, 0x06, 0x40, 0x07, 0xD0, 0x07, 0xD0, 0x07, 0xD0, 0x00, 0x02, 0x00, +0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x18, 0x00, 0x24, 0x00, 0x30, 0x00, +0x48, 0x00, 0x60, 0x00, 0x6C, 0x00, 0x28, 0x00, 0x3C, 0x00, 0x50, 0x00, 0x64, 0x00, 0xA0, 0x00, +0xC8, 0x00, 0xF0, 0x01, 0x18, 0x00, 0x64, 0x00, 0xA0, 0x00, 0xF0, 0x01, 0x68, 0x01, 0xF4, 0x02, +0x58, 0x03, 0x20, 0x03, 0xE8, 0x00, 0x64, 0x00, 0xA0, 0x00, 0xF0, 0x01, 0x68, 0x01, 0xF4, 0x02, +0x58, 0x03, 0x20, 0x03, 0xE8, 0x00, 0x64, 0x00, 0xA0, 0x00, 0xF0, 0x01, 0x68, 0x01, 0xF4, 0x02, +0x58, 0x03, 0x20, 0x03, 0xE8, 0x00, 0x64, 0x00, 0xA0, 0x00, 0xF0, 0x01, 0x68, 0x01, 0xF4, 0x02, +0x58, 0x03, 0x20, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x00, 0x64, 0x00, 0xA0, 0x00, 0xF0, 0x01, +0x68, 0x01, 0xF4, 0x02, 0x58, 0x03, 0x20, 0x03, 0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x00, 0x64, 0x00, +0xA0, 0x00, 0xF0, 0x01, 0x68, 0x01, 0xF4, 0x02, 0x58, 0x03, 0x20, 0x03, 0xE8, 0x03, 0xE8, 0x03, +0xE8, 0x00, 0x64, 0x00, 0xA0, 0x00, 0xF0, 0x01, 0x68, 0x01, 0xF4, 0x02, 0x58, 0x03, 0x20, 0x03, +0xE8, 0x03, 0xE8, 0x03, 0xE8, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x10, 0x18, 0x20, 0x30, 0x40, +0x50, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x07, 0x05, 0x05, 0x05, +0x06, 0x06, 0x07, 0x07, 0x08, 0x05, 0x06, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x05, 0x06, 0x06, +0x07, 0x07, 0x08, 0x09, 0x0A, 0x05, 0x06, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x05, 0x06, 0x06, +0x07, 0x07, 0x08, 0x09, 0x0A, 0x0A, 0x0B, 0x05, 0x06, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x0A, +0x0B, 0x05, 0x06, 0x06, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x0A, 0x0B, 0x05, 0x06, 0x06, 0x07, 0x07, +0x08, 0x09, 0x0A, 0x0A, 0x0B, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, +0x0C, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, +0x0C, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0C, 0x0C, 0x05, 0x06, 0x07, 0x08, 0x09, +0x0A, 0x0B, 0x0C, 0x0C, 0x0C, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0C, 0x0C, 0x05, +0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0C, 0x0C, 0x20, 0x1E, 0x1C, 0x18, 0x10, 0x18, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xC2, 0xAF, 0x80, 0xFE, 0x32, 0x12, 0x45, 0x04, 0x85, 0xD0, 0x0B, 0x75, 0xD0, 0x08, 0xAA, 0xE0, +0xC2, 0x8C, 0xE5, 0x8A, 0x24, 0x67, 0xF5, 0x8A, 0xE5, 0x8C, 0x34, 0x79, 0xF5, 0x8C, 0xD2, 0x8C, +0xEC, 0x24, 0x89, 0xF8, 0xE6, 0xBC, 0x03, 0x02, 0x74, 0xFF, 0xC3, 0x95, 0x81, 0xB4, 0x40, 0x00, +0x40, 0xCE, 0x79, 0x04, 0x78, 0x80, 0x16, 0xE6, 0x08, 0x70, 0x0B, 0xC2, 0xAF, 0xE6, 0x30, 0xE1, +0x03, 0x44, 0x18, 0xF6, 0xD2, 0xAF, 0x08, 0xD9, 0xED, 0xEA, 0x8B, 0xD0, 0x22, 0xE5, 0x0C, 0xFF, +0x23, 0x24, 0x81, 0xF8, 0x0F, 0x08, 0x08, 0xBF, 0x04, 0x04, 0x7F, 0x00, 0x78, 0x81, 0xE6, 0x30, +0xE4, 0xF2, 0x00, 0xE5, 0x0C, 0xC3, 0x9F, 0x50, 0x20, 0x05, 0x0C, 0x74, 0x88, 0x25, 0x0C, 0xF8, +0xE6, 0xFD, 0xA6, 0x81, 0x08, 0xE6, 0xAE, 0x0C, 0xBE, 0x03, 0x02, 0x74, 0xFF, 0xCD, 0xF8, 0xE8, +0x6D, 0x60, 0xE0, 0x08, 0xE6, 0xC0, 0xE0, 0x80, 0xF6, 0xE5, 0x0C, 0xD3, 0x9F, 0x40, 0x27, 0xE5, +0x0C, 0x24, 0x89, 0xF8, 0xE6, 0xAE, 0x0C, 0xBE, 0x03, 0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xCD, +0xF8, 0xE5, 0x81, 0x6D, 0x60, 0x06, 0xD0, 0xE0, 0xF6, 0x18, 0x80, 0xF5, 0xE5, 0x0C, 0x24, 0x88, +0xC8, 0xF6, 0x15, 0x0C, 0x80, 0xD3, 0xE5, 0x0C, 0x23, 0x24, 0x81, 0xF8, 0x7F, 0x04, 0xC2, 0xAF, +0xE6, 0x30, 0xE0, 0x03, 0x10, 0xE2, 0x0C, 0x7F, 0x00, 0x30, 0xE1, 0x07, 0x30, 0xE3, 0x04, 0x7F, +0x08, 0x54, 0xF4, 0x54, 0x7C, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x42, 0x07, 0x22, 0x78, 0x88, 0xA6, +0x81, 0x74, 0x03, 0x60, 0x06, 0xFF, 0x08, 0x76, 0xFF, 0xDF, 0xFB, 0x7F, 0x04, 0xE4, 0x78, 0x80, +0xF6, 0x08, 0xF6, 0x08, 0xDF, 0xFA, 0x78, 0x81, 0x76, 0x30, 0x90, 0x49, 0xF8, 0x74, 0x01, 0x93, +0xC0, 0xE0, 0xE4, 0x93, 0xC0, 0xE0, 0x43, 0x89, 0x01, 0x75, 0x8A, 0x60, 0x75, 0x8C, 0x79, 0xD2, +0x8C, 0xD2, 0xAF, 0x22, 0x03, 0xEF, 0xD3, 0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0x74, 0x81, +0x2F, 0x2F, 0xF8, 0xE6, 0x20, 0xE5, 0xF4, 0xC2, 0xAF, 0xE6, 0x44, 0x30, 0xF6, 0xD2, 0xAF, 0xAE, +0x0C, 0xEE, 0xC3, 0x9F, 0x50, 0x21, 0x0E, 0x74, 0x88, 0x2E, 0xF8, 0xE6, 0xF9, 0x08, 0xE6, 0x18, +0xBE, 0x03, 0x02, 0x74, 0xFF, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x09, 0xE7, 0x19, 0x19, 0xF7, 0x09, +0x09, 0x80, 0xF3, 0x16, 0x16, 0x80, 0xDA, 0xEE, 0xD3, 0x9F, 0x40, 0x04, 0x05, 0x81, 0x05, 0x81, +0xEE, 0xD3, 0x9F, 0x40, 0x22, 0x74, 0x88, 0x2E, 0xF8, 0x08, 0xE6, 0xF9, 0xEE, 0xB5, 0x0C, 0x02, +0xA9, 0x81, 0x18, 0x06, 0x06, 0xE6, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x19, 0x19, 0xE7, 0x09, 0x09, +0xF7, 0x19, 0x80, 0xF3, 0x1E, 0x80, 0xD9, 0xEF, 0x24, 0x88, 0xF8, 0xE6, 0x04, 0xF8, 0xEF, 0x2F, +0x04, 0x90, 0x49, 0xF8, 0x93, 0xF6, 0x08, 0xEF, 0x2F, 0x93, 0xF6, 0x7F, 0x00, 0x22, 0xEF, 0xD3, +0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0xEF, 0x23, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE5, 0xF4, +0xC2, 0xAF, 0xE6, 0x54, 0x8C, 0xF6, 0xD2, 0xAF, 0xE5, 0x0C, 0xB5, 0x07, 0x0A, 0x74, 0x88, 0x2F, +0xF8, 0xE6, 0xF5, 0x81, 0x02, 0x45, 0x4D, 0x50, 0x2E, 0x74, 0x89, 0x2F, 0xF8, 0xE6, 0xBF, 0x03, +0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xF9, 0x74, 0x88, 0x2F, 0xF8, 0xFB, 0xE6, 0xFC, 0xE9, 0x6C, +0x60, 0x08, 0xA8, 0x05, 0xE7, 0xF6, 0x1D, 0x19, 0x80, 0xF4, 0xA8, 0x03, 0xA6, 0x05, 0x1F, 0xE5, +0x0C, 0xB5, 0x07, 0xE3, 0x7F, 0x00, 0x22, 0x74, 0x89, 0x2F, 0xF8, 0xE6, 0xFD, 0x18, 0x86, 0x01, +0x0F, 0x74, 0x88, 0x2F, 0xF8, 0xA6, 0x01, 0x08, 0x86, 0x04, 0xE5, 0x0C, 0xB5, 0x07, 0x02, 0xAC, +0x81, 0xED, 0x6C, 0x60, 0x08, 0x0D, 0x09, 0xA8, 0x05, 0xE6, 0xF7, 0x80, 0xF4, 0xE5, 0x0C, 0xB5, +0x07, 0xDE, 0x89, 0x81, 0x7F, 0x00, 0x22, 0xEF, 0xD3, 0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, +0xEF, 0x23, 0x24, 0x81, 0xF8, 0xC2, 0xAF, 0xE6, 0x30, 0xE5, 0x05, 0x30, 0xE0, 0x02, 0xD2, 0xE4, +0xD2, 0xE2, 0xC6, 0xD2, 0xAF, 0x7F, 0x00, 0x30, 0xE2, 0x01, 0x0F, 0x02, 0x45, 0x4C, 0x8F, 0xF0, +0xE4, 0xFF, 0xFE, 0xE5, 0x0C, 0x23, 0x24, 0x80, 0xF8, 0xC2, 0xA9, 0x30, 0xF7, 0x0D, 0x7F, 0x08, +0xE6, 0x60, 0x0B, 0x2D, 0xF6, 0x60, 0x30, 0x50, 0x2E, 0x80, 0x07, 0x30, 0xF1, 0x06, 0xED, 0xF6, +0x60, 0x25, 0x7E, 0x02, 0x08, 0x30, 0xF0, 0x10, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x23, 0x0E, 0x30, +0xE2, 0x0C, 0xD2, 0xAF, 0x7F, 0x04, 0x80, 0x12, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x13, 0x54, 0xEC, +0x4E, 0xF6, 0xD2, 0xAF, 0x02, 0x45, 0x4D, 0x7F, 0x08, 0x08, 0xEF, 0x44, 0x83, 0xF4, 0xC2, 0xAF, +0x56, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x4F, 0xFF, 0x22, 0xE7, 0x09, 0xF6, 0x08, 0xDF, 0xFA, 0x80, +0x46, 0xE7, 0x09, 0xF2, 0x08, 0xDF, 0xFA, 0x80, 0x3E, 0x88, 0x82, 0x8C, 0x83, 0xE7, 0x09, 0xF0, +0xA3, 0xDF, 0xFA, 0x80, 0x32, 0xE3, 0x09, 0xF6, 0x08, 0xDF, 0xFA, 0x80, 0x78, 0xE3, 0x09, 0xF2, +0x08, 0xDF, 0xFA, 0x80, 0x70, 0x88, 0x82, 0x8C, 0x83, 0xE3, 0x09, 0xF0, 0xA3, 0xDF, 0xFA, 0x80, +0x64, 0x89, 0x82, 0x8A, 0x83, 0xE0, 0xA3, 0xF6, 0x08, 0xDF, 0xFA, 0x80, 0x58, 0x89, 0x82, 0x8A, +0x83, 0xE0, 0xA3, 0xF2, 0x08, 0xDF, 0xFA, 0x80, 0x4C, 0x80, 0xD2, 0x80, 0xFA, 0x80, 0xC6, 0x80, +0xD4, 0x80, 0x69, 0x80, 0xF2, 0x80, 0x33, 0x80, 0x10, 0x80, 0xA6, 0x80, 0xEA, 0x80, 0x9A, 0x80, +0xA8, 0x80, 0xDA, 0x80, 0xE2, 0x80, 0xCA, 0x80, 0x33, 0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE4, +0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, +0xCC, 0xC5, 0x83, 0xCC, 0xDF, 0xE9, 0xDE, 0xE7, 0x80, 0x0D, 0x89, 0x82, 0x8A, 0x83, 0xE4, 0x93, +0xA3, 0xF6, 0x08, 0xDF, 0xF9, 0xEC, 0xFA, 0xA9, 0xF0, 0xED, 0xFB, 0x22, 0x89, 0x82, 0x8A, 0x83, +0xEC, 0xFA, 0xE0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xF0, 0xA3, 0xC8, 0xC5, +0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xDF, 0xEA, 0xDE, 0xE8, 0x80, 0xDB, 0x89, 0x82, 0x8A, 0x83, +0xE4, 0x93, 0xA3, 0xF2, 0x08, 0xDF, 0xF9, 0x80, 0xCC, 0x88, 0xF0, 0xEF, 0x60, 0x01, 0x0E, 0x4E, +0x60, 0xC3, 0x88, 0xF0, 0xED, 0x24, 0x02, 0xB4, 0x04, 0x00, 0x50, 0xB9, 0xF5, 0x82, 0xEB, 0x24, +0x02, 0xB4, 0x04, 0x00, 0x50, 0xAF, 0x23, 0x23, 0x45, 0x82, 0x23, 0x90, 0x47, 0xF9, 0x73, 0xC5, +0xF0, 0xF8, 0xA3, 0xE0, 0x28, 0xF0, 0xC5, 0xF0, 0xF8, 0xE5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, +0x83, 0xE0, 0x38, 0xF0, 0x22, 0xBB, 0x01, 0x0A, 0x89, 0x82, 0x8A, 0x83, 0xE0, 0xF5, 0xF0, 0xA3, +0xE0, 0x22, 0x50, 0x06, 0x87, 0xF0, 0x09, 0xE7, 0x19, 0x22, 0xBB, 0xFE, 0x07, 0xE3, 0xF5, 0xF0, +0x09, 0xE3, 0x19, 0x22, 0x89, 0x82, 0x8A, 0x83, 0xE4, 0x93, 0xF5, 0xF0, 0x74, 0x01, 0x93, 0x22, +0xBB, 0x01, 0x10, 0xE5, 0x82, 0x29, 0xF5, 0x82, 0xE5, 0x83, 0x3A, 0xF5, 0x83, 0xE0, 0xF5, 0xF0, +0xA3, 0xE0, 0x22, 0x50, 0x09, 0xE9, 0x25, 0x82, 0xF8, 0x86, 0xF0, 0x08, 0xE6, 0x22, 0xBB, 0xFE, +0x0A, 0xE9, 0x25, 0x82, 0xF8, 0xE2, 0xF5, 0xF0, 0x08, 0xE2, 0x22, 0xE5, 0x83, 0x2A, 0xF5, 0x83, +0xE9, 0x93, 0xF5, 0xF0, 0xA3, 0xE9, 0x93, 0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0xA3, 0xE0, 0xFE, +0xA3, 0xE0, 0xFF, 0x22, 0xA4, 0x25, 0x82, 0xF5, 0x82, 0xE5, 0xF0, 0x35, 0x83, 0xF5, 0x83, 0x22, +0xE0, 0xFB, 0xA3, 0xE0, 0xFA, 0xA3, 0xE0, 0xF9, 0x22, 0xEB, 0xF0, 0xA3, 0xEA, 0xF0, 0xA3, 0xE9, +0xF0, 0x22, 0xD0, 0x83, 0xD0, 0x82, 0xF8, 0xE4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0D, +0xA3, 0xA3, 0x93, 0xF8, 0x74, 0x01, 0x93, 0xF5, 0x82, 0x88, 0x83, 0xE4, 0x73, 0x74, 0x02, 0x93, +0x68, 0x60, 0xEF, 0xA3, 0xA3, 0xA3, 0x80, 0xDF, 0x02, 0x49, 0xA6, 0x02, 0x45, 0xDD, 0xE4, 0x93, +0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0x40, 0x03, 0xF6, 0x80, 0x01, 0xF2, 0x08, 0xDF, 0xF4, 0x80, 0x29, +0xE4, 0x93, 0xA3, 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, 0x33, 0xC4, 0x54, 0x0F, 0x44, 0x20, +0xC8, 0x83, 0x40, 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, 0xDF, 0xE4, 0x80, 0x0B, 0x01, 0x02, +0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x49, 0xEB, 0xE4, 0x7E, 0x01, 0x93, 0x60, 0xBC, 0xA3, +0xFF, 0x54, 0x3F, 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, 0x93, 0xA3, 0x60, 0x01, 0x0E, 0xCF, +0x54, 0xC0, 0x25, 0xE0, 0x60, 0xA8, 0x40, 0xB8, 0xE4, 0x93, 0xA3, 0xFA, 0xE4, 0x93, 0xA3, 0xF8, +0xE4, 0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83, 0xCA, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, +0xC8, 0xCA, 0xC5, 0x83, 0xCA, 0xDF, 0xE9, 0xDE, 0xE7, 0x80, 0xBE, 0x00, 0x41, 0x9E, 0xA8, 0x00, +0x41, 0x9E, 0xA9, 0x00, 0x41, 0x9E, 0xBA, 0x00, 0x4A, 0xEA, 0x4D, 0xD3, 0x52, 0xD2, 0x57, 0xF6, +0x90, 0x00, 0xF0, 0xE0, 0x7F, 0x01, 0x20, 0xE2, 0x02, 0x7F, 0x03, 0x22, 0x51, 0x00, 0x90, 0x9C, +0x94, 0xEF, 0xF0, 0x51, 0x1E, 0x90, 0x01, 0x64, 0x74, 0x01, 0xF0, 0x02, 0x2D, 0x4A, 0x51, 0x89, +0x51, 0xB9, 0x51, 0x4B, 0x51, 0x6A, 0xE4, 0xF5, 0x0D, 0xF5, 0x0E, 0xF5, 0x0F, 0xF5, 0x10, 0xAD, +0x0D, 0x7F, 0x50, 0x12, 0x31, 0xE4, 0xAD, 0x0E, 0x7F, 0x51, 0x12, 0x31, 0xE4, 0xAD, 0x0F, 0x7F, +0x52, 0x12, 0x31, 0xE4, 0xAD, 0x10, 0x7F, 0x53, 0x02, 0x31, 0xE4, 0x75, 0x15, 0x12, 0xE4, 0xF5, +0x16, 0x75, 0x17, 0x07, 0x75, 0x18, 0x32, 0x90, 0x01, 0x30, 0xE5, 0x15, 0xF0, 0xA3, 0xE5, 0x16, +0xF0, 0xA3, 0xE5, 0x17, 0xF0, 0xA3, 0xE5, 0x18, 0xF0, 0x22, 0x75, 0x1D, 0x0E, 0x75, 0x1E, 0x01, +0x75, 0x1F, 0x03, 0x75, 0x20, 0x62, 0x90, 0x01, 0x38, 0xE5, 0x1D, 0xF0, 0xA3, 0xE5, 0x1E, 0xF0, +0xA3, 0xE5, 0x1F, 0xF0, 0xA3, 0xE5, 0x20, 0xF0, 0x22, 0x90, 0x01, 0x30, 0xE4, 0xF0, 0xA3, 0xF0, +0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x38, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, +0x50, 0x12, 0x31, 0xE4, 0xE4, 0xFD, 0x7F, 0x51, 0x12, 0x31, 0xE4, 0xE4, 0xFD, 0x7F, 0x52, 0x12, +0x31, 0xE4, 0xE4, 0xFD, 0x7F, 0x53, 0x02, 0x31, 0xE4, 0x90, 0x01, 0x34, 0x74, 0xFF, 0xF0, 0xA3, +0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x3C, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, +0x7F, 0x54, 0x12, 0x31, 0xE4, 0x7D, 0xFF, 0x7F, 0x55, 0x12, 0x31, 0xE4, 0x7D, 0xFF, 0x7F, 0x56, +0x12, 0x31, 0xE4, 0x7D, 0xFF, 0x7F, 0x57, 0x02, 0x31, 0xE4, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x80, +0xFD, 0x7F, 0x80, 0x12, 0x31, 0xE4, 0x71, 0x6B, 0x12, 0x32, 0x25, 0x71, 0x85, 0x7F, 0x01, 0x12, +0x46, 0x15, 0x90, 0x9D, 0xCA, 0x74, 0x02, 0xF0, 0xFF, 0x12, 0x46, 0x15, 0x90, 0x9D, 0xCA, 0xE0, +0x04, 0xF0, 0x7F, 0x03, 0x12, 0x46, 0x15, 0x90, 0x9D, 0xCA, 0xE0, 0x04, 0xF0, 0x51, 0x0C, 0x71, +0x39, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x40, 0xFD, 0x7F, 0x80, 0x12, 0x31, 0xE4, 0x75, 0x28, 0xFF, +0x71, 0x5C, 0x71, 0xB5, 0xE4, 0xFF, 0x02, 0x46, 0x9E, 0x71, 0x56, 0x71, 0x63, 0x91, 0xB7, 0x91, +0x0A, 0x71, 0x73, 0x90, 0x9D, 0xCE, 0xE0, 0x54, 0xFE, 0xF0, 0xA3, 0x74, 0x03, 0xF0, 0xA3, 0xF0, +0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0x22, 0xE4, 0x90, 0x9D, 0x36, 0xF0, 0x22, 0x75, 0xE8, 0x03, 0x75, +0xA8, 0x85, 0x22, 0xE4, 0x90, 0x9D, 0x30, 0xF0, 0xA3, 0xF0, 0x22, 0x90, 0x01, 0x94, 0xE0, 0x44, +0x01, 0xF0, 0x22, 0x90, 0x9D, 0xCB, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, 0x74, 0x0A, +0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x90, 0x01, 0x01, 0xE0, 0x44, 0x04, 0xF0, 0x90, 0x01, 0x9C, 0x74, +0x7E, 0xF0, 0xA3, 0x74, 0x92, 0xF0, 0xA3, 0x74, 0xA0, 0xF0, 0xA3, 0x74, 0x24, 0xF0, 0x90, 0x01, +0x9B, 0x74, 0x49, 0xF0, 0x90, 0x01, 0x9A, 0x74, 0xE0, 0xF0, 0x90, 0x01, 0x99, 0xE4, 0xF0, 0x90, +0x01, 0x98, 0x04, 0xF0, 0x22, 0xE4, 0x90, 0x9D, 0xD3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x98, 0xE0, +0x7F, 0x00, 0x30, 0xE4, 0x02, 0x7F, 0x01, 0xEF, 0x64, 0x01, 0x60, 0x3D, 0xC3, 0x90, 0x9D, 0xD4, +0xE0, 0x94, 0x88, 0x90, 0x9D, 0xD3, 0xE0, 0x94, 0x13, 0x40, 0x08, 0x90, 0x01, 0xC1, 0xE0, 0x44, +0x10, 0xF0, 0x22, 0x90, 0x9D, 0xD3, 0xE4, 0x75, 0xF0, 0x01, 0x11, 0x9F, 0x7F, 0x14, 0x7E, 0x00, +0x12, 0x32, 0x58, 0xD3, 0x90, 0x9D, 0xD4, 0xE0, 0x94, 0x32, 0x90, 0x9D, 0xD3, 0xE0, 0x94, 0x00, +0x40, 0xBA, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE3, 0xB3, 0x22, 0xE4, 0x90, 0x9D, 0xBA, 0xF0, 0x90, +0x9D, 0xB9, 0xE0, 0x54, 0x0F, 0xF0, 0x54, 0xF0, 0xF0, 0x90, 0x9D, 0xB7, 0xE0, 0x54, 0xFD, 0xF0, +0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x9D, 0xBF, 0x74, 0x01, 0xF0, 0xA3, 0xF0, 0x90, 0x9D, +0xB7, 0xE0, 0x54, 0xFB, 0xF0, 0xA3, 0xE0, 0x54, 0xFB, 0xF0, 0xE4, 0x90, 0x9D, 0xC2, 0xF0, 0x90, +0x9D, 0xC1, 0x74, 0x07, 0xF0, 0x90, 0x9D, 0xC4, 0xE4, 0xF0, 0xA3, 0x74, 0x02, 0xF0, 0xE4, 0x90, +0x9D, 0xBD, 0xF0, 0x90, 0x9D, 0xB7, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x9D, 0xBB, 0x74, 0x0C, 0xF0, +0x90, 0x9D, 0xB7, 0xE0, 0x54, 0xDF, 0xF0, 0x90, 0x9D, 0xBC, 0x74, 0x0C, 0xF0, 0x90, 0x9D, 0xB7, +0xE0, 0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x54, +0xF7, 0xF0, 0x90, 0x9C, 0x94, 0xE0, 0xFF, 0xB4, 0x01, 0x08, 0x90, 0x9D, 0xC3, 0x74, 0x93, 0xF0, +0x80, 0x0F, 0xEF, 0x90, 0x9D, 0xC3, 0xB4, 0x03, 0x05, 0x74, 0xDC, 0xF0, 0x80, 0x03, 0x74, 0x40, +0xF0, 0x90, 0x9D, 0xC6, 0x74, 0x01, 0xF0, 0xA3, 0x74, 0x03, 0xF0, 0xA3, 0xE0, 0x54, 0x01, 0x44, +0x28, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0x22, 0xE4, 0xFF, 0xE4, 0xFE, 0x75, 0xF0, 0x10, 0xEF, 0x90, +0x81, 0x00, 0xBE, 0x03, 0x11, 0x31, 0x24, 0xE5, 0x82, 0x2E, 0xF5, 0x82, 0xE4, 0x35, 0x83, 0xF5, +0x83, 0x74, 0x80, 0xF0, 0x80, 0x0E, 0x31, 0x24, 0xE5, 0x82, 0x2E, 0xF5, 0x82, 0xE4, 0x35, 0x83, +0xF5, 0x83, 0xE4, 0xF0, 0x75, 0xF0, 0x08, 0xEF, 0x90, 0x89, 0x00, 0x31, 0x24, 0xE5, 0x82, 0x2E, +0xF5, 0x82, 0xE4, 0x35, 0x83, 0xF5, 0x83, 0xE4, 0xF0, 0x0E, 0xBE, 0x10, 0xBE, 0x0F, 0xBF, 0x80, +0xB8, 0xE4, 0x90, 0xAF, 0x71, 0xF0, 0xFF, 0x75, 0xF0, 0x0A, 0xEF, 0x90, 0x8D, 0x01, 0x31, 0x24, +0xE4, 0xF0, 0xA3, 0xF0, 0x75, 0xF0, 0x0A, 0xEF, 0x90, 0x8D, 0x03, 0x31, 0x24, 0xE4, 0xF0, 0xA3, +0xF0, 0x75, 0xF0, 0x0A, 0xEF, 0x90, 0x8D, 0x05, 0x31, 0x24, 0xE4, 0xF0, 0xA3, 0xF0, 0x75, 0xF0, +0x0A, 0xEF, 0x90, 0x8D, 0x07, 0x31, 0x24, 0xE4, 0xF0, 0xA3, 0xF0, 0x75, 0xF0, 0x0A, 0xEF, 0x90, +0x8D, 0x09, 0x31, 0x24, 0xE4, 0xF0, 0xA3, 0xF0, 0xEF, 0x25, 0xE0, 0x24, 0x01, 0xF5, 0x82, 0xE4, +0x34, 0x92, 0xF5, 0x83, 0xE4, 0xF0, 0xA3, 0xF0, 0x74, 0x93, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x99, +0xF5, 0x83, 0xE4, 0xF0, 0x75, 0xF0, 0x09, 0xEF, 0x90, 0x94, 0x98, 0x31, 0x24, 0x74, 0x01, 0xF0, +0x75, 0xF0, 0x09, 0xEF, 0x90, 0x94, 0x99, 0x31, 0x24, 0xE4, 0xF0, 0x75, 0xF0, 0x09, 0xEF, 0x90, +0x94, 0x97, 0x31, 0x24, 0x74, 0x01, 0xF0, 0x75, 0xF0, 0x09, 0xEF, 0x90, 0x94, 0x95, 0x31, 0x24, +0x74, 0x09, 0xF0, 0xF5, 0xF0, 0xEF, 0x90, 0x94, 0x96, 0x31, 0x24, 0xE4, 0xF0, 0x75, 0xF0, 0x09, +0xEF, 0x90, 0x94, 0x93, 0x31, 0x24, 0x74, 0x13, 0xF0, 0x75, 0xF0, 0x09, 0xEF, 0x90, 0x94, 0x94, +0x31, 0x24, 0xE4, 0xF0, 0x75, 0xF0, 0x10, 0xEF, 0x90, 0x81, 0x00, 0x31, 0x24, 0x74, 0x13, 0xF0, +0x0F, 0xEF, 0x64, 0x80, 0x60, 0x02, 0xA1, 0x07, 0x7F, 0x20, 0x90, 0x9E, 0x7B, 0xE4, 0xF0, 0xA3, +0xDF, 0xFC, 0x22, 0xE4, 0x90, 0x9D, 0xD5, 0xF0, 0x90, 0x9D, 0xD5, 0xE0, 0x64, 0x01, 0xF0, 0x24, +0xD3, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x4D, 0xA3, 0xF0, 0x90, 0x9D, 0xBC, 0xE0, 0xFF, 0x90, 0x9D, +0xBB, 0xE0, 0x6F, 0x60, 0x03, 0x12, 0x5F, 0xC4, 0x90, 0x9D, 0xB7, 0xE0, 0x30, 0xE0, 0x09, 0x12, +0x67, 0xF4, 0xBF, 0x01, 0x03, 0x12, 0x6B, 0x36, 0x90, 0x9D, 0xBC, 0xE0, 0x90, 0x01, 0xBC, 0xF0, +0x90, 0x9D, 0x36, 0xE0, 0x90, 0x01, 0xBD, 0xF0, 0xD1, 0x3B, 0x90, 0x00, 0x02, 0xE0, 0x54, 0xFE, +0xF0, 0x7F, 0xF4, 0x7E, 0x01, 0x12, 0x32, 0x58, 0x90, 0x00, 0x02, 0xE0, 0x44, 0x01, 0xF0, 0x7F, +0xF4, 0x7E, 0x01, 0x12, 0x32, 0x58, 0x12, 0x45, 0x4D, 0x80, 0x9D, 0x12, 0x7A, 0x45, 0x12, 0x52, +0x73, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xE4, 0x90, 0x9E, 0xAB, 0xF0, 0x90, 0x00, 0x8F, +0xE0, 0x20, 0xE6, 0x03, 0x02, 0x51, 0x91, 0x90, 0x00, 0x8D, 0xE0, 0x90, 0x9E, 0xAA, 0xF0, 0x90, +0x00, 0x8C, 0xE0, 0x90, 0x9E, 0xAB, 0xF0, 0x90, 0x9E, 0xAA, 0xE0, 0x31, 0x42, 0x4E, 0x86, 0x01, +0x4E, 0x91, 0x02, 0x4E, 0x9C, 0x04, 0x4F, 0x8A, 0x05, 0x50, 0x82, 0x06, 0x51, 0x07, 0x07, 0x51, +0x4B, 0x08, 0x00, 0x00, 0x51, 0x83, 0x90, 0x9E, 0xAB, 0xE0, 0xFF, 0x12, 0x52, 0x18, 0x02, 0x51, +0x83, 0x90, 0x9E, 0xAB, 0xE0, 0xFF, 0x12, 0x51, 0xC4, 0x02, 0x51, 0x83, 0x90, 0x9E, 0xAB, 0xE0, +0x75, 0xF0, 0x09, 0x90, 0x94, 0x98, 0x31, 0x24, 0xE0, 0xFB, 0xE4, 0xFD, 0xFF, 0x12, 0x51, 0x9C, +0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, 0x09, 0x90, 0x94, 0x96, 0x12, 0x51, 0x96, 0x90, 0x9E, 0xAB, +0xE0, 0x75, 0xF0, 0x09, 0x90, 0x94, 0x9B, 0x12, 0x51, 0x96, 0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, +0x09, 0x90, 0x94, 0x99, 0x12, 0x51, 0x96, 0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, 0x09, 0x90, 0x94, +0x93, 0x31, 0x24, 0xE0, 0xFB, 0xE4, 0xFD, 0x0F, 0x12, 0x51, 0x9C, 0x90, 0x9E, 0xAB, 0xE0, 0x75, +0xF0, 0x09, 0x90, 0x94, 0x94, 0x12, 0x51, 0x96, 0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, 0x09, 0x90, +0x94, 0x97, 0x12, 0x51, 0x96, 0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, 0x09, 0x90, 0x94, 0x95, 0x12, +0x51, 0x96, 0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, 0x08, 0x90, 0x89, 0x00, 0x31, 0x24, 0xE0, 0xFB, +0xE4, 0xFD, 0x0F, 0x12, 0x51, 0x9C, 0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, 0x08, 0x90, 0x89, 0x01, +0x12, 0x51, 0x96, 0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, 0x08, 0x90, 0x89, 0x02, 0x12, 0x51, 0x96, +0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, 0x08, 0x90, 0x89, 0x03, 0x12, 0x51, 0x96, 0x90, 0x9E, 0xAB, +0xE0, 0x75, 0xF0, 0x08, 0x90, 0x89, 0x04, 0x31, 0x24, 0xE0, 0xFB, 0xE4, 0xFD, 0x0F, 0x12, 0x51, +0x9C, 0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, 0x08, 0x90, 0x89, 0x05, 0x12, 0x51, 0x96, 0x90, 0x9E, +0xAB, 0xE0, 0x75, 0xF0, 0x08, 0x90, 0x89, 0x06, 0x12, 0x51, 0x96, 0x90, 0x9E, 0xAB, 0xE0, 0x75, +0xF0, 0x08, 0x90, 0x89, 0x07, 0x31, 0x24, 0x02, 0x51, 0x46, 0x90, 0x9E, 0xAB, 0xE0, 0x25, 0xE0, +0x24, 0x01, 0xF5, 0x82, 0xE4, 0x34, 0x92, 0xF5, 0x83, 0xA3, 0xE0, 0xFB, 0xE4, 0xFD, 0xFF, 0x12, +0x51, 0x9C, 0x90, 0x9E, 0xAB, 0xE0, 0x25, 0xE0, 0x24, 0x01, 0xF5, 0x82, 0xE4, 0x34, 0x92, 0xF5, +0x83, 0xE0, 0xFB, 0x0D, 0x12, 0x51, 0x9C, 0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, 0x0A, 0x90, 0x8D, +0x01, 0x31, 0x24, 0xA3, 0xE0, 0xFB, 0x0D, 0x12, 0x51, 0x9C, 0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, +0x0A, 0x90, 0x8D, 0x01, 0x12, 0x51, 0x96, 0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, 0x0A, 0x90, 0x8D, +0x03, 0x31, 0x24, 0xA3, 0xE0, 0xFB, 0xE4, 0xFD, 0x0F, 0x12, 0x51, 0x9C, 0x90, 0x9E, 0xAB, 0xE0, +0x75, 0xF0, 0x0A, 0x90, 0x8D, 0x05, 0x31, 0x24, 0xA3, 0xE0, 0xFB, 0x0D, 0x12, 0x51, 0x9C, 0x90, +0x9E, 0xAB, 0xE0, 0x75, 0xF0, 0x0A, 0x90, 0x8D, 0x07, 0x12, 0x49, 0x24, 0xA3, 0xE0, 0xFB, 0x0D, +0x31, 0x9C, 0x90, 0x9E, 0xAB, 0xE0, 0x75, 0xF0, 0x0A, 0x90, 0x8D, 0x09, 0x12, 0x49, 0x24, 0xA3, +0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0xAB, 0xE0, 0x24, 0x93, 0xF5, 0x82, 0xE4, 0x34, 0x99, +0xF5, 0x83, 0xE0, 0xFB, 0xE4, 0xFD, 0x0F, 0x31, 0x9C, 0x90, 0x9E, 0xAB, 0xE0, 0x25, 0xE0, 0x24, +0x91, 0xF5, 0x82, 0xE4, 0x34, 0x93, 0xF5, 0x83, 0xA3, 0xE0, 0xFB, 0x7D, 0x02, 0x31, 0x9C, 0x90, +0x9E, 0xAB, 0xE0, 0x25, 0xE0, 0x24, 0x91, 0xF5, 0x82, 0xE4, 0x34, 0x93, 0xF5, 0x83, 0xE0, 0xFB, +0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x7B, 0xE0, 0xFB, 0xE4, 0xFD, 0x0F, 0x31, 0x9C, 0x90, 0x9E, 0x7C, +0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x7D, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x7E, +0x21, 0x46, 0x90, 0x9E, 0x83, 0xE0, 0xFB, 0xE4, 0xFD, 0xFF, 0x31, 0x9C, 0x90, 0x9E, 0x84, 0xE0, +0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x85, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x86, 0xE0, +0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x87, 0xE0, 0xFB, 0xE4, 0xFD, 0x0F, 0x31, 0x9C, 0x90, 0x9E, +0x88, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x89, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, +0x8A, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x8B, 0xE0, 0xFB, 0xE4, 0xFD, 0x0F, 0x31, 0x9C, +0x90, 0x9E, 0x8C, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x8D, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, +0x90, 0x9E, 0x8E, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x8F, 0xE0, 0xFB, 0xE4, 0xFD, 0x0F, +0x31, 0x9C, 0x90, 0x9E, 0x90, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x91, 0xE0, 0xFB, 0x0D, +0x31, 0x9C, 0x90, 0x9E, 0x92, 0x80, 0x3F, 0x90, 0x9E, 0x93, 0xE0, 0xFB, 0xE4, 0xFD, 0xFF, 0x31, +0x9C, 0x90, 0x9E, 0x94, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x95, 0xE0, 0xFB, 0x0D, 0x31, +0x9C, 0x90, 0x9E, 0x96, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x97, 0xE0, 0xFB, 0xE4, 0xFD, +0x0F, 0x31, 0x9C, 0x90, 0x9E, 0x98, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x99, 0xE0, 0xFB, +0x0D, 0x31, 0x9C, 0x90, 0x9E, 0x9A, 0xE0, 0xFB, 0x0D, 0x80, 0x36, 0x90, 0x9D, 0xBA, 0xE0, 0xFB, +0xE4, 0xFD, 0xFF, 0x31, 0x9C, 0x90, 0x9D, 0xB9, 0xE0, 0x54, 0x0F, 0xFB, 0x0D, 0x31, 0x9C, 0x90, +0x9D, 0xBB, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, 0x9D, 0xBC, 0xE0, 0xFB, 0x0D, 0x31, 0x9C, 0x90, +0x9E, 0xAB, 0xE0, 0x24, 0x36, 0xF5, 0x82, 0xE4, 0x34, 0x9D, 0xF5, 0x83, 0xE0, 0xFB, 0xE4, 0xFD, +0x0F, 0x31, 0x9C, 0x90, 0x00, 0x8F, 0xE0, 0x30, 0xE0, 0x07, 0xE4, 0xFD, 0x7F, 0x8D, 0x12, 0x31, +0xE4, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x12, 0x49, 0x24, 0xE0, 0xFB, 0x0D, 0xEF, 0x70, 0x04, 0x74, +0xF0, 0x80, 0x16, 0xEF, 0xB4, 0x01, 0x04, 0x74, 0xF4, 0x80, 0x0E, 0xEF, 0xB4, 0x02, 0x04, 0x74, +0xF8, 0x80, 0x06, 0xEF, 0xB4, 0x03, 0x0C, 0x74, 0xFC, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0x02, 0xF5, +0x83, 0xEB, 0xF0, 0x22, 0x8F, 0x27, 0x90, 0x00, 0x8F, 0xE0, 0x30, 0xE6, 0x4A, 0x90, 0x00, 0x8D, +0xE0, 0x64, 0x02, 0x70, 0x42, 0x90, 0x9E, 0xB9, 0xF0, 0x90, 0x9E, 0xB9, 0xE0, 0xFD, 0xE5, 0x27, +0x75, 0xF0, 0x08, 0xA4, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83, 0xE5, 0x82, 0x2D, +0xF5, 0x82, 0xE4, 0x35, 0x83, 0xF5, 0x83, 0xE0, 0xFB, 0xE4, 0xFF, 0x31, 0x9C, 0x90, 0x9E, 0xB9, +0xE0, 0x04, 0xF0, 0xE0, 0xC3, 0x94, 0x08, 0x40, 0xD0, 0x90, 0x00, 0x8F, 0xE0, 0x30, 0xE0, 0x07, +0xE4, 0xFD, 0x7F, 0x8D, 0x12, 0x31, 0xE4, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x8F, +0x26, 0x90, 0x00, 0x8F, 0xE0, 0x30, 0xE6, 0x46, 0x90, 0x00, 0x8D, 0xE0, 0x64, 0x01, 0x70, 0x3E, +0x90, 0x9E, 0xB8, 0xF0, 0x90, 0x9E, 0xB8, 0xE0, 0xFD, 0x75, 0xF0, 0x10, 0xE5, 0x26, 0x90, 0x81, +0x00, 0x12, 0x49, 0x24, 0xE5, 0x82, 0x2D, 0xF5, 0x82, 0xE4, 0x35, 0x83, 0xF5, 0x83, 0xE0, 0xFB, +0xE4, 0xFF, 0x31, 0x9C, 0x90, 0x9E, 0xB8, 0xE0, 0x04, 0xF0, 0xE0, 0xC3, 0x94, 0x10, 0x40, 0xD4, +0x90, 0x00, 0x8F, 0xE0, 0x30, 0xE0, 0x07, 0xE4, 0xFD, 0x7F, 0x8D, 0x12, 0x31, 0xE4, 0xD0, 0xD0, +0x92, 0xAF, 0x22, 0x90, 0x00, 0x8F, 0xE0, 0x30, 0xE6, 0x57, 0x90, 0x00, 0x8D, 0xE0, 0x64, 0x03, +0x70, 0x4F, 0x90, 0x00, 0x8F, 0xE0, 0xFE, 0x90, 0x00, 0x8E, 0xE0, 0xFD, 0xED, 0xFF, 0x90, 0x9D, +0xD7, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xE4, 0x90, 0x9D, 0xD6, 0xF0, 0x90, 0x9D, 0xD6, 0xE0, 0xFD, +0xFF, 0x90, 0x9D, 0xD8, 0xE0, 0x2F, 0xFF, 0x90, 0x9D, 0xD7, 0xE0, 0x34, 0x00, 0x8F, 0x82, 0xF5, +0x83, 0xE0, 0xFB, 0xE4, 0xFF, 0x31, 0x9C, 0x90, 0x9D, 0xD6, 0xE0, 0x04, 0xF0, 0xE0, 0xC3, 0x94, +0x10, 0x40, 0xD8, 0x90, 0x00, 0x8F, 0xE0, 0x30, 0xE0, 0x07, 0xE4, 0xFD, 0x7F, 0x8D, 0x12, 0x31, +0xE4, 0x22, 0xE4, 0xFB, 0xFA, 0xFD, 0x7F, 0x01, 0x12, 0x47, 0x4E, 0x90, 0x9D, 0xD9, 0xEF, 0xF0, +0x60, 0xF0, 0x90, 0x9E, 0x93, 0xE0, 0x04, 0xF0, 0x51, 0xEC, 0x80, 0xE6, 0xD3, 0x10, 0xAF, 0x01, +0xC3, 0xC0, 0xD0, 0x90, 0x01, 0xCC, 0xE0, 0x54, 0x0F, 0x90, 0x9D, 0xDA, 0xF0, 0x90, 0x9D, 0xDA, +0xE0, 0xFD, 0x70, 0x02, 0x81, 0x25, 0x90, 0x9E, 0xA8, 0xE0, 0xFF, 0x74, 0x01, 0x7E, 0x00, 0xA8, +0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0xEF, 0x5D, 0x70, 0x02, +0x81, 0x0F, 0x90, 0x9E, 0xA8, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD0, 0x12, 0x49, 0x24, 0xE0, +0x90, 0x9D, 0xDB, 0xF0, 0x75, 0x40, 0x01, 0x75, 0x41, 0x9D, 0x75, 0x42, 0xDB, 0x75, 0x43, 0x01, +0x7B, 0x01, 0x7A, 0x9D, 0x79, 0xDC, 0x12, 0x2B, 0x33, 0x90, 0x9E, 0xA8, 0xE0, 0x75, 0xF0, 0x04, +0x90, 0x01, 0xD1, 0x12, 0x49, 0x24, 0xE0, 0x90, 0x9D, 0xDD, 0xF0, 0x90, 0x9E, 0xA8, 0xE0, 0x75, +0xF0, 0x04, 0x90, 0x01, 0xD2, 0x12, 0x49, 0x24, 0xE0, 0x90, 0x9D, 0xDE, 0xF0, 0x90, 0x9E, 0xA8, +0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD3, 0x12, 0x49, 0x24, 0xE0, 0x90, 0x9D, 0xDF, 0xF0, 0x90, +0x9E, 0xA8, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF0, 0x12, 0x49, 0x24, 0xE0, 0x90, 0x9D, 0xE0, +0xF0, 0x90, 0x9E, 0xA8, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF1, 0x12, 0x49, 0x24, 0xE0, 0x90, +0x9D, 0xE1, 0xF0, 0x90, 0x9E, 0xA8, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF2, 0x12, 0x49, 0x24, +0xE0, 0x90, 0x9D, 0xE2, 0xF0, 0x90, 0x9E, 0xA8, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF3, 0x12, +0x49, 0x24, 0xE0, 0x90, 0x9D, 0xE3, 0xF0, 0x90, 0x9D, 0xDA, 0xE0, 0xFF, 0x90, 0x9E, 0xA8, 0xE0, +0xFE, 0x74, 0x01, 0xA8, 0x06, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0x5F, 0x90, 0x9D, +0xDA, 0xF0, 0x90, 0x9E, 0xA8, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, +0xD8, 0xFC, 0x90, 0x01, 0xCC, 0xF0, 0x90, 0x9D, 0xDC, 0xE0, 0xFF, 0x7B, 0x01, 0x7A, 0x9D, 0x79, +0xDD, 0x91, 0x2A, 0x90, 0x9E, 0xA8, 0xE0, 0x04, 0xF0, 0xE0, 0x54, 0x03, 0xF0, 0x41, 0xFD, 0x90, +0x01, 0xC0, 0xE0, 0x44, 0x02, 0xF0, 0x90, 0x01, 0x4D, 0xE0, 0x64, 0x80, 0xF0, 0x90, 0x9E, 0xA8, +0xE0, 0x90, 0x00, 0x89, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x9D, 0xE4, 0x12, 0x49, 0x39, +0xEF, 0x12, 0x49, 0x42, 0x54, 0x56, 0x00, 0x54, 0x5F, 0x01, 0x54, 0x68, 0x02, 0x54, 0x71, 0x03, +0x54, 0x7A, 0x04, 0x54, 0x83, 0x20, 0x54, 0x8B, 0x21, 0x54, 0x94, 0x23, 0x54, 0x9C, 0x40, 0x54, +0xAB, 0x42, 0x00, 0x00, 0x54, 0xB4, 0x90, 0x9D, 0xE4, 0x12, 0x49, 0x30, 0x02, 0x65, 0xE8, 0x90, +0x9D, 0xE4, 0x12, 0x49, 0x30, 0x02, 0x66, 0x30, 0x90, 0x9D, 0xE4, 0x12, 0x49, 0x30, 0x02, 0x66, +0xC8, 0x90, 0x9D, 0xE4, 0x12, 0x49, 0x30, 0x02, 0x7A, 0x7D, 0x90, 0x9D, 0xE4, 0x12, 0x49, 0x30, +0x02, 0x7A, 0x9D, 0x90, 0x9D, 0xE4, 0x12, 0x49, 0x30, 0x80, 0x31, 0x90, 0x9D, 0xE4, 0x12, 0x49, +0x30, 0x02, 0x67, 0x00, 0x90, 0x9D, 0xE4, 0x12, 0x49, 0x30, 0xE1, 0xE4, 0x90, 0x9E, 0x94, 0xE0, +0x04, 0xF0, 0x90, 0x9D, 0xE4, 0x12, 0x49, 0x30, 0x02, 0x79, 0x17, 0x90, 0x9D, 0xE4, 0x12, 0x49, +0x30, 0x02, 0x79, 0xFE, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x12, 0x1F, 0x96, 0x90, +0x9D, 0xBA, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xAF, 0xFF, 0x54, 0xF0, 0xC4, 0x54, 0x0F, 0xFE, +0x90, 0x9D, 0xB9, 0xE0, 0x54, 0xF0, 0x4E, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xAF, 0x54, 0x01, +0x25, 0xE0, 0xFE, 0x90, 0x9D, 0xB7, 0xE0, 0x54, 0xFD, 0x4E, 0xF0, 0xEF, 0x54, 0x0F, 0xC4, 0x54, +0xF0, 0xFF, 0x90, 0x9D, 0xB9, 0xE0, 0x54, 0x0F, 0x4F, 0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xAF, +0x90, 0x9D, 0xBB, 0xF0, 0xB1, 0x2B, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0xF0, +0x90, 0x9D, 0xBA, 0xE0, 0x90, 0x01, 0xBA, 0xF0, 0x90, 0x9D, 0xBB, 0xE0, 0x90, 0x01, 0xBB, 0xF0, +0x90, 0x9D, 0xB9, 0xE0, 0x54, 0x0F, 0x90, 0x01, 0xBE, 0xF0, 0x22, 0x90, 0x9D, 0xE7, 0x12, 0x49, +0x39, 0x12, 0x7A, 0xC7, 0x90, 0x9D, 0xBA, 0xE0, 0xFF, 0xB1, 0x5B, 0x90, 0x9D, 0xBA, 0xE0, 0x60, +0x19, 0x90, 0x9D, 0xE7, 0x12, 0x49, 0x30, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xAF, 0x54, 0x0F, 0xFF, +0x90, 0x00, 0x02, 0x12, 0x1F, 0xAF, 0xFD, 0x12, 0x7A, 0xD8, 0x22, 0xEF, 0x70, 0x3E, 0x7D, 0x01, +0xFF, 0x12, 0x5E, 0x47, 0x7D, 0x78, 0x7F, 0x02, 0x12, 0x5E, 0x47, 0x7D, 0x02, 0x7F, 0x03, 0x12, +0x5E, 0x47, 0x7D, 0xC8, 0x7F, 0x02, 0x12, 0x7A, 0x2D, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, +0x3C, 0x74, 0x02, 0xF0, 0x7D, 0x01, 0x7F, 0x0C, 0xB1, 0xF5, 0x90, 0x9D, 0xB7, 0xE0, 0x54, 0xF7, +0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x06, 0x0A, 0xE0, 0x54, 0xF8, 0xF0, 0x22, 0x90, 0x01, 0x30, 0x74, +0x01, 0xF0, 0x90, 0x01, 0x36, 0x74, 0x78, 0xF0, 0xA3, 0x74, 0x02, 0xF0, 0x7D, 0x01, 0xE4, 0xFF, +0xF1, 0xA9, 0x7D, 0x78, 0x7F, 0x02, 0xF1, 0xA9, 0x7D, 0x02, 0x7F, 0x03, 0xF1, 0xA9, 0x90, 0x06, +0x0A, 0xE0, 0x44, 0x07, 0xF0, 0x90, 0x9D, 0xC4, 0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x9D, +0x36, 0xE0, 0xB4, 0x01, 0x14, 0x90, 0x9D, 0xB8, 0xE0, 0x54, 0xFB, 0xF0, 0x90, 0x9D, 0xBC, 0xE0, +0x20, 0xE2, 0x0D, 0x7D, 0x01, 0x7F, 0x04, 0x80, 0x0C, 0x90, 0x9D, 0xB8, 0xE0, 0x44, 0x04, 0xF0, +0x22, 0x7D, 0x01, 0x7F, 0x04, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x9E, 0xB4, 0xED, +0xF0, 0x90, 0x9D, 0xBC, 0xE0, 0x90, 0x9E, 0xB5, 0xF0, 0x90, 0x9D, 0xB7, 0xE0, 0xFE, 0xC4, 0x13, +0x13, 0x54, 0x03, 0x30, 0xE0, 0x02, 0xE1, 0x53, 0xEE, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, +0xE0, 0x02, 0xE1, 0x53, 0x90, 0x9E, 0xB5, 0xE0, 0xFE, 0x6F, 0x70, 0x02, 0xE1, 0x53, 0xEF, 0x70, +0x02, 0xC1, 0xC4, 0x24, 0xFC, 0x60, 0x52, 0x24, 0xFE, 0x70, 0x02, 0xE1, 0x00, 0x24, 0xFE, 0x70, +0x02, 0xE1, 0x3E, 0x24, 0xFC, 0x60, 0x02, 0xE1, 0x53, 0xEE, 0xB4, 0x0E, 0x03, 0x12, 0x7B, 0x1C, +0x90, 0x9E, 0xB5, 0xE0, 0x70, 0x05, 0x7F, 0x01, 0x12, 0x6A, 0x9A, 0x90, 0x9E, 0xB5, 0xE0, 0xB4, +0x06, 0x02, 0xF1, 0xBE, 0x90, 0x9E, 0xB5, 0xE0, 0xB4, 0x04, 0x0F, 0x90, 0x9E, 0xB4, 0xE0, 0xFF, +0x60, 0x05, 0x12, 0x63, 0xEF, 0x80, 0x03, 0x12, 0x7B, 0x09, 0x90, 0x9E, 0xB5, 0xE0, 0x64, 0x08, +0x60, 0x02, 0xE1, 0x53, 0x12, 0x6A, 0xB3, 0xE1, 0x53, 0x90, 0x9E, 0xB5, 0xE0, 0x70, 0x05, 0x7F, +0x01, 0x12, 0x6A, 0x9A, 0x90, 0x9E, 0xB5, 0xE0, 0xB4, 0x06, 0x02, 0xF1, 0xBE, 0x90, 0x9E, 0xB5, +0xE0, 0xB4, 0x0E, 0x08, 0xF1, 0x58, 0xBF, 0x01, 0x03, 0x12, 0x7B, 0x1C, 0x90, 0x9E, 0xB5, 0xE0, +0x64, 0x0C, 0x60, 0x02, 0xE1, 0x53, 0xF1, 0x58, 0xEF, 0x64, 0x01, 0x60, 0x02, 0xE1, 0x53, 0x12, +0x60, 0xE0, 0xE1, 0x53, 0x90, 0x9E, 0xB5, 0xE0, 0xB4, 0x0E, 0x08, 0xF1, 0x58, 0xBF, 0x01, 0x03, +0x12, 0x7B, 0x1C, 0x90, 0x9E, 0xB5, 0xE0, 0xB4, 0x06, 0x02, 0xF1, 0xBE, 0x90, 0x9E, 0xB5, 0xE0, +0xB4, 0x0C, 0x08, 0xF1, 0x58, 0xBF, 0x01, 0x03, 0x12, 0x60, 0xE0, 0x90, 0x9E, 0xB5, 0xE0, 0x64, +0x04, 0x70, 0x60, 0x12, 0x68, 0xB1, 0xEF, 0x64, 0x01, 0x70, 0x58, 0x12, 0x69, 0xC7, 0x80, 0x53, +0x90, 0x9E, 0xB5, 0xE0, 0xB4, 0x0E, 0x08, 0xF1, 0x58, 0xBF, 0x01, 0x03, 0x12, 0x7B, 0x1C, 0x90, +0x9E, 0xB5, 0xE0, 0xB4, 0x06, 0x02, 0xF1, 0xBE, 0x90, 0x9E, 0xB5, 0xE0, 0xB4, 0x0C, 0x08, 0xF1, +0x58, 0xBF, 0x01, 0x03, 0x12, 0x60, 0xE0, 0x90, 0x9E, 0xB5, 0xE0, 0x70, 0x05, 0x7F, 0x01, 0x12, +0x6A, 0x9A, 0x90, 0x9E, 0xB5, 0xE0, 0xB4, 0x04, 0x1A, 0x12, 0x7B, 0x44, 0x80, 0x15, 0x90, 0x9E, +0xB5, 0xE0, 0xB4, 0x0C, 0x0E, 0x90, 0x9D, 0xB8, 0xE0, 0xFF, 0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, +0x02, 0xF1, 0xEC, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x12, 0x68, 0x98, 0xEF, 0x64, 0x01, 0x60, 0x08, +0x90, 0x01, 0xB8, 0x74, 0x01, 0xF0, 0x80, 0x38, 0x90, 0x9D, 0xB7, 0xE0, 0xFF, 0x13, 0x13, 0x13, +0x54, 0x1F, 0x30, 0xE0, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x02, 0xF0, 0x80, 0x23, 0xEF, 0xC4, 0x54, +0x0F, 0x30, 0xE0, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x14, 0x90, 0x9D, 0xBB, 0xE0, +0xD3, 0x94, 0x04, 0x40, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x80, 0x03, 0x7F, 0x01, 0x22, +0x90, 0x01, 0xB9, 0x74, 0x02, 0xF0, 0x7F, 0x00, 0x22, 0x74, 0x15, 0x2F, 0xF8, 0xE6, 0x4D, 0xFE, +0xF6, 0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0x90, 0x9D, +0xB8, 0xE0, 0x90, 0x06, 0x04, 0x20, 0xE0, 0x0C, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x9D, 0xBC, 0x74, +0x04, 0xF0, 0x80, 0x0A, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x9D, 0xBC, 0x74, 0x0C, 0xF0, 0x90, 0x05, +0x22, 0xE4, 0xF0, 0x22, 0x12, 0x1F, 0x96, 0x90, 0x9D, 0xC3, 0xF0, 0x22, 0x12, 0x69, 0xE3, 0x90, +0x9D, 0xBC, 0x74, 0x08, 0xF0, 0x22, 0xE4, 0xFB, 0xFA, 0xFD, 0x7F, 0x01, 0x12, 0x47, 0x4E, 0x90, +0x9D, 0xEC, 0xEF, 0xF0, 0x60, 0xF0, 0x11, 0x0A, 0x80, 0xEC, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, +0xD0, 0x90, 0x9D, 0x31, 0xE0, 0xFF, 0x90, 0x9D, 0x30, 0xE0, 0xFE, 0xB5, 0x07, 0x04, 0x7F, 0x01, +0x80, 0x02, 0x7F, 0x00, 0xEF, 0x64, 0x01, 0x60, 0x45, 0x90, 0x01, 0xAF, 0xE0, 0x70, 0x3F, 0xEE, +0x75, 0xF0, 0x0F, 0xA4, 0xFF, 0xAE, 0xF0, 0x24, 0x9A, 0xF9, 0x74, 0x9C, 0x3E, 0xFA, 0x7B, 0x01, +0xC0, 0x02, 0xC0, 0x01, 0x74, 0x9C, 0x2F, 0xF9, 0x74, 0x9C, 0x3E, 0xFA, 0x90, 0x9D, 0xF0, 0x12, +0x49, 0x39, 0xD0, 0x01, 0xD0, 0x02, 0x11, 0x73, 0x90, 0x9D, 0x30, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, +0x00, 0xB4, 0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x60, 0x05, 0xE4, 0x90, 0x9D, 0x30, 0xF0, 0xD0, 0xD0, +0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x9D, 0xED, 0x12, 0x49, 0x39, +0x90, 0x9E, 0xA9, 0xE0, 0xFF, 0x04, 0xF0, 0x90, 0x00, 0x01, 0xEF, 0x12, 0x1F, 0xEE, 0x7F, 0xAF, +0x7E, 0x01, 0x11, 0xE5, 0xEF, 0x60, 0x49, 0x90, 0x9D, 0xED, 0x12, 0x49, 0x30, 0x8B, 0x40, 0x8A, +0x41, 0x89, 0x42, 0x75, 0x43, 0x02, 0x7B, 0x01, 0x7A, 0x01, 0x79, 0xA0, 0x12, 0x2B, 0x33, 0x90, +0x9D, 0xF0, 0x12, 0x49, 0x30, 0x8B, 0x40, 0x8A, 0x41, 0x89, 0x42, 0x90, 0x9D, 0xED, 0x12, 0x49, +0x30, 0x12, 0x1F, 0x96, 0xFF, 0xC4, 0x54, 0x0F, 0xF5, 0x43, 0x7B, 0x01, 0x7A, 0x01, 0x79, 0xA2, +0x12, 0x2B, 0x33, 0x90, 0x01, 0xAF, 0x74, 0xFF, 0xF0, 0x90, 0x01, 0xCB, 0xE0, 0x64, 0x80, 0xF0, +0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x9D, 0xF3, 0xEE, +0xF0, 0xA3, 0xEF, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x9D, 0xF3, 0xE0, 0xFE, 0xA3, 0xE0, +0xF5, 0x82, 0x8E, 0x83, 0xE0, 0x60, 0x2D, 0xC3, 0x90, 0x9D, 0xF6, 0xE0, 0x94, 0xE8, 0x90, 0x9D, +0xF5, 0xE0, 0x94, 0x03, 0x40, 0x0B, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x80, 0xF0, 0x7F, 0x00, 0x80, +0x15, 0x90, 0x9D, 0xF5, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x48, 0x9F, 0x7F, 0x0A, 0x7E, 0x00, 0x12, +0x32, 0x58, 0x80, 0xC5, 0x7F, 0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, +0x83, 0xC0, 0x82, 0xC0, 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, +0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0x3B, 0xF0, 0x74, 0x59, +0xA3, 0xF0, 0x53, 0x91, 0xEF, 0x31, 0x8D, 0x74, 0x3B, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x59, +0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, +0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x00, 0x54, +0xE0, 0x55, 0x0D, 0xF5, 0x11, 0xA3, 0xE0, 0x55, 0x0E, 0xF5, 0x12, 0xA3, 0xE0, 0x55, 0x0F, 0xF5, +0x13, 0xA3, 0xE0, 0x55, 0x10, 0xF5, 0x14, 0xAD, 0x11, 0x7F, 0x54, 0x12, 0x31, 0xE4, 0xAD, 0x12, +0x7F, 0x55, 0x12, 0x31, 0xE4, 0xAD, 0x13, 0x7F, 0x56, 0x12, 0x31, 0xE4, 0xAD, 0x14, 0x7F, 0x57, +0x02, 0x31, 0xE4, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, 0x75, 0xD0, 0x00, +0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, +0x90, 0x01, 0xC4, 0x74, 0xC3, 0xF0, 0x74, 0x59, 0xA3, 0xF0, 0x12, 0x68, 0x13, 0xE5, 0x19, 0x30, +0xE0, 0x03, 0x12, 0x68, 0x40, 0xE5, 0x19, 0x30, 0xE1, 0x02, 0x51, 0x7B, 0xE5, 0x19, 0x30, 0xE4, +0x05, 0x7F, 0x02, 0x12, 0x47, 0x27, 0xE5, 0x1B, 0x30, 0xE0, 0x02, 0x51, 0xBE, 0xE5, 0x1B, 0x30, +0xE1, 0x02, 0xB1, 0xDE, 0xE5, 0x1B, 0x30, 0xE2, 0x02, 0xD1, 0x5F, 0xE5, 0x1B, 0x30, 0xE3, 0x03, +0x12, 0x69, 0x1D, 0xE5, 0x1B, 0x30, 0xE4, 0x03, 0x12, 0x69, 0x50, 0xE5, 0x1B, 0x30, 0xE5, 0x02, +0xF1, 0x3A, 0xE5, 0x1B, 0x30, 0xE6, 0x02, 0xF1, 0x1F, 0xE5, 0x1C, 0x30, 0xE1, 0x02, 0x91, 0x32, +0xE5, 0x1C, 0x30, 0xE4, 0x02, 0x91, 0x3B, 0xE5, 0x1C, 0x30, 0xE5, 0x02, 0x71, 0x82, 0xE5, 0x1C, +0x30, 0xE6, 0x02, 0x71, 0x4B, 0x74, 0xC3, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x59, 0xA3, 0xF0, +0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, +0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x04, 0x7E, 0xE0, 0xFF, +0xA3, 0xE0, 0x04, 0xFE, 0xEE, 0xD3, 0x9F, 0x50, 0x2F, 0xE4, 0xFD, 0xEE, 0x75, 0xF0, 0x08, 0xA4, +0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83, 0xE5, 0x82, 0x2D, 0xF5, 0x82, 0xE4, 0x35, +0x83, 0xF5, 0x83, 0xE0, 0xFC, 0x74, 0x72, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xAF, 0xF5, 0x83, 0xEC, +0xF0, 0x0D, 0xBD, 0x08, 0xD6, 0x0E, 0x80, 0xCC, 0x90, 0x04, 0x7F, 0xEF, 0xF0, 0x22, 0xE4, 0xFF, +0x90, 0x9D, 0xBA, 0xE0, 0x70, 0x02, 0x61, 0x4A, 0x90, 0x9D, 0x36, 0xE0, 0x64, 0x01, 0x70, 0x7A, +0x90, 0x9D, 0xB9, 0xE0, 0xC4, 0x54, 0x0F, 0x60, 0x24, 0x24, 0xFE, 0x60, 0x03, 0x04, 0x70, 0x1F, +0x90, 0x9D, 0xC0, 0xE0, 0x14, 0xF0, 0xE0, 0xFE, 0x60, 0x06, 0x90, 0x9D, 0xC2, 0xE0, 0x60, 0x0F, +0xEE, 0x70, 0x06, 0x90, 0x9D, 0xBF, 0xE0, 0xA3, 0xF0, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x01, 0xEF, +0x60, 0x48, 0x90, 0x9D, 0xBD, 0xE0, 0x44, 0x10, 0xF0, 0x90, 0x9D, 0xC2, 0xE0, 0x60, 0x03, 0xB4, +0x01, 0x09, 0xE4, 0xF5, 0x3B, 0x90, 0x9D, 0xC2, 0xE0, 0x80, 0x0D, 0xE4, 0xF5, 0x3B, 0x90, 0x9D, +0xC2, 0xE0, 0x75, 0xF0, 0x03, 0xA4, 0x24, 0xFE, 0xFF, 0x90, 0x9D, 0xC1, 0xE0, 0x2F, 0xF5, 0x3C, +0xE4, 0xFB, 0xFD, 0x7F, 0x54, 0x7E, 0x01, 0x12, 0x2B, 0xF0, 0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, +0x90, 0x9D, 0xBC, 0xE0, 0x20, 0xE2, 0x03, 0x12, 0x55, 0xF1, 0x22, 0x90, 0x07, 0x1F, 0xE0, 0x54, +0x7F, 0xF0, 0x90, 0x07, 0x1C, 0xE0, 0x54, 0x01, 0x90, 0x9D, 0xF9, 0xF0, 0x90, 0x9D, 0xF7, 0xE0, +0x54, 0xF0, 0x44, 0x02, 0xF0, 0x54, 0x0F, 0x44, 0x10, 0xF0, 0x7B, 0x01, 0x7A, 0x9D, 0x79, 0xF9, +0x90, 0x9D, 0xFD, 0x12, 0x49, 0x39, 0x7A, 0x9D, 0x79, 0xF7, 0x12, 0x67, 0x46, 0x7F, 0x03, 0x02, +0x47, 0x27, 0x90, 0x9E, 0x90, 0xE0, 0x04, 0xF0, 0xE4, 0xF5, 0x52, 0x90, 0x9D, 0x36, 0xE0, 0x70, +0x02, 0x81, 0x26, 0xE5, 0x52, 0x13, 0x13, 0x13, 0x54, 0x1F, 0xFF, 0xE5, 0x52, 0x54, 0x07, 0xFE, +0x74, 0x81, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x93, 0xF5, 0x83, 0xE0, 0xFD, 0xAF, 0x06, 0x74, 0x01, +0x7E, 0x00, 0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0xEF, +0x5D, 0x60, 0x63, 0x75, 0xF0, 0x10, 0xE5, 0x52, 0x90, 0x81, 0x01, 0x12, 0x49, 0x24, 0xE0, 0x20, +0xE7, 0x02, 0x80, 0x10, 0x75, 0xF0, 0x10, 0xE5, 0x52, 0x90, 0x81, 0x02, 0x12, 0x49, 0x24, 0xE0, +0xFF, 0x20, 0xE7, 0x09, 0x90, 0x01, 0xC1, 0xE0, 0x44, 0x20, 0xF0, 0x80, 0x39, 0xEF, 0x30, 0xE6, +0x2A, 0x90, 0x9E, 0x8D, 0xE0, 0x04, 0xF0, 0x75, 0xF0, 0x10, 0xE5, 0x52, 0x90, 0x81, 0x00, 0x12, +0x49, 0x24, 0xE0, 0xFD, 0x75, 0xF0, 0x09, 0xE5, 0x52, 0x90, 0x94, 0x96, 0x12, 0x49, 0x24, 0xE0, +0xF5, 0x6A, 0xE4, 0xFB, 0xAF, 0x52, 0x12, 0x6B, 0xD1, 0x80, 0x0B, 0x90, 0x9E, 0x8E, 0xE0, 0x04, +0xF0, 0xAF, 0x52, 0x12, 0x6F, 0x28, 0x05, 0x52, 0xE5, 0x52, 0xC3, 0x94, 0x80, 0x50, 0x02, 0x61, +0x8B, 0x22, 0x90, 0x9D, 0xBA, 0xE0, 0x60, 0x02, 0xF1, 0x92, 0x22, 0x90, 0x9E, 0x8F, 0xE0, 0x04, +0xF0, 0xE4, 0xFF, 0x8F, 0x52, 0xE4, 0xFC, 0x74, 0xF7, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0x9D, 0xF5, +0x83, 0xE4, 0xF0, 0x75, 0xF0, 0x10, 0xEC, 0x90, 0x81, 0x03, 0x12, 0x49, 0x24, 0xE0, 0xFF, 0x30, +0xE7, 0x0F, 0xEC, 0x70, 0x1D, 0xEF, 0x30, 0xE6, 0x19, 0x90, 0x9E, 0x8C, 0xE0, 0x04, 0xF0, 0x80, +0x11, 0xAF, 0x04, 0xF1, 0xCE, 0x74, 0xF7, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0x9D, 0xF5, 0x83, 0x74, +0x01, 0xF0, 0x0C, 0xBC, 0x80, 0xC1, 0x7F, 0x0C, 0x7E, 0x00, 0x12, 0x32, 0x58, 0xE4, 0xFC, 0x74, +0xF7, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0x9D, 0xF5, 0x83, 0xE0, 0x70, 0x02, 0xA1, 0xD5, 0x75, 0xF0, +0x10, 0xEC, 0x90, 0x81, 0x06, 0x12, 0x49, 0x24, 0xE0, 0xFD, 0x75, 0xF0, 0x10, 0xEC, 0x90, 0x81, +0x07, 0x12, 0x49, 0x24, 0xE0, 0xFE, 0xED, 0xFB, 0xEB, 0xFF, 0xEC, 0x25, 0xE0, 0x24, 0x01, 0xF5, +0x82, 0xE4, 0x34, 0x92, 0xF5, 0x83, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x75, 0xF0, 0x10, 0xEC, 0x90, +0x81, 0x0A, 0x12, 0x49, 0x24, 0xE0, 0xFD, 0x75, 0xF0, 0x10, 0xEC, 0x90, 0x81, 0x0B, 0x12, 0x49, +0x24, 0xE0, 0xFB, 0xFE, 0xED, 0xF5, 0x82, 0xE5, 0x82, 0xFF, 0x75, 0xF0, 0x0A, 0xEC, 0x90, 0x8D, +0x01, 0x12, 0x49, 0x24, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x75, 0xF0, 0x10, 0xEC, 0x90, 0x81, 0x0C, +0x12, 0x49, 0x24, 0xE0, 0xFF, 0x75, 0xF0, 0x0A, 0xEC, 0x90, 0x8D, 0x03, 0x12, 0x49, 0x24, 0xE4, +0xF0, 0xA3, 0xEF, 0xF0, 0x75, 0xF0, 0x10, 0xEC, 0x90, 0x81, 0x0D, 0x12, 0x49, 0x24, 0xE0, 0xFF, +0x75, 0xF0, 0x0A, 0xEC, 0x90, 0x8D, 0x05, 0x12, 0x49, 0x24, 0xE4, 0xF0, 0xA3, 0xEF, 0xF0, 0x75, +0xF0, 0x10, 0xEC, 0x90, 0x81, 0x0E, 0x12, 0x49, 0x24, 0xE0, 0xFF, 0x75, 0xF0, 0x0A, 0xEC, 0x90, +0x8D, 0x07, 0x12, 0x49, 0x24, 0xE4, 0xF0, 0xA3, 0xEF, 0xF0, 0x75, 0xF0, 0x10, 0xEC, 0x90, 0x81, +0x0F, 0x12, 0x49, 0x24, 0xE0, 0xFF, 0x75, 0xF0, 0x0A, 0xEC, 0x90, 0x8D, 0x09, 0x12, 0x49, 0x24, +0xE4, 0xF0, 0xA3, 0xEF, 0xF0, 0x75, 0xF0, 0x10, 0xEC, 0x90, 0x81, 0x09, 0x12, 0x49, 0x24, 0xE0, +0xFF, 0x74, 0x93, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0x99, 0xF5, 0x83, 0xEF, 0xF0, 0xEC, 0x70, 0x4E, +0xEB, 0x30, 0xE7, 0x05, 0x90, 0x9E, 0x8B, 0x80, 0x42, 0xEB, 0x30, 0xE6, 0x05, 0x90, 0x9E, 0x8A, +0x80, 0x39, 0xEB, 0x30, 0xE5, 0x05, 0x90, 0x9E, 0x89, 0x80, 0x30, 0xEB, 0x30, 0xE4, 0x05, 0x90, +0x9E, 0x88, 0x80, 0x27, 0xEB, 0x30, 0xE3, 0x05, 0x90, 0x9E, 0x87, 0x80, 0x1E, 0xEB, 0x30, 0xE2, +0x05, 0x90, 0x9E, 0x86, 0x80, 0x15, 0xEB, 0x30, 0xE1, 0x05, 0x90, 0x9E, 0x85, 0x80, 0x0C, 0xEB, +0x30, 0xE0, 0x05, 0x90, 0x9E, 0x84, 0x80, 0x03, 0x90, 0x9E, 0x83, 0xE0, 0x04, 0xF0, 0xAF, 0x04, +0xAD, 0x52, 0x12, 0x76, 0x33, 0x0C, 0xEC, 0x64, 0x80, 0x60, 0x02, 0x81, 0x8F, 0x22, 0x90, 0x9D, +0xBA, 0xE0, 0x60, 0x45, 0x90, 0x9D, 0xB8, 0xE0, 0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, +0x12, 0x90, 0x01, 0x3B, 0xE0, 0x30, 0xE4, 0x0B, 0xD1, 0x3D, 0x90, 0x9D, 0xBF, 0xE0, 0x14, 0x90, +0x05, 0x73, 0xF0, 0x90, 0x9E, 0xAC, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x48, 0x9F, 0xC3, 0x90, 0x9E, +0xAD, 0xE0, 0x94, 0x80, 0x90, 0x9E, 0xAC, 0xE0, 0x64, 0x80, 0x94, 0x80, 0x40, 0x0B, 0x90, 0x01, +0x98, 0xE0, 0x54, 0xFE, 0xF0, 0xE0, 0x44, 0x01, 0xF0, 0x12, 0x63, 0x03, 0x12, 0x60, 0x85, 0xE4, +0xFF, 0x91, 0x43, 0x12, 0x73, 0x7B, 0x90, 0x9E, 0x91, 0xE0, 0x04, 0xF0, 0x22, 0x7D, 0x02, 0x7F, +0x02, 0xD1, 0x47, 0x7D, 0x01, 0x7F, 0x02, 0x74, 0x15, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, +0xFE, 0xF6, 0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0x90, +0x9D, 0xBC, 0xE0, 0x64, 0x06, 0x60, 0x22, 0xD1, 0x8A, 0x90, 0x9D, 0xB8, 0xE0, 0x13, 0x13, 0x13, +0x54, 0x1F, 0x30, 0xE0, 0x14, 0x90, 0x9D, 0xBF, 0xE0, 0xFF, 0xA3, 0xE0, 0x6F, 0x70, 0x0A, 0xF1, +0x6E, 0xD1, 0x3D, 0x90, 0x9D, 0xC0, 0xE0, 0x14, 0xF0, 0x22, 0x90, 0x9D, 0x36, 0xE0, 0x64, 0x01, +0x60, 0x02, 0xE1, 0x1E, 0x90, 0x9D, 0xBA, 0xE0, 0x70, 0x02, 0xE1, 0x1E, 0x90, 0x9D, 0xB9, 0xE0, +0xC4, 0x54, 0x0F, 0x64, 0x01, 0x70, 0x22, 0x90, 0x06, 0xAB, 0xE0, 0x90, 0x9D, 0xC0, 0xF0, 0x90, +0x06, 0xAA, 0xE0, 0x90, 0x9D, 0xBF, 0xF0, 0xA3, 0xE0, 0xFF, 0x70, 0x08, 0x90, 0x9D, 0xBF, 0xE0, +0xFE, 0xFF, 0x80, 0x00, 0x90, 0x9D, 0xC0, 0xEF, 0xF0, 0x90, 0x9D, 0xB8, 0xE0, 0x44, 0x04, 0xF0, +0xE4, 0x90, 0x9D, 0xC2, 0xF0, 0x90, 0x9D, 0xC4, 0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x01, +0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x90, 0x9D, 0xBD, 0xE0, 0x54, 0xFD, 0xF0, +0x54, 0xEF, 0xF0, 0x90, 0x9D, 0xB9, 0xE0, 0xFF, 0xC4, 0x54, 0x0F, 0x24, 0xFD, 0x50, 0x02, 0x80, +0x03, 0x12, 0x65, 0x6A, 0x90, 0x9D, 0xB8, 0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x0E, +0x90, 0x9D, 0xBF, 0xE0, 0xFF, 0xA3, 0xE0, 0xB5, 0x07, 0x04, 0xF1, 0x6E, 0xD1, 0x43, 0x22, 0x90, +0x9D, 0x36, 0xE0, 0xB4, 0x01, 0x13, 0x90, 0x9D, 0xBA, 0xE0, 0x60, 0x0D, 0x90, 0x9D, 0xBD, 0xE0, +0x54, 0xFE, 0xF0, 0x54, 0x07, 0x70, 0x02, 0xF1, 0xC4, 0x22, 0x90, 0x9D, 0x36, 0xE0, 0xB4, 0x01, +0x15, 0x90, 0x9D, 0xBA, 0xE0, 0x60, 0x0F, 0x90, 0x9D, 0xB9, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, +0x02, 0x80, 0x04, 0x12, 0x64, 0x77, 0x22, 0x12, 0x62, 0xD5, 0xBF, 0x01, 0x10, 0x90, 0x9C, 0x96, +0xE0, 0xFF, 0xE4, 0xFD, 0x12, 0x62, 0x0A, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x22, 0xEF, 0x14, +0x90, 0x05, 0x73, 0xF0, 0x90, 0x01, 0x3F, 0x74, 0x10, 0xF0, 0xFD, 0x7F, 0x03, 0x74, 0x1D, 0x2F, +0xF8, 0xE6, 0x4D, 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, +0xF0, 0x22, 0x90, 0x9D, 0xBA, 0xE0, 0x64, 0x01, 0x70, 0x29, 0x90, 0x9D, 0xB9, 0xE0, 0x54, 0x0F, +0x60, 0x15, 0x90, 0x9D, 0xBC, 0xE0, 0x70, 0x04, 0xFF, 0x12, 0x6A, 0x9A, 0x90, 0x9D, 0xBC, 0xE0, +0x64, 0x0C, 0x60, 0x0F, 0x02, 0x7B, 0x09, 0x90, 0x9D, 0xBC, 0xE0, 0xC3, 0x94, 0x04, 0x50, 0x03, +0x12, 0x55, 0xF1, 0x22, 0x90, 0x9D, 0xBB, 0xE0, 0xFF, 0x7D, 0x01, 0x02, 0x55, 0xF5, 0x75, 0xF0, +0x10, 0xEF, 0x90, 0x81, 0x03, 0x12, 0x49, 0x24, 0xE0, 0x44, 0x40, 0xF0, 0x22, 0xC0, 0xE0, 0xC0, +0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, +0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xDD, 0xF0, +0x74, 0x5F, 0xA3, 0xF0, 0x53, 0x91, 0xDF, 0x51, 0xA8, 0xE5, 0x21, 0x30, 0xE1, 0x02, 0x11, 0x6A, +0xE5, 0x21, 0x30, 0xE2, 0x02, 0x71, 0x37, 0xE5, 0x21, 0x30, 0xE3, 0x02, 0x71, 0x73, 0xE5, 0x22, +0x30, 0xE0, 0x02, 0x31, 0x93, 0xE5, 0x24, 0x30, 0xE1, 0x05, 0x7F, 0x03, 0x12, 0x47, 0x27, 0xE5, +0x24, 0x30, 0xE4, 0x02, 0x11, 0x73, 0xE5, 0x24, 0x30, 0xE5, 0x02, 0x31, 0x16, 0xE5, 0x24, 0x30, +0xE6, 0x02, 0x31, 0xCC, 0x74, 0xDD, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x5F, 0xA3, 0xF0, 0xD0, +0x07, 0xD0, 0x06, 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0xD0, +0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x9D, 0xBA, 0xE0, 0x60, 0x02, +0xB1, 0x0C, 0x22, 0x71, 0xAF, 0x90, 0x9D, 0xBF, 0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0, 0x7D, 0x02, +0x7F, 0x02, 0x12, 0x57, 0xA9, 0x90, 0x9D, 0xCB, 0xE0, 0x30, 0xE0, 0x2D, 0x90, 0x9D, 0x36, 0xE0, +0xB4, 0x01, 0x26, 0x90, 0x9E, 0xBA, 0xE0, 0x04, 0xF0, 0xE0, 0xB4, 0x0A, 0x0B, 0x90, 0x9D, 0xCD, +0xE0, 0x04, 0xF0, 0xE4, 0x90, 0x9E, 0xBA, 0xF0, 0x90, 0x9D, 0xCD, 0xE0, 0xFF, 0x90, 0x9D, 0xCC, +0xE0, 0xB5, 0x07, 0x05, 0xE4, 0xA3, 0xF0, 0x11, 0xBA, 0x22, 0xE4, 0xFF, 0x8F, 0x6F, 0x51, 0xD5, +0xBF, 0x01, 0x1A, 0x90, 0x9C, 0x97, 0xE0, 0xFF, 0x7D, 0x01, 0x51, 0x0A, 0xAD, 0x07, 0xAC, 0x06, +0xAF, 0x6F, 0x91, 0xC1, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x7F, 0x01, 0x22, 0x7F, 0x00, 0x22, +0x90, 0x9D, 0x36, 0xE0, 0x64, 0x01, 0x70, 0x2D, 0x90, 0x9D, 0xB8, 0xE0, 0x54, 0xFD, 0xF0, 0x90, +0x05, 0x22, 0x74, 0x6F, 0xF0, 0x7F, 0x01, 0x11, 0xBC, 0xBF, 0x01, 0x0E, 0x90, 0x9D, 0xB7, 0xE0, +0x44, 0x80, 0xF0, 0x90, 0x9D, 0xBC, 0x74, 0x0E, 0xF0, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, +0x90, 0x01, 0xB8, 0x04, 0xF0, 0x22, 0x90, 0x9D, 0xB7, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x54, 0x03, +0x30, 0xE0, 0x27, 0xEF, 0x54, 0xBF, 0xF0, 0x90, 0x04, 0xE0, 0xE0, 0x90, 0x9D, 0xB8, 0x30, 0xE0, +0x06, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x10, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x01, 0xB9, 0x74, 0x01, +0xF0, 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x12, 0x5F, 0xC4, 0xE4, 0xFF, 0x90, 0x9D, 0xCE, 0xE0, +0x30, 0xE0, 0x3F, 0x90, 0x9D, 0xD2, 0xE0, 0xFD, 0x60, 0x38, 0x74, 0x01, 0x7E, 0x00, 0xA8, 0x07, +0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0x90, 0x04, 0xE0, 0xE0, 0xFB, +0xEF, 0x5B, 0x60, 0x06, 0xE4, 0x90, 0x9D, 0xD2, 0xF0, 0x22, 0x90, 0x9D, 0xD0, 0xE0, 0xB5, 0x05, +0x09, 0x90, 0x01, 0xC7, 0xE0, 0x44, 0x10, 0xF0, 0x41, 0x73, 0x11, 0xBA, 0x90, 0x9D, 0xD2, 0xE0, +0x04, 0xF0, 0x22, 0x91, 0x30, 0x90, 0x9E, 0x77, 0xEF, 0xF0, 0xE0, 0xFC, 0x54, 0x01, 0xFE, 0x90, +0x9D, 0xB7, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEC, 0x30, 0xE6, 0x20, 0x90, 0x01, 0x00, 0xE0, 0xB4, +0xEA, 0x09, 0x7F, 0x01, 0x7E, 0x00, 0x12, 0x32, 0x58, 0x80, 0xF0, 0x90, 0x01, 0x2F, 0xE0, 0x30, +0xE7, 0x03, 0xE4, 0xF0, 0x22, 0x90, 0x01, 0x2F, 0x74, 0x80, 0xF0, 0x22, 0x90, 0x9D, 0xB7, 0xE0, +0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x2C, 0xEF, 0x54, 0x7F, 0xF0, 0x90, 0x04, +0xE0, 0xE0, 0x90, 0x9D, 0xB8, 0x30, 0xE1, 0x06, 0xE0, 0x44, 0x02, 0xF0, 0x80, 0x0F, 0xE0, 0x54, +0xFD, 0xF0, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x04, 0xF0, 0x90, 0x9D, 0xBA, +0xE0, 0x60, 0x03, 0x12, 0x5F, 0xC4, 0x7F, 0x01, 0x21, 0x4C, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, +0xD0, 0x90, 0x9E, 0xAF, 0xED, 0xF0, 0x90, 0x9E, 0xAE, 0xEF, 0xF0, 0xE4, 0xFD, 0xFC, 0x51, 0x8A, +0x7C, 0x00, 0xAD, 0x07, 0x90, 0x9E, 0xAE, 0xE0, 0x90, 0x04, 0x25, 0xF0, 0x90, 0x9E, 0xAF, 0xE0, +0x60, 0x0E, 0x74, 0x0F, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, +0xAF, 0x05, 0x74, 0x08, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE4, 0xF0, 0x74, 0x09, +0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xF0, 0xF0, 0x74, 0x29, 0x2D, 0xF5, +0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xF7, 0xF0, 0xAE, 0x04, 0xAF, 0x05, 0xD0, 0xD0, +0x92, 0xAF, 0x22, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x9C, 0x94, 0xE0, 0x64, 0x02, +0x60, 0x07, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0xE4, 0xFE, 0xEF, 0x25, 0xE0, 0xFD, +0xEF, 0xC3, 0x94, 0x80, 0x90, 0xFD, 0x12, 0x50, 0x04, 0xE4, 0xF0, 0x80, 0x03, 0x74, 0x01, 0xF0, +0x90, 0xFD, 0x10, 0xED, 0xF0, 0xAF, 0x06, 0x22, 0x90, 0x01, 0x3C, 0xE0, 0x55, 0x1D, 0xF5, 0x21, +0xA3, 0xE0, 0x55, 0x1E, 0xF5, 0x22, 0xA3, 0xE0, 0x55, 0x1F, 0xF5, 0x23, 0xA3, 0xE0, 0x55, 0x20, +0xF5, 0x24, 0x90, 0x01, 0x3C, 0xE5, 0x21, 0xF0, 0xA3, 0xE5, 0x22, 0xF0, 0xA3, 0xE5, 0x23, 0xF0, +0xA3, 0xE5, 0x24, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x04, 0x1D, 0xE0, +0x60, 0x1A, 0x90, 0x05, 0x22, 0xE0, 0x54, 0x90, 0x60, 0x07, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x08, +0xF0, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE1, 0xE4, 0x7F, 0x00, 0x80, 0x02, 0x7F, 0x01, 0xD0, 0xD0, +0x92, 0xAF, 0x22, 0x90, 0x9D, 0xCE, 0xE0, 0x30, 0xE0, 0x2C, 0x90, 0x9D, 0xD1, 0xE0, 0x04, 0xF0, +0xE0, 0xFF, 0x90, 0x9D, 0xCF, 0xE0, 0xB5, 0x07, 0x1D, 0x90, 0x06, 0x92, 0xE0, 0x54, 0x1C, 0x70, +0x0A, 0x11, 0xBA, 0x90, 0x9D, 0xD2, 0xE0, 0x04, 0xF0, 0x80, 0x06, 0x90, 0x06, 0x92, 0x74, 0x1C, +0xF0, 0xE4, 0x90, 0x9D, 0xD1, 0xF0, 0x22, 0x90, 0x9D, 0xBA, 0xE0, 0x60, 0x35, 0x90, 0x06, 0x92, +0xE0, 0x30, 0xE0, 0x24, 0xE4, 0xF5, 0x3B, 0x90, 0x9D, 0xC8, 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, +0x3C, 0xE4, 0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x12, 0x2B, 0xF0, 0x90, 0x01, 0x5B, 0x74, 0x05, +0xF0, 0x90, 0x06, 0x92, 0x74, 0x01, 0xF0, 0x22, 0x90, 0x9D, 0xB7, 0xE0, 0x54, 0xF7, 0xF0, 0x12, +0x5F, 0xC4, 0x22, 0x90, 0x9D, 0xBA, 0xE0, 0x60, 0x35, 0x90, 0x06, 0x92, 0xE0, 0x30, 0xE1, 0x24, +0xE4, 0xF5, 0x3B, 0x90, 0x9D, 0xC8, 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x3C, 0xE4, 0xFB, 0xFD, +0x7F, 0x5C, 0x7E, 0x01, 0x12, 0x2B, 0xF0, 0x90, 0x01, 0x5F, 0x74, 0x05, 0xF0, 0x90, 0x06, 0x92, +0x74, 0x02, 0xF0, 0x22, 0x90, 0x9D, 0xB7, 0xE0, 0x54, 0xEF, 0xF0, 0x12, 0x5F, 0xC4, 0x22, 0x90, +0x9D, 0xBA, 0xE0, 0x60, 0x39, 0x90, 0x9D, 0x36, 0xE0, 0x64, 0x01, 0x70, 0x31, 0x90, 0x9D, 0xC0, +0xF0, 0x04, 0x60, 0x2A, 0x90, 0x9D, 0xBD, 0xE0, 0x44, 0x10, 0xF0, 0xE4, 0xF5, 0x3B, 0x90, 0x9D, +0xC1, 0xE0, 0xF5, 0x3C, 0xE4, 0xFB, 0xFD, 0x7F, 0x54, 0x7E, 0x01, 0x12, 0x2B, 0xF0, 0x90, 0x01, +0x57, 0x74, 0x05, 0xF0, 0x90, 0x9D, 0xBC, 0xE0, 0x20, 0xE2, 0x03, 0x12, 0x55, 0xF1, 0x22, 0xEF, +0x60, 0x3D, 0x90, 0x9D, 0x36, 0xE0, 0x64, 0x01, 0x70, 0x35, 0x90, 0x9D, 0xB8, 0xE0, 0x54, 0xFE, +0xF0, 0x90, 0x05, 0x22, 0x74, 0x0F, 0xF0, 0x90, 0x06, 0x04, 0xE0, 0x54, 0xBF, 0xF0, 0xE4, 0xFF, +0x11, 0xBC, 0xBF, 0x01, 0x0E, 0x90, 0x9D, 0xB7, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x9D, 0xBC, 0x74, +0x06, 0xF0, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x22, +0xE4, 0x90, 0x9E, 0x78, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x00, 0x83, 0xE0, 0x90, 0x9E, 0x78, +0xF0, 0x90, 0x00, 0x83, 0xE0, 0xFE, 0x90, 0x9E, 0x78, 0xE0, 0xFF, 0xB5, 0x06, 0x01, 0x22, 0xC3, +0x90, 0x9E, 0x7A, 0xE0, 0x94, 0x64, 0x90, 0x9E, 0x79, 0xE0, 0x94, 0x00, 0x40, 0x0D, 0x90, 0x01, +0xC0, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x9E, 0x78, 0xE0, 0xFF, 0x22, 0x90, 0x9E, 0x79, 0xE4, 0x75, +0xF0, 0x01, 0x12, 0x48, 0x9F, 0x80, 0xC2, 0x90, 0x01, 0x5F, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, +0x08, 0xF0, 0xE4, 0xF5, 0x3B, 0x90, 0x9D, 0xC8, 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x3C, 0xE4, +0xFB, 0xFD, 0x7F, 0x5C, 0x7E, 0x01, 0x12, 0x2B, 0xF0, 0x90, 0x01, 0x5F, 0x74, 0x05, 0xF0, 0x90, +0x06, 0x92, 0x74, 0x02, 0xF0, 0x90, 0x9D, 0xB7, 0xE0, 0x44, 0x10, 0xF0, 0x90, 0x9D, 0xBC, 0xE0, +0xC3, 0x94, 0x0C, 0x50, 0x0B, 0xE4, 0xFD, 0x7F, 0x0C, 0x12, 0x55, 0xF5, 0xE4, 0xFF, 0x11, 0xBC, +0x22, 0x74, 0x09, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0x3F, 0xF0, 0xEF, +0x60, 0x1D, 0x74, 0x29, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x10, 0xF0, +0x74, 0x09, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0x22, 0x74, +0x29, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xEF, 0xF0, 0x74, 0x09, 0x2D, +0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x40, 0xF0, 0x22, 0x90, 0x9D, 0xB7, 0xE0, +0xFF, 0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x11, 0xEF, 0x54, 0xFB, 0xF0, 0x90, 0x9D, 0xBD, 0xE0, +0x54, 0xFD, 0xF0, 0x54, 0x07, 0x70, 0x42, 0x80, 0x3D, 0x90, 0x9D, 0xC2, 0xE0, 0x04, 0xF0, 0x90, +0x9D, 0xBD, 0xE0, 0x54, 0xEF, 0xF0, 0x90, 0x9D, 0xC2, 0xE0, 0xFF, 0xB4, 0x01, 0x02, 0x80, 0x04, +0xEF, 0xB4, 0x02, 0x06, 0x90, 0x05, 0x58, 0xE0, 0x04, 0xF0, 0x90, 0x9D, 0xC6, 0xE0, 0xFF, 0x90, +0x9D, 0xC2, 0xE0, 0xD3, 0x9F, 0x40, 0x0F, 0x90, 0x9D, 0x36, 0xE0, 0xB4, 0x01, 0x0B, 0x90, 0x9D, +0xB8, 0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x12, 0x5F, 0xC4, 0x22, 0x90, 0x06, 0xA9, 0xE0, 0x90, 0x9D, +0xF7, 0xF0, 0xE0, 0x54, 0xC0, 0x70, 0x0D, 0x90, 0x9D, 0xBD, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD, +0xF0, 0x02, 0x5F, 0xC4, 0x90, 0x9D, 0xF7, 0xE0, 0x30, 0xE6, 0x22, 0x90, 0x9D, 0xBA, 0xE0, 0x64, +0x01, 0x70, 0x21, 0x90, 0x9D, 0xBD, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x9D, 0xB9, 0xE0, 0x54, 0x0F, +0x64, 0x02, 0x60, 0x05, 0x12, 0x5F, 0x57, 0x80, 0x0B, 0x91, 0x77, 0x80, 0x07, 0x90, 0x9D, 0xBD, +0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x9D, 0xF7, 0xE0, 0x90, 0x9D, 0xBD, 0x30, 0xE7, 0x25, 0xE0, 0x44, +0x02, 0xF0, 0xE4, 0xF5, 0x3B, 0x90, 0x9D, 0xC7, 0xE0, 0xF5, 0x3C, 0xE4, 0xFB, 0xFD, 0x7F, 0x54, +0x7E, 0x01, 0x12, 0x2B, 0xF0, 0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x9D, 0xB7, 0xE0, 0x44, +0x04, 0xF0, 0x22, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, 0x02, 0x09, 0xE0, 0xFD, 0x12, 0x1F, 0x96, +0xFE, 0xAF, 0x05, 0xED, 0x2E, 0x90, 0x9C, 0x95, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xAF, 0xFF, +0xED, 0x2F, 0x90, 0x9C, 0x96, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xAF, 0xFF, 0xED, 0x2F, 0x90, +0x9C, 0x97, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xAF, 0xFF, 0xED, 0x2F, 0x90, 0x9C, 0x98, 0xF0, +0x90, 0x00, 0x04, 0x12, 0x1F, 0xAF, 0xFF, 0xAE, 0x05, 0xED, 0x2F, 0x90, 0x9C, 0x99, 0xF0, 0x22, +0x90, 0x9D, 0xE7, 0x12, 0x49, 0x39, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xAF, 0xFF, 0xFE, 0x12, 0x1F, +0x96, 0xFD, 0xC3, 0x13, 0x30, 0xE0, 0x12, 0x90, 0x9D, 0xE7, 0x12, 0x49, 0x30, 0x90, 0x00, 0x02, +0x12, 0x1F, 0xAF, 0x90, 0x9D, 0xEB, 0xF0, 0x80, 0x05, 0x90, 0x9D, 0xEB, 0xEF, 0xF0, 0x90, 0x9D, +0xEA, 0xEE, 0xF0, 0x90, 0x9D, 0xEB, 0xE0, 0xFE, 0x90, 0x9D, 0xEA, 0xE0, 0xFF, 0xD3, 0x9E, 0x50, +0x38, 0x90, 0x9D, 0xE7, 0x12, 0x49, 0x30, 0x12, 0x1F, 0x96, 0x54, 0x01, 0xFE, 0x74, 0x36, 0x2F, +0xF5, 0x82, 0xE4, 0x34, 0x9D, 0xF5, 0x83, 0xEE, 0xF0, 0x74, 0x36, 0x2F, 0xF5, 0x82, 0xE4, 0x34, +0x9D, 0xF5, 0x83, 0xE0, 0x70, 0x04, 0xD1, 0xB9, 0x80, 0x07, 0x90, 0x9D, 0xEA, 0xE0, 0xFF, 0xD1, +0xAA, 0x90, 0x9D, 0xEA, 0xE0, 0x04, 0xF0, 0x80, 0xBA, 0x22, 0x75, 0xF0, 0x10, 0xEF, 0x90, 0x81, +0x05, 0x12, 0x49, 0x24, 0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x75, 0xF0, 0x10, 0xEF, 0x90, 0x81, 0x05, +0x12, 0x49, 0x24, 0xE0, 0x44, 0x04, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, +0x1F, 0x96, 0xFF, 0x90, 0x9D, 0xB6, 0xF0, 0xBF, 0x01, 0x12, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xAF, +0x64, 0x01, 0x60, 0x17, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x80, 0x0F, 0x90, 0x00, 0x01, 0x12, +0x1F, 0xAF, 0x64, 0x01, 0x60, 0x05, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, +0x90, 0x00, 0x02, 0x12, 0x1F, 0xAF, 0xFF, 0x30, 0xE0, 0x26, 0x12, 0x1F, 0x96, 0x90, 0x9D, 0xC6, +0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xAF, 0x90, 0x9D, 0xC7, 0xF0, 0xEF, 0x54, 0xFE, 0xFF, 0xA3, +0xE0, 0x54, 0x01, 0x4F, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xAF, 0x90, 0x9D, 0xC9, 0xF0, 0x22, +0x90, 0x9D, 0xC6, 0x74, 0x01, 0xF0, 0xA3, 0x74, 0x03, 0xF0, 0xA3, 0xE0, 0x54, 0x01, 0x44, 0x28, +0xF0, 0xA3, 0x74, 0x05, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x9D, 0xFA, +0x12, 0x49, 0x39, 0x90, 0x9D, 0x30, 0xE0, 0xFF, 0x70, 0x06, 0xA3, 0xE0, 0x64, 0x09, 0x60, 0x0A, +0xEF, 0x14, 0xFF, 0x90, 0x9D, 0x31, 0xE0, 0xB5, 0x07, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, +0xEF, 0x60, 0x09, 0x90, 0x01, 0xC1, 0xE0, 0x44, 0x02, 0xF0, 0x80, 0x73, 0x90, 0x9D, 0x31, 0xE0, +0x75, 0xF0, 0x0F, 0xA4, 0x24, 0x9A, 0xF9, 0x74, 0x9C, 0x35, 0xF0, 0xA8, 0x01, 0xFC, 0x7D, 0x01, +0x90, 0x9D, 0xFA, 0x12, 0x49, 0x30, 0x7E, 0x00, 0x7F, 0x02, 0x12, 0x48, 0x79, 0x90, 0x9D, 0x31, +0xE0, 0x75, 0xF0, 0x0F, 0xA4, 0x24, 0x9C, 0xF9, 0x74, 0x9C, 0x35, 0xF0, 0xFA, 0x7B, 0x01, 0xC0, +0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, 0x9D, 0xFD, 0x12, 0x49, 0x30, 0x8B, 0x40, 0x8A, 0x41, 0x89, +0x42, 0x90, 0x9D, 0xFA, 0x12, 0x49, 0x30, 0x12, 0x1F, 0x96, 0xFF, 0xC4, 0x54, 0x0F, 0xF5, 0x43, +0xD0, 0x01, 0xD0, 0x02, 0xD0, 0x03, 0x12, 0x2B, 0x33, 0x90, 0x9D, 0x31, 0xE0, 0x04, 0xF0, 0xE0, +0x7F, 0x00, 0xB4, 0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x60, 0x05, 0xE4, 0x90, 0x9D, 0x31, 0xF0, 0xD0, +0xD0, 0x92, 0xAF, 0x22, 0x7F, 0x02, 0x90, 0x9D, 0xCA, 0xE0, 0xFE, 0xEF, 0xC3, 0x9E, 0x50, 0x10, +0xEF, 0x25, 0xE0, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE4, 0x03, 0x7F, 0x00, 0x22, 0x0F, 0x80, 0xE6, +0x7F, 0x01, 0x22, 0x90, 0x01, 0x34, 0xE0, 0x55, 0x15, 0xF5, 0x19, 0xA3, 0xE0, 0x55, 0x16, 0xF5, +0x1A, 0xA3, 0xE0, 0x55, 0x17, 0xF5, 0x1B, 0xA3, 0xE0, 0x55, 0x18, 0xF5, 0x1C, 0x90, 0x01, 0x34, +0xE5, 0x19, 0xF0, 0xA3, 0xE5, 0x1A, 0xF0, 0xA3, 0xE5, 0x1B, 0xF0, 0xA3, 0xE5, 0x1C, 0xF0, 0x22, +0x90, 0x9D, 0xB9, 0xE0, 0xFF, 0xC4, 0x54, 0x0F, 0x24, 0xFD, 0x50, 0x02, 0x80, 0x49, 0xEF, 0x54, +0x0F, 0x60, 0x3C, 0x90, 0x01, 0x5B, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x04, 0xF0, 0x11, 0x98, +0xEF, 0x64, 0x01, 0x70, 0x32, 0xF5, 0x3B, 0x90, 0x9D, 0xC8, 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, +0x3C, 0xE4, 0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x12, 0x2B, 0xF0, 0x90, 0x01, 0x5B, 0x74, 0x05, +0xF0, 0x90, 0x06, 0x92, 0x74, 0x01, 0xF0, 0x90, 0x9D, 0xB7, 0xE0, 0x44, 0x08, 0xF0, 0x22, 0x11, +0x98, 0xBF, 0x01, 0x03, 0x12, 0x5F, 0xC4, 0x22, 0x90, 0x04, 0x1A, 0xE0, 0xF4, 0x60, 0x03, 0x7F, +0x00, 0x22, 0x90, 0x04, 0x1B, 0xE0, 0x54, 0x07, 0x64, 0x07, 0x7F, 0x01, 0x60, 0x02, 0x7F, 0x00, +0x22, 0x11, 0x98, 0xEF, 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x01, 0xF0, 0x80, 0x54, +0x90, 0x9D, 0xBD, 0xE0, 0xFF, 0x54, 0x03, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x02, 0xF0, 0x80, +0x43, 0x90, 0x9D, 0xBB, 0xE0, 0xFE, 0xE4, 0xC3, 0x9E, 0x50, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x04, +0xF0, 0x80, 0x31, 0xEF, 0x30, 0xE2, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x80, 0x25, 0x90, +0x9D, 0xBD, 0xE0, 0x30, 0xE4, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x10, 0xF0, 0x80, 0x16, 0x90, 0x9D, +0xB8, 0xE0, 0x13, 0x13, 0x54, 0x3F, 0x20, 0xE0, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x20, 0xF0, 0x80, +0x03, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x04, 0xF0, 0x7F, 0x00, 0x22, 0x90, 0x9D, 0x36, +0xE0, 0x64, 0x01, 0x70, 0x2A, 0x90, 0x9D, 0xBA, 0xE0, 0x60, 0x24, 0x90, 0x01, 0x57, 0xE4, 0xF0, +0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0xE4, 0xF5, 0x3B, 0x90, 0x9D, 0xC7, 0xE0, 0xF5, 0x3C, 0xE4, +0xFB, 0xFD, 0x7F, 0x54, 0x7E, 0x01, 0x12, 0x2B, 0xF0, 0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, 0x22, +0x90, 0x9D, 0x36, 0xE0, 0x64, 0x01, 0x70, 0x26, 0x90, 0x9D, 0xBA, 0xE0, 0x60, 0x20, 0x90, 0x01, +0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x90, 0x9D, 0xB7, 0xE0, 0x54, 0xFB, 0xF0, +0x90, 0x9D, 0xBD, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0x07, 0x70, 0x03, 0x12, 0x5F, 0xC4, 0x22, 0xE4, +0x90, 0x9E, 0xB0, 0xF0, 0xA3, 0xF0, 0x90, 0x05, 0xF8, 0xE0, 0x70, 0x0F, 0xA3, 0xE0, 0x70, 0x0B, +0xA3, 0xE0, 0x70, 0x07, 0xA3, 0xE0, 0x70, 0x03, 0x7F, 0x01, 0x22, 0xD3, 0x90, 0x9E, 0xB1, 0xE0, +0x94, 0xE8, 0x90, 0x9E, 0xB0, 0xE0, 0x94, 0x03, 0x40, 0x0A, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x20, +0xF0, 0x7F, 0x00, 0x22, 0x7F, 0x32, 0x7E, 0x00, 0x12, 0x32, 0x58, 0x90, 0x9E, 0xB0, 0xE4, 0x75, +0xF0, 0x01, 0x12, 0x48, 0x9F, 0x80, 0xBF, 0x90, 0x05, 0x22, 0x74, 0xFF, 0xF0, 0x31, 0x7F, 0x90, +0x01, 0x37, 0x74, 0x02, 0xF0, 0xFD, 0x7F, 0x03, 0x12, 0x57, 0xA9, 0x31, 0xE3, 0xE4, 0x90, 0x9D, +0xBC, 0xF0, 0x22, 0x31, 0x7F, 0x90, 0x00, 0x02, 0xE0, 0x54, 0xFE, 0xFD, 0x7F, 0x02, 0x12, 0x31, +0xE4, 0x90, 0x00, 0x02, 0xE0, 0x44, 0x01, 0xFD, 0x7F, 0x02, 0x12, 0x31, 0xE4, 0x90, 0x00, 0x02, +0xE0, 0x54, 0xFE, 0xF0, 0x7F, 0xB4, 0x7E, 0x08, 0x12, 0x2C, 0xFF, 0xEF, 0x44, 0x40, 0xFF, 0xEC, +0x90, 0x9E, 0xA4, 0x12, 0x20, 0xC0, 0x90, 0x9E, 0xA4, 0x12, 0x49, 0x18, 0x90, 0xAD, 0xBC, 0x12, +0x20, 0xC0, 0x7F, 0xB4, 0x7E, 0x08, 0x12, 0x2E, 0x45, 0x90, 0x01, 0x00, 0x74, 0x3F, 0xF0, 0xA3, +0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x20, 0xF0, 0x22, 0x90, 0x00, 0x10, 0xE0, +0x44, 0x0C, 0xFD, 0x7F, 0x10, 0x12, 0x31, 0xE4, 0x90, 0x00, 0x72, 0xE0, 0x54, 0xF3, 0xFD, 0x7F, +0x72, 0x12, 0x31, 0xE4, 0x90, 0x01, 0x01, 0xE0, 0x44, 0x02, 0xF0, 0x90, 0x01, 0x00, 0x74, 0xFF, +0xF0, 0x90, 0x06, 0xB7, 0x74, 0x09, 0xF0, 0x90, 0x06, 0xB4, 0x74, 0x86, 0xF0, 0x7F, 0xB4, 0x7E, +0x08, 0x12, 0x2C, 0xFF, 0xEF, 0x54, 0xBF, 0xFF, 0xEC, 0x90, 0x9E, 0xA0, 0x12, 0x20, 0xC0, 0x90, +0x9E, 0xA0, 0x12, 0x49, 0x18, 0x90, 0xAD, 0xBC, 0x12, 0x20, 0xC0, 0x7F, 0xB4, 0x7E, 0x08, 0x12, +0x2E, 0x45, 0x90, 0x00, 0x02, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, 0x9E, 0xBB, 0xEF, 0xF0, 0x51, +0x3C, 0x90, 0x9E, 0xBB, 0xE0, 0x60, 0x05, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x9D, 0xBC, 0x74, +0x04, 0xF0, 0x22, 0x51, 0x3C, 0x90, 0x9D, 0xBC, 0x74, 0x0C, 0xF0, 0x22, 0x8F, 0x25, 0xE4, 0x90, +0x9E, 0xB2, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x09, 0xE0, 0x7F, 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, +0xEF, 0x65, 0x25, 0x60, 0x3E, 0xC3, 0x90, 0x9E, 0xB3, 0xE0, 0x94, 0x88, 0x90, 0x9E, 0xB2, 0xE0, +0x94, 0x13, 0x40, 0x08, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x10, 0xF0, 0x22, 0x90, 0x9E, 0xB2, 0xE4, +0x75, 0xF0, 0x01, 0x12, 0x48, 0x9F, 0x7F, 0x14, 0x7E, 0x00, 0x12, 0x32, 0x58, 0xD3, 0x90, 0x9E, +0xB3, 0xE0, 0x94, 0x32, 0x90, 0x9E, 0xB2, 0xE0, 0x94, 0x00, 0x40, 0xB9, 0x90, 0x01, 0xC6, 0xE0, +0x30, 0xE0, 0xB2, 0x22, 0x71, 0x7C, 0x90, 0x00, 0x08, 0xE0, 0x54, 0xEF, 0xFD, 0x7F, 0x08, 0x12, +0x31, 0xE4, 0xE4, 0xFF, 0x80, 0x96, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x71, 0x4F, 0x71, +0x14, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x9D, 0xBC, +0xE0, 0x70, 0x07, 0x71, 0x84, 0xBF, 0x01, 0x02, 0x71, 0x26, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, +0x9D, 0xC3, 0xE0, 0xFD, 0x7F, 0x93, 0x12, 0x31, 0xE4, 0x90, 0x00, 0x08, 0xE0, 0x44, 0x10, 0xFD, +0x7F, 0x08, 0x12, 0x31, 0xE4, 0x7F, 0x01, 0x51, 0xBC, 0x90, 0x00, 0x90, 0xE0, 0x44, 0x01, 0xFD, +0x7F, 0x90, 0x12, 0x31, 0xE4, 0x7F, 0x14, 0x7E, 0x00, 0x02, 0x32, 0x58, 0x90, 0x00, 0x90, 0xE0, +0x20, 0xE0, 0xF9, 0x22, 0x90, 0x02, 0x87, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x01, 0xF0, +0x80, 0x12, 0x90, 0x02, 0x86, 0xE0, 0x20, 0xE1, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, +0x03, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x08, 0xF0, 0x7F, 0x00, 0x22, 0xF5, 0x6D, 0x74, +0x94, 0x25, 0x6B, 0xF5, 0x82, 0xE4, 0x34, 0x9B, 0xF5, 0x83, 0xE5, 0x6D, 0xF0, 0x75, 0xF0, 0x09, +0xE5, 0x6B, 0x90, 0x94, 0x96, 0x12, 0x49, 0x24, 0xE0, 0xF5, 0x6A, 0xE4, 0xFB, 0xAD, 0x6D, 0xAF, +0x6B, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xEF, 0x13, 0x13, 0x13, 0x54, 0x1F, 0xF9, 0xEF, +0x54, 0x07, 0xFE, 0x75, 0xF0, 0x10, 0xEF, 0x90, 0x81, 0x01, 0x12, 0x49, 0x24, 0xE0, 0xFC, 0xEB, +0x70, 0x1F, 0x74, 0x81, 0x29, 0xF5, 0x82, 0xE4, 0x34, 0x93, 0xF5, 0x83, 0xE0, 0xFB, 0x74, 0x01, +0xA8, 0x06, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0x5B, 0xF0, 0x53, 0x04, 0x7F, 0x80, +0x36, 0x74, 0x81, 0x29, 0xF5, 0x82, 0xE4, 0x34, 0x93, 0xF5, 0x83, 0xE0, 0xFC, 0x74, 0x01, 0xA8, +0x06, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0x4C, 0xF0, 0x75, 0xF0, 0x10, 0xEF, 0x90, 0x81, +0x01, 0x12, 0x49, 0x24, 0xE0, 0x54, 0x07, 0xFC, 0xED, 0x90, 0x43, 0x71, 0x93, 0x33, 0x33, 0x33, +0x54, 0xF8, 0x42, 0x04, 0x43, 0x04, 0x80, 0x75, 0xF0, 0x10, 0xEF, 0x90, 0x81, 0x00, 0x12, 0x49, +0x24, 0xED, 0xF0, 0x75, 0xF0, 0x10, 0xEF, 0x90, 0x81, 0x01, 0x12, 0x49, 0x24, 0xEC, 0xF0, 0x75, +0xF0, 0x10, 0xEF, 0x90, 0x81, 0x05, 0x12, 0x49, 0x24, 0xE0, 0x54, 0xFC, 0x45, 0x6A, 0xFE, 0x75, +0xF0, 0x10, 0xEF, 0x90, 0x81, 0x05, 0x12, 0x49, 0x24, 0xEE, 0xF0, 0x7D, 0x01, 0x12, 0x76, 0x33, +0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x8F, 0x6B, 0x90, 0x9E, +0x92, 0xE0, 0x04, 0xF0, 0x75, 0xF0, 0x09, 0xEF, 0x90, 0x94, 0x95, 0x12, 0x49, 0x24, 0xE0, 0x90, +0x9E, 0x9D, 0xF0, 0x12, 0x49, 0x42, 0x6C, 0xD7, 0x00, 0x6C, 0xD7, 0x01, 0x6C, 0xD7, 0x02, 0x6C, +0xD7, 0x03, 0x6C, 0xD7, 0x04, 0x6C, 0xD7, 0x05, 0x6C, 0xD7, 0x06, 0x6C, 0xD7, 0x07, 0x6C, 0xD7, +0x08, 0x6D, 0x39, 0x09, 0x6D, 0x3F, 0x0A, 0x6D, 0x45, 0x0B, 0x6D, 0x4B, 0x0C, 0x6D, 0x51, 0x0D, +0x6D, 0x57, 0x0E, 0x00, 0x00, 0x6D, 0x5F, 0xE4, 0xF5, 0x6C, 0x75, 0xF0, 0x08, 0xE5, 0x6B, 0x90, +0x89, 0x00, 0x12, 0x49, 0x24, 0xE5, 0x82, 0x25, 0x6C, 0xF5, 0x82, 0xE4, 0x35, 0x83, 0xF5, 0x83, +0xE0, 0xFF, 0x90, 0x9E, 0x9D, 0xE0, 0x75, 0xF0, 0x07, 0xA4, 0x24, 0x50, 0xF5, 0x82, 0xE4, 0x34, +0x40, 0xF5, 0x83, 0xE5, 0x82, 0x25, 0x6C, 0xF5, 0x82, 0xE4, 0x35, 0x83, 0xF5, 0x83, 0xE4, 0x93, +0xFE, 0xEF, 0x5E, 0xFF, 0x90, 0x9E, 0x9F, 0xF0, 0x75, 0xF0, 0x08, 0xE5, 0x6B, 0x90, 0x89, 0x00, +0x12, 0x49, 0x24, 0xE5, 0x82, 0x25, 0x6C, 0xF5, 0x82, 0xE4, 0x35, 0x83, 0xF5, 0x83, 0xEF, 0xF0, +0x05, 0x6C, 0xE5, 0x6C, 0xB4, 0x07, 0xA3, 0x80, 0x26, 0xAD, 0x6B, 0x7F, 0x44, 0x80, 0x1C, 0xAD, +0x6B, 0x7F, 0x4C, 0x80, 0x16, 0xAD, 0x6B, 0x7F, 0x8C, 0x80, 0x10, 0xAD, 0x6B, 0x7F, 0x94, 0x80, +0x0A, 0xAD, 0x6B, 0x7F, 0x9C, 0x80, 0x04, 0xAD, 0x6B, 0x7F, 0xA4, 0x7E, 0x04, 0xF1, 0xB4, 0x75, +0xF0, 0x09, 0xE5, 0x6B, 0x90, 0x94, 0x99, 0x12, 0x49, 0x24, 0xE0, 0xFD, 0xE4, 0x90, 0x9E, 0x9B, +0xF0, 0x7C, 0x06, 0x75, 0xF0, 0x08, 0xE5, 0x6B, 0x90, 0x89, 0x00, 0xBC, 0x06, 0x12, 0x12, 0x49, +0x24, 0xE5, 0x82, 0x2C, 0xF5, 0x82, 0xE4, 0x35, 0x83, 0xF5, 0x83, 0xE0, 0x54, 0x0F, 0x80, 0x0E, +0x12, 0x49, 0x24, 0xE5, 0x82, 0x2C, 0xF5, 0x82, 0xE4, 0x35, 0x83, 0xF5, 0x83, 0xE0, 0x90, 0x9E, +0x9E, 0xF0, 0x90, 0x9E, 0x9E, 0xE0, 0x60, 0x64, 0x75, 0x6C, 0x07, 0x74, 0x01, 0x7E, 0x00, 0xA8, +0x6C, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0x90, 0x9E, 0x9E, 0xE0, +0xFB, 0xEF, 0x5B, 0x60, 0x3E, 0xEC, 0x75, 0xF0, 0x08, 0xA4, 0x25, 0x6C, 0x90, 0x9E, 0x9B, 0xF0, +0xBD, 0x01, 0x0C, 0xE0, 0xD3, 0x94, 0x0B, 0x40, 0x06, 0xE0, 0x24, 0x20, 0xF0, 0x80, 0x39, 0xBD, +0x02, 0x0F, 0x90, 0x9E, 0x9B, 0xE0, 0xD3, 0x94, 0x1B, 0x40, 0x06, 0xE0, 0x24, 0x18, 0xF0, 0x80, +0x27, 0xBD, 0x03, 0x24, 0x90, 0x9E, 0x9B, 0xE0, 0xD3, 0x94, 0x1B, 0x40, 0x1B, 0xE0, 0x24, 0x22, +0xF0, 0x80, 0x15, 0x15, 0x6C, 0xE5, 0x6C, 0xC3, 0x94, 0x00, 0x50, 0x9F, 0xEC, 0x60, 0x09, 0x1C, +0xEC, 0xC3, 0x94, 0x00, 0x40, 0x02, 0xA1, 0x73, 0xE4, 0x90, 0x9E, 0x9C, 0xF0, 0xFC, 0x75, 0xF0, +0x08, 0xE5, 0x6B, 0x90, 0x89, 0x00, 0xBC, 0x06, 0x12, 0x12, 0x49, 0x24, 0xE5, 0x82, 0x2C, 0xF5, +0x82, 0xE4, 0x35, 0x83, 0xF5, 0x83, 0xE0, 0x54, 0x0F, 0x80, 0x0E, 0x12, 0x49, 0x24, 0xE5, 0x82, +0x2C, 0xF5, 0x82, 0xE4, 0x35, 0x83, 0xF5, 0x83, 0xE0, 0x90, 0x9E, 0x9E, 0xF0, 0x90, 0x9E, 0x9E, +0xE0, 0x60, 0x63, 0xE4, 0xF5, 0x6C, 0x74, 0x01, 0x7E, 0x00, 0xA8, 0x6C, 0x08, 0x80, 0x05, 0xC3, +0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0x90, 0x9E, 0x9E, 0xE0, 0xFB, 0xEF, 0x5B, 0x60, 0x3E, +0xEC, 0x75, 0xF0, 0x08, 0xA4, 0x25, 0x6C, 0x90, 0x9E, 0x9C, 0xF0, 0xBD, 0x01, 0x0C, 0xE0, 0xD3, +0x94, 0x0B, 0x40, 0x06, 0xE0, 0x24, 0x20, 0xF0, 0x80, 0x34, 0xBD, 0x02, 0x0F, 0x90, 0x9E, 0x9C, +0xE0, 0xD3, 0x94, 0x1B, 0x40, 0x06, 0xE0, 0x24, 0x18, 0xF0, 0x80, 0x22, 0xBD, 0x03, 0x1F, 0x90, +0x9E, 0x9C, 0xE0, 0xD3, 0x94, 0x1B, 0x40, 0x16, 0xE0, 0x24, 0x22, 0xF0, 0x80, 0x10, 0x05, 0x6C, +0xE5, 0x6C, 0x64, 0x08, 0x70, 0xA0, 0x0C, 0xEC, 0x64, 0x07, 0x60, 0x02, 0xC1, 0x1E, 0x90, 0x9E, +0x9B, 0xE0, 0xFF, 0x75, 0xF0, 0x09, 0xE5, 0x6B, 0x90, 0x94, 0x93, 0x12, 0x49, 0x24, 0xEF, 0xF0, +0x90, 0x9E, 0x9C, 0xE0, 0xFE, 0x75, 0xF0, 0x09, 0xE5, 0x6B, 0x90, 0x94, 0x94, 0x12, 0x49, 0x24, +0xEE, 0xF0, 0x75, 0xF0, 0x10, 0xE5, 0x6B, 0x90, 0x81, 0x00, 0x12, 0x49, 0x24, 0xE0, 0xFE, 0x54, +0x7F, 0xF5, 0x6D, 0xEE, 0x54, 0x80, 0xF5, 0x6E, 0xE5, 0x6D, 0xD3, 0x9F, 0x40, 0x08, 0x90, 0x9E, +0x9B, 0xE0, 0x45, 0x6E, 0x71, 0xAD, 0x90, 0x9E, 0x9C, 0xE0, 0xFF, 0xE5, 0x6D, 0xC3, 0x9F, 0x50, +0x05, 0xE5, 0x6E, 0x4F, 0x71, 0xAD, 0x75, 0xF0, 0x10, 0xE5, 0x6B, 0x90, 0x81, 0x03, 0x12, 0x49, +0x24, 0xE4, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x8F, 0x53, 0x90, 0x01, 0xC4, 0x74, 0x28, 0xF0, +0x74, 0x6F, 0xA3, 0xF0, 0x75, 0xF0, 0x10, 0xE5, 0x53, 0x90, 0x81, 0x05, 0x12, 0x49, 0x24, 0xE0, +0x54, 0x03, 0xFD, 0x75, 0xF0, 0x09, 0xE5, 0x53, 0x90, 0x94, 0x93, 0x12, 0x49, 0x24, 0xE0, 0xFF, +0x74, 0x14, 0x25, 0x53, 0xF5, 0x82, 0xE4, 0x34, 0x9C, 0xF5, 0x83, 0xE0, 0x54, 0x7F, 0xF5, 0x54, +0xD3, 0x9F, 0x40, 0x02, 0x8F, 0x54, 0xE5, 0x54, 0x25, 0xE0, 0x24, 0xBD, 0xF5, 0x82, 0xE4, 0x34, +0x42, 0xF5, 0x83, 0xE4, 0x93, 0xFE, 0x74, 0x01, 0x93, 0xFF, 0xE5, 0x54, 0x25, 0xE0, 0x24, 0x15, +0xF5, 0x82, 0xE4, 0x34, 0x42, 0xF5, 0x83, 0x74, 0x01, 0x93, 0x2F, 0xFF, 0xE4, 0x93, 0x3E, 0xC3, +0x13, 0xFE, 0xEF, 0x13, 0xFF, 0xE5, 0x53, 0x25, 0xE0, 0x24, 0x91, 0xF5, 0x82, 0xE4, 0x34, 0x93, +0xF5, 0x83, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x8D, 0x6A, 0xE4, 0xFB, 0xAD, 0x54, 0xAF, 0x53, 0x71, +0xD1, 0xAF, 0x54, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x8E, 0x5D, 0x8F, 0x5E, 0x7F, +0x08, 0x78, 0x5F, 0xE4, 0xF6, 0x08, 0xDF, 0xFC, 0x75, 0xF0, 0x09, 0xED, 0x90, 0x94, 0x99, 0x12, +0x49, 0x24, 0xE0, 0x90, 0x9E, 0xB6, 0xF0, 0x64, 0x01, 0x70, 0x43, 0x75, 0xF0, 0x08, 0xED, 0x90, +0x89, 0x00, 0x12, 0x49, 0x24, 0xE0, 0xF5, 0x5F, 0x75, 0xF0, 0x08, 0xED, 0x90, 0x89, 0x01, 0x12, +0x49, 0x24, 0xE0, 0xFE, 0x54, 0x0F, 0xF5, 0x60, 0xE4, 0xF5, 0x61, 0xF5, 0x62, 0xF5, 0x63, 0xEE, +0x54, 0xF0, 0xF5, 0x64, 0x75, 0xF0, 0x08, 0xED, 0x90, 0x89, 0x02, 0x12, 0x49, 0x24, 0xE0, 0xF5, +0x65, 0x75, 0xF0, 0x08, 0xED, 0x90, 0x89, 0x03, 0x12, 0x49, 0x24, 0xE0, 0xF5, 0x66, 0x90, 0x9E, +0xB6, 0xE0, 0xFE, 0xC3, 0x94, 0x02, 0x40, 0x4A, 0x75, 0xF0, 0x08, 0xED, 0x90, 0x89, 0x00, 0x12, +0x49, 0x24, 0xE0, 0xF5, 0x5F, 0x75, 0xF0, 0x08, 0xED, 0x90, 0x89, 0x01, 0x12, 0x49, 0x24, 0xE0, +0xF5, 0x60, 0x75, 0xF0, 0x08, 0xED, 0x90, 0x89, 0x02, 0x12, 0x49, 0x24, 0xE0, 0xF5, 0x61, 0x75, +0xF0, 0x08, 0xED, 0x90, 0x89, 0x03, 0x12, 0x49, 0x24, 0xE0, 0xFC, 0x54, 0x0F, 0xF5, 0x62, 0xEC, +0x54, 0xF0, 0xF9, 0xEE, 0xB4, 0x03, 0x09, 0xE9, 0x25, 0xE0, 0x25, 0xE0, 0xF5, 0x66, 0x80, 0x02, +0x89, 0x65, 0xE4, 0xFF, 0x74, 0x5F, 0x2F, 0xF8, 0xE6, 0xFE, 0xEF, 0x7A, 0x00, 0x25, 0x5E, 0xFB, +0xEA, 0x35, 0x5D, 0x8B, 0x82, 0xF5, 0x83, 0xE0, 0x5E, 0xF6, 0x0F, 0xBF, 0x08, 0xE6, 0xE5, 0x64, +0xC4, 0x54, 0x0F, 0x70, 0x08, 0xE5, 0x65, 0x70, 0x04, 0xE5, 0x66, 0x60, 0x24, 0x90, 0x9E, 0xB6, +0xE0, 0xB4, 0x01, 0x1D, 0xE5, 0x60, 0x54, 0x0F, 0xF9, 0xE5, 0x64, 0x54, 0xF0, 0x42, 0x01, 0x89, +0x60, 0x85, 0x65, 0x61, 0x85, 0x66, 0x62, 0xE4, 0xF5, 0x63, 0xF5, 0x64, 0xF5, 0x65, 0x75, 0x66, +0x80, 0x90, 0x9E, 0xB6, 0xE0, 0xFE, 0xC3, 0x94, 0x02, 0x40, 0x15, 0xEE, 0xB4, 0x02, 0x06, 0xE5, +0x65, 0x42, 0x62, 0x80, 0x08, 0xE5, 0x66, 0x13, 0x13, 0x54, 0x3F, 0x42, 0x62, 0x75, 0x66, 0x80, +0xE4, 0xFF, 0x74, 0x5F, 0x2F, 0xF8, 0xE6, 0xFE, 0x75, 0xF0, 0x08, 0xED, 0x90, 0x89, 0x00, 0x12, +0x49, 0x24, 0xE5, 0x82, 0x2F, 0xF5, 0x82, 0xE4, 0x35, 0x83, 0xF5, 0x83, 0xEE, 0xF0, 0x0F, 0xBF, +0x08, 0xE0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x8F, 0x5B, 0x90, 0x01, 0xC4, 0x74, 0x07, 0xF0, 0x74, +0x71, 0xA3, 0xF0, 0x75, 0xF0, 0x10, 0xE5, 0x5B, 0x90, 0x81, 0x00, 0x12, 0x49, 0x24, 0xE0, 0xF5, +0x5C, 0x54, 0x7F, 0xFD, 0x75, 0xF0, 0x09, 0xE5, 0x5B, 0x90, 0x94, 0x93, 0x12, 0x49, 0x24, 0xE0, +0xFF, 0x90, 0x9D, 0xFF, 0xF0, 0x75, 0xF0, 0x09, 0xE5, 0x5B, 0x90, 0x94, 0x99, 0x12, 0x49, 0x24, +0xE0, 0x90, 0x9E, 0x00, 0xF0, 0xED, 0x25, 0xE0, 0x24, 0x15, 0xF5, 0x82, 0xE4, 0x34, 0x42, 0xF5, +0x83, 0xE4, 0x93, 0xFA, 0x74, 0x01, 0x93, 0xFB, 0xE5, 0x5B, 0x25, 0xE0, 0x24, 0x91, 0xF5, 0x82, +0xE4, 0x34, 0x93, 0xF5, 0x83, 0xEA, 0xF0, 0xA3, 0xEB, 0xF0, 0x75, 0xF0, 0x09, 0xE5, 0x5B, 0x90, +0x94, 0x96, 0x12, 0x49, 0x24, 0xE0, 0xF9, 0xED, 0xC3, 0x9F, 0x40, 0x02, 0x41, 0x9C, 0x74, 0x14, +0x25, 0x5B, 0xF5, 0x82, 0xE4, 0x34, 0x9C, 0xF5, 0x83, 0xED, 0xF0, 0x90, 0x9E, 0x00, 0xE0, 0xFF, +0xB4, 0x01, 0x0C, 0xED, 0xC3, 0x94, 0x2C, 0x40, 0x06, 0x74, 0xE0, 0x2D, 0xFD, 0x80, 0x1E, 0xEF, +0xB4, 0x02, 0x0C, 0xED, 0xC3, 0x94, 0x2C, 0x40, 0x06, 0x74, 0xE8, 0x2D, 0xFD, 0x80, 0x0E, 0xEF, +0xB4, 0x03, 0x0A, 0xED, 0xC3, 0x94, 0x2C, 0x40, 0x04, 0x74, 0xDE, 0x2D, 0xFD, 0xEF, 0xB4, 0x01, +0x0F, 0x90, 0x9D, 0xFF, 0xE0, 0xC3, 0x94, 0x2C, 0x40, 0x06, 0xE0, 0x24, 0xE0, 0xF0, 0x80, 0x2A, +0x90, 0x9E, 0x00, 0xE0, 0xB4, 0x02, 0x0F, 0x90, 0x9D, 0xFF, 0xE0, 0xC3, 0x94, 0x2C, 0x40, 0x06, +0xE0, 0x24, 0xE8, 0xF0, 0x80, 0x14, 0x90, 0x9E, 0x00, 0xE0, 0xB4, 0x03, 0x0D, 0x90, 0x9D, 0xFF, +0xE0, 0xC3, 0x94, 0x2C, 0x40, 0x04, 0xE0, 0x24, 0xDE, 0xF0, 0xED, 0x04, 0xFC, 0x90, 0x9D, 0xFF, +0xE0, 0xFF, 0xEC, 0xD3, 0x9F, 0x50, 0x46, 0xEC, 0x13, 0x13, 0x13, 0x54, 0x1F, 0xFF, 0x75, 0xF0, +0x08, 0xE5, 0x5B, 0x90, 0x89, 0x00, 0x12, 0x49, 0x24, 0xE5, 0x82, 0x2F, 0xF5, 0x82, 0xE4, 0x35, +0x83, 0xF5, 0x83, 0xE0, 0xFB, 0x7A, 0x00, 0xEC, 0x54, 0x07, 0xFF, 0x74, 0x01, 0x7E, 0x00, 0xA8, +0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0xEE, 0x5A, 0xFE, 0xEF, +0x5B, 0x4E, 0x60, 0x06, 0xAD, 0x04, 0x8D, 0x5C, 0x80, 0x03, 0x0C, 0x80, 0xB0, 0x90, 0x9E, 0x00, +0xE0, 0xFF, 0xB4, 0x01, 0x19, 0xE5, 0x5C, 0xD3, 0x94, 0x0B, 0x40, 0x12, 0xE5, 0x5C, 0x94, 0x34, +0x50, 0x0C, 0x74, 0x20, 0x25, 0x5C, 0xF5, 0x5C, 0x74, 0x20, 0x2D, 0xFD, 0x80, 0x61, 0xEF, 0xB4, +0x02, 0x13, 0xE5, 0x5C, 0xD3, 0x94, 0x1B, 0x40, 0x0C, 0x74, 0x18, 0x25, 0x5C, 0xF5, 0x5C, 0x74, +0x18, 0x2D, 0xFD, 0x80, 0x4A, 0xEF, 0xB4, 0x03, 0x11, 0xE5, 0x5C, 0xD3, 0x94, 0x1B, 0x40, 0x3F, +0x74, 0x22, 0x25, 0x5C, 0xF5, 0x5C, 0x74, 0x22, 0x2D, 0xFD, 0x80, 0x33, 0x90, 0x9D, 0xFF, 0xE0, +0xFC, 0x6D, 0x70, 0x6C, 0x74, 0x14, 0x25, 0x5B, 0xF5, 0x82, 0xE4, 0x34, 0x9C, 0xF5, 0x83, 0xED, +0xF0, 0x75, 0xF0, 0x09, 0xE5, 0x5B, 0x90, 0x94, 0x97, 0x12, 0x49, 0x24, 0xE0, 0xB4, 0x01, 0x0C, +0xE5, 0x5C, 0x20, 0xE7, 0x07, 0xED, 0x44, 0x80, 0xF5, 0x5C, 0x80, 0x03, 0xAF, 0x5C, 0x22, 0xED, +0x25, 0xE0, 0x24, 0xBD, 0xF5, 0x82, 0xE4, 0x34, 0x42, 0xF5, 0x83, 0xE4, 0x93, 0xFE, 0x74, 0x01, +0x93, 0xFF, 0xED, 0x25, 0xE0, 0x24, 0x15, 0xF5, 0x82, 0xE4, 0x34, 0x42, 0xF5, 0x83, 0x74, 0x01, +0x93, 0x2F, 0xFF, 0xE4, 0x93, 0x3E, 0xC3, 0x13, 0xFE, 0xEF, 0x13, 0xFF, 0xE5, 0x5B, 0x25, 0xE0, +0x24, 0x91, 0xF5, 0x82, 0xE4, 0x34, 0x93, 0xF5, 0x83, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x80, 0x5D, +0xED, 0xD3, 0x9C, 0x40, 0x58, 0x90, 0x9D, 0xFF, 0xE0, 0xFF, 0x74, 0x14, 0x25, 0x5B, 0xF5, 0x82, +0xE4, 0x34, 0x9C, 0xF5, 0x83, 0xEF, 0xF0, 0xAD, 0x07, 0x8F, 0x5C, 0xED, 0x25, 0xE0, 0x24, 0xBD, +0xF5, 0x82, 0xE4, 0x34, 0x42, 0xF5, 0x83, 0xE4, 0x93, 0xFE, 0x74, 0x01, 0x93, 0xFF, 0xED, 0x25, +0xE0, 0x24, 0x15, 0xF5, 0x82, 0xE4, 0x34, 0x42, 0xF5, 0x83, 0x74, 0x01, 0x93, 0x2F, 0xFF, 0xE4, +0x93, 0x3E, 0xC3, 0x13, 0xFE, 0xEF, 0x13, 0xFF, 0xE5, 0x5B, 0x25, 0xE0, 0x24, 0x91, 0xF5, 0x82, +0xE4, 0x34, 0x93, 0xF5, 0x83, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xAF, 0x5C, 0x22, 0x89, 0x6A, 0x7B, +0x01, 0xAD, 0x5C, 0xAF, 0x5B, 0x12, 0x6B, 0xD1, 0xAF, 0x5C, 0x22, 0x90, 0x01, 0xC4, 0x74, 0x7B, +0xF0, 0x74, 0x73, 0xA3, 0xF0, 0xE4, 0xF5, 0x52, 0x90, 0x9D, 0x36, 0xE0, 0x70, 0x02, 0xC1, 0x27, +0x75, 0xF0, 0x09, 0xE5, 0x52, 0x90, 0x94, 0x98, 0x12, 0x49, 0x24, 0xE0, 0x64, 0x01, 0x60, 0x02, +0xC1, 0x27, 0xE5, 0x52, 0x25, 0xE0, 0x24, 0x01, 0xF5, 0x82, 0xE4, 0x34, 0x92, 0xF5, 0x83, 0xE0, +0xFE, 0xA3, 0xE0, 0xD3, 0x94, 0x00, 0xEE, 0x94, 0x00, 0x50, 0x02, 0xC1, 0x27, 0xE5, 0x52, 0x75, +0xF0, 0x0A, 0xA4, 0x24, 0x01, 0xF9, 0x74, 0x8D, 0x35, 0xF0, 0x75, 0x56, 0x01, 0xF5, 0x57, 0x89, +0x58, 0xE5, 0x52, 0x25, 0xE0, 0x24, 0x01, 0xF5, 0x82, 0xE4, 0x34, 0x92, 0xF5, 0x83, 0xE0, 0xFF, +0xA3, 0xE0, 0x90, 0x9D, 0xF9, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x74, 0x93, 0x25, 0x52, 0xF5, 0x82, +0xE4, 0x34, 0x99, 0xF5, 0x83, 0xE0, 0xFF, 0x90, 0x9D, 0xFB, 0xE4, 0xF0, 0xA3, 0xEF, 0xF0, 0x75, +0xF0, 0x10, 0xE5, 0x52, 0x90, 0x81, 0x00, 0x12, 0x49, 0x24, 0xE0, 0x54, 0x7F, 0x90, 0x9D, 0xF7, +0xF0, 0x54, 0x7F, 0xA3, 0xF0, 0x75, 0xF0, 0x09, 0xE5, 0x52, 0x90, 0x94, 0x93, 0x12, 0x49, 0x24, +0xE0, 0x90, 0x9D, 0xFE, 0xF0, 0x74, 0x14, 0x25, 0x52, 0xF5, 0x82, 0xE4, 0x34, 0x9B, 0xF5, 0x83, +0xE0, 0xC3, 0x94, 0x05, 0x40, 0x02, 0xC1, 0x21, 0x90, 0x9D, 0xFE, 0xE0, 0xFF, 0x90, 0x9D, 0xF8, +0xE0, 0x9F, 0x40, 0x13, 0x90, 0x9D, 0xFE, 0xE0, 0x90, 0x9D, 0xF8, 0xF0, 0x90, 0x9D, 0xF7, 0xE0, +0x54, 0x80, 0xFE, 0xF0, 0xEF, 0x4E, 0xF0, 0x90, 0x9D, 0xF8, 0xE0, 0xFF, 0x90, 0x41, 0xC1, 0x93, +0xFE, 0x74, 0x13, 0x25, 0x52, 0xF5, 0x82, 0xE4, 0x34, 0x9A, 0xF5, 0x83, 0xE0, 0xC3, 0x9E, 0x40, +0x06, 0xEF, 0x90, 0x41, 0x19, 0x80, 0x07, 0x90, 0x9D, 0xF8, 0xE0, 0x90, 0x41, 0x6D, 0x93, 0x90, +0x9D, 0xFD, 0xF0, 0x90, 0x9D, 0xFD, 0xE0, 0x75, 0xF0, 0x06, 0xA4, 0x24, 0x8F, 0xF9, 0x74, 0x40, +0x35, 0xF0, 0x75, 0x53, 0xFF, 0xF5, 0x54, 0x89, 0x55, 0x90, 0x9D, 0xF7, 0xE0, 0x90, 0x43, 0xC5, +0x93, 0xFF, 0xD3, 0x90, 0x9D, 0xFC, 0xE0, 0x9F, 0x90, 0x9D, 0xFB, 0xE0, 0x94, 0x00, 0x40, 0x02, +0xC1, 0x1B, 0xE5, 0x52, 0x25, 0xE0, 0x24, 0x91, 0xF5, 0x82, 0xE4, 0x34, 0x93, 0xF5, 0x83, 0xE0, +0xF5, 0x59, 0xA3, 0xE0, 0xF5, 0x5A, 0xAB, 0x53, 0xAA, 0x54, 0xA9, 0x55, 0x12, 0x1F, 0x96, 0xFF, +0x7E, 0x00, 0xAB, 0x56, 0xAA, 0x57, 0xA9, 0x58, 0x12, 0x48, 0xB5, 0xFD, 0xAC, 0xF0, 0x12, 0x20, +0x10, 0xEF, 0x25, 0x5A, 0xF5, 0x5A, 0xEE, 0x35, 0x59, 0xF5, 0x59, 0xAB, 0x53, 0xAA, 0x54, 0xA9, +0x55, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xAF, 0xFF, 0x7E, 0x00, 0xAB, 0x56, 0xAA, 0x57, 0xA9, 0x58, +0x90, 0x00, 0x02, 0x12, 0x48, 0xE0, 0xFD, 0xAC, 0xF0, 0x12, 0x20, 0x10, 0xEF, 0x25, 0x5A, 0xF5, +0x5A, 0xEE, 0x35, 0x59, 0xF5, 0x59, 0xAB, 0x53, 0xAA, 0x54, 0xA9, 0x55, 0x90, 0x00, 0x02, 0x12, +0x1F, 0xAF, 0xFF, 0x7E, 0x00, 0xAB, 0x56, 0xAA, 0x57, 0xA9, 0x58, 0x90, 0x00, 0x04, 0x12, 0x48, +0xE0, 0xFD, 0xAC, 0xF0, 0x12, 0x20, 0x10, 0xEF, 0x25, 0x5A, 0xF5, 0x5A, 0xEE, 0x35, 0x59, 0xF5, +0x59, 0xAB, 0x53, 0xAA, 0x54, 0xA9, 0x55, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xAF, 0xFF, 0x7E, 0x00, +0xAB, 0x56, 0xAA, 0x57, 0xA9, 0x58, 0x90, 0x00, 0x06, 0x12, 0x48, 0xE0, 0xFD, 0xAC, 0xF0, 0x12, +0x20, 0x10, 0xEF, 0x25, 0x5A, 0xF5, 0x5A, 0xEE, 0x35, 0x59, 0xF5, 0x59, 0xAB, 0x53, 0xAA, 0x54, +0xA9, 0x55, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xAF, 0xFF, 0x7E, 0x00, 0xAB, 0x56, 0xAA, 0x57, 0xA9, +0x58, 0x90, 0x00, 0x08, 0x12, 0x48, 0xE0, 0xFD, 0xAC, 0xF0, 0x12, 0x20, 0x10, 0xEF, 0x25, 0x5A, +0xF5, 0x5A, 0xEE, 0x35, 0x59, 0xF5, 0x59, 0xAB, 0x53, 0xAA, 0x54, 0xA9, 0x55, 0x90, 0x00, 0x05, +0x12, 0x1F, 0xAF, 0xFF, 0x7E, 0x00, 0x90, 0x9D, 0xF9, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0x12, 0x20, +0x10, 0xD3, 0xE5, 0x5A, 0x9F, 0xE5, 0x59, 0x9E, 0x40, 0x0C, 0xE5, 0x5A, 0x9F, 0xF5, 0x5A, 0xE5, +0x59, 0x9E, 0xF5, 0x59, 0x80, 0x05, 0xE4, 0xF5, 0x59, 0xF5, 0x5A, 0xE5, 0x52, 0x25, 0xE0, 0x24, +0x91, 0xF5, 0x82, 0xE4, 0x34, 0x93, 0xF5, 0x83, 0xE5, 0x59, 0xF0, 0xA3, 0xE5, 0x5A, 0xF0, 0x90, +0x9D, 0xF7, 0xE0, 0x25, 0xE0, 0x24, 0x15, 0xF5, 0x82, 0xE4, 0x34, 0x42, 0xF5, 0x83, 0xC3, 0x74, +0x01, 0x93, 0x95, 0x5A, 0xE4, 0x93, 0x95, 0x59, 0x50, 0x06, 0xAF, 0x52, 0x31, 0x07, 0x80, 0x21, +0x90, 0x9D, 0xF7, 0xE0, 0x25, 0xE0, 0x24, 0xBD, 0xF5, 0x82, 0xE4, 0x34, 0x42, 0xF5, 0x83, 0xD3, +0x74, 0x01, 0x93, 0x95, 0x5A, 0xE4, 0x93, 0x95, 0x59, 0x40, 0x06, 0x7D, 0x01, 0xAF, 0x52, 0xD1, +0xC5, 0xE4, 0xFD, 0xAF, 0x52, 0xD1, 0x33, 0x05, 0x52, 0xE5, 0x52, 0xC3, 0x94, 0x80, 0x50, 0x02, +0x61, 0x88, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xED, 0x60, 0x62, 0x75, 0xF0, 0x0A, +0xEF, 0x90, 0x8D, 0x01, 0x12, 0x49, 0x24, 0xE4, 0xF0, 0xA3, 0xF0, 0x75, 0xF0, 0x0A, 0xEF, 0x90, +0x8D, 0x03, 0x12, 0x49, 0x24, 0xE4, 0xF0, 0xA3, 0xF0, 0x75, 0xF0, 0x0A, 0xEF, 0x90, 0x8D, 0x05, +0x12, 0x49, 0x24, 0xE4, 0xF0, 0xA3, 0xF0, 0x75, 0xF0, 0x0A, 0xEF, 0x90, 0x8D, 0x07, 0x12, 0x49, +0x24, 0xE4, 0xF0, 0xA3, 0xF0, 0x75, 0xF0, 0x0A, 0xEF, 0x90, 0x8D, 0x09, 0x12, 0x49, 0x24, 0xE4, +0xF0, 0xA3, 0xF0, 0xEF, 0x25, 0xE0, 0x24, 0x01, 0xF5, 0x82, 0xE4, 0x34, 0x92, 0xF5, 0x83, 0xE4, +0xF0, 0xA3, 0xF0, 0x74, 0x93, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x99, 0xF5, 0x83, 0xE4, 0xF0, 0x75, +0xF0, 0x10, 0xEF, 0x90, 0x81, 0x03, 0x12, 0x49, 0x24, 0xE0, 0x54, 0xBF, 0x90, 0x9E, 0xB7, 0xF0, +0x44, 0x80, 0xFE, 0xF0, 0x75, 0xF0, 0x10, 0xEF, 0x90, 0x81, 0x03, 0x12, 0x49, 0x24, 0xEE, 0xF0, +0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x8F, 0x5B, 0x90, 0x01, 0xC4, 0x74, 0xC5, 0xF0, 0x74, 0x76, 0xA3, +0xF0, 0x75, 0xF0, 0x10, 0xE5, 0x5B, 0x90, 0x81, 0x00, 0x12, 0x49, 0x24, 0xE0, 0xF5, 0x5C, 0x54, +0x7F, 0xFF, 0x90, 0x9E, 0x01, 0xF0, 0x75, 0xF0, 0x09, 0xE5, 0x5B, 0x90, 0x94, 0x94, 0x12, 0x49, +0x24, 0xE0, 0x90, 0x9E, 0x03, 0xF0, 0x75, 0xF0, 0x09, 0xE5, 0x5B, 0x90, 0x94, 0x93, 0x12, 0x49, +0x24, 0xE0, 0xFE, 0x90, 0x9E, 0x04, 0xF0, 0x75, 0xF0, 0x10, 0xE5, 0x5B, 0x90, 0x81, 0x05, 0x12, +0x49, 0x24, 0xE0, 0x54, 0x03, 0xFC, 0x75, 0xF0, 0x09, 0xE5, 0x5B, 0x90, 0x94, 0x99, 0x12, 0x49, +0x24, 0xE0, 0xFB, 0xEF, 0xD3, 0x9E, 0x40, 0x0A, 0x90, 0x9E, 0x04, 0xE0, 0x90, 0x9E, 0x01, 0xF0, +0xF5, 0x5C, 0xED, 0x70, 0x03, 0x02, 0x78, 0xC8, 0x90, 0x9E, 0x02, 0xED, 0xF0, 0xE5, 0x5C, 0x30, +0xE7, 0x0A, 0x90, 0x9E, 0x01, 0xE0, 0xF5, 0x5C, 0xA3, 0xE0, 0x14, 0xF0, 0x90, 0x9E, 0x02, 0xE0, +0x70, 0x03, 0x02, 0x78, 0xC8, 0x90, 0x9E, 0x01, 0xE0, 0xFF, 0xB4, 0x2C, 0x08, 0xEC, 0x60, 0x05, +0x1C, 0xA3, 0xE0, 0x14, 0xF0, 0x90, 0x9E, 0x02, 0xE0, 0x70, 0x03, 0x02, 0x78, 0xC8, 0x90, 0x9E, +0x03, 0xE0, 0xFE, 0xEF, 0xD3, 0x9E, 0x50, 0x03, 0x02, 0x78, 0xC2, 0xE4, 0x90, 0x9E, 0x00, 0xF0, +0xBB, 0x01, 0x0F, 0xA3, 0xE0, 0xC3, 0x94, 0x2C, 0x40, 0x08, 0xE0, 0x24, 0xE0, 0xF0, 0x74, 0xE0, +0x80, 0x26, 0xBB, 0x02, 0x11, 0x90, 0x9E, 0x01, 0xE0, 0xC3, 0x94, 0x2C, 0x40, 0x08, 0xE0, 0x24, +0xE8, 0xF0, 0x74, 0xE8, 0x80, 0x12, 0xBB, 0x03, 0x13, 0x90, 0x9E, 0x01, 0xE0, 0xC3, 0x94, 0x2C, +0x40, 0x0A, 0xE0, 0x24, 0xDE, 0xF0, 0x74, 0xDE, 0x25, 0x5C, 0xF5, 0x5C, 0xBB, 0x01, 0x0F, 0xEE, +0xC3, 0x94, 0x2C, 0x40, 0x09, 0x90, 0x9E, 0x03, 0xE0, 0x24, 0xE0, 0xF0, 0x80, 0x22, 0xBB, 0x02, +0x0F, 0x90, 0x9E, 0x03, 0xE0, 0xC3, 0x94, 0x2C, 0x40, 0x06, 0xE0, 0x24, 0xE8, 0xF0, 0x80, 0x10, +0xBB, 0x03, 0x0D, 0x90, 0x9E, 0x03, 0xE0, 0xC3, 0x94, 0x2C, 0x40, 0x04, 0xE0, 0x24, 0xDE, 0xF0, +0x90, 0x9E, 0x01, 0xE0, 0x14, 0x90, 0x9D, 0xFF, 0xF0, 0x90, 0x9E, 0x03, 0xE0, 0xFF, 0x90, 0x9D, +0xFF, 0xE0, 0xF9, 0xC3, 0x9F, 0x40, 0x6A, 0xE9, 0x13, 0x13, 0x13, 0x54, 0x1F, 0xFF, 0x75, 0xF0, +0x08, 0xE5, 0x5B, 0x90, 0x89, 0x00, 0x12, 0x49, 0x24, 0xE5, 0x82, 0x2F, 0xF5, 0x82, 0xE4, 0x35, +0x83, 0xF5, 0x83, 0xE0, 0xF5, 0x82, 0x75, 0x83, 0x00, 0xE9, 0x54, 0x07, 0xFF, 0x74, 0x01, 0x7E, +0x00, 0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0xEE, 0x55, +0x83, 0xFE, 0xEF, 0x55, 0x82, 0x4E, 0x60, 0x29, 0x90, 0x9D, 0xFF, 0xE0, 0xF5, 0x5C, 0xA3, 0xE0, +0x04, 0xF0, 0x90, 0x9E, 0x02, 0xE0, 0xFF, 0x90, 0x9E, 0x00, 0xE0, 0x6F, 0x60, 0x13, 0x90, 0x9E, +0x03, 0xE0, 0xFF, 0xE5, 0x5C, 0xD3, 0x9F, 0x40, 0x08, 0x90, 0x9D, 0xFF, 0xE0, 0x14, 0xF0, 0x80, +0x88, 0xBB, 0x01, 0x1C, 0xE5, 0x5C, 0xD3, 0x94, 0x0B, 0x40, 0x15, 0xE5, 0x5C, 0x94, 0x34, 0x50, +0x0F, 0x74, 0x20, 0x25, 0x5C, 0xF5, 0x5C, 0x90, 0x9E, 0x01, 0xE0, 0x24, 0x20, 0xF0, 0x80, 0x38, +0xBB, 0x02, 0x16, 0xE5, 0x5C, 0xD3, 0x94, 0x1B, 0x40, 0x0F, 0x74, 0x18, 0x25, 0x5C, 0xF5, 0x5C, +0x90, 0x9E, 0x01, 0xE0, 0x24, 0x18, 0xF0, 0x80, 0x1F, 0xBB, 0x03, 0x1C, 0xE5, 0x5C, 0xD3, 0x94, +0x1B, 0x40, 0x15, 0x74, 0x22, 0x25, 0x5C, 0xF5, 0x5C, 0x90, 0x9E, 0x01, 0xE0, 0x24, 0x22, 0xF0, +0x80, 0x06, 0x90, 0x9E, 0x03, 0xE0, 0xF5, 0x5C, 0xE5, 0x5C, 0x25, 0xE0, 0x24, 0xBD, 0xF5, 0x82, +0xE4, 0x34, 0x42, 0xF5, 0x83, 0xE4, 0x93, 0xFE, 0x74, 0x01, 0x93, 0xFF, 0xE5, 0x5C, 0x25, 0xE0, +0x24, 0x15, 0xF5, 0x82, 0xE4, 0x34, 0x42, 0xF5, 0x83, 0x74, 0x01, 0x93, 0x2F, 0xFF, 0xE4, 0x93, +0x3E, 0xC3, 0x13, 0xFE, 0xEF, 0x13, 0xFF, 0xE5, 0x5B, 0x25, 0xE0, 0x24, 0x91, 0xF5, 0x82, 0xE4, +0x34, 0x93, 0xF5, 0x83, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x8C, 0x6A, 0xE4, 0xFB, 0xAD, 0x5C, 0xAF, +0x5B, 0x12, 0x6B, 0xD1, 0xAF, 0x5C, 0x22, 0x12, 0x1F, 0x96, 0x54, 0x3F, 0xFF, 0x90, 0x00, 0x01, +0x12, 0x1F, 0xAF, 0xFE, 0x54, 0x1F, 0xFD, 0xEE, 0x54, 0x80, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, +0x90, 0x9D, 0xE7, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xAF, 0xFE, 0x54, 0x03, 0x90, 0x9D, 0xE8, +0xF0, 0xEE, 0x54, 0x30, 0xC4, 0x54, 0x0F, 0x90, 0x9D, 0xEA, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, +0xAF, 0xFE, 0x54, 0x40, 0xFC, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x90, 0x9D, 0xE9, 0xF0, 0xEE, 0x54, +0x80, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0xFE, 0x75, 0xF0, 0x09, 0xEF, 0x90, 0x94, 0x95, 0x12, +0x49, 0x24, 0xED, 0xF0, 0x90, 0x9D, 0xE8, 0xE0, 0xFD, 0x75, 0xF0, 0x09, 0xEF, 0x90, 0x94, 0x96, +0x12, 0x49, 0x24, 0xED, 0xF0, 0x90, 0x9D, 0xE7, 0xE0, 0xFD, 0x75, 0xF0, 0x09, 0xEF, 0x90, 0x94, +0x97, 0x12, 0x49, 0x24, 0xED, 0xF0, 0x75, 0xF0, 0x09, 0xEF, 0x90, 0x94, 0x98, 0x12, 0x49, 0x24, +0x74, 0x01, 0xF0, 0x90, 0x9D, 0xEA, 0xE0, 0xFD, 0x75, 0xF0, 0x09, 0xEF, 0x90, 0x94, 0x99, 0x12, +0x49, 0x24, 0xED, 0xF0, 0x90, 0x9D, 0xE9, 0xE0, 0xFD, 0x75, 0xF0, 0x09, 0xEF, 0x90, 0x94, 0x9A, +0x12, 0x49, 0x24, 0xED, 0xF0, 0x75, 0xF0, 0x09, 0xEF, 0x90, 0x94, 0x9B, 0x12, 0x49, 0x24, 0xEE, +0xF0, 0xE4, 0xFE, 0xEE, 0xF5, 0x82, 0x75, 0x83, 0x00, 0xA3, 0xA3, 0xA3, 0x12, 0x1F, 0xAF, 0xFD, +0x75, 0xF0, 0x08, 0xEF, 0x90, 0x89, 0x00, 0x12, 0x49, 0x24, 0xE5, 0x82, 0x2E, 0xF5, 0x82, 0xE4, +0x35, 0x83, 0xF5, 0x83, 0xED, 0xF0, 0x0E, 0xEE, 0xB4, 0x04, 0xD8, 0x02, 0x6C, 0x85, 0x12, 0x1F, +0x96, 0xF5, 0x51, 0xC3, 0x94, 0x80, 0x50, 0x15, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xAF, 0xFF, 0x74, +0x13, 0x25, 0x51, 0xF5, 0x82, 0xE4, 0x34, 0x9A, 0xF5, 0x83, 0xEF, 0xF0, 0x22, 0xE5, 0x51, 0xB4, +0x80, 0x0A, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xAF, 0x90, 0x94, 0x91, 0xF0, 0x22, 0x74, 0x1D, 0x2F, +0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, +0xF5, 0x83, 0xEE, 0xF0, 0x22, 0x90, 0x00, 0x8F, 0xE0, 0x30, 0xE5, 0x30, 0x90, 0x00, 0x8E, 0xE0, +0x64, 0x05, 0x70, 0x28, 0xA3, 0xE0, 0x90, 0x9D, 0xD6, 0xF0, 0x90, 0x00, 0x8E, 0xE0, 0xFF, 0x90, +0x9D, 0xD6, 0xE0, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x00, +0x8F, 0xE0, 0x30, 0xE0, 0x07, 0xE4, 0xFD, 0x7F, 0x8E, 0x12, 0x31, 0xE4, 0x22, 0x12, 0x1F, 0x96, +0xFF, 0x54, 0x01, 0xFE, 0x90, 0x9D, 0xCB, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, +0xE0, 0x0A, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xAF, 0x90, 0x9D, 0xCC, 0xF0, 0x22, 0x12, 0x1F, 0x96, +0xFF, 0x54, 0x01, 0xFE, 0x90, 0x9D, 0xCE, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, +0xE0, 0x14, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xAF, 0x90, 0x9D, 0xCF, 0xF0, 0x90, 0x00, 0x02, 0x12, +0x1F, 0xAF, 0x90, 0x9D, 0xD0, 0xF0, 0x22, 0x90, 0x9D, 0xB7, 0xE0, 0x54, 0xFB, 0xF0, 0xE4, 0x90, +0x9D, 0xC2, 0xF0, 0x90, 0x9D, 0xBD, 0xF0, 0x22, 0xEF, 0x24, 0xFE, 0x60, 0x0C, 0x04, 0x70, 0x28, +0x90, 0x9D, 0xBF, 0x74, 0x01, 0xF0, 0xA3, 0xF0, 0x22, 0xED, 0x70, 0x0A, 0x90, 0x9D, 0xC9, 0xE0, +0x90, 0x9D, 0xBF, 0xF0, 0x80, 0x05, 0x90, 0x9D, 0xBF, 0xED, 0xF0, 0x90, 0x9D, 0xBF, 0xE0, 0xA3, +0xF0, 0x90, 0x9D, 0xB8, 0xE0, 0x44, 0x08, 0xF0, 0x22, 0x90, 0x06, 0x04, 0xE0, 0x54, 0x7F, 0xF0, +0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x9D, 0xBC, 0x74, 0x0C, 0xF0, 0x22, 0x90, 0x9D, 0xB8, 0xE0, +0xC3, 0x13, 0x20, 0xE0, 0x08, 0x90, 0x9D, 0xBC, 0x74, 0x0C, 0xF0, 0x80, 0x11, 0x90, 0x06, 0x04, +0xE0, 0x44, 0x40, 0xF0, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x9D, 0xBC, 0x74, 0x04, 0xF0, 0x90, 0x05, +0x22, 0xE4, 0xF0, 0x22, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, +0xF0, 0x90, 0x9D, 0xBC, 0x74, 0x06, 0xF0, 0x22, 0x47, 0xF8, +}; +u4Byte ArrayLength_MP_8188E_FW_AP = 15226; + + +void +ODM_ReadFirmware_MP_8188E_FW_AP( + IN PDM_ODM_T pDM_Odm, + OUT u1Byte *pFirmware, + OUT u4Byte *pFirmwareSize +) +{ + ODM_MoveMemory(pDM_Odm, pFirmware, Array_MP_8188E_FW_AP, ArrayLength_MP_8188E_FW_AP); + *pFirmwareSize = ArrayLength_MP_8188E_FW_AP; +} + + +#else + + +u1Byte Array_MP_8188E_FW_NIC_S[] = { +0xE2, 0x88, 0x10, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x22, 0x10, 0x14, 0xF6, 0x3D, 0x02, 0x00, +0xCD, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x02, 0x4B, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x02, 0x4C, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x02, 0x4B, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x50, 0x15, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xC2, 0xAF, 0x80, 0xFE, 0x32, 0x12, 0x48, 0x04, 0x85, 0xD0, 0x0B, 0x75, 0xD0, 0x08, 0xAA, 0xE0, +0xC2, 0x8C, 0xE5, 0x8A, 0x24, 0x67, 0xF5, 0x8A, 0xE5, 0x8C, 0x34, 0x79, 0xF5, 0x8C, 0xD2, 0x8C, +0xEC, 0x24, 0x89, 0xF8, 0xE6, 0xBC, 0x03, 0x02, 0x74, 0xFF, 0xC3, 0x95, 0x81, 0xB4, 0x40, 0x00, +0x40, 0xCE, 0x79, 0x04, 0x78, 0x80, 0x16, 0xE6, 0x08, 0x70, 0x0B, 0xC2, 0xAF, 0xE6, 0x30, 0xE1, +0x03, 0x44, 0x18, 0xF6, 0xD2, 0xAF, 0x08, 0xD9, 0xED, 0xEA, 0x8B, 0xD0, 0x22, 0xE5, 0x0C, 0xFF, +0x23, 0x24, 0x81, 0xF8, 0x0F, 0x08, 0x08, 0xBF, 0x04, 0x04, 0x7F, 0x00, 0x78, 0x81, 0xE6, 0x30, +0xE4, 0xF2, 0x00, 0xE5, 0x0C, 0xC3, 0x9F, 0x50, 0x20, 0x05, 0x0C, 0x74, 0x88, 0x25, 0x0C, 0xF8, +0xE6, 0xFD, 0xA6, 0x81, 0x08, 0xE6, 0xAE, 0x0C, 0xBE, 0x03, 0x02, 0x74, 0xFF, 0xCD, 0xF8, 0xE8, +0x6D, 0x60, 0xE0, 0x08, 0xE6, 0xC0, 0xE0, 0x80, 0xF6, 0xE5, 0x0C, 0xD3, 0x9F, 0x40, 0x27, 0xE5, +0x0C, 0x24, 0x89, 0xF8, 0xE6, 0xAE, 0x0C, 0xBE, 0x03, 0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xCD, +0xF8, 0xE5, 0x81, 0x6D, 0x60, 0x06, 0xD0, 0xE0, 0xF6, 0x18, 0x80, 0xF5, 0xE5, 0x0C, 0x24, 0x88, +0xC8, 0xF6, 0x15, 0x0C, 0x80, 0xD3, 0xE5, 0x0C, 0x23, 0x24, 0x81, 0xF8, 0x7F, 0x04, 0xC2, 0xAF, +0xE6, 0x30, 0xE0, 0x03, 0x10, 0xE2, 0x0C, 0x7F, 0x00, 0x30, 0xE1, 0x07, 0x30, 0xE3, 0x04, 0x7F, +0x08, 0x54, 0xF4, 0x54, 0x7C, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x42, 0x07, 0x22, 0x78, 0x88, 0xA6, +0x81, 0x74, 0x03, 0x60, 0x06, 0xFF, 0x08, 0x76, 0xFF, 0xDF, 0xFB, 0x7F, 0x04, 0xE4, 0x78, 0x80, +0xF6, 0x08, 0xF6, 0x08, 0xDF, 0xFA, 0x78, 0x81, 0x76, 0x30, 0x90, 0x4B, 0xDE, 0x74, 0x01, 0x93, +0xC0, 0xE0, 0xE4, 0x93, 0xC0, 0xE0, 0x43, 0x89, 0x01, 0x75, 0x8A, 0x60, 0x75, 0x8C, 0x79, 0xD2, +0x8C, 0xD2, 0xAF, 0x22, 0x03, 0xEF, 0xD3, 0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0x74, 0x81, +0x2F, 0x2F, 0xF8, 0xE6, 0x20, 0xE5, 0xF4, 0xC2, 0xAF, 0xE6, 0x44, 0x30, 0xF6, 0xD2, 0xAF, 0xAE, +0x0C, 0xEE, 0xC3, 0x9F, 0x50, 0x21, 0x0E, 0x74, 0x88, 0x2E, 0xF8, 0xE6, 0xF9, 0x08, 0xE6, 0x18, +0xBE, 0x03, 0x02, 0x74, 0xFF, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x09, 0xE7, 0x19, 0x19, 0xF7, 0x09, +0x09, 0x80, 0xF3, 0x16, 0x16, 0x80, 0xDA, 0xEE, 0xD3, 0x9F, 0x40, 0x04, 0x05, 0x81, 0x05, 0x81, +0xEE, 0xD3, 0x9F, 0x40, 0x22, 0x74, 0x88, 0x2E, 0xF8, 0x08, 0xE6, 0xF9, 0xEE, 0xB5, 0x0C, 0x02, +0xA9, 0x81, 0x18, 0x06, 0x06, 0xE6, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x19, 0x19, 0xE7, 0x09, 0x09, +0xF7, 0x19, 0x80, 0xF3, 0x1E, 0x80, 0xD9, 0xEF, 0x24, 0x88, 0xF8, 0xE6, 0x04, 0xF8, 0xEF, 0x2F, +0x04, 0x90, 0x4B, 0xDE, 0x93, 0xF6, 0x08, 0xEF, 0x2F, 0x93, 0xF6, 0x7F, 0x00, 0x22, 0xEF, 0xD3, +0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0xEF, 0x23, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE5, 0xF4, +0xC2, 0xAF, 0xE6, 0x54, 0x8C, 0xF6, 0xD2, 0xAF, 0xE5, 0x0C, 0xB5, 0x07, 0x0A, 0x74, 0x88, 0x2F, +0xF8, 0xE6, 0xF5, 0x81, 0x02, 0x48, 0x4D, 0x50, 0x2E, 0x74, 0x89, 0x2F, 0xF8, 0xE6, 0xBF, 0x03, +0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xF9, 0x74, 0x88, 0x2F, 0xF8, 0xFB, 0xE6, 0xFC, 0xE9, 0x6C, +0x60, 0x08, 0xA8, 0x05, 0xE7, 0xF6, 0x1D, 0x19, 0x80, 0xF4, 0xA8, 0x03, 0xA6, 0x05, 0x1F, 0xE5, +0x0C, 0xB5, 0x07, 0xE3, 0x7F, 0x00, 0x22, 0x74, 0x89, 0x2F, 0xF8, 0xE6, 0xFD, 0x18, 0x86, 0x01, +0x0F, 0x74, 0x88, 0x2F, 0xF8, 0xA6, 0x01, 0x08, 0x86, 0x04, 0xE5, 0x0C, 0xB5, 0x07, 0x02, 0xAC, +0x81, 0xED, 0x6C, 0x60, 0x08, 0x0D, 0x09, 0xA8, 0x05, 0xE6, 0xF7, 0x80, 0xF4, 0xE5, 0x0C, 0xB5, +0x07, 0xDE, 0x89, 0x81, 0x7F, 0x00, 0x22, 0xEF, 0xD3, 0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, +0xEF, 0x23, 0x24, 0x81, 0xF8, 0xC2, 0xAF, 0xE6, 0x30, 0xE5, 0x05, 0x30, 0xE0, 0x02, 0xD2, 0xE4, +0xD2, 0xE2, 0xC6, 0xD2, 0xAF, 0x7F, 0x00, 0x30, 0xE2, 0x01, 0x0F, 0x02, 0x48, 0x4C, 0x8F, 0xF0, +0xE4, 0xFF, 0xFE, 0xE5, 0x0C, 0x23, 0x24, 0x80, 0xF8, 0xC2, 0xA9, 0x30, 0xF7, 0x0D, 0x7F, 0x08, +0xE6, 0x60, 0x0B, 0x2D, 0xF6, 0x60, 0x30, 0x50, 0x2E, 0x80, 0x07, 0x30, 0xF1, 0x06, 0xED, 0xF6, +0x60, 0x25, 0x7E, 0x02, 0x08, 0x30, 0xF0, 0x10, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x23, 0x0E, 0x30, +0xE2, 0x0C, 0xD2, 0xAF, 0x7F, 0x04, 0x80, 0x12, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x13, 0x54, 0xEC, +0x4E, 0xF6, 0xD2, 0xAF, 0x02, 0x48, 0x4D, 0x7F, 0x08, 0x08, 0xEF, 0x44, 0x83, 0xF4, 0xC2, 0xAF, +0x56, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x4F, 0xFF, 0x22, 0xC5, 0xF0, 0xF8, 0xA3, 0xE0, 0x28, 0xF0, +0xC5, 0xF0, 0xF8, 0xE5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83, 0xE0, 0x38, 0xF0, 0x22, 0xEF, +0x5B, 0xFF, 0xEE, 0x5A, 0xFE, 0xED, 0x59, 0xFD, 0xEC, 0x58, 0xFC, 0x22, 0xEF, 0x4B, 0xFF, 0xEE, +0x4A, 0xFE, 0xED, 0x49, 0xFD, 0xEC, 0x48, 0xFC, 0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0xA3, 0xE0, +0xFE, 0xA3, 0xE0, 0xFF, 0x22, 0xE2, 0xFC, 0x08, 0xE2, 0xFD, 0x08, 0xE2, 0xFE, 0x08, 0xE2, 0xFF, +0x22, 0xE2, 0xFB, 0x08, 0xE2, 0xF9, 0x08, 0xE2, 0xFA, 0x08, 0xE2, 0xCB, 0xF8, 0x22, 0xEC, 0xF2, +0x08, 0xED, 0xF2, 0x08, 0xEE, 0xF2, 0x08, 0xEF, 0xF2, 0x22, 0xA4, 0x25, 0x82, 0xF5, 0x82, 0xE5, +0xF0, 0x35, 0x83, 0xF5, 0x83, 0x22, 0xE0, 0xFB, 0xA3, 0xE0, 0xFA, 0xA3, 0xE0, 0xF9, 0x22, 0xEB, +0xF0, 0xA3, 0xEA, 0xF0, 0xA3, 0xE9, 0xF0, 0x22, 0xD0, 0x83, 0xD0, 0x82, 0xF8, 0xE4, 0x93, 0x70, +0x12, 0x74, 0x01, 0x93, 0x70, 0x0D, 0xA3, 0xA3, 0x93, 0xF8, 0x74, 0x01, 0x93, 0xF5, 0x82, 0x88, +0x83, 0xE4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xEF, 0xA3, 0xA3, 0xA3, 0x80, 0xDF, 0x02, 0x4B, +0x8C, 0x02, 0x48, 0xDD, 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0x40, 0x03, 0xF6, 0x80, 0x01, +0xF2, 0x08, 0xDF, 0xF4, 0x80, 0x29, 0xE4, 0x93, 0xA3, 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, +0x33, 0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83, 0x40, 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, +0xDF, 0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x4B, 0xD1, 0xE4, +0x7E, 0x01, 0x93, 0x60, 0xBC, 0xA3, 0xFF, 0x54, 0x3F, 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, +0x93, 0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0, 0x25, 0xE0, 0x60, 0xA8, 0x40, 0xB8, 0xE4, 0x93, +0xA3, 0xFA, 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83, +0xCA, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83, 0xCA, 0xDF, 0xE9, 0xDE, 0xE7, 0x80, +0xBE, 0x00, 0x41, 0x82, 0x12, 0x00, 0x41, 0x82, 0x13, 0x00, 0x41, 0x82, 0x1F, 0x00, 0x58, 0xF0, +0x5F, 0xDD, 0x69, 0x7E, 0x6A, 0xC2, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, +0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, +0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xE6, 0xF0, 0x74, 0x4B, 0xA3, 0xF0, 0x91, 0x35, 0x74, +0xE6, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x4B, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, +0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, +0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x00, 0x54, 0xE0, 0x55, 0x35, 0xF5, 0x39, 0xA3, 0xE0, 0x55, +0x36, 0xF5, 0x3A, 0xA3, 0xE0, 0x55, 0x37, 0xF5, 0x3B, 0xA3, 0xE0, 0x55, 0x38, 0xF5, 0x3C, 0xAD, +0x39, 0x7F, 0x54, 0x12, 0x32, 0x1E, 0xAD, 0x3A, 0x7F, 0x55, 0x12, 0x32, 0x1E, 0xAD, 0x3B, 0x7F, +0x56, 0x12, 0x32, 0x1E, 0xAD, 0x3C, 0x7F, 0x57, 0x12, 0x32, 0x1E, 0x53, 0x91, 0xEF, 0x22, 0xC0, +0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, +0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, +0x6F, 0xF0, 0x74, 0x4C, 0xA3, 0xF0, 0x12, 0x72, 0x41, 0xE5, 0x41, 0x30, 0xE4, 0x04, 0x7F, 0x02, +0x51, 0x27, 0xE5, 0x41, 0x30, 0xE6, 0x02, 0xF1, 0xEF, 0xE5, 0x43, 0x30, 0xE0, 0x03, 0x12, 0x72, +0x9E, 0xE5, 0x43, 0x30, 0xE1, 0x03, 0x12, 0x54, 0x43, 0xE5, 0x43, 0x30, 0xE2, 0x03, 0x12, 0x53, +0xF7, 0xE5, 0x43, 0x30, 0xE3, 0x03, 0x12, 0x6F, 0xB0, 0xE5, 0x43, 0x30, 0xE4, 0x03, 0x12, 0x74, +0xA9, 0xE5, 0x43, 0x30, 0xE5, 0x03, 0x12, 0x6F, 0x58, 0xE5, 0x43, 0x30, 0xE6, 0x02, 0xB1, 0x0E, +0xE5, 0x44, 0x30, 0xE1, 0x03, 0x12, 0x74, 0xD8, 0x74, 0x6F, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, +0x4C, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, +0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x80, +0xDE, 0xE0, 0xB4, 0x01, 0x13, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x0D, 0x90, 0x81, 0x2B, 0xE0, 0x54, +0xFE, 0xF0, 0x54, 0x07, 0x70, 0x02, 0xB1, 0x29, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0x90, 0x81, 0x29, +0x30, 0xE0, 0x04, 0xE0, 0xFF, 0xE1, 0x6E, 0xE0, 0xFF, 0x7D, 0x01, 0x80, 0x04, 0xE4, 0xFD, 0x7F, +0x0C, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, 0x1D, 0xED, 0xF0, 0x90, 0x81, 0x24, +0xE0, 0xFE, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x30, 0xE0, 0x02, 0xC1, 0x8E, 0xEE, 0xC4, 0x13, 0x13, +0x13, 0x54, 0x01, 0x30, 0xE0, 0x02, 0xC1, 0x8E, 0x90, 0x81, 0x2A, 0xE0, 0xFE, 0x6F, 0x70, 0x02, +0xC1, 0x8E, 0xEF, 0x70, 0x02, 0xC1, 0x03, 0x24, 0xFE, 0x70, 0x02, 0xC1, 0x3D, 0x24, 0xFE, 0x60, +0x4A, 0x24, 0xFC, 0x70, 0x02, 0xC1, 0x78, 0x24, 0xFC, 0x60, 0x02, 0xC1, 0x8E, 0xEE, 0xB4, 0x0E, +0x02, 0xF1, 0x39, 0x90, 0x81, 0x2A, 0xE0, 0x70, 0x04, 0x7F, 0x01, 0xF1, 0x1B, 0x90, 0x81, 0x2A, +0xE0, 0xB4, 0x06, 0x02, 0xD1, 0xE8, 0x90, 0x81, 0x2A, 0xE0, 0xB4, 0x04, 0x0F, 0x90, 0x82, 0x1D, +0xE0, 0xFF, 0x60, 0x05, 0x12, 0x7A, 0xBA, 0x80, 0x03, 0x12, 0x5F, 0xB4, 0x90, 0x81, 0x2A, 0xE0, +0x64, 0x08, 0x60, 0x02, 0xC1, 0x8E, 0x12, 0x5B, 0xEB, 0xC1, 0x8E, 0x90, 0x81, 0x2A, 0xE0, 0x70, +0x04, 0x7F, 0x01, 0xF1, 0x1B, 0x90, 0x81, 0x2A, 0xE0, 0xB4, 0x06, 0x02, 0xD1, 0xE8, 0x90, 0x81, +0x2A, 0xE0, 0xB4, 0x0E, 0x07, 0xD1, 0x93, 0xBF, 0x01, 0x02, 0xF1, 0x39, 0x90, 0x81, 0x2A, 0xE0, +0x64, 0x0C, 0x60, 0x02, 0xC1, 0x8E, 0xD1, 0x93, 0xEF, 0x64, 0x01, 0x60, 0x02, 0xC1, 0x8E, 0xF1, +0x8D, 0xC1, 0x8E, 0x90, 0x81, 0x2A, 0xE0, 0xB4, 0x0E, 0x07, 0xD1, 0x93, 0xBF, 0x01, 0x02, 0xF1, +0x39, 0x90, 0x81, 0x2A, 0xE0, 0xB4, 0x06, 0x02, 0xD1, 0xE8, 0x90, 0x81, 0x2A, 0xE0, 0xB4, 0x0C, +0x07, 0xD1, 0x93, 0xBF, 0x01, 0x02, 0xF1, 0x8D, 0x90, 0x81, 0x2A, 0xE0, 0x64, 0x04, 0x70, 0x5E, +0x12, 0x7A, 0x0C, 0xEF, 0x64, 0x01, 0x70, 0x56, 0x12, 0x5D, 0x5A, 0x80, 0x51, 0x90, 0x81, 0x2A, +0xE0, 0xB4, 0x0E, 0x07, 0xD1, 0x93, 0xBF, 0x01, 0x02, 0xF1, 0x39, 0x90, 0x81, 0x2A, 0xE0, 0xB4, +0x06, 0x02, 0xD1, 0xE8, 0x90, 0x81, 0x2A, 0xE0, 0xB4, 0x0C, 0x07, 0xD1, 0x93, 0xBF, 0x01, 0x02, +0xF1, 0x8D, 0x90, 0x81, 0x2A, 0xE0, 0x70, 0x04, 0x7F, 0x01, 0xF1, 0x1B, 0x90, 0x81, 0x2A, 0xE0, +0xB4, 0x04, 0x1B, 0x12, 0x7B, 0x00, 0x80, 0x16, 0x90, 0x81, 0x2A, 0xE0, 0xB4, 0x0C, 0x0F, 0x90, +0x81, 0x25, 0xE0, 0xFF, 0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x03, 0x12, 0x5F, 0x55, 0xD0, 0xD0, +0x92, 0xAF, 0x22, 0xF1, 0xFC, 0xEF, 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x01, 0xF0, +0x80, 0x3D, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x08, 0x90, +0x01, 0xB8, 0x74, 0x02, 0xF0, 0x80, 0x28, 0xEF, 0xC4, 0x54, 0x0F, 0x30, 0xE0, 0x08, 0x90, 0x01, +0xB8, 0x74, 0x04, 0xF0, 0x80, 0x19, 0x90, 0x81, 0x29, 0xE0, 0xD3, 0x94, 0x04, 0x40, 0x08, 0x90, +0x01, 0xB8, 0x74, 0x08, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0x90, +0x01, 0xB9, 0x74, 0x02, 0xF0, 0x7F, 0x00, 0x22, 0x90, 0x81, 0x25, 0xE0, 0x90, 0x06, 0x04, 0x20, +0xE0, 0x0C, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0, 0x80, 0x17, 0xE0, 0x54, +0x7F, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0x7F, 0xF0, 0x90, +0x81, 0x23, 0x74, 0x0C, 0xF0, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x90, 0x82, 0x1C, 0xEF, 0xF0, +0x12, 0x5B, 0xFD, 0x90, 0x82, 0x1C, 0xE0, 0x60, 0x05, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, +0x2A, 0x74, 0x04, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x81, 0x25, 0xE0, 0xC3, 0x13, 0x20, +0xE0, 0x08, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x80, 0x1E, 0x90, 0x06, 0x04, 0xE0, 0x44, 0x40, +0xF0, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x44, +0x80, 0xF0, 0x90, 0x81, 0x23, 0x74, 0x04, 0xF0, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0xAE, 0x07, +0xF1, 0xE3, 0xBF, 0x01, 0x15, 0x90, 0x81, 0x1F, 0xE0, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x20, 0xE0, +0x09, 0xAF, 0x06, 0x7D, 0x01, 0xB1, 0x41, 0x7F, 0x01, 0x22, 0x7F, 0x00, 0x22, 0x90, 0x80, 0xDE, +0xE0, 0x64, 0x01, 0x70, 0x32, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x05, 0x22, 0x74, +0x6F, 0xF0, 0x7F, 0x01, 0x12, 0x56, 0xA8, 0xBF, 0x01, 0x12, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x80, +0xF0, 0x90, 0x81, 0x2A, 0x74, 0x0E, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x01, 0xB9, 0x74, +0x01, 0xF0, 0x90, 0x01, 0xB8, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x27, 0xE0, 0x64, 0x02, 0x60, 0x12, +0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x60, 0x0A, 0xF1, 0xFC, 0xEF, 0x70, 0x05, 0xFD, 0x7F, 0x0C, +0xB1, 0x41, 0x22, 0x90, 0x05, 0x43, 0xE0, 0x7F, 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0x22, 0x90, +0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x05, 0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0x22, 0x90, 0x04, 0x1A, 0xE0, +0xF4, 0x60, 0x03, 0x7F, 0x00, 0x22, 0x90, 0x04, 0x1B, 0xE0, 0x54, 0x07, 0x64, 0x07, 0x7F, 0x01, +0x60, 0x02, 0x7F, 0x00, 0x22, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, 0x75, +0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, +0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0x15, 0xF0, 0x74, 0x50, 0xA3, 0xF0, 0x12, 0x72, 0x6E, 0xE5, +0x49, 0x30, 0xE1, 0x02, 0x11, 0xC5, 0xE5, 0x49, 0x30, 0xE2, 0x03, 0x12, 0x75, 0x58, 0xE5, 0x49, +0x30, 0xE3, 0x03, 0x12, 0x75, 0x94, 0xE5, 0x4A, 0x30, 0xE0, 0x03, 0x12, 0x75, 0xD0, 0xE5, 0x4A, +0x30, 0xE4, 0x03, 0x12, 0x76, 0x6F, 0xE5, 0x4B, 0x30, 0xE1, 0x03, 0x12, 0x73, 0x3B, 0xE5, 0x4B, +0x30, 0xE0, 0x03, 0x12, 0x72, 0xF5, 0xE5, 0x4B, 0x30, 0xE3, 0x03, 0x12, 0x76, 0x85, 0xE5, 0x4C, +0x30, 0xE1, 0x05, 0x7F, 0x03, 0x12, 0x4A, 0x27, 0xE5, 0x4C, 0x30, 0xE4, 0x02, 0x11, 0xD9, 0xE5, +0x4C, 0x30, 0xE5, 0x03, 0x12, 0x76, 0x86, 0xE5, 0x4C, 0x30, 0xE6, 0x03, 0x12, 0x77, 0x1C, 0x74, +0x15, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x50, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, +0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, +0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x03, 0x12, 0x7B, 0x98, 0x90, 0x81, +0x40, 0xE0, 0x30, 0xE0, 0x03, 0x12, 0x5C, 0xEA, 0x22, 0x12, 0x7B, 0x33, 0x90, 0x81, 0x2D, 0xE0, +0x14, 0x90, 0x05, 0x73, 0xF0, 0x7D, 0x02, 0x7F, 0x02, 0x31, 0x31, 0x91, 0xBC, 0x90, 0x81, 0x42, +0xE0, 0x30, 0xE0, 0x33, 0x90, 0x81, 0x44, 0xE0, 0x90, 0x05, 0x73, 0xF0, 0x90, 0x81, 0x45, 0xE0, +0x60, 0x05, 0x14, 0xF0, 0x02, 0x5F, 0x55, 0x90, 0x81, 0x43, 0xE0, 0x14, 0x90, 0x81, 0x45, 0xF0, +0x90, 0x05, 0x73, 0x74, 0x01, 0xF0, 0xE4, 0xFF, 0x12, 0x5B, 0xBB, 0x7D, 0x02, 0x7F, 0x02, 0x31, +0x31, 0x7D, 0x01, 0x7F, 0x02, 0x31, 0x31, 0x22, 0x90, 0x01, 0x34, 0x74, 0x40, 0xF0, 0xFD, 0xE4, +0xFF, 0x74, 0x3D, 0x2F, 0xF8, 0xE6, 0x4D, 0xFE, 0xF6, 0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, +0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x05, 0x27, +0xE0, 0x90, 0x81, 0xD0, 0xF0, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x1F, 0xE0, +0x54, 0xFE, 0x4E, 0xFE, 0xF0, 0xEF, 0x54, 0x02, 0xFF, 0xEE, 0x54, 0xFD, 0x4F, 0xFF, 0xF0, 0x12, +0x1F, 0xA4, 0xFE, 0x54, 0x04, 0xFD, 0xEF, 0x54, 0xFB, 0x4D, 0xFF, 0x90, 0x81, 0x1F, 0xF0, 0xEE, +0x54, 0x08, 0xFE, 0xEF, 0x54, 0xF7, 0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x10, 0xFD, +0xEF, 0x54, 0xEF, 0x4D, 0xFF, 0x90, 0x81, 0x1F, 0xF0, 0xEE, 0x54, 0x20, 0xFE, 0xEF, 0x54, 0xDF, +0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x40, 0xFD, 0xEF, 0x54, 0xBF, 0x4D, 0x90, 0x81, +0x1F, 0xF0, 0xEE, 0xC3, 0x13, 0x20, 0xE0, 0x02, 0x41, 0x77, 0xE0, 0xFF, 0x20, 0xE0, 0x02, 0x41, +0x5E, 0x90, 0x81, 0xD0, 0x74, 0x21, 0xF0, 0xEF, 0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x0B, 0x31, +0x28, 0x90, 0x81, 0xD0, 0xE0, 0x44, 0x08, 0xF0, 0x80, 0x0C, 0xE4, 0x90, 0x81, 0x20, 0xF0, 0xA3, +0xF0, 0x7D, 0x40, 0xFF, 0x71, 0x5C, 0x90, 0x81, 0x1F, 0xE0, 0xFD, 0x13, 0x13, 0x13, 0x54, 0x1F, +0x30, 0xE0, 0x07, 0x90, 0x81, 0xD0, 0xE0, 0x44, 0x12, 0xF0, 0xED, 0xC4, 0x54, 0x0F, 0x30, 0xE0, +0x07, 0x90, 0x81, 0xD0, 0xE0, 0x44, 0x14, 0xF0, 0x90, 0x81, 0x1F, 0xE0, 0xC4, 0x13, 0x54, 0x07, +0x30, 0xE0, 0x07, 0x90, 0x81, 0xD0, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x1F, 0xE0, 0xC4, 0x13, +0x13, 0x54, 0x03, 0x30, 0xE0, 0x07, 0x90, 0x81, 0xD0, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0xD0, +0xE0, 0x90, 0x05, 0x27, 0xF0, 0x90, 0x81, 0x22, 0xE0, 0x70, 0x04, 0x7F, 0x01, 0xB1, 0xA3, 0x90, +0x81, 0x1F, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x30, 0xE0, 0x04, 0x7F, 0x04, 0x80, 0x23, +0x12, 0x4F, 0xE3, 0xEF, 0x60, 0x04, 0x7F, 0x01, 0x80, 0x19, 0x7F, 0x02, 0x80, 0x15, 0x90, 0x81, +0xD0, 0x74, 0x01, 0xF0, 0x90, 0x05, 0x27, 0xF0, 0x90, 0x81, 0x22, 0xE0, 0x64, 0x04, 0x60, 0x02, +0x61, 0x4D, 0xFF, 0xB1, 0xA3, 0x61, 0x4D, 0x90, 0x81, 0x1F, 0xE0, 0xFD, 0x20, 0xE0, 0x02, 0x61, +0x18, 0x90, 0x81, 0xD0, 0xE0, 0x44, 0x31, 0xF0, 0xED, 0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x0B, +0x31, 0x28, 0x90, 0x81, 0xD0, 0xE0, 0x44, 0x08, 0xF0, 0x80, 0x06, 0x7D, 0x40, 0xE4, 0xFF, 0x71, +0x5C, 0x90, 0x81, 0x1F, 0xE0, 0xFD, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x07, 0x90, 0x81, +0xD0, 0xE0, 0x44, 0x02, 0xF0, 0xED, 0xC4, 0x54, 0x0F, 0x30, 0xE0, 0x07, 0x90, 0x81, 0xD0, 0xE0, +0x44, 0x04, 0xF0, 0x90, 0x81, 0xD0, 0xE0, 0x90, 0x05, 0x27, 0xF0, 0x90, 0x81, 0x1F, 0xE0, 0xFF, +0xC4, 0x13, 0x13, 0x54, 0x03, 0x30, 0xE0, 0x0E, 0x90, 0x81, 0x23, 0xE0, 0x64, 0x02, 0x60, 0x6D, +0xE4, 0xFD, 0x7F, 0x02, 0x80, 0x23, 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x23, +0xE0, 0xB4, 0x02, 0x1A, 0x12, 0x7B, 0x1A, 0x12, 0x4F, 0xE3, 0xBF, 0x01, 0x09, 0x90, 0x81, 0x29, +0xE0, 0xFF, 0x7D, 0x01, 0x80, 0x03, 0xE4, 0xFD, 0xFF, 0x12, 0x4D, 0x41, 0x80, 0x3F, 0x90, 0x81, +0x2A, 0xE0, 0x90, 0x81, 0x23, 0xF0, 0x80, 0x35, 0x90, 0x81, 0xD0, 0x74, 0x01, 0xF0, 0x90, 0x05, +0x27, 0xF0, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x02, 0x06, 0x7D, 0x01, 0x7F, 0x04, 0x80, 0x0B, 0x90, +0x81, 0x23, 0xE0, 0xB4, 0x08, 0x07, 0x7D, 0x01, 0x7F, 0x0C, 0x12, 0x4D, 0x41, 0x12, 0x75, 0x4F, +0x90, 0x81, 0x29, 0xE0, 0xFF, 0x7D, 0x01, 0x12, 0x4D, 0x41, 0x12, 0x5A, 0x64, 0xD0, 0xD0, 0x92, +0xAF, 0x22, 0x7D, 0x02, 0x7F, 0x02, 0x71, 0x5C, 0x7D, 0x01, 0x7F, 0x02, 0x74, 0x3D, 0x2F, 0xF8, +0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE, 0xF6, 0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, +0x83, 0xEE, 0xF0, 0x22, 0xEF, 0x70, 0x37, 0x7D, 0x78, 0x7F, 0x02, 0x71, 0x5C, 0x7D, 0x02, 0x7F, +0x03, 0x71, 0x5C, 0x7D, 0xC8, 0x7F, 0x02, 0x12, 0x77, 0xE2, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, +0x01, 0x3C, 0x74, 0x02, 0xF0, 0x7D, 0x01, 0x7F, 0x0C, 0x12, 0x4D, 0x41, 0x90, 0x81, 0x24, 0xE0, +0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x06, 0x0A, 0xE0, 0x54, 0xF8, 0xF0, 0x22, 0x90, 0x01, +0x36, 0x74, 0x78, 0xF0, 0xA3, 0x74, 0x02, 0xF0, 0x7D, 0x78, 0xFF, 0x31, 0x31, 0x7D, 0x02, 0x7F, +0x03, 0x31, 0x31, 0x90, 0x06, 0x0A, 0xE0, 0x44, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xA3, 0xE0, 0x90, +0x05, 0x58, 0xF0, 0x90, 0x80, 0xDE, 0xE0, 0xB4, 0x01, 0x15, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFB, +0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x20, 0xE2, 0x0E, 0x7D, 0x01, 0x7F, 0x04, 0x02, 0x4D, 0x41, 0x90, +0x81, 0x25, 0xE0, 0x44, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x08, 0x90, +0x81, 0x23, 0xE0, 0x64, 0x02, 0x60, 0x3B, 0x90, 0x81, 0x27, 0xE0, 0x70, 0x04, 0xEF, 0x30, 0xE0, +0x0A, 0x90, 0x81, 0x2A, 0xE0, 0x64, 0x02, 0x60, 0x29, 0x91, 0xF1, 0x90, 0x81, 0x25, 0xE0, 0x13, +0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x15, 0x90, 0x81, 0x2D, 0xE0, 0xFF, 0xA3, 0xE0, 0x6F, 0x70, +0x0B, 0x12, 0x77, 0xBE, 0x71, 0x52, 0x90, 0x81, 0x2E, 0xE0, 0x14, 0xF0, 0x90, 0x01, 0xE6, 0xE0, +0x04, 0xF0, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x06, 0x90, 0x81, 0x21, 0x74, 0x01, 0xF0, +0x90, 0x81, 0x27, 0xE0, 0x60, 0x45, 0x90, 0x81, 0x25, 0xE0, 0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F, +0x30, 0xE0, 0x12, 0x90, 0x01, 0x3B, 0xE0, 0x30, 0xE4, 0x0B, 0x71, 0x52, 0x90, 0x81, 0x2D, 0xE0, +0x14, 0x90, 0x05, 0x73, 0xF0, 0x90, 0x82, 0x14, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x4A, 0xA9, 0xC3, +0x90, 0x82, 0x15, 0xE0, 0x94, 0x80, 0x90, 0x82, 0x14, 0xE0, 0x64, 0x80, 0x94, 0x80, 0x40, 0x0B, +0x90, 0x01, 0x98, 0xE0, 0x54, 0xFE, 0xF0, 0xE0, 0x44, 0x01, 0xF0, 0x12, 0x7D, 0xBE, 0x91, 0xBC, +0x12, 0x6F, 0x96, 0x90, 0x81, 0x42, 0xE0, 0x30, 0xE0, 0x11, 0x90, 0x01, 0x3B, 0xE0, 0x30, 0xE4, +0x0A, 0x71, 0x52, 0x90, 0x81, 0x44, 0xE0, 0x90, 0x05, 0x73, 0xF0, 0x22, 0x90, 0x81, 0x47, 0xE0, +0x30, 0xE0, 0x2D, 0x90, 0x80, 0xDE, 0xE0, 0xB4, 0x01, 0x26, 0x90, 0x82, 0x1F, 0xE0, 0x04, 0xF0, +0xE0, 0xB4, 0x0A, 0x0B, 0x90, 0x81, 0x49, 0xE0, 0x04, 0xF0, 0xE4, 0x90, 0x82, 0x1F, 0xF0, 0x90, +0x81, 0x49, 0xE0, 0xFF, 0x90, 0x81, 0x48, 0xE0, 0xB5, 0x07, 0x05, 0xE4, 0xA3, 0xF0, 0xD1, 0xA6, +0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x60, 0x02, 0xA1, 0x92, 0x90, 0x81, 0x27, 0xE0, 0x70, +0x02, 0xA1, 0x92, 0x90, 0x81, 0x26, 0xE0, 0xC4, 0x54, 0x0F, 0x64, 0x01, 0x70, 0x22, 0x90, 0x06, +0xAB, 0xE0, 0x90, 0x81, 0x2E, 0xF0, 0x90, 0x06, 0xAA, 0xE0, 0x90, 0x81, 0x2D, 0xF0, 0xA3, 0xE0, +0xFF, 0x70, 0x08, 0x90, 0x81, 0x2D, 0xE0, 0xFE, 0xFF, 0x80, 0x00, 0x90, 0x81, 0x2E, 0xEF, 0xF0, +0x90, 0x81, 0x25, 0xE0, 0x44, 0x04, 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, 0x81, 0x32, 0xA3, +0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, +0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x26, 0xE0, 0xFF, 0xC4, +0x54, 0x0F, 0x24, 0xFD, 0x50, 0x02, 0x80, 0x0F, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x05, 0x12, +0x6E, 0xB1, 0x80, 0x03, 0x12, 0x6D, 0xFF, 0x90, 0x81, 0x25, 0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, +0x30, 0xE0, 0x0F, 0x90, 0x81, 0x2D, 0xE0, 0xFF, 0xA3, 0xE0, 0xB5, 0x07, 0x05, 0x12, 0x77, 0xBE, +0x71, 0x58, 0x90, 0x81, 0x1F, 0xE0, 0xC3, 0x13, 0x20, 0xE0, 0x07, 0x90, 0x81, 0x25, 0xE0, 0x44, +0x04, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x22, 0xE0, 0x90, 0x82, +0x1E, 0xF0, 0x6F, 0x70, 0x02, 0xC1, 0xA1, 0xEF, 0x14, 0x60, 0x40, 0x14, 0x60, 0x68, 0x14, 0x70, +0x02, 0xC1, 0x53, 0x14, 0x70, 0x02, 0xC1, 0x7B, 0x24, 0x04, 0x60, 0x02, 0xC1, 0xA1, 0x90, 0x82, +0x1E, 0xE0, 0xFF, 0xB4, 0x04, 0x05, 0x12, 0x7C, 0x16, 0xC1, 0xA1, 0xEF, 0xB4, 0x02, 0x04, 0xF1, +0xE3, 0xC1, 0xA1, 0x90, 0x82, 0x1E, 0xE0, 0xFF, 0xB4, 0x03, 0x05, 0x12, 0x7C, 0x3A, 0xC1, 0xA1, +0xEF, 0x64, 0x01, 0x60, 0x02, 0xC1, 0xA1, 0xF1, 0xE5, 0xC1, 0xA1, 0x90, 0x82, 0x1E, 0xE0, 0xFF, +0xB4, 0x04, 0x05, 0x12, 0x7C, 0x03, 0xC1, 0xA1, 0xEF, 0xB4, 0x02, 0x04, 0xF1, 0xD5, 0xC1, 0xA1, +0x90, 0x82, 0x1E, 0xE0, 0xFF, 0xB4, 0x03, 0x05, 0x12, 0x7C, 0x2F, 0xC1, 0xA1, 0xEF, 0x60, 0x02, +0xC1, 0xA1, 0xF1, 0xA9, 0x80, 0x7B, 0x90, 0x82, 0x1E, 0xE0, 0xB4, 0x04, 0x05, 0x12, 0x5F, 0x92, +0x80, 0x6F, 0x90, 0x82, 0x1E, 0xE0, 0xB4, 0x01, 0x04, 0xF1, 0x9B, 0x80, 0x64, 0x90, 0x82, 0x1E, +0xE0, 0xB4, 0x03, 0x05, 0x12, 0x5F, 0x4C, 0x80, 0x58, 0x90, 0x82, 0x1E, 0xE0, 0x70, 0x52, 0xF1, +0xA5, 0x80, 0x4E, 0x90, 0x82, 0x1E, 0xE0, 0xFF, 0xB4, 0x04, 0x05, 0x12, 0x7C, 0x1B, 0x80, 0x41, +0xEF, 0xB4, 0x01, 0x04, 0xF1, 0xC8, 0x80, 0x39, 0xEF, 0xB4, 0x02, 0x05, 0x12, 0x5F, 0x43, 0x80, +0x30, 0x90, 0x82, 0x1E, 0xE0, 0x70, 0x2A, 0xF1, 0xC6, 0x80, 0x26, 0x90, 0x82, 0x1E, 0xE0, 0xFF, +0xB4, 0x03, 0x05, 0x12, 0x7C, 0x3F, 0x80, 0x19, 0xEF, 0xB4, 0x01, 0x04, 0xF1, 0xB2, 0x80, 0x11, +0xEF, 0xB4, 0x02, 0x05, 0x12, 0x5F, 0xC7, 0x80, 0x08, 0x90, 0x82, 0x1E, 0xE0, 0x70, 0x02, 0xF1, +0xB0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xE4, 0xFF, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x8F, +0x53, 0x90, 0x04, 0x1D, 0xE0, 0x60, 0x1F, 0x90, 0x05, 0x22, 0xE0, 0xF5, 0x56, 0x74, 0xFF, 0xF0, +0x12, 0x5D, 0x7A, 0xBF, 0x01, 0x08, 0xAF, 0x53, 0x12, 0x7C, 0xFF, 0x12, 0x7C, 0x60, 0x90, 0x05, +0x22, 0xE5, 0x56, 0xF0, 0x80, 0x03, 0x12, 0x7C, 0x60, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x7F, +0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, +0xE0, 0x54, 0x3F, 0xF0, 0xEF, 0x60, 0x1D, 0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, +0x83, 0xE0, 0x44, 0x10, 0xF0, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, +0x44, 0x80, 0xF0, 0x22, 0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, +0xEF, 0xF0, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x40, 0xF0, +0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, 0x17, 0xED, 0xF0, 0x90, 0x82, 0x16, +0xEF, 0xF0, 0xE4, 0xFD, 0xFC, 0x12, 0x7D, 0x4C, 0x7C, 0x00, 0xAD, 0x07, 0x90, 0x82, 0x16, 0xE0, +0x90, 0x04, 0x25, 0xF0, 0x90, 0x82, 0x17, 0xE0, 0x60, 0x0E, 0x74, 0x0F, 0x2F, 0xF5, 0x82, 0xE4, +0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0xAF, 0x05, 0x74, 0x08, 0x2F, 0xF5, 0x82, 0xE4, +0x34, 0xFC, 0xF5, 0x83, 0xE4, 0xF0, 0x74, 0x09, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, +0xE0, 0x54, 0xF0, 0xF0, 0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, +0xF7, 0xF0, 0xAE, 0x04, 0xAF, 0x05, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x12, 0x5C, 0xEA, 0x90, 0x81, +0x22, 0x74, 0x02, 0xF0, 0x22, 0xF1, 0xA9, 0x80, 0xF2, 0x90, 0x81, 0x22, 0x74, 0x01, 0xF0, 0x22, +0xF1, 0xA9, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, +0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0xF1, 0xA9, 0x90, 0x05, 0x22, 0x74, 0xFF, 0xF0, 0x90, 0x81, +0x22, 0x74, 0x03, 0xF0, 0x22, 0x12, 0x5B, 0xFD, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, 0x22, +0x04, 0xF0, 0x22, 0xF1, 0xD5, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0xE4, 0x90, 0x81, 0x22, +0xF0, 0x22, 0x90, 0x01, 0xC8, 0xE4, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x7B, 0x01, 0x7A, 0x81, 0x79, +0x56, 0x7F, 0xFF, 0xFE, 0x12, 0x2B, 0x27, 0xBF, 0x01, 0x09, 0x90, 0x81, 0x56, 0xE0, 0x64, 0x03, +0x60, 0x03, 0x22, 0x01, 0xB4, 0xE4, 0x90, 0x81, 0x5B, 0xF0, 0x90, 0x81, 0x5B, 0xE0, 0xFF, 0xC3, +0x94, 0x02, 0x40, 0x02, 0x01, 0xEF, 0xC3, 0x74, 0xFE, 0x9F, 0xFF, 0xE4, 0x94, 0x00, 0xFE, 0x7B, +0x01, 0x7A, 0x81, 0x79, 0x57, 0x12, 0x2B, 0x27, 0xEF, 0x64, 0x01, 0x70, 0x77, 0x90, 0x81, 0x57, +0xE0, 0xFF, 0x54, 0xC0, 0xFE, 0x60, 0x05, 0xEF, 0x54, 0x0C, 0x70, 0x16, 0x90, 0x81, 0x57, 0xE0, +0xFF, 0x54, 0x30, 0x60, 0x67, 0xEF, 0x54, 0x03, 0x60, 0x62, 0x90, 0x81, 0x58, 0x74, 0x01, 0xF0, +0x80, 0x05, 0xE4, 0x90, 0x81, 0x58, 0xF0, 0x90, 0x81, 0x58, 0xE0, 0x90, 0x81, 0x57, 0x70, 0x16, +0xE0, 0xFF, 0xEE, 0x13, 0x13, 0x54, 0x3F, 0x90, 0x81, 0x59, 0xF0, 0xEF, 0x54, 0x0C, 0x13, 0x13, +0x54, 0x3F, 0xA3, 0xF0, 0x80, 0x0D, 0xE0, 0xFE, 0x54, 0x30, 0x90, 0x81, 0x59, 0xF0, 0xEE, 0x54, +0x03, 0xA3, 0xF0, 0x90, 0x81, 0x59, 0xE0, 0x64, 0x30, 0x70, 0x54, 0xA3, 0xE0, 0x64, 0x02, 0x70, +0x4E, 0x90, 0x00, 0xF5, 0xE0, 0x54, 0x40, 0x90, 0x81, 0x5C, 0xF0, 0xE0, 0x70, 0x41, 0xA3, 0x74, +0x02, 0xF0, 0x80, 0x10, 0x90, 0x81, 0x5D, 0x74, 0x01, 0xF0, 0x80, 0x08, 0x90, 0x81, 0x5B, 0xE0, +0x04, 0xF0, 0x01, 0x1A, 0x90, 0x01, 0xC4, 0x74, 0xF2, 0xF0, 0x74, 0x57, 0xA3, 0xF0, 0x90, 0x81, +0x5D, 0xE0, 0x90, 0x01, 0xC8, 0xF0, 0x90, 0x81, 0x57, 0xE0, 0x90, 0x01, 0xC9, 0xF0, 0x90, 0x81, +0x58, 0xE0, 0x90, 0x01, 0xCA, 0xF0, 0xE4, 0xFD, 0x7F, 0x1F, 0x12, 0x32, 0x1E, 0x80, 0xD5, 0x22, +0x90, 0x00, 0x80, 0xE0, 0x44, 0x80, 0xFD, 0x7F, 0x80, 0x12, 0x32, 0x1E, 0x90, 0xFD, 0x00, 0xE0, +0x54, 0xBF, 0xF0, 0x12, 0x57, 0xF2, 0x31, 0xCB, 0x12, 0x32, 0x77, 0x12, 0x71, 0x94, 0x31, 0xB2, +0x7F, 0x01, 0x12, 0x49, 0x15, 0x90, 0x81, 0x46, 0x74, 0x02, 0xF0, 0xFF, 0x12, 0x49, 0x15, 0x90, +0x81, 0x46, 0xE0, 0x04, 0xF0, 0x7F, 0x03, 0x12, 0x49, 0x15, 0x90, 0x81, 0x46, 0xE0, 0x04, 0xF0, +0x31, 0x4F, 0x31, 0x90, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x40, 0xFD, 0x7F, 0x80, 0x12, 0x32, 0x1E, +0x75, 0x20, 0xFF, 0x31, 0xBC, 0x12, 0x71, 0xC4, 0x31, 0xD3, 0xE4, 0xFF, 0x02, 0x49, 0x9E, 0x51, +0x09, 0x90, 0x80, 0x3C, 0xEF, 0xF0, 0x31, 0x61, 0x90, 0x01, 0x64, 0x74, 0x01, 0xF0, 0x02, 0x2D, +0xA7, 0x12, 0x71, 0x33, 0x12, 0x71, 0x63, 0x51, 0x23, 0x51, 0x42, 0xE4, 0xF5, 0x35, 0xF5, 0x36, +0xF5, 0x37, 0xF5, 0x38, 0xAD, 0x35, 0x7F, 0x50, 0x12, 0x32, 0x1E, 0xAD, 0x36, 0x7F, 0x51, 0x12, +0x32, 0x1E, 0xAD, 0x37, 0x7F, 0x52, 0x12, 0x32, 0x1E, 0xAD, 0x38, 0x7F, 0x53, 0x02, 0x32, 0x1E, +0x31, 0xB6, 0x31, 0xC3, 0x51, 0x64, 0x12, 0x79, 0x06, 0x31, 0xDD, 0x31, 0xE8, 0x31, 0xF7, 0x90, +0x81, 0x4A, 0xE0, 0x54, 0xFE, 0xF0, 0xA3, 0x74, 0x03, 0xF0, 0xA3, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, +0xF0, 0x22, 0xE4, 0xF5, 0x4D, 0x22, 0xE4, 0x90, 0x80, 0xDE, 0xF0, 0x22, 0x75, 0xE8, 0x03, 0x75, +0xA8, 0x84, 0x22, 0xE4, 0x90, 0x80, 0xD8, 0xF0, 0xA3, 0xF0, 0x22, 0x90, 0x01, 0x94, 0xE0, 0x44, +0x01, 0xF0, 0x22, 0x90, 0x01, 0xE4, 0x74, 0x0C, 0xF0, 0xA3, 0xE4, 0xF0, 0x22, 0x90, 0x81, 0x40, +0xE0, 0x54, 0xFE, 0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x90, 0x81, 0x42, 0xE0, 0x54, 0xFE, 0xF0, 0xE4, +0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x22, 0x90, 0x81, 0x47, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0x7F, +0xF0, 0xA3, 0x74, 0x0A, 0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x90, 0x00, 0xF7, 0xE0, 0x20, 0xE7, 0x09, +0xE0, 0x7F, 0x01, 0x20, 0xE6, 0x0C, 0x7F, 0x02, 0x22, 0x90, 0x00, 0xF7, 0xE0, 0x30, 0xE6, 0x02, +0x7F, 0x03, 0x22, 0x75, 0x3D, 0x10, 0xE4, 0xF5, 0x3E, 0x75, 0x3F, 0x07, 0x75, 0x40, 0x02, 0x90, +0x01, 0x30, 0xE5, 0x3D, 0xF0, 0xA3, 0xE5, 0x3E, 0xF0, 0xA3, 0xE5, 0x3F, 0xF0, 0xA3, 0xE5, 0x40, +0xF0, 0x22, 0x75, 0x45, 0x0E, 0x75, 0x46, 0x01, 0x43, 0x46, 0x10, 0x75, 0x47, 0x03, 0x75, 0x48, +0x62, 0x90, 0x01, 0x38, 0xE5, 0x45, 0xF0, 0xA3, 0xE5, 0x46, 0xF0, 0xA3, 0xE5, 0x47, 0xF0, 0xA3, +0xE5, 0x48, 0xF0, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x54, 0xFB, +0xF0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0x54, 0xBF, 0xF0, 0xE4, 0xA3, 0xF0, +0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0x74, 0x0C, 0xF0, 0x22, 0x31, 0x9F, 0x12, 0x1F, 0xA4, 0xFF, 0x54, +0x01, 0xFE, 0x90, 0x81, 0x4A, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x14, +0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x4B, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, +0x90, 0x81, 0x4C, 0xF0, 0x22, 0x90, 0x81, 0xCD, 0x12, 0x4B, 0x1F, 0xEF, 0x12, 0x4B, 0x28, 0x5A, +0xEA, 0x00, 0x5A, 0xF3, 0x01, 0x5A, 0xFB, 0x02, 0x5B, 0x03, 0x03, 0x5B, 0x0C, 0x04, 0x5B, 0x14, +0x20, 0x5B, 0x1C, 0x21, 0x5B, 0x25, 0x23, 0x5B, 0x2D, 0x24, 0x5B, 0x36, 0x25, 0x5B, 0x3E, 0x26, +0x5B, 0x46, 0x27, 0x5B, 0x4E, 0xC0, 0x00, 0x00, 0x5B, 0x56, 0x90, 0x81, 0xCD, 0x12, 0x4B, 0x16, +0x02, 0x70, 0x9E, 0x90, 0x81, 0xCD, 0x12, 0x4B, 0x16, 0xC1, 0x95, 0x90, 0x81, 0xCD, 0x12, 0x4B, +0x16, 0x81, 0x9A, 0x90, 0x81, 0xCD, 0x12, 0x4B, 0x16, 0x02, 0x7D, 0x9E, 0x90, 0x81, 0xCD, 0x12, +0x4B, 0x16, 0x41, 0x89, 0x90, 0x81, 0xCD, 0x12, 0x4B, 0x16, 0xA1, 0xC2, 0x90, 0x81, 0xCD, 0x12, +0x4B, 0x16, 0x02, 0x70, 0xE6, 0x90, 0x81, 0xCD, 0x12, 0x4B, 0x16, 0xE1, 0x3B, 0x90, 0x81, 0xCD, +0x12, 0x4B, 0x16, 0x02, 0x51, 0x46, 0x90, 0x81, 0xCD, 0x12, 0x4B, 0x16, 0xE1, 0x62, 0x90, 0x81, +0xCD, 0x12, 0x4B, 0x16, 0x80, 0x18, 0x90, 0x81, 0xCD, 0x12, 0x4B, 0x16, 0x80, 0x3C, 0x90, 0x81, +0xCD, 0x12, 0x4B, 0x16, 0xE1, 0xA2, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x12, 0x1F, +0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x40, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0x90, 0x00, 0x01, +0x12, 0x1F, 0xBD, 0xFE, 0x90, 0x05, 0x54, 0xE0, 0xC3, 0x9E, 0x90, 0x81, 0x41, 0xF0, 0xEF, 0x20, +0xE0, 0x07, 0x71, 0xFD, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x12, 0x1F, 0xA4, 0x54, 0x01, 0xFF, +0x90, 0x81, 0x42, 0xE0, 0x54, 0xFE, 0x4F, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81, +0x43, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x44, 0xF0, 0x90, 0x81, 0x43, 0xE0, +0x90, 0x81, 0x45, 0xF0, 0x90, 0x81, 0x42, 0xE0, 0x54, 0x01, 0xFF, 0xAC, 0x07, 0xEF, 0x54, 0x01, +0xFE, 0x90, 0x81, 0x42, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEF, 0x90, 0x01, 0x53, 0xB4, 0x01, 0x12, +0xE4, 0xF0, 0x7D, 0x10, 0x7F, 0x03, 0x12, 0x77, 0xCD, 0x90, 0x81, 0x44, 0xE0, 0x90, 0x05, 0x73, +0xF0, 0x22, 0x74, 0x03, 0xF0, 0x7D, 0x10, 0xFF, 0x12, 0x77, 0xE2, 0x71, 0xFD, 0x90, 0x05, 0x22, +0xE4, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0xD3, 0x10, 0xAF, +0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x01, 0x01, 0xE0, 0x44, 0x02, 0xF0, 0x90, 0x01, 0x00, 0x74, 0xFF, +0xF0, 0x90, 0x06, 0xB7, 0x74, 0x09, 0xF0, 0x90, 0x06, 0xB4, 0x74, 0x86, 0xF0, 0x7F, 0x7C, 0x7E, +0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x54, 0x7F, 0xFC, 0x90, 0x82, 0x0A, 0x12, 0x20, 0xCE, 0x90, 0x82, +0x0A, 0x12, 0x4A, 0xD9, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2E, +0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0xCC, 0xC0, 0x00, 0xC0, 0x7F, 0x8C, 0x7E, 0x08, 0x12, +0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0x00, 0xC0, 0x00, 0x14, 0x7F, 0x70, 0x7E, 0x0E, +0x12, 0x2E, 0xA2, 0x90, 0x82, 0x02, 0x12, 0x20, 0xDA, 0x00, 0x03, 0x3E, 0x60, 0xE4, 0xFD, 0xFF, +0x91, 0x77, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xC0, 0x07, +0xC0, 0x05, 0x90, 0x82, 0x02, 0x12, 0x4A, 0xD9, 0x90, 0x81, 0xEE, 0x12, 0x20, 0xCE, 0xD0, 0x05, +0xD0, 0x07, 0x12, 0x6D, 0x26, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, +0xD0, 0x90, 0x81, 0xD0, 0x12, 0x4B, 0x1F, 0x12, 0x1F, 0xA4, 0xFF, 0x90, 0x81, 0x1E, 0xF0, 0xBF, +0x01, 0x12, 0x90, 0x81, 0xD0, 0x12, 0x4B, 0x16, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01, +0x60, 0x23, 0x80, 0x1E, 0x90, 0x81, 0xD0, 0x12, 0x4B, 0x16, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, +0x64, 0x01, 0x60, 0x11, 0x90, 0x81, 0x1F, 0xE0, 0x20, 0xE0, 0x07, 0xE4, 0xFF, 0x12, 0x55, 0xA3, +0x80, 0x03, 0x12, 0x72, 0xCF, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x05, 0x22, 0x74, 0xFF, 0xF0, +0xB1, 0x7A, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0xCC, 0xF0, 0x00, 0xC0, 0x7F, 0x8C, 0x7E, 0x08, +0x12, 0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x14, 0x7F, 0x70, 0x7E, +0x0E, 0x12, 0x2E, 0xA2, 0x90, 0x82, 0x02, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xFD, +0xFF, 0x91, 0x77, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x82, +0x0E, 0x12, 0x20, 0xCE, 0x90, 0x82, 0x0E, 0x12, 0x4A, 0xD9, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, +0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x01, 0x00, 0x74, 0x3F, 0xF0, 0xA3, 0xE0, 0x54, +0xFD, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x20, 0xF0, 0x22, 0x90, 0x05, 0x22, 0x74, 0xFF, 0xF0, +0xB1, 0x7A, 0x90, 0x01, 0x37, 0x74, 0x02, 0xF0, 0xFD, 0x7F, 0x03, 0x12, 0x51, 0x31, 0x91, 0xF0, +0xE4, 0x90, 0x81, 0x2A, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0xE4, 0x90, 0x82, 0x18, 0xF0, 0xA3, +0xF0, 0x90, 0x05, 0xF8, 0xE0, 0x70, 0x0F, 0xA3, 0xE0, 0x70, 0x0B, 0xA3, 0xE0, 0x70, 0x07, 0xA3, +0xE0, 0x70, 0x03, 0x7F, 0x01, 0x22, 0xD3, 0x90, 0x82, 0x19, 0xE0, 0x94, 0xE8, 0x90, 0x82, 0x18, +0xE0, 0x94, 0x03, 0x40, 0x0A, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x20, 0xF0, 0x7F, 0x00, 0x22, 0x7F, +0x32, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x90, 0x82, 0x18, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x4A, 0xA9, +0x80, 0xBF, 0x90, 0x81, 0xD0, 0x12, 0x4B, 0x1F, 0x90, 0x81, 0xD0, 0x12, 0x4B, 0x16, 0x90, 0x81, +0xD3, 0x12, 0x4B, 0x1F, 0x90, 0x81, 0xD0, 0x12, 0x4B, 0x16, 0x90, 0x00, 0x05, 0x12, 0x1F, 0xBD, +0x90, 0x81, 0x3F, 0xF0, 0x90, 0x81, 0xD3, 0x12, 0x4B, 0x16, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x7F, +0x90, 0x81, 0x27, 0xF0, 0xEF, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0xA3, 0xF0, 0x90, 0x00, 0x01, +0x12, 0x1F, 0xBD, 0xFF, 0x54, 0xF0, 0xC4, 0x54, 0x0F, 0xFE, 0x90, 0x81, 0x26, 0xE0, 0x54, 0xF0, +0x4E, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0x54, 0x01, 0x25, 0xE0, 0xFE, 0x90, 0x81, 0x24, +0xE0, 0x54, 0xFD, 0x4E, 0xF0, 0xEF, 0x54, 0x0F, 0xC4, 0x54, 0xF0, 0xFF, 0x90, 0x81, 0x26, 0xE0, +0x54, 0x0F, 0x4F, 0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x29, 0xF0, 0xD1, 0x65, +0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x90, 0x01, +0xBA, 0xF0, 0x90, 0x81, 0x29, 0xE0, 0x90, 0x01, 0xBB, 0xF0, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, +0x90, 0x01, 0xBE, 0xF0, 0x22, 0x90, 0x81, 0xD6, 0x12, 0x4B, 0x1F, 0xF1, 0x81, 0x90, 0x81, 0x27, +0xE0, 0xFF, 0x12, 0x53, 0x74, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x19, 0x90, 0x81, 0xD6, 0x12, 0x4B, +0x16, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x54, 0x0F, 0xFF, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, +0xFD, 0x12, 0x79, 0xDB, 0x22, 0x90, 0x81, 0xD0, 0x12, 0x4B, 0x1F, 0x90, 0x00, 0x01, 0x12, 0x1F, +0xBD, 0xFF, 0xFE, 0x12, 0x1F, 0xA4, 0xFD, 0xC3, 0x13, 0x30, 0xE0, 0x12, 0x90, 0x81, 0xD0, 0x12, +0x4B, 0x16, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0xD4, 0xF0, 0x80, 0x05, 0x90, 0x81, +0xD4, 0xEF, 0xF0, 0x90, 0x81, 0xD3, 0xEE, 0xF0, 0x90, 0x81, 0xD4, 0xE0, 0xFE, 0x90, 0x81, 0xD3, +0xE0, 0xFF, 0xD3, 0x9E, 0x50, 0x38, 0x90, 0x81, 0xD0, 0x12, 0x4B, 0x16, 0x12, 0x1F, 0xA4, 0x54, +0x01, 0xFE, 0x74, 0xDE, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83, 0xEE, 0xF0, 0x74, 0xDE, +0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83, 0xE0, 0x70, 0x04, 0xF1, 0x3A, 0x80, 0x07, 0x90, +0x81, 0xD3, 0xE0, 0xFF, 0xF1, 0x39, 0x90, 0x81, 0xD3, 0xE0, 0x04, 0xF0, 0x80, 0xBA, 0x90, 0x80, +0xDE, 0xE0, 0x70, 0x24, 0x90, 0x81, 0x2A, 0xE0, 0x70, 0x04, 0xFF, 0x12, 0x4F, 0x1B, 0x90, 0x81, +0x2A, 0xE0, 0x64, 0x0C, 0x60, 0x02, 0xF1, 0xB4, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xF7, 0xF0, 0x54, +0xEF, 0xF0, 0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0x22, 0x22, 0x22, 0x12, 0x1F, 0xA4, 0x90, 0x81, +0x31, 0xF0, 0x22, 0x71, 0xFD, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, 0x22, 0x91, 0xF0, 0x90, 0x81, +0x22, 0x74, 0x02, 0xF0, 0x22, 0x91, 0xEA, 0x90, 0x81, 0x2A, 0x74, 0x08, 0xF0, 0x90, 0x81, 0x23, +0xF0, 0x22, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x3E, 0xF0, 0x90, 0x81, 0x3E, 0xE0, 0x90, 0x01, 0xE7, +0xF0, 0x22, 0x90, 0x81, 0x40, 0xE0, 0x30, 0xE0, 0x07, 0x71, 0xFD, 0x90, 0x05, 0x22, 0xE4, 0xF0, +0x22, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFB, 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, 0x81, 0x2B, +0xF0, 0x22, 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x91, 0xEA, 0x90, 0x81, 0x22, 0x74, 0x02, +0xF0, 0x22, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x4F, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, +0x81, 0x50, 0xF0, 0x22, 0x90, 0x06, 0x04, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x05, 0x22, 0xE4, 0xF0, +0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x22, 0x71, 0xFD, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x90, +0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0xE4, 0x90, 0x81, +0x5E, 0xF0, 0x90, 0x81, 0x5E, 0xE0, 0x64, 0x01, 0xF0, 0x24, 0xDD, 0x90, 0x01, 0xC4, 0xF0, 0x74, +0x5F, 0xA3, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x0F, 0x90, 0x81, 0x2A, 0xE0, 0xFF, 0x90, 0x81, +0x29, 0xE0, 0x6F, 0x60, 0x03, 0x12, 0x4D, 0x29, 0xC2, 0xAF, 0x12, 0x72, 0x1A, 0xBF, 0x01, 0x02, +0x11, 0x23, 0xD2, 0xAF, 0xF1, 0xD6, 0x12, 0x32, 0x9E, 0xBF, 0x01, 0x02, 0x31, 0x24, 0x12, 0x48, +0x4D, 0x80, 0xBF, 0x90, 0x81, 0x24, 0xE0, 0x30, 0xE0, 0x23, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0x30, +0xE0, 0x19, 0xC3, 0x13, 0x30, 0xE0, 0x08, 0x12, 0x7C, 0x53, 0xBF, 0x01, 0x10, 0x80, 0x0A, 0x90, +0x81, 0x23, 0xE0, 0xFF, 0x60, 0x03, 0xB4, 0x08, 0x04, 0x80, 0x03, 0x11, 0x5E, 0x22, 0xD3, 0x10, +0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x11, 0xDF, 0x11, 0x77, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81, +0x2A, 0xE0, 0xFF, 0x60, 0x03, 0xB4, 0x08, 0x0E, 0x12, 0x7A, 0x8C, 0xBF, 0x01, 0x08, 0x11, 0x4E, +0x90, 0x01, 0xE5, 0xE0, 0x04, 0xF0, 0x22, 0xF1, 0xD7, 0x90, 0x00, 0x08, 0xE0, 0x54, 0xEF, 0xFD, +0x7F, 0x08, 0x12, 0x32, 0x1E, 0xE4, 0xFF, 0x8F, 0x50, 0xE4, 0x90, 0x81, 0x5F, 0xF0, 0xA3, 0xF0, +0x90, 0x01, 0x09, 0xE0, 0x7F, 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0xEF, 0x65, 0x50, 0x60, 0x3E, +0xC3, 0x90, 0x81, 0x60, 0xE0, 0x94, 0x88, 0x90, 0x81, 0x5F, 0xE0, 0x94, 0x13, 0x40, 0x08, 0x90, +0x01, 0xC0, 0xE0, 0x44, 0x10, 0xF0, 0x22, 0x90, 0x81, 0x5F, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x4A, +0xA9, 0x7F, 0x14, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0xD3, 0x90, 0x81, 0x60, 0xE0, 0x94, 0x32, 0x90, +0x81, 0x5F, 0xE0, 0x94, 0x00, 0x40, 0xB9, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE0, 0xB2, 0x22, 0x90, +0x81, 0x31, 0xE0, 0xFD, 0x7F, 0x93, 0x12, 0x32, 0x1E, 0x90, 0x81, 0x28, 0xE0, 0x60, 0x12, 0x90, +0x01, 0x2F, 0xE0, 0x30, 0xE7, 0x05, 0x74, 0x10, 0xF0, 0x80, 0x06, 0x90, 0x01, 0x2F, 0x74, 0x90, +0xF0, 0x90, 0x00, 0x08, 0xE0, 0x44, 0x10, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E, 0x7F, 0x01, 0x11, +0x87, 0x90, 0x00, 0x90, 0xE0, 0x44, 0x01, 0xFD, 0x7F, 0x90, 0x12, 0x32, 0x1E, 0x7F, 0x14, 0x7E, +0x00, 0x02, 0x32, 0xAA, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x2D, 0xA7, 0xE4, 0xF5, +0x52, 0x12, 0x32, 0x9E, 0xEF, 0x60, 0x71, 0x63, 0x52, 0x01, 0xE5, 0x52, 0x24, 0x24, 0x90, 0x01, +0xC4, 0xF0, 0x74, 0x61, 0xA3, 0xF0, 0x90, 0x00, 0x88, 0xE0, 0xF5, 0x50, 0xF5, 0x51, 0x54, 0x0F, +0x60, 0xDF, 0xE5, 0x50, 0x30, 0xE0, 0x0B, 0x20, 0xE4, 0x03, 0x12, 0x29, 0xC5, 0x53, 0x51, 0xEE, +0x80, 0x3D, 0xE5, 0x50, 0x30, 0xE1, 0x16, 0x20, 0xE5, 0x0E, 0x12, 0x11, 0xBD, 0xEF, 0x70, 0x03, +0x43, 0x51, 0x20, 0x90, 0x01, 0x06, 0xE4, 0xF0, 0x53, 0x51, 0xFD, 0x80, 0x22, 0xE5, 0x50, 0x30, +0xE2, 0x0A, 0x20, 0xE6, 0x02, 0x91, 0x2F, 0x53, 0x51, 0xFB, 0x80, 0x13, 0xE5, 0x50, 0x30, 0xE3, +0x0E, 0x20, 0xE7, 0x08, 0x31, 0xAD, 0xEF, 0x70, 0x03, 0x43, 0x51, 0x80, 0x53, 0x51, 0xF7, 0xAD, +0x51, 0x7F, 0x88, 0x12, 0x32, 0x1E, 0x80, 0x89, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x78, 0x10, 0x74, +0x01, 0xF2, 0x90, 0x02, 0x09, 0xE0, 0x78, 0x00, 0xF2, 0x08, 0x74, 0x20, 0xF2, 0x18, 0xE2, 0xFF, +0x30, 0xE0, 0x05, 0x08, 0xE2, 0x24, 0x80, 0xF2, 0xEF, 0xC3, 0x13, 0x90, 0xFD, 0x10, 0xF0, 0x78, +0x01, 0xE2, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x78, 0x03, 0xF2, 0x64, +0x04, 0x60, 0x0D, 0xE2, 0xFF, 0x64, 0x08, 0x60, 0x07, 0xEF, 0x64, 0x0C, 0x60, 0x02, 0x81, 0x1D, +0xE4, 0x78, 0x02, 0xF2, 0x78, 0x03, 0xE2, 0xFF, 0x18, 0xE2, 0xC3, 0x9F, 0x50, 0x2D, 0xE2, 0xFD, +0x18, 0xE2, 0x2D, 0x90, 0x81, 0x5F, 0xF0, 0xE0, 0xFF, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0xFC, +0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x04, 0x2D, 0xF8, 0xEE, 0xF2, 0xEF, 0xB4, 0xFF, 0x06, 0x90, 0xFD, +0x10, 0xE0, 0x04, 0xF0, 0x78, 0x02, 0xE2, 0x04, 0xF2, 0x80, 0xC9, 0x78, 0x04, 0xE2, 0x78, 0x12, +0xF2, 0xFF, 0x78, 0x05, 0xE2, 0x78, 0x11, 0xF2, 0x78, 0x06, 0xE2, 0x78, 0x13, 0xF2, 0x78, 0x07, +0xE2, 0x78, 0x14, 0xF2, 0x78, 0x08, 0xE2, 0x78, 0x33, 0xF2, 0x78, 0x09, 0xE2, 0x78, 0x34, 0xF2, +0x78, 0x0A, 0xE2, 0x78, 0x35, 0xF2, 0x78, 0x0B, 0xE2, 0x78, 0x36, 0xF2, 0x78, 0x0C, 0xE2, 0x78, +0x37, 0xF2, 0x78, 0x0D, 0xE2, 0x78, 0x38, 0xF2, 0x78, 0x0E, 0xE2, 0x78, 0x39, 0xF2, 0x78, 0x0F, +0xE2, 0x78, 0x3A, 0xF2, 0xE4, 0x78, 0x15, 0xF2, 0xEF, 0x24, 0xF8, 0x60, 0x75, 0x24, 0xFC, 0x60, +0x6C, 0x24, 0x08, 0x60, 0x02, 0x61, 0xFF, 0x78, 0x11, 0xE2, 0xB4, 0x01, 0x05, 0x12, 0x29, 0xC5, +0x81, 0x04, 0x78, 0x11, 0xE2, 0xB4, 0x02, 0x05, 0x12, 0x11, 0xBD, 0x81, 0x04, 0x78, 0x11, 0xE2, +0xB4, 0x03, 0x04, 0x91, 0x2F, 0x81, 0x04, 0x78, 0x11, 0xE2, 0xB4, 0x10, 0x17, 0x78, 0x14, 0xE2, +0xFE, 0x18, 0xE2, 0xFD, 0xED, 0xFF, 0x78, 0x16, 0xEE, 0xF2, 0xFE, 0x08, 0xEF, 0xF2, 0xFF, 0x12, +0x32, 0xAA, 0x81, 0x04, 0x78, 0x11, 0xE2, 0xB4, 0x11, 0x17, 0x78, 0x14, 0xE2, 0xFE, 0x18, 0xE2, +0xFD, 0xED, 0xFF, 0x78, 0x16, 0xEE, 0xF2, 0xFE, 0x08, 0xEF, 0xF2, 0xFF, 0x12, 0x32, 0x06, 0x81, +0x04, 0x78, 0x11, 0xE2, 0xF4, 0x60, 0x02, 0x81, 0x04, 0x18, 0xF2, 0x81, 0x04, 0x78, 0x15, 0x74, +0x01, 0xF2, 0x78, 0x11, 0xE2, 0x64, 0x07, 0x60, 0x02, 0x61, 0xE9, 0x78, 0x34, 0xE2, 0xFF, 0xE4, +0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12, 0x20, 0xBB, 0xC0, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, 0x07, +0x78, 0x33, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0xD0, 0x00, 0x12, 0x4A, 0xCC, 0xC0, 0x04, 0xC0, +0x05, 0xC0, 0x06, 0xC0, 0x07, 0x78, 0x35, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, +0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x4A, 0xCC, 0x78, 0x18, 0x12, +0x4A, 0xFE, 0x78, 0x15, 0xE2, 0x70, 0x02, 0x61, 0xD2, 0x18, 0xE2, 0xFF, 0x18, 0xE2, 0xFD, 0x91, +0x20, 0x78, 0x1C, 0x12, 0x4A, 0xFE, 0x78, 0x38, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, +0x12, 0x20, 0xBB, 0xC0, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, 0x07, 0x78, 0x37, 0xE2, 0xFF, 0xE4, +0xFC, 0xFD, 0xFE, 0xD0, 0x00, 0x12, 0x4A, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, +0x78, 0x39, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, +0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x4A, 0xCC, 0x78, 0x20, 0x12, 0x4A, 0xFE, 0x78, 0x20, 0x12, +0x4A, 0xE5, 0x12, 0x20, 0x9B, 0x78, 0x1C, 0x12, 0x4A, 0xF1, 0x12, 0x4A, 0xBF, 0xC0, 0x04, 0xC0, +0x05, 0xC0, 0x06, 0xC0, 0x07, 0x78, 0x18, 0x12, 0x4A, 0xE5, 0x78, 0x20, 0x12, 0x4A, 0xF1, 0x12, +0x4A, 0xBF, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x4A, 0xCC, 0x78, 0x18, 0x12, +0x4A, 0xFE, 0x78, 0x18, 0x12, 0x4A, 0xE5, 0x90, 0x82, 0x02, 0x12, 0x20, 0xCE, 0x78, 0x13, 0xE2, +0xFD, 0x08, 0xE2, 0xFF, 0x12, 0x5C, 0x77, 0x80, 0x1B, 0x78, 0x13, 0xE2, 0xFF, 0x08, 0xE2, 0xFD, +0x78, 0x11, 0xE2, 0xFB, 0x78, 0x15, 0xE2, 0x90, 0x81, 0xC1, 0xF0, 0xF1, 0xDF, 0x80, 0x05, 0x78, +0x10, 0x74, 0x02, 0xF2, 0x78, 0x10, 0xE2, 0xFF, 0xC3, 0x94, 0x02, 0x50, 0x10, 0xEF, 0x60, 0x0A, +0x78, 0x02, 0xE2, 0xFF, 0x18, 0xE2, 0x2F, 0xF2, 0x21, 0xCF, 0x7F, 0x01, 0x22, 0x7F, 0x00, 0x22, +0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x6B, 0xE7, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xE4, +0x90, 0x81, 0x6F, 0xF0, 0x90, 0x87, 0x5F, 0xE0, 0x90, 0x81, 0x6E, 0xF0, 0xE4, 0x90, 0x81, 0x7B, +0xF0, 0x90, 0x81, 0x6B, 0xF0, 0x90, 0x81, 0x6B, 0xE0, 0xFF, 0xC3, 0x94, 0x40, 0x50, 0x15, 0x74, +0x7E, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0x74, 0xFF, 0xF0, 0x90, 0x81, 0x6B, 0xE0, +0x04, 0xF0, 0x80, 0xE1, 0xE4, 0x90, 0x81, 0x6B, 0xF0, 0x90, 0x81, 0x6E, 0xE0, 0xFF, 0x90, 0x81, +0x6B, 0xE0, 0xFE, 0xC3, 0x9F, 0x40, 0x02, 0xA1, 0x39, 0x74, 0xDF, 0x2E, 0xF9, 0xE4, 0x34, 0x86, +0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x0A, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x60, +0x12, 0x2B, 0xED, 0x90, 0x81, 0x61, 0xE0, 0xFF, 0x12, 0x2F, 0x27, 0xEF, 0x04, 0x90, 0x81, 0x7B, +0xF0, 0x90, 0x81, 0x60, 0xE0, 0xFF, 0xA3, 0xE0, 0xFD, 0x12, 0x31, 0xEA, 0xEF, 0x24, 0xC8, 0x90, +0x81, 0x7D, 0xF0, 0x75, 0xF0, 0x08, 0xA4, 0xF0, 0x90, 0x81, 0x61, 0xE0, 0x54, 0x0F, 0x90, 0x81, +0x7C, 0xF0, 0xE4, 0x90, 0x81, 0x6A, 0xF0, 0x90, 0x81, 0x6C, 0xF0, 0x90, 0x81, 0x6C, 0xE0, 0xFF, +0xC3, 0x94, 0x04, 0x50, 0x57, 0x90, 0x81, 0x7C, 0xE0, 0xFE, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, +0x13, 0xD8, 0xFC, 0x20, 0xE0, 0x3E, 0x90, 0x81, 0x6C, 0xE0, 0x25, 0xE0, 0xFF, 0x90, 0x81, 0x7D, +0xE0, 0x2F, 0x24, 0x7E, 0xF9, 0xE4, 0x34, 0x81, 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x01, 0x90, +0x81, 0x6A, 0xE0, 0x75, 0xF0, 0x02, 0xA4, 0x24, 0x62, 0xF9, 0x74, 0x81, 0x35, 0xF0, 0x8B, 0x13, +0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x02, 0xD0, 0x01, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x90, 0x81, +0x6A, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x6C, 0xE0, 0x04, 0xF0, 0x80, 0x9F, 0x90, 0x81, 0x7B, 0xE0, +0xFF, 0x90, 0x81, 0x6B, 0xE0, 0x2F, 0xF0, 0x81, 0x69, 0xE4, 0x90, 0x81, 0x6F, 0xF0, 0x90, 0x81, +0x6F, 0xE0, 0xC3, 0x94, 0x40, 0x40, 0x02, 0xE1, 0xD5, 0xE0, 0xFF, 0x24, 0x7E, 0xF5, 0x82, 0xE4, +0x34, 0x81, 0xF5, 0x83, 0xE0, 0x90, 0x81, 0x71, 0xF0, 0xE0, 0xFE, 0x54, 0xF0, 0xC4, 0x54, 0x0F, +0xFD, 0x90, 0x81, 0x70, 0xF0, 0xEE, 0x54, 0x0F, 0xFE, 0xA3, 0xF0, 0x74, 0x7F, 0x2F, 0xF5, 0x82, +0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0x90, 0x81, 0x72, 0xF0, 0xFC, 0xEE, 0xFE, 0xEC, 0xFB, 0xEB, +0xFF, 0x90, 0x81, 0x77, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xED, 0x12, 0x4B, 0x28, 0x65, 0xB2, 0x00, +0x65, 0xE9, 0x01, 0x66, 0x9A, 0x02, 0x67, 0xC6, 0x03, 0x66, 0xB5, 0x04, 0x66, 0xD6, 0x05, 0x66, +0xD6, 0x06, 0x66, 0xD6, 0x07, 0x66, 0xD6, 0x08, 0x67, 0x5A, 0x09, 0x67, 0x90, 0x0A, 0x00, 0x00, +0x67, 0xD5, 0x90, 0x81, 0x6F, 0xE0, 0xFD, 0x24, 0x81, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, +0xE0, 0xFE, 0x74, 0x80, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFD, 0xED, 0xFF, +0x90, 0x81, 0x79, 0xEE, 0xF0, 0xFC, 0xA3, 0xEF, 0xF0, 0x90, 0x81, 0x72, 0xE0, 0xFF, 0x12, 0x2F, +0x96, 0x90, 0x81, 0x6D, 0x74, 0x02, 0xF0, 0xE1, 0xC6, 0x90, 0x81, 0x6F, 0xE0, 0x24, 0x81, 0xF5, +0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12, 0x20, +0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, 0x07, 0x90, 0x81, 0x6F, 0xE0, 0x24, 0x80, 0xF5, +0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x12, 0x4A, 0xCC, 0xC0, +0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0x6F, 0xE0, 0x24, 0x82, 0xF5, 0x82, 0xE4, +0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20, 0xBB, 0xD0, +0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x4A, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, +0xC0, 0x07, 0x90, 0x81, 0x6F, 0xE0, 0x24, 0x83, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, +0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x18, 0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, +0xD0, 0x00, 0x12, 0x4A, 0xCC, 0x90, 0x81, 0x73, 0x12, 0x20, 0xCE, 0x90, 0x81, 0x73, 0x12, 0x4A, +0xD9, 0x90, 0x85, 0x96, 0x12, 0x20, 0xCE, 0x90, 0x81, 0x77, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, +0x2E, 0xE4, 0x90, 0x81, 0x6D, 0x74, 0x04, 0xF0, 0xE1, 0xC6, 0x90, 0x81, 0x72, 0xE0, 0xFD, 0x90, +0x81, 0x6F, 0xE0, 0x24, 0x80, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFB, 0xE4, 0xFF, +0x12, 0x30, 0xC7, 0x80, 0x19, 0x90, 0x81, 0x72, 0xE0, 0xFD, 0x90, 0x81, 0x6F, 0xE0, 0x24, 0x80, +0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFB, 0xE4, 0xFF, 0x12, 0x30, 0x6A, 0x90, 0x81, +0x6D, 0x74, 0x01, 0xF0, 0xE1, 0xC6, 0x90, 0x81, 0x6D, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x6F, 0xE0, +0x24, 0x81, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, +0x08, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, 0x07, 0x90, 0x81, 0x6F, 0xE0, +0x24, 0x80, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x12, +0x4A, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0x71, 0xE0, 0xFF, 0xE4, +0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, +0x12, 0x4A, 0xCC, 0x90, 0x81, 0x73, 0x12, 0x20, 0xCE, 0x90, 0x81, 0x70, 0xE0, 0x24, 0xFB, 0xFF, +0xC0, 0x07, 0x90, 0x81, 0x73, 0x12, 0x4A, 0xD9, 0x90, 0x82, 0x02, 0x12, 0x20, 0xCE, 0x90, 0x81, +0x72, 0xE0, 0xFD, 0xD0, 0x07, 0x12, 0x5C, 0x77, 0x80, 0x6C, 0x90, 0x81, 0x6D, 0x74, 0x01, 0xF0, +0x90, 0x81, 0x6F, 0xE0, 0x24, 0x80, 0xF9, 0xE4, 0x34, 0x81, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, +0x15, 0x75, 0x16, 0x01, 0x7B, 0xFE, 0x7A, 0x80, 0x79, 0x33, 0x12, 0x2B, 0xED, 0x90, 0x81, 0x72, +0xE0, 0xFF, 0x90, 0x81, 0x71, 0xE0, 0xFD, 0xE4, 0x90, 0x81, 0xC1, 0xF0, 0x7B, 0x04, 0x80, 0x34, +0x90, 0x81, 0x6D, 0x74, 0x04, 0xF0, 0x90, 0x81, 0x6F, 0xE0, 0x24, 0x80, 0xF9, 0xE4, 0x34, 0x81, +0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x04, 0x7B, 0xFE, 0x7A, 0x80, 0x79, 0x33, +0x12, 0x2B, 0xED, 0x90, 0x81, 0x72, 0xE0, 0xFF, 0x90, 0x81, 0x71, 0xE0, 0xFD, 0xE4, 0x90, 0x81, +0xC1, 0xF0, 0x7B, 0x06, 0xF1, 0xDF, 0x90, 0x81, 0x6D, 0xE0, 0x24, 0x02, 0xFF, 0x90, 0x81, 0x6F, +0xE0, 0x2F, 0xF0, 0xA1, 0x3E, 0x22, 0x22, 0x90, 0x00, 0x90, 0xE0, 0x20, 0xE0, 0xF9, 0x22, 0xAC, +0x07, 0xED, 0xAD, 0x04, 0x78, 0x24, 0xF2, 0xED, 0x08, 0xF2, 0xEB, 0xB4, 0x04, 0x07, 0x78, 0x27, +0x74, 0x01, 0xF2, 0x80, 0x0E, 0xEB, 0x78, 0x27, 0xB4, 0x05, 0x05, 0x74, 0x02, 0xF2, 0x80, 0x03, +0x74, 0x04, 0xF2, 0xD3, 0x78, 0x25, 0xE2, 0x94, 0xFF, 0x18, 0xE2, 0x94, 0x00, 0x50, 0x63, 0xE4, +0x78, 0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF, 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x40, 0x02, 0x21, 0x7D, +0x74, 0x33, 0x2E, 0xF8, 0xE2, 0x78, 0x28, 0xF2, 0x90, 0x81, 0xC1, 0xE0, 0x60, 0x2D, 0x74, 0x37, +0x2E, 0xF8, 0xE2, 0x78, 0x32, 0xF2, 0xEE, 0xFF, 0x78, 0x25, 0xE2, 0x2F, 0xFF, 0x18, 0xE2, 0x34, +0x00, 0x8F, 0x82, 0xF5, 0x83, 0xE0, 0x78, 0x29, 0xF2, 0x78, 0x32, 0xE2, 0xFF, 0xF4, 0xFE, 0x78, +0x29, 0xE2, 0x5E, 0xFE, 0x18, 0xE2, 0xFD, 0xEF, 0x5D, 0x4E, 0xF2, 0x78, 0x24, 0x08, 0xE2, 0xFF, +0x08, 0xE2, 0x2F, 0xFF, 0x78, 0x28, 0xE2, 0xFD, 0x12, 0x32, 0x1E, 0x78, 0x26, 0xE2, 0x04, 0xF2, +0x80, 0xA1, 0xD3, 0x78, 0x25, 0xE2, 0x94, 0xFF, 0x18, 0xE2, 0x94, 0x07, 0x50, 0x69, 0xE4, 0x78, +0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF, 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x40, 0x02, 0x21, 0x7D, 0x74, +0x33, 0x2E, 0xF8, 0xE2, 0x78, 0x28, 0xF2, 0x90, 0x81, 0xC1, 0xE0, 0x60, 0x2D, 0x78, 0x26, 0xE2, +0xFF, 0xFD, 0x18, 0xE2, 0x2D, 0xFD, 0x18, 0xE2, 0x34, 0x00, 0x8D, 0x82, 0xF5, 0x83, 0xE0, 0x78, +0x29, 0xF2, 0x74, 0x37, 0x2F, 0xF8, 0xE2, 0x78, 0x32, 0xF2, 0xE2, 0xFF, 0xF4, 0xFE, 0x78, 0x29, +0xE2, 0x5E, 0xFE, 0x18, 0xE2, 0xFD, 0xEF, 0x5D, 0x4E, 0xF2, 0x78, 0x28, 0xE2, 0xFF, 0x78, 0x26, +0xE2, 0xFD, 0x18, 0xE2, 0x2D, 0xFD, 0x18, 0xE2, 0x34, 0x00, 0x8D, 0x82, 0xF5, 0x83, 0xEF, 0xF0, +0x78, 0x26, 0xE2, 0x04, 0xF2, 0x80, 0x9B, 0x90, 0x81, 0xC1, 0xE0, 0x60, 0x0F, 0x78, 0x24, 0xE2, +0xFE, 0x08, 0xE2, 0xFF, 0x12, 0x2D, 0x5C, 0x78, 0x2E, 0x12, 0x4A, 0xFE, 0xE4, 0x78, 0x26, 0xF2, +0x78, 0x27, 0xE2, 0xFF, 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x50, 0x5D, 0x74, 0x33, 0x2E, 0xF8, 0xE2, +0x78, 0x28, 0xF2, 0x90, 0x81, 0xC1, 0xE0, 0x60, 0x2B, 0x78, 0x2E, 0x12, 0x4A, 0xE5, 0x78, 0x26, +0xE2, 0xFB, 0x75, 0xF0, 0x08, 0xA4, 0xF9, 0xF8, 0x12, 0x20, 0xA8, 0x78, 0x29, 0xEF, 0xF2, 0x74, +0x37, 0x2B, 0xF8, 0xE2, 0x78, 0x32, 0xF2, 0xE2, 0xFE, 0xF4, 0x5F, 0xFF, 0x78, 0x28, 0xE2, 0xFD, +0xEE, 0x5D, 0x4F, 0xF2, 0x78, 0x28, 0xE2, 0xFF, 0x78, 0x26, 0xE2, 0xFD, 0xC3, 0x74, 0x03, 0x9D, +0xFD, 0xE4, 0x94, 0x00, 0xFC, 0x7B, 0xFE, 0x74, 0x2A, 0x2D, 0xF9, 0x74, 0x80, 0x3C, 0xFA, 0xEF, +0x12, 0x1F, 0xEA, 0xE2, 0x04, 0xF2, 0x80, 0x98, 0x78, 0x2A, 0x12, 0x4A, 0xE5, 0x90, 0x85, 0xBB, +0x12, 0x20, 0xCE, 0x78, 0x24, 0xE2, 0xFE, 0x08, 0xE2, 0xFF, 0x12, 0x2E, 0xA2, 0x22, 0xE4, 0xFB, +0xFA, 0xFD, 0x7F, 0x01, 0x12, 0x4A, 0x4E, 0x90, 0x81, 0xC2, 0xEF, 0xF0, 0x60, 0xF0, 0x31, 0x92, +0x80, 0xEC, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x01, 0xCC, 0xE0, 0x54, 0x0F, 0x90, +0x81, 0xC3, 0xF0, 0x90, 0x81, 0xC3, 0xE0, 0xFD, 0x70, 0x02, 0x41, 0xBD, 0x90, 0x82, 0x12, 0xE0, +0xFF, 0x74, 0x01, 0x7E, 0x00, 0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, +0xF9, 0xFF, 0xEF, 0x5D, 0x70, 0x02, 0x41, 0xB6, 0x90, 0x82, 0x12, 0xE0, 0x75, 0xF0, 0x04, 0x90, +0x01, 0xD0, 0x12, 0x4B, 0x0A, 0xE0, 0x90, 0x81, 0xC4, 0xF0, 0x75, 0x13, 0x01, 0x75, 0x14, 0x81, +0x75, 0x15, 0xC4, 0x75, 0x16, 0x01, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0xC5, 0x12, 0x2B, 0xED, 0x90, +0x82, 0x12, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD1, 0x12, 0x4B, 0x0A, 0xE0, 0x90, 0x81, 0xC6, +0xF0, 0x90, 0x82, 0x12, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD2, 0x12, 0x4B, 0x0A, 0xE0, 0x90, +0x81, 0xC7, 0xF0, 0x90, 0x82, 0x12, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD3, 0x12, 0x4B, 0x0A, +0xE0, 0x90, 0x81, 0xC8, 0xF0, 0x90, 0x82, 0x12, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF0, 0x12, +0x4B, 0x0A, 0xE0, 0x90, 0x81, 0xC9, 0xF0, 0x90, 0x82, 0x12, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, +0xF1, 0x12, 0x4B, 0x0A, 0xE0, 0x90, 0x81, 0xCA, 0xF0, 0x90, 0x82, 0x12, 0xE0, 0x75, 0xF0, 0x04, +0x90, 0x01, 0xF2, 0x12, 0x4B, 0x0A, 0xE0, 0x90, 0x81, 0xCB, 0xF0, 0x90, 0x82, 0x12, 0xE0, 0x75, +0xF0, 0x04, 0x90, 0x01, 0xF3, 0x12, 0x4B, 0x0A, 0xE0, 0x90, 0x81, 0xCC, 0xF0, 0x90, 0x81, 0xC3, +0xE0, 0xFF, 0x90, 0x82, 0x12, 0xE0, 0xFE, 0x74, 0x01, 0xA8, 0x06, 0x08, 0x80, 0x02, 0xC3, 0x33, +0xD8, 0xFC, 0xF4, 0x5F, 0x90, 0x81, 0xC3, 0xF0, 0x90, 0x82, 0x12, 0xE0, 0xFF, 0x74, 0x01, 0xA8, +0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0x90, 0x01, 0xCC, 0xF0, 0x90, 0x81, 0xC5, 0xE0, +0xFF, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0xC6, 0x12, 0x5A, 0xB5, 0x90, 0x82, 0x12, 0xE0, 0x04, 0xF0, +0xE0, 0x54, 0x03, 0xF0, 0x21, 0xA3, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x02, 0xF0, 0xD0, 0xD0, 0x92, +0xAF, 0x22, 0xE4, 0xFB, 0xFA, 0xFD, 0x7F, 0x01, 0x12, 0x4A, 0x4E, 0x90, 0x81, 0xD9, 0xEF, 0xF0, +0x60, 0xF0, 0x51, 0xD6, 0x80, 0xEC, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xE4, 0xFF, 0x90, +0x80, 0xD9, 0xE0, 0xFE, 0x90, 0x80, 0xD8, 0xE0, 0xFD, 0xB5, 0x06, 0x04, 0x7E, 0x01, 0x80, 0x02, +0x7E, 0x00, 0xEE, 0x64, 0x01, 0x60, 0x32, 0x90, 0x01, 0xAF, 0xE0, 0x70, 0x13, 0xED, 0x75, 0xF0, +0x0F, 0xA4, 0x24, 0x42, 0xF9, 0x74, 0x80, 0x35, 0xF0, 0xFA, 0x7B, 0x01, 0x71, 0x2E, 0x7F, 0x01, +0xEF, 0x60, 0x16, 0x90, 0x80, 0xD8, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4, 0x0A, 0x02, 0x7F, +0x01, 0xEF, 0x60, 0x05, 0xE4, 0x90, 0x80, 0xD8, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, +0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0xDA, 0x12, 0x4B, 0x1F, 0x90, 0x82, 0x13, 0xE0, 0xFF, +0x04, 0xF0, 0x90, 0x00, 0x01, 0xEF, 0x12, 0x1F, 0xFC, 0x7F, 0xAF, 0x7E, 0x01, 0x71, 0x91, 0xEF, +0x60, 0x3A, 0x90, 0x81, 0xDA, 0x12, 0x4B, 0x16, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x90, 0x00, +0x0E, 0x12, 0x1F, 0xBD, 0x24, 0x02, 0xF5, 0x16, 0x7B, 0x01, 0x7A, 0x01, 0x79, 0xA0, 0x12, 0x2B, +0xED, 0x90, 0x81, 0xDA, 0x12, 0x4B, 0x16, 0x90, 0x00, 0x0E, 0x12, 0x1F, 0xBD, 0x90, 0x01, 0xAE, +0xF0, 0xA3, 0x74, 0xFF, 0xF0, 0x90, 0x01, 0xCB, 0xE0, 0x64, 0x80, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, +0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, 0x06, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, +0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x82, 0x06, 0xE0, 0xFE, 0xA3, 0xE0, 0xF5, 0x82, 0x8E, 0x83, +0xE0, 0x60, 0x2D, 0xC3, 0x90, 0x82, 0x09, 0xE0, 0x94, 0xE8, 0x90, 0x82, 0x08, 0xE0, 0x94, 0x03, +0x40, 0x0B, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x80, 0xF0, 0x7F, 0x00, 0x80, 0x15, 0x90, 0x82, 0x08, +0xE4, 0x75, 0xF0, 0x01, 0x12, 0x4A, 0xA9, 0x7F, 0x0A, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x80, 0xC5, +0x7F, 0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81, 0xDD, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0xA3, +0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x90, 0x81, 0xEB, 0xF0, 0x7F, 0x24, 0x7E, 0x08, +0x12, 0x2D, 0x5C, 0x90, 0x81, 0xE3, 0x12, 0x20, 0xCE, 0x90, 0x81, 0xDD, 0xE0, 0xFB, 0x70, 0x08, +0x90, 0x81, 0xE3, 0x12, 0x4A, 0xD9, 0x80, 0x16, 0xEB, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, +0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, 0x2D, 0x5C, 0x90, 0x81, +0xE7, 0x12, 0x20, 0xCE, 0x90, 0x81, 0xDE, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x17, 0x12, +0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, 0x07, 0x90, 0x81, 0xE7, 0x12, 0x4A, 0xD9, +0xED, 0x54, 0x7F, 0xFD, 0xEC, 0x54, 0x80, 0xFC, 0x12, 0x4A, 0xCC, 0xEC, 0x44, 0x80, 0xFC, 0x90, +0x81, 0xE7, 0x12, 0x20, 0xCE, 0x90, 0x81, 0xE3, 0x12, 0x4A, 0xD9, 0xEC, 0x54, 0x7F, 0xFC, 0x90, +0x85, 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xDD, 0xE0, +0x75, 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, +0xE0, 0xFF, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0xE7, 0x12, 0x4A, 0xD9, 0x90, 0x85, 0xBB, 0x12, +0x20, 0xCE, 0xD0, 0x07, 0xD0, 0x06, 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xE3, 0x12, 0x4A, 0xD9, 0xEC, +0x44, 0x80, 0xFC, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2E, 0xA2, +0x90, 0x81, 0xDD, 0xE0, 0x70, 0x04, 0x7F, 0x20, 0x80, 0x09, 0x90, 0x81, 0xDD, 0xE0, 0xB4, 0x01, +0x16, 0x7F, 0x28, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0x78, 0x08, 0x12, 0x20, 0xA8, 0xEF, 0x54, 0x01, +0xFF, 0xE4, 0x90, 0x81, 0xEB, 0xEF, 0xF0, 0x90, 0x81, 0xEB, 0xE0, 0x90, 0x81, 0xDD, 0x60, 0x0E, +0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x66, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0x80, 0x0C, 0xE0, 0x75, +0xF0, 0x08, 0xA4, 0x24, 0x64, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, +0xFF, 0x12, 0x2D, 0x5C, 0xED, 0x54, 0x0F, 0xFD, 0xE4, 0xFC, 0x90, 0x81, 0xDF, 0x12, 0x20, 0xCE, +0x90, 0x81, 0xDF, 0x02, 0x4A, 0xD9, 0x90, 0x81, 0xEC, 0xEF, 0xF0, 0xAB, 0x05, 0x90, 0x81, 0xF2, +0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x03, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x14, 0x12, +0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, 0x07, 0x90, 0x81, 0xEE, 0x12, 0x4A, 0xD9, +0xED, 0x54, 0x0F, 0xFD, 0xE4, 0xFC, 0x12, 0x4A, 0xCC, 0xEC, 0x54, 0x0F, 0xFC, 0x90, 0x81, 0xF2, +0x12, 0x20, 0xCE, 0x90, 0x81, 0xEC, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x60, 0xF5, 0x82, 0xE4, +0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0xF2, +0x12, 0x4A, 0xD9, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0xD0, 0x07, 0xD0, 0x06, 0x02, 0x2E, 0xA2, +0xE0, 0x44, 0x02, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x39, 0xE0, 0xF5, 0x1E, 0xE4, 0xFB, 0xFD, +0x7F, 0x54, 0x7E, 0x01, 0x8E, 0x19, 0x8F, 0x1A, 0xE5, 0x1E, 0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0, +0x85, 0x19, 0x83, 0x85, 0x1A, 0x82, 0xF0, 0xE5, 0x1D, 0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0, 0xFF, +0xE5, 0x1E, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x4F, 0xA3, 0xF0, 0xEB, 0x54, 0x07, 0xC4, 0x33, 0x54, +0xE0, 0xFF, 0xE5, 0x1D, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x4F, 0x85, 0x1A, 0x82, 0x85, 0x19, 0x83, +0xA3, 0xA3, 0xF0, 0xBD, 0x01, 0x0C, 0x85, 0x1A, 0x82, 0x8E, 0x83, 0xA3, 0xA3, 0xA3, 0x74, 0x03, +0xF0, 0x22, 0x85, 0x1A, 0x82, 0x85, 0x19, 0x83, 0xA3, 0xA3, 0xA3, 0x74, 0x01, 0xF0, 0x22, 0xE4, +0x90, 0x81, 0x51, 0xF0, 0x90, 0x06, 0xA9, 0xE0, 0x90, 0x81, 0x51, 0xF0, 0xE0, 0x54, 0xC0, 0x70, +0x0D, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x02, 0x4D, 0x29, 0x90, 0x81, +0x51, 0xE0, 0x30, 0xE6, 0x21, 0x90, 0x81, 0x27, 0xE0, 0x64, 0x01, 0x70, 0x20, 0x90, 0x81, 0x2B, +0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x04, 0xF1, 0x3D, +0x80, 0x0B, 0xD1, 0x6C, 0x80, 0x07, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x81, 0x51, +0xE0, 0x90, 0x81, 0x2B, 0x30, 0xE7, 0x10, 0xB1, 0x90, 0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, +0x81, 0x24, 0xE0, 0x44, 0x04, 0xF0, 0x22, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, 0x01, 0x5F, 0xE4, +0xF0, 0x90, 0x01, 0x3C, 0x74, 0x08, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, 0xE0, 0xC3, 0x13, +0x54, 0x7F, 0xF5, 0x1E, 0xE4, 0xFB, 0xFD, 0x7F, 0x5C, 0x7E, 0x01, 0xB1, 0xA4, 0x90, 0x01, 0x5F, +0x74, 0x05, 0xF0, 0x90, 0x06, 0x92, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x10, 0xF0, +0x90, 0x81, 0x2A, 0xE0, 0x64, 0x0C, 0x60, 0x08, 0x12, 0x4D, 0x3D, 0xE4, 0xFF, 0x12, 0x56, 0xA8, +0x22, 0x90, 0x06, 0xA9, 0xE0, 0x90, 0x81, 0x51, 0xF0, 0xE0, 0xFD, 0x54, 0xC0, 0x70, 0x09, 0x90, +0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x80, 0x71, 0xED, 0x30, 0xE6, 0x4B, 0x90, 0x81, 0x27, 0xE0, +0x64, 0x02, 0x70, 0x2A, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0xC3, 0x13, 0x20, 0xE0, 0x09, 0x90, 0x81, +0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x28, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x01, 0x70, +0x2D, 0x90, 0x81, 0x2B, 0xE0, 0x44, 0x04, 0xF0, 0x7F, 0x01, 0xF1, 0x74, 0x80, 0x20, 0x90, 0x81, +0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x04, 0xF1, +0x3D, 0x80, 0x0B, 0xD1, 0x6C, 0x80, 0x07, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x81, +0x51, 0xE0, 0x90, 0x81, 0x2B, 0x30, 0xE7, 0x10, 0xB1, 0x90, 0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, +0x90, 0x81, 0x24, 0xE0, 0x44, 0x04, 0xF0, 0x22, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, 0x04, 0x1D, +0xE0, 0x70, 0x14, 0x90, 0x80, 0x3E, 0xE0, 0xFF, 0xE4, 0xFD, 0x12, 0x57, 0x31, 0x8E, 0x4E, 0x8F, +0x4F, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0xB4, 0x01, 0x14, 0x90, +0x81, 0x27, 0xE0, 0x60, 0x0E, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x02, 0x80, +0xCC, 0xD1, 0x6C, 0x22, 0x8F, 0x4E, 0x12, 0x77, 0x5A, 0xBF, 0x01, 0x19, 0x90, 0x80, 0x40, 0xE0, +0xFF, 0x7D, 0x01, 0x12, 0x57, 0x31, 0xAD, 0x07, 0xAC, 0x06, 0xAF, 0x4E, 0x12, 0x56, 0xE6, 0x90, +0x04, 0x1F, 0x74, 0x20, 0xF0, 0x22, 0x90, 0x81, 0x40, 0xE0, 0x30, 0xE0, 0x0C, 0xE4, 0xF5, 0x1D, +0xA3, 0xB1, 0x9A, 0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x01, 0xBE, 0xE0, 0x04, 0xF0, 0x22, +0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x70, 0x18, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x12, 0x90, 0x01, +0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xB1, 0x93, 0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, +0x22, 0x90, 0x81, 0xF6, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0xAD, 0x03, 0xAC, 0x02, 0xE4, 0x90, 0x81, +0xFE, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0xC4, 0x74, 0xD1, 0xF0, 0x74, 0x6F, 0xA3, 0xF0, 0xEC, 0x54, +0x3F, 0xFC, 0x90, 0x01, 0x40, 0xED, 0xF0, 0xAE, 0x04, 0xEE, 0xA3, 0xF0, 0x90, 0x81, 0xF6, 0xE0, +0x24, 0x81, 0x60, 0x34, 0x24, 0xDA, 0x60, 0x1C, 0x24, 0x3C, 0x70, 0x41, 0x90, 0x81, 0xF7, 0xE0, +0xC4, 0x33, 0x33, 0x33, 0x54, 0x80, 0x90, 0x81, 0xFB, 0xF0, 0xA3, 0x74, 0x69, 0xF0, 0xA3, 0x74, +0x80, 0xF0, 0x80, 0x2C, 0x90, 0x81, 0xF7, 0xE0, 0x54, 0x01, 0x90, 0x81, 0xFB, 0xF0, 0xA3, 0x74, +0xA5, 0xF0, 0xA3, 0x74, 0x01, 0xF0, 0x80, 0x18, 0x90, 0x81, 0xF7, 0xE0, 0xC4, 0x54, 0x10, 0x90, +0x81, 0xFB, 0xF0, 0xA3, 0x74, 0x7F, 0xF0, 0xA3, 0x74, 0x10, 0xF0, 0x80, 0x03, 0x7F, 0x00, 0x22, +0x90, 0x81, 0xFC, 0xE0, 0x90, 0x01, 0x06, 0xF0, 0x90, 0x81, 0xFB, 0xE0, 0x60, 0x0E, 0x90, 0x01, +0x42, 0xF0, 0x90, 0x81, 0xFA, 0xE0, 0x90, 0x01, 0x43, 0xF0, 0x80, 0x0D, 0x90, 0x01, 0x43, 0xE4, +0xF0, 0x90, 0x81, 0xFB, 0xE0, 0x90, 0x01, 0x42, 0xF0, 0x90, 0x81, 0xFD, 0xE0, 0xFF, 0x90, 0x01, +0x42, 0xE0, 0x5F, 0xFF, 0x90, 0x81, 0xFB, 0xE0, 0x6F, 0x60, 0xEE, 0x74, 0xD1, 0x04, 0x90, 0x01, +0xC4, 0xF0, 0x74, 0x6F, 0xA3, 0xF0, 0x90, 0x01, 0x43, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0x90, 0x02, +0x09, 0xE0, 0xFD, 0x12, 0x1F, 0xA4, 0xFE, 0xAF, 0x05, 0xED, 0x2E, 0x90, 0x80, 0x3D, 0xF0, 0x90, +0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x3E, 0xF0, 0x90, 0x00, 0x02, 0x12, +0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x3F, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0xFF, +0xED, 0x2F, 0x90, 0x80, 0x40, 0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0xAE, 0x05, 0xED, +0x2F, 0x90, 0x80, 0x41, 0xF0, 0x22, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0x30, 0xE0, 0x26, +0x12, 0x1F, 0xA4, 0x90, 0x81, 0x38, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x39, +0xF0, 0xEF, 0x54, 0xFE, 0xFF, 0xA3, 0xE0, 0x54, 0x01, 0x4F, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, +0xBD, 0x90, 0x81, 0x3B, 0xF0, 0x22, 0x90, 0x81, 0x38, 0x74, 0x01, 0xF0, 0xA3, 0x74, 0x05, 0xF0, +0xA3, 0xE0, 0x54, 0x01, 0x44, 0x28, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0x22, 0x8F, 0x0D, 0x22, 0x8F, +0x0E, 0x22, 0x22, 0x90, 0x01, 0x30, 0xE4, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, +0x38, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, 0x50, 0x12, 0x32, 0x1E, 0xE4, 0xFD, +0x7F, 0x51, 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x52, 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x53, +0x02, 0x32, 0x1E, 0x90, 0x01, 0x34, 0x74, 0xFF, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, +0x01, 0x3C, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, 0x54, 0x12, 0x32, 0x1E, 0x7D, +0xFF, 0x7F, 0x55, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x56, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, +0x57, 0x02, 0x32, 0x1E, 0x90, 0x01, 0x01, 0xE0, 0x44, 0x04, 0xF0, 0x90, 0x01, 0x9C, 0x74, 0x7E, +0xF0, 0xA3, 0x74, 0x92, 0xF0, 0xA3, 0x74, 0xA0, 0xF0, 0xA3, 0x74, 0x24, 0xF0, 0x90, 0x01, 0x9B, +0x74, 0x49, 0xF0, 0x90, 0x01, 0x9A, 0x74, 0xE0, 0xF0, 0x90, 0x01, 0x99, 0xE4, 0xF0, 0x90, 0x01, +0x98, 0x04, 0xF0, 0x22, 0xE4, 0x90, 0x81, 0x56, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x98, 0xE0, 0x7F, +0x00, 0x30, 0xE4, 0x02, 0x7F, 0x01, 0xEF, 0x64, 0x01, 0x60, 0x3E, 0xC3, 0x90, 0x81, 0x57, 0xE0, +0x94, 0x88, 0x90, 0x81, 0x56, 0xE0, 0x94, 0x13, 0x40, 0x08, 0x90, 0x01, 0xC1, 0xE0, 0x44, 0x10, +0xF0, 0x22, 0x90, 0x81, 0x56, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x4A, 0xA9, 0x7F, 0x14, 0x7E, 0x00, +0x12, 0x32, 0xAA, 0xD3, 0x90, 0x81, 0x57, 0xE0, 0x94, 0x32, 0x90, 0x81, 0x56, 0xE0, 0x94, 0x00, +0x40, 0xB9, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE3, 0xB2, 0x22, 0x7F, 0x02, 0x90, 0x81, 0x46, 0xE0, +0xFE, 0xEF, 0xC3, 0x9E, 0x50, 0x18, 0xEF, 0x25, 0xE0, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE4, 0x0B, +0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0xA3, 0xF0, 0x7F, 0x00, 0x22, 0x0F, 0x80, 0xDE, 0x7F, 0x01, +0x22, 0x90, 0x01, 0x34, 0xE0, 0x55, 0x3D, 0xF5, 0x41, 0xA3, 0xE0, 0x55, 0x3E, 0xF5, 0x42, 0xA3, +0xE0, 0x55, 0x3F, 0xF5, 0x43, 0xA3, 0xE0, 0x55, 0x40, 0xF5, 0x44, 0x90, 0x01, 0x34, 0xE5, 0x41, +0xF0, 0xA3, 0xE5, 0x42, 0xF0, 0xA3, 0xE5, 0x43, 0xF0, 0xA3, 0xE5, 0x44, 0xF0, 0x22, 0x90, 0x01, +0x3C, 0xE0, 0x55, 0x45, 0xF5, 0x49, 0xA3, 0xE0, 0x55, 0x46, 0xF5, 0x4A, 0xA3, 0xE0, 0x55, 0x47, +0xF5, 0x4B, 0xA3, 0xE0, 0x55, 0x48, 0xF5, 0x4C, 0x90, 0x01, 0x3C, 0xE5, 0x49, 0xF0, 0xA3, 0xE5, +0x4A, 0xF0, 0xA3, 0xE5, 0x4B, 0xF0, 0xA3, 0xE5, 0x4C, 0xF0, 0x53, 0x91, 0xDF, 0x22, 0x90, 0x81, +0x50, 0xE0, 0x60, 0x0F, 0xE4, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x02, 0xF0, 0x90, 0x05, 0xFC, +0xE0, 0x04, 0xF0, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x10, 0xA3, 0x74, 0x01, 0xF0, 0x90, 0x81, +0x1F, 0xE0, 0xFF, 0xC3, 0x13, 0x30, 0xE0, 0x02, 0x51, 0xCF, 0x71, 0xF9, 0x02, 0x5F, 0x72, 0xD3, +0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x1E, 0xE0, 0xB4, 0x01, 0x04, 0x7F, 0x04, 0x80, +0x0C, 0x12, 0x4F, 0xE3, 0xBF, 0x01, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x02, 0x12, 0x55, 0xA3, +0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x3D, 0x90, 0x81, 0x23, +0xE0, 0x7E, 0x00, 0xB4, 0x02, 0x02, 0x7E, 0x01, 0x90, 0x81, 0x22, 0xE0, 0x7D, 0x00, 0xB4, 0x04, +0x02, 0x7D, 0x01, 0xED, 0x4E, 0x70, 0x23, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x02, 0x80, 0xB0, 0x71, +0x82, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x08, 0x06, 0xE4, 0xFD, 0x7F, 0x0C, 0x80, 0x09, 0x90, 0x81, +0x23, 0xE0, 0x70, 0x06, 0xFD, 0x7F, 0x04, 0x12, 0x4D, 0x41, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0xFF, +0x30, 0xE0, 0x3E, 0x90, 0x81, 0x23, 0xE0, 0x7E, 0x00, 0xB4, 0x02, 0x02, 0x7E, 0x01, 0x90, 0x81, +0x22, 0xE0, 0x7D, 0x00, 0xB4, 0x04, 0x02, 0x7D, 0x01, 0xED, 0x4E, 0x70, 0x24, 0xEF, 0xC3, 0x13, +0x30, 0xE0, 0x02, 0x41, 0xCF, 0x71, 0xAA, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x0C, 0x06, 0xE4, 0xFD, +0x7F, 0x08, 0x80, 0x0A, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x04, 0x06, 0xE4, 0xFD, 0xFF, 0x12, 0x4D, +0x41, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x30, 0xE0, 0x0F, 0x90, +0x81, 0x23, 0xE0, 0x64, 0x02, 0x60, 0x07, 0x7D, 0x01, 0x7F, 0x02, 0x12, 0x4D, 0x41, 0x90, 0x81, +0x23, 0xE0, 0x64, 0x02, 0x60, 0x03, 0x12, 0x4F, 0xC8, 0x22, 0x90, 0x01, 0x57, 0xE0, 0x60, 0x48, +0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13, 0x13, 0x54, +0x3F, 0x30, 0xE0, 0x0C, 0xEF, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, 0xF0, 0x22, +0x90, 0x81, 0x30, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x38, +0xE0, 0xFF, 0x90, 0x81, 0x30, 0xE0, 0xD3, 0x9F, 0x40, 0x0E, 0x90, 0x80, 0xDE, 0xE0, 0xB4, 0x01, +0x07, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFB, 0xF0, 0x22, 0xE4, 0x90, 0x81, 0x51, 0xF0, 0x90, 0x81, +0x27, 0xE0, 0x70, 0x02, 0x81, 0xA8, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x60, 0x02, 0x81, 0xA8, +0x90, 0x81, 0x26, 0xE0, 0xFF, 0xC4, 0x54, 0x0F, 0x60, 0x22, 0x24, 0xFE, 0x60, 0x03, 0x04, 0x70, +0x21, 0x90, 0x81, 0x2E, 0xE0, 0x14, 0xF0, 0xE0, 0xFF, 0x60, 0x06, 0x90, 0x81, 0x30, 0xE0, 0x60, +0x11, 0xEF, 0x70, 0x08, 0x90, 0x81, 0x2D, 0xE0, 0xA3, 0xF0, 0x80, 0x00, 0x90, 0x81, 0x51, 0x74, +0x01, 0xF0, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x16, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x02, 0x05, +0xE4, 0x90, 0x81, 0x51, 0xF0, 0x12, 0x4F, 0xE3, 0xEF, 0x70, 0x04, 0x90, 0x81, 0x51, 0xF0, 0x90, +0x81, 0x51, 0xE0, 0x60, 0x43, 0x90, 0x81, 0x2B, 0xE0, 0x44, 0x10, 0xF0, 0x90, 0x81, 0x30, 0xE0, +0x60, 0x03, 0xB4, 0x01, 0x09, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x30, 0xE0, 0x80, 0x0D, 0xE4, 0xF5, +0x1D, 0x90, 0x81, 0x30, 0xE0, 0x75, 0xF0, 0x03, 0xA4, 0x24, 0xFE, 0xFF, 0x90, 0x81, 0x2F, 0xE0, +0x2F, 0x12, 0x6D, 0x9B, 0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x20, 0xE2, +0x07, 0x7D, 0x01, 0x7F, 0x04, 0x12, 0x4D, 0x41, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x70, +0x26, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x20, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, +0x02, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, 0xF0, +0x54, 0x07, 0x70, 0x03, 0x12, 0x4D, 0x29, 0x22, 0x90, 0x81, 0x27, 0xE0, 0x70, 0x07, 0x90, 0x81, +0x1F, 0xE0, 0x30, 0xE0, 0x12, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x09, 0x12, 0x4F, 0xE3, 0xBF, +0x01, 0x05, 0x02, 0x4F, 0xC8, 0x91, 0xF8, 0x22, 0x90, 0x81, 0x27, 0xE0, 0x64, 0x01, 0x70, 0x4E, +0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x60, 0x39, 0x12, 0x4D, 0x3D, 0x90, 0x01, 0x5B, 0xE4, 0xF0, +0x90, 0x01, 0x3C, 0x74, 0x04, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, 0xE0, 0xC3, 0x13, 0x54, +0x7F, 0xF5, 0x1E, 0xE4, 0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x12, 0x6D, 0xA4, 0x90, 0x01, 0x5B, +0x74, 0x05, 0xF0, 0x90, 0x06, 0x92, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x08, 0xF0, +0x22, 0x90, 0x81, 0x2A, 0xE0, 0x70, 0x07, 0x7D, 0x01, 0x7F, 0x04, 0x12, 0x4D, 0x41, 0x22, 0x12, +0x4F, 0xFC, 0xEF, 0x70, 0x02, 0x91, 0xF8, 0x22, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x35, 0x90, 0x06, +0x92, 0xE0, 0x30, 0xE0, 0x24, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, 0xE0, 0xC3, 0x13, 0x54, 0x7F, +0xF5, 0x1E, 0xE4, 0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x12, 0x6D, 0xA4, 0x90, 0x01, 0x5B, 0x74, +0x05, 0xF0, 0x90, 0x06, 0x92, 0x74, 0x01, 0xF0, 0x22, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xF7, 0xF0, +0x12, 0x4D, 0x29, 0x22, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x35, 0x90, 0x06, 0x92, 0xE0, 0x30, 0xE1, +0x24, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, 0xFB, +0xFD, 0x7F, 0x5C, 0x7E, 0x01, 0x12, 0x6D, 0xA4, 0x90, 0x01, 0x5F, 0x74, 0x05, 0xF0, 0x90, 0x06, +0x92, 0x74, 0x02, 0xF0, 0x22, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xEF, 0xF0, 0x12, 0x4D, 0x29, 0x22, +0xD1, 0x28, 0x90, 0x81, 0x52, 0xEF, 0xF0, 0x90, 0x81, 0x24, 0x30, 0xE0, 0x06, 0xE0, 0x44, 0x01, +0xF0, 0x80, 0x04, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x81, 0x52, 0xE0, 0x30, 0xE6, 0x11, 0x90, 0x01, +0x2F, 0xE0, 0x30, 0xE7, 0x04, 0xE4, 0xF0, 0x80, 0x06, 0x90, 0x01, 0x2F, 0x74, 0x80, 0xF0, 0x90, +0x81, 0x24, 0xE0, 0x30, 0xE0, 0x1A, 0x90, 0x81, 0x32, 0xE4, 0xF0, 0xA3, 0x74, 0x07, 0xF0, 0x90, +0x81, 0x32, 0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x04, 0xEC, 0xE0, 0x54, 0xDD, 0xF0, 0x22, +0x90, 0x04, 0xEC, 0xE0, 0x44, 0x22, 0xF0, 0x22, 0xE4, 0x90, 0x81, 0x53, 0xF0, 0xA3, 0xF0, 0xA3, +0xF0, 0x90, 0x00, 0x83, 0xE0, 0x90, 0x81, 0x53, 0xF0, 0x90, 0x00, 0x83, 0xE0, 0xFE, 0x90, 0x81, +0x53, 0xE0, 0xFF, 0xB5, 0x06, 0x01, 0x22, 0xC3, 0x90, 0x81, 0x55, 0xE0, 0x94, 0x64, 0x90, 0x81, +0x54, 0xE0, 0x94, 0x00, 0x40, 0x0D, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x53, +0xE0, 0xFF, 0x22, 0x90, 0x81, 0x54, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x4A, 0xA9, 0x80, 0xC2, 0x90, +0x81, 0x4F, 0xE0, 0x60, 0x0F, 0xE4, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x05, +0xFD, 0xE0, 0x04, 0xF0, 0x22, 0x22, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x54, 0x03, +0x30, 0xE0, 0x27, 0xEF, 0x54, 0xBF, 0xF0, 0x90, 0x04, 0xE0, 0xE0, 0x90, 0x81, 0x25, 0x30, 0xE0, +0x06, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x10, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x01, 0xB9, 0x74, 0x01, +0xF0, 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x12, 0x4D, 0x29, 0xE4, 0xFF, 0x90, 0x81, 0x4A, 0xE0, +0x30, 0xE0, 0x48, 0x90, 0x81, 0x4E, 0xE0, 0xFD, 0x60, 0x41, 0x74, 0x01, 0x7E, 0x00, 0xA8, 0x07, +0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0x90, 0x04, 0xE0, 0xE0, 0xFB, +0xEF, 0x5B, 0x60, 0x06, 0xE4, 0x90, 0x81, 0x4E, 0xF0, 0x22, 0x90, 0x81, 0x4C, 0xE0, 0xD3, 0x9D, +0x50, 0x10, 0x90, 0x01, 0xC7, 0x74, 0x10, 0xF0, 0xF1, 0x0C, 0x90, 0x81, 0x4A, 0xE0, 0x54, 0xFE, +0xF0, 0x22, 0x12, 0x56, 0xA6, 0x90, 0x81, 0x4E, 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x80, 0x3C, 0xE0, +0x64, 0x02, 0x60, 0x07, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, 0x81, 0x24, 0xE0, +0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x2C, 0xEF, 0x54, 0x7F, 0xF0, 0x90, 0x04, +0xE0, 0xE0, 0x90, 0x81, 0x25, 0x30, 0xE1, 0x06, 0xE0, 0x44, 0x02, 0xF0, 0x80, 0x0F, 0xE0, 0x54, +0xFD, 0xF0, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x04, 0xF0, 0x90, 0x81, 0x27, +0xE0, 0x60, 0x03, 0x12, 0x4D, 0x29, 0x7F, 0x01, 0xC1, 0xBC, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, +0xD0, 0x90, 0x04, 0x1D, 0xE0, 0x60, 0x1A, 0x90, 0x05, 0x22, 0xE0, 0x54, 0x90, 0x60, 0x07, 0x90, +0x01, 0xC0, 0xE0, 0x44, 0x08, 0xF0, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE1, 0xE4, 0x7F, 0x00, 0x80, +0x02, 0x7F, 0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xC3, 0xEE, 0x94, 0x01, 0x40, 0x0A, 0x0D, 0xED, +0x13, 0x90, 0xFD, 0x10, 0xF0, 0xE4, 0x2F, 0xFF, 0x22, 0xC3, 0xEE, 0x94, 0x01, 0x40, 0x1E, 0x90, +0xFD, 0x11, 0xE0, 0xB5, 0x05, 0x14, 0x90, 0x01, 0x17, 0xE0, 0xB5, 0x05, 0x07, 0x90, 0xFD, 0x11, +0xE4, 0xF0, 0x80, 0x06, 0xED, 0x04, 0x90, 0xFD, 0x11, 0xF0, 0xE4, 0x2F, 0xFF, 0x22, 0xEF, 0x14, +0x90, 0x05, 0x73, 0xF0, 0x90, 0x01, 0x3F, 0x74, 0x10, 0xF0, 0xFD, 0x7F, 0x03, 0x74, 0x45, 0x2F, +0xF8, 0xE6, 0x4D, 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, +0xF0, 0x22, 0x74, 0x45, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE, 0xF6, 0x74, 0x38, 0x2F, +0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, +0xD0, 0x90, 0x82, 0x1B, 0xED, 0xF0, 0x90, 0x82, 0x1A, 0xEF, 0xF0, 0xD3, 0x94, 0x07, 0x50, 0x70, +0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, +0x00, 0x47, 0xE0, 0x5F, 0xFD, 0x7F, 0x47, 0x12, 0x32, 0x1E, 0x90, 0x82, 0x1A, 0xE0, 0xFF, 0x74, +0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x46, 0xE0, 0x4F, +0xFD, 0x7F, 0x46, 0x12, 0x32, 0x1E, 0x90, 0x82, 0x1B, 0xE0, 0x60, 0x18, 0x90, 0x82, 0x1A, 0xE0, +0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x45, +0xE0, 0x4F, 0x80, 0x17, 0x90, 0x82, 0x1A, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, +0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x5F, 0xFD, 0x7F, 0x45, 0x80, 0x7E, +0x90, 0x82, 0x1A, 0xE0, 0x24, 0xF8, 0xF0, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, +0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x43, 0xE0, 0x5F, 0xFD, 0x7F, 0x43, +0x12, 0x32, 0x1E, 0x90, 0x82, 0x1A, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, +0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x43, 0xE0, 0x4F, 0xFD, 0x7F, 0x43, 0x12, 0x32, 0x1E, 0x90, +0x82, 0x1B, 0xE0, 0x60, 0x1D, 0x90, 0x82, 0x1A, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, 0xA8, 0x07, +0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x42, 0xE0, 0x4F, 0xFD, 0x7F, 0x42, +0x80, 0x1C, 0x90, 0x82, 0x1A, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, +0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x42, 0xE0, 0x5F, 0xFD, 0x7F, 0x42, 0x12, 0x32, +0x1E, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xE4, 0x90, 0x81, 0x27, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0x26, +0xE0, 0x54, 0x0F, 0xF0, 0x54, 0xF0, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0xF7, +0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x2D, 0x74, 0x01, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0x24, 0xE0, +0x54, 0xFB, 0xF0, 0xA3, 0xE0, 0x54, 0xFB, 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, 0x81, 0x2F, +0x74, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xE4, 0xF0, 0xA3, 0x74, 0x02, 0xF0, 0xE4, 0x90, 0x81, 0x2B, +0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x81, 0x29, 0x74, 0x0C, 0xF0, 0x90, 0x81, +0x24, 0xE0, 0x54, 0xDF, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, +0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x54, 0xF7, 0xF0, +0x90, 0x81, 0x34, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x90, 0x80, 0x3C, 0xE0, 0xB4, 0x01, +0x08, 0x90, 0x81, 0x31, 0x74, 0x99, 0xF0, 0x80, 0x12, 0x90, 0x80, 0x3C, 0xE0, 0x90, 0x81, 0x31, +0xB4, 0x03, 0x05, 0x74, 0x90, 0xF0, 0x80, 0x03, 0x74, 0x40, 0xF0, 0x90, 0x81, 0x38, 0x74, 0x01, +0xF0, 0xA3, 0x74, 0x05, 0xF0, 0xA3, 0xE0, 0x54, 0x01, 0x44, 0x28, 0xF0, 0xA3, 0x74, 0x05, 0xF0, +0xE4, 0xA3, 0xF0, 0xA3, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, +0xF0, 0x54, 0xDF, 0xF0, 0x54, 0xBF, 0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0xEF, 0x24, 0xFE, 0x60, 0x0C, +0x04, 0x70, 0x28, 0x90, 0x81, 0x2D, 0x74, 0x01, 0xF0, 0xA3, 0xF0, 0x22, 0xED, 0x70, 0x0A, 0x90, +0x81, 0x3B, 0xE0, 0x90, 0x81, 0x2D, 0xF0, 0x80, 0x05, 0x90, 0x81, 0x2D, 0xED, 0xF0, 0x90, 0x81, +0x2D, 0xE0, 0xA3, 0xF0, 0x90, 0x81, 0x25, 0xE0, 0x44, 0x08, 0xF0, 0x22, 0x12, 0x4F, 0xFC, 0xEF, +0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x01, 0xF0, 0x80, 0x67, 0x90, 0x81, 0x2B, 0xE0, +0xFF, 0x54, 0x03, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x02, 0xF0, 0x80, 0x56, 0x90, 0x81, 0x29, +0xE0, 0xFE, 0xE4, 0xC3, 0x9E, 0x50, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x44, 0xEF, +0x30, 0xE2, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x80, 0x38, 0x90, 0x81, 0x2B, 0xE0, 0x30, +0xE4, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x10, 0xF0, 0x80, 0x29, 0x90, 0x81, 0x25, 0xE0, 0x13, 0x13, +0x54, 0x3F, 0x20, 0xE0, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x20, 0xF0, 0x80, 0x16, 0x90, 0x81, 0x3E, +0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x80, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, +0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x04, 0xF0, 0x7F, 0x00, 0x22, 0x90, 0x02, 0x87, 0xE0, +0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x01, 0xF0, 0x80, 0x17, 0x90, 0x02, 0x86, 0xE0, 0x20, 0xE1, +0x08, 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, 0x7F, 0x01, +0x22, 0x90, 0x01, 0xB9, 0x74, 0x08, 0xF0, 0x7F, 0x00, 0x22, 0xEF, 0x60, 0x42, 0x90, 0x80, 0xDE, +0xE0, 0x64, 0x01, 0x70, 0x3A, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x05, 0x22, 0x74, +0x0F, 0xF0, 0x90, 0x06, 0x04, 0xE0, 0x54, 0xBF, 0xF0, 0xE4, 0xFF, 0x12, 0x56, 0xA8, 0xBF, 0x01, +0x12, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x06, 0xF0, 0x90, 0x81, +0x23, 0xF0, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x22, +0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x02, 0xF0, 0x90, 0x05, 0x27, 0xE0, +0x54, 0xBF, 0xF0, 0x90, 0x81, 0x23, 0x74, 0x02, 0xF0, 0x22, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, +0x81, 0x2A, 0x74, 0x04, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x23, 0x74, +0x04, 0xF0, 0x22, 0xE4, 0x90, 0x81, 0x52, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x59, 0x90, 0x80, +0xDE, 0xE0, 0x64, 0x01, 0x70, 0x51, 0x90, 0x81, 0x52, 0x04, 0xF0, 0xE4, 0x90, 0x81, 0x2E, 0xF0, +0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x16, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x02, 0x05, 0xE4, 0x90, +0x81, 0x52, 0xF0, 0x12, 0x4F, 0xE3, 0xEF, 0x70, 0x04, 0x90, 0x81, 0x52, 0xF0, 0x90, 0x81, 0x52, +0xE0, 0x60, 0x24, 0x90, 0x81, 0x2B, 0xE0, 0x44, 0x10, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x2F, +0x12, 0x6D, 0x9A, 0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x20, 0xE2, 0x07, +0x7D, 0x01, 0x7F, 0x04, 0x12, 0x4D, 0x41, 0x22, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13, 0x13, 0x54, +0x3F, 0x30, 0xE0, 0x11, 0xEF, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, 0xF0, 0x54, +0x07, 0x70, 0x42, 0x80, 0x3D, 0x90, 0x81, 0x30, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, +0xEF, 0xF0, 0x90, 0x81, 0x30, 0xE0, 0xFF, 0xB4, 0x01, 0x02, 0x80, 0x04, 0xEF, 0xB4, 0x02, 0x06, +0x90, 0x05, 0x58, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x38, 0xE0, 0xFF, 0x90, 0x81, 0x30, 0xE0, 0xD3, +0x9F, 0x40, 0x0F, 0x90, 0x80, 0xDE, 0xE0, 0xB4, 0x01, 0x0B, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFB, +0xF0, 0x22, 0x12, 0x4D, 0x29, 0x22, 0x22, 0x90, 0x05, 0x2B, 0xE0, 0x7F, 0x00, 0x30, 0xE7, 0x02, +0x7F, 0x01, 0x22, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x90, +0x81, 0x22, 0x74, 0x01, 0xF0, 0x22, 0x91, 0x03, 0x02, 0x57, 0xE5, 0x90, 0x05, 0x22, 0x74, 0xFF, +0xF0, 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, 0x22, 0x90, +0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, 0x22, 0x04, 0xF0, 0x22, 0x91, 0x2F, 0x02, 0x57, 0xE5, 0x90, +0x05, 0x22, 0x74, 0x6F, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x81, 0x22, 0x74, +0x04, 0xF0, 0x22, 0x90, 0x81, 0x22, 0xE0, 0x64, 0x02, 0x7F, 0x01, 0x60, 0x02, 0x7F, 0x00, 0x22, +0x90, 0x80, 0x3F, 0xE0, 0xFF, 0x7D, 0x01, 0x12, 0x57, 0x31, 0x8E, 0x54, 0x8F, 0x55, 0xAD, 0x55, +0xAC, 0x54, 0xAF, 0x53, 0x12, 0x56, 0xE6, 0xAF, 0x55, 0xAE, 0x54, 0x90, 0x04, 0x80, 0xE0, 0x54, +0x0F, 0xFD, 0xAC, 0x07, 0x74, 0x11, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, +0x01, 0xF0, 0x74, 0x11, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xFB, 0xF0, +0xAC, 0x07, 0x74, 0x16, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0xFA, 0xF0, +0x74, 0x15, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x1F, 0xF0, 0xAC, 0x07, +0x74, 0x06, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x0F, 0xF0, 0x90, 0x04, +0x53, 0xE4, 0xF0, 0x90, 0x04, 0x52, 0xF0, 0x90, 0x04, 0x51, 0x74, 0xFF, 0xF0, 0x90, 0x04, 0x50, +0x74, 0xFD, 0xF0, 0x74, 0x14, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xC0, +0x4D, 0xFD, 0x74, 0x14, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xED, 0xF0, 0x22, 0x90, +0x80, 0x3F, 0xE0, 0xFE, 0x90, 0x04, 0x1C, 0xE0, 0x6E, 0x70, 0x40, 0x90, 0x81, 0x2A, 0xE0, 0xFE, +0x64, 0x0E, 0x70, 0x1C, 0xEF, 0x70, 0x34, 0x90, 0x81, 0x24, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x06, +0x04, 0xE0, 0x54, 0xBF, 0xF0, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0, 0x22, +0xEE, 0xB4, 0x06, 0x17, 0xEF, 0x60, 0x14, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x06, +0x04, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x22, 0xE4, 0xFE, 0xEF, 0xC3, +0x13, 0xFD, 0xEF, 0x30, 0xE0, 0x02, 0x7E, 0x80, 0x90, 0xFD, 0x10, 0xED, 0xF0, 0xAF, 0x06, 0x22, +0xAB, 0x07, 0xAA, 0x06, 0xED, 0x2B, 0xFB, 0xE4, 0x3A, 0xFA, 0xC3, 0x90, 0x80, 0xDB, 0xE0, 0x9B, +0x90, 0x80, 0xDA, 0xE0, 0x9A, 0x50, 0x13, 0xA3, 0xE0, 0x24, 0x01, 0xFF, 0x90, 0x80, 0xDA, 0xE0, +0x34, 0x00, 0xFE, 0xC3, 0xEB, 0x9F, 0xFB, 0xEA, 0x9E, 0xFA, 0xEA, 0x90, 0xFD, 0x11, 0xF0, 0xAF, +0x03, 0x74, 0x00, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x22, 0x12, 0x1F, +0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x47, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEF, 0xC3, 0x13, +0x30, 0xE0, 0x0A, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x48, 0xF0, 0x22, 0x90, 0x81, +0x4A, 0xE0, 0x30, 0xE0, 0x2D, 0x90, 0x81, 0x4D, 0xE0, 0x04, 0xF0, 0xE0, 0xFF, 0x90, 0x81, 0x4B, +0xE0, 0xB5, 0x07, 0x1E, 0x90, 0x06, 0x92, 0xE0, 0x54, 0x1C, 0x70, 0x0B, 0x12, 0x56, 0xA6, 0x90, +0x81, 0x4E, 0xE0, 0x04, 0xF0, 0x80, 0x06, 0x90, 0x06, 0x92, 0x74, 0x1C, 0xF0, 0xE4, 0x90, 0x81, +0x4D, 0xF0, 0x22, 0x00, 0x74, 0x53, +}; +u4Byte ArrayLength_MP_8188E_FW_NIC_S = 15894; + + +void +ODM_ReadFirmware_MP_8188E_FW_NIC_S( + IN PDM_ODM_T pDM_Odm, + OUT u1Byte *pFirmware, + OUT u4Byte *pFirmwareSize +) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_CE)) + *((SIZE_PTR *)pFirmware) = (SIZE_PTR)Array_MP_8188E_FW_NIC_S; +#else + ODM_MoveMemory(pDM_Odm, pFirmware, Array_MP_8188E_FW_NIC_S, ArrayLength_MP_8188E_FW_NIC_S); +#endif + *pFirmwareSize = ArrayLength_MP_8188E_FW_NIC_S; +} + + +u1Byte Array_MP_8188E_FW_NIC_T[] = { +0xE1, 0x88, 0x10, 0x00, 0x0B, 0x00, 0x01, 0x00, 0x01, 0x21, 0x11, 0x27, 0x30, 0x36, 0x00, 0x00, +0x2D, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x02, 0x45, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xC1, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xA1, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x56, 0xF7, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xC2, 0xAF, 0x80, 0xFE, 0x32, 0x12, 0x42, 0x04, 0x85, 0xD0, 0x0B, 0x75, 0xD0, 0x08, 0xAA, 0xE0, +0xC2, 0x8C, 0xE5, 0x8A, 0x24, 0x67, 0xF5, 0x8A, 0xE5, 0x8C, 0x34, 0x79, 0xF5, 0x8C, 0xD2, 0x8C, +0xEC, 0x24, 0x89, 0xF8, 0xE6, 0xBC, 0x03, 0x02, 0x74, 0xFF, 0xC3, 0x95, 0x81, 0xB4, 0x40, 0x00, +0x40, 0xCE, 0x79, 0x04, 0x78, 0x80, 0x16, 0xE6, 0x08, 0x70, 0x0B, 0xC2, 0xAF, 0xE6, 0x30, 0xE1, +0x03, 0x44, 0x18, 0xF6, 0xD2, 0xAF, 0x08, 0xD9, 0xED, 0xEA, 0x8B, 0xD0, 0x22, 0xE5, 0x0C, 0xFF, +0x23, 0x24, 0x81, 0xF8, 0x0F, 0x08, 0x08, 0xBF, 0x04, 0x04, 0x7F, 0x00, 0x78, 0x81, 0xE6, 0x30, +0xE4, 0xF2, 0x00, 0xE5, 0x0C, 0xC3, 0x9F, 0x50, 0x20, 0x05, 0x0C, 0x74, 0x88, 0x25, 0x0C, 0xF8, +0xE6, 0xFD, 0xA6, 0x81, 0x08, 0xE6, 0xAE, 0x0C, 0xBE, 0x03, 0x02, 0x74, 0xFF, 0xCD, 0xF8, 0xE8, +0x6D, 0x60, 0xE0, 0x08, 0xE6, 0xC0, 0xE0, 0x80, 0xF6, 0xE5, 0x0C, 0xD3, 0x9F, 0x40, 0x27, 0xE5, +0x0C, 0x24, 0x89, 0xF8, 0xE6, 0xAE, 0x0C, 0xBE, 0x03, 0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xCD, +0xF8, 0xE5, 0x81, 0x6D, 0x60, 0x06, 0xD0, 0xE0, 0xF6, 0x18, 0x80, 0xF5, 0xE5, 0x0C, 0x24, 0x88, +0xC8, 0xF6, 0x15, 0x0C, 0x80, 0xD3, 0xE5, 0x0C, 0x23, 0x24, 0x81, 0xF8, 0x7F, 0x04, 0xC2, 0xAF, +0xE6, 0x30, 0xE0, 0x03, 0x10, 0xE2, 0x0C, 0x7F, 0x00, 0x30, 0xE1, 0x07, 0x30, 0xE3, 0x04, 0x7F, +0x08, 0x54, 0xF4, 0x54, 0x7C, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x42, 0x07, 0x22, 0x78, 0x88, 0xA6, +0x81, 0x74, 0x03, 0x60, 0x06, 0xFF, 0x08, 0x76, 0xFF, 0xDF, 0xFB, 0x7F, 0x04, 0xE4, 0x78, 0x80, +0xF6, 0x08, 0xF6, 0x08, 0xDF, 0xFA, 0x78, 0x81, 0x76, 0x30, 0x90, 0x45, 0xDE, 0x74, 0x01, 0x93, +0xC0, 0xE0, 0xE4, 0x93, 0xC0, 0xE0, 0x43, 0x89, 0x01, 0x75, 0x8A, 0x60, 0x75, 0x8C, 0x79, 0xD2, +0x8C, 0xD2, 0xAF, 0x22, 0x03, 0xEF, 0xD3, 0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0x74, 0x81, +0x2F, 0x2F, 0xF8, 0xE6, 0x20, 0xE5, 0xF4, 0xC2, 0xAF, 0xE6, 0x44, 0x30, 0xF6, 0xD2, 0xAF, 0xAE, +0x0C, 0xEE, 0xC3, 0x9F, 0x50, 0x21, 0x0E, 0x74, 0x88, 0x2E, 0xF8, 0xE6, 0xF9, 0x08, 0xE6, 0x18, +0xBE, 0x03, 0x02, 0x74, 0xFF, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x09, 0xE7, 0x19, 0x19, 0xF7, 0x09, +0x09, 0x80, 0xF3, 0x16, 0x16, 0x80, 0xDA, 0xEE, 0xD3, 0x9F, 0x40, 0x04, 0x05, 0x81, 0x05, 0x81, +0xEE, 0xD3, 0x9F, 0x40, 0x22, 0x74, 0x88, 0x2E, 0xF8, 0x08, 0xE6, 0xF9, 0xEE, 0xB5, 0x0C, 0x02, +0xA9, 0x81, 0x18, 0x06, 0x06, 0xE6, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x19, 0x19, 0xE7, 0x09, 0x09, +0xF7, 0x19, 0x80, 0xF3, 0x1E, 0x80, 0xD9, 0xEF, 0x24, 0x88, 0xF8, 0xE6, 0x04, 0xF8, 0xEF, 0x2F, +0x04, 0x90, 0x45, 0xDE, 0x93, 0xF6, 0x08, 0xEF, 0x2F, 0x93, 0xF6, 0x7F, 0x00, 0x22, 0xEF, 0xD3, +0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0xEF, 0x23, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE5, 0xF4, +0xC2, 0xAF, 0xE6, 0x54, 0x8C, 0xF6, 0xD2, 0xAF, 0xE5, 0x0C, 0xB5, 0x07, 0x0A, 0x74, 0x88, 0x2F, +0xF8, 0xE6, 0xF5, 0x81, 0x02, 0x42, 0x4D, 0x50, 0x2E, 0x74, 0x89, 0x2F, 0xF8, 0xE6, 0xBF, 0x03, +0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xF9, 0x74, 0x88, 0x2F, 0xF8, 0xFB, 0xE6, 0xFC, 0xE9, 0x6C, +0x60, 0x08, 0xA8, 0x05, 0xE7, 0xF6, 0x1D, 0x19, 0x80, 0xF4, 0xA8, 0x03, 0xA6, 0x05, 0x1F, 0xE5, +0x0C, 0xB5, 0x07, 0xE3, 0x7F, 0x00, 0x22, 0x74, 0x89, 0x2F, 0xF8, 0xE6, 0xFD, 0x18, 0x86, 0x01, +0x0F, 0x74, 0x88, 0x2F, 0xF8, 0xA6, 0x01, 0x08, 0x86, 0x04, 0xE5, 0x0C, 0xB5, 0x07, 0x02, 0xAC, +0x81, 0xED, 0x6C, 0x60, 0x08, 0x0D, 0x09, 0xA8, 0x05, 0xE6, 0xF7, 0x80, 0xF4, 0xE5, 0x0C, 0xB5, +0x07, 0xDE, 0x89, 0x81, 0x7F, 0x00, 0x22, 0xEF, 0xD3, 0x94, 0x03, 0x40, 0x03, 0x7F, 0xFF, 0x22, +0xEF, 0x23, 0x24, 0x81, 0xF8, 0xC2, 0xAF, 0xE6, 0x30, 0xE5, 0x05, 0x30, 0xE0, 0x02, 0xD2, 0xE4, +0xD2, 0xE2, 0xC6, 0xD2, 0xAF, 0x7F, 0x00, 0x30, 0xE2, 0x01, 0x0F, 0x02, 0x42, 0x4C, 0x8F, 0xF0, +0xE4, 0xFF, 0xFE, 0xE5, 0x0C, 0x23, 0x24, 0x80, 0xF8, 0xC2, 0xA9, 0x30, 0xF7, 0x0D, 0x7F, 0x08, +0xE6, 0x60, 0x0B, 0x2D, 0xF6, 0x60, 0x30, 0x50, 0x2E, 0x80, 0x07, 0x30, 0xF1, 0x06, 0xED, 0xF6, +0x60, 0x25, 0x7E, 0x02, 0x08, 0x30, 0xF0, 0x10, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x23, 0x0E, 0x30, +0xE2, 0x0C, 0xD2, 0xAF, 0x7F, 0x04, 0x80, 0x12, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x13, 0x54, 0xEC, +0x4E, 0xF6, 0xD2, 0xAF, 0x02, 0x42, 0x4D, 0x7F, 0x08, 0x08, 0xEF, 0x44, 0x83, 0xF4, 0xC2, 0xAF, +0x56, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x4F, 0xFF, 0x22, 0xC5, 0xF0, 0xF8, 0xA3, 0xE0, 0x28, 0xF0, +0xC5, 0xF0, 0xF8, 0xE5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83, 0xE0, 0x38, 0xF0, 0x22, 0xEF, +0x5B, 0xFF, 0xEE, 0x5A, 0xFE, 0xED, 0x59, 0xFD, 0xEC, 0x58, 0xFC, 0x22, 0xEF, 0x4B, 0xFF, 0xEE, +0x4A, 0xFE, 0xED, 0x49, 0xFD, 0xEC, 0x48, 0xFC, 0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0xA3, 0xE0, +0xFE, 0xA3, 0xE0, 0xFF, 0x22, 0xE2, 0xFC, 0x08, 0xE2, 0xFD, 0x08, 0xE2, 0xFE, 0x08, 0xE2, 0xFF, +0x22, 0xE2, 0xFB, 0x08, 0xE2, 0xF9, 0x08, 0xE2, 0xFA, 0x08, 0xE2, 0xCB, 0xF8, 0x22, 0xEC, 0xF2, +0x08, 0xED, 0xF2, 0x08, 0xEE, 0xF2, 0x08, 0xEF, 0xF2, 0x22, 0xA4, 0x25, 0x82, 0xF5, 0x82, 0xE5, +0xF0, 0x35, 0x83, 0xF5, 0x83, 0x22, 0xE0, 0xFB, 0xA3, 0xE0, 0xFA, 0xA3, 0xE0, 0xF9, 0x22, 0xEB, +0xF0, 0xA3, 0xEA, 0xF0, 0xA3, 0xE9, 0xF0, 0x22, 0xD0, 0x83, 0xD0, 0x82, 0xF8, 0xE4, 0x93, 0x70, +0x12, 0x74, 0x01, 0x93, 0x70, 0x0D, 0xA3, 0xA3, 0x93, 0xF8, 0x74, 0x01, 0x93, 0xF5, 0x82, 0x88, +0x83, 0xE4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xEF, 0xA3, 0xA3, 0xA3, 0x80, 0xDF, 0x02, 0x45, +0x8C, 0x02, 0x42, 0xDD, 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0x40, 0x03, 0xF6, 0x80, 0x01, +0xF2, 0x08, 0xDF, 0xF4, 0x80, 0x29, 0xE4, 0x93, 0xA3, 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, +0x33, 0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83, 0x40, 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, +0xDF, 0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x45, 0xD1, 0xE4, +0x7E, 0x01, 0x93, 0x60, 0xBC, 0xA3, 0xFF, 0x54, 0x3F, 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, +0x93, 0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0, 0x25, 0xE0, 0x60, 0xA8, 0x40, 0xB8, 0xE4, 0x93, +0xA3, 0xFA, 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83, +0xCA, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83, 0xCA, 0xDF, 0xE9, 0xDE, 0xE7, 0x80, +0xBE, 0x00, 0x41, 0x82, 0x09, 0x00, 0x41, 0x82, 0x0A, 0x00, 0x41, 0x82, 0x17, 0x00, 0x59, 0xE2, +0x5C, 0x24, 0x5E, 0x5D, 0x5F, 0xA1, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, +0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, +0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xE6, 0xF0, 0x74, 0x45, 0xA3, 0xF0, 0xD1, 0x35, 0x74, +0xE6, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x45, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, +0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, +0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x00, 0x54, 0xE0, 0x55, 0x35, 0xF5, 0x39, 0xA3, 0xE0, 0x55, +0x36, 0xF5, 0x3A, 0xA3, 0xE0, 0x55, 0x37, 0xF5, 0x3B, 0xA3, 0xE0, 0x55, 0x38, 0xF5, 0x3C, 0xAD, +0x39, 0x7F, 0x54, 0x12, 0x32, 0x1E, 0xAD, 0x3A, 0x7F, 0x55, 0x12, 0x32, 0x1E, 0xAD, 0x3B, 0x7F, +0x56, 0x12, 0x32, 0x1E, 0xAD, 0x3C, 0x7F, 0x57, 0x12, 0x32, 0x1E, 0x53, 0x91, 0xEF, 0x22, 0xC0, +0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, +0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, +0x6F, 0xF0, 0x74, 0x46, 0xA3, 0xF0, 0x12, 0x6C, 0x78, 0xE5, 0x41, 0x30, 0xE4, 0x04, 0x7F, 0x02, +0x91, 0x27, 0xE5, 0x41, 0x30, 0xE6, 0x03, 0x12, 0x6C, 0xD5, 0xE5, 0x43, 0x30, 0xE0, 0x03, 0x12, +0x51, 0xC2, 0xE5, 0x43, 0x30, 0xE1, 0x03, 0x12, 0x4D, 0x0C, 0xE5, 0x43, 0x30, 0xE2, 0x03, 0x12, +0x4C, 0xC1, 0xE5, 0x43, 0x30, 0xE3, 0x03, 0x12, 0x6C, 0xE2, 0xE5, 0x43, 0x30, 0xE4, 0x03, 0x12, +0x6D, 0x04, 0xE5, 0x43, 0x30, 0xE5, 0x03, 0x12, 0x6D, 0x33, 0xE5, 0x43, 0x30, 0xE6, 0x02, 0xF1, +0x0F, 0xE5, 0x44, 0x30, 0xE1, 0x03, 0x12, 0x51, 0x7F, 0x74, 0x6F, 0x04, 0x90, 0x01, 0xC4, 0xF0, +0x74, 0x46, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, +0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, +0x80, 0xDE, 0xE0, 0xB4, 0x01, 0x13, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x0D, 0x90, 0x81, 0x2B, 0xE0, +0x54, 0xFE, 0xF0, 0x54, 0x07, 0x70, 0x02, 0xF1, 0x2A, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0x90, 0x81, +0x29, 0x30, 0xE0, 0x05, 0xE0, 0xFF, 0x02, 0x74, 0x8F, 0xE0, 0xFF, 0x7D, 0x01, 0xD3, 0x10, 0xAF, +0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, 0x13, 0xED, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x90, 0x82, 0x14, +0xF0, 0x90, 0x81, 0x24, 0xE0, 0xFE, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x30, 0xE0, 0x03, 0x02, 0x48, +0xA0, 0xEE, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x03, 0x02, 0x48, 0xA0, 0x90, 0x82, +0x14, 0xE0, 0xFE, 0x6F, 0x70, 0x03, 0x02, 0x48, 0xA0, 0xEF, 0x70, 0x03, 0x02, 0x48, 0x17, 0x24, +0xFE, 0x70, 0x03, 0x02, 0x48, 0x50, 0x24, 0xFE, 0x60, 0x51, 0x24, 0xFC, 0x70, 0x03, 0x02, 0x48, +0x8B, 0x24, 0xFC, 0x60, 0x03, 0x02, 0x48, 0xA0, 0xEE, 0xB4, 0x0E, 0x03, 0x12, 0x49, 0x5E, 0x90, +0x82, 0x14, 0xE0, 0x70, 0x05, 0x7F, 0x01, 0x12, 0x49, 0x93, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x06, +0x03, 0x12, 0x49, 0x34, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x04, 0x0F, 0x90, 0x82, 0x13, 0xE0, 0xFF, +0x60, 0x05, 0x12, 0x73, 0x75, 0x80, 0x03, 0x12, 0x66, 0x26, 0x90, 0x82, 0x14, 0xE0, 0x64, 0x08, +0x60, 0x03, 0x02, 0x48, 0xA0, 0x12, 0x73, 0xD3, 0x02, 0x48, 0xA0, 0x90, 0x82, 0x14, 0xE0, 0x70, +0x05, 0x7F, 0x01, 0x12, 0x49, 0x93, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x06, 0x03, 0x12, 0x49, 0x34, +0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x09, 0x12, 0x48, 0xA5, 0xBF, 0x01, 0x03, 0x12, 0x49, 0x5E, +0x90, 0x82, 0x14, 0xE0, 0x64, 0x0C, 0x60, 0x02, 0x01, 0xA0, 0x11, 0xA5, 0xEF, 0x64, 0x01, 0x60, +0x02, 0x01, 0xA0, 0x11, 0xFA, 0x01, 0xA0, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x07, 0x11, 0xA5, +0xBF, 0x01, 0x02, 0x31, 0x5E, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x06, 0x02, 0x31, 0x34, 0x90, 0x82, +0x14, 0xE0, 0xB4, 0x0C, 0x07, 0x11, 0xA5, 0xBF, 0x01, 0x02, 0x11, 0xFA, 0x90, 0x82, 0x14, 0xE0, +0x64, 0x04, 0x70, 0x5C, 0x12, 0x72, 0xF5, 0xEF, 0x64, 0x01, 0x70, 0x54, 0x31, 0xBE, 0x80, 0x50, +0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0E, 0x07, 0x11, 0xA5, 0xBF, 0x01, 0x02, 0x31, 0x5E, 0x90, 0x82, +0x14, 0xE0, 0xB4, 0x06, 0x02, 0x31, 0x34, 0x90, 0x82, 0x14, 0xE0, 0xB4, 0x0C, 0x07, 0x11, 0xA5, +0xBF, 0x01, 0x02, 0x11, 0xFA, 0x90, 0x82, 0x14, 0xE0, 0x70, 0x04, 0x7F, 0x01, 0x31, 0x93, 0x90, +0x82, 0x14, 0xE0, 0xB4, 0x04, 0x1A, 0x12, 0x73, 0xBB, 0x80, 0x15, 0x90, 0x82, 0x14, 0xE0, 0xB4, +0x0C, 0x0E, 0x90, 0x81, 0x25, 0xE0, 0xFF, 0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x02, 0x31, 0xB1, +0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD1, 0xAB, 0xEF, 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, +0x01, 0xF0, 0x80, 0x3D, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, +0x08, 0x90, 0x01, 0xB8, 0x74, 0x02, 0xF0, 0x80, 0x28, 0xEF, 0xC4, 0x54, 0x0F, 0x30, 0xE0, 0x08, +0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x19, 0x90, 0x81, 0x29, 0xE0, 0xD3, 0x94, 0x04, 0x40, +0x08, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, 0x7F, 0x01, +0x22, 0x90, 0x01, 0xB9, 0x74, 0x02, 0xF0, 0x7F, 0x00, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, +0x70, 0x31, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x7F, +0x01, 0xF1, 0x0D, 0xBF, 0x01, 0x12, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x2A, +0x74, 0x0E, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, +0xB8, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x25, 0xE0, 0x90, 0x06, 0x04, 0x20, 0xE0, 0x0C, 0xE0, 0x44, +0x40, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0, 0x80, 0x0E, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x81, +0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x90, 0x81, +0x25, 0xE0, 0xC3, 0x13, 0x20, 0xE0, 0x08, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x80, 0x1E, 0x90, +0x06, 0x04, 0xE0, 0x44, 0x40, 0xF0, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0, +0x90, 0x05, 0x27, 0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x23, 0x74, 0x04, 0xF0, 0x90, 0x05, 0x22, +0xE4, 0xF0, 0x22, 0x90, 0x82, 0x15, 0xEF, 0xF0, 0x12, 0x54, 0x65, 0x90, 0x82, 0x15, 0xE0, 0x60, +0x05, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x04, 0xF0, 0x90, 0x81, 0x23, 0xF0, +0x22, 0x31, 0xE3, 0x90, 0x81, 0x2A, 0x74, 0x08, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x05, +0x22, 0x74, 0xFF, 0xF0, 0xF1, 0x3A, 0x90, 0x01, 0x37, 0x74, 0x02, 0xF0, 0xFD, 0x7F, 0x03, 0x51, +0x57, 0x31, 0xE3, 0xE4, 0x90, 0x81, 0x2A, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x05, 0x22, +0x74, 0xFF, 0xF0, 0xF1, 0x3A, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0xCC, 0xF0, 0x00, 0xC0, 0x7F, +0x8C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x14, +0x7F, 0x70, 0x7E, 0x0E, 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xF9, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, +0x00, 0xE4, 0xFD, 0xFF, 0x12, 0x55, 0x1C, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x44, +0x80, 0xFC, 0x90, 0x82, 0x05, 0x12, 0x20, 0xCE, 0x90, 0x82, 0x05, 0x12, 0x44, 0xD9, 0x90, 0x85, +0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x01, 0x00, 0x74, 0x3F, +0xF0, 0xA3, 0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x20, 0xF0, 0x22, 0x90, 0x01, +0x34, 0x74, 0x40, 0xF0, 0xFD, 0xE4, 0xFF, 0x74, 0x3D, 0x2F, 0xF8, 0xE6, 0x4D, 0xFE, 0xF6, 0x74, +0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, +0xC3, 0xC0, 0xD0, 0xE4, 0x90, 0x81, 0xCB, 0xF0, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, +0x81, 0x1F, 0xE0, 0x54, 0xFE, 0x4E, 0xFE, 0xF0, 0xEF, 0x54, 0x02, 0xFF, 0xEE, 0x54, 0xFD, 0x4F, +0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x04, 0xFD, 0xEF, 0x54, 0xFB, 0x4D, 0xFF, 0x90, 0x81, +0x1F, 0xF0, 0xEE, 0x54, 0x08, 0xFE, 0xEF, 0x54, 0xF7, 0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, +0x54, 0x10, 0xFD, 0xEF, 0x54, 0xEF, 0x4D, 0xFF, 0x90, 0x81, 0x1F, 0xF0, 0xEE, 0x54, 0x20, 0xFE, +0xEF, 0x54, 0xDF, 0x4E, 0xF0, 0x12, 0x1F, 0xA4, 0xC3, 0x13, 0x20, 0xE0, 0x02, 0x61, 0x5E, 0x90, +0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x6D, 0x90, 0x81, 0xCB, 0x74, 0x21, 0xF0, 0xEF, 0x13, 0x13, +0x54, 0x3F, 0x30, 0xE0, 0x0B, 0x51, 0x4E, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x08, 0xF0, 0x80, 0x0C, +0xE4, 0x90, 0x81, 0x20, 0xF0, 0xA3, 0xF0, 0x7D, 0x40, 0xFF, 0x91, 0x26, 0x90, 0x81, 0x1F, 0xE0, +0xFD, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x12, 0xF0, +0xED, 0xC4, 0x54, 0x0F, 0x30, 0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x14, 0xF0, 0x90, 0x81, +0x1F, 0xE0, 0xC4, 0x13, 0x54, 0x07, 0x30, 0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x80, 0xF0, +0x90, 0x81, 0xCB, 0xE0, 0x90, 0x05, 0x27, 0xF0, 0x90, 0x81, 0x22, 0xE0, 0x60, 0x02, 0x81, 0x17, +0x7F, 0x01, 0x80, 0x15, 0x90, 0x81, 0xCB, 0x74, 0x01, 0xF0, 0x90, 0x05, 0x27, 0xF0, 0x90, 0x81, +0x22, 0xE0, 0x64, 0x04, 0x60, 0x02, 0x81, 0x17, 0xFF, 0x12, 0x53, 0x0E, 0x81, 0x17, 0x90, 0x81, +0x1F, 0xE0, 0xFF, 0x20, 0xE0, 0x02, 0x61, 0xE7, 0x90, 0x81, 0xCB, 0x74, 0x31, 0xF0, 0xEF, 0x13, +0x13, 0x54, 0x3F, 0x30, 0xE0, 0x0B, 0x51, 0x4E, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x08, 0xF0, 0x80, +0x06, 0x7D, 0x40, 0xE4, 0xFF, 0x91, 0x26, 0x90, 0x81, 0x1F, 0xE0, 0xFD, 0x13, 0x13, 0x13, 0x54, +0x1F, 0x30, 0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x02, 0xF0, 0xED, 0xC4, 0x54, 0x0F, 0x30, +0xE0, 0x07, 0x90, 0x81, 0xCB, 0xE0, 0x44, 0x04, 0xF0, 0x90, 0x81, 0xCB, 0xE0, 0x90, 0x05, 0x27, +0xF0, 0x90, 0x81, 0x23, 0xE0, 0x64, 0x02, 0x70, 0x1D, 0xFD, 0x7F, 0x04, 0x12, 0x47, 0x3D, 0x12, +0x51, 0x73, 0xBF, 0x01, 0x09, 0x90, 0x81, 0x29, 0xE0, 0xFF, 0x7D, 0x01, 0x80, 0x03, 0xE4, 0xFD, +0xFF, 0x12, 0x47, 0x3D, 0x80, 0x41, 0x90, 0x81, 0x2A, 0xE0, 0x90, 0x81, 0x23, 0xF0, 0x90, 0x05, +0x27, 0xE0, 0x44, 0x40, 0xF0, 0x80, 0x30, 0x90, 0x81, 0xCB, 0x74, 0x01, 0xF0, 0x90, 0x05, 0x27, +0xF0, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x02, 0x06, 0x7D, 0x01, 0x7F, 0x04, 0x80, 0x0B, 0x90, 0x81, +0x23, 0xE0, 0xB4, 0x08, 0x07, 0x7D, 0x01, 0x7F, 0x0C, 0x12, 0x47, 0x3D, 0xD1, 0x34, 0x90, 0x81, +0x29, 0x12, 0x47, 0x39, 0x12, 0x5A, 0xA7, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x7D, 0x02, 0x7F, 0x02, +0x91, 0x26, 0x7D, 0x01, 0x7F, 0x02, 0x74, 0x3D, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE, +0xF6, 0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xEF, 0x70, +0x37, 0x7D, 0x78, 0x7F, 0x02, 0x91, 0x26, 0x7D, 0x02, 0x7F, 0x03, 0x91, 0x26, 0x7D, 0xC8, 0x7F, +0x02, 0x12, 0x71, 0x8F, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x7D, +0x01, 0x7F, 0x0C, 0x12, 0x47, 0x3D, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, +0x90, 0x06, 0x0A, 0xE0, 0x54, 0xF8, 0xF0, 0x22, 0x90, 0x01, 0x36, 0x74, 0x78, 0xF0, 0xA3, 0x74, +0x02, 0xF0, 0x7D, 0x78, 0xFF, 0x51, 0x57, 0x7D, 0x02, 0x7F, 0x03, 0x51, 0x57, 0x90, 0x06, 0x0A, +0xE0, 0x44, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x80, 0xDE, +0xE0, 0xB4, 0x01, 0x15, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x20, +0xE2, 0x0E, 0x7D, 0x01, 0x7F, 0x04, 0x02, 0x47, 0x3D, 0x90, 0x81, 0x25, 0xE0, 0x44, 0x04, 0xF0, +0x22, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x08, 0x90, 0x81, 0x23, 0xE0, 0x64, 0x02, 0x60, +0x3A, 0x90, 0x81, 0x27, 0xE0, 0x70, 0x04, 0xEF, 0x30, 0xE0, 0x0A, 0x90, 0x81, 0x2A, 0xE0, 0x64, +0x02, 0x60, 0x28, 0xB1, 0x83, 0x90, 0x81, 0x25, 0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, +0x14, 0x90, 0x81, 0x2D, 0xE0, 0xFF, 0xA3, 0xE0, 0x6F, 0x70, 0x0A, 0xF1, 0xCD, 0x91, 0x1C, 0x90, +0x81, 0x2E, 0xE0, 0x14, 0xF0, 0x90, 0x01, 0xE6, 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x1F, 0xE0, +0x30, 0xE0, 0x06, 0x90, 0x81, 0x21, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x45, 0x90, +0x81, 0x25, 0xE0, 0xFF, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x12, 0x90, 0x01, 0x3B, 0xE0, +0x30, 0xE4, 0x0B, 0x91, 0x1C, 0x90, 0x81, 0x2D, 0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0, 0x90, 0x82, +0x0B, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9, 0xC3, 0x90, 0x82, 0x0C, 0xE0, 0x94, 0x80, 0x90, +0x82, 0x0B, 0xE0, 0x64, 0x80, 0x94, 0x80, 0x40, 0x0B, 0x90, 0x01, 0x98, 0xE0, 0x54, 0xFE, 0xF0, +0xE0, 0x44, 0x01, 0xF0, 0x12, 0x75, 0xF8, 0xD1, 0xD6, 0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0, 0x0C, +0xE4, 0xF5, 0x1D, 0xA3, 0xF1, 0xFB, 0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x01, 0xBE, 0xE0, +0x04, 0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x60, 0x02, 0xC1, 0x23, 0x90, 0x81, 0x27, +0xE0, 0x70, 0x02, 0xC1, 0x23, 0x90, 0x81, 0x26, 0xE0, 0xC4, 0x54, 0x0F, 0x64, 0x01, 0x70, 0x22, +0x90, 0x06, 0xAB, 0xE0, 0x90, 0x81, 0x2E, 0xF0, 0x90, 0x06, 0xAA, 0xE0, 0x90, 0x81, 0x2D, 0xF0, +0xA3, 0xE0, 0xFF, 0x70, 0x08, 0x90, 0x81, 0x2D, 0xE0, 0xFE, 0xFF, 0x80, 0x00, 0x90, 0x81, 0x2E, +0xEF, 0xF0, 0x90, 0x81, 0x25, 0xE0, 0x44, 0x04, 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, 0x81, +0x32, 0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, +0x02, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x26, 0xE0, +0xFF, 0xC4, 0x54, 0x0F, 0x24, 0xFD, 0x50, 0x02, 0x80, 0x0F, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, +0x05, 0x12, 0x6D, 0xF2, 0x80, 0x03, 0x12, 0x6E, 0xC9, 0x90, 0x81, 0x25, 0xE0, 0x13, 0x13, 0x13, +0x54, 0x1F, 0x30, 0xE0, 0x0E, 0x90, 0x81, 0x2D, 0xE0, 0xFF, 0xA3, 0xE0, 0xB5, 0x07, 0x04, 0xF1, +0xCD, 0x91, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0xC3, 0x13, 0x20, 0xE0, 0x07, 0x90, 0x81, 0x25, 0xE0, +0x44, 0x04, 0xF0, 0x22, 0xD1, 0xAB, 0xEF, 0x70, 0x02, 0xD1, 0x3C, 0x22, 0x90, 0x81, 0x27, 0xE0, +0x64, 0x01, 0x70, 0x66, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x60, 0x51, 0x90, 0x81, 0x2A, 0xE0, +0x70, 0x03, 0xFF, 0x31, 0x93, 0x90, 0x81, 0x2A, 0xE0, 0x64, 0x0C, 0x60, 0x03, 0x12, 0x66, 0x26, +0x90, 0x01, 0x5B, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x04, 0xF0, 0xD1, 0xAB, 0xEF, 0x64, 0x01, +0x60, 0x38, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, +0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x12, 0x50, 0x05, 0x90, 0x01, 0x5B, 0x74, 0x05, 0xF0, 0x90, +0x06, 0x92, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x08, 0xF0, 0x22, 0x90, 0x81, 0x2A, +0xE0, 0x70, 0x07, 0x7D, 0x01, 0x7F, 0x04, 0x12, 0x47, 0x3D, 0x22, 0x90, 0x04, 0x1A, 0xE0, 0xF4, +0x60, 0x03, 0x7F, 0x00, 0x22, 0x90, 0x04, 0x1B, 0xE0, 0x54, 0x07, 0x64, 0x07, 0x7F, 0x01, 0x60, +0x02, 0x7F, 0x00, 0x22, 0x12, 0x50, 0x60, 0x90, 0x81, 0x2D, 0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0, +0x7D, 0x02, 0x7F, 0x02, 0x51, 0x57, 0x90, 0x81, 0x42, 0xE0, 0x30, 0xE0, 0x2D, 0x90, 0x80, 0xDE, +0xE0, 0xB4, 0x01, 0x26, 0x90, 0x82, 0x17, 0xE0, 0x04, 0xF0, 0xE0, 0xB4, 0x0A, 0x0B, 0x90, 0x81, +0x44, 0xE0, 0x04, 0xF0, 0xE4, 0x90, 0x82, 0x17, 0xF0, 0x90, 0x81, 0x44, 0xE0, 0xFF, 0x90, 0x81, +0x43, 0xE0, 0xB5, 0x07, 0x05, 0xE4, 0xA3, 0xF0, 0xF1, 0x0B, 0x22, 0xE4, 0xFF, 0x8F, 0x53, 0x90, +0x04, 0x1D, 0xE0, 0x60, 0x19, 0x90, 0x05, 0x22, 0xE0, 0xF5, 0x56, 0x74, 0xFF, 0xF0, 0xF1, 0x3A, +0xBF, 0x01, 0x03, 0x12, 0x74, 0xFB, 0x90, 0x05, 0x22, 0xE5, 0x56, 0xF0, 0x80, 0x03, 0x12, 0x74, +0xFB, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x7F, 0x01, 0x22, 0xE4, 0x90, 0x82, 0x0F, 0xF0, 0xA3, +0xF0, 0x90, 0x05, 0xF8, 0xE0, 0x70, 0x0F, 0xA3, 0xE0, 0x70, 0x0B, 0xA3, 0xE0, 0x70, 0x07, 0xA3, +0xE0, 0x70, 0x03, 0x7F, 0x01, 0x22, 0xD3, 0x90, 0x82, 0x10, 0xE0, 0x94, 0xE8, 0x90, 0x82, 0x0F, +0xE0, 0x94, 0x03, 0x40, 0x0A, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x20, 0xF0, 0x7F, 0x00, 0x22, 0x7F, +0x32, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x90, 0x82, 0x0F, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9, +0x80, 0xBF, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0x3F, 0xF0, +0xEF, 0x60, 0x1D, 0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x10, +0xF0, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0x22, +0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xEF, 0xF0, 0x74, 0x1F, +0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x40, 0xF0, 0x22, 0xEF, 0x14, 0x90, +0x05, 0x73, 0xF0, 0x90, 0x01, 0x3F, 0x74, 0x10, 0xF0, 0xFD, 0x7F, 0x03, 0x74, 0x45, 0x2F, 0xF8, +0xE6, 0x4D, 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, +0x22, 0xE0, 0x44, 0x02, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x39, 0xE0, 0xF5, 0x1E, 0xE4, 0xFB, +0xFD, 0x7F, 0x54, 0x7E, 0x01, 0x8E, 0x19, 0x8F, 0x1A, 0xE5, 0x1E, 0x54, 0x07, 0xC4, 0x33, 0x54, +0xE0, 0x85, 0x19, 0x83, 0x85, 0x1A, 0x82, 0xF0, 0xE5, 0x1D, 0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0, +0xFF, 0xE5, 0x1E, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x4F, 0xA3, 0xF0, 0xEB, 0x54, 0x07, 0xC4, 0x33, +0x54, 0xE0, 0xFF, 0xE5, 0x1D, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x4F, 0x85, 0x1A, 0x82, 0x85, 0x19, +0x83, 0xA3, 0xA3, 0xF0, 0xBD, 0x01, 0x0C, 0x85, 0x1A, 0x82, 0x8E, 0x83, 0xA3, 0xA3, 0xA3, 0x74, +0x03, 0xF0, 0x22, 0x85, 0x1A, 0x82, 0x85, 0x19, 0x83, 0xA3, 0xA3, 0xA3, 0x74, 0x01, 0xF0, 0x22, +0xE4, 0x90, 0x81, 0x4D, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x58, 0x90, 0x80, 0xDE, 0xE0, 0x64, +0x01, 0x70, 0x50, 0x90, 0x81, 0x4D, 0x04, 0xF0, 0xE4, 0x90, 0x81, 0x2E, 0xF0, 0x90, 0x81, 0x1F, +0xE0, 0x30, 0xE0, 0x15, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x02, 0x05, 0xE4, 0x90, 0x81, 0x4D, 0xF0, +0x31, 0x73, 0xEF, 0x70, 0x04, 0x90, 0x81, 0x4D, 0xF0, 0x90, 0x81, 0x4D, 0xE0, 0x60, 0x24, 0x90, +0x81, 0x2B, 0xE0, 0x44, 0x10, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x2F, 0x12, 0x4F, 0xFB, 0x90, +0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x20, 0xE2, 0x07, 0x7D, 0x01, 0x7F, 0x04, +0x12, 0x47, 0x3D, 0x22, 0xE4, 0x90, 0x81, 0x4C, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x70, 0x02, 0x21, +0x72, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x60, 0x02, 0x21, 0x72, 0x90, 0x81, 0x26, 0xE0, 0xFF, +0xC4, 0x54, 0x0F, 0x60, 0x22, 0x24, 0xFE, 0x60, 0x03, 0x04, 0x70, 0x21, 0x90, 0x81, 0x2E, 0xE0, +0x14, 0xF0, 0xE0, 0xFF, 0x60, 0x06, 0x90, 0x81, 0x30, 0xE0, 0x60, 0x11, 0xEF, 0x70, 0x08, 0x90, +0x81, 0x2D, 0xE0, 0xA3, 0xF0, 0x80, 0x00, 0x90, 0x81, 0x4C, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x1F, +0xE0, 0x30, 0xE0, 0x15, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x02, 0x05, 0xE4, 0x90, 0x81, 0x4C, 0xF0, +0x31, 0x73, 0xEF, 0x70, 0x04, 0x90, 0x81, 0x4C, 0xF0, 0x90, 0x81, 0x4C, 0xE0, 0x60, 0x43, 0x90, +0x81, 0x2B, 0xE0, 0x44, 0x10, 0xF0, 0x90, 0x81, 0x30, 0xE0, 0x60, 0x03, 0xB4, 0x01, 0x09, 0xE4, +0xF5, 0x1D, 0x90, 0x81, 0x30, 0xE0, 0x80, 0x0D, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x30, 0xE0, 0x75, +0xF0, 0x03, 0xA4, 0x24, 0xFE, 0xFF, 0x90, 0x81, 0x2F, 0xE0, 0x2F, 0x12, 0x4F, 0xFC, 0x90, 0x01, +0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x20, 0xE2, 0x07, 0x7D, 0x01, 0x7F, 0x04, 0x12, +0x47, 0x3D, 0x22, 0x90, 0x05, 0x43, 0xE0, 0x7F, 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0x22, 0x90, +0x81, 0x27, 0xE0, 0x70, 0x07, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x11, 0x90, 0x81, 0x1F, 0xE0, +0x30, 0xE0, 0x07, 0x31, 0x73, 0xBF, 0x01, 0x05, 0x41, 0x5B, 0x12, 0x4E, 0x3C, 0x22, 0xD3, 0x10, +0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x1E, 0xE0, 0xB4, 0x01, 0x04, 0x7F, 0x04, 0x80, 0x0B, +0x31, 0x73, 0xBF, 0x01, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x02, 0x71, 0x0E, 0xD0, 0xD0, 0x92, +0xAF, 0x22, 0x90, 0x81, 0x4B, 0xE0, 0x60, 0x0F, 0xE4, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x02, +0xF0, 0x90, 0x05, 0xFC, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x10, 0xA3, 0x74, +0x01, 0xF0, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0xC3, 0x13, 0x30, 0xE0, 0x02, 0x31, 0x9E, 0x11, 0xC4, +0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0, 0x07, 0x91, 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x22, 0x90, +0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x3D, 0x90, 0x81, 0x23, 0xE0, 0x7E, 0x00, 0xB4, 0x02, 0x02, +0x7E, 0x01, 0x90, 0x81, 0x22, 0xE0, 0x7D, 0x00, 0xB4, 0x04, 0x02, 0x7D, 0x01, 0xED, 0x4E, 0x70, +0x23, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x02, 0x21, 0x9E, 0x51, 0x45, 0x90, 0x81, 0x23, 0xE0, 0xB4, +0x08, 0x06, 0xE4, 0xFD, 0x7F, 0x0C, 0x80, 0x09, 0x90, 0x81, 0x23, 0xE0, 0x70, 0x06, 0xFD, 0x7F, +0x04, 0x12, 0x47, 0x3D, 0x22, 0x90, 0x81, 0x1E, 0xE0, 0xB4, 0x01, 0x0F, 0x90, 0x81, 0x23, 0xE0, +0x64, 0x02, 0x60, 0x07, 0x7D, 0x01, 0x7F, 0x02, 0x12, 0x47, 0x3D, 0x90, 0x81, 0x27, 0xE0, 0x64, +0x02, 0x60, 0x14, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x60, 0x0C, 0x12, 0x4E, 0xAB, 0xEF, 0x70, +0x06, 0xFD, 0x7F, 0x0C, 0x12, 0x47, 0x3D, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0xFF, 0x30, 0xE0, 0x3F, +0x90, 0x81, 0x23, 0xE0, 0x7E, 0x00, 0xB4, 0x02, 0x02, 0x7E, 0x01, 0x90, 0x81, 0x22, 0xE0, 0x7D, +0x00, 0xB4, 0x04, 0x02, 0x7D, 0x01, 0xED, 0x4E, 0x70, 0x25, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x02, +0x21, 0x9E, 0x12, 0x74, 0xAC, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x0C, 0x06, 0xE4, 0xFD, 0x7F, 0x08, +0x80, 0x0A, 0x90, 0x81, 0x23, 0xE0, 0xB4, 0x04, 0x06, 0xE4, 0xFD, 0xFF, 0x12, 0x47, 0x3D, 0x22, +0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x1F, 0x12, 0x1F, 0xA4, +0xFF, 0x90, 0x81, 0x1E, 0xF0, 0xBF, 0x01, 0x12, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, 0x90, 0x00, +0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01, 0x60, 0x21, 0x80, 0x1D, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, +0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01, 0x60, 0x0F, 0x90, 0x81, 0x1F, 0xE0, 0x20, 0xE0, +0x06, 0xE4, 0xFF, 0x71, 0x0E, 0x80, 0x02, 0x31, 0x9E, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, +0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x22, 0xE0, 0x90, 0x82, 0x16, 0xF0, 0x6F, 0x70, 0x02, +0x81, 0x04, 0xEF, 0x14, 0x60, 0x3E, 0x14, 0x60, 0x62, 0x14, 0x70, 0x02, 0x61, 0xB8, 0x14, 0x70, +0x02, 0x61, 0xDF, 0x24, 0x04, 0x60, 0x02, 0x81, 0x04, 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x04, +0x04, 0x91, 0x41, 0x81, 0x04, 0xEF, 0xB4, 0x02, 0x04, 0x91, 0x50, 0x81, 0x04, 0x90, 0x82, 0x16, +0xE0, 0xFF, 0xB4, 0x03, 0x04, 0x91, 0x54, 0x81, 0x04, 0xEF, 0x64, 0x01, 0x60, 0x02, 0x81, 0x04, +0x91, 0x43, 0x81, 0x04, 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x04, 0x04, 0x91, 0xF3, 0x81, 0x04, +0xEF, 0xB4, 0x02, 0x04, 0x91, 0x58, 0x81, 0x04, 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x03, 0x04, +0x91, 0xE8, 0x81, 0x04, 0xEF, 0x70, 0x7D, 0x91, 0x2B, 0x80, 0x79, 0x90, 0x82, 0x16, 0xE0, 0xB4, +0x04, 0x05, 0x12, 0x74, 0x60, 0x80, 0x6D, 0x90, 0x82, 0x16, 0xE0, 0xB4, 0x01, 0x04, 0x91, 0x21, +0x80, 0x62, 0x90, 0x82, 0x16, 0xE0, 0xB4, 0x03, 0x05, 0x12, 0x74, 0x71, 0x80, 0x56, 0x90, 0x82, +0x16, 0xE0, 0x70, 0x50, 0x91, 0x1F, 0x80, 0x4C, 0x90, 0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x04, 0x05, +0x12, 0x74, 0x4C, 0x80, 0x3F, 0xEF, 0xB4, 0x01, 0x04, 0x91, 0x34, 0x80, 0x37, 0xEF, 0xB4, 0x02, +0x04, 0x91, 0xDF, 0x80, 0x2F, 0x90, 0x82, 0x16, 0xE0, 0x70, 0x29, 0x91, 0x32, 0x80, 0x25, 0x90, +0x82, 0x16, 0xE0, 0xFF, 0xB4, 0x03, 0x05, 0x12, 0x74, 0x7B, 0x80, 0x18, 0xEF, 0xB4, 0x01, 0x04, +0x91, 0x0B, 0x80, 0x10, 0xEF, 0xB4, 0x02, 0x04, 0xB1, 0x06, 0x80, 0x08, 0x90, 0x82, 0x16, 0xE0, +0x70, 0x02, 0x91, 0x09, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x91, 0x2B, 0x90, 0x05, 0x22, 0x74, 0x6F, +0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0x91, +0x2B, 0x12, 0x49, 0xDD, 0x90, 0x81, 0x22, 0x74, 0x02, 0xF0, 0x22, 0x90, 0x81, 0x22, 0x74, 0x01, +0xF0, 0x22, 0x91, 0x2B, 0x90, 0x05, 0x22, 0x74, 0xFF, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, +0x22, 0x91, 0xF3, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0xE4, 0x90, 0x81, 0x22, 0xF0, 0x22, +0x91, 0x58, 0x80, 0xEF, 0x91, 0xE8, 0x80, 0xEB, 0x91, 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, +0x81, 0x22, 0x04, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x01, 0x01, 0xE0, +0x44, 0x02, 0xF0, 0x90, 0x01, 0x00, 0x74, 0xFF, 0xF0, 0x90, 0x06, 0xB7, 0x74, 0x09, 0xF0, 0x90, +0x06, 0xB4, 0x74, 0x86, 0xF0, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x54, 0x7F, 0xFC, +0x90, 0x82, 0x01, 0x12, 0x20, 0xCE, 0x90, 0x82, 0x01, 0x12, 0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12, +0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0xCC, +0xC0, 0x00, 0xC0, 0x7F, 0x8C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, +0x00, 0xC0, 0x00, 0x14, 0x7F, 0x70, 0x7E, 0x0E, 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xF9, 0x12, 0x20, +0xDA, 0x00, 0x03, 0x3E, 0x60, 0xE4, 0xFD, 0xFF, 0xB1, 0x1C, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x91, +0x65, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, 0x22, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, 0x22, +0x04, 0xF0, 0x22, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x90, +0x81, 0x22, 0x74, 0x01, 0xF0, 0x22, 0x91, 0x65, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x90, 0x05, +0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, +0xC3, 0xC0, 0xD0, 0xC0, 0x07, 0xC0, 0x05, 0x90, 0x81, 0xF9, 0x12, 0x44, 0xD9, 0x90, 0x81, 0xE5, +0x12, 0x20, 0xCE, 0xD0, 0x05, 0xD0, 0x07, 0x12, 0x60, 0xF5, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, +0x81, 0xC8, 0x12, 0x45, 0x1F, 0xEF, 0x12, 0x45, 0x28, 0x55, 0x71, 0x00, 0x55, 0x7A, 0x01, 0x55, +0x83, 0x02, 0x55, 0x8B, 0x03, 0x55, 0x94, 0x04, 0x55, 0x9C, 0x20, 0x55, 0xA4, 0x21, 0x55, 0xAD, +0x23, 0x55, 0xB5, 0x24, 0x55, 0xBE, 0x25, 0x55, 0xC7, 0x26, 0x55, 0xCF, 0xC0, 0x00, 0x00, 0x55, +0xD8, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x02, 0x6A, 0xB0, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, +0x02, 0x65, 0x81, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x41, 0xC0, 0x90, 0x81, 0xC8, 0x12, 0x45, +0x16, 0x02, 0x75, 0xD8, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x80, 0x44, 0x90, 0x81, 0xC8, 0x12, +0x45, 0x16, 0xC1, 0x4B, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x02, 0x6A, 0xF8, 0x90, 0x81, 0xC8, +0x12, 0x45, 0x16, 0xE1, 0xE1, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x02, 0x4A, 0x6C, 0x90, 0x81, +0xC8, 0x12, 0x45, 0x16, 0x02, 0x6B, 0x3E, 0x90, 0x81, 0xC8, 0x12, 0x45, 0x16, 0x80, 0x3E, 0x90, +0x81, 0xC8, 0x12, 0x45, 0x16, 0x02, 0x6B, 0x4E, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x01, 0xF0, 0x22, +0x12, 0x5A, 0x4B, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x45, 0xE0, 0x54, 0xFE, +0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x14, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81, +0x46, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x47, 0xF0, 0x22, 0x12, 0x1F, 0xA4, +0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0x90, 0x00, 0x01, 0x12, +0x1F, 0xBD, 0xFE, 0x90, 0x05, 0x54, 0xE0, 0xC3, 0x9E, 0x90, 0x81, 0x40, 0xF0, 0xEF, 0x20, 0xE0, +0x07, 0x91, 0x65, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0x01, 0x90, 0x01, +0xBC, 0xF0, 0x90, 0x81, 0x40, 0xE0, 0x90, 0x01, 0xBD, 0xF0, 0x22, 0x12, 0x1F, 0xA4, 0xFF, 0x54, +0x7F, 0x90, 0x81, 0x27, 0xF0, 0xEF, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0xA3, 0xF0, 0x90, 0x00, +0x01, 0x12, 0x1F, 0xBD, 0xFF, 0x54, 0xF0, 0xC4, 0x54, 0x0F, 0xFE, 0x90, 0x81, 0x26, 0xE0, 0x54, +0xF0, 0x4E, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0x54, 0x01, 0x25, 0xE0, 0xFE, 0x90, 0x81, +0x24, 0xE0, 0x54, 0xFD, 0x4E, 0xF0, 0xEF, 0x54, 0x0F, 0xC4, 0x54, 0xF0, 0xFF, 0x90, 0x81, 0x26, +0xE0, 0x54, 0x0F, 0x4F, 0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x29, 0xF0, 0xD1, +0xC6, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0xF0, 0x90, 0x81, 0x27, 0xE0, 0x90, +0x01, 0xBA, 0xF0, 0x90, 0x81, 0x29, 0xE0, 0x90, 0x01, 0xBB, 0xF0, 0x90, 0x81, 0x26, 0xE0, 0x54, +0x0F, 0x90, 0x01, 0xBE, 0xF0, 0x22, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x1F, 0x12, 0x72, 0xB3, 0x90, +0x81, 0x27, 0xE0, 0xFF, 0x12, 0x4C, 0x3E, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x19, 0x90, 0x81, 0xCB, +0x12, 0x45, 0x16, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x54, 0x0F, 0xFF, 0x90, 0x00, 0x02, 0x12, +0x1F, 0xBD, 0xFD, 0x12, 0x72, 0xC4, 0x22, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, +0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, +0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xF7, 0xF0, 0x74, 0x56, 0xA3, 0xF0, 0x12, 0x6C, +0xA5, 0xE5, 0x49, 0x30, 0xE1, 0x03, 0x12, 0x6F, 0x79, 0xE5, 0x49, 0x30, 0xE2, 0x02, 0xF1, 0xA5, +0xE5, 0x49, 0x30, 0xE3, 0x03, 0x12, 0x6F, 0x8D, 0xE5, 0x4A, 0x30, 0xE0, 0x03, 0x12, 0x6F, 0xC9, +0xE5, 0x4A, 0x30, 0xE4, 0x03, 0x12, 0x70, 0x22, 0xE5, 0x4B, 0x30, 0xE1, 0x02, 0x51, 0x78, 0xE5, +0x4B, 0x30, 0xE0, 0x02, 0x31, 0xFF, 0xE5, 0x4B, 0x30, 0xE3, 0x02, 0xF1, 0xE0, 0xE5, 0x4C, 0x30, +0xE1, 0x05, 0x7F, 0x03, 0x12, 0x44, 0x27, 0xE5, 0x4C, 0x30, 0xE4, 0x03, 0x12, 0x4E, 0xC4, 0xE5, +0x4C, 0x30, 0xE5, 0x03, 0x12, 0x70, 0x38, 0xE5, 0x4C, 0x30, 0xE6, 0x03, 0x12, 0x70, 0xCE, 0x74, +0xF7, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x56, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, +0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, +0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x34, 0x90, 0x06, 0x92, 0xE0, 0x30, +0xE0, 0x23, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, +0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0x11, 0x05, 0x90, 0x01, 0x5B, 0x74, 0x05, 0xF0, 0x90, 0x06, +0x92, 0x74, 0x01, 0xF0, 0x22, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xF7, 0xF0, 0x12, 0x47, 0x2A, 0x22, +0x22, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x31, 0xF0, 0x22, 0x90, 0x01, 0xC8, 0xE4, 0xF0, 0xA3, 0xF0, +0xA3, 0xF0, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x51, 0x7F, 0xFF, 0xFE, 0x12, 0x2B, 0x27, 0xBF, 0x01, +0x09, 0x90, 0x81, 0x51, 0xE0, 0x64, 0x03, 0x60, 0x03, 0x22, 0x01, 0xAB, 0xE4, 0x90, 0x81, 0x56, +0xF0, 0x90, 0x81, 0x56, 0xE0, 0xFF, 0xC3, 0x94, 0x02, 0x40, 0x02, 0x01, 0xE6, 0xC3, 0x74, 0xFE, +0x9F, 0xFF, 0xE4, 0x94, 0x00, 0xFE, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x52, 0x12, 0x2B, 0x27, 0xEF, +0x64, 0x01, 0x70, 0x77, 0x90, 0x81, 0x52, 0xE0, 0xFF, 0x54, 0xC0, 0xFE, 0x60, 0x05, 0xEF, 0x54, +0x0C, 0x70, 0x16, 0x90, 0x81, 0x52, 0xE0, 0xFF, 0x54, 0x30, 0x60, 0x67, 0xEF, 0x54, 0x03, 0x60, +0x62, 0x90, 0x81, 0x53, 0x74, 0x01, 0xF0, 0x80, 0x05, 0xE4, 0x90, 0x81, 0x53, 0xF0, 0x90, 0x81, +0x53, 0xE0, 0x90, 0x81, 0x52, 0x70, 0x16, 0xE0, 0xFF, 0xEE, 0x13, 0x13, 0x54, 0x3F, 0x90, 0x81, +0x54, 0xF0, 0xEF, 0x54, 0x0C, 0x13, 0x13, 0x54, 0x3F, 0xA3, 0xF0, 0x80, 0x0D, 0xE0, 0xFE, 0x54, +0x30, 0x90, 0x81, 0x54, 0xF0, 0xEE, 0x54, 0x03, 0xA3, 0xF0, 0x90, 0x81, 0x54, 0xE0, 0x64, 0x30, +0x70, 0x54, 0xA3, 0xE0, 0x64, 0x02, 0x70, 0x4E, 0x90, 0x00, 0xF5, 0xE0, 0x54, 0x40, 0x90, 0x81, +0x57, 0xF0, 0xE0, 0x70, 0x41, 0xA3, 0x74, 0x02, 0xF0, 0x80, 0x10, 0x90, 0x81, 0x58, 0x74, 0x01, +0xF0, 0x80, 0x08, 0x90, 0x81, 0x56, 0xE0, 0x04, 0xF0, 0x01, 0x11, 0x90, 0x01, 0xC4, 0x74, 0xE9, +0xF0, 0x74, 0x57, 0xA3, 0xF0, 0x90, 0x81, 0x58, 0xE0, 0x90, 0x01, 0xC8, 0xF0, 0x90, 0x81, 0x52, +0xE0, 0x90, 0x01, 0xC9, 0xF0, 0x90, 0x81, 0x53, 0xE0, 0x90, 0x01, 0xCA, 0xF0, 0xE4, 0xFD, 0x7F, +0x1F, 0x12, 0x32, 0x1E, 0x80, 0xD5, 0x22, 0x90, 0x00, 0xF7, 0xE0, 0x20, 0xE7, 0x09, 0xE0, 0x7F, +0x01, 0x20, 0xE6, 0x0C, 0x7F, 0x02, 0x22, 0x90, 0x00, 0xF7, 0xE0, 0x30, 0xE6, 0x02, 0x7F, 0x03, +0x22, 0x11, 0xE7, 0x90, 0x80, 0x3C, 0xEF, 0xF0, 0x31, 0x13, 0x90, 0x01, 0x64, 0x74, 0x01, 0xF0, +0x02, 0x2D, 0xA7, 0x31, 0x81, 0x31, 0xB1, 0x31, 0x40, 0x31, 0x5F, 0xE4, 0xF5, 0x35, 0xF5, 0x36, +0xF5, 0x37, 0xF5, 0x38, 0xAD, 0x35, 0x7F, 0x50, 0x12, 0x32, 0x1E, 0xAD, 0x36, 0x7F, 0x51, 0x12, +0x32, 0x1E, 0xAD, 0x37, 0x7F, 0x52, 0x12, 0x32, 0x1E, 0xAD, 0x38, 0x7F, 0x53, 0x02, 0x32, 0x1E, +0x75, 0x3D, 0x10, 0xE4, 0xF5, 0x3E, 0x75, 0x3F, 0x07, 0x75, 0x40, 0x02, 0x90, 0x01, 0x30, 0xE5, +0x3D, 0xF0, 0xA3, 0xE5, 0x3E, 0xF0, 0xA3, 0xE5, 0x3F, 0xF0, 0xA3, 0xE5, 0x40, 0xF0, 0x22, 0x75, +0x45, 0x0E, 0x75, 0x46, 0x01, 0x43, 0x46, 0x10, 0x75, 0x47, 0x03, 0x75, 0x48, 0x62, 0x90, 0x01, +0x38, 0xE5, 0x45, 0xF0, 0xA3, 0xE5, 0x46, 0xF0, 0xA3, 0xE5, 0x47, 0xF0, 0xA3, 0xE5, 0x48, 0xF0, +0x22, 0x90, 0x01, 0x30, 0xE4, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x38, 0xF0, +0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, 0x50, 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x51, +0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x52, 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x53, 0x02, 0x32, +0x1E, 0x90, 0x01, 0x34, 0x74, 0xFF, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x3C, +0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, 0x54, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, +0x55, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x56, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x57, 0x02, +0x32, 0x1E, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x80, 0xFD, 0x7F, 0x80, 0x12, 0x32, 0x1E, 0x90, 0xFD, +0x00, 0xE0, 0x54, 0xBF, 0xF0, 0x12, 0x57, 0xE9, 0x51, 0x77, 0x12, 0x32, 0x77, 0x51, 0xC9, 0x51, +0x5E, 0x7F, 0x01, 0x12, 0x43, 0x15, 0x90, 0x81, 0x41, 0x74, 0x02, 0xF0, 0xFF, 0x12, 0x43, 0x15, +0x90, 0x81, 0x41, 0xE0, 0x04, 0xF0, 0x7F, 0x03, 0x12, 0x43, 0x15, 0x90, 0x81, 0x41, 0xE0, 0x04, +0xF0, 0x31, 0x01, 0x51, 0x3F, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x40, 0xFD, 0x7F, 0x80, 0x12, 0x32, +0x1E, 0x75, 0x20, 0xFF, 0x51, 0x68, 0x51, 0xF9, 0x51, 0x7F, 0xE4, 0xFF, 0x02, 0x43, 0x9E, 0x51, +0x62, 0x51, 0x6F, 0x51, 0xA7, 0x71, 0x4F, 0x51, 0x8A, 0x51, 0x95, 0x90, 0x81, 0x45, 0xE0, 0x54, +0xFE, 0xF0, 0xA3, 0x74, 0x03, 0xF0, 0xA3, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0x22, 0xE4, 0xF5, +0x4D, 0x22, 0xE4, 0x90, 0x80, 0xDE, 0xF0, 0x22, 0x75, 0xE8, 0x03, 0x75, 0xA8, 0x84, 0x22, 0xE4, +0x90, 0x80, 0xD8, 0xF0, 0xA3, 0xF0, 0x22, 0x90, 0x01, 0x94, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, +0x01, 0xE4, 0x74, 0x0B, 0xF0, 0xA3, 0x74, 0x01, 0xF0, 0x22, 0x90, 0x81, 0x3F, 0xE0, 0x54, 0xFE, +0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x90, 0x81, 0x42, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, +0x74, 0x0A, 0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD, +0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0xE4, 0xA3, 0xF0, +0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0x74, 0x0C, 0xF0, 0x22, 0x90, 0x01, 0x01, 0xE0, 0x44, 0x04, 0xF0, +0x90, 0x01, 0x9C, 0x74, 0x7E, 0xF0, 0xA3, 0x74, 0x92, 0xF0, 0xA3, 0x74, 0xA0, 0xF0, 0xA3, 0x74, +0x24, 0xF0, 0x90, 0x01, 0x9B, 0x74, 0x49, 0xF0, 0x90, 0x01, 0x9A, 0x74, 0xE0, 0xF0, 0x90, 0x01, +0x99, 0xE4, 0xF0, 0x90, 0x01, 0x98, 0x04, 0xF0, 0x22, 0xE4, 0x90, 0x81, 0x51, 0xF0, 0xA3, 0xF0, +0x90, 0x01, 0x98, 0xE0, 0x7F, 0x00, 0x30, 0xE4, 0x02, 0x7F, 0x01, 0xEF, 0x64, 0x01, 0x60, 0x3E, +0xC3, 0x90, 0x81, 0x52, 0xE0, 0x94, 0x88, 0x90, 0x81, 0x51, 0xE0, 0x94, 0x13, 0x40, 0x08, 0x90, +0x01, 0xC1, 0xE0, 0x44, 0x10, 0xF0, 0x22, 0x90, 0x81, 0x51, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, +0xA9, 0x7F, 0x14, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0xD3, 0x90, 0x81, 0x52, 0xE0, 0x94, 0x32, 0x90, +0x81, 0x51, 0xE0, 0x94, 0x00, 0x40, 0xB9, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE3, 0xB2, 0x22, 0xE4, +0x90, 0x81, 0x27, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0xF0, 0x54, 0xF0, 0xF0, +0x90, 0x81, 0x24, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x2D, +0x74, 0x01, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFB, 0xF0, 0xA3, 0xE0, 0x54, 0xFB, +0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, 0x81, 0x2F, 0x74, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xE4, +0xF0, 0xA3, 0x74, 0x02, 0xF0, 0xE4, 0x90, 0x81, 0x2B, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFE, +0xF0, 0x90, 0x81, 0x29, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xDF, 0xF0, 0x90, 0x81, +0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, 0xE0, +0x54, 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x54, 0xF7, 0xF0, 0x90, 0x81, 0x34, 0x12, 0x20, 0xDA, 0x00, +0x00, 0x00, 0x00, 0x90, 0x80, 0x3C, 0xE0, 0xB4, 0x01, 0x08, 0x90, 0x81, 0x31, 0x74, 0x99, 0xF0, +0x80, 0x12, 0x90, 0x80, 0x3C, 0xE0, 0x90, 0x81, 0x31, 0xB4, 0x03, 0x05, 0x74, 0x90, 0xF0, 0x80, +0x03, 0x74, 0x40, 0xF0, 0x90, 0x81, 0x38, 0x74, 0x01, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0xA3, 0xE0, +0x54, 0x01, 0x44, 0x28, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xE0, 0x54, 0xFD, +0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0x54, 0xBF, 0xF0, +0xE4, 0xA3, 0xF0, 0x22, 0xE4, 0x90, 0x81, 0x59, 0xF0, 0x90, 0x81, 0x59, 0xE0, 0x64, 0x01, 0xF0, +0x24, 0x24, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x5C, 0xA3, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0xFF, 0x90, +0x81, 0x29, 0xE0, 0x6F, 0x60, 0x03, 0x12, 0x47, 0x2A, 0xD1, 0x08, 0xBF, 0x01, 0x02, 0x91, 0x5F, +0xB1, 0xF2, 0x12, 0x32, 0x9E, 0xBF, 0x01, 0x02, 0xB1, 0x67, 0x12, 0x42, 0x4D, 0x80, 0xCA, 0xD3, +0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0x24, 0xE0, 0x30, 0xE0, 0x24, 0x90, 0x81, 0x1F, +0xE0, 0xFF, 0x30, 0xE0, 0x1A, 0xC3, 0x13, 0x30, 0xE0, 0x07, 0xB1, 0xFB, 0xBF, 0x01, 0x12, 0x80, +0x0A, 0x90, 0x81, 0x23, 0xE0, 0xFF, 0x60, 0x03, 0xB4, 0x08, 0x06, 0x91, 0x96, 0x80, 0x02, 0x91, +0xA6, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xB1, 0x22, 0x91, +0xBA, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81, 0x2A, 0xE0, 0x70, 0x0D, 0xD1, 0x2F, 0xBF, 0x01, +0x08, 0x91, 0x96, 0x90, 0x01, 0xE5, 0xE0, 0x04, 0xF0, 0x22, 0xB1, 0xF3, 0x90, 0x00, 0x08, 0xE0, +0x54, 0xEF, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E, 0xE4, 0xFF, 0x8F, 0x50, 0xE4, 0x90, 0x81, 0x5A, +0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x09, 0xE0, 0x7F, 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0xEF, 0x65, +0x50, 0x60, 0x3E, 0xC3, 0x90, 0x81, 0x5B, 0xE0, 0x94, 0x88, 0x90, 0x81, 0x5A, 0xE0, 0x94, 0x13, +0x40, 0x08, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x10, 0xF0, 0x22, 0x90, 0x81, 0x5A, 0xE4, 0x75, 0xF0, +0x01, 0x12, 0x44, 0xA9, 0x7F, 0x14, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0xD3, 0x90, 0x81, 0x5B, 0xE0, +0x94, 0x32, 0x90, 0x81, 0x5A, 0xE0, 0x94, 0x00, 0x40, 0xB9, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE0, +0xB2, 0x22, 0x90, 0x81, 0x31, 0xE0, 0xFD, 0x7F, 0x93, 0x12, 0x32, 0x1E, 0x90, 0x81, 0x28, 0xE0, +0x60, 0x12, 0x90, 0x01, 0x2F, 0xE0, 0x30, 0xE7, 0x05, 0x74, 0x10, 0xF0, 0x80, 0x06, 0x90, 0x01, +0x2F, 0x74, 0x90, 0xF0, 0x90, 0x00, 0x08, 0xE0, 0x44, 0x10, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E, +0x7F, 0x01, 0x91, 0xCA, 0x90, 0x00, 0x90, 0xE0, 0x44, 0x01, 0xFD, 0x7F, 0x90, 0x12, 0x32, 0x1E, +0x7F, 0x14, 0x7E, 0x00, 0x02, 0x32, 0xAA, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x2D, +0xA7, 0xE4, 0xF5, 0x52, 0x12, 0x32, 0x9E, 0xEF, 0x60, 0x73, 0x63, 0x52, 0x01, 0xE5, 0x52, 0x24, +0x67, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x5D, 0xA3, 0xF0, 0x90, 0x00, 0x88, 0xE0, 0xF5, 0x50, 0xF5, +0x51, 0x54, 0x0F, 0x60, 0xDF, 0xE5, 0x50, 0x30, 0xE0, 0x0B, 0x20, 0xE4, 0x03, 0x12, 0x29, 0xC5, +0x53, 0x51, 0xEE, 0x80, 0x3F, 0xE5, 0x50, 0x30, 0xE1, 0x16, 0x20, 0xE5, 0x0E, 0x12, 0x11, 0xBD, +0xEF, 0x70, 0x03, 0x43, 0x51, 0x20, 0x90, 0x01, 0x06, 0xE4, 0xF0, 0x53, 0x51, 0xFD, 0x80, 0x24, +0xE5, 0x50, 0x30, 0xE2, 0x0B, 0x20, 0xE6, 0x03, 0x12, 0x67, 0x06, 0x53, 0x51, 0xFB, 0x80, 0x14, +0xE5, 0x50, 0x30, 0xE3, 0x0F, 0x20, 0xE7, 0x09, 0x12, 0x61, 0x6E, 0xEF, 0x70, 0x03, 0x43, 0x51, +0x80, 0x53, 0x51, 0xF7, 0xAD, 0x51, 0x7F, 0x88, 0x12, 0x32, 0x1E, 0x80, 0x87, 0xD0, 0xD0, 0x92, +0xAF, 0x22, 0x22, 0x90, 0x00, 0x90, 0xE0, 0x20, 0xE0, 0xF9, 0x22, 0x90, 0x81, 0x22, 0xE0, 0x64, +0x02, 0x7F, 0x01, 0x60, 0x02, 0x7F, 0x00, 0x22, 0x7F, 0x02, 0x90, 0x81, 0x41, 0xE0, 0xFE, 0xEF, +0xC3, 0x9E, 0x50, 0x18, 0xEF, 0x25, 0xE0, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE4, 0x0B, 0x90, 0x01, +0xB8, 0x74, 0x08, 0xF0, 0xA3, 0xF0, 0x7F, 0x00, 0x22, 0x0F, 0x80, 0xDE, 0x7F, 0x01, 0x22, 0x90, +0x02, 0x87, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x01, 0xF0, 0x80, 0x17, 0x90, 0x02, 0x86, +0xE0, 0x20, 0xE1, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, +0xF0, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x08, 0xF0, 0x7F, 0x00, 0x22, 0xE4, 0xFB, 0xFA, +0xFD, 0x7F, 0x01, 0x12, 0x44, 0x4E, 0x90, 0x81, 0xBD, 0xEF, 0xF0, 0x60, 0xF0, 0xD1, 0x71, 0x80, +0xEC, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x01, 0xCC, 0xE0, 0x54, 0x0F, 0x90, 0x81, +0xBE, 0xF0, 0x90, 0x81, 0xBE, 0xE0, 0xFD, 0x70, 0x02, 0xE1, 0x9C, 0x90, 0x82, 0x09, 0xE0, 0xFF, +0x74, 0x01, 0x7E, 0x00, 0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, +0xFF, 0xEF, 0x5D, 0x70, 0x02, 0xE1, 0x95, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, +0xD0, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xBF, 0xF0, 0x75, 0x13, 0x01, 0x75, 0x14, 0x81, 0x75, +0x15, 0xBF, 0x75, 0x16, 0x01, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0xC0, 0x12, 0x2B, 0xED, 0x90, 0x82, +0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD1, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC1, 0xF0, +0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD2, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, +0xC2, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD3, 0x12, 0x45, 0x0A, 0xE0, +0x90, 0x81, 0xC3, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF0, 0x12, 0x45, +0x0A, 0xE0, 0x90, 0x81, 0xC4, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF1, +0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC5, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, 0x04, 0x90, +0x01, 0xF2, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC6, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0x75, 0xF0, +0x04, 0x90, 0x01, 0xF3, 0x12, 0x45, 0x0A, 0xE0, 0x90, 0x81, 0xC7, 0xF0, 0x90, 0x81, 0xBE, 0xE0, +0xFF, 0x90, 0x82, 0x09, 0xE0, 0xFE, 0x74, 0x01, 0xA8, 0x06, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, +0xFC, 0xF4, 0x5F, 0x90, 0x81, 0xBE, 0xF0, 0x90, 0x82, 0x09, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, +0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0x90, 0x01, 0xCC, 0xF0, 0x90, 0x81, 0xC0, 0xE0, 0xFF, +0x7B, 0x01, 0x7A, 0x81, 0x79, 0xC1, 0x12, 0x55, 0x3F, 0x90, 0x82, 0x09, 0xE0, 0x04, 0xF0, 0xE0, +0x54, 0x03, 0xF0, 0xC1, 0x82, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x02, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, +0x22, 0xE4, 0xFB, 0xFA, 0xFD, 0x7F, 0x01, 0x12, 0x44, 0x4E, 0x90, 0x81, 0xD0, 0xEF, 0xF0, 0x60, +0xF0, 0x12, 0x6C, 0x19, 0x80, 0xEB, 0x90, 0x81, 0xD4, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0xA3, 0x12, +0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x90, 0x81, 0xE2, 0xF0, 0x7F, 0x24, 0x7E, 0x08, 0x12, +0x2D, 0x5C, 0x90, 0x81, 0xDA, 0x12, 0x20, 0xCE, 0x90, 0x81, 0xD4, 0xE0, 0xFB, 0x70, 0x08, 0x90, +0x81, 0xDA, 0x12, 0x44, 0xD9, 0x80, 0x16, 0xEB, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, +0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, 0x2D, 0x5C, 0x90, 0x81, 0xDE, +0x12, 0x20, 0xCE, 0x90, 0x81, 0xD5, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x17, 0x12, 0x20, +0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, 0x07, 0x90, 0x81, 0xDE, 0x12, 0x44, 0xD9, 0xED, +0x54, 0x7F, 0xFD, 0xEC, 0x54, 0x80, 0xFC, 0x12, 0x44, 0xCC, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x81, +0xDE, 0x12, 0x20, 0xCE, 0x90, 0x81, 0xDA, 0x12, 0x44, 0xD9, 0xEC, 0x54, 0x7F, 0xFC, 0x90, 0x85, +0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xD4, 0xE0, 0x75, +0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, +0xFF, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0xDE, 0x12, 0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12, 0x20, +0xCE, 0xD0, 0x07, 0xD0, 0x06, 0x12, 0x2E, 0xA2, 0x90, 0x81, 0xDA, 0x12, 0x44, 0xD9, 0xEC, 0x44, +0x80, 0xFC, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, +0x81, 0xD4, 0xE0, 0x70, 0x04, 0x7F, 0x20, 0x80, 0x09, 0x90, 0x81, 0xD4, 0xE0, 0xB4, 0x01, 0x16, +0x7F, 0x28, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0x78, 0x08, 0x12, 0x20, 0xA8, 0xEF, 0x54, 0x01, 0xFF, +0xE4, 0x90, 0x81, 0xE2, 0xEF, 0xF0, 0x90, 0x81, 0xE2, 0xE0, 0x90, 0x81, 0xD4, 0x60, 0x0E, 0xE0, +0x75, 0xF0, 0x08, 0xA4, 0x24, 0x66, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0x80, 0x0C, 0xE0, 0x75, 0xF0, +0x08, 0xA4, 0x24, 0x64, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, +0x12, 0x2D, 0x5C, 0xED, 0x54, 0x0F, 0xFD, 0xE4, 0xFC, 0x90, 0x81, 0xD6, 0x12, 0x20, 0xCE, 0x90, +0x81, 0xD6, 0x02, 0x44, 0xD9, 0x90, 0x81, 0xE3, 0xEF, 0xF0, 0xAB, 0x05, 0x90, 0x81, 0xE9, 0x12, +0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x03, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x14, 0x12, 0x20, +0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, 0x07, 0x90, 0x81, 0xE5, 0x12, 0x44, 0xD9, 0xED, +0x54, 0x0F, 0xFD, 0xE4, 0xFC, 0x12, 0x44, 0xCC, 0xEC, 0x54, 0x0F, 0xFC, 0x90, 0x81, 0xE9, 0x12, +0x20, 0xCE, 0x90, 0x81, 0xE3, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x60, 0xF5, 0x82, 0xE4, 0x34, +0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0xE9, 0x12, +0x44, 0xD9, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0xD0, 0x07, 0xD0, 0x06, 0x02, 0x2E, 0xA2, 0xD3, +0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x5F, 0xB6, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x78, 0x10, +0x74, 0x01, 0xF2, 0x90, 0x02, 0x09, 0xE0, 0x78, 0x00, 0xF2, 0x08, 0x74, 0x20, 0xF2, 0x18, 0xE2, +0xFF, 0x30, 0xE0, 0x05, 0x08, 0xE2, 0x24, 0x80, 0xF2, 0xEF, 0xC3, 0x13, 0x90, 0xFD, 0x10, 0xF0, +0x78, 0x01, 0xE2, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x78, 0x03, 0xF2, +0x64, 0x04, 0x60, 0x0D, 0xE2, 0xFF, 0x64, 0x08, 0x60, 0x07, 0xEF, 0x64, 0x0C, 0x60, 0x02, 0x61, +0xDE, 0xE4, 0x78, 0x02, 0xF2, 0x78, 0x03, 0xE2, 0xFF, 0x18, 0xE2, 0xC3, 0x9F, 0x50, 0x2D, 0xE2, +0xFD, 0x18, 0xE2, 0x2D, 0x90, 0x81, 0x5A, 0xF0, 0xE0, 0xFF, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, +0xFC, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x04, 0x2D, 0xF8, 0xEE, 0xF2, 0xEF, 0xB4, 0xFF, 0x06, 0x90, +0xFD, 0x10, 0xE0, 0x04, 0xF0, 0x78, 0x02, 0xE2, 0x04, 0xF2, 0x80, 0xC9, 0x78, 0x04, 0xE2, 0x78, +0x12, 0xF2, 0xFF, 0x78, 0x05, 0xE2, 0x78, 0x11, 0xF2, 0x78, 0x06, 0xE2, 0x78, 0x13, 0xF2, 0x78, +0x07, 0xE2, 0x78, 0x14, 0xF2, 0x78, 0x08, 0xE2, 0x78, 0x33, 0xF2, 0x78, 0x09, 0xE2, 0x78, 0x34, +0xF2, 0x78, 0x0A, 0xE2, 0x78, 0x35, 0xF2, 0x78, 0x0B, 0xE2, 0x78, 0x36, 0xF2, 0x78, 0x0C, 0xE2, +0x78, 0x37, 0xF2, 0x78, 0x0D, 0xE2, 0x78, 0x38, 0xF2, 0x78, 0x0E, 0xE2, 0x78, 0x39, 0xF2, 0x78, +0x0F, 0xE2, 0x78, 0x3A, 0xF2, 0xE4, 0x78, 0x15, 0xF2, 0xEF, 0x24, 0xF8, 0x60, 0x75, 0x24, 0xFC, +0x60, 0x6C, 0x24, 0x08, 0x60, 0x02, 0x61, 0xC0, 0x78, 0x11, 0xE2, 0xB4, 0x01, 0x05, 0x12, 0x29, +0xC5, 0x61, 0xC5, 0x78, 0x11, 0xE2, 0xB4, 0x02, 0x05, 0x12, 0x11, 0xBD, 0x61, 0xC5, 0x78, 0x11, +0xE2, 0xB4, 0x03, 0x04, 0xF1, 0x06, 0x61, 0xC5, 0x78, 0x11, 0xE2, 0xB4, 0x10, 0x17, 0x78, 0x14, +0xE2, 0xFE, 0x18, 0xE2, 0xFD, 0xED, 0xFF, 0x78, 0x16, 0xEE, 0xF2, 0xFE, 0x08, 0xEF, 0xF2, 0xFF, +0x12, 0x32, 0xAA, 0x61, 0xC5, 0x78, 0x11, 0xE2, 0xB4, 0x11, 0x17, 0x78, 0x14, 0xE2, 0xFE, 0x18, +0xE2, 0xFD, 0xED, 0xFF, 0x78, 0x16, 0xEE, 0xF2, 0xFE, 0x08, 0xEF, 0xF2, 0xFF, 0x12, 0x32, 0x06, +0x61, 0xC5, 0x78, 0x11, 0xE2, 0xF4, 0x60, 0x02, 0x61, 0xC5, 0x18, 0xF2, 0x61, 0xC5, 0x78, 0x15, +0x74, 0x01, 0xF2, 0x78, 0x11, 0xE2, 0x64, 0x07, 0x60, 0x02, 0x61, 0xAA, 0x78, 0x34, 0xE2, 0xFF, +0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12, 0x20, 0xBB, 0xC0, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, +0x07, 0x78, 0x33, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0xC0, 0x04, +0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x78, 0x35, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10, +0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x78, 0x18, +0x12, 0x44, 0xFE, 0x78, 0x15, 0xE2, 0x70, 0x02, 0x61, 0x93, 0x18, 0xE2, 0xFF, 0x18, 0xE2, 0xFD, +0x31, 0x5F, 0x78, 0x1C, 0x12, 0x44, 0xFE, 0x78, 0x38, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, +0x08, 0x12, 0x20, 0xBB, 0xC0, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, 0x07, 0x78, 0x37, 0xE2, 0xFF, +0xE4, 0xFC, 0xFD, 0xFE, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, +0x07, 0x78, 0x39, 0xE2, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20, 0xBB, 0xD0, 0x03, +0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x78, 0x20, 0x12, 0x44, 0xFE, 0x78, 0x20, +0x12, 0x44, 0xE5, 0x12, 0x20, 0x9B, 0x78, 0x1C, 0x12, 0x44, 0xF1, 0x12, 0x44, 0xBF, 0xC0, 0x04, +0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x78, 0x18, 0x12, 0x44, 0xE5, 0x78, 0x20, 0x12, 0x44, 0xF1, +0x12, 0x44, 0xBF, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x78, 0x18, +0x12, 0x44, 0xFE, 0x78, 0x18, 0x12, 0x44, 0xE5, 0x90, 0x81, 0xF9, 0x12, 0x20, 0xCE, 0x78, 0x13, +0xE2, 0xFD, 0x08, 0xE2, 0xFF, 0x12, 0x55, 0x1C, 0x80, 0x1B, 0x78, 0x13, 0xE2, 0xFF, 0x08, 0xE2, +0xFD, 0x78, 0x11, 0xE2, 0xFB, 0x78, 0x15, 0xE2, 0x90, 0x81, 0xBC, 0xF0, 0x71, 0xE1, 0x80, 0x05, +0x78, 0x10, 0x74, 0x02, 0xF2, 0x78, 0x10, 0xE2, 0xFF, 0xC3, 0x94, 0x02, 0x50, 0x10, 0xEF, 0x60, +0x0A, 0x78, 0x02, 0xE2, 0xFF, 0x18, 0xE2, 0x2F, 0xF2, 0x21, 0x90, 0x7F, 0x01, 0x22, 0x7F, 0x00, +0x22, 0xAC, 0x07, 0xED, 0xAD, 0x04, 0x78, 0x24, 0xF2, 0xED, 0x08, 0xF2, 0xEB, 0xB4, 0x04, 0x07, +0x78, 0x27, 0x74, 0x01, 0xF2, 0x80, 0x0E, 0xEB, 0x78, 0x27, 0xB4, 0x05, 0x05, 0x74, 0x02, 0xF2, +0x80, 0x03, 0x74, 0x04, 0xF2, 0xD3, 0x78, 0x25, 0xE2, 0x94, 0xFF, 0x18, 0xE2, 0x94, 0x00, 0x50, +0x63, 0xE4, 0x78, 0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF, 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x40, 0x02, +0xA1, 0x7F, 0x74, 0x33, 0x2E, 0xF8, 0xE2, 0x78, 0x28, 0xF2, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x2D, +0x74, 0x37, 0x2E, 0xF8, 0xE2, 0x78, 0x32, 0xF2, 0xEE, 0xFF, 0x78, 0x25, 0xE2, 0x2F, 0xFF, 0x18, +0xE2, 0x34, 0x00, 0x8F, 0x82, 0xF5, 0x83, 0xE0, 0x78, 0x29, 0xF2, 0x78, 0x32, 0xE2, 0xFF, 0xF4, +0xFE, 0x78, 0x29, 0xE2, 0x5E, 0xFE, 0x18, 0xE2, 0xFD, 0xEF, 0x5D, 0x4E, 0xF2, 0x78, 0x24, 0x08, +0xE2, 0xFF, 0x08, 0xE2, 0x2F, 0xFF, 0x78, 0x28, 0xE2, 0xFD, 0x12, 0x32, 0x1E, 0x78, 0x26, 0xE2, +0x04, 0xF2, 0x80, 0xA1, 0xD3, 0x78, 0x25, 0xE2, 0x94, 0xFF, 0x18, 0xE2, 0x94, 0x07, 0x50, 0x69, +0xE4, 0x78, 0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF, 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x40, 0x02, 0xA1, +0x7F, 0x74, 0x33, 0x2E, 0xF8, 0xE2, 0x78, 0x28, 0xF2, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x2D, 0x78, +0x26, 0xE2, 0xFF, 0xFD, 0x18, 0xE2, 0x2D, 0xFD, 0x18, 0xE2, 0x34, 0x00, 0x8D, 0x82, 0xF5, 0x83, +0xE0, 0x78, 0x29, 0xF2, 0x74, 0x37, 0x2F, 0xF8, 0xE2, 0x78, 0x32, 0xF2, 0xE2, 0xFF, 0xF4, 0xFE, +0x78, 0x29, 0xE2, 0x5E, 0xFE, 0x18, 0xE2, 0xFD, 0xEF, 0x5D, 0x4E, 0xF2, 0x78, 0x28, 0xE2, 0xFF, +0x78, 0x26, 0xE2, 0xFD, 0x18, 0xE2, 0x2D, 0xFD, 0x18, 0xE2, 0x34, 0x00, 0x8D, 0x82, 0xF5, 0x83, +0xEF, 0xF0, 0x78, 0x26, 0xE2, 0x04, 0xF2, 0x80, 0x9B, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x0F, 0x78, +0x24, 0xE2, 0xFE, 0x08, 0xE2, 0xFF, 0x12, 0x2D, 0x5C, 0x78, 0x2E, 0x12, 0x44, 0xFE, 0xE4, 0x78, +0x26, 0xF2, 0x78, 0x27, 0xE2, 0xFF, 0x18, 0xE2, 0xFE, 0xC3, 0x9F, 0x50, 0x5D, 0x74, 0x33, 0x2E, +0xF8, 0xE2, 0x78, 0x28, 0xF2, 0x90, 0x81, 0xBC, 0xE0, 0x60, 0x2B, 0x78, 0x2E, 0x12, 0x44, 0xE5, +0x78, 0x26, 0xE2, 0xFB, 0x75, 0xF0, 0x08, 0xA4, 0xF9, 0xF8, 0x12, 0x20, 0xA8, 0x78, 0x29, 0xEF, +0xF2, 0x74, 0x37, 0x2B, 0xF8, 0xE2, 0x78, 0x32, 0xF2, 0xE2, 0xFE, 0xF4, 0x5F, 0xFF, 0x78, 0x28, +0xE2, 0xFD, 0xEE, 0x5D, 0x4F, 0xF2, 0x78, 0x28, 0xE2, 0xFF, 0x78, 0x26, 0xE2, 0xFD, 0xC3, 0x74, +0x03, 0x9D, 0xFD, 0xE4, 0x94, 0x00, 0xFC, 0x7B, 0xFE, 0x74, 0x2A, 0x2D, 0xF9, 0x74, 0x80, 0x3C, +0xFA, 0xEF, 0x12, 0x1F, 0xEA, 0xE2, 0x04, 0xF2, 0x80, 0x98, 0x78, 0x2A, 0x12, 0x44, 0xE5, 0x90, +0x85, 0xBB, 0x12, 0x20, 0xCE, 0x78, 0x24, 0xE2, 0xFE, 0x08, 0xE2, 0xFF, 0x12, 0x2E, 0xA2, 0x22, +0x22, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x1F, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xFE, 0x12, +0x1F, 0xA4, 0xFD, 0xC3, 0x13, 0x30, 0xE0, 0x12, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, 0x90, 0x00, +0x02, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0xCF, 0xF0, 0x80, 0x05, 0x90, 0x81, 0xCF, 0xEF, 0xF0, 0x90, +0x81, 0xCE, 0xEE, 0xF0, 0x90, 0x81, 0xCF, 0xE0, 0xFE, 0x90, 0x81, 0xCE, 0xE0, 0xFF, 0xD3, 0x9E, +0x50, 0x38, 0x90, 0x81, 0xCB, 0x12, 0x45, 0x16, 0x12, 0x1F, 0xA4, 0x54, 0x01, 0xFE, 0x74, 0xDE, +0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83, 0xEE, 0xF0, 0x74, 0xDE, 0x2F, 0xF5, 0x82, 0xE4, +0x34, 0x80, 0xF5, 0x83, 0xE0, 0x70, 0x04, 0xD1, 0x25, 0x80, 0x07, 0x90, 0x81, 0xCE, 0xE0, 0xFF, +0xB1, 0x80, 0x90, 0x81, 0xCE, 0xE0, 0x04, 0xF0, 0x80, 0xBA, 0x90, 0x80, 0xDE, 0xE0, 0x70, 0x24, +0x90, 0x81, 0x2A, 0xE0, 0x70, 0x04, 0xFF, 0x12, 0x49, 0x93, 0x90, 0x81, 0x2A, 0xE0, 0x64, 0x0C, +0x60, 0x02, 0xD1, 0x26, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xBF, +0xF0, 0x54, 0x7F, 0xF0, 0x22, 0x22, 0x90, 0x06, 0x04, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x05, 0x22, +0xE4, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x22, 0x90, 0x81, 0xED, 0xEF, 0xF0, 0xA3, 0xED, +0xF0, 0xAD, 0x03, 0xAC, 0x02, 0xE4, 0x90, 0x81, 0xF5, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0xC4, 0x74, +0x39, 0xF0, 0x74, 0x66, 0xA3, 0xF0, 0xEC, 0x54, 0x3F, 0xFC, 0x90, 0x01, 0x40, 0xED, 0xF0, 0xAE, +0x04, 0xEE, 0xA3, 0xF0, 0x90, 0x81, 0xED, 0xE0, 0x24, 0x81, 0x60, 0x34, 0x24, 0xDA, 0x60, 0x1C, +0x24, 0x3C, 0x70, 0x41, 0x90, 0x81, 0xEE, 0xE0, 0xC4, 0x33, 0x33, 0x33, 0x54, 0x80, 0x90, 0x81, +0xF2, 0xF0, 0xA3, 0x74, 0x69, 0xF0, 0xA3, 0x74, 0x80, 0xF0, 0x80, 0x2C, 0x90, 0x81, 0xEE, 0xE0, +0x54, 0x01, 0x90, 0x81, 0xF2, 0xF0, 0xA3, 0x74, 0xA5, 0xF0, 0xA3, 0x74, 0x01, 0xF0, 0x80, 0x18, +0x90, 0x81, 0xEE, 0xE0, 0xC4, 0x54, 0x10, 0x90, 0x81, 0xF2, 0xF0, 0xA3, 0x74, 0x7F, 0xF0, 0xA3, +0x74, 0x10, 0xF0, 0x80, 0x03, 0x7F, 0x00, 0x22, 0x90, 0x81, 0xF3, 0xE0, 0x90, 0x01, 0x06, 0xF0, +0x90, 0x81, 0xF2, 0xE0, 0x60, 0x0E, 0x90, 0x01, 0x42, 0xF0, 0x90, 0x81, 0xF1, 0xE0, 0x90, 0x01, +0x43, 0xF0, 0x80, 0x0D, 0x90, 0x01, 0x43, 0xE4, 0xF0, 0x90, 0x81, 0xF2, 0xE0, 0x90, 0x01, 0x42, +0xF0, 0x90, 0x81, 0xF4, 0xE0, 0xFF, 0x90, 0x01, 0x42, 0xE0, 0x5F, 0xFF, 0x90, 0x81, 0xF2, 0xE0, +0x6F, 0x60, 0xEE, 0x74, 0x39, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x66, 0xA3, 0xF0, 0x90, 0x01, +0x43, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0xE4, 0x90, 0x81, 0x6A, 0xF0, 0x90, 0x87, 0x5F, 0xE0, 0x90, +0x81, 0x69, 0xF0, 0xE4, 0x90, 0x81, 0x76, 0xF0, 0x90, 0x81, 0x66, 0xF0, 0x90, 0x81, 0x66, 0xE0, +0xFF, 0xC3, 0x94, 0x40, 0x50, 0x15, 0x74, 0x79, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, +0x74, 0xFF, 0xF0, 0x90, 0x81, 0x66, 0xE0, 0x04, 0xF0, 0x80, 0xE1, 0xE4, 0x90, 0x81, 0x66, 0xF0, +0x90, 0x81, 0x69, 0xE0, 0xFF, 0x90, 0x81, 0x66, 0xE0, 0xFE, 0xC3, 0x9F, 0x40, 0x03, 0x02, 0x68, +0x12, 0x74, 0xDF, 0x2E, 0xF9, 0xE4, 0x34, 0x86, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, +0x16, 0x0A, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x5B, 0x12, 0x2B, 0xED, 0x90, 0x81, 0x5C, 0xE0, 0xFF, +0x12, 0x2F, 0x27, 0xEF, 0x04, 0x90, 0x81, 0x76, 0xF0, 0x90, 0x81, 0x5B, 0xE0, 0xFF, 0xA3, 0xE0, +0xFD, 0x12, 0x31, 0xEA, 0xEF, 0x24, 0xC8, 0x90, 0x81, 0x78, 0xF0, 0x75, 0xF0, 0x08, 0xA4, 0xF0, +0x90, 0x81, 0x5C, 0xE0, 0x54, 0x0F, 0x90, 0x81, 0x77, 0xF0, 0xE4, 0x90, 0x81, 0x65, 0xF0, 0x90, +0x81, 0x67, 0xF0, 0x90, 0x81, 0x67, 0xE0, 0xFF, 0xC3, 0x94, 0x04, 0x50, 0x57, 0x90, 0x81, 0x77, +0xE0, 0xFE, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x13, 0xD8, 0xFC, 0x20, 0xE0, 0x3E, 0x90, 0x81, +0x67, 0xE0, 0x25, 0xE0, 0xFF, 0x90, 0x81, 0x78, 0xE0, 0x2F, 0x24, 0x79, 0xF9, 0xE4, 0x34, 0x81, +0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x01, 0x90, 0x81, 0x65, 0xE0, 0x75, 0xF0, 0x02, 0xA4, 0x24, +0x5D, 0xF9, 0x74, 0x81, 0x35, 0xF0, 0x8B, 0x13, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x02, 0xD0, +0x01, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x90, 0x81, 0x65, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x67, 0xE0, +0x04, 0xF0, 0x80, 0x9F, 0x90, 0x81, 0x76, 0xE0, 0xFF, 0x90, 0x81, 0x66, 0xE0, 0x2F, 0xF0, 0x02, +0x67, 0x40, 0xE4, 0x90, 0x81, 0x6A, 0xF0, 0x90, 0x81, 0x6A, 0xE0, 0xC3, 0x94, 0x40, 0x40, 0x02, +0x41, 0xAF, 0xE0, 0xFF, 0x24, 0x79, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0x90, 0x81, +0x6C, 0xF0, 0xE0, 0xFE, 0x54, 0xF0, 0xC4, 0x54, 0x0F, 0xFD, 0x90, 0x81, 0x6B, 0xF0, 0xEE, 0x54, +0x0F, 0xFE, 0xA3, 0xF0, 0x74, 0x7A, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0x90, +0x81, 0x6D, 0xF0, 0xFC, 0xEE, 0xFE, 0xEC, 0xFB, 0xEB, 0xFF, 0x90, 0x81, 0x72, 0xEE, 0xF0, 0xA3, +0xEF, 0xF0, 0xED, 0x12, 0x45, 0x28, 0x68, 0x8B, 0x00, 0x68, 0xC2, 0x01, 0x69, 0x73, 0x02, 0x6A, +0xA0, 0x03, 0x69, 0x8E, 0x04, 0x69, 0xAF, 0x05, 0x69, 0xAF, 0x06, 0x69, 0xAF, 0x07, 0x69, 0xAF, +0x08, 0x6A, 0x33, 0x09, 0x6A, 0x69, 0x0A, 0x00, 0x00, 0x6A, 0xAF, 0x90, 0x81, 0x6A, 0xE0, 0xFD, +0x24, 0x7C, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x7B, 0x2D, 0xF5, 0x82, +0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFD, 0xED, 0xFF, 0x90, 0x81, 0x74, 0xEE, 0xF0, 0xFC, 0xA3, +0xEF, 0xF0, 0x90, 0x81, 0x6D, 0xE0, 0xFF, 0x12, 0x2F, 0x96, 0x90, 0x81, 0x68, 0x74, 0x02, 0xF0, +0x41, 0xA0, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7C, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, +0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, +0xAB, 0x07, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, +0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, +0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7D, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFF, 0xE4, +0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, +0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x81, 0x6A, 0xE0, 0x24, +0x7E, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x18, +0x12, 0x20, 0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x90, 0x81, +0x6E, 0x12, 0x20, 0xCE, 0x90, 0x81, 0x6E, 0x12, 0x44, 0xD9, 0x90, 0x85, 0x96, 0x12, 0x20, 0xCE, +0x90, 0x81, 0x72, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, 0x2E, 0xE4, 0x90, 0x81, 0x68, 0x74, 0x04, +0xF0, 0x41, 0xA0, 0x90, 0x81, 0x6D, 0xE0, 0xFD, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF5, 0x82, +0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFB, 0xE4, 0xFF, 0x12, 0x30, 0xC7, 0x80, 0x19, 0x90, 0x81, +0x6D, 0xE0, 0xFD, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, +0xE0, 0xFB, 0xE4, 0xFF, 0x12, 0x30, 0x6A, 0x90, 0x81, 0x68, 0x74, 0x01, 0xF0, 0x41, 0xA0, 0x90, +0x81, 0x68, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7C, 0xF5, 0x82, 0xE4, 0x34, 0x81, +0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x08, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9, +0x05, 0xAA, 0x06, 0xAB, 0x07, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF5, 0x82, 0xE4, 0x34, 0x81, +0xF5, 0x83, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x12, 0x44, 0xCC, 0xC0, 0x04, 0xC0, 0x05, 0xC0, +0x06, 0xC0, 0x07, 0x90, 0x81, 0x6C, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x10, 0x12, 0x20, +0xBB, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0x12, 0x44, 0xCC, 0x90, 0x81, 0x6E, 0x12, +0x20, 0xCE, 0x90, 0x81, 0x6B, 0xE0, 0x24, 0xFB, 0xFF, 0xC0, 0x07, 0x90, 0x81, 0x6E, 0x12, 0x44, +0xD9, 0x90, 0x81, 0xF9, 0x12, 0x20, 0xCE, 0x90, 0x81, 0x6D, 0xE0, 0xFD, 0xD0, 0x07, 0x12, 0x55, +0x1C, 0x80, 0x6D, 0x90, 0x81, 0x68, 0x74, 0x01, 0xF0, 0x90, 0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF9, +0xE4, 0x34, 0x81, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x01, 0x7B, 0xFE, 0x7A, +0x80, 0x79, 0x33, 0x12, 0x2B, 0xED, 0x90, 0x81, 0x6D, 0xE0, 0xFF, 0x90, 0x81, 0x6C, 0xE0, 0xFD, +0xE4, 0x90, 0x81, 0xBC, 0xF0, 0x7B, 0x04, 0x80, 0x34, 0x90, 0x81, 0x68, 0x74, 0x04, 0xF0, 0x90, +0x81, 0x6A, 0xE0, 0x24, 0x7B, 0xF9, 0xE4, 0x34, 0x81, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, +0x75, 0x16, 0x04, 0x7B, 0xFE, 0x7A, 0x80, 0x79, 0x33, 0x12, 0x2B, 0xED, 0x90, 0x81, 0x6D, 0xE0, +0xFF, 0x90, 0x81, 0x6C, 0xE0, 0xFD, 0xE4, 0x90, 0x81, 0xBC, 0xF0, 0x7B, 0x06, 0x12, 0x63, 0xE1, +0x90, 0x81, 0x68, 0xE0, 0x24, 0x02, 0xFF, 0x90, 0x81, 0x6A, 0xE0, 0x2F, 0xF0, 0x01, 0x17, 0x22, +0x90, 0x02, 0x09, 0xE0, 0xFD, 0x12, 0x1F, 0xA4, 0xFE, 0xAF, 0x05, 0xED, 0x2E, 0x90, 0x80, 0x3D, +0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x3E, 0xF0, 0x90, 0x00, +0x02, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x3F, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, +0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x40, 0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0xAE, +0x05, 0xED, 0x2F, 0x90, 0x80, 0x41, 0xF0, 0x22, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0x30, +0xE0, 0x26, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x38, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, +0x81, 0x39, 0xF0, 0xEF, 0x54, 0xFE, 0xFF, 0xA3, 0xE0, 0x54, 0x01, 0x4F, 0xF0, 0x90, 0x00, 0x03, +0x12, 0x1F, 0xBD, 0x90, 0x81, 0x3B, 0xF0, 0x22, 0x90, 0x81, 0x38, 0x74, 0x01, 0xF0, 0xA3, 0x74, +0x05, 0xF0, 0xA3, 0xE0, 0x54, 0x01, 0x44, 0x28, 0xF0, 0xA3, 0x74, 0x05, 0xF0, 0x22, 0x12, 0x1F, +0xA4, 0x90, 0x81, 0x3E, 0xF0, 0x90, 0x81, 0x3E, 0xE0, 0x90, 0x01, 0xE7, 0xF0, 0x22, 0x12, 0x1F, +0xA4, 0x90, 0x81, 0x4A, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x4B, 0xF0, 0x22, +0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0xFD, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xE4, +0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0xFD, 0xE0, 0xFE, 0xA3, 0xE0, 0xF5, 0x82, 0x8E, 0x83, 0xE0, +0x60, 0x2D, 0xC3, 0x90, 0x82, 0x00, 0xE0, 0x94, 0xE8, 0x90, 0x81, 0xFF, 0xE0, 0x94, 0x03, 0x40, +0x0B, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x80, 0xF0, 0x7F, 0x00, 0x80, 0x15, 0x90, 0x81, 0xFF, 0xE4, +0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9, 0x7F, 0x0A, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x80, 0xC5, 0x7F, +0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0xD1, +0x12, 0x45, 0x1F, 0x90, 0x82, 0x0A, 0xE0, 0xFF, 0x04, 0xF0, 0x90, 0x00, 0x01, 0xEF, 0x12, 0x1F, +0xFC, 0x7F, 0xAF, 0x7E, 0x01, 0x71, 0x60, 0xEF, 0x60, 0x3A, 0x90, 0x81, 0xD1, 0x12, 0x45, 0x16, +0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x90, 0x00, 0x0E, 0x12, 0x1F, 0xBD, 0x24, 0x02, 0xF5, 0x16, +0x7B, 0x01, 0x7A, 0x01, 0x79, 0xA0, 0x12, 0x2B, 0xED, 0x90, 0x81, 0xD1, 0x12, 0x45, 0x16, 0x90, +0x00, 0x0E, 0x12, 0x1F, 0xBD, 0x90, 0x01, 0xAE, 0xF0, 0xA3, 0x74, 0xFF, 0xF0, 0x90, 0x01, 0xCB, +0xE0, 0x64, 0x80, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, +0xE4, 0xFF, 0x90, 0x80, 0xD9, 0xE0, 0xFE, 0x90, 0x80, 0xD8, 0xE0, 0xFD, 0xB5, 0x06, 0x04, 0x7E, +0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x64, 0x01, 0x60, 0x32, 0x90, 0x01, 0xAF, 0xE0, 0x70, 0x13, +0xED, 0x75, 0xF0, 0x0F, 0xA4, 0x24, 0x42, 0xF9, 0x74, 0x80, 0x35, 0xF0, 0xFA, 0x7B, 0x01, 0x71, +0xB6, 0x7F, 0x01, 0xEF, 0x60, 0x16, 0x90, 0x80, 0xD8, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4, +0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x60, 0x05, 0xE4, 0x90, 0x80, 0xD8, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, +0x22, 0x8F, 0x0D, 0x22, 0x8F, 0x0E, 0x22, 0x22, 0x90, 0x01, 0x34, 0xE0, 0x55, 0x3D, 0xF5, 0x41, +0xA3, 0xE0, 0x55, 0x3E, 0xF5, 0x42, 0xA3, 0xE0, 0x55, 0x3F, 0xF5, 0x43, 0xA3, 0xE0, 0x55, 0x40, +0xF5, 0x44, 0x90, 0x01, 0x34, 0xE5, 0x41, 0xF0, 0xA3, 0xE5, 0x42, 0xF0, 0xA3, 0xE5, 0x43, 0xF0, +0xA3, 0xE5, 0x44, 0xF0, 0x22, 0x90, 0x01, 0x3C, 0xE0, 0x55, 0x45, 0xF5, 0x49, 0xA3, 0xE0, 0x55, +0x46, 0xF5, 0x4A, 0xA3, 0xE0, 0x55, 0x47, 0xF5, 0x4B, 0xA3, 0xE0, 0x55, 0x48, 0xF5, 0x4C, 0x90, +0x01, 0x3C, 0xE5, 0x49, 0xF0, 0xA3, 0xE5, 0x4A, 0xF0, 0xA3, 0xE5, 0x4B, 0xF0, 0xA3, 0xE5, 0x4C, +0xF0, 0x53, 0x91, 0xDF, 0x22, 0x90, 0x81, 0x1F, 0xE0, 0x30, 0xE0, 0x05, 0xE4, 0xA3, 0xF0, 0xA3, +0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x70, 0x19, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x13, +0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0x12, 0x4F, 0xF4, 0x90, 0x01, 0x57, +0x74, 0x05, 0xF0, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x70, 0x26, 0x90, 0x81, 0x27, 0xE0, +0x60, 0x20, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24, +0xE0, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0x07, 0x70, 0x03, 0x12, +0x47, 0x2A, 0x22, 0x90, 0x80, 0xDE, 0xE0, 0xB4, 0x01, 0x14, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x0E, +0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x02, 0x80, 0x03, 0xD1, 0x7F, 0x22, 0x90, +0x04, 0x1D, 0xE0, 0x70, 0x13, 0x90, 0x80, 0x3E, 0xE0, 0xFF, 0xE4, 0xFD, 0xB1, 0x69, 0x8E, 0x4E, +0x8F, 0x4F, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, +0x90, 0x82, 0x0E, 0xED, 0xF0, 0x90, 0x82, 0x0D, 0xEF, 0xF0, 0xE4, 0xFD, 0xFC, 0xF1, 0x37, 0x7C, +0x00, 0xAD, 0x07, 0x90, 0x82, 0x0D, 0xE0, 0x90, 0x04, 0x25, 0xF0, 0x90, 0x82, 0x0E, 0xE0, 0x60, +0x0E, 0x74, 0x0F, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0xAF, +0x05, 0x74, 0x08, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE4, 0xF0, 0x74, 0x09, 0x2F, +0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xF0, 0xF0, 0x74, 0x21, 0x2D, 0xF5, 0x82, +0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xF7, 0xF0, 0xAE, 0x04, 0xAF, 0x05, 0xD0, 0xD0, 0x92, +0xAF, 0x22, 0x8F, 0x4E, 0xF1, 0x4B, 0xBF, 0x01, 0x18, 0x90, 0x80, 0x40, 0xE0, 0xFF, 0x7D, 0x01, +0xB1, 0x69, 0xAD, 0x07, 0xAC, 0x06, 0xAF, 0x4E, 0x12, 0x4F, 0x82, 0x90, 0x04, 0x1F, 0x74, 0x20, +0xF0, 0x22, 0x90, 0x06, 0xA9, 0xE0, 0x90, 0x81, 0x4C, 0xF0, 0xE0, 0xFD, 0x54, 0xC0, 0x70, 0x09, +0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x80, 0x72, 0xED, 0x30, 0xE6, 0x4B, 0x90, 0x81, 0x27, +0xE0, 0x64, 0x02, 0x70, 0x2A, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0xC3, 0x13, 0x20, 0xE0, 0x09, 0x90, +0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x28, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x01, +0x70, 0x2D, 0x90, 0x81, 0x2B, 0xE0, 0x44, 0x04, 0xF0, 0x7F, 0x01, 0xB1, 0xD2, 0x80, 0x20, 0x90, +0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81, 0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x04, +0xB1, 0x4F, 0x80, 0x0B, 0xD1, 0x7F, 0x80, 0x07, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x90, +0x81, 0x4C, 0xE0, 0x90, 0x81, 0x2B, 0x30, 0xE7, 0x11, 0x12, 0x4F, 0xF1, 0x90, 0x01, 0x57, 0x74, +0x05, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x04, 0xF0, 0x22, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, +0x01, 0x5F, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x08, 0xF0, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, +0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, 0xFB, 0xFD, 0x7F, 0x5C, 0x7E, 0x01, 0x12, 0x50, +0x05, 0x90, 0x01, 0x5F, 0x74, 0x05, 0xF0, 0x90, 0x06, 0x92, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24, +0xE0, 0x44, 0x10, 0xF0, 0x90, 0x81, 0x2A, 0xE0, 0x64, 0x0C, 0x60, 0x0C, 0xE4, 0xFD, 0x7F, 0x0C, +0x12, 0x47, 0x3D, 0xE4, 0xFF, 0x12, 0x4F, 0x0D, 0x22, 0xE4, 0x90, 0x81, 0x4C, 0xF0, 0x90, 0x06, +0xA9, 0xE0, 0x90, 0x81, 0x4C, 0xF0, 0xE0, 0x54, 0xC0, 0x70, 0x0D, 0x90, 0x81, 0x2B, 0xE0, 0x54, +0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x02, 0x47, 0x2A, 0x90, 0x81, 0x4C, 0xE0, 0x30, 0xE6, 0x21, 0x90, +0x81, 0x27, 0xE0, 0x64, 0x01, 0x70, 0x20, 0x90, 0x81, 0x2B, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81, +0x26, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x04, 0xB1, 0x4F, 0x80, 0x0B, 0xD1, 0x7F, 0x80, 0x07, +0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x81, 0x4C, 0xE0, 0x90, 0x81, 0x2B, 0x30, 0xE7, +0x11, 0x12, 0x4F, 0xF1, 0x90, 0x01, 0x57, 0x74, 0x05, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x44, 0x04, +0xF0, 0x22, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0xE4, 0xFE, 0xEF, 0xC3, 0x13, 0xFD, 0xEF, 0x30, 0xE0, +0x02, 0x7E, 0x80, 0x90, 0xFD, 0x10, 0xED, 0xF0, 0xAF, 0x06, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, +0xC0, 0xD0, 0x90, 0x04, 0x1D, 0xE0, 0x60, 0x1A, 0x90, 0x05, 0x22, 0xE0, 0x54, 0x90, 0x60, 0x07, +0x90, 0x01, 0xC0, 0xE0, 0x44, 0x08, 0xF0, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE1, 0xE4, 0x7F, 0x00, +0x80, 0x02, 0x7F, 0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81, 0x27, 0xE0, 0x60, 0x03, 0x12, +0x73, 0xE1, 0x90, 0x81, 0x3F, 0xE0, 0x30, 0xE0, 0x03, 0x12, 0x49, 0xDD, 0x22, 0x90, 0x81, 0x27, +0xE0, 0x60, 0x35, 0x90, 0x06, 0x92, 0xE0, 0x30, 0xE1, 0x24, 0xE4, 0xF5, 0x1D, 0x90, 0x81, 0x3A, +0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x1E, 0xE4, 0xFB, 0xFD, 0x7F, 0x5C, 0x7E, 0x01, 0x12, 0x50, +0x05, 0x90, 0x01, 0x5F, 0x74, 0x05, 0xF0, 0x90, 0x06, 0x92, 0x74, 0x02, 0xF0, 0x22, 0x90, 0x81, +0x24, 0xE0, 0x54, 0xEF, 0xF0, 0x12, 0x47, 0x2A, 0x22, 0x12, 0x71, 0x48, 0x90, 0x81, 0x4D, 0xEF, +0xF0, 0x90, 0x81, 0x24, 0x30, 0xE0, 0x06, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x04, 0xE0, 0x54, 0xFE, +0xF0, 0x90, 0x81, 0x4D, 0xE0, 0x30, 0xE6, 0x11, 0x90, 0x01, 0x2F, 0xE0, 0x30, 0xE7, 0x04, 0xE4, +0xF0, 0x80, 0x06, 0x90, 0x01, 0x2F, 0x74, 0x80, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0x30, 0xE0, 0x1A, +0x90, 0x81, 0x32, 0xE4, 0xF0, 0xA3, 0x74, 0x07, 0xF0, 0x90, 0x81, 0x32, 0xA3, 0xE0, 0x90, 0x05, +0x58, 0xF0, 0x90, 0x04, 0xEC, 0xE0, 0x54, 0xDD, 0xF0, 0x22, 0x90, 0x04, 0xEC, 0xE0, 0x44, 0x22, +0xF0, 0x22, 0x90, 0x81, 0x4A, 0xE0, 0x60, 0x0F, 0xE4, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x01, +0xF0, 0x90, 0x05, 0xFD, 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0xC4, 0x13, 0x13, +0x54, 0x03, 0x30, 0xE0, 0x27, 0xEF, 0x54, 0xBF, 0xF0, 0x90, 0x04, 0xE0, 0xE0, 0x90, 0x81, 0x25, +0x30, 0xE0, 0x06, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x10, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x01, 0xB9, +0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x12, 0x47, 0x2A, 0xE4, 0xFF, 0x90, 0x81, +0x45, 0xE0, 0x30, 0xE0, 0x48, 0x90, 0x81, 0x49, 0xE0, 0xFD, 0x60, 0x41, 0x74, 0x01, 0x7E, 0x00, +0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0x90, 0x04, 0xE0, +0xE0, 0xFB, 0xEF, 0x5B, 0x60, 0x06, 0xE4, 0x90, 0x81, 0x49, 0xF0, 0x22, 0x90, 0x81, 0x47, 0xE0, +0xD3, 0x9D, 0x50, 0x10, 0x90, 0x01, 0xC7, 0x74, 0x10, 0xF0, 0x11, 0xBE, 0x90, 0x81, 0x45, 0xE0, +0x54, 0xFE, 0xF0, 0x22, 0x12, 0x4F, 0x0B, 0x90, 0x81, 0x49, 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x80, +0x3C, 0xE0, 0x64, 0x02, 0x60, 0x07, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, 0x81, +0x24, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x2C, 0xEF, 0x54, 0x7F, 0xF0, +0x90, 0x04, 0xE0, 0xE0, 0x90, 0x81, 0x25, 0x30, 0xE1, 0x06, 0xE0, 0x44, 0x02, 0xF0, 0x80, 0x0F, +0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x04, 0xF0, 0x90, +0x81, 0x27, 0xE0, 0x60, 0x03, 0x12, 0x47, 0x2A, 0x7F, 0x01, 0x01, 0x6E, 0xC3, 0xEE, 0x94, 0x01, +0x40, 0x0A, 0x0D, 0xED, 0x13, 0x90, 0xFD, 0x10, 0xF0, 0xE4, 0x2F, 0xFF, 0x22, 0xC3, 0xEE, 0x94, +0x01, 0x40, 0x24, 0x90, 0xFD, 0x11, 0xE0, 0x6D, 0x70, 0x1A, 0x90, 0x01, 0x17, 0xE0, 0xB5, 0x05, +0x0D, 0x90, 0x01, 0xE4, 0x74, 0x77, 0xF0, 0x90, 0xFD, 0x11, 0xE4, 0xF0, 0x80, 0x06, 0xED, 0x04, +0x90, 0xFD, 0x11, 0xF0, 0xE4, 0x2F, 0xFF, 0x22, 0xE4, 0x90, 0x81, 0x4E, 0xF0, 0xA3, 0xF0, 0xA3, +0xF0, 0x90, 0x00, 0x83, 0xE0, 0x90, 0x81, 0x4E, 0xF0, 0x90, 0x00, 0x83, 0xE0, 0xFE, 0x90, 0x81, +0x4E, 0xE0, 0xFF, 0xB5, 0x06, 0x01, 0x22, 0xC3, 0x90, 0x81, 0x50, 0xE0, 0x94, 0x64, 0x90, 0x81, +0x4F, 0xE0, 0x94, 0x00, 0x40, 0x0D, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x4E, +0xE0, 0xFF, 0x22, 0x90, 0x81, 0x4F, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x44, 0xA9, 0x80, 0xC2, 0x74, +0x45, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, 0x82, 0xE4, +0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, +0x12, 0xED, 0xF0, 0x90, 0x82, 0x11, 0xEF, 0xF0, 0xD3, 0x94, 0x07, 0x50, 0x70, 0xE0, 0xFF, 0x74, +0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x47, 0xE0, +0x5F, 0xFD, 0x7F, 0x47, 0x12, 0x32, 0x1E, 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, +0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x46, 0xE0, 0x4F, 0xFD, 0x7F, 0x46, +0x12, 0x32, 0x1E, 0x90, 0x82, 0x12, 0xE0, 0x60, 0x18, 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, +0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x4F, 0x80, +0x17, 0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, +0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x5F, 0xFD, 0x7F, 0x45, 0x80, 0x7E, 0x90, 0x82, 0x11, +0xE0, 0x24, 0xF8, 0xF0, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, +0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x43, 0xE0, 0x5F, 0xFD, 0x7F, 0x43, 0x12, 0x32, 0x1E, +0x90, 0x82, 0x11, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, +0xFF, 0x90, 0x00, 0x43, 0xE0, 0x4F, 0xFD, 0x7F, 0x43, 0x12, 0x32, 0x1E, 0x90, 0x82, 0x12, 0xE0, +0x60, 0x1D, 0x90, 0x82, 0x11, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, +0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x42, 0xE0, 0x4F, 0xFD, 0x7F, 0x42, 0x80, 0x1C, 0x90, +0x82, 0x11, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, +0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x42, 0xE0, 0x5F, 0xFD, 0x7F, 0x42, 0x12, 0x32, 0x1E, 0xD0, 0xD0, +0x92, 0xAF, 0x22, 0x90, 0x81, 0x24, 0xE0, 0x54, 0xFB, 0xF0, 0xE4, 0x90, 0x81, 0x30, 0xF0, 0x90, +0x81, 0x2B, 0xF0, 0x22, 0xEF, 0x24, 0xFE, 0x60, 0x0C, 0x04, 0x70, 0x28, 0x90, 0x81, 0x2D, 0x74, +0x01, 0xF0, 0xA3, 0xF0, 0x22, 0xED, 0x70, 0x0A, 0x90, 0x81, 0x3B, 0xE0, 0x90, 0x81, 0x2D, 0xF0, +0x80, 0x05, 0x90, 0x81, 0x2D, 0xED, 0xF0, 0x90, 0x81, 0x2D, 0xE0, 0xA3, 0xF0, 0x90, 0x81, 0x25, +0xE0, 0x44, 0x08, 0xF0, 0x22, 0x12, 0x4E, 0xAB, 0xEF, 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, +0x74, 0x01, 0xF0, 0x80, 0x67, 0x90, 0x81, 0x2B, 0xE0, 0xFF, 0x54, 0x03, 0x60, 0x08, 0x90, 0x01, +0xB8, 0x74, 0x02, 0xF0, 0x80, 0x56, 0x90, 0x81, 0x29, 0xE0, 0xFE, 0xE4, 0xC3, 0x9E, 0x50, 0x08, +0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x44, 0xEF, 0x30, 0xE2, 0x08, 0x90, 0x01, 0xB8, 0x74, +0x08, 0xF0, 0x80, 0x38, 0x90, 0x81, 0x2B, 0xE0, 0x30, 0xE4, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x10, +0xF0, 0x80, 0x29, 0x90, 0x81, 0x25, 0xE0, 0x13, 0x13, 0x54, 0x3F, 0x20, 0xE0, 0x08, 0x90, 0x01, +0xB8, 0x74, 0x20, 0xF0, 0x80, 0x16, 0x90, 0x81, 0x3E, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, +0x80, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74, +0x04, 0xF0, 0x7F, 0x00, 0x22, 0xEF, 0x60, 0x42, 0x90, 0x80, 0xDE, 0xE0, 0x64, 0x01, 0x70, 0x3A, +0x90, 0x81, 0x25, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x05, 0x22, 0x74, 0x0F, 0xF0, 0x90, 0x06, 0x04, +0xE0, 0x54, 0xBF, 0xF0, 0xE4, 0xFF, 0x12, 0x4F, 0x0D, 0xBF, 0x01, 0x12, 0x90, 0x81, 0x24, 0xE0, +0x44, 0x40, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x06, 0xF0, 0x90, 0x81, 0x23, 0xF0, 0x22, 0x90, 0x01, +0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0x22, 0x90, 0x05, 0x22, 0x74, 0x6F, +0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x81, 0x2A, 0x74, 0x02, 0xF0, 0x90, 0x81, +0x23, 0xF0, 0x22, 0x12, 0x54, 0x65, 0x90, 0x81, 0x2A, 0x74, 0x0C, 0xF0, 0x90, 0x81, 0x23, 0xF0, +0x22, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x11, 0xEF, 0x54, 0xFB, +0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0x07, 0x70, 0x42, 0x80, 0x3D, 0x90, 0x81, +0x30, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x30, 0xE0, 0xFF, +0xB4, 0x01, 0x02, 0x80, 0x04, 0xEF, 0xB4, 0x02, 0x06, 0x90, 0x05, 0x58, 0xE0, 0x04, 0xF0, 0x90, +0x81, 0x38, 0xE0, 0xFF, 0x90, 0x81, 0x30, 0xE0, 0xD3, 0x9F, 0x40, 0x0F, 0x90, 0x80, 0xDE, 0xE0, +0xB4, 0x01, 0x0B, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x12, 0x47, 0x2A, 0x22, 0x22, +0x90, 0x05, 0x2B, 0xE0, 0x7F, 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0x22, 0x90, 0x05, 0x22, 0x74, +0xFF, 0xF0, 0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x03, 0xF0, 0x22, +0x90, 0x05, 0x27, 0xE0, 0x44, 0x40, 0xF0, 0x12, 0x49, 0xDD, 0x90, 0x81, 0x22, 0x74, 0x02, 0xF0, +0x22, 0x12, 0x49, 0xE3, 0x90, 0x81, 0x22, 0x74, 0x02, 0xF0, 0x22, 0x90, 0x05, 0x22, 0x74, 0x6F, +0xF0, 0x90, 0x05, 0x27, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x81, 0x22, 0x74, 0x04, 0xF0, 0x22, 0xAE, +0x07, 0x12, 0x51, 0x73, 0xBF, 0x01, 0x12, 0x90, 0x81, 0x23, 0xE0, 0x64, 0x02, 0x60, 0x0A, 0xAF, +0x06, 0x7D, 0x01, 0x12, 0x47, 0x3D, 0x7F, 0x01, 0x22, 0x7F, 0x00, 0x22, 0x90, 0x01, 0x57, 0xE0, +0x60, 0x48, 0xE4, 0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x24, 0xE0, 0xFF, 0x13, +0x13, 0x54, 0x3F, 0x30, 0xE0, 0x0C, 0xEF, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xFD, +0xF0, 0x22, 0x90, 0x81, 0x30, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x2B, 0xE0, 0x54, 0xEF, 0xF0, 0x90, +0x81, 0x38, 0xE0, 0xFF, 0x90, 0x81, 0x30, 0xE0, 0xD3, 0x9F, 0x40, 0x0E, 0x90, 0x80, 0xDE, 0xE0, +0xB4, 0x01, 0x07, 0x90, 0x81, 0x25, 0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x90, 0x80, 0x3F, 0xE0, 0xFF, +0x7D, 0x01, 0x12, 0x6D, 0x69, 0x8E, 0x54, 0x8F, 0x55, 0xAD, 0x55, 0xAC, 0x54, 0xAF, 0x53, 0x12, +0x4F, 0x82, 0xAF, 0x55, 0xAE, 0x54, 0x90, 0x04, 0x80, 0xE0, 0x54, 0x0F, 0xFD, 0xAC, 0x07, 0x74, +0x11, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x01, 0xF0, 0x74, 0x11, 0x2C, +0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xFB, 0xF0, 0xAC, 0x07, 0x74, 0x16, 0x2C, +0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0xFA, 0xF0, 0x74, 0x15, 0x2C, 0xF5, 0x82, +0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x1F, 0xF0, 0xAC, 0x07, 0x74, 0x06, 0x2C, 0xF5, 0x82, +0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x0F, 0xF0, 0x90, 0x04, 0x53, 0xE4, 0xF0, 0x90, 0x04, +0x52, 0xF0, 0x90, 0x04, 0x51, 0x74, 0xFF, 0xF0, 0x90, 0x04, 0x50, 0x74, 0xFD, 0xF0, 0x74, 0x14, +0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xC0, 0x4D, 0xFD, 0x74, 0x14, 0x2F, +0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xED, 0xF0, 0x22, 0xAB, 0x07, 0xAA, 0x06, 0xED, 0x2B, +0xFB, 0xE4, 0x3A, 0xFA, 0xC3, 0x90, 0x80, 0xDB, 0xE0, 0x9B, 0x90, 0x80, 0xDA, 0xE0, 0x9A, 0x50, +0x13, 0xA3, 0xE0, 0x24, 0x01, 0xFF, 0x90, 0x80, 0xDA, 0xE0, 0x34, 0x00, 0xFE, 0xC3, 0xEB, 0x9F, +0xFB, 0xEA, 0x9E, 0xFA, 0xEA, 0x90, 0xFD, 0x11, 0xF0, 0xAF, 0x03, 0x74, 0x00, 0x2F, 0xF5, 0x82, +0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x22, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, +0x81, 0x42, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x0A, 0x90, 0x00, 0x01, +0x12, 0x1F, 0xBD, 0x90, 0x81, 0x43, 0xF0, 0x22, 0x90, 0x81, 0x45, 0xE0, 0x30, 0xE0, 0x2D, 0x90, +0x81, 0x48, 0xE0, 0x04, 0xF0, 0xE0, 0xFF, 0x90, 0x81, 0x46, 0xE0, 0xB5, 0x07, 0x1E, 0x90, 0x06, +0x92, 0xE0, 0x54, 0x1C, 0x70, 0x0B, 0x12, 0x4F, 0x0B, 0x90, 0x81, 0x49, 0xE0, 0x04, 0xF0, 0x80, +0x06, 0x90, 0x06, 0x92, 0x74, 0x1C, 0xF0, 0xE4, 0x90, 0x81, 0x48, 0xF0, 0x22, 0x00, 0xBB, 0x8E, +}; +u4Byte ArrayLength_MP_8188E_FW_NIC_T = 13904; + + +void +ODM_ReadFirmware_MP_8188E_FW_NIC_T( + IN PDM_ODM_T pDM_Odm, + OUT u1Byte *pFirmware, + OUT u4Byte *pFirmwareSize +) +{ +#if(DM_ODM_SUPPORT_TYPE & (ODM_CE)) + *((SIZE_PTR *)pFirmware) = (SIZE_PTR)Array_MP_8188E_FW_NIC_T; +#else + ODM_MoveMemory(pDM_Odm, pFirmware, Array_MP_8188E_FW_NIC_T, ArrayLength_MP_8188E_FW_NIC_T); +#endif + *pFirmwareSize = ArrayLength_MP_8188E_FW_NIC_T; +} + + +u1Byte Array_MP_8188E_FW_WoWLAN_S[] = { +0xE2, 0x88, 0x30, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x22, 0x10, 0x14, 0x26, 0x43, 0x02, 0x00, +0xCD, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x02, 0x4E, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x02, 0x4F, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x02, 0x4F, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x57, 0xF3, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xE7, 0x09, 0xF6, 0x08, 0xDF, 0xFA, 0x80, 0x46, 0xE7, 0x09, 0xF2, 0x08, 0xDF, 0xFA, 0x80, 0x3E, +0x88, 0x82, 0x8C, 0x83, 0xE7, 0x09, 0xF0, 0xA3, 0xDF, 0xFA, 0x80, 0x32, 0xE3, 0x09, 0xF6, 0x08, +0xDF, 0xFA, 0x80, 0x78, 0xE3, 0x09, 0xF2, 0x08, 0xDF, 0xFA, 0x80, 0x70, 0x88, 0x82, 0x8C, 0x83, +0xE3, 0x09, 0xF0, 0xA3, 0xDF, 0xFA, 0x80, 0x64, 0x89, 0x82, 0x8A, 0x83, 0xE0, 0xA3, 0xF6, 0x08, +0xDF, 0xFA, 0x80, 0x58, 0x89, 0x82, 0x8A, 0x83, 0xE0, 0xA3, 0xF2, 0x08, 0xDF, 0xFA, 0x80, 0x4C, +0x80, 0xD2, 0x80, 0xFA, 0x80, 0xC6, 0x80, 0xD4, 0x80, 0x69, 0x80, 0xF2, 0x80, 0x33, 0x80, 0x10, +0x80, 0xA6, 0x80, 0xEA, 0x80, 0x9A, 0x80, 0xA8, 0x80, 0xDA, 0x80, 0xE2, 0x80, 0xCA, 0x80, 0x33, +0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE4, 0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, +0xCC, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xDF, 0xE9, 0xDE, 0xE7, 0x80, +0x0D, 0x89, 0x82, 0x8A, 0x83, 0xE4, 0x93, 0xA3, 0xF6, 0x08, 0xDF, 0xF9, 0xEC, 0xFA, 0xA9, 0xF0, +0xED, 0xFB, 0x22, 0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, +0xC5, 0x83, 0xCC, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xDF, 0xEA, 0xDE, +0xE8, 0x80, 0xDB, 0x89, 0x82, 0x8A, 0x83, 0xE4, 0x93, 0xA3, 0xF2, 0x08, 0xDF, 0xF9, 0x80, 0xCC, +0x88, 0xF0, 0xEF, 0x60, 0x01, 0x0E, 0x4E, 0x60, 0xC3, 0x88, 0xF0, 0xED, 0x24, 0x02, 0xB4, 0x04, +0x00, 0x50, 0xB9, 0xF5, 0x82, 0xEB, 0x24, 0x02, 0xB4, 0x04, 0x00, 0x50, 0xAF, 0x23, 0x23, 0x45, +0x82, 0x23, 0x90, 0x48, 0x50, 0x73, 0xBB, 0x01, 0x09, 0x89, 0x82, 0x8A, 0x83, 0xF8, 0xE0, 0x28, +0xF0, 0x22, 0x50, 0x03, 0x27, 0xF7, 0x22, 0xBB, 0xFE, 0x05, 0xF8, 0xE3, 0x28, 0xF3, 0x22, 0x8A, +0x83, 0x89, 0x82, 0xF8, 0xE4, 0x93, 0x28, 0x22, 0xBB, 0x01, 0x0F, 0xF8, 0xE5, 0x82, 0x29, 0xF5, +0x82, 0xE5, 0x83, 0x3A, 0xF5, 0x83, 0xE0, 0x28, 0xF0, 0x22, 0x50, 0x09, 0xC5, 0x82, 0x29, 0xF8, +0xE5, 0x82, 0x26, 0xF6, 0x22, 0xBB, 0xFE, 0x09, 0xC5, 0x82, 0x29, 0xF8, 0xE2, 0x25, 0x82, 0xF2, +0x22, 0xF8, 0xEA, 0x25, 0x83, 0xF5, 0x83, 0xE9, 0x93, 0x28, 0x22, 0xC5, 0xF0, 0xF8, 0xA3, 0xE0, +0x28, 0xF0, 0xC5, 0xF0, 0xF8, 0xE5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83, 0xE0, 0x38, 0xF0, +0x22, 0xEF, 0x4B, 0xFF, 0xEE, 0x4A, 0xFE, 0xED, 0x49, 0xFD, 0xEC, 0x48, 0xFC, 0x22, 0xE0, 0xFC, +0xA3, 0xE0, 0xFD, 0xA3, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x22, 0xA4, 0x25, 0x82, 0xF5, 0x82, 0xE5, +0xF0, 0x35, 0x83, 0xF5, 0x83, 0x22, 0xE0, 0xFB, 0xA3, 0xE0, 0xFA, 0xA3, 0xE0, 0xF9, 0x22, 0xEB, +0xF0, 0xA3, 0xEA, 0xF0, 0xA3, 0xE9, 0xF0, 0x22, 0xBB, 0x01, 0x1A, 0x89, 0x82, 0x8A, 0x83, 0xD0, +0xF0, 0xD0, 0xE0, 0xF8, 0xD0, 0xE0, 0xF9, 0xD0, 0xE0, 0xFA, 0xD0, 0xE0, 0xFB, 0xE8, 0xC0, 0xE0, +0xC0, 0xF0, 0x02, 0x49, 0x8F, 0x50, 0x16, 0xE9, 0xF8, 0xD0, 0x83, 0xD0, 0x82, 0xD0, 0xE0, 0xF9, +0xD0, 0xE0, 0xFA, 0xD0, 0xE0, 0xFB, 0xC0, 0x82, 0xC0, 0x83, 0x02, 0x4C, 0x3C, 0xBB, 0xFE, 0x16, +0xE9, 0xF8, 0xD0, 0x83, 0xD0, 0x82, 0xD0, 0xE0, 0xF9, 0xD0, 0xE0, 0xFA, 0xD0, 0xE0, 0xFB, 0xC0, +0x82, 0xC0, 0x83, 0x02, 0x4C, 0x45, 0x22, 0xBB, 0x01, 0x20, 0xE5, 0x82, 0x29, 0xF5, 0x82, 0xE5, +0x83, 0x3A, 0xF5, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0xF8, 0xD0, 0xE0, 0xF9, 0xD0, 0xE0, 0xFA, 0xD0, +0xE0, 0xFB, 0xE8, 0xC0, 0xE0, 0xC0, 0xF0, 0x02, 0x49, 0x8F, 0x50, 0x18, 0xE9, 0x25, 0x82, 0xF8, +0xD0, 0x83, 0xD0, 0x82, 0xD0, 0xE0, 0xF9, 0xD0, 0xE0, 0xFA, 0xD0, 0xE0, 0xFB, 0xC0, 0x82, 0xC0, +0x83, 0x02, 0x4C, 0x3C, 0xBB, 0xFE, 0x18, 0xE9, 0x25, 0x82, 0xF8, 0xD0, 0x83, 0xD0, 0x82, 0xD0, +0xE0, 0xF9, 0xD0, 0xE0, 0xFA, 0xD0, 0xE0, 0xFB, 0xC0, 0x82, 0xC0, 0x83, 0x02, 0x4C, 0x45, 0x22, +0xD0, 0x83, 0xD0, 0x82, 0xF8, 0xE4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0D, 0xA3, 0xA3, +0x93, 0xF8, 0x74, 0x01, 0x93, 0xF5, 0x82, 0x88, 0x83, 0xE4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, +0xEF, 0xA3, 0xA3, 0xA3, 0x80, 0xDF, 0xE3, 0xF5, 0xF0, 0x09, 0xE2, 0x08, 0xB5, 0xF0, 0x6B, 0xDF, +0xF5, 0x80, 0x67, 0xE3, 0xF5, 0xF0, 0x09, 0xE6, 0x08, 0xB5, 0xF0, 0x5E, 0xDF, 0xF5, 0x80, 0x5A, +0x87, 0xF0, 0x09, 0xE6, 0x08, 0xB5, 0xF0, 0x52, 0xDF, 0xF6, 0x80, 0x4E, 0x87, 0xF0, 0x09, 0xE2, +0x08, 0xB5, 0xF0, 0x46, 0xDF, 0xF6, 0x80, 0x42, 0x88, 0x82, 0x8C, 0x83, 0x87, 0xF0, 0x09, 0xE0, +0xA3, 0xB5, 0xF0, 0x36, 0xDF, 0xF6, 0x80, 0x32, 0x88, 0x82, 0x8C, 0x83, 0x87, 0xF0, 0x09, 0xE4, +0x93, 0xA3, 0xB5, 0xF0, 0x25, 0xDF, 0xF5, 0x80, 0x21, 0x88, 0x82, 0x8C, 0x83, 0xE3, 0xF5, 0xF0, +0x09, 0xE0, 0xA3, 0xB5, 0xF0, 0x14, 0xDF, 0xF5, 0x80, 0x10, 0x88, 0x82, 0x8C, 0x83, 0xE3, 0xF5, +0xF0, 0x09, 0xE4, 0x93, 0xA3, 0xB5, 0xF0, 0x02, 0xDF, 0xF4, 0x02, 0x4B, 0x95, 0x80, 0x87, 0x80, +0xE9, 0x80, 0x90, 0x80, 0xD4, 0x80, 0x3E, 0x80, 0x15, 0x80, 0x6E, 0x80, 0x7E, 0x80, 0x9D, 0x80, +0xB7, 0x80, 0x8D, 0x80, 0xA3, 0x80, 0x51, 0x80, 0x74, 0x80, 0x3C, 0x02, 0x4B, 0xA1, 0x89, 0x82, +0x8A, 0x83, 0xEC, 0xFA, 0xE4, 0x93, 0xF5, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, +0xCC, 0xE4, 0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xB5, 0xF0, 0x76, 0xDF, +0xE3, 0xDE, 0xE1, 0x80, 0x70, 0x89, 0x82, 0x8A, 0x83, 0xE4, 0x93, 0xF5, 0xF0, 0xA3, 0xE2, 0x08, +0xB5, 0xF0, 0x62, 0xDF, 0xF4, 0x80, 0x5E, 0x89, 0x82, 0x8A, 0x83, 0xE0, 0xF5, 0xF0, 0xA3, 0xE6, +0x08, 0xB5, 0xF0, 0x51, 0xDF, 0xF5, 0x80, 0x4D, 0x89, 0x82, 0x8A, 0x83, 0xE0, 0xF5, 0xF0, 0xA3, +0xE2, 0x08, 0xB5, 0xF0, 0x40, 0xDF, 0xF5, 0x80, 0x3C, 0x89, 0x82, 0x8A, 0x83, 0xE4, 0x93, 0xF5, +0xF0, 0xA3, 0xE6, 0x08, 0xB5, 0xF0, 0x2E, 0xDF, 0xF4, 0x80, 0x2A, 0x80, 0x02, 0x80, 0x57, 0x89, +0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE4, 0x93, 0xF5, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, +0x83, 0xCC, 0xE0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xB5, 0xF0, 0x06, 0xDF, +0xE4, 0xDE, 0xE2, 0x80, 0x00, 0x7F, 0xFF, 0xB5, 0xF0, 0x02, 0x0F, 0x22, 0x40, 0x02, 0x7F, 0x01, +0x22, 0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE0, 0xF5, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, +0xC5, 0x83, 0xCC, 0xE0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xB5, 0xF0, 0xD5, +0xDF, 0xE5, 0xDE, 0xE3, 0x80, 0xCF, 0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE0, 0xF5, 0xF0, 0xA3, +0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xE4, 0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, +0xC5, 0x83, 0xCC, 0xB5, 0xF0, 0xAF, 0xDF, 0xE4, 0xDE, 0xE2, 0x80, 0xA9, 0x88, 0xF0, 0xEF, 0x60, +0x01, 0x0E, 0x4E, 0x60, 0xAB, 0xED, 0x24, 0x02, 0xB4, 0x04, 0x00, 0x50, 0x98, 0xF5, 0x82, 0xEB, +0x24, 0x02, 0xB4, 0x04, 0x00, 0x50, 0x8E, 0x23, 0x23, 0x45, 0x82, 0x23, 0x90, 0x4A, 0xDD, 0x73, +0xEF, 0x4E, 0x60, 0x12, 0xEF, 0x60, 0x01, 0x0E, 0xED, 0xBB, 0x01, 0x0B, 0x89, 0x82, 0x8A, 0x83, +0xF0, 0xA3, 0xDF, 0xFC, 0xDE, 0xFA, 0x22, 0x89, 0xF0, 0x50, 0x07, 0xF7, 0x09, 0xDF, 0xFC, 0xA9, +0xF0, 0x22, 0xBB, 0xFE, 0xFC, 0xF3, 0x09, 0xDF, 0xFC, 0xA9, 0xF0, 0x22, 0xEB, 0xF6, 0x08, 0xEA, +0xF6, 0x08, 0xE9, 0xF6, 0x22, 0xEB, 0xF2, 0x08, 0xEA, 0xF2, 0x08, 0xE9, 0xF2, 0x22, 0xC2, 0xAF, +0x80, 0xFE, 0x32, 0x12, 0x4C, 0x52, 0x85, 0xD0, 0x0B, 0x75, 0xD0, 0x08, 0xAA, 0xE0, 0xC2, 0x8C, +0xE5, 0x8A, 0x24, 0x67, 0xF5, 0x8A, 0xE5, 0x8C, 0x34, 0x79, 0xF5, 0x8C, 0xD2, 0x8C, 0xEC, 0x24, +0x8B, 0xF8, 0xE6, 0xBC, 0x04, 0x02, 0x74, 0xFF, 0xC3, 0x95, 0x81, 0xB4, 0x40, 0x00, 0x40, 0xCE, +0x79, 0x05, 0x78, 0x80, 0x16, 0xE6, 0x08, 0x70, 0x0B, 0xC2, 0xAF, 0xE6, 0x30, 0xE1, 0x03, 0x44, +0x18, 0xF6, 0xD2, 0xAF, 0x08, 0xD9, 0xED, 0xEA, 0x8B, 0xD0, 0x22, 0xE5, 0x0C, 0xFF, 0x23, 0x24, +0x81, 0xF8, 0x0F, 0x08, 0x08, 0xBF, 0x05, 0x04, 0x7F, 0x00, 0x78, 0x81, 0xE6, 0x30, 0xE4, 0xF2, +0x00, 0xE5, 0x0C, 0xC3, 0x9F, 0x50, 0x20, 0x05, 0x0C, 0x74, 0x8A, 0x25, 0x0C, 0xF8, 0xE6, 0xFD, +0xA6, 0x81, 0x08, 0xE6, 0xAE, 0x0C, 0xBE, 0x04, 0x02, 0x74, 0xFF, 0xCD, 0xF8, 0xE8, 0x6D, 0x60, +0xE0, 0x08, 0xE6, 0xC0, 0xE0, 0x80, 0xF6, 0xE5, 0x0C, 0xD3, 0x9F, 0x40, 0x27, 0xE5, 0x0C, 0x24, +0x8B, 0xF8, 0xE6, 0xAE, 0x0C, 0xBE, 0x04, 0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xCD, 0xF8, 0xE5, +0x81, 0x6D, 0x60, 0x06, 0xD0, 0xE0, 0xF6, 0x18, 0x80, 0xF5, 0xE5, 0x0C, 0x24, 0x8A, 0xC8, 0xF6, +0x15, 0x0C, 0x80, 0xD3, 0xE5, 0x0C, 0x23, 0x24, 0x81, 0xF8, 0x7F, 0x04, 0xC2, 0xAF, 0xE6, 0x30, +0xE0, 0x03, 0x10, 0xE2, 0x0C, 0x7F, 0x00, 0x30, 0xE1, 0x07, 0x30, 0xE3, 0x04, 0x7F, 0x08, 0x54, +0xF4, 0x54, 0x7C, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x42, 0x07, 0x22, 0x78, 0x8A, 0xA6, 0x81, 0x74, +0x04, 0x60, 0x06, 0xFF, 0x08, 0x76, 0xFF, 0xDF, 0xFB, 0x7F, 0x05, 0xE4, 0x78, 0x80, 0xF6, 0x08, +0xF6, 0x08, 0xDF, 0xFA, 0x78, 0x81, 0x76, 0x30, 0x90, 0x4F, 0xA3, 0x74, 0x01, 0x93, 0xC0, 0xE0, +0xE4, 0x93, 0xC0, 0xE0, 0x43, 0x89, 0x01, 0x75, 0x8A, 0x60, 0x75, 0x8C, 0x79, 0xD2, 0x8C, 0xD2, +0xAF, 0x22, 0x04, 0xEF, 0xD3, 0x94, 0x04, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0x74, 0x81, 0x2F, 0x2F, +0xF8, 0xE6, 0x20, 0xE5, 0xF4, 0xC2, 0xAF, 0xE6, 0x44, 0x30, 0xF6, 0xD2, 0xAF, 0xAE, 0x0C, 0xEE, +0xC3, 0x9F, 0x50, 0x21, 0x0E, 0x74, 0x8A, 0x2E, 0xF8, 0xE6, 0xF9, 0x08, 0xE6, 0x18, 0xBE, 0x04, +0x02, 0x74, 0xFF, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x09, 0xE7, 0x19, 0x19, 0xF7, 0x09, 0x09, 0x80, +0xF3, 0x16, 0x16, 0x80, 0xDA, 0xEE, 0xD3, 0x9F, 0x40, 0x04, 0x05, 0x81, 0x05, 0x81, 0xEE, 0xD3, +0x9F, 0x40, 0x22, 0x74, 0x8A, 0x2E, 0xF8, 0x08, 0xE6, 0xF9, 0xEE, 0xB5, 0x0C, 0x02, 0xA9, 0x81, +0x18, 0x06, 0x06, 0xE6, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x19, 0x19, 0xE7, 0x09, 0x09, 0xF7, 0x19, +0x80, 0xF3, 0x1E, 0x80, 0xD9, 0xEF, 0x24, 0x8A, 0xF8, 0xE6, 0x04, 0xF8, 0xEF, 0x2F, 0x04, 0x90, +0x4F, 0xA3, 0x93, 0xF6, 0x08, 0xEF, 0x2F, 0x93, 0xF6, 0x7F, 0x00, 0x22, 0xEF, 0xD3, 0x94, 0x04, +0x40, 0x03, 0x7F, 0xFF, 0x22, 0xEF, 0x23, 0x24, 0x81, 0xF8, 0xE6, 0x30, 0xE5, 0xF4, 0xC2, 0xAF, +0xE6, 0x54, 0x8C, 0xF6, 0xD2, 0xAF, 0xE5, 0x0C, 0xB5, 0x07, 0x0A, 0x74, 0x8A, 0x2F, 0xF8, 0xE6, +0xF5, 0x81, 0x02, 0x4C, 0x9B, 0x50, 0x2E, 0x74, 0x8B, 0x2F, 0xF8, 0xE6, 0xBF, 0x04, 0x02, 0x74, +0xFF, 0xFD, 0x18, 0xE6, 0xF9, 0x74, 0x8A, 0x2F, 0xF8, 0xFB, 0xE6, 0xFC, 0xE9, 0x6C, 0x60, 0x08, +0xA8, 0x05, 0xE7, 0xF6, 0x1D, 0x19, 0x80, 0xF4, 0xA8, 0x03, 0xA6, 0x05, 0x1F, 0xE5, 0x0C, 0xB5, +0x07, 0xE3, 0x7F, 0x00, 0x22, 0x74, 0x8B, 0x2F, 0xF8, 0xE6, 0xFD, 0x18, 0x86, 0x01, 0x0F, 0x74, +0x8A, 0x2F, 0xF8, 0xA6, 0x01, 0x08, 0x86, 0x04, 0xE5, 0x0C, 0xB5, 0x07, 0x02, 0xAC, 0x81, 0xED, +0x6C, 0x60, 0x08, 0x0D, 0x09, 0xA8, 0x05, 0xE6, 0xF7, 0x80, 0xF4, 0xE5, 0x0C, 0xB5, 0x07, 0xDE, +0x89, 0x81, 0x7F, 0x00, 0x22, 0xEF, 0xD3, 0x94, 0x04, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0xEF, 0x23, +0x24, 0x81, 0xF8, 0xC2, 0xAF, 0xE6, 0x30, 0xE5, 0x05, 0x30, 0xE0, 0x02, 0xD2, 0xE4, 0xD2, 0xE2, +0xC6, 0xD2, 0xAF, 0x7F, 0x00, 0x30, 0xE2, 0x01, 0x0F, 0x02, 0x4C, 0x9A, 0x8F, 0xF0, 0xE4, 0xFF, +0xFE, 0xE5, 0x0C, 0x23, 0x24, 0x80, 0xF8, 0xC2, 0xA9, 0x30, 0xF7, 0x0D, 0x7F, 0x08, 0xE6, 0x60, +0x0B, 0x2D, 0xF6, 0x60, 0x30, 0x50, 0x2E, 0x80, 0x07, 0x30, 0xF1, 0x06, 0xED, 0xF6, 0x60, 0x25, +0x7E, 0x02, 0x08, 0x30, 0xF0, 0x10, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x23, 0x0E, 0x30, 0xE2, 0x0C, +0xD2, 0xAF, 0x7F, 0x04, 0x80, 0x12, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, 0x13, 0x54, 0xEC, 0x4E, 0xF6, +0xD2, 0xAF, 0x02, 0x4C, 0x9B, 0x7F, 0x08, 0x08, 0xEF, 0x44, 0x83, 0xF4, 0xC2, 0xAF, 0x56, 0xC6, +0xD2, 0xAF, 0x54, 0x80, 0x4F, 0xFF, 0x22, 0x02, 0x4F, 0x35, 0x02, 0x4D, 0x2B, 0xE4, 0x93, 0xA3, +0xF8, 0xE4, 0x93, 0xA3, 0x40, 0x03, 0xF6, 0x80, 0x01, 0xF2, 0x08, 0xDF, 0xF4, 0x80, 0x29, 0xE4, +0x93, 0xA3, 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, 0x33, 0xC4, 0x54, 0x0F, 0x44, 0x20, 0xC8, +0x83, 0x40, 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, 0xDF, 0xE4, 0x80, 0x0B, 0x01, 0x02, 0x04, +0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x4F, 0x7A, 0xE4, 0x7E, 0x01, 0x93, 0x60, 0xBC, 0xA3, 0xFF, +0x54, 0x3F, 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, 0x93, 0xA3, 0x60, 0x01, 0x0E, 0xCF, 0x54, +0xC0, 0x25, 0xE0, 0x60, 0xA8, 0x40, 0xB8, 0xE4, 0x93, 0xA3, 0xFA, 0xE4, 0x93, 0xA3, 0xF8, 0xE4, +0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83, 0xCA, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, +0xCA, 0xC5, 0x83, 0xCA, 0xDF, 0xE9, 0xDE, 0xE7, 0x80, 0xBE, 0x00, 0x41, 0x83, 0xA7, 0x00, 0x41, +0x83, 0xA8, 0x00, 0x41, 0x83, 0xB3, 0x00, 0x44, 0x83, 0x4F, 0x00, 0x50, 0xF2, 0x01, 0x44, 0x83, +0x53, 0x00, 0x0F, 0xAC, 0x01, 0x44, 0x83, 0x57, 0x00, 0x0F, 0xAC, 0x03, 0x44, 0x83, 0x5B, 0x00, +0x0F, 0xAC, 0x04, 0x59, 0x92, 0x60, 0xED, 0x61, 0x0B, 0x62, 0x4F, 0x63, 0x74, 0xC0, 0xE0, 0xC0, +0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, +0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xAD, 0xF0, +0x74, 0x4F, 0xA3, 0xF0, 0x12, 0x6C, 0x7D, 0x74, 0xAD, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x4F, +0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, +0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0xC0, 0xE0, 0xC0, +0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, +0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xFD, 0xF0, +0x74, 0x4F, 0xA3, 0xF0, 0x12, 0x6C, 0xB7, 0xE5, 0x41, 0x30, 0xE3, 0x02, 0xF1, 0xE6, 0xE5, 0x41, +0x30, 0xE4, 0x05, 0x7F, 0x02, 0x12, 0x4E, 0x75, 0xE5, 0x43, 0x30, 0xE1, 0x02, 0x11, 0x65, 0x74, +0xFD, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x4F, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, +0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, +0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x51, 0x2B, 0x90, 0x81, 0xFB, 0xE0, 0x30, 0xE0, 0x2D, 0x90, 0x80, +0xA3, 0xE0, 0xB4, 0x01, 0x26, 0x90, 0x83, 0xB3, 0xE0, 0x04, 0xF0, 0xE0, 0xB4, 0x0A, 0x0B, 0x90, +0x81, 0xFD, 0xE0, 0x04, 0xF0, 0xE4, 0x90, 0x83, 0xB3, 0xF0, 0x90, 0x81, 0xFD, 0xE0, 0xFF, 0x90, +0x81, 0xFC, 0xE0, 0xB5, 0x07, 0x05, 0xE4, 0xA3, 0xF0, 0x11, 0x9C, 0x22, 0xE4, 0xFF, 0xD3, 0x10, +0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x8F, 0x4E, 0x90, 0x04, 0x1D, 0xE0, 0x60, 0x19, 0x90, 0x05, 0x22, +0xE0, 0xF5, 0x51, 0x74, 0xFF, 0xF0, 0x12, 0x6F, 0x85, 0xBF, 0x01, 0x02, 0x31, 0x20, 0x90, 0x05, +0x22, 0xE5, 0x51, 0xF0, 0x80, 0x02, 0x31, 0x20, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0x7F, 0x01, +0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, +0x54, 0x3F, 0xF0, 0xEF, 0x60, 0x1D, 0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, +0xE0, 0x44, 0x10, 0xF0, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, +0x80, 0xF0, 0x22, 0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xEF, +0xF0, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x40, 0xF0, 0x22, +0x90, 0x80, 0x04, 0xE0, 0xFF, 0x7D, 0x01, 0x31, 0xC1, 0x8E, 0x4F, 0x8F, 0x50, 0xAD, 0x50, 0xAC, +0x4F, 0xAF, 0x4E, 0x11, 0xD5, 0xAF, 0x50, 0xAE, 0x4F, 0x90, 0x04, 0x80, 0xE0, 0x54, 0x0F, 0xFD, +0xAC, 0x07, 0x74, 0x11, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x01, 0xF0, +0x74, 0x11, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xFB, 0xF0, 0xAC, 0x07, +0x74, 0x16, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0xFA, 0xF0, 0x74, 0x15, +0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x1F, 0xF0, 0xAC, 0x07, 0x74, 0x06, +0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x0F, 0xF0, 0x90, 0x04, 0x53, 0xE4, +0xF0, 0x90, 0x04, 0x52, 0xF0, 0x90, 0x04, 0x51, 0x74, 0xFF, 0xF0, 0x90, 0x04, 0x50, 0x74, 0xFD, +0xF0, 0x74, 0x14, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xC0, 0x4D, 0xFD, +0x74, 0x14, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xED, 0xF0, 0x22, 0xE0, 0xFF, 0x7D, +0x01, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x83, 0xAA, 0xED, 0xF0, 0x90, 0x83, 0xA9, +0xEF, 0xF0, 0xE4, 0xFD, 0xFC, 0x12, 0x5D, 0x8E, 0x7C, 0x00, 0xAD, 0x07, 0x90, 0x83, 0xA9, 0xE0, +0x90, 0x04, 0x25, 0xF0, 0x90, 0x83, 0xAA, 0xE0, 0x60, 0x0E, 0x74, 0x0F, 0x2F, 0xF5, 0x82, 0xE4, +0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0xAF, 0x05, 0x74, 0x08, 0x2F, 0xF5, 0x82, 0xE4, +0x34, 0xFC, 0xF5, 0x83, 0xE4, 0xF0, 0x74, 0x09, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, +0xE0, 0x54, 0xF0, 0xF0, 0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, +0xF7, 0xF0, 0xAE, 0x04, 0xAF, 0x05, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81, 0xFE, 0xE0, 0x30, +0xE0, 0x2C, 0x90, 0x82, 0x01, 0xE0, 0x04, 0xF0, 0xE0, 0xFF, 0x90, 0x81, 0xFF, 0xE0, 0xB5, 0x07, +0x1D, 0x90, 0x06, 0x92, 0xE0, 0x54, 0x1C, 0x70, 0x0A, 0x11, 0x9C, 0x90, 0x82, 0x02, 0xE0, 0x04, +0xF0, 0x80, 0x06, 0x90, 0x06, 0x92, 0x74, 0x1C, 0xF0, 0xE4, 0x90, 0x82, 0x01, 0xF0, 0x22, 0x90, +0x81, 0xFE, 0xE0, 0x30, 0xE0, 0x47, 0x90, 0x82, 0x02, 0xE0, 0xFD, 0x60, 0x40, 0x74, 0x01, 0x7E, +0x00, 0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0x90, 0x04, +0xE0, 0xE0, 0xFB, 0xEF, 0x5B, 0x60, 0x06, 0xE4, 0x90, 0x82, 0x02, 0xF0, 0x22, 0x90, 0x82, 0x00, +0xE0, 0xD3, 0x9D, 0x50, 0x10, 0x90, 0x01, 0xC7, 0x74, 0x10, 0xF0, 0x51, 0xAE, 0x90, 0x81, 0xFE, +0xE0, 0x54, 0xFE, 0xF0, 0x22, 0x11, 0x9C, 0x90, 0x82, 0x02, 0xE0, 0x04, 0xF0, 0x22, 0x90, 0x80, +0x01, 0xE0, 0x64, 0x02, 0x70, 0x4B, 0x90, 0x80, 0xE6, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, +0x01, 0x30, 0xE0, 0x08, 0x90, 0x01, 0x4D, 0xE0, 0x64, 0x80, 0xF0, 0x22, 0x90, 0x80, 0xE5, 0xE0, +0xFE, 0xC4, 0x13, 0x54, 0x07, 0x30, 0xE0, 0x13, 0xEF, 0x54, 0x7F, 0xFF, 0xE4, 0xFD, 0xD1, 0xD0, +0x90, 0x80, 0xE6, 0xE0, 0x54, 0x7F, 0xFF, 0x7D, 0x01, 0x80, 0x14, 0x90, 0x80, 0xE6, 0xE0, 0x54, +0x7F, 0xFF, 0x7D, 0x01, 0xD1, 0xD0, 0x90, 0x80, 0xE6, 0xE0, 0x54, 0x7F, 0xFF, 0xE4, 0xFD, 0xC1, +0xD0, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, +0x90, 0x82, 0x37, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0xE4, 0x90, 0x82, 0x42, 0xF0, +0xA3, 0x74, 0x08, 0xF0, 0xA3, 0xF0, 0x90, 0x06, 0x31, 0xE0, 0x54, 0xEF, 0x44, 0x08, 0xF0, 0x90, +0x82, 0x37, 0xA3, 0xE0, 0x24, 0x00, 0xF9, 0xE4, 0x34, 0xFB, 0xFA, 0x7B, 0x01, 0x12, 0x5D, 0xF8, +0x90, 0x82, 0x37, 0xA3, 0xE0, 0x2F, 0xFF, 0x90, 0x82, 0x44, 0xE0, 0x2F, 0x90, 0x82, 0x46, 0xF0, +0x7E, 0x00, 0x7F, 0x83, 0x7D, 0x00, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x55, 0x12, 0x4C, 0x10, 0x90, +0x82, 0x46, 0xE0, 0x24, 0x00, 0xF9, 0xE4, 0x34, 0xFB, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, +0x75, 0x16, 0x01, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x55, 0x12, 0x2B, 0xED, 0x90, 0x82, 0x46, 0xE0, +0x24, 0x01, 0xF9, 0xE4, 0x34, 0xFB, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x01, +0x7B, 0x01, 0x7A, 0x81, 0x79, 0x56, 0x12, 0x2B, 0xED, 0x90, 0x82, 0x46, 0xE0, 0x24, 0x02, 0xF9, +0xE4, 0x34, 0xFB, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x02, 0x7B, 0x01, 0x7A, +0x81, 0x79, 0x57, 0x12, 0x2B, 0xED, 0x90, 0x82, 0x46, 0xE0, 0x24, 0x04, 0xF9, 0xE4, 0x34, 0xFB, +0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x01, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x59, +0x12, 0x2B, 0xED, 0x90, 0x82, 0x46, 0xE0, 0x24, 0x05, 0xF9, 0xE4, 0x34, 0xFB, 0x75, 0x13, 0x01, +0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x02, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x5A, 0x12, 0x2B, 0xED, +0x90, 0x82, 0x46, 0xE0, 0x24, 0x07, 0xF9, 0xE4, 0x34, 0xFB, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, +0x15, 0x75, 0x16, 0x02, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x5C, 0x12, 0x2B, 0xED, 0xE4, 0x90, 0x82, +0x45, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0xFF, 0xC3, 0x94, 0x08, 0x50, 0x32, 0xA3, 0xE0, 0x24, 0x09, +0xD1, 0x9A, 0x7E, 0x00, 0x90, 0x82, 0x40, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x24, 0x00, 0xF5, 0x82, +0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x90, 0x82, 0x45, 0xE0, 0x24, 0x5E, 0xF5, 0x82, 0xE4, +0x34, 0x81, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0x04, 0xF0, 0x80, 0xC4, 0xE4, 0x90, +0x82, 0x45, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0xFF, 0xC3, 0x94, 0x20, 0x50, 0x32, 0xA3, 0xE0, 0x24, +0x11, 0xD1, 0x9A, 0x7E, 0x00, 0x90, 0x82, 0x40, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x24, 0x00, 0xF5, +0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x90, 0x82, 0x45, 0xE0, 0x24, 0x66, 0xF5, 0x82, +0xE4, 0x34, 0x81, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0x04, 0xF0, 0x80, 0xC4, 0xE4, +0x90, 0x82, 0x45, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0xFF, 0xC3, 0x94, 0x10, 0x50, 0x32, 0xA3, 0xE0, +0x24, 0x31, 0xD1, 0x9A, 0x7E, 0x00, 0x90, 0x82, 0x40, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x24, 0x00, +0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x90, 0x82, 0x45, 0xE0, 0x24, 0x86, 0xF5, +0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0x04, 0xF0, 0x80, 0xC4, +0xE4, 0x90, 0x82, 0x45, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0xFF, 0xC3, 0x94, 0x08, 0x50, 0x32, 0xA3, +0xE0, 0x24, 0x41, 0xD1, 0x9A, 0x7E, 0x00, 0x90, 0x82, 0x40, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x24, +0x00, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x90, 0x82, 0x45, 0xE0, 0x24, 0x96, +0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0x04, 0xF0, 0x80, +0xC4, 0xE4, 0x90, 0x82, 0x45, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0xFF, 0xC3, 0x94, 0x08, 0x50, 0x32, +0xA3, 0xE0, 0x24, 0x49, 0xD1, 0x9A, 0x7E, 0x00, 0x90, 0x82, 0x40, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, +0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x90, 0x82, 0x45, 0xE0, 0x24, +0x9E, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0x04, 0xF0, +0x80, 0xC4, 0xE4, 0x90, 0x82, 0x45, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0xFF, 0xC3, 0x94, 0x10, 0x50, +0x32, 0xA3, 0xE0, 0x24, 0x51, 0xD1, 0x9A, 0x7E, 0x00, 0x90, 0x82, 0x40, 0xEE, 0xF0, 0xA3, 0xEF, +0xF0, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x90, 0x82, 0x45, 0xE0, +0x24, 0xA6, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0x04, +0xF0, 0x80, 0xC4, 0xE4, 0x90, 0x82, 0x45, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0xFF, 0xC3, 0x94, 0x02, +0x50, 0x32, 0xA3, 0xE0, 0x24, 0x61, 0xD1, 0x9A, 0x7E, 0x00, 0x90, 0x82, 0x40, 0xEE, 0xF0, 0xA3, +0xEF, 0xF0, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x90, 0x82, 0x45, +0xE0, 0x24, 0xB6, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x82, 0x45, 0xE0, +0x04, 0xF0, 0x80, 0xC4, 0xE4, 0x90, 0x82, 0x45, 0xF0, 0x90, 0x82, 0x45, 0xE0, 0xFF, 0xC3, 0x94, +0x20, 0x50, 0x32, 0xA3, 0xE0, 0x24, 0x63, 0xD1, 0x9A, 0x7E, 0x00, 0x90, 0x82, 0x40, 0xEE, 0xF0, +0xA3, 0xEF, 0xF0, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x90, 0x82, +0x45, 0xE0, 0x24, 0xB8, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x82, 0x45, +0xE0, 0x04, 0xF0, 0x80, 0xC4, 0x90, 0x81, 0x57, 0xE0, 0xFC, 0xA3, 0xE0, 0xFA, 0xEC, 0xFF, 0xEA, +0xFE, 0x90, 0x82, 0x3C, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x81, 0xB6, 0xE0, 0xFE, 0xA3, 0xE0, +0xFD, 0xED, 0xFF, 0x90, 0x82, 0x3E, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x81, 0x5A, 0xE0, 0xFE, +0xA3, 0xE0, 0xFD, 0xED, 0xFF, 0x90, 0x82, 0x3A, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x30, 0xE3, 0x04, +0x51, 0xAE, 0x80, 0x3F, 0x90, 0x82, 0x3A, 0xA3, 0xE0, 0xFF, 0x7C, 0x00, 0x54, 0x07, 0xFD, 0x64, +0x01, 0x60, 0x05, 0xED, 0x64, 0x02, 0x70, 0x2B, 0xED, 0x64, 0x02, 0x4C, 0x70, 0x25, 0xEF, 0x54, +0x30, 0xFF, 0xE4, 0xC4, 0xF8, 0x54, 0xF0, 0xC8, 0xEF, 0xC4, 0x54, 0x0F, 0x48, 0x90, 0x81, 0xEE, +0xF0, 0xAE, 0x04, 0xAF, 0x05, 0xE4, 0xFD, 0x12, 0x77, 0xFE, 0x90, 0x06, 0x31, 0xE0, 0x54, 0xF7, +0x44, 0x10, 0xF0, 0x7F, 0x00, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xFD, 0xE4, 0x33, 0xFC, 0x7E, 0x00, +0xED, 0x2F, 0xFF, 0xEE, 0x3C, 0xFE, 0x90, 0x82, 0x39, 0xE0, 0xFD, 0xC3, 0xEE, 0x94, 0x01, 0x40, +0x1E, 0x90, 0xFD, 0x11, 0xE0, 0xB5, 0x05, 0x14, 0x90, 0x01, 0x17, 0xE0, 0xB5, 0x05, 0x07, 0x90, +0xFD, 0x11, 0xE4, 0xF0, 0x80, 0x06, 0xED, 0x04, 0x90, 0xFD, 0x11, 0xF0, 0xE4, 0x2F, 0xFF, 0x22, +0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x83, 0xAE, 0xED, 0xF0, 0x90, 0x83, 0xAD, 0xEF, +0xF0, 0xD3, 0x94, 0x07, 0x50, 0x70, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, +0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x47, 0xE0, 0x5F, 0xFD, 0x7F, 0x47, 0x12, 0x32, 0x1E, +0x90, 0x83, 0xAD, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, +0xFF, 0x90, 0x00, 0x46, 0xE0, 0x4F, 0xFD, 0x7F, 0x46, 0x12, 0x32, 0x1E, 0x90, 0x83, 0xAE, 0xE0, +0x60, 0x18, 0x90, 0x83, 0xAD, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, +0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x4F, 0x80, 0x17, 0x90, 0x83, 0xAD, 0xE0, 0xFF, 0x74, +0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x45, 0xE0, +0x5F, 0xFD, 0x7F, 0x45, 0x80, 0x7E, 0x90, 0x83, 0xAD, 0xE0, 0x24, 0xF8, 0xF0, 0xE0, 0x24, 0x04, +0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, +0x43, 0xE0, 0x5F, 0xFD, 0x7F, 0x43, 0x12, 0x32, 0x1E, 0x90, 0x83, 0xAD, 0xE0, 0xFF, 0x74, 0x01, +0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x43, 0xE0, 0x4F, 0xFD, +0x7F, 0x43, 0x12, 0x32, 0x1E, 0x90, 0x83, 0xAE, 0xE0, 0x60, 0x1D, 0x90, 0x83, 0xAD, 0xE0, 0x24, +0x04, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, +0x42, 0xE0, 0x4F, 0xFD, 0x7F, 0x42, 0x80, 0x1C, 0x90, 0x83, 0xAD, 0xE0, 0x24, 0x04, 0xFF, 0x74, +0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x42, 0xE0, +0x5F, 0xFD, 0x7F, 0x42, 0x12, 0x32, 0x1E, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x01, 0x67, 0xE4, 0xFF, +0x41, 0x5F, 0x7F, 0x01, 0x41, 0x5F, 0x90, 0x80, 0xE4, 0xE0, 0x30, 0xE0, 0x05, 0x7F, 0x04, 0x12, +0x4E, 0x75, 0x22, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, 0x75, 0xD0, 0x00, +0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, 0x06, 0xC0, 0x07, +0x90, 0x01, 0xC4, 0x74, 0xF3, 0xF0, 0x74, 0x57, 0xA3, 0xF0, 0x11, 0x64, 0xE5, 0x4C, 0x30, 0xE1, +0x05, 0x7F, 0x03, 0x12, 0x4E, 0x75, 0xE5, 0x4C, 0x30, 0xE4, 0x03, 0x12, 0x57, 0xDC, 0xE5, 0x4C, +0x30, 0xE5, 0x03, 0x12, 0x57, 0xDE, 0xE5, 0x4C, 0x30, 0xE6, 0x03, 0x12, 0x57, 0xE2, 0x74, 0xF3, +0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x57, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, 0xD0, +0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, +0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x01, 0x3C, 0xE0, 0x55, 0x45, 0xF5, 0x49, 0xA3, 0xE0, 0x55, 0x46, +0xF5, 0x4A, 0xA3, 0xE0, 0x55, 0x47, 0xF5, 0x4B, 0xA3, 0xE0, 0x55, 0x48, 0xF5, 0x4C, 0x90, 0x01, +0x3C, 0xE5, 0x49, 0xF0, 0xA3, 0xE5, 0x4A, 0xF0, 0xA3, 0xE5, 0x4B, 0xF0, 0xA3, 0xE5, 0x4C, 0xF0, +0x53, 0x91, 0xDF, 0x22, 0x90, 0x01, 0xC8, 0xE4, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x7B, 0x01, 0x7A, +0x82, 0x79, 0x03, 0x7F, 0xFF, 0xFE, 0x12, 0x2B, 0x27, 0xBF, 0x01, 0x09, 0x90, 0x82, 0x03, 0xE0, +0x64, 0x03, 0x60, 0x03, 0x22, 0x21, 0x56, 0xE4, 0x90, 0x82, 0x08, 0xF0, 0x90, 0x82, 0x08, 0xE0, +0xFF, 0xC3, 0x94, 0x02, 0x40, 0x02, 0x21, 0x91, 0xC3, 0x74, 0xFE, 0x9F, 0xFF, 0xE4, 0x94, 0x00, +0xFE, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x04, 0x12, 0x2B, 0x27, 0xEF, 0x64, 0x01, 0x70, 0x77, 0x90, +0x82, 0x04, 0xE0, 0xFF, 0x54, 0xC0, 0xFE, 0x60, 0x05, 0xEF, 0x54, 0x0C, 0x70, 0x16, 0x90, 0x82, +0x04, 0xE0, 0xFF, 0x54, 0x30, 0x60, 0x67, 0xEF, 0x54, 0x03, 0x60, 0x62, 0x90, 0x82, 0x05, 0x74, +0x01, 0xF0, 0x80, 0x05, 0xE4, 0x90, 0x82, 0x05, 0xF0, 0x90, 0x82, 0x05, 0xE0, 0x90, 0x82, 0x04, +0x70, 0x16, 0xE0, 0xFF, 0xEE, 0x13, 0x13, 0x54, 0x3F, 0x90, 0x82, 0x06, 0xF0, 0xEF, 0x54, 0x0C, +0x13, 0x13, 0x54, 0x3F, 0xA3, 0xF0, 0x80, 0x0D, 0xE0, 0xFE, 0x54, 0x30, 0x90, 0x82, 0x06, 0xF0, +0xEE, 0x54, 0x03, 0xA3, 0xF0, 0x90, 0x82, 0x06, 0xE0, 0x64, 0x30, 0x70, 0x54, 0xA3, 0xE0, 0x64, +0x02, 0x70, 0x4E, 0x90, 0x00, 0xF5, 0xE0, 0x54, 0x40, 0x90, 0x82, 0x09, 0xF0, 0xE0, 0x70, 0x41, +0xA3, 0x74, 0x02, 0xF0, 0x80, 0x10, 0x90, 0x82, 0x0A, 0x74, 0x01, 0xF0, 0x80, 0x08, 0x90, 0x82, +0x08, 0xE0, 0x04, 0xF0, 0x01, 0xBC, 0x90, 0x01, 0xC4, 0x74, 0x94, 0xF0, 0x74, 0x58, 0xA3, 0xF0, +0x90, 0x82, 0x0A, 0xE0, 0x90, 0x01, 0xC8, 0xF0, 0x90, 0x82, 0x04, 0xE0, 0x90, 0x01, 0xC9, 0xF0, +0x90, 0x82, 0x05, 0xE0, 0x90, 0x01, 0xCA, 0xF0, 0xE4, 0xFD, 0x7F, 0x1F, 0x12, 0x32, 0x1E, 0x80, +0xD5, 0x22, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x80, 0xFD, 0x7F, 0x80, 0x12, 0x32, 0x1E, 0x90, 0xFD, +0x00, 0xE0, 0x54, 0xBF, 0xF0, 0x11, 0x94, 0xF1, 0x76, 0x12, 0x32, 0x77, 0x12, 0x6B, 0xF7, 0xF1, +0x51, 0x7F, 0x01, 0x12, 0x4D, 0x63, 0x7F, 0x02, 0x12, 0x4D, 0x63, 0x7F, 0x03, 0x12, 0x4D, 0x63, +0x7F, 0x04, 0x12, 0x4D, 0x63, 0x31, 0xFF, 0x31, 0xE4, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x40, 0xFD, +0x7F, 0x80, 0x12, 0x32, 0x1E, 0x75, 0x20, 0xFF, 0xF1, 0x67, 0x12, 0x6C, 0x27, 0xF1, 0x7E, 0xE4, +0xFF, 0x02, 0x4D, 0xEC, 0xF1, 0x55, 0xF1, 0x6E, 0x51, 0x42, 0xF1, 0x88, 0x90, 0x81, 0xFE, 0xE0, +0x54, 0xFE, 0xF0, 0xA3, 0x74, 0x03, 0xF0, 0xA3, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0x22, 0xF1, +0xC7, 0x90, 0x80, 0x01, 0xEF, 0xF0, 0x51, 0x11, 0x90, 0x01, 0x64, 0x74, 0x01, 0xF0, 0x02, 0x2D, +0xA7, 0x12, 0x6B, 0x58, 0x12, 0x6B, 0x88, 0x12, 0x6B, 0xB9, 0x12, 0x6B, 0xD8, 0xE4, 0xF5, 0x35, +0xF5, 0x36, 0xF5, 0x37, 0xF5, 0x38, 0xAD, 0x35, 0x7F, 0x50, 0x12, 0x32, 0x1E, 0xAD, 0x36, 0x7F, +0x51, 0x12, 0x32, 0x1E, 0xAD, 0x37, 0x7F, 0x52, 0x12, 0x32, 0x1E, 0xAD, 0x38, 0x7F, 0x53, 0x02, +0x32, 0x1E, 0x90, 0x80, 0xE4, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x80, 0xE9, 0xE0, 0x54, 0xFE, 0xF0, +0x90, 0x06, 0x90, 0xE0, 0x44, 0x20, 0xF0, 0x90, 0x80, 0xE5, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD, +0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0x54, 0xBF, 0xF0, +0x54, 0x7F, 0xF0, 0xA3, 0xE0, 0x54, 0x80, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xE0, 0x54, 0xFE, 0xF0, +0x90, 0x80, 0xE6, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x80, 0xE8, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0xEF, +0x60, 0x58, 0x90, 0x04, 0xEC, 0xE0, 0x54, 0xDD, 0xF0, 0x90, 0x81, 0xF1, 0xE0, 0xFF, 0x60, 0x02, +0x71, 0x3D, 0x90, 0x01, 0xC7, 0xE4, 0xF0, 0x90, 0x01, 0x17, 0xE0, 0xFE, 0x90, 0x01, 0x16, 0xE0, +0x7C, 0x00, 0x24, 0x00, 0xFF, 0xEC, 0x3E, 0x90, 0x80, 0x9F, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x06, +0x09, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x05, 0x22, 0x74, 0xFF, 0xF0, 0x71, 0x9C, 0x90, 0x02, 0x86, +0xE0, 0x44, 0x04, 0xF0, 0x71, 0x09, 0xF1, 0x4F, 0x91, 0x2A, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0x90, +0x01, 0x34, 0x74, 0x08, 0xF0, 0xFD, 0xE4, 0xFF, 0xE1, 0x9A, 0x90, 0x04, 0xEC, 0xE0, 0x44, 0x22, +0xF0, 0x7D, 0x08, 0xE4, 0xFF, 0xF1, 0xAF, 0x90, 0x06, 0x90, 0xE4, 0xF0, 0x90, 0x02, 0x86, 0xE0, +0x54, 0xFB, 0xF0, 0x71, 0x1A, 0xF1, 0x50, 0x41, 0x42, 0x12, 0x65, 0xC1, 0x90, 0x02, 0x87, 0xE0, +0x70, 0xF7, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x02, 0xF0, 0x22, 0x51, 0x57, 0x90, 0x01, 0x3F, 0x74, +0x04, 0xF0, 0x90, 0x80, 0x01, 0xE0, 0xFF, 0xB4, 0x01, 0x07, 0x90, 0xFD, 0x00, 0xE0, 0x54, 0xEF, +0xF0, 0xEF, 0xB4, 0x01, 0x07, 0x90, 0xFE, 0x10, 0xE0, 0x54, 0xFB, 0xF0, 0x22, 0xB1, 0x8E, 0x7E, +0x00, 0x74, 0x00, 0x2F, 0xF9, 0xE4, 0x34, 0xFC, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, +0x16, 0x08, 0x7B, 0x01, 0x7A, 0x80, 0x79, 0xFB, 0x12, 0x2B, 0xED, 0x90, 0x80, 0xFB, 0xE0, 0x90, +0x81, 0x03, 0xF0, 0x90, 0x80, 0xFC, 0xE0, 0x90, 0x81, 0x04, 0xF0, 0x90, 0x80, 0xFD, 0xE0, 0x90, +0x81, 0x05, 0xF0, 0x90, 0x80, 0xFE, 0xE0, 0x90, 0x81, 0x06, 0xF0, 0x90, 0x80, 0xFF, 0xE0, 0x90, +0x81, 0x07, 0xF0, 0x90, 0x81, 0x00, 0xE0, 0x90, 0x81, 0x08, 0xF0, 0x90, 0x81, 0x01, 0xE0, 0x90, +0x81, 0x09, 0xF0, 0x90, 0x81, 0x02, 0xE0, 0x90, 0x81, 0x0A, 0xF0, 0x22, 0x12, 0x6F, 0x85, 0x90, +0x85, 0xBB, 0x12, 0x20, 0xDA, 0xCC, 0xF0, 0x00, 0xC0, 0x7F, 0x8C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, +0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x14, 0x7F, 0x70, 0x7E, 0x0E, 0x12, 0x2E, +0xA2, 0x90, 0x83, 0x97, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xFD, 0xFF, 0x91, 0x07, +0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x83, 0xA3, 0x12, 0x20, +0xCE, 0x90, 0x83, 0xA3, 0x12, 0x49, 0x6E, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x7C, 0x7E, +0x08, 0x12, 0x2E, 0xA2, 0x90, 0x01, 0x00, 0x74, 0x3F, 0xF0, 0xA3, 0xE0, 0x54, 0xFD, 0xF0, 0x90, +0x05, 0x53, 0xE0, 0x44, 0x20, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xC0, 0x07, +0xC0, 0x05, 0x90, 0x83, 0x97, 0x12, 0x49, 0x6E, 0x90, 0x83, 0x70, 0x12, 0x20, 0xCE, 0xD0, 0x05, +0xD0, 0x07, 0x12, 0x69, 0x30, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, +0xD0, 0x90, 0x01, 0x01, 0xE0, 0x44, 0x02, 0xF0, 0x90, 0x01, 0x00, 0x74, 0xFF, 0xF0, 0x90, 0x06, +0xB7, 0x74, 0x09, 0xF0, 0x90, 0x06, 0xB4, 0x74, 0x86, 0xF0, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2D, +0x5C, 0xEC, 0x54, 0x7F, 0xFC, 0x90, 0x83, 0x9F, 0x12, 0x20, 0xCE, 0x90, 0x83, 0x9F, 0x12, 0x49, +0x6E, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85, +0xBB, 0x12, 0x20, 0xDA, 0xCC, 0xC0, 0x00, 0xC0, 0x7F, 0x8C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, +0x85, 0xBB, 0x12, 0x20, 0xDA, 0x00, 0xC0, 0x00, 0x14, 0x7F, 0x70, 0x7E, 0x0E, 0x12, 0x2E, 0xA2, +0x90, 0x83, 0x97, 0x12, 0x20, 0xDA, 0x00, 0x03, 0x3E, 0x60, 0xE4, 0xFD, 0xFF, 0x91, 0x07, 0xD0, +0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x1F, 0xA4, 0xFF, 0x54, +0x01, 0xFE, 0x90, 0x80, 0xE4, 0xE0, 0x54, 0xFE, 0x4E, 0xFE, 0xF0, 0xEF, 0x54, 0x02, 0xFF, 0xEE, +0x54, 0xFD, 0x4F, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x04, 0xFD, 0xEF, 0x54, 0xFB, 0x4D, +0xFF, 0x90, 0x80, 0xE4, 0xF0, 0xEE, 0x54, 0x08, 0xFE, 0xEF, 0x54, 0xF7, 0x4E, 0xFF, 0xF0, 0x12, +0x1F, 0xA4, 0xFE, 0x54, 0x10, 0xFD, 0xEF, 0x54, 0xEF, 0x4D, 0xFF, 0x90, 0x80, 0xE4, 0xF0, 0xEE, +0x54, 0x20, 0xFE, 0xEF, 0x54, 0xDF, 0x4E, 0xF0, 0x90, 0x01, 0x17, 0xE0, 0xFE, 0x90, 0x01, 0x16, +0xE0, 0x7C, 0x00, 0x24, 0x00, 0xFF, 0xEC, 0x3E, 0x90, 0x80, 0x9F, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, +0x80, 0xE4, 0xE0, 0xC3, 0x13, 0x54, 0x01, 0xFF, 0xB1, 0x49, 0x90, 0x80, 0xE4, 0xE0, 0x13, 0x13, +0x54, 0x01, 0xFF, 0xF1, 0x5B, 0x90, 0x80, 0xE4, 0xE0, 0x13, 0x13, 0x13, 0x54, 0x01, 0xFF, 0xB1, +0x54, 0x90, 0x80, 0xE4, 0xE0, 0xC4, 0x54, 0x01, 0xFF, 0xF1, 0x61, 0x90, 0x80, 0xE4, 0xE0, 0x54, +0x01, 0xFF, 0x51, 0x8F, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xEF, 0x60, 0x07, 0x90, 0x81, 0xF2, 0xE0, +0xFF, 0xB1, 0xA2, 0x22, 0xE4, 0xFD, 0xFC, 0xEF, 0x60, 0x33, 0x90, 0x81, 0xF5, 0xE0, 0xFF, 0xB1, +0x8E, 0x7C, 0x00, 0xAD, 0x07, 0x74, 0x00, 0x2F, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, 0x90, +0x82, 0x1A, 0x12, 0x49, 0x8F, 0x90, 0x82, 0x1A, 0x12, 0x49, 0x86, 0x8B, 0x13, 0x8A, 0x14, 0x89, +0x15, 0x75, 0x16, 0x4A, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x0B, 0x12, 0x2B, 0xED, 0x22, 0xE4, 0xFE, +0xEF, 0xC3, 0x13, 0xFD, 0xEF, 0x30, 0xE0, 0x02, 0x7E, 0x80, 0x90, 0xFD, 0x10, 0xED, 0xF0, 0xAF, +0x06, 0x22, 0xB1, 0x8E, 0x7E, 0x00, 0x90, 0x83, 0xB1, 0xB1, 0xEA, 0x90, 0x83, 0xB1, 0xA3, 0xE0, +0x2F, 0x24, 0x36, 0xF9, 0xE4, 0x34, 0xFC, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, +0x04, 0x7B, 0x01, 0x7A, 0x80, 0x79, 0xF6, 0x12, 0x2B, 0xED, 0xE4, 0xFF, 0x74, 0x18, 0x2F, 0xF5, +0x82, 0xE4, 0x34, 0x06, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0xEA, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x80, +0xF5, 0x83, 0xEE, 0xF0, 0x0F, 0xEF, 0xB4, 0x06, 0xE3, 0x22, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x24, +0x20, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, 0xE4, 0x90, 0x83, 0xB4, 0xF0, 0xFF, 0x12, 0x1F, +0xA4, 0x30, 0xE7, 0x08, 0x90, 0x83, 0xB4, 0x74, 0x02, 0xF0, 0x80, 0x05, 0xE4, 0x90, 0x83, 0xB4, +0xF0, 0x12, 0x6E, 0xF9, 0x90, 0x83, 0xB4, 0xE0, 0x24, 0x18, 0x2F, 0xFF, 0x22, 0x90, 0x82, 0x17, +0x12, 0x49, 0x8F, 0xEF, 0x12, 0x4A, 0x40, 0x5E, 0x49, 0x00, 0x5E, 0x52, 0x01, 0x5E, 0x5A, 0x02, +0x5E, 0x63, 0x03, 0x5E, 0x6C, 0x04, 0x5E, 0x7C, 0x80, 0x5E, 0x74, 0x81, 0x5E, 0x84, 0x82, 0x5E, +0x8D, 0x83, 0x5E, 0x96, 0x84, 0x00, 0x00, 0x5E, 0x9F, 0x90, 0x82, 0x17, 0x12, 0x49, 0x86, 0x02, +0x6A, 0xD1, 0x90, 0x82, 0x17, 0x12, 0x49, 0x86, 0x80, 0x79, 0x90, 0x82, 0x17, 0x12, 0x49, 0x86, +0x02, 0x6B, 0x19, 0x90, 0x82, 0x17, 0x12, 0x49, 0x86, 0x02, 0x70, 0x53, 0x90, 0x82, 0x17, 0x12, +0x49, 0x86, 0x80, 0x33, 0x90, 0x82, 0x17, 0x12, 0x49, 0x86, 0x81, 0xA4, 0x90, 0x82, 0x17, 0x12, +0x49, 0x86, 0xE1, 0xE1, 0x90, 0x82, 0x17, 0x12, 0x49, 0x86, 0x02, 0x71, 0xB9, 0x90, 0x82, 0x17, +0x12, 0x49, 0x86, 0x02, 0x71, 0xD3, 0x90, 0x82, 0x17, 0x12, 0x49, 0x86, 0x02, 0x72, 0x35, 0x90, +0x01, 0xC0, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x31, 0xEC, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, +0x90, 0x81, 0xFE, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x14, 0x90, 0x00, +0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0xFF, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x82, +0x00, 0xF0, 0x22, 0x90, 0x82, 0x1A, 0x12, 0x49, 0x8F, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, +0xFE, 0x12, 0x1F, 0xA4, 0xFD, 0xC3, 0x13, 0x30, 0xE0, 0x12, 0x90, 0x82, 0x1A, 0x12, 0x49, 0x86, +0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x82, 0x1E, 0xF0, 0x80, 0x05, 0x90, 0x82, 0x1E, 0xEF, +0xF0, 0x90, 0x82, 0x1D, 0xEE, 0xF0, 0x90, 0x82, 0x1E, 0xE0, 0xFE, 0x90, 0x82, 0x1D, 0xE0, 0xFF, +0xD3, 0x9E, 0x50, 0x38, 0x90, 0x82, 0x1A, 0x12, 0x49, 0x86, 0x12, 0x1F, 0xA4, 0x54, 0x01, 0xFE, +0x74, 0xA3, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83, 0xEE, 0xF0, 0x74, 0xA3, 0x2F, 0xF5, +0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83, 0xE0, 0x70, 0x04, 0xF1, 0x4E, 0x80, 0x07, 0x90, 0x82, 0x1D, +0xE0, 0xFF, 0xF1, 0x4D, 0x90, 0x82, 0x1D, 0xE0, 0x04, 0xF0, 0x80, 0xBA, 0x22, 0x22, 0x22, 0x22, +0x22, 0xE4, 0xF5, 0x4D, 0x22, 0xE4, 0x90, 0x80, 0xA3, 0xF0, 0x22, 0x90, 0x82, 0x1A, 0xEF, 0xF0, +0x22, 0x90, 0x82, 0x1A, 0xEF, 0xF0, 0x22, 0x75, 0xE8, 0x03, 0x75, 0xA8, 0x84, 0x22, 0xE4, 0x90, +0x80, 0x9D, 0xF0, 0xA3, 0xF0, 0x22, 0x90, 0x01, 0x94, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, 0x01, +0xE4, 0x74, 0x0C, 0xF0, 0xA3, 0xE4, 0xF0, 0x22, 0x90, 0x81, 0xFB, 0xE0, 0x54, 0xFE, 0xF0, 0x54, +0x7F, 0xF0, 0xA3, 0x74, 0x0A, 0xF0, 0xE4, 0xA3, 0xF0, 0x22, 0x74, 0x3D, 0x2F, 0xF8, 0xE6, 0x4D, +0xFE, 0xF6, 0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0x74, +0x3D, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE, 0xF6, 0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, +0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0x90, 0x00, 0xF7, 0xE0, 0x20, 0xE7, 0x09, 0xE0, 0x7F, +0x01, 0x20, 0xE6, 0x0C, 0x7F, 0x02, 0x22, 0x90, 0x00, 0xF7, 0xE0, 0x30, 0xE6, 0x02, 0x7F, 0x03, +0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x1F, 0xA4, 0xFC, 0x20, 0xE0, 0x05, 0x71, +0x1A, 0x02, 0x60, 0xE8, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x80, 0xE5, 0xE0, 0x54, +0xFE, 0x4E, 0xFE, 0xF0, 0xEF, 0x54, 0x02, 0xFF, 0xEE, 0x54, 0xFD, 0x4F, 0xFF, 0xF0, 0x12, 0x1F, +0xA4, 0xFE, 0x54, 0x04, 0xFD, 0xEF, 0x54, 0xFB, 0x4D, 0xFF, 0x90, 0x80, 0xE5, 0xF0, 0xEE, 0x54, +0x08, 0xFE, 0xEF, 0x54, 0xF7, 0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x10, 0xFD, 0xEF, +0x54, 0xEF, 0x4D, 0xFF, 0x90, 0x80, 0xE5, 0xF0, 0xEE, 0x54, 0x20, 0xFE, 0xEF, 0x54, 0xDF, 0x4E, +0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x40, 0xFD, 0xEF, 0x54, 0xBF, 0x4D, 0xFF, 0x90, 0x80, +0xE5, 0xF0, 0xEE, 0x54, 0x80, 0xFE, 0xEF, 0x54, 0x7F, 0x4E, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, +0xBD, 0xFD, 0x54, 0x80, 0xFF, 0x90, 0x80, 0xE6, 0xE0, 0x54, 0x7F, 0x4F, 0xF0, 0xEC, 0x13, 0x13, +0x54, 0x3F, 0x30, 0xE0, 0x07, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x04, 0xF0, 0x12, 0x1F, 0xA4, 0x13, +0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x07, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x08, 0xF0, 0x90, 0x80, +0x01, 0xE0, 0x64, 0x02, 0x70, 0x44, 0x90, 0x80, 0xE6, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, +0x01, 0x20, 0xE0, 0x36, 0xED, 0x54, 0x7F, 0xFE, 0xEF, 0x54, 0x80, 0x4E, 0x90, 0x80, 0xE6, 0xF0, +0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x80, 0xE7, 0xF0, 0x90, 0x80, 0xE5, 0xE0, 0xC4, 0x13, +0x54, 0x07, 0x30, 0xE0, 0x09, 0xA3, 0xE0, 0x54, 0x7F, 0xFF, 0xE4, 0xFD, 0x80, 0x09, 0x90, 0x80, +0xE6, 0xE0, 0x54, 0x7F, 0xFF, 0x7D, 0x01, 0x12, 0x56, 0xD0, 0x90, 0x80, 0x01, 0xE0, 0xB4, 0x01, +0x07, 0x90, 0xFE, 0x10, 0xE0, 0x44, 0x04, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xE4, 0x90, 0x82, +0x0B, 0xF0, 0x90, 0x82, 0x0B, 0xE0, 0x64, 0x01, 0xF0, 0x24, 0xED, 0x90, 0x01, 0xC4, 0xF0, 0x74, +0x60, 0xA3, 0xF0, 0x31, 0x0A, 0x12, 0x4C, 0x9B, 0x80, 0xE8, 0x22, 0xE4, 0xFB, 0xFA, 0xFD, 0x7F, +0x01, 0x12, 0x4E, 0x9C, 0x90, 0x82, 0x0C, 0xEF, 0xF0, 0x60, 0xF0, 0x31, 0x1F, 0x80, 0xEC, 0xD3, +0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x01, 0xCC, 0xE0, 0x54, 0x0F, 0x90, 0x82, 0x0D, 0xF0, +0x90, 0x82, 0x0D, 0xE0, 0xFD, 0x70, 0x02, 0x41, 0x4A, 0x90, 0x83, 0xA7, 0xE0, 0xFF, 0x74, 0x01, +0x7E, 0x00, 0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, 0xF9, 0xFF, 0xEF, +0x5D, 0x70, 0x02, 0x41, 0x43, 0x90, 0x83, 0xA7, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD0, 0x12, +0x49, 0x7A, 0xE0, 0x90, 0x82, 0x0E, 0xF0, 0x75, 0x13, 0x01, 0x75, 0x14, 0x82, 0x75, 0x15, 0x0E, +0x75, 0x16, 0x01, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x0F, 0x12, 0x2B, 0xED, 0x90, 0x83, 0xA7, 0xE0, +0x75, 0xF0, 0x04, 0x90, 0x01, 0xD1, 0x12, 0x49, 0x7A, 0xE0, 0x90, 0x82, 0x10, 0xF0, 0x90, 0x83, +0xA7, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD2, 0x12, 0x49, 0x7A, 0xE0, 0x90, 0x82, 0x11, 0xF0, +0x90, 0x83, 0xA7, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD3, 0x12, 0x49, 0x7A, 0xE0, 0x90, 0x82, +0x12, 0xF0, 0x90, 0x83, 0xA7, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF0, 0x12, 0x49, 0x7A, 0xE0, +0x90, 0x82, 0x13, 0xF0, 0x90, 0x83, 0xA7, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF1, 0x12, 0x49, +0x7A, 0xE0, 0x90, 0x82, 0x14, 0xF0, 0x90, 0x83, 0xA7, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xF2, +0x12, 0x49, 0x7A, 0xE0, 0x90, 0x82, 0x15, 0xF0, 0x90, 0x83, 0xA7, 0xE0, 0x75, 0xF0, 0x04, 0x90, +0x01, 0xF3, 0x12, 0x49, 0x7A, 0xE0, 0x90, 0x82, 0x16, 0xF0, 0x90, 0x82, 0x0D, 0xE0, 0xFF, 0x90, +0x83, 0xA7, 0xE0, 0xFE, 0x74, 0x01, 0xA8, 0x06, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, +0x5F, 0x90, 0x82, 0x0D, 0xF0, 0x90, 0x83, 0xA7, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, +0x02, 0xC3, 0x33, 0xD8, 0xFC, 0x90, 0x01, 0xCC, 0xF0, 0x90, 0x82, 0x0F, 0xE0, 0xFF, 0x7B, 0x01, +0x7A, 0x82, 0x79, 0x10, 0x12, 0x5E, 0x1D, 0x90, 0x83, 0xA7, 0xE0, 0x04, 0xF0, 0xE0, 0x54, 0x03, +0xF0, 0x21, 0x30, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x02, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xE4, +0xFB, 0xFA, 0xFD, 0x7F, 0x01, 0x12, 0x4E, 0x9C, 0x90, 0x82, 0x1F, 0xEF, 0xF0, 0x60, 0xF0, 0x51, +0x63, 0x80, 0xEC, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xE4, 0xFF, 0x90, 0x80, 0x9E, 0xE0, +0xFE, 0x90, 0x80, 0x9D, 0xE0, 0xFD, 0xB5, 0x06, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, +0x64, 0x01, 0x60, 0x32, 0x90, 0x01, 0xAF, 0xE0, 0x70, 0x13, 0xED, 0x75, 0xF0, 0x0F, 0xA4, 0x24, +0x07, 0xF9, 0x74, 0x80, 0x35, 0xF0, 0xFA, 0x7B, 0x01, 0x51, 0xBB, 0x7F, 0x01, 0xEF, 0x60, 0x16, +0x90, 0x80, 0x9D, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4, 0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x60, +0x05, 0xE4, 0x90, 0x80, 0x9D, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, +0xC0, 0xD0, 0x90, 0x82, 0x20, 0x12, 0x49, 0x8F, 0x90, 0x83, 0xA8, 0xE0, 0xFF, 0x04, 0xF0, 0x90, +0x00, 0x01, 0xEF, 0x12, 0x1F, 0xFC, 0x7F, 0xAF, 0x7E, 0x01, 0x71, 0x1E, 0xEF, 0x60, 0x3A, 0x90, +0x82, 0x20, 0x12, 0x49, 0x86, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x90, 0x00, 0x0E, 0x12, 0x1F, +0xBD, 0x24, 0x02, 0xF5, 0x16, 0x7B, 0x01, 0x7A, 0x01, 0x79, 0xA0, 0x12, 0x2B, 0xED, 0x90, 0x82, +0x20, 0x12, 0x49, 0x86, 0x90, 0x00, 0x0E, 0x12, 0x1F, 0xBD, 0x90, 0x01, 0xAE, 0xF0, 0xA3, 0x74, +0xFF, 0xF0, 0x90, 0x01, 0xCB, 0xE0, 0x64, 0x80, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, +0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x83, 0x9B, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xE4, 0xA3, 0xF0, +0xA3, 0xF0, 0x90, 0x83, 0x9B, 0xE0, 0xFE, 0xA3, 0xE0, 0xF5, 0x82, 0x8E, 0x83, 0xE0, 0x60, 0x2D, +0xC3, 0x90, 0x83, 0x9E, 0xE0, 0x94, 0xE8, 0x90, 0x83, 0x9D, 0xE0, 0x94, 0x03, 0x40, 0x0B, 0x90, +0x01, 0xC0, 0xE0, 0x44, 0x80, 0xF0, 0x7F, 0x00, 0x80, 0x15, 0x90, 0x83, 0x9D, 0xE4, 0x75, 0xF0, +0x01, 0x12, 0x49, 0x4B, 0x7F, 0x0A, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x80, 0xC5, 0x7F, 0x01, 0xD0, +0xD0, 0x92, 0xAF, 0x22, 0xE4, 0xFB, 0xFA, 0xFD, 0x7F, 0x01, 0x12, 0x4E, 0x9C, 0x90, 0x82, 0x23, +0xEF, 0xF0, 0x60, 0xF0, 0xD1, 0xEB, 0xBF, 0x01, 0xEB, 0x71, 0x8D, 0x80, 0xE7, 0xD3, 0x10, 0xAF, +0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, 0x2E, 0x74, 0x08, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, +0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x1F, 0xE0, 0xFE, 0x90, 0x01, 0x1E, 0xE0, 0x7C, 0x00, 0x24, 0x00, +0xFF, 0xEC, 0x3E, 0x90, 0x82, 0x24, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x02, 0x82, 0xE0, 0x90, 0x82, +0x2D, 0xF0, 0x90, 0x80, 0xE4, 0xE0, 0x20, 0xE0, 0x02, 0xA1, 0xA9, 0x90, 0x80, 0xE9, 0xE0, 0x20, +0xE0, 0x07, 0x90, 0x01, 0x3F, 0xE0, 0x30, 0xE2, 0x18, 0x90, 0x80, 0x01, 0xE0, 0xB4, 0x01, 0x0E, +0x90, 0xFD, 0x01, 0xE0, 0x20, 0xE6, 0x07, 0x90, 0xFD, 0x00, 0xE0, 0x44, 0x10, 0xF0, 0x12, 0x52, +0xAE, 0xE4, 0x90, 0x82, 0x2C, 0xF0, 0x90, 0x82, 0x2D, 0xE0, 0xFF, 0x90, 0x82, 0x2C, 0xE0, 0xC3, +0x9F, 0x40, 0x02, 0xA1, 0xA9, 0x90, 0x82, 0x24, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0xEC, 0xFF, 0x90, +0xFD, 0x11, 0xF0, 0x90, 0x82, 0x26, 0xED, 0xF0, 0x90, 0x82, 0x30, 0xEF, 0xF0, 0x90, 0x82, 0x26, +0xE0, 0xFF, 0x24, 0x02, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x54, 0x0F, 0x33, 0x33, +0x33, 0x54, 0xF8, 0x90, 0x82, 0x2A, 0xF0, 0xEF, 0x24, 0x18, 0xFF, 0xE0, 0xFE, 0x2F, 0x90, 0x82, +0x27, 0xF0, 0x90, 0x82, 0x25, 0xE0, 0x24, 0x18, 0xFD, 0x90, 0x82, 0x24, 0xE0, 0x34, 0x00, 0xFC, +0xEE, 0x7E, 0x00, 0x2D, 0xFF, 0xEE, 0x3C, 0x90, 0x82, 0x28, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x82, +0x27, 0xE0, 0xFD, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x54, 0xFC, 0x90, +0x82, 0x2B, 0xF0, 0x74, 0x00, 0x2D, 0xF9, 0xE4, 0x34, 0xFB, 0xFA, 0x7B, 0x01, 0x12, 0x5D, 0xF8, +0x90, 0x82, 0x2F, 0xEF, 0xF0, 0x90, 0x82, 0x26, 0xE0, 0xFD, 0x24, 0x01, 0xF5, 0x82, 0xE4, 0x34, +0xFB, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x00, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, +0x7C, 0x00, 0x24, 0x00, 0xFF, 0xEC, 0x3E, 0x54, 0x3F, 0xFE, 0x90, 0x82, 0x31, 0xF0, 0xA3, 0xEF, +0xF0, 0x90, 0x82, 0x2A, 0xE0, 0x24, 0x18, 0xFD, 0xEC, 0x33, 0xFC, 0xED, 0x2F, 0xFF, 0xEC, 0x3E, +0xFE, 0xD1, 0x85, 0x90, 0x82, 0x26, 0xE0, 0x24, 0x0F, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, +0xE0, 0xFD, 0x90, 0x82, 0x24, 0xEE, 0x8F, 0xF0, 0x12, 0x49, 0x4B, 0x90, 0x80, 0x9F, 0xE0, 0xFE, +0xA3, 0xE0, 0xFF, 0xD3, 0x90, 0x82, 0x25, 0xE0, 0x9F, 0x90, 0x82, 0x24, 0xE0, 0x9E, 0x40, 0x1B, +0x90, 0x80, 0xA0, 0xE0, 0x24, 0x01, 0xFF, 0x90, 0x80, 0x9F, 0xE0, 0x34, 0x00, 0xFE, 0xC3, 0x90, +0x82, 0x25, 0xE0, 0x9F, 0xF0, 0x90, 0x82, 0x24, 0xE0, 0x9E, 0xF0, 0xED, 0x30, 0xE7, 0x06, 0x90, +0x01, 0xC7, 0x74, 0x21, 0xF0, 0xED, 0x30, 0xE6, 0x06, 0x90, 0x01, 0xC7, 0x74, 0x22, 0xF0, 0xED, +0x30, 0xE5, 0x06, 0x90, 0x01, 0xC7, 0x74, 0x23, 0xF0, 0x90, 0x82, 0x2B, 0xE0, 0x24, 0x40, 0x60, +0x04, 0x24, 0x20, 0x70, 0x21, 0x90, 0x80, 0xE5, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, +0x30, 0xE0, 0x43, 0x90, 0x82, 0x27, 0xE0, 0xFF, 0xF1, 0x28, 0xEF, 0x60, 0x39, 0x90, 0x82, 0x2B, +0xE0, 0xFF, 0xD1, 0xAE, 0x80, 0x30, 0x90, 0x82, 0x27, 0xE0, 0xFF, 0x90, 0x82, 0x2F, 0xE0, 0xFD, +0x90, 0x82, 0x2E, 0xE0, 0xFB, 0x90, 0x82, 0x30, 0xE0, 0x90, 0x82, 0x36, 0xF0, 0xF1, 0x7B, 0x90, +0x80, 0xE4, 0xE0, 0xFF, 0xC3, 0x13, 0x30, 0xE0, 0x0D, 0x90, 0x82, 0x27, 0xE0, 0xFF, 0x90, 0x82, +0x2F, 0xE0, 0xFD, 0x12, 0x70, 0x73, 0x90, 0x80, 0xE9, 0xE0, 0x20, 0xE0, 0x07, 0x90, 0x01, 0x3F, +0xE0, 0x30, 0xE2, 0x03, 0x12, 0x52, 0xAE, 0xD1, 0xC5, 0xBF, 0x01, 0x0D, 0x90, 0x82, 0x24, 0xB1, +0xAE, 0x90, 0x82, 0x2C, 0xE0, 0x04, 0xF0, 0x61, 0xF6, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xE0, 0xFE, +0xA3, 0xE0, 0xFF, 0x90, 0x02, 0x84, 0xEF, 0xF0, 0xEE, 0xA3, 0xF0, 0xA3, 0xE0, 0x44, 0x01, 0xF0, +0x22, 0x90, 0x01, 0x1F, 0xE0, 0xFE, 0x90, 0x01, 0x1E, 0xE0, 0x7C, 0x00, 0x24, 0x00, 0xFF, 0xEC, +0x3E, 0x90, 0x82, 0x1A, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x02, 0x87, 0xE0, 0xF9, 0x90, 0x80, 0xE4, +0xE0, 0x20, 0xE0, 0x02, 0xC1, 0x84, 0xEC, 0xC3, 0x99, 0x40, 0x02, 0xC1, 0x84, 0x90, 0x82, 0x1A, +0xE0, 0xFA, 0xA3, 0xE0, 0xFB, 0xEA, 0x90, 0xFD, 0x11, 0xF0, 0xAF, 0x03, 0xAD, 0x07, 0x74, 0x02, +0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x54, 0x0F, 0x33, 0x33, 0x33, 0x54, 0xF8, +0xFB, 0x74, 0x01, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x00, 0x2D, +0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x75, 0x83, 0x00, 0x24, 0x00, 0xFF, 0xE5, 0x83, +0x3E, 0x54, 0x3F, 0xFE, 0xEB, 0x24, 0x18, 0xFB, 0xE4, 0x33, 0xFA, 0xEB, 0x2F, 0xFF, 0xEA, 0x3E, +0xFE, 0xD1, 0x85, 0x90, 0x82, 0x1A, 0xEE, 0x8F, 0xF0, 0x12, 0x49, 0x4B, 0x90, 0x80, 0x9F, 0xE0, +0xFE, 0xA3, 0xE0, 0xFF, 0xD3, 0x90, 0x82, 0x1B, 0xE0, 0x9F, 0x90, 0x82, 0x1A, 0xE0, 0x9E, 0x40, +0x1B, 0x90, 0x80, 0xA0, 0xE0, 0x24, 0x01, 0xFF, 0x90, 0x80, 0x9F, 0xE0, 0x34, 0x00, 0xFE, 0xC3, +0x90, 0x82, 0x1B, 0xE0, 0x9F, 0xF0, 0x90, 0x82, 0x1A, 0xE0, 0x9E, 0xF0, 0x90, 0x82, 0x1A, 0xB1, +0xAE, 0x0C, 0xA1, 0xE6, 0x22, 0x7D, 0x7F, 0xEF, 0x5D, 0xC3, 0x60, 0x14, 0x74, 0xFF, 0x9D, 0xFD, +0x74, 0xFF, 0x94, 0x00, 0x5E, 0xFE, 0xED, 0x5F, 0x24, 0x80, 0xFF, 0xE4, 0x3E, 0xFE, 0x80, 0x0D, +0x74, 0xFF, 0x9D, 0xFD, 0x74, 0xFF, 0x94, 0x00, 0x5E, 0xFE, 0xED, 0x5F, 0xFF, 0x22, 0xEF, 0x90, +0x01, 0xC7, 0xB4, 0xA0, 0x05, 0x74, 0x04, 0xF0, 0x80, 0x03, 0x74, 0x08, 0xF0, 0x90, 0x80, 0xE9, +0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, 0x80, 0xE9, 0xE0, 0xFF, 0x20, 0xE0, 0x07, 0x90, 0x01, 0x3F, +0xE0, 0x30, 0xE2, 0x14, 0xEF, 0x44, 0x01, 0x90, 0x80, 0xE9, 0xF0, 0x90, 0x80, 0xE5, 0xE0, 0xC4, +0x54, 0x0F, 0x20, 0xE0, 0x03, 0x7F, 0x00, 0x22, 0x7F, 0x01, 0x22, 0xE4, 0x90, 0x83, 0xAF, 0xF0, +0xA3, 0xF0, 0x90, 0x02, 0x86, 0xE0, 0x20, 0xE1, 0x2C, 0xC3, 0x90, 0x83, 0xB0, 0xE0, 0x94, 0xD0, +0x90, 0x83, 0xAF, 0xE0, 0x94, 0x07, 0x40, 0x0A, 0x90, 0x01, 0xC1, 0xE0, 0x44, 0x04, 0xF0, 0x7F, +0x00, 0x22, 0x90, 0x83, 0xAF, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x49, 0x4B, 0x7F, 0x0A, 0x7E, 0x00, +0x12, 0x32, 0xAA, 0x80, 0xCD, 0x7F, 0x01, 0x22, 0xE4, 0xFE, 0x74, 0x10, 0x2E, 0xF5, 0x82, 0xE4, +0x34, 0x06, 0xF5, 0x83, 0xE0, 0xFD, 0x74, 0x39, 0x2E, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, +0xED, 0xF0, 0xEF, 0x2E, 0x24, 0x04, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFD, 0x74, +0x33, 0x2E, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xED, 0xF0, 0x0E, 0xEE, 0xB4, 0x06, 0xCA, +0x78, 0x39, 0x7C, 0x82, 0x7D, 0x01, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x33, 0x7E, 0x00, 0x7F, 0x06, +0x12, 0x4B, 0xEC, 0xEF, 0x7F, 0x00, 0x70, 0x02, 0x7F, 0x01, 0x22, 0x74, 0x00, 0x2F, 0xF5, 0x82, +0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x54, 0x0C, 0x64, 0x08, 0x70, 0x64, 0xEF, 0x2D, 0xFE, 0x24, +0x06, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x64, 0x88, 0x70, 0x53, 0x74, 0x07, 0x2E, +0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x64, 0x8E, 0x70, 0x44, 0xEF, 0x2D, 0x2B, 0xFE, +0x24, 0x01, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x64, 0x03, 0x70, 0x32, 0x74, 0x06, +0x2E, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x30, 0xE3, 0x1A, 0x90, 0x80, 0xE5, 0xE0, +0xC4, 0x13, 0x13, 0x54, 0x03, 0x30, 0xE0, 0x18, 0x90, 0x01, 0xC7, 0x74, 0x01, 0xF0, 0x90, 0x80, +0xE9, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x7E, 0x00, 0x90, 0x82, 0x36, 0xE0, 0xFD, 0x12, 0x53, 0x09, +0x22, 0x90, 0x83, 0x5F, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0xA3, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, +0x00, 0xE4, 0x90, 0x83, 0x6D, 0xF0, 0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0x90, 0x83, 0x65, +0x12, 0x20, 0xCE, 0x90, 0x83, 0x5F, 0xE0, 0xFB, 0x70, 0x08, 0x90, 0x83, 0x65, 0x12, 0x49, 0x6E, +0x80, 0x16, 0xEB, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, +0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, 0x2D, 0x5C, 0x90, 0x83, 0x69, 0x12, 0x20, 0xCE, 0x90, 0x83, +0x60, 0xE0, 0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x17, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, +0xAA, 0x06, 0xAB, 0x07, 0x90, 0x83, 0x69, 0x12, 0x49, 0x6E, 0xED, 0x54, 0x7F, 0xFD, 0xEC, 0x54, +0x80, 0xFC, 0x12, 0x49, 0x61, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x83, 0x69, 0x12, 0x20, 0xCE, 0x90, +0x83, 0x65, 0x12, 0x49, 0x6E, 0xEC, 0x54, 0x7F, 0xFC, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0x7F, +0x24, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x83, 0x5F, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x62, +0xF5, 0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xC0, 0x06, 0xC0, 0x07, +0x90, 0x83, 0x69, 0x12, 0x49, 0x6E, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0xD0, 0x07, 0xD0, 0x06, +0x12, 0x2E, 0xA2, 0x90, 0x83, 0x65, 0x12, 0x49, 0x6E, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x85, 0xBB, +0x12, 0x20, 0xCE, 0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x83, 0x5F, 0xE0, 0x70, 0x04, +0x7F, 0x20, 0x80, 0x09, 0x90, 0x83, 0x5F, 0xE0, 0xB4, 0x01, 0x16, 0x7F, 0x28, 0x7E, 0x08, 0x12, +0x2D, 0x5C, 0x78, 0x08, 0x12, 0x20, 0xA8, 0xEF, 0x54, 0x01, 0xFF, 0xE4, 0x90, 0x83, 0x6D, 0xEF, +0xF0, 0x90, 0x83, 0x6D, 0xE0, 0x90, 0x83, 0x5F, 0x60, 0x0E, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, +0x66, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0x80, 0x0C, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x64, 0xF5, +0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, 0x2D, 0x5C, 0xED, 0x54, +0x0F, 0xFD, 0xE4, 0xFC, 0x90, 0x83, 0x61, 0x12, 0x20, 0xCE, 0x90, 0x83, 0x61, 0x02, 0x49, 0x6E, +0x90, 0x83, 0x6E, 0xEF, 0xF0, 0xAB, 0x05, 0x90, 0x83, 0x74, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, +0x00, 0xAF, 0x03, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x14, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, +0xAA, 0x06, 0xAB, 0x07, 0x90, 0x83, 0x70, 0x12, 0x49, 0x6E, 0xED, 0x54, 0x0F, 0xFD, 0xE4, 0xFC, +0x12, 0x49, 0x61, 0xEC, 0x54, 0x0F, 0xFC, 0x90, 0x83, 0x74, 0x12, 0x20, 0xCE, 0x90, 0x83, 0x6E, +0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x60, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, +0xA3, 0xE0, 0xFF, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x83, 0x74, 0x12, 0x49, 0x6E, 0x90, 0x85, 0xBB, +0x12, 0x20, 0xCE, 0xD0, 0x07, 0xD0, 0x06, 0x02, 0x2E, 0xA2, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, +0xD0, 0x12, 0x67, 0xF1, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x8E, 0x19, 0x8F, 0x1A, 0xE5, 0x1E, 0x54, +0x07, 0xC4, 0x33, 0x54, 0xE0, 0x85, 0x19, 0x83, 0x85, 0x1A, 0x82, 0xF0, 0xE5, 0x1D, 0x54, 0x07, +0xC4, 0x33, 0x54, 0xE0, 0xFF, 0xE5, 0x1E, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x4F, 0xA3, 0xF0, 0xEB, +0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0, 0xFF, 0xE5, 0x1D, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x4F, 0x85, +0x1A, 0x82, 0x85, 0x19, 0x83, 0xA3, 0xA3, 0xF0, 0xBD, 0x01, 0x0C, 0x85, 0x1A, 0x82, 0x8E, 0x83, +0xA3, 0xA3, 0xA3, 0x74, 0x03, 0xF0, 0x22, 0x85, 0x1A, 0x82, 0x85, 0x19, 0x83, 0xA3, 0xA3, 0xA3, +0x74, 0x01, 0xF0, 0x22, 0x90, 0x83, 0x78, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0xAD, 0x03, 0xAC, 0x02, +0xE4, 0x90, 0x83, 0x80, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0xC4, 0x74, 0x04, 0xF0, 0x74, 0x6A, 0xA3, +0xF0, 0xEC, 0x54, 0x3F, 0xFC, 0x90, 0x01, 0x40, 0xED, 0xF0, 0xAE, 0x04, 0xEE, 0xA3, 0xF0, 0x90, +0x83, 0x78, 0xE0, 0x24, 0x81, 0x60, 0x34, 0x24, 0xDA, 0x60, 0x1C, 0x24, 0x3C, 0x70, 0x41, 0x90, +0x83, 0x79, 0xE0, 0xC4, 0x33, 0x33, 0x33, 0x54, 0x80, 0x90, 0x83, 0x7D, 0xF0, 0xA3, 0x74, 0x69, +0xF0, 0xA3, 0x74, 0x80, 0xF0, 0x80, 0x2C, 0x90, 0x83, 0x79, 0xE0, 0x54, 0x01, 0x90, 0x83, 0x7D, +0xF0, 0xA3, 0x74, 0xA5, 0xF0, 0xA3, 0x74, 0x01, 0xF0, 0x80, 0x18, 0x90, 0x83, 0x79, 0xE0, 0xC4, +0x54, 0x10, 0x90, 0x83, 0x7D, 0xF0, 0xA3, 0x74, 0x7F, 0xF0, 0xA3, 0x74, 0x10, 0xF0, 0x80, 0x03, +0x7F, 0x00, 0x22, 0x90, 0x83, 0x7E, 0xE0, 0x90, 0x01, 0x06, 0xF0, 0x90, 0x83, 0x7D, 0xE0, 0x60, +0x0E, 0x90, 0x01, 0x42, 0xF0, 0x90, 0x83, 0x7C, 0xE0, 0x90, 0x01, 0x43, 0xF0, 0x80, 0x0D, 0x90, +0x01, 0x43, 0xE4, 0xF0, 0x90, 0x83, 0x7D, 0xE0, 0x90, 0x01, 0x42, 0xF0, 0x90, 0x83, 0x7F, 0xE0, +0xFF, 0x90, 0x01, 0x42, 0xE0, 0x5F, 0xFF, 0x90, 0x83, 0x7D, 0xE0, 0x6F, 0x60, 0xEE, 0x74, 0x04, +0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x6A, 0xA3, 0xF0, 0x90, 0x01, 0x43, 0xE4, 0xF0, 0x7F, 0x01, +0x22, 0x90, 0x02, 0x09, 0xE0, 0xFD, 0x12, 0x1F, 0xA4, 0xFE, 0xAF, 0x05, 0xED, 0x2E, 0x90, 0x80, +0x02, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x03, 0xF0, 0x90, +0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x04, 0xF0, 0x90, 0x00, 0x03, 0x12, +0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x80, 0x05, 0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, +0xAE, 0x05, 0xED, 0x2F, 0x90, 0x80, 0x06, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, +0x12, 0x1F, 0xA4, 0xFF, 0x90, 0x80, 0xE3, 0xF0, 0xBF, 0x01, 0x12, 0x90, 0x00, 0x01, 0x12, 0x1F, +0xBD, 0x64, 0x01, 0x60, 0x17, 0x90, 0x05, 0x22, 0x74, 0x6F, 0xF0, 0x80, 0x0F, 0x90, 0x00, 0x01, +0x12, 0x1F, 0xBD, 0x64, 0x01, 0x60, 0x05, 0x90, 0x05, 0x22, 0xE4, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, +0x22, 0x8F, 0x0F, 0x22, 0x8F, 0x1F, 0x22, 0x22, 0x90, 0x01, 0x30, 0xE4, 0xF0, 0xA3, 0xF0, 0xA3, +0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x38, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, 0x50, +0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x51, 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x52, 0x12, 0x32, +0x1E, 0xE4, 0xFD, 0x7F, 0x53, 0x02, 0x32, 0x1E, 0x90, 0x01, 0x34, 0x74, 0xFF, 0xF0, 0xA3, 0xF0, +0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x3C, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, +0x54, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x55, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x56, 0x12, +0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x57, 0x02, 0x32, 0x1E, 0x75, 0x3D, 0x10, 0xE4, 0xF5, 0x3E, 0x75, +0x3F, 0x07, 0x75, 0x40, 0x02, 0x90, 0x01, 0x30, 0xE5, 0x3D, 0xF0, 0xA3, 0xE5, 0x3E, 0xF0, 0xA3, +0xE5, 0x3F, 0xF0, 0xA3, 0xE5, 0x40, 0xF0, 0x22, 0x75, 0x45, 0x0E, 0x75, 0x46, 0x01, 0x75, 0x47, +0x03, 0x75, 0x48, 0x62, 0x90, 0x01, 0x38, 0xE5, 0x45, 0xF0, 0xA3, 0xE5, 0x46, 0xF0, 0xA3, 0xE5, +0x47, 0xF0, 0xA3, 0xE5, 0x48, 0xF0, 0x22, 0x90, 0x01, 0x01, 0xE0, 0x44, 0x04, 0xF0, 0x90, 0x01, +0x9C, 0x74, 0x7E, 0xF0, 0xA3, 0x74, 0x92, 0xF0, 0xA3, 0x74, 0xA0, 0xF0, 0xA3, 0x74, 0x24, 0xF0, +0x90, 0x01, 0x9B, 0x74, 0x49, 0xF0, 0x90, 0x01, 0x9A, 0x74, 0xE0, 0xF0, 0x90, 0x01, 0x99, 0xE4, +0xF0, 0x90, 0x01, 0x98, 0x04, 0xF0, 0x22, 0xE4, 0x90, 0x82, 0x03, 0xF0, 0xA3, 0xF0, 0x90, 0x01, +0x98, 0xE0, 0x7F, 0x00, 0x30, 0xE4, 0x02, 0x7F, 0x01, 0xEF, 0x64, 0x01, 0x60, 0x3E, 0xC3, 0x90, +0x82, 0x04, 0xE0, 0x94, 0x88, 0x90, 0x82, 0x03, 0xE0, 0x94, 0x13, 0x40, 0x08, 0x90, 0x01, 0xC1, +0xE0, 0x44, 0x10, 0xF0, 0x22, 0x90, 0x82, 0x03, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x49, 0x4B, 0x7F, +0x14, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0xD3, 0x90, 0x82, 0x04, 0xE0, 0x94, 0x32, 0x90, 0x82, 0x03, +0xE0, 0x94, 0x00, 0x40, 0xB9, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE3, 0xB2, 0x22, 0x90, 0x00, 0x54, +0xE0, 0x55, 0x35, 0xF5, 0x39, 0xA3, 0xE0, 0x55, 0x36, 0xF5, 0x3A, 0xA3, 0xE0, 0x55, 0x37, 0xF5, +0x3B, 0xA3, 0xE0, 0x55, 0x38, 0xF5, 0x3C, 0xAD, 0x39, 0x7F, 0x54, 0x12, 0x32, 0x1E, 0xAD, 0x3A, +0x7F, 0x55, 0x12, 0x32, 0x1E, 0xAD, 0x3B, 0x7F, 0x56, 0x12, 0x32, 0x1E, 0xAD, 0x3C, 0x7F, 0x57, +0x12, 0x32, 0x1E, 0x53, 0x91, 0xEF, 0x22, 0x90, 0x01, 0x34, 0xE0, 0x55, 0x3D, 0xF5, 0x41, 0xA3, +0xE0, 0x55, 0x3E, 0xF5, 0x42, 0xA3, 0xE0, 0x55, 0x3F, 0xF5, 0x43, 0xA3, 0xE0, 0x55, 0x40, 0xF5, +0x44, 0x90, 0x01, 0x34, 0xE5, 0x41, 0xF0, 0xA3, 0xE5, 0x42, 0xF0, 0xA3, 0xE5, 0x43, 0xF0, 0xA3, +0xE5, 0x44, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x04, 0x1D, 0xE0, 0x60, +0x1A, 0x90, 0x05, 0x22, 0xE0, 0x54, 0x90, 0x60, 0x07, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x08, 0xF0, +0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE1, 0xE4, 0x7F, 0x00, 0x80, 0x02, 0x7F, 0x01, 0xD0, 0xD0, 0x92, +0xAF, 0x22, 0x90, 0x82, 0x49, 0x12, 0x49, 0x8F, 0x91, 0xE4, 0xEF, 0x64, 0x01, 0x60, 0x02, 0xA1, +0xE0, 0x90, 0x81, 0xF2, 0x12, 0x51, 0xBD, 0x90, 0x82, 0x50, 0x12, 0x5D, 0xEA, 0x90, 0x82, 0x52, +0xEF, 0xF0, 0x90, 0x82, 0x50, 0xA3, 0xE0, 0x24, 0x20, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, +0x90, 0x82, 0x4F, 0xE0, 0xFD, 0xB1, 0xE1, 0x90, 0x82, 0x50, 0xA3, 0xE0, 0x24, 0x30, 0xF9, 0xE4, +0x34, 0xFC, 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, 0x82, 0x4C, 0x12, 0x49, +0x86, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x75, 0x16, 0x06, 0xD0, 0x01, 0xD0, 0x02, 0xD0, 0x03, +0x12, 0x2B, 0xED, 0x90, 0x82, 0x50, 0xA3, 0xE0, 0xFF, 0xA3, 0xE0, 0x2F, 0x24, 0x3A, 0xF9, 0xE4, +0x34, 0xFC, 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, 0x82, 0x4C, 0x12, 0x49, +0x86, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x75, 0x16, 0x06, 0xD0, 0x01, 0xD0, 0x02, 0xD0, 0x03, +0x12, 0x2B, 0xED, 0x90, 0x82, 0x50, 0xA3, 0xE0, 0xFF, 0xA3, 0xE0, 0x2F, 0x24, 0x40, 0xF9, 0xE4, +0x34, 0xFC, 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, 0x82, 0x49, 0x12, 0x49, +0x86, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x75, 0x16, 0x04, 0xD0, 0x01, 0xD0, 0x02, 0xD0, 0x03, +0x12, 0x2B, 0xED, 0x90, 0x06, 0x30, 0xE0, 0x44, 0x10, 0xF0, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, +0x22, 0x90, 0x82, 0xEE, 0xED, 0xF0, 0x90, 0x82, 0xEB, 0x12, 0x49, 0x8F, 0xE4, 0x90, 0x82, 0xEF, +0xF0, 0xA3, 0xF0, 0x12, 0x5D, 0xF8, 0x90, 0x82, 0xEF, 0xEF, 0xF0, 0x90, 0x82, 0xEB, 0x12, 0x49, +0x86, 0xD1, 0xF9, 0x90, 0x82, 0xF0, 0xEF, 0xF0, 0x90, 0x80, 0xFA, 0xE0, 0x24, 0xFE, 0x60, 0x1D, +0x24, 0xFE, 0x60, 0x19, 0x14, 0x60, 0x07, 0x14, 0x60, 0x04, 0x24, 0x05, 0x70, 0x60, 0x7B, 0x01, +0x7A, 0x80, 0x79, 0xFB, 0x90, 0x82, 0xEE, 0xE0, 0xFD, 0xD1, 0x7F, 0x80, 0x23, 0x7B, 0x01, 0x7A, +0x81, 0x79, 0x03, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x8F, 0x90, 0x82, 0xEE, 0xE0, 0x90, 0x82, 0xF7, +0xF0, 0x90, 0x80, 0xFA, 0xE0, 0x90, 0x82, 0xF8, 0xF0, 0x7A, 0x80, 0x79, 0xFB, 0x12, 0x80, 0xDC, +0x90, 0x82, 0xF0, 0xE0, 0xFF, 0x90, 0x82, 0xEB, 0x12, 0x49, 0x86, 0x90, 0x82, 0xEF, 0xE0, 0x7C, +0x00, 0x29, 0xF9, 0xEC, 0x3A, 0xFA, 0xC3, 0xE9, 0x9F, 0xF9, 0xEA, 0x94, 0x00, 0xFA, 0x75, 0x13, +0x01, 0x75, 0x14, 0x80, 0x75, 0x15, 0xFB, 0xA3, 0xE0, 0xF5, 0x16, 0x12, 0x2B, 0xED, 0x22, 0x90, +0x82, 0xF4, 0xED, 0xF0, 0x90, 0x82, 0xF1, 0x12, 0x49, 0x8F, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, +0x90, 0x82, 0xF8, 0xF0, 0x90, 0x82, 0xF1, 0x12, 0x49, 0x86, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, +0x75, 0x16, 0x03, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0xF5, 0x12, 0x2B, 0xED, 0x90, 0x82, 0xF4, 0xE0, +0x70, 0x46, 0xFF, 0x74, 0xF5, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xE0, 0xB4, 0xFF, +0x0E, 0x74, 0xF5, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xE4, 0xF0, 0x80, 0x0F, 0x74, +0xF5, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xE0, 0x04, 0xF0, 0x80, 0x05, 0x0F, 0xEF, +0xB4, 0x03, 0xD0, 0x75, 0x13, 0x01, 0x75, 0x14, 0x82, 0x75, 0x15, 0xF5, 0x75, 0x16, 0x03, 0x90, +0x82, 0xF1, 0x12, 0x49, 0x86, 0x12, 0x2B, 0xED, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, +0x90, 0x83, 0x82, 0x12, 0x49, 0x8F, 0xE4, 0x90, 0x83, 0x85, 0xF0, 0x90, 0x83, 0x82, 0x12, 0x49, +0x86, 0xE9, 0x24, 0x04, 0xF9, 0xE4, 0x3A, 0x8B, 0x13, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x06, +0x7B, 0x01, 0x7A, 0x83, 0x79, 0x86, 0x12, 0x2B, 0xED, 0x90, 0x83, 0x86, 0xE0, 0x20, 0xE0, 0x05, +0x90, 0x81, 0xEF, 0x80, 0x03, 0x90, 0x81, 0xF0, 0xE0, 0x90, 0x80, 0xFA, 0xF0, 0x90, 0x80, 0xFA, +0xE0, 0x14, 0x60, 0x11, 0x14, 0x60, 0x16, 0x24, 0xFE, 0x60, 0x12, 0x14, 0x60, 0x07, 0x14, 0x60, +0x04, 0x24, 0x06, 0x80, 0x10, 0x90, 0x83, 0x85, 0x74, 0x04, 0xF0, 0x80, 0x0D, 0x90, 0x83, 0x85, +0x74, 0x08, 0xF0, 0x80, 0x05, 0xE4, 0x90, 0x83, 0x85, 0xF0, 0x90, 0x83, 0x85, 0xE0, 0xFF, 0xD0, +0xD0, 0x92, 0xAF, 0x22, 0xC3, 0xEE, 0x94, 0x01, 0x40, 0x0A, 0x0D, 0xED, 0x13, 0x90, 0xFD, 0x10, +0xF0, 0xE4, 0x2F, 0xFF, 0x22, 0xE4, 0x90, 0x83, 0xAB, 0xF0, 0xA3, 0xF0, 0x90, 0x05, 0xF8, 0xE0, +0x70, 0x0F, 0xA3, 0xE0, 0x70, 0x0B, 0xA3, 0xE0, 0x70, 0x07, 0xA3, 0xE0, 0x70, 0x03, 0x7F, 0x01, +0x22, 0xD3, 0x90, 0x83, 0xAC, 0xE0, 0x94, 0xE8, 0x90, 0x83, 0xAB, 0xE0, 0x94, 0x03, 0x40, 0x0A, +0x90, 0x01, 0xC0, 0xE0, 0x44, 0x20, 0xF0, 0x7F, 0x00, 0x22, 0x7F, 0x32, 0x7E, 0x00, 0x12, 0x32, +0xAA, 0x90, 0x83, 0xAB, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x49, 0x4B, 0x80, 0xBF, 0x74, 0x45, 0x2F, +0xF8, 0xE6, 0x4D, 0xFE, 0xF6, 0x74, 0x38, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, +0xF0, 0x22, 0x74, 0x45, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE, 0xF6, 0x74, 0x38, 0x2F, +0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0x90, 0x04, 0x1D, 0xE0, 0x70, 0x14, +0x90, 0x80, 0x03, 0xE0, 0xFF, 0xE4, 0xFD, 0x12, 0x51, 0xC1, 0x8E, 0x0D, 0x8F, 0x0E, 0x90, 0x04, +0x1F, 0x74, 0x20, 0xF0, 0x22, 0xAB, 0x07, 0xAA, 0x06, 0xED, 0x2B, 0xFB, 0xE4, 0x3A, 0xFA, 0xC3, +0x90, 0x80, 0xA0, 0xE0, 0x9B, 0x90, 0x80, 0x9F, 0xE0, 0x9A, 0x50, 0x13, 0xA3, 0xE0, 0x24, 0x01, +0xFF, 0x90, 0x80, 0x9F, 0xE0, 0x34, 0x00, 0xFE, 0xC3, 0xEB, 0x9F, 0xFB, 0xEA, 0x9E, 0xFA, 0xEA, +0x90, 0xFD, 0x11, 0xF0, 0xAF, 0x03, 0x74, 0x00, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, +0xE0, 0xFF, 0x22, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0xFB, 0xE0, 0x54, 0xFE, +0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x0A, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81, +0xFC, 0xF0, 0x22, 0x90, 0x82, 0x33, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0x78, 0x3B, 0x7C, 0x82, 0x7D, +0x01, 0x7B, 0xFF, 0x7A, 0x40, 0x79, 0xC0, 0x7E, 0x00, 0x7F, 0x06, 0x12, 0x48, 0xD0, 0x78, 0x41, +0x7C, 0x82, 0x7D, 0x01, 0x7B, 0xFF, 0x7A, 0x40, 0x79, 0xC6, 0x7E, 0x00, 0x7F, 0x04, 0x12, 0x48, +0xD0, 0x78, 0x45, 0x7C, 0x82, 0x7D, 0x01, 0x7B, 0xFF, 0x7A, 0x40, 0x79, 0xCA, 0x7E, 0x00, 0x7F, +0x04, 0x12, 0x48, 0xD0, 0x90, 0x82, 0x34, 0xE0, 0xFF, 0x90, 0x82, 0x33, 0xE0, 0x2F, 0xFF, 0x24, +0x06, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x64, 0x08, 0x60, 0x02, 0x21, 0xB8, 0x74, +0x07, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x64, 0x06, 0x60, 0x02, 0x21, 0xB8, +0x90, 0x06, 0x30, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x82, 0x33, 0xE0, 0x24, 0x0A, 0xF9, 0xE4, 0x34, +0xFB, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x06, 0x7B, 0x01, 0x7A, 0x82, 0x79, +0x35, 0x12, 0x2B, 0xED, 0x90, 0x82, 0x34, 0xE0, 0xFF, 0x90, 0x82, 0x33, 0xE0, 0x2F, 0x24, 0x10, +0xF9, 0xE4, 0x34, 0xFB, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x06, 0x7B, 0x01, +0x7A, 0x82, 0x79, 0x3B, 0x12, 0x2B, 0xED, 0x90, 0x82, 0x34, 0xE0, 0xFF, 0x90, 0x82, 0x33, 0xE0, +0x2F, 0x24, 0x16, 0xF9, 0xE4, 0x34, 0xFB, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, +0x04, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x41, 0x12, 0x2B, 0xED, 0x78, 0x35, 0x7C, 0x82, 0x7D, 0x01, +0x7B, 0x01, 0x7A, 0x80, 0x79, 0xEA, 0x7E, 0x00, 0x7F, 0x06, 0x12, 0x4B, 0xEC, 0xEF, 0x70, 0x58, +0x90, 0x82, 0x34, 0xE0, 0xFF, 0x90, 0x82, 0x33, 0xE0, 0x2F, 0x24, 0x20, 0xF9, 0xE4, 0x34, 0xFB, +0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x04, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x45, +0x12, 0x2B, 0xED, 0x78, 0x45, 0x7C, 0x82, 0x7D, 0x01, 0x7B, 0x01, 0x7A, 0x80, 0x79, 0xF6, 0x7E, +0x00, 0x7F, 0x04, 0x12, 0x4B, 0xEC, 0xEF, 0x70, 0x18, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x3B, 0x90, +0x82, 0x4C, 0x12, 0x49, 0x8F, 0xE4, 0x90, 0x82, 0x4F, 0xF0, 0x7A, 0x82, 0x79, 0x41, 0x02, 0x6D, +0x12, 0x90, 0x06, 0x30, 0xE0, 0x44, 0x20, 0xF0, 0x22, 0x90, 0x02, 0x09, 0xE0, 0x90, 0x82, 0x1A, +0xF0, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0xEF, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81, +0xF0, 0xF0, 0x22, 0x90, 0x02, 0x09, 0xE0, 0xFD, 0x12, 0x1F, 0xA4, 0xFE, 0xAF, 0x05, 0xED, 0x2E, +0x90, 0x81, 0xF1, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x81, 0xF2, +0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x81, 0xF3, 0xF0, 0x90, 0x00, +0x03, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x81, 0xF4, 0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, +0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x81, 0xF5, 0xF0, 0x90, 0x00, 0x05, 0x12, 0x1F, 0xBD, 0xFF, 0xED, +0x2F, 0x90, 0x81, 0xF6, 0xF0, 0x90, 0x00, 0x06, 0x12, 0x1F, 0xBD, 0xFF, 0xAE, 0x05, 0xED, 0x2F, +0x90, 0x81, 0xF7, 0xF0, 0x22, 0x90, 0x02, 0x09, 0xE0, 0xFD, 0x12, 0x1F, 0xA4, 0xFE, 0xAF, 0x05, +0xED, 0x2E, 0x90, 0x81, 0xF8, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, +0x81, 0xF9, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0xAE, 0x05, 0xED, 0x2F, 0x90, 0x81, +0xFA, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x82, 0xEB, 0x12, 0x49, 0x8F, +0x90, 0x82, 0xEE, 0xED, 0xF0, 0xE4, 0x90, 0x83, 0x3A, 0xF0, 0x90, 0x83, 0x3A, 0xE0, 0xFF, 0xC3, +0x94, 0x40, 0x50, 0x14, 0x74, 0xF7, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xE4, 0xF0, +0x90, 0x83, 0x3A, 0xE0, 0x04, 0xF0, 0x80, 0xE2, 0x90, 0x82, 0xEB, 0x12, 0x49, 0x86, 0x8B, 0x13, +0x8A, 0x14, 0x89, 0x15, 0x90, 0x82, 0xEE, 0xE0, 0xF5, 0x16, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0xF7, +0x12, 0x2B, 0xED, 0xE4, 0x90, 0x82, 0xF6, 0xF0, 0x90, 0x82, 0xF6, 0xE0, 0xFF, 0xC3, 0x94, 0x40, +0x50, 0x16, 0x74, 0xF7, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xE0, 0x64, 0x36, 0xF0, +0x90, 0x82, 0xF6, 0xE0, 0x04, 0xF0, 0x80, 0xE0, 0x90, 0x82, 0xEF, 0x12, 0x49, 0x86, 0x90, 0x82, +0xF2, 0xE0, 0xFF, 0xF5, 0x82, 0x75, 0x83, 0x00, 0x74, 0x80, 0x12, 0x1F, 0xFC, 0xEF, 0x75, 0xF0, +0x08, 0xA4, 0x24, 0x00, 0xFF, 0xE5, 0xF0, 0x34, 0x02, 0xFC, 0x90, 0x00, 0x7E, 0x12, 0x1F, 0xFC, +0xEF, 0x90, 0x00, 0x7F, 0x12, 0x1F, 0xFC, 0xE4, 0x90, 0x83, 0x37, 0xF0, 0xA3, 0xF0, 0x90, 0x83, +0x37, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xC3, 0x94, 0xC0, 0xEE, 0x94, 0x00, 0x40, 0x02, 0x81, 0xBD, +0xC3, 0xEF, 0x94, 0x40, 0xEE, 0x94, 0x00, 0x50, 0x52, 0xA3, 0x74, 0x40, 0xF0, 0x74, 0xF7, 0x2F, +0xF9, 0xE4, 0x34, 0x82, 0xFA, 0x7B, 0x01, 0x74, 0x40, 0x44, 0x88, 0xFD, 0x12, 0x28, 0x08, 0x90, +0x83, 0x37, 0xA3, 0xE0, 0x24, 0xFB, 0xF9, 0xE4, 0x34, 0x82, 0xFA, 0x7B, 0x01, 0xA3, 0xE0, 0x44, +0x89, 0xFD, 0x12, 0x28, 0x08, 0x90, 0x83, 0x37, 0xA3, 0xE0, 0x24, 0xFF, 0xF9, 0xE4, 0x34, 0x82, +0xFA, 0x7B, 0x01, 0xA3, 0xE0, 0x44, 0x8A, 0xFD, 0x12, 0x28, 0x08, 0x90, 0x83, 0x37, 0xA3, 0xE0, +0x24, 0x03, 0xF9, 0xE4, 0x34, 0x83, 0xFA, 0x7B, 0x01, 0x61, 0xFE, 0xE4, 0x90, 0x83, 0x39, 0xF0, +0x90, 0x82, 0xEF, 0x12, 0x49, 0x86, 0x90, 0x83, 0x37, 0xE0, 0xFE, 0xA3, 0xE0, 0x29, 0xF9, 0xEA, +0x3E, 0xFA, 0xE9, 0x24, 0xC0, 0xF9, 0xEA, 0x34, 0xFF, 0xFA, 0x74, 0x88, 0xFD, 0x12, 0x28, 0x08, +0x90, 0x82, 0xEF, 0x12, 0x49, 0x86, 0x90, 0x83, 0x37, 0xE0, 0xFE, 0xA3, 0xE0, 0x29, 0xF9, 0xEA, +0x3E, 0xFA, 0xE9, 0x24, 0xC4, 0xF9, 0xEA, 0x34, 0xFF, 0xFA, 0xA3, 0xE0, 0x44, 0x89, 0xFD, 0x12, +0x28, 0x08, 0x90, 0x82, 0xEF, 0x12, 0x49, 0x86, 0x90, 0x83, 0x37, 0xE0, 0xFE, 0xA3, 0xE0, 0x29, +0xF9, 0xEA, 0x3E, 0xFA, 0xE9, 0x24, 0xC8, 0xF9, 0xEA, 0x34, 0xFF, 0xFA, 0xA3, 0xE0, 0x44, 0x8A, +0xFD, 0x12, 0x28, 0x08, 0x90, 0x82, 0xEF, 0x12, 0x49, 0x86, 0x90, 0x83, 0x37, 0xE0, 0xFE, 0xA3, +0xE0, 0x29, 0xF9, 0xEA, 0x3E, 0xFA, 0xE9, 0x24, 0xCC, 0xF9, 0xEA, 0x34, 0xFF, 0xFA, 0xA3, 0xE0, +0x44, 0x8B, 0xFD, 0x12, 0x28, 0x08, 0x90, 0x83, 0x39, 0xE0, 0x44, 0x90, 0x90, 0x01, 0x8C, 0xF0, +0xE4, 0x90, 0x83, 0x3B, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x8C, 0xE0, 0x30, 0xE4, 0x22, 0xC3, 0x90, +0x83, 0x3C, 0xE0, 0x94, 0xE8, 0x90, 0x83, 0x3B, 0xE0, 0x94, 0x03, 0x50, 0x13, 0x7F, 0x01, 0x7E, +0x00, 0x12, 0x32, 0xAA, 0x90, 0x83, 0x3B, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x49, 0x4B, 0x80, 0xD7, +0x90, 0x83, 0x3B, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xC3, 0x94, 0xE8, 0xEE, 0x94, 0x03, 0x40, 0x0C, +0x90, 0x06, 0x31, 0xE0, 0x44, 0x01, 0xF0, 0xEE, 0x90, 0x06, 0x36, 0xF0, 0x90, 0x83, 0x38, 0xE0, +0x54, 0x3F, 0x64, 0x30, 0x70, 0x4B, 0x90, 0x83, 0x3B, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x8C, 0xE0, +0x20, 0xE5, 0x22, 0xC3, 0x90, 0x83, 0x3C, 0xE0, 0x94, 0xE8, 0x90, 0x83, 0x3B, 0xE0, 0x94, 0x03, +0x50, 0x13, 0x7F, 0x01, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x90, 0x83, 0x3B, 0xE4, 0x75, 0xF0, 0x01, +0x12, 0x49, 0x4B, 0x80, 0xD7, 0x90, 0x83, 0x3B, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xC3, 0x94, 0xE8, +0xEE, 0x94, 0x03, 0x40, 0x0C, 0x90, 0x06, 0x31, 0xE0, 0x44, 0x02, 0xF0, 0xEE, 0x90, 0x06, 0x36, +0xF0, 0x90, 0x83, 0x37, 0xE4, 0x75, 0xF0, 0x10, 0x12, 0x49, 0x4B, 0x61, 0x0E, 0x90, 0x82, 0xF3, +0x12, 0x49, 0x86, 0xE9, 0x24, 0x10, 0xF9, 0xE4, 0x3A, 0xFA, 0x7D, 0x80, 0x12, 0x2A, 0x8F, 0x90, +0x82, 0xF3, 0x12, 0x49, 0x86, 0xE9, 0x24, 0x0C, 0xF9, 0xE4, 0x3A, 0xFA, 0x7D, 0x81, 0x12, 0x2A, +0x8F, 0x90, 0x82, 0xF3, 0x12, 0x49, 0x86, 0xE9, 0x24, 0x08, 0xF9, 0xE4, 0x3A, 0xFA, 0x7D, 0x82, +0x12, 0x2A, 0x8F, 0x90, 0x82, 0xF3, 0x12, 0x49, 0x86, 0xE9, 0x24, 0x04, 0xF9, 0xE4, 0x3A, 0xFA, +0x7D, 0x83, 0x12, 0x2A, 0x8F, 0x90, 0x82, 0xF3, 0x12, 0x49, 0x86, 0x7D, 0x84, 0x12, 0x2A, 0x8F, +0xE4, 0x90, 0x83, 0x3A, 0xF0, 0x90, 0x83, 0x3A, 0xE0, 0xFF, 0xC3, 0x94, 0x40, 0x50, 0x14, 0x74, +0xF7, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xE4, 0xF0, 0x90, 0x83, 0x3A, 0xE0, 0x04, +0xF0, 0x80, 0xE2, 0x90, 0x82, 0xEB, 0x12, 0x49, 0x86, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x90, +0x82, 0xEE, 0xE0, 0xF5, 0x16, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0xF7, 0x12, 0x2B, 0xED, 0xE4, 0x90, +0x82, 0xF6, 0xF0, 0x90, 0x82, 0xF6, 0xE0, 0xFF, 0xC3, 0x94, 0x40, 0x50, 0x16, 0x74, 0xF7, 0x2F, +0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xE0, 0x64, 0x5C, 0xF0, 0x90, 0x82, 0xF6, 0xE0, 0x04, +0xF0, 0x80, 0xE0, 0xE4, 0x90, 0x82, 0xF6, 0xF0, 0x90, 0x82, 0xF3, 0x12, 0x49, 0x86, 0x90, 0x82, +0xF6, 0xE0, 0xFF, 0xF5, 0x82, 0x75, 0x83, 0x00, 0x12, 0x1F, 0xBD, 0xFE, 0x90, 0x82, 0xEF, 0x12, +0x49, 0x86, 0x8F, 0x82, 0x75, 0x83, 0x00, 0xEE, 0x12, 0x1F, 0xFC, 0x90, 0x82, 0xF6, 0xE0, 0x04, +0xF0, 0xE0, 0xB4, 0x14, 0xD3, 0x90, 0x82, 0xEF, 0x12, 0x49, 0x86, 0x90, 0x00, 0x14, 0x74, 0x80, +0x12, 0x1F, 0xFC, 0x90, 0x82, 0xF6, 0x74, 0x15, 0xF0, 0x90, 0x82, 0xF6, 0xE0, 0xFF, 0xC3, 0x94, +0x3E, 0x50, 0x17, 0x90, 0x82, 0xEF, 0x12, 0x49, 0x86, 0x8F, 0x82, 0x75, 0x83, 0x00, 0xE4, 0x12, +0x1F, 0xFC, 0x90, 0x82, 0xF6, 0xE0, 0x04, 0xF0, 0x80, 0xDF, 0x90, 0x82, 0xEF, 0x12, 0x49, 0x86, +0x90, 0x00, 0x3E, 0x74, 0x02, 0x12, 0x1F, 0xFC, 0x90, 0x00, 0x3F, 0x74, 0xA0, 0x12, 0x1F, 0xFC, +0xE4, 0x90, 0x83, 0x37, 0xF0, 0xA3, 0xF0, 0x90, 0x83, 0x37, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xC3, +0x94, 0x80, 0xEE, 0x94, 0x00, 0x40, 0x02, 0xE1, 0xA6, 0xC3, 0xEF, 0x94, 0x40, 0xEE, 0x94, 0x00, +0x50, 0x52, 0xA3, 0x74, 0x40, 0xF0, 0x74, 0xF7, 0x2F, 0xF9, 0xE4, 0x34, 0x82, 0xFA, 0x7B, 0x01, +0x74, 0x40, 0x44, 0x88, 0xFD, 0x12, 0x28, 0x08, 0x90, 0x83, 0x37, 0xA3, 0xE0, 0x24, 0xFB, 0xF9, +0xE4, 0x34, 0x82, 0xFA, 0x7B, 0x01, 0xA3, 0xE0, 0x44, 0x89, 0xFD, 0x12, 0x28, 0x08, 0x90, 0x83, +0x37, 0xA3, 0xE0, 0x24, 0xFF, 0xF9, 0xE4, 0x34, 0x82, 0xFA, 0x7B, 0x01, 0xA3, 0xE0, 0x44, 0x8A, +0xFD, 0x12, 0x28, 0x08, 0x90, 0x83, 0x37, 0xA3, 0xE0, 0x24, 0x03, 0xF9, 0xE4, 0x34, 0x83, 0xFA, +0x7B, 0x01, 0xC1, 0xE7, 0xE4, 0x90, 0x83, 0x39, 0xF0, 0x90, 0x82, 0xEF, 0x12, 0x49, 0x86, 0x90, +0x83, 0x37, 0xE0, 0xFE, 0xA3, 0xE0, 0x29, 0xF9, 0xEA, 0x3E, 0xFA, 0xE9, 0x24, 0xC0, 0xF9, 0xEA, +0x34, 0xFF, 0xFA, 0x74, 0x88, 0xFD, 0x12, 0x28, 0x08, 0x90, 0x82, 0xEF, 0x12, 0x49, 0x86, 0x90, +0x83, 0x37, 0xE0, 0xFE, 0xA3, 0xE0, 0x29, 0xF9, 0xEA, 0x3E, 0xFA, 0xE9, 0x24, 0xC4, 0xF9, 0xEA, +0x34, 0xFF, 0xFA, 0xA3, 0xE0, 0x44, 0x89, 0xFD, 0x12, 0x28, 0x08, 0x90, 0x82, 0xEF, 0x12, 0x49, +0x86, 0x90, 0x83, 0x37, 0xE0, 0xFE, 0xA3, 0xE0, 0x29, 0xF9, 0xEA, 0x3E, 0xFA, 0xE9, 0x24, 0xC8, +0xF9, 0xEA, 0x34, 0xFF, 0xFA, 0xA3, 0xE0, 0x44, 0x8A, 0xFD, 0x12, 0x28, 0x08, 0x90, 0x82, 0xEF, +0x12, 0x49, 0x86, 0x90, 0x83, 0x37, 0xE0, 0xFE, 0xA3, 0xE0, 0x29, 0xF9, 0xEA, 0x3E, 0xFA, 0xE9, +0x24, 0xCC, 0xF9, 0xEA, 0x34, 0xFF, 0xFA, 0xA3, 0xE0, 0x44, 0x8B, 0xFD, 0x12, 0x28, 0x08, 0x90, +0x83, 0x39, 0xE0, 0x44, 0x90, 0x90, 0x01, 0x8C, 0xF0, 0xE4, 0x90, 0x83, 0x3B, 0xF0, 0xA3, 0xF0, +0x90, 0x01, 0x8C, 0xE0, 0x30, 0xE4, 0x22, 0xC3, 0x90, 0x83, 0x3C, 0xE0, 0x94, 0xE8, 0x90, 0x83, +0x3B, 0xE0, 0x94, 0x03, 0x50, 0x13, 0x7F, 0x01, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x90, 0x83, 0x3B, +0xE4, 0x75, 0xF0, 0x01, 0x12, 0x49, 0x4B, 0x80, 0xD7, 0x90, 0x83, 0x3B, 0xE0, 0xFE, 0xA3, 0xE0, +0xFF, 0xC3, 0x94, 0xE8, 0xEE, 0x94, 0x03, 0x40, 0x0C, 0x90, 0x06, 0x31, 0xE0, 0x44, 0x01, 0xF0, +0xEE, 0x90, 0x06, 0x36, 0xF0, 0x90, 0x83, 0x38, 0xE0, 0x54, 0x3F, 0x64, 0x30, 0x70, 0x4B, 0x90, +0x83, 0x3B, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x8C, 0xE0, 0x20, 0xE5, 0x22, 0xC3, 0x90, 0x83, 0x3C, +0xE0, 0x94, 0xE8, 0x90, 0x83, 0x3B, 0xE0, 0x94, 0x03, 0x50, 0x13, 0x7F, 0x01, 0x7E, 0x00, 0x12, +0x32, 0xAA, 0x90, 0x83, 0x3B, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x49, 0x4B, 0x80, 0xD7, 0x90, 0x83, +0x3B, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xC3, 0x94, 0xE8, 0xEE, 0x94, 0x03, 0x40, 0x0C, 0x90, 0x06, +0x31, 0xE0, 0x44, 0x02, 0xF0, 0xEE, 0x90, 0x06, 0x36, 0xF0, 0x90, 0x83, 0x37, 0xE4, 0x75, 0xF0, +0x10, 0x12, 0x49, 0x4B, 0xA1, 0xF7, 0x90, 0x82, 0xF3, 0x12, 0x49, 0x86, 0xE9, 0x24, 0x10, 0xF9, +0xE4, 0x3A, 0xFA, 0x7D, 0x80, 0x12, 0x2A, 0x8F, 0x90, 0x82, 0xF3, 0x12, 0x49, 0x86, 0xE9, 0x24, +0x0C, 0xF9, 0xE4, 0x3A, 0xFA, 0x7D, 0x81, 0x12, 0x2A, 0x8F, 0x90, 0x82, 0xF3, 0x12, 0x49, 0x86, +0xE9, 0x24, 0x08, 0xF9, 0xE4, 0x3A, 0xFA, 0x7D, 0x82, 0x12, 0x2A, 0x8F, 0x90, 0x82, 0xF3, 0x12, +0x49, 0x86, 0xE9, 0x24, 0x04, 0xF9, 0xE4, 0x3A, 0xFA, 0x7D, 0x83, 0x12, 0x2A, 0x8F, 0x90, 0x82, +0xF3, 0x12, 0x49, 0x86, 0x7D, 0x84, 0x12, 0x2A, 0x8F, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x82, +0x49, 0xED, 0xF0, 0x90, 0x82, 0x47, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x51, 0xF1, 0x90, 0x82, 0x47, +0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xA3, 0xE0, 0xFD, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, +0x82, 0x4A, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0x90, 0x82, 0x62, 0x74, 0x18, 0xF0, +0x7E, 0x00, 0x7F, 0x80, 0x7D, 0x00, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x6A, 0x12, 0x4C, 0x10, 0x90, +0x81, 0xF4, 0xE0, 0xFF, 0x12, 0x5D, 0x8E, 0x90, 0x82, 0x61, 0xEF, 0xF0, 0xF9, 0xE0, 0xFE, 0x24, +0x21, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0x74, 0x41, 0xF0, 0xEE, 0x24, 0x20, 0xFD, 0xE4, +0x33, 0xFC, 0x90, 0x82, 0x62, 0xE0, 0x7A, 0x00, 0x2D, 0xFE, 0xEA, 0x3C, 0x90, 0x82, 0x66, 0xF0, +0xA3, 0xCE, 0xF0, 0x74, 0x20, 0x29, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, 0x90, 0x82, 0x4C, +0xE0, 0xFD, 0x12, 0x6D, 0xE1, 0x90, 0x82, 0x66, 0xE4, 0x75, 0xF0, 0x08, 0x12, 0x49, 0x4B, 0x90, +0x82, 0x66, 0xE4, 0x75, 0xF0, 0x08, 0x12, 0x49, 0x4B, 0x90, 0x82, 0x66, 0xE0, 0xFF, 0xA3, 0xE0, +0x90, 0x82, 0x64, 0xCF, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x82, 0x6A, 0x74, 0x01, 0xF0, 0xA3, 0x74, +0x03, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0x74, 0x5F, 0xF0, 0x90, 0x82, 0x66, 0xE4, 0x75, 0xF0, 0x04, +0x12, 0x49, 0x4B, 0x90, 0x81, 0x59, 0xE0, 0xFF, 0x7E, 0x02, 0xB4, 0xFE, 0x02, 0x7E, 0xFE, 0x90, +0x82, 0x66, 0xA3, 0xE0, 0xFD, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xEE, 0xF0, +0x74, 0x00, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x90, 0x82, 0x6E, 0xF0, 0x90, +0x82, 0x66, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x49, 0x4B, 0x90, 0x81, 0xEE, 0xE0, 0x90, 0x82, 0x4A, +0xB4, 0x01, 0x0B, 0xE0, 0x44, 0x03, 0xFC, 0xA3, 0xE0, 0x44, 0x10, 0xFD, 0x80, 0x09, 0xE0, 0x44, +0x03, 0xFC, 0xA3, 0xE0, 0x44, 0x20, 0xFD, 0x90, 0x82, 0x68, 0xEC, 0xF0, 0xA3, 0xED, 0xF0, 0x90, +0x82, 0x6F, 0x74, 0x03, 0xF0, 0xA3, 0x74, 0x12, 0xF0, 0x90, 0x82, 0x66, 0xE4, 0x75, 0xF0, 0x02, +0x12, 0x49, 0x4B, 0xEF, 0x64, 0xFE, 0x70, 0x37, 0x90, 0x82, 0x66, 0xA3, 0xE0, 0x24, 0x00, 0xF9, +0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0x8B, 0x13, 0x75, 0x14, 0x81, 0x75, 0x15, 0x5C, +0x75, 0x16, 0x02, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x75, 0x13, 0x01, 0x75, 0x14, 0x81, 0x75, 0x15, +0x5C, 0x75, 0x16, 0x02, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x71, 0x12, 0x2B, 0xED, 0x80, 0x60, 0x90, +0x81, 0x0B, 0xE0, 0xFF, 0xB4, 0x02, 0x2B, 0x90, 0x82, 0x66, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0x24, +0x00, 0xF5, 0x82, 0x74, 0xFC, 0x3C, 0xF5, 0x83, 0xE4, 0xF0, 0x74, 0x01, 0x2D, 0xF5, 0x82, 0x74, +0xFC, 0x3C, 0xF5, 0x83, 0x74, 0x20, 0xF0, 0xE4, 0x90, 0x82, 0x71, 0xF0, 0xA3, 0x74, 0x20, 0xF0, +0x80, 0x2D, 0xEF, 0xB4, 0x04, 0x29, 0x90, 0x82, 0x66, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x24, 0x00, +0xF5, 0x82, 0x74, 0xFC, 0x3E, 0xF5, 0x83, 0xE4, 0xF0, 0x74, 0x01, 0x2F, 0xF5, 0x82, 0x74, 0xFC, +0x3E, 0xF5, 0x83, 0x74, 0x10, 0xF0, 0xE4, 0x90, 0x82, 0x71, 0xF0, 0xA3, 0x74, 0x10, 0xF0, 0x90, +0x82, 0x66, 0xE4, 0x75, 0xF0, 0x02, 0x12, 0x49, 0x4B, 0xE4, 0x90, 0x82, 0x63, 0xF0, 0x90, 0x82, +0x63, 0xE0, 0xFF, 0x24, 0x5E, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, 0xFE, 0x90, 0x82, +0x66, 0xA3, 0xE0, 0xFD, 0xEF, 0x2D, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xEE, +0xF0, 0x90, 0x82, 0x63, 0xE0, 0xFF, 0x24, 0x5E, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xE0, +0xFE, 0x74, 0x73, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xEE, 0xF0, 0x90, 0x82, 0x63, +0xE0, 0x04, 0xF0, 0xE0, 0xB4, 0x08, 0xB7, 0x90, 0x82, 0x66, 0xE4, 0x75, 0xF0, 0x08, 0x12, 0x49, +0x4B, 0x90, 0x82, 0x66, 0xE4, 0x75, 0xF0, 0x20, 0x12, 0x49, 0x4B, 0x90, 0x82, 0x66, 0xE4, 0x75, +0xF0, 0x10, 0x12, 0x49, 0x4B, 0x90, 0x82, 0x66, 0xE4, 0x75, 0xF0, 0x08, 0x12, 0x49, 0x4B, 0x90, +0x82, 0x66, 0xE4, 0x75, 0xF0, 0x08, 0x12, 0x49, 0x4B, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x6A, 0x90, +0x82, 0xEF, 0x12, 0x49, 0x8F, 0x90, 0x82, 0xF2, 0x74, 0x63, 0xF0, 0x7A, 0x82, 0x79, 0x4D, 0xA3, +0x12, 0x49, 0x8F, 0x7A, 0x81, 0x79, 0x0D, 0x7D, 0x10, 0x12, 0x72, 0x63, 0xE4, 0x90, 0x82, 0x63, +0xF0, 0x90, 0x82, 0x63, 0xE0, 0xFF, 0xC3, 0x94, 0x10, 0x50, 0x42, 0x90, 0x82, 0x66, 0xA3, 0xE0, +0xFE, 0xEF, 0x2E, 0xFF, 0x90, 0x82, 0xEA, 0xF0, 0x7E, 0x00, 0x90, 0x81, 0xF4, 0xE0, 0xFD, 0x12, +0x6F, 0x74, 0x90, 0x82, 0x61, 0xEF, 0xF0, 0x90, 0x82, 0x63, 0xE0, 0x24, 0x4D, 0xF5, 0x82, 0xE4, +0x34, 0x82, 0xF5, 0x83, 0xE0, 0xFF, 0x90, 0x82, 0x61, 0xE0, 0x24, 0x00, 0xF5, 0x82, 0xE4, 0x34, +0xFC, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x82, 0x63, 0xE0, 0x04, 0xF0, 0x80, 0xB4, 0x12, 0x6C, 0xE4, +0xBF, 0x01, 0x19, 0x90, 0x81, 0xF4, 0x12, 0x51, 0xBD, 0x90, 0x82, 0x61, 0xEF, 0xF0, 0x90, 0x81, +0xF4, 0xE0, 0x90, 0x04, 0x25, 0xF0, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, +0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x81, 0xF0, 0xE0, 0xFD, 0xB4, 0x02, 0x0C, +0x90, 0x82, 0x81, 0x74, 0x80, 0xF0, 0xA3, 0x74, 0x08, 0xF0, 0x80, 0x0E, 0xED, 0xB4, 0x04, 0x0A, +0x90, 0x82, 0x81, 0x74, 0x80, 0xF0, 0xA3, 0x74, 0x10, 0xF0, 0xEF, 0x64, 0x02, 0x4E, 0x60, 0x02, +0x61, 0xDC, 0x90, 0x81, 0x56, 0xE0, 0xFF, 0x64, 0xFE, 0x70, 0x02, 0x61, 0xDC, 0xEF, 0x64, 0x02, +0x60, 0x07, 0xEF, 0x64, 0x03, 0x60, 0x02, 0x61, 0xDC, 0x90, 0x81, 0xB6, 0xE0, 0xFE, 0xA3, 0xE0, +0xFD, 0xED, 0xFF, 0x90, 0x82, 0x85, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x7E, 0x00, 0x7F, 0x20, 0x7D, +0x00, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x61, 0x12, 0x4C, 0x10, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0xB8, +0x90, 0x86, 0x67, 0x12, 0x49, 0x8F, 0x7A, 0x82, 0x79, 0x61, 0x90, 0x86, 0x6A, 0x12, 0x49, 0x8F, +0x7A, 0x81, 0x79, 0x1D, 0x7D, 0x03, 0x12, 0x02, 0x00, 0x75, 0x13, 0x01, 0x75, 0x14, 0x82, 0x75, +0x15, 0x69, 0x75, 0x16, 0x10, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x4A, 0x12, 0x2B, 0xED, 0x90, 0x82, +0x67, 0xE0, 0xFF, 0x54, 0x03, 0x90, 0x82, 0x87, 0xF0, 0x70, 0x02, 0x04, 0xF0, 0xEF, 0x54, 0x04, +0x90, 0x82, 0x88, 0xF0, 0x90, 0x82, 0x87, 0xE0, 0xFF, 0x90, 0x82, 0x5A, 0xF0, 0x90, 0x82, 0x82, +0xE0, 0x2F, 0xFE, 0x90, 0x82, 0x81, 0xE0, 0x34, 0x00, 0x90, 0x82, 0x83, 0xF0, 0xA3, 0xCE, 0xF0, +0x7E, 0x00, 0x7F, 0x06, 0x7D, 0x00, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x5B, 0x12, 0x4C, 0x10, 0x90, +0x82, 0x5A, 0xE0, 0xFF, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x4A, 0x71, 0xE1, 0xD0, 0xD0, 0x92, 0xAF, +0x22, 0x90, 0x82, 0x89, 0xEF, 0xF0, 0xA3, 0x12, 0x49, 0x8F, 0x90, 0x82, 0x8A, 0x12, 0x49, 0x86, +0x12, 0x1F, 0xA4, 0x90, 0x06, 0x74, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x06, 0x75, +0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x06, 0x76, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, +0xBD, 0x90, 0x06, 0x77, 0xF0, 0x90, 0x82, 0x89, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x02, 0x90, +0x06, 0x70, 0xF0, 0xA3, 0xE4, 0xF0, 0xA3, 0x04, 0xF0, 0xA3, 0x74, 0x80, 0xF0, 0x7F, 0x01, 0x7E, +0x00, 0x12, 0x32, 0xAA, 0x90, 0x82, 0x8A, 0x12, 0x49, 0x86, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, +0x90, 0x06, 0x74, 0xF0, 0x90, 0x00, 0x05, 0x12, 0x1F, 0xBD, 0x90, 0x06, 0x75, 0xF0, 0x90, 0x00, +0x06, 0x12, 0x1F, 0xBD, 0x90, 0x06, 0x76, 0xF0, 0x90, 0x00, 0x07, 0x12, 0x1F, 0xBD, 0x90, 0x06, +0x77, 0xF0, 0x90, 0x82, 0x89, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x03, 0x90, 0x06, 0x70, 0xF0, +0xA3, 0xE4, 0xF0, 0xA3, 0x04, 0xF0, 0xA3, 0x74, 0x80, 0xF0, 0x7F, 0x01, 0x7E, 0x00, 0x12, 0x32, +0xAA, 0x90, 0x82, 0x8A, 0x12, 0x49, 0x86, 0x90, 0x00, 0x08, 0x12, 0x1F, 0xBD, 0x90, 0x06, 0x74, +0xF0, 0x90, 0x00, 0x09, 0x12, 0x1F, 0xBD, 0x90, 0x06, 0x75, 0xF0, 0x90, 0x00, 0x0A, 0x12, 0x1F, +0xBD, 0x90, 0x06, 0x76, 0xF0, 0x90, 0x00, 0x0B, 0x12, 0x1F, 0xBD, 0x90, 0x06, 0x77, 0xF0, 0x90, +0x82, 0x89, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x04, 0x90, 0x06, 0x70, 0xF0, 0xA3, 0xE4, 0xF0, +0xA3, 0x04, 0xF0, 0xA3, 0x74, 0x80, 0xF0, 0x7F, 0x01, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x90, 0x82, +0x8A, 0x12, 0x49, 0x86, 0x90, 0x00, 0x0C, 0x12, 0x1F, 0xBD, 0x90, 0x06, 0x74, 0xF0, 0x90, 0x00, +0x0D, 0x12, 0x1F, 0xBD, 0x90, 0x06, 0x75, 0xF0, 0x90, 0x00, 0x0E, 0x12, 0x1F, 0xBD, 0x90, 0x06, +0x76, 0xF0, 0x90, 0x00, 0x0F, 0x12, 0x1F, 0xBD, 0x90, 0x06, 0x77, 0xF0, 0x90, 0x82, 0x89, 0xE0, +0x75, 0xF0, 0x08, 0xA4, 0x24, 0x05, 0x90, 0x06, 0x70, 0xF0, 0xA3, 0xE4, 0xF0, 0xA3, 0x04, 0xF0, +0xA3, 0x74, 0x80, 0xF0, 0x7F, 0x01, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x90, 0x82, 0x89, 0xE0, 0xFF, +0x44, 0x10, 0x90, 0x06, 0x74, 0xF0, 0xA3, 0x74, 0x80, 0xF0, 0xA3, 0x74, 0xFF, 0xF0, 0xA3, 0xF0, +0xEF, 0x75, 0xF0, 0x08, 0xA4, 0x90, 0x06, 0x70, 0xF0, 0xA3, 0xE4, 0xF0, 0xA3, 0x04, 0xF0, 0xA3, +0x74, 0x80, 0xF0, 0x7F, 0x01, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x90, 0x06, 0x74, 0x74, 0xFF, 0xF0, +0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x82, 0x89, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x04, 0x90, +0x06, 0x70, 0xF0, 0xA3, 0xE4, 0xF0, 0xA3, 0x04, 0xF0, 0xA3, 0x74, 0x80, 0xF0, 0x7F, 0x01, 0x7E, +0x00, 0x12, 0x32, 0xAA, 0x90, 0x06, 0x72, 0xE4, 0xF0, 0x22, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x8F, +0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFD, 0x70, 0x04, 0xFE, 0x7F, 0x01, 0x22, 0xED, 0xC3, 0x94, +0x06, 0x40, 0x68, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0xE9, 0x24, 0x02, 0xF9, 0xE4, 0x3A, 0xA8, +0x01, 0xFC, 0xAD, 0x03, 0x7B, 0x01, 0x7A, 0x83, 0x79, 0x4F, 0x7E, 0x00, 0x7F, 0x04, 0x12, 0x4B, +0xEC, 0xEF, 0x70, 0x47, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0x90, 0x00, 0x06, 0x12, 0x1F, 0xBD, +0x64, 0x01, 0x70, 0x37, 0x90, 0x00, 0x07, 0x12, 0x1F, 0xBD, 0x70, 0x2F, 0x90, 0x83, 0x8C, 0x12, +0x49, 0x86, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, 0x83, 0x92, 0x12, 0x49, 0x86, 0x12, 0x49, +0x98, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x24, 0x02, 0xFF, +0x90, 0x83, 0x92, 0x12, 0x49, 0x86, 0x90, 0x00, 0x03, 0xC1, 0xDF, 0x90, 0x83, 0x8F, 0x12, 0x49, +0x86, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0xE9, 0x24, 0x05, +0xF9, 0xE4, 0x3A, 0xFA, 0xC3, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 0xE9, 0x95, 0x82, 0xEA, 0x95, +0x83, 0x50, 0x53, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xC3, +0x94, 0x14, 0x40, 0x42, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0xE9, 0x24, 0x02, 0xF9, 0xE4, 0x3A, +0xA8, 0x01, 0xFC, 0xAD, 0x03, 0x7B, 0x01, 0x7A, 0x83, 0x79, 0x5B, 0x7E, 0x00, 0x7F, 0x04, 0x12, +0x4B, 0xEC, 0xEF, 0x70, 0x21, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0xE9, 0x24, 0x06, 0xF9, 0xE4, +0x3A, 0xFA, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, 0x83, 0x92, 0x12, 0x49, 0x86, 0x90, 0x00, +0x08, 0x12, 0x49, 0xE7, 0xE1, 0x54, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0x90, 0x00, 0x01, 0x12, +0x1F, 0xBD, 0xD3, 0x94, 0x06, 0x40, 0x5E, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0xE9, 0x24, 0x02, +0xF9, 0xE4, 0x3A, 0xA8, 0x01, 0xFC, 0xAD, 0x03, 0x7B, 0x01, 0x7A, 0x83, 0x79, 0x53, 0x7E, 0x00, +0x7F, 0x04, 0x12, 0x4B, 0xEC, 0xEF, 0x70, 0x3D, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0xE9, 0x24, +0x06, 0xF9, 0xE4, 0x3A, 0xFA, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, 0x83, 0x92, 0x12, 0x49, +0x86, 0x90, 0x00, 0x0B, 0x12, 0x49, 0xE7, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0x90, 0x00, 0x01, +0x12, 0x1F, 0xBD, 0x24, 0xFC, 0xFF, 0x90, 0x83, 0x92, 0x12, 0x49, 0x86, 0x90, 0x00, 0x0E, 0xEF, +0x12, 0x1F, 0xFC, 0x80, 0x6F, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0x90, 0x00, 0x01, 0x12, 0x1F, +0xBD, 0xD3, 0x94, 0x06, 0x40, 0x5E, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0xE9, 0x24, 0x02, 0xF9, +0xE4, 0x3A, 0xA8, 0x01, 0xFC, 0xAD, 0x03, 0x7B, 0x01, 0x7A, 0x83, 0x79, 0x57, 0x7E, 0x00, 0x7F, +0x04, 0x12, 0x4B, 0xEC, 0xEF, 0x70, 0x3D, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0xE9, 0x24, 0x06, +0xF9, 0xE4, 0x3A, 0xFA, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, 0x83, 0x92, 0x12, 0x49, 0x86, +0x90, 0x00, 0x0F, 0x12, 0x49, 0xE7, 0x90, 0x83, 0x8C, 0x12, 0x49, 0x86, 0x90, 0x00, 0x01, 0x12, +0x1F, 0xBD, 0x24, 0xFC, 0xFF, 0x90, 0x83, 0x92, 0x12, 0x49, 0x86, 0x90, 0x00, 0x12, 0xEF, 0x12, +0x1F, 0xFC, 0x80, 0x00, 0xE4, 0xFE, 0xFF, 0x22, 0x90, 0x83, 0x40, 0x12, 0x20, 0xCE, 0x90, 0x83, +0x3D, 0x12, 0x49, 0x8F, 0xE4, 0x90, 0x83, 0x4D, 0xF0, 0xA3, 0xF0, 0x90, 0x83, 0x47, 0x12, 0x49, +0x8F, 0x90, 0x83, 0x40, 0x12, 0x49, 0x6E, 0xE9, 0x2F, 0xF9, 0xEA, 0x3E, 0xFA, 0xEB, 0x3D, 0xFB, +0x90, 0x83, 0x4A, 0x12, 0x49, 0x8F, 0x90, 0x83, 0x4A, 0x12, 0x49, 0x86, 0xC0, 0x03, 0xC0, 0x02, +0xC0, 0x01, 0x90, 0x83, 0x47, 0x12, 0x49, 0x86, 0xE9, 0x24, 0x01, 0xF9, 0xE4, 0x3A, 0xFA, 0xC3, +0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 0xE9, 0x95, 0x82, 0xEA, 0x95, 0x83, 0x40, 0x03, 0x02, 0x80, +0xD3, 0x90, 0x83, 0x47, 0x12, 0x49, 0x86, 0x12, 0x1F, 0xA4, 0xB4, 0xDD, 0x4F, 0x90, 0x83, 0x40, +0x12, 0x49, 0x6E, 0x90, 0x83, 0x3D, 0x12, 0x49, 0x86, 0xE9, 0x2F, 0xF9, 0xEA, 0x3E, 0xFA, 0xEB, +0x3D, 0xFB, 0xE9, 0x24, 0xFF, 0xF9, 0xEA, 0x34, 0xFF, 0xFA, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, +0x90, 0x83, 0x47, 0x12, 0x49, 0x86, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 0x6B, 0x70, 0x08, 0xE9, +0x65, 0x82, 0x70, 0x03, 0xEA, 0x65, 0x83, 0x70, 0x03, 0x02, 0x80, 0xD3, 0x90, 0x83, 0x47, 0x12, +0x49, 0x86, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x70, 0x02, 0x01, 0xD3, 0x90, 0x83, 0x4A, 0x12, +0x49, 0x86, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, 0x83, 0x47, 0x12, 0x49, 0x86, 0x90, 0x00, +0x01, 0x12, 0x1F, 0xBD, 0xFF, 0x7E, 0x00, 0xE9, 0x24, 0x02, 0xF9, 0xE4, 0x3A, 0xFA, 0xE9, 0x2F, +0xF9, 0xEE, 0x3A, 0xFA, 0xD3, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xE0, 0xE9, 0x95, 0x82, 0xEA, 0x95, +0x83, 0x40, 0x02, 0x01, 0xD3, 0x90, 0x83, 0x47, 0x12, 0x49, 0x86, 0x12, 0x1F, 0xA4, 0xFF, 0xB4, +0x30, 0x36, 0x90, 0x83, 0x47, 0x12, 0x49, 0x86, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, 0x83, +0x44, 0x12, 0x49, 0x86, 0x90, 0x00, 0x04, 0x12, 0x49, 0xE7, 0x90, 0x83, 0x47, 0x12, 0x49, 0x86, +0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x24, 0x02, 0xFE, 0x90, 0x83, 0x44, 0x12, 0x49, 0x86, 0x90, +0x00, 0x07, 0xEE, 0x12, 0x1F, 0xFC, 0x80, 0x2F, 0xEF, 0xB4, 0xDD, 0x2B, 0x90, 0x83, 0x4A, 0x12, +0x49, 0x86, 0x90, 0x83, 0x8F, 0x12, 0x49, 0x8F, 0x90, 0x83, 0x44, 0x12, 0x49, 0x86, 0x90, 0x83, +0x92, 0x12, 0x49, 0x8F, 0x90, 0x83, 0x47, 0x12, 0x49, 0x86, 0x12, 0x7D, 0x7A, 0x90, 0x83, 0x4D, +0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x80, 0x1C, 0x90, 0x83, 0x47, 0x12, 0x49, 0x86, 0x90, 0x00, 0x01, +0x12, 0x1F, 0xBD, 0x24, 0x02, 0xFF, 0xE4, 0x33, 0x90, 0x83, 0x48, 0x8F, 0xF0, 0x12, 0x49, 0x4B, +0x02, 0x7F, 0x86, 0x90, 0x83, 0x4D, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x22, 0x90, 0x82, 0xF1, 0x12, +0x49, 0x8F, 0x90, 0x82, 0xF7, 0xE0, 0x60, 0x02, 0x21, 0xB0, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, +0x12, 0x1F, 0xA4, 0xF4, 0x60, 0x02, 0x21, 0xA5, 0x12, 0x1F, 0xEA, 0x90, 0x82, 0xF4, 0x12, 0x49, +0x86, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xF4, 0x60, 0x02, 0x21, 0x95, 0x90, 0x00, 0x01, 0x12, +0x1F, 0xFC, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xF4, 0x70, 0x6F, 0x90, 0x82, 0xF4, 0x12, 0x49, +0x86, 0x90, 0x00, 0x02, 0xE4, 0x12, 0x1F, 0xFC, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0xF4, 0x70, +0x4E, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, 0x90, 0x00, 0x03, 0xE4, 0x12, 0x1F, 0xFC, 0x90, 0x00, +0x04, 0x12, 0x1F, 0xBD, 0xF4, 0x70, 0x2D, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, 0x90, 0x00, 0x04, +0xE4, 0x12, 0x1F, 0xFC, 0x90, 0x00, 0x05, 0x12, 0x1F, 0xBD, 0x90, 0x82, 0xF4, 0xB4, 0xFF, 0x0C, +0x12, 0x49, 0x86, 0x90, 0x00, 0x05, 0xE4, 0x12, 0x1F, 0xFC, 0x80, 0x44, 0x12, 0x49, 0x86, 0x90, +0x00, 0x05, 0x80, 0x2A, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, 0x90, 0x00, 0x04, 0x80, 0x1F, 0x90, +0x82, 0xF4, 0x12, 0x49, 0x86, 0x90, 0x00, 0x03, 0x80, 0x14, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, +0x90, 0x00, 0x02, 0x80, 0x09, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, 0x90, 0x00, 0x01, 0x74, 0x01, +0x12, 0x49, 0x18, 0x80, 0x0B, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, 0x74, 0x01, 0x12, 0x48, 0xF6, +0x90, 0x82, 0xF8, 0xE0, 0xFF, 0x64, 0x04, 0x60, 0x02, 0x41, 0x5F, 0x90, 0x82, 0xF4, 0x12, 0x49, +0x86, 0x12, 0x1F, 0xA4, 0xFE, 0x90, 0x82, 0xF1, 0x12, 0x49, 0x86, 0xEE, 0x12, 0x1F, 0xEA, 0x90, +0x82, 0xF4, 0x12, 0x49, 0x86, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFE, 0x90, 0x82, 0xF1, 0x12, +0x49, 0x86, 0x90, 0x00, 0x01, 0xEE, 0x12, 0x1F, 0xFC, 0x90, 0x00, 0x02, 0xE4, 0x12, 0x1F, 0xFC, +0x90, 0x00, 0x03, 0x74, 0x20, 0x12, 0x1F, 0xFC, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, 0x90, 0x00, +0x02, 0x12, 0x1F, 0xBD, 0xFE, 0x90, 0x82, 0xF1, 0x12, 0x49, 0x86, 0x90, 0x00, 0x04, 0xEE, 0x12, +0x1F, 0xFC, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0xFE, 0x90, +0x82, 0xF1, 0x12, 0x49, 0x86, 0x90, 0x00, 0x05, 0xEE, 0x12, 0x1F, 0xFC, 0x90, 0x82, 0xF4, 0x12, +0x49, 0x86, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFE, 0x90, 0x82, 0xF1, 0x12, 0x49, 0x86, 0x90, +0x00, 0x06, 0xEE, 0x12, 0x1F, 0xFC, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, 0x90, 0x00, 0x05, 0x12, +0x1F, 0xBD, 0xFE, 0x90, 0x82, 0xF1, 0x12, 0x49, 0x86, 0x90, 0x00, 0x07, 0xEE, 0x61, 0x1F, 0xEF, +0x64, 0x02, 0x60, 0x02, 0x61, 0x22, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, 0x12, 0x1F, 0xA4, 0xFF, +0x90, 0x82, 0xF1, 0x12, 0x49, 0x86, 0xEF, 0x12, 0x1F, 0xEA, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, +0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x44, 0x20, 0x54, 0x7F, 0xFF, 0x90, 0x82, 0xF1, 0x12, 0x49, +0x86, 0x90, 0x00, 0x01, 0xEF, 0x12, 0x1F, 0xFC, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, 0x90, 0x00, +0x01, 0x12, 0x1F, 0xBD, 0xFF, 0x90, 0x82, 0xF1, 0x12, 0x49, 0x86, 0x90, 0x00, 0x02, 0xEF, 0x12, +0x1F, 0xFC, 0x90, 0x00, 0x03, 0x74, 0x20, 0x12, 0x1F, 0xFC, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, +0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0x90, 0x82, 0xF1, 0x12, 0x49, 0x86, 0x90, 0x00, 0x04, +0xEF, 0x12, 0x1F, 0xFC, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, +0xFF, 0x90, 0x82, 0xF1, 0x12, 0x49, 0x86, 0x90, 0x00, 0x05, 0xEF, 0x12, 0x1F, 0xFC, 0x90, 0x82, +0xF4, 0x12, 0x49, 0x86, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0x90, 0x82, 0xF1, 0x12, 0x49, +0x86, 0x90, 0x00, 0x06, 0xEF, 0x12, 0x1F, 0xFC, 0x90, 0x82, 0xF4, 0x12, 0x49, 0x86, 0x90, 0x00, +0x05, 0x12, 0x1F, 0xBD, 0xFF, 0x90, 0x82, 0xF1, 0x12, 0x49, 0x86, 0x90, 0x00, 0x07, 0xEF, 0x12, +0x1F, 0xFC, 0x22, 0x00, 0xAF, 0x8C, +}; +u4Byte ArrayLength_MP_8188E_FW_WoWLAN_S = 17222; + + +void +ODM_ReadFirmware_MP_8188E_FW_WoWLAN_S( + IN PDM_ODM_T pDM_Odm, + OUT u1Byte *pFirmware, + OUT u4Byte *pFirmwareSize +) +{ +#if (DM_ODM_SUPPORT_TYPE & (ODM_CE)) + *((SIZE_PTR *)pFirmware) = (SIZE_PTR)Array_MP_8188E_FW_WoWLAN_S; +#else + ODM_MoveMemory(pDM_Odm, pFirmware, Array_MP_8188E_FW_WoWLAN_S, ArrayLength_MP_8188E_FW_WoWLAN_S); +#endif + *pFirmwareSize = ArrayLength_MP_8188E_FW_WoWLAN_S; +} + + +u1Byte Array_MP_8188E_FW_WoWLAN_T[] = { +0xE1, 0x88, 0x30, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x15, 0x22, 0x26, 0x28, 0x3D, 0x00, 0x00, +0x8F, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x02, 0x46, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xE1, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xE1, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x50, 0x17, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xE7, 0x09, 0xF6, 0x08, 0xDF, 0xFA, 0x80, 0x46, 0xE7, 0x09, 0xF2, 0x08, 0xDF, 0xFA, 0x80, 0x3E, +0x88, 0x82, 0x8C, 0x83, 0xE7, 0x09, 0xF0, 0xA3, 0xDF, 0xFA, 0x80, 0x32, 0xE3, 0x09, 0xF6, 0x08, +0xDF, 0xFA, 0x80, 0x78, 0xE3, 0x09, 0xF2, 0x08, 0xDF, 0xFA, 0x80, 0x70, 0x88, 0x82, 0x8C, 0x83, +0xE3, 0x09, 0xF0, 0xA3, 0xDF, 0xFA, 0x80, 0x64, 0x89, 0x82, 0x8A, 0x83, 0xE0, 0xA3, 0xF6, 0x08, +0xDF, 0xFA, 0x80, 0x58, 0x89, 0x82, 0x8A, 0x83, 0xE0, 0xA3, 0xF2, 0x08, 0xDF, 0xFA, 0x80, 0x4C, +0x80, 0xD2, 0x80, 0xFA, 0x80, 0xC6, 0x80, 0xD4, 0x80, 0x69, 0x80, 0xF2, 0x80, 0x33, 0x80, 0x10, +0x80, 0xA6, 0x80, 0xEA, 0x80, 0x9A, 0x80, 0xA8, 0x80, 0xDA, 0x80, 0xE2, 0x80, 0xCA, 0x80, 0x33, +0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE4, 0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, +0xCC, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xDF, 0xE9, 0xDE, 0xE7, 0x80, +0x0D, 0x89, 0x82, 0x8A, 0x83, 0xE4, 0x93, 0xA3, 0xF6, 0x08, 0xDF, 0xF9, 0xEC, 0xFA, 0xA9, 0xF0, +0xED, 0xFB, 0x22, 0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, +0xC5, 0x83, 0xCC, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xDF, 0xEA, 0xDE, +0xE8, 0x80, 0xDB, 0x89, 0x82, 0x8A, 0x83, 0xE4, 0x93, 0xA3, 0xF2, 0x08, 0xDF, 0xF9, 0x80, 0xCC, +0x88, 0xF0, 0xEF, 0x60, 0x01, 0x0E, 0x4E, 0x60, 0xC3, 0x88, 0xF0, 0xED, 0x24, 0x02, 0xB4, 0x04, +0x00, 0x50, 0xB9, 0xF5, 0x82, 0xEB, 0x24, 0x02, 0xB4, 0x04, 0x00, 0x50, 0xAF, 0x23, 0x23, 0x45, +0x82, 0x23, 0x90, 0x41, 0x50, 0x73, 0xC5, 0xF0, 0xF8, 0xA3, 0xE0, 0x28, 0xF0, 0xC5, 0xF0, 0xF8, +0xE5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83, 0xE0, 0x38, 0xF0, 0x22, 0xEF, 0x4B, 0xFF, 0xEE, +0x4A, 0xFE, 0xED, 0x49, 0xFD, 0xEC, 0x48, 0xFC, 0x22, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0xA3, 0xE0, +0xFE, 0xA3, 0xE0, 0xFF, 0x22, 0xA4, 0x25, 0x82, 0xF5, 0x82, 0xE5, 0xF0, 0x35, 0x83, 0xF5, 0x83, +0x22, 0xE0, 0xFB, 0xA3, 0xE0, 0xFA, 0xA3, 0xE0, 0xF9, 0x22, 0xEB, 0xF0, 0xA3, 0xEA, 0xF0, 0xA3, +0xE9, 0xF0, 0x22, 0xD0, 0x83, 0xD0, 0x82, 0xF8, 0xE4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, +0x0D, 0xA3, 0xA3, 0x93, 0xF8, 0x74, 0x01, 0x93, 0xF5, 0x82, 0x88, 0x83, 0xE4, 0x73, 0x74, 0x02, +0x93, 0x68, 0x60, 0xEF, 0xA3, 0xA3, 0xA3, 0x80, 0xDF, 0xE3, 0xF5, 0xF0, 0x09, 0xE2, 0x08, 0xB5, +0xF0, 0x6B, 0xDF, 0xF5, 0x80, 0x67, 0xE3, 0xF5, 0xF0, 0x09, 0xE6, 0x08, 0xB5, 0xF0, 0x5E, 0xDF, +0xF5, 0x80, 0x5A, 0x87, 0xF0, 0x09, 0xE6, 0x08, 0xB5, 0xF0, 0x52, 0xDF, 0xF6, 0x80, 0x4E, 0x87, +0xF0, 0x09, 0xE2, 0x08, 0xB5, 0xF0, 0x46, 0xDF, 0xF6, 0x80, 0x42, 0x88, 0x82, 0x8C, 0x83, 0x87, +0xF0, 0x09, 0xE0, 0xA3, 0xB5, 0xF0, 0x36, 0xDF, 0xF6, 0x80, 0x32, 0x88, 0x82, 0x8C, 0x83, 0x87, +0xF0, 0x09, 0xE4, 0x93, 0xA3, 0xB5, 0xF0, 0x25, 0xDF, 0xF5, 0x80, 0x21, 0x88, 0x82, 0x8C, 0x83, +0xE3, 0xF5, 0xF0, 0x09, 0xE0, 0xA3, 0xB5, 0xF0, 0x14, 0xDF, 0xF5, 0x80, 0x10, 0x88, 0x82, 0x8C, +0x83, 0xE3, 0xF5, 0xF0, 0x09, 0xE4, 0x93, 0xA3, 0xB5, 0xF0, 0x02, 0xDF, 0xF4, 0x02, 0x43, 0x98, +0x80, 0x87, 0x80, 0xE9, 0x80, 0x90, 0x80, 0xD4, 0x80, 0x3E, 0x80, 0x15, 0x80, 0x6E, 0x80, 0x7E, +0x80, 0x9D, 0x80, 0xB7, 0x80, 0x8D, 0x80, 0xA3, 0x80, 0x51, 0x80, 0x74, 0x80, 0x3C, 0x02, 0x43, +0xA4, 0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE4, 0x93, 0xF5, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, +0xCC, 0xC5, 0x83, 0xCC, 0xE4, 0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xB5, +0xF0, 0x76, 0xDF, 0xE3, 0xDE, 0xE1, 0x80, 0x70, 0x89, 0x82, 0x8A, 0x83, 0xE4, 0x93, 0xF5, 0xF0, +0xA3, 0xE2, 0x08, 0xB5, 0xF0, 0x62, 0xDF, 0xF4, 0x80, 0x5E, 0x89, 0x82, 0x8A, 0x83, 0xE0, 0xF5, +0xF0, 0xA3, 0xE6, 0x08, 0xB5, 0xF0, 0x51, 0xDF, 0xF5, 0x80, 0x4D, 0x89, 0x82, 0x8A, 0x83, 0xE0, +0xF5, 0xF0, 0xA3, 0xE2, 0x08, 0xB5, 0xF0, 0x40, 0xDF, 0xF5, 0x80, 0x3C, 0x89, 0x82, 0x8A, 0x83, +0xE4, 0x93, 0xF5, 0xF0, 0xA3, 0xE6, 0x08, 0xB5, 0xF0, 0x2E, 0xDF, 0xF4, 0x80, 0x2A, 0x80, 0x02, +0x80, 0x57, 0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE4, 0x93, 0xF5, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, +0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xE0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xB5, +0xF0, 0x06, 0xDF, 0xE4, 0xDE, 0xE2, 0x80, 0x00, 0x7F, 0xFF, 0xB5, 0xF0, 0x02, 0x0F, 0x22, 0x40, +0x02, 0x7F, 0x01, 0x22, 0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE0, 0xF5, 0xF0, 0xA3, 0xC8, 0xC5, +0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xE0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, +0xB5, 0xF0, 0xD5, 0xDF, 0xE5, 0xDE, 0xE3, 0x80, 0xCF, 0x89, 0x82, 0x8A, 0x83, 0xEC, 0xFA, 0xE0, +0xF5, 0xF0, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xE4, 0x93, 0xA3, 0xC8, 0xC5, +0x82, 0xC8, 0xCC, 0xC5, 0x83, 0xCC, 0xB5, 0xF0, 0xAF, 0xDF, 0xE4, 0xDE, 0xE2, 0x80, 0xA9, 0x88, +0xF0, 0xEF, 0x60, 0x01, 0x0E, 0x4E, 0x60, 0xAB, 0xED, 0x24, 0x02, 0xB4, 0x04, 0x00, 0x50, 0x98, +0xF5, 0x82, 0xEB, 0x24, 0x02, 0xB4, 0x04, 0x00, 0x50, 0x8E, 0x23, 0x23, 0x45, 0x82, 0x23, 0x90, +0x42, 0xE0, 0x73, 0xC2, 0xAF, 0x80, 0xFE, 0x32, 0x12, 0x44, 0x17, 0x85, 0xD0, 0x0B, 0x75, 0xD0, +0x08, 0xAA, 0xE0, 0xC2, 0x8C, 0xE5, 0x8A, 0x24, 0x67, 0xF5, 0x8A, 0xE5, 0x8C, 0x34, 0x79, 0xF5, +0x8C, 0xD2, 0x8C, 0xEC, 0x24, 0x87, 0xF8, 0xE6, 0xBC, 0x02, 0x02, 0x74, 0xFF, 0xC3, 0x95, 0x81, +0xB4, 0x40, 0x00, 0x40, 0xCE, 0x79, 0x03, 0x78, 0x80, 0x16, 0xE6, 0x08, 0x70, 0x0B, 0xC2, 0xAF, +0xE6, 0x30, 0xE1, 0x03, 0x44, 0x18, 0xF6, 0xD2, 0xAF, 0x08, 0xD9, 0xED, 0xEA, 0x8B, 0xD0, 0x22, +0xE5, 0x0C, 0xFF, 0x23, 0x24, 0x81, 0xF8, 0x0F, 0x08, 0x08, 0xBF, 0x03, 0x04, 0x7F, 0x00, 0x78, +0x81, 0xE6, 0x30, 0xE4, 0xF2, 0x00, 0xE5, 0x0C, 0xC3, 0x9F, 0x50, 0x20, 0x05, 0x0C, 0x74, 0x86, +0x25, 0x0C, 0xF8, 0xE6, 0xFD, 0xA6, 0x81, 0x08, 0xE6, 0xAE, 0x0C, 0xBE, 0x02, 0x02, 0x74, 0xFF, +0xCD, 0xF8, 0xE8, 0x6D, 0x60, 0xE0, 0x08, 0xE6, 0xC0, 0xE0, 0x80, 0xF6, 0xE5, 0x0C, 0xD3, 0x9F, +0x40, 0x27, 0xE5, 0x0C, 0x24, 0x87, 0xF8, 0xE6, 0xAE, 0x0C, 0xBE, 0x02, 0x02, 0x74, 0xFF, 0xFD, +0x18, 0xE6, 0xCD, 0xF8, 0xE5, 0x81, 0x6D, 0x60, 0x06, 0xD0, 0xE0, 0xF6, 0x18, 0x80, 0xF5, 0xE5, +0x0C, 0x24, 0x86, 0xC8, 0xF6, 0x15, 0x0C, 0x80, 0xD3, 0xE5, 0x0C, 0x23, 0x24, 0x81, 0xF8, 0x7F, +0x04, 0xC2, 0xAF, 0xE6, 0x30, 0xE0, 0x03, 0x10, 0xE2, 0x0C, 0x7F, 0x00, 0x30, 0xE1, 0x07, 0x30, +0xE3, 0x04, 0x7F, 0x08, 0x54, 0xF4, 0x54, 0x7C, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x42, 0x07, 0x22, +0x78, 0x86, 0xA6, 0x81, 0x74, 0x02, 0x60, 0x06, 0xFF, 0x08, 0x76, 0xFF, 0xDF, 0xFB, 0x7F, 0x03, +0xE4, 0x78, 0x80, 0xF6, 0x08, 0xF6, 0x08, 0xDF, 0xFA, 0x78, 0x81, 0x76, 0x30, 0x90, 0x47, 0x50, +0x74, 0x01, 0x93, 0xC0, 0xE0, 0xE4, 0x93, 0xC0, 0xE0, 0x43, 0x89, 0x01, 0x75, 0x8A, 0x60, 0x75, +0x8C, 0x79, 0xD2, 0x8C, 0xD2, 0xAF, 0x22, 0x02, 0xEF, 0xD3, 0x94, 0x02, 0x40, 0x03, 0x7F, 0xFF, +0x22, 0x74, 0x81, 0x2F, 0x2F, 0xF8, 0xE6, 0x20, 0xE5, 0xF4, 0xC2, 0xAF, 0xE6, 0x44, 0x30, 0xF6, +0xD2, 0xAF, 0xAE, 0x0C, 0xEE, 0xC3, 0x9F, 0x50, 0x21, 0x0E, 0x74, 0x86, 0x2E, 0xF8, 0xE6, 0xF9, +0x08, 0xE6, 0x18, 0xBE, 0x02, 0x02, 0x74, 0xFF, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x09, 0xE7, 0x19, +0x19, 0xF7, 0x09, 0x09, 0x80, 0xF3, 0x16, 0x16, 0x80, 0xDA, 0xEE, 0xD3, 0x9F, 0x40, 0x04, 0x05, +0x81, 0x05, 0x81, 0xEE, 0xD3, 0x9F, 0x40, 0x22, 0x74, 0x86, 0x2E, 0xF8, 0x08, 0xE6, 0xF9, 0xEE, +0xB5, 0x0C, 0x02, 0xA9, 0x81, 0x18, 0x06, 0x06, 0xE6, 0xFD, 0xED, 0x69, 0x60, 0x09, 0x19, 0x19, +0xE7, 0x09, 0x09, 0xF7, 0x19, 0x80, 0xF3, 0x1E, 0x80, 0xD9, 0xEF, 0x24, 0x86, 0xF8, 0xE6, 0x04, +0xF8, 0xEF, 0x2F, 0x04, 0x90, 0x47, 0x50, 0x93, 0xF6, 0x08, 0xEF, 0x2F, 0x93, 0xF6, 0x7F, 0x00, +0x22, 0xEF, 0xD3, 0x94, 0x02, 0x40, 0x03, 0x7F, 0xFF, 0x22, 0xEF, 0x23, 0x24, 0x81, 0xF8, 0xE6, +0x30, 0xE5, 0xF4, 0xC2, 0xAF, 0xE6, 0x54, 0x8C, 0xF6, 0xD2, 0xAF, 0xE5, 0x0C, 0xB5, 0x07, 0x0A, +0x74, 0x86, 0x2F, 0xF8, 0xE6, 0xF5, 0x81, 0x02, 0x44, 0x60, 0x50, 0x2E, 0x74, 0x87, 0x2F, 0xF8, +0xE6, 0xBF, 0x02, 0x02, 0x74, 0xFF, 0xFD, 0x18, 0xE6, 0xF9, 0x74, 0x86, 0x2F, 0xF8, 0xFB, 0xE6, +0xFC, 0xE9, 0x6C, 0x60, 0x08, 0xA8, 0x05, 0xE7, 0xF6, 0x1D, 0x19, 0x80, 0xF4, 0xA8, 0x03, 0xA6, +0x05, 0x1F, 0xE5, 0x0C, 0xB5, 0x07, 0xE3, 0x7F, 0x00, 0x22, 0x74, 0x87, 0x2F, 0xF8, 0xE6, 0xFD, +0x18, 0x86, 0x01, 0x0F, 0x74, 0x86, 0x2F, 0xF8, 0xA6, 0x01, 0x08, 0x86, 0x04, 0xE5, 0x0C, 0xB5, +0x07, 0x02, 0xAC, 0x81, 0xED, 0x6C, 0x60, 0x08, 0x0D, 0x09, 0xA8, 0x05, 0xE6, 0xF7, 0x80, 0xF4, +0xE5, 0x0C, 0xB5, 0x07, 0xDE, 0x89, 0x81, 0x7F, 0x00, 0x22, 0xEF, 0xD3, 0x94, 0x02, 0x40, 0x03, +0x7F, 0xFF, 0x22, 0xEF, 0x23, 0x24, 0x81, 0xF8, 0xC2, 0xAF, 0xE6, 0x30, 0xE5, 0x05, 0x30, 0xE0, +0x02, 0xD2, 0xE4, 0xD2, 0xE2, 0xC6, 0xD2, 0xAF, 0x7F, 0x00, 0x30, 0xE2, 0x01, 0x0F, 0x02, 0x44, +0x5F, 0x8F, 0xF0, 0xE4, 0xFF, 0xFE, 0xE5, 0x0C, 0x23, 0x24, 0x80, 0xF8, 0xC2, 0xA9, 0x30, 0xF7, +0x0D, 0x7F, 0x08, 0xE6, 0x60, 0x0B, 0x2D, 0xF6, 0x60, 0x30, 0x50, 0x2E, 0x80, 0x07, 0x30, 0xF1, +0x06, 0xED, 0xF6, 0x60, 0x25, 0x7E, 0x02, 0x08, 0x30, 0xF0, 0x10, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, +0x23, 0x0E, 0x30, 0xE2, 0x0C, 0xD2, 0xAF, 0x7F, 0x04, 0x80, 0x12, 0xC2, 0xAF, 0xE6, 0x10, 0xE7, +0x13, 0x54, 0xEC, 0x4E, 0xF6, 0xD2, 0xAF, 0x02, 0x44, 0x60, 0x7F, 0x08, 0x08, 0xEF, 0x44, 0x83, +0xF4, 0xC2, 0xAF, 0x56, 0xC6, 0xD2, 0xAF, 0x54, 0x80, 0x4F, 0xFF, 0x22, 0x02, 0x46, 0xFA, 0x02, +0x44, 0xF0, 0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0x40, 0x03, 0xF6, 0x80, 0x01, 0xF2, 0x08, +0xDF, 0xF4, 0x80, 0x29, 0xE4, 0x93, 0xA3, 0xF8, 0x54, 0x07, 0x24, 0x0C, 0xC8, 0xC3, 0x33, 0xC4, +0x54, 0x0F, 0x44, 0x20, 0xC8, 0x83, 0x40, 0x04, 0xF4, 0x56, 0x80, 0x01, 0x46, 0xF6, 0xDF, 0xE4, +0x80, 0x0B, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x47, 0x3F, 0xE4, 0x7E, 0x01, +0x93, 0x60, 0xBC, 0xA3, 0xFF, 0x54, 0x3F, 0x30, 0xE5, 0x09, 0x54, 0x1F, 0xFE, 0xE4, 0x93, 0xA3, +0x60, 0x01, 0x0E, 0xCF, 0x54, 0xC0, 0x25, 0xE0, 0x60, 0xA8, 0x40, 0xB8, 0xE4, 0x93, 0xA3, 0xFA, +0xE4, 0x93, 0xA3, 0xF8, 0xE4, 0x93, 0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83, 0xCA, 0xF0, +0xA3, 0xC8, 0xC5, 0x82, 0xC8, 0xCA, 0xC5, 0x83, 0xCA, 0xDF, 0xE9, 0xDE, 0xE7, 0x80, 0xBE, 0x00, +0x41, 0x83, 0xF1, 0x00, 0x41, 0x83, 0xF2, 0x00, 0x41, 0x84, 0x04, 0x00, 0x41, 0x84, 0x05, 0x00, +0x59, 0x9D, 0x5F, 0xD5, 0x61, 0xA3, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, 0xD0, +0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, 0xC0, +0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0x56, 0xF0, 0x74, 0x47, 0xA3, 0xF0, 0x12, 0x67, 0xDB, +0xE5, 0x3C, 0x30, 0xE7, 0x02, 0xF1, 0xAD, 0x74, 0x56, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x47, +0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, +0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x7F, 0x01, 0x7E, +0x00, 0x12, 0x32, 0x06, 0x90, 0x00, 0xF2, 0xE0, 0x20, 0xE6, 0x0C, 0x90, 0x00, 0x05, 0xE0, 0x44, +0x80, 0xFD, 0x7F, 0x05, 0x12, 0x32, 0x1E, 0x22, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, +0xC0, 0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, +0x05, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xC8, 0xF0, 0x74, 0x47, 0xA3, 0xF0, 0x12, +0x68, 0x15, 0xE5, 0x41, 0x30, 0xE3, 0x03, 0x12, 0x57, 0xC6, 0xE5, 0x41, 0x30, 0xE4, 0x03, 0x12, +0x57, 0xBF, 0xE5, 0x43, 0x30, 0xE0, 0x02, 0x11, 0x66, 0xE5, 0x43, 0x30, 0xE1, 0x03, 0x12, 0x68, +0x72, 0xE5, 0x43, 0x30, 0xE2, 0x03, 0x12, 0x68, 0xE9, 0xE5, 0x43, 0x30, 0xE3, 0x03, 0x12, 0x6F, +0xCE, 0xE5, 0x43, 0x30, 0xE4, 0x03, 0x12, 0x6F, 0xEA, 0xE5, 0x43, 0x30, 0xE5, 0x03, 0x12, 0x6E, +0x7E, 0xE5, 0x43, 0x30, 0xE6, 0x03, 0x12, 0x70, 0x19, 0xE5, 0x44, 0x30, 0xE1, 0x02, 0xF1, 0xDE, +0x74, 0xC8, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x47, 0xA3, 0xF0, 0xD0, 0x07, 0xD0, 0x06, 0xD0, +0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, 0xD0, 0xD0, 0xD0, 0x82, 0xD0, +0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0xE4, 0xF5, 0x19, 0x90, 0x81, 0x3E, 0xE0, 0x60, 0x72, 0x90, +0x80, 0xF9, 0xE0, 0x64, 0x01, 0x70, 0x6A, 0x90, 0x81, 0x3C, 0xE0, 0xC4, 0x54, 0x0F, 0x60, 0x22, +0x24, 0xFE, 0x60, 0x03, 0x04, 0x70, 0x1E, 0x90, 0x81, 0x45, 0xE0, 0x14, 0xF0, 0xE0, 0xFF, 0x60, +0x06, 0x90, 0x81, 0x47, 0xE0, 0x60, 0x0E, 0xEF, 0x70, 0x08, 0x90, 0x81, 0x44, 0xE0, 0xA3, 0xF0, +0x80, 0x00, 0x75, 0x19, 0x01, 0xE5, 0x19, 0x60, 0x38, 0x90, 0x81, 0x42, 0xE0, 0x44, 0x10, 0xF0, +0x90, 0x81, 0x47, 0xE0, 0x60, 0x03, 0xB4, 0x01, 0x09, 0xE4, 0xF5, 0x52, 0x90, 0x81, 0x47, 0xE0, +0x80, 0x0D, 0xE4, 0xF5, 0x52, 0x90, 0x81, 0x47, 0xE0, 0x75, 0xF0, 0x03, 0xA4, 0x24, 0xFE, 0xFF, +0x90, 0x81, 0x46, 0xE0, 0x2F, 0x12, 0x57, 0xED, 0x90, 0x81, 0x41, 0xE0, 0x20, 0xE2, 0x02, 0x11, +0xE2, 0x22, 0x7D, 0x01, 0x7F, 0x04, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x84, 0x01, +0xED, 0xF0, 0x90, 0x81, 0x3A, 0xE0, 0xFE, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x30, 0xE0, 0x02, 0x41, +0x3D, 0xEE, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x02, 0x41, 0x3D, 0x90, 0x81, 0x41, +0xE0, 0xFE, 0x6F, 0x70, 0x02, 0x41, 0x3D, 0xEF, 0x70, 0x02, 0x21, 0xA5, 0x24, 0xFE, 0x70, 0x02, +0x21, 0xDE, 0x24, 0xFE, 0x60, 0x47, 0x24, 0xFC, 0x70, 0x02, 0x41, 0x18, 0x24, 0xFC, 0x60, 0x02, +0x41, 0x2D, 0xEE, 0xB4, 0x0E, 0x02, 0x51, 0xA9, 0x90, 0x81, 0x41, 0xE0, 0x70, 0x04, 0x7F, 0x01, +0x51, 0xCC, 0x90, 0x81, 0x41, 0xE0, 0xB4, 0x06, 0x02, 0x51, 0x88, 0x90, 0x81, 0x41, 0xE0, 0xB4, +0x04, 0x0D, 0x90, 0x84, 0x01, 0xE0, 0xFF, 0x60, 0x04, 0x71, 0xE7, 0x80, 0x02, 0xF1, 0x1E, 0x90, +0x81, 0x41, 0xE0, 0x64, 0x08, 0x60, 0x02, 0x41, 0x2D, 0x71, 0xA5, 0x41, 0x2D, 0x90, 0x81, 0x41, +0xE0, 0x70, 0x04, 0x7F, 0x01, 0x51, 0xCC, 0x90, 0x81, 0x41, 0xE0, 0xB4, 0x06, 0x02, 0x51, 0x88, +0x90, 0x81, 0x41, 0xE0, 0xB4, 0x0E, 0x07, 0x51, 0x42, 0xBF, 0x01, 0x02, 0x51, 0xA9, 0x90, 0x81, +0x41, 0xE0, 0x64, 0x0C, 0x60, 0x02, 0x41, 0x2D, 0x51, 0x42, 0xEF, 0x64, 0x01, 0x60, 0x02, 0x41, +0x2D, 0x51, 0xF8, 0x41, 0x2D, 0x90, 0x81, 0x41, 0xE0, 0xB4, 0x0E, 0x07, 0x51, 0x42, 0xBF, 0x01, +0x02, 0x51, 0xA9, 0x90, 0x81, 0x41, 0xE0, 0xB4, 0x06, 0x02, 0x51, 0x88, 0x90, 0x81, 0x41, 0xE0, +0xB4, 0x0C, 0x07, 0x51, 0x42, 0xBF, 0x01, 0x02, 0x51, 0xF8, 0x90, 0x81, 0x41, 0xE0, 0x64, 0x04, +0x70, 0x5B, 0x12, 0x72, 0x95, 0xEF, 0x64, 0x01, 0x70, 0x53, 0x71, 0xB2, 0x80, 0x4F, 0x90, 0x81, +0x41, 0xE0, 0xB4, 0x0E, 0x07, 0x51, 0x42, 0xBF, 0x01, 0x02, 0x51, 0xA9, 0x90, 0x81, 0x41, 0xE0, +0xB4, 0x06, 0x02, 0x51, 0x88, 0x90, 0x81, 0x41, 0xE0, 0xB4, 0x0C, 0x07, 0x51, 0x42, 0xBF, 0x01, +0x02, 0x51, 0xF8, 0x90, 0x81, 0x41, 0xE0, 0x70, 0x04, 0x7F, 0x01, 0x51, 0xCC, 0x90, 0x81, 0x41, +0xE0, 0xB4, 0x04, 0x19, 0xF1, 0x12, 0x80, 0x15, 0x90, 0x81, 0x41, 0xE0, 0xB4, 0x0C, 0x0E, 0x90, +0x81, 0x3B, 0xE0, 0xFF, 0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x02, 0x71, 0x9B, 0x90, 0x81, 0x41, +0xE0, 0x90, 0x01, 0xBA, 0xF0, 0x90, 0x81, 0x40, 0xE0, 0x90, 0x01, 0xBB, 0xF0, 0xD0, 0xD0, 0x92, +0xAF, 0x22, 0x12, 0x72, 0x7C, 0xEF, 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x01, 0xF0, +0x80, 0x2D, 0x90, 0x81, 0x3A, 0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x08, 0x90, 0x01, +0xB8, 0x74, 0x02, 0xF0, 0x80, 0x19, 0x90, 0x81, 0x40, 0xE0, 0xD3, 0x94, 0x04, 0x40, 0x08, 0x90, +0x01, 0xB8, 0x74, 0x08, 0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0x90, +0x01, 0xB9, 0x74, 0x02, 0xF0, 0x7F, 0x00, 0x22, 0x90, 0x81, 0x3B, 0xE0, 0x90, 0x06, 0x04, 0x20, +0xE0, 0x08, 0xE0, 0x44, 0x40, 0xF0, 0x7D, 0x04, 0x80, 0x06, 0xE0, 0x54, 0x7F, 0xF0, 0x7D, 0x0C, +0x7F, 0x01, 0x71, 0x33, 0xE4, 0xFD, 0xFF, 0x80, 0x44, 0x90, 0x81, 0x3B, 0xE0, 0xC3, 0x13, 0x20, +0xE0, 0x04, 0x7D, 0x0C, 0x80, 0x0D, 0x90, 0x06, 0x04, 0xE0, 0x44, 0x40, 0xF0, 0xE0, 0x44, 0x80, +0xF0, 0x7D, 0x04, 0x7F, 0x01, 0x71, 0x33, 0xE4, 0xFD, 0xFF, 0x80, 0x21, 0x90, 0x84, 0x00, 0xEF, +0xF0, 0xD1, 0x97, 0x90, 0x84, 0x00, 0xE0, 0x60, 0x05, 0xE4, 0xFD, 0xFF, 0x51, 0xED, 0x7D, 0x04, +0x7F, 0x01, 0x80, 0x4F, 0xE4, 0xFD, 0x7F, 0x0C, 0x11, 0xE6, 0xE4, 0xFD, 0xFF, 0x90, 0x05, 0x22, +0xEF, 0xF0, 0x90, 0x80, 0x05, 0xED, 0xF0, 0x22, 0x90, 0x80, 0xF9, 0xE0, 0x64, 0x01, 0x70, 0x2E, +0x90, 0x81, 0x3B, 0xE0, 0x54, 0xFD, 0xF0, 0x7D, 0x2C, 0x7F, 0x6F, 0x51, 0xED, 0x7D, 0x08, 0x7F, +0x01, 0x91, 0x29, 0xBF, 0x01, 0x0D, 0x90, 0x81, 0x3A, 0xE0, 0x44, 0x80, 0xF0, 0x7D, 0x0E, 0x7F, +0x01, 0x80, 0x10, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x04, 0xF0, 0x22, 0x7D, +0x0C, 0x7F, 0x01, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xAC, 0x07, 0xEF, 0x14, 0x60, 0x15, +0x14, 0x60, 0x19, 0x24, 0x02, 0x70, 0x1A, 0xED, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x3A, 0xE0, 0x54, +0xFE, 0x4E, 0xF0, 0x80, 0x0C, 0x90, 0x81, 0x41, 0xED, 0xF0, 0x80, 0x05, 0x90, 0x81, 0x40, 0xED, +0xF0, 0x90, 0x00, 0x8F, 0xE0, 0x30, 0xE4, 0x2E, 0xEC, 0x14, 0x60, 0x07, 0x14, 0x60, 0x1D, 0x24, +0x02, 0x70, 0x23, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0x01, 0xC4, 0x33, 0x33, 0x33, 0x54, 0x80, 0xFF, +0x90, 0x81, 0x41, 0xE0, 0x54, 0x7F, 0x4F, 0xFD, 0x7F, 0x88, 0x80, 0x07, 0x90, 0x81, 0x40, 0xE0, +0xFD, 0x7F, 0x89, 0x12, 0x32, 0x1E, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x7D, 0x2F, 0x91, 0xF4, 0x7D, +0x08, 0x7F, 0x01, 0x80, 0x8E, 0xD1, 0x97, 0xE4, 0xFD, 0xFF, 0x51, 0xED, 0x7D, 0x0C, 0x7F, 0x01, +0x80, 0x81, 0x7D, 0x2D, 0xB1, 0x6E, 0x90, 0x01, 0x37, 0x74, 0x02, 0xF0, 0xFD, 0x7F, 0x03, 0xF1, +0xC9, 0x91, 0xF8, 0xE4, 0xFD, 0x7F, 0x01, 0x61, 0x33, 0x90, 0x81, 0x3E, 0xE0, 0x64, 0x01, 0x70, +0x15, 0x90, 0x81, 0x3C, 0xE0, 0x54, 0x0F, 0x60, 0x05, 0x51, 0xE4, 0x02, 0x56, 0xA5, 0x90, 0x81, +0x41, 0xE0, 0x70, 0x02, 0x11, 0xE2, 0x22, 0xEF, 0x60, 0x3A, 0x90, 0x80, 0xF9, 0xE0, 0x64, 0x01, +0x70, 0x32, 0x90, 0x81, 0x3B, 0xE0, 0x54, 0xFE, 0xF0, 0x7D, 0x2B, 0x7F, 0x0F, 0x51, 0xED, 0x90, +0x06, 0x04, 0xE0, 0x54, 0xBF, 0xF0, 0x91, 0x25, 0xBF, 0x01, 0x0D, 0x90, 0x81, 0x3A, 0xE0, 0x44, +0x40, 0xF0, 0x7D, 0x06, 0x7F, 0x01, 0x61, 0x33, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, +0xB8, 0x74, 0x08, 0xF0, 0x22, 0x7D, 0x08, 0xE4, 0xFF, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, +0x90, 0x83, 0xD5, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0x90, 0x80, 0x03, 0xE0, 0x04, 0xF0, 0x90, 0x04, +0x1D, 0xE0, 0x60, 0x21, 0x90, 0x05, 0x22, 0xE0, 0x90, 0x83, 0xD9, 0xF0, 0x7D, 0x26, 0xB1, 0x6E, +0xEF, 0x64, 0x01, 0x70, 0x03, 0x12, 0x6D, 0x88, 0x90, 0x83, 0xD9, 0xE0, 0xFF, 0x7D, 0x27, 0x51, +0xED, 0x91, 0x77, 0x80, 0x05, 0x91, 0x77, 0x12, 0x6D, 0x88, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, +0x7F, 0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x83, 0xD5, 0xE0, 0xFF, 0xD3, 0x10, 0xAF, 0x01, +0xC3, 0xC0, 0xD0, 0x90, 0x84, 0x02, 0xEF, 0xF0, 0x90, 0x80, 0x09, 0xE0, 0xFF, 0x90, 0x04, 0x1C, +0xE0, 0x6F, 0x70, 0x4B, 0x90, 0x81, 0x41, 0xE0, 0x64, 0x0E, 0x70, 0x18, 0x90, 0x84, 0x02, 0xE0, +0x70, 0x3D, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x06, 0x04, 0xE0, 0x54, 0x7F, 0xF0, +0x71, 0x2F, 0x80, 0x26, 0x90, 0x81, 0x41, 0xE0, 0x64, 0x06, 0x70, 0x23, 0x90, 0x84, 0x02, 0xE0, +0x60, 0x1D, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0xBF, 0xF0, 0x90, 0x06, 0x04, 0xE0, 0x44, 0x40, 0xF0, +0xE0, 0x44, 0x80, 0xF0, 0x90, 0x81, 0x41, 0x74, 0x04, 0xF0, 0xE4, 0xFD, 0xFF, 0x51, 0xED, 0xD0, +0xD0, 0x92, 0xAF, 0x22, 0x12, 0x56, 0xA5, 0x90, 0x81, 0x41, 0xE0, 0x64, 0x0C, 0x60, 0x04, 0x51, +0xE4, 0x91, 0x25, 0x22, 0x7F, 0xFF, 0x51, 0xED, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xB1, +0x72, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0xCC, 0xF0, 0x00, 0xC0, 0x7F, 0x8C, 0x7E, 0x08, 0x12, +0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x14, 0x7F, 0x70, 0x7E, 0x0E, +0x12, 0x2E, 0xA2, 0x90, 0x83, 0xCB, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xFD, 0xFF, +0x12, 0x64, 0xF6, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x83, +0xE6, 0x12, 0x20, 0xCE, 0x90, 0x83, 0xE6, 0x12, 0x42, 0x19, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, +0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x01, 0x00, 0x74, 0x3F, 0xF0, 0xA3, 0xE0, 0x54, +0xFD, 0xF0, 0x90, 0x05, 0x53, 0xE0, 0x44, 0x20, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x7F, 0xFF, +0x51, 0xED, 0xE4, 0x90, 0x83, 0xF7, 0xF0, 0xA3, 0xF0, 0x90, 0x05, 0xF8, 0xE0, 0x70, 0x0F, 0xA3, +0xE0, 0x70, 0x0B, 0xA3, 0xE0, 0x70, 0x07, 0xA3, 0xE0, 0x70, 0x03, 0x7F, 0x01, 0x22, 0xD3, 0x90, +0x83, 0xF8, 0xE0, 0x94, 0xE8, 0x90, 0x83, 0xF7, 0xE0, 0x94, 0x03, 0x40, 0x0A, 0x90, 0x01, 0xC0, +0xE0, 0x44, 0x20, 0xF0, 0x7F, 0x00, 0x22, 0x7F, 0x32, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x90, 0x83, +0xF7, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x41, 0xF6, 0x80, 0xBF, 0xEF, 0x60, 0x59, 0x90, 0x04, 0xEC, +0xE0, 0x54, 0xDD, 0xF0, 0x90, 0x83, 0x30, 0xE0, 0xFF, 0x60, 0x03, 0x12, 0x5F, 0x8B, 0x90, 0x01, +0xC7, 0xE4, 0xF0, 0x90, 0x01, 0x17, 0xE0, 0xFE, 0x90, 0x01, 0x16, 0xE0, 0x7C, 0x00, 0x24, 0x00, +0xFF, 0xEC, 0x3E, 0x90, 0x80, 0xF7, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x06, 0x09, 0xE0, 0x54, 0xFE, +0xF0, 0x7D, 0x35, 0x91, 0xF4, 0x90, 0x02, 0x86, 0xE0, 0x44, 0x04, 0xF0, 0x12, 0x78, 0xFF, 0xF1, +0xF2, 0xD1, 0x97, 0xE4, 0xFD, 0xFF, 0x51, 0xED, 0x12, 0x7B, 0xCB, 0x90, 0x01, 0x34, 0x74, 0x08, +0xF0, 0xFD, 0xE4, 0xFF, 0xE1, 0xC9, 0x90, 0x04, 0xEC, 0xE0, 0x44, 0x22, 0xF0, 0x7D, 0x08, 0xE4, +0xFF, 0x12, 0x68, 0xD1, 0x90, 0x06, 0x90, 0xE0, 0x54, 0xF0, 0xF0, 0x90, 0x02, 0x86, 0xE0, 0x54, +0xFB, 0xF0, 0xF1, 0xF4, 0xF1, 0xF3, 0x90, 0x81, 0x7D, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x81, 0x85, +0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x20, 0xF0, 0xD3, 0x10, 0xAF, 0x01, 0xC3, +0xC0, 0xD0, 0x90, 0x81, 0x80, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x54, 0xFB, 0xF0, 0x54, +0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, 0xE0, +0x54, 0x80, 0xF0, 0xE4, 0xA3, 0xF0, 0x90, 0x81, 0x84, 0xE0, 0x54, 0xFE, 0xF0, 0x90, 0x81, 0x81, +0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x81, 0x84, 0xE0, 0x54, 0xFD, 0xF0, 0xE4, 0xFD, 0x7F, 0x8F, 0x12, +0x32, 0x1E, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x01, +0x01, 0xE0, 0x44, 0x02, 0xF0, 0x90, 0x01, 0x00, 0x74, 0xFF, 0xF0, 0x90, 0x06, 0xB7, 0x74, 0x09, +0xF0, 0x90, 0x06, 0xB4, 0x74, 0x86, 0xF0, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0xEC, 0x54, +0x7F, 0xFC, 0x90, 0x83, 0xE2, 0x12, 0x20, 0xCE, 0x90, 0x83, 0xE2, 0x12, 0x42, 0x19, 0x90, 0x85, +0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x7C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, 0x20, +0xDA, 0xCC, 0xC0, 0x00, 0xC0, 0x7F, 0x8C, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x85, 0xBB, 0x12, +0x20, 0xDA, 0x00, 0xC0, 0x00, 0x14, 0x7F, 0x70, 0x7E, 0x0E, 0x12, 0x2E, 0xA2, 0x90, 0x83, 0xCB, +0x12, 0x20, 0xDA, 0x00, 0x03, 0x3E, 0x60, 0xE4, 0xFD, 0xFF, 0x12, 0x64, 0xF6, 0xD0, 0xD0, 0x92, +0xAF, 0x22, 0x7D, 0x2E, 0x7F, 0x6F, 0x51, 0xED, 0x7D, 0x02, 0x7F, 0x01, 0x61, 0x33, 0x90, 0x06, +0x04, 0xE0, 0x54, 0x7F, 0xF0, 0xE4, 0xFD, 0xFF, 0x51, 0xED, 0x7D, 0x0C, 0x7F, 0x01, 0x61, 0x33, +0xEF, 0x70, 0x4E, 0x7D, 0x78, 0x7F, 0x02, 0x12, 0x68, 0xD1, 0x7D, 0x02, 0x7F, 0x03, 0x12, 0x68, +0xD1, 0x7D, 0xC8, 0x7F, 0x02, 0x12, 0x71, 0x53, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, +0x74, 0x02, 0xF0, 0x90, 0x80, 0xF9, 0xE0, 0x70, 0x13, 0xD1, 0x97, 0xF1, 0x1E, 0x90, 0x81, 0x3A, +0xE0, 0x54, 0xF7, 0xF0, 0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0x80, 0x06, 0x7D, 0x01, 0x7F, 0x0C, +0x11, 0xE6, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0xF7, 0xF0, 0x90, 0x06, 0x0A, 0xE0, 0x54, 0xF8, 0xF0, +0x22, 0x90, 0x01, 0x36, 0x74, 0x78, 0xF0, 0xA3, 0x74, 0x02, 0xF0, 0x7D, 0x78, 0xFF, 0xF1, 0xC9, +0x7D, 0x02, 0x7F, 0x03, 0xF1, 0xC9, 0x90, 0x06, 0x0A, 0xE0, 0x44, 0x07, 0xF0, 0x90, 0x81, 0x49, +0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x80, 0xF9, 0xE0, 0xB4, 0x01, 0x14, 0x90, 0x81, 0x3B, +0xE0, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x41, 0xE0, 0x20, 0xE2, 0x0D, 0x7D, 0x01, 0x7F, 0x04, 0x01, +0xE6, 0x90, 0x81, 0x3B, 0xE0, 0x44, 0x04, 0xF0, 0x22, 0x74, 0x3D, 0x2F, 0xF8, 0xE6, 0x4D, 0xFE, +0xF6, 0x74, 0x30, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0x90, 0x81, +0x3E, 0xE0, 0x60, 0x02, 0x71, 0xC9, 0x22, 0xE4, 0xFD, 0xFF, 0x51, 0xED, 0x7D, 0x04, 0x7F, 0x01, +0x61, 0x33, 0x22, 0x22, 0xD1, 0x4B, 0x90, 0x01, 0x3F, 0x74, 0x04, 0xF0, 0x90, 0x80, 0x06, 0xE0, +0xFF, 0xB4, 0x01, 0x07, 0x90, 0xFD, 0x00, 0xE0, 0x54, 0xEF, 0xF0, 0xEF, 0xB4, 0x01, 0x07, 0x90, +0xFE, 0x10, 0xE0, 0x54, 0xFB, 0xF0, 0x22, 0xC0, 0xE0, 0xC0, 0xF0, 0xC0, 0x83, 0xC0, 0x82, 0xC0, +0xD0, 0x75, 0xD0, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xC0, 0x02, 0xC0, 0x03, 0xC0, 0x04, 0xC0, 0x05, +0xC0, 0x06, 0xC0, 0x07, 0x90, 0x01, 0xC4, 0x74, 0x17, 0xF0, 0x74, 0x50, 0xA3, 0xF0, 0x12, 0x68, +0x42, 0xE5, 0x49, 0x30, 0xE1, 0x02, 0x11, 0x9B, 0xE5, 0x49, 0x30, 0xE2, 0x02, 0x11, 0xB6, 0xE5, +0x4A, 0x30, 0xE0, 0x03, 0x12, 0x70, 0x35, 0xE5, 0x4C, 0x30, 0xE1, 0x04, 0x7F, 0x04, 0xF1, 0xB0, +0xE5, 0x4C, 0x30, 0xE4, 0x02, 0x11, 0xA4, 0xE5, 0x4C, 0x30, 0xE5, 0x02, 0x11, 0xFE, 0xE5, 0x4C, +0x30, 0xE6, 0x02, 0x31, 0x82, 0x74, 0x17, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x50, 0xA3, 0xF0, +0xD0, 0x07, 0xD0, 0x06, 0xD0, 0x05, 0xD0, 0x04, 0xD0, 0x03, 0xD0, 0x02, 0xD0, 0x01, 0xD0, 0x00, +0xD0, 0xD0, 0xD0, 0x82, 0xD0, 0x83, 0xD0, 0xF0, 0xD0, 0xE0, 0x32, 0x90, 0x81, 0x3E, 0xE0, 0x60, +0x02, 0xF1, 0x67, 0x22, 0x11, 0xCF, 0x90, 0x81, 0x44, 0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0, 0x7D, +0x02, 0x7F, 0x02, 0x02, 0x4F, 0xC9, 0x90, 0x81, 0x3E, 0xE0, 0x60, 0x12, 0x90, 0x06, 0x92, 0xE0, +0x30, 0xE1, 0x02, 0xC1, 0xA5, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0xF7, 0xF0, 0x31, 0xBF, 0x22, 0x90, +0x81, 0x3E, 0xE0, 0x60, 0x28, 0x90, 0x80, 0xF9, 0xE0, 0x64, 0x01, 0x70, 0x20, 0x90, 0x81, 0x45, +0xF0, 0x04, 0x60, 0x19, 0x90, 0x81, 0x42, 0xE0, 0x44, 0x10, 0xF0, 0xE4, 0xF5, 0x52, 0x90, 0x81, +0x46, 0xF1, 0xEC, 0x90, 0x81, 0x41, 0xE0, 0x20, 0xE2, 0x03, 0x12, 0x48, 0xE2, 0x22, 0x90, 0x81, +0x3A, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x54, 0x03, 0x30, 0xE0, 0x26, 0xEF, 0x54, 0xBF, 0xF0, 0x90, +0x04, 0xE0, 0xE0, 0x90, 0x81, 0x3B, 0x30, 0xE0, 0x06, 0xE0, 0x44, 0x01, 0xF0, 0x80, 0x10, 0xE0, +0x54, 0xFE, 0xF0, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0x74, 0x04, 0xF0, 0x31, +0xBF, 0xE4, 0xFF, 0x90, 0x83, 0x44, 0xE0, 0x30, 0xE0, 0x47, 0x90, 0x83, 0x49, 0xE0, 0xFD, 0x60, +0x40, 0x74, 0x01, 0x7E, 0x00, 0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, +0xF9, 0xFF, 0x90, 0x04, 0xE0, 0xE0, 0xFB, 0xEF, 0x5B, 0x60, 0x0B, 0xE4, 0x90, 0x83, 0x49, 0xF0, +0x90, 0x83, 0x4B, 0x04, 0xF0, 0x22, 0x90, 0x83, 0x46, 0xE0, 0xD3, 0x9D, 0x50, 0x0A, 0x31, 0xC9, +0x90, 0x83, 0x44, 0xE0, 0x54, 0xFE, 0xF0, 0x22, 0x12, 0x4C, 0x25, 0x90, 0x83, 0x49, 0xE0, 0x04, +0xF0, 0x22, 0x90, 0x81, 0x3A, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x2B, +0xEF, 0x54, 0x7F, 0xF0, 0x90, 0x04, 0xE0, 0xE0, 0x90, 0x81, 0x3B, 0x30, 0xE1, 0x06, 0xE0, 0x44, +0x02, 0xF0, 0x80, 0x0F, 0xE0, 0x54, 0xFD, 0xF0, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, +0xB8, 0x04, 0xF0, 0x90, 0x81, 0x3E, 0xE0, 0x60, 0x02, 0x31, 0xBF, 0x7F, 0x01, 0x21, 0x33, 0x90, +0x81, 0x40, 0xE0, 0xFF, 0x7D, 0x01, 0x02, 0x48, 0xE6, 0x90, 0x01, 0xC7, 0x74, 0x10, 0xF0, 0x7F, +0x01, 0x90, 0x84, 0x03, 0xEF, 0xF0, 0x90, 0x80, 0x06, 0xE0, 0x64, 0x02, 0x70, 0x1F, 0x90, 0x84, +0x03, 0xE0, 0xFF, 0x64, 0x01, 0x70, 0x24, 0x90, 0x81, 0x81, 0xE0, 0xFE, 0xC4, 0x13, 0x13, 0x13, +0x54, 0x01, 0x30, 0xE0, 0x14, 0x90, 0x01, 0x4D, 0xE0, 0x64, 0x80, 0xF0, 0x22, 0x90, 0x06, 0x90, +0xE0, 0x44, 0x01, 0xF0, 0x90, 0x84, 0x03, 0xE0, 0xFF, 0x51, 0x0C, 0x22, 0xAD, 0x07, 0x90, 0x81, +0x82, 0xE0, 0x75, 0xF0, 0x40, 0xA4, 0xFF, 0x90, 0x83, 0xEA, 0xE5, 0xF0, 0xF0, 0xA3, 0xEF, 0xF0, +0xE4, 0xA3, 0xF0, 0x90, 0x81, 0x83, 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0x90, 0x83, 0xED, 0xF0, 0xED, +0x64, 0x01, 0x60, 0x02, 0x41, 0xDC, 0x90, 0x83, 0xEA, 0xE0, 0x70, 0x02, 0xA3, 0xE0, 0x60, 0x0B, +0x90, 0x83, 0xEA, 0x74, 0xFF, 0x75, 0xF0, 0xD0, 0x12, 0x41, 0xF6, 0x90, 0x81, 0x81, 0xE0, 0x54, +0x7F, 0xFF, 0x90, 0x81, 0x80, 0xE0, 0xFE, 0xC4, 0x13, 0x54, 0x07, 0x7D, 0x00, 0x20, 0xE0, 0x02, +0x7D, 0x01, 0x51, 0xEE, 0x51, 0xDD, 0x90, 0x81, 0x83, 0xE0, 0x30, 0xE0, 0x6F, 0x90, 0x83, 0xEA, +0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, 0x32, 0xAA, 0x90, 0x81, 0x81, 0xE0, 0x54, 0x7F, 0xFF, 0x90, +0x81, 0x80, 0xE0, 0xFE, 0xC4, 0x13, 0x54, 0x07, 0x7D, 0x00, 0x20, 0xE0, 0x02, 0x7D, 0x01, 0x51, +0xEE, 0xE4, 0x90, 0x83, 0xEC, 0xF0, 0x90, 0x83, 0xED, 0xE0, 0xFF, 0x90, 0x83, 0xEC, 0xE0, 0xC3, +0x9F, 0x50, 0x39, 0x90, 0x83, 0xEA, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, 0x32, 0xAA, 0x51, 0xDD, +0x90, 0x83, 0xEA, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, 0x32, 0xAA, 0x90, 0x81, 0x81, 0xE0, 0x54, +0x7F, 0xFF, 0x90, 0x81, 0x80, 0xE0, 0xFE, 0xC4, 0x13, 0x54, 0x07, 0x7D, 0x00, 0x20, 0xE0, 0x02, +0x7D, 0x01, 0x51, 0xEE, 0x90, 0x83, 0xEC, 0xE0, 0x04, 0xF0, 0x80, 0xBA, 0x22, 0x90, 0x81, 0x81, +0xE0, 0x54, 0x7F, 0xFF, 0x90, 0x81, 0x80, 0xE0, 0xFE, 0xC4, 0x13, 0x54, 0x01, 0xFD, 0xD3, 0x10, +0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x83, 0xFA, 0xED, 0xF0, 0x90, 0x83, 0xF9, 0xEF, 0xF0, 0xD3, +0x94, 0x07, 0x50, 0x70, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, +0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x47, 0xE0, 0x5F, 0xFD, 0x7F, 0x47, 0x12, 0x32, 0x1E, 0x90, 0x83, +0xF9, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, +0x00, 0x46, 0xE0, 0x4F, 0xFD, 0x7F, 0x46, 0x12, 0x32, 0x1E, 0x90, 0x83, 0xFA, 0xE0, 0x60, 0x18, +0x90, 0x83, 0xF9, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, +0xFF, 0x90, 0x00, 0x45, 0xE0, 0x4F, 0x80, 0x17, 0x90, 0x83, 0xF9, 0xE0, 0xFF, 0x74, 0x01, 0xA8, +0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x45, 0xE0, 0x5F, 0xFD, +0x7F, 0x45, 0x80, 0x7E, 0x90, 0x83, 0xF9, 0xE0, 0x24, 0xF8, 0xF0, 0xE0, 0x24, 0x04, 0xFF, 0x74, +0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x43, 0xE0, +0x5F, 0xFD, 0x7F, 0x43, 0x12, 0x32, 0x1E, 0x90, 0x83, 0xF9, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, +0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x43, 0xE0, 0x4F, 0xFD, 0x7F, 0x43, +0x12, 0x32, 0x1E, 0x90, 0x83, 0xFA, 0xE0, 0x60, 0x1D, 0x90, 0x83, 0xF9, 0xE0, 0x24, 0x04, 0xFF, +0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xFF, 0x90, 0x00, 0x42, 0xE0, +0x4F, 0xFD, 0x7F, 0x42, 0x80, 0x1C, 0x90, 0x83, 0xF9, 0xE0, 0x24, 0x04, 0xFF, 0x74, 0x01, 0xA8, +0x07, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, 0xFF, 0x90, 0x00, 0x42, 0xE0, 0x5F, 0xFD, +0x7F, 0x42, 0x12, 0x32, 0x1E, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, +0xD0, 0x90, 0x83, 0x65, 0x74, 0x08, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, +0x90, 0x83, 0x6C, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x1F, 0xE0, 0xFE, 0x90, 0x01, 0x1E, +0xE0, 0x7C, 0x00, 0x24, 0x00, 0xFF, 0xEC, 0x3E, 0x90, 0x83, 0x5D, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, +0x02, 0x82, 0xE0, 0x90, 0x83, 0x64, 0xF0, 0x90, 0x81, 0x7D, 0xE0, 0x20, 0xE0, 0x02, 0xC1, 0xA0, +0x90, 0x81, 0x85, 0xE0, 0x20, 0xE0, 0x07, 0x90, 0x01, 0x3F, 0xE0, 0x30, 0xE2, 0x19, 0x90, 0x80, +0x06, 0xE0, 0xB4, 0x01, 0x0E, 0x90, 0xFD, 0x01, 0xE0, 0x20, 0xE6, 0x07, 0x90, 0xFD, 0x00, 0xE0, +0x44, 0x10, 0xF0, 0x7F, 0x01, 0x31, 0xD1, 0xE4, 0x90, 0x83, 0x63, 0xF0, 0x90, 0x83, 0x64, 0xE0, +0xFF, 0x90, 0x83, 0x63, 0xE0, 0xC3, 0x9F, 0x40, 0x02, 0xC1, 0xA0, 0x90, 0x83, 0x5D, 0xE0, 0xFC, +0xA3, 0xE0, 0xFD, 0xEC, 0xFF, 0x90, 0xFD, 0x11, 0xF0, 0xAE, 0x05, 0xAA, 0x06, 0x90, 0x83, 0x67, +0xEF, 0xF0, 0x74, 0x02, 0x2A, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x54, 0x0F, 0x33, +0x33, 0x33, 0x54, 0xF8, 0xFF, 0x74, 0x03, 0x2A, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, +0x54, 0x03, 0xFE, 0xEF, 0x24, 0x18, 0x2E, 0x90, 0x83, 0x6C, 0xF0, 0xE0, 0xFF, 0x2A, 0x90, 0x83, +0x5F, 0xF0, 0x7E, 0x00, 0x90, 0x83, 0x5D, 0xE0, 0xFC, 0xA3, 0xE0, 0x2F, 0xFF, 0xEE, 0x3C, 0x90, +0x83, 0x60, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x83, 0x5F, 0xE0, 0xFD, 0x24, 0x00, 0xF5, 0x82, 0xE4, +0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFE, 0x54, 0xFC, 0x90, 0x83, 0x62, 0xF0, 0xAF, 0x06, 0x74, 0x01, +0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFD, 0x90, 0x83, 0x5F, 0xE0, 0x24, 0x04, +0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF1, 0x42, 0x90, 0x83, 0x66, 0xEF, 0xF0, 0x74, 0x01, 0x2A, 0xF5, +0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x00, 0x2A, 0xF5, 0x82, 0xE4, 0x34, 0xFB, +0xF5, 0x83, 0xE0, 0x7C, 0x00, 0x24, 0x00, 0xFF, 0xEC, 0x3E, 0x54, 0x3F, 0xFE, 0x90, 0x83, 0x68, +0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x83, 0x6C, 0xE0, 0x2F, 0xFF, 0xEC, 0x3E, 0xFE, 0x12, 0x77, 0xDC, +0x74, 0x0F, 0x2A, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFD, 0x90, 0x83, 0x5D, 0xEE, +0x8F, 0xF0, 0x12, 0x41, 0xF6, 0x90, 0x80, 0xF7, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x90, 0x83, 0x5D, +0xE0, 0xFA, 0xA3, 0xE0, 0xD3, 0x9F, 0xEA, 0x9E, 0x40, 0x22, 0x90, 0x83, 0x5D, 0xE0, 0xFE, 0xA3, +0xE0, 0xFF, 0x90, 0x80, 0xF7, 0xE0, 0xFA, 0xA3, 0xE0, 0x24, 0x01, 0xFB, 0xE4, 0x3A, 0xFA, 0xC3, +0xEF, 0x9B, 0xFF, 0xEE, 0x9A, 0x90, 0x83, 0x5D, 0xF0, 0xA3, 0xEF, 0xF0, 0xED, 0x30, 0xE7, 0x06, +0x90, 0x01, 0xC7, 0x74, 0x21, 0xF0, 0xED, 0x30, 0xE6, 0x06, 0x90, 0x01, 0xC7, 0x74, 0x22, 0xF0, +0xED, 0x30, 0xE5, 0x06, 0x90, 0x01, 0xC7, 0x74, 0x23, 0xF0, 0x90, 0x83, 0x62, 0xE0, 0x24, 0x40, +0x60, 0x04, 0x24, 0x20, 0x70, 0x1F, 0x90, 0x81, 0x80, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, +0x01, 0x20, 0xE0, 0x02, 0xC1, 0x46, 0xD1, 0xE0, 0xEF, 0x60, 0x7B, 0x90, 0x83, 0x62, 0xE0, 0xFF, +0x12, 0x7A, 0xC8, 0x80, 0x71, 0xD1, 0xE0, 0xEF, 0x60, 0x26, 0x90, 0x83, 0x60, 0xE0, 0xFE, 0xA3, +0xE0, 0xFF, 0x90, 0x83, 0x66, 0xE0, 0xFD, 0x90, 0x83, 0x65, 0xE0, 0xFB, 0x90, 0x83, 0x67, 0xE0, +0x90, 0x83, 0x73, 0xF0, 0x12, 0x75, 0xD9, 0xEF, 0x60, 0x06, 0x90, 0x83, 0x6E, 0x74, 0x01, 0xF0, +0x90, 0x81, 0x7D, 0xE0, 0xC3, 0x13, 0x30, 0xE0, 0x19, 0x90, 0x83, 0x60, 0xE0, 0xFE, 0xA3, 0xE0, +0xFF, 0x90, 0x83, 0x66, 0xE0, 0xFD, 0x12, 0x73, 0xE7, 0xEF, 0x60, 0x06, 0x90, 0x83, 0x6E, 0x74, +0x01, 0xF0, 0x90, 0x81, 0x7D, 0xE0, 0xFF, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x30, 0xE0, 0x16, +0x90, 0x83, 0x6E, 0xE0, 0x70, 0x10, 0x90, 0x83, 0x60, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x90, 0x83, +0x66, 0xE0, 0xFD, 0x12, 0x76, 0xBC, 0x90, 0x81, 0x85, 0xE0, 0x20, 0xE0, 0x07, 0x90, 0x01, 0x3F, +0xE0, 0x30, 0xE2, 0x04, 0x7F, 0x01, 0x31, 0xD1, 0x12, 0x7A, 0xA2, 0xEF, 0x64, 0x01, 0x70, 0x40, +0x12, 0x79, 0x4F, 0x90, 0x83, 0x6D, 0xEF, 0xF0, 0x64, 0x01, 0x60, 0x27, 0x90, 0x81, 0x85, 0xE0, +0x44, 0x01, 0xF0, 0x90, 0x83, 0x6D, 0xE0, 0xFF, 0xB4, 0x02, 0x08, 0x90, 0x01, 0xC7, 0x74, 0x42, +0xF0, 0x80, 0x0A, 0xEF, 0xB4, 0x04, 0x06, 0x90, 0x01, 0xC7, 0x74, 0x43, 0xF0, 0x7F, 0x01, 0x31, +0xD1, 0x80, 0x0D, 0x90, 0x83, 0x5D, 0xF1, 0xD2, 0x90, 0x83, 0x63, 0xE0, 0x04, 0xF0, 0x81, 0x6C, +0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x81, 0x3A, 0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, +0x05, 0x90, 0x01, 0x5B, 0xE4, 0xF0, 0x90, 0x06, 0x92, 0x74, 0x02, 0xF0, 0x90, 0x01, 0x3C, 0x74, +0x04, 0xF0, 0xE4, 0xF5, 0x52, 0x90, 0x81, 0x78, 0xE0, 0xC3, 0x13, 0x54, 0x7F, 0xF5, 0x53, 0xE4, +0xFB, 0xFD, 0x7F, 0x58, 0x7E, 0x01, 0xF1, 0xF6, 0x90, 0x81, 0x3A, 0xE0, 0x44, 0x08, 0xF0, 0x22, +0x90, 0x83, 0x5F, 0xE0, 0xFF, 0xE4, 0xFE, 0xEF, 0x2E, 0x24, 0x04, 0xF5, 0x82, 0xE4, 0x34, 0xFB, +0xF5, 0x83, 0xE0, 0xFD, 0x74, 0x6F, 0x2E, 0xF5, 0x82, 0xE4, 0x34, 0x83, 0xF5, 0x83, 0xED, 0xF0, +0x0E, 0xEE, 0xB4, 0x06, 0xE2, 0x78, 0x86, 0x7C, 0x81, 0x7D, 0x01, 0x7B, 0x01, 0x7A, 0x83, 0x79, +0x6F, 0x7E, 0x00, 0x7F, 0x06, 0x12, 0x43, 0xEF, 0xEF, 0x7F, 0x00, 0x70, 0x02, 0x7F, 0x01, 0x22, +0xA3, 0xE0, 0xFE, 0x24, 0x20, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0xFF, 0x74, 0x21, +0x2E, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0xFD, 0x74, 0x24, 0x2E, 0xF5, 0x82, 0xE4, +0x34, 0xFC, 0xF5, 0x83, 0xE0, 0xFB, 0xE4, 0xFE, 0xEF, 0x30, 0xE7, 0x04, 0x7C, 0x02, 0x80, 0x02, +0xE4, 0xFC, 0xED, 0x30, 0xE6, 0x09, 0xAF, 0x03, 0x12, 0x6E, 0x9B, 0xAE, 0x07, 0x80, 0x02, 0xE4, +0xFE, 0xEC, 0x24, 0x18, 0x2E, 0xFF, 0x22, 0x90, 0x81, 0x3A, 0xE0, 0xFF, 0x13, 0x13, 0x54, 0x3F, +0x30, 0xE0, 0x11, 0xEF, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x42, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0x07, +0x70, 0x2D, 0x80, 0x29, 0x90, 0x81, 0x47, 0xE0, 0x04, 0xF0, 0x90, 0x81, 0x42, 0xE0, 0x54, 0xEF, +0xF0, 0x90, 0x81, 0x76, 0xE0, 0xFF, 0x90, 0x81, 0x47, 0xE0, 0xD3, 0x9F, 0x40, 0x0F, 0x90, 0x80, +0xF9, 0xE0, 0xB4, 0x01, 0x0A, 0x90, 0x81, 0x3B, 0xE0, 0x54, 0xFB, 0xF0, 0x22, 0x31, 0xBF, 0x22, +0x8F, 0x0D, 0x7F, 0x02, 0x12, 0x46, 0x3A, 0x90, 0x80, 0x01, 0xE0, 0x45, 0x0D, 0xF0, 0x22, 0x12, +0x66, 0x21, 0x7F, 0x02, 0x80, 0xEA, 0x90, 0x81, 0x7D, 0xE0, 0x30, 0xE0, 0x04, 0x7F, 0x10, 0xF1, +0xB0, 0x22, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x90, 0x02, 0x84, 0xEF, 0xF0, 0xEE, 0xA3, 0xF0, 0xA3, +0xE0, 0x44, 0x01, 0xF0, 0x22, 0xF0, 0xE4, 0xF5, 0x52, 0x90, 0x81, 0x77, 0xE0, 0xF5, 0x53, 0xE4, +0xFB, 0xFD, 0x7F, 0x54, 0x7E, 0x01, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x8E, 0x4E, 0x8F, +0x4F, 0xE5, 0x53, 0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0, 0x85, 0x4E, 0x83, 0x85, 0x4F, 0x82, 0xF0, +0xE5, 0x52, 0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0, 0xFF, 0xE5, 0x53, 0x13, 0x13, 0x13, 0x54, 0x1F, +0x4F, 0xA3, 0xF0, 0xEB, 0x54, 0x07, 0xC4, 0x33, 0x54, 0xE0, 0xFF, 0xE5, 0x52, 0x13, 0x13, 0x13, +0x54, 0x1F, 0x4F, 0x85, 0x4F, 0x82, 0x85, 0x4E, 0x83, 0xA3, 0xA3, 0xF0, 0xBD, 0x01, 0x0D, 0x85, +0x4F, 0x82, 0x8E, 0x83, 0xA3, 0xA3, 0xA3, 0x74, 0x03, 0xF0, 0x80, 0x0C, 0x85, 0x4F, 0x82, 0x85, +0x4E, 0x83, 0xA3, 0xA3, 0xA3, 0x74, 0x01, 0xF0, 0x85, 0x4F, 0x82, 0x85, 0x4E, 0x83, 0xA3, 0xA3, +0xA3, 0x74, 0x05, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x00, 0xF7, 0xE0, 0x20, 0xE7, 0x09, +0xE0, 0x7F, 0x01, 0x20, 0xE6, 0x0C, 0x7F, 0x02, 0x22, 0x90, 0x00, 0xF7, 0xE0, 0x30, 0xE6, 0x02, +0x7F, 0x03, 0x22, 0x11, 0x69, 0x90, 0x80, 0x06, 0xEF, 0xF0, 0x11, 0x95, 0x90, 0x01, 0x64, 0x74, +0x01, 0xF0, 0x02, 0x2D, 0xA7, 0x31, 0x01, 0x31, 0x31, 0x11, 0xC3, 0x11, 0xE2, 0xE4, 0xF5, 0x35, +0xF5, 0x36, 0xF5, 0x37, 0x75, 0x38, 0x80, 0xAD, 0x35, 0x7F, 0x50, 0x12, 0x32, 0x1E, 0xAD, 0x36, +0x7F, 0x51, 0x12, 0x32, 0x1E, 0xAD, 0x37, 0x7F, 0x52, 0x12, 0x32, 0x1E, 0xAD, 0x38, 0x7F, 0x53, +0x02, 0x32, 0x1E, 0x75, 0x3D, 0x10, 0xE4, 0xF5, 0x3E, 0x75, 0x3F, 0x07, 0x75, 0x40, 0x02, 0x90, +0x01, 0x30, 0xE5, 0x3D, 0xF0, 0xA3, 0xE5, 0x3E, 0xF0, 0xA3, 0xE5, 0x3F, 0xF0, 0xA3, 0xE5, 0x40, +0xF0, 0x22, 0x75, 0x45, 0x06, 0x75, 0x46, 0x01, 0x75, 0x47, 0x03, 0x75, 0x48, 0x62, 0x90, 0x01, +0x38, 0xE5, 0x45, 0xF0, 0xA3, 0xE5, 0x46, 0xF0, 0xA3, 0xE5, 0x47, 0xF0, 0xA3, 0xE5, 0x48, 0xF0, +0x22, 0x90, 0x01, 0x30, 0xE4, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x38, 0xF0, +0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, 0x50, 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x51, +0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x52, 0x12, 0x32, 0x1E, 0xE4, 0xFD, 0x7F, 0x53, 0x02, 0x32, +0x1E, 0x90, 0x01, 0x34, 0x74, 0xFF, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, 0x3C, +0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xFD, 0x7F, 0x54, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, +0x55, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x56, 0x12, 0x32, 0x1E, 0x7D, 0xFF, 0x7F, 0x57, 0x02, +0x32, 0x1E, 0x90, 0x01, 0xCF, 0xE0, 0x90, 0x83, 0xFF, 0xF0, 0xE0, 0xFF, 0x30, 0xE0, 0x07, 0x90, +0x01, 0xCF, 0xE0, 0x54, 0xFE, 0xF0, 0xEF, 0x30, 0xE5, 0x22, 0x90, 0x01, 0xCF, 0xE0, 0x54, 0xDF, +0xF0, 0x90, 0x01, 0x34, 0x74, 0x20, 0xF0, 0xE4, 0xF5, 0xA8, 0xF5, 0xE8, 0x31, 0x01, 0x90, 0x00, +0x03, 0xE0, 0x54, 0xFB, 0xFD, 0x7F, 0x03, 0x12, 0x32, 0x1E, 0x80, 0xFE, 0x22, 0x90, 0x00, 0x80, +0xE0, 0x44, 0x80, 0xFD, 0x7F, 0x80, 0x12, 0x32, 0x1E, 0x90, 0xFD, 0x00, 0xE0, 0x54, 0xBF, 0xF0, +0x51, 0x2F, 0x12, 0x32, 0x77, 0x51, 0x10, 0x51, 0x4A, 0x7F, 0x01, 0x12, 0x45, 0x28, 0x90, 0x83, +0x3F, 0x74, 0x02, 0xF0, 0xFF, 0x12, 0x45, 0x28, 0x90, 0x83, 0x3F, 0xE0, 0x04, 0xF0, 0x11, 0x83, +0x31, 0xEC, 0x90, 0x00, 0x80, 0xE0, 0x44, 0x40, 0xFD, 0x7F, 0x80, 0x12, 0x32, 0x1E, 0x75, 0x20, +0xFF, 0x51, 0x17, 0x51, 0x1E, 0x51, 0x25, 0xE4, 0xFF, 0x02, 0x45, 0xB1, 0x51, 0x11, 0x51, 0x3C, +0x12, 0x71, 0x6B, 0x12, 0x4E, 0x36, 0x51, 0x58, 0x51, 0x6F, 0x90, 0x83, 0x4C, 0xE0, 0x54, 0x7F, +0xF0, 0x54, 0xBF, 0xF0, 0x54, 0xDF, 0xF0, 0x54, 0xF0, 0xF0, 0xE4, 0x90, 0x83, 0x4E, 0xF0, 0x22, +0x22, 0xE4, 0x90, 0x80, 0xF9, 0xF0, 0x22, 0x75, 0xE8, 0x03, 0x75, 0xA8, 0x84, 0x22, 0x90, 0x01, +0xC7, 0x74, 0xFE, 0xF0, 0x22, 0x90, 0x01, 0xE4, 0x74, 0x10, 0xF0, 0xA3, 0xE4, 0xF0, 0x22, 0x90, +0x01, 0x94, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x01, 0xC7, 0xE4, 0xF0, 0x22, 0xE4, 0x90, 0x80, 0xF5, +0xF0, 0xA3, 0xF0, 0x90, 0x80, 0x5D, 0xF0, 0xA3, 0xF0, 0x22, 0xE4, 0x90, 0x80, 0x01, 0xF0, 0xA3, +0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x22, 0x90, 0x83, 0x40, 0xE0, 0x54, 0xFE, 0xF0, 0x54, +0x7F, 0xF0, 0x54, 0xFB, 0xF0, 0xA3, 0x74, 0x0A, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0x22, 0x90, +0x83, 0x44, 0xE0, 0x54, 0xFE, 0xF0, 0xA3, 0x74, 0x08, 0xF0, 0xA3, 0x74, 0x03, 0xF0, 0xE4, 0x90, +0x83, 0x48, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x83, 0x44, 0xE0, 0x54, 0xFB, 0xF0, 0xE4, 0x90, +0x83, 0x47, 0xF0, 0x90, 0x83, 0x4B, 0xF0, 0x22, 0x51, 0x6F, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, +0xFE, 0x90, 0x83, 0x44, 0xE0, 0x54, 0xFE, 0x4E, 0xF0, 0xEF, 0xC3, 0x13, 0x30, 0xE0, 0x2C, 0x90, +0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x83, 0x45, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, +0x83, 0x46, 0xF0, 0x12, 0x1F, 0xA4, 0x54, 0x04, 0xFF, 0x90, 0x83, 0x44, 0xE0, 0x54, 0xFB, 0x4F, +0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0x90, 0x83, 0x47, 0xF0, 0x22, 0x90, 0x83, 0x5E, 0x12, +0x42, 0x3A, 0x90, 0x83, 0x5D, 0xEF, 0xF0, 0x12, 0x42, 0x43, 0x5B, 0x1E, 0x00, 0x5B, 0x27, 0x01, +0x5B, 0x2F, 0x02, 0x5B, 0x38, 0x03, 0x5B, 0x40, 0x04, 0x5B, 0x48, 0x14, 0x5B, 0x50, 0x20, 0x5B, +0x58, 0x21, 0x5B, 0x61, 0x23, 0x5B, 0x69, 0x25, 0x5B, 0x79, 0x80, 0x5B, 0x71, 0x81, 0x5B, 0x82, +0x82, 0x5B, 0x8A, 0x83, 0x5B, 0x93, 0x84, 0x5B, 0x9C, 0x88, 0x00, 0x00, 0x5B, 0xA4, 0x90, 0x83, +0x5E, 0x12, 0x42, 0x31, 0x02, 0x65, 0x4E, 0x90, 0x83, 0x5E, 0x12, 0x42, 0x31, 0x81, 0x18, 0x90, +0x83, 0x5E, 0x12, 0x42, 0x31, 0x02, 0x65, 0x9A, 0x90, 0x83, 0x5E, 0x12, 0x42, 0x31, 0xE1, 0xA9, +0x90, 0x83, 0x5E, 0x12, 0x42, 0x31, 0x41, 0x98, 0x90, 0x83, 0x5E, 0x12, 0x42, 0x31, 0xE1, 0x2D, +0x90, 0x83, 0x5E, 0x12, 0x42, 0x31, 0xA1, 0xEB, 0x90, 0x83, 0x5E, 0x12, 0x42, 0x31, 0x02, 0x65, +0xDD, 0x90, 0x83, 0x5E, 0x12, 0x42, 0x31, 0xE1, 0x1D, 0x90, 0x83, 0x5E, 0x12, 0x42, 0x31, 0xE1, +0x25, 0x90, 0x83, 0x5E, 0x12, 0x42, 0x31, 0x81, 0x97, 0x90, 0x83, 0x5E, 0x12, 0x42, 0x31, 0x02, +0x79, 0x65, 0x90, 0x83, 0x5E, 0x12, 0x42, 0x31, 0xE1, 0x71, 0x90, 0x83, 0x5E, 0x12, 0x42, 0x31, +0x02, 0x7B, 0x07, 0x90, 0x83, 0x5E, 0x12, 0x42, 0x31, 0x02, 0x7B, 0x69, 0x90, 0x83, 0x5E, 0x12, +0x42, 0x31, 0xE1, 0x3C, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x83, 0x5D, 0xE0, 0x90, +0x01, 0xC2, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x80, 0x5E, 0xE0, 0xFF, +0x90, 0x80, 0x5D, 0xE0, 0xB5, 0x07, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x70, 0x43, +0x90, 0x80, 0x5D, 0xE0, 0xFE, 0x75, 0xF0, 0x08, 0x90, 0x80, 0x0D, 0x12, 0x42, 0x25, 0xE0, 0xFD, +0xEE, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x0E, 0xF9, 0x74, 0x80, 0x35, 0xF0, 0xFA, 0x7B, 0x01, 0xAF, +0x05, 0x51, 0xDC, 0x90, 0x80, 0x5D, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4, 0x0A, 0x02, 0x7F, +0x01, 0xEF, 0x60, 0x05, 0xE4, 0x90, 0x80, 0x5D, 0xF0, 0x12, 0x66, 0x21, 0x90, 0x80, 0x01, 0xE0, +0x44, 0x02, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x8B, 0x1A, 0x8A, 0x1B, 0x89, 0x1C, 0x90, 0x00, +0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xF5, 0x1E, 0x12, 0x1F, 0xA4, 0xFE, 0xC3, 0x13, 0x30, 0xE0, 0x0A, +0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xF5, 0x1F, 0x80, 0x02, 0x8F, 0x1F, 0x85, 0x1E, 0x1D, 0xE5, +0x1D, 0xD3, 0x95, 0x1F, 0x50, 0x33, 0xAB, 0x1A, 0xAA, 0x1B, 0xA9, 0x1C, 0x12, 0x1F, 0xA4, 0x54, +0x01, 0xFF, 0x74, 0xF9, 0x25, 0x1D, 0xF5, 0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83, 0xEF, 0xF0, 0x74, +0xF9, 0x25, 0x1D, 0xF5, 0x82, 0xE4, 0x34, 0x80, 0xF5, 0x83, 0xE0, 0xAF, 0x1D, 0x70, 0x04, 0xF1, +0x1C, 0x80, 0x02, 0xF1, 0x1B, 0x05, 0x1D, 0x80, 0xC6, 0xE5, 0x1E, 0x70, 0x19, 0x90, 0x80, 0xF9, +0xE0, 0x70, 0x13, 0x12, 0x4E, 0x97, 0x12, 0x4F, 0x1E, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0xF7, 0xF0, +0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x12, 0x1F, +0xA4, 0xFF, 0x54, 0x01, 0xFE, 0x90, 0x81, 0x7D, 0xE0, 0x54, 0xFE, 0x4E, 0xFE, 0xF0, 0xEF, 0x54, +0x02, 0xFF, 0xEE, 0x54, 0xFD, 0x4F, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x04, 0xFD, 0xEF, +0x54, 0xFB, 0x4D, 0xFF, 0x90, 0x81, 0x7D, 0xF0, 0xEE, 0x54, 0x08, 0xFE, 0xEF, 0x54, 0xF7, 0x4E, +0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x10, 0xFD, 0xEF, 0x54, 0xEF, 0x4D, 0xFF, 0x90, 0x81, +0x7D, 0xF0, 0xEE, 0x54, 0x20, 0xFE, 0xEF, 0x54, 0xDF, 0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, +0x54, 0x40, 0xFD, 0xEF, 0x54, 0xBF, 0x4D, 0xFF, 0x90, 0x81, 0x7D, 0xF0, 0xEE, 0x54, 0x80, 0xFE, +0xEF, 0x54, 0x7F, 0x4E, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x54, 0x01, 0xFF, 0x90, 0x81, +0x7F, 0xE0, 0x54, 0xFE, 0x4F, 0xF0, 0x90, 0x01, 0x17, 0xE0, 0xFE, 0x90, 0x01, 0x16, 0xE0, 0x7C, +0x00, 0x24, 0x00, 0xFF, 0xEC, 0x3E, 0x90, 0x80, 0xF7, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x81, 0x7D, +0xE0, 0xC3, 0x13, 0x54, 0x01, 0xFF, 0xB1, 0x47, 0x90, 0x81, 0x7D, 0xE0, 0x54, 0x01, 0xFF, 0x12, +0x4D, 0xBA, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xEF, 0x60, 0x07, 0x90, 0x83, 0x31, 0xE0, 0xFF, 0xB1, +0x52, 0x22, 0xF1, 0x5D, 0x90, 0x83, 0xEE, 0xE4, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x83, 0xEE, 0x12, +0x57, 0x20, 0x90, 0x83, 0xF0, 0xEF, 0xF0, 0x90, 0x83, 0xEE, 0xA3, 0xE0, 0x24, 0x30, 0xF9, 0xE4, +0x34, 0xFC, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x06, 0x7B, 0x01, 0x7A, 0x81, +0x79, 0x9C, 0x12, 0x2B, 0xED, 0x90, 0x83, 0xEE, 0xA3, 0xE0, 0xFF, 0xA3, 0xE0, 0x2F, 0x24, 0x36, +0xF9, 0xE4, 0x34, 0xFC, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x04, 0x7B, 0x01, +0x7A, 0x81, 0x79, 0xA2, 0x12, 0x2B, 0xED, 0x90, 0x83, 0xEE, 0xA3, 0xE0, 0xFF, 0xA3, 0xE0, 0x2F, +0x24, 0x3A, 0xF9, 0xE4, 0x34, 0xFC, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x06, +0x7B, 0x01, 0x7A, 0x81, 0x79, 0xA6, 0x12, 0x2B, 0xED, 0x90, 0x83, 0xEE, 0xA3, 0xE0, 0xFF, 0xA3, +0xE0, 0x2F, 0x24, 0x40, 0xF9, 0xE4, 0x34, 0xFC, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, +0x16, 0x04, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0xAC, 0x02, 0x2B, 0xED, 0x90, 0x83, 0x61, 0x12, 0x42, +0x3A, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x7F, 0x90, 0x81, 0x3E, 0xF0, 0xEF, 0xC4, 0x13, 0x13, 0x13, +0x54, 0x01, 0xA3, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0x54, 0xF0, 0xC4, 0x54, 0x0F, +0xFE, 0x90, 0x81, 0x3C, 0xE0, 0x54, 0xF0, 0x4E, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0x54, +0x01, 0x25, 0xE0, 0xFE, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0xFD, 0x4E, 0xF0, 0xEF, 0x54, 0x0F, 0xC4, +0x54, 0xF0, 0xFF, 0x90, 0x81, 0x3C, 0xE0, 0x54, 0x0F, 0x4F, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, +0xBD, 0x90, 0x81, 0x3D, 0xF0, 0x90, 0x00, 0x06, 0x12, 0x1F, 0xBD, 0x30, 0xE0, 0x5E, 0xC3, 0x13, +0x54, 0x07, 0xFF, 0xC3, 0x94, 0x04, 0x90, 0x81, 0x50, 0x50, 0x04, 0xEF, 0xF0, 0x80, 0x2E, 0x74, +0x03, 0xF0, 0x90, 0x83, 0x61, 0x12, 0x42, 0x31, 0xE9, 0x24, 0x06, 0xF9, 0xE4, 0x3A, 0xFA, 0x12, +0x1F, 0xA4, 0xFF, 0x74, 0x03, 0x24, 0xFD, 0xFE, 0xEF, 0xC4, 0x54, 0x0F, 0xFD, 0xEF, 0x54, 0x0F, +0xFF, 0xED, 0x2E, 0x54, 0x0F, 0xFE, 0xC4, 0x54, 0xF0, 0x4F, 0x12, 0x1F, 0xEA, 0x90, 0x83, 0x61, +0x12, 0x42, 0x31, 0x90, 0x00, 0x06, 0x12, 0x1F, 0xBD, 0xC4, 0x54, 0x0F, 0xFF, 0xC3, 0x94, 0x04, +0x90, 0x81, 0x46, 0x50, 0x05, 0x74, 0x04, 0xF0, 0x80, 0x02, 0xEF, 0xF0, 0x90, 0x83, 0x61, 0x12, +0x42, 0x31, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFD, 0x7F, 0x02, 0x12, 0x4B, 0x33, 0x90, 0x83, +0x61, 0x12, 0x42, 0x31, 0xD1, 0xEB, 0x90, 0x01, 0xB9, 0x74, 0x01, 0xF0, 0x90, 0x01, 0xB8, 0xF0, +0x90, 0x81, 0x3E, 0xE0, 0x90, 0x01, 0xBA, 0xF0, 0x90, 0x81, 0x40, 0xE0, 0x90, 0x01, 0xBB, 0xF0, +0x90, 0x81, 0x3C, 0xE0, 0x54, 0x0F, 0x90, 0x01, 0xBE, 0xF0, 0x22, 0x90, 0x83, 0x64, 0x12, 0x42, +0x3A, 0xF1, 0x4C, 0x90, 0x81, 0x3E, 0xE0, 0xFF, 0x12, 0x4F, 0x30, 0x90, 0x81, 0x3E, 0xE0, 0x60, +0x19, 0x90, 0x83, 0x64, 0x12, 0x42, 0x31, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x54, 0x0F, 0xFF, +0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFD, 0x12, 0x73, 0x14, 0x22, 0x22, 0x22, 0x12, 0x1F, 0xA4, +0x90, 0x81, 0x48, 0xF0, 0x22, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x7C, 0xF0, 0x22, 0x12, 0x1F, 0xA4, +0x54, 0x01, 0xFF, 0x90, 0x83, 0x51, 0xE0, 0x54, 0xFE, 0x4F, 0xF0, 0x22, 0x90, 0x02, 0x09, 0xE0, +0xFF, 0x12, 0x1F, 0xA4, 0xFE, 0xEF, 0x2E, 0x90, 0x83, 0x3E, 0xF0, 0x22, 0x90, 0x81, 0x3A, 0xE0, +0x54, 0xFB, 0xF0, 0xE4, 0x90, 0x81, 0x47, 0xF0, 0x90, 0x81, 0x42, 0xF0, 0x22, 0xE4, 0xFE, 0xEF, +0xC3, 0x13, 0xFD, 0xEF, 0x30, 0xE0, 0x02, 0x7E, 0x80, 0x90, 0xFD, 0x10, 0xED, 0xF0, 0xAF, 0x06, +0x22, 0x90, 0x02, 0x09, 0xE0, 0x90, 0x83, 0x61, 0xF0, 0x12, 0x1F, 0xA4, 0x90, 0x83, 0x2E, 0xF0, +0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x83, 0x2F, 0xF0, 0x22, 0xF1, 0x5D, 0x7E, 0x00, 0x74, +0x00, 0x2F, 0xF9, 0xE4, 0x34, 0xFC, 0x75, 0x13, 0x01, 0xF5, 0x14, 0x89, 0x15, 0x75, 0x16, 0x08, +0x7B, 0x01, 0x7A, 0x82, 0x79, 0x48, 0x02, 0x2B, 0xED, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, +0x90, 0x83, 0x40, 0xE0, 0x54, 0xFE, 0x4E, 0xFE, 0xF0, 0xEF, 0x54, 0x04, 0xFF, 0xEE, 0x54, 0xFB, +0x4F, 0xF0, 0x12, 0x1F, 0xA4, 0xC3, 0x13, 0x30, 0xE0, 0x0A, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, +0x90, 0x83, 0x41, 0xF0, 0x22, 0xE4, 0x90, 0x83, 0x58, 0xF0, 0x90, 0x83, 0x58, 0xE0, 0x64, 0x01, +0xF0, 0x24, 0xD5, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x5F, 0xA3, 0xF0, 0x90, 0x81, 0x3E, 0xE0, 0x60, +0x0F, 0x90, 0x81, 0x41, 0xE0, 0xFF, 0x90, 0x81, 0x40, 0xE0, 0x6F, 0x60, 0x03, 0x12, 0x51, 0xBF, +0xC2, 0xAF, 0x31, 0x12, 0xBF, 0x01, 0x02, 0x11, 0x12, 0xD2, 0xAF, 0x11, 0xF4, 0x12, 0x44, 0x60, +0x80, 0xC8, 0x90, 0x81, 0x3A, 0xE0, 0x30, 0xE0, 0x02, 0x11, 0x1C, 0x22, 0x90, 0x81, 0x41, 0xE0, +0xFF, 0x60, 0x03, 0xB4, 0x08, 0x0D, 0x31, 0x43, 0xBF, 0x01, 0x08, 0x11, 0x34, 0x90, 0x01, 0xE5, +0xE0, 0x04, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x11, 0xAF, 0x11, 0x44, 0xD0, +0xD0, 0x92, 0xAF, 0x22, 0x11, 0xF5, 0x90, 0x00, 0x08, 0xE0, 0x54, 0xEF, 0xFD, 0x7F, 0x08, 0x12, +0x32, 0x1E, 0xE4, 0xFF, 0x90, 0x83, 0x59, 0xEF, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x01, +0x09, 0xE0, 0x7F, 0x00, 0x30, 0xE7, 0x02, 0x7F, 0x01, 0x90, 0x83, 0x59, 0xE0, 0x6F, 0x60, 0x3E, +0xC3, 0x90, 0x83, 0x5B, 0xE0, 0x94, 0x88, 0x90, 0x83, 0x5A, 0xE0, 0x94, 0x13, 0x40, 0x08, 0x90, +0x01, 0xC0, 0xE0, 0x44, 0x10, 0xF0, 0x22, 0x90, 0x83, 0x5A, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x41, +0xF6, 0x7F, 0x14, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0xD3, 0x90, 0x83, 0x5B, 0xE0, 0x94, 0x32, 0x90, +0x83, 0x5A, 0xE0, 0x94, 0x00, 0x40, 0xB7, 0x90, 0x01, 0xC6, 0xE0, 0x30, 0xE0, 0xB0, 0x22, 0x90, +0x81, 0x48, 0xE0, 0xFD, 0x7F, 0x93, 0x12, 0x32, 0x1E, 0x90, 0x81, 0x3F, 0xE0, 0x60, 0x12, 0x90, +0x01, 0x2F, 0xE0, 0x30, 0xE7, 0x05, 0x74, 0x10, 0xF0, 0x80, 0x06, 0x90, 0x01, 0x2F, 0x74, 0x90, +0xF0, 0x90, 0x00, 0x08, 0xE0, 0x44, 0x10, 0xFD, 0x7F, 0x08, 0x12, 0x32, 0x1E, 0x7F, 0x01, 0x11, +0x54, 0x90, 0x00, 0x90, 0xE0, 0x44, 0x01, 0xFD, 0x7F, 0x90, 0x12, 0x32, 0x1E, 0x7F, 0x14, 0x7E, +0x00, 0x02, 0x32, 0xAA, 0x22, 0x90, 0x01, 0xC4, 0x74, 0xF5, 0xF0, 0x74, 0x60, 0xA3, 0xF0, 0x90, +0x00, 0x90, 0xE0, 0x20, 0xE0, 0xF9, 0x74, 0xF5, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x60, 0xA3, +0xF0, 0x22, 0x7D, 0x02, 0x90, 0x01, 0xC4, 0x74, 0x12, 0xF0, 0x74, 0x61, 0xA3, 0xF0, 0x90, 0x83, +0x3F, 0xE0, 0xFF, 0xED, 0xC3, 0x9F, 0x50, 0x18, 0xED, 0x25, 0xE0, 0x24, 0x81, 0xF8, 0xE6, 0x30, +0xE4, 0x0B, 0x90, 0x01, 0xB8, 0x74, 0x08, 0xF0, 0xA3, 0xF0, 0x7F, 0x00, 0x22, 0x0D, 0x80, 0xDE, +0x7F, 0x01, 0x22, 0x90, 0x02, 0x87, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x01, 0xF0, 0x80, +0x49, 0x90, 0x81, 0x7D, 0xE0, 0x30, 0xE0, 0x0E, 0x90, 0x02, 0x82, 0xE0, 0x60, 0x08, 0x90, 0x01, +0xB8, 0x74, 0x02, 0xF0, 0x80, 0x34, 0x90, 0x81, 0x85, 0xE0, 0x30, 0xE0, 0x08, 0x90, 0x01, 0xB8, +0x74, 0x08, 0xF0, 0x80, 0x25, 0x90, 0x02, 0x86, 0xE0, 0x20, 0xE1, 0x08, 0x90, 0x01, 0xB8, 0x74, +0x04, 0xF0, 0x80, 0x16, 0x90, 0x04, 0x1D, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x40, 0xF0, +0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x08, 0xF0, +0x7F, 0x00, 0x22, 0xE4, 0xFB, 0xFA, 0xFD, 0x7F, 0x01, 0x12, 0x46, 0x61, 0x90, 0x83, 0x5C, 0xEF, +0xF0, 0x60, 0xF0, 0x90, 0x80, 0x01, 0xE0, 0xFF, 0x60, 0xE9, 0xC2, 0xAF, 0x30, 0xE1, 0x06, 0x54, +0xFD, 0xF0, 0x12, 0x5B, 0xB4, 0xD2, 0xAF, 0xC2, 0xAF, 0x90, 0x80, 0x01, 0xE0, 0xFF, 0x30, 0xE2, +0x05, 0x54, 0xFB, 0xF0, 0x31, 0xF1, 0xD2, 0xAF, 0xC2, 0xAF, 0x90, 0x80, 0x01, 0xE0, 0xFF, 0x30, +0xE4, 0x0B, 0x54, 0xEF, 0xF0, 0x51, 0xAC, 0xBF, 0x01, 0x03, 0x12, 0x53, 0xFA, 0xD2, 0xAF, 0x80, +0xC2, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xE4, 0xFF, 0x90, 0x80, 0xF6, 0xE0, 0xFE, 0x90, +0x80, 0xF5, 0xE0, 0xFD, 0xB5, 0x06, 0x04, 0x7E, 0x01, 0x80, 0x02, 0x7E, 0x00, 0xEE, 0x64, 0x01, +0x60, 0x32, 0x90, 0x01, 0xAF, 0xE0, 0x70, 0x13, 0xED, 0x75, 0xF0, 0x0F, 0xA4, 0x24, 0x5F, 0xF9, +0x74, 0x80, 0x35, 0xF0, 0xFA, 0x7B, 0x01, 0x51, 0x49, 0x7F, 0x01, 0xEF, 0x60, 0x16, 0x90, 0x80, +0xF5, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4, 0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x60, 0x05, 0xE4, +0x90, 0x80, 0xF5, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, +0x90, 0x83, 0x5D, 0x12, 0x42, 0x3A, 0x90, 0x83, 0xF2, 0xE0, 0xFF, 0x04, 0xF0, 0x90, 0x00, 0x01, +0xEF, 0x12, 0x1F, 0xFC, 0x7F, 0xAF, 0x7E, 0x01, 0x51, 0xE9, 0xEF, 0x60, 0x3A, 0x90, 0x83, 0x5D, +0x12, 0x42, 0x31, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x90, 0x00, 0x0E, 0x12, 0x1F, 0xBD, 0x24, +0x02, 0xF5, 0x16, 0x7B, 0x01, 0x7A, 0x01, 0x79, 0xA0, 0x12, 0x2B, 0xED, 0x90, 0x83, 0x5D, 0x12, +0x42, 0x31, 0x90, 0x00, 0x0E, 0x12, 0x1F, 0xBD, 0x90, 0x01, 0xAE, 0xF0, 0xA3, 0x74, 0xFF, 0xF0, +0x90, 0x01, 0xCB, 0xE0, 0x64, 0x80, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xE4, 0x90, 0x83, 0xFB, +0xF0, 0xA3, 0xF0, 0x90, 0x02, 0x86, 0xE0, 0x20, 0xE1, 0x2C, 0xC3, 0x90, 0x83, 0xFC, 0xE0, 0x94, +0xD0, 0x90, 0x83, 0xFB, 0xE0, 0x94, 0x07, 0x40, 0x0A, 0x90, 0x01, 0xC1, 0xE0, 0x44, 0x04, 0xF0, +0x7F, 0x00, 0x22, 0x90, 0x83, 0xFB, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x41, 0xF6, 0x7F, 0x0A, 0x7E, +0x00, 0x12, 0x32, 0xAA, 0x80, 0xCD, 0x7F, 0x01, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, +0x90, 0x83, 0xDA, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xE4, 0xA3, 0xF0, 0xA3, 0xF0, 0x90, 0x83, 0xDA, +0xE0, 0xFE, 0xA3, 0xE0, 0xF5, 0x82, 0x8E, 0x83, 0xE0, 0x60, 0x2D, 0xC3, 0x90, 0x83, 0xDD, 0xE0, +0x94, 0xE8, 0x90, 0x83, 0xDC, 0xE0, 0x94, 0x03, 0x40, 0x0B, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x80, +0xF0, 0x7F, 0x00, 0x80, 0x15, 0x90, 0x83, 0xDC, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x41, 0xF6, 0x7F, +0x0A, 0x7E, 0x00, 0x12, 0x32, 0xAA, 0x80, 0xC5, 0x7F, 0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, +0x83, 0x9A, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0xA3, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xE4, +0x90, 0x83, 0xA8, 0xF0, 0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2D, 0x5C, 0x90, 0x83, 0xA0, 0x12, 0x20, +0xCE, 0x90, 0x83, 0x9A, 0xE0, 0xFB, 0x70, 0x08, 0x90, 0x83, 0xA0, 0x12, 0x42, 0x19, 0x80, 0x16, +0xEB, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, +0xA3, 0xE0, 0xFF, 0x12, 0x2D, 0x5C, 0x90, 0x83, 0xA4, 0x12, 0x20, 0xCE, 0x90, 0x83, 0x9B, 0xE0, +0xFF, 0xE4, 0xFC, 0xFD, 0xFE, 0x78, 0x17, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, +0xAB, 0x07, 0x90, 0x83, 0xA4, 0x12, 0x42, 0x19, 0xED, 0x54, 0x7F, 0xFD, 0xEC, 0x54, 0x80, 0xFC, +0x12, 0x42, 0x0C, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x83, 0xA4, 0x12, 0x20, 0xCE, 0x90, 0x83, 0xA0, +0x12, 0x42, 0x19, 0xEC, 0x54, 0x7F, 0xFC, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0x7F, 0x24, 0x7E, +0x08, 0x12, 0x2E, 0xA2, 0x90, 0x83, 0x9A, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x62, 0xF5, 0x82, +0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xC0, 0x06, 0xC0, 0x07, 0x90, 0x83, +0xA4, 0x12, 0x42, 0x19, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0xD0, 0x07, 0xD0, 0x06, 0x12, 0x2E, +0xA2, 0x90, 0x83, 0xA0, 0x12, 0x42, 0x19, 0xEC, 0x44, 0x80, 0xFC, 0x90, 0x85, 0xBB, 0x12, 0x20, +0xCE, 0x7F, 0x24, 0x7E, 0x08, 0x12, 0x2E, 0xA2, 0x90, 0x83, 0x9A, 0xE0, 0x70, 0x04, 0x7F, 0x20, +0x80, 0x09, 0x90, 0x83, 0x9A, 0xE0, 0xB4, 0x01, 0x16, 0x7F, 0x28, 0x7E, 0x08, 0x12, 0x2D, 0x5C, +0x78, 0x08, 0x12, 0x20, 0xA8, 0xEF, 0x54, 0x01, 0xFF, 0xE4, 0x90, 0x83, 0xA8, 0xEF, 0xF0, 0x90, +0x83, 0xA8, 0xE0, 0x90, 0x83, 0x9A, 0x60, 0x0E, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x66, 0xF5, +0x82, 0xE4, 0x34, 0x87, 0x80, 0x0C, 0xE0, 0x75, 0xF0, 0x08, 0xA4, 0x24, 0x64, 0xF5, 0x82, 0xE4, +0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x12, 0x2D, 0x5C, 0xED, 0x54, 0x0F, 0xFD, +0xE4, 0xFC, 0x90, 0x83, 0x9C, 0x12, 0x20, 0xCE, 0x90, 0x83, 0x9C, 0x02, 0x42, 0x19, 0xD3, 0x10, +0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x71, 0x3F, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x83, 0xB7, 0xEF, +0xF0, 0xAB, 0x05, 0x90, 0x83, 0xBD, 0x12, 0x20, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x03, 0xE4, +0xFC, 0xFD, 0xFE, 0x78, 0x14, 0x12, 0x20, 0xBB, 0xA8, 0x04, 0xA9, 0x05, 0xAA, 0x06, 0xAB, 0x07, +0x90, 0x83, 0xB9, 0x12, 0x42, 0x19, 0xED, 0x54, 0x0F, 0xFD, 0xE4, 0xFC, 0x12, 0x42, 0x0C, 0xEC, +0x54, 0x0F, 0xFC, 0x90, 0x83, 0xBD, 0x12, 0x20, 0xCE, 0x90, 0x83, 0xB7, 0xE0, 0x75, 0xF0, 0x08, +0xA4, 0x24, 0x60, 0xF5, 0x82, 0xE4, 0x34, 0x87, 0xF5, 0x83, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xC0, +0x06, 0xC0, 0x07, 0x90, 0x83, 0xBD, 0x12, 0x42, 0x19, 0x90, 0x85, 0xBB, 0x12, 0x20, 0xCE, 0xD0, +0x07, 0xD0, 0x06, 0x02, 0x2E, 0xA2, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0xC0, 0x07, 0xC0, +0x05, 0x90, 0x83, 0xCB, 0x12, 0x42, 0x19, 0x90, 0x83, 0xB9, 0x12, 0x20, 0xCE, 0xD0, 0x05, 0xD0, +0x07, 0x91, 0x8C, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x83, 0xFD, 0xEF, 0xF0, 0x7F, 0x02, 0x12, +0x46, 0x3A, 0x90, 0x80, 0x01, 0xE0, 0xFF, 0x90, 0x83, 0xFD, 0xE0, 0xFE, 0xEF, 0x4E, 0x90, 0x80, +0x01, 0xF0, 0x22, 0x90, 0x83, 0xFE, 0xEF, 0xF0, 0x7F, 0x02, 0x12, 0x46, 0x3A, 0x90, 0x80, 0x02, +0xE0, 0xFF, 0x90, 0x83, 0xFE, 0xE0, 0xFE, 0xEF, 0x4E, 0x90, 0x80, 0x02, 0xF0, 0x22, 0x90, 0x02, +0x09, 0xE0, 0xF5, 0x1A, 0x12, 0x1F, 0xA4, 0x25, 0x1A, 0x90, 0x80, 0x07, 0xF0, 0x90, 0x00, 0x01, +0x12, 0x1F, 0xBD, 0x25, 0x1A, 0x90, 0x80, 0x08, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0x25, +0x1A, 0x90, 0x80, 0x09, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0x25, 0x1A, 0x90, 0x80, 0x0A, +0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0x25, 0x1A, 0x90, 0x80, 0x0B, 0xF0, 0x90, 0x00, 0x05, +0x12, 0x1F, 0xBD, 0x25, 0x1A, 0x90, 0x80, 0x0C, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, +0xD0, 0x8B, 0x1A, 0x8A, 0x1B, 0x89, 0x1C, 0x12, 0x1F, 0xA4, 0xFF, 0x90, 0x81, 0x39, 0xF0, 0xBF, +0x01, 0x10, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01, 0x60, 0x1C, 0x7D, 0x13, 0x7F, 0x6F, +0x80, 0x13, 0xAB, 0x1A, 0xAA, 0x1B, 0xA9, 0x1C, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x64, 0x01, +0x60, 0x06, 0xE4, 0xFD, 0xFF, 0x12, 0x4A, 0xED, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x00, 0x02, +0x12, 0x1F, 0xBD, 0xFF, 0x30, 0xE0, 0x26, 0x12, 0x1F, 0xA4, 0x90, 0x81, 0x76, 0xF0, 0x90, 0x00, +0x01, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x77, 0xF0, 0xEF, 0x54, 0xFE, 0xFF, 0xA3, 0xE0, 0x54, 0x01, +0x4F, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x79, 0xF0, 0x22, 0x90, 0x81, 0x76, +0x74, 0x05, 0xF0, 0xA3, 0xF0, 0xA3, 0xE0, 0x54, 0x01, 0x44, 0x28, 0xF0, 0xA3, 0x74, 0x05, 0xF0, +0x22, 0x90, 0x01, 0xCC, 0xE0, 0x54, 0x0F, 0x90, 0x83, 0xF3, 0xF0, 0x90, 0x83, 0xF3, 0xE0, 0xFD, +0x70, 0x02, 0xE1, 0x70, 0x90, 0x80, 0x5D, 0xE0, 0xFF, 0x70, 0x06, 0xA3, 0xE0, 0x64, 0x09, 0x60, +0x0A, 0xEF, 0x14, 0xFF, 0x90, 0x80, 0x5E, 0xE0, 0xB5, 0x07, 0x04, 0x7F, 0x01, 0x80, 0x02, 0x7F, +0x00, 0xEF, 0x60, 0x08, 0x90, 0x01, 0xC1, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x90, 0x83, 0xF1, 0xE0, +0xFF, 0x74, 0x01, 0x7E, 0x00, 0xA8, 0x07, 0x08, 0x80, 0x05, 0xC3, 0x33, 0xCE, 0x33, 0xCE, 0xD8, +0xF9, 0xFF, 0xEF, 0x5D, 0x70, 0x02, 0xE1, 0x4D, 0xE4, 0x90, 0x83, 0xF4, 0xF0, 0x90, 0x83, 0xF4, +0xE0, 0xF9, 0xC3, 0x94, 0x04, 0x50, 0x73, 0x90, 0x83, 0xF1, 0xE0, 0x75, 0xF0, 0x04, 0xA4, 0xFF, +0xE9, 0xFD, 0x7C, 0x00, 0x2F, 0xFF, 0xEC, 0x35, 0xF0, 0xFE, 0x74, 0xD0, 0x2F, 0xF5, 0x82, 0x74, +0x01, 0x3E, 0xF5, 0x83, 0xE0, 0xFF, 0x90, 0x80, 0x5E, 0xE0, 0x75, 0xF0, 0x08, 0x90, 0x80, 0x0D, +0x12, 0x42, 0x25, 0xE5, 0x82, 0x29, 0xF5, 0x82, 0xE4, 0x35, 0x83, 0xF5, 0x83, 0xEF, 0xF0, 0x90, +0x83, 0xF1, 0xE0, 0x75, 0xF0, 0x04, 0xA4, 0x2D, 0xFF, 0xEC, 0x35, 0xF0, 0xFE, 0x74, 0xF0, 0x2F, +0xF5, 0x82, 0x74, 0x01, 0x3E, 0xF5, 0x83, 0xE0, 0xFF, 0x90, 0x80, 0x5E, 0xE0, 0x75, 0xF0, 0x08, +0x90, 0x80, 0x11, 0x12, 0x42, 0x25, 0xE5, 0x82, 0x29, 0xF5, 0x82, 0xE4, 0x35, 0x83, 0xF5, 0x83, +0xEF, 0xF0, 0x90, 0x83, 0xF4, 0xE0, 0x04, 0xF0, 0x80, 0x83, 0x90, 0x83, 0xF3, 0xE0, 0xFF, 0x90, +0x83, 0xF1, 0xE0, 0xFE, 0x74, 0x01, 0xA8, 0x06, 0x08, 0x80, 0x02, 0xC3, 0x33, 0xD8, 0xFC, 0xF4, +0x5F, 0x90, 0x83, 0xF3, 0xF0, 0x90, 0x83, 0xF1, 0xE0, 0xFF, 0x74, 0x01, 0xA8, 0x07, 0x08, 0x80, +0x02, 0xC3, 0x33, 0xD8, 0xFC, 0x90, 0x01, 0xCC, 0xF0, 0x90, 0x83, 0xF1, 0xE0, 0x04, 0xF0, 0xE0, +0x54, 0x03, 0xF0, 0x90, 0x80, 0x5E, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4, 0x0A, 0x02, 0x7F, +0x01, 0xEF, 0x70, 0x02, 0xC1, 0x2B, 0xE4, 0x90, 0x80, 0x5E, 0xF0, 0xC1, 0x2B, 0x90, 0x01, 0xC0, +0xE0, 0x44, 0x02, 0xF0, 0x90, 0x83, 0xF1, 0xE0, 0x44, 0x80, 0x90, 0x00, 0x8A, 0xF0, 0x90, 0x83, +0xF1, 0xE0, 0x75, 0xF0, 0x04, 0x90, 0x01, 0xD0, 0x12, 0x42, 0x25, 0xE0, 0x90, 0x01, 0xC3, 0xF0, +0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x80, 0xF5, 0xE0, 0xFF, 0x70, 0x06, 0xA3, +0xE0, 0x64, 0x09, 0x60, 0x0A, 0xEF, 0x14, 0xFF, 0x90, 0x80, 0xF6, 0xE0, 0xB5, 0x07, 0x04, 0x7F, +0x01, 0x80, 0x02, 0x7F, 0x00, 0xEF, 0x60, 0x09, 0x90, 0x01, 0xC1, 0xE0, 0x44, 0x02, 0xF0, 0x80, +0x35, 0xC0, 0x01, 0x90, 0x80, 0xF6, 0xE0, 0x75, 0xF0, 0x0F, 0xA4, 0x24, 0x5F, 0xF9, 0x74, 0x80, +0x35, 0xF0, 0xA8, 0x01, 0xFC, 0x7D, 0x01, 0xD0, 0x01, 0x7E, 0x00, 0x7F, 0x0F, 0x12, 0x41, 0xD0, +0x90, 0x80, 0xF6, 0xE0, 0x04, 0xF0, 0xE0, 0x7F, 0x00, 0xB4, 0x0A, 0x02, 0x7F, 0x01, 0xEF, 0x60, +0x05, 0xE4, 0x90, 0x80, 0xF6, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x00, 0x54, 0xE0, 0x55, +0x35, 0xF5, 0x39, 0xA3, 0xE0, 0x55, 0x36, 0xF5, 0x3A, 0xA3, 0xE0, 0x55, 0x37, 0xF5, 0x3B, 0xA3, +0xE0, 0x55, 0x38, 0xF5, 0x3C, 0xAD, 0x39, 0x7F, 0x54, 0x12, 0x32, 0x1E, 0xAD, 0x3A, 0x7F, 0x55, +0x12, 0x32, 0x1E, 0xAD, 0x3B, 0x7F, 0x56, 0x12, 0x32, 0x1E, 0xAD, 0x3C, 0x7F, 0x57, 0x12, 0x32, +0x1E, 0x53, 0x91, 0xEF, 0x22, 0x90, 0x01, 0x34, 0xE0, 0x55, 0x3D, 0xF5, 0x41, 0xA3, 0xE0, 0x55, +0x3E, 0xF5, 0x42, 0xA3, 0xE0, 0x55, 0x3F, 0xF5, 0x43, 0xA3, 0xE0, 0x55, 0x40, 0xF5, 0x44, 0x90, +0x01, 0x34, 0xE5, 0x41, 0xF0, 0xA3, 0xE5, 0x42, 0xF0, 0xA3, 0xE5, 0x43, 0xF0, 0xA3, 0xE5, 0x44, +0xF0, 0x22, 0x90, 0x01, 0x3C, 0xE0, 0x55, 0x45, 0xF5, 0x49, 0xA3, 0xE0, 0x55, 0x46, 0xF5, 0x4A, +0xA3, 0xE0, 0x55, 0x47, 0xF5, 0x4B, 0xA3, 0xE0, 0x55, 0x48, 0xF5, 0x4C, 0x90, 0x01, 0x3C, 0xE5, +0x49, 0xF0, 0xA3, 0xE5, 0x4A, 0xF0, 0xA3, 0xE5, 0x4B, 0xF0, 0xA3, 0xE5, 0x4C, 0xF0, 0x53, 0x91, +0xDF, 0x22, 0x90, 0x81, 0x3E, 0xE0, 0x60, 0x45, 0x90, 0x81, 0x3B, 0xE0, 0xFF, 0x13, 0x13, 0x13, +0x54, 0x1F, 0x30, 0xE0, 0x12, 0x90, 0x01, 0x3B, 0xE0, 0x30, 0xE4, 0x0B, 0x11, 0xC7, 0x90, 0x81, +0x44, 0xE0, 0x14, 0x90, 0x05, 0x73, 0xF0, 0x90, 0x83, 0xF5, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x41, +0xF6, 0xC3, 0x90, 0x83, 0xF6, 0xE0, 0x94, 0x80, 0x90, 0x83, 0xF5, 0xE0, 0x64, 0x80, 0x94, 0x80, +0x40, 0x0B, 0x90, 0x01, 0x98, 0xE0, 0x54, 0xFE, 0xF0, 0xE0, 0x44, 0x01, 0xF0, 0xF1, 0x54, 0x31, +0xDC, 0xE4, 0x90, 0x83, 0x43, 0xF0, 0x22, 0x7D, 0x02, 0x7F, 0x02, 0x11, 0xD1, 0x7D, 0x01, 0x7F, +0x02, 0x74, 0x3D, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE, 0xF6, 0x74, 0x30, 0x2F, 0xF5, +0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0x90, 0x83, 0x4A, 0xE0, 0x04, 0xF0, 0x90, +0x81, 0x41, 0xE0, 0x64, 0x02, 0x60, 0x28, 0x31, 0x20, 0x90, 0x81, 0x3B, 0xE0, 0x13, 0x13, 0x13, +0x54, 0x1F, 0x30, 0xE0, 0x14, 0x90, 0x81, 0x44, 0xE0, 0xFF, 0xA3, 0xE0, 0x6F, 0x70, 0x0A, 0x31, +0xB8, 0x11, 0xC7, 0x90, 0x81, 0x45, 0xE0, 0x14, 0xF0, 0x90, 0x01, 0xE6, 0xE0, 0x04, 0xF0, 0x22, +0x90, 0x80, 0xF9, 0xE0, 0x64, 0x01, 0x60, 0x02, 0x21, 0xB7, 0x90, 0x81, 0x3E, 0xE0, 0x70, 0x02, +0x21, 0xB7, 0x90, 0x81, 0x3C, 0xE0, 0xC4, 0x54, 0x0F, 0x64, 0x01, 0x70, 0x26, 0x90, 0x06, 0xAB, +0xE0, 0x90, 0x81, 0x45, 0xF0, 0x90, 0x06, 0xAA, 0xE0, 0x04, 0x90, 0x81, 0x44, 0xF0, 0xA3, 0xE0, +0xFF, 0x70, 0x08, 0x90, 0x81, 0x44, 0xE0, 0xFE, 0xFF, 0x80, 0x03, 0xEF, 0x04, 0xFF, 0x90, 0x81, +0x45, 0xEF, 0xF0, 0x90, 0x81, 0x3B, 0xE0, 0x44, 0x04, 0xF0, 0xE4, 0x90, 0x81, 0x47, 0xF0, 0x90, +0x81, 0x49, 0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, +0x74, 0x02, 0xF0, 0x90, 0x81, 0x42, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0xEF, 0xF0, 0x90, 0x81, 0x3C, +0xE0, 0xFF, 0xC4, 0x54, 0x0F, 0x24, 0xFD, 0x50, 0x02, 0x80, 0x02, 0x51, 0x40, 0x90, 0x81, 0x3B, +0xE0, 0x13, 0x13, 0x13, 0x54, 0x1F, 0x30, 0xE0, 0x0E, 0x90, 0x81, 0x44, 0xE0, 0xFF, 0xA3, 0xE0, +0xB5, 0x07, 0x04, 0x31, 0xB8, 0x11, 0xCD, 0x22, 0xEF, 0x14, 0x90, 0x05, 0x73, 0xF0, 0x90, 0x01, +0x3F, 0x74, 0x10, 0xF0, 0xFD, 0x7F, 0x03, 0x74, 0x45, 0x2F, 0xF8, 0xE6, 0x4D, 0xFE, 0xF6, 0x74, +0x38, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0x90, 0x83, 0x40, 0xE0, +0x30, 0xE0, 0x37, 0x90, 0x80, 0xF9, 0xE0, 0x64, 0x01, 0x70, 0x2F, 0x90, 0x84, 0x04, 0xE0, 0x04, +0xF0, 0xE0, 0xB4, 0x0A, 0x0B, 0x90, 0x83, 0x42, 0xE0, 0x04, 0xF0, 0xE4, 0x90, 0x84, 0x04, 0xF0, +0x90, 0x83, 0x42, 0xE0, 0xFF, 0x90, 0x83, 0x41, 0xE0, 0xD3, 0x9F, 0x50, 0x0D, 0x90, 0x83, 0x43, +0xE0, 0x70, 0x07, 0xE4, 0x90, 0x83, 0x42, 0xF0, 0x51, 0x1B, 0x22, 0x90, 0x83, 0x40, 0xE0, 0xFF, +0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x16, 0x7B, 0x00, 0x7A, 0x00, 0x79, 0x00, 0x90, 0x83, 0x8B, +0x12, 0x42, 0x3A, 0xE4, 0x90, 0x83, 0x8E, 0xF0, 0xA3, 0x04, 0xF0, 0x61, 0x5A, 0x02, 0x4C, 0x25, +0xE4, 0xF5, 0x19, 0x90, 0x06, 0xA9, 0xE0, 0xF5, 0x19, 0x54, 0xC0, 0x70, 0x0D, 0x90, 0x81, 0x42, +0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x02, 0x51, 0xBF, 0xE5, 0x19, 0x30, 0xE6, 0x22, 0x90, +0x81, 0x3E, 0xE0, 0x64, 0x01, 0x70, 0x21, 0x90, 0x81, 0x42, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x81, +0x3C, 0xE0, 0x54, 0x0F, 0x64, 0x02, 0x60, 0x04, 0x51, 0xA3, 0x80, 0x0C, 0x12, 0x4C, 0xE4, 0x80, +0x07, 0x90, 0x81, 0x42, 0xE0, 0x54, 0xFE, 0xF0, 0xE5, 0x19, 0x90, 0x81, 0x42, 0x30, 0xE7, 0x0E, +0xE0, 0x44, 0x02, 0x12, 0x57, 0xE5, 0x90, 0x81, 0x3A, 0xE0, 0x44, 0x04, 0xF0, 0x22, 0xE0, 0x54, +0xFD, 0xF0, 0x22, 0x90, 0x04, 0x1D, 0xE0, 0x70, 0x19, 0x90, 0x80, 0x08, 0xE0, 0xFF, 0x7B, 0x18, +0xE4, 0xFD, 0x51, 0xC3, 0x90, 0x83, 0x52, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x04, 0x1F, 0x74, +0x20, 0xF0, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x83, 0xDF, 0xED, 0xF0, 0xA3, +0xEB, 0xF0, 0x90, 0x83, 0xDE, 0xEF, 0xF0, 0xE4, 0xFD, 0xFC, 0x12, 0x5F, 0x5D, 0x7C, 0x00, 0xAD, +0x07, 0x90, 0x83, 0xDE, 0xE0, 0x90, 0x04, 0x25, 0xF0, 0x90, 0x83, 0xDF, 0xE0, 0x60, 0x0E, 0x74, +0x0F, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, 0xAF, 0x05, 0x74, +0x08, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE4, 0xF0, 0x74, 0x09, 0x2F, 0xF5, 0x82, +0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xF0, 0xF0, 0xAF, 0x05, 0x74, 0x16, 0x2F, 0xF5, 0x82, +0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0x01, 0xFE, 0x90, 0x83, 0xE0, 0xE0, 0x25, 0xE0, 0x25, +0xE0, 0xFB, 0xEE, 0x44, 0x02, 0x4B, 0xFE, 0x74, 0x16, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, +0x83, 0xEE, 0xF0, 0x74, 0x21, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xF7, +0xF0, 0xAE, 0x04, 0xAF, 0x05, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, +0xD0, 0x90, 0x83, 0x88, 0x12, 0x42, 0x3A, 0x78, 0x94, 0x7C, 0x83, 0x7D, 0x01, 0x7B, 0xFF, 0x7A, +0x40, 0x79, 0xCE, 0x7E, 0x00, 0x7F, 0x06, 0x12, 0x41, 0xD0, 0x90, 0x05, 0x22, 0xE0, 0x90, 0x83, +0x93, 0xF0, 0x90, 0x04, 0x1D, 0xE0, 0x60, 0x0A, 0x7D, 0x33, 0x12, 0x4D, 0x6E, 0xBF, 0x01, 0x15, +0x80, 0x00, 0x90, 0x83, 0x31, 0xE0, 0xFF, 0x7B, 0x18, 0x7D, 0x01, 0x51, 0xC3, 0x90, 0x83, 0x90, +0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x83, 0x90, 0x12, 0x57, 0x20, 0x90, 0x83, 0x92, 0xEF, 0xF0, +0x90, 0x83, 0x90, 0xA3, 0xE0, 0x24, 0x20, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, 0x90, 0x83, +0x8E, 0xE0, 0xFD, 0x91, 0xDE, 0x90, 0x83, 0x8F, 0xE0, 0x60, 0x02, 0x81, 0x54, 0xA3, 0xA3, 0xE0, +0x24, 0x30, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, +0x83, 0x8B, 0x12, 0x42, 0x31, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x75, 0x16, 0x06, 0xD0, 0x01, +0xD0, 0x02, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x90, 0x83, 0x90, 0xA3, 0xE0, 0xFF, 0xA3, 0xE0, 0x2F, +0x24, 0x3A, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, +0x83, 0x8B, 0x12, 0x42, 0x31, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x75, 0x16, 0x06, 0xD0, 0x01, +0xD0, 0x02, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x90, 0x83, 0x90, 0xA3, 0xE0, 0xFF, 0xA3, 0xE0, 0x2F, +0x24, 0x40, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0xC0, 0x02, 0xC0, 0x01, 0x90, +0x83, 0x88, 0x12, 0x42, 0x31, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x75, 0x16, 0x04, 0xD0, 0x01, +0xD0, 0x02, 0x80, 0x69, 0x90, 0x83, 0x8F, 0xE0, 0x64, 0x01, 0x70, 0x66, 0xA3, 0xA3, 0xE0, 0x24, +0x30, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0x8B, 0x13, 0x75, 0x14, 0x81, 0x75, +0x15, 0x9C, 0x75, 0x16, 0x06, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x90, 0x83, 0x90, 0xA3, 0xE0, 0xFF, +0xA3, 0xE0, 0x2F, 0x24, 0x3A, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, 0xC0, 0x03, 0x8B, 0x13, +0x75, 0x14, 0x81, 0x75, 0x15, 0xA6, 0x75, 0x16, 0x06, 0xD0, 0x03, 0x12, 0x2B, 0xED, 0x90, 0x83, +0x90, 0xA3, 0xE0, 0xFF, 0xA3, 0xE0, 0x2F, 0x24, 0x40, 0xF9, 0xE4, 0x34, 0xFC, 0xFA, 0x7B, 0x01, +0xC0, 0x03, 0x8B, 0x13, 0x75, 0x14, 0x81, 0x75, 0x15, 0xAC, 0x75, 0x16, 0x04, 0xD0, 0x03, 0x12, +0x2B, 0xED, 0x90, 0x06, 0x30, 0xE0, 0x44, 0x10, 0xF0, 0x90, 0x83, 0x93, 0xE0, 0xFF, 0x7D, 0x34, +0x12, 0x4A, 0xED, 0x90, 0x04, 0x1F, 0x74, 0x20, 0xF0, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x83, +0xD2, 0xED, 0xF0, 0x90, 0x83, 0xCF, 0x12, 0x42, 0x3A, 0xE4, 0x90, 0x83, 0xD3, 0xF0, 0xA3, 0xF0, +0x12, 0x1F, 0xA4, 0xFF, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFD, 0x90, 0x00, 0x04, 0x12, 0x1F, +0xBD, 0xFB, 0x12, 0x57, 0x46, 0x90, 0x83, 0xD3, 0xEF, 0xF0, 0x90, 0x83, 0xCF, 0x12, 0x42, 0x31, +0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0xD1, 0x9B, 0x90, 0x83, 0xD4, 0xEF, 0xF0, 0x90, 0x82, +0x51, 0xE0, 0x24, 0xFE, 0x60, 0x1D, 0x24, 0xFE, 0x60, 0x19, 0x14, 0x60, 0x07, 0x14, 0x60, 0x04, +0x24, 0x05, 0x70, 0x53, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x48, 0x90, 0x83, 0xD2, 0xE0, 0xFD, 0xD1, +0xDA, 0x80, 0x16, 0x7B, 0x01, 0x7A, 0x82, 0x79, 0x48, 0x90, 0x83, 0xD2, 0xE0, 0xFD, 0x90, 0x82, +0x51, 0xE0, 0x90, 0x83, 0xAD, 0xF0, 0x12, 0x7C, 0x03, 0x90, 0x83, 0xD4, 0xE0, 0xFF, 0x90, 0x83, +0xCF, 0x12, 0x42, 0x31, 0x90, 0x83, 0xD3, 0xE0, 0x7C, 0x00, 0x29, 0xF9, 0xEC, 0x3A, 0xFA, 0xC3, +0xE9, 0x9F, 0xF9, 0xEA, 0x94, 0x00, 0xFA, 0x75, 0x13, 0x01, 0x75, 0x14, 0x82, 0x75, 0x15, 0x48, +0xA3, 0xE0, 0xF5, 0x16, 0x12, 0x2B, 0xED, 0x22, 0x90, 0x80, 0x09, 0xE0, 0xFF, 0x90, 0x83, 0xD6, +0xE0, 0xFB, 0x7D, 0x01, 0x51, 0xC3, 0x90, 0x83, 0xD7, 0xEE, 0xF0, 0xFC, 0xA3, 0xEF, 0xF0, 0xFD, +0x90, 0x83, 0xD5, 0xE0, 0xFF, 0xD1, 0x33, 0x90, 0x83, 0xD7, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x90, +0x04, 0x80, 0xE0, 0x54, 0x0F, 0xFD, 0xAC, 0x07, 0x74, 0x11, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, +0xF5, 0x83, 0xE0, 0x44, 0x01, 0xF0, 0x74, 0x11, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, +0xE0, 0x54, 0xFB, 0xF0, 0xAC, 0x07, 0x74, 0x16, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, +0xE0, 0x44, 0xFA, 0xF0, 0x74, 0x15, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, +0x1F, 0xF0, 0xAC, 0x07, 0x74, 0x06, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, +0x0F, 0xF0, 0x90, 0x04, 0x53, 0xE4, 0xF0, 0x90, 0x04, 0x52, 0xF0, 0x90, 0x04, 0x51, 0x74, 0xFF, +0xF0, 0x90, 0x04, 0x50, 0x74, 0xFD, 0xF0, 0x74, 0x14, 0x2C, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, +0x83, 0xE0, 0x54, 0xC0, 0x4D, 0xFD, 0x74, 0x14, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, +0xED, 0xF0, 0x22, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0x3F, +0xF0, 0xEF, 0x60, 0x1D, 0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, +0x10, 0xF0, 0x74, 0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x80, 0xF0, +0x22, 0x74, 0x21, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x54, 0xEF, 0xF0, 0x74, +0x1F, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFC, 0xF5, 0x83, 0xE0, 0x44, 0x40, 0xF0, 0x22, 0x90, 0x80, +0xF9, 0xE0, 0xB4, 0x01, 0x15, 0x90, 0x81, 0x3E, 0xE0, 0x60, 0x0F, 0x90, 0x81, 0x3C, 0xE0, 0x54, +0x0F, 0x64, 0x02, 0x60, 0x02, 0x41, 0xA3, 0x12, 0x4C, 0xE4, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, +0xC0, 0xD0, 0xEF, 0x20, 0xE0, 0x05, 0x90, 0x83, 0x2E, 0x80, 0x03, 0x90, 0x83, 0x2F, 0xE0, 0x90, +0x82, 0x51, 0xF0, 0x90, 0x82, 0x51, 0xE0, 0x14, 0x60, 0x13, 0x14, 0x60, 0x14, 0x24, 0xFE, 0x60, +0x10, 0x14, 0x60, 0x09, 0x14, 0x60, 0x06, 0x24, 0x06, 0xE4, 0xFE, 0x80, 0x06, 0x7E, 0x04, 0x80, +0x02, 0x7E, 0x08, 0xAF, 0x06, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0x90, 0x83, 0xC4, 0xED, 0xF0, 0x90, +0x83, 0xC1, 0x12, 0x42, 0x3A, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0x90, 0x83, 0xC8, 0xF0, 0x90, +0x83, 0xC1, 0x12, 0x42, 0x31, 0x8B, 0x13, 0x8A, 0x14, 0x89, 0x15, 0x75, 0x16, 0x03, 0x7B, 0x01, +0x7A, 0x83, 0x79, 0xC5, 0x12, 0x2B, 0xED, 0x90, 0x83, 0xC4, 0xE0, 0x70, 0x46, 0xFF, 0x74, 0xC5, +0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x83, 0xF5, 0x83, 0xE0, 0xB4, 0xFF, 0x0E, 0x74, 0xC5, 0x2F, 0xF5, +0x82, 0xE4, 0x34, 0x83, 0xF5, 0x83, 0xE4, 0xF0, 0x80, 0x0F, 0x74, 0xC5, 0x2F, 0xF5, 0x82, 0xE4, +0x34, 0x83, 0xF5, 0x83, 0xE0, 0x04, 0xF0, 0x80, 0x05, 0x0F, 0xEF, 0xB4, 0x03, 0xD0, 0x75, 0x13, +0x01, 0x75, 0x14, 0x83, 0x75, 0x15, 0xC5, 0x75, 0x16, 0x03, 0x90, 0x83, 0xC1, 0x12, 0x42, 0x31, +0x12, 0x2B, 0xED, 0x22, 0x90, 0x83, 0x44, 0xE0, 0x30, 0xE0, 0x72, 0x90, 0x83, 0x48, 0xE0, 0x04, +0xF0, 0x90, 0x83, 0x4B, 0xE0, 0x64, 0x01, 0x70, 0x27, 0x90, 0x83, 0x44, 0xE0, 0x13, 0x13, 0x54, +0x3F, 0x30, 0xE0, 0x1C, 0x90, 0x83, 0x4A, 0xE0, 0x70, 0x16, 0x90, 0x83, 0x47, 0xE0, 0xFF, 0xA3, +0xE0, 0xC3, 0x9F, 0x40, 0x0B, 0x12, 0x51, 0xC9, 0x90, 0x83, 0x44, 0xE0, 0x54, 0xFE, 0xF0, 0x22, +0x90, 0x83, 0x48, 0xE0, 0xFF, 0x90, 0x83, 0x45, 0xE0, 0xD3, 0x9F, 0x50, 0x30, 0x90, 0x06, 0x92, +0xE0, 0x20, 0xE2, 0x1A, 0x90, 0x83, 0x4A, 0xE0, 0x70, 0x14, 0x7D, 0x08, 0xFF, 0x12, 0x4C, 0x29, +0x90, 0x83, 0x49, 0xE0, 0x04, 0xF0, 0x90, 0x83, 0x43, 0xE0, 0x04, 0xF0, 0x80, 0x06, 0x90, 0x06, +0x92, 0x74, 0x04, 0xF0, 0xE4, 0x90, 0x83, 0x48, 0xF0, 0x90, 0x83, 0x4A, 0xF0, 0x22, 0x90, 0x80, +0xF9, 0xE0, 0x64, 0x01, 0x70, 0x13, 0x90, 0x81, 0x3E, 0xE0, 0x60, 0x0D, 0x90, 0x01, 0x57, 0xE4, +0xF0, 0x90, 0x01, 0x3C, 0x74, 0x02, 0x12, 0x57, 0xE5, 0x22, 0x90, 0x80, 0xF9, 0xE0, 0x64, 0x01, +0x70, 0x26, 0x90, 0x81, 0x3E, 0xE0, 0x60, 0x20, 0x90, 0x01, 0x57, 0xE4, 0xF0, 0x90, 0x01, 0x3C, +0x74, 0x02, 0xF0, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0xFB, 0xF0, 0x90, 0x81, 0x42, 0xE0, 0x54, 0xFD, +0xF0, 0x54, 0x07, 0x70, 0x03, 0x12, 0x51, 0xBF, 0x22, 0x90, 0x80, 0xF9, 0xE0, 0xB4, 0x01, 0x14, +0x90, 0x81, 0x3E, 0xE0, 0x60, 0x0E, 0x90, 0x81, 0x42, 0xE0, 0x54, 0xFE, 0xF0, 0x54, 0x07, 0x70, +0x03, 0x12, 0x51, 0xBF, 0x22, 0x11, 0xA8, 0x90, 0x83, 0x54, 0xEF, 0xF0, 0x30, 0xE0, 0x05, 0x7D, +0x01, 0xE4, 0x80, 0x02, 0xE4, 0xFD, 0xFF, 0x12, 0x4B, 0x33, 0x90, 0x83, 0x54, 0xE0, 0x30, 0xE6, +0x11, 0x90, 0x01, 0x2F, 0xE0, 0x30, 0xE7, 0x04, 0xE4, 0xF0, 0x80, 0x06, 0x90, 0x01, 0x2F, 0x74, +0x80, 0xF0, 0x90, 0x81, 0x3A, 0xE0, 0x30, 0xE0, 0x25, 0x90, 0x81, 0x75, 0xE0, 0x24, 0x07, 0xFF, +0x90, 0x81, 0x50, 0xE0, 0xFE, 0xC3, 0xEF, 0x9E, 0xFF, 0x90, 0x81, 0x53, 0xF0, 0x90, 0x81, 0x49, +0xE4, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x04, 0xEC, 0xE0, 0x54, 0xDD, 0xF0, 0x80, 0x10, 0x90, 0x81, +0x49, 0xE4, 0xF0, 0xA3, 0x74, 0x02, 0xF0, 0x90, 0x04, 0xEC, 0xE0, 0x44, 0x22, 0xF0, 0x90, 0x81, +0x49, 0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x22, 0xE4, 0x90, 0x83, 0x55, 0xF0, 0xA3, 0xF0, 0xA3, +0xF0, 0x90, 0x00, 0x83, 0xE0, 0x90, 0x83, 0x55, 0xF0, 0x90, 0x00, 0x83, 0xE0, 0xFE, 0x90, 0x83, +0x55, 0xE0, 0xFF, 0xB5, 0x06, 0x01, 0x22, 0xC3, 0x90, 0x83, 0x57, 0xE0, 0x94, 0x64, 0x90, 0x83, +0x56, 0xE0, 0x94, 0x00, 0x40, 0x0D, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0x83, 0x55, +0xE0, 0xFF, 0x22, 0x90, 0x83, 0x56, 0xE4, 0x75, 0xF0, 0x01, 0x12, 0x41, 0xF6, 0x80, 0xC2, 0xD3, +0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x04, 0x1D, 0xE0, 0x60, 0x1A, 0x90, 0x05, 0x22, 0xE0, +0x54, 0x90, 0x60, 0x07, 0x90, 0x01, 0xC0, 0xE0, 0x44, 0x08, 0xF0, 0x90, 0x01, 0xC6, 0xE0, 0x30, +0xE1, 0xE4, 0x7F, 0x00, 0x80, 0x02, 0x7F, 0x01, 0xD0, 0xD0, 0x92, 0xAF, 0x22, 0xC3, 0xEE, 0x94, +0x01, 0x40, 0x0A, 0x0D, 0xED, 0x13, 0x90, 0xFD, 0x10, 0xF0, 0xE4, 0x2F, 0xFF, 0x22, 0xC3, 0xEE, +0x94, 0x01, 0x40, 0x1E, 0x90, 0xFD, 0x11, 0xE0, 0xB5, 0x05, 0x14, 0x90, 0x01, 0x17, 0xE0, 0xB5, +0x05, 0x07, 0x90, 0xFD, 0x11, 0xE4, 0xF0, 0x80, 0x06, 0xED, 0x04, 0x90, 0xFD, 0x11, 0xF0, 0xE4, +0x2F, 0xFF, 0x22, 0x74, 0x45, 0x2F, 0xF8, 0xE6, 0xFE, 0xED, 0xF4, 0x5E, 0xFE, 0xF6, 0x74, 0x38, +0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x22, 0xE4, 0x90, 0x81, 0x3E, 0xF0, +0xA3, 0xF0, 0x90, 0x81, 0x3C, 0xE0, 0x54, 0x0F, 0xF0, 0xA3, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x3C, +0xE0, 0x54, 0xF0, 0xF0, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0xFD, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xF7, +0xF0, 0x90, 0x81, 0x44, 0x74, 0x01, 0xF0, 0xA3, 0xF0, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0xFB, 0xF0, +0xA3, 0xE0, 0x54, 0xFB, 0xF0, 0xE4, 0x90, 0x81, 0x47, 0xF0, 0x90, 0x81, 0x46, 0x74, 0x08, 0xF0, +0x90, 0x81, 0x49, 0xE4, 0xF0, 0xA3, 0x74, 0x02, 0xF0, 0xE4, 0x90, 0x81, 0x42, 0xF0, 0x90, 0x81, +0x3A, 0xE0, 0x54, 0xDF, 0xF0, 0xE4, 0xFD, 0xFF, 0x12, 0x4B, 0x33, 0x7D, 0x0C, 0x7F, 0x02, 0x12, +0x4B, 0x33, 0x12, 0x4B, 0x2F, 0x90, 0x81, 0x3A, 0xE0, 0x54, 0xBF, 0xF0, 0x54, 0x7F, 0xF0, 0xA3, +0xE0, 0x54, 0xFE, 0xF0, 0x54, 0xFD, 0xF0, 0x54, 0xF7, 0xF0, 0x90, 0x81, 0x4B, 0x12, 0x20, 0xDA, +0x54, 0x33, 0x77, 0x70, 0xE4, 0x90, 0x81, 0x75, 0xF0, 0x90, 0x81, 0x4F, 0xF0, 0x90, 0x80, 0x06, +0xE0, 0xB4, 0x01, 0x08, 0x90, 0x81, 0x48, 0x74, 0x99, 0xF0, 0x80, 0x12, 0x90, 0x80, 0x06, 0xE0, +0x90, 0x81, 0x48, 0xB4, 0x03, 0x05, 0x74, 0x90, 0xF0, 0x80, 0x03, 0x74, 0x40, 0xF0, 0x90, 0x81, +0x76, 0x74, 0x05, 0xF0, 0xA3, 0xF0, 0xA3, 0xE0, 0x54, 0x01, 0x44, 0x28, 0xF0, 0xA3, 0x74, 0x05, +0xF0, 0xE4, 0x90, 0x81, 0x50, 0xF0, 0x90, 0x81, 0x75, 0xE0, 0x24, 0x07, 0x90, 0x81, 0x53, 0xF0, +0xA3, 0x74, 0x08, 0xF0, 0xE4, 0xA3, 0xF0, 0x90, 0x81, 0x7A, 0xF0, 0xA3, 0xE0, 0x54, 0xFE, 0xF0, +0x54, 0xFD, 0xF0, 0x54, 0xFB, 0xF0, 0x54, 0xF7, 0xF0, 0x54, 0xEF, 0xF0, 0x54, 0xDF, 0xF0, 0x54, +0xBF, 0xF0, 0x90, 0x06, 0x04, 0xE0, 0x54, 0x7F, 0xF0, 0x90, 0x06, 0x0A, 0xE0, 0x54, 0xF8, 0xF0, +0xE4, 0xFD, 0xFF, 0x12, 0x4A, 0xED, 0xE4, 0x90, 0x81, 0x7C, 0xF0, 0x22, 0x90, 0x04, 0x1A, 0xE0, +0xF4, 0x60, 0x03, 0x7F, 0x00, 0x22, 0x90, 0x04, 0x1B, 0xE0, 0x54, 0x07, 0x64, 0x07, 0x7F, 0x01, +0x60, 0x02, 0x7F, 0x00, 0x22, 0x51, 0x7C, 0xEF, 0x64, 0x01, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, +0x01, 0xF0, 0x80, 0x67, 0x90, 0x81, 0x42, 0xE0, 0xFF, 0x54, 0x03, 0x60, 0x08, 0x90, 0x01, 0xB8, +0x74, 0x02, 0xF0, 0x80, 0x56, 0x90, 0x81, 0x40, 0xE0, 0xFE, 0xE4, 0xC3, 0x9E, 0x50, 0x08, 0x90, +0x01, 0xB8, 0x74, 0x04, 0xF0, 0x80, 0x44, 0xEF, 0x30, 0xE2, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x08, +0xF0, 0x80, 0x38, 0x90, 0x81, 0x42, 0xE0, 0x30, 0xE4, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x10, 0xF0, +0x80, 0x29, 0x90, 0x81, 0x3B, 0xE0, 0x13, 0x13, 0x54, 0x3F, 0x20, 0xE0, 0x08, 0x90, 0x01, 0xB8, +0x74, 0x20, 0xF0, 0x80, 0x16, 0x90, 0x81, 0x7C, 0xE0, 0x60, 0x08, 0x90, 0x01, 0xB8, 0x74, 0x80, +0xF0, 0x80, 0x08, 0x90, 0x01, 0xB8, 0xE4, 0xF0, 0x7F, 0x01, 0x22, 0x90, 0x01, 0xB9, 0x74, 0x04, +0xF0, 0x7F, 0x00, 0x22, 0xEF, 0x24, 0xFE, 0x60, 0x0B, 0x04, 0x70, 0x27, 0x90, 0x81, 0x44, 0x74, +0x02, 0xF0, 0x80, 0x16, 0xED, 0x70, 0x0A, 0x90, 0x81, 0x79, 0xE0, 0x90, 0x81, 0x44, 0xF0, 0x80, +0x05, 0x90, 0x81, 0x44, 0xED, 0xF0, 0x90, 0x81, 0x44, 0xE0, 0xA3, 0xF0, 0x90, 0x81, 0x3B, 0xE0, +0x44, 0x08, 0xF0, 0x22, 0xAC, 0x07, 0x90, 0x81, 0x3A, 0xE0, 0x30, 0xE0, 0x32, 0x90, 0x81, 0x50, +0xE0, 0xD3, 0x94, 0x03, 0x50, 0x07, 0x90, 0x81, 0x46, 0xEB, 0xF0, 0x80, 0x0A, 0xED, 0x24, 0xFD, +0x2B, 0x90, 0x81, 0x46, 0xF0, 0x7D, 0x03, 0x90, 0x81, 0x75, 0xE0, 0x24, 0x07, 0xC3, 0x9D, 0x2C, +0xFF, 0x90, 0x81, 0x53, 0xF0, 0x90, 0x81, 0x49, 0xE4, 0xF0, 0xA3, 0xEF, 0xF0, 0x80, 0x0E, 0x90, +0x81, 0x49, 0xE4, 0xF0, 0xA3, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x46, 0xEB, 0xF0, 0x90, 0x81, 0x49, +0xA3, 0xE0, 0x90, 0x05, 0x58, 0xF0, 0x22, 0xFD, 0x90, 0x83, 0x6F, 0xE0, 0x34, 0x00, 0xFC, 0x7E, +0x00, 0xED, 0x2F, 0xFF, 0xEE, 0x3C, 0xFE, 0xE4, 0xFD, 0xAB, 0x07, 0xAA, 0x06, 0xED, 0x2B, 0xFB, +0xE4, 0x3A, 0xFA, 0xC3, 0x90, 0x80, 0xF8, 0xE0, 0x9B, 0x90, 0x80, 0xF7, 0xE0, 0x9A, 0x50, 0x13, +0xA3, 0xE0, 0x24, 0x01, 0xFF, 0x90, 0x80, 0xF7, 0xE0, 0x34, 0x00, 0xFE, 0xC3, 0xEB, 0x9F, 0xFB, +0xEA, 0x9E, 0xFA, 0xEA, 0x90, 0xFD, 0x11, 0xF0, 0xAF, 0x03, 0x74, 0x00, 0x2F, 0xF5, 0x82, 0xE4, +0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFF, 0x22, 0x90, 0x83, 0x6F, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xA3, +0xED, 0xF0, 0x78, 0x78, 0x7C, 0x83, 0x7D, 0x01, 0x7B, 0xFF, 0x7A, 0x40, 0x79, 0xC0, 0x7E, 0x00, +0x7F, 0x06, 0x12, 0x41, 0xD0, 0x78, 0x7E, 0x7C, 0x83, 0x7D, 0x01, 0x7B, 0xFF, 0x7A, 0x40, 0x79, +0xC6, 0x7E, 0x00, 0x7F, 0x04, 0x12, 0x41, 0xD0, 0x78, 0x82, 0x7C, 0x83, 0x7D, 0x01, 0x7B, 0xFF, +0x7A, 0x40, 0x79, 0xCA, 0x7E, 0x00, 0x7F, 0x04, 0x12, 0x41, 0xD0, 0xE4, 0x90, 0x83, 0x87, 0xF0, +0x90, 0x83, 0x71, 0xE0, 0xFF, 0x90, 0x83, 0x70, 0xE0, 0x2F, 0xFF, 0x90, 0x83, 0x6F, 0xE0, 0x34, +0x00, 0xCF, 0x24, 0x06, 0xCF, 0x34, 0x00, 0xFE, 0xE4, 0xFD, 0x71, 0xA9, 0xEF, 0x64, 0x08, 0x60, +0x02, 0xA1, 0xD3, 0x90, 0x83, 0x71, 0xE0, 0xFF, 0x90, 0x83, 0x70, 0xE0, 0x2F, 0xFF, 0x90, 0x83, +0x6F, 0xE0, 0x34, 0x00, 0xCF, 0x24, 0x07, 0xCF, 0x34, 0x00, 0xFE, 0xE4, 0xFD, 0x71, 0xA9, 0xEF, +0x64, 0x06, 0x60, 0x02, 0xA1, 0xD3, 0x90, 0x83, 0x87, 0x04, 0xF0, 0xE4, 0x90, 0x83, 0x86, 0xF0, +0x90, 0x83, 0x86, 0xE0, 0xFF, 0xC3, 0x94, 0x06, 0x50, 0x1F, 0x90, 0x83, 0x70, 0xE0, 0x24, 0x0A, +0x71, 0x97, 0x90, 0x83, 0x86, 0xE0, 0x24, 0x72, 0xF5, 0x82, 0xE4, 0x34, 0x83, 0xF5, 0x83, 0xEF, +0xF0, 0x90, 0x83, 0x86, 0xE0, 0x04, 0xF0, 0x80, 0xD7, 0x78, 0x72, 0x7C, 0x83, 0x7D, 0x01, 0x7B, +0x01, 0x7A, 0x81, 0x79, 0x8C, 0x7E, 0x00, 0x7F, 0x06, 0x12, 0x43, 0xEF, 0xEF, 0x60, 0x02, 0xA1, +0xD3, 0x90, 0x83, 0x86, 0xF0, 0x90, 0x83, 0x86, 0xE0, 0xFF, 0xC3, 0x94, 0x04, 0x50, 0x2E, 0x90, +0x83, 0x71, 0xE0, 0xFD, 0x90, 0x83, 0x70, 0xE0, 0x2D, 0xFD, 0x90, 0x83, 0x6F, 0xE0, 0x34, 0x00, +0xCD, 0x24, 0x20, 0xCD, 0x71, 0x9C, 0x90, 0x83, 0x86, 0xE0, 0x24, 0x82, 0xF5, 0x82, 0xE4, 0x34, +0x83, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x83, 0x86, 0xE0, 0x04, 0xF0, 0x80, 0xC8, 0x78, 0x82, 0x7C, +0x83, 0x7D, 0x01, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0xA2, 0x7E, 0x00, 0x7F, 0x04, 0x12, 0x43, 0xEF, +0xEF, 0x60, 0x02, 0xA1, 0xCA, 0x90, 0x06, 0x30, 0xE0, 0x44, 0x01, 0x54, 0xDF, 0xF0, 0x90, 0x81, +0x7F, 0xE0, 0x30, 0xE0, 0x0F, 0x90, 0x01, 0xC7, 0x74, 0x09, 0xF0, 0x90, 0x81, 0x85, 0xE0, 0x44, +0x01, 0xF0, 0xA1, 0xD3, 0xE4, 0x90, 0x83, 0x86, 0xF0, 0x90, 0x83, 0x86, 0xE0, 0xFF, 0xC3, 0x94, +0x06, 0x50, 0x2E, 0x90, 0x83, 0x71, 0xE0, 0xFD, 0x90, 0x83, 0x70, 0xE0, 0x2D, 0xFD, 0x90, 0x83, +0x6F, 0xE0, 0x34, 0x00, 0xCD, 0x24, 0x10, 0xCD, 0x71, 0x9C, 0x90, 0x83, 0x86, 0xE0, 0x24, 0x78, +0xF5, 0x82, 0xE4, 0x34, 0x83, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x83, 0x86, 0xE0, 0x04, 0xF0, 0x80, +0xC8, 0xE4, 0x90, 0x83, 0x86, 0xF0, 0x90, 0x83, 0x86, 0xE0, 0xFF, 0xC3, 0x94, 0x04, 0x50, 0x2E, +0x90, 0x83, 0x71, 0xE0, 0xFD, 0x90, 0x83, 0x70, 0xE0, 0x2D, 0xFD, 0x90, 0x83, 0x6F, 0xE0, 0x34, +0x00, 0xCD, 0x24, 0x16, 0xCD, 0x71, 0x9C, 0x90, 0x83, 0x86, 0xE0, 0x24, 0x7E, 0xF5, 0x82, 0xE4, +0x34, 0x83, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x83, 0x86, 0xE0, 0x04, 0xF0, 0x80, 0xC8, 0x7B, 0x01, +0x7A, 0x83, 0x79, 0x78, 0x90, 0x83, 0x8B, 0x12, 0x42, 0x3A, 0xE4, 0x90, 0x83, 0x8E, 0xF0, 0xA3, +0xF0, 0x7A, 0x83, 0x79, 0x7E, 0x12, 0x6B, 0x5A, 0x80, 0x09, 0x90, 0x06, 0x30, 0xE0, 0x44, 0x21, +0x54, 0xEF, 0xF0, 0x90, 0x83, 0x87, 0xE0, 0xFF, 0x22, 0x90, 0x83, 0x71, 0xED, 0xF0, 0xA3, 0xEB, +0xF0, 0x90, 0x83, 0x6F, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0xE4, 0x90, 0x83, 0x74, 0xF0, 0xFD, 0x71, +0xA9, 0xEF, 0x54, 0x0C, 0x64, 0x08, 0x70, 0x74, 0x90, 0x83, 0x6F, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, +0xA3, 0xE0, 0x24, 0x06, 0xFD, 0x71, 0xA9, 0xEF, 0x64, 0x88, 0x70, 0x60, 0x90, 0x83, 0x6F, 0xE0, +0xFE, 0xA3, 0xE0, 0xFF, 0xA3, 0xE0, 0x24, 0x07, 0xFD, 0x71, 0xA9, 0xEF, 0x64, 0x8E, 0x70, 0x4C, +0x90, 0x83, 0x74, 0x04, 0xF0, 0x90, 0x83, 0x6F, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x90, 0x83, 0x72, +0xE0, 0xFD, 0x90, 0x83, 0x71, 0xE0, 0x2D, 0x04, 0xFD, 0x71, 0xA9, 0xEF, 0x64, 0x03, 0x70, 0x2C, +0x90, 0x83, 0x6F, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x90, 0x83, 0x72, 0xE0, 0xFD, 0x90, 0x83, 0x71, +0xE0, 0x2D, 0x24, 0x06, 0xFD, 0x71, 0xA9, 0xEF, 0x90, 0x01, 0xC7, 0x30, 0xE3, 0x04, 0x74, 0x01, +0x80, 0x02, 0x74, 0x02, 0xF0, 0x90, 0x81, 0x85, 0xE0, 0x44, 0x01, 0xF0, 0x90, 0x83, 0x74, 0xE0, +0xFF, 0x22, 0x90, 0x83, 0x7F, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x7D, 0x09, 0x71, 0xA9, 0xEF, 0x64, +0x06, 0x70, 0x36, 0x90, 0x83, 0x7F, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x7D, 0x14, 0x71, 0xA9, 0xEF, +0x70, 0x27, 0x90, 0x83, 0x7F, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x7D, 0x15, 0x71, 0xA9, 0xEF, 0x64, +0x50, 0x70, 0x16, 0x90, 0x83, 0x7F, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0x7D, 0x21, 0x71, 0xA9, 0xEF, +0x20, 0xE0, 0x03, 0x30, 0xE2, 0x03, 0x7F, 0x01, 0x22, 0x7F, 0x00, 0x22, 0x90, 0x83, 0x6F, 0xEE, +0xF0, 0xA3, 0xEF, 0xF0, 0xA3, 0xED, 0xF0, 0x78, 0x72, 0x7C, 0x83, 0x7D, 0x01, 0x7B, 0xFF, 0x7A, +0x40, 0x79, 0xD4, 0x7E, 0x00, 0x7F, 0x06, 0x12, 0x41, 0xD0, 0x78, 0x79, 0x7C, 0x83, 0x7D, 0x01, +0x7B, 0xFF, 0x7A, 0x40, 0x79, 0xDA, 0x7E, 0x00, 0x7F, 0x04, 0x12, 0x41, 0xD0, 0xE4, 0x90, 0x83, +0x78, 0xF0, 0x90, 0x83, 0x78, 0xE0, 0xFF, 0xC3, 0x94, 0x06, 0x50, 0x1F, 0x90, 0x83, 0x70, 0xE0, +0x24, 0x04, 0x71, 0x97, 0x90, 0x83, 0x78, 0xE0, 0x24, 0x72, 0xF5, 0x82, 0xE4, 0x34, 0x83, 0xF5, +0x83, 0xEF, 0xF0, 0x90, 0x83, 0x78, 0xE0, 0x04, 0xF0, 0x80, 0xD7, 0x78, 0x72, 0x7C, 0x83, 0x7D, +0x01, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0x86, 0x7E, 0x00, 0x7F, 0x06, 0x12, 0x43, 0xEF, 0xEF, 0x60, +0x02, 0xE1, 0xDB, 0x90, 0x83, 0x71, 0xE0, 0xFF, 0x90, 0x83, 0x70, 0xE0, 0x2F, 0xFF, 0x90, 0x83, +0x6F, 0xE0, 0x34, 0x00, 0xFE, 0x90, 0x83, 0x7D, 0xF0, 0xA3, 0xEF, 0xF0, 0x24, 0x06, 0xFF, 0xE4, +0x3E, 0xFE, 0xE4, 0xFD, 0x71, 0xA9, 0xEF, 0x64, 0x08, 0x60, 0x02, 0xE1, 0xDB, 0x90, 0x83, 0x7E, +0xE0, 0x24, 0x07, 0xFF, 0x90, 0x83, 0x7D, 0xE0, 0x34, 0x00, 0xFE, 0xE4, 0xFD, 0x71, 0xA9, 0xEF, +0x70, 0x69, 0x90, 0x83, 0x78, 0xF0, 0x90, 0x83, 0x78, 0xE0, 0xFF, 0xC3, 0x94, 0x04, 0x50, 0x23, +0x90, 0x83, 0x7E, 0xE0, 0x24, 0x18, 0xFD, 0x90, 0x83, 0x7D, 0x71, 0x9B, 0x90, 0x83, 0x78, 0xE0, +0x24, 0x79, 0xF5, 0x82, 0xE4, 0x34, 0x83, 0xF5, 0x83, 0xEF, 0xF0, 0x90, 0x83, 0x78, 0xE0, 0x04, +0xF0, 0x80, 0xD3, 0x78, 0x79, 0x7C, 0x83, 0x7D, 0x01, 0x7B, 0x01, 0x7A, 0x81, 0x79, 0xA2, 0x7E, +0x00, 0x7F, 0x04, 0x12, 0x43, 0xEF, 0xEF, 0x70, 0x22, 0x90, 0x83, 0x7E, 0xE0, 0x24, 0x08, 0xFF, +0x90, 0x83, 0x7D, 0xE0, 0x34, 0x00, 0xFE, 0xD1, 0x72, 0xEF, 0x64, 0x01, 0x60, 0x0D, 0x90, 0x01, +0xC7, 0x74, 0x22, 0xF0, 0x90, 0x81, 0x85, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0x7D, 0x7F, 0xEF, 0x5D, +0xC3, 0x60, 0x14, 0x74, 0xFF, 0x9D, 0xFD, 0x74, 0xFF, 0x94, 0x00, 0x5E, 0xFE, 0xED, 0x5F, 0x24, +0x80, 0xFF, 0xE4, 0x3E, 0xFE, 0x80, 0x0D, 0x74, 0xFF, 0x9D, 0xFD, 0x74, 0xFF, 0x94, 0x00, 0x5E, +0xFE, 0xED, 0x5F, 0xFF, 0x22, 0x90, 0x01, 0x1F, 0xE0, 0xFE, 0x90, 0x01, 0x1E, 0xE0, 0x7C, 0x00, +0x24, 0x00, 0xFF, 0xEC, 0x3E, 0x90, 0x83, 0x61, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x02, 0x87, 0xE0, +0x90, 0x83, 0x65, 0xF0, 0x90, 0x81, 0x7D, 0xE0, 0x20, 0xE0, 0x02, 0x01, 0xFE, 0x90, 0x83, 0x65, +0xE0, 0xFF, 0xEC, 0xC3, 0x9F, 0x40, 0x02, 0x01, 0xFE, 0x90, 0x83, 0x61, 0xE0, 0xFA, 0xA3, 0xE0, +0xFB, 0xEA, 0x90, 0xFD, 0x11, 0xF0, 0xAF, 0x03, 0xAD, 0x07, 0x74, 0x02, 0x2D, 0xF5, 0x82, 0xE4, +0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x54, 0x0F, 0x33, 0x33, 0x33, 0x54, 0xF8, 0xF9, 0x74, 0x01, 0x2D, +0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x00, 0x2D, 0xF5, 0x82, 0xE4, 0x34, +0xFB, 0xF5, 0x83, 0xE0, 0x7A, 0x00, 0x24, 0x00, 0xFF, 0xEA, 0x3E, 0x54, 0x3F, 0x90, 0x83, 0x63, +0xF0, 0xA3, 0xEF, 0xF0, 0x74, 0x03, 0x2D, 0xF5, 0x82, 0xE4, 0x34, 0xFB, 0xF5, 0x83, 0xE0, 0x54, +0x03, 0xFF, 0x7E, 0x00, 0xAD, 0x01, 0xED, 0x24, 0x18, 0xFB, 0xEA, 0x33, 0xCB, 0x2F, 0xFF, 0xEE, +0x3B, 0x90, 0x83, 0x63, 0x8F, 0xF0, 0x12, 0x41, 0xF6, 0x90, 0x83, 0x63, 0xE0, 0xFE, 0xA3, 0xE0, +0xFF, 0x12, 0x77, 0xDC, 0x90, 0x83, 0x63, 0xEE, 0xF0, 0xA3, 0xEF, 0xF0, 0x90, 0x83, 0x61, 0xEE, +0x8F, 0xF0, 0x12, 0x41, 0xF6, 0x90, 0x80, 0xF7, 0xE0, 0xFE, 0xA3, 0xE0, 0xFF, 0xD3, 0x90, 0x83, +0x62, 0xE0, 0x9F, 0x90, 0x83, 0x61, 0xE0, 0x9E, 0x40, 0x1B, 0x90, 0x80, 0xF8, 0xE0, 0x24, 0x01, +0xFF, 0x90, 0x80, 0xF7, 0xE0, 0x34, 0x00, 0xFE, 0xC3, 0x90, 0x83, 0x62, 0xE0, 0x9F, 0xF0, 0x90, +0x83, 0x61, 0xE0, 0x9E, 0xF0, 0x90, 0x83, 0x61, 0x12, 0x57, 0xD2, 0x0C, 0x01, 0x2D, 0x22, 0x31, +0x4F, 0xAD, 0x07, 0x90, 0x01, 0xC4, 0x74, 0xFF, 0xF0, 0x74, 0x78, 0xA3, 0xF0, 0xED, 0x64, 0x01, +0x60, 0x22, 0x90, 0x81, 0x85, 0xE0, 0x44, 0x01, 0xF0, 0xED, 0xB4, 0x02, 0x08, 0x90, 0x01, 0xC7, +0x74, 0x40, 0xF0, 0x80, 0x0A, 0xED, 0xB4, 0x04, 0x06, 0x90, 0x01, 0xC7, 0x74, 0x41, 0xF0, 0x7F, +0x01, 0x02, 0x51, 0xD1, 0x11, 0x05, 0x90, 0x02, 0x87, 0xE0, 0x70, 0xF8, 0x90, 0x06, 0x90, 0xE0, +0x44, 0x02, 0xF0, 0x74, 0xFF, 0x04, 0x90, 0x01, 0xC4, 0xF0, 0x74, 0x78, 0xA3, 0xF0, 0x22, 0x90, +0x02, 0x86, 0xE0, 0x20, 0xE2, 0x03, 0x7F, 0x04, 0x22, 0x90, 0x02, 0x86, 0xE0, 0x7F, 0x01, 0x20, +0xE1, 0x02, 0x7F, 0x02, 0x22, 0xD3, 0x10, 0xAF, 0x01, 0xC3, 0xC0, 0xD0, 0x90, 0x83, 0x61, 0x12, +0x42, 0x3A, 0x12, 0x1F, 0xA4, 0x20, 0xE0, 0x05, 0x12, 0x4F, 0xF4, 0x41, 0x9D, 0x90, 0x82, 0x50, +0x74, 0x05, 0xF0, 0x90, 0x83, 0x61, 0x12, 0x42, 0x31, 0x12, 0x1F, 0xA4, 0xFF, 0x54, 0x01, 0xFE, +0x90, 0x81, 0x80, 0xE0, 0x54, 0xFE, 0x4E, 0xFE, 0xF0, 0xEF, 0x54, 0x02, 0xFF, 0xEE, 0x54, 0xFD, +0x4F, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x04, 0xFD, 0xEF, 0x54, 0xFB, 0x4D, 0xFF, 0x90, +0x81, 0x80, 0xF0, 0xEE, 0x54, 0x08, 0xFE, 0xEF, 0x54, 0xF7, 0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, +0xFE, 0x54, 0x10, 0xFD, 0xEF, 0x54, 0xEF, 0x4D, 0xFF, 0x90, 0x81, 0x80, 0xF0, 0xEE, 0x54, 0x20, +0xFE, 0xEF, 0x54, 0xDF, 0x4E, 0xFF, 0xF0, 0x12, 0x1F, 0xA4, 0xFE, 0x54, 0x40, 0xFD, 0xEF, 0x54, +0xBF, 0x4D, 0xFF, 0x90, 0x81, 0x80, 0xF0, 0xEE, 0x54, 0x80, 0xFE, 0xEF, 0x54, 0x7F, 0x4E, 0xF0, +0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x54, 0x80, 0xFF, 0x90, 0x81, 0x81, 0xE0, 0x54, 0x7F, 0x4F, +0xF0, 0x12, 0x1F, 0xA4, 0x13, 0x13, 0x54, 0x3F, 0x30, 0xE0, 0x07, 0x90, 0x06, 0x90, 0xE0, 0x44, +0x04, 0xF0, 0x90, 0x83, 0x61, 0x12, 0x42, 0x31, 0x12, 0x1F, 0xA4, 0x13, 0x13, 0x13, 0x54, 0x1F, +0x30, 0xE0, 0x07, 0x90, 0x06, 0x90, 0xE0, 0x44, 0x08, 0xF0, 0x90, 0x80, 0x06, 0xE0, 0xB4, 0x02, +0x0D, 0x90, 0x81, 0x81, 0xE0, 0xC4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x20, 0xE0, 0x51, 0x90, 0x00, +0x01, 0x12, 0x1F, 0xBD, 0x54, 0x7F, 0xFF, 0x90, 0x81, 0x81, 0xE0, 0x54, 0x80, 0x4F, 0xF0, 0x90, +0x00, 0x02, 0x12, 0x1F, 0xBD, 0x90, 0x81, 0x82, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0xFF, +0x54, 0x01, 0xFE, 0x90, 0x81, 0x83, 0xE0, 0x54, 0xFE, 0x4E, 0xFE, 0xF0, 0xEF, 0x54, 0xFE, 0xFF, +0xEE, 0x54, 0x01, 0x4F, 0xF0, 0x90, 0x81, 0x81, 0xE0, 0x54, 0x7F, 0xFF, 0x90, 0x81, 0x80, 0xE0, +0xFE, 0xC4, 0x13, 0x54, 0x07, 0x7D, 0x00, 0x20, 0xE0, 0x02, 0x7D, 0x01, 0x12, 0x52, 0xEE, 0x90, +0x80, 0x06, 0xE0, 0xB4, 0x01, 0x07, 0x90, 0xFE, 0x10, 0xE0, 0x44, 0x04, 0xF0, 0xD0, 0xD0, 0x92, +0xAF, 0x22, 0x90, 0x81, 0x85, 0xE0, 0xFF, 0x20, 0xE0, 0x07, 0x90, 0x01, 0x3F, 0xE0, 0x30, 0xE2, +0x14, 0xEF, 0x44, 0x01, 0x90, 0x81, 0x85, 0xF0, 0x90, 0x81, 0x80, 0xE0, 0xC4, 0x54, 0x0F, 0x20, +0xE0, 0x03, 0x7F, 0x00, 0x22, 0x7F, 0x01, 0x22, 0xEF, 0x90, 0x01, 0xC7, 0xB4, 0xA0, 0x05, 0x74, +0x04, 0xF0, 0x80, 0x03, 0x74, 0x08, 0xF0, 0x90, 0x81, 0x85, 0xE0, 0x44, 0x01, 0xF0, 0x22, 0xE4, +0xFF, 0x74, 0x48, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x82, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0xA4, 0x2F, +0xF5, 0x82, 0xE4, 0x34, 0x01, 0xF5, 0x83, 0xEE, 0xF0, 0x0F, 0xEF, 0xB4, 0x08, 0xE3, 0x90, 0x82, +0x50, 0xE0, 0x90, 0x04, 0x4C, 0xF0, 0x22, 0x90, 0x02, 0x09, 0xE0, 0xFD, 0x12, 0x1F, 0xA4, 0xFE, +0xAF, 0x05, 0xED, 0x2E, 0x90, 0x83, 0x30, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0xFF, 0xED, +0x2F, 0x90, 0x83, 0x31, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x83, +0x32, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x83, 0x33, 0xF0, 0x90, +0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x83, 0x34, 0xF0, 0x90, 0x00, 0x05, 0x12, +0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x83, 0x35, 0xF0, 0x90, 0x00, 0x06, 0x12, 0x1F, 0xBD, 0xFF, +0xAE, 0x05, 0xED, 0x2F, 0x90, 0x83, 0x36, 0xF0, 0x22, 0x90, 0x02, 0x09, 0xE0, 0xFD, 0x12, 0x1F, +0xA4, 0xFE, 0xAF, 0x05, 0xED, 0x2E, 0x90, 0x83, 0x37, 0xF0, 0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, +0xFF, 0xED, 0x2F, 0x90, 0x83, 0x38, 0xF0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, +0x90, 0x83, 0x39, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x83, 0x3A, +0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x83, 0x3B, 0xF0, 0x90, 0x00, +0x05, 0x12, 0x1F, 0xBD, 0xFF, 0xED, 0x2F, 0x90, 0x83, 0x3C, 0xF0, 0x90, 0x00, 0x06, 0x12, 0x1F, +0xBD, 0xFF, 0xAE, 0x05, 0xED, 0x2F, 0x90, 0x83, 0x3D, 0xF0, 0x22, 0xE4, 0xFF, 0x74, 0x18, 0x2F, +0xF5, 0x82, 0xE4, 0x34, 0x06, 0xF5, 0x83, 0xE0, 0xFE, 0x74, 0x8C, 0x2F, 0xF5, 0x82, 0xE4, 0x34, +0x81, 0xF5, 0x83, 0xEE, 0xF0, 0x74, 0x10, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x06, 0xF5, 0x83, 0xE0, +0xFE, 0x74, 0x86, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x81, 0xF5, 0x83, 0xEE, 0xF0, 0x0F, 0xEF, 0xB4, +0x06, 0xCB, 0x22, 0x90, 0x83, 0xA9, 0x12, 0x42, 0x3A, 0x12, 0x1F, 0xA4, 0x90, 0x83, 0xAE, 0xF0, +0x90, 0x00, 0x01, 0x12, 0x1F, 0xBD, 0x90, 0x83, 0xAF, 0xF0, 0x90, 0x00, 0x04, 0x12, 0x1F, 0xBD, +0x90, 0x83, 0xB0, 0xF0, 0x90, 0x00, 0x05, 0x12, 0x1F, 0xBD, 0x90, 0x83, 0xB1, 0xF0, 0x90, 0x00, +0x06, 0x12, 0x1F, 0xBD, 0x90, 0x83, 0xB2, 0xF0, 0x90, 0x00, 0x07, 0x12, 0x1F, 0xBD, 0x90, 0x83, +0xB3, 0xF0, 0x90, 0x00, 0x03, 0x12, 0x1F, 0xBD, 0x90, 0x83, 0xB6, 0xF0, 0xED, 0x70, 0x31, 0xFF, +0x74, 0xAE, 0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x83, 0xF5, 0x83, 0xE0, 0xB4, 0xFF, 0x0E, 0x74, 0xAE, +0x2F, 0xF5, 0x82, 0xE4, 0x34, 0x83, 0xF5, 0x83, 0xE4, 0xF0, 0x80, 0x0F, 0x74, 0xAE, 0x2F, 0xF5, +0x82, 0xE4, 0x34, 0x83, 0xF5, 0x83, 0xE0, 0x04, 0xF0, 0x80, 0x05, 0x0F, 0xEF, 0xB4, 0x06, 0xD0, +0x90, 0x83, 0xAD, 0xE0, 0xFF, 0xB4, 0x04, 0x25, 0xA3, 0xE0, 0xFE, 0x90, 0x83, 0xA9, 0x12, 0x42, +0x31, 0xEE, 0x12, 0x1F, 0xEA, 0x90, 0x83, 0xAF, 0xE0, 0xFE, 0x90, 0x83, 0xA9, 0x12, 0x42, 0x31, +0x90, 0x00, 0x01, 0xEE, 0x12, 0x1F, 0xFC, 0x90, 0x00, 0x02, 0xE4, 0x80, 0x30, 0xEF, 0xB4, 0x02, +0x2F, 0x90, 0x83, 0xAF, 0xE0, 0xFF, 0x90, 0x83, 0xA9, 0x12, 0x42, 0x31, 0xEF, 0x12, 0x1F, 0xEA, +0x90, 0x83, 0xAF, 0xE0, 0x44, 0x20, 0x54, 0x7F, 0xFF, 0x90, 0x83, 0xA9, 0x12, 0x42, 0x31, 0x90, +0x00, 0x01, 0xEF, 0x12, 0x1F, 0xFC, 0x90, 0x83, 0xAE, 0xE0, 0x90, 0x00, 0x02, 0x12, 0x1F, 0xFC, +0x90, 0x83, 0xA9, 0x12, 0x42, 0x31, 0xE9, 0x24, 0x03, 0xF9, 0xE4, 0x3A, 0xFA, 0x12, 0x1F, 0xA4, +0x44, 0x20, 0x12, 0x1F, 0xEA, 0x90, 0x83, 0xB0, 0xE0, 0xFF, 0x90, 0x83, 0xA9, 0x12, 0x42, 0x31, +0x90, 0x00, 0x04, 0xEF, 0x12, 0x1F, 0xFC, 0x90, 0x83, 0xB1, 0xE0, 0x90, 0x00, 0x05, 0x12, 0x1F, +0xFC, 0x90, 0x83, 0xB2, 0xE0, 0x90, 0x00, 0x06, 0x12, 0x1F, 0xFC, 0x90, 0x83, 0xB3, 0xE0, 0x90, +0x00, 0x07, 0x02, 0x1F, 0xFC, 0x00, 0xD1, 0x45, +}; +u4Byte ArrayLength_MP_8188E_FW_WoWLAN_T = 15688; + + +void +ODM_ReadFirmware_MP_8188E_FW_WoWLAN_T( + IN PDM_ODM_T pDM_Odm, + OUT u1Byte *pFirmware, + OUT u4Byte *pFirmwareSize +) +{ +#if (DM_ODM_SUPPORT_TYPE & (ODM_CE)) + *((SIZE_PTR *)pFirmware) = (SIZE_PTR)Array_MP_8188E_FW_WoWLAN_T; +#else + ODM_MoveMemory(pDM_Odm, pFirmware, Array_MP_8188E_FW_WoWLAN_T, ArrayLength_MP_8188E_FW_WoWLAN_T); +#endif + *pFirmwareSize = ArrayLength_MP_8188E_FW_WoWLAN_T; +} + + + +#endif // end of DM_ODM_SUPPORT_TYPE & (ODM_AP) + + +#endif // end of HWIMG_SUPPORT + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.h new file mode 100644 index 0000000..0a8afdf --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_FW.h @@ -0,0 +1,83 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + +#if (RTL8188E_SUPPORT == 1) +#ifndef __INC_MP_FW_HW_IMG_8188E_H +#define __INC_MP_FW_HW_IMG_8188E_H + + +/****************************************************************************** +* FW_AP.TXT +******************************************************************************/ + +void +ODM_ReadFirmware_MP_8188E_FW_AP( + IN PDM_ODM_T pDM_Odm, + OUT u1Byte *pFirmware, + OUT u4Byte *pFirmwareSize +); + +/****************************************************************************** +* FW_NIC_S.TXT +******************************************************************************/ + +void +ODM_ReadFirmware_MP_8188E_FW_NIC_S( + IN PDM_ODM_T pDM_Odm, + OUT u1Byte *pFirmware, + OUT u4Byte *pFirmwareSize +); + +/****************************************************************************** +* FW_NIC_T.TXT +******************************************************************************/ + +void +ODM_ReadFirmware_MP_8188E_FW_NIC_T( + IN PDM_ODM_T pDM_Odm, + OUT u1Byte *pFirmware, + OUT u4Byte *pFirmwareSize +); + +/****************************************************************************** +* FW_WoWLAN_S.TXT +******************************************************************************/ + +void +ODM_ReadFirmware_MP_8188E_FW_WoWLAN_S( + IN PDM_ODM_T pDM_Odm, + OUT u1Byte *pFirmware, + OUT u4Byte *pFirmwareSize +); + +/****************************************************************************** +* FW_WoWLAN_T.TXT +******************************************************************************/ + +void +ODM_ReadFirmware_MP_8188E_FW_WoWLAN_T( + IN PDM_ODM_T pDM_Odm, + OUT u1Byte *pFirmware, + OUT u4Byte *pFirmwareSize +); + +#endif +#endif // end of HWIMG_SUPPORT + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.c new file mode 100644 index 0000000..1dc548e --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.c @@ -0,0 +1,608 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + + +#include "../odm_precomp.h" +#ifdef CONFIG_IOL_IOREG_CFG +#include <rtw_iol.h> +#endif +#if (RTL8188E_SUPPORT == 1) +static BOOLEAN +CheckCondition( + const u4Byte Condition, + const u4Byte Hex + ) +{ + u4Byte _board = (Hex & 0x000000FF); + u4Byte _interface = (Hex & 0x0000FF00) >> 8; + u4Byte _platform = (Hex & 0x00FF0000) >> 16; + u4Byte cond = Condition; + + if ( Condition == 0xCDCDCDCD ) + return TRUE; + + cond = Condition & 0x000000FF; + if ( (_board != cond) && (cond != 0xFF) ) + return FALSE; + + cond = Condition & 0x0000FF00; + cond = cond >> 8; + if ( ((_interface & cond) == 0) && (cond != 0x07) ) + return FALSE; + + cond = Condition & 0x00FF0000; + cond = cond >> 16; + if ( ((_platform & cond) == 0) && (cond != 0x0F) ) + return FALSE; + return TRUE; +} + + +/****************************************************************************** +* MAC_REG.TXT +******************************************************************************/ + +u4Byte Array_MP_8188E_MAC_REG[] = { + 0x026, 0x00000041, + 0x027, 0x00000035, + 0xFF0F0718, 0xABCD, + 0x040, 0x0000000C, + 0xCDCDCDCD, 0xCDCD, + 0x040, 0x00000000, + 0xFF0F0718, 0xDEAD, + 0x428, 0x0000000A, + 0x429, 0x00000010, + 0x430, 0x00000000, + 0x431, 0x00000001, + 0x432, 0x00000002, + 0x433, 0x00000004, + 0x434, 0x00000005, + 0x435, 0x00000006, + 0x436, 0x00000007, + 0x437, 0x00000008, + 0x438, 0x00000000, + 0x439, 0x00000000, + 0x43A, 0x00000001, + 0x43B, 0x00000002, + 0x43C, 0x00000004, + 0x43D, 0x00000005, + 0x43E, 0x00000006, + 0x43F, 0x00000007, + 0x440, 0x0000005D, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000015, + 0x445, 0x000000F0, + 0x446, 0x0000000F, + 0x447, 0x00000000, + 0x458, 0x00000041, + 0x459, 0x000000A8, + 0x45A, 0x00000072, + 0x45B, 0x000000B9, + 0x460, 0x00000066, + 0x461, 0x00000066, + 0x480, 0x00000008, + 0x4C8, 0x000000FF, + 0x4C9, 0x00000008, + 0x4CC, 0x000000FF, + 0x4CD, 0x000000FF, + 0x4CE, 0x00000001, + 0x4D3, 0x00000001, + 0x500, 0x00000026, + 0x501, 0x000000A2, + 0x502, 0x0000002F, + 0x503, 0x00000000, + 0x504, 0x00000028, + 0x505, 0x000000A3, + 0x506, 0x0000005E, + 0x507, 0x00000000, + 0x508, 0x0000002B, + 0x509, 0x000000A4, + 0x50A, 0x0000005E, + 0x50B, 0x00000000, + 0x50C, 0x0000004F, + 0x50D, 0x000000A4, + 0x50E, 0x00000000, + 0x50F, 0x00000000, + 0x512, 0x0000001C, + 0x514, 0x0000000A, + 0x516, 0x0000000A, + 0x525, 0x0000004F, + 0x550, 0x00000010, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55D, 0x000000FF, + 0x605, 0x00000030, + 0x608, 0x0000000E, + 0x609, 0x0000002A, + 0x620, 0x000000FF, + 0x621, 0x000000FF, + 0x622, 0x000000FF, + 0x623, 0x000000FF, + 0x624, 0x000000FF, + 0x625, 0x000000FF, + 0x626, 0x000000FF, + 0x627, 0x000000FF, + 0x652, 0x00000020, + 0x63C, 0x0000000A, + 0x63D, 0x0000000A, + 0x63E, 0x0000000E, + 0x63F, 0x0000000E, + 0x640, 0x00000040, + 0x66E, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70A, 0x00000065, + 0x70B, 0x00000087, + +}; + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_MAC_REG( + IN PDM_ODM_T pDM_Odm + ) +{ + #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) + + u4Byte hex = 0; + u4Byte i = 0; + u2Byte count = 0; + pu4Byte ptr_array = NULL; + u1Byte platform = pDM_Odm->SupportPlatform; + u1Byte _interface = pDM_Odm->SupportInterface; + u1Byte board = pDM_Odm->BoardType; + u4Byte ArrayLen = sizeof(Array_MP_8188E_MAC_REG)/sizeof(u4Byte); + pu4Byte Array = Array_MP_8188E_MAC_REG; + BOOLEAN biol = FALSE; + +#ifdef CONFIG_IOL_IOREG_CFG + PADAPTER Adapter = pDM_Odm->Adapter; + struct xmit_frame *pxmit_frame; + u8 bndy_cnt = 1; + #ifdef CONFIG_IOL_IOREG_CFG_DBG + struct cmd_cmp cmpdata[ArrayLen]; + u4Byte cmpdata_idx=0; + #endif +#endif //CONFIG_IOL_IOREG_CFG + HAL_STATUS rst =HAL_STATUS_SUCCESS; + + hex += board; + hex += _interface << 8; + hex += platform << 16; + hex += 0xFF000000; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_8188E_MAC_REG, hex = 0x%X\n", hex)); + +#ifdef CONFIG_IOL_IOREG_CFG + biol = rtw_IOL_applied(Adapter); + + if(biol){ + if((pxmit_frame=rtw_IOL_accquire_xmit_frame(Adapter)) == NULL) + { + printk("rtw_IOL_accquire_xmit_frame failed\n"); + return HAL_STATUS_FAILURE; + } + } + +#endif //CONFIG_IOL_IOREG_CFG + for (i = 0; i < ArrayLen; i += 2 ) + { + u4Byte v1 = Array[i]; + u4Byte v2 = Array[i+1]; + + // This (offset, data) pair meets the condition. + if ( v1 < 0xCDCDCDCD ) + { + #ifdef CONFIG_IOL_IOREG_CFG + + if(biol){ + + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + rtw_IOL_append_WB_cmd(pxmit_frame,(u2Byte)v1, (u1Byte)v2,0xFF); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + cmpdata[cmpdata_idx].addr = v1; + cmpdata[cmpdata_idx].value= v2; + cmpdata_idx++; + #endif + } + else + #endif //endif CONFIG_IOL_IOREG_CFG + { + odm_ConfigMAC_8188E(pDM_Odm, v1, (u1Byte)v2); + } + continue; + } + else + { // This line is the start line of branch. + if ( !CheckCondition(Array[i], hex) ) + { // Discard the following (offset, data) pairs. + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + i -= 2; // prevent from for-loop += 2 + } + else // Configure matched pairs and skip to end of if-else. + { + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + #ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + rtw_IOL_append_WB_cmd(pxmit_frame,(u2Byte)v1, (u1Byte)v2,0xFF); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + cmpdata[cmpdata_idx].addr = v1; + cmpdata[cmpdata_idx].value= v2; + cmpdata_idx++; + #endif + } + else + #endif //#ifdef CONFIG_IOL_IOREG_CFG + { + odm_ConfigMAC_8188E(pDM_Odm, v1, (u1Byte)v2); + } + READ_NEXT_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + + } + } + } + +#ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + //printk("==> %s, pktlen = %d,bndy_cnt = %d\n",__FUNCTION__,pxmit_frame->attrib.pktlen+4+32,bndy_cnt); + + if(rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) + { + #ifdef CONFIG_IOL_IOREG_CFG_DBG + printk("~~~ IOL Config MAC Success !!! \n"); + //compare writed data + { + u4Byte idx; + u1Byte cdata; + // HAL_STATUS_FAILURE; + printk(" MAC data compare => array_len:%d \n",cmpdata_idx); + for(idx=0;idx< cmpdata_idx;idx++) + { + cdata = ODM_Read1Byte(pDM_Odm, cmpdata[idx].addr); + if(cdata != cmpdata[idx].value){ + printk("### MAC data compared failed !! addr:0x%04x, data:(0x%02x : 0x%02x) ###\n", + cmpdata[idx].addr,cmpdata[idx].value,cdata); + //rst = HAL_STATUS_FAILURE; + } + } + + + //dump data from TX packet buffer + //if(rst == HAL_STATUS_FAILURE) + { + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + + } + else{ + printk("~~~ MAC IOL_exec_cmds Failed !!! \n"); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + { + //dump data from TX packet buffer + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + rst = HAL_STATUS_FAILURE; + } + + } +#endif //#ifdef CONFIG_IOL_IOREG_CFG + return rst; +} + +/****************************************************************************** +* MAC_REG_ICUT.TXT +******************************************************************************/ + +u4Byte Array_MP_8188E_MAC_REG_ICUT[] = { + 0x026, 0x00000041, + 0x027, 0x00000035, + 0x428, 0x0000000A, + 0x429, 0x00000010, + 0x430, 0x00000000, + 0x431, 0x00000001, + 0x432, 0x00000002, + 0x433, 0x00000004, + 0x434, 0x00000005, + 0x435, 0x00000006, + 0x436, 0x00000007, + 0x437, 0x00000008, + 0x438, 0x00000000, + 0x439, 0x00000000, + 0x43A, 0x00000001, + 0x43B, 0x00000002, + 0x43C, 0x00000004, + 0x43D, 0x00000005, + 0x43E, 0x00000006, + 0x43F, 0x00000007, + 0x440, 0x0000005D, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000015, + 0x445, 0x000000F0, + 0x446, 0x0000000F, + 0x447, 0x00000000, + 0x458, 0x00000041, + 0x459, 0x000000A8, + 0x45A, 0x00000072, + 0x45B, 0x000000B9, + 0x460, 0x00000066, + 0x461, 0x00000066, + 0x480, 0x00000008, + 0x4C8, 0x000000FF, + 0x4C9, 0x00000008, + 0x4CC, 0x000000FF, + 0x4CD, 0x000000FF, + 0x4CE, 0x00000001, + 0x4D3, 0x00000001, + 0x500, 0x00000026, + 0x501, 0x000000A2, + 0x502, 0x0000002F, + 0x503, 0x00000000, + 0x504, 0x00000028, + 0x505, 0x000000A3, + 0x506, 0x0000005E, + 0x507, 0x00000000, + 0x508, 0x0000002B, + 0x509, 0x000000A4, + 0x50A, 0x0000005E, + 0x50B, 0x00000000, + 0x50C, 0x0000004F, + 0x50D, 0x000000A4, + 0x50E, 0x00000000, + 0x50F, 0x00000000, + 0x512, 0x0000001C, + 0x514, 0x0000000A, + 0x516, 0x0000000A, + 0x525, 0x0000004F, + 0x550, 0x00000010, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55D, 0x000000FF, + 0x605, 0x00000030, + 0x608, 0x0000000E, + 0x609, 0x0000002A, + 0x620, 0x000000FF, + 0x621, 0x000000FF, + 0x622, 0x000000FF, + 0x623, 0x000000FF, + 0x624, 0x000000FF, + 0x625, 0x000000FF, + 0x626, 0x000000FF, + 0x627, 0x000000FF, + 0x652, 0x00000020, + 0x63C, 0x0000000A, + 0x63D, 0x0000000A, + 0x63E, 0x0000000E, + 0x63F, 0x0000000E, + 0x640, 0x00000040, + 0x66E, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70A, 0x00000065, + 0x70B, 0x00000087, + +}; + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_MAC_REG_ICUT( + IN PDM_ODM_T pDM_Odm + ) +{ + #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) + + u4Byte hex = 0; + u4Byte i = 0; + u2Byte count = 0; + pu4Byte ptr_array = NULL; + u1Byte platform = pDM_Odm->SupportPlatform; + u1Byte _interface = pDM_Odm->SupportInterface; + u1Byte board = pDM_Odm->BoardType; + u4Byte ArrayLen = sizeof(Array_MP_8188E_MAC_REG_ICUT)/sizeof(u4Byte); + pu4Byte Array = Array_MP_8188E_MAC_REG_ICUT; + BOOLEAN biol = FALSE; + +#ifdef CONFIG_IOL_IOREG_CFG + PADAPTER Adapter = pDM_Odm->Adapter; + struct xmit_frame *pxmit_frame; + u8 bndy_cnt = 1; + #ifdef CONFIG_IOL_IOREG_CFG_DBG + struct cmd_cmp cmpdata[ArrayLen]; + u4Byte cmpdata_idx=0; + #endif +#endif //CONFIG_IOL_IOREG_CFG + HAL_STATUS rst =HAL_STATUS_SUCCESS; + + hex += board; + hex += _interface << 8; + hex += platform << 16; + hex += 0xFF000000; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_8188E_MAC_REG_ICUT, hex = 0x%X\n", hex)); + +#ifdef CONFIG_IOL_IOREG_CFG + biol = rtw_IOL_applied(Adapter); + + if(biol){ + if((pxmit_frame=rtw_IOL_accquire_xmit_frame(Adapter)) == NULL) + { + printk("rtw_IOL_accquire_xmit_frame failed\n"); + return HAL_STATUS_FAILURE; + } + } + +#endif //CONFIG_IOL_IOREG_CFG + for (i = 0; i < ArrayLen; i += 2 ) + { + u4Byte v1 = Array[i]; + u4Byte v2 = Array[i+1]; + + // This (offset, data) pair meets the condition. + if ( v1 < 0xCDCDCDCD ) + { + #ifdef CONFIG_IOL_IOREG_CFG + + if(biol){ + + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + rtw_IOL_append_WB_cmd(pxmit_frame,(u2Byte)v1, (u1Byte)v2,0xFF); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + cmpdata[cmpdata_idx].addr = v1; + cmpdata[cmpdata_idx].value= v2; + cmpdata_idx++; + #endif + } + else + #endif //endif CONFIG_IOL_IOREG_CFG + { + odm_ConfigMAC_8188E(pDM_Odm, v1, (u1Byte)v2); + } + continue; + } + else + { // This line is the start line of branch. + if ( !CheckCondition(Array[i], hex) ) + { // Discard the following (offset, data) pairs. + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + i -= 2; // prevent from for-loop += 2 + } + else // Configure matched pairs and skip to end of if-else. + { + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + #ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + rtw_IOL_append_WB_cmd(pxmit_frame,(u2Byte)v1, (u1Byte)v2,0xFF); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + cmpdata[cmpdata_idx].addr = v1; + cmpdata[cmpdata_idx].value= v2; + cmpdata_idx++; + #endif + } + else + #endif //#ifdef CONFIG_IOL_IOREG_CFG + { + odm_ConfigMAC_8188E(pDM_Odm, v1, (u1Byte)v2); + } + READ_NEXT_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + + } + } + } + +#ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + //printk("==> %s, pktlen = %d,bndy_cnt = %d\n",__FUNCTION__,pxmit_frame->attrib.pktlen+4+32,bndy_cnt); + + if(rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) + { + #ifdef CONFIG_IOL_IOREG_CFG_DBG + printk("~~~ IOL Config MAC Success !!! \n"); + //compare writed data + { + u4Byte idx; + u1Byte cdata; + // HAL_STATUS_FAILURE; + printk(" MAC data compare => array_len:%d \n",cmpdata_idx); + for(idx=0;idx< cmpdata_idx;idx++) + { + cdata = ODM_Read1Byte(pDM_Odm, cmpdata[idx].addr); + if(cdata != cmpdata[idx].value){ + printk("### MAC data compared failed !! addr:0x%04x, data:(0x%02x : 0x%02x) ###\n", + cmpdata[idx].addr,cmpdata[idx].value,cdata); + //rst = HAL_STATUS_FAILURE; + } + } + + + //dump data from TX packet buffer + //if(rst == HAL_STATUS_FAILURE) + { + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + + } + else{ + printk("~~~ MAC IOL_exec_cmds Failed !!! \n"); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + { + //dump data from TX packet buffer + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + rst = HAL_STATUS_FAILURE; + } + + } +#endif //#ifdef CONFIG_IOL_IOREG_CFG + return rst; +} + +#endif // end of HWIMG_SUPPORT + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.h new file mode 100644 index 0000000..38d0b2e --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_MAC.h @@ -0,0 +1,47 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + +#if (RTL8188E_SUPPORT == 1) +#ifndef __INC_MP_MAC_HW_IMG_8188E_H +#define __INC_MP_MAC_HW_IMG_8188E_H + +//static BOOLEAN CheckCondition(const u4Byte Condition, const u4Byte Hex); + +/****************************************************************************** +* MAC_REG.TXT +******************************************************************************/ + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_MAC_REG( // TC: Test Chip, MP: MP Chip + IN PDM_ODM_T pDM_Odm +); + +/****************************************************************************** +* MAC_REG_ICUT.TXT +******************************************************************************/ + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_MAC_REG_ICUT( // TC: Test Chip, MP: MP Chip + IN PDM_ODM_T pDM_Odm +); + +#endif +#endif // end of HWIMG_SUPPORT + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.c new file mode 100644 index 0000000..79a0410 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.c @@ -0,0 +1,1404 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + + +#include "../odm_precomp.h" + +#ifdef CONFIG_IOL_IOREG_CFG +#include <rtw_iol.h> +#endif + +#if (RTL8188E_SUPPORT == 1) +static BOOLEAN +CheckCondition( + const u4Byte Condition, + const u4Byte Hex + ) +{ + u4Byte _board = (Hex & 0x000000FF); + u4Byte _interface = (Hex & 0x0000FF00) >> 8; + u4Byte _platform = (Hex & 0x00FF0000) >> 16; + u4Byte cond = Condition; + + if ( Condition == 0xCDCDCDCD ) + return TRUE; + + cond = Condition & 0x000000FF; + if ( (_board != cond) && (cond != 0xFF) ) + return FALSE; + + cond = Condition & 0x0000FF00; + cond = cond >> 8; + if ( ((_interface & cond) == 0) && (cond != 0x07) ) + return FALSE; + + cond = Condition & 0x00FF0000; + cond = cond >> 16; + if ( ((_platform & cond) == 0) && (cond != 0x0F) ) + return FALSE; + return TRUE; +} + + +/****************************************************************************** +* RadioA_1T.TXT +******************************************************************************/ + +u4Byte Array_MP_8188E_RadioA_1T[] = { + 0x000, 0x00030000, + 0x008, 0x00084000, + 0x018, 0x00000407, + 0x019, 0x00000012, + 0x01E, 0x00080009, + 0x01F, 0x00000880, + 0x02F, 0x0001A060, + 0x03F, 0x00000000, + 0x042, 0x000060C0, + 0x057, 0x000D0000, + 0x058, 0x000BE180, + 0x067, 0x00001552, + 0x083, 0x00000000, + 0x0B0, 0x000FF8FC, + 0x0B1, 0x00054400, + 0x0B2, 0x000CCC19, + 0x0B4, 0x00043003, + 0x0B6, 0x0004953E, + 0x0B7, 0x0001C718, + 0x0B8, 0x000060FF, + 0x0B9, 0x00080001, + 0x0BA, 0x00040000, + 0x0BB, 0x00000400, + 0x0BF, 0x000C0000, + 0x0C2, 0x00002400, + 0x0C3, 0x00000009, + 0x0C4, 0x00040C91, + 0x0C5, 0x00099999, + 0x0C6, 0x000000A3, + 0x0C7, 0x00088820, + 0x0C8, 0x00076C06, + 0x0C9, 0x00000000, + 0x0CA, 0x00080000, + 0x0DF, 0x00000180, + 0x0EF, 0x000001A0, + 0x051, 0x0006B27D, + 0xFF0F0400, 0xABCD, + 0x052, 0x0007E4DD, + 0xCDCDCDCD, 0xCDCD, + 0x052, 0x0007E49D, + 0xFF0F0400, 0xDEAD, + 0x053, 0x00000073, + 0x056, 0x00051FF3, + 0x035, 0x00000086, + 0x035, 0x00000186, + 0x035, 0x00000286, + 0x036, 0x00001C25, + 0x036, 0x00009C25, + 0x036, 0x00011C25, + 0x036, 0x00019C25, + 0x0B6, 0x00048538, + 0x018, 0x00000C07, + 0x05A, 0x0004BD00, + 0x019, 0x000739D0, + 0xFF0F0718, 0xABCD, + 0x034, 0x0000A093, + 0x034, 0x0000908F, + 0x034, 0x0000808C, + 0x034, 0x0000704F, + 0x034, 0x0000604C, + 0x034, 0x00005049, + 0x034, 0x0000400C, + 0x034, 0x00003009, + 0x034, 0x00002006, + 0x034, 0x00001003, + 0x034, 0x00000000, + 0xCDCDCDCD, 0xCDCD, + 0x034, 0x0000ADF3, + 0x034, 0x00009DF0, + 0x034, 0x00008DED, + 0x034, 0x00007DEA, + 0x034, 0x00006DE7, + 0x034, 0x000054EE, + 0x034, 0x000044EB, + 0x034, 0x000034E8, + 0x034, 0x0000246B, + 0x034, 0x00001468, + 0x034, 0x0000006D, + 0xFF0F0718, 0xDEAD, + 0x000, 0x00030159, + 0x084, 0x00068200, + 0x086, 0x000000CE, + 0x087, 0x00048A00, + 0x08E, 0x00065540, + 0x08F, 0x00088000, + 0x0EF, 0x000020A0, + 0x03B, 0x000F02B0, + 0x03B, 0x000EF7B0, + 0x03B, 0x000D4FB0, + 0x03B, 0x000CF060, + 0x03B, 0x000B0090, + 0x03B, 0x000A0080, + 0x03B, 0x00090080, + 0x03B, 0x0008F780, + 0x03B, 0x000722B0, + 0x03B, 0x0006F7B0, + 0x03B, 0x00054FB0, + 0x03B, 0x0004F060, + 0x03B, 0x00030090, + 0x03B, 0x00020080, + 0x03B, 0x00010080, + 0x03B, 0x0000F780, + 0x0EF, 0x000000A0, + 0x000, 0x00010159, + 0x018, 0x0000F407, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0x01F, 0x00080003, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0x01E, 0x00000001, + 0x01F, 0x00080000, + 0x000, 0x00033E60, + +}; + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_RadioA_1T( + IN PDM_ODM_T pDM_Odm + ) +{ + #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) + + u4Byte hex = 0; + u4Byte i = 0; + u2Byte count = 0; + pu4Byte ptr_array = NULL; + u1Byte platform = pDM_Odm->SupportPlatform; + u1Byte _interface = pDM_Odm->SupportInterface; + u1Byte board = pDM_Odm->BoardType; + u4Byte ArrayLen = sizeof(Array_MP_8188E_RadioA_1T)/sizeof(u4Byte); + pu4Byte Array = Array_MP_8188E_RadioA_1T; + BOOLEAN biol = FALSE; +#ifdef CONFIG_IOL_IOREG_CFG + PADAPTER Adapter = pDM_Odm->Adapter; + struct xmit_frame *pxmit_frame; + u8 bndy_cnt = 1; + #ifdef CONFIG_IOL_IOREG_CFG_DBG + struct cmd_cmp cmpdata[ArrayLen]; + u4Byte cmpdata_idx=0; + #endif +#endif//#ifdef CONFIG_IOL_IOREG_CFG + HAL_STATUS rst =HAL_STATUS_SUCCESS; + + hex += board; + hex += _interface << 8; + hex += platform << 16; + hex += 0xFF000000; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_8188E_RadioA_1T, hex = 0x%X\n", hex)); +#ifdef CONFIG_IOL_IOREG_CFG + biol = rtw_IOL_applied(Adapter); + + if(biol){ + if((pxmit_frame=rtw_IOL_accquire_xmit_frame(Adapter)) == NULL) + { + printk("rtw_IOL_accquire_xmit_frame failed\n"); + return HAL_STATUS_FAILURE; + } + } +#endif//#ifdef CONFIG_IOL_IOREG_CFG + + for (i = 0; i < ArrayLen; i += 2 ) + { + u4Byte v1 = Array[i]; + u4Byte v2 = Array[i+1]; + + // This (offset, data) pair meets the condition. + if ( v1 < 0xCDCDCDCD ) + { + #ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + + if(v1 == 0xffe) + { + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,50); + } + else if (v1 == 0xfd){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,5); + } + else if (v1 == 0xfc){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,1); + } + else if (v1 == 0xfb){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,50); + } + else if (v1 == 0xfa){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,5); + } + else if (v1 == 0xf9){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,1); + } + else{ + rtw_IOL_append_WRF_cmd(pxmit_frame, ODM_RF_PATH_A,(u2Byte)v1, v2,bRFRegOffsetMask) ; + #ifdef CONFIG_IOL_IOREG_CFG_DBG + cmpdata[cmpdata_idx].addr = v1; + cmpdata[cmpdata_idx].value= v2; + cmpdata_idx++; + #endif + } + + } + else + #endif //#ifdef CONFIG_IOL_IOREG_CFG + { + odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2); + } + continue; + } + else + { // This line is the start line of branch. + if ( !CheckCondition(Array[i], hex) ) + { // Discard the following (offset, data) pairs. + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + i -= 2; // prevent from for-loop += 2 + } + else // Configure matched pairs and skip to end of if-else. + { + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + #ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + + if(v1 == 0xffe) + { + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,50); + } + else if (v1 == 0xfd){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,5); + } + else if (v1 == 0xfc){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,1); + } + else if (v1 == 0xfb){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,50); + } + else if (v1 == 0xfa){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,5); + } + else if (v1 == 0xf9){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,1); + } + else{ + rtw_IOL_append_WRF_cmd(pxmit_frame, ODM_RF_PATH_A,(u2Byte)v1, v2,bRFRegOffsetMask) ; + #ifdef CONFIG_IOL_IOREG_CFG_DBG + cmpdata[cmpdata_idx].addr = v1; + cmpdata[cmpdata_idx].value= v2; + cmpdata_idx++; + #endif + + } + } + else + #endif //#ifdef CONFIG_IOL_IOREG_CFG + { + odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2); + } + READ_NEXT_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + + } + } + } +#ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + //printk("==> %s, pktlen = %d,bndy_cnt = %d\n",__FUNCTION__,pxmit_frame->attrib.pktlen+4+32,bndy_cnt); + if(rtw_IOL_exec_cmds_sync(pDM_Odm->Adapter, pxmit_frame, 1000, bndy_cnt)) + { + #ifdef CONFIG_IOL_IOREG_CFG_DBG + printk("~~~ %s Success !!! \n",__FUNCTION__); + { + u4Byte idx; + u4Byte cdata; + printk(" %s data compare => array_len:%d \n",__FUNCTION__,cmpdata_idx); + printk("### %s data compared !!###\n",__FUNCTION__); + for(idx=0;idx< cmpdata_idx;idx++) + { + cdata = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A,cmpdata[idx].addr,bRFRegOffsetMask); + if(cdata != cmpdata[idx].value){ + printk("addr:0x%04x, data:(0x%02x : 0x%02x) \n", + cmpdata[idx].addr,cmpdata[idx].value,cdata); + rst = HAL_STATUS_FAILURE; + } + } + printk("### %s data compared !!###\n",__FUNCTION__); + //if(rst == HAL_STATUS_FAILURE) + {//dump data from TX packet buffer + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + + } + else{ + rst = HAL_STATUS_FAILURE; + printk("~~~ IOL Config %s Failed !!! \n",__FUNCTION__); + #ifdef CONFIG_IOL_IOREG_CFG_DBG + { + //dump data from TX packet buffer + rtw_IOL_cmd_tx_pkt_buf_dump(pDM_Odm->Adapter,pxmit_frame->attrib.pktlen+32); + } + #endif //CONFIG_IOL_IOREG_CFG_DBG + } + } + + +#endif //#ifdef CONFIG_IOL_IOREG_CFG + return rst; +} + +/****************************************************************************** +* RadioA_1T_ICUT.TXT +******************************************************************************/ + +u4Byte Array_MP_8188E_RadioA_1T_ICUT[] = { + 0x000, 0x00030000, + 0x008, 0x00084000, + 0x018, 0x00000407, + 0x019, 0x00000012, + 0x01E, 0x00080009, + 0x01F, 0x00000880, + 0x02F, 0x0001A060, + 0x03F, 0x00000000, + 0x042, 0x000060C0, + 0x057, 0x000D0000, + 0x058, 0x000BE180, + 0x067, 0x00001552, + 0x083, 0x00000000, + 0x0B0, 0x000FF8FC, + 0x0B1, 0x00054400, + 0x0B2, 0x000CCC19, + 0x0B4, 0x00043003, + 0x0B6, 0x0004953E, + 0x0B7, 0x0001C718, + 0x0B8, 0x000060FF, + 0x0B9, 0x00080001, + 0x0BA, 0x00040000, + 0x0BB, 0x00000400, + 0x0BF, 0x000C0000, + 0x0C2, 0x00002400, + 0x0C3, 0x00000009, + 0x0C4, 0x00040C91, + 0x0C5, 0x00099999, + 0x0C6, 0x000000A3, + 0x0C7, 0x00088820, + 0x0C8, 0x00076C06, + 0x0C9, 0x00000000, + 0x0CA, 0x00080000, + 0x0DF, 0x00000180, + 0x0EF, 0x000001A0, + 0x051, 0x0006B27D, + 0xFF0F0400, 0xABCD, + 0x052, 0x0007E4DD, + 0xCDCDCDCD, 0xCDCD, + 0x052, 0x0007E49D, + 0xFF0F0400, 0xDEAD, + 0x053, 0x00000073, + 0x056, 0x00051FF3, + 0x035, 0x00000086, + 0x035, 0x00000186, + 0x035, 0x00000286, + 0x036, 0x00001C25, + 0x036, 0x00009C25, + 0x036, 0x00011C25, + 0x036, 0x00019C25, + 0x0B6, 0x00048538, + 0x018, 0x00000C07, + 0x05A, 0x0004BD00, + 0x019, 0x000739D0, + 0x034, 0x0000ADF3, + 0x034, 0x00009DF0, + 0x034, 0x00008DED, + 0x034, 0x00007DEA, + 0x034, 0x00006DE7, + 0x034, 0x000054EE, + 0x034, 0x000044EB, + 0x034, 0x000034E8, + 0x034, 0x0000246B, + 0x034, 0x00001468, + 0x034, 0x0000006D, + 0x000, 0x00030159, + 0x084, 0x00068200, + 0x086, 0x000000CE, + 0x087, 0x00048A00, + 0x08E, 0x00065540, + 0x08F, 0x00088000, + 0x0EF, 0x000020A0, + 0x03B, 0x000F02B0, + 0x03B, 0x000EF7B0, + 0x03B, 0x000D4FB0, + 0x03B, 0x000CF060, + 0x03B, 0x000B0090, + 0x03B, 0x000A0080, + 0x03B, 0x00090080, + 0x03B, 0x0008F780, + 0x03B, 0x000722B0, + 0x03B, 0x0006F7B0, + 0x03B, 0x00054FB0, + 0x03B, 0x0004F060, + 0x03B, 0x00030090, + 0x03B, 0x00020080, + 0x03B, 0x00010080, + 0x03B, 0x0000F780, + 0x0EF, 0x000000A0, + 0x000, 0x00010159, + 0x018, 0x0000F407, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0x01F, 0x00080003, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0x01E, 0x00000001, + 0x01F, 0x00080000, + 0x000, 0x00033E60, + +}; + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_RadioA_1T_ICUT( + IN PDM_ODM_T pDM_Odm + ) +{ + #define READ_NEXT_PAIR(v1, v2, i) do { i += 2; v1 = Array[i]; v2 = Array[i+1]; } while(0) + + u4Byte hex = 0; + u4Byte i = 0; + u2Byte count = 0; + pu4Byte ptr_array = NULL; + u1Byte platform = pDM_Odm->SupportPlatform; + u1Byte _interface = pDM_Odm->SupportInterface; + u1Byte board = pDM_Odm->BoardType; + u4Byte ArrayLen = sizeof(Array_MP_8188E_RadioA_1T_ICUT)/sizeof(u4Byte); + pu4Byte Array = Array_MP_8188E_RadioA_1T_ICUT; + BOOLEAN biol = FALSE; +#ifdef CONFIG_IOL_IOREG_CFG + PADAPTER Adapter = pDM_Odm->Adapter; + struct xmit_frame *pxmit_frame; + u8 bndy_cnt = 1; + #ifdef CONFIG_IOL_IOREG_CFG_DBG + struct cmd_cmp cmpdata[ArrayLen]; + u4Byte cmpdata_idx=0; + #endif +#endif//#ifdef CONFIG_IOL_IOREG_CFG + HAL_STATUS rst =HAL_STATUS_SUCCESS; + + hex += board; + hex += _interface << 8; + hex += platform << 16; + hex += 0xFF000000; + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_8188E_RadioA_1T_ICUT, hex = 0x%X\n", hex)); +#ifdef CONFIG_IOL_IOREG_CFG + biol = rtw_IOL_applied(Adapter); + + if(biol){ + if((pxmit_frame=rtw_IOL_accquire_xmit_frame(Adapter)) == NULL) + { + printk("rtw_IOL_accquire_xmit_frame failed\n"); + return HAL_STATUS_FAILURE; + } + } +#endif//#ifdef CONFIG_IOL_IOREG_CFG + + for (i = 0; i < ArrayLen; i += 2 ) + { + u4Byte v1 = Array[i]; + u4Byte v2 = Array[i+1]; + + // This (offset, data) pair meets the condition. + if ( v1 < 0xCDCDCDCD ) + { + #ifdef CONFIG_IOL_IOREG_CFG + if(biol){ + if(rtw_IOL_cmd_boundary_handle(pxmit_frame)) + bndy_cnt++; + + if(v1 == 0xffe) + { + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,50); + } + else if (v1 == 0xfd){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,5); + } + else if (v1 == 0xfc){ + rtw_IOL_append_DELAY_MS_cmd(pxmit_frame,1); + } + else if (v1 == 0xfb){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,50); + } + else if (v1 == 0xfa){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,5); + } + else if (v1 == 0xf9){ + rtw_IOL_append_DELAY_US_cmd(pxmit_frame,1); + } + else{ + rtw_IOL_append_WRF_cmd(pxmit_frame, ODM_RF_PATH_A,(u2Byte)v1, v2,bRFRegOffsetMask) ; + #ifdef CONFIG_IOL_IOREG_CFG_DBG + cmpdata[cmpdata_idx].addr = v1; + cmpdata[cmpdata_idx].value= v2; + cmpdata_idx++; + #endif + } + + } + else + #endif //#ifdef CONFIG_IOL_IOREG_CFG + { + odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2); + } + continue; + } + else + { // This line is the start line of branch. + if ( !CheckCondition(Array[i], hex) ) + { // Discard the following (offset, data) pairs. + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + i -= 2; // prevent from for-loop += 2 + } + else // Configure matched pairs and skip to end of if-else. + { + READ_NEXT_PAIR(v1, v2, i); + while (v2 != 0xDEAD && + v2 != 0xCDEF && + v2 != 0xCDCD && i < ArrayLen -2) + { + odm_ConfigRF_RadioA_8188E(pDM_Odm, v1, v2); + READ_NEXT_PAIR(v1, v2, i); + } + + while (v2 != 0xDEAD && i < ArrayLen -2) + { + READ_NEXT_PAIR(v1, v2, i); + } + + } + } + } + return rst; +} + +/****************************************************************************** +* TxPowerTrack_AP.TXT +******************************************************************************/ + +u1Byte gDeltaSwingTableIdx_MP_5GB_N_TxPowerTrack_AP_8188E[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16, 17, 17, 17, 17, 18, 18, 18}, + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18}, + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18}, +}; +u1Byte gDeltaSwingTableIdx_MP_5GB_P_TxPowerTrack_AP_8188E[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, +}; +u1Byte gDeltaSwingTableIdx_MP_5GA_N_TxPowerTrack_AP_8188E[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16, 17, 17, 17, 17, 18, 18, 18}, + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18}, + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18}, +}; +u1Byte gDeltaSwingTableIdx_MP_5GA_P_TxPowerTrack_AP_8188E[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, +}; +u1Byte gDeltaSwingTableIdx_MP_2GB_N_TxPowerTrack_AP_8188E[] = {0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11}; +u1Byte gDeltaSwingTableIdx_MP_2GB_P_TxPowerTrack_AP_8188E[] = {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9}; +u1Byte gDeltaSwingTableIdx_MP_2GA_N_TxPowerTrack_AP_8188E[] = {0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11}; +u1Byte gDeltaSwingTableIdx_MP_2GA_P_TxPowerTrack_AP_8188E[] = {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9}; +u1Byte gDeltaSwingTableIdx_MP_2GCCKB_N_TxPowerTrack_AP_8188E[] = {0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11}; +u1Byte gDeltaSwingTableIdx_MP_2GCCKB_P_TxPowerTrack_AP_8188E[] = {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9}; +u1Byte gDeltaSwingTableIdx_MP_2GCCKA_N_TxPowerTrack_AP_8188E[] = {0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11}; +u1Byte gDeltaSwingTableIdx_MP_2GCCKA_P_TxPowerTrack_AP_8188E[] = {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9}; + +void +ODM_ReadAndConfig_MP_8188E_TxPowerTrack_AP( + IN PDM_ODM_T pDM_Odm + ) +{ + PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_MP_8188E\n")); + + + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GA_P, gDeltaSwingTableIdx_MP_2GA_P_TxPowerTrack_AP_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GA_N, gDeltaSwingTableIdx_MP_2GA_N_TxPowerTrack_AP_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GB_P, gDeltaSwingTableIdx_MP_2GB_P_TxPowerTrack_AP_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GB_N, gDeltaSwingTableIdx_MP_2GB_N_TxPowerTrack_AP_8188E, DELTA_SWINGIDX_SIZE); + + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_P, gDeltaSwingTableIdx_MP_2GCCKA_P_TxPowerTrack_AP_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_N, gDeltaSwingTableIdx_MP_2GCCKA_N_TxPowerTrack_AP_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_P, gDeltaSwingTableIdx_MP_2GCCKB_P_TxPowerTrack_AP_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_N, gDeltaSwingTableIdx_MP_2GCCKB_N_TxPowerTrack_AP_8188E, DELTA_SWINGIDX_SIZE); + + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P, gDeltaSwingTableIdx_MP_5GA_P_TxPowerTrack_AP_8188E, DELTA_SWINGIDX_SIZE*3); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N, gDeltaSwingTableIdx_MP_5GA_N_TxPowerTrack_AP_8188E, DELTA_SWINGIDX_SIZE*3); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P, gDeltaSwingTableIdx_MP_5GB_P_TxPowerTrack_AP_8188E, DELTA_SWINGIDX_SIZE*3); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N, gDeltaSwingTableIdx_MP_5GB_N_TxPowerTrack_AP_8188E, DELTA_SWINGIDX_SIZE*3); +} + +/****************************************************************************** +* TxPowerTrack_PCIE.TXT +******************************************************************************/ + +u1Byte gDeltaSwingTableIdx_MP_5GB_N_TxPowerTrack_PCIE_8188E[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16, 17, 17, 17, 17, 18, 18, 18}, + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18}, + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18}, +}; +u1Byte gDeltaSwingTableIdx_MP_5GB_P_TxPowerTrack_PCIE_8188E[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, +}; +u1Byte gDeltaSwingTableIdx_MP_5GA_N_TxPowerTrack_PCIE_8188E[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16, 17, 17, 17, 17, 18, 18, 18}, + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18}, + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18}, +}; +u1Byte gDeltaSwingTableIdx_MP_5GA_P_TxPowerTrack_PCIE_8188E[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, +}; +u1Byte gDeltaSwingTableIdx_MP_2GB_N_TxPowerTrack_PCIE_8188E[] = {0, 0, 0, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11}; +u1Byte gDeltaSwingTableIdx_MP_2GB_P_TxPowerTrack_PCIE_8188E[] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9}; +u1Byte gDeltaSwingTableIdx_MP_2GA_N_TxPowerTrack_PCIE_8188E[] = {0, 0, 0, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11}; +u1Byte gDeltaSwingTableIdx_MP_2GA_P_TxPowerTrack_PCIE_8188E[] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9}; +u1Byte gDeltaSwingTableIdx_MP_2GCCKB_N_TxPowerTrack_PCIE_8188E[] = {0, 0, 0, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11}; +u1Byte gDeltaSwingTableIdx_MP_2GCCKB_P_TxPowerTrack_PCIE_8188E[] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9}; +u1Byte gDeltaSwingTableIdx_MP_2GCCKA_N_TxPowerTrack_PCIE_8188E[] = {0, 0, 0, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11}; +u1Byte gDeltaSwingTableIdx_MP_2GCCKA_P_TxPowerTrack_PCIE_8188E[] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9}; + +void +ODM_ReadAndConfig_MP_8188E_TxPowerTrack_PCIE( + IN PDM_ODM_T pDM_Odm + ) +{ + PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_MP_8188E\n")); + + + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GA_P, gDeltaSwingTableIdx_MP_2GA_P_TxPowerTrack_PCIE_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GA_N, gDeltaSwingTableIdx_MP_2GA_N_TxPowerTrack_PCIE_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GB_P, gDeltaSwingTableIdx_MP_2GB_P_TxPowerTrack_PCIE_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GB_N, gDeltaSwingTableIdx_MP_2GB_N_TxPowerTrack_PCIE_8188E, DELTA_SWINGIDX_SIZE); + + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_P, gDeltaSwingTableIdx_MP_2GCCKA_P_TxPowerTrack_PCIE_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_N, gDeltaSwingTableIdx_MP_2GCCKA_N_TxPowerTrack_PCIE_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_P, gDeltaSwingTableIdx_MP_2GCCKB_P_TxPowerTrack_PCIE_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_N, gDeltaSwingTableIdx_MP_2GCCKB_N_TxPowerTrack_PCIE_8188E, DELTA_SWINGIDX_SIZE); + + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P, gDeltaSwingTableIdx_MP_5GA_P_TxPowerTrack_PCIE_8188E, DELTA_SWINGIDX_SIZE*3); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N, gDeltaSwingTableIdx_MP_5GA_N_TxPowerTrack_PCIE_8188E, DELTA_SWINGIDX_SIZE*3); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P, gDeltaSwingTableIdx_MP_5GB_P_TxPowerTrack_PCIE_8188E, DELTA_SWINGIDX_SIZE*3); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N, gDeltaSwingTableIdx_MP_5GB_N_TxPowerTrack_PCIE_8188E, DELTA_SWINGIDX_SIZE*3); +} + +/****************************************************************************** +* TxPowerTrack_USB.TXT +******************************************************************************/ + +u1Byte gDeltaSwingTableIdx_MP_5GB_N_TxPowerTrack_USB_8188E[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16, 17, 17, 17, 17, 18, 18, 18}, + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18}, + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18}, +}; +u1Byte gDeltaSwingTableIdx_MP_5GB_P_TxPowerTrack_USB_8188E[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, +}; +u1Byte gDeltaSwingTableIdx_MP_5GA_N_TxPowerTrack_USB_8188E[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16, 17, 17, 17, 17, 18, 18, 18}, + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18}, + {0, 1, 2, 3, 3, 5, 5, 6, 6, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18}, +}; +u1Byte gDeltaSwingTableIdx_MP_5GA_P_TxPowerTrack_USB_8188E[][DELTA_SWINGIDX_SIZE] = { + {0, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15}, +}; +u1Byte gDeltaSwingTableIdx_MP_2GB_N_TxPowerTrack_USB_8188E[] = {0, 0, 0, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11}; +u1Byte gDeltaSwingTableIdx_MP_2GB_P_TxPowerTrack_USB_8188E[] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9}; +u1Byte gDeltaSwingTableIdx_MP_2GA_N_TxPowerTrack_USB_8188E[] = {0, 0, 0, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11}; +u1Byte gDeltaSwingTableIdx_MP_2GA_P_TxPowerTrack_USB_8188E[] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9}; +u1Byte gDeltaSwingTableIdx_MP_2GCCKB_N_TxPowerTrack_USB_8188E[] = {0, 0, 0, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11}; +u1Byte gDeltaSwingTableIdx_MP_2GCCKB_P_TxPowerTrack_USB_8188E[] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9}; +u1Byte gDeltaSwingTableIdx_MP_2GCCKA_N_TxPowerTrack_USB_8188E[] = {0, 0, 0, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11}; +u1Byte gDeltaSwingTableIdx_MP_2GCCKA_P_TxPowerTrack_USB_8188E[] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9}; + +void +ODM_ReadAndConfig_MP_8188E_TxPowerTrack_USB( + IN PDM_ODM_T pDM_Odm + ) +{ + PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_MP_8188E\n")); + + + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GA_P, gDeltaSwingTableIdx_MP_2GA_P_TxPowerTrack_USB_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GA_N, gDeltaSwingTableIdx_MP_2GA_N_TxPowerTrack_USB_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GB_P, gDeltaSwingTableIdx_MP_2GB_P_TxPowerTrack_USB_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GB_N, gDeltaSwingTableIdx_MP_2GB_N_TxPowerTrack_USB_8188E, DELTA_SWINGIDX_SIZE); + + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_P, gDeltaSwingTableIdx_MP_2GCCKA_P_TxPowerTrack_USB_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_N, gDeltaSwingTableIdx_MP_2GCCKA_N_TxPowerTrack_USB_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_P, gDeltaSwingTableIdx_MP_2GCCKB_P_TxPowerTrack_USB_8188E, DELTA_SWINGIDX_SIZE); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_N, gDeltaSwingTableIdx_MP_2GCCKB_N_TxPowerTrack_USB_8188E, DELTA_SWINGIDX_SIZE); + + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P, gDeltaSwingTableIdx_MP_5GA_P_TxPowerTrack_USB_8188E, DELTA_SWINGIDX_SIZE*3); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N, gDeltaSwingTableIdx_MP_5GA_N_TxPowerTrack_USB_8188E, DELTA_SWINGIDX_SIZE*3); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P, gDeltaSwingTableIdx_MP_5GB_P_TxPowerTrack_USB_8188E, DELTA_SWINGIDX_SIZE*3); + ODM_MoveMemory(pDM_Odm, pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N, gDeltaSwingTableIdx_MP_5GB_N_TxPowerTrack_USB_8188E, DELTA_SWINGIDX_SIZE*3); +} + +/****************************************************************************** +* TXPWR_LMT.TXT +******************************************************************************/ + +pu1Byte Array_MP_8188E_TXPWR_LMT[] = { + "FCC", "2.4G", "20M", "CCK", "1T", "01", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "01", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "01", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "02", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "02", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "02", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "03", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "03", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "03", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "04", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "04", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "04", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "05", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "05", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "05", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "06", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "06", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "06", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "07", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "07", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "07", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "08", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "08", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "08", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "09", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "09", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "09", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "10", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "10", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "10", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "11", "32", + "ETSI", "2.4G", "20M", "CCK", "1T", "11", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "11", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "12", "63", + "ETSI", "2.4G", "20M", "CCK", "1T", "12", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "12", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "13", "63", + "ETSI", "2.4G", "20M", "CCK", "1T", "13", "32", + "MKK", "2.4G", "20M", "CCK", "1T", "13", "32", + "FCC", "2.4G", "20M", "CCK", "1T", "14", "63", + "ETSI", "2.4G", "20M", "CCK", "1T", "14", "63", + "MKK", "2.4G", "20M", "CCK", "1T", "14", "32", + "FCC", "2.4G", "20M", "OFDM", "1T", "01", "28", + "ETSI", "2.4G", "20M", "OFDM", "1T", "01", "30", + "MKK", "2.4G", "20M", "OFDM", "1T", "01", "30", + "FCC", "2.4G", "20M", "OFDM", "1T", "02", "28", + "ETSI", "2.4G", "20M", "OFDM", "1T", "02", "30", + "MKK", "2.4G", "20M", "OFDM", "1T", "02", "30", + "FCC", "2.4G", "20M", "OFDM", "1T", "03", "30", + "ETSI", "2.4G", "20M", "OFDM", "1T", "03", "30", + "MKK", "2.4G", "20M", "OFDM", "1T", "03", "30", + "FCC", "2.4G", "20M", "OFDM", "1T", "04", "30", + "ETSI", "2.4G", "20M", "OFDM", "1T", "04", "30", + "MKK", "2.4G", "20M", "OFDM", "1T", "04", "30", + "FCC", "2.4G", "20M", "OFDM", "1T", "05", "30", + "ETSI", "2.4G", "20M", "OFDM", "1T", "05", "30", + "MKK", "2.4G", "20M", "OFDM", "1T", "05", "30", + "FCC", "2.4G", "20M", "OFDM", "1T", "06", "30", + "ETSI", "2.4G", "20M", "OFDM", "1T", "06", "30", + "MKK", "2.4G", "20M", "OFDM", "1T", "06", "30", + "FCC", "2.4G", "20M", "OFDM", "1T", "07", "30", + "ETSI", "2.4G", "20M", "OFDM", "1T", "07", "30", + "MKK", "2.4G", "20M", "OFDM", "1T", "07", "30", + "FCC", "2.4G", "20M", "OFDM", "1T", "08", "30", + "ETSI", "2.4G", "20M", "OFDM", "1T", "08", "30", + "MKK", "2.4G", "20M", "OFDM", "1T", "08", "30", + "FCC", "2.4G", "20M", "OFDM", "1T", "09", "28", + "ETSI", "2.4G", "20M", "OFDM", "1T", "09", "30", + "MKK", "2.4G", "20M", "OFDM", "1T", "09", "30", + "FCC", "2.4G", "20M", "OFDM", "1T", "10", "28", + "ETSI", "2.4G", "20M", "OFDM", "1T", "10", "30", + "MKK", "2.4G", "20M", "OFDM", "1T", "10", "30", + "FCC", "2.4G", "20M", "OFDM", "1T", "11", "28", + "ETSI", "2.4G", "20M", "OFDM", "1T", "11", "30", + "MKK", "2.4G", "20M", "OFDM", "1T", "11", "30", + "FCC", "2.4G", "20M", "OFDM", "1T", "12", "63", + "ETSI", "2.4G", "20M", "OFDM", "1T", "12", "30", + "MKK", "2.4G", "20M", "OFDM", "1T", "12", "30", + "FCC", "2.4G", "20M", "OFDM", "1T", "13", "63", + "ETSI", "2.4G", "20M", "OFDM", "1T", "13", "30", + "MKK", "2.4G", "20M", "OFDM", "1T", "13", "30", + "FCC", "2.4G", "20M", "OFDM", "1T", "14", "63", + "ETSI", "2.4G", "20M", "OFDM", "1T", "14", "63", + "MKK", "2.4G", "20M", "OFDM", "1T", "14", "63", + "FCC", "2.4G", "20M", "HT", "1T", "01", "28", + "ETSI", "2.4G", "20M", "HT", "1T", "01", "30", + "MKK", "2.4G", "20M", "HT", "1T", "01", "30", + "FCC", "2.4G", "20M", "HT", "1T", "02", "28", + "ETSI", "2.4G", "20M", "HT", "1T", "02", "30", + "MKK", "2.4G", "20M", "HT", "1T", "02", "30", + "FCC", "2.4G", "20M", "HT", "1T", "03", "30", + "ETSI", "2.4G", "20M", "HT", "1T", "03", "30", + "MKK", "2.4G", "20M", "HT", "1T", "03", "30", + "FCC", "2.4G", "20M", "HT", "1T", "04", "30", + "ETSI", "2.4G", "20M", "HT", "1T", "04", "30", + "MKK", "2.4G", "20M", "HT", "1T", "04", "30", + "FCC", "2.4G", "20M", "HT", "1T", "05", "30", + "ETSI", "2.4G", "20M", "HT", "1T", "05", "30", + "MKK", "2.4G", "20M", "HT", "1T", "05", "30", + "FCC", "2.4G", "20M", "HT", "1T", "06", "30", + "ETSI", "2.4G", "20M", "HT", "1T", "06", "30", + "MKK", "2.4G", "20M", "HT", "1T", "06", "30", + "FCC", "2.4G", "20M", "HT", "1T", "07", "30", + "ETSI", "2.4G", "20M", "HT", "1T", "07", "30", + "MKK", "2.4G", "20M", "HT", "1T", "07", "30", + "FCC", "2.4G", "20M", "HT", "1T", "08", "30", + "ETSI", "2.4G", "20M", "HT", "1T", "08", "30", + "MKK", "2.4G", "20M", "HT", "1T", "08", "30", + "FCC", "2.4G", "20M", "HT", "1T", "09", "28", + "ETSI", "2.4G", "20M", "HT", "1T", "09", "30", + "MKK", "2.4G", "20M", "HT", "1T", "09", "30", + "FCC", "2.4G", "20M", "HT", "1T", "10", "28", + "ETSI", "2.4G", "20M", "HT", "1T", "10", "30", + "MKK", "2.4G", "20M", "HT", "1T", "10", "30", + "FCC", "2.4G", "20M", "HT", "1T", "11", "28", + "ETSI", "2.4G", "20M", "HT", "1T", "11", "30", + "MKK", "2.4G", "20M", "HT", "1T", "11", "30", + "FCC", "2.4G", "20M", "HT", "1T", "12", "63", + "ETSI", "2.4G", "20M", "HT", "1T", "12", "30", + "MKK", "2.4G", "20M", "HT", "1T", "12", "30", + "FCC", "2.4G", "20M", "HT", "1T", "13", "63", + "ETSI", "2.4G", "20M", "HT", "1T", "13", "30", + "MKK", "2.4G", "20M", "HT", "1T", "13", "30", + "FCC", "2.4G", "20M", "HT", "1T", "14", "63", + "ETSI", "2.4G", "20M", "HT", "1T", "14", "63", + "MKK", "2.4G", "20M", "HT", "1T", "14", "63", + "FCC", "2.4G", "20M", "HT", "2T", "01", "28", + "ETSI", "2.4G", "20M", "HT", "2T", "01", "30", + "MKK", "2.4G", "20M", "HT", "2T", "01", "30", + "FCC", "2.4G", "20M", "HT", "2T", "02", "28", + "ETSI", "2.4G", "20M", "HT", "2T", "02", "30", + "MKK", "2.4G", "20M", "HT", "2T", "02", "30", + "FCC", "2.4G", "20M", "HT", "2T", "03", "30", + "ETSI", "2.4G", "20M", "HT", "2T", "03", "30", + "MKK", "2.4G", "20M", "HT", "2T", "03", "30", + "FCC", "2.4G", "20M", "HT", "2T", "04", "30", + "ETSI", "2.4G", "20M", "HT", "2T", "04", "30", + "MKK", "2.4G", "20M", "HT", "2T", "04", "30", + "FCC", "2.4G", "20M", "HT", "2T", "05", "30", + "ETSI", "2.4G", "20M", "HT", "2T", "05", "30", + "MKK", "2.4G", "20M", "HT", "2T", "05", "30", + "FCC", "2.4G", "20M", "HT", "2T", "06", "30", + "ETSI", "2.4G", "20M", "HT", "2T", "06", "30", + "MKK", "2.4G", "20M", "HT", "2T", "06", "30", + "FCC", "2.4G", "20M", "HT", "2T", "07", "30", + "ETSI", "2.4G", "20M", "HT", "2T", "07", "30", + "MKK", "2.4G", "20M", "HT", "2T", "07", "30", + "FCC", "2.4G", "20M", "HT", "2T", "08", "30", + "ETSI", "2.4G", "20M", "HT", "2T", "08", "30", + "MKK", "2.4G", "20M", "HT", "2T", "08", "30", + "FCC", "2.4G", "20M", "HT", "2T", "09", "28", + "ETSI", "2.4G", "20M", "HT", "2T", "09", "30", + "MKK", "2.4G", "20M", "HT", "2T", "09", "30", + "FCC", "2.4G", "20M", "HT", "2T", "10", "28", + "ETSI", "2.4G", "20M", "HT", "2T", "10", "30", + "MKK", "2.4G", "20M", "HT", "2T", "10", "30", + "FCC", "2.4G", "20M", "HT", "2T", "11", "28", + "ETSI", "2.4G", "20M", "HT", "2T", "11", "30", + "MKK", "2.4G", "20M", "HT", "2T", "11", "30", + "FCC", "2.4G", "20M", "HT", "2T", "12", "63", + "ETSI", "2.4G", "20M", "HT", "2T", "12", "30", + "MKK", "2.4G", "20M", "HT", "2T", "12", "30", + "FCC", "2.4G", "20M", "HT", "2T", "13", "63", + "ETSI", "2.4G", "20M", "HT", "2T", "13", "30", + "MKK", "2.4G", "20M", "HT", "2T", "13", "30", + "FCC", "2.4G", "20M", "HT", "2T", "14", "63", + "ETSI", "2.4G", "20M", "HT", "2T", "14", "63", + "MKK", "2.4G", "20M", "HT", "2T", "14", "63", + "FCC", "2.4G", "40M", "HT", "1T", "01", "63", + "ETSI", "2.4G", "40M", "HT", "1T", "01", "63", + "MKK", "2.4G", "40M", "HT", "1T", "01", "63", + "FCC", "2.4G", "40M", "HT", "1T", "02", "63", + "ETSI", "2.4G", "40M", "HT", "1T", "02", "63", + "MKK", "2.4G", "40M", "HT", "1T", "02", "63", + "FCC", "2.4G", "40M", "HT", "1T", "03", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "03", "26", + "MKK", "2.4G", "40M", "HT", "1T", "03", "26", + "FCC", "2.4G", "40M", "HT", "1T", "04", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "04", "26", + "MKK", "2.4G", "40M", "HT", "1T", "04", "26", + "FCC", "2.4G", "40M", "HT", "1T", "05", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "05", "26", + "MKK", "2.4G", "40M", "HT", "1T", "05", "26", + "FCC", "2.4G", "40M", "HT", "1T", "06", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "06", "26", + "MKK", "2.4G", "40M", "HT", "1T", "06", "26", + "FCC", "2.4G", "40M", "HT", "1T", "07", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "07", "26", + "MKK", "2.4G", "40M", "HT", "1T", "07", "26", + "FCC", "2.4G", "40M", "HT", "1T", "08", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "08", "26", + "MKK", "2.4G", "40M", "HT", "1T", "08", "26", + "FCC", "2.4G", "40M", "HT", "1T", "09", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "09", "26", + "MKK", "2.4G", "40M", "HT", "1T", "09", "26", + "FCC", "2.4G", "40M", "HT", "1T", "10", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "10", "26", + "MKK", "2.4G", "40M", "HT", "1T", "10", "26", + "FCC", "2.4G", "40M", "HT", "1T", "11", "26", + "ETSI", "2.4G", "40M", "HT", "1T", "11", "26", + "MKK", "2.4G", "40M", "HT", "1T", "11", "26", + "FCC", "2.4G", "40M", "HT", "1T", "12", "63", + "ETSI", "2.4G", "40M", "HT", "1T", "12", "26", + "MKK", "2.4G", "40M", "HT", "1T", "12", "26", + "FCC", "2.4G", "40M", "HT", "1T", "13", "63", + "ETSI", "2.4G", "40M", "HT", "1T", "13", "26", + "MKK", "2.4G", "40M", "HT", "1T", "13", "26", + "FCC", "2.4G", "40M", "HT", "1T", "14", "63", + "ETSI", "2.4G", "40M", "HT", "1T", "14", "63", + "MKK", "2.4G", "40M", "HT", "1T", "14", "63", + "FCC", "2.4G", "40M", "HT", "2T", "01", "63", + "ETSI", "2.4G", "40M", "HT", "2T", "01", "63", + "MKK", "2.4G", "40M", "HT", "2T", "01", "63", + "FCC", "2.4G", "40M", "HT", "2T", "02", "63", + "ETSI", "2.4G", "40M", "HT", "2T", "02", "63", + "MKK", "2.4G", "40M", "HT", "2T", "02", "63", + "FCC", "2.4G", "40M", "HT", "2T", "03", "26", + "ETSI", "2.4G", "40M", "HT", "2T", "03", "26", + "MKK", "2.4G", "40M", "HT", "2T", "03", "26", + "FCC", "2.4G", "40M", "HT", "2T", "04", "26", + "ETSI", "2.4G", "40M", "HT", "2T", "04", "26", + "MKK", "2.4G", "40M", "HT", "2T", "04", "26", + "FCC", "2.4G", "40M", "HT", "2T", "05", "26", + "ETSI", "2.4G", "40M", "HT", "2T", "05", "26", + "MKK", "2.4G", "40M", "HT", "2T", "05", "26", + "FCC", "2.4G", "40M", "HT", "2T", "06", "26", + "ETSI", "2.4G", "40M", "HT", "2T", "06", "26", + "MKK", "2.4G", "40M", "HT", "2T", "06", "26", + "FCC", "2.4G", "40M", "HT", "2T", "07", "26", + "ETSI", "2.4G", "40M", "HT", "2T", "07", "26", + "MKK", "2.4G", "40M", "HT", "2T", "07", "26", + "FCC", "2.4G", "40M", "HT", "2T", "08", "26", + "ETSI", "2.4G", "40M", "HT", "2T", "08", "26", + "MKK", "2.4G", "40M", "HT", "2T", "08", "26", + "FCC", "2.4G", "40M", "HT", "2T", "09", "26", + "ETSI", "2.4G", "40M", "HT", "2T", "09", "26", + "MKK", "2.4G", "40M", "HT", "2T", "09", "26", + "FCC", "2.4G", "40M", "HT", "2T", "10", "26", + "ETSI", "2.4G", "40M", "HT", "2T", "10", "26", + "MKK", "2.4G", "40M", "HT", "2T", "10", "26", + "FCC", "2.4G", "40M", "HT", "2T", "11", "26", + "ETSI", "2.4G", "40M", "HT", "2T", "11", "26", + "MKK", "2.4G", "40M", "HT", "2T", "11", "26", + "FCC", "2.4G", "40M", "HT", "2T", "12", "63", + "ETSI", "2.4G", "40M", "HT", "2T", "12", "26", + "MKK", "2.4G", "40M", "HT", "2T", "12", "26", + "FCC", "2.4G", "40M", "HT", "2T", "13", "63", + "ETSI", "2.4G", "40M", "HT", "2T", "13", "26", + "MKK", "2.4G", "40M", "HT", "2T", "13", "26", + "FCC", "2.4G", "40M", "HT", "2T", "14", "63", + "ETSI", "2.4G", "40M", "HT", "2T", "14", "63", + "MKK", "2.4G", "40M", "HT", "2T", "14", "63", + "FCC", "5G", "20M", "OFDM", "1T", "36", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "36", "32", + "MKK", "5G", "20M", "OFDM", "1T", "36", "32", + "FCC", "5G", "20M", "OFDM", "1T", "40", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "40", "32", + "MKK", "5G", "20M", "OFDM", "1T", "40", "32", + "FCC", "5G", "20M", "OFDM", "1T", "44", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "44", "32", + "MKK", "5G", "20M", "OFDM", "1T", "44", "32", + "FCC", "5G", "20M", "OFDM", "1T", "48", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "48", "32", + "MKK", "5G", "20M", "OFDM", "1T", "48", "32", + "FCC", "5G", "20M", "OFDM", "1T", "52", "34", + "ETSI", "5G", "20M", "OFDM", "1T", "52", "32", + "MKK", "5G", "20M", "OFDM", "1T", "52", "32", + "FCC", "5G", "20M", "OFDM", "1T", "56", "34", + "ETSI", "5G", "20M", "OFDM", "1T", "56", "32", + "MKK", "5G", "20M", "OFDM", "1T", "56", "32", + "FCC", "5G", "20M", "OFDM", "1T", "60", "32", + "ETSI", "5G", "20M", "OFDM", "1T", "60", "32", + "MKK", "5G", "20M", "OFDM", "1T", "60", "32", + "FCC", "5G", "20M", "OFDM", "1T", "64", "28", + "ETSI", "5G", "20M", "OFDM", "1T", "64", "32", + "MKK", "5G", "20M", "OFDM", "1T", "64", "32", + "FCC", "5G", "20M", "OFDM", "1T", "100", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "100", "32", + "MKK", "5G", "20M", "OFDM", "1T", "100", "32", + "FCC", "5G", "20M", "OFDM", "1T", "114", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "114", "32", + "MKK", "5G", "20M", "OFDM", "1T", "114", "32", + "FCC", "5G", "20M", "OFDM", "1T", "108", "32", + "ETSI", "5G", "20M", "OFDM", "1T", "108", "32", + "MKK", "5G", "20M", "OFDM", "1T", "108", "32", + "FCC", "5G", "20M", "OFDM", "1T", "112", "34", + "ETSI", "5G", "20M", "OFDM", "1T", "112", "32", + "MKK", "5G", "20M", "OFDM", "1T", "112", "32", + "FCC", "5G", "20M", "OFDM", "1T", "116", "34", + "ETSI", "5G", "20M", "OFDM", "1T", "116", "32", + "MKK", "5G", "20M", "OFDM", "1T", "116", "32", + "FCC", "5G", "20M", "OFDM", "1T", "120", "34", + "ETSI", "5G", "20M", "OFDM", "1T", "120", "32", + "MKK", "5G", "20M", "OFDM", "1T", "120", "32", + "FCC", "5G", "20M", "OFDM", "1T", "124", "34", + "ETSI", "5G", "20M", "OFDM", "1T", "124", "32", + "MKK", "5G", "20M", "OFDM", "1T", "124", "32", + "FCC", "5G", "20M", "OFDM", "1T", "128", "32", + "ETSI", "5G", "20M", "OFDM", "1T", "128", "32", + "MKK", "5G", "20M", "OFDM", "1T", "128", "32", + "FCC", "5G", "20M", "OFDM", "1T", "132", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "132", "32", + "MKK", "5G", "20M", "OFDM", "1T", "132", "32", + "FCC", "5G", "20M", "OFDM", "1T", "136", "30", + "ETSI", "5G", "20M", "OFDM", "1T", "136", "32", + "MKK", "5G", "20M", "OFDM", "1T", "136", "32", + "FCC", "5G", "20M", "OFDM", "1T", "140", "28", + "ETSI", "5G", "20M", "OFDM", "1T", "140", "32", + "MKK", "5G", "20M", "OFDM", "1T", "140", "32", + "FCC", "5G", "20M", "OFDM", "1T", "149", "34", + "ETSI", "5G", "20M", "OFDM", "1T", "149", "32", + "MKK", "5G", "20M", "OFDM", "1T", "149", "63", + "FCC", "5G", "20M", "OFDM", "1T", "153", "34", + "ETSI", "5G", "20M", "OFDM", "1T", "153", "32", + "MKK", "5G", "20M", "OFDM", "1T", "153", "63", + "FCC", "5G", "20M", "OFDM", "1T", "157", "34", + "ETSI", "5G", "20M", "OFDM", "1T", "157", "32", + "MKK", "5G", "20M", "OFDM", "1T", "157", "63", + "FCC", "5G", "20M", "OFDM", "1T", "161", "34", + "ETSI", "5G", "20M", "OFDM", "1T", "161", "32", + "MKK", "5G", "20M", "OFDM", "1T", "161", "63", + "FCC", "5G", "20M", "OFDM", "1T", "165", "34", + "ETSI", "5G", "20M", "OFDM", "1T", "165", "32", + "MKK", "5G", "20M", "OFDM", "1T", "165", "63", + "FCC", "5G", "20M", "HT", "1T", "36", "30", + "ETSI", "5G", "20M", "HT", "1T", "36", "32", + "MKK", "5G", "20M", "HT", "1T", "36", "32", + "FCC", "5G", "20M", "HT", "1T", "40", "30", + "ETSI", "5G", "20M", "HT", "1T", "40", "32", + "MKK", "5G", "20M", "HT", "1T", "40", "32", + "FCC", "5G", "20M", "HT", "1T", "44", "30", + "ETSI", "5G", "20M", "HT", "1T", "44", "32", + "MKK", "5G", "20M", "HT", "1T", "44", "32", + "FCC", "5G", "20M", "HT", "1T", "48", "30", + "ETSI", "5G", "20M", "HT", "1T", "48", "32", + "MKK", "5G", "20M", "HT", "1T", "48", "32", + "FCC", "5G", "20M", "HT", "1T", "52", "34", + "ETSI", "5G", "20M", "HT", "1T", "52", "32", + "MKK", "5G", "20M", "HT", "1T", "52", "32", + "FCC", "5G", "20M", "HT", "1T", "56", "34", + "ETSI", "5G", "20M", "HT", "1T", "56", "32", + "MKK", "5G", "20M", "HT", "1T", "56", "32", + "FCC", "5G", "20M", "HT", "1T", "60", "32", + "ETSI", "5G", "20M", "HT", "1T", "60", "32", + "MKK", "5G", "20M", "HT", "1T", "60", "32", + "FCC", "5G", "20M", "HT", "1T", "64", "28", + "ETSI", "5G", "20M", "HT", "1T", "64", "32", + "MKK", "5G", "20M", "HT", "1T", "64", "32", + "FCC", "5G", "20M", "HT", "1T", "100", "30", + "ETSI", "5G", "20M", "HT", "1T", "100", "32", + "MKK", "5G", "20M", "HT", "1T", "100", "32", + "FCC", "5G", "20M", "HT", "1T", "114", "30", + "ETSI", "5G", "20M", "HT", "1T", "114", "32", + "MKK", "5G", "20M", "HT", "1T", "114", "32", + "FCC", "5G", "20M", "HT", "1T", "108", "32", + "ETSI", "5G", "20M", "HT", "1T", "108", "32", + "MKK", "5G", "20M", "HT", "1T", "108", "32", + "FCC", "5G", "20M", "HT", "1T", "112", "34", + "ETSI", "5G", "20M", "HT", "1T", "112", "32", + "MKK", "5G", "20M", "HT", "1T", "112", "32", + "FCC", "5G", "20M", "HT", "1T", "116", "34", + "ETSI", "5G", "20M", "HT", "1T", "116", "32", + "MKK", "5G", "20M", "HT", "1T", "116", "32", + "FCC", "5G", "20M", "HT", "1T", "120", "34", + "ETSI", "5G", "20M", "HT", "1T", "120", "32", + "MKK", "5G", "20M", "HT", "1T", "120", "32", + "FCC", "5G", "20M", "HT", "1T", "124", "34", + "ETSI", "5G", "20M", "HT", "1T", "124", "32", + "MKK", "5G", "20M", "HT", "1T", "124", "32", + "FCC", "5G", "20M", "HT", "1T", "128", "32", + "ETSI", "5G", "20M", "HT", "1T", "128", "32", + "MKK", "5G", "20M", "HT", "1T", "128", "32", + "FCC", "5G", "20M", "HT", "1T", "132", "30", + "ETSI", "5G", "20M", "HT", "1T", "132", "32", + "MKK", "5G", "20M", "HT", "1T", "132", "32", + "FCC", "5G", "20M", "HT", "1T", "136", "30", + "ETSI", "5G", "20M", "HT", "1T", "136", "32", + "MKK", "5G", "20M", "HT", "1T", "136", "32", + "FCC", "5G", "20M", "HT", "1T", "140", "28", + "ETSI", "5G", "20M", "HT", "1T", "140", "32", + "MKK", "5G", "20M", "HT", "1T", "140", "32", + "FCC", "5G", "20M", "HT", "1T", "149", "34", + "ETSI", "5G", "20M", "HT", "1T", "149", "32", + "MKK", "5G", "20M", "HT", "1T", "149", "63", + "FCC", "5G", "20M", "HT", "1T", "153", "34", + "ETSI", "5G", "20M", "HT", "1T", "153", "32", + "MKK", "5G", "20M", "HT", "1T", "153", "63", + "FCC", "5G", "20M", "HT", "1T", "157", "34", + "ETSI", "5G", "20M", "HT", "1T", "157", "32", + "MKK", "5G", "20M", "HT", "1T", "157", "63", + "FCC", "5G", "20M", "HT", "1T", "161", "34", + "ETSI", "5G", "20M", "HT", "1T", "161", "32", + "MKK", "5G", "20M", "HT", "1T", "161", "63", + "FCC", "5G", "20M", "HT", "1T", "165", "34", + "ETSI", "5G", "20M", "HT", "1T", "165", "32", + "MKK", "5G", "20M", "HT", "1T", "165", "63", + "FCC", "5G", "20M", "HT", "2T", "36", "28", + "ETSI", "5G", "20M", "HT", "2T", "36", "30", + "MKK", "5G", "20M", "HT", "2T", "36", "30", + "FCC", "5G", "20M", "HT", "2T", "40", "28", + "ETSI", "5G", "20M", "HT", "2T", "40", "30", + "MKK", "5G", "20M", "HT", "2T", "40", "30", + "FCC", "5G", "20M", "HT", "2T", "44", "28", + "ETSI", "5G", "20M", "HT", "2T", "44", "30", + "MKK", "5G", "20M", "HT", "2T", "44", "30", + "FCC", "5G", "20M", "HT", "2T", "48", "28", + "ETSI", "5G", "20M", "HT", "2T", "48", "30", + "MKK", "5G", "20M", "HT", "2T", "48", "30", + "FCC", "5G", "20M", "HT", "2T", "52", "34", + "ETSI", "5G", "20M", "HT", "2T", "52", "30", + "MKK", "5G", "20M", "HT", "2T", "52", "30", + "FCC", "5G", "20M", "HT", "2T", "56", "32", + "ETSI", "5G", "20M", "HT", "2T", "56", "30", + "MKK", "5G", "20M", "HT", "2T", "56", "30", + "FCC", "5G", "20M", "HT", "2T", "60", "30", + "ETSI", "5G", "20M", "HT", "2T", "60", "30", + "MKK", "5G", "20M", "HT", "2T", "60", "30", + "FCC", "5G", "20M", "HT", "2T", "64", "26", + "ETSI", "5G", "20M", "HT", "2T", "64", "30", + "MKK", "5G", "20M", "HT", "2T", "64", "30", + "FCC", "5G", "20M", "HT", "2T", "100", "28", + "ETSI", "5G", "20M", "HT", "2T", "100", "30", + "MKK", "5G", "20M", "HT", "2T", "100", "30", + "FCC", "5G", "20M", "HT", "2T", "114", "28", + "ETSI", "5G", "20M", "HT", "2T", "114", "30", + "MKK", "5G", "20M", "HT", "2T", "114", "30", + "FCC", "5G", "20M", "HT", "2T", "108", "30", + "ETSI", "5G", "20M", "HT", "2T", "108", "30", + "MKK", "5G", "20M", "HT", "2T", "108", "30", + "FCC", "5G", "20M", "HT", "2T", "112", "32", + "ETSI", "5G", "20M", "HT", "2T", "112", "30", + "MKK", "5G", "20M", "HT", "2T", "112", "30", + "FCC", "5G", "20M", "HT", "2T", "116", "32", + "ETSI", "5G", "20M", "HT", "2T", "116", "30", + "MKK", "5G", "20M", "HT", "2T", "116", "30", + "FCC", "5G", "20M", "HT", "2T", "120", "34", + "ETSI", "5G", "20M", "HT", "2T", "120", "30", + "MKK", "5G", "20M", "HT", "2T", "120", "30", + "FCC", "5G", "20M", "HT", "2T", "124", "32", + "ETSI", "5G", "20M", "HT", "2T", "124", "30", + "MKK", "5G", "20M", "HT", "2T", "124", "30", + "FCC", "5G", "20M", "HT", "2T", "128", "30", + "ETSI", "5G", "20M", "HT", "2T", "128", "30", + "MKK", "5G", "20M", "HT", "2T", "128", "30", + "FCC", "5G", "20M", "HT", "2T", "132", "28", + "ETSI", "5G", "20M", "HT", "2T", "132", "30", + "MKK", "5G", "20M", "HT", "2T", "132", "30", + "FCC", "5G", "20M", "HT", "2T", "136", "28", + "ETSI", "5G", "20M", "HT", "2T", "136", "30", + "MKK", "5G", "20M", "HT", "2T", "136", "30", + "FCC", "5G", "20M", "HT", "2T", "140", "26", + "ETSI", "5G", "20M", "HT", "2T", "140", "30", + "MKK", "5G", "20M", "HT", "2T", "140", "30", + "FCC", "5G", "20M", "HT", "2T", "149", "34", + "ETSI", "5G", "20M", "HT", "2T", "149", "30", + "MKK", "5G", "20M", "HT", "2T", "149", "63", + "FCC", "5G", "20M", "HT", "2T", "153", "34", + "ETSI", "5G", "20M", "HT", "2T", "153", "30", + "MKK", "5G", "20M", "HT", "2T", "153", "63", + "FCC", "5G", "20M", "HT", "2T", "157", "34", + "ETSI", "5G", "20M", "HT", "2T", "157", "30", + "MKK", "5G", "20M", "HT", "2T", "157", "63", + "FCC", "5G", "20M", "HT", "2T", "161", "34", + "ETSI", "5G", "20M", "HT", "2T", "161", "30", + "MKK", "5G", "20M", "HT", "2T", "161", "63", + "FCC", "5G", "20M", "HT", "2T", "165", "34", + "ETSI", "5G", "20M", "HT", "2T", "165", "30", + "MKK", "5G", "20M", "HT", "2T", "165", "63", + "FCC", "5G", "40M", "HT", "1T", "38", "30", + "ETSI", "5G", "40M", "HT", "1T", "38", "32", + "MKK", "5G", "40M", "HT", "1T", "38", "32", + "FCC", "5G", "40M", "HT", "1T", "46", "30", + "ETSI", "5G", "40M", "HT", "1T", "46", "32", + "MKK", "5G", "40M", "HT", "1T", "46", "32", + "FCC", "5G", "40M", "HT", "1T", "54", "32", + "ETSI", "5G", "40M", "HT", "1T", "54", "32", + "MKK", "5G", "40M", "HT", "1T", "54", "32", + "FCC", "5G", "40M", "HT", "1T", "62", "32", + "ETSI", "5G", "40M", "HT", "1T", "62", "32", + "MKK", "5G", "40M", "HT", "1T", "62", "32", + "FCC", "5G", "40M", "HT", "1T", "102", "28", + "ETSI", "5G", "40M", "HT", "1T", "102", "32", + "MKK", "5G", "40M", "HT", "1T", "102", "32", + "FCC", "5G", "40M", "HT", "1T", "110", "32", + "ETSI", "5G", "40M", "HT", "1T", "110", "32", + "MKK", "5G", "40M", "HT", "1T", "110", "32", + "FCC", "5G", "40M", "HT", "1T", "118", "34", + "ETSI", "5G", "40M", "HT", "1T", "118", "32", + "MKK", "5G", "40M", "HT", "1T", "118", "32", + "FCC", "5G", "40M", "HT", "1T", "126", "34", + "ETSI", "5G", "40M", "HT", "1T", "126", "32", + "MKK", "5G", "40M", "HT", "1T", "126", "32", + "FCC", "5G", "40M", "HT", "1T", "134", "32", + "ETSI", "5G", "40M", "HT", "1T", "134", "32", + "MKK", "5G", "40M", "HT", "1T", "134", "32", + "FCC", "5G", "40M", "HT", "1T", "151", "34", + "ETSI", "5G", "40M", "HT", "1T", "151", "32", + "MKK", "5G", "40M", "HT", "1T", "151", "63", + "FCC", "5G", "40M", "HT", "1T", "159", "34", + "ETSI", "5G", "40M", "HT", "1T", "159", "32", + "MKK", "5G", "40M", "HT", "1T", "159", "63", + "FCC", "5G", "40M", "HT", "2T", "38", "28", + "ETSI", "5G", "40M", "HT", "2T", "38", "30", + "MKK", "5G", "40M", "HT", "2T", "38", "30", + "FCC", "5G", "40M", "HT", "2T", "46", "28", + "ETSI", "5G", "40M", "HT", "2T", "46", "30", + "MKK", "5G", "40M", "HT", "2T", "46", "30", + "FCC", "5G", "40M", "HT", "2T", "54", "30", + "ETSI", "5G", "40M", "HT", "2T", "54", "30", + "MKK", "5G", "40M", "HT", "2T", "54", "30", + "FCC", "5G", "40M", "HT", "2T", "62", "30", + "ETSI", "5G", "40M", "HT", "2T", "62", "30", + "MKK", "5G", "40M", "HT", "2T", "62", "30", + "FCC", "5G", "40M", "HT", "2T", "102", "26", + "ETSI", "5G", "40M", "HT", "2T", "102", "30", + "MKK", "5G", "40M", "HT", "2T", "102", "30", + "FCC", "5G", "40M", "HT", "2T", "110", "30", + "ETSI", "5G", "40M", "HT", "2T", "110", "30", + "MKK", "5G", "40M", "HT", "2T", "110", "30", + "FCC", "5G", "40M", "HT", "2T", "118", "34", + "ETSI", "5G", "40M", "HT", "2T", "118", "30", + "MKK", "5G", "40M", "HT", "2T", "118", "30", + "FCC", "5G", "40M", "HT", "2T", "126", "32", + "ETSI", "5G", "40M", "HT", "2T", "126", "30", + "MKK", "5G", "40M", "HT", "2T", "126", "30", + "FCC", "5G", "40M", "HT", "2T", "134", "30", + "ETSI", "5G", "40M", "HT", "2T", "134", "30", + "MKK", "5G", "40M", "HT", "2T", "134", "30", + "FCC", "5G", "40M", "HT", "2T", "151", "34", + "ETSI", "5G", "40M", "HT", "2T", "151", "30", + "MKK", "5G", "40M", "HT", "2T", "151", "63", + "FCC", "5G", "40M", "HT", "2T", "159", "34", + "ETSI", "5G", "40M", "HT", "2T", "159", "30", + "MKK", "5G", "40M", "HT", "2T", "159", "63", + "FCC", "5G", "80M", "VHT", "1T", "42", "30", + "ETSI", "5G", "80M", "VHT", "1T", "42", "32", + "MKK", "5G", "80M", "VHT", "1T", "42", "32", + "FCC", "5G", "80M", "VHT", "1T", "58", "28", + "ETSI", "5G", "80M", "VHT", "1T", "58", "32", + "MKK", "5G", "80M", "VHT", "1T", "58", "32", + "FCC", "5G", "80M", "VHT", "1T", "106", "30", + "ETSI", "5G", "80M", "VHT", "1T", "106", "32", + "MKK", "5G", "80M", "VHT", "1T", "106", "32", + "FCC", "5G", "80M", "VHT", "1T", "122", "34", + "ETSI", "5G", "80M", "VHT", "1T", "122", "32", + "MKK", "5G", "80M", "VHT", "1T", "122", "32", + "FCC", "5G", "80M", "VHT", "1T", "155", "34", + "ETSI", "5G", "80M", "VHT", "1T", "155", "32", + "MKK", "5G", "80M", "VHT", "1T", "155", "63", + "FCC", "5G", "80M", "VHT", "2T", "42", "28", + "ETSI", "5G", "80M", "VHT", "2T", "42", "30", + "MKK", "5G", "80M", "VHT", "2T", "42", "30", + "FCC", "5G", "80M", "VHT", "2T", "58", "26", + "ETSI", "5G", "80M", "VHT", "2T", "58", "30", + "MKK", "5G", "80M", "VHT", "2T", "58", "30", + "FCC", "5G", "80M", "VHT", "2T", "106", "28", + "ETSI", "5G", "80M", "VHT", "2T", "106", "30", + "MKK", "5G", "80M", "VHT", "2T", "106", "30", + "FCC", "5G", "80M", "VHT", "2T", "122", "32", + "ETSI", "5G", "80M", "VHT", "2T", "122", "30", + "MKK", "5G", "80M", "VHT", "2T", "122", "30", + "FCC", "5G", "80M", "VHT", "2T", "155", "34", + "ETSI", "5G", "80M", "VHT", "2T", "155", "30", + "MKK", "5G", "80M", "VHT", "2T", "155", "63" +}; + +void +ODM_ReadAndConfig_MP_8188E_TXPWR_LMT( + IN PDM_ODM_T pDM_Odm + ) +{ + u4Byte i = 0; + u4Byte ArrayLen = sizeof(Array_MP_8188E_TXPWR_LMT)/sizeof(pu1Byte); + pu1Byte *Array = Array_MP_8188E_TXPWR_LMT; + + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ReadAndConfig_MP_8188E_TXPWR_LMT\n")); + + for (i = 0; i < ArrayLen; i += 7 ) + { + pu1Byte regulation = Array[i]; + pu1Byte band = Array[i+1]; + pu1Byte bandwidth = Array[i+2]; + pu1Byte rate = Array[i+3]; + pu1Byte rfPath = Array[i+4]; + pu1Byte chnl = Array[i+5]; + pu1Byte val = Array[i+6]; + + odm_ConfigBB_TXPWR_LMT_8188E(pDM_Odm, regulation, band, bandwidth, rate, rfPath, chnl, val); + } + +} + +#endif // end of HWIMG_SUPPORT + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.h new file mode 100644 index 0000000..bb186b4 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalHWImg8188E_RF.h @@ -0,0 +1,83 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + +#if (RTL8188E_SUPPORT == 1) +#ifndef __INC_MP_RF_HW_IMG_8188E_H +#define __INC_MP_RF_HW_IMG_8188E_H + +//static BOOLEAN CheckCondition(const u4Byte Condition, const u4Byte Hex); + +/****************************************************************************** +* RadioA_1T.TXT +******************************************************************************/ + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_RadioA_1T( // TC: Test Chip, MP: MP Chip + IN PDM_ODM_T pDM_Odm +); + +/****************************************************************************** +* RadioA_1T_ICUT.TXT +******************************************************************************/ + +HAL_STATUS +ODM_ReadAndConfig_MP_8188E_RadioA_1T_ICUT( // TC: Test Chip, MP: MP Chip + IN PDM_ODM_T pDM_Odm +); + +/****************************************************************************** +* TxPowerTrack_AP.TXT +******************************************************************************/ + +void +ODM_ReadAndConfig_MP_8188E_TxPowerTrack_AP( // TC: Test Chip, MP: MP Chip + IN PDM_ODM_T pDM_Odm +); + +/****************************************************************************** +* TxPowerTrack_PCIE.TXT +******************************************************************************/ + +void +ODM_ReadAndConfig_MP_8188E_TxPowerTrack_PCIE( // TC: Test Chip, MP: MP Chip + IN PDM_ODM_T pDM_Odm +); + +/****************************************************************************** +* TxPowerTrack_USB.TXT +******************************************************************************/ + +void +ODM_ReadAndConfig_MP_8188E_TxPowerTrack_USB( // TC: Test Chip, MP: MP Chip + IN PDM_ODM_T pDM_Odm +); + +/****************************************************************************** +* TXPWR_LMT.TXT +******************************************************************************/ + +void +ODM_ReadAndConfig_MP_8188E_TXPWR_LMT( // TC: Test Chip, MP: MP Chip + IN PDM_ODM_T pDM_Odm +); + +#endif +#endif // end of HWIMG_SUPPORT + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.c new file mode 100644 index 0000000..3a2e805 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.c @@ -0,0 +1,3299 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + + +#include "../odm_precomp.h" + + + +/*---------------------------Define Local Constant---------------------------*/ +// 2010/04/25 MH Define the max tx power tracking tx agc power. +#define ODM_TXPWRTRACK_MAX_IDX_88E 6 + +/*---------------------------Define Local Constant---------------------------*/ + + +//3============================================================ +//3 Tx Power Tracking +//3============================================================ + + +void setIqkMatrix_8188E( + PDM_ODM_T pDM_Odm, + u1Byte OFDM_index, + u1Byte RFPath, + s4Byte IqkResult_X, + s4Byte IqkResult_Y + ) +{ + s4Byte ele_A=0, ele_D, ele_C=0, value32; + + ele_D = (OFDMSwingTable_New[OFDM_index] & 0xFFC00000)>>22; + + //new element A = element D x X + if((IqkResult_X != 0) && (*(pDM_Odm->pBandType) == ODM_BAND_2_4G)) + { + if ((IqkResult_X & 0x00000200) != 0) //consider minus + IqkResult_X = IqkResult_X | 0xFFFFFC00; + ele_A = ((IqkResult_X * ele_D)>>8)&0x000003FF; + + //new element C = element D x Y + if ((IqkResult_Y & 0x00000200) != 0) + IqkResult_Y = IqkResult_Y | 0xFFFFFC00; + ele_C = ((IqkResult_Y * ele_D)>>8)&0x000003FF; + + //if (RFPath == ODM_RF_PATH_A) + switch (RFPath) + { + case ODM_RF_PATH_A: + //wirte new elements A, C, D to regC80 and regC94, element B is always 0 + value32 = (ele_D<<22)|((ele_C&0x3F)<<16)|ele_A; + ODM_SetBBReg(pDM_Odm, rOFDM0_XATxIQImbalance, bMaskDWord, value32); + + value32 = (ele_C&0x000003C0)>>6; + ODM_SetBBReg(pDM_Odm, rOFDM0_XCTxAFE, bMaskH4Bits, value32); + + value32 = ((IqkResult_X * ele_D)>>7)&0x01; + ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT24, value32); + break; + case ODM_RF_PATH_B: + //wirte new elements A, C, D to regC88 and regC9C, element B is always 0 + value32=(ele_D<<22)|((ele_C&0x3F)<<16) |ele_A; + ODM_SetBBReg(pDM_Odm, rOFDM0_XBTxIQImbalance, bMaskDWord, value32); + + value32 = (ele_C&0x000003C0)>>6; + ODM_SetBBReg(pDM_Odm, rOFDM0_XDTxAFE, bMaskH4Bits, value32); + + value32 = ((IqkResult_X * ele_D)>>7)&0x01; + ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT28, value32); + + break; + default: + break; + } + } + else + { + switch (RFPath) + { + case ODM_RF_PATH_A: + ODM_SetBBReg(pDM_Odm, rOFDM0_XATxIQImbalance, bMaskDWord, OFDMSwingTable_New[OFDM_index]); + ODM_SetBBReg(pDM_Odm, rOFDM0_XCTxAFE, bMaskH4Bits, 0x00); + ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT24, 0x00); + break; + + case ODM_RF_PATH_B: + ODM_SetBBReg(pDM_Odm, rOFDM0_XBTxIQImbalance, bMaskDWord, OFDMSwingTable_New[OFDM_index]); + ODM_SetBBReg(pDM_Odm, rOFDM0_XDTxAFE, bMaskH4Bits, 0x00); + ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT28, 0x00); + break; + + default: + break; + } + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("TxPwrTracking path B: X = 0x%x, Y = 0x%x ele_A = 0x%x ele_C = 0x%x ele_D = 0x%x 0xeb4 = 0x%x 0xebc = 0x%x\n", + (u4Byte)IqkResult_X, (u4Byte)IqkResult_Y, (u4Byte)ele_A, (u4Byte)ele_C, (u4Byte)ele_D, (u4Byte)IqkResult_X, (u4Byte)IqkResult_Y)); +} + +void DoIQK_8188E( + PDM_ODM_T pDM_Odm, + u1Byte DeltaThermalIndex, + u1Byte ThermalValue, + u1Byte Threshold + ) +{ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + PADAPTER Adapter = pDM_Odm->Adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); +#endif + + ODM_ResetIQKResult(pDM_Odm); + +#if(DM_ODM_SUPPORT_TYPE & ODM_WIN) +#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) +#if USE_WORKITEM + PlatformAcquireMutex(&pHalData->mxChnlBwControl); +#else + PlatformAcquireSpinLock(Adapter, RT_CHANNEL_AND_BANDWIDTH_SPINLOCK); +#endif +#elif((DEV_BUS_TYPE == RT_USB_INTERFACE) || (DEV_BUS_TYPE == RT_SDIO_INTERFACE)) + PlatformAcquireMutex(&pHalData->mxChnlBwControl); +#endif +#endif + + + pDM_Odm->RFCalibrateInfo.ThermalValue_IQK= ThermalValue; +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + PHY_IQCalibrate_8188E(pDM_Odm, FALSE); +#else + PHY_IQCalibrate_8188E(Adapter, FALSE); +#endif + +#if(DM_ODM_SUPPORT_TYPE & ODM_WIN) +#if (DEV_BUS_TYPE == RT_PCI_INTERFACE) +#if USE_WORKITEM + PlatformReleaseMutex(&pHalData->mxChnlBwControl); +#else + PlatformReleaseSpinLock(Adapter, RT_CHANNEL_AND_BANDWIDTH_SPINLOCK); +#endif +#elif((DEV_BUS_TYPE == RT_USB_INTERFACE) || (DEV_BUS_TYPE == RT_SDIO_INTERFACE)) + PlatformReleaseMutex(&pHalData->mxChnlBwControl); +#endif +#endif +} + +/*----------------------------------------------------------------------------- + * Function: odm_TxPwrTrackSetPwr88E() + * + * Overview: 88E change all channel tx power accordign to flag. + * OFDM & CCK are all different. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 04/23/2012 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +VOID +ODM_TxPwrTrackSetPwr88E( + PDM_ODM_T pDM_Odm, + PWRTRACK_METHOD Method, + u1Byte RFPath, + u1Byte ChannelMappedIndex + ) +{ + PADAPTER Adapter = pDM_Odm->Adapter; + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); + u1Byte PwrTrackingLimit_OFDM = 30; //+0dB + u1Byte PwrTrackingLimit_CCK= 28; //-2dB + u1Byte TxRate = 0xFF; + u1Byte Final_OFDM_Swing_Index = 0; + u1Byte Final_CCK_Swing_Index = 0; + u1Byte i = 0; + +#if (MP_DRIVER==1) + if ( *(pDM_Odm->mp_mode) == 1) + { +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE )) + #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) + PMPT_CONTEXT pMptCtx = &(Adapter->MptCtx); + #elif (DM_ODM_SUPPORT_TYPE & (ODM_CE)) + PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.MptCtx); + #endif + TxRate = MptToMgntRate(pMptCtx->MptRateIndex); +#endif + } + else +#endif + { + u2Byte rate = *(pDM_Odm->pForcedDataRate); + + if(!rate) //auto rate + { + if(pDM_Odm->TxRate != 0xFF) + #if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) + TxRate = Adapter->HalFunc.GetHwRateFromMRateHandler(pDM_Odm->TxRate); + #elif (DM_ODM_SUPPORT_TYPE & (ODM_CE)) + TxRate = HwRateToMRate(pDM_Odm->TxRate); + #endif + } + else //force rate + { + TxRate = (u1Byte)rate; + } + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("===>ODM_TxPwrTrackSetPwr8723B\n")); + + if(TxRate != 0xFF) + { + //2 CCK + if((TxRate >= MGN_1M)&&(TxRate <= MGN_11M)) + PwrTrackingLimit_CCK = 28; //-2dB + //2 OFDM + else if((TxRate >= MGN_6M)&&(TxRate <= MGN_48M)) + PwrTrackingLimit_OFDM= 36; //+3dB + else if(TxRate == MGN_54M) + PwrTrackingLimit_OFDM= 34; //+2dB + + //2 HT + else if((TxRate >= MGN_MCS0)&&(TxRate <= MGN_MCS2)) //QPSK/BPSK + PwrTrackingLimit_OFDM= 38; //+4dB + else if((TxRate >= MGN_MCS3)&&(TxRate <= MGN_MCS4)) //16QAM + PwrTrackingLimit_OFDM= 36; //+3dB + else if((TxRate >= MGN_MCS5)&&(TxRate <= MGN_MCS7)) //64QAM + PwrTrackingLimit_OFDM= 34; //+2dB + + else + PwrTrackingLimit_OFDM = pDM_Odm->DefaultOfdmIndex; //Default OFDM index = 30 + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("TxRate=0x%x, PwrTrackingLimit=%d\n", TxRate, PwrTrackingLimit_OFDM)); + + if (Method == TXAGC) + { + u4Byte pwr = 0, TxAGC = 0; + PADAPTER Adapter = pDM_Odm->Adapter; + + pDM_Odm->Remnant_OFDMSwingIdx[RFPath] = pDM_Odm->Absolute_OFDMSwingIdx[RFPath]; //Remnant index equal to aboslute compensate value. + + ODM_RT_TRACE(pDM_Odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("odm_TxPwrTrackSetPwr88E CH=%d\n", *(pDM_Odm->pChannel))); + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE )) + + #if (MP_DRIVER == 1) + if ( *(pDM_Odm->mp_mode) == 1) + { + pwr = PHY_QueryBBReg(Adapter, rTxAGC_A_Rate18_06, 0xFF); + pwr += pDM_Odm->RFCalibrateInfo.PowerIndexOffset[ODM_RF_PATH_A]; + PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, pwr); + TxAGC = (pwr<<16)|(pwr<<8)|(pwr); + PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, TxAGC); + //RT_DISP(FPHY, PHY_TXPWR, ("ODM_TxPwrTrackSetPwr88E: CCK Tx-rf(A) Power = 0x%x\n", TxAGC)); + + pwr = PHY_QueryBBReg(Adapter, rTxAGC_A_Rate18_06, 0xFF); + pwr += (pDM_Odm->BbSwingIdxOfdm[ODM_RF_PATH_A] - pDM_Odm->BbSwingIdxOfdmBase[RF_PATH_A]); + TxAGC |= ((pwr<<24)|(pwr<<16)|(pwr<<8)|pwr); + PHY_SetBBReg(Adapter, rTxAGC_A_Rate18_06, bMaskDWord, TxAGC); + PHY_SetBBReg(Adapter, rTxAGC_A_Rate54_24, bMaskDWord, TxAGC); + PHY_SetBBReg(Adapter, rTxAGC_A_Mcs03_Mcs00, bMaskDWord, TxAGC); + PHY_SetBBReg(Adapter, rTxAGC_A_Mcs07_Mcs04, bMaskDWord, TxAGC); + PHY_SetBBReg(Adapter, rTxAGC_A_Mcs11_Mcs08, bMaskDWord, TxAGC); + PHY_SetBBReg(Adapter, rTxAGC_A_Mcs15_Mcs12, bMaskDWord, TxAGC); + //RT_DISP(FPHY, PHY_TXPWR, ("ODM_TxPwrTrackSetPwr88E: OFDM Tx-rf(A) Power = 0x%x\n", TxAGC)); + } + else + #endif + { + //PHY_SetTxPowerLevel8188E(pDM_Odm->Adapter, *pDM_Odm->pChannel); + pDM_Odm->Modify_TxAGC_Flag_PathA = TRUE; + pDM_Odm->Modify_TxAGC_Flag_PathA_CCK = TRUE; + + if (RFPath == ODM_RF_PATH_A) + { + PHY_SetTxPowerIndexByRateSection(Adapter, ODM_RF_PATH_A, pHalData->CurrentChannel, CCK ); + PHY_SetTxPowerIndexByRateSection(Adapter, ODM_RF_PATH_A, pHalData->CurrentChannel, OFDM ); + PHY_SetTxPowerIndexByRateSection(Adapter, ODM_RF_PATH_A, pHalData->CurrentChannel, HT_MCS0_MCS7 ); + } + } + + +#endif +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + //PHY_RF6052SetCCKTxPower(pDM_Odm->priv, *(pDM_Odm->pChannel)); + //PHY_RF6052SetOFDMTxPower(pDM_Odm->priv, *(pDM_Odm->pChannel)); +#endif + + } + else if (Method == BBSWING) + { + Final_OFDM_Swing_Index = pDM_Odm->DefaultOfdmIndex + pDM_Odm->Absolute_OFDMSwingIdx[RFPath]; + Final_CCK_Swing_Index = pDM_Odm->DefaultCckIndex + pDM_Odm->Absolute_OFDMSwingIdx[RFPath]; + + if (Final_OFDM_Swing_Index >= PwrTrackingLimit_OFDM) + Final_OFDM_Swing_Index = PwrTrackingLimit_OFDM; + else if (Final_OFDM_Swing_Index < 0) + Final_OFDM_Swing_Index = 0; + + if (Final_CCK_Swing_Index >= CCK_TABLE_SIZE) + Final_CCK_Swing_Index = CCK_TABLE_SIZE-1; + else if (pDM_Odm->BbSwingIdxCck < 0) + Final_CCK_Swing_Index = 0; + + // Adjust BB swing by OFDM IQ matrix + if (RFPath == ODM_RF_PATH_A) + { + setIqkMatrix_8188E(pDM_Odm, Final_OFDM_Swing_Index, ODM_RF_PATH_A, + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][0], + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][1]); + // Adjust BB swing by CCK filter coefficient + if(!pDM_Odm->RFCalibrateInfo.bCCKinCH14){ + ODM_Write1Byte(pDM_Odm, 0xa22, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][0]); + ODM_Write1Byte(pDM_Odm, 0xa23, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][1]); + ODM_Write1Byte(pDM_Odm, 0xa24, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][2]); + ODM_Write1Byte(pDM_Odm, 0xa25, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][3]); + ODM_Write1Byte(pDM_Odm, 0xa26, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][4]); + ODM_Write1Byte(pDM_Odm, 0xa27, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][5]); + ODM_Write1Byte(pDM_Odm, 0xa28, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][6]); + ODM_Write1Byte(pDM_Odm, 0xa29, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][7]); + } + else + { + ODM_Write1Byte(pDM_Odm, 0xa22, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][0]); + ODM_Write1Byte(pDM_Odm, 0xa23, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][1]); + ODM_Write1Byte(pDM_Odm, 0xa24, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][2]); + ODM_Write1Byte(pDM_Odm, 0xa25, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][3]); + ODM_Write1Byte(pDM_Odm, 0xa26, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][4]); + ODM_Write1Byte(pDM_Odm, 0xa27, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][5]); + ODM_Write1Byte(pDM_Odm, 0xa28, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][6]); + ODM_Write1Byte(pDM_Odm, 0xa29, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][7]); + } + } + } + else if (Method == MIX_MODE) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("pDM_Odm->DefaultOfdmIndex=%d, pDM_Odm->DefaultCCKIndex=%d, pDM_Odm->Absolute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n", + pDM_Odm->DefaultOfdmIndex, pDM_Odm->DefaultCckIndex, pDM_Odm->Absolute_OFDMSwingIdx[RFPath],RFPath )); + + Final_CCK_Swing_Index = pDM_Odm->DefaultCckIndex + pDM_Odm->Absolute_OFDMSwingIdx[RFPath]; + Final_OFDM_Swing_Index = pDM_Odm->DefaultOfdmIndex + pDM_Odm->Absolute_OFDMSwingIdx[RFPath]; + + if(Final_OFDM_Swing_Index > PwrTrackingLimit_OFDM ) //BBSwing higher then Limit + { + pDM_Odm->Remnant_OFDMSwingIdx[RFPath] = Final_OFDM_Swing_Index - PwrTrackingLimit_OFDM; + + setIqkMatrix_8188E(pDM_Odm, PwrTrackingLimit_OFDM, ODM_RF_PATH_A, + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][0], + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][1]); + + pDM_Odm->Modify_TxAGC_Flag_PathA = TRUE; + + PHY_SetTxPowerIndexByRateSection(Adapter, ODM_RF_PATH_A, pHalData->CurrentChannel, OFDM ); + PHY_SetTxPowerIndexByRateSection(Adapter, ODM_RF_PATH_A, pHalData->CurrentChannel, HT_MCS0_MCS7 ); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("******Path_A Over BBSwing Limit , PwrTrackingLimit = %d , Remnant TxAGC Value = %d \n", PwrTrackingLimit_OFDM, pDM_Odm->Remnant_OFDMSwingIdx[RFPath])); + } + else if (Final_OFDM_Swing_Index < 0) + { + pDM_Odm->Remnant_OFDMSwingIdx[RFPath] = Final_OFDM_Swing_Index; + + setIqkMatrix_8188E(pDM_Odm, 0, ODM_RF_PATH_A, + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][0], + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][1]); + + pDM_Odm->Modify_TxAGC_Flag_PathA = TRUE; + + PHY_SetTxPowerIndexByRateSection(Adapter, ODM_RF_PATH_A, pHalData->CurrentChannel, OFDM ); + PHY_SetTxPowerIndexByRateSection(Adapter, ODM_RF_PATH_A, pHalData->CurrentChannel, HT_MCS0_MCS7 ); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("******Path_A Lower then BBSwing lower bound 0 , Remnant TxAGC Value = %d \n", pDM_Odm->Remnant_OFDMSwingIdx[RFPath])); + } + else + { + setIqkMatrix_8188E(pDM_Odm, Final_OFDM_Swing_Index, ODM_RF_PATH_A, + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][0], + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[ChannelMappedIndex].Value[0][1]); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("******Path_A Compensate with BBSwing , Final_OFDM_Swing_Index = %d \n", Final_OFDM_Swing_Index)); + + if(pDM_Odm->Modify_TxAGC_Flag_PathA) //If TxAGC has changed, reset TxAGC again + { + pDM_Odm->Remnant_OFDMSwingIdx[RFPath] = 0; + + PHY_SetTxPowerIndexByRateSection(Adapter, ODM_RF_PATH_A, pHalData->CurrentChannel, OFDM ); + PHY_SetTxPowerIndexByRateSection(Adapter, ODM_RF_PATH_A, pHalData->CurrentChannel, HT_MCS0_MCS7 ); + + pDM_Odm->Modify_TxAGC_Flag_PathA = FALSE; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("******Path_A pDM_Odm->Modify_TxAGC_Flag = FALSE \n")); + } + } + + if(Final_CCK_Swing_Index > PwrTrackingLimit_CCK) + { + pDM_Odm->Remnant_CCKSwingIdx = Final_CCK_Swing_Index - PwrTrackingLimit_CCK; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("******Path_A CCK Over Limit , PwrTrackingLimit_CCK = %d , pDM_Odm->Remnant_CCKSwingIdx = %d \n", PwrTrackingLimit_CCK, pDM_Odm->Remnant_CCKSwingIdx)); + + // Adjust BB swing by CCK filter coefficient + + if(!pDM_Odm->RFCalibrateInfo.bCCKinCH14) + { + ODM_Write1Byte(pDM_Odm, 0xa22, CCKSwingTable_Ch1_Ch13_New[PwrTrackingLimit_CCK][0]); + ODM_Write1Byte(pDM_Odm, 0xa23, CCKSwingTable_Ch1_Ch13_New[PwrTrackingLimit_CCK][1]); + ODM_Write1Byte(pDM_Odm, 0xa24, CCKSwingTable_Ch1_Ch13_New[PwrTrackingLimit_CCK][2]); + ODM_Write1Byte(pDM_Odm, 0xa25, CCKSwingTable_Ch1_Ch13_New[PwrTrackingLimit_CCK][3]); + ODM_Write1Byte(pDM_Odm, 0xa26, CCKSwingTable_Ch1_Ch13_New[PwrTrackingLimit_CCK][4]); + ODM_Write1Byte(pDM_Odm, 0xa27, CCKSwingTable_Ch1_Ch13_New[PwrTrackingLimit_CCK][5]); + ODM_Write1Byte(pDM_Odm, 0xa28, CCKSwingTable_Ch1_Ch13_New[PwrTrackingLimit_CCK][6]); + ODM_Write1Byte(pDM_Odm, 0xa29, CCKSwingTable_Ch1_Ch13_New[PwrTrackingLimit_CCK][7]); + } + else + { + ODM_Write1Byte(pDM_Odm, 0xa22, CCKSwingTable_Ch14_New[PwrTrackingLimit_CCK][0]); + ODM_Write1Byte(pDM_Odm, 0xa23, CCKSwingTable_Ch14_New[PwrTrackingLimit_CCK][1]); + ODM_Write1Byte(pDM_Odm, 0xa24, CCKSwingTable_Ch14_New[PwrTrackingLimit_CCK][2]); + ODM_Write1Byte(pDM_Odm, 0xa25, CCKSwingTable_Ch14_New[PwrTrackingLimit_CCK][3]); + ODM_Write1Byte(pDM_Odm, 0xa26, CCKSwingTable_Ch14_New[PwrTrackingLimit_CCK][4]); + ODM_Write1Byte(pDM_Odm, 0xa27, CCKSwingTable_Ch14_New[PwrTrackingLimit_CCK][5]); + ODM_Write1Byte(pDM_Odm, 0xa28, CCKSwingTable_Ch14_New[PwrTrackingLimit_CCK][6]); + ODM_Write1Byte(pDM_Odm, 0xa29, CCKSwingTable_Ch14_New[PwrTrackingLimit_CCK][7]); + } + + pDM_Odm->Modify_TxAGC_Flag_PathA_CCK = TRUE; + + PHY_SetTxPowerIndexByRateSection(Adapter, ODM_RF_PATH_A, pHalData->CurrentChannel, CCK ); + + } + else if(Final_CCK_Swing_Index < 0) // Lowest CCK Index = 0 + { + pDM_Odm->Remnant_CCKSwingIdx = Final_CCK_Swing_Index; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("******Path_A CCK Under Limit , PwrTrackingLimit_CCK = %d , pDM_Odm->Remnant_CCKSwingIdx = %d \n", 0, pDM_Odm->Remnant_CCKSwingIdx)); + + if(!pDM_Odm->RFCalibrateInfo.bCCKinCH14) + { + ODM_Write1Byte(pDM_Odm, 0xa22, CCKSwingTable_Ch1_Ch13_New[0][0]); + ODM_Write1Byte(pDM_Odm, 0xa23, CCKSwingTable_Ch1_Ch13_New[0][1]); + ODM_Write1Byte(pDM_Odm, 0xa24, CCKSwingTable_Ch1_Ch13_New[0][2]); + ODM_Write1Byte(pDM_Odm, 0xa25, CCKSwingTable_Ch1_Ch13_New[0][3]); + ODM_Write1Byte(pDM_Odm, 0xa26, CCKSwingTable_Ch1_Ch13_New[0][4]); + ODM_Write1Byte(pDM_Odm, 0xa27, CCKSwingTable_Ch1_Ch13_New[0][5]); + ODM_Write1Byte(pDM_Odm, 0xa28, CCKSwingTable_Ch1_Ch13_New[0][6]); + ODM_Write1Byte(pDM_Odm, 0xa29, CCKSwingTable_Ch1_Ch13_New[0][7]); + } + else + { + ODM_Write1Byte(pDM_Odm, 0xa22, CCKSwingTable_Ch14_New[0][0]); + ODM_Write1Byte(pDM_Odm, 0xa23, CCKSwingTable_Ch14_New[0][1]); + ODM_Write1Byte(pDM_Odm, 0xa24, CCKSwingTable_Ch14_New[0][2]); + ODM_Write1Byte(pDM_Odm, 0xa25, CCKSwingTable_Ch14_New[0][3]); + ODM_Write1Byte(pDM_Odm, 0xa26, CCKSwingTable_Ch14_New[0][4]); + ODM_Write1Byte(pDM_Odm, 0xa27, CCKSwingTable_Ch14_New[0][5]); + ODM_Write1Byte(pDM_Odm, 0xa28, CCKSwingTable_Ch14_New[0][6]); + ODM_Write1Byte(pDM_Odm, 0xa29, CCKSwingTable_Ch14_New[0][7]); + } + + pDM_Odm->Modify_TxAGC_Flag_PathA_CCK = TRUE; + + PHY_SetTxPowerIndexByRateSection(Adapter, ODM_RF_PATH_A, pHalData->CurrentChannel, CCK ); + + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("******Path_A CCK Compensate with BBSwing , Final_CCK_Swing_Index = %d \n", Final_CCK_Swing_Index)); + + if(!pDM_Odm->RFCalibrateInfo.bCCKinCH14) + { + ODM_Write1Byte(pDM_Odm, 0xa22, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][0]); + ODM_Write1Byte(pDM_Odm, 0xa23, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][1]); + ODM_Write1Byte(pDM_Odm, 0xa24, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][2]); + ODM_Write1Byte(pDM_Odm, 0xa25, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][3]); + ODM_Write1Byte(pDM_Odm, 0xa26, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][4]); + ODM_Write1Byte(pDM_Odm, 0xa27, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][5]); + ODM_Write1Byte(pDM_Odm, 0xa28, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][6]); + ODM_Write1Byte(pDM_Odm, 0xa29, CCKSwingTable_Ch1_Ch13_New[Final_CCK_Swing_Index][7]); + } + else + { + ODM_Write1Byte(pDM_Odm, 0xa22, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][0]); + ODM_Write1Byte(pDM_Odm, 0xa23, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][1]); + ODM_Write1Byte(pDM_Odm, 0xa24, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][2]); + ODM_Write1Byte(pDM_Odm, 0xa25, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][3]); + ODM_Write1Byte(pDM_Odm, 0xa26, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][4]); + ODM_Write1Byte(pDM_Odm, 0xa27, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][5]); + ODM_Write1Byte(pDM_Odm, 0xa28, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][6]); + ODM_Write1Byte(pDM_Odm, 0xa29, CCKSwingTable_Ch14_New[Final_CCK_Swing_Index][7]); + } + + if(pDM_Odm->Modify_TxAGC_Flag_PathA_CCK) //If TxAGC has changed, reset TxAGC again + { + pDM_Odm->Remnant_CCKSwingIdx = 0; + PHY_SetTxPowerIndexByRateSection(Adapter, ODM_RF_PATH_A, pHalData->CurrentChannel, CCK ); + pDM_Odm->Modify_TxAGC_Flag_PathA_CCK= FALSE; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("******Path_A pDM_Odm->Modify_TxAGC_Flag_CCK = FALSE \n")); + } + } + } + else + { + return; + } +} // odm_TxPwrTrackSetPwr88E + +VOID +GetDeltaSwingTable_8188E( + IN PDM_ODM_T pDM_Odm, + OUT pu1Byte *TemperatureUP_A, + OUT pu1Byte *TemperatureDOWN_A, + OUT pu1Byte *TemperatureUP_B, + OUT pu1Byte *TemperatureDOWN_B + ) +{ + *TemperatureUP_A = (pu1Byte)DeltaSwingTableIdx_2GA_P_8188E; + *TemperatureDOWN_A = (pu1Byte)DeltaSwingTableIdx_2GA_N_8188E; + *TemperatureUP_B = (pu1Byte)DeltaSwingTableIdx_2GA_P_8188E; + *TemperatureDOWN_B = (pu1Byte)DeltaSwingTableIdx_2GA_N_8188E; +} + +void ConfigureTxpowerTrack_8188E( + PTXPWRTRACK_CFG pConfig + ) +{ + pConfig->SwingTableSize_CCK = CCK_TABLE_SIZE; + pConfig->SwingTableSize_OFDM = OFDM_TABLE_SIZE; + pConfig->Threshold_IQK = IQK_THRESHOLD; + pConfig->AverageThermalNum = AVG_THERMAL_NUM_88E; + pConfig->RfPathCount = MAX_PATH_NUM_8188E; + pConfig->ThermalRegAddr = RF_T_METER_88E; + + pConfig->ODM_TxPwrTrackSetPwr = ODM_TxPwrTrackSetPwr88E; + pConfig->DoIQK = DoIQK_8188E; + pConfig->PHY_LCCalibrate = PHY_LCCalibrate_8188E; + pConfig->GetDeltaSwingTable = GetDeltaSwingTable_8188E; +} + +//1 7. IQK +#define MAX_TOLERANCE 5 +#define IQK_DELAY_TIME 1 //ms + +u1Byte //bit0 = 1 => Tx OK, bit1 = 1 => Rx OK +phy_PathA_IQK_8188E( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN BOOLEAN configPathB + ) +{ + u4Byte regEAC, regE94, regE9C, regEA4; + u1Byte result = 0x00; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK!\n")); + + //1 Tx IQK + //path-A IQK setting + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A IQK setting!\n")); + ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1c); + ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x30008c1c); + ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x8214032a); + ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28160000); + + //LO calibration setting + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x00462911); + + //One shot, path A LOK & IQK + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); + + // delay x ms + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); + //PlatformStallExecution(IQK_DELAY_TIME_88E*1000); + ODM_delay_ms(IQK_DELAY_TIME_88E); + + // Check failed + regEAC = ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_A_2, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); + regE94 = ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_A, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x\n", regE94)); + regE9C= ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_A, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe9c = 0x%x\n", regE9C)); + regEA4= ODM_GetBBReg(pDM_Odm, rRx_Power_Before_IQK_A_2, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea4 = 0x%x\n", regEA4)); + + if(!(regEAC & BIT28) && + (((regE94 & 0x03FF0000)>>16) != 0x142) && + (((regE9C & 0x03FF0000)>>16) != 0x42) ) + result |= 0x01; + else //if Tx not OK, ignore Rx + return result; + +#if 0 + if(!(regEAC & BIT27) && //if Tx is OK, check whether Rx is OK + (((regEA4 & 0x03FF0000)>>16) != 0x132) && + (((regEAC & 0x03FF0000)>>16) != 0x36)) + result |= 0x02; + else + RT_DISP(FINIT, INIT_IQK, ("Path A Rx IQK fail!!\n")); +#endif + + return result; + + + } + +u1Byte //bit0 = 1 => Tx OK, bit1 = 1 => Rx OK +phy_PathA_RxIQK( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN BOOLEAN configPathB + ) +{ + u4Byte regEAC, regE94, regE9C, regEA4, u4tmp; + u1Byte result = 0x00; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK!\n")); + + //1 Get TXIMR setting + //modify RXIQK mode table + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table!\n")); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_WE_LUT, bRFRegOffsetMask, 0x800a0 ); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000 ); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0000f ); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf117B ); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000); + + //IQK setting + ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, 0x01007c00); + ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x81004800); + + //path-A IQK setting + ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1c); + ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x30008c1c); + ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x82160804); + ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28160000); + + //LO calibration setting + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911); + + //One shot, path A LOK & IQK + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); + + // delay x ms + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); + //PlatformStallExecution(IQK_DELAY_TIME_88E*1000); + ODM_delay_ms(IQK_DELAY_TIME_88E); + + + // Check failed + regEAC = ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_A_2, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); + regE94 = ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_A, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x\n", regE94)); + regE9C= ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_A, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe9c = 0x%x\n", regE9C)); + + if(!(regEAC & BIT28) && + (((regE94 & 0x03FF0000)>>16) != 0x142) && + (((regE9C & 0x03FF0000)>>16) != 0x42) ) + result |= 0x01; + else //if Tx not OK, ignore Rx + return result; + + u4tmp = 0x80007C00 | (regE94&0x3FF0000) | ((regE9C&0x3FF0000) >> 16); + ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, u4tmp); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe40 = 0x%x u4tmp = 0x%x \n", ODM_GetBBReg(pDM_Odm, rTx_IQK, bMaskDWord), u4tmp)); + + + //1 RX IQK + //modify RXIQK mode table + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A Rx IQK modify RXIQK mode table 2!\n")); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_WE_LUT, bRFRegOffsetMask, 0x800a0 ); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_RCK_OS, bRFRegOffsetMask, 0x30000 ); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_TXPA_G1, bRFRegOffsetMask, 0x0000f ); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_TXPA_G2, bRFRegOffsetMask, 0xf7ffa ); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000); + + //IQK setting + ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x01004800); + + //path-A IQK setting + ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x30008c1c); + ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x10008c1c); + ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x82160c05); + ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28160c05); + + //LO calibration setting + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LO calibration setting!\n")); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x0046a911); + + //One shot, path A LOK & IQK + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf9000000); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000); + + // delay x ms + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME_88E)); + //PlatformStallExecution(IQK_DELAY_TIME_88E*1000); + ODM_delay_ms(IQK_DELAY_TIME_88E); + + // Check failed + regEAC = ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_A_2, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); + regE94 = ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_A, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe94 = 0x%x\n", regE94)); + regE9C= ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_A, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xe9c = 0x%x\n", regE9C)); + regEA4= ODM_GetBBReg(pDM_Odm, rRx_Power_Before_IQK_A_2, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xea4 = 0x%x\n", regEA4)); + +#if 0 + if(!(regEAC & BIT28) && + (((regE94 & 0x03FF0000)>>16) != 0x142) && + (((regE9C & 0x03FF0000)>>16) != 0x42) ) + result |= 0x01; + else //if Tx not OK, ignore Rx + return result; +#endif + + if(!(regEAC & BIT27) && //if Tx is OK, check whether Rx is OK + (((regEA4 & 0x03FF0000)>>16) != 0x132) && + (((regEAC & 0x03FF0000)>>16) != 0x36)) + result |= 0x02; + else + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK fail!!\n")); + + return result; + + +} + +u1Byte //bit0 = 1 => Tx OK, bit1 = 1 => Rx OK +phy_PathB_IQK_8188E( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm +#else + IN PADAPTER pAdapter +#endif + ) +{ + u4Byte regEAC, regEB4, regEBC, regEC4, regECC; + u1Byte result = 0x00; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK!\n")); + + //One shot, path B LOK & IQK + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("One shot, path A LOK & IQK!\n")); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Cont, bMaskDWord, 0x00000002); + ODM_SetBBReg(pDM_Odm, rIQK_AGC_Cont, bMaskDWord, 0x00000000); + + // delay x ms + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Delay %d ms for One shot, path B LOK & IQK.\n", IQK_DELAY_TIME_88E)); + //PlatformStallExecution(IQK_DELAY_TIME_88E*1000); + ODM_delay_ms(IQK_DELAY_TIME_88E); + + // Check failed + regEAC = ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_A_2, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeac = 0x%x\n", regEAC)); + regEB4 = ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_B, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xeb4 = 0x%x\n", regEB4)); + regEBC= ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_B, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xebc = 0x%x\n", regEBC)); + regEC4= ODM_GetBBReg(pDM_Odm, rRx_Power_Before_IQK_B_2, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xec4 = 0x%x\n", regEC4)); + regECC= ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_B_2, bMaskDWord); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xecc = 0x%x\n", regECC)); + + if(!(regEAC & BIT31) && + (((regEB4 & 0x03FF0000)>>16) != 0x142) && + (((regEBC & 0x03FF0000)>>16) != 0x42)) + result |= 0x01; + else + return result; + + if(!(regEAC & BIT30) && + (((regEC4 & 0x03FF0000)>>16) != 0x132) && + (((regECC & 0x03FF0000)>>16) != 0x36)) + result |= 0x02; + else + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Rx IQK fail!!\n")); + + + return result; + +} + +VOID +_PHY_PathAFillIQKMatrix( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN BOOLEAN bIQKOK, + IN s4Byte result[][8], + IN u1Byte final_candidate, + IN BOOLEAN bTxOnly + ) +{ + u4Byte Oldval_0, X, TX0_A, reg; + s4Byte Y, TX0_C; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQ Calibration %s !\n",(bIQKOK)?"Success":"Failed")); + + if(final_candidate == 0xFF) + return; + + else if(bIQKOK) + { + Oldval_0 = (ODM_GetBBReg(pDM_Odm, rOFDM0_XATxIQImbalance, bMaskDWord) >> 22) & 0x3FF; + + X = result[final_candidate][0]; + if ((X & 0x00000200) != 0) + X = X | 0xFFFFFC00; + TX0_A = (X * Oldval_0) >> 8; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("X = 0x%x, TX0_A = 0x%x, Oldval_0 0x%x\n", X, TX0_A, Oldval_0)); + ODM_SetBBReg(pDM_Odm, rOFDM0_XATxIQImbalance, 0x3FF, TX0_A); + + ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT(31), ((X* Oldval_0>>7) & 0x1)); + + Y = result[final_candidate][1]; + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + + + TX0_C = (Y * Oldval_0) >> 8; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Y = 0x%x, TX = 0x%x\n", Y, TX0_C)); + ODM_SetBBReg(pDM_Odm, rOFDM0_XCTxAFE, 0xF0000000, ((TX0_C&0x3C0)>>6)); + ODM_SetBBReg(pDM_Odm, rOFDM0_XATxIQImbalance, 0x003F0000, (TX0_C&0x3F)); + + ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT(29), ((Y* Oldval_0>>7) & 0x1)); + + if(bTxOnly) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("_PHY_PathAFillIQKMatrix only Tx OK\n")); + return; + } + + reg = result[final_candidate][2]; +#if (DM_ODM_SUPPORT_TYPE==ODM_AP) + if( RTL_ABS(reg ,0x100) >= 16) + reg = 0x100; +#endif + ODM_SetBBReg(pDM_Odm, rOFDM0_XARxIQImbalance, 0x3FF, reg); + + reg = result[final_candidate][3] & 0x3F; + ODM_SetBBReg(pDM_Odm, rOFDM0_XARxIQImbalance, 0xFC00, reg); + + reg = (result[final_candidate][3] >> 6) & 0xF; + ODM_SetBBReg(pDM_Odm, rOFDM0_RxIQExtAnta, 0xF0000000, reg); + } +} + +VOID +_PHY_PathBFillIQKMatrix( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN BOOLEAN bIQKOK, + IN s4Byte result[][8], + IN u1Byte final_candidate, + IN BOOLEAN bTxOnly //do Tx only + ) +{ + u4Byte Oldval_1, X, TX1_A, reg; + s4Byte Y, TX1_C; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQ Calibration %s !\n",(bIQKOK)?"Success":"Failed")); + + if(final_candidate == 0xFF) + return; + + else if(bIQKOK) + { + Oldval_1 = (ODM_GetBBReg(pDM_Odm, rOFDM0_XBTxIQImbalance, bMaskDWord) >> 22) & 0x3FF; + + X = result[final_candidate][4]; + if ((X & 0x00000200) != 0) + X = X | 0xFFFFFC00; + TX1_A = (X * Oldval_1) >> 8; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("X = 0x%x, TX1_A = 0x%x\n", X, TX1_A)); + ODM_SetBBReg(pDM_Odm, rOFDM0_XBTxIQImbalance, 0x3FF, TX1_A); + + ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT(27), ((X* Oldval_1>>7) & 0x1)); + + Y = result[final_candidate][5]; + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + + TX1_C = (Y * Oldval_1) >> 8; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Y = 0x%x, TX1_C = 0x%x\n", Y, TX1_C)); + ODM_SetBBReg(pDM_Odm, rOFDM0_XDTxAFE, 0xF0000000, ((TX1_C&0x3C0)>>6)); + ODM_SetBBReg(pDM_Odm, rOFDM0_XBTxIQImbalance, 0x003F0000, (TX1_C&0x3F)); + + ODM_SetBBReg(pDM_Odm, rOFDM0_ECCAThreshold, BIT(25), ((Y* Oldval_1>>7) & 0x1)); + + if(bTxOnly) + return; + + reg = result[final_candidate][6]; + ODM_SetBBReg(pDM_Odm, rOFDM0_XBRxIQImbalance, 0x3FF, reg); + + reg = result[final_candidate][7] & 0x3F; + ODM_SetBBReg(pDM_Odm, rOFDM0_XBRxIQImbalance, 0xFC00, reg); + + reg = (result[final_candidate][7] >> 6) & 0xF; + ODM_SetBBReg(pDM_Odm, rOFDM0_AGCRSSITable, 0x0000F000, reg); + } +} + +// +// 2011/07/26 MH Add an API for testing IQK fail case. +// +// MP Already declare in odm.c +#if !(DM_ODM_SUPPORT_TYPE & ODM_WIN) +BOOLEAN +ODM_CheckPowerStatus( + IN PADAPTER Adapter) +{ +/* + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + RT_RF_POWER_STATE rtState; + PMGNT_INFO pMgntInfo = &(Adapter->MgntInfo); + + // 2011/07/27 MH We are not testing ready~~!! We may fail to get correct value when init sequence. + if (pMgntInfo->init_adpt_in_progress == TRUE) + { + ODM_RT_TRACE(pDM_Odm,COMP_INIT, DBG_LOUD, ("ODM_CheckPowerStatus Return TRUE, due to initadapter")); + return TRUE; + } + + // + // 2011/07/19 MH We can not execute tx pwoer tracking/ LLC calibrate or IQK. + // + Adapter->HalFunc.GetHwRegHandler(Adapter, HW_VAR_RF_STATE, (pu1Byte)(&rtState)); + if(Adapter->bDriverStopped || Adapter->bDriverIsGoingToPnpSetPowerSleep || rtState == eRfOff) + { + ODM_RT_TRACE(pDM_Odm,COMP_INIT, DBG_LOUD, ("ODM_CheckPowerStatus Return FALSE, due to %d/%d/%d\n", + Adapter->bDriverStopped, Adapter->bDriverIsGoingToPnpSetPowerSleep, rtState)); + return FALSE; + } +*/ + return TRUE; +} +#endif + +VOID +_PHY_SaveADDARegisters( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN pu4Byte ADDAReg, + IN pu4Byte ADDABackup, + IN u4Byte RegisterNum + ) +{ + u4Byte i; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif + + if (ODM_CheckPowerStatus(pAdapter) == FALSE) + return; +#endif + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save ADDA parameters.\n")); + for( i = 0 ; i < RegisterNum ; i++){ + ADDABackup[i] = ODM_GetBBReg(pDM_Odm, ADDAReg[i], bMaskDWord); + } +} + + +VOID +_PHY_SaveMACRegisters( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN pu4Byte MACReg, + IN pu4Byte MACBackup + ) +{ + u4Byte i; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Save MAC parameters.\n")); + for( i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++){ + MACBackup[i] = ODM_Read1Byte(pDM_Odm, MACReg[i]); + } + MACBackup[i] = ODM_Read4Byte(pDM_Odm, MACReg[i]); + +} + + +VOID +_PHY_ReloadADDARegisters( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN pu4Byte ADDAReg, + IN pu4Byte ADDABackup, + IN u4Byte RegiesterNum + ) +{ + u4Byte i; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Reload ADDA power saving parameters !\n")); + for(i = 0 ; i < RegiesterNum; i++) + { + ODM_SetBBReg(pDM_Odm, ADDAReg[i], bMaskDWord, ADDABackup[i]); + } +} + +VOID +_PHY_ReloadMACRegisters( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN pu4Byte MACReg, + IN pu4Byte MACBackup + ) +{ + u4Byte i; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Reload MAC parameters !\n")); + for(i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++){ + ODM_Write1Byte(pDM_Odm, MACReg[i], (u1Byte)MACBackup[i]); + } + ODM_Write4Byte(pDM_Odm, MACReg[i], MACBackup[i]); +} + + +VOID +_PHY_PathADDAOn( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN pu4Byte ADDAReg, + IN BOOLEAN isPathAOn, + IN BOOLEAN is2T + ) +{ + u4Byte pathOn; + u4Byte i; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("ADDA ON.\n")); + + pathOn = isPathAOn ? 0x04db25a4 : 0x0b1b25a4; + if(FALSE == is2T){ + pathOn = 0x0bdb25a0; + ODM_SetBBReg(pDM_Odm, ADDAReg[0], bMaskDWord, 0x0b1b25a0); + } + else{ + ODM_SetBBReg(pDM_Odm,ADDAReg[0], bMaskDWord, pathOn); + } + + for( i = 1 ; i < IQK_ADDA_REG_NUM ; i++){ + ODM_SetBBReg(pDM_Odm,ADDAReg[i], bMaskDWord, pathOn); + } + +} + +VOID +_PHY_MACSettingCalibration( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN pu4Byte MACReg, + IN pu4Byte MACBackup + ) +{ + u4Byte i = 0; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("MAC settings for Calibration.\n")); + + ODM_Write1Byte(pDM_Odm, MACReg[i], 0x3F); + + for(i = 1 ; i < (IQK_MAC_REG_NUM - 1); i++){ + ODM_Write1Byte(pDM_Odm, MACReg[i], (u1Byte)(MACBackup[i]&(~BIT3))); + } + ODM_Write1Byte(pDM_Odm, MACReg[i], (u1Byte)(MACBackup[i]&(~BIT5))); + +} + +VOID +_PHY_PathAStandBy( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm +#else + IN PADAPTER pAdapter +#endif + ) +{ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path-A standby mode!\n")); + + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x0); + ODM_SetBBReg(pDM_Odm, 0x840, bMaskDWord, 0x00010000); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000); +} + +VOID +_PHY_PIModeSwitch( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN BOOLEAN PIMode + ) +{ + u4Byte mode; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("BB Switch to %s mode!\n", (PIMode ? "PI" : "SI"))); + + mode = PIMode ? 0x01000100 : 0x01000000; + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_HSSIParameter1, bMaskDWord, mode); + ODM_SetBBReg(pDM_Odm, rFPGA0_XB_HSSIParameter1, bMaskDWord, mode); +} + +BOOLEAN +phy_SimularityCompare_8188E( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN s4Byte result[][8], + IN u1Byte c1, + IN u1Byte c2 + ) +{ + u4Byte i, j, diff, SimularityBitMap, bound = 0; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + u1Byte final_candidate[2] = {0xFF, 0xFF}; //for path A and path B + BOOLEAN bResult = TRUE; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + BOOLEAN is2T = IS_92C_SERIAL( pHalData->VersionID); +#else + BOOLEAN is2T = 0; +#endif + + if(is2T) + bound = 8; + else + bound = 4; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("===> IQK:phy_SimularityCompare_8188E c1 %d c2 %d!!!\n", c1, c2)); + + + SimularityBitMap = 0; + + for( i = 0; i < bound; i++ ) + { + diff = (result[c1][i] > result[c2][i]) ? (result[c1][i] - result[c2][i]) : (result[c2][i] - result[c1][i]); + if (diff > MAX_TOLERANCE) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:phy_SimularityCompare_8188E differnece overflow index %d compare1 0x%x compare2 0x%x!!!\n", i, result[c1][i], result[c2][i])); + + if((i == 2 || i == 6) && !SimularityBitMap) + { + if(result[c1][i]+result[c1][i+1] == 0) + final_candidate[(i/4)] = c2; + else if (result[c2][i]+result[c2][i+1] == 0) + final_candidate[(i/4)] = c1; + else + SimularityBitMap = SimularityBitMap|(1<<i); + } + else + SimularityBitMap = SimularityBitMap|(1<<i); + } + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:phy_SimularityCompare_8188E SimularityBitMap %d !!!\n", SimularityBitMap)); + + if ( SimularityBitMap == 0) + { + for( i = 0; i < (bound/4); i++ ) + { + if(final_candidate[i] != 0xFF) + { + for( j = i*4; j < (i+1)*4-2; j++) + result[3][j] = result[final_candidate[i]][j]; + bResult = FALSE; + } + } + return bResult; + } + else if (!(SimularityBitMap & 0x0F)) //path A OK + { + for(i = 0; i < 4; i++) + result[3][i] = result[c1][i]; + return FALSE; + } + else if (!(SimularityBitMap & 0xF0) && is2T) //path B OK + { + for(i = 4; i < 8; i++) + result[3][i] = result[c1][i]; + return FALSE; + } + else + return FALSE; + +} + + + +VOID +phy_IQCalibrate_8188E( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN s4Byte result[][8], + IN u1Byte t, + IN BOOLEAN is2T + ) +{ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + u4Byte i; + u1Byte PathAOK=0, PathBOK=0; + u4Byte ADDA_REG[IQK_ADDA_REG_NUM] = { + rFPGA0_XCD_SwitchControl, rBlue_Tooth, + rRx_Wait_CCA, rTx_CCK_RFON, + rTx_CCK_BBON, rTx_OFDM_RFON, + rTx_OFDM_BBON, rTx_To_Rx, + rTx_To_Tx, rRx_CCK, + rRx_OFDM, rRx_Wait_RIFS, + rRx_TO_Rx, rStandby, + rSleep, rPMPD_ANAEN }; + u4Byte IQK_MAC_REG[IQK_MAC_REG_NUM] = { + REG_TXPAUSE, REG_BCN_CTRL, + REG_BCN_CTRL_1, REG_GPIO_MUXCFG}; + + //since 92C & 92D have the different define in IQK_BB_REG + u4Byte IQK_BB_REG_92C[IQK_BB_REG_NUM] = { + rOFDM0_TRxPathEnable, rOFDM0_TRMuxPar, + rFPGA0_XCD_RFInterfaceSW, rConfig_AntA, rConfig_AntB, + rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, + rFPGA0_XB_RFInterfaceOE, rCCK0_AFESetting + }; + + u4Byte retryCount = 2; + + if ( *(pDM_Odm->mp_mode) == 1) + retryCount = 9; + + // Note: IQ calibration must be performed after loading + // PHY_REG.txt , and radio_a, radio_b.txt + + //u4Byte bbvalue; + +#if (DM_ODM_SUPPORT_TYPE & (ODM_AP|ODM_ADSL)) +#ifdef MP_TEST + if(pDM_Odm->priv->pshare->rf_ft_var.mp_specific) + retryCount = 9; +#endif +#endif + + + if(t==0) + { +// bbvalue = ODM_GetBBReg(pDM_Odm, rFPGA0_RFMOD, bMaskDWord); +// RT_DISP(FINIT, INIT_IQK, ("phy_IQCalibrate_8188E()==>0x%08x\n",bbvalue)); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2T ? "2T2R" : "1T1R"), t)); + + // Save ADDA parameters, turn Path A ADDA on +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_SaveADDARegisters(pAdapter, ADDA_REG, pDM_Odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); + _PHY_SaveMACRegisters(pAdapter, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); + _PHY_SaveADDARegisters(pAdapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); +#else + _PHY_SaveADDARegisters(pDM_Odm, ADDA_REG, pDM_Odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); + _PHY_SaveMACRegisters(pDM_Odm, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); + _PHY_SaveADDARegisters(pDM_Odm, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); +#endif + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQ Calibration for %s for %d times\n", (is2T ? "2T2R" : "1T1R"), t)); + +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + + _PHY_PathADDAOn(pAdapter, ADDA_REG, TRUE, is2T); +#else + _PHY_PathADDAOn(pDM_Odm, ADDA_REG, TRUE, is2T); +#endif + + + if(t==0) + { + pDM_Odm->RFCalibrateInfo.bRfPiEnable = (u1Byte)ODM_GetBBReg(pDM_Odm, rFPGA0_XA_HSSIParameter1, BIT(8)); + } + + if(!pDM_Odm->RFCalibrateInfo.bRfPiEnable){ + // Switch BB to PI mode to do IQ Calibration. +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_PIModeSwitch(pAdapter, TRUE); +#else + _PHY_PIModeSwitch(pDM_Odm, TRUE); +#endif + } + + + //MAC settings +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_MACSettingCalibration(pAdapter, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); +#else + _PHY_MACSettingCalibration(pDM_Odm, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); +#endif + + //BB setting + //ODM_SetBBReg(pDM_Odm, rFPGA0_RFMOD, BIT24, 0x00); + ODM_SetBBReg(pDM_Odm, rCCK0_AFESetting, 0x0f000000, 0xf); + ODM_SetBBReg(pDM_Odm, rOFDM0_TRxPathEnable, bMaskDWord, 0x03a05600); + ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800e4); + ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22204000); + + + ODM_SetBBReg(pDM_Odm, rFPGA0_XAB_RFInterfaceSW, BIT10, 0x01); + ODM_SetBBReg(pDM_Odm, rFPGA0_XAB_RFInterfaceSW, BIT26, 0x01); + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, BIT10, 0x00); + ODM_SetBBReg(pDM_Odm, rFPGA0_XB_RFInterfaceOE, BIT10, 0x00); + + + if(is2T) + { + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00010000); + ODM_SetBBReg(pDM_Odm, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00010000); + } + + //Page B init + //AP or IQK + ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x0f600000); + + if(is2T) + { + ODM_SetBBReg(pDM_Odm, rConfig_AntB, bMaskDWord, 0x0f600000); + } + + // IQ calibration setting + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK setting!\n")); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000); + ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, 0x01007c00); + ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x81004800); + + for(i = 0 ; i < retryCount ; i++){ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + PathAOK = phy_PathA_IQK_8188E(pAdapter, is2T); +#else + PathAOK = phy_PathA_IQK_8188E(pDM_Odm, is2T); +#endif +// if(PathAOK == 0x03){ + if(PathAOK == 0x01){ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Tx IQK Success!!\n")); + result[t][0] = (ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; + result[t][1] = (ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; + break; + } +#if 0 + else if (i == (retryCount-1) && PathAOK == 0x01) //Tx IQK OK + { + RT_DISP(FINIT, INIT_IQK, ("Path A IQK Only Tx Success!!\n")); + + result[t][0] = (ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; + result[t][1] = (ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; + } +#endif + } + + for(i = 0 ; i < retryCount ; i++){ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + PathAOK = phy_PathA_RxIQK(pAdapter, is2T); +#else + PathAOK = phy_PathA_RxIQK(pDM_Odm, is2T); +#endif + if(PathAOK == 0x03){ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK Success!!\n")); +// result[t][0] = (ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16; +// result[t][1] = (ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16; + result[t][2] = (ODM_GetBBReg(pDM_Odm, rRx_Power_Before_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; + result[t][3] = (ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_A_2, bMaskDWord)&0x3FF0000)>>16; + break; + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A Rx IQK Fail!!\n")); + } + } + + if(0x00 == PathAOK){ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path A IQK failed!!\n")); + } + + if(is2T){ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_PathAStandBy(pAdapter); + + // Turn Path B ADDA on + _PHY_PathADDAOn(pAdapter, ADDA_REG, FALSE, is2T); +#else + _PHY_PathAStandBy(pDM_Odm); + + // Turn Path B ADDA on + _PHY_PathADDAOn(pDM_Odm, ADDA_REG, FALSE, is2T); +#endif + + for(i = 0 ; i < retryCount ; i++){ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + PathBOK = phy_PathB_IQK_8188E(pAdapter); +#else + PathBOK = phy_PathB_IQK_8188E(pDM_Odm); +#endif + if(PathBOK == 0x03){ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK Success!!\n")); + result[t][4] = (ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16; + result[t][5] = (ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16; + result[t][6] = (ODM_GetBBReg(pDM_Odm, rRx_Power_Before_IQK_B_2, bMaskDWord)&0x3FF0000)>>16; + result[t][7] = (ODM_GetBBReg(pDM_Odm, rRx_Power_After_IQK_B_2, bMaskDWord)&0x3FF0000)>>16; + break; + } + else if (i == (retryCount - 1) && PathBOK == 0x01) //Tx IQK OK + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B Only Tx IQK Success!!\n")); + result[t][4] = (ODM_GetBBReg(pDM_Odm, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16; + result[t][5] = (ODM_GetBBReg(pDM_Odm, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16; + } + } + + if(0x00 == PathBOK){ + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("Path B IQK failed!!\n")); + } + } + + //Back to BB mode, load original value + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:Back to BB mode, load original value!\n")); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0); + + if(t!=0) + { + if(!pDM_Odm->RFCalibrateInfo.bRfPiEnable){ + // Switch back BB to SI mode after finish IQ Calibration. +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_PIModeSwitch(pAdapter, FALSE); +#else + _PHY_PIModeSwitch(pDM_Odm, FALSE); +#endif + } +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + + // Reload ADDA power saving parameters + _PHY_ReloadADDARegisters(pAdapter, ADDA_REG, pDM_Odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); + + // Reload MAC parameters + _PHY_ReloadMACRegisters(pAdapter, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); + + _PHY_ReloadADDARegisters(pAdapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); +#else + // Reload ADDA power saving parameters + _PHY_ReloadADDARegisters(pDM_Odm, ADDA_REG, pDM_Odm->RFCalibrateInfo.ADDA_backup, IQK_ADDA_REG_NUM); + + // Reload MAC parameters + _PHY_ReloadMACRegisters(pDM_Odm, IQK_MAC_REG, pDM_Odm->RFCalibrateInfo.IQK_MAC_backup); + + _PHY_ReloadADDARegisters(pDM_Odm, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup, IQK_BB_REG_NUM); +#endif + + + // Restore RX initial gain + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00032ed3); + if(is2T){ + ODM_SetBBReg(pDM_Odm, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00032ed3); + } + + //load 0xe30 IQC default value + ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00); + ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00); + + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_IQCalibrate_8188E() <==\n")); + +} + + +VOID +phy_LCCalibrate_8188E( + IN PDM_ODM_T pDM_Odm, + IN BOOLEAN is2T + ) +{ + u1Byte tmpReg; + u4Byte RF_Amode=0, RF_Bmode=0, LC_Cal; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + PADAPTER pAdapter = pDM_Odm->Adapter; +#endif + //Check continuous TX and Packet TX + tmpReg = ODM_Read1Byte(pDM_Odm, 0xd03); + + if((tmpReg&0x70) != 0) //Deal with contisuous TX case + ODM_Write1Byte(pDM_Odm, 0xd03, tmpReg&0x8F); //disable all continuous TX + else // Deal with Packet TX case + ODM_Write1Byte(pDM_Odm, REG_TXPAUSE, 0xFF); // block all queues + + if((tmpReg&0x70) != 0) + { + //1. Read original RF mode + //Path-A +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + RF_Amode = PHY_QueryRFReg(pAdapter, ODM_RF_PATH_A, RF_AC, bMask12Bits); + + //Path-B + if(is2T) + RF_Bmode = PHY_QueryRFReg(pAdapter, ODM_RF_PATH_B, RF_AC, bMask12Bits); +#else + RF_Amode = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_AC, bMask12Bits); + + //Path-B + if(is2T) + RF_Bmode = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_B, RF_AC, bMask12Bits); +#endif + + //2. Set RF mode = standby mode + //Path-A + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_AC, bMask12Bits, (RF_Amode&0x8FFFF)|0x10000); + + //Path-B + if(is2T) + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, RF_AC, bMask12Bits, (RF_Bmode&0x8FFFF)|0x10000); + } + + //3. Read RF reg18 +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + LC_Cal = PHY_QueryRFReg(pAdapter, ODM_RF_PATH_A, RF_CHNLBW, bMask12Bits); +#else + LC_Cal = ODM_GetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, bMask12Bits); +#endif + + //4. Set LC calibration begin bit15 + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_CHNLBW, bMask12Bits, LC_Cal|0x08000); + + ODM_delay_ms(100); + + + //Restore original situation + if((tmpReg&0x70) != 0) //Deal with contisuous TX case + { + //Path-A + ODM_Write1Byte(pDM_Odm, 0xd03, tmpReg); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_AC, bMask12Bits, RF_Amode); + + //Path-B + if(is2T) + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, RF_AC, bMask12Bits, RF_Bmode); + } + else // Deal with Packet TX case + { + ODM_Write1Byte(pDM_Odm, REG_TXPAUSE, 0x00); + } +} + +//Analog Pre-distortion calibration +#define APK_BB_REG_NUM 8 +#define APK_CURVE_REG_NUM 4 +#define PATH_NUM 2 + +VOID +phy_APCalibrate_8188E( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN s1Byte delta, + IN BOOLEAN is2T + ) +{ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + u4Byte regD[PATH_NUM]; + u4Byte tmpReg, index, offset, apkbound; + u1Byte path, i, pathbound = PATH_NUM; + u4Byte BB_backup[APK_BB_REG_NUM]; + u4Byte BB_REG[APK_BB_REG_NUM] = { + rFPGA1_TxBlock, rOFDM0_TRxPathEnable, + rFPGA0_RFMOD, rOFDM0_TRMuxPar, + rFPGA0_XCD_RFInterfaceSW, rFPGA0_XAB_RFInterfaceSW, + rFPGA0_XA_RFInterfaceOE, rFPGA0_XB_RFInterfaceOE }; + u4Byte BB_AP_MODE[APK_BB_REG_NUM] = { + 0x00000020, 0x00a05430, 0x02040000, + 0x000800e4, 0x00204000 }; + u4Byte BB_normal_AP_MODE[APK_BB_REG_NUM] = { + 0x00000020, 0x00a05430, 0x02040000, + 0x000800e4, 0x22204000 }; + + u4Byte AFE_backup[IQK_ADDA_REG_NUM]; + u4Byte AFE_REG[IQK_ADDA_REG_NUM] = { + rFPGA0_XCD_SwitchControl, rBlue_Tooth, + rRx_Wait_CCA, rTx_CCK_RFON, + rTx_CCK_BBON, rTx_OFDM_RFON, + rTx_OFDM_BBON, rTx_To_Rx, + rTx_To_Tx, rRx_CCK, + rRx_OFDM, rRx_Wait_RIFS, + rRx_TO_Rx, rStandby, + rSleep, rPMPD_ANAEN }; + + u4Byte MAC_backup[IQK_MAC_REG_NUM]; + u4Byte MAC_REG[IQK_MAC_REG_NUM] = { + REG_TXPAUSE, REG_BCN_CTRL, + REG_BCN_CTRL_1, REG_GPIO_MUXCFG}; + + u4Byte APK_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = { + {0x0852c, 0x1852c, 0x5852c, 0x1852c, 0x5852c}, + {0x2852e, 0x0852e, 0x3852e, 0x0852e, 0x0852e} + }; + + u4Byte APK_normal_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = { + {0x0852c, 0x0a52c, 0x3a52c, 0x5a52c, 0x5a52c}, //path settings equal to path b settings + {0x0852c, 0x0a52c, 0x5a52c, 0x5a52c, 0x5a52c} + }; + + u4Byte APK_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = { + {0x52019, 0x52014, 0x52013, 0x5200f, 0x5208d}, + {0x5201a, 0x52019, 0x52016, 0x52033, 0x52050} + }; + + u4Byte APK_normal_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = { + {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}, //path settings equal to path b settings + {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a} + }; + + u4Byte AFE_on_off[PATH_NUM] = { + 0x04db25a4, 0x0b1b25a4}; //path A on path B off / path A off path B on + + u4Byte APK_offset[PATH_NUM] = { + rConfig_AntA, rConfig_AntB}; + + u4Byte APK_normal_offset[PATH_NUM] = { + rConfig_Pmpd_AntA, rConfig_Pmpd_AntB}; + + u4Byte APK_value[PATH_NUM] = { + 0x92fc0000, 0x12fc0000}; + + u4Byte APK_normal_value[PATH_NUM] = { + 0x92680000, 0x12680000}; + + s1Byte APK_delta_mapping[APK_BB_REG_NUM][13] = { + {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-6, -4, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0} + }; + + u4Byte APK_normal_setting_value_1[13] = { + 0x01017018, 0xf7ed8f84, 0x1b1a1816, 0x2522201e, 0x322e2b28, + 0x433f3a36, 0x5b544e49, 0x7b726a62, 0xa69a8f84, 0xdfcfc0b3, + 0x12680000, 0x00880000, 0x00880000 + }; + + u4Byte APK_normal_setting_value_2[16] = { + 0x01c7021d, 0x01670183, 0x01000123, 0x00bf00e2, 0x008d00a3, + 0x0068007b, 0x004d0059, 0x003a0042, 0x002b0031, 0x001f0025, + 0x0017001b, 0x00110014, 0x000c000f, 0x0009000b, 0x00070008, + 0x00050006 + }; + + u4Byte APK_result[PATH_NUM][APK_BB_REG_NUM]; //val_1_1a, val_1_2a, val_2a, val_3a, val_4a +// u4Byte AP_curve[PATH_NUM][APK_CURVE_REG_NUM]; + + s4Byte BB_offset, delta_V, delta_offset; + +#if MP_DRIVER == 1 +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.MptCtx); +#else + PMPT_CONTEXT pMptCtx = &(pAdapter->MptCtx); +#endif + + if ( *(pDM_Odm->mp_mode) == 1) + { + pMptCtx->APK_bound[0] = 45; + pMptCtx->APK_bound[1] = 52; + } +#endif + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("==>phy_APCalibrate_8188E() delta %d\n", delta)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("AP Calibration for %s\n", (is2T ? "2T2R" : "1T1R"))); + if(!is2T) + pathbound = 1; + + //2 FOR NORMAL CHIP SETTINGS + +// Temporarily do not allow normal driver to do the following settings because these offset +// and value will cause RF internal PA to be unpredictably disabled by HW, such that RF Tx signal +// will disappear after disable/enable card many times on 88CU. RF SD and DD have not find the +// root cause, so we remove these actions temporarily. Added by tynli and SD3 Allen. 2010.05.31. +//#if MP_DRIVER != 1 + if (*(pDM_Odm->mp_mode) != 1) + return; +//#endif + //settings adjust for normal chip + for(index = 0; index < PATH_NUM; index ++) + { + APK_offset[index] = APK_normal_offset[index]; + APK_value[index] = APK_normal_value[index]; + AFE_on_off[index] = 0x6fdb25a4; + } + + for(index = 0; index < APK_BB_REG_NUM; index ++) + { + for(path = 0; path < pathbound; path++) + { + APK_RF_init_value[path][index] = APK_normal_RF_init_value[path][index]; + APK_RF_value_0[path][index] = APK_normal_RF_value_0[path][index]; + } + BB_AP_MODE[index] = BB_normal_AP_MODE[index]; + } + + apkbound = 6; + + //save BB default value + for(index = 0; index < APK_BB_REG_NUM ; index++) + { + if(index == 0) //skip + continue; + BB_backup[index] = ODM_GetBBReg(pDM_Odm, BB_REG[index], bMaskDWord); + } + + //save MAC default value +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_SaveMACRegisters(pAdapter, MAC_REG, MAC_backup); + + //save AFE default value + _PHY_SaveADDARegisters(pAdapter, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); +#else + _PHY_SaveMACRegisters(pDM_Odm, MAC_REG, MAC_backup); + + //save AFE default value + _PHY_SaveADDARegisters(pDM_Odm, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); +#endif + + for(path = 0; path < pathbound; path++) + { + + + if(path == ODM_RF_PATH_A) + { + //path A APK + //load APK setting + //path-A + offset = rPdp_AntA; + for(index = 0; index < 11; index ++) + { + ODM_SetBBReg(pDM_Odm, offset, bMaskDWord, APK_normal_setting_value_1[index]); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", offset, ODM_GetBBReg(pDM_Odm, offset, bMaskDWord))); + + offset += 0x04; + } + + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000); + + offset = rConfig_AntA; + for(; index < 13; index ++) + { + ODM_SetBBReg(pDM_Odm, offset, bMaskDWord, APK_normal_setting_value_1[index]); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", offset, ODM_GetBBReg(pDM_Odm, offset, bMaskDWord))); + + offset += 0x04; + } + + //page-B1 + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x40000000); + + //path A + offset = rPdp_AntA; + for(index = 0; index < 16; index++) + { + ODM_SetBBReg(pDM_Odm, offset, bMaskDWord, APK_normal_setting_value_2[index]); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", offset, ODM_GetBBReg(pDM_Odm, offset, bMaskDWord))); + + offset += 0x04; + } + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); + } + else if(path == ODM_RF_PATH_B) + { + //path B APK + //load APK setting + //path-B + offset = rPdp_AntB; + for(index = 0; index < 10; index ++) + { + ODM_SetBBReg(pDM_Odm, offset, bMaskDWord, APK_normal_setting_value_1[index]); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", offset, ODM_GetBBReg(pDM_Odm, offset, bMaskDWord))); + + offset += 0x04; + } + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntA, bMaskDWord, 0x12680000); +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + PHY_SetBBReg(pAdapter, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000); +#else + PHY_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x12680000); +#endif + + offset = rConfig_AntA; + index = 11; + for(; index < 13; index ++) //offset 0xb68, 0xb6c + { + ODM_SetBBReg(pDM_Odm, offset, bMaskDWord, APK_normal_setting_value_1[index]); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", offset, ODM_GetBBReg(pDM_Odm, offset, bMaskDWord))); + + offset += 0x04; + } + + //page-B1 + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x40000000); + + //path B + offset = 0xb60; + for(index = 0; index < 16; index++) + { + ODM_SetBBReg(pDM_Odm, offset, bMaskDWord, APK_normal_setting_value_2[index]); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", offset, ODM_GetBBReg(pDM_Odm, offset, bMaskDWord))); + + offset += 0x04; + } + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0); + } + + //save RF default value +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + regD[path] = PHY_QueryRFReg(pAdapter, path, RF_TXBIAS_A, bMaskDWord); +#else + regD[path] = ODM_GetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)path, RF_TXBIAS_A, bMaskDWord); +#endif + + //Path A AFE all on, path B AFE All off or vise versa + for(index = 0; index < IQK_ADDA_REG_NUM ; index++) + ODM_SetBBReg(pDM_Odm, AFE_REG[index], bMaskDWord, AFE_on_off[path]); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xe70 %x\n", ODM_GetBBReg(pDM_Odm, rRx_Wait_CCA, bMaskDWord))); + + //BB to AP mode + if(path == 0) + { + for(index = 0; index < APK_BB_REG_NUM ; index++) + { + + if(index == 0) //skip + continue; + else if (index < 5) + ODM_SetBBReg(pDM_Odm, BB_REG[index], bMaskDWord, BB_AP_MODE[index]); + else if (BB_REG[index] == 0x870) + ODM_SetBBReg(pDM_Odm, BB_REG[index], bMaskDWord, BB_backup[index]|BIT10|BIT26); + else + ODM_SetBBReg(pDM_Odm, BB_REG[index], BIT10, 0x0); + } + + ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00); + ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00); + } + else //path B + { + ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_B, bMaskDWord, 0x01008c00); + ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_B, bMaskDWord, 0x01008c00); + + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x800 %x\n", ODM_GetBBReg(pDM_Odm, 0x800, bMaskDWord))); + + //MAC settings +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_MACSettingCalibration(pAdapter, MAC_REG, MAC_backup); +#else + _PHY_MACSettingCalibration(pDM_Odm, MAC_REG, MAC_backup); +#endif + + if(path == ODM_RF_PATH_A) //Path B to standby mode + { + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, RF_AC, bMaskDWord, 0x10000); + } + else //Path A to standby mode + { + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_AC, bMaskDWord, 0x10000); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_MODE1, bMaskDWord, 0x1000f); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_MODE2, bMaskDWord, 0x20103); + } + + delta_offset = ((delta+14)/2); + if(delta_offset < 0) + delta_offset = 0; + else if (delta_offset > 12) + delta_offset = 12; + + //AP calibration + for(index = 0; index < APK_BB_REG_NUM; index++) + { + if(index != 1) //only DO PA11+PAD01001, AP RF setting + continue; + + tmpReg = APK_RF_init_value[path][index]; +#if 1 + if(!pDM_Odm->RFCalibrateInfo.bAPKThermalMeterIgnore) + { + BB_offset = (tmpReg & 0xF0000) >> 16; + + if(!(tmpReg & BIT15)) //sign bit 0 + { + BB_offset = -BB_offset; + } + + delta_V = APK_delta_mapping[index][delta_offset]; + + BB_offset += delta_V; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() APK index %d tmpReg 0x%x delta_V %d delta_offset %d\n", index, tmpReg, delta_V, delta_offset)); + + if(BB_offset < 0) + { + tmpReg = tmpReg & (~BIT15); + BB_offset = -BB_offset; + } + else + { + tmpReg = tmpReg | BIT15; + } + tmpReg = (tmpReg & 0xFFF0FFFF) | (BB_offset << 16); + } +#endif + + ODM_SetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)path, RF_IPA_A, bMaskDWord, 0x8992e); +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xc %x\n", PHY_QueryRFReg(pAdapter, path, RF_IPA_A, bMaskDWord))); + ODM_SetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)path, RF_AC, bMaskDWord, APK_RF_value_0[path][index]); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x0 %x\n", PHY_QueryRFReg(pAdapter, path, RF_AC, bMaskDWord))); + ODM_SetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)path, RF_TXBIAS_A, bMaskDWord, tmpReg); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xd %x\n", PHY_QueryRFReg(pAdapter, path, RF_TXBIAS_A, bMaskDWord))); +#else + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xc %x\n", ODM_GetRFReg(pDM_Odm, path, RF_IPA_A, bMaskDWord))); + ODM_SetRFReg(pDM_Odm, path, RF_AC, bMaskDWord, APK_RF_value_0[path][index]); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x0 %x\n", ODM_GetRFReg(pDM_Odm, path, RF_AC, bMaskDWord))); + ODM_SetRFReg(pDM_Odm, path, RF_TXBIAS_A, bMaskDWord, tmpReg); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xd %x\n", ODM_GetRFReg(pDM_Odm, path, RF_TXBIAS_A, bMaskDWord))); +#endif + + // PA11+PAD01111, one shot + i = 0; + do + { + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80000000); + { + ODM_SetBBReg(pDM_Odm, APK_offset[path], bMaskDWord, APK_value[0]); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", APK_offset[path], ODM_GetBBReg(pDM_Odm, APK_offset[path], bMaskDWord))); + ODM_delay_ms(3); + ODM_SetBBReg(pDM_Odm, APK_offset[path], bMaskDWord, APK_value[1]); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0x%x value 0x%x\n", APK_offset[path], ODM_GetBBReg(pDM_Odm, APK_offset[path], bMaskDWord))); + + ODM_delay_ms(20); + } + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); + + if(path == ODM_RF_PATH_A) + tmpReg = ODM_GetBBReg(pDM_Odm, rAPK, 0x03E00000); + else + tmpReg = ODM_GetBBReg(pDM_Odm, rAPK, 0xF8000000); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_APCalibrate_8188E() offset 0xbd8[25:21] %x\n", tmpReg)); + + + i++; + } + while(tmpReg > apkbound && i < 4); + + APK_result[path][index] = tmpReg; + } + } + + //reload MAC default value +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_ReloadMACRegisters(pAdapter, MAC_REG, MAC_backup); +#else + _PHY_ReloadMACRegisters(pDM_Odm, MAC_REG, MAC_backup); +#endif + + //reload BB default value + for(index = 0; index < APK_BB_REG_NUM ; index++) + { + + if(index == 0) //skip + continue; + ODM_SetBBReg(pDM_Odm, BB_REG[index], bMaskDWord, BB_backup[index]); + } + + //reload AFE default value +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_ReloadADDARegisters(pAdapter, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); +#else + _PHY_ReloadADDARegisters(pDM_Odm, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); +#endif + + //reload RF path default value + for(path = 0; path < pathbound; path++) + { + ODM_SetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)path, 0xd, bMaskDWord, regD[path]); + if(path == ODM_RF_PATH_B) + { + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_MODE1, bMaskDWord, 0x1000f); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_MODE2, bMaskDWord, 0x20101); + } + + //note no index == 0 + if (APK_result[path][1] > 6) + APK_result[path][1] = 6; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("apk path %d result %d 0x%x \t", path, 1, APK_result[path][1])); + } + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("\n")); + + + for(path = 0; path < pathbound; path++) + { + ODM_SetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)path, 0x3, bMaskDWord, + ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (APK_result[path][1] << 5) | APK_result[path][1])); + if(path == ODM_RF_PATH_A) + ODM_SetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)path, 0x4, bMaskDWord, + ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x00 << 5) | 0x05)); + else + ODM_SetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)path, 0x4, bMaskDWord, + ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x02 << 5) | 0x05)); +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + if(!IS_HARDWARE_TYPE_8723A(pAdapter)) + ODM_SetRFReg(pDM_Odm, (ODM_RF_RADIO_PATH_E)path, RF_BS_PA_APSET_G9_G11, bMaskDWord, + ((0x08 << 15) | (0x08 << 10) | (0x08 << 5) | 0x08)); +#endif + } + + pDM_Odm->RFCalibrateInfo.bAPKdone = TRUE; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("<==phy_APCalibrate_8188E()\n")); +} + + + +#define DP_BB_REG_NUM 7 +#define DP_RF_REG_NUM 1 +#define DP_RETRY_LIMIT 10 +#define DP_PATH_NUM 2 +#define DP_DPK_NUM 3 +#define DP_DPK_VALUE_NUM 2 + + + + + +VOID +PHY_IQCalibrate_8188E( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN BOOLEAN bReCovery + ) +{ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #else // (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + + #if (MP_DRIVER == 1) + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PMPT_CONTEXT pMptCtx = &(pAdapter->MptCtx); + #else// (DM_ODM_SUPPORT_TYPE == ODM_CE) + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.MptCtx); + #endif + #endif//(MP_DRIVER == 1) +#endif + + s4Byte result[4][8]; //last is final result + u1Byte i, final_candidate, Indexforchannel; + u1Byte channelToIQK = 7; + BOOLEAN bPathAOK, bPathBOK; + s4Byte RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC, RegTmp = 0; + BOOLEAN is12simular, is13simular, is23simular; + BOOLEAN bStartContTx = FALSE, bSingleTone = FALSE, bCarrierSuppression = FALSE; + u4Byte IQK_BB_REG_92C[IQK_BB_REG_NUM] = { + rOFDM0_XARxIQImbalance, rOFDM0_XBRxIQImbalance, + rOFDM0_ECCAThreshold, rOFDM0_AGCRSSITable, + rOFDM0_XATxIQImbalance, rOFDM0_XBTxIQImbalance, + rOFDM0_XCTxAFE, rOFDM0_XDTxAFE, + rOFDM0_RxIQExtAnta}; + u4Byte StartTime; + s4Byte ProgressingTime; + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE) ) + if (ODM_CheckPowerStatus(pAdapter) == FALSE) + return; +#else + prtl8192cd_priv priv = pDM_Odm->priv; + +#ifdef MP_TEST + if(priv->pshare->rf_ft_var.mp_specific) + { + if((OPMODE & WIFI_MP_CTX_PACKET) || (OPMODE & WIFI_MP_CTX_ST)) + return; + } +#endif + + if(priv->pshare->IQK_88E_done) + bReCovery= 1; + priv->pshare->IQK_88E_done = 1; + +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) + if(!(pDM_Odm->SupportAbility & ODM_RF_CALIBRATION)) + { + return; + } +#endif + +#if MP_DRIVER == 1 + if (*(pDM_Odm->mp_mode) == 1) + { + bStartContTx = pMptCtx->bStartContTx; + bSingleTone = pMptCtx->bSingleTone; + bCarrierSuppression = pMptCtx->bCarrierSuppression; + } +#endif + + // 20120213<Kordan> Turn on when continuous Tx to pass lab testing. (required by Edlu) + if(bSingleTone || bCarrierSuppression) + return; + +#if DISABLE_BB_RF + return; +#endif + + if (pDM_Odm->RFCalibrateInfo.bIQKInProgress) + return; + +#if (DM_ODM_SUPPORT_TYPE & (ODM_CE|ODM_AP)) + if(bReCovery) +#else//for ODM_WIN + if(bReCovery && (!pAdapter->bInHctTest)) //YJ,add for PowerTest,120405 +#endif + { + ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("PHY_IQCalibrate_8188E: Return due to bReCovery!\n")); +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_ReloadADDARegisters(pAdapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup_recover, 9); +#else + _PHY_ReloadADDARegisters(pDM_Odm, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup_recover, 9); +#endif + return; + } + + ODM_AcquireSpinLock(pDM_Odm, RT_IQK_SPINLOCK); + pDM_Odm->RFCalibrateInfo.bIQKInProgress = TRUE; + ODM_ReleaseSpinLock(pDM_Odm, RT_IQK_SPINLOCK); + + StartTime = ODM_GetCurrentTime( pDM_Odm); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK:Start!!!\n")); + + + + for(i = 0; i < 8; i++) + { + result[0][i] = 0; + result[1][i] = 0; + result[2][i] = 0; + result[3][i] = 0; + } + final_candidate = 0xff; + bPathAOK = FALSE; + bPathBOK = FALSE; + is12simular = FALSE; + is23simular = FALSE; + is13simular = FALSE; + + + for (i=0; i<3; i++) + { +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + + if(IS_92C_SERIAL( pHalData->VersionID)) + { + phy_IQCalibrate_8188E(pAdapter, result, i, TRUE); + } + else +#endif + { + // For 88C 1T1R +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + phy_IQCalibrate_8188E(pAdapter, result, i, FALSE); +#else + phy_IQCalibrate_8188E(pDM_Odm, result, i, FALSE); +#endif + } + + if(i == 1) + { +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + is12simular = phy_SimularityCompare_8188E(pAdapter, result, 0, 1); +#else + is12simular = phy_SimularityCompare_8188E(pDM_Odm, result, 0, 1); +#endif + if(is12simular) + { + final_candidate = 0; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is12simular final_candidate is %x\n",final_candidate)); + break; + } + } + + if(i == 2) + { +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + is13simular = phy_SimularityCompare_8188E(pAdapter, result, 0, 2); +#else + is13simular = phy_SimularityCompare_8188E(pDM_Odm, result, 0, 2); +#endif + if(is13simular) + { + final_candidate = 0; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is13simular final_candidate is %x\n",final_candidate)); + + break; + } +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + is23simular = phy_SimularityCompare_8188E(pAdapter, result, 1, 2); +#else + is23simular = phy_SimularityCompare_8188E(pDM_Odm, result, 1, 2); +#endif + if(is23simular) + { + final_candidate = 1; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: is23simular final_candidate is %x\n",final_candidate)); + } + else + { + for(i = 0; i < 8; i++) + RegTmp += result[3][i]; + + if(RegTmp != 0) + final_candidate = 3; + else + final_candidate = 0xFF; + } + } + } +// RT_TRACE(COMP_INIT,DBG_LOUD,("Release Mutex in IQCalibrate \n")); + + for (i=0; i<4; i++) + { + RegE94 = result[i][0]; + RegE9C = result[i][1]; + RegEA4 = result[i][2]; + RegEAC = result[i][3]; + RegEB4 = result[i][4]; + RegEBC = result[i][5]; + RegEC4 = result[i][6]; + RegECC = result[i][7]; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: RegE94=%x RegE9C=%x RegEA4=%x RegEAC=%x RegEB4=%x RegEBC=%x RegEC4=%x RegECC=%x\n ", RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC)); + } + + if(final_candidate != 0xff) + { + pDM_Odm->RFCalibrateInfo.RegE94 = RegE94 = result[final_candidate][0]; + pDM_Odm->RFCalibrateInfo.RegE9C = RegE9C = result[final_candidate][1]; + RegEA4 = result[final_candidate][2]; + RegEAC = result[final_candidate][3]; + pDM_Odm->RFCalibrateInfo.RegEB4 = RegEB4 = result[final_candidate][4]; + pDM_Odm->RFCalibrateInfo.RegEBC = RegEBC = result[final_candidate][5]; + RegEC4 = result[final_candidate][6]; + RegECC = result[final_candidate][7]; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: final_candidate is %x\n",final_candidate)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: RegE94=%x RegE9C=%x RegEA4=%x RegEAC=%x RegEB4=%x RegEBC=%x RegEC4=%x RegECC=%x\n ", RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC)); + bPathAOK = bPathBOK = TRUE; + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK: FAIL use default value\n")); + + pDM_Odm->RFCalibrateInfo.RegE94 = pDM_Odm->RFCalibrateInfo.RegEB4 = 0x100; //X default value + pDM_Odm->RFCalibrateInfo.RegE9C = pDM_Odm->RFCalibrateInfo.RegEBC = 0x0; //Y default value + } + + if((RegE94 != 0)/*&&(RegEA4 != 0)*/) + { +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_PathAFillIQKMatrix(pAdapter, bPathAOK, result, final_candidate, (RegEA4 == 0)); +#else + _PHY_PathAFillIQKMatrix(pDM_Odm, bPathAOK, result, final_candidate, (RegEA4 == 0)); +#endif + } + +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + if (IS_92C_SERIAL(pHalData->VersionID)) + { + if((RegEB4 != 0)/*&&(RegEC4 != 0)*/) + { + _PHY_PathBFillIQKMatrix(pAdapter, bPathBOK, result, final_candidate, (RegEC4 == 0)); + } + } +#endif + +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + Indexforchannel = ODM_GetRightChnlPlaceforIQK(pHalData->CurrentChannel); +#else + Indexforchannel = 0; +#endif + +//To Fix BSOD when final_candidate is 0xff +//by sherry 20120321 + if(final_candidate < 4) + { + for(i = 0; i < IQK_Matrix_REG_NUM; i++) + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].Value[0][i] = result[final_candidate][i]; + pDM_Odm->RFCalibrateInfo.IQKMatrixRegSetting[Indexforchannel].bIQKDone = TRUE; + } + //RT_DISP(FINIT, INIT_IQK, ("\nIQK OK Indexforchannel %d.\n", Indexforchannel)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("\nIQK OK Indexforchannel %d.\n", Indexforchannel)); +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + + _PHY_SaveADDARegisters(pAdapter, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup_recover, 9); +#else + _PHY_SaveADDARegisters(pDM_Odm, IQK_BB_REG_92C, pDM_Odm->RFCalibrateInfo.IQK_BB_backup_recover, IQK_BB_REG_NUM); +#endif + + ODM_AcquireSpinLock(pDM_Odm, RT_IQK_SPINLOCK); + pDM_Odm->RFCalibrateInfo.bIQKInProgress = FALSE; + ODM_ReleaseSpinLock(pDM_Odm, RT_IQK_SPINLOCK); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK finished\n")); + ProgressingTime = ODM_GetProgressingTime( pDM_Odm, StartTime); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("IQK ProgressingTime = %d\n", ProgressingTime)); + +} + + +VOID +PHY_LCCalibrate_8188E( + IN PDM_ODM_T pDM_Odm + ) +{ + BOOLEAN bStartContTx = FALSE, bSingleTone = FALSE, bCarrierSuppression = FALSE; + u4Byte timeout = 2000, timecount = 0; + u4Byte StartTime; + s4Byte ProgressingTime; + + + +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + PADAPTER pAdapter = pDM_Odm->Adapter; + //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + #if (MP_DRIVER == 1) + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PMPT_CONTEXT pMptCtx = &(pAdapter->MptCtx); + #else// (DM_ODM_SUPPORT_TYPE == ODM_CE) + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.MptCtx); + #endif + #endif//(MP_DRIVER == 1) +#endif + +#if MP_DRIVER == 1 + if (*(pDM_Odm->mp_mode) == 1) + { + bStartContTx = pMptCtx->bStartContTx; + bSingleTone = pMptCtx->bSingleTone; + bCarrierSuppression = pMptCtx->bCarrierSuppression; + } +#endif + + +#if DISABLE_BB_RF + return; +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) + if(!(pDM_Odm->SupportAbility & ODM_RF_CALIBRATION)) + { + return; + } +#endif + // 20120213<Kordan> Turn on when continuous Tx to pass lab testing. (required by Edlu) + if(bSingleTone || bCarrierSuppression) + return; + + StartTime = ODM_GetCurrentTime( pDM_Odm); + while(*(pDM_Odm->pbScanInProcess) && timecount < timeout) + { + ODM_delay_ms(50); + timecount += 50; + } + + pDM_Odm->RFCalibrateInfo.bLCKInProgress = TRUE; + + //ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LCK:Start!!!interface %d currentband %x delay %d ms\n", pDM_Odm->interfaceIndex, pHalData->CurrentBandType92D, timecount)); + phy_LCCalibrate_8188E(pDM_Odm, FALSE); + + pDM_Odm->RFCalibrateInfo.bLCKInProgress = FALSE; + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LCK:Finish!!!interface %d\n", pDM_Odm->InterfaceIndex)); + ProgressingTime = ODM_GetProgressingTime( pDM_Odm, StartTime); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("LCK ProgressingTime = %d\n", ProgressingTime)); +} + +VOID +PHY_APCalibrate_8188E( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN s1Byte delta + ) +{ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif +#if DISABLE_BB_RF + return; +#endif + + return; +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) + if(!(pDM_Odm->SupportAbility & ODM_RF_CALIBRATION)) + { + return; + } +#endif + +#if FOR_BRAZIL_PRETEST != 1 + if(pDM_Odm->RFCalibrateInfo.bAPKdone) +#endif + return; + +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + if(IS_92C_SERIAL( pHalData->VersionID)){ + phy_APCalibrate_8188E(pAdapter, delta, TRUE); + } + else +#endif + { + // For 88C 1T1R +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + phy_APCalibrate_8188E(pAdapter, delta, FALSE); +#else + phy_APCalibrate_8188E(pDM_Odm, delta, FALSE); +#endif + } +} +VOID phy_SetRFPathSwitch_8188E( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN BOOLEAN bMain, + IN BOOLEAN is2T + ) +{ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #elif (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif + + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + if(!pAdapter->bHWInitReady) + #elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + if(pAdapter->hw_init_completed == _FALSE) + #endif + { + u1Byte u1bTmp; + u1bTmp = ODM_Read1Byte(pDM_Odm, REG_LEDCFG2) | BIT7; + ODM_Write1Byte(pDM_Odm, REG_LEDCFG2, u1bTmp); + //ODM_SetBBReg(pDM_Odm, REG_LEDCFG0, BIT23, 0x01); + ODM_SetBBReg(pDM_Odm, rFPGA0_XAB_RFParameter, BIT13, 0x01); + } + +#endif + + if(is2T) //92C + { + if(bMain) + ODM_SetBBReg(pDM_Odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6, 0x1); //92C_Path_A + else + ODM_SetBBReg(pDM_Odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6, 0x2); //BT + } + else //88C + { + + // <20120504, Kordan> [8188E] We should make AntDiversity controlled by HW (0x870[9:8] = 0), + // otherwise the following action has no effect. (0x860[9:8] has the effect only if AntDiversity controlled by SW) + ODM_SetBBReg(pDM_Odm, rFPGA0_XAB_RFInterfaceSW, BIT8|BIT9, 0x0); + ODM_SetBBReg(pDM_Odm, 0x914, bMaskLWord, 0x0201); // Set up the Ant mapping table + + if(bMain) + { + //ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, BIT8|BIT9, 0x2); // Tx Main (SW control)(The right antenna) + //4 [ Tx ] + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, BIT14|BIT13|BIT12, 0x1); // Tx Main (HW control)(The right antenna) + + //4 [ Rx ] + ODM_SetBBReg(pDM_Odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT4|BIT3, 0x1); // AntDivType = TRDiv, right antenna + if (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) + ODM_SetBBReg(pDM_Odm, rConfig_ram64x16, BIT31, 0x1); // RxCG, Default is RxCG. AntDivType = 2RDiv, left antenna + + } + else + { + //ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, BIT8|BIT9, 0x1); // Tx Aux (SW control)(The left antenna) + //4 [ Tx ] + ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, BIT14|BIT13|BIT12, 0x0); // Tx Aux (HW control)(The left antenna) + + //4 [ Rx ] + ODM_SetBBReg(pDM_Odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT4|BIT3, 0x0); // AntDivType = TRDiv, left antenna + if (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV) + ODM_SetBBReg(pDM_Odm, rConfig_ram64x16, BIT31, 0x0); // RxCS, AntDivType = 2RDiv, right antenna + } + + } +} +VOID PHY_SetRFPathSwitch_8188E( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN BOOLEAN bMain + ) +{ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); +#endif + +#if DISABLE_BB_RF + return; +#endif + +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + if (IS_92C_SERIAL(pHalData->VersionID)) + { + phy_SetRFPathSwitch_8188E(pAdapter, bMain, TRUE); + } + else +#endif + { + // For 88C 1T1R +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + phy_SetRFPathSwitch_8188E(pAdapter, bMain, FALSE); +#else + phy_SetRFPathSwitch_8188E(pDM_Odm, bMain, FALSE); +#endif + } +} + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) +//digital predistortion +VOID +phy_DigitalPredistortion( +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PADAPTER pAdapter, +#else + IN PDM_ODM_T pDM_Odm, +#endif + IN BOOLEAN is2T + ) +{ +#if (RT_PLATFORM == PLATFORM_WINDOWS) +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + + u4Byte tmpReg, tmpReg2, index, i; + u1Byte path, pathbound = PATH_NUM; + u4Byte AFE_backup[IQK_ADDA_REG_NUM]; + u4Byte AFE_REG[IQK_ADDA_REG_NUM] = { + rFPGA0_XCD_SwitchControl, rBlue_Tooth, + rRx_Wait_CCA, rTx_CCK_RFON, + rTx_CCK_BBON, rTx_OFDM_RFON, + rTx_OFDM_BBON, rTx_To_Rx, + rTx_To_Tx, rRx_CCK, + rRx_OFDM, rRx_Wait_RIFS, + rRx_TO_Rx, rStandby, + rSleep, rPMPD_ANAEN }; + + u4Byte BB_backup[DP_BB_REG_NUM]; + u4Byte BB_REG[DP_BB_REG_NUM] = { + rOFDM0_TRxPathEnable, rFPGA0_RFMOD, + rOFDM0_TRMuxPar, rFPGA0_XCD_RFInterfaceSW, + rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE, + rFPGA0_XB_RFInterfaceOE}; + u4Byte BB_settings[DP_BB_REG_NUM] = { + 0x00a05430, 0x02040000, 0x000800e4, 0x22208000, + 0x0, 0x0, 0x0}; + + u4Byte RF_backup[DP_PATH_NUM][DP_RF_REG_NUM]; + u4Byte RF_REG[DP_RF_REG_NUM] = { + RF_TXBIAS_A}; + + u4Byte MAC_backup[IQK_MAC_REG_NUM]; + u4Byte MAC_REG[IQK_MAC_REG_NUM] = { + REG_TXPAUSE, REG_BCN_CTRL, + REG_BCN_CTRL_1, REG_GPIO_MUXCFG}; + + u4Byte Tx_AGC[DP_DPK_NUM][DP_DPK_VALUE_NUM] = { + {0x1e1e1e1e, 0x03901e1e}, + {0x18181818, 0x03901818}, + {0x0e0e0e0e, 0x03900e0e} + }; + + u4Byte AFE_on_off[PATH_NUM] = { + 0x04db25a4, 0x0b1b25a4}; //path A on path B off / path A off path B on + + u1Byte RetryCount = 0; + + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("==>phy_DigitalPredistortion()\n")); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("phy_DigitalPredistortion for %s\n", (is2T ? "2T2R" : "1T1R"))); + + //save BB default value + for(index=0; index<DP_BB_REG_NUM; index++) + BB_backup[index] = ODM_GetBBReg(pDM_Odm, BB_REG[index], bMaskDWord); + + //save MAC default value +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_SaveMACRegisters(pAdapter, BB_REG, MAC_backup); +#else + _PHY_SaveMACRegisters(pDM_Odm, BB_REG, MAC_backup); +#endif + + //save RF default value + for(path=0; path<DP_PATH_NUM; path++) + { + for(index=0; index<DP_RF_REG_NUM; index++) +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + RF_backup[path][index] = PHY_QueryRFReg(pAdapter, path, RF_REG[index], bMaskDWord); +#else + RF_backup[path][index] = ODM_GetRFReg(pAdapter, path, RF_REG[index], bMaskDWord); +#endif + } + + //save AFE default value +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_SaveADDARegisters(pAdapter, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); +#else + _PHY_SaveADDARegisters(pDM_Odm, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); +#endif + + //Path A/B AFE all on + for(index = 0; index < IQK_ADDA_REG_NUM ; index++) + ODM_SetBBReg(pDM_Odm, AFE_REG[index], bMaskDWord, 0x6fdb25a4); + + //BB register setting + for(index = 0; index < DP_BB_REG_NUM; index++) + { + if(index < 4) + ODM_SetBBReg(pDM_Odm, BB_REG[index], bMaskDWord, BB_settings[index]); + else if (index == 4) + ODM_SetBBReg(pDM_Odm,BB_REG[index], bMaskDWord, BB_backup[index]|BIT10|BIT26); + else + ODM_SetBBReg(pDM_Odm, BB_REG[index], BIT10, 0x00); + } + + //MAC register setting +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_MACSettingCalibration(pAdapter, MAC_REG, MAC_backup); +#else + _PHY_MACSettingCalibration(pDM_Odm, MAC_REG, MAC_backup); +#endif + + //PAGE-E IQC setting + ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00); + ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00); + ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_B, bMaskDWord, 0x01008c00); + ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_B, bMaskDWord, 0x01008c00); + + //path_A DPK + //Path B to standby mode + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, RF_AC, bMaskDWord, 0x10000); + + // PA gain = 11 & PAD1 => tx_agc 1f ~11 + // PA gain = 11 & PAD2 => tx_agc 10~0e + // PA gain = 01 => tx_agc 0b~0d + // PA gain = 00 => tx_agc 0a~00 + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x40000000); + ODM_SetBBReg(pDM_Odm, 0xbc0, bMaskDWord, 0x0005361f); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); + + //do inner loopback DPK 3 times + for(i = 0; i < 3; i++) + { + //PA gain = 11 & PAD2 => tx_agc = 0x0f/0x0c/0x07 + for(index = 0; index < 3; index++) + ODM_SetBBReg(pDM_Odm, 0xe00+index*4, bMaskDWord, Tx_AGC[i][0]); + ODM_SetBBReg(pDM_Odm,0xe00+index*4, bMaskDWord, Tx_AGC[i][1]); + for(index = 0; index < 4; index++) + ODM_SetBBReg(pDM_Odm,0xe10+index*4, bMaskDWord, Tx_AGC[i][0]); + + // PAGE_B for Path-A inner loopback DPK setting + ODM_SetBBReg(pDM_Odm,rPdp_AntA, bMaskDWord, 0x02097098); + ODM_SetBBReg(pDM_Odm,rPdp_AntA_4, bMaskDWord, 0xf76d9f84); + ODM_SetBBReg(pDM_Odm,rConfig_Pmpd_AntA, bMaskDWord, 0x0004ab87); + ODM_SetBBReg(pDM_Odm,rConfig_AntA, bMaskDWord, 0x00880000); + + //----send one shot signal----// + // Path A + ODM_SetBBReg(pDM_Odm,rConfig_Pmpd_AntA, bMaskDWord, 0x80047788); + ODM_delay_ms(1); + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntA, bMaskDWord, 0x00047788); + ODM_delay_ms(50); + } + + //PA gain = 11 => tx_agc = 1a + for(index = 0; index < 3; index++) + ODM_SetBBReg(pDM_Odm,0xe00+index*4, bMaskDWord, 0x34343434); + ODM_SetBBReg(pDM_Odm,0xe08+index*4, bMaskDWord, 0x03903434); + for(index = 0; index < 4; index++) + ODM_SetBBReg(pDM_Odm,0xe10+index*4, bMaskDWord, 0x34343434); + + //==================================== + // PAGE_B for Path-A DPK setting + //==================================== + // open inner loopback @ b00[19]:10 od 0xb00 0x01097018 + ODM_SetBBReg(pDM_Odm,rPdp_AntA, bMaskDWord, 0x02017098); + ODM_SetBBReg(pDM_Odm,rPdp_AntA_4, bMaskDWord, 0xf76d9f84); + ODM_SetBBReg(pDM_Odm,rConfig_Pmpd_AntA, bMaskDWord, 0x0004ab87); + ODM_SetBBReg(pDM_Odm,rConfig_AntA, bMaskDWord, 0x00880000); + + //rf_lpbk_setup + //1.rf 00:5205a, rf 0d:0e52c + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x0c, bMaskDWord, 0x8992b); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x0d, bMaskDWord, 0x0e52c); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, 0x00, bMaskDWord, 0x5205a ); + + //----send one shot signal----// + // Path A + ODM_SetBBReg(pDM_Odm,rConfig_Pmpd_AntA, bMaskDWord, 0x800477c0); + ODM_delay_ms(1); + ODM_SetBBReg(pDM_Odm,rConfig_Pmpd_AntA, bMaskDWord, 0x000477c0); + ODM_delay_ms(50); + + while(RetryCount < DP_RETRY_LIMIT && !pDM_Odm->RFCalibrateInfo.bDPPathAOK) + { + //----read back measurement results----// + ODM_SetBBReg(pDM_Odm, rPdp_AntA, bMaskDWord, 0x0c297018); + tmpReg = ODM_GetBBReg(pDM_Odm, 0xbe0, bMaskDWord); + ODM_delay_ms(10); + ODM_SetBBReg(pDM_Odm, rPdp_AntA, bMaskDWord, 0x0c29701f); + tmpReg2 = ODM_GetBBReg(pDM_Odm, 0xbe8, bMaskDWord); + ODM_delay_ms(10); + + tmpReg = (tmpReg & bMaskHWord) >> 16; + tmpReg2 = (tmpReg2 & bMaskHWord) >> 16; + if(tmpReg < 0xf0 || tmpReg > 0x105 || tmpReg2 > 0xff ) + { + ODM_SetBBReg(pDM_Odm, rPdp_AntA, bMaskDWord, 0x02017098); + + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80000000); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); + ODM_delay_ms(1); + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntA, bMaskDWord, 0x800477c0); + ODM_delay_ms(1); + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntA, bMaskDWord, 0x000477c0); + ODM_delay_ms(50); + RetryCount++; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("path A DPK RetryCount %d 0xbe0[31:16] %x 0xbe8[31:16] %x\n", RetryCount, tmpReg, tmpReg2)); + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("path A DPK Sucess\n")); + pDM_Odm->RFCalibrateInfo.bDPPathAOK = TRUE; + break; + } + } + RetryCount = 0; + + //DPP path A + if(pDM_Odm->RFCalibrateInfo.bDPPathAOK) + { + // DP settings + ODM_SetBBReg(pDM_Odm, rPdp_AntA, bMaskDWord, 0x01017098); + ODM_SetBBReg(pDM_Odm, rPdp_AntA_4, bMaskDWord, 0x776d9f84); + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntA, bMaskDWord, 0x0004ab87); + ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x00880000); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x40000000); + + for(i=rPdp_AntA; i<=0xb3c; i+=4) + { + ODM_SetBBReg(pDM_Odm, i, bMaskDWord, 0x40004000); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("path A ofsset = 0x%x\n", i)); + } + + //pwsf + ODM_SetBBReg(pDM_Odm, 0xb40, bMaskDWord, 0x40404040); + ODM_SetBBReg(pDM_Odm, 0xb44, bMaskDWord, 0x28324040); + ODM_SetBBReg(pDM_Odm, 0xb48, bMaskDWord, 0x10141920); + + for(i=0xb4c; i<=0xb5c; i+=4) + { + ODM_SetBBReg(pDM_Odm, i, bMaskDWord, 0x0c0c0c0c); + } + + //TX_AGC boundary + ODM_SetBBReg(pDM_Odm, 0xbc0, bMaskDWord, 0x0005361f); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); + } + else + { + ODM_SetBBReg(pDM_Odm, rPdp_AntA, bMaskDWord, 0x00000000); + ODM_SetBBReg(pDM_Odm, rPdp_AntA_4, bMaskDWord, 0x00000000); + } + + //DPK path B + if(is2T) + { + //Path A to standby mode + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_AC, bMaskDWord, 0x10000); + + // LUTs => tx_agc + // PA gain = 11 & PAD1, => tx_agc 1f ~11 + // PA gain = 11 & PAD2, => tx_agc 10 ~0e + // PA gain = 01 => tx_agc 0b ~0d + // PA gain = 00 => tx_agc 0a ~00 + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x40000000); + ODM_SetBBReg(pDM_Odm, 0xbc4, bMaskDWord, 0x0005361f); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); + + //do inner loopback DPK 3 times + for(i = 0; i < 3; i++) + { + //PA gain = 11 & PAD2 => tx_agc = 0x0f/0x0c/0x07 + for(index = 0; index < 4; index++) + ODM_SetBBReg(pDM_Odm, 0x830+index*4, bMaskDWord, Tx_AGC[i][0]); + for(index = 0; index < 2; index++) + ODM_SetBBReg(pDM_Odm, 0x848+index*4, bMaskDWord, Tx_AGC[i][0]); + for(index = 0; index < 2; index++) + ODM_SetBBReg(pDM_Odm, 0x868+index*4, bMaskDWord, Tx_AGC[i][0]); + + // PAGE_B for Path-A inner loopback DPK setting + ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x02097098); + ODM_SetBBReg(pDM_Odm, rPdp_AntB_4, bMaskDWord, 0xf76d9f84); + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x0004ab87); + ODM_SetBBReg(pDM_Odm, rConfig_AntB, bMaskDWord, 0x00880000); + + //----send one shot signal----// + // Path B + ODM_SetBBReg(pDM_Odm,rConfig_Pmpd_AntB, bMaskDWord, 0x80047788); + ODM_delay_ms(1); + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x00047788); + ODM_delay_ms(50); + } + + // PA gain = 11 => tx_agc = 1a + for(index = 0; index < 4; index++) + ODM_SetBBReg(pDM_Odm, 0x830+index*4, bMaskDWord, 0x34343434); + for(index = 0; index < 2; index++) + ODM_SetBBReg(pDM_Odm, 0x848+index*4, bMaskDWord, 0x34343434); + for(index = 0; index < 2; index++) + ODM_SetBBReg(pDM_Odm, 0x868+index*4, bMaskDWord, 0x34343434); + + // PAGE_B for Path-B DPK setting + ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x02017098); + ODM_SetBBReg(pDM_Odm, rPdp_AntB_4, bMaskDWord, 0xf76d9f84); + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x0004ab87); + ODM_SetBBReg(pDM_Odm, rConfig_AntB, bMaskDWord, 0x00880000); + + // RF lpbk switches on + ODM_SetBBReg(pDM_Odm, 0x840, bMaskDWord, 0x0101000f); + ODM_SetBBReg(pDM_Odm, 0x840, bMaskDWord, 0x01120103); + + //Path-B RF lpbk + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x0c, bMaskDWord, 0x8992b); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, 0x0d, bMaskDWord, 0x0e52c); + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_B, RF_AC, bMaskDWord, 0x5205a); + + //----send one shot signal----// + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x800477c0); + ODM_delay_ms(1); + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x000477c0); + ODM_delay_ms(50); + + while(RetryCount < DP_RETRY_LIMIT && !pDM_Odm->RFCalibrateInfo.bDPPathBOK) + { + //----read back measurement results----// + ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x0c297018); + tmpReg = ODM_GetBBReg(pDM_Odm, 0xbf0, bMaskDWord); + ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x0c29701f); + tmpReg2 = ODM_GetBBReg(pDM_Odm, 0xbf8, bMaskDWord); + + tmpReg = (tmpReg & bMaskHWord) >> 16; + tmpReg2 = (tmpReg2 & bMaskHWord) >> 16; + + if(tmpReg < 0xf0 || tmpReg > 0x105 || tmpReg2 > 0xff) + { + ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x02017098); + + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80000000); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); + ODM_delay_ms(1); + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x800477c0); + ODM_delay_ms(1); + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x000477c0); + ODM_delay_ms(50); + RetryCount++; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("path B DPK RetryCount %d 0xbf0[31:16] %x, 0xbf8[31:16] %x\n", RetryCount , tmpReg, tmpReg2)); + } + else + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("path B DPK Success\n")); + pDM_Odm->RFCalibrateInfo.bDPPathBOK = TRUE; + break; + } + } + + //DPP path B + if(pDM_Odm->RFCalibrateInfo.bDPPathBOK) + { + // DP setting + // LUT by SRAM + ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x01017098); + ODM_SetBBReg(pDM_Odm, rPdp_AntB_4, bMaskDWord, 0x776d9f84); + ODM_SetBBReg(pDM_Odm, rConfig_Pmpd_AntB, bMaskDWord, 0x0004ab87); + ODM_SetBBReg(pDM_Odm, rConfig_AntB, bMaskDWord, 0x00880000); + + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x40000000); + for(i=0xb60; i<=0xb9c; i+=4) + { + ODM_SetBBReg(pDM_Odm, i, bMaskDWord, 0x40004000); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("path B ofsset = 0x%x\n", i)); + } + + // PWSF + ODM_SetBBReg(pDM_Odm, 0xba0, bMaskDWord, 0x40404040); + ODM_SetBBReg(pDM_Odm, 0xba4, bMaskDWord, 0x28324050); + ODM_SetBBReg(pDM_Odm, 0xba8, bMaskDWord, 0x0c141920); + + for(i=0xbac; i<=0xbbc; i+=4) + { + ODM_SetBBReg(pDM_Odm, i, bMaskDWord, 0x0c0c0c0c); + } + + // tx_agc boundary + ODM_SetBBReg(pDM_Odm, 0xbc4, bMaskDWord, 0x0005361f); + ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000); + + } + else + { + ODM_SetBBReg(pDM_Odm, rPdp_AntB, bMaskDWord, 0x00000000); + ODM_SetBBReg(pDM_Odm, rPdp_AntB_4, bMaskDWord, 0x00000000); + } + } + + //reload BB default value + for(index=0; index<DP_BB_REG_NUM; index++) + ODM_SetBBReg(pDM_Odm, BB_REG[index], bMaskDWord, BB_backup[index]); + + //reload RF default value + for(path = 0; path<DP_PATH_NUM; path++) + { + for( i = 0 ; i < DP_RF_REG_NUM ; i++){ + ODM_SetRFReg(pDM_Odm, path, RF_REG[i], bMaskDWord, RF_backup[path][i]); + } + } + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_MODE1, bMaskDWord, 0x1000f); //standby mode + ODM_SetRFReg(pDM_Odm, ODM_RF_PATH_A, RF_MODE2, bMaskDWord, 0x20101); //RF lpbk switches off + + //reload AFE default value +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + _PHY_ReloadADDARegisters(pAdapter, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); + + //reload MAC default value + _PHY_ReloadMACRegisters(pAdapter, MAC_REG, MAC_backup); +#else + _PHY_ReloadADDARegisters(pDM_Odm, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); + + //reload MAC default value + _PHY_ReloadMACRegisters(pDM_Odm, MAC_REG, MAC_backup); +#endif + + pDM_Odm->RFCalibrateInfo.bDPdone = TRUE; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("<==phy_DigitalPredistortion()\n")); +#endif +} + +VOID +PHY_DigitalPredistortion_8188E( +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PADAPTER pAdapter +#else + IN PDM_ODM_T pDM_Odm +#endif + ) +{ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif +#if DISABLE_BB_RF + return; +#endif + + return; + + if(pDM_Odm->RFCalibrateInfo.bDPdone) + return; +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + + if(pDM_Odm->RFType == ODM_2T2R){ + phy_DigitalPredistortion(pAdapter, TRUE); + } + else +#endif + { + // For 88C 1T1R + phy_DigitalPredistortion(pAdapter, FALSE); + } +} + + + +//return value TRUE => Main; FALSE => Aux + +BOOLEAN phy_QueryRFPathSwitch_8188E( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN BOOLEAN is2T + ) +{ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + #if (DM_ODM_SUPPORT_TYPE == ODM_CE) + PDM_ODM_T pDM_Odm = &pHalData->odmpriv; + #endif + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + PDM_ODM_T pDM_Odm = &pHalData->DM_OutSrc; + #endif +#endif + if(!pAdapter->bHWInitReady) + { + u1Byte u1bTmp; + u1bTmp = ODM_Read1Byte(pDM_Odm, REG_LEDCFG2) | BIT7; + ODM_Write1Byte(pDM_Odm, REG_LEDCFG2, u1bTmp); + //ODM_SetBBReg(pDM_Odm, REG_LEDCFG0, BIT23, 0x01); + ODM_SetBBReg(pDM_Odm, rFPGA0_XAB_RFParameter, BIT13, 0x01); + } + + if(is2T) // + { + if(ODM_GetBBReg(pDM_Odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT6) == 0x01) + return TRUE; + else + return FALSE; + } + else + { + if((ODM_GetBBReg(pDM_Odm, rFPGA0_XB_RFInterfaceOE, BIT5|BIT4|BIT3) == 0x1)) + return TRUE; + else + return FALSE; + } +} + + + +//return value TRUE => Main; FALSE => Aux +BOOLEAN PHY_QueryRFPathSwitch_8188E( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm +#else + IN PADAPTER pAdapter +#endif + ) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + +#if DISABLE_BB_RF + return TRUE; +#endif +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + + //if(IS_92C_SERIAL( pHalData->VersionID)){ + if(IS_2T2R( pHalData->VersionID)){ + return phy_QueryRFPathSwitch_8188E(pAdapter, TRUE); + } + else +#endif + { + // For 88C 1T1R +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + return phy_QueryRFPathSwitch_8188E(pAdapter, FALSE); +#else + return phy_QueryRFPathSwitch_8188E(pDM_Odm, FALSE); +#endif + } +} +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.h new file mode 100644 index 0000000..fdb42a3 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/HalPhyRf_8188e.h @@ -0,0 +1,141 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#ifndef __HAL_PHY_RF_8188E_H__ +#define __HAL_PHY_RF_8188E_H__ + +/*--------------------------Define Parameters-------------------------------*/ +#define IQK_DELAY_TIME_88E 10 //ms +#define index_mapping_NUM_88E 15 +#define AVG_THERMAL_NUM_88E 4 + +#include "../HalPhyRf.h" + +void ConfigureTxpowerTrack_8188E( + PTXPWRTRACK_CFG pConfig + ); + +VOID +GetDeltaSwingTable_8188E( + IN PDM_ODM_T pDM_Odm, + OUT pu1Byte *TemperatureUP_A, + OUT pu1Byte *TemperatureDOWN_A, + OUT pu1Byte *TemperatureUP_B, + OUT pu1Byte *TemperatureDOWN_B + ); + +void DoIQK_8188E( + PDM_ODM_T pDM_Odm, + u1Byte DeltaThermalIndex, + u1Byte ThermalValue, + u1Byte Threshold + ); + +VOID +ODM_TxPwrTrackSetPwr88E( + PDM_ODM_T pDM_Odm, + PWRTRACK_METHOD Method, + u1Byte RFPath, + u1Byte ChannelMappedIndex + ); + +//1 7. IQK + +void +PHY_IQCalibrate_8188E( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER Adapter, +#endif + IN BOOLEAN bReCovery); + + +// +// LC calibrate +// +void +PHY_LCCalibrate_8188E( + IN PDM_ODM_T pDM_Odm +); + +// +// AP calibrate +// +void +PHY_APCalibrate_8188E( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN s1Byte delta); +void +PHY_DigitalPredistortion_8188E( IN PADAPTER pAdapter); + + +VOID +_PHY_SaveADDARegisters( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN pu4Byte ADDAReg, + IN pu4Byte ADDABackup, + IN u4Byte RegisterNum + ); + +VOID +_PHY_PathADDAOn( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN pu4Byte ADDAReg, + IN BOOLEAN isPathAOn, + IN BOOLEAN is2T + ); + +VOID +_PHY_MACSettingCalibration( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm, +#else + IN PADAPTER pAdapter, +#endif + IN pu4Byte MACReg, + IN pu4Byte MACBackup + ); + + +VOID +_PHY_PathAStandBy( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + IN PDM_ODM_T pDM_Odm +#else + IN PADAPTER pAdapter +#endif + ); + + +#endif // #ifndef __HAL_PHY_RF_8188E_H__ + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RTL8188E.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RTL8188E.c new file mode 100644 index 0000000..27281df --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RTL8188E.c @@ -0,0 +1,459 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +//============================================================ +// include files +//============================================================ + +#include "../odm_precomp.h" + +#if (RTL8188E_SUPPORT == 1) + +VOID +ODM_DIG_LowerBound_88E( + IN PDM_ODM_T pDM_Odm +) +{ + pDIG_T pDM_DigTable = &pDM_Odm->DM_DigTable; + + if(pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV) + { + pDM_DigTable->rx_gain_range_min = (u1Byte) pDM_DigTable->AntDiv_RSSI_max; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_DIG_LowerBound_88E(): pDM_DigTable->AntDiv_RSSI_max=%d \n",pDM_DigTable->AntDiv_RSSI_max)); + } + //If only one Entry connected +} + + +//3============================================================ +//3 Dynamic Primary CCA +//3============================================================ + +VOID +odm_PrimaryCCA_Init( + IN PDM_ODM_T pDM_Odm) +{ + pPri_CCA_T PrimaryCCA = &(pDM_Odm->DM_PriCCA); + PrimaryCCA->DupRTS_flag = 0; + PrimaryCCA->intf_flag = 0; + PrimaryCCA->intf_type = 0; + PrimaryCCA->Monitor_flag = 0; + PrimaryCCA->PriCCA_flag = 0; +} + +BOOLEAN +ODM_DynamicPrimaryCCA_DupRTS( + IN PDM_ODM_T pDM_Odm + ) +{ + pPri_CCA_T PrimaryCCA = &(pDM_Odm->DM_PriCCA); + + return PrimaryCCA->DupRTS_flag; +} + +VOID +odm_DynamicPrimaryCCA( + IN PDM_ODM_T pDM_Odm + ) +{ + PADAPTER Adapter = pDM_Odm->Adapter; // for NIC + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) + PRT_WLAN_STA pEntry; +#endif + + PFALSE_ALARM_STATISTICS FalseAlmCnt = &(pDM_Odm->FalseAlmCnt); + pPri_CCA_T PrimaryCCA = &(pDM_Odm->DM_PriCCA); + + BOOLEAN Is40MHz; + BOOLEAN Client_40MHz = FALSE, Client_tmp = FALSE; // connected client BW + BOOLEAN bConnected = FALSE; // connected or not + static u1Byte Client_40MHz_pre = 0; + static u8Byte lastTxOkCnt = 0; + static u8Byte lastRxOkCnt = 0; + static u4Byte Counter = 0; + static u1Byte Delay = 1; + u8Byte curTxOkCnt; + u8Byte curRxOkCnt; + u1Byte SecCHOffset; + u1Byte i; + +#if((DM_ODM_SUPPORT_TYPE==ODM_ADSL) ||( DM_ODM_SUPPORT_TYPE==ODM_CE)) + return; +#endif + + if(pDM_Odm->SupportICType != ODM_RTL8188E) + return; + + Is40MHz = *(pDM_Odm->pBandWidth); + SecCHOffset = *(pDM_Odm->pSecChOffset); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Second CH Offset = %d\n", SecCHOffset)); + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + if(Is40MHz==1) + SecCHOffset = SecCHOffset%2+1; // NIC's definition is reverse to AP 1:secondary below, 2: secondary above + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Second CH Offset = %d\n", SecCHOffset)); + //3 Check Current WLAN Traffic + curTxOkCnt = Adapter->TxStats.NumTxBytesUnicast - lastTxOkCnt; + curRxOkCnt = Adapter->RxStats.NumRxBytesUnicast - lastRxOkCnt; + lastTxOkCnt = Adapter->TxStats.NumTxBytesUnicast; + lastRxOkCnt = Adapter->RxStats.NumRxBytesUnicast; +#elif (DM_ODM_SUPPORT_TYPE == ODM_AP) + //3 Check Current WLAN Traffic + curTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast)-lastTxOkCnt; + curRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast)-lastRxOkCnt; + lastTxOkCnt = *(pDM_Odm->pNumTxBytesUnicast); + lastRxOkCnt = *(pDM_Odm->pNumRxBytesUnicast); +#endif + + //==================Debug Message==================== + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("TP = %llu\n", curTxOkCnt+curRxOkCnt)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Is40MHz = %d\n", Is40MHz)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("BW_LSC = %d\n", FalseAlmCnt->Cnt_BW_LSC)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("BW_USC = %d\n", FalseAlmCnt->Cnt_BW_USC)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("CCA OFDM = %d\n", FalseAlmCnt->Cnt_OFDM_CCA)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("CCA CCK = %d\n", FalseAlmCnt->Cnt_CCK_CCA)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("OFDM FA = %d\n", FalseAlmCnt->Cnt_Ofdm_fail)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("CCK FA = %d\n", FalseAlmCnt->Cnt_Cck_fail)); + //================================================ + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + if (ACTING_AS_AP(Adapter)) // primary cca process only do at AP mode +#endif + { + + #if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("ACTING as AP mode=%d\n", ACTING_AS_AP(Adapter))); + //3 To get entry's connection and BW infomation status. + for(i=0;i<ASSOCIATE_ENTRY_NUM;i++) + { + if(IsAPModeExist(Adapter)&&GetFirstExtAdapter(Adapter)!=NULL) + pEntry=AsocEntry_EnumStation(GetFirstExtAdapter(Adapter), i); + else + pEntry=AsocEntry_EnumStation(GetDefaultAdapter(Adapter), i); + if(pEntry!=NULL) + { + Client_tmp = pEntry->BandWidth; // client BW + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Client_BW=%d\n", Client_tmp)); + if(Client_tmp>Client_40MHz) + Client_40MHz = Client_tmp; // 40M/20M coexist => 40M priority is High + + if(pEntry->bAssociated) + { + bConnected=TRUE; // client is connected or not + break; + } + } + else + { + break; + } + } +#elif (DM_ODM_SUPPORT_TYPE == ODM_AP) + //3 To get entry's connection and BW infomation status. + + PSTA_INFO_T pstat; + + for(i=0; i<ODM_ASSOCIATE_ENTRY_NUM; i++) + { + pstat = pDM_Odm->pODM_StaInfo[i]; + if(IS_STA_VALID(pstat) ) + { + Client_tmp = pstat->tx_bw; + if(Client_tmp>Client_40MHz) + Client_40MHz = Client_tmp; // 40M/20M coexist => 40M priority is High + + bConnected = TRUE; + } + } +#endif + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("bConnected=%d\n", bConnected)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Is Client 40MHz=%d\n", Client_40MHz)); + //1 Monitor whether the interference exists or not + if(PrimaryCCA->Monitor_flag == 1) + { + if(SecCHOffset == 1) // secondary channel is below the primary channel + { + if((FalseAlmCnt->Cnt_OFDM_CCA > 500)&&(FalseAlmCnt->Cnt_BW_LSC > FalseAlmCnt->Cnt_BW_USC+500)) + { + if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) + { + PrimaryCCA->intf_type = 1; + PrimaryCCA->PriCCA_flag = 1; + ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 2); // USC MF + if(PrimaryCCA->DupRTS_flag == 1) + PrimaryCCA->DupRTS_flag = 0; + } + else + { + PrimaryCCA->intf_type = 2; + if(PrimaryCCA->DupRTS_flag == 0) + PrimaryCCA->DupRTS_flag = 1; + } + + } + else // interferecne disappear + { + PrimaryCCA->DupRTS_flag = 0; + PrimaryCCA->intf_flag = 0; + PrimaryCCA->intf_type = 0; + } + } + else if(SecCHOffset == 2) // secondary channel is above the primary channel + { + if((FalseAlmCnt->Cnt_OFDM_CCA > 500)&&(FalseAlmCnt->Cnt_BW_USC > FalseAlmCnt->Cnt_BW_LSC+500)) + { + if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) + { + PrimaryCCA->intf_type = 1; + PrimaryCCA->PriCCA_flag = 1; + ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 1); // LSC MF + if(PrimaryCCA->DupRTS_flag == 1) + PrimaryCCA->DupRTS_flag = 0; + } + else + { + PrimaryCCA->intf_type = 2; + if(PrimaryCCA->DupRTS_flag == 0) + PrimaryCCA->DupRTS_flag = 1; + } + + } + else // interferecne disappear + { + PrimaryCCA->DupRTS_flag = 0; + PrimaryCCA->intf_flag = 0; + PrimaryCCA->intf_type = 0; + } + + + } + PrimaryCCA->Monitor_flag = 0; + } + + //1 Dynamic Primary CCA Main Function + if(PrimaryCCA->Monitor_flag == 0) + { + if(Is40MHz) // if RFBW==40M mode which require to process primary cca + { + //2 STA is NOT Connected + if(!bConnected) + { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("STA NOT Connected!!!!\n")); + + if(PrimaryCCA->PriCCA_flag == 1) // reset primary cca when STA is disconnected + { + PrimaryCCA->PriCCA_flag = 0; + ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 0); + } + if(PrimaryCCA->DupRTS_flag == 1) // reset Duplicate RTS when STA is disconnected + PrimaryCCA->DupRTS_flag = 0; + + if(SecCHOffset == 1) // secondary channel is below the primary channel + { + if((FalseAlmCnt->Cnt_OFDM_CCA > 800)&&(FalseAlmCnt->Cnt_BW_LSC*5 > FalseAlmCnt->Cnt_BW_USC*9)) + { + PrimaryCCA->intf_flag = 1; // secondary channel interference is detected!!! + if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) + PrimaryCCA->intf_type = 1; // interference is shift + else + PrimaryCCA->intf_type = 2; // interference is in-band + } + else + { + PrimaryCCA->intf_flag = 0; + PrimaryCCA->intf_type = 0; + } + } + else if(SecCHOffset == 2) // secondary channel is above the primary channel + { + if((FalseAlmCnt->Cnt_OFDM_CCA > 800)&&(FalseAlmCnt->Cnt_BW_USC*5 > FalseAlmCnt->Cnt_BW_LSC*9)) + { + PrimaryCCA->intf_flag = 1; // secondary channel interference is detected!!! + if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) + PrimaryCCA->intf_type = 1; // interference is shift + else + PrimaryCCA->intf_type = 2; // interference is in-band + } + else + { + PrimaryCCA->intf_flag = 0; + PrimaryCCA->intf_type = 0; + } + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("PrimaryCCA=%d\n",PrimaryCCA->PriCCA_flag)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Intf_Type=%d\n", PrimaryCCA->intf_type)); + } + //2 STA is Connected + else + { + if(Client_40MHz == 0) //3 // client BW = 20MHz + { + if(PrimaryCCA->PriCCA_flag == 0) + { + PrimaryCCA->PriCCA_flag = 1; + if(SecCHOffset==1) + ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 2); + else if(SecCHOffset==2) + ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 1); + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("STA Connected 20M!!! PrimaryCCA=%d\n", PrimaryCCA->PriCCA_flag)); + } + else //3 // client BW = 40MHz + { + if(PrimaryCCA->intf_flag == 1) // interference is detected!! + { + if(PrimaryCCA->intf_type == 1) + { + if(PrimaryCCA->PriCCA_flag!=1) + { + PrimaryCCA->PriCCA_flag = 1; + if(SecCHOffset==1) + ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 2); + else if(SecCHOffset==2) + ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 1); + } + } + else if(PrimaryCCA->intf_type == 2) + { + if(PrimaryCCA->DupRTS_flag!=1) + PrimaryCCA->DupRTS_flag = 1; + } + } + else // if intf_flag==0 + { + if((curTxOkCnt+curRxOkCnt)<10000) //idle mode or TP traffic is very low + { + if(SecCHOffset == 1) + { + if((FalseAlmCnt->Cnt_OFDM_CCA > 800)&&(FalseAlmCnt->Cnt_BW_LSC*5 > FalseAlmCnt->Cnt_BW_USC*9)) + { + PrimaryCCA->intf_flag = 1; + if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) + PrimaryCCA->intf_type = 1; // interference is shift + else + PrimaryCCA->intf_type = 2; // interference is in-band + } + } + else if(SecCHOffset == 2) + { + if((FalseAlmCnt->Cnt_OFDM_CCA > 800)&&(FalseAlmCnt->Cnt_BW_USC*5 > FalseAlmCnt->Cnt_BW_LSC*9)) + { + PrimaryCCA->intf_flag = 1; + if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) + PrimaryCCA->intf_type = 1; // interference is shift + else + PrimaryCCA->intf_type = 2; // interference is in-band + } + + } + } + else // TP Traffic is High + { + if(SecCHOffset == 1) + { + if(FalseAlmCnt->Cnt_BW_LSC > (FalseAlmCnt->Cnt_BW_USC+500)) + { + if(Delay == 0) // add delay to avoid interference occurring abruptly, jump one time + { + PrimaryCCA->intf_flag = 1; + if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) + PrimaryCCA->intf_type = 1; // interference is shift + else + PrimaryCCA->intf_type = 2; // interference is in-band + Delay = 1; + } + else + Delay = 0; + } + } + else if(SecCHOffset == 2) + { + if(FalseAlmCnt->Cnt_BW_USC > (FalseAlmCnt->Cnt_BW_LSC+500)) + { + if(Delay == 0) // add delay to avoid interference occurring abruptly + { + PrimaryCCA->intf_flag = 1; + if(FalseAlmCnt->Cnt_Ofdm_fail > FalseAlmCnt->Cnt_OFDM_CCA>>1) + PrimaryCCA->intf_type = 1; // interference is shift + else + PrimaryCCA->intf_type = 2; // interference is in-band + Delay = 1; + } + else + Delay = 0; + } + } + } + } + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Primary CCA=%d\n", PrimaryCCA->PriCCA_flag)); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Duplicate RTS=%d\n", PrimaryCCA->DupRTS_flag)); + } + + }// end of connected + } + } + //1 Dynamic Primary CCA Monitor Counter + if((PrimaryCCA->PriCCA_flag == 1)||(PrimaryCCA->DupRTS_flag == 1)) + { + if(Client_40MHz == 0) // client=20M no need to monitor primary cca flag + { + Client_40MHz_pre = Client_40MHz; + return; + } + Counter++; + ODM_RT_TRACE(pDM_Odm,ODM_COMP_DYNAMIC_PRICCA, ODM_DBG_LOUD, ("Counter=%d\n", Counter)); + if((Counter == 30)||((Client_40MHz -Client_40MHz_pre)==1)) // Every 60 sec to monitor one time + { + PrimaryCCA->Monitor_flag = 1; // monitor flag is triggered!!!!! + if(PrimaryCCA->PriCCA_flag == 1) + { + PrimaryCCA->PriCCA_flag = 0; + ODM_SetBBReg(pDM_Odm, 0xc6c, BIT8|BIT7, 0); + } + Counter = 0; + } + } + } + + Client_40MHz_pre = Client_40MHz; +} +#else //#if (RTL8188E_SUPPORT == 1) + +VOID +odm_PrimaryCCA_Init( + IN PDM_ODM_T pDM_Odm) +{ +} +VOID +odm_DynamicPrimaryCCA( + IN PDM_ODM_T pDM_Odm + ) +{ +} +BOOLEAN +ODM_DynamicPrimaryCCA_DupRTS( + IN PDM_ODM_T pDM_Odm + ) +{ + return FALSE; +} +#endif //#if (RTL8188E_SUPPORT == 1) + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RTL8188E.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RTL8188E.h new file mode 100644 index 0000000..45a9d11 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RTL8188E.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __ODM_RTL8188E_H__ +#define __ODM_RTL8188E_H__ + + +#define MAIN_ANT_CG_TRX 1 +#define AUX_ANT_CG_TRX 0 +#define MAIN_ANT_CGCS_RX 0 +#define AUX_ANT_CGCS_RX 1 + +VOID +ODM_DIG_LowerBound_88E( + IN PDM_ODM_T pDM_Odm +); + + + + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN|ODM_CE)) +VOID +ODM_SetTxAntByTxInfo_88E( + IN PDM_ODM_T pDM_Odm, + IN pu1Byte pDesc, + IN u1Byte macId +); +#else// (DM_ODM_SUPPORT_TYPE == ODM_AP) +VOID +ODM_SetTxAntByTxInfo_88E( + IN PDM_ODM_T pDM_Odm +); +#endif + +VOID +odm_PrimaryCCA_Init( + IN PDM_ODM_T pDM_Odm); + +BOOLEAN +ODM_DynamicPrimaryCCA_DupRTS( + IN PDM_ODM_T pDM_Odm); + +VOID +odm_DynamicPrimaryCCA( + IN PDM_ODM_T pDM_Odm); + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.c b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.c new file mode 100644 index 0000000..25ad4b1 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.c @@ -0,0 +1,234 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + + + +#include "../odm_precomp.h" + +#if (RTL8188E_SUPPORT == 1) + +void +odm_ConfigRFReg_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Addr, + IN u4Byte Data, + IN ODM_RF_RADIO_PATH_E RF_PATH, + IN u4Byte RegAddr + ) +{ + if(Addr == 0xffe) + { + #ifdef CONFIG_LONG_DELAY_ISSUE + ODM_sleep_ms(50); + #else + ODM_delay_ms(50); + #endif + } + else if (Addr == 0xfd) + { + ODM_delay_ms(5); + } + else if (Addr == 0xfc) + { + ODM_delay_ms(1); + } + else if (Addr == 0xfb) + { + ODM_delay_us(50); + } + else if (Addr == 0xfa) + { + ODM_delay_us(5); + } + else if (Addr == 0xf9) + { + ODM_delay_us(1); + } + else + { + ODM_SetRFReg(pDM_Odm, RF_PATH, RegAddr, bRFRegOffsetMask, Data); + // Add 1us delay between BB/RF register setting. + ODM_delay_us(1); + } +} + + +void +odm_ConfigRF_RadioA_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Addr, + IN u4Byte Data + ) +{ + u4Byte content = 0x1000; // RF_Content: radioa_txt + u4Byte maskforPhySet= (u4Byte)(content&0xE000); + + odm_ConfigRFReg_8188E(pDM_Odm, Addr, Data, ODM_RF_PATH_A, Addr|maskforPhySet); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigRFWithHeaderFile: [RadioA] %08X %08X\n", Addr, Data)); +} + +void +odm_ConfigRF_RadioB_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Addr, + IN u4Byte Data + ) +{ + u4Byte content = 0x1001; // RF_Content: radiob_txt + u4Byte maskforPhySet= (u4Byte)(content&0xE000); + + odm_ConfigRFReg_8188E(pDM_Odm, Addr, Data, ODM_RF_PATH_B, Addr|maskforPhySet); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigRFWithHeaderFile: [RadioB] %08X %08X\n", Addr, Data)); + +} + +void +odm_ConfigMAC_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Addr, + IN u1Byte Data + ) +{ + ODM_Write1Byte(pDM_Odm, Addr, Data); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigMACWithHeaderFile: [MAC_REG] %08X %08X\n", Addr, Data)); +} + +void +odm_ConfigBB_AGC_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Addr, + IN u4Byte Bitmask, + IN u4Byte Data + ) +{ + ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data); + // Add 1us delay between BB/RF register setting. + ODM_delay_us(1); + + ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigBBWithHeaderFile: [AGC_TAB] %08X %08X\n", Addr, Data)); +} + +void +odm_ConfigBB_PHY_REG_PG_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Band, + IN u4Byte RfPath, + IN u4Byte TxNum, + IN u4Byte Addr, + IN u4Byte Bitmask, + IN u4Byte Data + ) +{ + if (Addr == 0xfe){ + #ifdef CONFIG_LONG_DELAY_ISSUE + ODM_sleep_ms(50); + #else + ODM_delay_ms(50); + #endif + } + else if (Addr == 0xfd){ + ODM_delay_ms(5); + } + else if (Addr == 0xfc){ + ODM_delay_ms(1); + } + else if (Addr == 0xfb){ + ODM_delay_us(50); + } + else if (Addr == 0xfa){ + ODM_delay_us(5); + } + else if (Addr == 0xf9){ + ODM_delay_us(1); + } + else { + ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_LOUD, ("===> ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X %08X\n", Addr, Bitmask, Data)); + + #if !(DM_ODM_SUPPORT_TYPE&ODM_AP) + PHY_StoreTxPowerByRate(pDM_Odm->Adapter, Band, RfPath, TxNum, Addr, Bitmask, Data); + #endif + } +} + +void +odm_ConfigBB_TXPWR_LMT_8188E( + IN PDM_ODM_T pDM_Odm, + IN pu1Byte Regulation, + IN pu1Byte Band, + IN pu1Byte Bandwidth, + IN pu1Byte RateSection, + IN pu1Byte RfPath, + IN pu1Byte Channel, + IN pu1Byte PowerLimit + ) +{ +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN)) + PHY_SetTxPowerLimit(pDM_Odm, Regulation, Band, + Bandwidth, RateSection, RfPath, Channel, PowerLimit); +#elif (DM_ODM_SUPPORT_TYPE & (ODM_CE)) + PHY_SetTxPowerLimit(pDM_Odm->Adapter, Regulation, Band, + Bandwidth, RateSection, RfPath, Channel, PowerLimit); +#endif +} + +void +odm_ConfigBB_PHY_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Addr, + IN u4Byte Bitmask, + IN u4Byte Data + ) +{ + if (Addr == 0xfe){ + #ifdef CONFIG_LONG_DELAY_ISSUE + ODM_sleep_ms(50); + #else + ODM_delay_ms(50); + #endif + } + else if (Addr == 0xfd){ + ODM_delay_ms(5); + } + else if (Addr == 0xfc){ + ODM_delay_ms(1); + } + else if (Addr == 0xfb){ + ODM_delay_us(50); + } + else if (Addr == 0xfa){ + ODM_delay_us(5); + } + else if (Addr == 0xf9){ + ODM_delay_us(1); + } + else { + if (Addr == 0xa24) + pDM_Odm->RFCalibrateInfo.RegA24 = Data; + ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data); + + // Add 1us delay between BB/RF register setting. + ODM_delay_us(1); + ODM_RT_TRACE(pDM_Odm,ODM_COMP_INIT, ODM_DBG_TRACE, ("===> ODM_ConfigBBWithHeaderFile: [PHY_REG] %08X %08X\n", Addr, Data)); + } +} +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.h b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.h new file mode 100644 index 0000000..999c772 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/OUTSRC/rtl8188e/odm_RegConfig8188E.h @@ -0,0 +1,96 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __INC_ODM_REGCONFIG_H_8188E +#define __INC_ODM_REGCONFIG_H_8188E + +#if (RTL8188E_SUPPORT == 1) + +void +odm_ConfigRFReg_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Addr, + IN u4Byte Data, + IN ODM_RF_RADIO_PATH_E RF_PATH, + IN u4Byte RegAddr + ); + +void +odm_ConfigRF_RadioA_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Addr, + IN u4Byte Data + ); + +void +odm_ConfigRF_RadioB_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Addr, + IN u4Byte Data + ); + +void +odm_ConfigMAC_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Addr, + IN u1Byte Data + ); + +void +odm_ConfigBB_AGC_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Addr, + IN u4Byte Bitmask, + IN u4Byte Data + ); + +void +odm_ConfigBB_PHY_REG_PG_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Band, + IN u4Byte RfPath, + IN u4Byte TxNum, + IN u4Byte Addr, + IN u4Byte Bitmask, + IN u4Byte Data + ); + +void +odm_ConfigBB_PHY_8188E( + IN PDM_ODM_T pDM_Odm, + IN u4Byte Addr, + IN u4Byte Bitmask, + IN u4Byte Data + ); + +void +odm_ConfigBB_TXPWR_LMT_8188E( + IN PDM_ODM_T pDM_Odm, + IN pu1Byte Regulation, + IN pu1Byte Band, + IN pu1Byte Bandwidth, + IN pu1Byte RateSection, + IN pu1Byte RfPath, + IN pu1Byte Channel, + IN pu1Byte PowerLimit + ); + +#endif +#endif // end of SUPPORT + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e1ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e1ant.c new file mode 100644 index 0000000..38c89d1 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e1ant.c @@ -0,0 +1,3417 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8192E Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8192E_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8192e_1ant glcoex_dm_8192e_1ant; +static struct coex_dm_8192e_1ant *coex_dm = &glcoex_dm_8192e_1ant; +static struct coex_sta_8192e_1ant glcoex_sta_8192e_1ant; +static struct coex_sta_8192e_1ant *coex_sta = &glcoex_sta_8192e_1ant; + +const char *const glbt_info_src_8192e_1ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u32 glcoex_ver_date_8192e_1ant = 20140527; +u32 glcoex_ver_8192e_1ant = 0x4f; + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8192e1ant_ + * ************************************************************ */ +u8 halbtc8192e1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8192e1ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 index, IN u8 level_num, IN u8 rssi_thresh, IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8192e1ant_update_ra_mask(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 dis_rate_mask) +{ + coex_dm->cur_ra_mask = dis_rate_mask; + + if (force_exec || (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_RAMASK, + &coex_dm->cur_ra_mask); + coex_dm->pre_ra_mask = coex_dm->cur_ra_mask; +} + +void halbtc8192e1ant_auto_rate_fallback_retry(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + boolean wifi_under_b_mode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + if (wifi_under_b_mode) { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +void halbtc8192e1ant_retry_limit(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || + (coex_dm->pre_retry_limit_type != + coex_dm->cur_retry_limit_type)) { + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +void halbtc8192e1ant_ampdu_max_time(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || + (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +void halbtc8192e1ant_limited_tx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ra_mask_type, IN u8 arfr_type, + IN u8 retry_limit_type, IN u8 ampdu_time_type) +{ + switch (ra_mask_type) { + case 0: /* normal mode */ + halbtc8192e1ant_update_ra_mask(btcoexist, force_exec, + 0x0); + break; + case 1: /* disable cck 1/2 */ + halbtc8192e1ant_update_ra_mask(btcoexist, force_exec, + 0x00000003); + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ + halbtc8192e1ant_update_ra_mask(btcoexist, force_exec, + 0x0001f1f7); + break; + default: + break; + } + + halbtc8192e1ant_auto_rate_fallback_retry(btcoexist, force_exec, + arfr_type); + halbtc8192e1ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8192e1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type); +} + +void halbtc8192e1ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +void halbtc8192e1ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +void halbtc8192e1ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + static u8 num_of_bt_counter_chk = 0; + + /* to avoid 0x76e[3] = 1 (WLAN_Act control by PTA) during IPS */ + /* if (! (btcoexist->btc_read_1byte(btcoexist, 0x76e) & 0x8) ) */ + + if (coex_sta->under_ips) { + coex_sta->high_priority_tx = 65535; + coex_sta->high_priority_rx = 65535; + coex_sta->low_priority_tx = 65535; + coex_sta->low_priority_rx = 65535; + return; + } + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + if ((coex_sta->low_priority_tx >= 1050) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n", + reg_hp_rx, reg_hp_tx, reg_lp_rx, reg_lp_tx); + BTC_TRACE(trace_buf); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + if ((reg_hp_tx == 0) && (reg_hp_rx == 0) && (reg_lp_tx == 0) && + (reg_lp_rx == 0)) { + num_of_bt_counter_chk++; + if (num_of_bt_counter_chk >= 3) { + halbtc8192e1ant_query_bt_info(btcoexist); + num_of_bt_counter_chk = 0; + } + } +} + + +void halbtc8192e1ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ + s32 wifi_rssi = 0; + boolean wifi_busy = false, wifi_under_b_mode = false; + static u8 cck_lock_counter = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + if (coex_sta->under_ips) { + coex_sta->crc_ok_cck = 0; + coex_sta->crc_ok_11g = 0; + coex_sta->crc_ok_11n = 0; + coex_sta->crc_ok_11n_agg = 0; + + coex_sta->crc_err_cck = 0; + coex_sta->crc_err_11g = 0; + coex_sta->crc_err_11n = 0; + coex_sta->crc_err_11n_agg = 0; + } else { + coex_sta->crc_ok_cck = btcoexist->btc_read_4byte(btcoexist, + 0xf88); + coex_sta->crc_ok_11g = btcoexist->btc_read_2byte(btcoexist, + 0xf94); + coex_sta->crc_ok_11n = btcoexist->btc_read_2byte(btcoexist, + 0xf90); + coex_sta->crc_ok_11n_agg = btcoexist->btc_read_2byte(btcoexist, + 0xfb8); + + coex_sta->crc_err_cck = btcoexist->btc_read_4byte(btcoexist, + 0xf84); + coex_sta->crc_err_11g = btcoexist->btc_read_2byte(btcoexist, + 0xf96); + coex_sta->crc_err_11n = btcoexist->btc_read_2byte(btcoexist, + 0xf92); + coex_sta->crc_err_11n_agg = btcoexist->btc_read_2byte(btcoexist, + 0xfba); + } + + + /* reset counter */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xf16, 0x1, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xf16, 0x1, 0x0); + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + if ((coex_dm->bt_status == BT_8192E_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == + BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY) || + (coex_dm->bt_status == + BT_8192E_1ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > (coex_sta->crc_ok_11g + + coex_sta->crc_ok_11n + + coex_sta->crc_ok_11n_agg)) { + if (cck_lock_counter < 5) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + + if (cck_lock_counter >= 5) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + coex_sta->pre_ccklock = coex_sta->cck_lock; + + +} + +boolean halbtc8192e1ant_is_wifi_status_changed(IN struct btc_coexist *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + } + + return false; +} + +void halbtc8192e1ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + +u8 halbtc8192e1ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8192E_1ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_1ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_1ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_1ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_1ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_1ANT_COEX_ALGO_SCO; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_1ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +void halbtc8192e1ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8192e1ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8192e1ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8192e1ant_set_sw_penalty_tx_rate_adaptive(IN struct btc_coexist + *btcoexist, IN boolean low_penalty_ra) +{ + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* op_code, 0x6= Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT(0); + h2c_parameter[2] = + 0x00; /* normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[3] = 0xf7; /* MCS7 or OFDM54 */ + h2c_parameter[4] = 0xf8; /* MCS6 or OFDM48 */ + h2c_parameter[5] = 0xf9; /* MCS5 or OFDM36 */ + } + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +void halbtc8192e1ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + halbtc8192e1ant_set_sw_penalty_tx_rate_adaptive(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +void halbtc8192e1ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8192e1ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8192e1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8192e1ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** CoexTable(%d) **********\n", type); + BTC_TRACE(trace_buf); + + coex_sta->coex_table_type = type; + + switch (type) { + case 0: + halbtc8192e1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x55555555, 0xffffff, 0x3); + break; + case 1: + halbtc8192e1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8192e1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 3: + halbtc8192e1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 4: + halbtc8192e1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaa5a5a, 0xffffff, 0x3); + break; + case 5: + halbtc8192e1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0xaa5a5a5a, 0xffffff, 0x3); + break; + case 6: + halbtc8192e1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 7: + halbtc8192e1ant_coex_table(btcoexist, force_exec, + 0xaaaaaaaa, 0xaaaaaaaa, 0xffffff, 0x3); + break; + default: + break; + } +} + +void halbtc8192e1ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT(0); /* function enable */ + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8192e1ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8192e1ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8192e1ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8192e1ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8192e1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8192e1ant_sw_mechanism(IN struct btc_coexist *btcoexist, + IN boolean low_penalty_ra) +{ + halbtc8192e1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +void halbtc8192e1ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean init_hwcfg, IN boolean wifi_off) +{ + u32 u32tmp = 0; + + if (init_hwcfg) { + btcoexist->btc_write_1byte(btcoexist, 0x944, 0x24); + btcoexist->btc_write_4byte(btcoexist, 0x930, 0x700700); + if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30430004); + else + btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30030004); + + /* 0x4c[27][24]='00', Set Antenna to BB */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT(24); + u32tmp &= ~BIT(27); + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + } else if (wifi_off) { + if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30430004); + else + btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30030004); + + /* 0x4c[27][24]='11', Set Antenna to BT, 0x64[8:7]=0, 0x64[2]=1 */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp |= BIT(24); + u32tmp |= BIT(27); + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + } + + /* ext switch setting */ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x4); + break; + case BTC_ANT_PATH_BT: + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20); + break; + default: + case BTC_ANT_PATH_PTA: + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x4); + break; + } +} + +void halbtc8192e1ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], FW for 1Ant AP mode\n"); + BTC_TRACE(trace_buf); + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + } + } + + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + + +void halbtc8192e1ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_busy = false; + u8 rssi_adjust_val = 0; + u8 ps_tdma_byte4_val = 0x50, ps_tdma_byte0_val = 0x51, + ps_tdma_byte3_val = 0x10; + s8 wifi_duration_adjust = 0x0; + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (coex_dm->cur_ps_tdma_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(off, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + + if (coex_sta->scan_ap_num <= 5) + wifi_duration_adjust = 5; + else if (coex_sta->scan_ap_num >= 40) + wifi_duration_adjust = -15; + else if (coex_sta->scan_ap_num >= 20) + wifi_duration_adjust = -10; + + if (!coex_sta->force_lps_on) { /* only for A2DP-only case 1/2/9/11 while wifi noisy threshold > 30 */ + ps_tdma_byte0_val = 0x61; /* no null-pkt */ + ps_tdma_byte3_val = 0x11; /* no tx-pause at BT-slot */ + ps_tdma_byte4_val = 0x10; /* 0x778 = d/1 toggle */ + } + + if ((type == 3) || (type == 13) || (type == 14)) + ps_tdma_byte4_val = ps_tdma_byte4_val & + 0xbf; /* no dynamic slot for multi-profile */ + + if (bt_link_info->slave_role == true) + ps_tdma_byte4_val = ps_tdma_byte4_val | + 0x1; /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + + if (turn_on) { + switch (type) { + default: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x51, + 0x1a, 0x1a, 0x0, ps_tdma_byte4_val); + break; + case 1: + halbtc8192e1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x3a + + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 2: + halbtc8192e1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x2d + + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 3: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x51, + 0x1d, 0x1d, 0x0, ps_tdma_byte4_val); + break; + case 4: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x93, + 0x15, 0x3, 0x14, 0x0); + break; + case 5: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x61, + 0x15, 0x3, 0x11, 0x11); + break; + case 6: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x61, + 0x20, 0x3, 0x11, 0x11); + break; + case 7: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x13, + 0xc, 0x5, 0x0, 0x0); + break; + case 8: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x93, + 0x25, 0x3, 0x10, 0x0); + break; + case 9: + halbtc8192e1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 10: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x13, + 0xa, 0xa, 0x0, 0x40); + break; + case 11: + halbtc8192e1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x21, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 12: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x51, + 0x0a, 0x0a, 0x0, 0x50); + break; + case 13: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x51, + 0x12, 0x12, 0x0, ps_tdma_byte4_val); + break; + case 14: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x51, + 0x21, 0x3, 0x10, ps_tdma_byte4_val); + break; + case 15: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x13, + 0xa, 0x3, 0x8, 0x0); + break; + case 16: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x93, + 0x15, 0x3, 0x10, 0x0); + break; + case 18: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x93, + 0x25, 0x3, 0x10, 0x0); + break; + case 20: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x61, + 0x3f, 0x03, 0x11, 0x10); + break; + case 21: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x61, + 0x25, 0x03, 0x11, 0x11); + break; + case 22: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x61, + 0x25, 0x03, 0x11, 0x10); + break; + case 23: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x3, 0x31, 0x18); + break; + case 24: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0xe3, + 0x15, 0x3, 0x31, 0x18); + break; + case 25: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0xe3, + 0xa, 0x3, 0x31, 0x18); + break; + case 26: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0xe3, + 0xa, 0x3, 0x31, 0x18); + break; + case 27: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x3, 0x31, 0x98); + break; + case 28: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x69, + 0x25, 0x3, 0x31, 0x0); + break; + case 29: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0xab, + 0x1a, 0x1a, 0x1, 0x10); + break; + case 30: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x51, + 0x30, 0x3, 0x10, 0x10); + break; + case 31: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0xd3, + 0x1a, 0x1a, 0, 0x58); + break; + case 32: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x61, + 0x35, 0x3, 0x11, 0x11); + break; + case 33: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0xa3, + 0x25, 0x3, 0x30, 0x90); + break; + case 34: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x53, + 0x1a, 0x1a, 0x0, 0x10); + break; + case 35: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x63, + 0x1a, 0x1a, 0x0, 0x10); + break; + case 36: + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0xd3, + 0x12, 0x3, 0x14, 0x50); + break; + case 40: /* SoftAP only with no sta associated,BT disable ,TDMA mode for power saving */ + /* here softap mode screen off will cost 70-80mA for phone */ + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x23, + 0x18, 0x00, 0x10, 0x24); + break; + } + } else { + + /* disable PS tdma */ + switch (type) { + case 8: /* PTA Control */ + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x8, + 0x0, 0x0, 0x0, 0x0); + halbtc8192e1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, false, false); + break; + case 0: + default: /* Software control, Antenna at BT side */ + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x0, 0x0); + halbtc8192e1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_BT, false, false); + break; + case 9: /* Software control, Antenna at WiFi side */ + halbtc8192e1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x0, 0x0); + halbtc8192e1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_WIFI, false, false); + break; + } + } + rssi_adjust_val = 0; + btcoexist->btc_set(btcoexist, + BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssi_adjust_val); + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x\n", + btcoexist->btc_read_4byte(btcoexist, 0x948), + btcoexist->btc_read_1byte(btcoexist, 0x765), + btcoexist->btc_read_1byte(btcoexist, 0x67)); + BTC_TRACE(trace_buf); + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void halbtc8192e1ant_coex_all_off(IN struct btc_coexist *btcoexist) +{ + /* sw all off */ + halbtc8192e1ant_sw_mechanism(btcoexist, false); + + /* hw all off */ + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +boolean halbtc8192e1ant_is_common_action(IN struct btc_coexist *btcoexist) +{ + boolean common = false, wifi_connected = false, wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected && + BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (wifi_connected && + (BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (!wifi_connected && + (BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (wifi_connected && + (BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (!wifi_connected && + (BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE != coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else { + if (wifi_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } + + common = false; + } + + return common; +} + + +void halbtc8192e1ant_tdma_duration_adjust_for_acl(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + static s32 up, dn, m, n, wait_count; + s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */ + u8 retry_count = 0, bt_info_ext; + boolean wifi_busy = false; + /*static boolean pre_wifi_busy = false;*/ + + if (BT_8192E_1ANT_WIFI_STATUS_CONNECTED_BUSY == wifi_status) + wifi_busy = true; + else + wifi_busy = false; + + if ((BT_8192E_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == + wifi_status) || + (BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifi_status) || + (BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SPECIFIC_PKT == + wifi_status)) { + if (coex_dm->cur_ps_tdma != 1 && + coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 3 && + coex_dm->cur_ps_tdma != 9) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 9); + coex_dm->ps_tdma_du_adj_type = 9; + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } + return; + } + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + /* ============ */ + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /* acquire the BT TRx retry count from BT_Info byte2 */ + retry_count = coex_sta->bt_retry_cnt; + bt_info_ext = coex_sta->bt_info_ext; + + if ((coex_sta->low_priority_tx) > 1050 || + (coex_sta->low_priority_rx) > 1250) + retry_count++; + + result = 0; + wait_count++; + + if (retry_count == + 0) { /* no retry in the last 2-second duration */ + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { /* if retry count during continuous n*2 seconds is 0, enlarge WiFi duration */ + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + } + } else if (retry_count <= + 3) { /* <=3 retry in the last 2-second duration */ + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { /* if continuous 2 retry count(every 2 seconds) >0 and < 3, reduce WiFi duration */ + if (wait_count <= 2) + m++; /* to avoid loop between the two levels */ + else + m = 1; + + if (m >= 20) /* maximum of m = 20 ' will recheck if need to adjust wifi duration in maximum time interval 120 seconds */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + } else { /* retry count > 3, once retry count > 3, to reduce WiFi duration */ + if (wait_count == 1) + m++; /* to avoid loop between the two levels */ + else + m = 1; + + if (m >= 20) /* maximum of m = 20 ' will recheck if need to adjust wifi duration in maximum time interval 120 seconds */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + + if (result == -1) { + if ((BT_INFO_8192E_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) || + (coex_dm->cur_ps_tdma == 2))) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } + } else if (result == 1) { + if ((BT_INFO_8192E_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) || + (coex_dm->cur_ps_tdma == 2))) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = 1; + } + } else { /* no change */ + /* Bryant Modify + if(wifi_busy != pre_wifi_busy) + { + pre_wifi_busy = wifi_busy; + halbtc8192e1ant_ps_tdma(btcoexist, FORCE_EXEC, true, coex_dm->cur_ps_tdma); + } + */ + } + + if (coex_dm->cur_ps_tdma != 1 && + coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 9 && + coex_dm->cur_ps_tdma != 11) { + /* recover to previous adjust type */ + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->ps_tdma_du_adj_type); + } + } +} + +void halbtc8192e1ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +void halbtc8192e1ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + case BTC_PS_LPS_ON: + halbtc8192e1ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8192e1ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + coex_sta->force_lps_on = true; + break; + case BTC_PS_LPS_OFF: + halbtc8192e1ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + default: + break; + } +} + +void halbtc8192e1ant_action_wifi_only(IN struct btc_coexist *btcoexist) +{ + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9); +} + +void halbtc8192e1ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false; + + /* This function check if bt is disabled */ + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is enabled !!\n"); + BTC_TRACE(trace_buf); + } else { + bt_disable_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], bt all counters=0, %d times!!\n", + bt_disable_cnt); + BTC_TRACE(trace_buf); + if (bt_disable_cnt >= 2) { + bt_disabled = true; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!\n"); + BTC_TRACE(trace_buf); + halbtc8192e1ant_action_wifi_only(btcoexist); + } + } + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + coex_sta->bt_disabled = bt_disabled; + if (!bt_disabled) { + } else { + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + } + } +} + +/* ********************************************* + * + * Software Coex Mechanism start + * + * ********************************************* */ + +/* SCO only or SCO+PAN(HS) */ + +/* +void halbtc8192e1ant_action_sco(IN struct btc_coexist* btcoexist) +{ + halbtc8192e1ant_sw_mechanism(btcoexist, true); +} + + +void halbtc8192e1ant_action_hid(IN struct btc_coexist* btcoexist) +{ + halbtc8192e1ant_sw_mechanism(btcoexist, true); +} + + +void halbtc8192e1ant_action_a2dp(IN struct btc_coexist* btcoexist) +{ + halbtc8192e1ant_sw_mechanism(btcoexist, false); +} + +void halbtc8192e1ant_action_a2dp_pan_hs(IN struct btc_coexist* btcoexist) +{ + halbtc8192e1ant_sw_mechanism(btcoexist, false); +} + +void halbtc8192e1ant_action_pan_edr(IN struct btc_coexist* btcoexist) +{ + halbtc8192e1ant_sw_mechanism(btcoexist, false); +} + + +void halbtc8192e1ant_action_pan_hs(IN struct btc_coexist* btcoexist) +{ + halbtc8192e1ant_sw_mechanism(btcoexist, false); +} + + +void halbtc8192e1ant_action_pan_edr_a2dp(IN struct btc_coexist* btcoexist) +{ + halbtc8192e1ant_sw_mechanism(btcoexist, false); +} + +void halbtc8192e1ant_action_pan_edr_hid(IN struct btc_coexist* btcoexist) +{ + halbtc8192e1ant_sw_mechanism(btcoexist, true); +} + + +void halbtc8192e1ant_action_hid_a2dp_pan_edr(IN struct btc_coexist* btcoexist) +{ + halbtc8192e1ant_sw_mechanism(btcoexist, true); +} + +void halbtc8192e1ant_action_hid_a2dp(IN struct btc_coexist* btcoexist) +{ + halbtc8192e1ant_sw_mechanism(btcoexist, true); +} + +*/ + +/* ********************************************* + * + * Non-Software Coex Mechanism start + * + * ********************************************* */ +void halbtc8192e1ant_action_wifi_multi_port(IN struct btc_coexist *btcoexist) +{ + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8192e1ant_action_hs(IN struct btc_coexist *btcoexist) +{ + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8192e1ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, ap_enable = false, wifi_busy = false, + bt_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + if ((!wifi_connected) && (!coex_sta->wifi_is_high_pri_task)) { + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + /* SCO/HID/A2DP busy */ + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if ((bt_link_info->pan_exist) || (wifi_busy)) { + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + } +} + +void halbtc8192e1ant_action_bt_sco_hid_only_busy(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* tdma and coex table */ + + if (bt_link_info->sco_exist) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } else { /* HID */ + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } +} + +void halbtc8192e1ant_action_wifi_connected_bt_acl_busy(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + u8 bt_rssi_state; + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + bt_rssi_state = halbtc8192e1ant_bt_rssi_state(2, 28, 0); + + if ((coex_sta->low_priority_rx >= 1000) && + (coex_sta->low_priority_rx != 65535)) + bt_link_info->slave_role = true; + else + bt_link_info->slave_role = false; + + if (bt_link_info->hid_only) { /* HID */ + halbtc8192e1ant_action_bt_sco_hid_only_busy(btcoexist, + wifi_status); + coex_dm->auto_tdma_adjust = false; + return; + } else if (bt_link_info->a2dp_only) { /* A2DP */ + if (BT_8192E_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8192e1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } else { + halbtc8192e1ant_tdma_duration_adjust_for_acl(btcoexist, + wifi_status); +#if 0 + if (coex_sta->cck_lock) + halbtc8192e1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 3); + else +#endif + halbtc8192e1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = true; + } + } else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { /* A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP) */ + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } else if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { /* HID+A2DP */ + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + coex_dm->auto_tdma_adjust = false; + + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + } else if ((bt_link_info->pan_only) || (bt_link_info->hid_exist && + bt_link_info->pan_exist)) { /* PAN(OPP,FTP), HID+PAN(OPP,FTP) */ + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } else { + /* BT no-profile busy (0x9) */ + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } +} + +void halbtc8192e1ant_action_wifi_not_connected(IN struct btc_coexist *btcoexist) +{ + /* power save state */ + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + halbtc8192e1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8192e1ant_action_wifi_not_connected_scan(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + if (BT_8192E_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8192e1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8192e1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8192e1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((BT_8192E_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8192e1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + /* Bryant Add */ + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8192e1ant_action_wifi_not_connected_asso_auth( + IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (bt_link_info->pan_exist) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8192e1ant_action_wifi_connected_scan(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + if (BT_8192E_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8192e1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8192e1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8192e1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((BT_8192E_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8192e1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + /* Bryant Add */ + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8192e1ant_action_wifi_connected_specific_packet( + IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (bt_link_info->pan_exist) { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8192e1ant_action_wifi_connected(IN struct btc_coexist *btcoexist) +{ + boolean wifi_busy = false; + boolean scan = false, link = false, roam = false; + boolean under_4way = false, ap_enable = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect()===>\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (under_4way) { + halbtc8192e1ant_action_wifi_connected_specific_packet(btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + if (scan || link || roam) { + if (scan) + halbtc8192e1ant_action_wifi_connected_scan(btcoexist); + else + halbtc8192e1ant_action_wifi_connected_specific_packet( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + /* power save state */ + if (!ap_enable && + BT_8192E_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status && + !btcoexist->bt_link_info.hid_only) { + if (btcoexist->bt_link_info.a2dp_only) { /* A2DP */ + if (!wifi_busy) + halbtc8192e1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + else { /* busy */ + if (coex_sta->scan_ap_num >= + BT_8192E_1ANT_WIFI_NOISY_THRESH) /* no force LPS, no PS-TDMA, use pure TDMA */ + halbtc8192e1ant_power_save_state( + btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8192e1ant_power_save_state( + btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + } else if ((coex_sta->pan_exist == false) && + (coex_sta->a2dp_exist == false) && + (coex_sta->hid_exist == false)) + halbtc8192e1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + else + halbtc8192e1ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + } else + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + /* tdma and coex table */ + if (!wifi_busy) { + if (BT_8192E_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8192e1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else if ((BT_8192E_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8192e1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + + if ((coex_sta->high_priority_tx) + + (coex_sta->high_priority_rx) <= 60) + halbtc8192e1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + else + halbtc8192e1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } + } else { + if (BT_8192E_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8192e1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else if ((BT_8192E_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8192e1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else { + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + + if ((coex_sta->high_priority_tx) + + (coex_sta->high_priority_rx) <= 60) + halbtc8192e1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + else + halbtc8192e1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } + } +} + +void halbtc8192e1ant_run_sw_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + algorithm = halbtc8192e1ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + + if (halbtc8192e1ant_is_common_action(btcoexist)) { + + } else { + switch (coex_dm->cur_algorithm) { + case BT_8192E_1ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_action_sco(btcoexist); */ + break; + case BT_8192E_1ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID.\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_action_hid(btcoexist); */ + break; + case BT_8192E_1ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_action_a2dp(btcoexist); */ + break; + case BT_8192E_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_action_a2dp_pan_hs(btcoexist); */ + break; + case BT_8192E_1ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_action_pan_edr(btcoexist); */ + break; + case BT_8192E_1ANT_COEX_ALGO_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HS mode.\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_action_pan_hs(btcoexist); */ + break; + case BT_8192E_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_action_pan_edr_a2dp(btcoexist); */ + break; + case BT_8192E_1ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_action_pan_edr_hid(btcoexist); */ + break; + case BT_8192E_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_action_hid_a2dp_pan_edr(btcoexist); */ + break; + case BT_8192E_1ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_action_hid_a2dp(btcoexist); */ + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = coexist All Off!!\n"); + BTC_TRACE(trace_buf); + /* halbtc8192e1ant_coex_all_off(btcoexist); */ + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +void halbtc8192e1ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + boolean increase_scan_dev_num = false; + boolean bt_ctrl_agg_buf_size = false; + boolean miracast_plus_bt = false; + u8 agg_buf_size = 5; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if ((BT_8192E_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8192E_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + increase_scan_dev_num = true; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, + &increase_scan_dev_num); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + BTC_TRACE(trace_buf); + + if (bt_link_info->bt_link_exist) { + halbtc8192e1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, + 0, 1); + miracast_plus_bt = true; + } else { + halbtc8192e1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, + 0, 0); + miracast_plus_bt = false; + } + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + halbtc8192e1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if ((bt_link_info->a2dp_exist) && + (coex_sta->c2h_bt_inquiry_page)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8192e1ant_action_bt_inquiry(btcoexist); + } else + halbtc8192e1ant_action_wifi_multi_port(btcoexist); + + return; + } + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + if ((bt_link_info->bt_link_exist) && (wifi_connected)) { + halbtc8192e1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, 0, 1); + + if (bt_link_info->sco_exist) + halbtc8192e1ant_limited_rx(btcoexist, NORMAL_EXEC, + false, true, 0x5); + else + halbtc8192e1ant_limited_rx(btcoexist, NORMAL_EXEC, + false, true, 0x8); + + halbtc8192e1ant_sw_mechanism(btcoexist, true); + halbtc8192e1ant_run_sw_coexist_mechanism( + btcoexist); /* just print debug message */ + } else { + halbtc8192e1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + halbtc8192e1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x5); + + halbtc8192e1ant_sw_mechanism(btcoexist, false); + halbtc8192e1ant_run_sw_coexist_mechanism( + btcoexist); /* just print debug message */ + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8192e1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8192e1ant_action_hs(btcoexist); + return; + } + + + if (!wifi_connected) { + boolean scan = false, link = false, roam = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is non connected-idle !!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + if (scan) + halbtc8192e1ant_action_wifi_not_connected_scan( + btcoexist); + else + halbtc8192e1ant_action_wifi_not_connected_asso_auth( + btcoexist); + } else + halbtc8192e1ant_action_wifi_not_connected(btcoexist); + } else /* wifi LPS/Busy */ + halbtc8192e1ant_action_wifi_connected(btcoexist); +} + +void halbtc8192e1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + + /* sw all off */ + halbtc8192e1ant_sw_mechanism(btcoexist, false); + + /* halbtc8192e1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); */ + halbtc8192e1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + coex_sta->pop_event_cnt = 0; +} + +void halbtc8192e1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + u16 u16tmp = 0; + u8 u8tmp = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 1Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + + /* antenna sw ctrl to bt */ + halbtc8192e1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, true, false); + + halbtc8192e1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + /* antenna switch control parameter */ + btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555); + + /* coex parameters */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + /* 0x790[5:0]=0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + /* enable counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* enable PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x40, 0x20); + /* enable mailbox interface */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x40); + u16tmp |= BIT(9); + btcoexist->btc_write_2byte(btcoexist, 0x40, u16tmp); + + /* enable PTA I2C mailbox */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x101); + u8tmp |= BIT(4); + btcoexist->btc_write_1byte(btcoexist, 0x101, u8tmp); + + /* enable bt clock when wifi is disabled. */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x93); + u8tmp |= BIT(0); + btcoexist->btc_write_1byte(btcoexist, 0x93, u8tmp); + /* enable bt clock when suspend. */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x7); + u8tmp |= BIT(0); + btcoexist->btc_write_1byte(btcoexist, 0x7, u8tmp); +} + + +/* +void halbtc8192e1ant_wifi_off_hw_cfg(IN struct btc_coexist* btcoexist) +{ + + +} +*/ + +/* ************************************************************ + * work around function start with wa_halbtc8192e1ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8192e1ant_ + * ************************************************************ */ +void ex_halbtc8192e1ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ +#if 0 + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + + btcoexist->stop_coex_dm = true; + + btcoexist->btc_write_1byte(btcoexist, 0x67, 0x20); + + /* enable BB, REG_SYS_FUNC_EN such that we can write 0x948 correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT(0) | BIT(1)); + + /* set GRAN_BT = 1 */ + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + /* set WLAN_ACT = 0 */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* */ + /* S0 or S1 setting and Local register setting(By the setting fw can get ant number, S0/S1, ... info) */ + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + + u8tmp |= 0x1; /* antenna inverse */ + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + /* set to S1 */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x280); + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + u8tmp |= 0x1; /* antenna inverse */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + } + + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x384, + u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, + u8tmp); + } +#endif +} + +void ex_halbtc8192e1ant_pre_load_firmware(IN struct btc_coexist *btcoexist) +{ +} + +void ex_halbtc8192e1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8192e1ant_init_hw_config(btcoexist, wifi_only); + btcoexist->stop_coex_dm = false; +} + +void ex_halbtc8192e1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = false; + + halbtc8192e1ant_init_coex_dm(btcoexist); + + halbtc8192e1ant_query_bt_info(btcoexist); +} + +void ex_halbtc8192e1ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u32 u32tmp[4]; + u32 fw_ver = 0, bt_patch_ver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + if (btcoexist->stop_coex_dm) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "Ant PG number/ Ant mechanism:", + board_info->pg_ant_num, board_info->btdm_ant_num); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", + "CoexVer/ FwVer/ PatchVer", + glcoex_ver_date_8192e_1ant, glcoex_ver_8192e_1ant, fw_ver, + bt_patch_ver, bt_patch_ver); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "Wifi channel informed to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", + "BT [status/ rssi/ retryCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") + : ((BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi, coex_sta->bt_retry_cnt); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + "SCO/HID/PAN/A2DP", + bt_link_info->sco_exist, bt_link_info->hid_exist, + bt_link_info->pan_exist, bt_link_info->a2dp_exist); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext & BIT(0)) ? "Basic rate" : "EDR rate"); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8192E_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8192e_1ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + if (!btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanisms]============"); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", + "PS TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + coex_dm->auto_tdma_adjust); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", + "Latest error condition(should be 0)", + coex_dm->error_condition); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", + "IgnWlanAct", + coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + } + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc04); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xd04); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x90c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0xc04/ 0xd04/ 0x90c", + u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x778", + u8tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x92c); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x930); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x92c/ 0x930", + (u8tmp[0]), u32tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x4f); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x40/ 0x4f", + u8tmp[0], u8tmp[1]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", + u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", + u32tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(hp rx[31:16]/tx[15:0])", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(lp rx[31:16]/tx[15:0])", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8192E_1ANT == 1) + halbtc8192e1ant_monitor_bt_ctr(btcoexist); +#endif + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + +void ex_halbtc8192e1ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8192e1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, + true); + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = false; + + halbtc8192e1ant_init_hw_config(btcoexist, false); + halbtc8192e1ant_init_coex_dm(btcoexist); + halbtc8192e1ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8192e1ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8192e1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + u8 u8tmpa, u8tmpb; + u32 u32tmp; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if (BTC_SCAN_START == type) { + coex_sta->wifi_is_high_pri_task = true; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + + halbtc8192e1ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 8); /* Force antenna setup for no scan result issue */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x67); + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x\n", + u32tmp, u8tmpa, u8tmpb); + BTC_TRACE(trace_buf); + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + } + + if (coex_sta->bt_disabled) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + halbtc8192e1ant_query_bt_info(btcoexist); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + halbtc8192e1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8192e1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8192e1ant_action_wifi_multi_port(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8192e1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8192e1ant_action_hs(btcoexist); + return; + } + + if (BTC_SCAN_START == type) { + if (!wifi_connected) /* non-connected scan */ + halbtc8192e1ant_action_wifi_not_connected_scan( + btcoexist); + else /* wifi is connected */ + halbtc8192e1ant_action_wifi_connected_scan(btcoexist); + } else if (BTC_SCAN_FINISH == type) { + if (!wifi_connected) /* non-connected scan */ + halbtc8192e1ant_action_wifi_not_connected(btcoexist); + else + halbtc8192e1ant_action_wifi_connected(btcoexist); + } +} + +void ex_halbtc8192e1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + coex_sta->bt_disabled) + return; + + if (BTC_ASSOCIATE_START == type) { + coex_sta->wifi_is_high_pri_task = true; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify\n"); + BTC_TRACE(trace_buf); + coex_dm->arp_cnt = 0; + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify\n"); + BTC_TRACE(trace_buf); + /* coex_dm->arp_cnt = 0; */ + } + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + halbtc8192e1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8192e1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8192e1ant_action_wifi_multi_port(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8192e1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8192e1ant_action_hs(btcoexist); + return; + } + + if (BTC_ASSOCIATE_START == type) + halbtc8192e1ant_action_wifi_not_connected_asso_auth(btcoexist); + else if (BTC_ASSOCIATE_FINISH == type) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (!wifi_connected) /* non-connected scan */ + halbtc8192e1ant_action_wifi_not_connected(btcoexist); + else + halbtc8192e1ant_action_wifi_connected(btcoexist); + } +} + +void ex_halbtc8192e1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + boolean wifi_under_b_mode = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + coex_sta->bt_disabled) + return; + + if (BTC_MEDIA_CONNECT == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x10); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } + + coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, + 0x430); + coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, + 0x434); + coex_dm->backup_retry_limit = btcoexist->btc_read_2byte( + btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = btcoexist->btc_read_1byte( + btcoexist, 0x456); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + coex_dm->arp_cnt = 0; + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + } + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + /* h2c_parameter[0] = 0x1; */ + h2c_parameter[0] = 0x0; + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8192e1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + coex_sta->bt_disabled) + return; + + if (BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type || + BTC_PACKET_ARP == type) { + if (BTC_PACKET_ARP == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ARP notify\n"); + BTC_TRACE(trace_buf); + + coex_dm->arp_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ARP Packet Count = %d\n", + coex_dm->arp_cnt); + BTC_TRACE(trace_buf); + + if (coex_dm->arp_cnt >= + 10) /* if APR PKT > 10 after connect, do not go to ActionWifiConnectedSpecificPacket(btcoexist) */ + coex_sta->wifi_is_high_pri_task = false; + else + coex_sta->wifi_is_high_pri_task = true; + } else { + coex_sta->wifi_is_high_pri_task = true; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet DHCP or EAPOL notify\n"); + BTC_TRACE(trace_buf); + } + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet [Type = %d] notify\n", type); + BTC_TRACE(trace_buf); + } + + coex_sta->specific_pkt_period_cnt = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + halbtc8192e1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8192e1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8192e1ant_action_wifi_multi_port(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8192e1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8192e1ant_action_hs(btcoexist); + return; + } + + if (BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type || + ((BTC_PACKET_ARP == type) && (coex_sta->wifi_is_high_pri_task))) + halbtc8192e1ant_action_wifi_connected_specific_packet(btcoexist); +} + +void ex_halbtc8192e1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + boolean wifi_connected = false; + boolean bt_busy = false; + + coex_sta->c2h_bt_info_req_sent = false; + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8192E_1ANT_MAX) + rsp_source = BT_INFO_SRC_8192E_1ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt info[%d], length=%d, hex data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + if (BT_INFO_SRC_8192E_1ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0] */ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->bt_info_c2h[rsp_source][2] & 0x20) + coex_sta->c2h_bt_page = true; + else + coex_sta->c2h_bt_page = false; + + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3] * 2 - 90; + /* coex_sta->bt_info_c2h[rsp_source][3]*2+10; */ + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rsp_source][4]; + + coex_sta->bt_tx_rx_mask = (coex_sta->bt_info_c2h[rsp_source][2] + & 0x40); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TX_RX_MASK, + &coex_sta->bt_tx_rx_mask); + if (!coex_sta->bt_tx_rx_mask) { + /* BT into is responded by BT FW and BT RF REG 0x3C != 0x15 => Need to switch BT TRx Mask */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x15\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x3c, 0x15); + } + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + if (coex_sta->bt_info_ext & BIT(1)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) + ex_halbtc8192e1ant_media_status_notify( + btcoexist, BTC_MEDIA_CONNECT); + else + ex_halbtc8192e1ant_media_status_notify( + btcoexist, BTC_MEDIA_DISCONNECT); + } + + if (coex_sta->bt_info_ext & BIT(3)) { + if (!btcoexist->manual_control && + !btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8192e1ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, false); + } + } else { + /* BT already NOT ignore Wlan active, do nothing here. */ + } +#if (BT_AUTO_REPORT_ONLY_8192E_1ANT == 0) + if ((coex_sta->bt_info_ext & BIT(4))) { + /* BT auto report already enabled, do nothing */ + } else + halbtc8192e1ant_bt_auto_report(btcoexist, FORCE_EXEC, + true); +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (bt_info & BT_INFO_8192E_1ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status */ + if (!(bt_info & BT_INFO_8192E_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8192E_1ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8192E_1ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8192E_1ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8192E_1ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + } + + halbtc8192e1ant_update_bt_link_info(btcoexist); + + bt_info = bt_info & + 0x1f; /* mask profile bit for connect-ilde identification ( for CSR case: A2DP idle --> 0x41) */ + + if (!(bt_info & BT_INFO_8192E_1ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info == + BT_INFO_8192E_1ANT_B_CONNECTION) { /* connection exists but no busy */ + coex_dm->bt_status = BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + BTC_TRACE(trace_buf); + } else if ((bt_info & BT_INFO_8192E_1ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8192E_1ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8192E_1ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info & BT_INFO_8192E_1ANT_B_ACL_BUSY) { + if (BT_8192E_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status) + coex_dm->auto_tdma_adjust = false; + coex_dm->bt_status = BT_8192E_1ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + BTC_TRACE(trace_buf); + } else { + coex_dm->bt_status = BT_8192E_1ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + BTC_TRACE(trace_buf); + } + + if ((BT_8192E_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8192E_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + halbtc8192e1ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8192e1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u32 u32tmp; + u8 u8tmpa, u8tmpb, u8tmpc; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], RF Status notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_RF_ON == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned ON!!\n"); + BTC_TRACE(trace_buf); + btcoexist->stop_coex_dm = false; + } else if (BTC_RF_OFF == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned OFF!!\n"); + BTC_TRACE(trace_buf); + + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8192e1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8192e1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, + true); + + halbtc8192e1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + btcoexist->stop_coex_dm = true; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x67); + u8tmpc = btcoexist->btc_read_1byte(btcoexist, 0x76e); + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x, 0x76e=0x%x\n", + u32tmp, u8tmpa, u8tmpb, u8tmpc); + BTC_TRACE(trace_buf); + + } +} + +void ex_halbtc8192e1ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + halbtc8192e1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8192e1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, true); + + halbtc8192e1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + ex_halbtc8192e1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + btcoexist->stop_coex_dm = true; +} + +void ex_halbtc8192e1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Pnp notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_WIFI_PNP_SLEEP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + + halbtc8192e1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8192e1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + halbtc8192e1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, + true); + + /* Sinda 20150819, workaround for driver skip leave IPS/LPS to speed up sleep time. */ + /* Driver do not leave IPS/LPS when driver is going to sleep, so BTCoexistence think wifi is still under IPS/LPS */ + /* BT should clear UnderIPS/UnderLPS state to avoid mismatch state after wakeup. */ + coex_sta->under_ips = false; + coex_sta->under_lps = false; + btcoexist->stop_coex_dm = true; + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + btcoexist->stop_coex_dm = false; + halbtc8192e1ant_init_hw_config(btcoexist, false); + halbtc8192e1ant_init_coex_dm(btcoexist); + halbtc8192e1ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8192e1ant_coex_dm_reset(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], *****************Coex DM Reset*****************\n"); + BTC_TRACE(trace_buf); + + halbtc8192e1ant_init_hw_config(btcoexist, false); + /* btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); */ + /* btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x0); */ + halbtc8192e1ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8192e1ant_periodical(IN struct btc_coexist *btcoexist) +{ +#if (BT_AUTO_REPORT_ONLY_8192E_1ANT == 0) + halbtc8192e1ant_query_bt_info(btcoexist); + halbtc8192e1ant_monitor_bt_enable_disable(btcoexist); +#else + halbtc8192e1ant_monitor_bt_ctr(btcoexist); + halbtc8192e1ant_monitor_wifi_ctr(btcoexist); + + if (halbtc8192e1ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + + halbtc8192e1ant_run_coexist_mechanism(btcoexist); + + coex_sta->specific_pkt_period_cnt++; +#endif +} + + +void ex_halbtc8192e1ant_dbg_control(IN struct btc_coexist *btcoexist, + IN u8 op_code, IN u8 op_len, IN u8 *pdata) +{ + switch (op_code) { + case BTC_DBG_SET_COEX_NORMAL: + btcoexist->manual_control = false; + halbtc8192e1ant_init_coex_dm(btcoexist); + break; + case BTC_DBG_SET_COEX_WIFI_ONLY: + btcoexist->manual_control = true; + halbtc8192e1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8192e1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 9); + break; + case BTC_DBG_SET_COEX_BT_ONLY: + /* todo */ + break; + default: + break; + } +} + +#endif /* #if (RTL8192E_SUPPORT == 1) */ + +#endif /* #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e1ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e1ant.h new file mode 100644 index 0000000..e75127c --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e1ant.h @@ -0,0 +1,226 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8192E_SUPPORT == 1) + +/* ******************************************* + * The following is for 8192E 1ANT BT Co-exist definition + * ******************************************* */ +#define BT_AUTO_REPORT_ONLY_8192E_1ANT 1 + +#define BT_INFO_8192E_1ANT_B_FTP BIT(7) +#define BT_INFO_8192E_1ANT_B_A2DP BIT(6) +#define BT_INFO_8192E_1ANT_B_HID BIT(5) +#define BT_INFO_8192E_1ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8192E_1ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8192E_1ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8192E_1ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8192E_1ANT_B_CONNECTION BIT(0) + +#define BT_INFO_8192E_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT(0))) ? true : false) + +#define BTC_RSSI_COEX_THRESH_TOL_8192E_1ANT 2 + +#define BT_8192E_1ANT_WIFI_NOISY_THRESH 30 /* max: 255 */ + +enum bt_info_src_8192e_1ant { + BT_INFO_SRC_8192E_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8192E_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8192E_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8192E_1ANT_MAX +}; + +enum bt_8192e_1ant_bt_status { + BT_8192E_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8192E_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8192E_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8192E_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8192E_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8192E_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8192E_1ANT_BT_STATUS_MAX +}; + +enum bt_8192e_1ant_wifi_status { + BT_8192E_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8192E_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_SPECIFIC_PKT = 0x3, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8192E_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8192E_1ANT_WIFI_STATUS_MAX +}; + +enum bt_8192e_1ant_coex_algo { + BT_8192E_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8192E_1ANT_COEX_ALGO_SCO = 0x1, + BT_8192E_1ANT_COEX_ALGO_HID = 0x2, + BT_8192E_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8192E_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8192E_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8192E_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8192E_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8192E_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8192E_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8192E_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8192E_1ANT_COEX_ALGO_MAX = 0xb, +}; + +struct coex_dm_8192e_1ant { + /* fw mechanism */ + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean auto_tdma_adjust; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + /* sw mechanism */ + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + boolean limited_dig; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u32 pre_ra_mask; + u32 cur_ra_mask; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; + u32 arp_cnt; + + u8 error_condition; +}; + +struct coex_sta_8192e_1ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + + boolean under_lps; + boolean under_ips; + u32 specific_pkt_period_cnt; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + s8 bt_rssi; + boolean bt_tx_rx_mask; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + boolean c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8192E_1ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8192E_1ANT_MAX]; + boolean c2h_bt_inquiry_page; + boolean c2h_bt_page; /* Add for win8.1 page out issue */ + boolean wifi_is_high_pri_task; /* Add for win8.1 page out issue */ + u8 bt_retry_cnt; + u8 bt_info_ext; + u32 pop_event_cnt; + u8 scan_ap_num; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_agg; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_agg; + + boolean cck_lock; + boolean pre_ccklock; + u8 coex_table_type; + + boolean force_lps_on; +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8192e1ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8192e1ant_pre_load_firmware(IN struct btc_coexist *btcoexist); +void ex_halbtc8192e1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8192e1ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8192e1ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8192e1ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8192e1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8192e1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8192e1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8192e1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8192e1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8192e1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8192e1ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8192e1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state); +void ex_halbtc8192e1ant_coex_dm_reset(IN struct btc_coexist *btcoexist); +void ex_halbtc8192e1ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8192e1ant_display_coex_info(IN struct btc_coexist *btcoexist); +void ex_halbtc8192e1ant_dbg_control(IN struct btc_coexist *btcoexist, + IN u8 op_code, IN u8 op_len, IN u8 *pdata); + +#else /* #if (RTL8192E_SUPPORT == 1) */ +#define ex_halbtc8192e1ant_power_on_setting(btcoexist) +#define ex_halbtc8192e1ant_pre_load_firmware(btcoexist) +#define ex_halbtc8192e1ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8192e1ant_init_coex_dm(btcoexist) +#define ex_halbtc8192e1ant_ips_notify(btcoexist, type) +#define ex_halbtc8192e1ant_lps_notify(btcoexist, type) +#define ex_halbtc8192e1ant_scan_notify(btcoexist, type) +#define ex_halbtc8192e1ant_connect_notify(btcoexist, type) +#define ex_halbtc8192e1ant_media_status_notify(btcoexist, type) +#define ex_halbtc8192e1ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8192e1ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8192e1ant_rf_status_notify(btcoexist, type) +#define ex_halbtc8192e1ant_halt_notify(btcoexist) +#define ex_halbtc8192e1ant_pnp_notify(btcoexist, pnp_state) +#define ex_halbtc8192e1ant_coex_dm_reset(btcoexist) +#define ex_halbtc8192e1ant_periodical(btcoexist) +#define ex_halbtc8192e1ant_display_coex_info(btcoexist) +#define ex_halbtc8192e1ant_dbg_control(btcoexist, op_code, op_len, pdata) + +#endif + +#endif diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e2ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e2ant.c new file mode 100644 index 0000000..312877d --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e2ant.c @@ -0,0 +1,4377 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8192E Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8192E_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8192e_2ant glcoex_dm_8192e_2ant; +static struct coex_dm_8192e_2ant *coex_dm = &glcoex_dm_8192e_2ant; +static struct coex_sta_8192e_2ant glcoex_sta_8192e_2ant; +static struct coex_sta_8192e_2ant *coex_sta = &glcoex_sta_8192e_2ant; + +const char *const glbt_info_src_8192e_2ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; +/* ************************************************************ + * BtCoex Version Format: + * 1. date : glcoex_ver_date_XXXXX_1ant + * 2. WifiCoexVersion : glcoex_ver_XXXX_1ant + * 3. BtCoexVersion : glcoex_ver_btdesired_XXXXX_1ant + * 4. others : glcoex_ver_XXXXXX_XXXXX_1ant + * + * Variable should be indicated IC and Antenna numbers !!! + * Please strictly follow this order and naming style !!! + * + * ************************************************************ */ +u32 glcoex_ver_date_8192e_2ant = 20160818; +u32 glcoex_ver_8192e_2ant = 0x44; +u32 glcoex_ver_btdesired_8192e_2ant = 0x44; +/*1. add coex. log for wifi/BT coex. version*/ +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8192e2ant_ + * ************************************************************ */ +u8 halbtc8192e2ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8192e2ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 index, IN u8 level_num, IN u8 rssi_thresh, IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8192e2ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false; + + /* This function check if bt is disabled */ + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is enabled !!\n"); + BTC_TRACE(trace_buf); + } else { + bt_disable_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], bt all counters=0, %d times!!\n", + bt_disable_cnt); + BTC_TRACE(trace_buf); + if (bt_disable_cnt >= 2) { + bt_disabled = true; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!\n"); + BTC_TRACE(trace_buf); + } + } + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + coex_sta->bt_disabled = bt_disabled; + /* if (!bt_disabled) { + } else { + } */ + } +} + +u32 halbtc8192e2ant_decide_ra_mask(IN struct btc_coexist *btcoexist, + IN u8 ss_type, IN u32 ra_mask_type) +{ + u32 dis_ra_mask = 0x0; + + switch (ra_mask_type) { + case 0: /* normal mode */ + if (ss_type == 2) + dis_ra_mask = 0x0; /* enable 2ss */ + else + dis_ra_mask = 0xfff00000; /* disable 2ss */ + break; + case 1: /* disable cck 1/2 */ + if (ss_type == 2) + dis_ra_mask = 0x00000003; /* enable 2ss */ + else + dis_ra_mask = 0xfff00003; /* disable 2ss */ + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ + if (ss_type == 2) + dis_ra_mask = 0x0001f1f7; /* enable 2ss */ + else + dis_ra_mask = 0xfff1f1f7; /* disable 2ss */ + break; + default: + break; + } + + return dis_ra_mask; +} + +void halbtc8192e2ant_update_ra_mask(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 dis_rate_mask) +{ + coex_dm->cur_ra_mask = dis_rate_mask; + + if (force_exec || (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_RAMASK, + &coex_dm->cur_ra_mask); + coex_dm->pre_ra_mask = coex_dm->cur_ra_mask; +} + +void halbtc8192e2ant_auto_rate_fallback_retry(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + boolean wifi_under_b_mode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + if (wifi_under_b_mode) { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +void halbtc8192e2ant_retry_limit(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || + (coex_dm->pre_retry_limit_type != + coex_dm->cur_retry_limit_type)) { + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +void halbtc8192e2ant_ampdu_max_time(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || + (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +void halbtc8192e2ant_limited_tx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ra_mask_type, IN u8 arfr_type, + IN u8 retry_limit_type, IN u8 ampdu_time_type) +{ + u32 dis_ra_mask = 0x0; + + coex_dm->cur_ra_mask_type = ra_mask_type; + dis_ra_mask = halbtc8192e2ant_decide_ra_mask(btcoexist, + coex_dm->cur_ss_type, ra_mask_type); + halbtc8192e2ant_update_ra_mask(btcoexist, force_exec, dis_ra_mask); + + halbtc8192e2ant_auto_rate_fallback_retry(btcoexist, force_exec, + arfr_type); + halbtc8192e2ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8192e2ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type); +} + +void halbtc8192e2ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +void halbtc8192e2ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx); + BTC_TRACE(trace_buf); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + + +void halbtc8192e2ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ +#if 1 + + coex_sta->crc_ok_cck = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_CCK); + coex_sta->crc_ok_11g = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_LEGACY); + coex_sta->crc_ok_11n = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_HT); + coex_sta->crc_ok_11n_vht = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_VHT); + + coex_sta->crc_err_cck = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_CCK); + coex_sta->crc_err_11g = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_LEGACY); + coex_sta->crc_err_11n = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_HT); + coex_sta->crc_err_11n_vht = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_VHT); +#endif +} + + + +void halbtc8192e2ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex],Query BT info!!!! H2C 0x61 = 0x1\n"); + BTC_TRACE(trace_buf); +} + +boolean halbtc8192e2ant_is_wifi_status_changed(IN struct btc_coexist *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + + wifi_rssi_state = halbtc8192e2ant_wifi_rssi_state(btcoexist, 0, + 2, 34, 0); + + if ((BTC_RSSI_STATE_HIGH == wifi_rssi_state) || + (BTC_RSSI_STATE_LOW == wifi_rssi_state)) + return true; + } + + return false; +} + +void halbtc8192e2ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + +u8 halbtc8192e2ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8192E_2ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_2ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_2ANT_COEX_ALGO_SCO_PAN; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + if (stack_info->num_of_hid >= 2) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID*2 + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_2ANT_COEX_ALGO_HID_A2DP; + } + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_2ANT_COEX_ALGO_HID; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_2ANT_COEX_ALGO_SCO_PAN; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8192E_2ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_2ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8192E_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +void halbtc8192e2ant_set_fw_dac_swing_level(IN struct btc_coexist *btcoexist, + IN u8 dac_swing_lvl) +{ + u8 h2c_parameter[1] = {0}; + + /* There are several type of dacswing */ + /* 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ + h2c_parameter[0] = dac_swing_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +void halbtc8192e2ant_set_fw_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN u8 dec_bt_pwr_lvl) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = dec_bt_pwr_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +void halbtc8192e2ant_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 dec_bt_pwr_lvl) +{ + coex_dm->cur_bt_dec_pwr_lvl = dec_bt_pwr_lvl; + + if (!force_exec) { +#if 0 /* work around, avoid h2c command fail. */ + if (coex_dm->pre_bt_dec_pwr_lvl == coex_dm->cur_bt_dec_pwr_lvl) + return; +#endif + } + halbtc8192e2ant_set_fw_dec_bt_pwr(btcoexist, + coex_dm->cur_bt_dec_pwr_lvl); + + coex_dm->pre_bt_dec_pwr_lvl = coex_dm->cur_bt_dec_pwr_lvl; +} + +void halbtc8192e2ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8192e2ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8192e2ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8192e2ant_fw_dac_swing_lvl(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 fw_dac_swing_lvl) +{ + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + + if (!force_exec) { + if (coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + halbtc8192e2ant_set_fw_dac_swing_level(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +void halbtc8192e2ant_set_sw_rf_rx_lpf_corner(IN struct btc_coexist *btcoexist, + IN boolean rx_rf_shrink_on) +{ + if (rx_rf_shrink_on) { + /* Shrink RF Rx LPF corner */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Shrink RF Rx LPF corner!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff, + 0xffffc); + } else { + /* Resume RF Rx LPF corner */ + /* After initialized, we can use coex_dm->bt_rf_0x1e_backup */ + if (btcoexist->initilized) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Resume RF Rx LPF corner!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, coex_dm->bt_rf_0x1e_backup); + } + } +} + +void halbtc8192e2ant_rf_shrink(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rx_rf_shrink_on) +{ + coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + + if (!force_exec) { + if (coex_dm->pre_rf_rx_lpf_shrink == + coex_dm->cur_rf_rx_lpf_shrink) + return; + } + halbtc8192e2ant_set_sw_rf_rx_lpf_corner(btcoexist, + coex_dm->cur_rf_rx_lpf_shrink); + + coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +void halbtc8192e2ant_set_sw_penalty_tx_rate_adaptive(IN struct btc_coexist + *btcoexist, IN boolean low_penalty_ra) +{ + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* op_code, 0x6= Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT(0); + h2c_parameter[2] = + 0x00; /* normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[3] = 0xf7; /* MCS7 or OFDM54 */ + h2c_parameter[4] = 0xf8; /* MCS6 or OFDM48 */ + h2c_parameter[5] = 0xf9; /* MCS5 or OFDM36 */ + } + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +void halbtc8192e2ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + halbtc8192e2ant_set_sw_penalty_tx_rate_adaptive(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +void halbtc8192e2ant_set_dac_swing_reg(IN struct btc_coexist *btcoexist, + IN u32 level) +{ + u8 val = (u8)level; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Write SwDacSwing = 0x%x\n", level); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val); +} + +void halbtc8192e2ant_set_sw_full_time_dac_swing(IN struct btc_coexist + *btcoexist, IN boolean sw_dac_swing_on, IN u32 sw_dac_swing_lvl) +{ + if (sw_dac_swing_on) + halbtc8192e2ant_set_dac_swing_reg(btcoexist, sw_dac_swing_lvl); + else + halbtc8192e2ant_set_dac_swing_reg(btcoexist, 0x18); +} + + +void halbtc8192e2ant_dac_swing(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean dac_swing_on, IN u32 dac_swing_lvl) +{ + coex_dm->cur_dac_swing_on = dac_swing_on; + coex_dm->cur_dac_swing_lvl = dac_swing_lvl; + + if (!force_exec) { + if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && + (coex_dm->pre_dac_swing_lvl == + coex_dm->cur_dac_swing_lvl)) + return; + } + delay_ms(30); + halbtc8192e2ant_set_sw_full_time_dac_swing(btcoexist, dac_swing_on, + dac_swing_lvl); + + coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; + coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +void halbtc8192e2ant_set_adc_back_off(IN struct btc_coexist *btcoexist, + IN boolean adc_back_off) +{ + if (adc_back_off) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB BackOff Level On!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc05, 0x30, 0x3); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB BackOff Level Off!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc05, 0x30, 0x1); + } +} + +void halbtc8192e2ant_adc_back_off(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean adc_back_off) +{ + coex_dm->cur_adc_back_off = adc_back_off; + + if (!force_exec) { + if (coex_dm->pre_adc_back_off == coex_dm->cur_adc_back_off) + return; + } + halbtc8192e2ant_set_adc_back_off(btcoexist, coex_dm->cur_adc_back_off); + + coex_dm->pre_adc_back_off = coex_dm->cur_adc_back_off; +} + +void halbtc8192e2ant_set_agc_table(IN struct btc_coexist *btcoexist, + IN boolean agc_table_en) +{ + /* =================BB AGC Gain Table */ + if (agc_table_en) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB Agc Table On!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x0a1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x091B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x081C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x071D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x061E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x051F0001); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB Agc Table Off!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001); + } +} + +void halbtc8192e2ant_agc_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean agc_table_en) +{ + coex_dm->cur_agc_table_en = agc_table_en; + + if (!force_exec) { + if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en) + return; + } + halbtc8192e2ant_set_agc_table(btcoexist, agc_table_en); + + coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en; +} + +void halbtc8192e2ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8192e2ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8192e2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8192e2ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + switch (type) { + case 0: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x55555555, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 1: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x55dd55dd, + 0x5ada5ada, 0xffffff, 0x3); + break; + case 3: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x5fdf5fdf, + 0x5fdb5fdb, 0xffffff, 0x3); + break; + case 4: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0xdfffdfff, + 0x5ffb5ffb, 0xffffff, 0x3); + break; + case 5: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x5ddd5ddd, + 0x5fdb5fdb, 0xffffff, 0x3); + break; + case 6: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x5fff5fff, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 7: + if (coex_sta->scan_ap_num <= NOISY_AP_NUM_THRESH_8192E) + halbtc8192e2ant_coex_table(btcoexist, force_exec, + 0xffffffff, 0xfafafafa, 0xffffff, 0x3); + else + halbtc8192e2ant_coex_table(btcoexist, force_exec, + 0xffffffff, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 8: + halbtc8192e2ant_coex_table(btcoexist, force_exec, 0x5f5f5f5f, + 0x5a5a5a5a, 0xffffff, 0x3); + break; + default: + break; + } +} + +void halbtc8192e2ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT(0); /* function enable */ + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8192e2ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8192e2ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8192e2ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8192e2ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8192e2ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8192e2ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], FW for 1Ant AP mode\n"); + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + } + } + + h2c_parameter[0] = byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = byte5; + + coex_dm->ps_tdma_para[0] = byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +void halbtc8192e2ant_sw_mechanism1(IN struct btc_coexist *btcoexist, + IN boolean shrink_rx_lpf, IN boolean low_penalty_ra, + IN boolean limited_dig, IN boolean bt_lna_constrain) +{ + /* + u32 wifi_bw; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 != wifi_bw) + { + if (shrink_rx_lpf) + shrink_rx_lpf = false; + } + */ + + halbtc8192e2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); + /* halbtc8192e2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); */ +} + +void halbtc8192e2ant_sw_mechanism2(IN struct btc_coexist *btcoexist, + IN boolean agc_table_shift, IN boolean adc_back_off, + IN boolean sw_dac_swing, IN u32 dac_swing_lvl) +{ + halbtc8192e2ant_agc_table(btcoexist, NORMAL_EXEC, agc_table_shift); + /* halbtc8192e2ant_adc_back_off(btcoexist, NORMAL_EXEC, adc_back_off); */ + halbtc8192e2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing, + dac_swing_lvl); +} + +void halbtc8192e2ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean init_hwcfg, IN boolean wifi_off) +{ + u32 u32tmp = 0; + + if (init_hwcfg) { + btcoexist->btc_write_1byte(btcoexist, 0x944, 0x24); + btcoexist->btc_write_4byte(btcoexist, 0x930, 0x700700); + if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30430004); + else + btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30030004); + + /* 0x4c[27][24]='00', Set Antenna to BB */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT(24); + u32tmp &= ~BIT(27); + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + } else if (wifi_off) { + if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30430004); + else + btcoexist->btc_write_4byte(btcoexist, 0x64, 0x30030004); + + /* 0x4c[27][24]='11', Set Antenna to BT, 0x64[8:7]=0, 0x64[2]=1 */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp |= BIT(24); + u32tmp |= BIT(27); + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + } + + /* ext switch setting */ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x4); + break; + case BTC_ANT_PATH_BT: + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x20); + break; + default: + case BTC_ANT_PATH_PTA: + btcoexist->btc_write_1byte(btcoexist, 0x92c, 0x4); + break; + } +} + +void halbtc8192e2ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + s8 wifi_duration_adjust = 0x0; + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + + if (coex_sta->scan_ap_num >= 40) + wifi_duration_adjust = -15; + else if (coex_sta->scan_ap_num >= 20) + wifi_duration_adjust = -10; + + + if (turn_on) { + switch (type) { + case 1: + default: /*d1,wb*/ + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x3c, + 0x03, 0x11, 0x10); + break; + case 2: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x32, + 0x03, 0x11, 0x10); + break; + case 3: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x28, + 0x03, 0x11, 0x10); + break; + case 4: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1e, + 0x03, 0x11, 0x10); + break; + case 5: /*d1,pb,TXpause*/ + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x63, 0x3c, + 0x03, 0x90, 0x10); + break; + case 6: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x63, 0x32, + 0x03, 0x90, 0x10); + break; + case 7: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x63, 0x28, + 0x03, 0x90, 0x10); + break; + case 8: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x63, 0x1e, + 0x03, 0x90, 0x10); + break; + case 9: /*d1,bb*/ + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x3c, + 0x03, 0x31, 0x10); + break; + case 10: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x32, + 0x03, 0x31, 0x10); + break; + case 11: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x28, + 0x03, 0x31, 0x10); + break; + case 12: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1e, + 0x03, 0x31, 0x10); + break; + case 13: /*d1,bb,TXpause*/ + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x3c, + 0x03, 0x30, 0x10); + break; + case 14: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x32, + 0x03, 0x30, 0x10); + break; + case 15: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x28, + 0x03, 0x30, 0x10); + break; + case 16: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1e, + 0x03, 0x30, 0x10); + break; + case 17: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x61, 0x20, + 0x03, 0x10, 0x10); + break; + case 18: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5, 0x5, + 0xe1, 0x90); + break; + case 19: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x25, + 0x25, 0xe1, 0x90); + break; + case 20: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x25, + 0x25, 0x60, 0x90); + break; + case 21: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x61, 0x35, + 0x03, 0x11, 0x11); + break; + case 22: /* d1,wb */ + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x14, + 0x03, 0x11, 0x14); + break; + case 23: /* d1,pb,TXpause */ + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x63, 0x14, + 0x03, 0x90, 0x14); + break; + case 24: /* d1,bb */ + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x14, + 0x03, 0x31, 0x14); + break; + case 25: /* d1,bb,TXpause */ + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x14, + 0x03, 0x30, 0x14); + break; + case 71: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, + 0x1a, 0xe1, 0x90); + break; + /* following cases is for wifi rssi low // bad antenna isolation, started from 81 */ + case 80: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x51, 0x3c, + 0x3, 0x10, 0x50); + break; + case 81: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x51, + 0x3a + wifi_duration_adjust, 0x3, 0x10, 0x50); + break; + case 82: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x51, + 0x30 + wifi_duration_adjust, 0x03, 0x10, 0x50); + break; + case 83: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x51, 0x21, + 0x03, 0x10, 0x50); + break; + case 84: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x51, 0x15, + 0x3, 0x10, 0x50); + break; + case 85: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x51, 0x3a, + 0x03, 0x10, 0x50); + break; + case 86: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x51, 0x21, + 0x03, 0x10, 0x50); + break; + case 87: + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x51, 0x14, + 0x03, 0x10, 0x54); + break; + + } + } else { + /* disable PS tdma */ + switch (type) { + default: + case 0: /* ANT2PTA, 0x778=1 */ + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x8, + 0x0, 0x0, 0x0, 0x0); + halbtc8192e2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, false, false); + break; + case 1: /* ANT2BT, 0x778=3 */ + halbtc8192e2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x8, 0x0); + delay_ms(5); + halbtc8192e2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_BT, false, false); + break; + + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void halbtc8192e2ant_set_switch_ss_type(IN struct btc_coexist *btcoexist, + IN u8 ss_type) +{ + u8 mimo_ps = BTC_MIMO_PS_DYNAMIC; + u32 dis_ra_mask = 0x0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], REAL set SS Type = %d\n", ss_type); + BTC_TRACE(trace_buf); + + dis_ra_mask = halbtc8192e2ant_decide_ra_mask(btcoexist, ss_type, + coex_dm->cur_ra_mask_type); + halbtc8192e2ant_update_ra_mask(btcoexist, FORCE_EXEC, dis_ra_mask); + + if (ss_type == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); + /* switch ofdm path */ + btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x11); + btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x1); + btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81111111); + /* switch cck patch */ + /* btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x1); */ + /* btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x81); */ + mimo_ps = BTC_MIMO_PS_STATIC; + } else if (ss_type == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + btcoexist->btc_write_1byte(btcoexist, 0xc04, 0x33); + btcoexist->btc_write_1byte(btcoexist, 0xd04, 0x3); + btcoexist->btc_write_4byte(btcoexist, 0x90c, 0x81121313); + /* remove, if 0xe77[2]=0x0 then CCK will fail, advised by Jenyu */ + /* btcoexist->btc_write_1byte_bitmask(btcoexist, 0xe77, 0x4, 0x0); */ + /* btcoexist->btc_write_1byte(btcoexist, 0xa07, 0x41); */ + mimo_ps = BTC_MIMO_PS_DYNAMIC; + } + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_SEND_MIMO_PS, + &mimo_ps); /* set rx 1ss or 2ss */ +} + +void halbtc8192e2ant_switch_ss_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 new_ss_type) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], %s Switch SS Type = %d\n", + (force_exec ? "force to" : ""), new_ss_type); + BTC_TRACE(trace_buf); + coex_dm->cur_ss_type = new_ss_type; + + if (!force_exec) { + if (coex_dm->pre_ss_type == coex_dm->cur_ss_type) + return; + } + halbtc8192e2ant_set_switch_ss_type(btcoexist, coex_dm->cur_ss_type); + + coex_dm->pre_ss_type = coex_dm->cur_ss_type; +} + +void halbtc8192e2ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +void halbtc8192e2ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + boolean ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + ps_type = BTC_PS_WIFI_NATIVE; + lps_val = 0x0; + rpwm_val = 0x0; + } + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + break; + case BTC_PS_LPS_ON: + halbtc8192e2ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8192e2ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + break; + default: + break; + } +} + + +void halbtc8192e2ant_coex_all_off(IN struct btc_coexist *btcoexist) +{ + /* fw all off */ + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + /* hw all off */ + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8192e2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); + halbtc8192e2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, 0); + + halbtc8192e2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + halbtc8192e2ant_switch_ss_type(btcoexist, FORCE_EXEC, 2); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +void halbtc8192e2ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + + + /* halbtc8192e2ant_switch_ss_type(btcoexist, NORMAL_EXEC, 1);*/ + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 21); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +boolean halbtc8192e2ant_is_common_action(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean common = false, wifi_connected = false, wifi_busy = false; + boolean bt_hs_on = false, low_pwr_disable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (bt_link_info->sco_exist || bt_link_info->hid_exist) + halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 0, 0, 0); + else + halbtc8192e2ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + if (!wifi_connected) { + + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non-connected idle!!\n"); + BTC_TRACE(trace_buf); + + if ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) || + (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + /* halbtc8192e2ant_switch_ss_type(btcoexist, NORMAL_EXEC, 2);*/ + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + } else { + /* halbtc8192e2ant_switch_ss_type(btcoexist, NORMAL_EXEC, 1);*/ + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + } + + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, + false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + + common = true; + } else { + if (BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + /* halbtc8192e2ant_switch_ss_type(btcoexist, NORMAL_EXEC, 2);*/ + + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 6); + halbtc8192e2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + common = true; + } else if (BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status) { + + if (bt_hs_on) + return false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + /* halbtc8192e2ant_switch_ss_type(btcoexist, NORMAL_EXEC, 2);*/ + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 6); + halbtc8192e2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + common = true; + } else { + + if (wifi_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + BTC_TRACE(trace_buf); + common = false; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + /* halbtc8192e2ant_switch_ss_type(btcoexist, NORMAL_EXEC, 1);*/ + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 21); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, + NORMAL_EXEC, 6); + halbtc8192e2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, 0); + halbtc8192e2ant_sw_mechanism1(btcoexist, false, + false, false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, + false, false, 0x18); + common = true; + } + } + } + + return common; +} +void halbtc8192e2ant_tdma_duration_adjust(IN struct btc_coexist *btcoexist, + IN boolean sco_hid, IN boolean tx_pause, IN u8 max_interval) +{ + static s32 up, dn, m, n, wait_count; + s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */ + u8 retry_count = 0; + + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + { + if (sco_hid) { + if (tx_pause) { + if (max_interval == 1) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = + 13; + } else if (max_interval == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (max_interval == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } + } else { + if (max_interval == 1) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = + 9; + } else if (max_interval == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (max_interval == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } + } + } else { + if (tx_pause) { + if (max_interval == 1) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = + 5; + } else if (max_interval == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (max_interval == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } + } else { + if (max_interval == 1) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (max_interval == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (max_interval == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } + } + } + } + /* ============ */ + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /* acquire the BT TRx retry count from BT_Info byte2 */ + retry_count = coex_sta->bt_retry_cnt; + result = 0; + wait_count++; + + if (retry_count == + 0) { /* no retry in the last 2-second duration */ + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { /* if retry count during continuous n*2 seconds is 0, enlarge WiFi duration */ + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + } + } else if (retry_count <= + 3) { /* <=3 retry in the last 2-second duration */ + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { /* if continuous 2 retry count(every 2 seconds) >0 and < 3, reduce WiFi duration */ + if (wait_count <= 2) + m++; /* to avoid loop between the two levels */ + else + m = 1; + + if (m >= 20) /* maximum of m = 20 ' will recheck if need to adjust wifi duration in maximum time interval 120 seconds */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + } else { /* retry count > 3, once retry count > 3, to reduce WiFi duration */ + if (wait_count == 1) + m++; /* to avoid loop between the two levels */ + else + m = 1; + + if (m >= 20) /* maximum of m = 20 ' will recheck if need to adjust wifi duration in maximum time interval 120 seconds */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + + if (max_interval == 1) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 13); + coex_dm->ps_tdma_du_adj_type = 13; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = + 5; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = + 13; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 1); + coex_dm->ps_tdma_du_adj_type = 1; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 71); + coex_dm->ps_tdma_du_adj_type = + 71; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = + 9; + } + } + } + } else if (max_interval == 2) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } + } + } + } else if (max_interval == 3) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8192e2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8192e2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } + } + } + } + } + + /* if current PsTdma not match with the recorded one (when scan, dhcp...), */ + /* then we have to adjust it back to the previous record one. */ + if (coex_dm->cur_ps_tdma != coex_dm->ps_tdma_du_adj_type) { + boolean scan = false, link = false, roam = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PsTdma type dismatch!!!, cur_ps_tdma=%d, recordPsTdma=%d\n", + coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (!scan && !link && !roam) + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->ps_tdma_du_adj_type); + else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"); + BTC_TRACE(trace_buf); + } + } +} + +/* ****************** + * pstdma for wifi rssi low + * ****************** */ +void halbtc8192e2ant_tdma_duration_adjust_for_wifi_rssi_low( + IN struct btc_coexist *btcoexist/* , */ /* IN u8 wifi_status */) +{ + static s32 up, dn, m, n, wait_count; + s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */ + u8 retry_count = 0, bt_info_ext; + + coex_dm->auto_tdma_adjust = false; + + retry_count = coex_sta->bt_retry_cnt; + bt_info_ext = coex_sta->bt_info_ext; + + if (!coex_dm->auto_tdma_adjust_low_rssi) { + coex_dm->auto_tdma_adjust_low_rssi = true; + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 81); + coex_dm->ps_tdma_du_adj_type = 81; + /* ============ */ + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /* acquire the BT TRx retry count from BT_Info byte2 + * retry_count = coex_sta->bt_retry_cnt; + * bt_info_ext = coex_sta->bt_info_ext; */ + result = 0; + wait_count++; + + if ((coex_sta->low_priority_tx) > 1050 || + (coex_sta->low_priority_rx) > 1250) + retry_count++; + + if (retry_count == + 0) { /* no retry in the last 2-second duration */ + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { /* if retry count during continuous n*2 seconds is 0, enlarge WiFi duration */ + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + } + } else if (retry_count <= + 3) { /* <=3 retry in the last 2-second duration */ + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { /* if continuous 2 retry count(every 2 seconds) >0 and < 3, reduce WiFi duration */ + if (wait_count <= 2) + m++; /* to avoid loop between the two levels */ + else + m = 1; + + if (m >= 20) /* maximum of m = 20 ' will recheck if need to adjust wifi duration in maximum time interval 120 seconds */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + } else { /* retry count > 3, once retry count > 3, to reduce WiFi duration */ + if (wait_count == 1) + m++; /* to avoid loop between the two levels */ + else + m = 1; + + if (m >= 20) /* maximum of m = 20 ' will recheck if need to adjust wifi duration in maximum time interval 120 seconds */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 80) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 81); + coex_dm->ps_tdma_du_adj_type = 81; + } else if (coex_dm->cur_ps_tdma == 81) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 82); + coex_dm->ps_tdma_du_adj_type = 82; + } else if (coex_dm->cur_ps_tdma == 82) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 83); + coex_dm->ps_tdma_du_adj_type = 83; + } else if (coex_dm->cur_ps_tdma == 83) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 84); + coex_dm->ps_tdma_du_adj_type = 84; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 84) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 83); + coex_dm->ps_tdma_du_adj_type = 83; + } else if (coex_dm->cur_ps_tdma == 83) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 82); + coex_dm->ps_tdma_du_adj_type = 82; + } else if (coex_dm->cur_ps_tdma == 82) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 81); + coex_dm->ps_tdma_du_adj_type = 81; + } else if ((coex_dm->cur_ps_tdma == 81) && + (coex_sta->scan_ap_num <= 5)) { + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 81); + coex_dm->ps_tdma_du_adj_type = 81; + } + } + + if (coex_dm->cur_ps_tdma != 80 && + coex_dm->cur_ps_tdma != 81 && + coex_dm->cur_ps_tdma != 82 && + coex_dm->cur_ps_tdma != 83 && + coex_dm->cur_ps_tdma != 84) { + /* recover to previous adjust type */ + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->ps_tdma_du_adj_type); + } + } +} + + +void halbtc8192e2ant_get_bt_rssi_threshold(IN struct btc_coexist *btcoexist, + IN u8 *pThres0, IN u8 *pThres1) +{ + u8 ant_type; + + struct btc_board_info *board_info = &btcoexist->board_info; + + ant_type = board_info->ant_type; + + switch (ant_type) { + case BTC_ANT_TYPE_0: + *pThres0 = 100; + *pThres1 = 100; + break; + case BTC_ANT_TYPE_1: + *pThres0 = 34; + *pThres1 = 42; + break; + case BTC_ANT_TYPE_2: + *pThres0 = 34; + *pThres1 = 42; + break; + case BTC_ANT_TYPE_3: + *pThres0 = 34; + *pThres1 = 42; + break; + case BTC_ANT_TYPE_4: + *pThres0 = 34; + *pThres1 = 42; + break; + default: + break; + } +} + + + + +/* SCO only or SCO+PAN(HS) */ +void halbtc8192e2ant_action_sco(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + halbtc8192e2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, + &bt_thresh1); + bt_rssi_state = halbtc8192e2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + + wifi_rssi_state = halbtc8192e2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + else + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + else + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + + halbtc8192e2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +void halbtc8192e2ant_action_sco_pan(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + + halbtc8192e2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, + &bt_thresh1); + bt_rssi_state = halbtc8192e2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + + wifi_rssi_state = halbtc8192e2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + + if ((BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state)))) + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + else + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + else + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 86); + + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + else + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); +} + + +void halbtc8192e2ant_action_hid(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 anttype = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_ANT_TYPE, &anttype); + + wifi_rssi_state = halbtc8192e2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + bt_rssi_state = halbtc8192e2ant_bt_rssi_state(3, 34, 42); + + if (anttype == 0) { + /*ANTTYPE = 0 92E 2ant with SPDT*/ + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (anttype == 1) { + /*92E 2ant with coupler and bad ant. isolation, 92E 3ant with bad ant. isolation*/ + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (anttype == 2) { + /*ANTTYPE = 2, 92E 2ant with coupler and normal/good ant. isolation, 92E 3ant with normal ant. isolation*/ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) { + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 9); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 3); + } else { + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 9); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 3); + } + } else if (anttype == 3) { + /*ANTTYPE = 3, 92E 3ant with good ant. isolation*/ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) { + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } else { + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } + } + + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8192e2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +void halbtc8192e2ant_action_a2dp(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + boolean long_dist = false; + u8 anttype = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_ANT_TYPE, &anttype); + + wifi_rssi_state = halbtc8192e2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + bt_rssi_state = halbtc8192e2ant_bt_rssi_state(3, 34, 42); + + if (anttype == 0) { + /*ANTTYPE = 0 92E 2ant with SPDT*/ + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 87); + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + } else if (anttype == 1) { + /*92E 2ant with coupler and bad ant. isolation, 92E 3ant with bad ant. isolation*/ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) { + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 25); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } else { + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 87); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } + } else if (anttype == 2) { + /*ANTTYPE = 2, 92E 2ant with coupler and normal/good ant. isolation, 92E 3ant with normal ant. isolation*/ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) { + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 5); + } else { + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 87); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } + } else if (anttype == 3) { + /*ANTTYPE = 3, 92E 3ant with good ant. isolation*/ + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } + + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, true, + 0x06); + else + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); +} + +void halbtc8192e2ant_action_a2dp_pan_hs(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifi_rssi_state = halbtc8192e2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + bt_rssi_state = halbtc8192e2ant_bt_rssi_state(3, 34, 42); + + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + + if ((bt_rssi_state == BTC_RSSI_STATE_LOW) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, true, 2); + halbtc8192e2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + } else if ((bt_rssi_state == BTC_RSSI_STATE_MEDIUM) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, false, + 2); + halbtc8192e2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + } else if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_tdma_duration_adjust(btcoexist, false, false, + 2); + halbtc8192e2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 4); + } + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + true, 0x6); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + true, 0x6); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + true, 0x6); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + true, 0x6); + } + } +} + +void halbtc8192e2ant_action_pan_edr(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + halbtc8192e2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, + &bt_thresh1); + bt_rssi_state = halbtc8192e2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + /* wifi_rssi_state = halbtc8192e2ant_wifi_rssi_state(btcoexist, 0, 2, 34, 0); */ + wifi_rssi_state = BTC_RSSI_STATE_LOW; + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + else + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); + else + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 85); + + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + else + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); +} + +/* PAN(HS) only */ +void halbtc8192e2ant_action_pan_hs(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifi_rssi_state = halbtc8192e2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + bt_rssi_state = halbtc8192e2ant_bt_rssi_state(3, 34, 42); + + /* halbtc8192e2ant_switch_ss_type(btcoexist, NORMAL_EXEC, 1);*/ + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + + if ((bt_rssi_state == BTC_RSSI_STATE_LOW) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) + halbtc8192e2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + else if ((bt_rssi_state == BTC_RSSI_STATE_MEDIUM) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) + halbtc8192e2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + halbtc8192e2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* PAN(EDR)+A2DP */ +void halbtc8192e2ant_action_pan_edr_a2dp(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + halbtc8192e2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, + &bt_thresh1); + bt_rssi_state = halbtc8192e2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + /* wifi_rssi_state = halbtc8192e2ant_wifi_rssi_state(btcoexist, 0, 2, 34, 0); */ + wifi_rssi_state = BTC_RSSI_STATE_LOW; + + if ((BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state)))) + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + else + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4); + else + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 86); + + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + else + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + +} + +void halbtc8192e2ant_action_pan_edr_hid(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + halbtc8192e2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, + &bt_thresh1); + bt_rssi_state = halbtc8192e2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + + wifi_rssi_state = halbtc8192e2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + + if ((BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state)))) + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + else + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + else + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 86); + + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + else + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + + +} + +/* HID+A2DP+PAN(EDR) */ +void halbtc8192e2ant_action_hid_a2dp_pan_edr(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + halbtc8192e2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, + &bt_thresh1); + bt_rssi_state = halbtc8192e2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + wifi_rssi_state = halbtc8192e2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + + if ((BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state)))) + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + else + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 4); + else + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 86); + + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + else + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); +} + +void halbtc8192e2ant_action_hid_a2dp(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0, anttype = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_ANT_TYPE, &anttype); + + wifi_rssi_state = halbtc8192e2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + bt_rssi_state = halbtc8192e2ant_bt_rssi_state(3, 34, 42); + + if (anttype == 0) { + /*92E 2ant with SPDT*/ + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 87); + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + + } else if (anttype == 1) { + /*92E 2ant with coupler and bad ant. isolation, 92E 3ant with bad ant. isolation*/ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) { + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 25); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + } else { + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 87); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + } + } else if (anttype == 2) { + /*ANTTYPE = 2, 92E 2ant with coupler and normal/good ant. isolation, 92E 3ant with normal ant. isolation*/ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) { + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 25); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + } else { + halbtc8192e2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 87); + halbtc8192e2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + } + } else if (anttype == 3) { + /*ANTTYPE = 3, 92E 3ant with good ant. isolation*/ + halbtc8192e2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } + + halbtc8192e2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + halbtc8192e2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + halbtc8192e2ant_sw_mechanism1(btcoexist, false, false, false, false); + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8192E)) + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, true, + 0x06); + else + halbtc8192e2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); +} + +void halbtc8192e2ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + algorithm = halbtc8192e2ant_action_algorithm(btcoexist); + if (coex_sta->c2h_bt_inquiry_page && + (BT_8192E_2ANT_COEX_ALGO_PANHS != algorithm)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_action_bt_inquiry(btcoexist); + return; + } + + coex_dm->cur_algorithm = algorithm; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Algorithm = %d\n", + coex_dm->cur_algorithm); + BTC_TRACE(trace_buf); + + if (halbtc8192e2ant_is_common_action(btcoexist)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant common.\n"); + BTC_TRACE(trace_buf); + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + + } else { + if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], pre_algorithm=%d, cur_algorithm=%d\n", + coex_dm->pre_algorithm, coex_dm->cur_algorithm); + BTC_TRACE(trace_buf); + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + + } + switch (coex_dm->cur_algorithm) { + case BT_8192E_2ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_action_sco(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_SCO_PAN: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = SCO+PAN(EDR).\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_action_sco_pan(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID.\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_action_hid(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_action_a2dp(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_action_pan_edr(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HS mode.\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_action_pan_hs(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_action_pan_edr_hid(btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_action_hid_a2dp_pan_edr( + btcoexist); + break; + case BT_8192E_2ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_action_hid_a2dp(btcoexist); + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = unknown!!\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_coex_all_off(btcoexist); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +void halbtc8192e2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean back_up) +{ + u16 u16tmp = 0; + u8 u8tmp = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 2Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + + if (back_up) { + /* backup rf 0x1e value */ + coex_dm->bt_rf_0x1e_backup = + btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff); + + coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, + 0x430); + coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, + 0x434); + coex_dm->backup_retry_limit = btcoexist->btc_read_2byte( + btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = btcoexist->btc_read_1byte( + btcoexist, 0x456); + } + + /* antenna sw ctrl to bt */ + halbtc8192e2ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, true, false); + + halbtc8192e2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + /* antenna switch control parameter */ + /* btcoexist->btc_write_4byte(btcoexist, 0x858, 0x55555555); */ + + /* coex parameters */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); + /* 0x790[5:0]=0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + /* enable counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* enable PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x40, 0x20); + /* enable mailbox interface */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x40); + u16tmp |= BIT(9); + btcoexist->btc_write_2byte(btcoexist, 0x40, u16tmp); + + /* enable PTA I2C mailbox */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x101); + u8tmp |= BIT(4); + btcoexist->btc_write_1byte(btcoexist, 0x101, u8tmp); + + /* enable bt clock when wifi is disabled. */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x93); + u8tmp |= BIT(0); + btcoexist->btc_write_1byte(btcoexist, 0x93, u8tmp); + /* enable bt clock when suspend. */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x7); + u8tmp |= BIT(0); + btcoexist->btc_write_1byte(btcoexist, 0x7, u8tmp); + + /* Give bt_coex_supported_version the default value */ + coex_sta->bt_coex_supported_version = 0; +} + +/* ************************************************************ + * work around function start with wa_halbtc8192e2ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8192e2ant_ + * ************************************************************ */ +void ex_halbtc8192e2ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ +} + +void ex_halbtc8192e2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8192e2ant_init_hw_config(btcoexist, true); +} + +void ex_halbtc8192e2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + halbtc8192e2ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8192e2ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u16 u16tmp[4]; + u32 u32tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + u32 fw_ver = 0, bt_patch_ver = 0, bt_coex_ver = 0; + u32 phyver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "Ant PG number/ Ant mechanism:", + board_info->pg_ant_num, board_info->btdm_ant_num); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "Antenna type:", + board_info->ant_type); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + bt_coex_ver = ((coex_sta->bt_coex_supported_version & 0xff00) >> 8); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8192e_2ant, glcoex_ver_8192e_2ant, + glcoex_ver_btdesired_8192e_2ant, bt_coex_ver, + (bt_coex_ver == 0xff ? "Unknown" : (bt_coex_ver >= + glcoex_ver_btdesired_8192e_2ant ? "Match" : + "Mis-Match"))); + CL_PRINTF(cli_buf); + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ v%d", + "W_FW/ B_FW/ Phy", fw_ver, bt_patch_ver, phyver); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "Wifi channel informed to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", + "BT [status/ rssi/ retryCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") + : ((BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi, coex_sta->bt_retry_cnt); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + "SCO/HID/PAN/A2DP", + stack_info->sco_exist, stack_info->hid_exist, + stack_info->pan_exist, stack_info->a2dp_exist); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext & BIT(0)) ? "Basic rate" : "EDR rate"); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8192E_2ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8192e_2ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "SS Type", + coex_dm->cur_ss_type); + CL_PRINTF(cli_buf); + + /* Sw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Sw mechanism]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "SM1[ShRf/ LpRA/ LimDig]", + coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra, + coex_dm->limited_dig); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", + "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", + coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, + coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); + CL_PRINTF(cli_buf); + + /* Fw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Fw mechanism]============"); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", + "PS TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + coex_dm->auto_tdma_adjust); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "DecBtPwr/ IgnWlanAct", + coex_dm->cur_bt_dec_pwr_lvl, coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + "RF-A, 0x1e initVal", + coex_dm->bt_rf_0x1e_backup); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "backup ARFR1/ARFR2/RL/AMaxTime", + coex_dm->backup_arfr_cnt1, coex_dm->backup_arfr_cnt2, + coex_dm->backup_retry_limit, + coex_dm->backup_ampdu_max_time); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc04); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xd04); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x90c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0xc04/ 0xd04/ 0x90c", + u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x778", + u8tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x92c); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x930); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x92c/ 0x930", + (u8tmp[0]), u32tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x4f); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x40/ 0x4f", + u8tmp[0], u8tmp[1]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", + u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", + u32tmp[0]); + CL_PRINTF(cli_buf); + + fa_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_OFDM); + fa_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_CCK); + cca_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_OFDM); + cca_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_CCK); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", + cca_cck, fa_cck, cca_ofdm, fa_ofdm); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11n-agg", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11n-agg", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(hp rx[31:16]/tx[15:0])", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(lp rx[31:16]/tx[15:0])", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 1) + halbtc8192e2ant_monitor_bt_ctr(btcoexist); +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8192e2ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + halbtc8192e2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8192e2ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, + true); + halbtc8192e2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = false; + halbtc8192e2ant_init_hw_config(btcoexist, false); + halbtc8192e2ant_init_coex_dm(btcoexist); + halbtc8192e2ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8192e2ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8192e2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + if (BTC_SCAN_START == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + } else if (BTC_SCAN_FINISH == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + + } +} + +void ex_halbtc8192e2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + if (BTC_ASSOCIATE_START == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify\n"); + BTC_TRACE(trace_buf); + } else if (BTC_ASSOCIATE_FINISH == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify\n"); + BTC_TRACE(trace_buf); + } +} + +void ex_halbtc8192e2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + coex_sta->bt_disabled) + return; + + if (BTC_MEDIA_CONNECT == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + } + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + h2c_parameter[0] = 0x1; + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8192e2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + if (type == BTC_PACKET_DHCP) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], DHCP Packet notify\n"); + BTC_TRACE(trace_buf); + } +} + +void ex_halbtc8192e2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + boolean bt_busy = false, limited_dig = false; + boolean wifi_connected = false; + + coex_sta->c2h_bt_info_req_sent = false; + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8192E_2ANT_MAX) + rsp_source = BT_INFO_SRC_8192E_2ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt info[%d], length=%d, hex data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + if (BT_INFO_SRC_8192E_2ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0] */ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rsp_source][4]; + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + if ((coex_sta->bt_info_ext & BIT(1))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) + ex_halbtc8192e2ant_media_status_notify( + btcoexist, BTC_MEDIA_CONNECT); + else + ex_halbtc8192e2ant_media_status_notify( + btcoexist, BTC_MEDIA_DISCONNECT); + } + + if ((coex_sta->bt_info_ext & BIT(3))) { + if (!btcoexist->manual_control && + !btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8192e2ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, false); + } + } else { + /* BT already NOT ignore Wlan active, do nothing here. */ + } + +#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) + if ((coex_sta->bt_info_ext & BIT(4))) { + /* BT auto report already enabled, do nothing */ + } else + halbtc8192e2ant_bt_auto_report(btcoexist, FORCE_EXEC, + true); +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (bt_info & BT_INFO_8192E_2ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status */ + if (!(bt_info & BT_INFO_8192E_2ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8192E_2ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8192E_2ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8192E_2ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8192E_2ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + } + + halbtc8192e2ant_update_bt_link_info(btcoexist); + + if (!(bt_info & BT_INFO_8192E_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info == + BT_INFO_8192E_2ANT_B_CONNECTION) { /* connection exists but no busy */ + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + BTC_TRACE(trace_buf); + } else if ((bt_info & BT_INFO_8192E_2ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8192E_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info & BT_INFO_8192E_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + BTC_TRACE(trace_buf); + } else { + coex_dm->bt_status = BT_8192E_2ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + BTC_TRACE(trace_buf); + } + + if ((BT_8192E_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8192E_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { + bt_busy = true; + limited_dig = true; + } else { + bt_busy = false; + limited_dig = false; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + coex_dm->limited_dig = limited_dig; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + + halbtc8192e2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8192e2ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8192e2ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, true); + halbtc8192e2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + ex_halbtc8192e2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8192e2ant_periodical(IN struct btc_coexist *btcoexist) +{ + + if ((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) + coex_sta->bt_coex_supported_version = + btcoexist->btc_get_bt_coex_supported_version(btcoexist); + +#if (BT_AUTO_REPORT_ONLY_8192E_2ANT == 0) + halbtc8192e2ant_query_bt_info(btcoexist); + halbtc8192e2ant_monitor_bt_ctr(btcoexist); + halbtc8192e2ant_monitor_wifi_ctr(btcoexist); + halbtc8192e2ant_monitor_bt_enable_disable(btcoexist); +#else + halbtc8192e2ant_monitor_wifi_ctr(btcoexist); + + if (halbtc8192e2ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + halbtc8192e2ant_run_coexist_mechanism(btcoexist); +#endif +} + +#endif + +#endif /* #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) */ + + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e2ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e2ant.h new file mode 100644 index 0000000..00fed71 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8192e2ant.h @@ -0,0 +1,211 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8192E_SUPPORT == 1) +/* ******************************************* + * The following is for 8192E 2Ant BT Co-exist definition + * ******************************************* */ +#define BT_AUTO_REPORT_ONLY_8192E_2ANT 0 + +#define BT_INFO_8192E_2ANT_B_FTP BIT(7) +#define BT_INFO_8192E_2ANT_B_A2DP BIT(6) +#define BT_INFO_8192E_2ANT_B_HID BIT(5) +#define BT_INFO_8192E_2ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8192E_2ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8192E_2ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8192E_2ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8192E_2ANT_B_CONNECTION BIT(0) + +#define BTC_RSSI_COEX_THRESH_TOL_8192E_2ANT 2 +#define NOISY_AP_NUM_THRESH_8192E 10 + +enum bt_info_src_8192e_2ant { + BT_INFO_SRC_8192E_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8192E_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8192E_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8192E_2ANT_MAX +}; + +enum bt_8192e_2ant_bt_status { + BT_8192E_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8192E_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8192E_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8192E_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8192E_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8192E_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8192E_2ANT_BT_STATUS_MAX +}; + +enum bt_8192e_2ant_coex_algo { + BT_8192E_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8192E_2ANT_COEX_ALGO_SCO = 0x1, + BT_8192E_2ANT_COEX_ALGO_SCO_PAN = 0x2, + BT_8192E_2ANT_COEX_ALGO_HID = 0x3, + BT_8192E_2ANT_COEX_ALGO_A2DP = 0x4, + BT_8192E_2ANT_COEX_ALGO_A2DP_PANHS = 0x5, + BT_8192E_2ANT_COEX_ALGO_PANEDR = 0x6, + BT_8192E_2ANT_COEX_ALGO_PANHS = 0x7, + BT_8192E_2ANT_COEX_ALGO_PANEDR_A2DP = 0x8, + BT_8192E_2ANT_COEX_ALGO_PANEDR_HID = 0x9, + BT_8192E_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0xa, + BT_8192E_2ANT_COEX_ALGO_HID_A2DP = 0xb, + BT_8192E_2ANT_COEX_ALGO_MAX = 0xc +}; + +struct coex_dm_8192e_2ant { + /* fw mechanism */ + u8 pre_bt_dec_pwr_lvl; + u8 cur_bt_dec_pwr_lvl; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean reset_tdma_adjust; + boolean auto_tdma_adjust; + boolean auto_tdma_adjust_low_rssi; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + + /* sw mechanism */ + boolean pre_rf_rx_lpf_shrink; + boolean cur_rf_rx_lpf_shrink; + u32 bt_rf_0x1e_backup; + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + boolean pre_dac_swing_on; + u32 pre_dac_swing_lvl; + boolean cur_dac_swing_on; + u32 cur_dac_swing_lvl; + boolean pre_adc_back_off; + boolean cur_adc_back_off; + boolean pre_agc_table_en; + boolean cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + boolean limited_dig; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u8 pre_ss_type; + u8 cur_ss_type; + + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + + u32 pre_ra_mask; + u32 cur_ra_mask; + u8 cur_ra_mask_type; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; +}; + +struct coex_sta_8192e_2ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + + boolean under_lps; + boolean under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + boolean c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8192E_2ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8192E_2ANT_MAX]; + boolean c2h_bt_inquiry_page; + u8 bt_retry_cnt; + u8 bt_info_ext; + u8 scan_ap_num; + u32 bt_coex_supported_version; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_vht; +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8192e2ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8192e2ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8192e2ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8192e2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8192e2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8192e2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8192e2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8192e2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8192e2ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8192e2ant_display_coex_info(IN struct btc_coexist *btcoexist); + +#else /* #if (RTL8192E_SUPPORT == 1) */ +#define ex_halbtc8192e2ant_power_on_setting(btcoexist) +#define ex_halbtc8192e2ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8192e2ant_init_coex_dm(btcoexist) +#define ex_halbtc8192e2ant_ips_notify(btcoexist, type) +#define ex_halbtc8192e2ant_lps_notify(btcoexist, type) +#define ex_halbtc8192e2ant_scan_notify(btcoexist, type) +#define ex_halbtc8192e2ant_connect_notify(btcoexist, type) +#define ex_halbtc8192e2ant_media_status_notify(btcoexist, type) +#define ex_halbtc8192e2ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8192e2ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8192e2ant_halt_notify(btcoexist) +#define ex_halbtc8192e2ant_periodical(btcoexist) +#define ex_halbtc8192e2ant_display_coex_info(btcoexist) + +#endif + +#endif + + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8703b1ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8703b1ant.c new file mode 100644 index 0000000..8471ed7 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8703b1ant.c @@ -0,0 +1,4293 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8703B Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8703B_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8703b_1ant glcoex_dm_8703b_1ant; +static struct coex_dm_8703b_1ant *coex_dm = &glcoex_dm_8703b_1ant; +static struct coex_sta_8703b_1ant glcoex_sta_8703b_1ant; +static struct coex_sta_8703b_1ant *coex_sta = &glcoex_sta_8703b_1ant; +static struct psdscan_sta_8703b_1ant gl_psd_scan_8703b_1ant; +static struct psdscan_sta_8703b_1ant *psd_scan = &gl_psd_scan_8703b_1ant; + + +const char *const glbt_info_src_8703b_1ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; +/* ************************************************************ + * BtCoex Version Format: + * 1. date : glcoex_ver_date_XXXXX_1ant + * 2. WifiCoexVersion : glcoex_ver_XXXX_1ant + * 3. BtCoexVersion : glcoex_ver_btdesired_XXXXX_1ant + * 4. others : glcoex_ver_XXXXXX_XXXXX_1ant + * + * Variable should be indicated IC and Antenna numbers !!! + * Please strictly follow this order and naming style !!! + * + * ************************************************************ */ +u32 glcoex_ver_date_8703b_1ant = 20161027; +u32 glcoex_ver_8703b_1ant = 0x0f; +u32 glcoex_ver_btdesired_8703b_1ant = 0x0d; + + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8703b1ant_ + * ************************************************************ */ +u8 halbtc8703b1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8703B_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8703B_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8703B_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8703b1ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 index, IN u8 level_num, IN u8 rssi_thresh, IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8703B_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8703B_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8703B_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8703b1ant_update_ra_mask(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 dis_rate_mask) +{ + coex_dm->cur_ra_mask = dis_rate_mask; + + if (force_exec || (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_RAMASK, + &coex_dm->cur_ra_mask); + coex_dm->pre_ra_mask = coex_dm->cur_ra_mask; +} + +void halbtc8703b1ant_auto_rate_fallback_retry(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + boolean wifi_under_b_mode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + if (wifi_under_b_mode) { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +void halbtc8703b1ant_retry_limit(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || + (coex_dm->pre_retry_limit_type != + coex_dm->cur_retry_limit_type)) { + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +void halbtc8703b1ant_ampdu_max_time(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || + (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +void halbtc8703b1ant_limited_tx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ra_mask_type, IN u8 arfr_type, + IN u8 retry_limit_type, IN u8 ampdu_time_type) +{ + switch (ra_mask_type) { + case 0: /* normal mode */ + halbtc8703b1ant_update_ra_mask(btcoexist, force_exec, + 0x0); + break; + case 1: /* disable cck 1/2 */ + halbtc8703b1ant_update_ra_mask(btcoexist, force_exec, + 0x00000003); + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ + halbtc8703b1ant_update_ra_mask(btcoexist, force_exec, + 0x0001f1f7); + break; + default: + break; + } + + halbtc8703b1ant_auto_rate_fallback_retry(btcoexist, force_exec, + arfr_type); + halbtc8703b1ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8703b1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type); +} + +void halbtc8703b1ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +void halbtc8703b1ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +void halbtc8703b1ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + static u8 num_of_bt_counter_chk = 0, cnt_slave = 0, cnt_overhead = 0, + cnt_autoslot_hang = 0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + /* to avoid 0x76e[3] = 1 (WLAN_Act control by PTA) during IPS */ + /* if (! (btcoexist->btc_read_1byte(btcoexist, 0x76e) & 0x8) ) */ + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + if (BT_8703B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + + if (coex_sta->high_priority_rx >= 15) { + if (cnt_overhead < 3) + cnt_overhead++; + + if (cnt_overhead == 3) + coex_sta->is_hiPri_rx_overhead = true; + } else { + if (cnt_overhead > 0) + cnt_overhead--; + + if (cnt_overhead == 0) + coex_sta->is_hiPri_rx_overhead = false; + } + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n", + reg_hp_rx, reg_hp_tx, reg_lp_rx, reg_lp_tx); + + BTC_TRACE(trace_buf); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + if ((coex_sta->low_priority_tx > 1150) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + + if ((coex_sta->low_priority_rx >= 1150) && + (coex_sta->low_priority_rx >= coex_sta->low_priority_tx) + && (!coex_sta->under_ips) && (!coex_sta->c2h_bt_inquiry_page) && + (coex_sta->bt_link_exist)) { + if (cnt_slave >= 2) { + bt_link_info->slave_role = true; + cnt_slave = 2; + } else + cnt_slave++; + } else { + if (cnt_slave == 0) { + bt_link_info->slave_role = false; + cnt_slave = 0; + } else + cnt_slave--; + + } + + if (coex_sta->is_tdma_btautoslot) { + if ((coex_sta->low_priority_tx >= 1300) && + (coex_sta->low_priority_rx <= 150)) { + if (cnt_autoslot_hang >= 2) { + coex_sta->is_tdma_btautoslot_hang = true; + cnt_autoslot_hang = 2; + } else + cnt_autoslot_hang++; + } else { + if (cnt_autoslot_hang == 0) { + coex_sta->is_tdma_btautoslot_hang = false; + cnt_autoslot_hang = 0; + } else + cnt_autoslot_hang--; + } + } + + if (!coex_sta->bt_disabled) { + if ((coex_sta->high_priority_tx == 0) && + (coex_sta->high_priority_rx == 0) && + (coex_sta->low_priority_tx == 0) && + (coex_sta->low_priority_rx == 0)) { + num_of_bt_counter_chk++; + if (num_of_bt_counter_chk >= 3) { + halbtc8703b1ant_query_bt_info(btcoexist); + num_of_bt_counter_chk = 0; + } + } + } + +} + + +void halbtc8703b1ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ +#if 1 + s32 wifi_rssi = 0; + boolean wifi_busy = false, wifi_under_b_mode = false, + wifi_scan = false; + boolean bt_idle = false, wl_idle = false; + static u8 cck_lock_counter = 0, wl_noisy_count0 = 0, + wl_noisy_count1 = 3, wl_noisy_count2 = 0; + u32 total_cnt, reg_val1, reg_val2, cck_cnt; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + + coex_sta->crc_ok_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_CCK); + coex_sta->crc_ok_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_LEGACY); + coex_sta->crc_ok_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_HT); + coex_sta->crc_ok_11n_vht = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_VHT); + + coex_sta->crc_err_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_CCK); + coex_sta->crc_err_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_LEGACY); + coex_sta->crc_err_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_HT); + coex_sta->crc_err_11n_vht = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_VHT); + + cck_cnt = coex_sta->crc_ok_cck + coex_sta->crc_err_cck; + + if (cck_cnt > 250) { + if (wl_noisy_count2 < 3) + wl_noisy_count2++; + + if (wl_noisy_count2 == 3) { + wl_noisy_count0 = 0; + wl_noisy_count1 = 0; + } + } else if (cck_cnt < 50) { + if (wl_noisy_count0 < 3) + wl_noisy_count0++; + + if (wl_noisy_count0 == 3) { + wl_noisy_count1 = 0; + wl_noisy_count2 = 0; + } + } else { + if (wl_noisy_count1 < 3) + wl_noisy_count1++; + + if (wl_noisy_count1 == 3) { + wl_noisy_count0 = 0; + wl_noisy_count2 = 0; + } + } + + if (wl_noisy_count2 == 3) + coex_sta->wl_noisy_level = 2; + else if (wl_noisy_count1 == 3) + coex_sta->wl_noisy_level = 1; + else + coex_sta->wl_noisy_level = 0; + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + total_cnt = coex_sta->crc_ok_cck + coex_sta->crc_ok_11g + + coex_sta->crc_ok_11n + coex_sta->crc_ok_11n_vht; + + if ((coex_dm->bt_status == BT_8703B_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == BT_8703B_1ANT_BT_STATUS_ACL_SCO_BUSY) || + (coex_dm->bt_status == BT_8703B_1ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > (total_cnt - + coex_sta->crc_ok_cck)) { + if (cck_lock_counter < 3) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + + if (cck_lock_counter >= 3) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + if (coex_sta->cck_lock) + coex_sta->cck_ever_lock = true; + + coex_sta->pre_ccklock = coex_sta->cck_lock; + +#endif +} + + + +boolean halbtc8703b1ant_is_wifibt_status_changed(IN struct btc_coexist + *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false, pre_bt_off = false, pre_bt_slave = false; + static u8 pre_hid_busy_num = 0, pre_wl_noisy_level = 0; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (coex_sta->bt_disabled != pre_bt_off) { + pre_bt_off = coex_sta->bt_disabled; + + if (coex_sta->bt_disabled) + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!\n"); + else + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is enabled !!\n"); + + BTC_TRACE(trace_buf); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + + return true; + } + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + if (coex_sta->wl_noisy_level != pre_wl_noisy_level) { + pre_wl_noisy_level = coex_sta->wl_noisy_level; + return true; + } + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->hid_busy_num != pre_hid_busy_num) { + pre_hid_busy_num = coex_sta->hid_busy_num; + return true; + } + } + + if (bt_link_info->slave_role != pre_bt_slave) { + pre_bt_slave = bt_link_info->slave_role; + return true; + } + + return false; +} + + +void halbtc8703b1ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + boolean bt_busy = false; + + + coex_sta->num_of_profile = 0; + + /* set link exist status */ + if (!(coex_sta->bt_info & BT_INFO_8703B_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (coex_sta->bt_info & BT_INFO_8703B_1ANT_B_FTP) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->pan_exist = false; + + if (coex_sta->bt_info & BT_INFO_8703B_1ANT_B_A2DP) { + coex_sta->a2dp_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->a2dp_exist = false; + + if (coex_sta->bt_info & BT_INFO_8703B_1ANT_B_HID) { + coex_sta->hid_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->hid_exist = false; + + if (coex_sta->bt_info & BT_INFO_8703B_1ANT_B_SCO_ESCO) { + coex_sta->sco_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->sco_exist = false; + + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + bt_link_info->acl_busy = coex_sta->acl_busy; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; + + if (coex_sta->bt_info & BT_INFO_8703B_1ANT_B_INQ_PAGE) { + coex_dm->bt_status = BT_8703B_1ANT_BT_STATUS_INQ_PAGE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Inq/page!!!\n"); + } else if (!(coex_sta->bt_info & BT_INFO_8703B_1ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8703B_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + } else if (coex_sta->bt_info == BT_INFO_8703B_1ANT_B_CONNECTION) { + /* connection exists but no busy */ + coex_dm->bt_status = BT_8703B_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if (((coex_sta->bt_info & BT_INFO_8703B_1ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8703B_1ANT_B_SCO_BUSY)) && + (coex_sta->bt_info & BT_INFO_8703B_1ANT_B_ACL_BUSY)) { + coex_dm->bt_status = BT_8703B_1ANT_BT_STATUS_ACL_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL SCO busy!!!\n"); + } else if ((coex_sta->bt_info & BT_INFO_8703B_1ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8703B_1ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8703B_1ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (coex_sta->bt_info & BT_INFO_8703B_1ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8703B_1ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8703B_1ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + } + + BTC_TRACE(trace_buf); + + if ((BT_8703B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8703B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8703B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); +} + + +void halbtc8703b1ant_update_wifi_channel_info(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + h2c_parameter[0] = + 0x1; /* enable BT AFH skip WL channel for 8703b because BT Rx LO interference */ + /* h2c_parameter[0] = 0x0; */ + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); + +} + +void halbtc8703b1ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8703b1ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8703b1ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8703b1ant_set_fw_low_penalty_ra(IN struct btc_coexist + *btcoexist, IN boolean low_penalty_ra) +{ + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* op_code, 0x6= Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT(0); + h2c_parameter[2] = + 0x00; /* normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[3] = 0xf7; /* MCS7 or OFDM54 */ + h2c_parameter[4] = 0xf8; /* MCS6 or OFDM48 */ + h2c_parameter[5] = 0xf9; /* MCS5 or OFDM36 */ + } + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +void halbtc8703b1ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + + halbtc8703b1ant_set_fw_low_penalty_ra(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +void halbtc8703b1ant_write_score_board( + IN struct btc_coexist *btcoexist, + IN u16 bitpos, + IN boolean state +) +{ + + static u16 originalval = 0x8002; + + if (state) + originalval = originalval | bitpos; + else + originalval = originalval & (~bitpos); + + + btcoexist->btc_write_2byte(btcoexist, 0xaa, originalval); +#if 0 + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "\n [BTCoex], ********** Write Scoreboard = %x**********\n", + originalval); + BTC_TRACE(trace_buf); +#endif + +} + +void halbtc8703b1ant_read_score_board( + IN struct btc_coexist *btcoexist, + IN u16 *score_board_val +) +{ + + *score_board_val = (btcoexist->btc_read_2byte(btcoexist, + 0xaa)) & 0x7fff; +} + +void halbtc8703b1ant_post_state_to_bt( + IN struct btc_coexist *btcoexist, + IN u16 type, + IN boolean state +) +{ + halbtc8703b1ant_write_score_board(btcoexist, (u16) type, state); +} + +void halbtc8703b1ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false; + u16 u16tmp; + + /* This function check if bt is disabled */ +#if 1 + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + + +#else /* 8703b BT can't show correct on/off status in scoreboard[1] 2015/11/26 */ + + halbtc8703b1ant_read_score_board(btcoexist, &u16tmp); + + bt_active = u16tmp & BIT(1); + + +#endif + + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } else { + + bt_disable_cnt++; + if (bt_disable_cnt >= 2) { + bt_disabled = true; + bt_disable_cnt = 2; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } + + if (bt_disabled) + halbtc8703b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + else + halbtc8703b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, true); + + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + coex_sta->bt_disabled = bt_disabled; + + } +} + + + +void halbtc8703b1ant_enable_gnt_to_gpio(IN struct btc_coexist *btcoexist, + IN boolean isenable) +{ + +#if (BT_8703B_1ANT_ENABLE_GNTBT_TO_GPIO14 == 1) + if (isenable) { + /* enable GNT_WL/GNT_BT debug signal to GPIO14/15 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x1); + + /* enable GNT_BT debug to GPIO */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x40, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x1, 0x0); + } else { + /* enable GNT_WL/GNT_BT debug signal to GPIO14/15 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x0); + + /* Disable GNT_BT debug to GPIO, and enable chip_wakeup_host */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x40, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x1, 0x1); + } +#endif +} + +u32 halbtc8703b1ant_ltecoex_indirect_read_reg(IN struct btc_coexist *btcoexist, + IN u16 reg_addr) +{ + u32 j = 0; + + + /* wait for ready bit before access 0x7c0 */ + btcoexist->btc_write_4byte(btcoexist, 0x7c0, 0x800F0000 | reg_addr); + + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x7c3)&BIT(5)) == 0) && + (j < BT_8703B_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + return btcoexist->btc_read_4byte(btcoexist, + 0x7c8); /* get read data */ + +} + +void halbtc8703b1ant_ltecoex_indirect_write_reg(IN struct btc_coexist + *btcoexist, + IN u16 reg_addr, IN u32 bit_mask, IN u32 reg_value) +{ + u32 val, i = 0, j = 0, bitpos = 0; + + + if (bit_mask == 0x0) + return; + if (bit_mask == 0xffffffff) { + btcoexist->btc_write_4byte(btcoexist, 0x7c4, + reg_value); /* put write data */ + + /* wait for ready bit before access 0x7c0 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x7c3)&BIT(5)) == 0) && + (j < BT_8703B_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + btcoexist->btc_write_4byte(btcoexist, 0x7c0, + 0xc00F0000 | reg_addr); + } else { + for (i = 0; i <= 31; i++) { + if (((bit_mask >> i) & 0x1) == 0x1) { + bitpos = i; + break; + } + } + + /* read back register value before write */ + val = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, + reg_addr); + val = (val & (~bit_mask)) | (reg_value << bitpos); + + btcoexist->btc_write_4byte(btcoexist, 0x7c4, + val); /* put write data */ + + /* wait for ready bit before access 0x7c0 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x7c3)&BIT(5)) == 0) && + (j < BT_8703B_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + btcoexist->btc_write_4byte(btcoexist, 0x7c0, + 0xc00F0000 | reg_addr); + + } + +} + +void halbtc8703b1ant_ltecoex_enable(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 val; + + val = (enable) ? 1 : 0; + halbtc8703b1ant_ltecoex_indirect_write_reg(btcoexist, 0x38, 0x80, + val); /* 0x38[7] */ + +} + +void halbtc8703b1ant_ltecoex_pathcontrol_owner(IN struct btc_coexist *btcoexist, + IN boolean wifi_control) +{ + u8 val; + + val = (wifi_control) ? 1 : 0; + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x4, + val); /* 0x70[26] */ + +} + +void halbtc8703b1ant_ltecoex_set_gnt_bt(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, val_orig = 0; + + if (!sw_control) + val = 0x0; + else if (state & 0x1) + val = 0x3; + else + val = 0x1; + + val_orig = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + + switch (control_block) { + case BT_8703B_1ANT_GNT_BLOCK_RFC_BB: + default: + val = ((val << 14) | (val << 10)) | (val_orig & 0xffff33ff); + break; + case BT_8703B_1ANT_GNT_BLOCK_RFC: + val = (val << 14) | (val_orig & 0xffff3fff); + break; + case BT_8703B_1ANT_GNT_BLOCK_BB: + val = (val << 10) | (val_orig & 0xfffff3ff); + break; + } + + halbtc8703b1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, 0xffffffff, val); +} + + +void halbtc8703b1ant_ltecoex_set_gnt_wl(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, val_orig = 0; + + if (!sw_control) + val = 0x0; + else if (state & 0x1) + val = 0x3; + else + val = 0x1; + + val_orig = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + + switch (control_block) { + case BT_8703B_1ANT_GNT_BLOCK_RFC_BB: + default: + val = ((val << 12) | (val << 8)) | (val_orig & 0xffffccff); + break; + case BT_8703B_1ANT_GNT_BLOCK_RFC: + val = (val << 12) | (val_orig & 0xffffcfff); + break; + case BT_8703B_1ANT_GNT_BLOCK_BB: + val = (val << 8) | (val_orig & 0xfffffcff); + break; + } + + halbtc8703b1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, 0xffffffff, val); +} + + +void halbtc8703b1ant_ltecoex_set_coex_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u16 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8703B_1ANT_CTT_WL_VS_LTE: + reg_addr = 0xa0; + break; + case BT_8703B_1ANT_CTT_BT_VS_LTE: + reg_addr = 0xa4; + break; + } + + if (reg_addr != 0x0000) + halbtc8703b1ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xffff, table_content); /* 0xa0[15:0] or 0xa4[15:0] */ + + +} + + +void halbtc8703b1ant_ltecoex_set_break_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u8 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8703B_1ANT_LBTT_WL_BREAK_LTE: + reg_addr = 0xa8; + break; + case BT_8703B_1ANT_LBTT_BT_BREAK_LTE: + reg_addr = 0xac; + break; + case BT_8703B_1ANT_LBTT_LTE_BREAK_WL: + reg_addr = 0xb0; + break; + case BT_8703B_1ANT_LBTT_LTE_BREAK_BT: + reg_addr = 0xb4; + break; + } + + if (reg_addr != 0x0000) + halbtc8703b1ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xff, table_content); /* 0xa8[15:0] or 0xb4[15:0] */ + + +} + +void halbtc8703b1ant_set_wltoggle_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 interval, + IN u8 val0x6c4_b0, IN u8 val0x6c4_b1, IN u8 val0x6c4_b2, + IN u8 val0x6c4_b3) +{ + static u8 pre_h2c_parameter[6] = {0}; + u8 cur_h2c_parameter[6] = {0}; + u8 i, match_cnt = 0; + + cur_h2c_parameter[0] = 0x7; /* op_code, 0x7= wlan toggle slot*/ + + cur_h2c_parameter[1] = interval; + cur_h2c_parameter[2] = val0x6c4_b0; + cur_h2c_parameter[3] = val0x6c4_b1; + cur_h2c_parameter[4] = val0x6c4_b2; + cur_h2c_parameter[5] = val0x6c4_b3; + + if (!force_exec) { + for (i = 1; i <= 5; i++) { + if (cur_h2c_parameter[i] != pre_h2c_parameter[i]) + break; + + match_cnt++; + } + + if (match_cnt == 5) + return; + } + + for (i = 1; i <= 5; i++) + pre_h2c_parameter[i] = cur_h2c_parameter[i]; + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, cur_h2c_parameter); +} + + +void halbtc8703b1ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8703b1ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8703b1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8703b1ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + u32 break_table; + u8 select_table; + + coex_sta->coex_table_type = type; + + if (coex_sta->concurrent_rx_mode_on == true) { + break_table = 0xf0ffffff; /* set WL hi-pri can break BT */ + select_table = + 0xb; /* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */ + } else { + break_table = 0xffffff; + select_table = 0x3; + } + + switch (type) { + case 0: + halbtc8703b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x55555555, break_table, + select_table); + break; + case 1: + halbtc8703b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, break_table, + select_table); + break; + case 2: + halbtc8703b1ant_coex_table(btcoexist, force_exec, + 0xaa5a5a5a, 0xaa5a5a5a, break_table, + select_table); + break; + case 3: + halbtc8703b1ant_coex_table(btcoexist, force_exec, + 0xaa555555, 0xaa5a5a5a, break_table, + select_table); + break; + case 4: + halbtc8703b1ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0x5a5a5a5a, break_table, + select_table); + break; + case 5: + halbtc8703b1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5a5a5a5a, break_table, + select_table); + break; + case 6: + halbtc8703b1ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0x5a5a5a5a, break_table, + select_table); + break; + case 7: + halbtc8703b1ant_coex_table(btcoexist, force_exec, + 0xaaaaaaaa, 0xaaaaaaaa, break_table, + select_table); + break; + case 8: + halbtc8703b1ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0xaaaaaaaa, break_table, + select_table); + break; + case 9: + halbtc8703b1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0xaaaa5aaa, break_table, + select_table); + break; + default: + break; + } +} + +void halbtc8703b1ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT(0);/* function enable */ + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8703b1ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8703b1ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8703b1ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8703b1ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8703b1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8703b1ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + u8 h2c_parameter[5] = {0x8, 0, 0, 0, 0}; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + /*halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); */ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + /*halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8);*/ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +void halbtc8703b1ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + coex_sta->force_lps_on = false; + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + + break; + case BTC_PS_LPS_ON: + coex_sta->force_lps_on = true; + halbtc8703b1ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8703b1ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + + break; + case BTC_PS_LPS_OFF: + coex_sta->force_lps_on = false; + halbtc8703b1ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + + break; + default: + break; + } +} + + + +void halbtc8703b1ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + if (byte5 & BIT(2)) + coex_sta->is_tdma_btautoslot = true; + else + coex_sta->is_tdma_btautoslot = false; + + /* release bt-auto slot for auto-slot hang is detected!! */ + if (coex_sta->is_tdma_btautoslot) + if ((coex_sta->is_tdma_btautoslot_hang) || + (bt_link_info->slave_role)) + byte5 = byte5 & 0xfb; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], FW for 1Ant AP mode\n"); + BTC_TRACE(trace_buf); + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + + halbtc8703b1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + } + } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + + halbtc8703b1ant_power_save_state( + btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } else { + halbtc8703b1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, + 0x0); + } + + + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + + +void halbtc8703b1ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_busy = false; + u8 rssi_adjust_val = 0; + static u8 psTdmaByte4Modify = 0x0, pre_psTdmaByte4Modify = 0x0; + static boolean pre_wifi_busy = false; + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (wifi_busy != pre_wifi_busy) { + force_exec = true; + pre_wifi_busy = wifi_busy; + } + + /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + if ((bt_link_info->slave_role) && (bt_link_info->a2dp_exist)) + psTdmaByte4Modify = 0x1; + else + psTdmaByte4Modify = 0x0; + + if (pre_psTdmaByte4Modify != psTdmaByte4Modify) { + + force_exec = true; + pre_psTdmaByte4Modify = psTdmaByte4Modify; + } + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + + if (coex_dm->cur_ps_tdma_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(off, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } + + if (turn_on) { + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + } + + + if (turn_on) { + switch (type) { + default: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x35, 0x03, 0x11, 0x11); + break; + + case 3: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x3a, 0x03, 0x10, 0x50); + break; + case 4: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x21, 0x03, 0x10, 0x50); + break; + case 5: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x15, 0x03, 0x11, 0x11); + break; + case 6: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x20, 0x03, 0x11, 0x11); + break; + case 7: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x10, 0x03, 0x10, 0x54 | + psTdmaByte4Modify); + break; + case 8: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x10, 0x03, 0x10, 0x54 | + psTdmaByte4Modify); + break; + case 9: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x55, 0x10, 0x03, 0x10, 0x54 | + psTdmaByte4Modify); + break; + case 10: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x30, 0x03, 0x11, 0x10); + break; + case 11: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x65, 0x25, 0x03, 0x11, 0x11 | + psTdmaByte4Modify); + break; + case 12: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x55, 0x30, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 13: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x25, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 14: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x15, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 15: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x20, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 16: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x10, 0x03, 0x11, 0x15 | + psTdmaByte4Modify); + break; + case 17: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x10, 0x03, 0x11, 0x14); + break; + case 18: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x30, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 19: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x15, 0x03, 0x11, 0x10); + break; + case 20: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x30, 0x03, 0x11, 0x10); + break; + case 21: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x30, 0x03, 0x11, 0x10); + break; + case 22: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x25, 0x03, 0x11, 0x10); + break; + case 23: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x10, 0x03, 0x11, 0x10); + break; + case 32: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x35, 0x03, 0x11, 0x11); + break; + case 33: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x35, 0x03, 0x11, 0x10); + break; + case 57: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x10, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 58: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x10, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 67: + halbtc8703b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x10, 0x03, 0x11, 0x10 | + psTdmaByte4Modify); + break; + } + } else { + + /* disable PS tdma */ + switch (type) { + case 8: /* PTA Control */ + halbtc8703b1ant_set_fw_pstdma(btcoexist, 0x8, + 0x0, 0x0, 0x0, 0x0); + break; + case 0: + default: /* Software control, Antenna at BT side */ + halbtc8703b1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x0, 0x0); + break; + case 1: /* 2-Ant, 0x778=3, antenna control by antenna diversity */ + halbtc8703b1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x48, 0x0); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void halbtc8703b1ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean force_exec, + IN u8 phase) +{ + u32 cnt_bt_cal_chk = 0; + boolean is_in_mp_mode = false; + u8 u8tmp = 0; + u32 u32tmp1 = 0, u32tmp2 = 0; + + + u32tmp1 = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + + /* To avoid indirect access fail */ + if (((u32tmp1 & 0xf000) >> 12) != ((u32tmp1 & 0x0f00) >> 8)) { + force_exec = true; + coex_sta->gnt_error_cnt++; + } + +#if 1 + u32tmp2 = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, + 0x54); + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (Before Ant Setup) 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x**********\n", + u8tmp, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); +#endif + + coex_dm->cur_ant_pos_type = ant_pos_type; + + if (!force_exec) { + if (coex_dm->cur_ant_pos_type == coex_dm->pre_ant_pos_type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** Skip Antenna Path Setup because no change!!**********\n"); + BTC_TRACE(trace_buf); + return; + } + } + + coex_dm->pre_ant_pos_type = coex_dm->cur_ant_pos_type; + + switch (phase) { + case BT_8703B_1ANT_PHASE_COEX_INIT: + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8703b1ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8703b1ant_ltecoex_set_coex_table( + btcoexist, + BT_8703B_1ANT_CTT_WL_VS_LTE, + 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8703b1ant_ltecoex_set_coex_table( + btcoexist, + BT_8703B_1ANT_CTT_BT_VS_LTE, + 0xffff); + + /* Wait If BT IQK running, because Path control owner is at BT during BT IQK (setup by WiFi firmware) */ + while (cnt_bt_cal_chk <= 20) { + u8tmp = btcoexist->btc_read_1byte( + btcoexist, + 0x49d); + cnt_bt_cal_chk++; + if (u8tmp & BIT(0)) { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ########### BT is calibrating (wait cnt=%d) ###########\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + delay_ms(50); + } else { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ********** BT is NOT calibrating (wait cnt=%d)**********\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + break; + } + } + + + /* set Path control owner to WL at initial step */ + halbtc8703b1ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8703B_1ANT_PCO_WLSIDE); + + /* set GNT_BT to SW high */ + halbtc8703b1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8703B_1ANT_GNT_BLOCK_RFC_BB, + BT_8703B_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8703B_1ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW low */ + halbtc8703b1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8703B_1ANT_GNT_BLOCK_RFC_BB, + BT_8703B_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8703B_1ANT_SIG_STA_SET_TO_LOW); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + coex_sta->run_time_state = false; + break; + case BT_8703B_1ANT_PHASE_WLANONLY_INIT: + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8703b1ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8703b1ant_ltecoex_set_coex_table( + btcoexist, + BT_8703B_1ANT_CTT_WL_VS_LTE, + 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8703b1ant_ltecoex_set_coex_table( + btcoexist, + BT_8703B_1ANT_CTT_BT_VS_LTE, + 0xffff); + + /* set Path control owner to WL at initial step */ + halbtc8703b1ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8703B_1ANT_PCO_WLSIDE); + + /* set GNT_BT to SW low */ + halbtc8703b1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8703B_1ANT_GNT_BLOCK_RFC_BB, + BT_8703B_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8703B_1ANT_SIG_STA_SET_TO_LOW); + /* Set GNT_WL to SW high */ + halbtc8703b1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8703B_1ANT_GNT_BLOCK_RFC_BB, + BT_8703B_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8703B_1ANT_SIG_STA_SET_TO_HIGH); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = + BTC_ANT_PATH_WIFI; + + coex_sta->run_time_state = false; + break; + case BT_8703B_1ANT_PHASE_WLAN_OFF: + /* Disable LTE Coex Function in WiFi side */ + halbtc8703b1ant_ltecoex_enable(btcoexist, 0x0); + + /* set Path control owner to BT */ + halbtc8703b1ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8703B_1ANT_PCO_BTSIDE); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + coex_sta->run_time_state = false; + break; + case BT_8703B_1ANT_PHASE_2G_RUNTIME: + halbtc8703b1ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8703B_1ANT_PCO_WLSIDE); + + /* set GNT_BT to PTA */ + halbtc8703b1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8703B_1ANT_GNT_BLOCK_RFC_BB, + BT_8703B_1ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8703B_1ANT_SIG_STA_SET_BY_HW); + /* Set GNT_WL to PTA */ + halbtc8703b1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8703B_1ANT_GNT_BLOCK_RFC_BB, + BT_8703B_1ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8703B_1ANT_SIG_STA_SET_BY_HW); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_PTA; + + coex_sta->run_time_state = true; + break; + case BT_8703B_1ANT_PHASE_BTMPMODE: + halbtc8703b1ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8703B_1ANT_PCO_WLSIDE); + + /* set GNT_BT to high */ + halbtc8703b1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8703B_1ANT_GNT_BLOCK_RFC_BB, + BT_8703B_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8703B_1ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to low */ + halbtc8703b1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8703B_1ANT_GNT_BLOCK_RFC_BB, + BT_8703B_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8703B_1ANT_SIG_STA_SET_TO_LOW); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + coex_sta->run_time_state = false; + break; + } + + +#if 1 + u32tmp1 = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (After Ant-Setup) 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x**********\n", + u8tmp, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); + +#endif +} + + +boolean halbtc8703b1ant_is_common_action(IN struct btc_coexist *btcoexist) +{ + boolean common = false, wifi_connected = false, wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected && + BT_8703B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + common = true; + } else if (wifi_connected && + (BT_8703B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + common = true; + } else if (!wifi_connected && + (BT_8703B_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + common = true; + } else if (wifi_connected && + (BT_8703B_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + common = true; + } else if (!wifi_connected && + (BT_8703B_1ANT_BT_STATUS_CONNECTED_IDLE != + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + common = true; + } else { + if (wifi_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } + + common = false; + } + + return common; +} + + +/* ********************************************* + * + * Non-Software Coex Mechanism start + * + * ********************************************* */ +u8 halbtc8703b1ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8703B_1ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8703B_1ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8703B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8703B_1ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8703B_1ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8703B_1ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8703B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8703B_1ANT_COEX_ALGO_SCO; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8703B_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8703B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8703B_1ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8703B_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8703B_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8703B_1ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8703B_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8703B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8703B_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8703B_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8703B_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8703B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8703B_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8703B_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8703B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +void halbtc8703b1ant_action_bt_whql_test(IN struct btc_coexist *btcoexist) +{ + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8703B_1ANT_PHASE_2G_RUNTIME); + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8703b1ant_action_bt_hs(IN struct btc_coexist *btcoexist) +{ + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8703b1ant_action_bt_relink(IN struct btc_coexist *btcoexist) +{ + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + coex_sta->bt_relink_downcount = 2; +} + +void halbtc8703b1ant_action_bt_idle(IN struct btc_coexist *btcoexist) +{ + boolean wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_busy) { + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + } else {/* if wl busy */ + + if (BT_8703B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + + if (coex_sta->is_hiPri_rx_overhead) + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + else + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 33); + } else { + + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + } + } +} + +void halbtc8703b1ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, wifi_busy = false, bt_busy = false; + boolean wifi_scan = false, wifi_link = false, wifi_roam = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &wifi_link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &wifi_roam); + + if ((coex_sta->bt_create_connection) && ((wifi_link) || (wifi_roam) + || (wifi_scan) || (wifi_busy) || (coex_sta->wifi_is_high_pri_task))) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi link/roam/Scan/busy/hi-pri-task + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + + if ((bt_link_info->a2dp_exist) && (!bt_link_info->pan_exist)) + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 17); + else + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + } else if ((!wifi_connected) && (!wifi_scan)) { + + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (bt_link_info->pan_exist) { + + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist) { + + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 16); + + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + + if ((wifi_link) || (wifi_roam) || (wifi_scan) || (wifi_busy) + || (coex_sta->wifi_is_high_pri_task)) + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 21); + else + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } +} + + +void halbtc8703b1ant_action_bt_sco_hid_only_busy(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, wifi_busy = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, + &wifi_bw); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + + if (bt_link_info->sco_exist) { + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } else if (coex_sta->hid_busy_num >= 2) {/*for 4/18 hid */ + /* if 11bg mode */ + if (wifi_bw == 0) { + + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + halbtc8703b1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x1, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + } else { + + if (wifi_busy) { + + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + halbtc8703b1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + } else { + + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + } + } + } else { + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 3); + } +} + + +void halbtc8703b1ant_action_wifi_only(IN struct btc_coexist *btcoexist) +{ + halbtc8703b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8703B_1ANT_PHASE_2G_RUNTIME); + halbtc8703b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); +} + +void halbtc8703b1ant_action_wifi_multi_port(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8703B_1ANT_PHASE_2G_RUNTIME); + + if (!bt_link_info->pan_exist) + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + else + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8703b1ant_action_wifi_linkscan_process(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + if (bt_link_info->pan_exist) { + + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + } else if (bt_link_info->a2dp_exist) { + + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 17); + + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 21); + + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } +} + +void halbtc8703b1ant_action_wifi_connected_bt_acl_busy(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_busy = false, wifi_turbo = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d, wl_noisy_level = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; +#endif + + if ((coex_sta->bt_relink_downcount != 0) + && (!bt_link_info->pan_exist) && (wifi_busy)) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Re-Link + A2DP + WL busy\n"); + BTC_TRACE(trace_buf); + + /*halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32);*/ + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + } else if (bt_link_info->a2dp_only) { /* A2DP */ + if (!wifi_busy) { + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + + if (coex_sta->wl_noisy_level == 2) + halbtc8703b1ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 17); + else + halbtc8703b1ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + + if (wifi_turbo) + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + else + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if (((bt_link_info->a2dp_exist) && + (bt_link_info->pan_exist)) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { /* A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP) */ + + if ((bt_link_info->hid_exist) && (coex_sta->hid_busy_num >= 2)) { + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + halbtc8703b1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 12); + } else if (wifi_busy) { + if (((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) || + (!coex_sta->is_A2DP_3M)) + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + else if (wifi_turbo) + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 18); + else + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 13); + } else + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 14); + + if (bt_link_info->hid_exist) + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + else if (wifi_turbo) + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + else + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) {/* HID+A2DP */ + + if ((wifi_busy) && (coex_sta->hid_busy_num >= 2)) { /*for 4/18 hid */ + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + halbtc8703b1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 9); + } else { + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 8); + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } + + } else if ((bt_link_info->pan_only) + || (bt_link_info->hid_exist && bt_link_info->pan_exist)) { + /* PAN(OPP,FTP), HID+PAN(OPP,FTP) */ + + if ((bt_link_info->hid_exist) && (bt_link_info->pan_exist) && + (coex_sta->hid_busy_num >= 2)) { + + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + halbtc8703b1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 12); + } else { + + if (!wifi_busy) + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 4); + else + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + + if (bt_link_info->hid_exist) + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + else if (wifi_turbo) + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + else + halbtc8703b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else { + /* BT no-profile busy (0x9) */ + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } +} + +void halbtc8703b1ant_action_wifi_not_connected(IN struct btc_coexist *btcoexist) +{ + /* tdma and coex table */ + halbtc8703b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8703b1ant_action_wifi_connected(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_busy = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect()===>\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8703B_1ANT_PHASE_2G_RUNTIME); + + if (BT_8703B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + + if (bt_link_info->hid_only)/* HID only */ + halbtc8703b1ant_action_bt_sco_hid_only_busy(btcoexist); + else + halbtc8703b1ant_action_wifi_connected_bt_acl_busy(btcoexist); + + } else if ((BT_8703B_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8703B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8703b1ant_action_bt_sco_hid_only_busy(btcoexist); + } else + halbtc8703b1ant_action_bt_idle(btcoexist); +} + + +void halbtc8703b1ant_run_sw_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + algorithm = halbtc8703b1ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + + if (halbtc8703b1ant_is_common_action(btcoexist)) { + + } else { + switch (coex_dm->cur_algorithm) { + case BT_8703B_1ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8703B_1ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8703B_1ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8703B_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + break; + case BT_8703B_1ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + break; + case BT_8703B_1ANT_COEX_ALGO_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HS mode.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8703B_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8703B_1ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8703B_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8703B_1ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = coexist All Off!!\n"); + BTC_TRACE(trace_buf); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +void halbtc8703b1ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + boolean increase_scan_dev_num = false; + boolean bt_ctrl_agg_buf_size = false; + boolean miracast_plus_bt = false, wifi_under_5g = false; + u8 agg_buf_size = 5; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0, wifi_bw; + u8 iot_peer = BTC_IOT_PEER_UNKNOWN; + boolean scan = false, link = false, roam = false, under_4way = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (!coex_sta->run_time_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], return for run_time_state = false !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->freeze_coexrun_by_btinfo) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), return for freeze_coexrun_by_btinfo\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->bt_whck_test) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under WHCK TEST!!!\n"); + BTC_TRACE(trace_buf); + halbtc8703b1ant_action_bt_whql_test(btcoexist); + return; + } + + if (coex_sta->bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!!\n"); + halbtc8703b1ant_action_wifi_only(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + BTC_TRACE(trace_buf); + halbtc8703b1ant_action_bt_inquiry(btcoexist); + return; + } + + if (coex_sta->is_setupLink) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is re-link !!!\n"); + halbtc8703b1ant_action_bt_relink(btcoexist); + return; + } + + if ((BT_8703B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8703B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8703B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + increase_scan_dev_num = true; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, + &increase_scan_dev_num); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + BTC_TRACE(trace_buf); + + if (bt_link_info->bt_link_exist) + miracast_plus_bt = true; + else + miracast_plus_bt = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + halbtc8703b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + false, 0x5); + + if (scan || link || roam || under_4way) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], scan = %d, link = %d, roam = %d 4way = %d!!!\n", + scan, link, roam, under_4way); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under linkscan process + Multi-Port !!\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_action_wifi_linkscan_process(btcoexist); + } else + halbtc8703b1ant_action_wifi_multi_port(btcoexist); + + return; + } else { + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + } + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, &wifi_connected); + + if ((bt_link_info->bt_link_exist) && (wifi_connected)) { + + btcoexist->btc_get(btcoexist, BTC_GET_U1_IOT_PEER, &iot_peer); + + if (BTC_IOT_PEER_CISCO == iot_peer) { + + if (BTC_WIFI_BW_HT40 == wifi_bw) + halbtc8703b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, true, 0x10); + else + halbtc8703b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, true, 0x8); + } else + halbtc8703b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x5); + } + + halbtc8703b1ant_run_sw_coexist_mechanism( + btcoexist); /* just print debug message */ + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is hs\n"); + BTC_TRACE(trace_buf); + halbtc8703b1ant_action_bt_hs(btcoexist); + return; + } + + if ((BT_8703B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) || + (BT_8703B_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is idle\n"); + BTC_TRACE(trace_buf); + halbtc8703b1ant_action_bt_idle(btcoexist); + return; + } + + if (scan || link || roam || under_4way) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], scan = %d, link = %d, roam = %d 4way = %d!!!\n", + scan, link, roam, under_4way); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under linkscan process!!\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_action_wifi_linkscan_process(btcoexist); + } else if (wifi_connected) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under connected!!\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_action_wifi_connected(btcoexist); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under not-connected!!\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_action_wifi_not_connected(btcoexist); + } +} + + +void halbtc8703b1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + + halbtc8703b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->pop_event_cnt = 0; + coex_sta->cnt_RemoteNameReq = 0; + coex_sta->cnt_ReInit = 0; + coex_sta->cnt_setupLink = 0; + coex_sta->cnt_IgnWlanAct = 0; + coex_sta->cnt_Page = 0; +} + +void halbtc8703b1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean back_up, IN boolean wifi_only) +{ + u32 u32tmp0 = 0, u32tmp1 = 0, u32tmp2 = 0; + u8 i = 0; + + u32tmp0 = btcoexist->btc_read_4byte(btcoexist, 0x70), + u32tmp1 = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "\n [BTCoex], ********** 0x70/ 0x38/ 0x54 (Before Init HW config) = 0x%x/ 0x%x/ 0x%x**********\n", + u32tmp0, + u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 1Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->gnt_error_cnt = 0; + coex_sta->bt_relink_downcount = 0; + + for (i = 0; i <= 9; i++) + coex_sta->bt_afh_map[i] = 0; + + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = (btcoexist->btc_read_1byte(btcoexist, + 0xf1) & 0xf0) >> 4; + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + + /* BT report packet sample rate */ + btcoexist->btc_write_1byte(btcoexist, 0x790, 0x5); + + /* Enable BT counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + + /* Enable PTA (3-wire function form BT side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x41, 0x02, 0x1); + + /* Enable PTA (tx/rx signal form WiFi side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4c6, 0x10, 0x1); + + halbtc8703b1ant_enable_gnt_to_gpio(btcoexist, false); + + if (btcoexist->btc_read_1byte(btcoexist, 0x80) == 0xc6) + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ONOFF, true); + + halbtc8703b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + + /* Antenna config */ + if (wifi_only) { + coex_sta->concurrent_rx_mode_on = false; + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI, + FORCE_EXEC, + BT_8703B_1ANT_PHASE_WLANONLY_INIT); + } else { + coex_sta->concurrent_rx_mode_on = true; + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x953, 0x2, 0x1); + /* RF 0x1[0] = 0->Set GNT_WL_RF_Rx always = 1 for con-current Rx */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0x1, 0x0); + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8703B_1ANT_PHASE_COEX_INIT); + } + + /* PTA parameter */ + halbtc8703b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + u32tmp0 = btcoexist->btc_read_4byte(btcoexist, 0x70), + u32tmp1 = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** 0x70/ 0x38/ 0x54 (After Init HW config) = 0x%x/ 0x%x/ 0x%x**********\n", + u32tmp0, + u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); + +} + + + +/* ************************************************************ + * work around function start with wa_halbtc8703b1ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8703b1ant_ + * ************************************************************ */ +void ex_halbtc8703b1ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Execute 8703b 1-Ant PowerOn Setting xxxxxxxxxxxxxxxx!!\n"); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Ant Det Finish = %s, Ant Det Number = %d\n", + (board_info->btdm_ant_det_finish ? "Yes" : "No"), + board_info->btdm_ant_num_by_ant_det); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = true; + + /* enable BB, REG_SYS_FUNC_EN such that we can write BB/MAC reg correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT(0) | BIT(1)); + + /* set Path control owner to WiFi */ + halbtc8703b1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8703B_1ANT_PCO_WLSIDE); + + /* set GNT_BT to high */ + halbtc8703b1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8703B_1ANT_GNT_BLOCK_RFC_BB, + BT_8703B_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8703B_1ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to low */ + halbtc8703b1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8703B_1ANT_GNT_BLOCK_RFC_BB, + BT_8703B_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8703B_1ANT_SIG_STA_SET_TO_LOW); + + /* set WLAN_ACT = 0 */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + halbtc8703b1ant_enable_gnt_to_gpio(btcoexist, false); + + /* */ + /* S0 or S1 setting and Local register setting(By the setting fw can get ant number, S0/S1, ... info) */ + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + + u8tmp = 0; + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + + if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, u8tmp); + + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** 0x70(MAC)/0x38/0x54 (Power-On) =0x%x/ 0x%x/ 0x%x**********\n", + btcoexist->btc_read_4byte(btcoexist, 0x70), + halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38), + halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, 0x54)); + BTC_TRACE(trace_buf); + + +} + +void ex_halbtc8703b1ant_pre_load_firmware(IN struct btc_coexist *btcoexist) +{ +} + +void ex_halbtc8703b1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8703b1ant_init_hw_config(btcoexist, true, wifi_only); + btcoexist->stop_coex_dm = false; +} + +void ex_halbtc8703b1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8703b1ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u16 u16tmp[4]; + u32 u32tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + u32 fw_ver = 0, bt_patch_ver = 0, bt_coex_ver = 0; + static u8 pop_report_in_10s = 0; + u32 phyver = 0; + boolean lte_coex_on = false; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + if (btcoexist->stop_coex_dm) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (psd_scan->ant_det_try_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + "Ant PG Num/ Mech/ Pos", + board_info->pg_ant_num, board_info->btdm_ant_num, + board_info->btdm_ant_pos); + CL_PRINTF(cli_buf); + } else { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %d (%d/%d/%d)", + "Ant PG Num/ Mech(Ant_Det)/ Pos", + board_info->pg_ant_num, + board_info->btdm_ant_num_by_ant_det, + board_info->btdm_ant_pos, + psd_scan->ant_det_try_count, + psd_scan->ant_det_fail_count, + psd_scan->ant_det_result); + CL_PRINTF(cli_buf); + + if (board_info->btdm_ant_det_finish) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "Ant Det PSD Value", + psd_scan->ant_det_peak_val); + CL_PRINTF(cli_buf); + } + } + + + /*bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver;*/ + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + + bt_coex_ver = ((coex_sta->bt_coex_supported_version & 0xff00) >> 8); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8703b_1ant, glcoex_ver_8703b_1ant, + glcoex_ver_btdesired_8703b_1ant, + bt_coex_ver, + (bt_coex_ver == 0xff ? "Unknown" : + (bt_coex_ver >= glcoex_ver_btdesired_8703b_1ant ? + "Match":"Mis-Match"))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ v%d/ %c", + "W_FW/ B_FW/ Phy/ Kt", + fw_ver, bt_patch_ver, phyver, + coex_sta->cut_version + 65); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "Wifi channel informed to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s", + "WifibHiPri/ Ccklock/ CckEverLock", + (coex_sta->wifi_is_high_pri_task ? "Yes" : "No"), + (coex_sta->cck_lock ? "Yes" : "No"), + (coex_sta->cck_ever_lock ? "Yes" : "No")); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + pop_report_in_10s++; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d/ %d] ", + "BT [status/ rssi/ retryCnt/ popCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page") + : ((BT_8703B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8703B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi - 100, coex_sta->bt_retry_cnt, + coex_sta->pop_event_cnt); + CL_PRINTF(cli_buf); + + if (pop_report_in_10s >= 5) { + coex_sta->pop_event_cnt = 0; + pop_report_in_10s = 0; + } + + if (coex_sta->num_of_profile != 0) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s%s%s%s%s", + "Profiles", + ((bt_link_info->a2dp_exist) ? "A2DP," : ""), + ((bt_link_info->sco_exist) ? "SCO," : ""), + ((bt_link_info->hid_exist) ? + ((coex_sta->hid_busy_num >= 2) ? "HID(4/18)," : + "HID(2/18),") : ""), + ((bt_link_info->pan_exist) ? "PAN," : ""), + ((coex_sta->voice_over_HOGP) ? "Voice" : "")); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = None", + "Profiles"); + + CL_PRINTF(cli_buf); + + if (bt_link_info->a2dp_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %d/ %s", + "A2DP Rate/Bitpool/Auto_Slot", + ((coex_sta->is_A2DP_3M) ? "3M" : "No_3M"), + coex_sta->a2dp_bit_pool, + ((coex_sta->is_autoslot) ? "On" : "Off") + ); + CL_PRINTF(cli_buf); + } + + if (bt_link_info->hid_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "HID PairNum/Forbid_Slot", + coex_sta->hid_pair_cnt, + coex_sta->forbidden_slot + ); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ 0x%x", + "Role/IgnWlanAct/Feature", + ((bt_link_info->slave_role) ? "Slave" : "Master"), + ((coex_dm->cur_ignore_wlan_act) ? "Yes" : "No"), + coex_sta->bt_coex_supported_feature); + CL_PRINTF(cli_buf); + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", + "ReInit/ReLink/IgnWlact/Page/NameReq", + coex_sta->cnt_ReInit, + coex_sta->cnt_setupLink, + coex_sta->cnt_IgnWlanAct, + coex_sta->cnt_Page, + coex_sta->cnt_RemoteNameReq + ); + CL_PRINTF(cli_buf); + + halbtc8703b1ant_read_score_board(btcoexist, &u16tmp[0]); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %04x", + "ScoreBoard[14:0] (from BT)", u16tmp[0]); + CL_PRINTF(cli_buf); + + if (coex_sta->num_of_profile > 0) { + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + "AFH MAP", + coex_sta->bt_afh_map[0], + coex_sta->bt_afh_map[1], + coex_sta->bt_afh_map[2], + coex_sta->bt_afh_map[3], + coex_sta->bt_afh_map[4], + coex_sta->bt_afh_map[5], + coex_sta->bt_afh_map[6], + coex_sta->bt_afh_map[7], + coex_sta->bt_afh_map[8], + coex_sta->bt_afh_map[9] + ); + CL_PRINTF(cli_buf); + } + + for (i = 0; i < BT_INFO_SRC_8703B_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8703b_1ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + if (btcoexist->manual_control) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanisms] (before Manual)============"); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanisms]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "SM[LowPenaltyRA]", + coex_dm->cur_low_penalty_ra); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (%s,%s)", + "PS TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + (coex_dm->cur_ps_tdma_on ? "On" : "Off"), + (coex_dm->auto_tdma_adjust ? "Adj" : "Fix")); + + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "WL/BT Coex Table Type", + coex_sta->coex_table_type); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x778/0x6cc/IgnWlanAct", + u8tmp[0], u32tmp[0], coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + lte_coex_on = ((u32tmp[0] & BIT(7)) >> 7) ? true : false; + + if (lte_coex_on) { + u32tmp[0] = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa0); + u32tmp[1] = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa4); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "LTE Coex Table W_L/B_L", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa8); + u32tmp[1] = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xac); + u32tmp[2] = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xb0); + u32tmp[3] = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xb4); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "LTE Break Table W_L/B_L/L_W/L_B", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff, + u32tmp[2] & 0xffff, u32tmp[3] & 0xffff); + CL_PRINTF(cli_buf); + } + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x73); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %s", + "LTE CoexOn/Path Ctrl Owner", + (int)((u32tmp[0] & BIT(7)) >> 7), + ((u8tmp[0] & BIT(2)) ? "WL" : "BT")); + CL_PRINTF(cli_buf); + + if (lte_coex_on) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "LTE 3Wire/OPMode/UART/UARTMode", + (int)((u32tmp[0] & BIT(6)) >> 6), + (int)((u32tmp[0] & (BIT(5) | BIT(4))) >> 4), + (int)((u32tmp[0] & BIT(3)) >> 3), + (int)(u32tmp[0] & (BIT(2) | BIT(1) | BIT(0)))); + CL_PRINTF(cli_buf); + } + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (BB:%s)/ %s (BB:%s)/ %s %d", + "GNT_WL_Ctrl/GNT_BT_Ctrl/Dbg", + ((u32tmp[0] & BIT(12)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(8)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(14)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(10)) ? "SW" : "HW"), + ((u8tmp[0] & BIT(3)) ? "On" : "Off"), + coex_sta->gnt_error_cnt); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8703b1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "GNT_WL/GNT_BT/LTE_Busy/UART_Busy", + (int)((u32tmp[0] & BIT(2)) >> 2), + (int)((u32tmp[0] & BIT(3)) >> 3), + (int)((u32tmp[0] & BIT(1)) >> 1), (int)(u32tmp[0] & BIT(0))); + CL_PRINTF(cli_buf); + + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x4c6); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x4c6[4]/0x40[5] (WL/BT PTA)", + (int)((u8tmp[0] & BIT(4)) >> 4), + (int)((u8tmp[1] & BIT(5)) >> 5)); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x953); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ %s", + "0x550(bcn ctrl)/0x522/4-RxAGC", + u32tmp[0], u8tmp[0], (u8tmp[1] & 0x2) ? "On" : "Off"); + CL_PRINTF(cli_buf); + + fa_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, PHYDM_INFO_FA_OFDM); + fa_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, PHYDM_INFO_FA_CCK); + cca_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, PHYDM_INFO_CCA_OFDM); + cca_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, PHYDM_INFO_CCA_CCK); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", + cca_cck, fa_cck, cca_ofdm, fa_ofdm); + CL_PRINTF(cli_buf); + +#if 1 + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11n-agg", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11n-agg", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + CL_PRINTF(cli_buf); +#endif + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s/ %d", + "WlHiPri/ Locking/ Locked/ Noisy", + (coex_sta->wifi_is_high_pri_task ? "Yes" : "No"), + (coex_sta->cck_lock ? "Yes" : "No"), + (coex_sta->cck_ever_lock ? "Yes" : "No"), + coex_sta->wl_noisy_level); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d %s", + "0x770(Hi-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx, + (coex_sta->is_hiPri_rx_overhead ? "(scan overhead!!)" : "")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d %s", + "0x774(Lo-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx, + (bt_link_info->slave_role ? "(Slave!!)" : ( + coex_sta->is_tdma_btautoslot_hang ? "(auto-slot hang!!)" : ""))); + CL_PRINTF(cli_buf); + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8703b1ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + coex_sta->under_lps = false; + + /* Write WL "Active" in Score-board for LPS off */ + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, false); + + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ONOFF, false); + + halbtc8703b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8703B_1ANT_PHASE_WLAN_OFF); + + halbtc8703b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, true); + + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ONOFF, true); + + halbtc8703b1ant_init_hw_config(btcoexist, false, false); + halbtc8703b1ant_init_coex_dm(btcoexist); + halbtc8703b1ant_query_bt_info(btcoexist); + + coex_sta->under_ips = false; + } +} + +void ex_halbtc8703b1ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + coex_sta->under_ips = false; + + if (coex_sta->force_lps_on == true) { /* LPS No-32K */ + /* Write WL "Active" in Score-board for PS-TDMA */ + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, true); + + } else { /* LPS-32K, need check if this h2c 0x71 can work?? (2015/08/28) */ + /* Write WL "Non-Active" in Score-board for Native-PS */ + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, false); + } + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + + + /* Write WL "Active" in Score-board for LPS off */ + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, true); + } +} + +void ex_halbtc8703b1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + halbtc8703b1ant_query_bt_info(btcoexist); + + if (BTC_SCAN_START == type) { + + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_SCAN, true); + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, true); + + halbtc8703b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 8); + + /* Force antenna setup for no scan result issue */ + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8703B_1ANT_PHASE_2G_RUNTIME); + + halbtc8703b1ant_run_coexist_mechanism(btcoexist); + + } else { + + coex_sta->wifi_is_high_pri_task = false; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify (Scan-AP = %d)\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_run_coexist_mechanism(btcoexist); + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START Notify() end\n"); + BTC_TRACE(trace_buf); + +} + +void ex_halbtc8703b1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (BTC_ASSOCIATE_START == type) { + coex_sta->wifi_is_high_pri_task = true; + + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_SCAN, true); + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, true); + + halbtc8703b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 8); + + /* Force antenna setup for no scan result issue */ + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8703B_1ANT_PHASE_2G_RUNTIME); + /* psd_scan->ant_det_is_ant_det_available = true; */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify\n"); + BTC_TRACE(trace_buf); + coex_dm->arp_cnt = 0; + + halbtc8703b1ant_run_coexist_mechanism(btcoexist); + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_run_coexist_mechanism(btcoexist); + } + +} + +void ex_halbtc8703b1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_under_b_mode = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if (BTC_MEDIA_CONNECT == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, true); + halbtc8703b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 8); + + /* Force antenna setup for no scan result issue */ + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8703B_1ANT_PHASE_2G_RUNTIME); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + /* btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x10); */ /*CCK Tx */ + /* btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x10); */ /*CCK Rx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } + + coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, + 0x430); + coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, + 0x434); + coex_dm->backup_retry_limit = btcoexist->btc_read_2byte( + btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = btcoexist->btc_read_1byte( + btcoexist, 0x456); + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, false); + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + + coex_sta->cck_ever_lock = false; + } + + halbtc8703b1ant_update_wifi_channel_info(btcoexist, type); + +} + +void ex_halbtc8703b1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean under_4way = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (under_4way) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ---- under_4way!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } else if (BTC_PACKET_ARP == type) { + + coex_dm->arp_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ARP notify -cnt = %d\n", + coex_dm->arp_cnt); + BTC_TRACE(trace_buf); + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet DHCP or EAPOL notify [Type = %d]\n", + type); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } + + if (coex_sta->wifi_is_high_pri_task) { + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_SCAN, true); + halbtc8703b1ant_run_coexist_mechanism(btcoexist); + } +} + +void ex_halbtc8703b1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 i, rsp_source = 0; + boolean wifi_connected = false; + boolean wifi_scan = false, wifi_link = false, wifi_roam = false, + wifi_busy = false; + + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8703B_1ANT_MAX) + rsp_source = BT_INFO_SRC_8703B_1ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt_info[%d], len=%d, data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + coex_sta->bt_info = coex_sta->bt_info_c2h[rsp_source][1]; + coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + coex_sta->bt_info_ext2 = coex_sta->bt_info_c2h[rsp_source][5]; + + if (BT_INFO_SRC_8703B_1ANT_WIFI_FW != rsp_source) { + + /* if 0xff, it means BT is under WHCK test */ + coex_sta->bt_whck_test = ((coex_sta->bt_info == 0xff) ? true : + false); + + coex_sta->bt_create_connection = (( + coex_sta->bt_info_c2h[rsp_source][2] & 0x80) ? true : + false); + + /* unit: %, value-100 to translate to unit: dBm */ + coex_sta->bt_rssi = coex_sta->bt_info_c2h[rsp_source][3] * 2 + + 10; + + coex_sta->c2h_bt_remote_name_req = (( + coex_sta->bt_info_c2h[rsp_source][2] & 0x20) ? true : + false); + + coex_sta->is_A2DP_3M = ((coex_sta->bt_info_c2h[rsp_source][2] & + 0x10) ? true : false); + + coex_sta->acl_busy = ((coex_sta->bt_info_c2h[rsp_source][1] & + 0x9) ? true : false); + + coex_sta->voice_over_HOGP = ((coex_sta->bt_info_ext & 0x10) ? + true : false); + + coex_sta->c2h_bt_inquiry_page = ((coex_sta->bt_info & + BT_INFO_8703B_1ANT_B_INQ_PAGE) ? true : false); + + coex_sta->a2dp_bit_pool = ((( + coex_sta->bt_info_c2h[rsp_source][1] & 0x49) == 0x49) ? + coex_sta->bt_info_c2h[rsp_source][6] : 0); + + coex_sta->bt_retry_cnt = coex_sta->bt_info_c2h[rsp_source][2] & + 0xf; + + coex_sta->is_autoslot = coex_sta->bt_info_ext2 & 0x8; + + coex_sta->forbidden_slot = coex_sta->bt_info_ext2 & 0x7; + + coex_sta->hid_busy_num = (coex_sta->bt_info_ext2 & 0x30) >> 4; + + coex_sta->hid_pair_cnt = (coex_sta->bt_info_ext2 & 0xc0) >> 6; + + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->c2h_bt_remote_name_req) + coex_sta->cnt_RemoteNameReq++; + + if (coex_sta->bt_info_ext & BIT(1)) + coex_sta->cnt_ReInit++; + + if (coex_sta->bt_info_ext & BIT(2)) { + coex_sta->cnt_setupLink++; + coex_sta->is_setupLink = true; + } else + coex_sta->is_setupLink = false; + + if (coex_sta->bt_info_ext & BIT(3)) + coex_sta->cnt_IgnWlanAct++; + + if (coex_sta->bt_create_connection) { + coex_sta->cnt_Page++; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &wifi_link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &wifi_roam); + + if ((wifi_link) || (wifi_roam) || (wifi_scan) || + (coex_sta->wifi_is_high_pri_task) || (wifi_busy)) { + + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_SCAN, true); + + } else { + + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_SCAN, false); + } + } else + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_SCAN, false); + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + + if ((!btcoexist->manual_control) && + (!btcoexist->stop_coex_dm)) { + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* Re-Init */ + if ((coex_sta->bt_info_ext & BIT(1))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + if (wifi_connected) + halbtc8703b1ant_update_wifi_channel_info( + btcoexist, BTC_MEDIA_CONNECT); + else + halbtc8703b1ant_update_wifi_channel_info( + btcoexist, + BTC_MEDIA_DISCONNECT); + } + + + /* If Ignore_WLanAct && not SetUp_Link */ + if ((coex_sta->bt_info_ext & BIT(3)) && + (!(coex_sta->bt_info_ext & BIT(2))) && + (!(coex_sta->bt_info_ext & BIT(6)))) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8703b1ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, false); + } else { + if (coex_sta->bt_info_ext & BIT(2)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ignore Wlan active because Re-link!!\n"); + BTC_TRACE(trace_buf); + } else if (coex_sta->bt_info_ext & BIT(6)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ignore Wlan active because Role-Switch!!\n"); + BTC_TRACE(trace_buf); + } + } + } + + } + if ((coex_sta->bt_info_ext & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit4 check, query BLE Scan type!!\n"); + BTC_TRACE(trace_buf); + coex_sta->bt_ble_scan_type = btcoexist->btc_get_ble_scan_type_from_bt(btcoexist); + + if ((coex_sta->bt_ble_scan_type & 0x1) == 0x1) + coex_sta->bt_ble_scan_para[0] = btcoexist->btc_get_ble_scan_para_from_bt(btcoexist, 0x1); + if ((coex_sta->bt_ble_scan_type & 0x2) == 0x2) + coex_sta->bt_ble_scan_para[1] = btcoexist->btc_get_ble_scan_para_from_bt(btcoexist, 0x2); + if ((coex_sta->bt_ble_scan_type & 0x4) == 0x4) + coex_sta->bt_ble_scan_para[2] = btcoexist->btc_get_ble_scan_para_from_bt(btcoexist, 0x4); + } + + halbtc8703b1ant_update_bt_link_info(btcoexist); + + halbtc8703b1ant_run_coexist_mechanism(btcoexist); +} + + +void ex_halbtc8703b1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], RF Status notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_RF_ON == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned ON!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = false; + + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, true); + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ONOFF, true); + + /* halbtc8703b1ant_init_hw_config(btcoexist, false, false); */ + } else if (BTC_RF_OFF == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned OFF!!\n"); + BTC_TRACE(trace_buf); + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ONOFF, false); + + halbtc8703b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8703B_1ANT_PHASE_WLAN_OFF); + + btcoexist->stop_coex_dm = true; + + } +} + +void ex_halbtc8703b1ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ONOFF, false); + + halbtc8703b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8703B_1ANT_PHASE_WLAN_OFF); + + ex_halbtc8703b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + halbtc8703b1ant_enable_gnt_to_gpio(btcoexist, false); + + btcoexist->stop_coex_dm = true; +} + +void ex_halbtc8703b1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Pnp notify\n"); + BTC_TRACE(trace_buf); + + if ((BTC_WIFI_PNP_SLEEP == pnp_state) || + (BTC_WIFI_PNP_SLEEP_KEEP_ANT == pnp_state)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ONOFF, false); + + if (BTC_WIFI_PNP_SLEEP_KEEP_ANT == pnp_state) { + + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8703B_1ANT_PHASE_2G_RUNTIME); + } else { + + halbtc8703b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8703B_1ANT_PHASE_WLAN_OFF); + } + + btcoexist->stop_coex_dm = true; + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ACTIVE, true); + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_ONOFF, true); + + btcoexist->stop_coex_dm = false; + } +} + +void ex_halbtc8703b1ant_coex_dm_reset(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], *****************Coex DM Reset*****************\n"); + BTC_TRACE(trace_buf); + + halbtc8703b1ant_init_hw_config(btcoexist, false, false); + halbtc8703b1ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8703b1ant_periodical(IN struct btc_coexist *btcoexist) +{ + u32 bt_patch_ver; + boolean wifi_busy = false; + static u8 cnt = 0; + boolean bt_relink_finish = false; + +#if (BT_AUTO_REPORT_ONLY_8703B_1ANT == 0) + halbtc8703b1ant_query_bt_info(btcoexist); +#endif + + halbtc8703b1ant_monitor_bt_ctr(btcoexist); + halbtc8703b1ant_monitor_wifi_ctr(btcoexist); + + halbtc8703b1ant_monitor_bt_enable_disable(btcoexist); + +# if 1 + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + /* halbtc8703b1ant_read_score_board(btcoexist, &bt_scoreboard_val); */ + + if (wifi_busy) { + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_UNDERTEST, true); + /* + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_WLBUSY, true); + + if (bt_scoreboard_val & BIT(6)) + halbtc8703b1ant_query_bt_info(btcoexist); */ + } else { + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_UNDERTEST, false); + /* + halbtc8703b1ant_post_state_to_bt(btcoexist, + BT_8703B_1ANT_SCOREBOARD_WLBUSY, + false); */ + } +#endif + + if (coex_sta->bt_relink_downcount != 0) { + coex_sta->bt_relink_downcount--; + + if (coex_sta->bt_relink_downcount == 0) + bt_relink_finish = true; + } + + /* for 4-way, DHCP, EAPOL packet */ + if (coex_sta->specific_pkt_period_cnt > 0) { + + coex_sta->specific_pkt_period_cnt--; + + if ((coex_sta->specific_pkt_period_cnt == 0) && + (coex_sta->wifi_is_high_pri_task)) + coex_sta->wifi_is_high_pri_task = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ***************** Hi-Pri Task = %s*****************\n", + (coex_sta->wifi_is_high_pri_task ? "Yes" : + "No")); + BTC_TRACE(trace_buf); + + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->bt_coex_supported_feature == 0) + btcoexist->btc_get(btcoexist, BTC_GET_U4_SUPPORTED_FEATURE, + &coex_sta->bt_coex_supported_feature); + + if ((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) + btcoexist->btc_get(btcoexist, BTC_GET_U4_SUPPORTED_VERSION, + &coex_sta->bt_coex_supported_version); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + btcoexist->bt_info.bt_get_fw_ver = bt_patch_ver; + + if (coex_sta->num_of_profile > 0) { + cnt++; + + if (cnt >= 3) { + btcoexist->btc_get_bt_afh_map_from_bt(btcoexist, 0, + &coex_sta->bt_afh_map[0]); + cnt = 0; + } + } + } + + if (halbtc8703b1ant_is_wifibt_status_changed(btcoexist)) + halbtc8703b1ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8703b1ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ + /* No Antenna Detection required because 8730b is only 1-Ant */ +} + +void ex_halbtc8703b1ant_antenna_isolation(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ + + +} + +void ex_halbtc8703b1ant_psd_scan(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ + + +} + +void ex_halbtc8703b1ant_display_ant_detection(IN struct btc_coexist *btcoexist) +{ + +} + +#endif + +#endif /* #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) */ + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8703b1ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8703b1ant.h new file mode 100644 index 0000000..ed5ebe0 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8703b1ant.h @@ -0,0 +1,404 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8703B_SUPPORT == 1) +/* ******************************************* + * The following is for 8703B 1ANT BT Co-exist definition + * ******************************************* */ +#define BT_AUTO_REPORT_ONLY_8703B_1ANT 1 +#define BT_8703B_1ANT_ENABLE_GNTBT_TO_GPIO14 0 + +#define BT_INFO_8703B_1ANT_B_FTP BIT(7) +#define BT_INFO_8703B_1ANT_B_A2DP BIT(6) +#define BT_INFO_8703B_1ANT_B_HID BIT(5) +#define BT_INFO_8703B_1ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8703B_1ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8703B_1ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8703B_1ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8703B_1ANT_B_CONNECTION BIT(0) + +#define BT_INFO_8703B_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT(0))) ? true : false) + +#define BTC_RSSI_COEX_THRESH_TOL_8703B_1ANT 2 + +#define BT_8703B_1ANT_WIFI_NOISY_THRESH 50 /* max: 255 */ + +/* for Antenna detection */ +#define BT_8703B_1ANT_ANTDET_PSDTHRES_BACKGROUND 50 +#define BT_8703B_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION 70 +#define BT_8703B_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION 55 +#define BT_8703B_1ANT_ANTDET_PSDTHRES_1ANT 35 +#define BT_8703B_1ANT_ANTDET_RETRY_INTERVAL 10 /* retry timer if ant det is fail, unit: second */ +#define BT_8703B_1ANT_ANTDET_SWEEPPOINT_DELAY 40000 +#define BT_8703B_1ANT_ANTDET_ENABLE 0 +#define BT_8703B_1ANT_ANTDET_COEXMECHANISMSWITCH_ENABLE 0 + +#define BT_8703B_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT 30000 + +enum bt_8703b_1ant_signal_state { + BT_8703B_1ANT_SIG_STA_SET_TO_LOW = 0x0, + BT_8703B_1ANT_SIG_STA_SET_BY_HW = 0x0, + BT_8703B_1ANT_SIG_STA_SET_TO_HIGH = 0x1, + BT_8703B_1ANT_SIG_STA_MAX +}; + +enum bt_8703b_1ant_path_ctrl_owner { + BT_8703B_1ANT_PCO_BTSIDE = 0x0, + BT_8703B_1ANT_PCO_WLSIDE = 0x1, + BT_8703B_1ANT_PCO_MAX +}; + +enum bt_8703b_1ant_gnt_ctrl_type { + BT_8703B_1ANT_GNT_TYPE_CTRL_BY_PTA = 0x0, + BT_8703B_1ANT_GNT_TYPE_CTRL_BY_SW = 0x1, + BT_8703B_1ANT_GNT_TYPE_MAX +}; + +enum bt_8703b_1ant_gnt_ctrl_block { + BT_8703B_1ANT_GNT_BLOCK_RFC_BB = 0x0, + BT_8703B_1ANT_GNT_BLOCK_RFC = 0x1, + BT_8703B_1ANT_GNT_BLOCK_BB = 0x2, + BT_8703B_1ANT_GNT_BLOCK_MAX +}; + +enum bt_8703b_1ant_lte_coex_table_type { + BT_8703B_1ANT_CTT_WL_VS_LTE = 0x0, + BT_8703B_1ANT_CTT_BT_VS_LTE = 0x1, + BT_8703B_1ANT_CTT_MAX +}; + +enum bt_8703b_1ant_lte_break_table_type { + BT_8703B_1ANT_LBTT_WL_BREAK_LTE = 0x0, + BT_8703B_1ANT_LBTT_BT_BREAK_LTE = 0x1, + BT_8703B_1ANT_LBTT_LTE_BREAK_WL = 0x2, + BT_8703B_1ANT_LBTT_LTE_BREAK_BT = 0x3, + BT_8703B_1ANT_LBTT_MAX +}; + +enum bt_info_src_8703b_1ant { + BT_INFO_SRC_8703B_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8703B_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8703B_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8703B_1ANT_MAX +}; + +enum bt_8703b_1ant_bt_status { + BT_8703B_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8703B_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8703B_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8703B_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8703B_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8703B_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8703B_1ANT_BT_STATUS_MAX +}; + +enum bt_8703b_1ant_wifi_status { + BT_8703B_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8703B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8703B_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8703B_1ANT_WIFI_STATUS_CONNECTED_SPECIFIC_PKT = 0x3, + BT_8703B_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8703B_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8703B_1ANT_WIFI_STATUS_MAX +}; + +enum bt_8703b_1ant_coex_algo { + BT_8703B_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8703B_1ANT_COEX_ALGO_SCO = 0x1, + BT_8703B_1ANT_COEX_ALGO_HID = 0x2, + BT_8703B_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8703B_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8703B_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8703B_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8703B_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8703B_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8703B_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8703B_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8703B_1ANT_COEX_ALGO_MAX = 0xb, +}; + +enum bt_8703b_1ant_phase { + BT_8703B_1ANT_PHASE_COEX_INIT = 0x0, + BT_8703B_1ANT_PHASE_WLANONLY_INIT = 0x1, + BT_8703B_1ANT_PHASE_WLAN_OFF = 0x2, + BT_8703B_1ANT_PHASE_2G_RUNTIME = 0x3, + BT_8703B_1ANT_PHASE_5G_RUNTIME = 0x4, + BT_8703B_1ANT_PHASE_BTMPMODE = 0x5, + BT_8703B_1ANT_PHASE_ANTENNA_DET = 0x6, + BT_8703B_1ANT_PHASE_MAX +}; + +enum bt_8703b_1ant_Scoreboard { + BT_8703B_1ANT_SCOREBOARD_ACTIVE = BIT(0), + BT_8703B_1ANT_SCOREBOARD_ONOFF = BIT(1), + BT_8703B_1ANT_SCOREBOARD_SCAN = BIT(2), + BT_8703B_1ANT_SCOREBOARD_UNDERTEST = BIT(3), + BT_8703B_1ANT_SCOREBOARD_WLBUSY = BIT(6) +}; + + +struct coex_dm_8703b_1ant { + /* hw setting */ + u8 pre_ant_pos_type; + u8 cur_ant_pos_type; + /* fw mechanism */ + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean auto_tdma_adjust; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + /* sw mechanism */ + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + boolean limited_dig; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u32 pre_ra_mask; + u32 cur_ra_mask; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; + u32 arp_cnt; + + u8 error_condition; +}; + +struct coex_sta_8703b_1ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + boolean bt_hi_pri_link_exist; + u8 num_of_profile; + + boolean under_lps; + boolean under_ips; + u32 specific_pkt_period_cnt; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + boolean is_hiPri_rx_overhead; + s8 bt_rssi; + boolean bt_tx_rx_mask; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + u8 bt_info_c2h[BT_INFO_SRC_8703B_1ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8703B_1ANT_MAX]; + boolean bt_whck_test; + boolean c2h_bt_inquiry_page; + boolean c2h_bt_remote_name_req; + boolean c2h_bt_page; /* Add for win8.1 page out issue */ + boolean wifi_is_high_pri_task; /* Add for win8.1 page out issue */ + u8 bt_retry_cnt; + u8 bt_info_ext; + u8 bt_info_ext2; + u32 pop_event_cnt; + u8 scan_ap_num; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_vht; + + boolean cck_lock; + boolean pre_ccklock; + boolean cck_ever_lock; + u8 coex_table_type; + + boolean force_lps_on; + + boolean concurrent_rx_mode_on; + + u16 score_board; + u8 isolation_btween_wb; /* 0~ 50 */ + + u8 a2dp_bit_pool; + u8 cut_version; + boolean acl_busy; + boolean bt_create_connection; + + u32 bt_coex_supported_feature; + u32 bt_coex_supported_version; + + u8 bt_ble_scan_type; + u32 bt_ble_scan_para[3]; + + boolean run_time_state; + boolean freeze_coexrun_by_btinfo; + + boolean is_A2DP_3M; + boolean voice_over_HOGP; + u8 bt_info; + boolean is_autoslot; + u8 forbidden_slot; + u8 hid_busy_num; + u8 hid_pair_cnt; + + u32 cnt_RemoteNameReq; + u32 cnt_setupLink; + u32 cnt_ReInit; + u32 cnt_IgnWlanAct; + u32 cnt_Page; + + u16 bt_reg_vendor_ac; + u16 bt_reg_vendor_ae; + + boolean is_setupLink; + u8 wl_noisy_level; + u32 gnt_error_cnt; + + u8 bt_afh_map[10]; + u8 bt_relink_downcount; + boolean is_tdma_btautoslot; + boolean is_tdma_btautoslot_hang; +}; + +#define BT_8703B_1ANT_ANTDET_PSD_POINTS 256 /* MAX:1024 */ +#define BT_8703B_1ANT_ANTDET_PSD_AVGNUM 1 /* MAX:3 */ +#define BT_8703B_1ANT_ANTDET_BUF_LEN 16 + +struct psdscan_sta_8703b_1ant { + + u32 ant_det_bt_le_channel; /* BT LE Channel ex:2412 */ + u32 ant_det_bt_tx_time; + u32 ant_det_pre_psdscan_peak_val; + boolean ant_det_is_ant_det_available; + u32 ant_det_psd_scan_peak_val; + boolean ant_det_is_btreply_available; + u32 ant_det_psd_scan_peak_freq; + + u8 ant_det_result; + u8 ant_det_peak_val[BT_8703B_1ANT_ANTDET_BUF_LEN]; + u8 ant_det_peak_freq[BT_8703B_1ANT_ANTDET_BUF_LEN]; + u32 ant_det_try_count; + u32 ant_det_fail_count; + u32 ant_det_inteval_count; + u32 ant_det_thres_offset; + + u32 real_cent_freq; + s32 real_offset; + u32 real_span; + + u32 psd_band_width; /* unit: Hz */ + u32 psd_point; /* 128/256/512/1024 */ + u32 psd_report[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_report_max_hold[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_start_point; + u32 psd_stop_point; + u32 psd_max_value_point; + u32 psd_max_value; + u32 psd_start_base; + u32 psd_avg_num; /* 1/8/16/32 */ + u32 psd_gen_count; + boolean is_psd_running; + boolean is_psd_show_max_only; +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8703b1ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8703b1ant_pre_load_firmware(IN struct btc_coexist *btcoexist); +void ex_halbtc8703b1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8703b1ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8703b1ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8703b1ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8703b1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8703b1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8703b1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8703b1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8703b1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8703b1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8703b1ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8703b1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state); +void ex_halbtc8703b1ant_coex_dm_reset(IN struct btc_coexist *btcoexist); +void ex_halbtc8703b1ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8703b1ant_display_coex_info(IN struct btc_coexist *btcoexist); +void ex_halbtc8703b1ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); +void ex_halbtc8703b1ant_antenna_isolation(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); + +void ex_halbtc8703b1ant_psd_scan(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); +void ex_halbtc8703b1ant_display_ant_detection(IN struct btc_coexist *btcoexist); + +#else +#define ex_halbtc8703b1ant_power_on_setting(btcoexist) +#define ex_halbtc8703b1ant_pre_load_firmware(btcoexist) +#define ex_halbtc8703b1ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8703b1ant_init_coex_dm(btcoexist) +#define ex_halbtc8703b1ant_ips_notify(btcoexist, type) +#define ex_halbtc8703b1ant_lps_notify(btcoexist, type) +#define ex_halbtc8703b1ant_scan_notify(btcoexist, type) +#define ex_halbtc8703b1ant_connect_notify(btcoexist, type) +#define ex_halbtc8703b1ant_media_status_notify(btcoexist, type) +#define ex_halbtc8703b1ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8703b1ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8703b1ant_rf_status_notify(btcoexist, type) +#define ex_halbtc8703b1ant_halt_notify(btcoexist) +#define ex_halbtc8703b1ant_pnp_notify(btcoexist, pnp_state) +#define ex_halbtc8703b1ant_coex_dm_reset(btcoexist) +#define ex_halbtc8703b1ant_periodical(btcoexist) +#define ex_halbtc8703b1ant_display_coex_info(btcoexist) +#define ex_halbtc8703b1ant_antenna_detection(btcoexist, cent_freq, offset, span, seconds) +#define ex_halbtc8703b1ant_antenna_isolation(btcoexist, cent_freq, offset, span, seconds) +#define ex_halbtc8703b1ant_psd_scan(btcoexist, cent_freq, offset, span, seconds) +#define ex_halbtc8703b1ant_display_ant_detection(btcoexist) + +#endif + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b1ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b1ant.c new file mode 100644 index 0000000..98b12ac --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b1ant.c @@ -0,0 +1,5113 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8723B Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8723B_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8723b_1ant glcoex_dm_8723b_1ant; +static struct coex_dm_8723b_1ant *coex_dm = &glcoex_dm_8723b_1ant; +static struct coex_sta_8723b_1ant glcoex_sta_8723b_1ant; +static struct coex_sta_8723b_1ant *coex_sta = &glcoex_sta_8723b_1ant; +static struct psdscan_sta_8723b_1ant gl_psd_scan_8723b_1ant; +static struct psdscan_sta_8723b_1ant *psd_scan = &gl_psd_scan_8723b_1ant; + + +const char *const glbt_info_src_8723b_1ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u32 glcoex_ver_date_8723b_1ant = 20161007; +u32 glcoex_ver_8723b_1ant = 0x69; +u32 glcoex_ver_btdesired_8723b_1ant = 0x69; + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8723b1ant_ + * ************************************************************ */ + +void halbtc8723b1ant_update_ra_mask(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 dis_rate_mask) +{ + coex_dm->cur_ra_mask = dis_rate_mask; + + if (force_exec || (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_RAMASK, + &coex_dm->cur_ra_mask); + coex_dm->pre_ra_mask = coex_dm->cur_ra_mask; +} + +void halbtc8723b1ant_auto_rate_fallback_retry(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + boolean wifi_under_b_mode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + if (wifi_under_b_mode) { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +void halbtc8723b1ant_retry_limit(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || + (coex_dm->pre_retry_limit_type != + coex_dm->cur_retry_limit_type)) { + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +void halbtc8723b1ant_ampdu_max_time(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || + (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +void halbtc8723b1ant_limited_tx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ra_mask_type, IN u8 arfr_type, + IN u8 retry_limit_type, IN u8 ampdu_time_type) +{ + switch (ra_mask_type) { + case 0: /* normal mode */ + halbtc8723b1ant_update_ra_mask(btcoexist, force_exec, + 0x0); + break; + case 1: /* disable cck 1/2 */ + halbtc8723b1ant_update_ra_mask(btcoexist, force_exec, + 0x00000003); + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ + halbtc8723b1ant_update_ra_mask(btcoexist, force_exec, + 0x0001f1f7); + break; + default: + break; + } + + halbtc8723b1ant_auto_rate_fallback_retry(btcoexist, force_exec, + arfr_type); + halbtc8723b1ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8723b1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type); +} + +void halbtc8723b1ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +void halbtc8723b1ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +void halbtc8723b1ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + static u32 num_of_bt_counter_chk = 0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + /* to avoid 0x76e[3] = 1 (WLAN_Act control by PTA) during IPS */ + /* if (! (btcoexist->btc_read_1byte(btcoexist, 0x76e) & 0x8) ) */ + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + if ((coex_sta->high_priority_tx + coex_sta->high_priority_rx < 50) && + (bt_link_info->hid_exist == true)) + bt_link_info->hid_exist = false; + + if ((coex_sta->low_priority_tx > 1050) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + + if ((coex_sta->low_priority_rx >= 950) && (!coex_sta->under_ips) + && (coex_sta->low_priority_rx >= + coex_sta->low_priority_tx) && + (!coex_sta->c2h_bt_inquiry_page)) + bt_link_info->slave_role = true; + else + bt_link_info->slave_role = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n", + reg_hp_rx, reg_hp_tx, reg_lp_rx, reg_lp_tx); + BTC_TRACE(trace_buf); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + /* This part is for wifi FW and driver to update BT's status as disabled. */ + /* The flow is as the following */ + /* 1. disable BT */ + /* 2. if all BT Tx/Rx counter=0, after 6 sec we query bt info */ + /* 3. Because BT will not rsp from mailbox, so wifi fw will know BT is disabled */ + /* 4. FW will rsp c2h for BT that driver will know BT is disabled. */ + if ((reg_hp_tx == 0) && (reg_hp_rx == 0) && (reg_lp_tx == 0) && + (reg_lp_rx == 0)) { + num_of_bt_counter_chk++; + if (num_of_bt_counter_chk >= 3) { + halbtc8723b1ant_query_bt_info(btcoexist); + num_of_bt_counter_chk = 0; + } + } + +} + + +void halbtc8723b1ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ + s32 wifi_rssi = 0; + boolean wifi_busy = false, wifi_under_b_mode = false; + static u8 cck_lock_counter = 0; + u32 total_cnt; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + +#if 1 + + coex_sta->crc_ok_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_CCK); + coex_sta->crc_ok_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_LEGACY); + coex_sta->crc_ok_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_HT); + coex_sta->crc_ok_11n_vht = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_VHT); + + coex_sta->crc_err_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_CCK); + coex_sta->crc_err_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_LEGACY); + coex_sta->crc_err_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_HT); + coex_sta->crc_err_11n_vht = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_VHT); + +#endif + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + total_cnt = coex_sta->crc_ok_cck + coex_sta->crc_ok_11g + + coex_sta->crc_ok_11n + + coex_sta->crc_ok_11n_vht; + + if ((coex_dm->bt_status == BT_8723B_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == + BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY) || + (coex_dm->bt_status == + BT_8723B_1ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > (total_cnt - + coex_sta->crc_ok_cck)) { + if (cck_lock_counter < 3) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + + if (cck_lock_counter >= 3) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + if (coex_sta->cck_lock) + coex_sta->cck_ever_lock = true; + + coex_sta->pre_ccklock = coex_sta->cck_lock; + + +} + +boolean halbtc8723b1ant_is_wifi_status_changed(IN struct btc_coexist *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + + + } + + return false; +} + +void halbtc8723b1ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false, bt_change = false; + + /* This function check if bt is disabled */ + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + } else { + bt_disable_cnt++; + if (bt_disable_cnt >= 10) + bt_disabled = true; + } + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + bt_change = true; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + + btcoexist->btc_set(btcoexist, + BTC_SET_BL_BT_ENABLE_DISABLE_CHANGE, + &bt_change); + + coex_sta->bt_disabled = bt_disabled; + } else { + btcoexist->btc_set(btcoexist, + BTC_SET_BL_BT_ENABLE_DISABLE_CHANGE, + &bt_change); + } +} + +void halbtc8723b1ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + bt_link_info->bt_hi_pri_link_exist = coex_sta->bt_hi_pri_link_exist; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + +void halbtc8723b1ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8723b1ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8723b1ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8723b1ant_set_sw_penalty_tx_rate_adaptive(IN struct btc_coexist + *btcoexist, IN boolean low_penalty_ra) +{ + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* op_code, 0x6= Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT(0); + h2c_parameter[2] = + 0x00; /* normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[3] = 0xf7; /* MCS7 or OFDM54 */ + h2c_parameter[4] = 0xf8; /* MCS6 or OFDM48 */ + h2c_parameter[5] = 0xf9; /* MCS5 or OFDM36 */ + } + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +void halbtc8723b1ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + halbtc8723b1ant_set_sw_penalty_tx_rate_adaptive(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +void halbtc8723b1ant_sw_mechanism(IN struct btc_coexist *btcoexist, + IN boolean low_penalty_ra) +{ + halbtc8723b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +void halbtc8723b1ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + + + +void halbtc8723b1ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8723b1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8723b1ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + +#if BT_8723B_1ANT_ANTDET_ENABLE +#if BT_8723B_1ANT_ANTDET_COEXMECHANISMSWITCH_ENABLE + if (board_info->btdm_ant_num_by_ant_det == 2) { + if (type == 3) + type = 14; + else if (type == 4) + type = 13; + else if (type == 5) + type = 8; + } +#endif +#endif + + coex_sta->coex_table_type = type; + + switch (type) { + case 0: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x55555555, 0xffffff, 0x3); + break; + case 1: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 3: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 4: + if ((coex_sta->cck_ever_lock) && + (coex_sta->scan_ap_num <= 5)) + halbtc8723b1ant_coex_table(btcoexist, + force_exec, 0x55555555, 0xaaaa5a5a, + 0xffffff, 0x3); + else + halbtc8723b1ant_coex_table(btcoexist, + force_exec, 0x55555555, 0x5a5a5a5a, + 0xffffff, 0x3); + break; + case 5: + if ((coex_sta->cck_ever_lock) && + (coex_sta->scan_ap_num <= 5)) + halbtc8723b1ant_coex_table(btcoexist, + force_exec, 0x5a5a5a5a, 0x5aaa5a5a, + 0xffffff, 0x3); + else + halbtc8723b1ant_coex_table(btcoexist, + force_exec, 0x5a5a5a5a, 0x5aaa5a5a, + 0xffffff, 0x3); + break; + case 6: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 7: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0xaaaaaaaa, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 8: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 9: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 10: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 11: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 12: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 13: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x5fff5fff, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 14: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x5fff5fff, 0x5ada5ada, 0xffffff, 0x3); + break; + case 15: + halbtc8723b1ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0xaaaaaaaa, 0xffffff, 0x3); + break; + default: + break; + } +} + +void halbtc8723b1ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT(0); /* function enable */ + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8723b1ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8723b1ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8723b1ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8723b1ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8723b1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8723b1ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean force_exec, IN boolean init_hwcfg, + IN boolean wifi_off) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 fw_ver = 0, u32tmp = 0, cnt_bt_cal_chk = 0; + boolean pg_ext_switch = false; + boolean use_ext_switch = false; + boolean is_in_mp_mode = false; + u8 h2c_parameter[2] = {0}, u8tmp = 0; + u32 u32tmp_1[4]; + boolean is_fw_ready; + + coex_dm->cur_ant_pos_type = ant_pos_type; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, + &fw_ver); /* [31:16]=fw ver, [15:0]=fw sub ver */ + + if ((fw_ver > 0 && fw_ver < 0xc0000) || pg_ext_switch) + use_ext_switch = true; + +#if BT_8723B_1ANT_ANTDET_ENABLE +#if BT_8723B_1ANT_ANTDET_COEXMECHANISMSWITCH_ENABLE + if (ant_pos_type == BTC_ANT_PATH_PTA) { + if ((board_info->btdm_ant_det_finish) && + (board_info->btdm_ant_num_by_ant_det == 2)) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = BTC_ANT_PATH_WIFI; + else + ant_pos_type = BTC_ANT_PATH_BT; + } + } +#endif +#endif + + if (init_hwcfg) { + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x780); /* WiFi TRx Mask on */ + /* remove due to interrupt is disabled that polling c2h will fail and delay 100ms. */ + /* btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, 0x3c, 0x15); */ /*BT TRx Mask on */ + + if (fw_ver >= 0x180000) { + /* Use H2C to set GNT_BT to HIGH */ + h2c_parameter[0] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, + h2c_parameter); + + cnt_bt_cal_chk = 0; + while (1) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_FW_READY, &is_fw_ready); + if (is_fw_ready == false) { + BTC_SPRINTF(trace_buf , BT_TMP_BUF_SIZE, + ("halbtc8723b1ant_set_ant_path(): we don't need to wait for H2C command completion because of Fw download fail!!!\n")); + BTC_TRACE(trace_buf); + break; + } + + if (btcoexist->btc_read_1byte(btcoexist, + 0x765) == 0x18) + break; + + cnt_bt_cal_chk++; + if (cnt_bt_cal_chk > 20) + break; + } + } else { + /* set grant_bt to high */ + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + } + /* set wlan_act control by PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, + 0x0); /* BT select s0/s1 is controlled by BT */ + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x39, 0x8, 0x1); + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); + btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); + } else if (wifi_off) { + if (fw_ver >= 0x180000) { + /* Use H2C to set GNT_BT to HIGH */ + h2c_parameter[0] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, + h2c_parameter); + + cnt_bt_cal_chk = 0; + while (1) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_FW_READY, &is_fw_ready); + if (is_fw_ready == false) { + BTC_SPRINTF(trace_buf , BT_TMP_BUF_SIZE, + ("halbtc8723b1ant_set_ant_path(): we don't need to wait for H2C command completion because of Fw download fail!!!\n")); + BTC_TRACE(trace_buf); + break; + } + + if (btcoexist->btc_read_1byte(btcoexist, + 0x765) == 0x18) + break; + + cnt_bt_cal_chk++; + if (cnt_bt_cal_chk > 20) + break; + } + } else { + /* set grant_bt to high */ + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + } + /* set wlan_act to always low */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_IS_IN_MP_MODE, + &is_in_mp_mode); + if (!is_in_mp_mode) + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x20, 0x0); /* BT select s0/s1 is controlled by BT */ + else + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x20, 0x1); /* BT select s0/s1 is controlled by WiFi */ + + /* 0x4c[24:23]=00, Set Antenna control by BT_RFE_CTRL BT Vendor 0xac=0xf002 */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT(23); + u32tmp &= ~BIT(24); + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + } else { + /* Use H2C to set GNT_BT to LOW */ + if (fw_ver >= 0x180000) { + if (btcoexist->btc_read_1byte(btcoexist, 0x765) != 0) { + h2c_parameter[0] = 0; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, + h2c_parameter); + + cnt_bt_cal_chk = 0; + while (1) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_FW_READY, &is_fw_ready); + if (is_fw_ready == false) { + BTC_SPRINTF(trace_buf , + BT_TMP_BUF_SIZE, + ("halbtc8723b1ant_set_ant_path(): we don't need to wait for H2C command completion because of Fw download fail!!!\n")); + BTC_TRACE(trace_buf); + break; + } + + if (btcoexist->btc_read_1byte(btcoexist, + 0x765) == 0x0) + break; + + cnt_bt_cal_chk++; + if (cnt_bt_cal_chk > 20) + break; + } + } + } else { + /* BT calibration check */ + while (cnt_bt_cal_chk <= 20) { + u8tmp = btcoexist->btc_read_1byte(btcoexist, + 0x49d); + cnt_bt_cal_chk++; + if (u8tmp & BIT(0)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ########### BT is calibrating (wait cnt=%d) ###########\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + delay_ms(50); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** BT is NOT calibrating (wait cnt=%d)**********\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + break; + } + } + + /* set grant_bt to PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x0); + } + + if (btcoexist->btc_read_1byte(btcoexist, 0x76e) != 0xc) { + /* set wlan_act control by PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + } + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, + 0x1); /* BT select s0/s1 is controlled by WiFi */ + } + + if (use_ext_switch) { + if (init_hwcfg) { + /* 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT(23); + u32tmp |= BIT(24); + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + + + u32tmp_1[0] = btcoexist->btc_read_4byte(btcoexist, + 0x948); + if ((u32tmp_1[0] == 0x40) || (u32tmp_1[0] == 0x240)) + btcoexist->btc_write_4byte(btcoexist, 0x948, + u32tmp_1[0]); + else + btcoexist->btc_write_4byte(btcoexist, 0x948, + 0x0); + + + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) { + /* tell firmware "no antenna inverse" */ + h2c_parameter[0] = 0; + h2c_parameter[1] = 1; /* ext switch type */ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } else { + /* tell firmware "antenna inverse" */ + h2c_parameter[0] = 1; + h2c_parameter[1] = 1; /* ext switch type */ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } + } + + if (force_exec || + (coex_dm->cur_ant_pos_type != + coex_dm->pre_ant_pos_type)) { + /* ext switch setting */ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, + 0x1); + else + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, + 0x2); + break; + case BTC_ANT_PATH_BT: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, + 0x2); + else + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, + 0x1); + break; + default: + case BTC_ANT_PATH_PTA: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, + 0x1); + else + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x92c, 0x3, + 0x2); + break; + } + } + } else { + if (init_hwcfg) { + /* 0x4c[23]=1, 0x4c[24]=0 Antenna control by 0x64 */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp |= BIT(23); + u32tmp &= ~BIT(24); + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + + /* Fix Ext switch Main->S1, Aux->S0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, + 0x0); + + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) { + + /* tell firmware "no antenna inverse" */ + h2c_parameter[0] = 0; + h2c_parameter[1] = + 0; /* internal switch type */ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } else { + + /* tell firmware "antenna inverse" */ + h2c_parameter[0] = 1; + h2c_parameter[1] = + 0; /* internal switch type */ + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } + } + + if (force_exec || + (coex_dm->cur_ant_pos_type != + coex_dm->pre_ant_pos_type)) { + /* internal switch setting */ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) { + u32tmp_1[0] = btcoexist->btc_read_4byte( + btcoexist, 0x948); + if ((u32tmp_1[0] == 0x40) || + (u32tmp_1[0] == 0x240)) + btcoexist->btc_write_4byte( + btcoexist, 0x948, + u32tmp_1[0]); + else + btcoexist->btc_write_4byte( + btcoexist, 0x948, 0x0); + } else { + u32tmp_1[0] = btcoexist->btc_read_4byte( + btcoexist, 0x948); + if ((u32tmp_1[0] == 0x40) || + (u32tmp_1[0] == 0x240)) + btcoexist->btc_write_4byte( + btcoexist, 0x948, + u32tmp_1[0]); + else + btcoexist->btc_write_4byte( + btcoexist, 0x948, + 0x280); + } + break; + case BTC_ANT_PATH_BT: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) { + u32tmp_1[0] = btcoexist->btc_read_4byte( + btcoexist, 0x948); + if ((u32tmp_1[0] == 0x40) || + (u32tmp_1[0] == 0x240)) + btcoexist->btc_write_4byte( + btcoexist, 0x948, + u32tmp_1[0]); + else + btcoexist->btc_write_4byte( + btcoexist, 0x948, + 0x280); + } else { + u32tmp_1[0] = btcoexist->btc_read_4byte( + btcoexist, 0x948); + if ((u32tmp_1[0] == 0x40) || + (u32tmp_1[0] == 0x240)) + btcoexist->btc_write_4byte( + btcoexist, 0x948, + u32tmp_1[0]); + else + btcoexist->btc_write_4byte( + btcoexist, 0x948, 0x0); + } + break; + default: + case BTC_ANT_PATH_PTA: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_4byte( + btcoexist, 0x948, + 0x200); + else + btcoexist->btc_write_4byte( + btcoexist, 0x948, 0x80); + break; + } + } + } + + coex_dm->pre_ant_pos_type = coex_dm->cur_ant_pos_type; +} + +void halbtc8723b1ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + u8 h2c_parameter[5] = {0x8, 0, 0, 0, 0}; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + /* halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); */ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + /* halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); */ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + + +void halbtc8723b1ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + case BTC_PS_LPS_ON: + halbtc8723b1ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8723b1ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + coex_sta->force_lps_on = true; + break; + case BTC_PS_LPS_OFF: + halbtc8723b1ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + default: + break; + } +} + + +void halbtc8723b1ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + + halbtc8723b1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + } + } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + halbtc8723b1ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + + } else { + halbtc8723b1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + } + + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + + +void halbtc8723b1ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_busy = false; + u8 rssi_adjust_val = 0; + u8 ps_tdma_byte4_val = 0x50, ps_tdma_byte0_val = 0x51, + ps_tdma_byte3_val = 0x10; + s8 wifi_duration_adjust = 0x0; + static boolean pre_wifi_busy = false; + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + +#if BT_8723B_1ANT_ANTDET_ENABLE +#if BT_8723B_1ANT_ANTDET_COEXMECHANISMSWITCH_ENABLE + if (board_info->btdm_ant_num_by_ant_det == 2) { + if (turn_on) + type = type + + 100; /* for WiFi RSSI low or BT RSSI low */ + else + type = 1; /* always translate to TDMA(off,1) for TDMA-off case */ + } + +#endif +#endif + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (wifi_busy != pre_wifi_busy) { + force_exec = true; + pre_wifi_busy = wifi_busy; + } + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + + if (coex_sta->scan_ap_num <= 5) { + wifi_duration_adjust = 5; + + if (coex_sta->a2dp_bit_pool >= 35) + wifi_duration_adjust = -10; + else if (coex_sta->a2dp_bit_pool >= 45) + wifi_duration_adjust = -15; + } else if (coex_sta->scan_ap_num >= 40) { + wifi_duration_adjust = -15; + + if (coex_sta->a2dp_bit_pool < 35) + wifi_duration_adjust = -5; + else if (coex_sta->a2dp_bit_pool < 45) + wifi_duration_adjust = -10; + } else if (coex_sta->scan_ap_num >= 20) { + wifi_duration_adjust = -10; + + if (coex_sta->a2dp_bit_pool >= 45) + wifi_duration_adjust = -15; + } else { + wifi_duration_adjust = 0; + + if (coex_sta->a2dp_bit_pool >= 35) + wifi_duration_adjust = -10; + else if (coex_sta->a2dp_bit_pool >= 45) + wifi_duration_adjust = -15; + } + + if ((type == 1) || (type == 2) || (type == 9) || (type == 11) || + (type == 101) + || (type == 102) || (type == 109) || (type == 101)) { + if (!coex_sta->force_lps_on) { /* Native power save TDMA, only for A2DP-only case 1/2/9/11 while wifi noisy threshold > 30 */ + ps_tdma_byte0_val = 0x61; /* no null-pkt */ + ps_tdma_byte3_val = 0x11; /* no tx-pause at BT-slot */ + ps_tdma_byte4_val = + 0x10; /* 0x778 = d/1 toggle, no dynamic slot */ + } else { + ps_tdma_byte0_val = 0x51; /* null-pkt */ + ps_tdma_byte3_val = 0x10; /* tx-pause at BT-slot */ + ps_tdma_byte4_val = + 0x50; /* 0x778 = d/1 toggle, dynamic slot */ + } + } else if ((type == 3) || (type == 13) || (type == 14) || + (type == 103) || (type == 113) || (type == 114)) { + ps_tdma_byte0_val = 0x51; /* null-pkt */ + ps_tdma_byte3_val = 0x10; /* tx-pause at BT-slot */ + ps_tdma_byte4_val = + 0x10; /* 0x778 = d/1 toggle, no dynamic slot */ +#if 0 + if (!wifi_busy) + ps_tdma_byte4_val = ps_tdma_byte4_val | + 0x1; /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ +#endif + } else { /* native power save case */ + ps_tdma_byte0_val = 0x61; /* no null-pkt */ + ps_tdma_byte3_val = 0x11; /* no tx-pause at BT-slot */ + ps_tdma_byte4_val = + 0x11; /* 0x778 = d/1 toggle, no dynamic slot */ + /* psTdmaByte4Va is not defne for 0x778 = d/1, 1/1 case */ + } + + /* if (bt_link_info->slave_role == true) */ + if ((bt_link_info->slave_role == true) && (bt_link_info->a2dp_exist)) + ps_tdma_byte4_val = ps_tdma_byte4_val | + 0x1; /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + + if (type > 100) { + ps_tdma_byte0_val = ps_tdma_byte0_val | + 0x82; /* set antenna control by SW */ + ps_tdma_byte3_val = ps_tdma_byte3_val | + 0x60; /* set antenna no toggle, control by antenna diversity */ + } + + + if (turn_on) { + switch (type) { + default: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x51, + 0x1a, 0x1a, 0x0, ps_tdma_byte4_val); + break; + case 1: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x3a + + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 2: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x2d + + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 3: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x30, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 4: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x93, + 0x15, 0x3, 0x14, 0x0); + break; + case 5: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x1f, 0x3, + ps_tdma_byte3_val, 0x11); + break; + case 6: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x20, 0x3, + ps_tdma_byte3_val, 0x11); + break; + case 7: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x13, + 0xc, 0x5, 0x0, 0x0); + break; + case 8: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x93, + 0x25, 0x3, 0x10, 0x0); + break; + case 9: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 10: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x13, + 0xa, 0xa, 0x0, 0x40); + break; + case 11: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x21, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 12: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x51, + 0x0a, 0x0a, 0x0, 0x50); + break; + case 13: + if (coex_sta->scan_ap_num <= 3) + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x40, 0x3, + ps_tdma_byte3_val, + ps_tdma_byte4_val); + else + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, + ps_tdma_byte4_val); + break; + case 14: + if (coex_sta->scan_ap_num <= 3) + halbtc8723b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x30, 0x3, 0x10, 0x50); + else + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, + ps_tdma_byte4_val); + break; + case 15: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x13, + 0xa, 0x3, 0x8, 0x0); + break; + case 16: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x93, + 0x15, 0x3, 0x10, 0x0); + break; + case 18: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x93, + 0x25, 0x3, 0x10, 0x0); + break; + case 20: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x3f, 0x03, + ps_tdma_byte3_val, 0x10); + break; + case 21: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x61, + 0x25, 0x03, 0x11, 0x11); + break; + case 22: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x25, 0x03, + ps_tdma_byte3_val, 0x10); + break; + case 23: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x3, 0x31, 0x18); + break; + case 24: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0xe3, + 0x15, 0x3, 0x31, 0x18); + break; + case 25: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0xe3, + 0xa, 0x3, 0x31, 0x18); + break; + case 26: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0xe3, + 0xa, 0x3, 0x31, 0x18); + break; + case 27: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x3, 0x31, 0x98); + break; + case 28: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x69, + 0x25, 0x3, 0x31, 0x0); + break; + case 29: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0xab, + 0x1a, 0x1a, 0x1, 0x10); + break; + case 30: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x51, + 0x30, 0x3, 0x10, 0x10); + break; + case 31: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0xd3, + 0x1a, 0x1a, 0, 0x58); + break; + case 32: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x35, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 33: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x35, 0x3, + ps_tdma_byte3_val, 0x10); + break; + case 34: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x53, + 0x1a, 0x1a, 0x0, 0x10); + break; + case 35: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x63, + 0x1a, 0x1a, 0x0, 0x10); + break; + case 36: + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0xd3, + 0x12, 0x3, 0x14, 0x50); + break; + case 40: /* SoftAP only with no sta associated,BT disable ,TDMA mode for power saving */ + /* here softap mode screen off will cost 70-80mA for phone */ + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x23, + 0x18, 0x00, 0x10, 0x24); + break; + + /* for 1-Ant translate to 2-Ant */ + case 101: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x3a + + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 102: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x2d + + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 103: + /* halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x51, 0x1d, 0x1d, 0x0, ps_tdma_byte4_val); */ + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x3a, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 105: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x15, 0x3, + ps_tdma_byte3_val, 0x11); + break; + case 106: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x20, 0x3, + ps_tdma_byte3_val, 0x11); + break; + case 109: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 111: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x21, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 113: + /* halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x51, 0x12, 0x12, 0x0, ps_tdma_byte4_val); */ + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 114: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 120: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x3f, 0x03, + ps_tdma_byte3_val, 0x10); + break; + case 122: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x25, 0x03, + ps_tdma_byte3_val, 0x10); + break; + case 132: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x25, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 133: + halbtc8723b1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x25, 0x03, + ps_tdma_byte3_val, 0x11); + break; + + } + } else { + + /* disable PS tdma */ + switch (type) { + case 8: /* PTA Control */ + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x8, + 0x0, 0x0, 0x0, 0x0); + break; + case 0: + default: /* Software control, Antenna at BT side */ + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x0, 0x0); + break; + case 1: /* 2-Ant, 0x778=3, antenna control by antenna diversity */ + halbtc8723b1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x48, 0x0); + break; + } + } + rssi_adjust_val = 0; + btcoexist->btc_set(btcoexist, + BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssi_adjust_val); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x\n", + btcoexist->btc_read_4byte(btcoexist, 0x948), + btcoexist->btc_read_1byte(btcoexist, 0x765), + btcoexist->btc_read_1byte(btcoexist, 0x67)); + BTC_TRACE(trace_buf); + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void halbtc8723b1ant_tdma_duration_adjust_for_acl(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + static s32 up, dn, m, n, wait_count; + s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */ + u8 retry_count = 0, bt_info_ext; + boolean wifi_busy = false; + + if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY == wifi_status) + wifi_busy = true; + else + wifi_busy = false; + + if ((BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == + wifi_status) || + (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifi_status) || + (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIFIC_PKT == + wifi_status)) { + if (coex_dm->cur_ps_tdma != 1 && + coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 3 && + coex_dm->cur_ps_tdma != 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 9); + coex_dm->ps_tdma_du_adj_type = 9; + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } + return; + } + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + /* ============ */ + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /* acquire the BT TRx retry count from BT_Info byte2 */ + retry_count = coex_sta->bt_retry_cnt; + bt_info_ext = coex_sta->bt_info_ext; + + if ((coex_sta->low_priority_tx) > 1050 || + (coex_sta->low_priority_rx) > 1250) + retry_count++; + + result = 0; + wait_count++; + + if (retry_count == + 0) { /* no retry in the last 2-second duration */ + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { /* if retry count during continuous n*2 seconds is 0, enlarge WiFi duration */ + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + } + } else if (retry_count <= + 3) { /* <=3 retry in the last 2-second duration */ + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { /* if continuous 2 retry count(every 2 seconds) >0 and < 3, reduce WiFi duration */ + if (wait_count <= 2) + m++; /* to avoid loop between the two levels */ + else + m = 1; + + if (m >= 20) /* maximum of m = 20 ' will recheck if need to adjust wifi duration in maximum time interval 120 seconds */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + } else { /* retry count > 3, once retry count > 3, to reduce WiFi duration */ + if (wait_count == 1) + m++; /* to avoid loop between the two levels */ + else + m = 1; + + if (m >= 20) /* maximum of m = 20 ' will recheck if need to adjust wifi duration in maximum time interval 120 seconds */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + + if (result == -1) { + /* if( (BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) ||(coex_dm->cur_ps_tdma == 2)) ) + { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } + else */ if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } + } else if (result == 1) { + /* if( (BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) ||(coex_dm->cur_ps_tdma == 2)) ) + { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } + else */ if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = 1; + } + } else { /* no change */ + /* Bryant Modify + if(wifi_busy != pre_wifi_busy) + { + pre_wifi_busy = wifi_busy; + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, true, coex_dm->cur_ps_tdma); + } + */ + + } + + if (coex_dm->cur_ps_tdma != 1 && + coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 9 && + coex_dm->cur_ps_tdma != 11) { + /* recover to previous adjust type */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->ps_tdma_du_adj_type); + } + } +} + + +/* ********************************************* + * + * Non-Software Coex Mechanism start + * + * ********************************************* */ +void halbtc8723b1ant_action_bt_whck_test(IN struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, NORMAL_EXEC, + false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + + +void halbtc8723b1ant_action_hs(IN struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8723b1ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, ap_enable = false, wifi_busy = false, + bt_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + if (coex_sta->bt_abnormal_scan) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 33); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + } else if ((!wifi_connected) && (!coex_sta->wifi_is_high_pri_task)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + /* SCO/HID/A2DP busy */ + + if (coex_sta->c2h_bt_remote_name_req) + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 33); + else + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if ((bt_link_info->pan_exist) || (wifi_busy)) { + + if (coex_sta->c2h_bt_remote_name_req) + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 33); + else + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + + } +} + +void halbtc8723b1ant_action_bt_sco_hid_only_busy(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* tdma and coex table */ + + if (bt_link_info->sco_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } else { /* HID */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } +} + +void halbtc8723b1ant_action_wifi_only(IN struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, FORCE_EXEC, + false, false); +} + +void halbtc8723b1ant_action_wifi_multi_port(IN struct btc_coexist *btcoexist) +{ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, NORMAL_EXEC, + false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8723b1ant_action_wifi_connected_bt_acl_busy(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + if ((coex_sta->low_priority_rx >= 950) && (!coex_sta->under_ips)) + bt_link_info->slave_role = true; + else + bt_link_info->slave_role = false; + + if (bt_link_info->hid_only) { /* HID */ + halbtc8723b1ant_action_bt_sco_hid_only_busy(btcoexist, + wifi_status); + coex_dm->auto_tdma_adjust = false; + return; + } else if (bt_link_info->a2dp_only) { /* A2DP */ + if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } else { + halbtc8723b1ant_tdma_duration_adjust_for_acl(btcoexist, + wifi_status); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = true; + } + } else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { /* A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP) */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } else if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { /* HID+A2DP */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + coex_dm->auto_tdma_adjust = false; + + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if ((bt_link_info->pan_only) || (bt_link_info->hid_exist && + bt_link_info->pan_exist)) { /* PAN(OPP,FTP), HID+PAN(OPP,FTP) */ + + if (BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 9); + else + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } else { + /* BT no-profile busy (0x9) */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } +} + +void halbtc8723b1ant_action_wifi_not_connected(IN struct btc_coexist *btcoexist) +{ + + /* tdma and coex table */ + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, NORMAL_EXEC, + false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8723b1ant_action_wifi_not_connected_scan(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + /* tdma and coex table */ + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8723b1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + /* Bryant Add */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8723b1ant_action_wifi_not_connected_asso_auth( + IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else if (bt_link_info->pan_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 2); + } +} + +void halbtc8723b1ant_action_wifi_connected_scan(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + /* tdma and coex table */ + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8723b1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + /* Bryant Add */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8723b1ant_action_wifi_connected_specific_packet( + IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + /* no specific packet process for both WiFi and BT very busy */ + if ((wifi_busy) && ((bt_link_info->pan_exist) || + (coex_sta->num_of_profile >= 2))) + return; + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist)) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } else if (bt_link_info->a2dp_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (bt_link_info->pan_exist) { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8723b1ant_action_wifi_connected(IN struct btc_coexist *btcoexist) +{ + boolean wifi_busy = false; + boolean scan = false, link = false, roam = false; + boolean under_4way = false, ap_enable = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect()===>\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (under_4way) { + halbtc8723b1ant_action_wifi_connected_specific_packet( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + if (scan || link || roam) { + if (scan) + halbtc8723b1ant_action_wifi_connected_scan(btcoexist); + else + halbtc8723b1ant_action_wifi_connected_specific_packet( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + + /* tdma and coex table */ + if (!wifi_busy) { + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8723b1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8723b1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else { + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + halbtc8723b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, NORMAL_EXEC, false, false); + /* if ((coex_sta->high_priority_tx) + + (coex_sta->high_priority_rx) <= 60) */ + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + /* else + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); */ + } + } else { + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8723b1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else if ((BT_8723B_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8723b1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else { + /* halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + halbtc8723b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, NORMAL_EXEC, false, false); + if ((coex_sta->high_priority_tx) + + (coex_sta->high_priority_rx) <= 60) + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + else + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); */ + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8723b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, NORMAL_EXEC, false, false); + halbtc8723b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + + } + } +} + +void halbtc8723b1ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false, wifi_busy = false; + boolean increase_scan_dev_num = false; + boolean bt_ctrl_agg_buf_size = false; + boolean miracast_plus_bt = false; + u8 agg_buf_size = 5; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0, wifi_bw; + u8 iot_peer = BTC_IOT_PEER_UNKNOWN; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->bt_whck_test) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under WHCK TEST!!!\n"); + BTC_TRACE(trace_buf); + halbtc8723b1ant_action_bt_whck_test(btcoexist); + return; + } + + if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + increase_scan_dev_num = true; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, + &increase_scan_dev_num); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + if (bt_link_info->bt_link_exist) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, + 0, 1); + miracast_plus_bt = true; + } else { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, + 0, 0); + miracast_plus_bt = false; + } + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if (((bt_link_info->a2dp_exist) || (wifi_busy)) && + (coex_sta->c2h_bt_inquiry_page)) + halbtc8723b1ant_action_bt_inquiry(btcoexist); + else + halbtc8723b1ant_action_wifi_multi_port(btcoexist); + + return; + } + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if ((bt_link_info->bt_link_exist) && (wifi_connected)) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, 0, 1); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_IOT_PEER, &iot_peer); + + /* if(BTC_IOT_PEER_CISCO != iot_peer) */ + if ((BTC_IOT_PEER_CISCO != iot_peer) && + (BTC_IOT_PEER_BROADCOM != iot_peer)) { + if (bt_link_info->sco_exist) /* if (bt_link_info->bt_hi_pri_link_exist) */ + /* halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, true, false, 0x5); */ + halbtc8723b1ant_limited_rx(btcoexist, + NORMAL_EXEC, true, false, 0x5); + else + halbtc8723b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, false, 0x5); + /* halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, 0x8); */ + } else { + if (bt_link_info->sco_exist) + halbtc8723b1ant_limited_rx(btcoexist, + NORMAL_EXEC, true, false, 0x5); + else if (bt_link_info->hid_exist) + halbtc8723b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, true, 0x3); + else { + if (BTC_WIFI_BW_HT40 == wifi_bw) + halbtc8723b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, true, 0x10); + else + halbtc8723b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, true, 0x8); + } + } + + halbtc8723b1ant_sw_mechanism(btcoexist, true); + + /* low pelnaty ra in pcr ra */ + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 35); + + } else { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x5); + + halbtc8723b1ant_sw_mechanism(btcoexist, false); + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8723b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8723b1ant_action_hs(btcoexist); + return; + } + + + if (!wifi_connected) { + boolean scan = false, link = false, roam = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is non connected-idle !!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + if (scan) + halbtc8723b1ant_action_wifi_not_connected_scan( + btcoexist); + else + halbtc8723b1ant_action_wifi_not_connected_asso_auth( + btcoexist); + } else + halbtc8723b1ant_action_wifi_not_connected(btcoexist); + } else /* wifi LPS/Busy */ + halbtc8723b1ant_action_wifi_connected(btcoexist); +} + +void halbtc8723b1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + + /* sw all off */ + halbtc8723b1ant_sw_mechanism(btcoexist, false); + + /* halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); */ + /* halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); */ + + coex_sta->pop_event_cnt = 0; +} + +void halbtc8723b1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean back_up, IN boolean wifi_only) +{ + u32 u32tmp = 0; /* , fw_ver; */ + u8 u8tmpa = 0, u8tmpb = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 1Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + + psd_scan->ant_det_is_ant_det_available = false; + + + /* Give bt_coex_supported_version the default value */ + coex_sta->bt_coex_supported_version = 0; + + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = (btcoexist->btc_read_1byte(btcoexist, + 0xf1) & 0xf0) >> 4; + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + + /* 0x790[5:0]=0x5 */ + btcoexist->btc_write_1byte(btcoexist, 0x790, 0x5); + + /* Enable counter statistics */ + /* btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); */ /*0x76e[3] =1, WLAN_Act control by PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + + + /* btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1); */ /*BT select s0/s1 is controlled by WiFi */ + + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + + /* Antenna config */ + if (wifi_only) + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI, + FORCE_EXEC, true, false); + else + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, true, false); + + /* PTA parameter */ + halbtc8723b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x67); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x\n", + u32tmp, u8tmpa, u8tmpb); + BTC_TRACE(trace_buf); + +} + +/* Donot remove optimize off flag, otherwise antenna detection would trigger BT collapsed */ +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +void halbtc8723b1ant_mechanism_switch(IN struct btc_coexist *btcoexist, + IN boolean bSwitchTo2Antenna) +{ + + if (bSwitchTo2Antenna) { + + /* BT TRx mask off */ + btcoexist->btc_set_bt_trx_mask(btcoexist, 0); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT TRx Mask off for mechanism_switch\n"); + + BTC_TRACE(trace_buf); + + } else { + + /* BT TRx mask on */ + btcoexist->btc_set_bt_trx_mask(btcoexist, 1); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT TRx Mask on for mechanism_switch\n"); + + BTC_TRACE(trace_buf); + } + + +#if 0 + if (bSwitchTo2Antenna) { /* 1-Ant -> 2-Ant */ + /* un-lock TRx Mask setup for 8723b f-cut */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xdd, 0x80, 0x1); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xdf, 0x1, 0x1); + /* WiFi TRx Mask on */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + + /* BT TRx Mask un-lock 0x2c[0], 0x30[0] = 1 */ + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, 0x2c, + 0x7c45); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, 0x30, + 0x7c45); + + /* BT TRx Mask on */ + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, 0x3c, 0x1); + + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, false, false); + } else { + /* WiFi TRx Mask on */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x780); + + /* lock TRx Mask setup for 8723b f-cut */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xdd, 0x80, 0x0); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xdf, 0x1, 0x0); + + /* BT TRx Mask on */ + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, 0x3c, 0x15); + + /* BT TRx Mask ock 0x2c[0], 0x30[0] = 0 */ + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, 0x2c, + 0x7c44); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, 0x30, + 0x7c44); + + + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); + } + +#endif +} + +u32 halbtc8723b1ant_psd_log2base(IN struct btc_coexist *btcoexist, IN u32 val) +{ + u8 j; + u32 tmp, tmp2, val_integerd_b = 0, tindex, shiftcount = 0; + u32 result, val_fractiond_b = 0, table_fraction[21] = {0, 432, 332, 274, 232, 200, + 174, 151, 132, 115, 100, 86, 74, 62, 51, 42, + 32, 23, 15, 7, 0 + }; + + if (val == 0) + return 0; + + tmp = val; + + while (1) { + if (tmp == 1) + break; + + tmp = (tmp >> 1); + shiftcount++; + } + + + val_integerd_b = shiftcount + 1; + + tmp2 = 1; + for (j = 1; j <= val_integerd_b; j++) + tmp2 = tmp2 * 2; + + tmp = (val * 100) / tmp2; + tindex = tmp / 5; + + if (tindex > 20) + tindex = 20; + + val_fractiond_b = table_fraction[tindex]; + + result = val_integerd_b * 100 - val_fractiond_b; + + return result; + + +} + +void halbtc8723b1ant_psd_show_antenna_detect_result(IN struct btc_coexist + *btcoexist) +{ + u8 *cli_buf = btcoexist->cli_buf; + struct btc_board_info *board_info = &btcoexist->board_info; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n============[Antenna Detection info] ============\n"); + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 1) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (>%d)", + "Ant Det Result", "2-Antenna (Bad-Isolation)", + BT_8723B_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else if (psd_scan->ant_det_result == 2) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "2-Antenna (Good-Isolation)", + BT_8723B_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset, + BT_8723B_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "1-Antenna", + BT_8723B_1ANT_ANTDET_PSDTHRES_1ANT, + BT_8723B_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset); + + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s ", + "Antenna Detection Finish", + (board_info->btdm_ant_det_finish + ? "Yes" : "No")); + CL_PRINTF(cli_buf); + + switch (psd_scan->ant_det_result) { + case 0: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is not available)"); + break; + case 1: /* 2-Ant bad-isolation */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 2: /* 2-Ant good-isolation */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 3: /* 1-Ant */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 4: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Uncertainty result)"); + break; + case 5: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "(Pre-Scan fai)"); + break; + case 6: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(WiFi is Scanning)"); + break; + case 7: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is not idle)"); + break; + case 8: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Abort by WiFi Scanning)"); + break; + case 9: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Antenna Init is not ready)"); + break; + case 10: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is Inquiry or page)"); + break; + case 11: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is Disabled)"); + break; + } + CL_PRINTF(cli_buf); + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "Ant Detect Total Count", psd_scan->ant_det_try_count); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "Ant Detect Fail Count", psd_scan->ant_det_fail_count); + CL_PRINTF(cli_buf); + + if ((!board_info->btdm_ant_det_finish) && + (psd_scan->ant_det_result != 5)) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Response", + (psd_scan->ant_det_result ? "ok" : "fail")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ms", "BT Tx Time", + psd_scan->ant_det_bt_tx_time); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "BT Tx Ch", + psd_scan->ant_det_bt_le_channel); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + "WiFi PSD Cent-Ch/Offset/Span", + psd_scan->real_cent_freq, psd_scan->real_offset, + psd_scan->real_span); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d dB", + "PSD Pre-Scan Peak Value", + psd_scan->ant_det_pre_psdscan_peak_val / 100); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (<= %d)", + "PSD Pre-Scan result", + (psd_scan->ant_det_result != 5 ? "ok" : "fail"), + BT_8723B_1ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 5) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s dB", + "PSD Scan Peak Value", psd_scan->ant_det_peak_val); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s MHz", + "PSD Scan Peak Freq", psd_scan->ant_det_peak_freq); + CL_PRINTF(cli_buf); + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "TFBGA Package", + (board_info->tfbga_package) ? "Yes" : "No"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "PSD Threshold Offset", psd_scan->ant_det_thres_offset); + CL_PRINTF(cli_buf); + +} + +void halbtc8723b1ant_psd_showdata(IN struct btc_coexist *btcoexist) +{ + u8 *cli_buf = btcoexist->cli_buf; + u32 delta_freq_per_point; + u32 freq, freq1, freq2, n = 0, i = 0, j = 0, m = 0, psd_rep1, psd_rep2; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n\n============[PSD info] (%d)============\n", + psd_scan->psd_gen_count); + CL_PRINTF(cli_buf); + + if (psd_scan->psd_gen_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n No data !!\n"); + CL_PRINTF(cli_buf); + return; + } + + if (psd_scan->psd_point == 0) + delta_freq_per_point = 0; + else + delta_freq_per_point = psd_scan->psd_band_width / + psd_scan->psd_point; + + /* if (psd_scan->is_psd_show_max_only) */ + if (0) { + psd_rep1 = psd_scan->psd_max_value / 100; + psd_rep2 = psd_scan->psd_max_value - psd_rep1 * 100; + + freq = ((psd_scan->real_cent_freq - 20) * 1000000 + + psd_scan->psd_max_value_point * delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (freq2 < 100) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n Freq = %d.0%d MHz", + freq1, freq2); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n Freq = %d.%d MHz", + freq1, freq2); + + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + ", Value = %d.0%d dB, (%d)\n", + psd_rep1, psd_rep2, psd_scan->psd_max_value); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + ", Value = %d.%d dB, (%d)\n", + psd_rep1, psd_rep2, psd_scan->psd_max_value); + + CL_PRINTF(cli_buf); + } else { + m = psd_scan->psd_start_point; + n = psd_scan->psd_start_point; + i = 1; + j = 1; + + while (1) { + do { + freq = ((psd_scan->real_cent_freq - 20) * + 1000000 + m * + delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (i == 1) { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.000", + freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.0%2d", + freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.%3d", + freq1, + freq2); + } else if ((i % 8 == 0) || + (m == psd_scan->psd_stop_point)) { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.000\n", freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.0%2d\n", freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.%3d\n", freq1, + freq2); + } else { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.000", freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.0%2d", freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.%3d", freq1, + freq2); + } + + i++; + m++; + CL_PRINTF(cli_buf); + + } while ((i <= 8) && (m <= psd_scan->psd_stop_point)); + + + do { + psd_rep1 = psd_scan->psd_report_max_hold[n] / + 100; + psd_rep2 = psd_scan->psd_report_max_hold[n] - + psd_rep1 * + 100; + + if (j == 1) { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Val %7d.0%d", + psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Val %7d.%d", + psd_rep1, + psd_rep2); + } else if ((j % 8 == 0) || + (n == psd_scan->psd_stop_point)) { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.0%d\n", psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.%d\n", psd_rep1, + psd_rep2); + } else { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.0%d", psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.%d", psd_rep1, + psd_rep2); + } + + j++; + n++; + CL_PRINTF(cli_buf); + + } while ((j <= 8) && (n <= psd_scan->psd_stop_point)); + + if ((m > psd_scan->psd_stop_point) || + (n > psd_scan->psd_stop_point)) + break; + + i = 1; + j = 1; + } + } + + +} + +void halbtc8723b1ant_psd_max_holddata(IN struct btc_coexist *btcoexist, + IN u32 gen_count) +{ + u32 i = 0, i_max = 0, val_max = 0; + + if (gen_count == 1) { + memcpy(psd_scan->psd_report_max_hold, + psd_scan->psd_report, + BT_8723B_1ANT_ANTDET_PSD_POINTS * sizeof(u32)); + + psd_scan->psd_max_value_point = 0; + psd_scan->psd_max_value = 0; + + } else { + for (i = psd_scan->psd_start_point; + i <= psd_scan->psd_stop_point; i++) { + if (psd_scan->psd_report[i] > + psd_scan->psd_report_max_hold[i]) + psd_scan->psd_report_max_hold[i] = + psd_scan->psd_report[i]; + + /* search Max Value */ + if (i == psd_scan->psd_start_point) { + i_max = i; + val_max = psd_scan->psd_report_max_hold[i]; + } else { + if (psd_scan->psd_report_max_hold[i] > + val_max) { + i_max = i; + val_max = psd_scan->psd_report_max_hold[i]; + } + } + + } + + psd_scan->psd_max_value_point = i_max; + psd_scan->psd_max_value = val_max; + + } + + +} + +u32 halbtc8723b1ant_psd_getdata(IN struct btc_coexist *btcoexist, IN u32 point) +{ + /* reg 0x808[9:0]: FFT data x */ + /* reg 0x808[22]: 0-->1 to get 1 FFT data y */ + /* reg 0x8b4[15:0]: FFT data y report */ + + u32 val = 0, psd_report = 0; + int k = 0; + + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + + val &= 0xffbffc00; + val |= point; + + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + val |= 0x00400000; + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + while (1) { + if (k++ > BT_8723B_1ANT_ANTDET_SWEEPPOINT_DELAY) + break; + } + + val = btcoexist->btc_read_4byte(btcoexist, 0x8b4); + + psd_report = val & 0x0000ffff; + + return psd_report; +} + + +boolean halbtc8723b1ant_psd_sweep_point(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN s32 offset, IN u32 span, IN u32 points, + IN u32 avgnum, IN u32 loopcnt) +{ + u32 i, val, n, k = 0, j, point_index = 0; + u32 points1 = 0, psd_report = 0; + u32 start_p = 0, stop_p = 0, delta_freq_per_point = 156250; + u32 psd_center_freq = 20 * 10 ^ 6; + boolean outloop = false, scan , roam, is_sweep_ok = true; + u8 flag = 0; + u32 tmp; + u32 wifi_original_channel = 1; + + psd_scan->is_psd_running = true; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx PSD Sweep Start!!\n"); + BTC_TRACE(trace_buf); + + do { + switch (flag) { + case 0: /* Get PSD parameters */ + default: + + psd_scan->psd_band_width = 40 * 1000000; + psd_scan->psd_point = points; + psd_scan->psd_start_base = points / 2; + psd_scan->psd_avg_num = avgnum; + psd_scan->real_cent_freq = cent_freq; + psd_scan->real_offset = offset; + psd_scan->real_span = span; + + + points1 = psd_scan->psd_point; + delta_freq_per_point = psd_scan->psd_band_width / + psd_scan->psd_point; + + /* PSD point setup */ + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + val &= 0xffff0fff; + + switch (psd_scan->psd_point) { + case 128: + val |= 0x0; + break; + case 256: + default: + val |= 0x00004000; + break; + case 512: + val |= 0x00008000; + break; + case 1024: + val |= 0x0000c000; + break; + } + + switch (psd_scan->psd_avg_num) { + case 1: + val |= 0x0; + break; + case 8: + val |= 0x00001000; + break; + case 16: + val |= 0x00002000; + break; + case 32: + default: + val |= 0x00003000; + break; + } + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + flag = 1; + break; + case 1: /* calculate the PSD point index from freq/offset/span */ + psd_center_freq = psd_scan->psd_band_width / 2 + + offset * (1000000); + + start_p = psd_scan->psd_start_base + (psd_center_freq - + span * (1000000) / 2) / delta_freq_per_point; + psd_scan->psd_start_point = start_p - + psd_scan->psd_start_base; + + stop_p = psd_scan->psd_start_base + (psd_center_freq + + span * (1000000) / 2) / delta_freq_per_point; + psd_scan->psd_stop_point = stop_p - + psd_scan->psd_start_base - 1; + + flag = 2; + break; + case 2: /* set RF channel/BW/Mode */ + + /* set 3-wire off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x88c); + val |= 0x00300000; + btcoexist->btc_write_4byte(btcoexist, 0x88c, val); + + /* CCK off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x800); + val &= 0xfeffffff; + btcoexist->btc_write_4byte(btcoexist, 0x800, val); + + /* store WiFi original channel */ + wifi_original_channel = btcoexist->btc_get_rf_reg( + btcoexist, BTC_RF_A, 0x18, 0x3ff); + + /* Set RF channel */ + if (cent_freq == 2484) + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x18, 0x3ff, 0xe); + else + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x18, 0x3ff, (cent_freq - 2412) / 5 + + 1); /* WiFi TRx Mask on */ + + + /* Set RF Rx filter corner */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, 0x3e4); + + /* Set TRx mask off */ + /* un-lock TRx Mask setup */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xdd, + 0x80, 0x1); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xdf, + 0x1, 0x1); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + + /* Set RF mode = Rx, RF Gain = 0x8a0 */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x0, + 0xfffff, 0x308a0); + + while (1) { + if (k++ > BT_8723B_1ANT_ANTDET_SWEEPPOINT_DELAY) + break; + } + flag = 3; + break; + case 3: + psd_scan->psd_gen_count = 0; + for (j = 1; j <= loopcnt; j++) { + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || roam) { + is_sweep_ok = false; + break; + } + memset(psd_scan->psd_report, 0, + psd_scan->psd_point * sizeof(u32)); + start_p = psd_scan->psd_start_point + + psd_scan->psd_start_base; + stop_p = psd_scan->psd_stop_point + + psd_scan->psd_start_base + 1; + + i = start_p; + point_index = 0; + + while (i < stop_p) { + if (i >= points1) + psd_report = + halbtc8723b1ant_psd_getdata( + btcoexist, i - points1); + else + psd_report = + halbtc8723b1ant_psd_getdata( + btcoexist, i); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Point=%d, psd_raw_data = 0x%08x\n", + i, psd_report); + BTC_TRACE(trace_buf); + if (psd_report == 0) + tmp = 0; + else + /* tmp = 20*log10((double)psd_report); */ + /* 20*log2(x)/log2(10), log2Base return theresult of the psd_report*100 */ + tmp = 6 * halbtc8723b1ant_psd_log2base( + btcoexist, psd_report); + + n = i - psd_scan->psd_start_base; + psd_scan->psd_report[n] = tmp; + + + halbtc8723b1ant_psd_max_holddata( + btcoexist, j); + + i++; + + } + + psd_scan->psd_gen_count = j; + } + + flag = 100; + break; + case 99: /* error */ + + outloop = true; + break; + case 100: /* recovery */ + + /* set 3-wire on */ + val = btcoexist->btc_read_4byte(btcoexist, 0x88c); + val &= 0xffcfffff; + btcoexist->btc_write_4byte(btcoexist, 0x88c, val); + + /* CCK on */ + val = btcoexist->btc_read_4byte(btcoexist, 0x800); + val |= 0x01000000; + btcoexist->btc_write_4byte(btcoexist, 0x800, val); + + /* PSD off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + val &= 0xffbfffff; + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + /* TRx Mask on */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x780); + + /* lock TRx Mask setup */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xdd, + 0x80, 0x0); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xdf, + 0x1, 0x0); + + /* Set RF Rx filter corner */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, 0x0); + + /* restore WiFi original channel */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x18, + 0x3ff, wifi_original_channel); + + outloop = true; + break; + + } + + } while (!outloop); + + + + psd_scan->is_psd_running = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx PSD Sweep Stop!!\n"); + BTC_TRACE(trace_buf); + return is_sweep_ok; + +} + +void halbtc8723b1ant_psd_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 bt_tx_time, IN u32 bt_le_channel) +{ + u32 i = 0; + u32 wlpsd_cent_freq = 2484, wlpsd_span = 2, wlpsd_sweep_count = 50; + s32 wlpsd_offset = -4; + u8 bt_le_ch[13] = {3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 33}; + + u8 h2c_parameter[3] = {0}, u8tmpa, u8tmpb; + + u8 state = 0; + boolean outloop = false, bt_resp = false; + u32 freq, freq1, freq2, psd_rep1, psd_rep2, delta_freq_per_point, + u32tmp; + struct btc_board_info *board_info = &btcoexist->board_info; + + board_info->btdm_ant_det_finish = false; + memset(psd_scan->ant_det_peak_val, 0, 16 * sizeof(u8)); + memset(psd_scan->ant_det_peak_freq, 0, 16 * sizeof(u8)); + + if (board_info->tfbga_package) /* for TFBGA */ + psd_scan->ant_det_thres_offset = 5; + else + psd_scan->ant_det_thres_offset = 0; + + do { + switch (state) { + case 0: + if (bt_le_channel == 39) + wlpsd_cent_freq = 2484; + else { + for (i = 1; i <= 13; i++) { + if (bt_le_ch[i - 1] == + bt_le_channel) { + wlpsd_cent_freq = 2412 + + (i - 1) * 5; + break; + } + } + + if (i == 14) { + + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Abort!!, Invalid LE channel = %d\n ", + bt_le_channel); + BTC_TRACE(trace_buf); + outloop = true; + break; + } + } + + wlpsd_sweep_count = bt_tx_time * 238 / + 100; /* bt_tx_time/0.42 */ + wlpsd_sweep_count = wlpsd_sweep_count / 5; + + if (wlpsd_sweep_count % 5 != 0) + wlpsd_sweep_count = (wlpsd_sweep_count / + 5 + 1) * 5; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), BT_LETxTime=%d, BT_LECh = %d\n", + bt_tx_time, bt_le_channel); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), wlpsd_cent_freq=%d, wlpsd_offset = %d, wlpsd_span = %d, wlpsd_sweep_count = %d\n", + wlpsd_cent_freq, + wlpsd_offset, + wlpsd_span, + wlpsd_sweep_count); + BTC_TRACE(trace_buf); + + state = 1; + break; + case 1: /* stop coex DM & set antenna path */ + /* Stop Coex DM */ + + /* + btcoexist->stop_coex_dm = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Stop Coex DM!!\n"); + BTC_TRACE(trace_buf); */ + + /* Set TDMA off, */ + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, + false, 0); + + /* Set coex table */ + halbtc8723b1ant_coex_table_with_type(btcoexist, + FORCE_EXEC, 0); + + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna at Main Port\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna at Aux Port\n"); + BTC_TRACE(trace_buf); + } + + /* Set Antenna path, switch WiFi to un-certain antenna port */ + halbtc8723b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_BT, FORCE_EXEC, false, + false); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set Antenna to BT!!\n"); + BTC_TRACE(trace_buf); + + /* Set AFH mask on at WiFi channel 2472MHz +/- 10MHz */ + h2c_parameter[0] = 0x1; + h2c_parameter[1] = 0xd; + h2c_parameter[2] = 0x14; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set AFH on, Cent-Ch= %d, Mask=%d\n", + h2c_parameter[1], + h2c_parameter[2]); + BTC_TRACE(trace_buf); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, + h2c_parameter); + + u32tmp = btcoexist->btc_read_4byte(btcoexist, + 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, + 0x778); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], 0x948=0x%x, 0x765=0x%x, 0x778=0x%x\n", + u32tmp, u8tmpa, u8tmpb); + BTC_TRACE(trace_buf); + + state = 2; + break; + case 2: /* Pre-sweep background psd */ + if (!halbtc8723b1ant_psd_sweep_point(btcoexist, + wlpsd_cent_freq, wlpsd_offset, wlpsd_span, + BT_8723B_1ANT_ANTDET_PSD_POINTS, + BT_8723B_1ANT_ANTDET_PSD_AVGNUM, 3)) { + board_info->btdm_ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 8; + state = 99; + break; + } + + psd_scan->ant_det_pre_psdscan_peak_val = + psd_scan->psd_max_value; + + if (psd_scan->psd_max_value > + (BT_8723B_1ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset) * 100) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Abort Antenna Detection!! becaus background = %d > thres (%d)\n", + psd_scan->psd_max_value / 100, + BT_8723B_1ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + BTC_TRACE(trace_buf); + board_info->btdm_ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 5; + state = 99; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Start Antenna Detection!! becaus background = %d <= thres (%d)\n", + psd_scan->psd_max_value / 100, + BT_8723B_1ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + BTC_TRACE(trace_buf); + state = 3; + } + break; + case 3: + bt_resp = btcoexist->btc_set_bt_ant_detection( + btcoexist, (u8)(bt_tx_time & 0xff), + (u8)(bt_le_channel & 0xff)); + + if (!halbtc8723b1ant_psd_sweep_point(btcoexist, + wlpsd_cent_freq, wlpsd_offset, + wlpsd_span, + BT_8723B_1ANT_ANTDET_PSD_POINTS, + BT_8723B_1ANT_ANTDET_PSD_AVGNUM, + wlpsd_sweep_count)) { + board_info->btdm_ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 8; + state = 99; + break; + } + + psd_scan->ant_det_psd_scan_peak_val = + psd_scan->psd_max_value; + psd_scan->ant_det_psd_scan_peak_freq = + psd_scan->psd_max_value_point; + state = 4; + break; + case 4: + + if (psd_scan->psd_point == 0) + delta_freq_per_point = 0; + else + delta_freq_per_point = + psd_scan->psd_band_width / + psd_scan->psd_point; + + psd_rep1 = psd_scan->psd_max_value / 100; + psd_rep2 = psd_scan->psd_max_value - psd_rep1 * + 100; + + freq = ((psd_scan->real_cent_freq - 20) * + 1000000 + psd_scan->psd_max_value_point + * delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (freq2 < 100) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Max Value: Freq = %d.0%d MHz", + freq1, freq2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_freq, + BT_8723B_1ANT_ANTDET_BUF_LEN, + "%d.0%d", freq1, freq2); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Max Value: Freq = %d.%d MHz", + freq1, freq2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_freq, + BT_8723B_1ANT_ANTDET_BUF_LEN, + "%d.%d", freq1, freq2); + } + + if (psd_rep2 < 10) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + ", Value = %d.0%d dB\n", + psd_rep1, psd_rep2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_val, + BT_8723B_1ANT_ANTDET_BUF_LEN, + "%d.0%d", psd_rep1, psd_rep2); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + ", Value = %d.%d dB\n", + psd_rep1, psd_rep2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_val, + BT_8723B_1ANT_ANTDET_BUF_LEN, + "%d.%d", psd_rep1, psd_rep2); + } + + psd_scan->ant_det_is_btreply_available = true; + + if (bt_resp == false) { + psd_scan->ant_det_is_btreply_available = + false; + psd_scan->ant_det_result = 0; + board_info->btdm_ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), BT Response = Fail\n "); + BTC_TRACE(trace_buf); + } else if (psd_scan->psd_max_value > + (BT_8723B_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION) + * 100) { + psd_scan->ant_det_result = 1; + board_info->btdm_ant_det_finish = true; + board_info->btdm_ant_det_already_init_phydm = + true; + board_info->btdm_ant_num_by_ant_det = 2; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 2-Ant, Bad-Isolation!!\n"); + BTC_TRACE(trace_buf); + } else if (psd_scan->psd_max_value > + (BT_8723B_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset) * 100) { + psd_scan->ant_det_result = 2; + board_info->btdm_ant_det_finish = true; + board_info->btdm_ant_det_already_init_phydm = + true; + board_info->btdm_ant_num_by_ant_det = 2; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 2-Ant, Good-Isolation!!\n"); + BTC_TRACE(trace_buf); + } else if (psd_scan->psd_max_value > + (BT_8723B_1ANT_ANTDET_PSDTHRES_1ANT) * + 100) { + psd_scan->ant_det_result = 3; + board_info->btdm_ant_det_finish = true; + board_info->btdm_ant_det_already_init_phydm = + true; + board_info->btdm_ant_num_by_ant_det = 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 1-Ant!!\n"); + BTC_TRACE(trace_buf); + } else { + psd_scan->ant_det_result = 4; + board_info->btdm_ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 1-Ant, un-certainity!!\n"); + BTC_TRACE(trace_buf); + } + + state = 99; + break; + case 99: /* restore setup */ + + /* Set AFH mask off at WiFi channel 2472MHz +/- 10MHz */ + h2c_parameter[0] = 0x0; + h2c_parameter[1] = 0x0; + h2c_parameter[2] = 0x0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set AFH on, Cent-Ch= %d, Mask=%d\n", + h2c_parameter[1], h2c_parameter[2]); + BTC_TRACE(trace_buf); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, + h2c_parameter); + + /* Set Antenna Path */ + halbtc8723b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, FORCE_EXEC, false, + false); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set Antenna to PTA\n!!"); + BTC_TRACE(trace_buf); + + /* Resume Coex DM */ + /* + btcoexist->stop_coex_dm = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Resume Coex DM\n!!"); + BTC_TRACE(trace_buf); */ + + /* stimulate coex running */ + /* + halbtc8723b1ant_run_coexist_mechanism( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Stimulate Coex running\n!!"); + BTC_TRACE(trace_buf); + */ + + outloop = true; + break; + } + + } while (!outloop); + + + +} + +void halbtc8723b1ant_psd_antenna_detection_check(IN struct btc_coexist + *btcoexist) +{ + static u32 ant_det_count = 0, ant_det_fail_count = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + + boolean scan, roam; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + + /* psd_scan->ant_det_bt_tx_time = 20; */ + psd_scan->ant_det_bt_tx_time = + BT_8723B_1ANT_ANTDET_BTTXTIME; /* 0.42ms*50 = 20ms (0.42ms = 1 PSD sweep) */ + psd_scan->ant_det_bt_le_channel = BT_8723B_1ANT_ANTDET_BTTXCHANNEL; + + ant_det_count++; + + psd_scan->ant_det_try_count = ant_det_count; + + if (scan || roam) { + board_info->btdm_ant_det_finish = false; + psd_scan->ant_det_result = 6; + } else if (coex_sta->bt_disabled) { + board_info->btdm_ant_det_finish = false; + psd_scan->ant_det_result = 11; + } else if (coex_sta->num_of_profile >= 1) { + board_info->btdm_ant_det_finish = false; + psd_scan->ant_det_result = 7; + } else if ( + !psd_scan->ant_det_is_ant_det_available) { /* Antenna initial setup is not ready */ + board_info->btdm_ant_det_finish = false; + psd_scan->ant_det_result = 9; + } else if (coex_sta->c2h_bt_inquiry_page) { + board_info->btdm_ant_det_finish = false; + psd_scan->ant_det_result = 10; + } else { + btcoexist->stop_coex_dm = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Stop Coex DM!!\n"); + BTC_TRACE(trace_buf); + + halbtc8723b1ant_psd_antenna_detection(btcoexist, + psd_scan->ant_det_bt_tx_time, + psd_scan->ant_det_bt_le_channel); + + delay_ms(psd_scan->ant_det_bt_tx_time); + + btcoexist->stop_coex_dm = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Resume Coex DM\n!!"); + BTC_TRACE(trace_buf); + + /* stimulate coex running */ + + halbtc8723b1ant_run_coexist_mechanism( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Stimulate Coex running\n!!"); + BTC_TRACE(trace_buf); + } + + board_info->ant_det_result = psd_scan->ant_det_result; + if (!board_info->btdm_ant_det_finish) + ant_det_fail_count++; + + psd_scan->ant_det_fail_count = ant_det_fail_count; + +} + + +/* ************************************************************ + * work around function start with wa_halbtc8723b1ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8723b1ant_ + * ************************************************************ */ +void ex_halbtc8723b1ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + u32 value; + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Execute 8723b 1-Ant PowerOn Setting xxxxxxxxxxxxxxxx!!\n"); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Ant Det Finish = %s, Ant Det Number = %d\n", + (board_info->btdm_ant_det_finish ? "Yes" : "No"), + board_info->btdm_ant_num_by_ant_det); + BTC_TRACE(trace_buf); + + + btcoexist->stop_coex_dm = true; + + btcoexist->btc_write_1byte(btcoexist, 0x67, 0x20); + + /* enable BB, REG_SYS_FUNC_EN such that we can write 0x948 correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT(0) | BIT(1)); + + /* set GRAN_BT = 1 */ + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + /* set WLAN_ACT = 0 */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* */ + /* S0 or S1 setting and Local register setting(By the setting fw can get ant number, S0/S1, ... info) */ + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + + u8tmp |= 0x1; /* antenna inverse */ + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + /* set to S1 */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x280); + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + value = 1; + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + u8tmp |= 0x1; /* antenna inverse */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + value = 0; + } + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ANTPOSREGRISTRY_CTRL, + &value); + + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x384, + u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, + u8tmp); + } +} + +void ex_halbtc8723b1ant_pre_load_firmware(IN struct btc_coexist *btcoexist) +{ +} + +void ex_halbtc8723b1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8723b1ant_init_hw_config(btcoexist, true, wifi_only); + btcoexist->stop_coex_dm = false; +} + +void ex_halbtc8723b1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = false; + + halbtc8723b1ant_init_coex_dm(btcoexist); + + halbtc8723b1ant_query_bt_info(btcoexist); +} + +void ex_halbtc8723b1ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u16 u16tmp[4]; + u32 u32tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + u32 fw_ver = 0, bt_patch_ver = 0; + u32 bt_coex_ver = 0; + static u8 pop_report_in_10s = 0; + u32 phyver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + if (btcoexist->stop_coex_dm) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (psd_scan->ant_det_try_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + "Ant PG Num/ Mech/ Pos", + board_info->pg_ant_num, board_info->btdm_ant_num, + board_info->btdm_ant_pos); + CL_PRINTF(cli_buf); + } else { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %d (%d/%d/%d)", + "Ant PG Num/ Mech(Ant_Det)/ Pos", + board_info->pg_ant_num, + board_info->btdm_ant_num_by_ant_det, + board_info->btdm_ant_pos, + psd_scan->ant_det_try_count, + psd_scan->ant_det_fail_count, + psd_scan->ant_det_result); + CL_PRINTF(cli_buf); + + if (board_info->btdm_ant_det_finish) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "Ant Det PSD Value", + psd_scan->ant_det_peak_val); + CL_PRINTF(cli_buf); + } + } + + if (board_info->ant_det_result_five_complete) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d", + "Ant number by AntDet", + board_info->btdm_ant_num_by_ant_det); + CL_PRINTF(cli_buf); + } + + /* btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); */ + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + bt_coex_ver = ((coex_sta->bt_coex_supported_version & 0xff00) >> 8); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8723b_1ant, glcoex_ver_8723b_1ant, + glcoex_ver_btdesired_8723b_1ant, + bt_coex_ver, + (bt_coex_ver == 0xff ? "Unknown" : + (bt_coex_ver >= glcoex_ver_btdesired_8723b_1ant ? + "Match" : "Mis-Match"))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ v%d/ %c", + "W_FW/ B_FW/ Phy/ Kt", + fw_ver, bt_patch_ver, phyver, + coex_sta->cut_version + 65); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "Wifi channel informed to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s", + "WifibHiPri/ Ccklock/ CckEverLock", + (coex_sta->wifi_is_high_pri_task ? "Yes" : "No"), + (coex_sta->cck_lock ? "Yes" : "No"), + (coex_sta->cck_ever_lock ? "Yes" : "No")); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Abnormal scan", + (coex_sta->bt_abnormal_scan) ? "Yes" : "No"); + CL_PRINTF(cli_buf); + + pop_report_in_10s++; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d/ %d] ", + "BT [status/ rssi/ retryCnt/ popCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") + : ((BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi, coex_sta->bt_retry_cnt, + coex_sta->pop_event_cnt); + CL_PRINTF(cli_buf); + + if (pop_report_in_10s >= 5) { + coex_sta->pop_event_cnt = 0; + pop_report_in_10s = 0; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d / %d / %d / %d / %d / %d", + "SCO/HID/PAN/A2DP/NameReq/WHQL", + bt_link_info->sco_exist, bt_link_info->hid_exist, + bt_link_info->pan_exist, bt_link_info->a2dp_exist, + coex_sta->c2h_bt_remote_name_req, + coex_sta->bt_whck_test); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Role", + (bt_link_info->slave_role) ? "Slave" : "Master"); + CL_PRINTF(cli_buf); + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %d", + "A2DP Rate/Bitpool", + (bt_info_ext & BIT(0)) ? "BR" : "EDR", coex_sta->a2dp_bit_pool); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8723B_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8723b_1ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + + if (btcoexist->manual_control) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanisms] (before Manual)============"); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanisms]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "SM[LowPenaltyRA]", + coex_dm->cur_low_penalty_ra); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + if (board_info->btdm_ant_num_by_ant_det == 2) { + if (coex_dm->cur_ps_tdma_on) + ps_tdma_case = ps_tdma_case + + 100; /* for WiFi RSSI low or BT RSSI low */ + else + ps_tdma_case = + 1; /* always translate to TDMA(off,1) for TDMA-off case */ + } + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (%s,%s)", + "PS TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + (coex_dm->cur_ps_tdma_on ? "On" : "Off"), + (coex_dm->auto_tdma_adjust ? "Adj" : "Fix")); + + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "Coex Table Type", + coex_sta->coex_table_type); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "IgnWlanAct", + coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + /* + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Latest error condition(should be 0)", + coex_dm->error_condition); + CL_PRINTF(cli_buf); + */ + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "backup ARFR1/ARFR2/RL/AMaxTime", + coex_dm->backup_arfr_cnt1, coex_dm->backup_arfr_cnt2, + coex_dm->backup_retry_limit, + coex_dm->backup_ampdu_max_time); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x880); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x778/0x6cc/0x880[29:25]", + u8tmp[0], u32tmp[0], (u32tmp[1] & 0x3e000000) >> 25); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x764); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x76e); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x948/ 0x67[5] / 0x764 / 0x76e", + u32tmp[0], ((u8tmp[0] & 0x20) >> 5), (u32tmp[1] & 0xffff), + u8tmp[1]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", + u32tmp[0] & 0x3, u32tmp[1] & 0xff, u32tmp[2] & 0x3); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x38[11]/0x40/0x4c[24:23]/0x64[0]", + ((u8tmp[0] & 0x8) >> 3), u8tmp[1], + ((u32tmp[0] & 0x01800000) >> 23), u8tmp[2] & 0x1); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", + u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0xc50(dig)/0x49c(null-drop)", + u32tmp[0] & 0xff, u8tmp[0]); + CL_PRINTF(cli_buf); + + fa_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_OFDM); + fa_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_CCK); + cca_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_OFDM); + cca_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_CCK); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", + cca_cck, fa_cck, cca_ofdm, fa_ofdm); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11n-agg", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11n-agg", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(high-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(low-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 1) + /* halbtc8723b1ant_monitor_bt_ctr(btcoexist); */ +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8723b1ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, false, true); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + + halbtc8723b1ant_init_hw_config(btcoexist, false, false); + halbtc8723b1ant_init_coex_dm(btcoexist); + halbtc8723b1ant_query_bt_info(btcoexist); + + coex_sta->under_ips = false; + } +} + +void ex_halbtc8723b1ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8723b1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + u8 u8tmpa, u8tmpb; + u32 u32tmp; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if (BTC_SCAN_START == type) { + coex_sta->wifi_is_high_pri_task = true; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + psd_scan->ant_det_is_ant_det_available = true; + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 8); /* Force antenna setup for no scan result issue */ + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x67); + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x\n", + u32tmp, u8tmpa, u8tmpb); + BTC_TRACE(trace_buf); + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + } + + if (coex_sta->bt_disabled) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + halbtc8723b1ant_query_bt_info(btcoexist); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8723b1ant_action_wifi_multi_port(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8723b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8723b1ant_action_hs(btcoexist); + return; + } + + if (BTC_SCAN_START == type) { + if (!wifi_connected) /* non-connected scan */ + halbtc8723b1ant_action_wifi_not_connected_scan( + btcoexist); + else /* wifi is connected */ + halbtc8723b1ant_action_wifi_connected_scan(btcoexist); + } else if (BTC_SCAN_FINISH == type) { + if (!wifi_connected) /* non-connected scan */ + halbtc8723b1ant_action_wifi_not_connected(btcoexist); + else + halbtc8723b1ant_action_wifi_connected(btcoexist); + } +} + +void ex_halbtc8723b1ant_set_antenna_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (type == 2) /* two antenna */ + halbtc8723b1ant_mechanism_switch(btcoexist, true); + else /* one antenna */ + halbtc8723b1ant_mechanism_switch(btcoexist, false); +} + +void ex_halbtc8723b1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if (BTC_ASSOCIATE_START == type) { + coex_sta->wifi_is_high_pri_task = true; + psd_scan->ant_det_is_ant_det_available = true; + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 8); /* Force antenna setup for no scan result issue */ + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify\n"); + BTC_TRACE(trace_buf); + coex_dm->arp_cnt = 0; + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify\n"); + BTC_TRACE(trace_buf); + /* coex_dm->arp_cnt = 0; */ + } + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8723b1ant_action_wifi_multi_port(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8723b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8723b1ant_action_hs(btcoexist); + return; + } + + if (BTC_ASSOCIATE_START == type) + halbtc8723b1ant_action_wifi_not_connected_asso_auth(btcoexist); + else if (BTC_ASSOCIATE_FINISH == type) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (!wifi_connected) /* non-connected scan */ + halbtc8723b1ant_action_wifi_not_connected(btcoexist); + else + halbtc8723b1ant_action_wifi_connected(btcoexist); + } +} + +void ex_halbtc8723b1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + boolean wifi_under_b_mode = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if (BTC_MEDIA_CONNECT == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 8); /* Force antenna setup for no scan result issue */ + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); + psd_scan->ant_det_is_ant_det_available = true; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } + + coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, + 0x430); + coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, + 0x434); + coex_dm->backup_retry_limit = btcoexist->btc_read_2byte( + btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = btcoexist->btc_read_1byte( + btcoexist, 0x456); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + coex_dm->arp_cnt = 0; + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + + coex_sta->cck_ever_lock = false; + } + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + /* h2c_parameter[0] = 0x1; */ + h2c_parameter[0] = 0x0; + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8723b1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false, under_4way = false; + u8 agg_buf_size = 5; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if (BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type || + BTC_PACKET_ARP == type) { + if (BTC_PACKET_ARP == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ARP notify\n"); + BTC_TRACE(trace_buf); + + coex_dm->arp_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ARP Packet Count = %d\n", + coex_dm->arp_cnt); + BTC_TRACE(trace_buf); + + if ((coex_dm->arp_cnt >= 10) && + (!under_4way)) /* if APR PKT > 10 after connect, do not go to ActionWifiConnectedSpecificPacket(btcoexist) */ + coex_sta->wifi_is_high_pri_task = false; + else + coex_sta->wifi_is_high_pri_task = true; + } else { + coex_sta->wifi_is_high_pri_task = true; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet DHCP or EAPOL notify\n"); + BTC_TRACE(trace_buf); + } + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet [Type = %d] notify\n", type); + BTC_TRACE(trace_buf); + } + + coex_sta->specific_pkt_period_cnt = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + halbtc8723b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8723b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8723b1ant_action_wifi_multi_port(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8723b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8723b1ant_action_hs(btcoexist); + return; + } + + if (BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type || + ((BTC_PACKET_ARP == type) && (coex_sta->wifi_is_high_pri_task))) + halbtc8723b1ant_action_wifi_connected_specific_packet( + btcoexist); +} + +/* Donot remove optimize off flag, otherwise antenna detection would trigger BT collapsed */ +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +void ex_halbtc8723b1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + boolean wifi_connected = false; + boolean bt_busy = false; + struct btc_board_info *board_info = &btcoexist->board_info; + + coex_sta->c2h_bt_info_req_sent = false; + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8723B_1ANT_MAX) + rsp_source = BT_INFO_SRC_8723B_1ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt info[%d], length=%d, hex data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + /* if 0xff, it means BT is under WHCK test */ + if (bt_info == 0xff) + coex_sta->bt_whck_test = true; + else + coex_sta->bt_whck_test = false; + + if (BT_INFO_SRC_8723B_1ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0] */ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->bt_info_c2h[rsp_source][2] & 0x20) + coex_sta->c2h_bt_remote_name_req = true; + else + coex_sta->c2h_bt_remote_name_req = false; + + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3] * 2 - 90; + /* coex_sta->bt_info_c2h[rsp_source][3]*2+10; */ + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rsp_source][4]; + + if (coex_sta->bt_info_c2h[rsp_source][1] == 0x49) { + coex_sta->a2dp_bit_pool = + coex_sta->bt_info_c2h[rsp_source][6]; + } else + coex_sta->a2dp_bit_pool = 0; + + coex_sta->bt_tx_rx_mask = (coex_sta->bt_info_c2h[rsp_source][2] + & 0x40); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TX_RX_MASK, + &coex_sta->bt_tx_rx_mask); + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT info Notify() return because stop_coex_dm\n"); + BTC_TRACE(trace_buf); + + return; + } + + +#if BT_8723B_1ANT_ANTDET_ENABLE +#if BT_8723B_1ANT_ANTDET_COEXMECHANISMSWITCH_ENABLE + if ((board_info->btdm_ant_det_finish) && + (board_info->btdm_ant_num_by_ant_det == 2)) { + if (coex_sta->bt_tx_rx_mask) { + + /* BT TRx mask off */ + btcoexist->btc_set_bt_trx_mask(btcoexist, 0); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT TRx Mask off for BT Info Notify\n"); + BTC_TRACE(trace_buf); +#if 0 + /* BT into is responded by BT FW and BT RF REG 0x3C != 0x15 => Need to switch BT TRx Mask */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x1\n"); + BTC_TRACE(trace_buf); + + /* BT TRx Mask un-lock 0x2c[0], 0x30[0] = 1 */ + btcoexist->btc_set_bt_reg(btcoexist, + BTC_BT_REG_RF, 0x2c, 0x7c45); + btcoexist->btc_set_bt_reg(btcoexist, + BTC_BT_REG_RF, 0x30, 0x7c45); + + btcoexist->btc_set_bt_reg(btcoexist, + BTC_BT_REG_RF, 0x3c, 0x1); +#endif + } + } else +#endif +#endif + + { + if (!coex_sta->bt_tx_rx_mask) { + + /* BT TRx mask on */ + btcoexist->btc_set_bt_trx_mask(btcoexist, 1); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT TRx Mask on for BT Info Notify\n"); + BTC_TRACE(trace_buf); +#if 0 + /* BT into is responded by BT FW and BT RF REG 0x3C != 0x15 => Need to switch BT TRx Mask */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x15\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_bt_reg(btcoexist, + BTC_BT_REG_RF, + 0x3c, 0x15); + + /* BT TRx Mask lock 0x2c[0], 0x30[0] = 0 */ + btcoexist->btc_set_bt_reg(btcoexist, + BTC_BT_REG_RF, + 0x2c, 0x7c44); + btcoexist->btc_set_bt_reg(btcoexist, + BTC_BT_REG_RF, + 0x30, 0x7c44); +#endif + } + } + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + if (coex_sta->bt_info_ext & BIT(1)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) + ex_halbtc8723b1ant_media_status_notify( + btcoexist, BTC_MEDIA_CONNECT); + else + ex_halbtc8723b1ant_media_status_notify( + btcoexist, BTC_MEDIA_DISCONNECT); + } + + if (coex_sta->bt_info_ext & BIT(3)) { + if (!btcoexist->manual_control && + !btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8723b1ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, false); + } + } else { + /* BT already NOT ignore Wlan active, do nothing here. */ + } +#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) + if ((coex_sta->bt_info_ext & BIT(4))) { + /* BT auto report already enabled, do nothing */ + } else + halbtc8723b1ant_bt_auto_report(btcoexist, FORCE_EXEC, + true); +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (bt_info & BT_INFO_8723B_1ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + coex_sta->num_of_profile = 0; + + /* set link exist status */ + if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + + coex_sta->bt_hi_pri_link_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8723B_1ANT_B_FTP) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8723B_1ANT_B_A2DP) { + coex_sta->a2dp_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8723B_1ANT_B_HID) { + coex_sta->hid_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) { + coex_sta->sco_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->sco_exist = false; + + if ((coex_sta->hid_exist == false) && + (coex_sta->c2h_bt_inquiry_page == false) && + (coex_sta->sco_exist == false)) { + if (coex_sta->high_priority_tx + + coex_sta->high_priority_rx >= 160) { + coex_sta->hid_exist = true; + coex_sta->wrong_profile_notification++; + coex_sta->num_of_profile++; + bt_info = bt_info | 0x28; + } + } + + /* Add Hi-Pri Tx/Rx counter to avoid false detection */ + if (((coex_sta->hid_exist) || (coex_sta->sco_exist)) && + (coex_sta->high_priority_tx + + coex_sta->high_priority_rx >= 160) + && (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->bt_hi_pri_link_exist = true; + + if ((bt_info & BT_INFO_8723B_1ANT_B_ACL_BUSY) && + (coex_sta->num_of_profile == 0)) { + if (coex_sta->low_priority_tx + + coex_sta->low_priority_rx >= 160) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + coex_sta->wrong_profile_notification++; + bt_info = bt_info | 0x88; + } + } + } + + halbtc8723b1ant_update_bt_link_info(btcoexist); + + bt_info = bt_info & + 0x1f; /* mask profile bit for connect-ilde identification ( for CSR case: A2DP idle --> 0x41) */ + + if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + else if (bt_info == + BT_INFO_8723B_1ANT_B_CONNECTION) /* connection exists but no busy */ + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE; + else if ((bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8723B_1ANT_B_SCO_BUSY)) + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_SCO_BUSY; + else if (bt_info & BT_INFO_8723B_1ANT_B_ACL_BUSY) { + if (BT_8723B_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status) + coex_dm->auto_tdma_adjust = false; + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_ACL_BUSY; + } else + coex_dm->bt_status = BT_8723B_1ANT_BT_STATUS_MAX; + + if ((BT_8723B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + halbtc8723b1ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8723b1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u32 u32tmp; + u8 u8tmpa, u8tmpb, u8tmpc; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], RF Status notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_RF_ON == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned ON!!\n"); + BTC_TRACE(trace_buf); + btcoexist->stop_coex_dm = false; + } else if (BTC_RF_OFF == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned OFF!!\n"); + BTC_TRACE(trace_buf); + + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, false, true); + + halbtc8723b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + btcoexist->stop_coex_dm = true; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x67); + u8tmpc = btcoexist->btc_read_1byte(btcoexist, 0x76e); + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], 0x948=0x%x, 0x765=0x%x, 0x67=0x%x, 0x76e=0x%x\n", + u32tmp, u8tmpa, u8tmpb, u8tmpc); + BTC_TRACE(trace_buf); + + } +} + +void ex_halbtc8723b1ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8723b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, FORCE_EXEC, + false, true); + + halbtc8723b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + ex_halbtc8723b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + btcoexist->stop_coex_dm = true; +} + +void ex_halbtc8723b1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + if (BTC_WIFI_PNP_SLEEP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + + halbtc8723b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8723b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, false, true); + halbtc8723b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + + /* Sinda 20150819, workaround for driver skip leave IPS/LPS to speed up sleep time. */ + /* Driver do not leave IPS/LPS when driver is going to sleep, so BTCoexistence think wifi is still under IPS/LPS */ + /* BT should clear UnderIPS/UnderLPS state to avoid mismatch state after wakeup. */ + coex_sta->under_ips = false; + coex_sta->under_lps = false; + btcoexist->stop_coex_dm = true; + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + btcoexist->stop_coex_dm = false; + halbtc8723b1ant_init_hw_config(btcoexist, false, false); + halbtc8723b1ant_init_coex_dm(btcoexist); + halbtc8723b1ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8723b1ant_coex_dm_reset(IN struct btc_coexist *btcoexist) +{ + + halbtc8723b1ant_init_hw_config(btcoexist, false, false); + /* btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); */ + /* btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x2, 0xfffff, 0x0); */ + halbtc8723b1ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8723b1ant_periodical(IN struct btc_coexist *btcoexist) +{ + u32 bt_patch_ver; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ==========================Periodical===========================\n"); + BTC_TRACE(trace_buf); + +#if (BT_AUTO_REPORT_ONLY_8723B_1ANT == 0) + halbtc8723b1ant_query_bt_info(btcoexist); +#endif + halbtc8723b1ant_monitor_bt_ctr(btcoexist); + halbtc8723b1ant_monitor_wifi_ctr(btcoexist); + + halbtc8723b1ant_monitor_bt_enable_disable(btcoexist); + + + if (halbtc8723b1ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust || + btcoexist->bt_info.bt_enable_disable_change) + halbtc8723b1ant_run_coexist_mechanism(btcoexist); + + if (((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) && (!coex_sta->bt_disabled)) + btcoexist->btc_get(btcoexist, BTC_GET_U4_SUPPORTED_VERSION, &coex_sta->bt_coex_supported_version); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + btcoexist->bt_info.bt_get_fw_ver = bt_patch_ver; + coex_sta->specific_pkt_period_cnt++; + + /* sample to set bt to execute Ant detection */ + /* btcoexist->btc_set_bt_ant_detection(btcoexist, 20, 14); + * + if (psd_scan->is_ant_det_enable) + { + if (psd_scan->psd_gen_count > psd_scan->realseconds) + psd_scan->psd_gen_count = 0; + + halbtc8723b1ant_antenna_detection(btcoexist, psd_scan->realcent_freq, psd_scan->realoffset, psd_scan->realspan, psd_scan->realseconds); + psd_scan->psd_gen_total_count +=2; + psd_scan->psd_gen_count += 2; + } + */ +} + +/* Donot remove optimize off flag, otherwise antenna detection would trigger BT collapsed */ +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +void ex_halbtc8723b1ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ +#if BT_8723B_1ANT_ANTDET_ENABLE + static u32 ant_det_count = 0, ant_det_fail_count = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + /*boolean scan, roam;*/ + + if (seconds == 0) { + psd_scan->ant_det_try_count = 0; + psd_scan->ant_det_fail_count = 0; + ant_det_count = 0; + ant_det_fail_count = 0; + board_info->btdm_ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + return; + } + + if (!board_info->btdm_ant_det_finish) { + psd_scan->ant_det_inteval_count = + psd_scan->ant_det_inteval_count + 2; + + if (psd_scan->ant_det_inteval_count >= + BT_8723B_1ANT_ANTDET_RETRY_INTERVAL) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Timer is up, Try Detect!!\n"); + BTC_TRACE(trace_buf); + halbtc8723b1ant_psd_antenna_detection_check(btcoexist); + + if (board_info->btdm_ant_det_finish) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Success!!\n"); + BTC_TRACE(trace_buf); + + +#if 1 + if (board_info->btdm_ant_num_by_ant_det == 2) + halbtc8723b1ant_mechanism_switch( + btcoexist, true); + else + halbtc8723b1ant_mechanism_switch( + btcoexist, false); +#endif + + board_info->btdm_ant_det_complete_fail = false; + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Fail!!\n"); + BTC_TRACE(trace_buf); + + board_info->btdm_ant_det_complete_fail = true; + } + psd_scan->ant_det_inteval_count = 0; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Timer is not up! (%d)\n", + psd_scan->ant_det_inteval_count); + BTC_TRACE(trace_buf); + } + + } +#endif + + + /* + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + + psd_scan->ant_det_bt_tx_time = seconds; + psd_scan->ant_det_bt_le_channel = cent_freq; + + if (seconds == 0) + { + psd_scan->ant_det_try_count = 0; + psd_scan->ant_det_fail_count = 0; + ant_det_count = 0; + ant_det_fail_count = 0; + board_info->btdm_ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + return; + } + else + { + ant_det_count++; + + psd_scan->ant_det_try_count = ant_det_count; + + if (scan ||roam) + { + board_info->btdm_ant_det_finish = false; + psd_scan->ant_det_result = 6; + } + else if (coex_sta->num_of_profile >= 1) + { + board_info->btdm_ant_det_finish = false; + psd_scan->ant_det_result = 7; + } + else if (!psd_scan->ant_det_is_ant_det_available) + { + board_info->btdm_ant_det_finish = false; + psd_scan->ant_det_result = 9; + } + else if (coex_sta->c2h_bt_inquiry_page) + { + board_info->btdm_ant_det_finish = false; + psd_scan->ant_det_result = 10; + } + else + { + + } + + if (!board_info->btdm_ant_det_finish) + ant_det_fail_count++; + + psd_scan->ant_det_fail_count = ant_det_fail_count; + } + */ +} + + +void ex_halbtc8723b1ant_display_ant_detection(IN struct btc_coexist *btcoexist) +{ +#if BT_8723B_1ANT_ANTDET_ENABLE + struct btc_board_info *board_info = &btcoexist->board_info; + + if (psd_scan->ant_det_try_count != 0) { + halbtc8723b1ant_psd_show_antenna_detect_result(btcoexist); + + if (board_info->btdm_ant_det_finish) + halbtc8723b1ant_psd_showdata(btcoexist); + return; + } +#endif + + /* halbtc8723b1ant_show_psd_data(btcoexist); */ +} + +#endif + +#endif /* #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) */ + + + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b1ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b1ant.h new file mode 100644 index 0000000..af476d9 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b1ant.h @@ -0,0 +1,293 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8723B_SUPPORT == 1) +/* ******************************************* + * The following is for 8723B 1ANT BT Co-exist definition + * ******************************************* */ +#define BT_AUTO_REPORT_ONLY_8723B_1ANT 1 + +#define BT_INFO_8723B_1ANT_B_FTP BIT(7) +#define BT_INFO_8723B_1ANT_B_A2DP BIT(6) +#define BT_INFO_8723B_1ANT_B_HID BIT(5) +#define BT_INFO_8723B_1ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8723B_1ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8723B_1ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8723B_1ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8723B_1ANT_B_CONNECTION BIT(0) + +#define BT_INFO_8723B_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT(0))) ? true : false) + +#define BTC_RSSI_COEX_THRESH_TOL_8723B_1ANT 2 + +#define BT_8723B_1ANT_WIFI_NOISY_THRESH 50 /* 30 /max: 255 */ + +/* for Antenna detection */ +#define BT_8723B_1ANT_ANTDET_PSDTHRES_BACKGROUND 50 +#define BT_8723B_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION 70 +#define BT_8723B_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION 48 +#define BT_8723B_1ANT_ANTDET_PSDTHRES_1ANT 32 +#define BT_8723B_1ANT_ANTDET_RETRY_INTERVAL 10 /* retry timer if ant det is fail, unit: second */ +#define BT_8723B_1ANT_ANTDET_SWEEPPOINT_DELAY 40000 +#define BT_8723B_1ANT_ANTDET_ENABLE 1 +#define BT_8723B_1ANT_ANTDET_COEXMECHANISMSWITCH_ENABLE 1 +#define BT_8723B_1ANT_ANTDET_BTTXTIME 100 +#define BT_8723B_1ANT_ANTDET_BTTXCHANNEL 39 + +enum bt_info_src_8723b_1ant { + BT_INFO_SRC_8723B_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723B_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723B_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723B_1ANT_MAX +}; + +enum bt_8723b_1ant_bt_status { + BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723B_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8723B_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8723B_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8723B_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8723B_1ANT_BT_STATUS_MAX +}; + +enum bt_8723b_1ant_wifi_status { + BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SPECIFIC_PKT = 0x3, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8723B_1ANT_WIFI_STATUS_MAX +}; + +enum bt_8723b_1ant_coex_algo { + BT_8723B_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723B_1ANT_COEX_ALGO_SCO = 0x1, + BT_8723B_1ANT_COEX_ALGO_HID = 0x2, + BT_8723B_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8723B_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8723B_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8723B_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8723B_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8723B_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8723B_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8723B_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8723B_1ANT_COEX_ALGO_MAX = 0xb, +}; + +struct coex_dm_8723b_1ant { + /* hw setting */ + u8 pre_ant_pos_type; + u8 cur_ant_pos_type; + /* fw mechanism */ + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean auto_tdma_adjust; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + /* sw mechanism */ + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 bt_status; + u8 wifi_chnl_info[3]; + + u32 pre_ra_mask; + u32 cur_ra_mask; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; + u32 arp_cnt; + + u8 error_condition; +}; + +struct coex_sta_8723b_1ant { + boolean bt_disabled; + boolean bt_enable_disable_change; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + boolean bt_hi_pri_link_exist; + u8 num_of_profile; + boolean bt_abnormal_scan; + + boolean under_lps; + boolean under_ips; + u32 specific_pkt_period_cnt; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + s8 bt_rssi; + boolean bt_tx_rx_mask; + boolean c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8723B_1ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_1ANT_MAX]; + boolean bt_whck_test; + boolean c2h_bt_inquiry_page; + boolean c2h_bt_remote_name_req; + boolean wifi_is_high_pri_task; /* Add for win8.1 page out issue */ + u8 bt_retry_cnt; + u8 bt_info_ext; + u32 pop_event_cnt; + u8 scan_ap_num; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_vht; + + boolean cck_lock; + boolean pre_ccklock; + boolean cck_ever_lock; + u8 coex_table_type; + + boolean force_lps_on; + u32 wrong_profile_notification; + u32 bt_coex_supported_version; + u8 a2dp_bit_pool; + u8 cut_version; +}; + +#define BT_8723B_1ANT_ANTDET_PSD_POINTS 256 /* MAX:1024 */ +#define BT_8723B_1ANT_ANTDET_PSD_AVGNUM 1 /* MAX:3 */ +#define BT_8723B_1ANT_ANTDET_BUF_LEN 16 + +struct psdscan_sta_8723b_1ant { + + u32 ant_det_bt_le_channel; /* BT LE Channel ex:2412 */ + u32 ant_det_bt_tx_time; + u32 ant_det_pre_psdscan_peak_val; + boolean ant_det_is_ant_det_available; + u32 ant_det_psd_scan_peak_val; + boolean ant_det_is_btreply_available; + u32 ant_det_psd_scan_peak_freq; + + u8 ant_det_result; + u8 ant_det_peak_val[BT_8723B_1ANT_ANTDET_BUF_LEN]; + u8 ant_det_peak_freq[BT_8723B_1ANT_ANTDET_BUF_LEN]; + u32 ant_det_try_count; + u32 ant_det_fail_count; + u32 ant_det_inteval_count; + u32 ant_det_thres_offset; + + u32 real_cent_freq; + s32 real_offset; + u32 real_span; + + u32 psd_band_width; /* unit: Hz */ + u32 psd_point; /* 128/256/512/1024 */ + u32 psd_report[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_report_max_hold[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_start_point; + u32 psd_stop_point; + u32 psd_max_value_point; + u32 psd_max_value; + u32 psd_start_base; + u32 psd_avg_num; /* 1/8/16/32 */ + u32 psd_gen_count; + boolean is_psd_running; + boolean is_psd_show_max_only; +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8723b1ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_pre_load_firmware(IN struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8723b1ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b1ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b1ant_set_antenna_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8723b1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b1ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state); +void ex_halbtc8723b1ant_coex_dm_reset(IN struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_display_coex_info(IN struct btc_coexist *btcoexist); +void ex_halbtc8723b1ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); + +void ex_halbtc8723b1ant_display_ant_detection(IN struct btc_coexist *btcoexist); + +#else +#define ex_halbtc8723b1ant_power_on_setting(btcoexist) +#define ex_halbtc8723b1ant_pre_load_firmware(btcoexist) +#define ex_halbtc8723b1ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8723b1ant_init_coex_dm(btcoexist) +#define ex_halbtc8723b1ant_ips_notify(btcoexist, type) +#define ex_halbtc8723b1ant_lps_notify(btcoexist, type) +#define ex_halbtc8723b1ant_scan_notify(btcoexist, type) +#define ex_halbtc8723b1ant_set_antenna_notify(btcoexist, type) +#define ex_halbtc8723b1ant_connect_notify(btcoexist, type) +#define ex_halbtc8723b1ant_media_status_notify(btcoexist, type) +#define ex_halbtc8723b1ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8723b1ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8723b1ant_rf_status_notify(btcoexist, type) +#define ex_halbtc8723b1ant_halt_notify(btcoexist) +#define ex_halbtc8723b1ant_pnp_notify(btcoexist, pnp_state) +#define ex_halbtc8723b1ant_coex_dm_reset(btcoexist) +#define ex_halbtc8723b1ant_periodical(btcoexist) +#define ex_halbtc8723b1ant_display_coex_info(btcoexist) +#define ex_halbtc8723b1ant_antenna_detection(btcoexist, cent_freq, offset, span, seconds) +#define ex_halbtc8723b1ant_display_ant_detection(btcoexist) + +#endif + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b2ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b2ant.c new file mode 100644 index 0000000..3b1dd4a --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b2ant.c @@ -0,0 +1,4958 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8723B Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8723B_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8723b_2ant glcoex_dm_8723b_2ant; +static struct coex_dm_8723b_2ant *coex_dm = &glcoex_dm_8723b_2ant; +static struct coex_sta_8723b_2ant glcoex_sta_8723b_2ant; +static struct coex_sta_8723b_2ant *coex_sta = &glcoex_sta_8723b_2ant; + +const char *const glbt_info_src_8723b_2ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u32 glcoex_ver_date_8723b_2ant = 20161007; +u32 glcoex_ver_8723b_2ant = 0x4c; +u32 glcoex_ver_btdesired_8723b_2ant = 0x4c; + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8723b2ant_ + * ************************************************************ */ +u8 halbtc8723b2ant_bt_rssi_state(u8 *ppre_bt_rssi_state, u8 level_num, + u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = *ppre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return *ppre_bt_rssi_state; + } + + if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_MEDIUM) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + *ppre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8723b2ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 *pprewifi_rssi_state, IN u8 level_num, IN u8 rssi_thresh, + IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = *pprewifi_rssi_state; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((*pprewifi_rssi_state == BTC_RSSI_STATE_LOW) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return *pprewifi_rssi_state; + } + + if ((*pprewifi_rssi_state == BTC_RSSI_STATE_LOW) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((*pprewifi_rssi_state == BTC_RSSI_STATE_MEDIUM) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + *pprewifi_rssi_state = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8723b2ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false; + + /* This function check if bt is disabled */ + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + } else { + bt_disable_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], bt all counters=0, %d times!!\n", + bt_disable_cnt); + BTC_TRACE(trace_buf); + if (bt_disable_cnt >= 10) + bt_disabled = true; + } + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + + coex_sta->bt_disabled = bt_disabled; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + if (bt_disabled) { + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + } + } +} + + +void halbtc8723b2ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); +} + +void halbtc8723b2ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + if ((coex_sta->low_priority_tx > 1050) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + + if ((coex_sta->low_priority_rx >= 950) && + (coex_sta->low_priority_rx >= coex_sta->low_priority_tx) && + (!coex_sta->under_ips)) + bt_link_info->slave_role = true; + else + bt_link_info->slave_role = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx); + BTC_TRACE(trace_buf); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +void halbtc8723b2ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ +#if 1 + + coex_sta->crc_ok_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_CCK); + coex_sta->crc_ok_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_LEGACY); + coex_sta->crc_ok_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_HT); + coex_sta->crc_ok_11n_vht = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_VHT); + + coex_sta->crc_err_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_CCK); + coex_sta->crc_err_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_LEGACY); + coex_sta->crc_err_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_HT); + coex_sta->crc_err_11n_vht = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_VHT); + +#endif +} + +void halbtc8723b2ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +boolean halbtc8723b2ant_is_wifi_status_changed(IN struct btc_coexist *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false; + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + + if ((BTC_RSSI_STATE_HIGH == wifi_rssi_state) || + (BTC_RSSI_STATE_LOW == wifi_rssi_state)) + return true; + + } + + return false; +} + +void halbtc8723b2ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + +u8 halbtc8723b2ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8723B_2ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723B_2ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723B_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723B_2ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_HID_A2DP; + } + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723B_2ANT_COEX_ALGO_HID; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +void halbtc8723b2ant_set_fw_dac_swing_level(IN struct btc_coexist *btcoexist, + IN u8 dac_swing_lvl) +{ + u8 h2c_parameter[1] = {0}; + + /* There are several type of dacswing */ + /* 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ + h2c_parameter[0] = dac_swing_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +void halbtc8723b2ant_set_fw_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN u8 dec_bt_pwr_lvl) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = dec_bt_pwr_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +void halbtc8723b2ant_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 dec_bt_pwr_lvl) +{ + coex_dm->cur_bt_dec_pwr_lvl = dec_bt_pwr_lvl; + + if (!force_exec) { + if (coex_dm->pre_bt_dec_pwr_lvl == coex_dm->cur_bt_dec_pwr_lvl) + return; + } + halbtc8723b2ant_set_fw_dec_bt_pwr(btcoexist, + coex_dm->cur_bt_dec_pwr_lvl); + + coex_dm->pre_bt_dec_pwr_lvl = coex_dm->cur_bt_dec_pwr_lvl; +} + +void halbtc8723b2ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8723b2ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8723b2ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8723b2ant_fw_dac_swing_lvl(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 fw_dac_swing_lvl) +{ + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + + if (!force_exec) { + if (coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + halbtc8723b2ant_set_fw_dac_swing_level(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +void halbtc8723b2ant_set_sw_rf_rx_lpf_corner(IN struct btc_coexist *btcoexist, + IN boolean rx_rf_shrink_on) +{ + if (rx_rf_shrink_on) { + /* Shrink RF Rx LPF corner */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Shrink RF Rx LPF corner!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff, + 0xffffc); + } else { + /* Resume RF Rx LPF corner */ + /* After initialized, we can use coex_dm->bt_rf_0x1e_backup */ + if (btcoexist->initilized) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Resume RF Rx LPF corner!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, coex_dm->bt_rf_0x1e_backup); + } + } +} + +void halbtc8723b2ant_rf_shrink(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rx_rf_shrink_on) +{ + coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + + if (!force_exec) { + if (coex_dm->pre_rf_rx_lpf_shrink == + coex_dm->cur_rf_rx_lpf_shrink) + return; + } + halbtc8723b2ant_set_sw_rf_rx_lpf_corner(btcoexist, + coex_dm->cur_rf_rx_lpf_shrink); + + coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +void halbtc8723b2ant_set_sw_penalty_tx_rate_adaptive(IN struct btc_coexist + *btcoexist, IN boolean low_penalty_ra) +{ + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* op_code, 0x6= Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT(0); + h2c_parameter[2] = + 0x00; /* normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[3] = 0xf4; /* MCS7 or OFDM54 */ + h2c_parameter[4] = 0xf5; /* MCS6 or OFDM48 */ + h2c_parameter[5] = 0xf6; /* MCS5 or OFDM36 */ + } + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +void halbtc8723b2ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + halbtc8723b2ant_set_sw_penalty_tx_rate_adaptive(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +void halbtc8723b2ant_set_dac_swing_reg(IN struct btc_coexist *btcoexist, + IN u32 level) +{ + u8 val = (u8)level; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Write SwDacSwing = 0x%x\n", level); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x883, 0x3e, val); +} + +void halbtc8723b2ant_set_sw_full_time_dac_swing(IN struct btc_coexist + *btcoexist, IN boolean sw_dac_swing_on, IN u32 sw_dac_swing_lvl) +{ + if (sw_dac_swing_on) + halbtc8723b2ant_set_dac_swing_reg(btcoexist, sw_dac_swing_lvl); + else + halbtc8723b2ant_set_dac_swing_reg(btcoexist, 0x18); +} + + +void halbtc8723b2ant_dac_swing(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean dac_swing_on, IN u32 dac_swing_lvl) +{ + coex_dm->cur_dac_swing_on = dac_swing_on; + coex_dm->cur_dac_swing_lvl = dac_swing_lvl; + + if (!force_exec) { + if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && + (coex_dm->pre_dac_swing_lvl == + coex_dm->cur_dac_swing_lvl)) + return; + } + delay_ms(30); + halbtc8723b2ant_set_sw_full_time_dac_swing(btcoexist, dac_swing_on, + dac_swing_lvl); + + coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; + coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +void halbtc8723b2ant_set_adc_back_off(IN struct btc_coexist *btcoexist, + IN boolean adc_back_off) +{ + if (adc_back_off) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB BackOff Level On!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc05, 0x30, 0x3); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB BackOff Level Off!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc05, 0x30, 0x1); + } +} + +void halbtc8723b2ant_adc_back_off(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean adc_back_off) +{ + coex_dm->cur_adc_back_off = adc_back_off; + + if (!force_exec) { + if (coex_dm->pre_adc_back_off == coex_dm->cur_adc_back_off) + return; + } + halbtc8723b2ant_set_adc_back_off(btcoexist, coex_dm->cur_adc_back_off); + + coex_dm->pre_adc_back_off = coex_dm->cur_adc_back_off; +} + +void halbtc8723b2ant_set_agc_table(IN struct btc_coexist *btcoexist, + IN boolean agc_table_en) +{ + u8 rssi_adjust_val = 0; + + /* =================BB AGC Gain Table */ + if (agc_table_en) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB Agc Table On!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6e1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6d1B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6c1C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6b1D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6a1E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x691F0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x68200001); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB Agc Table Off!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa4200001); + } + + + /* =================RF Gain */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); + if (agc_table_en) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Agc Table On!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, + 0x38fff); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, + 0x38ffe); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Agc Table Off!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, + 0x380c3); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, + 0x28ce6); + } + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x1); + if (agc_table_en) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Agc Table On!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, 0xfffff, + 0x38fff); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, 0xfffff, + 0x38ffe); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Agc Table Off!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, 0xfffff, + 0x380c3); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, 0xfffff, + 0x28ce6); + } + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x0); + + /* set rssi_adjust_val for wifi module. */ + if (agc_table_en) + rssi_adjust_val = 8; + btcoexist->btc_set(btcoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, + &rssi_adjust_val); +} + +void halbtc8723b2ant_agc_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean agc_table_en) +{ + coex_dm->cur_agc_table_en = agc_table_en; + + if (!force_exec) { + if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en) + return; + } + halbtc8723b2ant_set_agc_table(btcoexist, agc_table_en); + + coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en; +} + +void halbtc8723b2ant_sw_mechanism1(IN struct btc_coexist *btcoexist, + IN boolean shrink_rx_lpf, IN boolean low_penalty_ra, + IN boolean limited_dig, IN boolean bt_lna_constrain) +{ + /* + u32 wifi_bw; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 != wifi_bw) + { + if (shrink_rx_lpf) + shrink_rx_lpf = false; + } + */ + + /* halbtc8723b2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); */ + halbtc8723b2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +void halbtc8723b2ant_sw_mechanism2(IN struct btc_coexist *btcoexist, + IN boolean agc_table_shift, IN boolean adc_back_off, + IN boolean sw_dac_swing, IN u32 dac_swing_lvl) +{ + /* halbtc8723b2ant_agc_table(btcoexist, NORMAL_EXEC, agc_table_shift); */ + /* halbtc8723b2ant_adc_back_off(btcoexist, NORMAL_EXEC, adc_back_off); */ + /* halbtc8723b2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing, dac_swing_lvl); */ +} + +void halbtc8723b2ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8723b2ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8723b2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8723b2ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_sta->coex_table_type = type; + + switch (type) { + case 0: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x55555555, 0xffffff, 0x3); + break; + case 1: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5afa5afa, 0xffffff, 0x3); + break; + case 2: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x5ada5ada, 0x5ada5ada, 0xffffff, 0x3); + break; + case 3: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0xaaaaaaaa, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 4: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0xffffffff, 0xffffffff, 0xffffff, 0x3); + break; + case 5: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x5fff5fff, 0x5fff5fff, 0xffffff, 0x3); + break; + case 6: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x55ff55ff, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 7: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 8: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 9: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 10: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 11: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 12: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 13: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x5fff5fff, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 14: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x5fff5fff, 0x5ada5ada, 0xffffff, 0x3); + break; + case 15: + halbtc8723b2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0xaaaaaaaa, 0xffffff, 0x3); + break; + default: + break; + } +} + +void halbtc8723b2ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT(0); /* function enable */ + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8723b2ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8723b2ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8723b2ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8723b2ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8723b2ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8723b2ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + u8 h2c_parameter[5] = {0x0, 0, 0, 48, 0}; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + /* halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); */ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + /* halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); */ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +void halbtc8723b2ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + case BTC_PS_LPS_ON: + halbtc8723b2ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8723b2ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + coex_sta->force_lps_on = true; + break; + case BTC_PS_LPS_OFF: + halbtc8723b2ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + default: + break; + } +} + + +void halbtc8723b2ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + + if ((coex_sta->a2dp_exist) && (coex_sta->hid_exist)) + byte5 = byte5 | 0x1; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + + halbtc8723b2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + } + } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + halbtc8723b2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + + } else { + halbtc8723b2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + } + + h2c_parameter[0] = byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = byte5; + + coex_dm->ps_tdma_para[0] = byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +void halbtc8723b2ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state1, bt_rssi_state; + s8 wifi_duration_adjust = 0x0; + u8 psTdmaByte4Modify = 0x0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES + - coex_dm->switch_thres_offset, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], %s turn %s PS TDMA, type=%d\n", + (force_exec ? "force to" : ""), (turn_on ? "ON" : "OFF"), type); + BTC_TRACE(trace_buf); + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + if (!(BTC_RSSI_HIGH(wifi_rssi_state1) && + BTC_RSSI_HIGH(bt_rssi_state)) && turn_on) + /* if (halbtc8723b2ant_CoexSwitchThresCheck(btcoexist) && turn_on) */ + { + type = type + 100; /* for WiFi RSSI low or BT RSSI low */ + coex_dm->is_switch_to_1dot5_ant = true; + } else + coex_dm->is_switch_to_1dot5_ant = false; + + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + + if (coex_sta->scan_ap_num <= 5) { + if (coex_sta->a2dp_bit_pool >= 45) + wifi_duration_adjust = -15; + else if (coex_sta->a2dp_bit_pool >= 35) + wifi_duration_adjust = -10; + else + wifi_duration_adjust = 5; + } else if (coex_sta->scan_ap_num <= 20) { + if (coex_sta->a2dp_bit_pool >= 45) + wifi_duration_adjust = -15; + else if (coex_sta->a2dp_bit_pool >= 35) + wifi_duration_adjust = -10; + else + wifi_duration_adjust = 0; + } else if (coex_sta->scan_ap_num <= 40) { + if (coex_sta->a2dp_bit_pool >= 45) + wifi_duration_adjust = -15; + else if (coex_sta->a2dp_bit_pool >= 35) + wifi_duration_adjust = -10; + else + wifi_duration_adjust = -5; + } else { + if (coex_sta->a2dp_bit_pool >= 45) + wifi_duration_adjust = -15; + else if (coex_sta->a2dp_bit_pool >= 35) + wifi_duration_adjust = -10; + else + wifi_duration_adjust = -10; + } + + if ((bt_link_info->slave_role == true) && (bt_link_info->a2dp_exist)) + psTdmaByte4Modify = + 0x1; /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + + + if (turn_on) { + switch (type) { + case 1: + default: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c + wifi_duration_adjust, 0x03, 0xf1, + 0x90 | psTdmaByte4Modify); + break; + case 2: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x2d + wifi_duration_adjust, 0x03, 0xf1, + 0x90 | psTdmaByte4Modify); + break; + case 3: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1c, 0x3, 0xf1, 0x90 | + psTdmaByte4Modify); + break; + case 4: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x10, 0x03, 0xf1, 0x90 | + psTdmaByte4Modify); + break; + case 5: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c + wifi_duration_adjust, 0x3, 0x70, + 0x90 | psTdmaByte4Modify); + break; + case 6: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x2d + wifi_duration_adjust, 0x3, 0x70, + 0x90 | psTdmaByte4Modify); + break; + case 7: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1c, 0x3, 0x70, 0x90 | + psTdmaByte4Modify); + break; + case 8: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xa3, + 0x10, 0x3, 0x70, 0x90 | + psTdmaByte4Modify); + break; + case 9: + /* + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c + wifi_duration_adjust, 0x03, 0xf1, + 0x90 | psTdmaByte4Modify); + */ + /* Bryant Modify for BT no-profile busy case */ + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c + wifi_duration_adjust, 0x03, 0xf1, + 0x91); + + break; + case 10: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x2d + wifi_duration_adjust, 0x03, 0xf1, + 0x90 | psTdmaByte4Modify); + break; + case 11: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1c, 0x3, 0xf1, 0x90 | + psTdmaByte4Modify); + break; + case 12: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x10, 0x3, 0xf1, 0x90 | + psTdmaByte4Modify); + break; + case 13: + /* + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c + wifi_duration_adjust, 0x3, 0x70, + 0x90 | psTdmaByte4Modify); + */ + /* Bryant Modify for BT no-profile busy case */ + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c + wifi_duration_adjust, 0x3, 0x70, + 0x91); + break; + case 14: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x2d + wifi_duration_adjust, 0x3, 0x70, + 0x90 | psTdmaByte4Modify); + break; + case 15: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1c, 0x3, 0x70, 0x90 | + psTdmaByte4Modify); + break; + case 16: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x10, 0x3, 0x70, 0x90 | + psTdmaByte4Modify); + break; + case 17: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xa3, + 0x2f, 0x2f, 0x60, 0x90); + break; + case 18: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x5, 0x5, 0xe1, 0x90); + break; + case 19: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x25, 0xe1, 0x90); + break; + case 20: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x25, 0x60, 0x90); + break; + case 21: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x15, 0x03, 0x70, 0x90); + break; + case 22: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x35, 0x03, 0xf1, 0x90); + break; + case 23: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x35, 0x03, 0x71, 0x10); + break; + + case 25: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x30, 0x03, 0x71, 0x10); + break; + + case 33: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1c, 0x3, 0xf1, 0x91); + + break; + case 71: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c + wifi_duration_adjust, 0x03, 0xf1, + 0x90); + break; + case 101: + case 105: + case 113: + case 171: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x3a + wifi_duration_adjust, 0x03, 0x70, + 0x50 | psTdmaByte4Modify); + break; + case 102: + case 106: + case 110: + case 114: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x2d + wifi_duration_adjust, 0x03, 0x70, + 0x50 | psTdmaByte4Modify); + break; + case 103: + case 107: + case 111: + case 115: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x1c, 0x03, 0x70, 0x50 | + psTdmaByte4Modify); + break; + case 104: + case 108: + case 112: + case 116: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x10, 0x03, 0x70, 0x50 | + psTdmaByte4Modify); + break; + case 109: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c, 0x03, 0xf1, 0x90 | + psTdmaByte4Modify); + break; + /* case 113: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c, 0x03, 0x70, 0x90 | + psTdmaByte4Modify); + break; */ + case 121: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x15, 0x03, 0x70, 0x90 | + psTdmaByte4Modify); + break; + case 122: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x35, 0x03, 0x71, 0x11); + break; + case 123: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x35, 0x03, 0x71, 0x10); + break; + case 125: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x30, 0x03, 0x70, 0x51); + break; + + case 133: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x1c, 0x3, 0x70, 0x51); + + break; + } + } else { + /* disable PS tdma */ + switch (type) { + case 0: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x40, 0x0); + break; + case 1: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x48, 0x0); + break; + default: + halbtc8723b2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x40, 0x0); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + + +void halbtc8723b2ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean init_hwcfg, IN boolean wifi_off) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 fw_ver = 0, u32tmp = 0, cnt_bt_cal_chk = 0; + boolean pg_ext_switch = false; + boolean use_ext_switch = false; + u8 h2c_parameter[2] = {0}; + u32 u32tmp_1[4]; + boolean is_fw_ready; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_EXT_SWITCH, &pg_ext_switch); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, + &fw_ver); /* [31:16]=fw ver, [15:0]=fw sub ver */ + + if ((fw_ver > 0 && fw_ver < 0xc0000) || pg_ext_switch) + use_ext_switch = true; + + if (init_hwcfg) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x39, 0x8, 0x1); + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x944, 0x3, 0x3); + btcoexist->btc_write_1byte(btcoexist, 0x930, 0x77); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, 0x1); + + if (fw_ver >= 0x180000) { + /* Use H2C to set GNT_BT to High to avoid A2DP click */ + h2c_parameter[0] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, + h2c_parameter); + + cnt_bt_cal_chk = 0; + while (1) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_FW_READY, &is_fw_ready); + if (is_fw_ready == false) + break; + + if (btcoexist->btc_read_1byte(btcoexist, + 0x765) == 0x18) + break; + + cnt_bt_cal_chk++; + if (cnt_bt_cal_chk > 20) + break; + } + } else + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + u32tmp_1[0] = btcoexist->btc_read_4byte(btcoexist, 0x948); + if ((u32tmp_1[0] == 0x40) || (u32tmp_1[0] == 0x240)) + btcoexist->btc_write_4byte(btcoexist, 0x948, + u32tmp_1[0]); + else + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); /* WiFi TRx Mask off */ + /* remove due to interrupt is disabled that polling c2h will fail and delay 100ms. */ + /* btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, 0x3c, 0x01); */ /*BT TRx Mask off */ + + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { + /* tell firmware "no antenna inverse" */ + h2c_parameter[0] = 0; + } else { + /* tell firmware "antenna inverse" */ + h2c_parameter[0] = 1; + } + + if (use_ext_switch) { + /* ext switch type */ + h2c_parameter[1] = 1; + } else { + /* int switch type */ + h2c_parameter[1] = 0; + } + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, h2c_parameter); + } else { + if (fw_ver >= 0x180000) { + /* Use H2C to set GNT_BT to "Control by PTA"*/ + h2c_parameter[0] = 0; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, + h2c_parameter); + + cnt_bt_cal_chk = 0; + while (1) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_FW_READY, &is_fw_ready); + if (is_fw_ready == false) + break; + + if (btcoexist->btc_read_1byte(btcoexist, + 0x765) == 0x0) + break; + + cnt_bt_cal_chk++; + if (cnt_bt_cal_chk > 20) + break; + } + } else + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x0); + } + + /* ext switch setting */ + if (use_ext_switch) { + if (init_hwcfg) { + /* 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT(23); + u32tmp |= BIT(24); + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + } + u32tmp_1[0] = btcoexist->btc_read_4byte(btcoexist, 0x948); + if ((u32tmp_1[0] == 0x40) || (u32tmp_1[0] == 0x240)) + btcoexist->btc_write_4byte(btcoexist, 0x948, + u32tmp_1[0]); + else + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + + switch (ant_pos_type) { + case BTC_ANT_WIFI_AT_MAIN: + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x1); /* ext switch main at wifi */ + break; + case BTC_ANT_WIFI_AT_AUX: + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x92c, 0x3, + 0x2); /* ext switch aux at wifi */ + break; + } + } else { /* internal switch */ + if (init_hwcfg) { + /* 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp |= BIT(23); + u32tmp &= ~BIT(24); + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + } + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, + 0x0); /* fixed external switch S1->Main, S0->Aux */ + switch (ant_pos_type) { + case BTC_ANT_WIFI_AT_MAIN: + u32tmp_1[0] = btcoexist->btc_read_4byte(btcoexist, + 0x948); + if ((u32tmp_1[0] == 0x40) || (u32tmp_1[0] == 0x240)) + btcoexist->btc_write_4byte(btcoexist, 0x948, + u32tmp_1[0]); + else + btcoexist->btc_write_4byte(btcoexist, 0x948, + 0x0); + break; + case BTC_ANT_WIFI_AT_AUX: + u32tmp_1[0] = btcoexist->btc_read_4byte(btcoexist, + 0x948); + if ((u32tmp_1[0] == 0x40) || (u32tmp_1[0] == 0x240)) + btcoexist->btc_write_4byte(btcoexist, 0x948, + u32tmp_1[0]); + else + btcoexist->btc_write_4byte(btcoexist, 0x948, + 0x280); + break; + } + } +} +#if 0 +boolean halbtc8723b2ant_CoexSwitchThresCheck(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state1, bt_rssi_state; + u32 vendor; + u8 offset = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_VENDOR, &vendor); + + /* if (vendor == BTC_VENDOR_LENOVO) */ + /* offset = 20; */ + + wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES + - coex_dm->switch_thres_offset, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + + if (BTC_RSSI_LOW(wifi_rssi_state1) || BTC_RSSI_LOW(bt_rssi_state)) + return true; + + return false; +} +#endif + + +void halbtc8723b2ant_coex_all_off(IN struct btc_coexist *btcoexist) +{ + /* fw all off */ + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + /* hw all off */ + /* btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); */ + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8723b2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723b2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); + halbtc8723b2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, 0); + + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + coex_sta->pop_event_cnt = 0; + +} + +void halbtc8723b2ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW, + prewifi_rssi_state1 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + boolean wifi_connected = false; + boolean low_pwr_disable = true; + boolean scan = false, link = false, roam = false; + boolean wifi_busy = false; + + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, 15, 0); + wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state1, 2, + BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + + if (coex_sta->bt_abnormal_scan) { + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 23); + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + } else if (scan || link || roam) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi link process + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + } else if (wifi_connected) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + if (wifi_busy) + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + else + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi no-link + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + } + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + /* + coex_dm->need_recover0x948 = true; + coex_dm->backup0x948 = btcoexist->btc_read_4byte(btcoexist, 0x948); + + halbtc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_AUX, false, false); + */ +} + + +void halbtc8723b2ant_action_wifi_link_process(IN struct btc_coexist *btcoexist) +{ + u32 u32tmp; + u8 u8tmpa, u8tmpb; + + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 15); + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x76e); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], 0x948=0x%x, 0x765=0x%x, 0x76e=0x%x\n", + u32tmp, u8tmpa, u8tmpb); + BTC_TRACE(trace_buf); +} + +boolean halbtc8723b2ant_action_wifi_idle_process(IN struct btc_coexist + *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW, + prewifi_rssi_state1 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u8 ap_num = 0; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, 15, 0); + /* wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, 1, 2, BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES-coex_dm->switch_thres_offset-coex_dm->switch_thres_offset, 0); */ + wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state1, 2, + BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset - coex_dm->switch_thres_offset, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset - coex_dm->switch_thres_offset, 0); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); + + /* define the office environment */ + if (BTC_RSSI_HIGH(wifi_rssi_state1) && + (coex_sta->hid_exist == true) && + (coex_sta->a2dp_exist == true)) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi idle process for BT HID+A2DP exist!!\n"); + BTC_TRACE(trace_buf); + + halbtc8723b2ant_dac_swing(btcoexist, NORMAL_EXEC, true, 0x6); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, + false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + return true; + } + + halbtc8723b2ant_dac_swing(btcoexist, NORMAL_EXEC, true, 0x18); + return false; +} + + + +boolean halbtc8723b2ant_is_common_action(IN struct btc_coexist *btcoexist) +{ + boolean common = false, wifi_connected = false, wifi_busy = false; + boolean bt_hs_on = false, low_pwr_disable = false; + boolean asus_8723b = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non-connected idle!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, + false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + + common = true; + } else { + if (BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, + false, false, 0x8); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + halbtc8723b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 0xb); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, + false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + common = true; + } else if (BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status) { + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + if (bt_hs_on) + return false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, + false, false, 0x8); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + halbtc8723b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 0xb); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + common = true; + } else { + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + if (wifi_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + BTC_TRACE(trace_buf); + /* btcoexist->btc_get(btcoexist, + BTC_GET_BL_IS_ASUS_8723B, &asus_8723b); + if (!asus_8723b) + common = false; + else + common = halbtc8723b2ant_action_wifi_idle_process( + btcoexist); */ + common = false; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + /* common = false; */ + common = halbtc8723b2ant_action_wifi_idle_process( + btcoexist); + } + } + } + + return common; +} +void halbtc8723b2ant_tdma_duration_adjust(IN struct btc_coexist *btcoexist, + IN boolean sco_hid, IN boolean tx_pause, IN u8 max_interval) +{ + static s32 up, dn, m, n, wait_count; + s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */ + u8 retry_count = 0; + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + { + if (sco_hid) { + if (tx_pause) { + if (max_interval == 1) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = + 13; + } else if (max_interval == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (max_interval == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } + } else { + if (max_interval == 1) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = + 9; + } else if (max_interval == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (max_interval == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } + } + } else { + if (tx_pause) { + if (max_interval == 1) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = + 5; + } else if (max_interval == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (max_interval == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } + } else { + if (max_interval == 1) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (max_interval == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (max_interval == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } + } + } + } + /* ============ */ + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /* acquire the BT TRx retry count from BT_Info byte2 */ + retry_count = coex_sta->bt_retry_cnt; + + if ((coex_sta->low_priority_tx) > 1050 || + (coex_sta->low_priority_rx) > 1250) + retry_count++; + + result = 0; + wait_count++; + + if (retry_count == + 0) { /* no retry in the last 2-second duration */ + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { /* if retry count during continuous n*2 seconds is 0, enlarge WiFi duration */ + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + } + } else if (retry_count <= + 3) { /* <=3 retry in the last 2-second duration */ + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) {/* if continuous 2 retry count(every 2 seconds) >0 and < 3, reduce WiFi duration */ + if (wait_count <= 2) + m++; /* to avoid loop between the two levels */ + else + m = 1; + + if (m >= 20) /* maximum of m = 20 ' will recheck if need to adjust wifi duration in maximum time interval 120 seconds */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + } else { /* retry count > 3, once retry count > 3, to reduce WiFi duration */ + if (wait_count == 1) + m++; /* to avoid loop between the two levels */ + else + m = 1; + + if (m >= 20) /* maximum of m = 20 ' will recheck if need to adjust wifi duration in maximum time interval 120 seconds */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + + if (max_interval == 1) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 71) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 13); + coex_dm->ps_tdma_du_adj_type = 13; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = + 5; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = + 13; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 71); + coex_dm->ps_tdma_du_adj_type = 71; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 71) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 71); + coex_dm->ps_tdma_du_adj_type = + 71; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = + 9; + } + } + } + } else if (max_interval == 2) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } + } + } + } else if (max_interval == 3) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8723b2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8723b2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } + } + } + } + } + + /* if current PsTdma not match with the recorded one (when scan, dhcp...), */ + /* then we have to adjust it back to the previous record one. */ + if (coex_dm->cur_ps_tdma != coex_dm->ps_tdma_du_adj_type) { + boolean scan = false, link = false, roam = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PsTdma type dismatch!!!, cur_ps_tdma=%d, recordPsTdma=%d\n", + coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (!scan && !link && !roam) + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->ps_tdma_du_adj_type); + else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"); + BTC_TRACE(trace_buf); + } + } +} + +/* SCO only or SCO+PAN(HS) */ +void halbtc8723b2ant_action_sco(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, 15, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_LEGACY == wifi_bw) /* for SCO quality at 11b/g mode */ + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + else /* for SCO quality & wifi performance balance at 11n mode */ + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); /* for voice quality */ + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + true, 0x4); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + true, 0x4); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + true, 0x4); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + true, 0x4); + } + } +} + + +void halbtc8723b2ant_action_hid(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 25); + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, 15, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_LEGACY == wifi_bw) /* for HID at 11b/g mode */ + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + else /* for HID quality & wifi performance balance at 11n mode */ + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 9); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + else + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +void halbtc8723b2ant_action_a2dp(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW, + prewifi_rssi_state1 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + u8 ap_num = 0; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, 15, 0); + wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state1, 2, + BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); + + /* define the office environment */ + if ((ap_num >= 10) && BTC_RSSI_HIGH(wifi_rssi_state1) && + BTC_RSSI_HIGH(bt_rssi_state)) { + /* dbg_print(" AP#>10(%d)\n", ap_num); */ + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + true, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + true, 0x18); + } + return; + + } + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + + } else { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 13); + } + + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + halbtc8723b2ant_tdma_duration_adjust(btcoexist, false, false, + 1); + else + halbtc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 1); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b2ant_action_a2dp_pan_hs(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW, + prewifi_rssi_state1 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, 15, 0); + wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state1, 2, + BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + + } else { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 13); + } + + halbtc8723b2ant_tdma_duration_adjust(btcoexist, false, true, 2); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b2ant_action_pan_edr(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW, + prewifi_rssi_state1 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, 15, 0); + wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state1, 2, + BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 10); + } else { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 13); + } + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); + else + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + + +/* PAN(HS) only */ +void halbtc8723b2ant_action_pan_hs(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW, + prewifi_rssi_state1 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, 15, 0); + wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state1, 2, + BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* PAN(EDR)+A2DP */ +void halbtc8723b2ant_action_pan_edr_a2dp(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW, + prewifi_rssi_state1 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u8 ap_num = 0; + u32 wifi_bw; + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, 15, 0); + wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state1, 2, + BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &ap_num); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 12); + + if (ap_num < 10) + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, + false, 1); + else + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, + false, 3); + + } else { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 13); + if (ap_num < 10) + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, + true, 1); + else + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, + true, 3); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b2ant_action_pan_edr_hid(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW, + prewifi_rssi_state1 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 25); + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, 15, 0); + wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state1, 2, + BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + } else { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 14); + } + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (BTC_WIFI_BW_HT40 == wifi_bw) { + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 3); + /* halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 11); */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x780); + } else { + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 6); + /* halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + } + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, false, 2); + } else { + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + /* halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 14); */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 2); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* HID+A2DP+PAN(EDR) */ +void halbtc8723b2ant_action_hid_a2dp_pan_edr(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW, + prewifi_rssi_state1 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 25); + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, 15, 0); + wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state1, 2, + BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + } else { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 14); + } + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (BTC_WIFI_BW_HT40 == wifi_bw) + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, + true, 3); + else + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, + false, 3); + } else + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, true, 3); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b2ant_action_hid_a2dp(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW, + prewifi_rssi_state1 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + u8 ap_num = 0; + + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 35); + + + wifi_rssi_state = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, 15, 0); + /* bt_rssi_state = halbtc8723b2ant_bt_rssi_state(2, 29, 0); */ + wifi_rssi_state1 = halbtc8723b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state1, 2, + BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 0); + bt_rssi_state = halbtc8723b2ant_bt_rssi_state(&pre_bt_rssi_state, 3, + BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES - + coex_dm->switch_thres_offset, 37); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &ap_num); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8723b2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, 0x5); + + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_LEGACY == wifi_bw) { + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else if (BTC_RSSI_MEDIUM(bt_rssi_state)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + } else { + /* only 802.11N mode we have to dec bt power to 4 degree */ + if (BTC_RSSI_HIGH(bt_rssi_state)) { + /* need to check ap Number of Not */ + if (ap_num < 10) + halbtc8723b2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, 4); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, 2); + } else if (BTC_RSSI_MEDIUM(bt_rssi_state)) + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + } + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + } else { + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 14); + } + + if (BTC_RSSI_HIGH(bt_rssi_state)) { + if (ap_num < 10) + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, + false, 2); + + else + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, + false, 3); + } else { + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 18); + btcoexist->btc_write_1byte(btcoexist, 0x456, 0x38); + btcoexist->btc_write_2byte(btcoexist, 0x42a, 0x0808); + btcoexist->btc_write_4byte(btcoexist, 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, 0x434, 0x01010000); + + if (ap_num < 10) + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, + true, 2); + + else + halbtc8723b2ant_tdma_duration_adjust(btcoexist, true, + true, 3); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8723b2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8723b2ant_action_bt_whck_test(IN struct btc_coexist *btcoexist) +{ + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8723b2ant_action_wifi_multi_port(IN struct btc_coexist *btcoexist) +{ + halbtc8723b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8723b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + halbtc8723b2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8723b2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + /* hw all off */ + /* btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); */ + halbtc8723b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); +} + +void halbtc8723b2ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + u32 num_of_wifi_link = 0; + u32 wifi_link_status = 0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean miracast_plus_bt = false; + boolean scan = false, link = false, roam = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->bt_whck_test) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under WHCK TEST!!!\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_action_bt_whck_test(btcoexist); + return; + } + + algorithm = halbtc8723b2ant_action_algorithm(btcoexist); + if (coex_sta->c2h_bt_inquiry_page && + (BT_8723B_2ANT_COEX_ALGO_PANHS != algorithm)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_action_bt_inquiry(btcoexist); + return; + } + + /* + if(coex_dm->need_recover0x948) + { + coex_dm->need_recover0x948 = false; + btcoexist->btc_write_4byte(btcoexist, 0x948, coex_dm->backup0x948); + } + */ + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under Link Process !!\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_action_wifi_link_process(btcoexist); + return; + } + + /* for P2P */ + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + BTC_TRACE(trace_buf); + + if (bt_link_info->bt_link_exist) + miracast_plus_bt = true; + else + miracast_plus_bt = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + halbtc8723b2ant_action_wifi_multi_port(btcoexist); + + return; + } + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + coex_dm->cur_algorithm = algorithm; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Algorithm = %d\n", + coex_dm->cur_algorithm); + BTC_TRACE(trace_buf); + + if (halbtc8723b2ant_is_common_action(btcoexist)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant common.\n"); + BTC_TRACE(trace_buf); + coex_dm->auto_tdma_adjust = false; + } else { + if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], pre_algorithm=%d, cur_algorithm=%d\n", + coex_dm->pre_algorithm, coex_dm->cur_algorithm); + BTC_TRACE(trace_buf); + coex_dm->auto_tdma_adjust = false; + } + switch (coex_dm->cur_algorithm) { + case BT_8723B_2ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_action_sco(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID.\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_action_hid(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_action_a2dp(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_action_pan_edr(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HS mode.\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_action_pan_hs(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_action_pan_edr_hid(btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_action_hid_a2dp_pan_edr( + btcoexist); + break; + case BT_8723B_2ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_action_hid_a2dp(btcoexist); + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_coex_all_off(btcoexist); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +void halbtc8723b2ant_wifi_off_hw_cfg(IN struct btc_coexist *btcoexist) +{ + boolean is_in_mp_mode = false; + u8 h2c_parameter[2] = {0}; + u32 fw_ver = 0; + + /* set wlan_act to low */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x780); /* WiFi goto standby while GNT_BT 0-->1 */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + if (fw_ver >= 0x180000) { + /* Use H2C to set GNT_BT to HIGH */ + h2c_parameter[0] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, h2c_parameter); + } else + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_IS_IN_MP_MODE, + &is_in_mp_mode); + if (!is_in_mp_mode) + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, + 0x0); /* BT select s0/s1 is controlled by BT */ + else + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, + 0x1); /* BT select s0/s1 is controlled by WiFi */ +} + +void halbtc8723b2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean back_up) +{ + u8 u8tmp = 0; + u32 vendor; + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 2Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_get(btcoexist, BTC_GET_U4_VENDOR, &vendor); + if (vendor == BTC_VENDOR_LENOVO) + coex_dm->switch_thres_offset = 0; + else if (vendor == BTC_VENDOR_ASUS) + coex_dm->switch_thres_offset = 0; + else + coex_dm->switch_thres_offset = 20; + + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = (btcoexist->btc_read_1byte(btcoexist, + 0xf1) & 0xf0) >> 4; + + /* backup rf 0x1e value */ + coex_dm->bt_rf_0x1e_backup = + btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff); + + /* 0x790[5:0]=0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + /* Antenna config */ + halbtc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, true, + false); + coex_sta->dis_ver_info_cnt = 0; + + /* PTA parameter */ + halbtc8723b2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + /* Enable counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, + 0x4); /* 0x76e[3] =1, WLAN_Act control by PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + + /* Give bt_coex_supported_version the default value */ + coex_sta->bt_coex_supported_version = 0; + +} + +/* ************************************************************ + * work around function start with wa_halbtc8723b2ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8723b2ant_ + * ************************************************************ */ +void ex_halbtc8723b2ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u16 u16tmp = 0x0; + u32 value = 0; + u32 u32tmp_1[4]; + + btcoexist->btc_write_1byte(btcoexist, 0x67, 0x20); + + /* enable BB, REG_SYS_FUNC_EN such that we can write 0x948 correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT(0) | BIT(1)); + + btcoexist->btc_write_4byte(btcoexist, 0x948, 0x0); + + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + /* set to S1 */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + } + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ANTPOSREGRISTRY_CTRL, + &value); + } +} + +void ex_halbtc8723b2ant_pre_load_firmware(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x4; /* Set BIT2 by default since it's 2ant case */ + + /* */ + /* S0 or S1 setting and Local register setting(By the setting fw can get ant number, S0/S1, ... info) */ + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + u8tmp |= 0x1; /* antenna inverse */ + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + } else { + if (board_info->single_ant_path == 1) { + /* set to S0 */ + u8tmp |= 0x1; /* antenna inverse */ + } + + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x384, + u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, + u8tmp); + } +} + +void ex_halbtc8723b2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8723b2ant_init_hw_config(btcoexist, true); +} + +void ex_halbtc8723b2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + halbtc8723b2ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8723b2ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u32 u32tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + u32 fw_ver = 0, bt_patch_ver = 0; + u32 bt_coex_ver = 0; + static u8 pop_report_in_10s = 0; + u32 phyver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "Ant PG number/ Ant mechanism:", + board_info->pg_ant_num, board_info->btdm_ant_num); + CL_PRINTF(cli_buf); + + /* btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); */ + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + bt_coex_ver = coex_sta->bt_coex_supported_version & 0xff; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8723b_2ant, glcoex_ver_8723b_2ant, + glcoex_ver_btdesired_8723b_2ant, + bt_coex_ver, + (bt_coex_ver == 0xff ? "Unknown" : + (bt_coex_ver >= glcoex_ver_btdesired_8723b_2ant ? + "Match" : "Mis-Match"))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ v%d/ %c", + "W_FW/ B_FW/ Phy/ Kt", + fw_ver, bt_patch_ver, phyver, + coex_sta->cut_version + 65); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "Wifi channel informed to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Abnormal scan", + (coex_sta->bt_abnormal_scan) ? "Yes" : "No"); + CL_PRINTF(cli_buf); + + pop_report_in_10s++; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d/ %d] ", + "BT [status/ rssi/ retryCnt/ popCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") + : ((BT_8723B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi - 100, coex_sta->bt_retry_cnt, + coex_sta->pop_event_cnt); + CL_PRINTF(cli_buf); + + if (pop_report_in_10s >= 5) { + coex_sta->pop_event_cnt = 0; + pop_report_in_10s = 0; + } + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d / %d / %d / %d / %d / %d", + "SCO/HID/PAN/A2DP/NameReq/WHQL", + bt_link_info->sco_exist, bt_link_info->hid_exist, + bt_link_info->pan_exist, bt_link_info->a2dp_exist, + coex_sta->c2h_bt_remote_name_req, + coex_sta->bt_whck_test); + CL_PRINTF(cli_buf); + + { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Role", + (bt_link_info->slave_role) ? "Slave" : "Master"); + CL_PRINTF(cli_buf); + } + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", + "A2DP Rate/Bitpool", + (bt_info_ext & BIT(0)) ? "BR" : "EDR", coex_sta->a2dp_bit_pool); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8723B_2ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8723b_2ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + /* Sw mechanism */ + if (btcoexist->manual_control) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Sw mechanism] (before Manual)============"); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Sw mechanism]============"); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "SM1[ShRf/ LpRA/ LimDig]", + coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra, + coex_dm->limited_dig); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", + "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", + coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, + coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); + CL_PRINTF(cli_buf); + + /* Fw mechanism */ + if (btcoexist->manual_control) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Fw mechanism] (before Manual) ============"); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Fw mechanism]============"); + + ps_tdma_case = coex_dm->cur_ps_tdma; + + if (coex_dm->is_switch_to_1dot5_ant) + ps_tdma_case = ps_tdma_case + 100; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (%s,%s)", + "PS TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + (coex_dm->cur_ps_tdma_on ? "On" : "Off"), + (coex_dm->auto_tdma_adjust ? "Adj" : "Fix")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "Coex Table Type", + coex_sta->coex_table_type); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "DecBtPwr/ IgnWlanAct", + coex_dm->cur_bt_dec_pwr_lvl, coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + "RF-A, 0x1e initVal", + coex_dm->bt_rf_0x1e_backup); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x880); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x778/0x880[29:25]", + u8tmp[0], (u32tmp[0] & 0x3e000000) >> 25); + CL_PRINTF(cli_buf); + + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x765); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x948/ 0x67[5] / 0x765", + u32tmp[0], ((u8tmp[0] & 0x20) >> 5), u8tmp[1]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x92c); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x930); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x944); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x92c[1:0]/ 0x930[7:0]/0x944[1:0]", + u32tmp[0] & 0x3, u32tmp[1] & 0xff, u32tmp[2] & 0x3); + CL_PRINTF(cli_buf); + + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x39); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x38[11]/0x40/0x4c[24:23]/0x64[0]", + ((u8tmp[0] & 0x8) >> 3), u8tmp[1], + ((u32tmp[0] & 0x01800000) >> 23), u8tmp[2] & 0x1); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", + u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0xc50(dig)/0x49c(null-drop)", + u32tmp[0] & 0xff, u8tmp[0]); + CL_PRINTF(cli_buf); + + fa_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_OFDM); + fa_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_CCK); + cca_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_OFDM); + cca_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_CCK); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", + cca_cck, fa_cck, cca_ofdm, fa_ofdm); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11n-agg", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11n-agg", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(high-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(low-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 1) + /* halbtc8723b2ant_monitor_bt_ctr(btcoexist); */ +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8723b2ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + halbtc8723b2ant_wifi_off_hw_cfg(btcoexist); + halbtc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + halbtc8723b2ant_coex_all_off(btcoexist); + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = false; + halbtc8723b2ant_init_hw_config(btcoexist, false); + halbtc8723b2ant_init_coex_dm(btcoexist); + halbtc8723b2ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8723b2ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8723b2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u32 u32tmp; + u8 u8tmpa, u8tmpb; + + + + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x948); + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x76e); + + if (BTC_SCAN_START == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, + false, false); + } else if (BTC_SCAN_FINISH == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], 0x948=0x%x, 0x765=0x%x, 0x76e=0x%x\n", + u32tmp, u8tmpa, u8tmpb); + BTC_TRACE(trace_buf); +} + +void ex_halbtc8723b2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + if (BTC_ASSOCIATE_START == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, + false, false); + } else if (BTC_ASSOCIATE_FINISH == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify\n"); + BTC_TRACE(trace_buf); + } +} + +void ex_halbtc8723b2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + u8 ap_num = 0; + + if (BTC_MEDIA_CONNECT == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, + false, false); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + } + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + h2c_parameter[0] = 0x1; + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else { + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &ap_num); + if (ap_num < 10) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8723b2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + if (type == BTC_PACKET_DHCP) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], DHCP Packet notify\n"); + BTC_TRACE(trace_buf); + } +} + +void ex_halbtc8723b2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + boolean bt_busy = false, limited_dig = false; + boolean wifi_connected = false; + + coex_sta->c2h_bt_info_req_sent = false; + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8723B_2ANT_MAX) + rsp_source = BT_INFO_SRC_8723B_2ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt info[%d], length=%d, hex data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), return for Manual CTRL<===\n"); + BTC_TRACE(trace_buf); + return; + } + + /* if 0xff, it means BT is under WHCK test */ + if (bt_info == 0xff) + coex_sta->bt_whck_test = true; + else + coex_sta->bt_whck_test = false; + + if (BT_INFO_SRC_8723B_2ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0] */ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rsp_source][4]; + + if (coex_sta->bt_info_c2h[rsp_source][2] & 0x20) + coex_sta->c2h_bt_remote_name_req = true; + else + coex_sta->c2h_bt_remote_name_req = false; + + if (coex_sta->bt_info_c2h[rsp_source][1] == 0x49) { + coex_sta->a2dp_bit_pool = + coex_sta->bt_info_c2h[rsp_source][6]; + } else + coex_sta->a2dp_bit_pool = 0; + + coex_sta->bt_tx_rx_mask = (coex_sta->bt_info_c2h[rsp_source][2] + & 0x40); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TX_RX_MASK, + &coex_sta->bt_tx_rx_mask); + if (coex_sta->bt_tx_rx_mask) { + /* BT into is responded by BT FW and BT RF REG 0x3C != 0x01 => Need to switch BT TRx Mask */ + /* BT TRx mask off */ + btcoexist->btc_set_bt_trx_mask(btcoexist, 0); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT TRx Mask off for BT Info Notify\n"); + BTC_TRACE(trace_buf); +#if 0 + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x01\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x3c, 0x01); +#endif + } + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + if ((coex_sta->bt_info_ext & BIT(1))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) + ex_halbtc8723b2ant_media_status_notify( + btcoexist, BTC_MEDIA_CONNECT); + else + ex_halbtc8723b2ant_media_status_notify( + btcoexist, BTC_MEDIA_DISCONNECT); + } + + if ((coex_sta->bt_info_ext & BIT(3))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, + false); + } else { + /* BT already NOT ignore Wlan active, do nothing here. */ + } +#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) + if ((coex_sta->bt_info_ext & BIT(4))) { + /* BT auto report already enabled, do nothing */ + } else + halbtc8723b2ant_bt_auto_report(btcoexist, FORCE_EXEC, + true); +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (bt_info & BT_INFO_8723B_2ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status */ + if (!(bt_info & BT_INFO_8723B_2ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8723B_2ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8723B_2ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8723B_2ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8723B_2ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + + if ((coex_sta->hid_exist == false) && + (coex_sta->c2h_bt_inquiry_page == false) && + (coex_sta->sco_exist == false)) { + if (coex_sta->high_priority_tx + + coex_sta->high_priority_rx >= 160) { + coex_sta->hid_exist = true; + bt_info = bt_info | 0x28; + } + } + } + + halbtc8723b2ant_update_bt_link_info(btcoexist); + + if (!(bt_info & BT_INFO_8723B_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info == + BT_INFO_8723B_2ANT_B_CONNECTION) { /* connection exists but no busy */ + coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + BTC_TRACE(trace_buf); + } else if ((bt_info & BT_INFO_8723B_2ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8723B_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info & BT_INFO_8723B_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + BTC_TRACE(trace_buf); + } else { + coex_dm->bt_status = BT_8723B_2ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + BTC_TRACE(trace_buf); + } + + if ((BT_8723B_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8723B_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { + bt_busy = true; + limited_dig = true; + } else { + bt_busy = false; + limited_dig = false; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + coex_dm->limited_dig = limited_dig; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + + halbtc8723b2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8723b2ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8723b2ant_wifi_off_hw_cfg(btcoexist); + /* remove due to interrupt is disabled that polling c2h will fail and delay 100ms. */ + /* btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, 0x3c, 0x15); */ /*BT goto standby while GNT_BT 1-->0 */ + halbtc8723b2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + ex_halbtc8723b2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8723b2ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Pnp notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_WIFI_PNP_SLEEP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + + /* Sinda 20150819, workaround for driver skip leave IPS/LPS to speed up sleep time. */ + /* Driver do not leave IPS/LPS when driver is going to sleep, so BTCoexistence think wifi is still under IPS/LPS */ + /* BT should clear UnderIPS/UnderLPS state to avoid mismatch state after wakeup. */ + coex_sta->under_ips = false; + coex_sta->under_lps = false; + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_init_hw_config(btcoexist, false); + halbtc8723b2ant_init_coex_dm(btcoexist); + halbtc8723b2ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8723b2ant_periodical(IN struct btc_coexist *btcoexist) +{ + u32 bt_patch_ver; + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ==========================Periodical===========================\n"); + BTC_TRACE(trace_buf); + if (coex_sta->dis_ver_info_cnt <= 5) { + coex_sta->dis_ver_info_cnt += 1; + if (coex_sta->dis_ver_info_cnt == 3) { + /* Antenna config to set 0x765 = 0x0 (GNT_BT control by PTA) after initial */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set GNT_BT control by PTA\n"); + BTC_TRACE(trace_buf); + halbtc8723b2ant_set_ant_path(btcoexist, + BTC_ANT_WIFI_AT_MAIN, false, false); + } + } + + if (((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) && (!coex_sta->bt_disabled)) + btcoexist->btc_get(btcoexist, BTC_GET_U4_SUPPORTED_VERSION, &coex_sta->bt_coex_supported_version); + + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + btcoexist->bt_info.bt_get_fw_ver = bt_patch_ver; + +#if (BT_AUTO_REPORT_ONLY_8723B_2ANT == 0) + halbtc8723b2ant_query_bt_info(btcoexist); + halbtc8723b2ant_monitor_bt_enable_disable(btcoexist); +#else + halbtc8723b2ant_monitor_bt_ctr(btcoexist); + halbtc8723b2ant_monitor_wifi_ctr(btcoexist); + + /* for some BT speaker that Hi-Pri pkt appear begore start play, this will cause HID exist */ + if ((coex_sta->high_priority_tx + coex_sta->high_priority_rx < 50) && + (bt_link_info->hid_exist == true)) + bt_link_info->hid_exist = false; + + if (halbtc8723b2ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + halbtc8723b2ant_run_coexist_mechanism(btcoexist); +#endif +} + +#endif + +#endif /* #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) */ + + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b2ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b2ant.h new file mode 100644 index 0000000..b44959c --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723b2ant.h @@ -0,0 +1,217 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8723B_SUPPORT == 1) +/* ******************************************* + * The following is for 8723B 2Ant BT Co-exist definition + * ******************************************* */ +#define BT_AUTO_REPORT_ONLY_8723B_2ANT 1 + + +#define BT_INFO_8723B_2ANT_B_FTP BIT(7) +#define BT_INFO_8723B_2ANT_B_A2DP BIT(6) +#define BT_INFO_8723B_2ANT_B_HID BIT(5) +#define BT_INFO_8723B_2ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8723B_2ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8723B_2ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8723B_2ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8723B_2ANT_B_CONNECTION BIT(0) + +#define BTC_RSSI_COEX_THRESH_TOL_8723B_2ANT 2 + + +#define BT_8723B_2ANT_WIFI_RSSI_COEXSWITCH_THRES 42 /* WiFi RSSI Threshold for 2-Ant TDMA/1-Ant PS-TDMA translation */ +#define BT_8723B_2ANT_BT_RSSI_COEXSWITCH_THRES 46 /* BT RSSI Threshold for 2-Ant TDMA/1-Ant PS-TDMA translation */ + +enum bt_info_src_8723b_2ant { + BT_INFO_SRC_8723B_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723B_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723B_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723B_2ANT_MAX +}; + +enum bt_8723b_2ant_bt_status { + BT_8723B_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723B_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8723B_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8723B_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8723B_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8723B_2ANT_BT_STATUS_MAX +}; + +enum bt_8723b_2ant_coex_algo { + BT_8723B_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723B_2ANT_COEX_ALGO_SCO = 0x1, + BT_8723B_2ANT_COEX_ALGO_HID = 0x2, + BT_8723B_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8723B_2ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8723B_2ANT_COEX_ALGO_PANEDR = 0x5, + BT_8723B_2ANT_COEX_ALGO_PANHS = 0x6, + BT_8723B_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8723B_2ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8723B_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8723B_2ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8723B_2ANT_COEX_ALGO_MAX = 0xb, +}; + +struct coex_dm_8723b_2ant { + /* fw mechanism */ + u8 pre_bt_dec_pwr_lvl; + u8 cur_bt_dec_pwr_lvl; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean reset_tdma_adjust; + boolean auto_tdma_adjust; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + + /* sw mechanism */ + boolean pre_rf_rx_lpf_shrink; + boolean cur_rf_rx_lpf_shrink; + u32 bt_rf_0x1e_backup; + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + boolean pre_dac_swing_on; + u32 pre_dac_swing_lvl; + boolean cur_dac_swing_on; + u32 cur_dac_swing_lvl; + boolean pre_adc_back_off; + boolean cur_adc_back_off; + boolean pre_agc_table_en; + boolean cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + boolean limited_dig; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + boolean need_recover0x948; + u32 backup0x948; + + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + boolean is_switch_to_1dot5_ant; + u8 switch_thres_offset; +}; + +struct coex_sta_8723b_2ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + boolean bt_abnormal_scan; + boolean under_lps; + boolean under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + boolean bt_tx_rx_mask; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + boolean c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8723B_2ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8723B_2ANT_MAX]; + boolean bt_whck_test; + boolean c2h_bt_inquiry_page; + boolean c2h_bt_remote_name_req; + u8 bt_retry_cnt; + u8 bt_info_ext; + u32 pop_event_cnt; + u8 scan_ap_num; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_vht; + + u32 bt_coex_supported_version; + + u8 coex_table_type; + boolean force_lps_on; + + u8 dis_ver_info_cnt; + + u8 a2dp_bit_pool; + u8 cut_version; +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8723b2ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8723b2ant_pre_load_firmware(IN struct btc_coexist *btcoexist); +void ex_halbtc8723b2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8723b2ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8723b2ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b2ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723b2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8723b2ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8723b2ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state); +void ex_halbtc8723b2ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8723b2ant_display_coex_info(IN struct btc_coexist *btcoexist); + +#else +#define ex_halbtc8723b2ant_power_on_setting(btcoexist) +#define ex_halbtc8723b2ant_pre_load_firmware(btcoexist) +#define ex_halbtc8723b2ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8723b2ant_init_coex_dm(btcoexist) +#define ex_halbtc8723b2ant_ips_notify(btcoexist, type) +#define ex_halbtc8723b2ant_lps_notify(btcoexist, type) +#define ex_halbtc8723b2ant_scan_notify(btcoexist, type) +#define ex_halbtc8723b2ant_connect_notify(btcoexist, type) +#define ex_halbtc8723b2ant_media_status_notify(btcoexist, type) +#define ex_halbtc8723b2ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8723b2ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8723b2ant_halt_notify(btcoexist) +#define ex_halbtc8723b2ant_pnp_notify(btcoexist, pnp_state) +#define ex_halbtc8723b2ant_periodical(btcoexist) +#define ex_halbtc8723b2ant_display_coex_info(btcoexist) + +#endif + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723bwifionly.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723bwifionly.c new file mode 100644 index 0000000..9be8d62 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723bwifionly.c @@ -0,0 +1,68 @@ +#include "mp_precomp.h" + + +VOID +ex_hal8723b_wifi_only_hw_config( + IN struct wifi_only_cfg *pwifionlycfg + ) +{ + struct wifi_only_haldata *pwifionly_haldata = &pwifionlycfg->haldata_info; + + + halwifionly_write1byte(pwifionlycfg, 0x778, 0x3); /* Set pta for wifi first priority, 0x1 need to reference pta table to determine wifi and bt priority */ + halwifionly_bitmaskwrite1byte(pwifionlycfg, 0x40, 0x20, 0x1); + + /* Set Antenna path to Wifi */ + halwifionly_write2byte(pwifionlycfg, 0x0765, 0x8); /* Set pta for wifi first priority, 0x0 need to reference pta table to determine wifi and bt priority */ + halwifionly_write2byte(pwifionlycfg, 0x076e, 0xc); + + halwifionly_write4byte(pwifionlycfg, 0x000006c0, 0xaaaaaaaa); /* pta table, 0xaaaaaaaa means wifi is higher priority than bt */ + halwifionly_write4byte(pwifionlycfg, 0x000006c4, 0xaaaaaaaa); + + halwifionly_bitmaskwrite1byte(pwifionlycfg, 0x67, 0x20, 0x1); /* BT select s0/s1 is controlled by WiFi */ + + /* 0x948 setting */ + if (pwifionlycfg->chip_interface == WIFIONLY_INTF_PCI) { + /* HP Foxconn NGFF at S0 + not sure HP pg correct or not(EEPROMBluetoothSingleAntPath), so here we just write + 0x948=0x280 for HP HW id NIC. */ + if (pwifionly_haldata->customer_id == CUSTOMER_HP_1) { + halwifionly_write4byte(pwifionlycfg, 0x948, 0x280); + halwifionly_phy_set_rf_reg(pwifionlycfg, 0, 0x1, 0xfffff, 0x0); /* WiFi TRx Mask off */ + return; + } + } + + if (pwifionly_haldata->efuse_pg_antnum == 2) { + halwifionly_write4byte(pwifionlycfg, 0x948, 0x0); + } else { + /* 3Attention !!! For 8723BU !!!! + For 8723BU single ant case: jira [USB-1237] + Because of 8723BU S1 has HW problem, we only can use S0 instead. + Whether Efuse 0xc3 [6] is 0 or 1, we should always use S0 and write 0x948 to 80/280 + + -------------------------------------------------- + BT Team : + When in Single Ant case, Reg[0x948] has two case : 0x80 or 0x200 + When in Two Ant case, Reg[0x948] has two case : 0x280 or 0x0 + Efuse 0xc3 [6] Antenna Path + 0xc3 [6] = 0 ==> S1 ==> 0x948 = 0/40/200 + 0xc3 [6] = 1 ==> S0 ==> 0x948 = 80/240/280 */ + + if (pwifionlycfg->chip_interface == WIFIONLY_INTF_USB) + halwifionly_write4byte(pwifionlycfg, 0x948, 0x80); + else { + if (pwifionly_haldata->efuse_pg_antpath == 0) + halwifionly_write4byte(pwifionlycfg, 0x948, 0x0); + else + halwifionly_write4byte(pwifionlycfg, 0x948, 0x280); + } + + } + + + /* after 8723B F-cut, TRx Mask should be set when 0x948=0x0 or 0x280 + PHY_SetRFReg(Adapter, 0, 0x1, 0xfffff, 0x780); WiFi TRx Mask on */ + halwifionly_phy_set_rf_reg(pwifionlycfg, 0, 0x1, 0xfffff, 0x0); /*WiFi TRx Mask off */ + +} diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723bwifionly.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723bwifionly.h new file mode 100644 index 0000000..0265ab3 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723bwifionly.h @@ -0,0 +1,8 @@ +#ifndef __INC_HAL8723BWIFIONLYHWCFG_H +#define __INC_HAL8723BWIFIONLYHWCFG_H + +VOID +ex_hal8723b_wifi_only_hw_config( + IN struct wifi_only_cfg *pwifionlycfg + ); +#endif diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d1ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d1ant.c new file mode 100644 index 0000000..80d4ca5 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d1ant.c @@ -0,0 +1,6225 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8723D Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8723D_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8723d_1ant glcoex_dm_8723d_1ant; +static struct coex_dm_8723d_1ant *coex_dm = &glcoex_dm_8723d_1ant; +static struct coex_sta_8723d_1ant glcoex_sta_8723d_1ant; +static struct coex_sta_8723d_1ant *coex_sta = &glcoex_sta_8723d_1ant; +static struct psdscan_sta_8723d_1ant gl_psd_scan_8723d_1ant; +static struct psdscan_sta_8723d_1ant *psd_scan = &gl_psd_scan_8723d_1ant; + + +const char *const glbt_info_src_8723d_1ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; +/* ************************************************************ + * BtCoex Version Format: + * 1. date : glcoex_ver_date_XXXXX_1ant + * 2. WifiCoexVersion : glcoex_ver_XXXX_1ant + * 3. BtCoexVersion : glcoex_ver_btdesired_XXXXX_1ant + * 4. others : glcoex_ver_XXXXXX_XXXXX_1ant + * + * Variable should be indicated IC and Antenna numbers !!! + * Please strictly follow this order and naming style !!! + * + * ************************************************************ */ +u32 glcoex_ver_date_8723d_1ant = 20161027; +u32 glcoex_ver_8723d_1ant = 0x0f; +u32 glcoex_ver_btdesired_8723d_1ant = 0x0d; + + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8723d1ant_ + * ************************************************************ */ +u8 halbtc8723d1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723D_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723D_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723D_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8723d1ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 index, IN u8 level_num, IN u8 rssi_thresh, IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723D_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723D_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723D_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8723d1ant_update_ra_mask(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 dis_rate_mask) +{ + coex_dm->cur_ra_mask = dis_rate_mask; + + if (force_exec || (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_RAMASK, + &coex_dm->cur_ra_mask); + coex_dm->pre_ra_mask = coex_dm->cur_ra_mask; +} + +void halbtc8723d1ant_auto_rate_fallback_retry(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + boolean wifi_under_b_mode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + if (wifi_under_b_mode) { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +void halbtc8723d1ant_retry_limit(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || + (coex_dm->pre_retry_limit_type != + coex_dm->cur_retry_limit_type)) { + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +void halbtc8723d1ant_ampdu_max_time(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || + (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +void halbtc8723d1ant_limited_tx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ra_mask_type, IN u8 arfr_type, + IN u8 retry_limit_type, IN u8 ampdu_time_type) +{ + switch (ra_mask_type) { + case 0: /* normal mode */ + halbtc8723d1ant_update_ra_mask(btcoexist, force_exec, + 0x0); + break; + case 1: /* disable cck 1/2 */ + halbtc8723d1ant_update_ra_mask(btcoexist, force_exec, + 0x00000003); + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ + halbtc8723d1ant_update_ra_mask(btcoexist, force_exec, + 0x0001f1f7); + break; + default: + break; + } + + halbtc8723d1ant_auto_rate_fallback_retry(btcoexist, force_exec, + arfr_type); + halbtc8723d1ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8723d1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type); +} + +void halbtc8723d1ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +void halbtc8723d1ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WL query BT info!!\n"); + BTC_TRACE(trace_buf); +} + +void halbtc8723d1ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + static u8 num_of_bt_counter_chk = 0, cnt_slave = 0, cnt_overhead = 0, + cnt_autoslot_hang = 0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + /* to avoid 0x76e[3] = 1 (WLAN_Act control by PTA) during IPS */ + /* if (! (btcoexist->btc_read_1byte(btcoexist, 0x76e) & 0x8) ) */ + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + if (BT_8723D_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + + if (coex_sta->high_priority_rx >= 15) { + if (cnt_overhead < 3) + cnt_overhead++; + + if (cnt_overhead == 3) + coex_sta->is_hiPri_rx_overhead = true; + } else { + if (cnt_overhead > 0) + cnt_overhead--; + + if (cnt_overhead == 0) + coex_sta->is_hiPri_rx_overhead = false; + } + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n", + reg_hp_rx, reg_hp_tx, reg_lp_rx, reg_lp_tx); + + BTC_TRACE(trace_buf); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + if ((coex_sta->low_priority_tx > 1150) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + + if ((coex_sta->low_priority_rx >= 1150) && + (coex_sta->low_priority_rx >= coex_sta->low_priority_tx) + && (!coex_sta->under_ips) && (!coex_sta->c2h_bt_inquiry_page) && + (coex_sta->bt_link_exist)) { + if (cnt_slave >= 2) { + bt_link_info->slave_role = true; + cnt_slave = 2; + } else + cnt_slave++; + } else { + if (cnt_slave == 0) { + bt_link_info->slave_role = false; + cnt_slave = 0; + } else + cnt_slave--; + + } + + if (coex_sta->is_tdma_btautoslot) { + if ((coex_sta->low_priority_tx >= 1300) && + (coex_sta->low_priority_rx <= 150)) { + if (cnt_autoslot_hang >= 2) { + coex_sta->is_tdma_btautoslot_hang = true; + cnt_autoslot_hang = 2; + } else + cnt_autoslot_hang++; + } else { + if (cnt_autoslot_hang == 0) { + coex_sta->is_tdma_btautoslot_hang = false; + cnt_autoslot_hang = 0; + } else + cnt_autoslot_hang--; + } + } + + if (!coex_sta->bt_disabled) { + + if ((coex_sta->high_priority_tx == 0) && + (coex_sta->high_priority_rx == 0) && + (coex_sta->low_priority_tx == 0) && + (coex_sta->low_priority_rx == 0)) { + num_of_bt_counter_chk++; + if (num_of_bt_counter_chk >= 3) { + halbtc8723d1ant_query_bt_info(btcoexist); + num_of_bt_counter_chk = 0; + } + } + } + +} + +void halbtc8723d1ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ +#if 1 + s32 wifi_rssi = 0; + boolean wifi_busy = false, wifi_under_b_mode = false, + wifi_scan = false; + boolean bt_idle = false, wl_idle = false; + static u8 cck_lock_counter = 0, wl_noisy_count0 = 0, + wl_noisy_count1 = 3, wl_noisy_count2 = 0; + u32 total_cnt, reg_val1, reg_val2, cck_cnt; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + + coex_sta->crc_ok_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_CCK); + coex_sta->crc_ok_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_LEGACY); + coex_sta->crc_ok_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_HT); + coex_sta->crc_ok_11n_vht = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_VHT); + + coex_sta->crc_err_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_CCK); + coex_sta->crc_err_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_LEGACY); + coex_sta->crc_err_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_HT); + coex_sta->crc_err_11n_vht = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_VHT); + + cck_cnt = coex_sta->crc_ok_cck + coex_sta->crc_err_cck; + + if (cck_cnt > 250) { + if (wl_noisy_count2 < 3) + wl_noisy_count2++; + + if (wl_noisy_count2 == 3) { + wl_noisy_count0 = 0; + wl_noisy_count1 = 0; + } + } else if (cck_cnt < 50) { + if (wl_noisy_count0 < 3) + wl_noisy_count0++; + + if (wl_noisy_count0 == 3) { + wl_noisy_count1 = 0; + wl_noisy_count2 = 0; + } + } else { + if (wl_noisy_count1 < 3) + wl_noisy_count1++; + + if (wl_noisy_count1 == 3) { + wl_noisy_count0 = 0; + wl_noisy_count2 = 0; + } + } + + if (wl_noisy_count2 == 3) + coex_sta->wl_noisy_level = 2; + else if (wl_noisy_count1 == 3) + coex_sta->wl_noisy_level = 1; + else + coex_sta->wl_noisy_level = 0; + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + total_cnt = coex_sta->crc_ok_cck + coex_sta->crc_ok_11g + + coex_sta->crc_ok_11n + coex_sta->crc_ok_11n_vht; + + if ((coex_dm->bt_status == BT_8723D_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == BT_8723D_1ANT_BT_STATUS_ACL_SCO_BUSY) || + (coex_dm->bt_status == BT_8723D_1ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > (total_cnt - + coex_sta->crc_ok_cck)) { + if (cck_lock_counter < 3) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + + if (cck_lock_counter >= 3) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + if (coex_sta->cck_lock) + coex_sta->cck_ever_lock = true; + + coex_sta->pre_ccklock = coex_sta->cck_lock; + +#endif +} + + + +boolean halbtc8723d1ant_is_wifibt_status_changed(IN struct btc_coexist + *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false, pre_bt_off = false, pre_bt_slave = false; + static u8 pre_hid_busy_num = 0, pre_wl_noisy_level = 0; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (coex_sta->bt_disabled != pre_bt_off) { + pre_bt_off = coex_sta->bt_disabled; + + if (coex_sta->bt_disabled) + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!\n"); + else + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is enabled !!\n"); + + BTC_TRACE(trace_buf); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->bt_reg_vendor_ac = 0xffff; + coex_sta->bt_reg_vendor_ae = 0xffff; + return true; + } + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + if (coex_sta->wl_noisy_level != pre_wl_noisy_level) { + pre_wl_noisy_level = coex_sta->wl_noisy_level; + return true; + } + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->hid_busy_num != pre_hid_busy_num) { + pre_hid_busy_num = coex_sta->hid_busy_num; + return true; + } + } + + if (bt_link_info->slave_role != pre_bt_slave) { + pre_bt_slave = bt_link_info->slave_role; + return true; + } + + return false; +} + +void halbtc8723d1ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + boolean bt_busy = false; + + + coex_sta->num_of_profile = 0; + + /* set link exist status */ + if (!(coex_sta->bt_info & BT_INFO_8723D_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (coex_sta->bt_info & BT_INFO_8723D_1ANT_B_FTP) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->pan_exist = false; + + if (coex_sta->bt_info & BT_INFO_8723D_1ANT_B_A2DP) { + coex_sta->a2dp_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->a2dp_exist = false; + + if (coex_sta->bt_info & BT_INFO_8723D_1ANT_B_HID) { + coex_sta->hid_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->hid_exist = false; + + if (coex_sta->bt_info & BT_INFO_8723D_1ANT_B_SCO_ESCO) { + coex_sta->sco_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->sco_exist = false; + + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + bt_link_info->acl_busy = coex_sta->acl_busy; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; + + if (coex_sta->bt_info & BT_INFO_8723D_1ANT_B_INQ_PAGE) { + coex_dm->bt_status = BT_8723D_1ANT_BT_STATUS_INQ_PAGE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Inq/page!!!\n"); + } else if (!(coex_sta->bt_info & BT_INFO_8723D_1ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8723D_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + } else if (coex_sta->bt_info == BT_INFO_8723D_1ANT_B_CONNECTION) { + /* connection exists but no busy */ + coex_dm->bt_status = BT_8723D_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if (((coex_sta->bt_info & BT_INFO_8723D_1ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8723D_1ANT_B_SCO_BUSY)) && + (coex_sta->bt_info & BT_INFO_8723D_1ANT_B_ACL_BUSY)) { + coex_dm->bt_status = BT_8723D_1ANT_BT_STATUS_ACL_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL SCO busy!!!\n"); + } else if ((coex_sta->bt_info & BT_INFO_8723D_1ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8723D_1ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8723D_1ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (coex_sta->bt_info & BT_INFO_8723D_1ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8723D_1ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8723D_1ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + } + + BTC_TRACE(trace_buf); + + if ((BT_8723D_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8723D_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723D_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); +} + + +void halbtc8723d1ant_update_wifi_channel_info(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + h2c_parameter[0] = + 0x1; /* enable BT AFH skip WL channel for 8723d because BT Rx LO interference */ + /* h2c_parameter[0] = 0x0; */ + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); + +} + +u8 halbtc8723d1ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8723D_1ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_1ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_1ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_1ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_1ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_1ANT_COEX_ALGO_SCO; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_1ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_1ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +void halbtc8723d1ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8723d1ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8723d1ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8723d1ant_set_fw_low_penalty_ra(IN struct btc_coexist + *btcoexist, IN boolean low_penalty_ra) +{ +#if 1 + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* op_code, 0x6= Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT(0); + h2c_parameter[2] = + 0x00; /* normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[3] = 0xf7; /* MCS7 or OFDM54 */ + h2c_parameter[4] = 0xf8; /* MCS6 or OFDM48 */ + h2c_parameter[5] = 0xf9; /* MCS5 or OFDM36 */ + } + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +#endif +} + +void halbtc8723d1ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ +#if 1 + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + + halbtc8723d1ant_set_fw_low_penalty_ra(btcoexist, + coex_dm->cur_low_penalty_ra); + +#if 0 + if (low_penalty_ra) + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 15); + else + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 0); +#endif + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; + +#endif + +} + +void halbtc8723d1ant_write_score_board( + IN struct btc_coexist *btcoexist, + IN u16 bitpos, + IN boolean state +) +{ + + static u16 originalval = 0x8002; + + if (state) + originalval = originalval | bitpos; + else + originalval = originalval & (~bitpos); + + + btcoexist->btc_write_2byte(btcoexist, 0xaa, originalval); + +} + +void halbtc8723d1ant_read_score_board( + IN struct btc_coexist *btcoexist, + IN u16 *score_board_val +) +{ + + *score_board_val = (btcoexist->btc_read_2byte(btcoexist, + 0xaa)) & 0x7fff; +} + +void halbtc8723d1ant_post_state_to_bt( + IN struct btc_coexist *btcoexist, + IN u16 type, + IN boolean state +) +{ + halbtc8723d1ant_write_score_board(btcoexist, (u16) type, state); +} + +void halbtc8723d1ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false; + u16 u16tmp; + + /* This function check if bt is disabled */ +#if 0 + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + + +#else + + /* Read BT on/off status from scoreboard[1], enable this only if BT patch support this feature */ + halbtc8723d1ant_read_score_board(btcoexist, &u16tmp); + + bt_active = u16tmp & BIT(1); + + +#endif + + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } else { + + bt_disable_cnt++; + if (bt_disable_cnt >= 2) { + bt_disabled = true; + bt_disable_cnt = 2; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } + + if (bt_disabled) + halbtc8723d1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + else + halbtc8723d1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, true); + + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + coex_sta->bt_disabled = bt_disabled; + } + +} + + + +void halbtc8723d1ant_enable_gnt_to_gpio(IN struct btc_coexist *btcoexist, + boolean isenable) +{ +#if BT_8723D_1ANT_COEX_DBG + if (isenable) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x1); + + /* enable GNT_BT to GPIO debug */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x40, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x1, 0x0); + + /* 0x48[20] = 0 for GPIO14 = GNT_WL*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4a, 0x10, 0x0); + /* 0x40[17] = 0 for GPIO14 = GNT_WL*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x42, 0x02, 0x0); + + /* 0x66[9] = 0 for GPIO15 = GNT_B T*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x02, 0x0); + /* 0x66[7] = 0 + for GPIO15 = GNT_BT*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, 0x80, 0x0); + /* 0x8[8] = 0 for GPIO15 = GNT_BT*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x9, 0x1, 0x0); + + /* BT Vendor Reg 0x76[0] = 0 for GPIO15 = GNT_BT, this is not set here*/ + } else { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x0); + + /* Disable GNT_BT debug to GPIO, and enable chip_wakeup_host */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x40, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x1, 0x1); + + /* 0x48[20] = 0 for GPIO14 = GNT_WL*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4a, 0x10, 0x1); + } + +#endif +} + +u32 halbtc8723d1ant_ltecoex_indirect_read_reg(IN struct btc_coexist *btcoexist, + IN u16 reg_addr) +{ + u32 j = 0; + + + /* wait for ready bit before access 0x7c0 */ + btcoexist->btc_write_4byte(btcoexist, 0x7c0, 0x800F0000 | reg_addr); + + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x7c3)&BIT(5)) == 0) && + (j < BT_8723D_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + return btcoexist->btc_read_4byte(btcoexist, + 0x7c8); /* get read data */ + +} + +void halbtc8723d1ant_ltecoex_indirect_write_reg(IN struct btc_coexist + *btcoexist, + IN u16 reg_addr, IN u32 bit_mask, IN u32 reg_value) +{ + u32 val, i = 0, j = 0, bitpos = 0; + + + if (bit_mask == 0x0) + return; + if (bit_mask == 0xffffffff) { + btcoexist->btc_write_4byte(btcoexist, 0x7c4, + reg_value); /* put write data */ + + /* wait for ready bit before access 0x7c0 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x7c3)&BIT(5)) == 0) && + (j < BT_8723D_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + btcoexist->btc_write_4byte(btcoexist, 0x7c0, + 0xc00F0000 | reg_addr); + } else { + for (i = 0; i <= 31; i++) { + if (((bit_mask >> i) & 0x1) == 0x1) { + bitpos = i; + break; + } + } + + /* read back register value before write */ + val = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, + reg_addr); + val = (val & (~bit_mask)) | (reg_value << bitpos); + + btcoexist->btc_write_4byte(btcoexist, 0x7c4, + val); /* put write data */ + + /* wait for ready bit before access 0x7c0 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x7c3)&BIT(5)) == 0) && + (j < BT_8723D_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + btcoexist->btc_write_4byte(btcoexist, 0x7c0, + 0xc00F0000 | reg_addr); + + } + +} + +void halbtc8723d1ant_ltecoex_enable(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 val; + + val = (enable) ? 1 : 0; + halbtc8723d1ant_ltecoex_indirect_write_reg(btcoexist, 0x38, 0x80, + val); /* 0x38[7] */ + +} + +void halbtc8723d1ant_ltecoex_pathcontrol_owner(IN struct btc_coexist *btcoexist, + IN boolean wifi_control) +{ + u8 val; + + val = (wifi_control) ? 1 : 0; + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x4, + val); /* 0x70[26] */ + +} + +void halbtc8723d1ant_ltecoex_set_gnt_bt(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, val_orig = 0; + + if (!sw_control) + val = 0x0; + else if (state & 0x1) + val = 0x3; + else + val = 0x1; + + val_orig = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + + switch (control_block) { + case BT_8723D_1ANT_GNT_BLOCK_RFC_BB: + default: + val = ((val << 14) | (val << 10)) | (val_orig & 0xffff33ff); + break; + case BT_8723D_1ANT_GNT_BLOCK_RFC: + val = (val << 14) | (val_orig & 0xffff3fff); + break; + case BT_8723D_1ANT_GNT_BLOCK_BB: + val = (val << 10) | (val_orig & 0xfffff3ff); + break; + } + + halbtc8723d1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, 0xffffffff, val); +} + + +void halbtc8723d1ant_ltecoex_set_gnt_wl(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, val_orig = 0; + + if (!sw_control) + val = 0x0; + else if (state & 0x1) + val = 0x3; + else + val = 0x1; + + val_orig = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + + switch (control_block) { + case BT_8723D_1ANT_GNT_BLOCK_RFC_BB: + default: + val = ((val << 12) | (val << 8)) | (val_orig & 0xffffccff); + break; + case BT_8723D_1ANT_GNT_BLOCK_RFC: + val = (val << 12) | (val_orig & 0xffffcfff); + break; + case BT_8723D_1ANT_GNT_BLOCK_BB: + val = (val << 8) | (val_orig & 0xfffffcff); + break; + } + + halbtc8723d1ant_ltecoex_indirect_write_reg(btcoexist, 0x38, + 0xffffffff, val); +} + + +void halbtc8723d1ant_ltecoex_set_coex_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u16 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8723D_1ANT_CTT_WL_VS_LTE: + reg_addr = 0xa0; + break; + case BT_8723D_1ANT_CTT_BT_VS_LTE: + reg_addr = 0xa4; + break; + } + + if (reg_addr != 0x0000) + halbtc8723d1ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xffff, table_content); /* 0xa0[15:0] or 0xa4[15:0] */ + + +} + + +void halbtc8723d1ant_ltecoex_set_break_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u8 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8723D_1ANT_LBTT_WL_BREAK_LTE: + reg_addr = 0xa8; + break; + case BT_8723D_1ANT_LBTT_BT_BREAK_LTE: + reg_addr = 0xac; + break; + case BT_8723D_1ANT_LBTT_LTE_BREAK_WL: + reg_addr = 0xb0; + break; + case BT_8723D_1ANT_LBTT_LTE_BREAK_BT: + reg_addr = 0xb4; + break; + } + + if (reg_addr != 0x0000) + halbtc8723d1ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xff, table_content); /* 0xa8[15:0] or 0xb4[15:0] */ + +} + +void halbtc8723d1ant_set_wltoggle_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 interval, + IN u8 val0x6c4_b0, IN u8 val0x6c4_b1, IN u8 val0x6c4_b2, + IN u8 val0x6c4_b3) +{ + static u8 pre_h2c_parameter[6] = {0}; + u8 cur_h2c_parameter[6] = {0}; + u8 i, match_cnt = 0; + + cur_h2c_parameter[0] = 0x7; /* op_code, 0x7= wlan toggle slot*/ + + cur_h2c_parameter[1] = interval; + cur_h2c_parameter[2] = val0x6c4_b0; + cur_h2c_parameter[3] = val0x6c4_b1; + cur_h2c_parameter[4] = val0x6c4_b2; + cur_h2c_parameter[5] = val0x6c4_b3; + + if (!force_exec) { + for (i = 1; i <= 5; i++) { + if (cur_h2c_parameter[i] != pre_h2c_parameter[i]) + break; + + match_cnt++; + } + + if (match_cnt == 5) + return; + } + + for (i = 1; i <= 5; i++) + pre_h2c_parameter[i] = cur_h2c_parameter[i]; + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, cur_h2c_parameter); +} + + +void halbtc8723d1ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8723d1ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + + halbtc8723d1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8723d1ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + u32 break_table; + u8 select_table; + + coex_sta->coex_table_type = type; + + if (coex_sta->concurrent_rx_mode_on == true) { + break_table = 0xf0ffffff; /* set WL hi-pri can break BT */ + select_table = + 0xb; /* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */ + } else { + break_table = 0xffffff; + select_table = 0x3; + } + + switch (type) { + case 0: + halbtc8723d1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x55555555, break_table, + select_table); + break; + case 1: + halbtc8723d1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, break_table, + select_table); + break; + case 2: + halbtc8723d1ant_coex_table(btcoexist, force_exec, + 0xaa5a5a5a, 0xaa5a5a5a, break_table, + select_table); + break; + case 3: + halbtc8723d1ant_coex_table(btcoexist, force_exec, + 0xaa555555, 0xaa5a5a5a, break_table, + select_table); + break; + case 4: + halbtc8723d1ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0x5a5a5a5a, break_table, + select_table); + break; + case 5: + halbtc8723d1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5a5a5a5a, break_table, + select_table); + break; + case 6: + halbtc8723d1ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0x5a5a5a5a, break_table, + select_table); + break; + case 7: + halbtc8723d1ant_coex_table(btcoexist, force_exec, + 0xaaaaaaaa, 0xaaaaaaaa, break_table, + select_table); + break; + case 8: + halbtc8723d1ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0xaaaaaaaa, break_table, + select_table); + break; + case 9: + halbtc8723d1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0xaaaa5aaa, break_table, + select_table); + break; + default: + break; + } +} + +void halbtc8723d1ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) { + h2c_parameter[0] |= BIT(0); /* function enable */ + } + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8723d1ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8723d1ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8723d1ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8723d1ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8723d1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8723d1ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + u8 h2c_parameter[5] = {0x8, 0, 0, 0, 0}; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + /*halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); */ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + /*halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8);*/ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +void halbtc8723d1ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + coex_sta->force_lps_on = false; + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + + break; + case BTC_PS_LPS_ON: + coex_sta->force_lps_on = true; + halbtc8723d1ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8723d1ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + + break; + case BTC_PS_LPS_OFF: + coex_sta->force_lps_on = false; + halbtc8723d1ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + + break; + default: + break; + } +} + + +void halbtc8723d1ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + if (byte5 & BIT(2)) + coex_sta->is_tdma_btautoslot = true; + else + coex_sta->is_tdma_btautoslot = false; + + /* release bt-auto slot for auto-slot hang is detected!! */ + if (coex_sta->is_tdma_btautoslot) + if ((coex_sta->is_tdma_btautoslot_hang) || + (bt_link_info->slave_role)) + byte5 = byte5 & 0xfb; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], FW for AP mode\n"); + BTC_TRACE(trace_buf); + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + + halbtc8723d1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + } + } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + + halbtc8723d1ant_power_save_state( + btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } else { + halbtc8723d1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, + 0x0); + } + + + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + + +void halbtc8723d1ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + struct btc_board_info *board_info = &btcoexist->board_info; + boolean wifi_busy = false; + static u8 psTdmaByte4Modify = 0x0, pre_psTdmaByte4Modify = 0x0; + static boolean pre_wifi_busy = false; + + +#if BT_8723D_1ANT_ANTDET_ENABLE + + if (board_info->btdm_ant_num_by_ant_det == 2) { +#if 0 + if (turn_on) + type = type + + 100; +#endif + } + +#endif + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (wifi_busy != pre_wifi_busy) { + force_exec = true; + pre_wifi_busy = wifi_busy; + } + + /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + if ((bt_link_info->slave_role) && (bt_link_info->a2dp_exist)) + psTdmaByte4Modify = 0x1; + else + psTdmaByte4Modify = 0x0; + + if (pre_psTdmaByte4Modify != psTdmaByte4Modify) { + + force_exec = true; + pre_psTdmaByte4Modify = psTdmaByte4Modify; + } + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + + if (coex_dm->cur_ps_tdma_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(off, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } + + + if (turn_on) { + switch (type) { + default: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x35, 0x03, 0x11, 0x11); + break; + case 3: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x51, 0x3a, 0x03, 0x10, 0x50); + break; + case 4: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x51, 0x21, 0x03, 0x10, 0x50); + break; + case 5: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x15, 0x03, 0x11, 0x11); + break; + case 6: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x20, 0x03, 0x11, 0x11); + break; + case 7: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x51, 0x10, 0x03, 0x10, 0x54 | + psTdmaByte4Modify); + break; + case 8: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x51, 0x10, 0x03, 0x10, 0x54 | + psTdmaByte4Modify); + break; + case 9: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x55, 0x10, 0x03, 0x10, 0x54 | + psTdmaByte4Modify); + break; + case 10: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x30, 0x03, 0x11, 0x10); + break; + case 11: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x65, 0x25, 0x03, 0x11, 0x11 | + psTdmaByte4Modify); + break; + case 12: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x55, 0x30, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 13: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x51, 0x25, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 14: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x51, 0x15, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 15: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x51, 0x20, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 16: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x10, 0x03, 0x11, 0x15 | + psTdmaByte4Modify); + break; + case 17: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x10, 0x03, 0x11, 0x14); + break; + case 18: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x51, 0x30, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 19: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x15, 0x03, 0x11, 0x10); + break; + case 20: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x30, 0x03, 0x11, 0x10); + break; + case 21: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x30, 0x03, 0x11, 0x10); + break; + case 22: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x25, 0x03, 0x11, 0x10); + break; + case 23: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x10, 0x03, 0x11, 0x10); + break; + case 32: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x35, 0x03, 0x11, 0x11); + break; + case 33: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x35, 0x03, 0x11, 0x10); + break; + case 57: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x51, 0x10, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 58: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x51, 0x10, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 67: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0x61, 0x10, 0x03, 0x11, 0x10 | + psTdmaByte4Modify); + break; + /* 1-Ant to 2-Ant TDMA case */ + case 103: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x3a, 0x03, 0x70, 0x10); + break; + case 104: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x21, 0x03, 0x70, 0x10); + break; + case 105: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x15, 0x03, 0x71, 0x11); + break; + case 106: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x20, 0x03, 0x71, 0x11); + break; + case 107: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x10, 0x03, 0x70, 0x14 | + psTdmaByte4Modify); + break; + case 108: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x10, 0x03, 0x70, 0x14 | + psTdmaByte4Modify); + break; + case 113: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x25, 0x03, 0x70, 0x10 | + psTdmaByte4Modify); + break; + case 114: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x15, 0x03, 0x70, 0x10 | + psTdmaByte4Modify); + break; + case 115: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x20, 0x03, 0x70, 0x10 | + psTdmaByte4Modify); + break; + case 117: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x10, 0x03, 0x71, 0x14 | + psTdmaByte4Modify); + break; + case 119: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x15, 0x03, 0x71, 0x10); + break; + case 120: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x30, 0x03, 0x71, 0x10); + break; + case 121: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x30, 0x03, 0x71, 0x10); + break; + case 122: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x25, 0x03, 0x71, 0x10); + break; + case 132: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x35, 0x03, 0x71, 0x11); + break; + case 133: + halbtc8723d1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x35, 0x03, 0x71, 0x10); + break; + } + } else { + + /* disable PS tdma */ + switch (type) { + case 8: /* PTA Control */ + halbtc8723d1ant_set_fw_pstdma(btcoexist, 0x8, + 0x0, 0x0, 0x0, 0x0); + break; + case 0: + default: /* Software control, Antenna at BT side */ + halbtc8723d1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x0, 0x0); + break; + case 1: /* 2-Ant, 0x778=3, antenna control by antenna diversity */ + halbtc8723d1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x48, 0x0); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + + +void halbtc8723d1ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean force_exec, + IN u8 phase) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 cnt_bt_cal_chk = 0; + boolean is_in_mp_mode = false, is_hw_ant_div_on = false; + u8 u8tmp0 = 0, u8tmp1 = 0; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + u16 u16tmp0, u16tmp1 = 0; + +#if BT_8723D_1ANT_ANTDET_ENABLE + + if (ant_pos_type == BTC_ANT_PATH_PTA) { + if ((board_info->btdm_ant_det_finish) && + (board_info->btdm_ant_num_by_ant_det == 2)) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = BTC_ANT_PATH_WIFI; + else + ant_pos_type = BTC_ANT_PATH_BT; + } + } + +#endif + + u32tmp1 = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + + /* To avoid indirect access fail */ + if (((u32tmp1 & 0xf000) >> 12) != ((u32tmp1 & 0x0f00) >> 8)) { + force_exec = true; + coex_sta->gnt_error_cnt++; + } + +#if BT_8723D_1ANT_COEX_DBG + u32tmp2 = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u16tmp0 = btcoexist->btc_read_2byte(btcoexist, 0xaa); + u16tmp1 = btcoexist->btc_read_2byte(btcoexist, 0x948); + u8tmp1 = btcoexist->btc_read_1byte(btcoexist, 0x73); + u8tmp0 = btcoexist->btc_read_1byte(btcoexist, 0x67); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** 0x67 = 0x%x, 0x948 = 0x%x, 0x73 = 0x%x(Before Set Ant Pat)\n", + u8tmp0, u16tmp1, u8tmp1); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], **********0x38= 0x%x, 0x54= 0x%x, 0xaa = 0x%x(Before Set Ant Path)\n", + u32tmp1, u32tmp2, u16tmp0); + BTC_TRACE(trace_buf); +#endif + + coex_dm->cur_ant_pos_type = ant_pos_type; + + if (!force_exec) { + if (coex_dm->cur_ant_pos_type == coex_dm->pre_ant_pos_type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** Skip Antenna Path Setup because no change!!**********\n"); + BTC_TRACE(trace_buf); + return; + } + } + + coex_dm->pre_ant_pos_type = coex_dm->cur_ant_pos_type; + + + switch (phase) { + case BT_8723D_1ANT_PHASE_COEX_POWERON: + /* Set Path control to WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x80, 0x0); + + /* set Path control owner to WL at initial step */ + halbtc8723d1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8723D_1ANT_PCO_BTSIDE); + + /* set GNT_BT to SW high */ + halbtc8723d1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8723D_1ANT_GNT_BLOCK_RFC_BB, + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_1ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW low */ + halbtc8723d1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8723D_1ANT_GNT_BLOCK_RFC_BB, + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_1ANT_SIG_STA_SET_TO_HIGH); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + coex_sta->run_time_state = false; + + break; + case BT_8723D_1ANT_PHASE_COEX_INIT: + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8723d1ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8723d1ant_ltecoex_set_coex_table(btcoexist, + BT_8723D_1ANT_CTT_WL_VS_LTE, 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8723d1ant_ltecoex_set_coex_table(btcoexist, + BT_8723D_1ANT_CTT_BT_VS_LTE, 0xffff); + + /* Wait If BT IQK running, because Path control owner is at BT during BT IQK (setup by WiFi firmware) */ + while (cnt_bt_cal_chk <= 20) { + u8tmp0 = btcoexist->btc_read_1byte(btcoexist, + 0x49d); + cnt_bt_cal_chk++; + if (u8tmp0 & BIT(0)) { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ########### BT is calibrating (wait cnt=%d) ###########\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + delay_ms(50); + } else { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ********** WL is NOT calibrating (wait cnt=%d)**********\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + break; + } + } + + /* Set Path control to WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x80, 0x1); + + /* set Path control owner to WL at initial step */ + halbtc8723d1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8723D_1ANT_PCO_WLSIDE); + + /* set GNT_BT to SW high */ + halbtc8723d1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8723D_1ANT_GNT_BLOCK_RFC_BB, + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_1ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW low */ + halbtc8723d1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8723D_1ANT_GNT_BLOCK_RFC_BB, + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_1ANT_SIG_STA_SET_TO_HIGH); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + coex_sta->run_time_state = false; + break; + case BT_8723D_1ANT_PHASE_WLANONLY_INIT: + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8723d1ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8723d1ant_ltecoex_set_coex_table(btcoexist, + BT_8723D_1ANT_CTT_WL_VS_LTE, 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8723d1ant_ltecoex_set_coex_table(btcoexist, + BT_8723D_1ANT_CTT_BT_VS_LTE, 0xffff); + + /* Set Path control to WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x80, 0x1); + + /* set Path control owner to WL at initial step */ + halbtc8723d1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8723D_1ANT_PCO_WLSIDE); + + /* set GNT_BT to SW low */ + halbtc8723d1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8723D_1ANT_GNT_BLOCK_RFC_BB, + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_1ANT_SIG_STA_SET_TO_LOW); + /* Set GNT_WL to SW high */ + halbtc8723d1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8723D_1ANT_GNT_BLOCK_RFC_BB, + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_1ANT_SIG_STA_SET_TO_HIGH); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_WIFI; + + coex_sta->run_time_state = false; + break; + case BT_8723D_1ANT_PHASE_WLAN_OFF: + /* Disable LTE Coex Function in WiFi side */ + halbtc8723d1ant_ltecoex_enable(btcoexist, 0x0); + + /* Set Path control to BT */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x80, 0x0); + + /* set Path control owner to BT */ + halbtc8723d1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8723D_1ANT_PCO_BTSIDE); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + coex_sta->run_time_state = false; + break; + case BT_8723D_1ANT_PHASE_2G_RUNTIME: + + /* wait for WL/BT IQK finish, keep 0x38 = 0xff00 for WL IQK */ + while (cnt_bt_cal_chk <= 20) { + u8tmp0 = btcoexist->btc_read_1byte(btcoexist, + 0x1e6); + + u8tmp1 = btcoexist->btc_read_1byte(btcoexist, + 0x49d); + + cnt_bt_cal_chk++; + if ((u8tmp0 & BIT(0)) || (u8tmp1 & BIT(0))) { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ########### WL or BT is IQK (wait cnt=%d)\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + delay_ms(50); + } else { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ********** WL and BT is NOT IQK (wait cnt=%d)\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + break; + } + } + + + /* Set Path control to WL */ + /* btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x80, 0x1); */ + + halbtc8723d1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8723D_1ANT_PCO_WLSIDE); + + /* set GNT_BT to PTA */ + halbtc8723d1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8723D_1ANT_GNT_BLOCK_RFC_BB, + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8723D_1ANT_SIG_STA_SET_BY_HW); + /* Set GNT_WL to PTA */ + halbtc8723d1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8723D_1ANT_GNT_BLOCK_RFC_BB, + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8723D_1ANT_SIG_STA_SET_BY_HW); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_PTA; + + coex_sta->run_time_state = true; + break; + case BT_8723D_1ANT_PHASE_BTMPMODE: + halbtc8723d1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8723D_1ANT_PCO_WLSIDE); + + /* Set Path control to WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x80, 0x1); + + /* set GNT_BT to high */ + halbtc8723d1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8723D_1ANT_GNT_BLOCK_RFC_BB, + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_1ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to low */ + halbtc8723d1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8723D_1ANT_GNT_BLOCK_RFC_BB, + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_1ANT_SIG_STA_SET_TO_LOW); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + coex_sta->run_time_state = false; + break; + case BT_8723D_1ANT_PHASE_ANTENNA_DET: + halbtc8723d1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8723D_1ANT_PCO_WLSIDE); + + /* Set Path control to WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x80, 0x1); + + /* set GNT_BT to high */ + halbtc8723d1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8723D_1ANT_GNT_BLOCK_RFC_BB, + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_1ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to high */ + halbtc8723d1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8723D_1ANT_GNT_BLOCK_RFC_BB, + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_1ANT_SIG_STA_SET_TO_HIGH); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + coex_sta->run_time_state = false; + + break; + } + + + is_hw_ant_div_on = board_info->ant_div_cfg; + + if ((is_hw_ant_div_on) && (phase != BT_8723D_1ANT_PHASE_ANTENNA_DET)) + + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) + /* 0x948 = 0x200, 0x0 while antenna diversity */ + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x100); + else /* 0x948 = 0x80, 0x0 while antenna diversity */ + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x40); + + else if ((is_hw_ant_div_on == false) && + (phase != BT_8723D_1ANT_PHASE_WLAN_OFF)) { /* internal switch setting */ + + switch (ant_pos_type) { + + case BTC_ANT_PATH_WIFI: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + + btcoexist->btc_write_2byte( + btcoexist, 0x948, 0x0); + else + btcoexist->btc_write_2byte( + btcoexist, 0x948, 0x280); + + break; + case BTC_ANT_PATH_BT: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + + btcoexist->btc_write_2byte( + btcoexist, 0x948, 0x280); + else + btcoexist->btc_write_2byte( + btcoexist, 0x948, 0x0); + + break; + default: + case BTC_ANT_PATH_PTA: + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_2byte( + btcoexist, 0x948, + 0x200); + else + btcoexist->btc_write_2byte( + btcoexist, 0x948, 0x80); + break; + } + } + + +#if BT_8723D_1ANT_COEX_DBG + u32tmp1 = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u16tmp0 = btcoexist->btc_read_2byte(btcoexist, 0xaa); + u16tmp1 = btcoexist->btc_read_2byte(btcoexist, 0x948); + u8tmp1 = btcoexist->btc_read_1byte(btcoexist, 0x73); + u8tmp0 = btcoexist->btc_read_1byte(btcoexist, 0x67); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** 0x67 = 0x%x, 0x948 = 0x%x, 0x73 = 0x%x(After Set Ant Pat)\n", + u8tmp0, u16tmp1, u8tmp1); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], **********0x38= 0x%x, 0x54= 0x%x, 0xaa = 0x%x(After Set Ant Path)\n", + u32tmp1, u32tmp2, u16tmp0); + BTC_TRACE(trace_buf); +#endif + +} + + +boolean halbtc8723d1ant_is_common_action(IN struct btc_coexist *btcoexist) +{ + boolean common = false, wifi_connected = false, wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected && + BT_8723D_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + common = true; + } else if (wifi_connected && + (BT_8723D_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + common = true; + } else if (!wifi_connected && + (BT_8723D_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + common = true; + } else if (wifi_connected && + (BT_8723D_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + common = true; + } else if (!wifi_connected && + (BT_8723D_1ANT_BT_STATUS_CONNECTED_IDLE != + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + common = true; + } else { + if (wifi_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } + + common = false; + } + + return common; +} + + +/* ********************************************* + * + * Non-Software Coex Mechanism start + * + * ********************************************* */ +void halbtc8723d1ant_action_bt_whql_test(IN struct btc_coexist *btcoexist) +{ + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8723d1ant_action_bt_hs(IN struct btc_coexist *btcoexist) +{ + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8723d1ant_action_bt_relink(IN struct btc_coexist *btcoexist) +{ + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + coex_sta->bt_relink_downcount = 2; +} + +void halbtc8723d1ant_action_bt_idle(IN struct btc_coexist *btcoexist) +{ + boolean wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_busy) { + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } else { + /* if wl busy */ + if (BT_8723D_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + } else { + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + } +} + +} + +void halbtc8723d1ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, wifi_busy = false, bt_busy = false; + boolean wifi_scan = false, wifi_link = false, wifi_roam = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &wifi_link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &wifi_roam); + + + if ((coex_sta->bt_create_connection) && ((wifi_link) || (wifi_roam) + || (wifi_scan) || (wifi_busy) || (coex_sta->wifi_is_high_pri_task))) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi link/roam/Scan/busy/hi-pri-task + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + + if ((bt_link_info->a2dp_exist) && (!bt_link_info->pan_exist)) + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 17); + else + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + } else if ((!wifi_connected) && (!wifi_scan)) { + + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (bt_link_info->pan_exist) { + + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + } else if (bt_link_info->a2dp_exist) { + + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 16); + + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + + if ((wifi_link) || (wifi_roam) || (wifi_scan) || (wifi_busy) + || (coex_sta->wifi_is_high_pri_task)) + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 21); + else + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } +} + + +void halbtc8723d1ant_action_bt_sco_hid_only_busy(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, wifi_busy = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, + &wifi_bw); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + + if (bt_link_info->sco_exist) { + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 5); + } else if (coex_sta->hid_busy_num >= 2) { + /*for 4/18 hid */ + /* if 11bg mode */ + if (wifi_bw == 0) { + + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + halbtc8723d1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x1, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 11); + } else { + + if (wifi_busy) { + + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + halbtc8723d1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 11); + } else { + + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 3); + + } + } + } else { + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 3); + } +} + + +void halbtc8723d1ant_action_wifi_only(IN struct btc_coexist *btcoexist) +{ + halbtc8723d1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + halbtc8723d1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); +} + +void halbtc8723d1ant_action_wifi_multi_port(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + + if (!bt_link_info->pan_exist) + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + else + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8723d1ant_action_wifi_linkscan_process(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + if (bt_link_info->pan_exist) { + + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + } else if (bt_link_info->a2dp_exist) { + + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 17); + + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 21); + + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } +} + +void halbtc8723d1ant_action_wifi_connected_bt_acl_busy(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_busy = false, wifi_turbo = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &coex_sta->scan_ap_num); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d, wl_noisy_level = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; +#endif + + if ((coex_sta->bt_relink_downcount != 0) + && (!bt_link_info->pan_exist) && (wifi_busy)) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Re-Link + A2DP + WL busy\n"); + BTC_TRACE(trace_buf); + + /*halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32);*/ + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + } else if (bt_link_info->a2dp_only) { /* A2DP */ + if (!wifi_busy) { + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + + if (coex_sta->wl_noisy_level == 2) + halbtc8723d1ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 17); + else + halbtc8723d1ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + + if (wifi_turbo) + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + else + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if (((bt_link_info->a2dp_exist) && + (bt_link_info->pan_exist)) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { /* A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP) */ + + if ((bt_link_info->hid_exist) && (coex_sta->hid_busy_num >= 2)) { + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + if (wifi_bw == 0) /* 11bg mode */ + halbtc8723d1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x1, 0xaa, + 0x5a, 0xaa, + 0xaa); + else + halbtc8723d1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 12); + } else if (wifi_busy) { + if (((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) || + (!coex_sta->is_A2DP_3M)) + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + else if (wifi_turbo) + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 18); + else + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 13); + } else + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 14); + + if (bt_link_info->hid_exist) + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + else if (wifi_turbo) + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + else + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { /* HID+A2DP */ + + if ((wifi_busy) && (coex_sta->hid_busy_num >= 2)) { /*for 4/18 hid */ + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + if (wifi_bw == 0) /* 11bg mode */ + halbtc8723d1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x1, 0xaa, + 0x5a, 0xaa, + 0xaa); + else + halbtc8723d1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 9); + } else { + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 8); + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } + + } else if ((bt_link_info->pan_only) + || (bt_link_info->hid_exist && bt_link_info->pan_exist)) { + /* PAN(OPP,FTP), HID+PAN(OPP,FTP) */ + + if ((bt_link_info->hid_exist) && (bt_link_info->pan_exist) && + (coex_sta->hid_busy_num >= 2)) { + + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + if (wifi_bw == 0) /* 11bg mode */ + halbtc8723d1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x1, 0xaa, + 0x5a, 0xaa, + 0xaa); + else + halbtc8723d1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 12); + } else { + if (!wifi_busy) + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 4); + else + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + + if (bt_link_info->hid_exist) + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + else if (wifi_turbo) + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + else + halbtc8723d1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else { + /* BT no-profile busy (0x9) */ + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } +} + +void halbtc8723d1ant_action_wifi_not_connected(IN struct btc_coexist *btcoexist) +{ + /* tdma and coex table */ + halbtc8723d1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + + +void halbtc8723d1ant_action_wifi_connected(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_busy = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect()===>\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + + if (BT_8723D_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + + if (bt_link_info->hid_only) /* HID only */ + halbtc8723d1ant_action_bt_sco_hid_only_busy(btcoexist); + else + halbtc8723d1ant_action_wifi_connected_bt_acl_busy(btcoexist); + + } else if ((BT_8723D_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8723D_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8723d1ant_action_bt_sco_hid_only_busy(btcoexist); + } else + halbtc8723d1ant_action_bt_idle(btcoexist); +} + + +void halbtc8723d1ant_run_sw_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + algorithm = halbtc8723d1ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + + if (halbtc8723d1ant_is_common_action(btcoexist)) { + + } else { + switch (coex_dm->cur_algorithm) { + case BT_8723D_1ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8723D_1ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8723D_1ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8723D_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + break; + case BT_8723D_1ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + break; + case BT_8723D_1ANT_COEX_ALGO_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HS mode.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8723D_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8723D_1ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8723D_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + break; + case BT_8723D_1ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = coexist All Off!!\n"); + BTC_TRACE(trace_buf); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + + +void halbtc8723d1ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + boolean increase_scan_dev_num = false; + boolean bt_ctrl_agg_buf_size = false; + boolean miracast_plus_bt = false, wifi_under_5g = false; + u8 agg_buf_size = 5; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0, wifi_bw; + u8 iot_peer = BTC_IOT_PEER_UNKNOWN; + boolean scan = false, link = false, roam = false, under_4way = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (!coex_sta->run_time_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], return for run_time_state = false !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->freeze_coexrun_by_btinfo) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), return for freeze_coexrun_by_btinfo\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->bt_whck_test) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under WHCK TEST!!!\n"); + BTC_TRACE(trace_buf); + halbtc8723d1ant_action_bt_whql_test(btcoexist); + return; + } + + if (coex_sta->bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!!\n"); + halbtc8723d1ant_action_wifi_only(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + BTC_TRACE(trace_buf); + halbtc8723d1ant_action_bt_inquiry(btcoexist); + return; + } + + if (coex_sta->is_setupLink) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is re-link !!!\n"); + halbtc8723d1ant_action_bt_relink(btcoexist); + return; + } + + if ((BT_8723D_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8723D_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723D_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + increase_scan_dev_num = true; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, + &increase_scan_dev_num); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + BTC_TRACE(trace_buf); + + if (bt_link_info->bt_link_exist) + miracast_plus_bt = true; + else + miracast_plus_bt = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + halbtc8723d1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + false, 0x5); + + if (scan || link || roam || under_4way) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], scan = %d, link = %d, roam = %d 4way = %d!!!\n", + scan, link, roam, under_4way); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under linkscan process + Multi-Port !!\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_action_wifi_linkscan_process(btcoexist); + } else + halbtc8723d1ant_action_wifi_multi_port(btcoexist); + + return; + } else { + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + } + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if ((bt_link_info->bt_link_exist) && (wifi_connected)) { + + btcoexist->btc_get(btcoexist, BTC_GET_U1_IOT_PEER, &iot_peer); + + if (BTC_IOT_PEER_CISCO == iot_peer) { + + if (BTC_WIFI_BW_HT40 == wifi_bw) + halbtc8723d1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, true, 0x10); + else + halbtc8723d1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, true, 0x8); + } else + halbtc8723d1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x5); + } + + halbtc8723d1ant_run_sw_coexist_mechanism( + btcoexist); /* just print debug message */ + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is hs\n"); + BTC_TRACE(trace_buf); + halbtc8723d1ant_action_bt_hs(btcoexist); + return; + } + + if ((BT_8723D_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) || + (BT_8723D_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is idle\n"); + BTC_TRACE(trace_buf); + halbtc8723d1ant_action_bt_idle(btcoexist); + return; + } + + if (scan || link || roam || under_4way) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], scan = %d, link = %d, roam = %d 4way = %d!!!\n", + scan, link, roam, under_4way); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under linkscan process!!\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_action_wifi_linkscan_process(btcoexist); + } else if (wifi_connected) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under connected!!\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_action_wifi_connected(btcoexist); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under not-connected!!\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_action_wifi_not_connected(btcoexist); + } +} + + +void halbtc8723d1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + halbtc8723d1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->pop_event_cnt = 0; + coex_sta->cnt_RemoteNameReq = 0; + coex_sta->cnt_ReInit = 0; + coex_sta->cnt_setupLink = 0; + coex_sta->cnt_IgnWlanAct = 0; + coex_sta->cnt_Page = 0; + coex_sta->cnt_RoleSwitch = 0; + + halbtc8723d1ant_query_bt_info(btcoexist); +} + +void halbtc8723d1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean back_up, IN boolean wifi_only) +{ + u32 u32tmp1 = 0, u32tmp2 = 0; + u16 u16tmp1 = 0; + u8 u8tmp0 = 0, u8tmp1 = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + u8 i = 0; + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 1Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + +#if BT_8723D_1ANT_COEX_DBG + u32tmp1 = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + u32tmp2 = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, + 0x54); + u16tmp1 = btcoexist->btc_read_2byte(btcoexist, 0x948); + u8tmp1 = btcoexist->btc_read_1byte(btcoexist, 0x73); + u8tmp0 = btcoexist->btc_read_1byte(btcoexist, 0x67); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** 0x67 = 0x%x, 0x948 = 0x%x, 0x73 = 0x%x(Before init_hw_config)\n", + u8tmp0, u16tmp1, u8tmp1); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], **********0x38= 0x%x, 0x54= 0x%x (Before init_hw_config)\n", + u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); +#endif + + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->bt_reg_vendor_ac = 0xffff; + coex_sta->bt_reg_vendor_ae = 0xffff; + coex_sta->isolation_btween_wb = BT_8723D_1ANT_DEFAULT_ISOLATION; + coex_sta->gnt_error_cnt = 0; + coex_sta->bt_relink_downcount = 0; + + for (i = 0; i <= 9; i++) + coex_sta->bt_afh_map[i] = 0; + + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = (btcoexist->btc_read_1byte(btcoexist, + 0xf1) & 0xf0) >> 4; + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + + /* BT report packet sample rate */ + btcoexist->btc_write_1byte(btcoexist, 0x790, 0x5); + + /* Init 0x778 = 0x1 for 1-Ant */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + + /* Enable PTA (3-wire function form BT side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x41, 0x02, 0x1); + + /* Enable PTA (tx/rx signal form WiFi side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4c6, 0x10, 0x1); + + halbtc8723d1ant_enable_gnt_to_gpio(btcoexist, true); + + /* check if WL firmware download ok */ + if (btcoexist->btc_read_1byte(btcoexist, 0x80) == 0xc6) + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ONOFF, true); + + /* PTA parameter */ + halbtc8723d1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + + halbtc8723d1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + psd_scan->ant_det_is_ant_det_available = true; + + /* Antenna config */ + if (wifi_only) { + coex_sta->concurrent_rx_mode_on = false; + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_WLANONLY_INIT); + + btcoexist->stop_coex_dm = true; + } else { + /*Set BT polluted packet on for Tx rate adaptive not including Tx retry break by PTA, 0x45c[19] =1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + + coex_sta->concurrent_rx_mode_on = true; + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x953, 0x2, 0x1); + /* RF 0x1[0] = 0->Set GNT_WL_RF_Rx always = 1 for con-current Rx */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0x1, 0x0); + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_COEX_INIT); + + btcoexist->stop_coex_dm = false; + } + + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** Single Antenna, Antenna at Main Port: S1**********\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** Single Antenna, Antenna at Aux Port: S0**********\n"); + BTC_TRACE(trace_buf); + } + +} + +u32 halbtc8723d1ant_psd_log2base(IN struct btc_coexist *btcoexist, IN u32 val) +{ + u8 j; + u32 tmp, tmp2, val_integerd_b = 0, tindex, shiftcount = 0; + u32 result, val_fractiond_b = 0, table_fraction[21] = {0, 432, 332, 274, 232, 200, + 174, 151, 132, 115, 100, 86, 74, 62, 51, 42, + 32, 23, 15, 7, 0 + }; + + if (val == 0) + return 0; + + tmp = val; + + while (1) { + if (tmp == 1) + break; + else { + tmp = (tmp >> 1); + shiftcount++; + } + } + + + val_integerd_b = shiftcount + 1; + + tmp2 = 1; + for (j = 1; j <= val_integerd_b; j++) + tmp2 = tmp2 * 2; + + tmp = (val * 100) / tmp2; + tindex = tmp / 5; + + if (tindex > 20) + tindex = 20; + + val_fractiond_b = table_fraction[tindex]; + + result = val_integerd_b * 100 - val_fractiond_b; + + return result; + + +} + +void halbtc8723d1ant_psd_show_antenna_detect_result(IN struct btc_coexist + *btcoexist) +{ + u8 *cli_buf = btcoexist->cli_buf; + struct btc_board_info *board_info = &btcoexist->board_info; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n============[Antenna Detection info] ============\n"); + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 12) { /* Get Ant Det from BT */ + + if (board_info->btdm_ant_num_by_ant_det == 1) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "1-Antenna", + BT_8723D_1ANT_ANTDET_PSDTHRES_1ANT, + BT_8723D_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION); + else { + + if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8723D_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION) + * 100) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (>%d)", + "Ant Det Result", "2-Antenna (Bad-Isolation)", + BT_8723D_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "2-Antenna (Good-Isolation)", + BT_8723D_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION, + BT_8723D_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + } + } else if (psd_scan->ant_det_result == 1) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (>%d)", + "Ant Det Result", "2-Antenna (Bad-Isolation)", + BT_8723D_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else if (psd_scan->ant_det_result == 2) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "2-Antenna (Good-Isolation)", + BT_8723D_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset, + BT_8723D_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "1-Antenna", + BT_8723D_1ANT_ANTDET_PSDTHRES_1ANT, + BT_8723D_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset); + + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s ", + "Antenna Detection Finish", + (board_info->btdm_ant_det_finish + ? "Yes" : "No")); + CL_PRINTF(cli_buf); + + switch (psd_scan->ant_det_result) { + case 0: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is not available)"); + break; + case 1: /* 2-Ant bad-isolation */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 2: /* 2-Ant good-isolation */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 3: /* 1-Ant */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 4: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Uncertainty result)"); + break; + case 5: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "(Pre-Scan fai)"); + break; + case 6: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(WiFi is Scanning)"); + break; + case 7: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is not idle)"); + break; + case 8: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Abort by WiFi Scanning)"); + break; + case 9: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Antenna Init is not ready)"); + break; + case 10: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is Inquiry or page)"); + break; + case 11: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is Disabled)"); + case 12: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available, result from BT"); + break; + } + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 12) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d dB", + "PSD Scan Peak Value", + psd_scan->ant_det_psd_scan_peak_val / 100); + CL_PRINTF(cli_buf); + return; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "Ant Detect Total Count", psd_scan->ant_det_try_count); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "Ant Detect Fail Count", psd_scan->ant_det_fail_count); + CL_PRINTF(cli_buf); + + if ((!board_info->btdm_ant_det_finish) && + (psd_scan->ant_det_result != 5)) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Response", + (psd_scan->ant_det_result ? "ok" : "fail")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ms", "BT Tx Time", + psd_scan->ant_det_bt_tx_time); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "BT Tx Ch", + psd_scan->ant_det_bt_le_channel); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + "WiFi PSD Cent-Ch/Offset/Span", + psd_scan->real_cent_freq, psd_scan->real_offset, + psd_scan->real_span); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d dB", + "PSD Pre-Scan Peak Value", + psd_scan->ant_det_pre_psdscan_peak_val / 100); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (<= %d)", + "PSD Pre-Scan result", + (psd_scan->ant_det_result != 5 ? "ok" : "fail"), + BT_8723D_1ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 5) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s dB", + "PSD Scan Peak Value", psd_scan->ant_det_peak_val); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s MHz", + "PSD Scan Peak Freq", psd_scan->ant_det_peak_freq); + CL_PRINTF(cli_buf); + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "TFBGA Package", + (board_info->tfbga_package) ? "Yes" : "No"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "PSD Threshold Offset", psd_scan->ant_det_thres_offset); + CL_PRINTF(cli_buf); + +} + + + +void halbtc8723d1ant_psd_showdata(IN struct btc_coexist *btcoexist) +{ + u8 *cli_buf = btcoexist->cli_buf; + u32 delta_freq_per_point; + u32 freq, freq1, freq2, n = 0, i = 0, j = 0, m = 0, psd_rep1, psd_rep2; + + if (psd_scan->ant_det_result == 12) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n\n============[PSD info] (%d)============\n", + psd_scan->psd_gen_count); + CL_PRINTF(cli_buf); + + if (psd_scan->psd_gen_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n No data !!\n"); + CL_PRINTF(cli_buf); + return; + } + + if (psd_scan->psd_point == 0) + delta_freq_per_point = 0; + else + delta_freq_per_point = psd_scan->psd_band_width / + psd_scan->psd_point; + + /* if (psd_scan->is_psd_show_max_only) */ + if (0) { + psd_rep1 = psd_scan->psd_max_value / 100; + psd_rep2 = psd_scan->psd_max_value - psd_rep1 * 100; + + freq = ((psd_scan->real_cent_freq - 20) * 1000000 + + psd_scan->psd_max_value_point * delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (freq2 < 100) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n Freq = %d.0%d MHz", + freq1, freq2); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n Freq = %d.%d MHz", + freq1, freq2); + + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + ", Value = %d.0%d dB, (%d)\n", + psd_rep1, psd_rep2, psd_scan->psd_max_value); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + ", Value = %d.%d dB, (%d)\n", + psd_rep1, psd_rep2, psd_scan->psd_max_value); + + CL_PRINTF(cli_buf); + } else { + m = psd_scan->psd_start_point; + n = psd_scan->psd_start_point; + i = 1; + j = 1; + + while (1) { + do { + freq = ((psd_scan->real_cent_freq - 20) * + 1000000 + m * + delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (i == 1) { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.000", + freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.0%2d", + freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.%3d", + freq1, + freq2); + } else if ((i % 8 == 0) || + (m == psd_scan->psd_stop_point)) { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.000\n", freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.0%2d\n", freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.%3d\n", freq1, + freq2); + } else { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.000", freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.0%2d", freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.%3d", freq1, + freq2); + } + + i++; + m++; + CL_PRINTF(cli_buf); + + } while ((i <= 8) && (m <= psd_scan->psd_stop_point)); + + + do { + psd_rep1 = psd_scan->psd_report_max_hold[n] / + 100; + psd_rep2 = psd_scan->psd_report_max_hold[n] - + psd_rep1 * + 100; + + if (j == 1) { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Val %7d.0%d", + psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Val %7d.%d", + psd_rep1, + psd_rep2); + } else if ((j % 8 == 0) || + (n == psd_scan->psd_stop_point)) { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.0%d\n", psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.%d\n", psd_rep1, + psd_rep2); + } else { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.0%d", psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.%d", psd_rep1, + psd_rep2); + } + + j++; + n++; + CL_PRINTF(cli_buf); + + } while ((j <= 8) && (n <= psd_scan->psd_stop_point)); + + if ((m > psd_scan->psd_stop_point) || + (n > psd_scan->psd_stop_point)) + break; + else { + i = 1; + j = 1; + } + + } + } + + +} + + +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +void halbtc8723d1ant_psd_maxholddata(IN struct btc_coexist *btcoexist, + IN u32 gen_count) +{ + u32 i = 0; + u32 loop_i_max = 0, loop_val_max = 0; + + if (gen_count == 1) { + memcpy(psd_scan->psd_report_max_hold, + psd_scan->psd_report, + BT_8723D_1ANT_ANTDET_PSD_POINTS * sizeof(u32)); + } + + for (i = psd_scan->psd_start_point; + i <= psd_scan->psd_stop_point; i++) { + + /* update max-hold value at each freq point */ + if (psd_scan->psd_report[i] > psd_scan->psd_report_max_hold[i]) + psd_scan->psd_report_max_hold[i] = + psd_scan->psd_report[i]; + + /* search the max value in this seep */ + if (psd_scan->psd_report[i] > loop_val_max) { + loop_val_max = psd_scan->psd_report[i]; + loop_i_max = i; + } + } + + if (gen_count <= BT_8723D_1ANT_ANTDET_PSD_SWWEEPCOUNT) + psd_scan->psd_loop_max_value[gen_count - 1] = loop_val_max; +} + +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +u32 halbtc8723d1ant_psd_getdata(IN struct btc_coexist *btcoexist, IN u32 point) +{ + /* reg 0x808[9:0]: FFT data x */ + /* reg 0x808[22]: 0-->1 to get 1 FFT data y */ + /* reg 0x8b4[15:0]: FFT data y report */ + + u32 val = 0, psd_report = 0; + int k = 0; + + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + + val &= 0xffbffc00; + val |= point; + + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + val |= 0x00400000; + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + while (1) { + if (k++ > BT_8723D_1ANT_ANTDET_SWEEPPOINT_DELAY) + break; + } + + val = btcoexist->btc_read_4byte(btcoexist, 0x8b4); + + psd_report = val & 0x0000ffff; + + return psd_report; +} + +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +boolean halbtc8723d1ant_psd_sweep_point(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN s32 offset, IN u32 span, IN u32 points, + IN u32 avgnum, IN u32 loopcnt) +{ + u32 i = 0, val = 0, n = 0, k = 0, j, point_index = 0; + u32 points1 = 0, psd_report = 0; + u32 start_p = 0, stop_p = 0, delta_freq_per_point = 156250; + u32 psd_center_freq = 20 * 10 ^ 6; + boolean outloop = false, scan , roam, is_sweep_ok = true; + u8 flag = 0; + u32 tmp = 0, u32tmp1 = 0; + u32 wifi_original_channel = 1; + u32 psd_sum = 0, avg_cnt = 0; + u32 i_max = 0, val_max = 0, val_max2 = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx PSD Sweep Start!!\n"); + BTC_TRACE(trace_buf); + + do { + switch (flag) { + case 0: /* Get PSD parameters */ + default: + + psd_scan->psd_band_width = 40 * 1000000; + psd_scan->psd_point = points; + psd_scan->psd_start_base = points / 2; + psd_scan->psd_avg_num = avgnum; + psd_scan->real_cent_freq = cent_freq; + psd_scan->real_offset = offset; + psd_scan->real_span = span; + + + points1 = psd_scan->psd_point; + delta_freq_per_point = psd_scan->psd_band_width / + psd_scan->psd_point; + + /* PSD point setup */ + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + val &= 0xffff0fff; + + switch (psd_scan->psd_point) { + case 128: + val |= 0x0; + break; + case 256: + default: + val |= 0x00004000; + break; + case 512: + val |= 0x00008000; + break; + case 1024: + val |= 0x0000c000; + break; + } + + switch (psd_scan->psd_avg_num) { + case 1: + val |= 0x0; + break; + case 8: + val |= 0x00001000; + break; + case 16: + val |= 0x00002000; + break; + case 32: + default: + val |= 0x00003000; + break; + } + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + flag = 1; + break; + case 1: /* calculate the PSD point index from freq/offset/span */ + psd_center_freq = psd_scan->psd_band_width / 2 + + offset * (1000000); + + start_p = psd_scan->psd_start_base + (psd_center_freq - + span * (1000000) / 2) / delta_freq_per_point; + psd_scan->psd_start_point = start_p - + psd_scan->psd_start_base; + + stop_p = psd_scan->psd_start_base + (psd_center_freq + + span * (1000000) / 2) / delta_freq_per_point; + psd_scan->psd_stop_point = stop_p - + psd_scan->psd_start_base - 1; + + flag = 2; + break; + case 2: /* set RF channel/BW/Mode */ + + /* set 3-wire off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x88c); + val |= 0x00300000; + btcoexist->btc_write_4byte(btcoexist, 0x88c, val); + + /* CCK off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x800); + val &= 0xfeffffff; + btcoexist->btc_write_4byte(btcoexist, 0x800, val); + + /* Tx-pause on */ + btcoexist->btc_write_1byte(btcoexist, 0x522, 0x6f); + + /* store WiFi original channel */ + wifi_original_channel = btcoexist->btc_get_rf_reg( + btcoexist, BTC_RF_A, 0x18, 0x3ff); + + /* Set RF channel */ + if (cent_freq == 2484) + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x18, 0x3ff, 0xe); + else + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x18, 0x3ff, (cent_freq - 2412) / 5 + + 1); /* WiFi TRx Mask on */ + + /* save original RCK value */ + u32tmp1 = btcoexist->btc_get_rf_reg( + btcoexist, BTC_RF_A, 0x1d, 0xfffff); + + /* Enter debug mode */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xde, + 0x2, 0x1); + + /* Set RF Rx filter corner */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1d, + 0xfffff, 0x2e); + + + /* Set RF mode = Rx, RF Gain = 0x320a0 */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x0, + 0xfffff, 0x320a0); + + while (1) { + if (k++ > BT_8723D_1ANT_ANTDET_SWEEPPOINT_DELAY) + break; + } + flag = 3; + break; + case 3: + psd_scan->psd_gen_count = 0; + for (j = 1; j <= loopcnt; j++) { + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || roam) { + is_sweep_ok = false; + break; + } + memset(psd_scan->psd_report, 0, + psd_scan->psd_point * sizeof(u32)); + start_p = psd_scan->psd_start_point + + psd_scan->psd_start_base; + stop_p = psd_scan->psd_stop_point + + psd_scan->psd_start_base + 1; + + i = start_p; + point_index = 0; + + while (i < stop_p) { + if (i >= points1) + psd_report = + halbtc8723d1ant_psd_getdata( + btcoexist, i - points1); + else + psd_report = + halbtc8723d1ant_psd_getdata( + btcoexist, i); + + if (psd_report == 0) + tmp = 0; + else + /* tmp = 20*log10((double)psd_report); */ + /* 20*log2(x)/log2(10), log2Base return theresult of the psd_report*100 */ + tmp = 6 * halbtc8723d1ant_psd_log2base( + btcoexist, psd_report); + + n = i - psd_scan->psd_start_base; + psd_scan->psd_report[n] = tmp; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Point=%d, psd_dB_data = %d\n", + i, psd_scan->psd_report[n]); + BTC_TRACE(trace_buf); + + i++; + + } + + halbtc8723d1ant_psd_maxholddata(btcoexist, j); + + psd_scan->psd_gen_count = j; + + /*Accumulate Max PSD value in this loop if the value > threshold */ + if (psd_scan->psd_loop_max_value[j - 1] >= + 4000) { + psd_sum = psd_sum + + psd_scan->psd_loop_max_value[j - + 1]; + avg_cnt++; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Loop=%d, Max_dB_data = %d\n", + j, psd_scan->psd_loop_max_value[j + - 1]); + BTC_TRACE(trace_buf); + + } + + if (loopcnt == BT_8723D_1ANT_ANTDET_PSD_SWWEEPCOUNT) { + + /* search the Max Value between each-freq-point-max-hold value of all sweep*/ + for (i = 1; + i <= BT_8723D_1ANT_ANTDET_PSD_SWWEEPCOUNT; + i++) { + + if (i == 1) { + i_max = i; + val_max = psd_scan->psd_loop_max_value[i + - 1]; + val_max2 = + psd_scan->psd_loop_max_value[i + - 1]; + } else if ( + psd_scan->psd_loop_max_value[i - + 1] > val_max) { + val_max2 = val_max; + i_max = i; + val_max = psd_scan->psd_loop_max_value[i + - 1]; + } else if ( + psd_scan->psd_loop_max_value[i - + 1] > val_max2) + val_max2 = + psd_scan->psd_loop_max_value[i + - 1]; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "i = %d, val_hold= %d, val_max = %d, val_max2 = %d\n", + i, psd_scan->psd_loop_max_value[i + - 1], + val_max, val_max2); + + BTC_TRACE(trace_buf); + } + + psd_scan->psd_max_value_point = i_max; + psd_scan->psd_max_value = val_max; + psd_scan->psd_max_value2 = val_max2; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "val_max = %d, val_max2 = %d\n", + psd_scan->psd_max_value, + psd_scan->psd_max_value2); + BTC_TRACE(trace_buf); + } + + if (avg_cnt != 0) { + psd_scan->psd_avg_value = (psd_sum / avg_cnt); + if ((psd_sum % avg_cnt) >= (avg_cnt / 2)) + psd_scan->psd_avg_value++; + } else + psd_scan->psd_avg_value = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "AvgLoop=%d, Avg_dB_data = %d\n", + avg_cnt, psd_scan->psd_avg_value); + BTC_TRACE(trace_buf); + + flag = 100; + break; + case 99: /* error */ + + outloop = true; + break; + case 100: /* recovery */ + + /* set 3-wire on */ + val = btcoexist->btc_read_4byte(btcoexist, 0x88c); + val &= 0xffcfffff; + btcoexist->btc_write_4byte(btcoexist, 0x88c, val); + + /* CCK on */ + val = btcoexist->btc_read_4byte(btcoexist, 0x800); + val |= 0x01000000; + btcoexist->btc_write_4byte(btcoexist, 0x800, val); + + /* Tx-pause off */ + btcoexist->btc_write_1byte(btcoexist, 0x522, 0x0); + + /* PSD off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + val &= 0xffbfffff; + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + /* restore RF Rx filter corner */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1d, + 0xfffff, u32tmp1); + + /* Exit debug mode */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xde, + 0x2, 0x0); + + /* restore WiFi original channel */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x18, + 0x3ff, wifi_original_channel); + + outloop = true; + break; + + } + + } while (!outloop); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx PSD Sweep Stop!!\n"); + BTC_TRACE(trace_buf); + return is_sweep_ok; + +} + +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +boolean halbtc8723d1ant_psd_antenna_detection(IN struct btc_coexist + *btcoexist) +{ + u32 i = 0; + u32 wlpsd_cent_freq = 2484, wlpsd_span = 2; + s32 wlpsd_offset = -4; + u32 bt_tx_time, bt_le_channel; + u8 bt_le_ch[13] = {3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 33}; + + u8 h2c_parameter[3] = {0}, u8tmpa, u8tmpb; + + u8 state = 0; + boolean outloop = false, bt_resp = false, ant_det_finish = false; + u32 freq, freq1, freq2, psd_rep1, psd_rep2, delta_freq_per_point, + u32tmp, u32tmp0, u32tmp1, u32tmp2 ; + struct btc_board_info *board_info = &btcoexist->board_info; + + memset(psd_scan->ant_det_peak_val, 0, 16 * sizeof(u8)); + memset(psd_scan->ant_det_peak_freq, 0, 16 * sizeof(u8)); + + psd_scan->ant_det_bt_tx_time = + BT_8723D_1ANT_ANTDET_BTTXTIME; /* 0.42ms*50 = 20ms (0.42ms = 1 PSD sweep) */ + psd_scan->ant_det_bt_le_channel = BT_8723D_1ANT_ANTDET_BTTXCHANNEL; + + bt_tx_time = psd_scan->ant_det_bt_tx_time; + bt_le_channel = psd_scan->ant_det_bt_le_channel; + + if (board_info->tfbga_package) /* for TFBGA */ + psd_scan->ant_det_thres_offset = 5; + else + psd_scan->ant_det_thres_offset = 0; + + do { + switch (state) { + case 0: + if (bt_le_channel == 39) + wlpsd_cent_freq = 2484; + else { + for (i = 1; i <= 13; i++) { + if (bt_le_ch[i - 1] == + bt_le_channel) { + wlpsd_cent_freq = 2412 + + (i - 1) * 5; + break; + } + } + + if (i == 14) { + + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Abort!!, Invalid LE channel = %d\n ", + bt_le_channel); + BTC_TRACE(trace_buf); + outloop = true; + break; + } + } +#if 0 + wlpsd_sweep_count = bt_tx_time * 238 / + 100; /* bt_tx_time/0.42 */ + wlpsd_sweep_count = wlpsd_sweep_count / 5; + + if (wlpsd_sweep_count % 5 != 0) + wlpsd_sweep_count = (wlpsd_sweep_count / + 5 + 1) * 5; +#endif + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), BT_LETxTime=%d, BT_LECh = %d\n", + bt_tx_time, bt_le_channel); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), wlpsd_cent_freq=%d, wlpsd_offset = %d, wlpsd_span = %d, wlpsd_sweep_count = %d\n", + wlpsd_cent_freq, + wlpsd_offset, + wlpsd_span, + BT_8723D_1ANT_ANTDET_PSD_SWWEEPCOUNT); + BTC_TRACE(trace_buf); + + state = 1; + break; + case 1: /* stop coex DM & set antenna path */ + /* Stop Coex DM */ + btcoexist->stop_coex_dm = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Stop Coex DM!!\n"); + BTC_TRACE(trace_buf); + + /* Set TDMA off, */ + halbtc8723d1ant_ps_tdma(btcoexist, FORCE_EXEC, + false, 0); + + /* Set coex table */ + halbtc8723d1ant_coex_table_with_type(btcoexist, + FORCE_EXEC, 0); + + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna at Main Port\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna at Aux Port\n"); + BTC_TRACE(trace_buf); + } + + /* Set Antenna path, switch WiFi to un-certain antenna port */ + /* Set Antenna Path, both GNT_WL/GNT_BT = 1, and control by SW */ + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_ANTENNA_DET); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set Antenna to BT!!\n"); + BTC_TRACE(trace_buf); + + /* Set AFH mask on at WiFi channel 2472MHz +/- 10MHz */ + h2c_parameter[0] = 0x1; + h2c_parameter[1] = 0xd; + h2c_parameter[2] = 0x14; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set AFH on, Cent-Ch= %d, Mask=%d\n", + h2c_parameter[1], + h2c_parameter[2]); + BTC_TRACE(trace_buf); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, + h2c_parameter); + + u32tmp = btcoexist->btc_read_2byte(btcoexist, 0x948); + u32tmp0 = btcoexist->btc_read_4byte(btcoexist, 0x70); + u32tmp1 = halbtc8723d1ant_ltecoex_indirect_read_reg( + btcoexist, 0x38); + u32tmp2 = halbtc8723d1ant_ltecoex_indirect_read_reg( + btcoexist, 0x54); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** 0x948 = 0x%x, 0x70 = 0x%x, 0x38= 0x%x, 0x54= 0x%x (Before Ant Det)\n", + u32tmp, u32tmp0, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); + + state = 2; + break; + case 2: /* Pre-sweep background psd */ + if (!halbtc8723d1ant_psd_sweep_point(btcoexist, + wlpsd_cent_freq, wlpsd_offset, wlpsd_span, + BT_8723D_1ANT_ANTDET_PSD_POINTS, + BT_8723D_1ANT_ANTDET_PSD_AVGNUM, 3)) { + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 8; + state = 99; + break; + } + + psd_scan->ant_det_pre_psdscan_peak_val = + psd_scan->psd_max_value; + + if (psd_scan->ant_det_pre_psdscan_peak_val > + (BT_8723D_1ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset) * 100) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Abort Antenna Detection!! becaus background = %d > thres (%d)\n", + psd_scan->ant_det_pre_psdscan_peak_val / + 100, + BT_8723D_1ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + BTC_TRACE(trace_buf); + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 5; + state = 99; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Start Antenna Detection!! becaus background = %d <= thres (%d)\n", + psd_scan->ant_det_pre_psdscan_peak_val / + 100, + BT_8723D_1ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + BTC_TRACE(trace_buf); + state = 3; + } + break; + case 3: + + bt_resp = btcoexist->btc_set_bt_ant_detection( + btcoexist, (u8)(bt_tx_time & 0xff), + (u8)(bt_le_channel & 0xff)); + + /* Sync WL Rx PSD with BT Tx time because H2C->Mailbox delay */ + delay_ms(20); + + if (!halbtc8723d1ant_psd_sweep_point(btcoexist, + wlpsd_cent_freq, wlpsd_offset, + wlpsd_span, + BT_8723D_1ANT_ANTDET_PSD_POINTS, + BT_8723D_1ANT_ANTDET_PSD_AVGNUM, + BT_8723D_1ANT_ANTDET_PSD_SWWEEPCOUNT)) { + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 8; + state = 99; + break; + } + +#if 1 + psd_scan->ant_det_psd_scan_peak_val = + psd_scan->psd_max_value; +#endif +#if 0 + psd_scan->ant_det_psd_scan_peak_val = + ((psd_scan->psd_max_value - psd_scan->psd_avg_value) < + 800) ? + psd_scan->psd_max_value : (( + psd_scan->psd_max_value - + psd_scan->psd_max_value2 <= 300) ? + psd_scan->psd_avg_value : + psd_scan->psd_max_value2); +#endif + psd_scan->ant_det_psd_scan_peak_freq = + psd_scan->psd_max_value_point; + state = 4; + break; + case 4: + + if (psd_scan->psd_point == 0) + delta_freq_per_point = 0; + else + delta_freq_per_point = + psd_scan->psd_band_width / + psd_scan->psd_point; + + psd_rep1 = psd_scan->ant_det_psd_scan_peak_val / 100; + psd_rep2 = psd_scan->ant_det_psd_scan_peak_val - + psd_rep1 * + 100; + + freq = ((psd_scan->real_cent_freq - 20) * + 1000000 + psd_scan->psd_max_value_point + * delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (freq2 < 100) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Max Value: Freq = %d.0%d MHz", + freq1, freq2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_freq, + BT_8723D_1ANT_ANTDET_BUF_LEN, + "%d.0%d", freq1, freq2); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Max Value: Freq = %d.%d MHz", + freq1, freq2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_freq, + BT_8723D_1ANT_ANTDET_BUF_LEN, + "%d.%d", freq1, freq2); + } + + if (psd_rep2 < 10) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + ", Value = %d.0%d dB\n", + psd_rep1, psd_rep2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_val, + BT_8723D_1ANT_ANTDET_BUF_LEN, + "%d.0%d", psd_rep1, psd_rep2); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + ", Value = %d.%d dB\n", + psd_rep1, psd_rep2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_val, + BT_8723D_1ANT_ANTDET_BUF_LEN, + "%d.%d", psd_rep1, psd_rep2); + } + + psd_scan->ant_det_is_btreply_available = true; + + if (bt_resp == false) { + psd_scan->ant_det_is_btreply_available = + false; + psd_scan->ant_det_result = 0; + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), BT Response = Fail\n "); + BTC_TRACE(trace_buf); + } else if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8723D_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION) + * 100) { + psd_scan->ant_det_result = 1; + ant_det_finish = true; + board_info->btdm_ant_num_by_ant_det = 2; + coex_sta->isolation_btween_wb = (u8)(85 - + psd_scan->ant_det_psd_scan_peak_val / + 100) & 0xff; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 2-Ant, Bad-Isolation!!\n"); + BTC_TRACE(trace_buf); + } else if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8723D_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset) * 100) { + psd_scan->ant_det_result = 2; + ant_det_finish = true; + board_info->btdm_ant_num_by_ant_det = 2; + coex_sta->isolation_btween_wb = (u8)(85 - + psd_scan->ant_det_psd_scan_peak_val / + 100) & 0xff; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 2-Ant, Good-Isolation!!\n"); + BTC_TRACE(trace_buf); + } else if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8723D_1ANT_ANTDET_PSDTHRES_1ANT) * + 100) { + psd_scan->ant_det_result = 3; + ant_det_finish = true; + board_info->btdm_ant_num_by_ant_det = 1; + coex_sta->isolation_btween_wb = (u8)(85 - + psd_scan->ant_det_psd_scan_peak_val / + 100) & 0xff; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 1-Ant!!\n"); + BTC_TRACE(trace_buf); + } else { + psd_scan->ant_det_result = 4; + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 1-Ant, un-certainity!!\n"); + BTC_TRACE(trace_buf); + } + + state = 99; + break; + case 99: /* restore setup */ + + /* Set AFH mask off at WiFi channel 2472MHz +/- 10MHz */ + h2c_parameter[0] = 0x0; + h2c_parameter[1] = 0x0; + h2c_parameter[2] = 0x0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set AFH on, Cent-Ch= %d, Mask=%d\n", + h2c_parameter[1], h2c_parameter[2]); + BTC_TRACE(trace_buf); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, + h2c_parameter); + + /* Set Antenna Path, GNT_WL/GNT_BT control by PTA */ + /* Set Antenna path, switch WiFi to certain antenna port */ + halbtc8723d1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set Antenna to PTA\n!!"); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Resume Coex DM\n!!"); + BTC_TRACE(trace_buf); + + outloop = true; + break; + } + + } while (!outloop); + + return ant_det_finish; + +} + +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +boolean halbtc8723d1ant_psd_antenna_detection_check(IN struct btc_coexist + *btcoexist) +{ + static u32 ant_det_count = 0, ant_det_fail_count = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + + boolean scan, roam, ant_det_finish = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + ant_det_count++; + + psd_scan->ant_det_try_count = ant_det_count; + + if (scan || roam) { + ant_det_finish = false; + psd_scan->ant_det_result = 6; + } else if (coex_sta->bt_disabled) { + ant_det_finish = false; + psd_scan->ant_det_result = 11; + } else if (coex_sta->num_of_profile >= 1) { + ant_det_finish = false; + psd_scan->ant_det_result = 7; + } else if ( + !psd_scan->ant_det_is_ant_det_available) { /* Antenna initial setup is not ready */ + ant_det_finish = false; + psd_scan->ant_det_result = 9; + } else if (coex_sta->c2h_bt_inquiry_page) { + ant_det_finish = false; + psd_scan->ant_det_result = 10; + } else { + + ant_det_finish = halbtc8723d1ant_psd_antenna_detection( + btcoexist); + + delay_ms(psd_scan->ant_det_bt_tx_time); + } + + /* board_info->ant_det_result = psd_scan->ant_det_result; */ + + if (!ant_det_finish) + ant_det_fail_count++; + + psd_scan->ant_det_fail_count = ant_det_fail_count; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), result = %d, fail_count = %d, finish = %s\n", + psd_scan->ant_det_result, + psd_scan->ant_det_fail_count, + ant_det_finish == true ? "Yes" : "No"); + BTC_TRACE(trace_buf); + + return ant_det_finish; + +} + + + +/* ************************************************************ + * work around function start with wa_halbtc8723d1ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8723d1ant_ + * ************************************************************ */ +void ex_halbtc8723d1ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + u32 value = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Execute 8723d 1-Ant PowerOn Setting xxxxxxxxxxxxxxxx!!\n"); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Ant Det Finish = %s, Ant Det Number = %d\n", + (board_info->btdm_ant_det_finish ? "Yes" : "No"), + board_info->btdm_ant_num_by_ant_det); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = true; + psd_scan->ant_det_is_ant_det_available = false; + + /* enable BB, REG_SYS_FUNC_EN such that we can write BB Register correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT(0) | BIT(1)); + + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + + /* Set Antenna Path to BT side */ + /* Check efuse 0xc3[6] for Single Antenna Path */ + if (board_info->single_ant_path == 0) { + /* set to S1 */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + u8tmp = 0; + value = 1; + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + u8tmp = 1; + value = 0; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (Power On) single_ant_path = %d, btdm_ant_pos = %d **********\n", + board_info->single_ant_path , board_info->btdm_ant_pos); + BTC_TRACE(trace_buf); + + /* Set Antenna Path to BT side */ + halbtc8723d1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_COEX_POWERON); + + /* Write Single Antenna Position to Registry to tell BT for 8723d. This line can be removed + since BT EFuse also add "single antenna position" in EFuse for 8723d*/ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ANTPOSREGRISTRY_CTRL, + &value); + + /* Save"single antenna position" info in Local register setting for FW reading, because FW may not ready at power on */ + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x3e0, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, u8tmp); + + /* enable GNT_WL/GNT_BT debug signal to GPIO14/15 */ + halbtc8723d1ant_enable_gnt_to_gpio(btcoexist, true); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** LTE coex Reg 0x38 (Power-On) = 0x%x**********\n", + halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, 0x38)); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** MAC Reg 0x70/ BB Reg 0x948 (Power-On) = 0x%x / 0x%x**********\n", + btcoexist->btc_read_4byte(btcoexist, 0x70), + btcoexist->btc_read_2byte(btcoexist, 0x948)); + BTC_TRACE(trace_buf); + +} + +void ex_halbtc8723d1ant_pre_load_firmware(IN struct btc_coexist *btcoexist) +{ +} + +void ex_halbtc8723d1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8723d1ant_init_hw_config(btcoexist, true, wifi_only); +} + +void ex_halbtc8723d1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + halbtc8723d1ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8723d1ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, ps_tdma_case = 0; + u16 u16tmp[4]; + u32 u32tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + u32 fw_ver = 0, bt_patch_ver = 0, bt_coex_ver = 0; + static u8 pop_report_in_10s = 0; + u32 phyver = 0; + boolean lte_coex_on = false; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + if (btcoexist->stop_coex_dm) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (psd_scan->ant_det_try_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %s", + "Ant PG Num/ Mech/ Pos", + board_info->pg_ant_num, board_info->btdm_ant_num, + (board_info->btdm_ant_pos == 1 ? "S1" : "S0")); + CL_PRINTF(cli_buf); + } else { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %s (%d/%d/%d)", + "Ant PG Num/ Mech(Ant_Det)/ Pos", + board_info->pg_ant_num, + board_info->btdm_ant_num_by_ant_det, + (board_info->btdm_ant_pos == 1 ? "S1" : "S0"), + psd_scan->ant_det_try_count, + psd_scan->ant_det_fail_count, + psd_scan->ant_det_result); + CL_PRINTF(cli_buf); + + if (board_info->btdm_ant_det_finish) { + + if (psd_scan->ant_det_result != 12) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s", + "Ant Det PSD Value", + psd_scan->ant_det_peak_val); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d", + "Ant Det PSD Value", + psd_scan->ant_det_psd_scan_peak_val + / 100); + CL_PRINTF(cli_buf); + } + } + + if (board_info->ant_det_result_five_complete) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d", + "AntDet(Registry) Num/PSD Value", + board_info->btdm_ant_num_by_ant_det, + (board_info->antdetval & 0x7f)); + CL_PRINTF(cli_buf); + } + + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + + bt_coex_ver = ((coex_sta->bt_coex_supported_version & 0xff00) >> 8); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8723d_1ant, glcoex_ver_8723d_1ant, + glcoex_ver_btdesired_8723d_1ant, + bt_coex_ver, + (bt_coex_ver == 0xff ? "Unknown" : + (coex_sta->bt_disabled ? "BT-disable" : + (bt_coex_ver >= glcoex_ver_btdesired_8723d_1ant ? + "Match" : "Mis-Match")))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ v%d/ %c", + "W_FW/ B_FW/ Phy/ Kt", + fw_ver, bt_patch_ver, phyver, + coex_sta->cut_version + 65); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "Wifi channel informed to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + pop_report_in_10s++; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = [%s/ %d dBm/ %d/ %d] ", + "BT [status/ rssi/ retryCnt/ popCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page") + : ((BT_8723D_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8723D_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi - 100, coex_sta->bt_retry_cnt, + coex_sta->pop_event_cnt); + CL_PRINTF(cli_buf); + + if (pop_report_in_10s >= 5) { + coex_sta->pop_event_cnt = 0; + pop_report_in_10s = 0; + } + + if (coex_sta->num_of_profile != 0) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s%s%s%s%s", + "Profiles", + ((bt_link_info->a2dp_exist) ? "A2DP," : ""), + ((bt_link_info->sco_exist) ? "SCO," : ""), + ((bt_link_info->hid_exist) ? + ((coex_sta->hid_busy_num >= 2) ? "HID(4/18)," : + "HID(2/18),") : ""), + ((bt_link_info->pan_exist) ? "PAN," : ""), + ((coex_sta->voice_over_HOGP) ? "Voice" : "")); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = None", + "Profiles"); + + CL_PRINTF(cli_buf); + + if (bt_link_info->a2dp_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %d/ %s", + "A2DP Rate/Bitpool/Auto_Slot", + ((coex_sta->is_A2DP_3M) ? "3M" : "No_3M"), + coex_sta->a2dp_bit_pool, + ((coex_sta->is_autoslot) ? "On" : "Off") + ); + CL_PRINTF(cli_buf); + } + + if (bt_link_info->hid_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "HID PairNum/Forbid_Slot", + coex_sta->hid_pair_cnt, + coex_sta->forbidden_slot + ); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %d/ %s/ 0x%x", + "Role/RoleSwCnt/IgnWlact/Feature", + ((bt_link_info->slave_role) ? "Slave" : "Master"), + coex_sta->cnt_RoleSwitch, + ((coex_dm->cur_ignore_wlan_act) ? "Yes" : "No"), + coex_sta->bt_coex_supported_feature); + CL_PRINTF(cli_buf); + + if ((coex_sta->bt_ble_scan_type & 0x7) != 0x0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "BLEScan Type/TV/Init/Ble", + coex_sta->bt_ble_scan_type, + (coex_sta->bt_ble_scan_type & 0x1 ? + coex_sta->bt_ble_scan_para[0] : 0x0), + (coex_sta->bt_ble_scan_type & 0x2 ? + coex_sta->bt_ble_scan_para[1] : 0x0), + (coex_sta->bt_ble_scan_type & 0x4 ? + coex_sta->bt_ble_scan_para[2] : 0x0)); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", + "ReInit/ReLink/IgnWlact/Page/NameReq", + coex_sta->cnt_ReInit, + coex_sta->cnt_setupLink, + coex_sta->cnt_IgnWlanAct, + coex_sta->cnt_Page, + coex_sta->cnt_RemoteNameReq + ); + CL_PRINTF(cli_buf); + + halbtc8723d1ant_read_score_board(btcoexist, &u16tmp[0]); + + if ((coex_sta->bt_reg_vendor_ae == 0xffff) || + (coex_sta->bt_reg_vendor_ac == 0xffff)) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = x/ x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", u16tmp[0]); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", + ((coex_sta->bt_reg_vendor_ae & BIT(4)) >> 4), + coex_sta->bt_reg_vendor_ac & 0x3, u16tmp[0]); + CL_PRINTF(cli_buf); + + if (coex_sta->num_of_profile > 0) { + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + "AFH MAP", + coex_sta->bt_afh_map[0], + coex_sta->bt_afh_map[1], + coex_sta->bt_afh_map[2], + coex_sta->bt_afh_map[3], + coex_sta->bt_afh_map[4], + coex_sta->bt_afh_map[5], + coex_sta->bt_afh_map[6], + coex_sta->bt_afh_map[7], + coex_sta->bt_afh_map[8], + coex_sta->bt_afh_map[9] + ); + CL_PRINTF(cli_buf); + } + + for (i = 0; i < BT_INFO_SRC_8723D_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x (%d)", + glbt_info_src_8723d_1ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + + if (btcoexist->manual_control) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanisms] (before Manual)============"); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Mechanisms]============"); + + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x (case-%d, %s)", + "TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + (coex_dm->cur_ps_tdma_on ? "TDMA On" : "TDMA Off")); + + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ 0x%x/ 0x%x/ 0x%x", + "Table/0x6c0/0x6c4/0x6c8", + coex_sta->coex_table_type, u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x", + "0x778/0x6cc", + u8tmp[0], u32tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s", + "AntDiv/ ForceLPS", + ((board_info->ant_div_cfg) ? "On" : "Off"), + ((coex_sta->force_lps_on) ? "On" : "Off")); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + lte_coex_on = ((u32tmp[0] & BIT(7)) >> 7) ? true : false; + + if (lte_coex_on) { + + u32tmp[0] = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa0); + u32tmp[1] = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa4); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "LTE Coex Table W_L/B_L", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa8); + u32tmp[1] = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, + 0xac); + u32tmp[2] = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, + 0xb0); + u32tmp[3] = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, + 0xb4); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "LTE Break Table W_L/B_L/L_W/L_B", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff, + u32tmp[2] & 0xffff, u32tmp[3] & 0xffff); + CL_PRINTF(cli_buf); + + } + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + /* + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + */ + + u32tmp[0] = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp[1] = halbtc8723d1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x73); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s", + "LTE Coex/Path Owner", + ((lte_coex_on) ? "On" : "Off") , + ((u8tmp[0] & BIT(2)) ? "WL" : "BT")); + CL_PRINTF(cli_buf); + + if (lte_coex_on) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %d/ %d", + "LTE 3Wire/OPMode/UART/UARTMode", + (int)((u32tmp[0] & BIT(6)) >> 6), + (int)((u32tmp[0] & (BIT(5) | BIT(4))) >> 4), + (int)((u32tmp[0] & BIT(3)) >> 3), + (int)(u32tmp[0] & (BIT(2) | BIT(1) | BIT(0)))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "LTE_Busy/UART_Busy", + (int)((u32tmp[1] & BIT(1)) >> 1), (int)(u32tmp[1] & BIT(0))); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (BB:%s)/ %s (BB:%s)/ %s %d", + "GNT_WL_Ctrl/GNT_BT_Ctrl/Dbg", + ((u32tmp[0] & BIT(12)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(8)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(14)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(10)) ? "SW" : "HW"), + ((u8tmp[0] & BIT(3)) ? "On" : "Off"), + coex_sta->gnt_error_cnt); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "GNT_WL/GNT_BT", + (int)((u32tmp[1] & BIT(2)) >> 2), + (int)((u32tmp[1] & BIT(3)) >> 3)); + CL_PRINTF(cli_buf); + + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x948); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x948/0x67[7]", + u16tmp[0], (int)((u8tmp[0] & BIT(7)) >> 7)); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x964); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x864); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0xab7); + u8tmp[3] = btcoexist->btc_read_1byte(btcoexist, 0xa01); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x964[1]/0x864[0]/0xab7[5]/0xa01[7]", + (int)((u8tmp[0] & BIT(1)) >> 1), (int)((u8tmp[1] & BIT(0))), + (int)((u8tmp[2] & BIT(3)) >> 3), + (int)((u8tmp[3] & BIT(7)) >> 7)); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x4c6); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x45e); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x4c6[4]/0x40[5]/0x45e[3](TxRetry)", + (int)((u8tmp[0] & BIT(4)) >> 4), + (int)((u8tmp[1] & BIT(5)) >> 5), + (int)((u8tmp[2] & BIT(3)) >> 3)); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x953); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ %s", + "0x550/0x522/4-RxAGC", + u32tmp[0], u8tmp[0], (u8tmp[1] & 0x2) ? "On" : "Off"); + CL_PRINTF(cli_buf); + + fa_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, PHYDM_INFO_FA_OFDM); + fa_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, PHYDM_INFO_FA_CCK); + cca_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, PHYDM_INFO_CCA_OFDM); + cca_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, PHYDM_INFO_CCA_CCK); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", + cca_cck, fa_cck, cca_ofdm, fa_ofdm); + CL_PRINTF(cli_buf); + +#if 1 + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11n-agg", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11n-agg", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + CL_PRINTF(cli_buf); +#endif + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s/ %d", + "WlHiPri/ Locking/ Locked/ Noisy", + (coex_sta->wifi_is_high_pri_task ? "Yes" : "No"), + (coex_sta->cck_lock ? "Yes" : "No"), + (coex_sta->cck_ever_lock ? "Yes" : "No"), + coex_sta->wl_noisy_level); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d %s", + "0x770(Hi-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx, + (coex_sta->is_hiPri_rx_overhead ? "(scan overhead!!)" : "")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d %s", + "0x774(Lo-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx, + (bt_link_info->slave_role ? "(Slave!!)" : ( + coex_sta->is_tdma_btautoslot_hang ? "(auto-slot hang!!)" : ""))); + CL_PRINTF(cli_buf); + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8723d1ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + + /* Write WL "Active" in Score-board for LPS off */ + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, false); + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ONOFF, false); + + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_WLAN_OFF); + + halbtc8723d1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, true); + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ONOFF, true); + + halbtc8723d1ant_init_hw_config(btcoexist, false, false); + halbtc8723d1ant_init_coex_dm(btcoexist);; + + coex_sta->under_ips = false; + } +} + +void ex_halbtc8723d1ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + + if (coex_sta->force_lps_on == true) { /* LPS No-32K */ + /* Write WL "Active" in Score-board for PS-TDMA */ + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, true); + + } else { /* LPS-32K, need check if this h2c 0x71 can work?? (2015/08/28) */ + /* Write WL "Non-Active" in Score-board for Native-PS */ + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, false); + + } + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + + /* Write WL "Active" in Score-board for LPS off */ + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, true); + + } +} + +void ex_halbtc8723d1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + coex_sta->freeze_coexrun_by_btinfo = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + halbtc8723d1ant_query_bt_info(btcoexist); + + if (BTC_SCAN_START == type) { + + if (!wifi_connected) + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_SCAN, true); + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, true); + + /* Force antenna setup for no scan result issue */ + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + + halbtc8723d1ant_run_coexist_mechanism(btcoexist); + + } else { + + coex_sta->wifi_is_high_pri_task = false; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify (Scan-AP = %d)\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_run_coexist_mechanism(btcoexist); + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN Notify() end\n"); + BTC_TRACE(trace_buf); + +} + +void ex_halbtc8723d1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (BTC_ASSOCIATE_START == type) { + + coex_sta->wifi_is_high_pri_task = true; + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, true); + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_SCAN, true); + + /* Force antenna setup for no scan result issue */ + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify\n"); + BTC_TRACE(trace_buf); + + coex_dm->arp_cnt = 0; + + halbtc8723d1ant_run_coexist_mechanism(btcoexist); + + /* To keep TDMA case during connect process, + to avoid changed by Btinfo and runcoexmechanism */ + coex_sta->freeze_coexrun_by_btinfo = true; + } else { + + coex_sta->wifi_is_high_pri_task = false; + coex_sta->freeze_coexrun_by_btinfo = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_run_coexist_mechanism(btcoexist); + } + +} + +void ex_halbtc8723d1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_under_b_mode = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if (BTC_MEDIA_CONNECT == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, true); + + /* Force antenna setup for no scan result issue */ + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + /* btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x10); */ /*CCK Tx */ + /* btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x10); */ /*CCK Rx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } + + coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, + 0x430); + coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, + 0x434); + coex_dm->backup_retry_limit = btcoexist->btc_read_2byte( + btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = btcoexist->btc_read_1byte( + btcoexist, 0x456); + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, false); + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + + coex_sta->cck_ever_lock = false; + } + + halbtc8723d1ant_update_wifi_channel_info(btcoexist, type); + +} + +void ex_halbtc8723d1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean under_4way = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (under_4way) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ---- under_4way!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } else if (BTC_PACKET_ARP == type) { + + coex_dm->arp_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ARP notify -cnt = %d\n", + coex_dm->arp_cnt); + BTC_TRACE(trace_buf); + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet DHCP or EAPOL notify [Type = %d]\n", + type); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } + + if (coex_sta->wifi_is_high_pri_task) { + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_SCAN, true); + halbtc8723d1ant_run_coexist_mechanism(btcoexist); + } +} + +void ex_halbtc8723d1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 i, rsp_source = 0; + boolean wifi_connected = false; + boolean wifi_scan = false, wifi_link = false, wifi_roam = false, + wifi_busy = false; + + if (psd_scan->is_AntDet_running == true) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], bt_info_notify return for AntDet is running\n"); + BTC_TRACE(trace_buf); + return; + } + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8723D_1ANT_MAX) + rsp_source = BT_INFO_SRC_8723D_1ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt_info[%d], len=%d, data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + coex_sta->bt_info = coex_sta->bt_info_c2h[rsp_source][1]; + coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + coex_sta->bt_info_ext2 = coex_sta->bt_info_c2h[rsp_source][5]; + + if (BT_INFO_SRC_8723D_1ANT_WIFI_FW != rsp_source) { + + /* if 0xff, it means BT is under WHCK test */ + coex_sta->bt_whck_test = ((coex_sta->bt_info == 0xff) ? true : + false); + + coex_sta->bt_create_connection = (( + coex_sta->bt_info_c2h[rsp_source][2] & 0x80) ? true : + false); + + /* unit: %, value-100 to translate to unit: dBm */ + coex_sta->bt_rssi = coex_sta->bt_info_c2h[rsp_source][3] * 2 + + 10; + + coex_sta->c2h_bt_remote_name_req = (( + coex_sta->bt_info_c2h[rsp_source][2] & 0x20) ? true : + false); + + coex_sta->is_A2DP_3M = ((coex_sta->bt_info_c2h[rsp_source][2] & + 0x10) ? true : false); + + coex_sta->acl_busy = ((coex_sta->bt_info_c2h[rsp_source][1] & + 0x9) ? true : false); + + coex_sta->voice_over_HOGP = ((coex_sta->bt_info_ext & 0x10) ? + true : false); + + coex_sta->c2h_bt_inquiry_page = ((coex_sta->bt_info & + BT_INFO_8723D_1ANT_B_INQ_PAGE) ? true : false); + + coex_sta->a2dp_bit_pool = ((( + coex_sta->bt_info_c2h[rsp_source][1] & 0x49) == 0x49) ? + coex_sta->bt_info_c2h[rsp_source][6] : 0); + + coex_sta->bt_retry_cnt = coex_sta->bt_info_c2h[rsp_source][2] & + 0xf; + + coex_sta->is_autoslot = coex_sta->bt_info_ext2 & 0x8; + + coex_sta->forbidden_slot = coex_sta->bt_info_ext2 & 0x7; + + coex_sta->hid_busy_num = (coex_sta->bt_info_ext2 & 0x30) >> 4; + + coex_sta->hid_pair_cnt = (coex_sta->bt_info_ext2 & 0xc0) >> 6; + + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->c2h_bt_remote_name_req) + coex_sta->cnt_RemoteNameReq++; + + if (coex_sta->bt_info_ext & BIT(1)) + coex_sta->cnt_ReInit++; + + if (coex_sta->bt_info_ext & BIT(2)) { + coex_sta->cnt_setupLink++; + coex_sta->is_setupLink = true; + } else + coex_sta->is_setupLink = false; + + if (coex_sta->bt_info_ext & BIT(3)) + coex_sta->cnt_IgnWlanAct++; + + if (coex_sta->bt_info_ext & BIT(6)) + coex_sta->cnt_RoleSwitch++; + + if (coex_sta->bt_create_connection) { + coex_sta->cnt_Page++; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &wifi_link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &wifi_roam); + + if ((wifi_link) || (wifi_roam) || (wifi_scan) || + (coex_sta->wifi_is_high_pri_task) || (wifi_busy)) { + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_SCAN, true); + + } else { + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_SCAN, false); + } + } else + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_SCAN, false); + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + + if ((!btcoexist->manual_control) && + (!btcoexist->stop_coex_dm)) { + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* Re-Init */ + if ((coex_sta->bt_info_ext & BIT(1))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + if (wifi_connected) + halbtc8723d1ant_update_wifi_channel_info( + btcoexist, BTC_MEDIA_CONNECT); + else + halbtc8723d1ant_update_wifi_channel_info( + btcoexist, + BTC_MEDIA_DISCONNECT); + } + + + /* If Ignore_WLanAct && not SetUp_Link or Role_Switch */ + if ((coex_sta->bt_info_ext & BIT(3)) && + (!(coex_sta->bt_info_ext & BIT(2))) && + (!(coex_sta->bt_info_ext & BIT(6)))) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8723d1ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, false); + } else { + if (coex_sta->bt_info_ext & BIT(2)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ignore Wlan active because Re-link!!\n"); + BTC_TRACE(trace_buf); + } else if (coex_sta->bt_info_ext & BIT(6)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ignore Wlan active because Role-Switch!!\n"); + BTC_TRACE(trace_buf); + } + } + } + + } + + if ((coex_sta->bt_info_ext & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit4 check, query BLE Scan type!!\n"); + BTC_TRACE(trace_buf); + coex_sta->bt_ble_scan_type = btcoexist->btc_get_ble_scan_type_from_bt(btcoexist); + + if ((coex_sta->bt_ble_scan_type & 0x1) == 0x1) + coex_sta->bt_ble_scan_para[0] = btcoexist->btc_get_ble_scan_para_from_bt(btcoexist, 0x1); + if ((coex_sta->bt_ble_scan_type & 0x2) == 0x2) + coex_sta->bt_ble_scan_para[1] = btcoexist->btc_get_ble_scan_para_from_bt(btcoexist, 0x2); + if ((coex_sta->bt_ble_scan_type & 0x4) == 0x4) + coex_sta->bt_ble_scan_para[2] = btcoexist->btc_get_ble_scan_para_from_bt(btcoexist, 0x4); + } + + halbtc8723d1ant_update_bt_link_info(btcoexist); + + halbtc8723d1ant_run_coexist_mechanism(btcoexist); +} + + + +void ex_halbtc8723d1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], RF Status notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_RF_ON == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned ON!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = false; + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, true); + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ONOFF, true); + + } else if (BTC_RF_OFF == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned OFF!!\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ONOFF, false); + + halbtc8723d1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_WLAN_OFF); + + btcoexist->stop_coex_dm = true; + } +} + +void ex_halbtc8723d1ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ONOFF, false); + + halbtc8723d1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8723D_1ANT_PHASE_WLAN_OFF); + + halbtc8723d1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + ex_halbtc8723d1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + btcoexist->stop_coex_dm = true; +} + +void ex_halbtc8723d1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Pnp notify\n"); + BTC_TRACE(trace_buf); + + if ((BTC_WIFI_PNP_SLEEP == pnp_state) || + (BTC_WIFI_PNP_SLEEP_KEEP_ANT == pnp_state)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ONOFF, false); + + if (BTC_WIFI_PNP_SLEEP_KEEP_ANT == pnp_state) { + + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + } else { + + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_WLAN_OFF); + } + + btcoexist->stop_coex_dm = true; + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ACTIVE, true); + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_ONOFF, true); + + btcoexist->stop_coex_dm = false; + } +} + + +void ex_halbtc8723d1ant_coex_dm_reset(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], *****************Coex DM Reset*****************\n"); + BTC_TRACE(trace_buf); + + halbtc8723d1ant_init_hw_config(btcoexist, false, false); + halbtc8723d1ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8723d1ant_periodical(IN struct btc_coexist *btcoexist) +{ + + struct btc_board_info *board_info = &btcoexist->board_info; + boolean wifi_busy = false; + u4Byte value = 0; + u32 bt_patch_ver; + static u8 cnt = 0; + boolean bt_relink_finish = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ************* Periodical *************\n"); + BTC_TRACE(trace_buf); + +#if (BT_AUTO_REPORT_ONLY_8723D_1ANT == 0) + halbtc8723d1ant_query_bt_info(btcoexist); + +#endif + + halbtc8723d1ant_monitor_bt_ctr(btcoexist); + halbtc8723d1ant_monitor_wifi_ctr(btcoexist); + + halbtc8723d1ant_monitor_bt_enable_disable(btcoexist); + +# if 1 + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + /* halbtc8723d1ant_read_score_board(btcoexist, &bt_scoreboard_val); */ + + if (wifi_busy) { + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_UNDERTEST, true); + /* + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_WLBUSY, true); + + if (bt_scoreboard_val & BIT(6)) + halbtc8723d1ant_query_bt_info(btcoexist); */ + } else { + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_UNDERTEST, false); + /* + halbtc8723d1ant_post_state_to_bt(btcoexist, + BT_8723D_1ANT_SCOREBOARD_WLBUSY, + false); */ + } +#endif + + if (coex_sta->bt_relink_downcount != 0) { + coex_sta->bt_relink_downcount--; + + if (coex_sta->bt_relink_downcount == 0) + bt_relink_finish = true; + } + + /* for 4-way, DHCP, EAPOL packet */ + if (coex_sta->specific_pkt_period_cnt > 0) { + + coex_sta->specific_pkt_period_cnt--; + + if ((coex_sta->specific_pkt_period_cnt == 0) && + (coex_sta->wifi_is_high_pri_task)) + coex_sta->wifi_is_high_pri_task = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ***************** Hi-Pri Task = %s*****************\n", + (coex_sta->wifi_is_high_pri_task ? "Yes" : + "No")); + BTC_TRACE(trace_buf); + + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->bt_coex_supported_feature == 0) + btcoexist->btc_get(btcoexist, BTC_GET_U4_SUPPORTED_FEATURE, + &coex_sta->bt_coex_supported_feature); + + if ((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) + btcoexist->btc_get(btcoexist, BTC_GET_U4_SUPPORTED_VERSION, + &coex_sta->bt_coex_supported_version); + + if (coex_sta->bt_reg_vendor_ac == 0xffff) + coex_sta->bt_reg_vendor_ac = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, + 0xac) & 0xffff); + + if (coex_sta->bt_reg_vendor_ae == 0xffff) + coex_sta->bt_reg_vendor_ae = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, + 0xae) & 0xffff); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, + &bt_patch_ver); + btcoexist->bt_info.bt_get_fw_ver = bt_patch_ver; + + if (coex_sta->num_of_profile > 0) { + cnt++; + + if (cnt >= 3) { + btcoexist->btc_get_bt_afh_map_from_bt(btcoexist, 0, + &coex_sta->bt_afh_map[0]); + cnt = 0; + } + } + +#if BT_8723D_1ANT_ANTDET_ENABLE + + if (board_info->btdm_ant_det_finish) { + if ((psd_scan->ant_det_result == 12) && + (psd_scan->ant_det_psd_scan_peak_val == 0) + && (!psd_scan->is_AntDet_running)) { + psd_scan->ant_det_psd_scan_peak_val = + btcoexist->btc_get_ant_det_val_from_bt( + btcoexist) * 100; + + board_info->antdetval = psd_scan->ant_det_psd_scan_peak_val/100; + value = board_info->antdetval; + +#ifdef PLATFORM_WINDOWS + { + PWCHAR registryName; + + registryName = L"antdetval"; + PlatformWriteCommonDwordRegistry(registryName, &value); + } +#endif + } + } + +#endif + } + + if (halbtc8723d1ant_is_wifibt_status_changed(btcoexist)) + halbtc8723d1ant_run_coexist_mechanism(btcoexist); + + +} + +void ex_halbtc8723d1ant_set_antenna_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (type == 2) { /* two antenna */ + board_info->ant_div_cfg = true; + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + } else { /* one antenna */ + halbtc8723d1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + } +} + +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +void ex_halbtc8723d1ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ + + static u32 ant_det_count = 0, ant_det_fail_count = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + u16 u16tmp; + u8 AntDetval = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Ext Call AntennaDetect()!!\n"); + BTC_TRACE(trace_buf); + +#if BT_8723D_1ANT_ANTDET_ENABLE + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Call AntennaDetect()!!\n"); + BTC_TRACE(trace_buf); + + if (seconds == 0) { + psd_scan->ant_det_try_count = 0; + psd_scan->ant_det_fail_count = 0; + ant_det_count = 0; + ant_det_fail_count = 0; + board_info->btdm_ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + return; + } + + if (!board_info->btdm_ant_det_finish) { + psd_scan->ant_det_inteval_count = + psd_scan->ant_det_inteval_count + 2; + + if (psd_scan->ant_det_inteval_count >= + BT_8723D_2ANT_ANTDET_RETRY_INTERVAL) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Timer is up, Try Detect!!\n"); + BTC_TRACE(trace_buf); + + psd_scan->is_AntDet_running = true; + + halbtc8723d1ant_read_score_board(btcoexist, &u16tmp); + + if (u16tmp & BIT( + 2)) { /* Antenna detection is already done before last WL power on */ + board_info->btdm_ant_det_finish = true; + psd_scan->ant_det_try_count = 1; + psd_scan->ant_det_fail_count = 0; + board_info->btdm_ant_num_by_ant_det = (u16tmp & + BIT(3)) ? 1 : 2; + psd_scan->ant_det_result = 12; + + psd_scan->ant_det_psd_scan_peak_val = + btcoexist->btc_get_ant_det_val_from_bt( + btcoexist) * 100; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Result from BT (%d-Ant)\n", + board_info->btdm_ant_num_by_ant_det); + BTC_TRACE(trace_buf); + } else + board_info->btdm_ant_det_finish = + halbtc8723d1ant_psd_antenna_detection_check( + btcoexist); + + board_info->ant_det_result = psd_scan->ant_det_result; + btcoexist->bdontenterLPS = false; + + if (board_info->btdm_ant_det_finish) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Success!!\n"); + BTC_TRACE(trace_buf); + + if (board_info->btdm_ant_num_by_ant_det == 2) { + board_info->ant_div_cfg = true; + halbtc8723d1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_WIFI, FORCE_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + } else + halbtc8723d1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8723D_1ANT_PHASE_2G_RUNTIME); + + /*for 8723d, btc_set_bt_trx_mask is just used to + notify BT stop le tx and Ant Det Result , not set BT RF TRx Mask */ + if (psd_scan->ant_det_result != 12) { + + AntDetval = (u8)( + psd_scan->ant_det_psd_scan_peak_val + / 100) & 0x7f; + + AntDetval = + (board_info->btdm_ant_num_by_ant_det + == 1) ? (AntDetval | 0x80) : + AntDetval; + board_info->antdetval = AntDetval; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Ant Count = %d, PSD Val = %d\n", + ((AntDetval & + 0x80) ? 1 + : 2), AntDetval + & 0x7f); + BTC_TRACE(trace_buf); + + if (btcoexist->btc_set_bt_trx_mask( + btcoexist, AntDetval)) + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Notify BT stop le tx by set_bt_trx_mask ok!\n"); + else + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Notify BT stop le tx by set_bt_trx_mask fail!\n"); + + BTC_TRACE(trace_buf); + } else + board_info->antdetval = + psd_scan->ant_det_psd_scan_peak_val/100; + + board_info->btdm_ant_det_complete_fail = false; + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Fail!!\n"); + BTC_TRACE(trace_buf); + + board_info->btdm_ant_det_complete_fail = true; + } + + psd_scan->ant_det_inteval_count = 0; + psd_scan->is_AntDet_running = false; + /* stimulate coex running */ + halbtc8723d1ant_run_coexist_mechanism( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Stimulate Coex running\n!!"); + BTC_TRACE(trace_buf); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Timer is not up! (%d)\n", + psd_scan->ant_det_inteval_count); + BTC_TRACE(trace_buf); + + if (psd_scan->ant_det_inteval_count == 8) + btcoexist->bdontenterLPS = true; + else + btcoexist->bdontenterLPS = false; + } + + } +#endif + + +} + + +void ex_halbtc8723d1ant_display_ant_detection(IN struct btc_coexist *btcoexist) +{ +#if BT_8723D_1ANT_ANTDET_ENABLE + struct btc_board_info *board_info = &btcoexist->board_info; + + if (psd_scan->ant_det_try_count != 0) { + halbtc8723d1ant_psd_show_antenna_detect_result(btcoexist); + + if (board_info->btdm_ant_det_finish) + halbtc8723d1ant_psd_showdata(btcoexist); + } +#endif + +} + +void ex_halbtc8723d1ant_antenna_isolation(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ + + +} + +void ex_halbtc8723d1ant_psd_scan(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ + + +} + + +#endif + +#endif /* #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) */ + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d1ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d1ant.h new file mode 100644 index 0000000..76edd5a --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d1ant.h @@ -0,0 +1,413 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8723D_SUPPORT == 1) + +/* ******************************************* + * The following is for 8723D 1ANT BT Co-exist definition + * ******************************************* */ +#define BT_8723D_1ANT_COEX_DBG 0 +#define BT_AUTO_REPORT_ONLY_8723D_1ANT 1 + +#define BT_INFO_8723D_1ANT_B_FTP BIT(7) +#define BT_INFO_8723D_1ANT_B_A2DP BIT(6) +#define BT_INFO_8723D_1ANT_B_HID BIT(5) +#define BT_INFO_8723D_1ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8723D_1ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8723D_1ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8723D_1ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8723D_1ANT_B_CONNECTION BIT(0) + +#define BT_INFO_8723D_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT(0))) ? true : false) + +#define BTC_RSSI_COEX_THRESH_TOL_8723D_1ANT 2 + +#define BT_8723D_1ANT_WIFI_NOISY_THRESH 30 /* max: 255 */ +#define BT_8723D_1ANT_DEFAULT_ISOLATION 15 /* unit: dB */ + + +/* for Antenna detection */ +#define BT_8723D_1ANT_ANTDET_PSDTHRES_BACKGROUND 50 +#define BT_8723D_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION 70 +#define BT_8723D_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION 55 +#define BT_8723D_1ANT_ANTDET_PSDTHRES_1ANT 35 +#define BT_8723D_1ANT_ANTDET_RETRY_INTERVAL 10 /* retry timer if ant det is fail, unit: second */ +#define BT_8723D_1ANT_ANTDET_SWEEPPOINT_DELAY 60000 +#define BT_8723D_1ANT_ANTDET_ENABLE 1 +#define BT_8723D_1ANT_ANTDET_BTTXTIME 100 +#define BT_8723D_1ANT_ANTDET_BTTXCHANNEL 39 +#define BT_8723D_1ANT_ANTDET_PSD_SWWEEPCOUNT 50 + +#define BT_8723D_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT 30000 + +enum bt_8723d_1ant_signal_state { + BT_8723D_1ANT_SIG_STA_SET_TO_LOW = 0x0, + BT_8723D_1ANT_SIG_STA_SET_BY_HW = 0x0, + BT_8723D_1ANT_SIG_STA_SET_TO_HIGH = 0x1, + BT_8723D_1ANT_SIG_STA_MAX +}; + +enum bt_8723d_1ant_path_ctrl_owner { + BT_8723D_1ANT_PCO_BTSIDE = 0x0, + BT_8723D_1ANT_PCO_WLSIDE = 0x1, + BT_8723D_1ANT_PCO_MAX +}; + +enum bt_8723d_1ant_gnt_ctrl_type { + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_PTA = 0x0, + BT_8723D_1ANT_GNT_TYPE_CTRL_BY_SW = 0x1, + BT_8723D_1ANT_GNT_TYPE_MAX +}; + +enum bt_8723d_1ant_gnt_ctrl_block { + BT_8723D_1ANT_GNT_BLOCK_RFC_BB = 0x0, + BT_8723D_1ANT_GNT_BLOCK_RFC = 0x1, + BT_8723D_1ANT_GNT_BLOCK_BB = 0x2, + BT_8723D_1ANT_GNT_BLOCK_MAX +}; + +enum bt_8723d_1ant_lte_coex_table_type { + BT_8723D_1ANT_CTT_WL_VS_LTE = 0x0, + BT_8723D_1ANT_CTT_BT_VS_LTE = 0x1, + BT_8723D_1ANT_CTT_MAX +}; + +enum bt_8723d_1ant_lte_break_table_type { + BT_8723D_1ANT_LBTT_WL_BREAK_LTE = 0x0, + BT_8723D_1ANT_LBTT_BT_BREAK_LTE = 0x1, + BT_8723D_1ANT_LBTT_LTE_BREAK_WL = 0x2, + BT_8723D_1ANT_LBTT_LTE_BREAK_BT = 0x3, + BT_8723D_1ANT_LBTT_MAX +}; + +enum bt_info_src_8723d_1ant { + BT_INFO_SRC_8723D_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723D_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723D_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723D_1ANT_MAX +}; + +enum bt_8723d_1ant_bt_status { + BT_8723D_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723D_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723D_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8723D_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8723D_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8723D_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8723D_1ANT_BT_STATUS_MAX +}; + +enum bt_8723d_1ant_wifi_status { + BT_8723D_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723D_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8723D_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8723D_1ANT_WIFI_STATUS_CONNECTED_SPECIFIC_PKT = 0x3, + BT_8723D_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8723D_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8723D_1ANT_WIFI_STATUS_MAX +}; + +enum bt_8723d_1ant_coex_algo { + BT_8723D_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723D_1ANT_COEX_ALGO_SCO = 0x1, + BT_8723D_1ANT_COEX_ALGO_HID = 0x2, + BT_8723D_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8723D_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8723D_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8723D_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8723D_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8723D_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8723D_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8723D_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8723D_1ANT_COEX_ALGO_MAX = 0xb, +}; + +enum bt_8723d_1ant_phase { + BT_8723D_1ANT_PHASE_COEX_INIT = 0x0, + BT_8723D_1ANT_PHASE_WLANONLY_INIT = 0x1, + BT_8723D_1ANT_PHASE_WLAN_OFF = 0x2, + BT_8723D_1ANT_PHASE_2G_RUNTIME = 0x3, + BT_8723D_1ANT_PHASE_5G_RUNTIME = 0x4, + BT_8723D_1ANT_PHASE_BTMPMODE = 0x5, + BT_8723D_1ANT_PHASE_ANTENNA_DET = 0x6, + BT_8723D_1ANT_PHASE_COEX_POWERON = 0x7, + BT_8723D_1ANT_PHASE_MAX +}; + +enum bt_8723d_1ant_Scoreboard { + BT_8723D_1ANT_SCOREBOARD_ACTIVE = BIT(0), + BT_8723D_1ANT_SCOREBOARD_ONOFF = BIT(1), + BT_8723D_1ANT_SCOREBOARD_SCAN = BIT(2), + BT_8723D_1ANT_SCOREBOARD_UNDERTEST = BIT(3), + BT_8723D_1ANT_SCOREBOARD_WLBUSY = BIT(6) +}; + +struct coex_dm_8723d_1ant { + /* hw setting */ + u8 pre_ant_pos_type; + u8 cur_ant_pos_type; + /* fw mechanism */ + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + /* sw mechanism */ + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + boolean limited_dig; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u32 pre_ra_mask; + u32 cur_ra_mask; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; + u32 arp_cnt; + + u8 error_condition; +}; + +struct coex_sta_8723d_1ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + boolean bt_hi_pri_link_exist; + u8 num_of_profile; + + boolean under_lps; + boolean under_ips; + u32 specific_pkt_period_cnt; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + boolean is_hiPri_rx_overhead; + s8 bt_rssi; + boolean bt_tx_rx_mask; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + u8 bt_info_c2h[BT_INFO_SRC_8723D_1ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8723D_1ANT_MAX]; + boolean bt_whck_test; + boolean c2h_bt_inquiry_page; + boolean c2h_bt_remote_name_req; + boolean c2h_bt_page; /* Add for win8.1 page out issue */ + boolean wifi_is_high_pri_task; /* Add for win8.1 page out issue */ + u8 bt_retry_cnt; + u8 bt_info_ext; + u8 bt_info_ext2; + u32 pop_event_cnt; + u8 scan_ap_num; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_vht; + + boolean cck_lock; + boolean pre_ccklock; + boolean cck_ever_lock; + u8 coex_table_type; + + boolean force_lps_on; + + boolean concurrent_rx_mode_on; + + u16 score_board; + u8 isolation_btween_wb; /* 0~ 50 */ + + u8 a2dp_bit_pool; + u8 cut_version; + boolean acl_busy; + boolean bt_create_connection; + + u32 bt_coex_supported_feature; + u32 bt_coex_supported_version; + + u8 bt_ble_scan_type; + u32 bt_ble_scan_para[3]; + + boolean run_time_state; + boolean freeze_coexrun_by_btinfo; + + boolean is_A2DP_3M; + boolean voice_over_HOGP; + u8 bt_info; + boolean is_autoslot; + u8 forbidden_slot; + u8 hid_busy_num; + u8 hid_pair_cnt; + + u32 cnt_RemoteNameReq; + u32 cnt_setupLink; + u32 cnt_ReInit; + u32 cnt_IgnWlanAct; + u32 cnt_Page; + u32 cnt_RoleSwitch; + + u16 bt_reg_vendor_ac; + u16 bt_reg_vendor_ae; + + boolean is_setupLink; + u8 wl_noisy_level; + u32 gnt_error_cnt; + + u8 bt_afh_map[10]; + u8 bt_relink_downcount; + boolean is_tdma_btautoslot; + boolean is_tdma_btautoslot_hang; +}; + +#define BT_8723D_1ANT_ANTDET_PSD_POINTS 256 /* MAX:1024 */ +#define BT_8723D_1ANT_ANTDET_PSD_AVGNUM 1 /* MAX:3 */ +#define BT_8723D_1ANT_ANTDET_BUF_LEN 16 + +struct psdscan_sta_8723d_1ant { + + u32 ant_det_bt_le_channel; /* BT LE Channel ex:2412 */ + u32 ant_det_bt_tx_time; + u32 ant_det_pre_psdscan_peak_val; + boolean ant_det_is_ant_det_available; + u32 ant_det_psd_scan_peak_val; + boolean ant_det_is_btreply_available; + u32 ant_det_psd_scan_peak_freq; + + u8 ant_det_result; + u8 ant_det_peak_val[BT_8723D_1ANT_ANTDET_BUF_LEN]; + u8 ant_det_peak_freq[BT_8723D_1ANT_ANTDET_BUF_LEN]; + u32 ant_det_try_count; + u32 ant_det_fail_count; + u32 ant_det_inteval_count; + u32 ant_det_thres_offset; + + u32 real_cent_freq; + s32 real_offset; + u32 real_span; + + u32 psd_band_width; /* unit: Hz */ + u32 psd_point; /* 128/256/512/1024 */ + u32 psd_report[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_report_max_hold[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_start_point; + u32 psd_stop_point; + u32 psd_max_value_point; + u32 psd_max_value; + u32 psd_max_value2; + u32 psd_avg_value; /* filter loop_max_value that below BT_8723D_1ANT_ANTDET_PSDTHRES_1ANT, and average the rest*/ + u32 psd_loop_max_value[BT_8723D_1ANT_ANTDET_PSD_SWWEEPCOUNT]; /*max value in each loop */ + u32 psd_start_base; + u32 psd_avg_num; /* 1/8/16/32 */ + u32 psd_gen_count; + boolean is_AntDet_running; + boolean is_psd_show_max_only; +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8723d1ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8723d1ant_pre_load_firmware(IN struct btc_coexist *btcoexist); +void ex_halbtc8723d1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8723d1ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8723d1ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d1ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8723d1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d1ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8723d1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state); +void ex_halbtc8723d1ant_coex_dm_reset(IN struct btc_coexist *btcoexist); +void ex_halbtc8723d1ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8723d1ant_set_antenna_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d1ant_display_coex_info(IN struct btc_coexist *btcoexist); +void ex_halbtc8723d1ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); +void ex_halbtc8723d1ant_antenna_isolation(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); + +void ex_halbtc8723d1ant_psd_scan(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); +void ex_halbtc8723d1ant_display_ant_detection(IN struct btc_coexist *btcoexist); + +#else +#define ex_halbtc8723d1ant_power_on_setting(btcoexist) +#define ex_halbtc8723d1ant_pre_load_firmware(btcoexist) +#define ex_halbtc8723d1ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8723d1ant_init_coex_dm(btcoexist) +#define ex_halbtc8723d1ant_ips_notify(btcoexist, type) +#define ex_halbtc8723d1ant_lps_notify(btcoexist, type) +#define ex_halbtc8723d1ant_scan_notify(btcoexist, type) +#define ex_halbtc8723d1ant_connect_notify(btcoexist, type) +#define ex_halbtc8723d1ant_media_status_notify(btcoexist, type) +#define ex_halbtc8723d1ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8723d1ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8723d1ant_rf_status_notify(btcoexist, type) +#define ex_halbtc8723d1ant_halt_notify(btcoexist) +#define ex_halbtc8723d1ant_pnp_notify(btcoexist, pnp_state) +#define ex_halbtc8723d1ant_coex_dm_reset(btcoexist) +#define ex_halbtc8723d1ant_periodical(btcoexist) +#define ex_halbtc8723d1ant_display_coex_info(btcoexist) +#define ex_halbtc8723d1ant_set_antenna_notify(btcoexist, type) +#define ex_halbtc8723d1ant_antenna_detection(btcoexist, cent_freq, offset, span, seconds) +#define ex_halbtc8723d1ant_antenna_isolation(btcoexist, cent_freq, offset, span, seconds) +#define ex_halbtc8723d1ant_psd_scan(btcoexist, cent_freq, offset, span, seconds) +#define ex_halbtc8723d1ant_display_ant_detection(btcoexist) +#endif + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d2ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d2ant.c new file mode 100644 index 0000000..da21d95 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d2ant.c @@ -0,0 +1,6774 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8723D Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8723D_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8723d_2ant glcoex_dm_8723d_2ant; +static struct coex_dm_8723d_2ant *coex_dm = &glcoex_dm_8723d_2ant; +static struct coex_sta_8723d_2ant glcoex_sta_8723d_2ant; +static struct coex_sta_8723d_2ant *coex_sta = &glcoex_sta_8723d_2ant; +static struct psdscan_sta_8723d_2ant gl_psd_scan_8723d_2ant; +static struct psdscan_sta_8723d_2ant *psd_scan = &gl_psd_scan_8723d_2ant; + +const char *const glbt_info_src_8723d_2ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; +/* ************************************************************ + * BtCoex Version Format: + * 1. date : glcoex_ver_date_XXXXX_1ant + * 2. WifiCoexVersion : glcoex_ver_XXXX_1ant + * 3. BtCoexVersion : glcoex_ver_btdesired_XXXXX_1ant + * 4. others : glcoex_ver_XXXXXX_XXXXX_1ant + * + * Variable should be indicated IC and Antenna numbers !!! + * Please strictly follow this order and naming style !!! + * + * ************************************************************ */ +u32 glcoex_ver_date_8723d_2ant = 20161027; +u32 glcoex_ver_8723d_2ant = 0x0f; +u32 glcoex_ver_btdesired_8723d_2ant = 0x0d; + + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8723d2ant_ + * ************************************************************ */ +u8 halbtc8723d2ant_bt_rssi_state(u8 *ppre_bt_rssi_state, u8 level_num, + u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = *ppre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723D_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return *ppre_bt_rssi_state; + } + + if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723D_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_MEDIUM) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723D_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + *ppre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8723d2ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 *pprewifi_rssi_state, IN u8 level_num, IN u8 rssi_thresh, + IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = *pprewifi_rssi_state; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((*pprewifi_rssi_state == BTC_RSSI_STATE_LOW) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723D_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return *pprewifi_rssi_state; + } + + if ((*pprewifi_rssi_state == BTC_RSSI_STATE_LOW) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8723D_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((*pprewifi_rssi_state == BTC_RSSI_STATE_MEDIUM) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8723D_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + *pprewifi_rssi_state = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8723d2ant_coex_switch_threshold(IN struct btc_coexist *btcoexist, + IN u8 isolation_measuared) +{ + s8 interference_wl_tx = 0, interference_bt_tx = 0; + + + interference_wl_tx = BT_8723D_2ANT_WIFI_MAX_TX_POWER - + isolation_measuared; + interference_bt_tx = BT_8723D_2ANT_BT_MAX_TX_POWER - + isolation_measuared; + + + + coex_sta->wifi_coex_thres = BT_8723D_2ANT_WIFI_RSSI_COEXSWITCH_THRES1; + coex_sta->wifi_coex_thres2 = BT_8723D_2ANT_WIFI_RSSI_COEXSWITCH_THRES2; + + coex_sta->bt_coex_thres = BT_8723D_2ANT_BT_RSSI_COEXSWITCH_THRES1; + coex_sta->bt_coex_thres2 = BT_8723D_2ANT_BT_RSSI_COEXSWITCH_THRES2; + + + /* + coex_sta->wifi_coex_thres = interference_wl_tx + BT_8723D_2ANT_WIFI_SIR_THRES1; + coex_sta->wifi_coex_thres2 = interference_wl_tx + BT_8723D_2ANT_WIFI_SIR_THRES2; + + coex_sta->bt_coex_thres = interference_bt_tx + BT_8723D_2ANT_BT_SIR_THRES1; + coex_sta->bt_coex_thres2 = interference_bt_tx + BT_8723D_2ANT_BT_SIR_THRES2; + */ + + + + + + /* + if ( BT_8723D_2ANT_WIFI_RSSI_COEXSWITCH_THRES1 < (isolation_measuared - + BT_8723D_2ANT_DEFAULT_ISOLATION) ) + coex_sta->wifi_coex_thres = BT_8723D_2ANT_WIFI_RSSI_COEXSWITCH_THRES1; + else + coex_sta->wifi_coex_thres = BT_8723D_2ANT_WIFI_RSSI_COEXSWITCH_THRES1 - (isolation_measuared - + BT_8723D_2ANT_DEFAULT_ISOLATION); + + if ( BT_8723D_2ANT_BT_RSSI_COEXSWITCH_THRES1 < (isolation_measuared - + BT_8723D_2ANT_DEFAULT_ISOLATION) ) + coex_sta->bt_coex_thres = BT_8723D_2ANT_BT_RSSI_COEXSWITCH_THRES1; + else + coex_sta->bt_coex_thres = BT_8723D_2ANT_BT_RSSI_COEXSWITCH_THRES1 - (isolation_measuared - + BT_8723D_2ANT_DEFAULT_ISOLATION); + + */ +} + + +void halbtc8723d2ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); +} + +void halbtc8723d2ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +void halbtc8723d2ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + static u8 num_of_bt_counter_chk = 0, cnt_slave = 0, cnt_overhead = 0, + cnt_autoslot_hang = 0; + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + if (BT_8723D_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + + if (coex_sta->high_priority_rx >= 15) { + if (cnt_overhead < 3) + cnt_overhead++; + + if (cnt_overhead == 3) + coex_sta->is_hiPri_rx_overhead = true; + } else { + if (cnt_overhead > 0) + cnt_overhead--; + + if (cnt_overhead == 0) + coex_sta->is_hiPri_rx_overhead = false; + } + } + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + if ((coex_sta->low_priority_tx > 1050) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + + if ((coex_sta->low_priority_rx >= 950) && + (coex_sta->low_priority_rx >= coex_sta->low_priority_tx) + && (!coex_sta->under_ips) && (!coex_sta->c2h_bt_inquiry_page) && + (coex_sta->bt_link_exist)) { + if (cnt_slave >= 2) { + bt_link_info->slave_role = true; + cnt_slave = 2; + } else + cnt_slave++; + } else { + if (cnt_slave == 0) { + bt_link_info->slave_role = false; + cnt_slave = 0; + } else + cnt_slave--; + + } + + if (coex_sta->is_tdma_btautoslot) { + if ((coex_sta->low_priority_tx >= 1300) && + (coex_sta->low_priority_rx <= 150)) { + if (cnt_autoslot_hang >= 2) { + coex_sta->is_tdma_btautoslot_hang = true; + cnt_autoslot_hang = 2; + } else + cnt_autoslot_hang++; + } else { + if (cnt_autoslot_hang == 0) { + coex_sta->is_tdma_btautoslot_hang = false; + cnt_autoslot_hang = 0; + } else + cnt_autoslot_hang--; + } + } + + if (!coex_sta->bt_disabled) { + + if ((coex_sta->high_priority_tx == 0) && + (coex_sta->high_priority_rx == 0) && + (coex_sta->low_priority_tx == 0) && + (coex_sta->low_priority_rx == 0)) { + num_of_bt_counter_chk++; + if (num_of_bt_counter_chk >= 3) { + halbtc8723d2ant_query_bt_info(btcoexist); + num_of_bt_counter_chk = 0; + } + } + } + +} + +void halbtc8723d2ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ +#if 1 + s32 wifi_rssi = 0; + boolean wifi_busy = false, wifi_under_b_mode = false, + wifi_scan = false; + boolean bt_idle = false, wl_idle = false; + static u8 cck_lock_counter = 0, wl_noisy_count0 = 0, + wl_noisy_count1 = 3, wl_noisy_count2 = 0; + u32 total_cnt, reg_val1, reg_val2, cck_cnt; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + coex_sta->crc_ok_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_CCK); + coex_sta->crc_ok_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_LEGACY); + coex_sta->crc_ok_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_HT); + coex_sta->crc_ok_11n_vht = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_VHT); + + coex_sta->crc_err_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_CCK); + coex_sta->crc_err_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_LEGACY); + coex_sta->crc_err_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_HT); + coex_sta->crc_err_11n_vht = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_VHT); + + cck_cnt = coex_sta->crc_ok_cck + coex_sta->crc_err_cck; + + if (cck_cnt > 250) { + if (wl_noisy_count2 < 3) + wl_noisy_count2++; + + if (wl_noisy_count2 == 3) { + wl_noisy_count0 = 0; + wl_noisy_count1 = 0; + } + } else if (cck_cnt < 50) { + if (wl_noisy_count0 < 3) + wl_noisy_count0++; + + if (wl_noisy_count0 == 3) { + wl_noisy_count1 = 0; + wl_noisy_count2 = 0; + } + } else { + if (wl_noisy_count1 < 3) + wl_noisy_count1++; + + if (wl_noisy_count1 == 3) { + wl_noisy_count0 = 0; + wl_noisy_count2 = 0; + } + } + + if (wl_noisy_count2 == 3) + coex_sta->wl_noisy_level = 2; + else if (wl_noisy_count1 == 3) + coex_sta->wl_noisy_level = 1; + else + coex_sta->wl_noisy_level = 0; + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + total_cnt = coex_sta->crc_ok_cck + coex_sta->crc_ok_11g + + coex_sta->crc_ok_11n + coex_sta->crc_ok_11n_vht; + + if ((coex_dm->bt_status == BT_8723D_2ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == BT_8723D_2ANT_BT_STATUS_ACL_SCO_BUSY) || + (coex_dm->bt_status == BT_8723D_2ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > (total_cnt - + coex_sta->crc_ok_cck)) { + if (cck_lock_counter < 3) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + + if (cck_lock_counter >= 3) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + if (coex_sta->cck_lock) + coex_sta->cck_ever_lock = true; + + coex_sta->pre_ccklock = coex_sta->cck_lock; + +#endif +} + + + +boolean halbtc8723d2ant_is_wifibt_status_changed(IN struct btc_coexist + *btcoexist) +{ + + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false, pre_bt_off = false, pre_bt_slave = false; + static u8 pre_hid_busy_num = 0, pre_wl_noisy_level = 0; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (coex_sta->bt_disabled != pre_bt_off) { + pre_bt_off = coex_sta->bt_disabled; + + if (coex_sta->bt_disabled) + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!\n"); + else + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is enabled !!\n"); + + BTC_TRACE(trace_buf); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->bt_reg_vendor_ac = 0xffff; + coex_sta->bt_reg_vendor_ae = 0xffff; + return true; + } + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + if (coex_sta->wl_noisy_level != pre_wl_noisy_level) { + pre_wl_noisy_level = coex_sta->wl_noisy_level; + return true; + } + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->hid_busy_num != pre_hid_busy_num) { + pre_hid_busy_num = coex_sta->hid_busy_num; + return true; + } + } + + if (bt_link_info->slave_role != pre_bt_slave) { + pre_bt_slave = bt_link_info->slave_role; + return true; + } + + return false; +} + +void halbtc8723d2ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + boolean bt_busy = false; + + + coex_sta->num_of_profile = 0; + + /* set link exist status */ + if (!(coex_sta->bt_info & BT_INFO_8723D_2ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (coex_sta->bt_info & BT_INFO_8723D_2ANT_B_FTP) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->pan_exist = false; + + if (coex_sta->bt_info & BT_INFO_8723D_2ANT_B_A2DP) { + coex_sta->a2dp_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->a2dp_exist = false; + + if (coex_sta->bt_info & BT_INFO_8723D_2ANT_B_HID) { + coex_sta->hid_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->hid_exist = false; + + if (coex_sta->bt_info & BT_INFO_8723D_2ANT_B_SCO_ESCO) { + coex_sta->sco_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->sco_exist = false; + + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + bt_link_info->acl_busy = coex_sta->acl_busy; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; + + if (coex_sta->bt_info & BT_INFO_8723D_2ANT_B_INQ_PAGE) { + coex_dm->bt_status = BT_8723D_2ANT_BT_STATUS_INQ_PAGE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Inq/page!!!\n"); + } else if (!(coex_sta->bt_info & BT_INFO_8723D_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8723D_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + } else if (coex_sta->bt_info == BT_INFO_8723D_2ANT_B_CONNECTION) { + /* connection exists but no busy */ + coex_dm->bt_status = BT_8723D_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if (((coex_sta->bt_info & BT_INFO_8723D_2ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8723D_2ANT_B_SCO_BUSY)) && + (coex_sta->bt_info & BT_INFO_8723D_2ANT_B_ACL_BUSY)) { + coex_dm->bt_status = BT_8723D_2ANT_BT_STATUS_ACL_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL SCO busy!!!\n"); + } else if ((coex_sta->bt_info & BT_INFO_8723D_2ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8723D_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8723D_2ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (coex_sta->bt_info & BT_INFO_8723D_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8723D_2ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8723D_2ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + } + + BTC_TRACE(trace_buf); + + if ((BT_8723D_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8723D_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8723D_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); +} + +void halbtc8723d2ant_update_wifi_channel_info(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + h2c_parameter[0] = + 0x1; /* enable BT AFH skip WL channel for 8723d because BT Rx LO interference */ + /* h2c_parameter[0] = 0x0; */ + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); + +} + +void halbtc8723d2ant_set_fw_dac_swing_level(IN struct btc_coexist *btcoexist, + IN u8 dac_swing_lvl) +{ + u8 h2c_parameter[1] = {0}; + + /* There are several type of dacswing */ + /* 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ + h2c_parameter[0] = dac_swing_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +void halbtc8723d2ant_fw_dac_swing_lvl(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 fw_dac_swing_lvl) +{ + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + + if (!force_exec) { + if (coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + halbtc8723d2ant_set_fw_dac_swing_level(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +void halbtc8723d2ant_set_fw_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN u8 dec_bt_pwr_lvl) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = dec_bt_pwr_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +void halbtc8723d2ant_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 dec_bt_pwr_lvl) +{ + coex_dm->cur_bt_dec_pwr_lvl = dec_bt_pwr_lvl; + + if (!force_exec) { + if (coex_dm->pre_bt_dec_pwr_lvl == coex_dm->cur_bt_dec_pwr_lvl) + return; + } + halbtc8723d2ant_set_fw_dec_bt_pwr(btcoexist, + coex_dm->cur_bt_dec_pwr_lvl); + + coex_dm->pre_bt_dec_pwr_lvl = coex_dm->cur_bt_dec_pwr_lvl; +} + +void halbtc8723d2ant_set_fw_low_penalty_ra(IN struct btc_coexist + *btcoexist, IN boolean low_penalty_ra) +{ +#if 1 + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* op_code, 0x6= Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT(0); + h2c_parameter[2] = + 0x00; /* normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[3] = 0xf7; /* MCS7 or OFDM54 */ + h2c_parameter[4] = 0xf8; /* MCS6 or OFDM48 */ + h2c_parameter[5] = 0xf9; /* MCS5 or OFDM36 */ + } + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +#endif +} + +void halbtc8723d2ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ +#if 1 + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + + halbtc8723d2ant_set_fw_low_penalty_ra(btcoexist, + coex_dm->cur_low_penalty_ra); + +#if 0 + if (low_penalty_ra) + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 15); + else + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 0); +#endif + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; + +#endif +} + +void halbtc8723d2ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8723d2ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8723d2ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8723d2ant_write_score_board( + IN struct btc_coexist *btcoexist, + IN u16 bitpos, + IN boolean state +) +{ + + static u16 originalval = 0x8002; + + if (state) + originalval = originalval | bitpos; + else + originalval = originalval & (~bitpos); + + + btcoexist->btc_write_2byte(btcoexist, 0xaa, originalval); + +} + +void halbtc8723d2ant_read_score_board( + IN struct btc_coexist *btcoexist, + IN u16 *score_board_val +) +{ + + *score_board_val = (btcoexist->btc_read_2byte(btcoexist, + 0xaa)) & 0x7fff; +} + + +void halbtc8723d2ant_post_state_to_bt( + IN struct btc_coexist *btcoexist, + IN u16 type, + IN boolean state +) +{ + + halbtc8723d2ant_write_score_board(btcoexist, (u16) type, state); + +} + +void halbtc8723d2ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false; + u16 u16tmp; + + /* This function check if bt is disabled */ +#if 0 + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + + +#else + + /* Read BT on/off status from scoreboard[1], enable this only if BT patch support this feature */ + halbtc8723d2ant_read_score_board(btcoexist, &u16tmp); + + bt_active = u16tmp & BIT(1); + + +#endif + + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } else { + + bt_disable_cnt++; + if (bt_disable_cnt >= 2) { + bt_disabled = true; + bt_disable_cnt = 2; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } + + if (bt_disabled) + halbtc8723d2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + else + halbtc8723d2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, true); + + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + coex_sta->bt_disabled = bt_disabled; + } + +} + + + +void halbtc8723d2ant_enable_gnt_to_gpio(IN struct btc_coexist *btcoexist, + boolean isenable) +{ +#if BT_8723D_2ANT_COEX_DBG + if (isenable) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x1); + + /* enable GNT_BT to GPIO debug */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x40, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x1, 0x0); + + /* 0x48[20] = 0 for GPIO14 = GNT_WL*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4a, 0x10, 0x0); + /* 0x40[17] = 0 for GPIO14 = GNT_WL*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x42, 0x02, 0x0); + + /* 0x66[9] = 0 for GPIO15 = GNT_BT*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x02, 0x0); + /* 0x66[7] = 0 + for GPIO15 = GNT_BT*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, 0x80, 0x0); + /* 0x8[8] = 0 for GPIO15 = GNT_BT*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x9, 0x1, 0x0); + + /* BT Vendor Reg 0x76[0] = 0 for GPIO15 = GNT_BT, this is not set here*/ + } else { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x0); + + /* Disable GNT_BT debug to GPIO, and enable chip_wakeup_host */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x40, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x1, 0x1); + + /* 0x48[20] = 0 for GPIO14 = GNT_WL*/ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4a, 0x10, 0x1); + } + +#endif +} + +u32 halbtc8723d2ant_ltecoex_indirect_read_reg(IN struct btc_coexist *btcoexist, + IN u16 reg_addr) +{ + u32 j = 0; + + + /* wait for ready bit before access 0x7c0 */ + btcoexist->btc_write_4byte(btcoexist, 0x7c0, 0x800F0000 | reg_addr); + + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x7c3)&BIT(5)) == 0) && + (j < BT_8723D_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + return btcoexist->btc_read_4byte(btcoexist, + 0x7c8); /* get read data */ + +} + +void halbtc8723d2ant_ltecoex_indirect_write_reg(IN struct btc_coexist + *btcoexist, + IN u16 reg_addr, IN u32 bit_mask, IN u32 reg_value) +{ + u32 val, i = 0, j = 0, bitpos = 0; + + + if (bit_mask == 0x0) + return; + if (bit_mask == 0xffffffff) { + btcoexist->btc_write_4byte(btcoexist, 0x7c4, + reg_value); /* put write data */ + + /* wait for ready bit before access 0x7c0 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x7c3)&BIT(5)) == 0) && + (j < BT_8723D_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + btcoexist->btc_write_4byte(btcoexist, 0x7c0, + 0xc00F0000 | reg_addr); + } else { + for (i = 0; i <= 31; i++) { + if (((bit_mask >> i) & 0x1) == 0x1) { + bitpos = i; + break; + } + } + + /* read back register value before write */ + val = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, + reg_addr); + val = (val & (~bit_mask)) | (reg_value << bitpos); + + btcoexist->btc_write_4byte(btcoexist, 0x7c4, + val); /* put write data */ + + /* wait for ready bit before access 0x7c0 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x7c3)&BIT(5)) == 0) && + (j < BT_8723D_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + btcoexist->btc_write_4byte(btcoexist, 0x7c0, + 0xc00F0000 | reg_addr); + + } + +} + +void halbtc8723d2ant_ltecoex_enable(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 val; + + val = (enable) ? 1 : 0; + halbtc8723d2ant_ltecoex_indirect_write_reg(btcoexist, 0x38, 0x80, + val); /* 0x38[7] */ + +} + +void halbtc8723d2ant_ltecoex_pathcontrol_owner(IN struct btc_coexist *btcoexist, + IN boolean wifi_control) +{ + u8 val; + + val = (wifi_control) ? 1 : 0; + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x4, + val); /* 0x70[26] */ + +} + +void halbtc8723d2ant_ltecoex_set_gnt_bt(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, val_orig = 0; + + if (!sw_control) + val = 0x0; + else if (state & 0x1) + val = 0x3; + else + val = 0x1; + + val_orig = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + + switch (control_block) { + case BT_8723D_2ANT_GNT_BLOCK_RFC_BB: + default: + val = ((val << 14) | (val << 10)) | (val_orig & 0xffff33ff); + break; + case BT_8723D_2ANT_GNT_BLOCK_RFC: + val = (val << 14) | (val_orig & 0xffff3fff); + break; + case BT_8723D_2ANT_GNT_BLOCK_BB: + val = (val << 10) | (val_orig & 0xfffff3ff); + break; + } + + halbtc8723d2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, 0xffffffff, val); +} + + +void halbtc8723d2ant_ltecoex_set_gnt_wl(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, val_orig = 0; + + if (!sw_control) + val = 0x0; + else if (state & 0x1) + val = 0x3; + else + val = 0x1; + + val_orig = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + + switch (control_block) { + case BT_8723D_2ANT_GNT_BLOCK_RFC_BB: + default: + val = ((val << 12) | (val << 8)) | (val_orig & 0xffffccff); + break; + case BT_8723D_2ANT_GNT_BLOCK_RFC: + val = (val << 12) | (val_orig & 0xffffcfff); + break; + case BT_8723D_2ANT_GNT_BLOCK_BB: + val = (val << 8) | (val_orig & 0xfffffcff); + break; + } + + halbtc8723d2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, 0xffffffff, val); +} + +void halbtc8723d2ant_ltecoex_set_coex_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u16 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8723D_2ANT_CTT_WL_VS_LTE: + reg_addr = 0xa0; + break; + case BT_8723D_2ANT_CTT_BT_VS_LTE: + reg_addr = 0xa4; + break; + } + + if (reg_addr != 0x0000) + halbtc8723d2ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xffff, table_content); /* 0xa0[15:0] or 0xa4[15:0] */ + + +} + + +void halbtc8723d2ant_ltecoex_set_break_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u8 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8723D_2ANT_LBTT_WL_BREAK_LTE: + reg_addr = 0xa8; + break; + case BT_8723D_2ANT_LBTT_BT_BREAK_LTE: + reg_addr = 0xac; + break; + case BT_8723D_2ANT_LBTT_LTE_BREAK_WL: + reg_addr = 0xb0; + break; + case BT_8723D_2ANT_LBTT_LTE_BREAK_BT: + reg_addr = 0xb4; + break; + } + + if (reg_addr != 0x0000) + halbtc8723d2ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xff, table_content); /* 0xa8[15:0] or 0xb4[15:0] */ + + +} + +void halbtc8723d2ant_set_wltoggle_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 interval, + IN u8 val0x6c4_b0, IN u8 val0x6c4_b1, IN u8 val0x6c4_b2, + IN u8 val0x6c4_b3) +{ + static u8 pre_h2c_parameter[6] = {0}; + u8 cur_h2c_parameter[6] = {0}; + u8 i, match_cnt = 0; + + cur_h2c_parameter[0] = 0x7; /* op_code, 0x7= wlan toggle slot*/ + + cur_h2c_parameter[1] = interval; + cur_h2c_parameter[2] = val0x6c4_b0; + cur_h2c_parameter[3] = val0x6c4_b1; + cur_h2c_parameter[4] = val0x6c4_b2; + cur_h2c_parameter[5] = val0x6c4_b3; + + if (!force_exec) { + for (i = 1; i <= 5; i++) { + if (cur_h2c_parameter[i] != pre_h2c_parameter[i]) + break; + + match_cnt++; + } + + if (match_cnt == 5) + return; + } + + for (i = 1; i <= 5; i++) + pre_h2c_parameter[i] = cur_h2c_parameter[i]; + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, cur_h2c_parameter); +} + +void halbtc8723d2ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8723d2ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8723d2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8723d2ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + u32 break_table; + u8 select_table; + + coex_sta->coex_table_type = type; + + if (coex_sta->concurrent_rx_mode_on == true) { + break_table = 0xf0ffffff; /* set WL hi-pri can break BT */ + select_table = + 0xb; /* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */ + } else { + break_table = 0xffffff; + select_table = 0x3; + } + + switch (type) { + case 0: + halbtc8723d2ant_coex_table(btcoexist, force_exec, + 0xffffffff, 0xffffffff, break_table, select_table); + break; + case 1: + halbtc8723d2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, break_table, select_table); + break; + case 2: + halbtc8723d2ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5a5a5a5a, break_table, select_table); + break; + case 3: + halbtc8723d2ant_coex_table(btcoexist, force_exec, + 0xaa555555, 0xaa5a5a5a, break_table, select_table); + break; + case 4: + halbtc8723d2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, break_table, select_table); + break; + case 5: + halbtc8723d2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x55555555, break_table, select_table); + break; + case 6: + halbtc8723d2ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0xfafafafa, break_table, select_table); + break; + case 7: + halbtc8723d2ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0xaa5a5a5a, break_table, select_table); + break; + case 8: + halbtc8723d2ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0xfafafafa, break_table, select_table); + break; + case 9: + halbtc8723d2ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0xaaaa5aaa, break_table, select_table); + break; + default: + break; + } +} + +void halbtc8723d2ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) { + h2c_parameter[0] |= BIT(0); /* function enable */ + } + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8723d2ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8723d2ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8723d2ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8723d2ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8723d2ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8723d2ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + u8 h2c_parameter[5] = {0, 0, 0, 0x40, 0}; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + /*halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); */ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + /*halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8);*/ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +void halbtc8723d2ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + case BTC_PS_LPS_ON: + halbtc8723d2ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8723d2ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + coex_sta->force_lps_on = true; + break; + case BTC_PS_LPS_OFF: + halbtc8723d2ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + default: + break; + } +} + + + +void halbtc8723d2ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + if (byte5 & BIT(2)) + coex_sta->is_tdma_btautoslot = true; + else + coex_sta->is_tdma_btautoslot = false; + + /* release bt-auto slot for auto-slot hang is detected!! */ + if (coex_sta->is_tdma_btautoslot) + if ((coex_sta->is_tdma_btautoslot_hang) || + (bt_link_info->slave_role)) + byte5 = byte5 & 0xfb; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], FW for AP mode\n"); + BTC_TRACE(trace_buf); + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + + halbtc8723d2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + } + } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + + halbtc8723d2ant_power_save_state( + btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } else { + halbtc8723d2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, + 0x0); + } + + + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +void halbtc8723d2ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + + static u8 psTdmaByte4Modify = 0x0, pre_psTdmaByte4Modify = 0x0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + if ((bt_link_info->slave_role) && (bt_link_info->a2dp_exist)) + psTdmaByte4Modify = 0x1; + else + psTdmaByte4Modify = 0x0; + + if (pre_psTdmaByte4Modify != psTdmaByte4Modify) { + + force_exec = true; + pre_psTdmaByte4Modify = psTdmaByte4Modify; + } + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + + if (coex_dm->cur_ps_tdma_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(off, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } + + + if (turn_on) { + switch (type) { + case 1: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x10, 0x03, 0x91, + 0x54 | psTdmaByte4Modify); + break; + case 2: + default: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x35, 0x03, 0x11, + 0x11 | psTdmaByte4Modify); + break; + case 3: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x3a, 0x3, 0x91, + 0x10 | psTdmaByte4Modify); + break; + case 4: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x21, 0x3, 0x91, + 0x10 | psTdmaByte4Modify); + break; + case 5: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x25, 0x3, 0x91, + 0x10 | psTdmaByte4Modify); + break; + case 6: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x10, 0x3, 0x91, + 0x10 | psTdmaByte4Modify); + break; + case 7: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x20, 0x3, 0x91, + 0x10 | psTdmaByte4Modify); + break; + case 8: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x15, 0x03, 0x11, + 0x11); + break; + case 10: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x30, 0x03, 0x11, + 0x10); + break; + case 11: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x35, 0x03, 0x11, + 0x10 | psTdmaByte4Modify); + break; + case 12: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x35, 0x03, 0x11, 0x11); + break; + case 13: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x1c, 0x03, 0x11, + 0x10 | psTdmaByte4Modify); + break; + case 14: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x20, 0x03, 0x11, + 0x11); + break; + case 15: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x10, 0x03, 0x11, + 0x14); + break; + case 16: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x10, 0x03, 0x11, + 0x15); + break; + case 21: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x30, 0x03, 0x11, + 0x10); + break; + case 22: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x25, 0x03, 0x11, + 0x10); + break; + case 23: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x10, 0x03, 0x11, + 0x10); + break; + case 51: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x10, 0x03, 0x91, + 0x10 | psTdmaByte4Modify); + break; + case 101: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x51, + 0x10, 0x03, 0x10, + 0x54 | psTdmaByte4Modify); + break; + case 102: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x61, + 0x35, 0x03, 0x11, + 0x11 | psTdmaByte4Modify); + break; + case 103: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x51, + 0x3a, 0x3, 0x10, + 0x50 | psTdmaByte4Modify); + break; + case 104: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x51, + 0x21, 0x3, 0x10, + 0x50 | psTdmaByte4Modify); + break; + case 105: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x51, + 0x25, 0x3, 0x10, + 0x50 | psTdmaByte4Modify); + break; + case 106: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x51, + 0x10, 0x3, 0x10, + 0x50 | psTdmaByte4Modify); + break; + case 107: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x51, + 0x20, 0x3, 0x10, + 0x50 | psTdmaByte4Modify); + break; + case 108: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x51, + 0x30, 0x3, 0x10, + 0x50 | psTdmaByte4Modify); + break; + case 109: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x55, + 0x10, 0x03, 0x10, + 0x54 | psTdmaByte4Modify); + break; + case 110: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x55, + 0x30, 0x03, 0x10, + 0x50 | psTdmaByte4Modify); + break; + case 111: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x65, + 0x25, 0x03, 0x11, + 0x11 | psTdmaByte4Modify); + break; + case 151: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x51, + 0x10, 0x03, 0x10, + 0x50 | psTdmaByte4Modify); + break; + } + } else { + /* disable PS tdma */ + switch (type) { + case 0: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x40, 0x0); + break; + case 1: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x48, 0x0); + break; + default: + halbtc8723d2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x40, 0x0); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void halbtc8723d2ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean force_exec, + IN u8 phase) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 u32tmp = 0; + boolean pg_ext_switch = false, is_hw_ant_div_on = false; + u8 h2c_parameter[2] = {0}; + u32 cnt_bt_cal_chk = 0; + u8 u8tmp0 = 0, u8tmp1 = 0; + boolean is_in_mp_mode = false; + u32 u32tmp0 = 0, u32tmp1 = 0, u32tmp2 = 0; + u16 u16tmp0 = 0, u16tmp1 = 0; + + + u32tmp1 = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + + /* To avoid indirect access fail */ + if (((u32tmp1 & 0xf000) >> 12) != ((u32tmp1 & 0x0f00) >> 8)) { + force_exec = true; + coex_sta->gnt_error_cnt++; + } + + +#if BT_8723D_2ANT_COEX_DBG + u32tmp2 = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u16tmp0 = btcoexist->btc_read_2byte(btcoexist, 0xaa); + u16tmp1 = btcoexist->btc_read_2byte(btcoexist, 0x948); + u8tmp1 = btcoexist->btc_read_1byte(btcoexist, 0x73); + u8tmp0 = btcoexist->btc_read_1byte(btcoexist, 0x67); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** 0x67 = 0x%x, 0x948 = 0x%x, 0x73 = 0x%x(Before Set Ant Pat)\n", + u8tmp0, u16tmp1, u8tmp1); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], **********0x38= 0x%x, 0x54= 0x%x, 0xaa = 0x%x (Before Set Ant Path)\n", + u32tmp1, u32tmp2, u16tmp0); + BTC_TRACE(trace_buf); +#endif + + coex_dm->cur_ant_pos_type = ant_pos_type; + + if (!force_exec) { + if (coex_dm->cur_ant_pos_type == coex_dm->pre_ant_pos_type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** Skip Antenna Path Setup because no change!!**********\n"); + BTC_TRACE(trace_buf); + return; + } + } + + coex_dm->pre_ant_pos_type = coex_dm->cur_ant_pos_type; + + switch (phase) { + case BT_8723D_2ANT_PHASE_COEX_POWERON: + /* Set Path control to WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x80, 0x0); + + /* set Path control owner to WL at initial step */ + halbtc8723d2ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8723D_2ANT_PCO_BTSIDE); + + /* set GNT_BT to SW high */ + halbtc8723d2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8723D_2ANT_GNT_BLOCK_RFC_BB, + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_2ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW low */ + halbtc8723d2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8723D_2ANT_GNT_BLOCK_RFC_BB, + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_2ANT_SIG_STA_SET_TO_HIGH); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_WIFI; + + coex_sta->run_time_state = false; + + break; + case BT_8723D_2ANT_PHASE_COEX_INIT: + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8723d2ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8723d2ant_ltecoex_set_coex_table( + btcoexist, + BT_8723D_2ANT_CTT_WL_VS_LTE, + 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8723d2ant_ltecoex_set_coex_table( + btcoexist, + BT_8723D_2ANT_CTT_BT_VS_LTE, + 0xffff); + + /* Wait If BT IQK running, because Path control owner is at BT during BT IQK (setup by WiFi firmware) */ + while (cnt_bt_cal_chk <= 20) { + u8tmp0 = btcoexist->btc_read_1byte( + btcoexist, + 0x49d); + cnt_bt_cal_chk++; + if (u8tmp0 & BIT(0)) { + BTC_SPRINTF( + trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ########### BT is calibrating (wait cnt=%d) ###########\n", + cnt_bt_cal_chk); + BTC_TRACE( + trace_buf); + delay_ms(50); + } else { + BTC_SPRINTF( + trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ********** BT is NOT calibrating (wait cnt=%d)**********\n", + cnt_bt_cal_chk); + BTC_TRACE( + trace_buf); + break; + } + } + + + /* Set Path control to WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x67, 0x80, 0x1); + + /* set Path control owner to WL at initial step */ + halbtc8723d2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8723D_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW high */ + halbtc8723d2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8723D_2ANT_GNT_BLOCK_RFC_BB, + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_2ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW high */ + halbtc8723d2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8723D_2ANT_GNT_BLOCK_RFC_BB, + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_2ANT_SIG_STA_SET_TO_HIGH); + + coex_sta->run_time_state = false; + + if (BTC_ANT_PATH_AUTO == ant_pos_type) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = + BTC_ANT_WIFI_AT_MAIN; + else + ant_pos_type = + BTC_ANT_WIFI_AT_AUX; + } + + break; + case BT_8723D_2ANT_PHASE_WLANONLY_INIT: + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8723d2ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8723d2ant_ltecoex_set_coex_table( + btcoexist, + BT_8723D_2ANT_CTT_WL_VS_LTE, + 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8723d2ant_ltecoex_set_coex_table( + btcoexist, + BT_8723D_2ANT_CTT_BT_VS_LTE, + 0xffff); + + /* Set Path control to WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x67, 0x80, 0x1); + + /* set Path control owner to WL at initial step */ + halbtc8723d2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8723D_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Low */ + halbtc8723d2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8723D_2ANT_GNT_BLOCK_RFC_BB, + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_2ANT_SIG_STA_SET_TO_LOW); + /* Set GNT_WL to SW high */ + halbtc8723d2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8723D_2ANT_GNT_BLOCK_RFC_BB, + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_2ANT_SIG_STA_SET_TO_HIGH); + + coex_sta->run_time_state = false; + + if (BTC_ANT_PATH_AUTO == ant_pos_type) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = + BTC_ANT_WIFI_AT_MAIN; + else + ant_pos_type = + BTC_ANT_WIFI_AT_AUX; + } + + break; + case BT_8723D_2ANT_PHASE_WLAN_OFF: + /* Disable LTE Coex Function in WiFi side */ + halbtc8723d2ant_ltecoex_enable(btcoexist, 0x0); + + /* Set Path control to BT */ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x67, 0x80, 0x0); + + /* set Path control owner to BT */ + halbtc8723d2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8723D_2ANT_PCO_BTSIDE); + + coex_sta->run_time_state = false; + break; + case BT_8723D_2ANT_PHASE_2G_RUNTIME: + + /* wait for WL/BT IQK finish, keep 0x38 = 0xff00 for WL IQK */ + while (cnt_bt_cal_chk <= 20) { + u8tmp0 = btcoexist->btc_read_1byte( + btcoexist, + 0x1e6); + + u8tmp1 = btcoexist->btc_read_1byte( + btcoexist, + 0x49d); + + cnt_bt_cal_chk++; + if ((u8tmp0 & BIT(0)) || + (u8tmp1 & BIT(0))) { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ########### WL or BT is IQK (wait cnt=%d)\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + delay_ms(50); + } else { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ********** WL and BT is NOT IQK (wait cnt=%d)\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + break; + } + } + + /* Set Path control to WL */ + /* btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x80, 0x1);*/ + + /* set Path control owner to WL at runtime step */ + halbtc8723d2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8723D_2ANT_PCO_WLSIDE); + + + halbtc8723d2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8723D_2ANT_GNT_BLOCK_RFC_BB, + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8723D_2ANT_SIG_STA_SET_TO_HIGH); + + /* Set GNT_WL to PTA */ + halbtc8723d2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8723D_2ANT_GNT_BLOCK_RFC_BB, + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8723D_2ANT_SIG_STA_SET_BY_HW); + + coex_sta->run_time_state = true; + + if (BTC_ANT_PATH_AUTO == ant_pos_type) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = + BTC_ANT_WIFI_AT_MAIN; + else + ant_pos_type = + BTC_ANT_WIFI_AT_AUX; + } + + break; + case BT_8723D_2ANT_PHASE_BTMPMODE: + /* Disable LTE Coex Function in WiFi side */ + halbtc8723d2ant_ltecoex_enable(btcoexist, 0x0); + + /* Set Path control to WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0x67, 0x80, 0x1); + + /* set Path control owner to WL */ + halbtc8723d2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8723D_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Hi */ + halbtc8723d2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8723D_2ANT_GNT_BLOCK_RFC_BB, + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_2ANT_SIG_STA_SET_TO_HIGH); + + /* Set GNT_WL to SW Lo */ + halbtc8723d2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8723D_2ANT_GNT_BLOCK_RFC_BB, + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_2ANT_SIG_STA_SET_TO_LOW); + + coex_sta->run_time_state = false; + + if (BTC_ANT_PATH_AUTO == ant_pos_type) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = + BTC_ANT_WIFI_AT_MAIN; + else + ant_pos_type = + BTC_ANT_WIFI_AT_AUX; + } + + break; + case BT_8723D_2ANT_PHASE_ANTENNA_DET: + + /* Set Path control to WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, + 0x80, 0x1); + + /* set Path control owner to WL */ + halbtc8723d2ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8723D_2ANT_PCO_WLSIDE); + + /* Set Antenna Path, both GNT_WL/GNT_BT = 1, and control by SW */ + /* set GNT_BT to SW high */ + halbtc8723d2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8723D_2ANT_GNT_BLOCK_RFC_BB, + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_2ANT_SIG_STA_SET_TO_HIGH); + + /* Set GNT_WL to SW high */ + halbtc8723d2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8723D_2ANT_GNT_BLOCK_RFC_BB, + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8723D_2ANT_SIG_STA_SET_TO_HIGH); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_WIFI_AT_AUX; + + coex_sta->run_time_state = false; + + break; + } + + is_hw_ant_div_on = board_info->ant_div_cfg; + + if ((is_hw_ant_div_on) && (phase != BT_8723D_2ANT_PHASE_ANTENNA_DET)) + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x140); + else if ((is_hw_ant_div_on == false) && + (phase != BT_8723D_2ANT_PHASE_WLAN_OFF)) { + + switch (ant_pos_type) { + case BTC_ANT_WIFI_AT_MAIN: + + btcoexist->btc_write_2byte(btcoexist, + 0x948, 0x0); + break; + case BTC_ANT_WIFI_AT_AUX: + + btcoexist->btc_write_2byte(btcoexist, + 0x948, 0x280); + break; + } + } + + +#if BT_8723D_2ANT_COEX_DBG + u32tmp1 = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u16tmp0 = btcoexist->btc_read_2byte(btcoexist, 0xaa); + u16tmp1 = btcoexist->btc_read_2byte(btcoexist, 0x948); + u8tmp1 = btcoexist->btc_read_1byte(btcoexist, 0x73); + u8tmp0 = btcoexist->btc_read_1byte(btcoexist, 0x67); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** 0x67 = 0x%x, 0x948 = 0x%x, 0x73 = 0x%x(After Set Ant Pat)\n", + u8tmp0, u16tmp1, u8tmp1); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], **********0x38= 0x%x, 0x54= 0x%x, 0xaa= 0x%x (After Set Ant Path)\n", + u32tmp1, u32tmp2, u16tmp0); + BTC_TRACE(trace_buf); +#endif + +} + +u8 halbtc8723d2ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8723D_2ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 0) { + + if (bt_link_info->acl_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No-Profile busy\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_2ANT_COEX_ALGO_NOPROFILEBUSY; + } + } else if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_2ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_2ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_2ANT_COEX_ALGO_SCO; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP ==> A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_2ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_PANEDR; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_HID_A2DP; + } + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_2ANT_COEX_ALGO_HID; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP ==> HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8723D_2ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_PANEDR_HID; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_PANEDR_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8723D_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + + return algorithm; +} + + + +void halbtc8723d2ant_action_coex_all_off(IN struct btc_coexist *btcoexist) +{ + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + /* fw all off */ + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8723d2ant_action_bt_whql_test(IN struct btc_coexist *btcoexist) +{ + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +} + +void halbtc8723d2ant_action_bt_hs(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d, wl_noisy = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; +#endif + + + wifi_rssi_state = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + + } else { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } + +} + + +void halbtc8723d2ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + + boolean wifi_connected = false; + boolean wifi_scan = false, wifi_link = false, wifi_roam = false; + boolean wifi_busy = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &wifi_link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &wifi_roam); + + if ((coex_sta->bt_create_connection) && ((wifi_link) || (wifi_roam) + || (wifi_scan) || (wifi_busy) || (coex_sta->wifi_is_high_pri_task))) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi link/roam/Scan/busy/hi-pri-task + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 8); + + if ((bt_link_info->a2dp_exist) && (!bt_link_info->pan_exist)) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 15); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 11); + } else if ((!wifi_connected) && (!wifi_scan)) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi no-link + no-scan + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (bt_link_info->pan_exist) { + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + + } else if (bt_link_info->a2dp_exist) { + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 16); + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + } else { + + if ((wifi_link) || (wifi_roam) || (wifi_scan) || (wifi_busy) + || (coex_sta->wifi_is_high_pri_task)) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 21); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + } + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); +} + + +void halbtc8723d2ant_action_bt_relink(IN struct btc_coexist *btcoexist) +{ + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8); + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + coex_sta->bt_relink_downcount = 2; +} + +void halbtc8723d2ant_action_bt_idle(IN struct btc_coexist *btcoexist) +{ + boolean wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_busy) { + + halbtc8723d2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else { /* if wl busy */ + + if (BT_8723D_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + + halbtc8723d2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else { + + halbtc8723d2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 12); + } + } + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + +} + + + +/* SCO only or SCO+PAN(HS) */ +void halbtc8723d2ant_action_sco(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, + &wifi_bw); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 1); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 8); + } + +} + + +void halbtc8723d2ant_action_hid(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + u32 wifi_bw = 1; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + wifi_rssi_state = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + /*for 4/18 hid */ + if (coex_sta->hid_busy_num >= 2) { + if (wifi_bw == 0) { /* if 11bg mode */ + + halbtc8723d2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + halbtc8723d2ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x1, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 111); + } else { + + if (wifi_busy) { + halbtc8723d2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + halbtc8723d2ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 111); + } else { + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 3); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + } + } + } else { + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 3); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + } + } + +} + + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +void halbtc8723d2ant_action_a2dp(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d, wl_noisy = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; +#endif + + wifi_rssi_state = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 2); + } else { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if ((coex_sta->bt_relink_downcount != 0) + && (wifi_busy)) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Re-Link + A2DP + WL busy\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + + } else { + + if (wifi_turbo) + halbtc8723d2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + if (wifi_busy) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 101); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 102); + } + + } + +} + + +void halbtc8723d2ant_action_pan_edr(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d, wl_noisy = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; +#endif + + wifi_rssi_state = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + +#if 0 + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +#endif + + +#if 1 + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 4); + } else { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (wifi_turbo) + halbtc8723d2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + if (wifi_busy) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 103); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 104); + + } + +#endif + +} + +void halbtc8723d2ant_action_hid_a2dp(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, + &wifi_bw); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 2); + } else { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if ((coex_sta->bt_relink_downcount != 0) + && (wifi_busy)) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Re-Link + A2DP + WL busy\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } else if (wifi_busy) { + if (coex_sta->hid_busy_num >= 2) { + halbtc8723d2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + if (wifi_bw == 0) /*11bg mode */ + halbtc8723d2ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x1, 0xaa, + 0x5a, 0xaa, + 0xaa); + else + halbtc8723d2ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 109); + } else { + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 101); + } + } else { + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 1); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 102); + } + + } + +} + + +void halbtc8723d2ant_action_a2dp_pan_hs(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d, wl_noisy = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; +#endif + + + wifi_rssi_state = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + } else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 6); + + } else { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (wifi_turbo) + halbtc8723d2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + if (wifi_busy) { + + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 107); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 105); + } else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 106); + + } + +} + + +/* PAN(EDR)+A2DP */ +void halbtc8723d2ant_action_pan_edr_a2dp(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d, wl_noisy = %d\n", + coex_sta->scan_ap_num, coex_sta->wl_noisy_level); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->wl_noisy_level == 0)) + wifi_turbo = true; +#endif + + + wifi_rssi_state = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + + if (((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) || + (!coex_sta->is_A2DP_3M)) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + } else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 6); + } else { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (wifi_turbo) + halbtc8723d2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + if (wifi_busy) { + + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 107); + else if (wifi_turbo) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 108); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 105); + } else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 106); + + } + +} + + +void halbtc8723d2ant_action_pan_edr_hid(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, + &wifi_bw); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 4); + } else { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (coex_sta->hid_busy_num >= 2) { + + halbtc8723d2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + if (wifi_bw == 0) /*11bg mode */ + halbtc8723d2ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x1, 0xaa, + 0x5a, 0xaa, + 0xaa); + else + halbtc8723d2ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 110); + } else { + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + + if (wifi_busy) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 103); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 104); + } + + } + +} + + +/* HID+A2DP+PAN(EDR) */ +void halbtc8723d2ant_action_hid_a2dp_pan_edr(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, + &wifi_bw); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8723d2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8723d2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x6); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + + if (((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) || + (!coex_sta->is_A2DP_3M)) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + } else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 6); + } else { + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (coex_sta->hid_busy_num >= 2) { + halbtc8723d2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + if (wifi_bw == 0) /*11bg mode */ + halbtc8723d2ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x1, 0xaa, + 0x5a, 0xaa, + 0xaa); + else + halbtc8723d2ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 110); + } else { + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + + if (wifi_busy) { + + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 107); + else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 105); + } else + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 106); + } + } + +} + + +void halbtc8723d2ant_action_wifi_multi_port(IN struct btc_coexist *btcoexist) +{ + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* hw all off */ + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +} + +void halbtc8723d2ant_action_wifi_linkscan_process(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + + if (bt_link_info->pan_exist) { + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + + } else if (bt_link_info->a2dp_exist) { + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 15); + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + } else { + + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 21); + + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 8); + } + +} + +void halbtc8723d2ant_action_wifi_not_connected(IN struct btc_coexist *btcoexist) +{ + halbtc8723d2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + /* fw all off */ + halbtc8723d2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8723d2ant_action_wifi_connected(IN struct btc_coexist *btcoexist) +{ + switch (coex_dm->cur_algorithm) { + + case BT_8723D_2ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_sco(btcoexist); + break; + case BT_8723D_2ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID.\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_hid(btcoexist); + break; + case BT_8723D_2ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_a2dp(btcoexist); + break; + case BT_8723D_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8723D_2ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_pan_edr(btcoexist); + break; + case BT_8723D_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8723D_2ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_pan_edr_hid(btcoexist); + break; + case BT_8723D_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_hid_a2dp_pan_edr( + btcoexist); + break; + case BT_8723D_2ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_hid_a2dp(btcoexist); + break; + case BT_8723D_2ANT_COEX_ALGO_NOPROFILEBUSY: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = No-Profile busy.\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_bt_idle(btcoexist); + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_coex_all_off(btcoexist); + break; + } + + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + +} + + +void halbtc8723d2ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + u32 num_of_wifi_link = 0; + u32 wifi_link_status = 0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean miracast_plus_bt = false; + boolean scan = false, link = false, roam = false, + under_4way = false, + wifi_connected = false, wifi_under_5g = false, + bt_hs_on = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (!coex_sta->run_time_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], return for run_time_state = false !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->freeze_coexrun_by_btinfo) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), return for freeze_coexrun_by_btinfo\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->bt_whck_test) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under WHCK TEST!!!\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_bt_whql_test(btcoexist); + return; + } + + if (coex_sta->bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled!!!\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_coex_all_off(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_bt_inquiry(btcoexist); + return; + } + + if (coex_sta->is_setupLink) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is re-link !!!\n"); + halbtc8723d2ant_action_bt_relink(btcoexist); + return; + } + + /* for P2P */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + BTC_TRACE(trace_buf); + + if (bt_link_info->bt_link_exist) + miracast_plus_bt = true; + else + miracast_plus_bt = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + if (scan || link || roam || under_4way) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], scan = %d, link = %d, roam = %d 4way = %d!!!\n", + scan, link, roam, under_4way); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under linkscan process + Multi-Port !!\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_action_wifi_linkscan_process(btcoexist); + } else + halbtc8723d2ant_action_wifi_multi_port(btcoexist); + + return; + } else { + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is hs\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_bt_hs(btcoexist); + return; + } + + if ((BT_8723D_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) || + (BT_8723D_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, bt idle!!.\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_action_bt_idle(btcoexist); + return; + } + + algorithm = halbtc8723d2ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Algorithm = %d\n", + coex_dm->cur_algorithm); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (scan || link || roam || under_4way) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under Link Process !!\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_wifi_linkscan_process(btcoexist); + } else if (wifi_connected) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, wifi connected!!.\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_wifi_connected(btcoexist); + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, wifi not-connected!!.\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_action_wifi_not_connected(btcoexist); + } +} + + +void halbtc8723d2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0x18); + halbtc8723d2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + halbtc8723d2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + + coex_sta->pop_event_cnt = 0; + coex_sta->cnt_RemoteNameReq = 0; + coex_sta->cnt_ReInit = 0; + coex_sta->cnt_setupLink = 0; + coex_sta->cnt_IgnWlanAct = 0; + coex_sta->cnt_Page = 0; + + halbtc8723d2ant_query_bt_info(btcoexist); +} + + +void halbtc8723d2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + u8 u8tmp0 = 0, u8tmp1 = 0; + u32 vendor; + u32 u32tmp0 = 0, u32tmp1 = 0, u32tmp2 = 0; + u16 u16tmp1 = 0; + u8 i = 0; + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 2Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + +#if BT_8723D_2ANT_COEX_DBG + u32tmp1 = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + u32tmp2 = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, + 0x54); + u16tmp1 = btcoexist->btc_read_2byte(btcoexist, 0x948); + u8tmp1 = btcoexist->btc_read_1byte(btcoexist, 0x73); + u8tmp0 = btcoexist->btc_read_1byte(btcoexist, 0x67); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** 0x67 = 0x%x, 0x948 = 0x%x, 0x73 = 0x%x(Before init_hw_config)\n", + u8tmp0, u16tmp1, u8tmp1); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], **********0x38= 0x%x, 0x54= 0x%x (Before init_hw_config)\n", + u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); +#endif + + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->bt_reg_vendor_ac = 0xffff; + coex_sta->bt_reg_vendor_ae = 0xffff; + coex_sta->gnt_error_cnt = 0; + coex_sta->bt_relink_downcount = 0; + + for (i = 0; i <= 9; i++) + coex_sta->bt_afh_map[i] = 0; + +#if 0 + btcoexist->btc_get(btcoexist, BTC_GET_U4_VENDOR, &vendor); + if (vendor == BTC_VENDOR_LENOVO) + coex_dm->switch_thres_offset = 0; + else + coex_dm->switch_thres_offset = 20; +#endif + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = (btcoexist->btc_read_1byte(btcoexist, + 0xf1) & 0xf0) >> 4; + + coex_sta->dis_ver_info_cnt = 0; + + /* default isolation = 15dB */ + coex_sta->isolation_btween_wb = BT_8723D_2ANT_DEFAULT_ISOLATION; + halbtc8723d2ant_coex_switch_threshold(btcoexist, + coex_sta->isolation_btween_wb); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + + /* BT report packet sample rate */ + btcoexist->btc_write_1byte(btcoexist, 0x790, 0x5); + + /* Init 0x778 = 0x1 for 2-Ant */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + + /* Enable PTA (3-wire function form BT side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x41, 0x02, 0x1); + + /* Enable PTA (tx/rx signal form WiFi side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4c6, 0x10, 0x1); + + halbtc8723d2ant_enable_gnt_to_gpio(btcoexist, true); + + /* check if WL firmware download ok */ + if (btcoexist->btc_read_1byte(btcoexist, 0x80) == 0xc6) + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ONOFF, true); + + /* Enable counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, + 0x4); /* 0x76e[3] =1, WLAN_Act control by PTA */ + + /* WLAN_Tx by GNT_WL 0x950[29] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x953, 0x20, 0x0); + + halbtc8723d2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + halbtc8723d2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + psd_scan->ant_det_is_ant_det_available = true; + + if (wifi_only) { + coex_sta->concurrent_rx_mode_on = false; + /* Path config */ + /* Set Antenna Path */ + halbtc8723d2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_2ANT_PHASE_WLANONLY_INIT); + + btcoexist->stop_coex_dm = true; + } else { + /*Set BT polluted packet on for Tx rate adaptive not including Tx retry break by PTA, 0x45c[19] =1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + + coex_sta->concurrent_rx_mode_on = true; + /* btcoexist->btc_write_1byte_bitmask(btcoexist, 0x953, 0x2, 0x1); */ + + /* RF 0x1[0] = 0->Set GNT_WL_RF_Rx always = 1 for con-current Rx */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0x1, 0x0); + + /* Path config */ + halbtc8723d2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_2ANT_PHASE_COEX_INIT); + + btcoexist->stop_coex_dm = false; + } + + +} + +u32 halbtc8723d2ant_psd_log2base(IN struct btc_coexist *btcoexist, IN u32 val) +{ + u8 j; + u32 tmp, tmp2, val_integerd_b = 0, tindex, shiftcount = 0; + u32 result, val_fractiond_b = 0, table_fraction[21] = {0, 432, 332, 274, 232, 200, + 174, 151, 132, 115, 100, 86, 74, 62, 51, 42, + 32, 23, 15, 7, 0 + }; + + if (val == 0) + return 0; + + tmp = val; + + while (1) { + if (tmp == 1) + break; + else { + tmp = (tmp >> 1); + shiftcount++; + } + } + + + val_integerd_b = shiftcount + 1; + + tmp2 = 1; + for (j = 1; j <= val_integerd_b; j++) + tmp2 = tmp2 * 2; + + tmp = (val * 100) / tmp2; + tindex = tmp / 5; + + if (tindex > 20) + tindex = 20; + + val_fractiond_b = table_fraction[tindex]; + + result = val_integerd_b * 100 - val_fractiond_b; + + return result; + + +} + +void halbtc8723d2ant_psd_show_antenna_detect_result(IN struct btc_coexist + *btcoexist) +{ + u8 *cli_buf = btcoexist->cli_buf; + struct btc_board_info *board_info = &btcoexist->board_info; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n============[Antenna Detection info] ============\n"); + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 12) { /* Get Ant Det from BT */ + + if (board_info->btdm_ant_num_by_ant_det == 1) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "1-Antenna", + BT_8723D_2ANT_ANTDET_PSDTHRES_1ANT, + BT_8723D_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION); + else { + + if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8723D_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION) + * 100) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (>%d)", + "Ant Det Result", "2-Antenna (Bad-Isolation)", + BT_8723D_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "2-Antenna (Good-Isolation)", + BT_8723D_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset, + BT_8723D_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + } + + } else if (psd_scan->ant_det_result == 1) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (>%d)", + "Ant Det Result", "2-Antenna (Bad-Isolation)", + BT_8723D_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else if (psd_scan->ant_det_result == 2) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "2-Antenna (Good-Isolation)", + BT_8723D_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset, + BT_8723D_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "1-Antenna", + BT_8723D_2ANT_ANTDET_PSDTHRES_1ANT, + BT_8723D_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset); + + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s ", + "Antenna Detection Finish", + (board_info->btdm_ant_det_finish + ? "Yes" : "No")); + CL_PRINTF(cli_buf); + + switch (psd_scan->ant_det_result) { + case 0: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is not available)"); + break; + case 1: /* 2-Ant bad-isolation */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 2: /* 2-Ant good-isolation */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 3: /* 1-Ant */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 4: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Uncertainty result)"); + break; + case 5: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "(Pre-Scan fai)"); + break; + case 6: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(WiFi is Scanning)"); + break; + case 7: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is not idle)"); + break; + case 8: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Abort by WiFi Scanning)"); + break; + case 9: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Antenna Init is not ready)"); + break; + case 10: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is Inquiry or page)"); + break; + case 11: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is Disabled)"); + case 12: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available, result from BT"); + break; + } + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 12) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d dB", + "PSD Scan Peak Value", + psd_scan->ant_det_psd_scan_peak_val / 100); + CL_PRINTF(cli_buf); + return; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "Ant Detect Total Count", psd_scan->ant_det_try_count); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "Ant Detect Fail Count", psd_scan->ant_det_fail_count); + CL_PRINTF(cli_buf); + + if ((!board_info->btdm_ant_det_finish) && + (psd_scan->ant_det_result != 5)) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Response", + (psd_scan->ant_det_result ? "ok" : "fail")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ms", "BT Tx Time", + psd_scan->ant_det_bt_tx_time); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "BT Tx Ch", + psd_scan->ant_det_bt_le_channel); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + "WiFi PSD Cent-Ch/Offset/Span", + psd_scan->real_cent_freq, psd_scan->real_offset, + psd_scan->real_span); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d dB", + "PSD Pre-Scan Peak Value", + psd_scan->ant_det_pre_psdscan_peak_val / 100); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (<= %d)", + "PSD Pre-Scan result", + (psd_scan->ant_det_result != 5 ? "ok" : "fail"), + BT_8723D_2ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 5) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s dB", + "PSD Scan Peak Value", psd_scan->ant_det_peak_val); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s MHz", + "PSD Scan Peak Freq", psd_scan->ant_det_peak_freq); + CL_PRINTF(cli_buf); + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "TFBGA Package", + (board_info->tfbga_package) ? "Yes" : "No"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "PSD Threshold Offset", psd_scan->ant_det_thres_offset); + CL_PRINTF(cli_buf); + +} + +void halbtc8723d2ant_psd_showdata(IN struct btc_coexist *btcoexist) +{ + u8 *cli_buf = btcoexist->cli_buf; + u32 delta_freq_per_point; + u32 freq, freq1, freq2, n = 0, i = 0, j = 0, m = 0, psd_rep1, psd_rep2; + + if (psd_scan->ant_det_result == 12) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n\n============[PSD info] (%d)============\n", + psd_scan->psd_gen_count); + CL_PRINTF(cli_buf); + + if (psd_scan->psd_gen_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n No data !!\n"); + CL_PRINTF(cli_buf); + return; + } + + if (psd_scan->psd_point == 0) + delta_freq_per_point = 0; + else + delta_freq_per_point = psd_scan->psd_band_width / + psd_scan->psd_point; + + /* if (psd_scan->is_psd_show_max_only) */ + if (0) { + psd_rep1 = psd_scan->psd_max_value / 100; + psd_rep2 = psd_scan->psd_max_value - psd_rep1 * 100; + + freq = ((psd_scan->real_cent_freq - 20) * 1000000 + + psd_scan->psd_max_value_point * delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (freq2 < 100) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n Freq = %d.0%d MHz", + freq1, freq2); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n Freq = %d.%d MHz", + freq1, freq2); + + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + ", Value = %d.0%d dB, (%d)\n", + psd_rep1, psd_rep2, psd_scan->psd_max_value); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + ", Value = %d.%d dB, (%d)\n", + psd_rep1, psd_rep2, psd_scan->psd_max_value); + + CL_PRINTF(cli_buf); + } else { + m = psd_scan->psd_start_point; + n = psd_scan->psd_start_point; + i = 1; + j = 1; + + while (1) { + do { + freq = ((psd_scan->real_cent_freq - 20) * + 1000000 + m * + delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (i == 1) { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.000", + freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.0%2d", + freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.%3d", + freq1, + freq2); + } else if ((i % 8 == 0) || + (m == psd_scan->psd_stop_point)) { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.000\n", freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.0%2d\n", freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.%3d\n", freq1, + freq2); + } else { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.000", freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.0%2d", freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.%3d", freq1, + freq2); + } + + i++; + m++; + CL_PRINTF(cli_buf); + + } while ((i <= 8) && (m <= psd_scan->psd_stop_point)); + + + do { + psd_rep1 = psd_scan->psd_report_max_hold[n] / + 100; + psd_rep2 = psd_scan->psd_report_max_hold[n] - + psd_rep1 * + 100; + + if (j == 1) { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Val %7d.0%d", + psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Val %7d.%d", + psd_rep1, + psd_rep2); + } else if ((j % 8 == 0) || + (n == psd_scan->psd_stop_point)) { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.0%d\n", psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.%d\n", psd_rep1, + psd_rep2); + } else { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.0%d", psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.%d", psd_rep1, + psd_rep2); + } + + j++; + n++; + CL_PRINTF(cli_buf); + + } while ((j <= 8) && (n <= psd_scan->psd_stop_point)); + + if ((m > psd_scan->psd_stop_point) || + (n > psd_scan->psd_stop_point)) + break; + else { + i = 1; + j = 1; + } + + } + } + + +} + +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +void halbtc8723d2ant_psd_maxholddata(IN struct btc_coexist *btcoexist, + IN u32 gen_count) +{ + u32 i = 0; + u32 loop_i_max = 0, loop_val_max = 0; + + if (gen_count == 1) { + memcpy(psd_scan->psd_report_max_hold, + psd_scan->psd_report, + BT_8723D_2ANT_ANTDET_PSD_POINTS * sizeof(u32)); + } + + for (i = psd_scan->psd_start_point; + i <= psd_scan->psd_stop_point; i++) { + + /* update max-hold value at each freq point */ + if (psd_scan->psd_report[i] > psd_scan->psd_report_max_hold[i]) + psd_scan->psd_report_max_hold[i] = + psd_scan->psd_report[i]; + + /* search the max value in this seep */ + if (psd_scan->psd_report[i] > loop_val_max) { + loop_val_max = psd_scan->psd_report[i]; + loop_i_max = i; + } + } + + if (gen_count <= BT_8723D_2ANT_ANTDET_PSD_SWWEEPCOUNT) + psd_scan->psd_loop_max_value[gen_count - 1] = loop_val_max; + +} + + +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +u32 halbtc8723d2ant_psd_getdata(IN struct btc_coexist *btcoexist, IN u32 point) +{ + /* reg 0x808[9:0]: FFT data x */ + /* reg 0x808[22]: 0-->1 to get 1 FFT data y */ + /* reg 0x8b4[15:0]: FFT data y report */ + + u32 val = 0, psd_report = 0; + int k = 0; + + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + + val &= 0xffbffc00; + val |= point; + + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + val |= 0x00400000; + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + while (1) { + if (k++ > BT_8723D_2ANT_ANTDET_SWEEPPOINT_DELAY) + break; + } + + val = btcoexist->btc_read_4byte(btcoexist, 0x8b4); + + psd_report = val & 0x0000ffff; + + return psd_report; +} + +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +boolean halbtc8723d2ant_psd_sweep_point(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN s32 offset, IN u32 span, IN u32 points, + IN u32 avgnum, IN u32 loopcnt) +{ + u32 i = 0, val = 0, n = 0, k = 0, j, point_index = 0; + u32 points1 = 0, psd_report = 0; + u32 start_p = 0, stop_p = 0, delta_freq_per_point = 156250; + u32 psd_center_freq = 20 * 10 ^ 6; + boolean outloop = false, scan , roam, is_sweep_ok = true; + u8 flag = 0; + u32 tmp = 0, u32tmp1 = 0; + u32 wifi_original_channel = 1; + u32 psd_sum = 0, avg_cnt = 0; + u32 i_max = 0, val_max = 0, val_max2 = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx PSD Sweep Start!!\n"); + BTC_TRACE(trace_buf); + + do { + switch (flag) { + case 0: /* Get PSD parameters */ + default: + + psd_scan->psd_band_width = 40 * 1000000; + psd_scan->psd_point = points; + psd_scan->psd_start_base = points / 2; + psd_scan->psd_avg_num = avgnum; + psd_scan->real_cent_freq = cent_freq; + psd_scan->real_offset = offset; + psd_scan->real_span = span; + + + points1 = psd_scan->psd_point; + delta_freq_per_point = psd_scan->psd_band_width / + psd_scan->psd_point; + + /* PSD point setup */ + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + val &= 0xffff0fff; + + switch (psd_scan->psd_point) { + case 128: + val |= 0x0; + break; + case 256: + default: + val |= 0x00004000; + break; + case 512: + val |= 0x00008000; + break; + case 1024: + val |= 0x0000c000; + break; + } + + switch (psd_scan->psd_avg_num) { + case 1: + val |= 0x0; + break; + case 8: + val |= 0x00001000; + break; + case 16: + val |= 0x00002000; + break; + case 32: + default: + val |= 0x00003000; + break; + } + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + flag = 1; + break; + case 1: /* calculate the PSD point index from freq/offset/span */ + psd_center_freq = psd_scan->psd_band_width / 2 + + offset * (1000000); + + start_p = psd_scan->psd_start_base + (psd_center_freq - + span * (1000000) / 2) / delta_freq_per_point; + psd_scan->psd_start_point = start_p - + psd_scan->psd_start_base; + + stop_p = psd_scan->psd_start_base + (psd_center_freq + + span * (1000000) / 2) / delta_freq_per_point; + psd_scan->psd_stop_point = stop_p - + psd_scan->psd_start_base - 1; + + flag = 2; + break; + case 2: /* set RF channel/BW/Mode */ + + /* set 3-wire off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x88c); + val |= 0x00300000; + btcoexist->btc_write_4byte(btcoexist, 0x88c, val); + + /* CCK off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x800); + val &= 0xfeffffff; + btcoexist->btc_write_4byte(btcoexist, 0x800, val); + + /* Tx-pause on */ + btcoexist->btc_write_1byte(btcoexist, 0x522, 0x6f); + + /* store WiFi original channel */ + wifi_original_channel = btcoexist->btc_get_rf_reg( + btcoexist, BTC_RF_A, 0x18, 0x3ff); + + /* Set RF channel */ + if (cent_freq == 2484) + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x18, 0x3ff, 0xe); + else + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x18, 0x3ff, (cent_freq - 2412) / 5 + + 1); /* WiFi TRx Mask on */ + + /* save original RCK value */ + u32tmp1 = btcoexist->btc_get_rf_reg( + btcoexist, BTC_RF_A, 0x1d, 0xfffff); + + /* Enter debug mode */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xde, + 0x2, 0x1); + + /* Set RF Rx filter corner */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1d, + 0xfffff, 0x2e); + + + /* Set RF mode = Rx, RF Gain = 0x320a0 */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x0, + 0xfffff, 0x320a0); + + while (1) { + if (k++ > BT_8723D_2ANT_ANTDET_SWEEPPOINT_DELAY) + break; + } + flag = 3; + break; + case 3: + psd_scan->psd_gen_count = 0; + for (j = 1; j <= loopcnt; j++) { + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || roam) { + is_sweep_ok = false; + break; + } + memset(psd_scan->psd_report, 0, + psd_scan->psd_point * sizeof(u32)); + start_p = psd_scan->psd_start_point + + psd_scan->psd_start_base; + stop_p = psd_scan->psd_stop_point + + psd_scan->psd_start_base + 1; + + i = start_p; + point_index = 0; + + while (i < stop_p) { + if (i >= points1) + psd_report = + halbtc8723d2ant_psd_getdata( + btcoexist, i - points1); + else + psd_report = + halbtc8723d2ant_psd_getdata( + btcoexist, i); + + if (psd_report == 0) + tmp = 0; + else + /* tmp = 20*log10((double)psd_report); */ + /* 20*log2(x)/log2(10), log2Base return theresult of the psd_report*100 */ + tmp = 6 * halbtc8723d2ant_psd_log2base( + btcoexist, psd_report); + + n = i - psd_scan->psd_start_base; + psd_scan->psd_report[n] = tmp; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Point=%d, psd_dB_data = %d\n", + i, psd_scan->psd_report[n]); + BTC_TRACE(trace_buf); + + i++; + + } + + halbtc8723d2ant_psd_maxholddata(btcoexist, j); + + psd_scan->psd_gen_count = j; + + /*Accumulate Max PSD value in this loop if the value > threshold */ + if (psd_scan->psd_loop_max_value[j - 1] >= + 4000) { + psd_sum = psd_sum + + psd_scan->psd_loop_max_value[j - + 1]; + avg_cnt++; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Loop=%d, Max_dB_data = %d\n", + j, psd_scan->psd_loop_max_value[j + - 1]); + BTC_TRACE(trace_buf); + + } + + if (loopcnt == BT_8723D_2ANT_ANTDET_PSD_SWWEEPCOUNT) { + + /* search the Max Value between each-freq-point-max-hold value of all sweep*/ + for (i = 1; + i <= BT_8723D_2ANT_ANTDET_PSD_SWWEEPCOUNT; + i++) { + + if (i == 1) { + i_max = i; + val_max = psd_scan->psd_loop_max_value[i + - 1]; + val_max2 = + psd_scan->psd_loop_max_value[i + - 1]; + } else if ( + psd_scan->psd_loop_max_value[i - + 1] > val_max) { + val_max2 = val_max; + i_max = i; + val_max = psd_scan->psd_loop_max_value[i + - 1]; + } else if ( + psd_scan->psd_loop_max_value[i - + 1] > val_max2) + val_max2 = + psd_scan->psd_loop_max_value[i + - 1]; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "i = %d, val_hold= %d, val_max = %d, val_max2 = %d\n", + i, psd_scan->psd_loop_max_value[i + - 1], + val_max, val_max2); + + BTC_TRACE(trace_buf); + } + + psd_scan->psd_max_value_point = i_max; + psd_scan->psd_max_value = val_max; + psd_scan->psd_max_value2 = val_max2; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "val_max = %d, val_max2 = %d\n", + psd_scan->psd_max_value, + psd_scan->psd_max_value2); + BTC_TRACE(trace_buf); + } + + if (avg_cnt != 0) { + psd_scan->psd_avg_value = (psd_sum / avg_cnt); + if ((psd_sum % avg_cnt) >= (avg_cnt / 2)) + psd_scan->psd_avg_value++; + } else + psd_scan->psd_avg_value = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "AvgLoop=%d, Avg_dB_data = %d\n", + avg_cnt, psd_scan->psd_avg_value); + BTC_TRACE(trace_buf); + + flag = 100; + break; + case 99: /* error */ + + outloop = true; + break; + case 100: /* recovery */ + + /* set 3-wire on */ + val = btcoexist->btc_read_4byte(btcoexist, 0x88c); + val &= 0xffcfffff; + btcoexist->btc_write_4byte(btcoexist, 0x88c, val); + + /* CCK on */ + val = btcoexist->btc_read_4byte(btcoexist, 0x800); + val |= 0x01000000; + btcoexist->btc_write_4byte(btcoexist, 0x800, val); + + /* Tx-pause off */ + btcoexist->btc_write_1byte(btcoexist, 0x522, 0x0); + + /* PSD off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + val &= 0xffbfffff; + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + /* restore RF Rx filter corner */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1d, + 0xfffff, u32tmp1); + + /* Exit debug mode */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xde, + 0x2, 0x0); + + /* restore WiFi original channel */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x18, + 0x3ff, wifi_original_channel); + + outloop = true; + break; + + } + + } while (!outloop); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx PSD Sweep Stop!!\n"); + BTC_TRACE(trace_buf); + return is_sweep_ok; + +} + +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +boolean halbtc8723d2ant_psd_antenna_detection(IN struct btc_coexist + *btcoexist) +{ + u32 i = 0; + u32 wlpsd_cent_freq = 2484, wlpsd_span = 2; + s32 wlpsd_offset = -4; + u32 bt_tx_time, bt_le_channel; + u8 bt_le_ch[13] = {3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 33}; + + u8 h2c_parameter[3] = {0}, u8tmpa, u8tmpb; + + u8 state = 0; + boolean outloop = false, bt_resp = false, ant_det_finish = false; + u32 freq, freq1, freq2, psd_rep1, psd_rep2, delta_freq_per_point, + u32tmp, u32tmp0, u32tmp1, u32tmp2 ; + struct btc_board_info *board_info = &btcoexist->board_info; + + memset(psd_scan->ant_det_peak_val, 0, 16 * sizeof(u8)); + memset(psd_scan->ant_det_peak_freq, 0, 16 * sizeof(u8)); + + psd_scan->ant_det_bt_tx_time = + BT_8723D_2ANT_ANTDET_BTTXTIME; /* 0.42ms*50 = 20ms (0.42ms = 1 PSD sweep) */ + psd_scan->ant_det_bt_le_channel = BT_8723D_2ANT_ANTDET_BTTXCHANNEL; + + bt_tx_time = psd_scan->ant_det_bt_tx_time; + bt_le_channel = psd_scan->ant_det_bt_le_channel; + + if (board_info->tfbga_package) /* for TFBGA */ + psd_scan->ant_det_thres_offset = 5; + else + psd_scan->ant_det_thres_offset = 0; + + do { + switch (state) { + case 0: + if (bt_le_channel == 39) + wlpsd_cent_freq = 2484; + else { + for (i = 1; i <= 13; i++) { + if (bt_le_ch[i - 1] == + bt_le_channel) { + wlpsd_cent_freq = 2412 + + (i - 1) * 5; + break; + } + } + + if (i == 14) { + + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Abort!!, Invalid LE channel = %d\n ", + bt_le_channel); + BTC_TRACE(trace_buf); + outloop = true; + break; + } + } +#if 0 + wlpsd_sweep_count = bt_tx_time * 238 / + 100; /* bt_tx_time/0.42 */ + wlpsd_sweep_count = wlpsd_sweep_count / 5; + + if (wlpsd_sweep_count % 5 != 0) + wlpsd_sweep_count = (wlpsd_sweep_count / + 5 + 1) * 5; +#endif + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), BT_LETxTime=%d, BT_LECh = %d\n", + bt_tx_time, bt_le_channel); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), wlpsd_cent_freq=%d, wlpsd_offset = %d, wlpsd_span = %d, wlpsd_sweep_count = %d\n", + wlpsd_cent_freq, + wlpsd_offset, + wlpsd_span, + BT_8723D_2ANT_ANTDET_PSD_SWWEEPCOUNT); + BTC_TRACE(trace_buf); + + state = 1; + break; + case 1: /* stop coex DM & set antenna path */ + /* Stop Coex DM */ + btcoexist->stop_coex_dm = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Stop Coex DM!!\n"); + BTC_TRACE(trace_buf); + + /* Set TDMA off, */ + halbtc8723d2ant_ps_tdma(btcoexist, FORCE_EXEC, + false, 0); + + /* Set coex table */ + halbtc8723d2ant_coex_table_with_type(btcoexist, + FORCE_EXEC, 0); + + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna at Main Port\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna at Aux Port\n"); + BTC_TRACE(trace_buf); + } + + /* Set Antenna path, switch WiFi to un-certain antenna port */ + /* Set Antenna Path, both GNT_WL/GNT_BT = 1, and control by SW */ + halbtc8723d2ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, + BT_8723D_2ANT_PHASE_ANTENNA_DET); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set Antenna to BT!!\n"); + BTC_TRACE(trace_buf); + + /* Set AFH mask on at WiFi channel 2472MHz +/- 10MHz */ + h2c_parameter[0] = 0x1; + h2c_parameter[1] = 0xd; + h2c_parameter[2] = 0x14; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set AFH on, Cent-Ch= %d, Mask=%d\n", + h2c_parameter[1], + h2c_parameter[2]); + BTC_TRACE(trace_buf); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, + h2c_parameter); + + u32tmp = btcoexist->btc_read_2byte(btcoexist, 0x948); + u32tmp0 = btcoexist->btc_read_4byte(btcoexist, 0x70); + u32tmp1 = halbtc8723d2ant_ltecoex_indirect_read_reg( + btcoexist, 0x38); + u32tmp2 = halbtc8723d2ant_ltecoex_indirect_read_reg( + btcoexist, 0x54); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** 0x948 = 0x%x, 0x70 = 0x%x, 0x38= 0x%x, 0x54= 0x%x (Before Ant Det)\n", + u32tmp, u32tmp0, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); + + state = 2; + break; + case 2: /* Pre-sweep background psd */ + if (!halbtc8723d2ant_psd_sweep_point(btcoexist, + wlpsd_cent_freq, wlpsd_offset, wlpsd_span, + BT_8723D_2ANT_ANTDET_PSD_POINTS, + BT_8723D_2ANT_ANTDET_PSD_AVGNUM, 3)) { + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 8; + state = 99; + break; + } + + psd_scan->ant_det_pre_psdscan_peak_val = + psd_scan->psd_max_value; + + if (psd_scan->ant_det_pre_psdscan_peak_val > + (BT_8723D_2ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset) * 100) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Abort Antenna Detection!! becaus background = %d > thres (%d)\n", + psd_scan->ant_det_pre_psdscan_peak_val / + 100, + BT_8723D_2ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + BTC_TRACE(trace_buf); + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 5; + state = 99; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Start Antenna Detection!! becaus background = %d <= thres (%d)\n", + psd_scan->ant_det_pre_psdscan_peak_val / + 100, + BT_8723D_2ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + BTC_TRACE(trace_buf); + state = 3; + } + break; + case 3: + bt_resp = btcoexist->btc_set_bt_ant_detection( + btcoexist, (u8)(bt_tx_time & 0xff), + (u8)(bt_le_channel & 0xff)); + + /* Sync WL Rx PSD with BT Tx time because H2C->Mailbox delay */ + delay_ms(20); + + if (!halbtc8723d2ant_psd_sweep_point(btcoexist, + wlpsd_cent_freq, wlpsd_offset, + wlpsd_span, + BT_8723D_2ANT_ANTDET_PSD_POINTS, + BT_8723D_2ANT_ANTDET_PSD_AVGNUM, + BT_8723D_2ANT_ANTDET_PSD_SWWEEPCOUNT)) { + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 8; + state = 99; + break; + } + +#if 1 + psd_scan->ant_det_psd_scan_peak_val = + psd_scan->psd_max_value; +#endif +#if 0 + psd_scan->ant_det_psd_scan_peak_val = + ((psd_scan->psd_max_value - psd_scan->psd_avg_value) < + 800) ? + psd_scan->psd_max_value : (( + psd_scan->psd_max_value - + psd_scan->psd_max_value2 <= 300) ? + psd_scan->psd_avg_value : + psd_scan->psd_max_value2); +#endif + psd_scan->ant_det_psd_scan_peak_freq = + psd_scan->psd_max_value_point; + state = 4; + break; + case 4: + + if (psd_scan->psd_point == 0) + delta_freq_per_point = 0; + else + delta_freq_per_point = + psd_scan->psd_band_width / + psd_scan->psd_point; + + psd_rep1 = psd_scan->ant_det_psd_scan_peak_val / 100; + psd_rep2 = psd_scan->ant_det_psd_scan_peak_val - + psd_rep1 * + 100; + + freq = ((psd_scan->real_cent_freq - 20) * + 1000000 + psd_scan->psd_max_value_point + * delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (freq2 < 100) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Max Value: Freq = %d.0%d MHz", + freq1, freq2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_freq, + BT_8723D_2ANT_ANTDET_BUF_LEN, + "%d.0%d", freq1, freq2); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Max Value: Freq = %d.%d MHz", + freq1, freq2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_freq, + BT_8723D_2ANT_ANTDET_BUF_LEN, + "%d.%d", freq1, freq2); + } + + if (psd_rep2 < 10) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + ", Value = %d.0%d dB\n", + psd_rep1, psd_rep2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_val, + BT_8723D_2ANT_ANTDET_BUF_LEN, + "%d.0%d", psd_rep1, psd_rep2); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + ", Value = %d.%d dB\n", + psd_rep1, psd_rep2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_val, + BT_8723D_2ANT_ANTDET_BUF_LEN, + "%d.%d", psd_rep1, psd_rep2); + } + + psd_scan->ant_det_is_btreply_available = true; + + if (bt_resp == false) { + psd_scan->ant_det_is_btreply_available = + false; + psd_scan->ant_det_result = 0; + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), BT Response = Fail\n "); + BTC_TRACE(trace_buf); + } else if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8723D_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION) + * 100) { + psd_scan->ant_det_result = 1; + ant_det_finish = true; + board_info->btdm_ant_num_by_ant_det = 2; + coex_sta->isolation_btween_wb = (u8)(85 - + psd_scan->ant_det_psd_scan_peak_val / + 100) & 0xff; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 2-Ant, Bad-Isolation!!\n"); + BTC_TRACE(trace_buf); + } else if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8723D_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset) * 100) { + psd_scan->ant_det_result = 2; + ant_det_finish = true; + board_info->btdm_ant_num_by_ant_det = 2; + coex_sta->isolation_btween_wb = (u8)(85 - + psd_scan->ant_det_psd_scan_peak_val / + 100) & 0xff; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 2-Ant, Good-Isolation!!\n"); + BTC_TRACE(trace_buf); + } else if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8723D_2ANT_ANTDET_PSDTHRES_1ANT) * + 100) { + psd_scan->ant_det_result = 3; + ant_det_finish = true; + board_info->btdm_ant_num_by_ant_det = 1; + coex_sta->isolation_btween_wb = (u8)(85 - + psd_scan->ant_det_psd_scan_peak_val / + 100) & 0xff; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 1-Ant!!\n"); + BTC_TRACE(trace_buf); + } else { + psd_scan->ant_det_result = 4; + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 1-Ant, un-certainity!!\n"); + BTC_TRACE(trace_buf); + } + + state = 99; + break; + case 99: /* restore setup */ + + /* Set AFH mask off at WiFi channel 2472MHz +/- 10MHz */ + h2c_parameter[0] = 0x0; + h2c_parameter[1] = 0x0; + h2c_parameter[2] = 0x0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set AFH on, Cent-Ch= %d, Mask=%d\n", + h2c_parameter[1], h2c_parameter[2]); + BTC_TRACE(trace_buf); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, + h2c_parameter); + + /* Set Antenna Path, GNT_WL/GNT_BT control by PTA */ + /* Set Antenna path, switch WiFi to certain antenna port */ + halbtc8723d2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8723D_2ANT_PHASE_2G_RUNTIME); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set Antenna to PTA\n!!"); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Resume Coex DM\n!!"); + BTC_TRACE(trace_buf); + + outloop = true; + break; + } + + } while (!outloop); + + return ant_det_finish; + +} + +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +boolean halbtc8723d2ant_psd_antenna_detection_check(IN struct btc_coexist + *btcoexist) +{ + static u32 ant_det_count = 0, ant_det_fail_count = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + + boolean scan, roam, ant_det_finish = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + ant_det_count++; + + psd_scan->ant_det_try_count = ant_det_count; + + if (scan || roam) { + ant_det_finish = false; + psd_scan->ant_det_result = 6; + } else if (coex_sta->bt_disabled) { + ant_det_finish = false; + psd_scan->ant_det_result = 11; + } else if (coex_sta->num_of_profile >= 1) { + ant_det_finish = false; + psd_scan->ant_det_result = 7; + } else if ( + !psd_scan->ant_det_is_ant_det_available) { /* Antenna initial setup is not ready */ + ant_det_finish = false; + psd_scan->ant_det_result = 9; + } else if (coex_sta->c2h_bt_inquiry_page) { + ant_det_finish = false; + psd_scan->ant_det_result = 10; + } else { + + ant_det_finish = halbtc8723d2ant_psd_antenna_detection( + btcoexist); + + delay_ms(psd_scan->ant_det_bt_tx_time); + } + + + if (!ant_det_finish) + ant_det_fail_count++; + + psd_scan->ant_det_fail_count = ant_det_fail_count; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), result = %d, fail_count = %d, finish = %s\n", + psd_scan->ant_det_result, + psd_scan->ant_det_fail_count, + ant_det_finish == true ? "Yes" : "No"); + BTC_TRACE(trace_buf); + + return ant_det_finish; + +} + + +/* ************************************************************ + * work around function start with wa_halbtc8723d2ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8723d2ant_ + * ************************************************************ */ +void ex_halbtc8723d2ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + u32 value = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Execute 8723d 2-Ant PowerOn Setting xxxxxxxxxxxxxxxx!!\n"); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Ant Det Finish = %s, Ant Det Number = %d\n", + (board_info->btdm_ant_det_finish ? "Yes" : "No"), + board_info->btdm_ant_num_by_ant_det); + BTC_TRACE(trace_buf); + + + btcoexist->stop_coex_dm = true; + psd_scan->ant_det_is_ant_det_available = false; + + /* enable BB, REG_SYS_FUNC_EN such that we can write BB Register correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT(0) | BIT(1)); + + + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + + /* Set path control to WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x80, 0x1); + btcoexist->btc_write_2byte(btcoexist, 0x948, 0x0); + + /* Check efuse 0xc3[6] for Single Antenna Path */ + if (board_info->single_ant_path == 0) { + /* set to S1 */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + u8tmp = 4; + value = 1; + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + u8tmp = 5; + value = 0; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (Power On) single_ant_path = %d, btdm_ant_pos = %d **********\n", + board_info->single_ant_path , board_info->btdm_ant_pos); + BTC_TRACE(trace_buf); + + /* Set Antenna Path to BT side */ + halbtc8723d2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_1ANT_PHASE_COEX_POWERON); + + /* Write Single Antenna Position to Registry to tell BT for 872db. This line can be removed + since BT EFuse also add "single antenna position" in EFuse for 8723d*/ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ANTPOSREGRISTRY_CTRL, + &value); + + /* Save"single antenna position" info in Local register setting for FW reading, because FW may not ready at power on */ + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x3e0, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, u8tmp); + + /* enable GNT_WL/GNT_BT debug signal to GPIO14/15 */ + halbtc8723d2ant_enable_gnt_to_gpio(btcoexist, true); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** LTE coex Reg 0x38 (Power-On) = 0x%x**********\n", + halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, 0x38)); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** MAC Reg 0x70/ BB Reg 0x948 (Power-On) = 0x%x / 0x%x**********\n", + btcoexist->btc_read_4byte(btcoexist, 0x70), + btcoexist->btc_read_2byte(btcoexist, 0x948)); + BTC_TRACE(trace_buf); +} + +void ex_halbtc8723d2ant_pre_load_firmware(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x4; /* Set BIT2 by default since it's 2ant case */ + + /* */ + /* S0 or S1 setting and Local register setting(By the setting fw can get ant number, S0/S1, ... info) */ + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + u8tmp |= 0x1; /* antenna inverse */ + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + u8tmp |= 0x1; /* antenna inverse */ + } + + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x3e0, + u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, + u8tmp); + } +} + + +void ex_halbtc8723d2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8723d2ant_init_hw_config(btcoexist, wifi_only); +} + +void ex_halbtc8723d2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + + halbtc8723d2ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8723d2ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, ps_tdma_case = 0; + u32 u32tmp[4]; + u16 u16tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck, bt_coex_ver = 0; + u32 fw_ver = 0, bt_patch_ver = 0; + static u8 pop_report_in_10s = 0; + u32 phyver = 0; + boolean lte_coex_on = false; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (psd_scan->ant_det_try_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %s", + "Ant PG Num/ Mech/ Pos", + board_info->pg_ant_num, board_info->btdm_ant_num, + (board_info->btdm_ant_pos == 1 ? "S1" : "S0")); + CL_PRINTF(cli_buf); + } else { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %s (retry=%d/fail=%d/result=%d)", + "Ant PG Num/ Mech(Ant_Det)/ Pos", + board_info->pg_ant_num, + board_info->btdm_ant_num_by_ant_det, + (board_info->btdm_ant_pos == 1 ? "S1" : "S0"), + psd_scan->ant_det_try_count, + psd_scan->ant_det_fail_count, + psd_scan->ant_det_result); + CL_PRINTF(cli_buf); + + if (board_info->btdm_ant_det_finish) { + + if (psd_scan->ant_det_result != 12) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s", + "Ant Det PSD Value", + psd_scan->ant_det_peak_val); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d", + "Ant Det PSD Value", + psd_scan->ant_det_psd_scan_peak_val + / 100); + CL_PRINTF(cli_buf); + } + } + + if (board_info->ant_det_result_five_complete) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d", + "AntDet(Registry) Num/PSD Value", + board_info->btdm_ant_num_by_ant_det, + (board_info->antdetval & 0x7f)); + CL_PRINTF(cli_buf); + } + + + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + + bt_coex_ver = coex_sta->bt_coex_supported_version & 0xff; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8723d_2ant, glcoex_ver_8723d_2ant, + glcoex_ver_btdesired_8723d_2ant, + bt_coex_ver, + (bt_coex_ver == 0xff ? "Unknown" : + (coex_sta->bt_disabled ? "BT-disable" : + (bt_coex_ver >= glcoex_ver_btdesired_8723d_2ant ? + "Match" : "Mis-Match")))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ v%d/ %c", + "W_FW/ B_FW/ Phy/ Kt", + fw_ver, bt_patch_ver, phyver, + coex_sta->cut_version + 65); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "Wifi channel informed to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d ", + "Isolation/WL_Thres/BT_Thres", + coex_sta->isolation_btween_wb, + coex_sta->wifi_coex_thres, + coex_sta->bt_coex_thres); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + pop_report_in_10s++; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = [%s/ %d dBm/ %d/ %d] ", + "BT [status/ rssi/ retryCnt/ popCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page") + : ((BT_8723D_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8723D_2ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi - 100, coex_sta->bt_retry_cnt, + coex_sta->pop_event_cnt); + CL_PRINTF(cli_buf); + + if (pop_report_in_10s >= 5) { + coex_sta->pop_event_cnt = 0; + pop_report_in_10s = 0; + } + + + if (coex_sta->num_of_profile != 0) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s%s%s%s%s", + "Profiles", + ((bt_link_info->a2dp_exist) ? "A2DP," : ""), + ((bt_link_info->sco_exist) ? "SCO," : ""), + ((bt_link_info->hid_exist) ? + ((coex_sta->hid_busy_num >= 2) ? "HID(4/18)," : + "HID(2/18),") : ""), + ((bt_link_info->pan_exist) ? "PAN," : ""), + ((coex_sta->voice_over_HOGP) ? "Voice" : "")); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = None", + "Profiles"); + + CL_PRINTF(cli_buf); + + + if (bt_link_info->a2dp_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %d/ %s", + "A2DP Rate/Bitpool/Auto_Slot", + ((coex_sta->is_A2DP_3M) ? "3M" : "No_3M"), + coex_sta->a2dp_bit_pool, + ((coex_sta->is_autoslot) ? "On" : "Off") + ); + CL_PRINTF(cli_buf); + } + + if (bt_link_info->hid_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "HID PairNum/Forbid_Slot", + coex_sta->hid_pair_cnt, + coex_sta->forbidden_slot + ); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ 0x%x/ 0x%x", + "Role/IgnWlanAct/Feature/BLEScan", + ((bt_link_info->slave_role) ? "Slave" : "Master"), + ((coex_dm->cur_ignore_wlan_act) ? "Yes" : "No"), + coex_sta->bt_coex_supported_feature, + coex_sta->bt_ble_scan_type); + CL_PRINTF(cli_buf); + + if ((coex_sta->bt_ble_scan_type & 0x7) != 0x0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%08x/ 0x%08x/ 0x%08x", + "BLEScan Intv-Win TV/Init/Ble", + (coex_sta->bt_ble_scan_type & 0x1 ? + coex_sta->bt_ble_scan_para[0] : 0x0), + (coex_sta->bt_ble_scan_type & 0x2 ? + coex_sta->bt_ble_scan_para[1] : 0x0), + (coex_sta->bt_ble_scan_type & 0x4 ? + coex_sta->bt_ble_scan_para[2] : 0x0)); + + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", + "ReInit/ReLink/IgnWlact/Page/NameReq", + coex_sta->cnt_ReInit, + coex_sta->cnt_setupLink, + coex_sta->cnt_IgnWlanAct, + coex_sta->cnt_Page, + coex_sta->cnt_RemoteNameReq + ); + CL_PRINTF(cli_buf); + + halbtc8723d2ant_read_score_board(btcoexist, &u16tmp[0]); + + if ((coex_sta->bt_reg_vendor_ae == 0xffff) || + (coex_sta->bt_reg_vendor_ac == 0xffff)) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = x/ x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", u16tmp[0]); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", + ((coex_sta->bt_reg_vendor_ae & BIT(4)) >> 4), + coex_sta->bt_reg_vendor_ac & 0x3, u16tmp[0]); + CL_PRINTF(cli_buf); + + if (coex_sta->num_of_profile > 0) { + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + "AFH MAP", + coex_sta->bt_afh_map[0], + coex_sta->bt_afh_map[1], + coex_sta->bt_afh_map[2], + coex_sta->bt_afh_map[3], + coex_sta->bt_afh_map[4], + coex_sta->bt_afh_map[5], + coex_sta->bt_afh_map[6], + coex_sta->bt_afh_map[7], + coex_sta->bt_afh_map[8], + coex_sta->bt_afh_map[9] + ); + CL_PRINTF(cli_buf); + } + + for (i = 0; i < BT_INFO_SRC_8723D_2ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x (%d)", + glbt_info_src_8723d_2ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + /* Sw mechanism */ + if (btcoexist->manual_control) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanism] (before Manual)============"); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Mechanism]============"); + + CL_PRINTF(cli_buf); + + + ps_tdma_case = coex_dm->cur_ps_tdma; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x (case-%d, %s, %s)", + "TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + (coex_dm->cur_ps_tdma_on ? "TDMA On" : "TDMA Off"), + (coex_dm->is_switch_to_1dot5_ant ? "1.5Ant" : "2Ant")); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ 0x%x/ 0x%x/ 0x%x", + "Table/0x6c0/0x6c4/0x6c8", + coex_sta->coex_table_type, u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x", + "0x778/0x6cc", + u8tmp[0], u32tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s", + "AntDiv/ ForceLPS", + ((board_info->ant_div_cfg) ? "On" : "Off"), + ((coex_sta->force_lps_on) ? "On" : "Off")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "WL_DACSwing/ BT_Dec_Pwr", coex_dm->cur_fw_dac_swing_lvl, + coex_dm->cur_bt_dec_pwr_lvl); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + lte_coex_on = ((u32tmp[0] & BIT(7)) >> 7) ? true : false; + + if (lte_coex_on) { + + u32tmp[0] = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, + 0xa0); + u32tmp[1] = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, + 0xa4); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "LTE Coex Table W_L/B_L", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, + 0xa8); + u32tmp[1] = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, + 0xac); + u32tmp[2] = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, + 0xb0); + u32tmp[3] = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, + 0xb4); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "LTE Break Table W_L/B_L/L_W/L_B", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff, + u32tmp[2] & 0xffff, u32tmp[3] & 0xffff); + CL_PRINTF(cli_buf); + + } + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + /* + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + */ + u32tmp[0] = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp[1] = halbtc8723d2ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x73); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s", + "LTE Coex/Path Owner", + ((lte_coex_on) ? "On" : "Off") , + ((u8tmp[0] & BIT(2)) ? "WL" : "BT")); + CL_PRINTF(cli_buf); + + if (lte_coex_on) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %d/ %d", + "LTE 3Wire/OPMode/UART/UARTMode", + (int)((u32tmp[0] & BIT(6)) >> 6), + (int)((u32tmp[0] & (BIT(5) | BIT(4))) >> 4), + (int)((u32tmp[0] & BIT(3)) >> 3), + (int)(u32tmp[0] & (BIT(2) | BIT(1) | BIT(0)))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "LTE_Busy/UART_Busy", + (int)((u32tmp[1] & BIT(1)) >> 1), (int)(u32tmp[1] & BIT(0))); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (BB:%s)/ %s (BB:%s)/ %s %d", + "GNT_WL_Ctrl/GNT_BT_Ctrl/Dbg", + ((u32tmp[0] & BIT(12)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(8)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(14)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(10)) ? "SW" : "HW"), + ((u8tmp[0] & BIT(3)) ? "On" : "Off"), + coex_sta->gnt_error_cnt); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "GNT_WL/GNT_BT", + (int)((u32tmp[1] & BIT(2)) >> 2), + (int)((u32tmp[1] & BIT(3)) >> 3)); + CL_PRINTF(cli_buf); + + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x948); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x67); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x948/0x67[7]", + u16tmp[0], (int)((u8tmp[0] & BIT(7)) >> 7)); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x964); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x864); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0xab7); + u8tmp[3] = btcoexist->btc_read_1byte(btcoexist, 0xa01); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x964[1]/0x864[0]/0xab7[5]/0xa01[7]", + (int)((u8tmp[0] & BIT(1)) >> 1), (int)((u8tmp[1] & BIT(0))), + (int)((u8tmp[2] & BIT(3)) >> 3), + (int)((u8tmp[3] & BIT(7)) >> 7)); + CL_PRINTF(cli_buf); + + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x4c6); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x45e); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x4c6[4]/0x40[5]/0x45e[3](TxRetry)", + (int)((u8tmp[0] & BIT(4)) >> 4), + (int)((u8tmp[1] & BIT(5)) >> 5), + (int)((u8tmp[2] & BIT(3)) >> 3)); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x953); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ %s", + "0x550/0x522/4-RxAGC", + u32tmp[0], u8tmp[0], (u8tmp[1] & 0x2) ? "On" : "Off"); + CL_PRINTF(cli_buf); + + fa_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, PHYDM_INFO_FA_OFDM); + fa_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, PHYDM_INFO_FA_CCK); + cca_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, PHYDM_INFO_CCA_OFDM); + cca_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, PHYDM_INFO_CCA_CCK); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", + cca_cck, fa_cck, cca_ofdm, fa_ofdm); + CL_PRINTF(cli_buf); + +#if 1 + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11n-agg", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11n-agg", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + CL_PRINTF(cli_buf); +#endif + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s/ %d", + "WlHiPri/ Locking/ Locked/ Noisy", + (coex_sta->wifi_is_high_pri_task ? "Yes" : "No"), + (coex_sta->cck_lock ? "Yes" : "No"), + (coex_sta->cck_ever_lock ? "Yes" : "No"), + coex_sta->wl_noisy_level); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d %s", + "0x770(Hi-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx, + (coex_sta->is_hiPri_rx_overhead ? "(scan overhead!!)" : "")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d %s", + "0x774(Lo-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx, + (bt_link_info->slave_role ? "(Slave!!)" : ( + coex_sta->is_tdma_btautoslot_hang ? "(auto-slot hang!!)" : ""))); + CL_PRINTF(cli_buf); + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8723d2ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + coex_sta->under_lps = false; + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, false); + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ONOFF, false); + + halbtc8723d2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_2ANT_PHASE_WLAN_OFF); + + halbtc8723d2ant_action_coex_all_off(btcoexist); + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = false; + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, true); + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ONOFF, true); + + halbtc8723d2ant_init_hw_config(btcoexist, false); + halbtc8723d2ant_init_coex_dm(btcoexist); + halbtc8723d2ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8723d2ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + coex_sta->under_ips = false; + + if (coex_sta->force_lps_on == true) { /* LPS No-32K */ + /* Write WL "Active" in Score-board for PS-TDMA */ + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, true); + + } else { /* LPS-32K, need check if this h2c 0x71 can work?? (2015/08/28) */ + /* Write WL "Non-Active" in Score-board for Native-PS */ + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, false); + } + + + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, true); + } +} + +void ex_halbtc8723d2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u32 u32tmp; + u8 u8tmpa, u8tmpb; + boolean wifi_connected = false; + + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* this can't be removed for RF off_on event, or BT would dis-connect */ + halbtc8723d2ant_query_bt_info(btcoexist); + + if (BTC_SCAN_START == type) { + + if (!wifi_connected) + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_SCAN, true); + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, true); + + halbtc8723d2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_2ANT_PHASE_2G_RUNTIME); + + halbtc8723d2ant_run_coexist_mechanism(btcoexist); + + } else if (BTC_SCAN_FINISH == type) { + + coex_sta->wifi_is_high_pri_task = false; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify (Scan-AP = %d)\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_SCAN, false); + + halbtc8723d2ant_run_coexist_mechanism(btcoexist); + } + +} + +void ex_halbtc8723d2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if (BTC_ASSOCIATE_START == type) { + + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, true); + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, true); + + halbtc8723d2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_2ANT_PHASE_2G_RUNTIME); + + halbtc8723d2ant_run_coexist_mechanism(btcoexist); + /* To keep TDMA case during connect process, + to avoid changed by Btinfo and runcoexmechanism */ + coex_sta->freeze_coexrun_by_btinfo = true; + + coex_dm->arp_cnt = 0; + + } else if (BTC_ASSOCIATE_FINISH == type) { + + coex_sta->wifi_is_high_pri_task = false; + coex_sta->freeze_coexrun_by_btinfo = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_run_coexist_mechanism(btcoexist); + } +} + +void ex_halbtc8723d2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + u8 ap_num = 0; + boolean wifi_under_b_mode = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if (BTC_MEDIA_CONNECT == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, true); + + halbtc8723d2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_2ANT_PHASE_2G_RUNTIME); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, false); + } + + + halbtc8723d2ant_update_wifi_channel_info(btcoexist, type); +} + +void ex_halbtc8723d2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean under_4way = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (under_4way) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ---- under_4way!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + + } else if (BTC_PACKET_ARP == type) { + + coex_dm->arp_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ARP notify -cnt = %d\n", + coex_dm->arp_cnt); + BTC_TRACE(trace_buf); + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet DHCP or EAPOL notify [Type = %d]\n", + type); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } + + if (coex_sta->wifi_is_high_pri_task) { + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, true); + halbtc8723d2ant_run_coexist_mechanism(btcoexist); + } + +} + +void ex_halbtc8723d2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 i, rsp_source = 0; + boolean wifi_connected = false; + boolean wifi_scan = false, wifi_link = false, wifi_roam = false, + wifi_busy = false; + + if (psd_scan->is_AntDet_running == true) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], bt_info_notify return for AntDet is running\n"); + BTC_TRACE(trace_buf); + return; + } + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8723D_2ANT_MAX) + rsp_source = BT_INFO_SRC_8723D_2ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt_info[%d], len=%d, data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + coex_sta->bt_info = coex_sta->bt_info_c2h[rsp_source][1]; + coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + coex_sta->bt_info_ext2 = coex_sta->bt_info_c2h[rsp_source][5]; + + if (BT_INFO_SRC_8723D_2ANT_WIFI_FW != rsp_source) { + + /* if 0xff, it means BT is under WHCK test */ + coex_sta->bt_whck_test = ((coex_sta->bt_info == 0xff) ? true : + false); + + coex_sta->bt_create_connection = (( + coex_sta->bt_info_c2h[rsp_source][2] & 0x80) ? true : + false); + + /* unit: %, value-100 to translate to unit: dBm */ + coex_sta->bt_rssi = coex_sta->bt_info_c2h[rsp_source][3] * 2 + + 10; + + coex_sta->c2h_bt_remote_name_req = (( + coex_sta->bt_info_c2h[rsp_source][2] & 0x20) ? true : + false); + + coex_sta->is_A2DP_3M = ((coex_sta->bt_info_c2h[rsp_source][2] & + 0x10) ? true : false); + + coex_sta->acl_busy = ((coex_sta->bt_info_c2h[rsp_source][1] & + 0x9) ? true : false); + + coex_sta->voice_over_HOGP = ((coex_sta->bt_info_ext & 0x10) ? + true : false); + + coex_sta->c2h_bt_inquiry_page = ((coex_sta->bt_info & + BT_INFO_8723D_2ANT_B_INQ_PAGE) ? true : false); + + coex_sta->a2dp_bit_pool = ((( + coex_sta->bt_info_c2h[rsp_source][1] & 0x49) == 0x49) ? + coex_sta->bt_info_c2h[rsp_source][6] : 0); + + coex_sta->bt_retry_cnt = coex_sta->bt_info_c2h[rsp_source][2] & + 0xf; + + coex_sta->is_autoslot = coex_sta->bt_info_ext2 & 0x8; + + coex_sta->forbidden_slot = coex_sta->bt_info_ext2 & 0x7; + + coex_sta->hid_busy_num = (coex_sta->bt_info_ext2 & 0x30) >> 4; + + coex_sta->hid_pair_cnt = (coex_sta->bt_info_ext2 & 0xc0) >> 6; + + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->c2h_bt_remote_name_req) + coex_sta->cnt_RemoteNameReq++; + + if (coex_sta->bt_info_ext & BIT(1)) + coex_sta->cnt_ReInit++; + + if (coex_sta->bt_info_ext & BIT(2)) { + coex_sta->cnt_setupLink++; + coex_sta->is_setupLink = true; + } else + coex_sta->is_setupLink = false; + + if (coex_sta->bt_info_ext & BIT(3)) + coex_sta->cnt_IgnWlanAct++; + + if (coex_sta->bt_create_connection) { + coex_sta->cnt_Page++; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &wifi_link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &wifi_roam); + + if ((wifi_link) || (wifi_roam) || (wifi_scan) || + (coex_sta->wifi_is_high_pri_task) || (wifi_busy)) { + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_SCAN, true); + + } else { + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_SCAN, false); + } + } else + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_SCAN, false); + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + + if ((!btcoexist->manual_control) && + (!btcoexist->stop_coex_dm)) { + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* Re-Init */ + if ((coex_sta->bt_info_ext & BIT(1))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + if (wifi_connected) + halbtc8723d2ant_update_wifi_channel_info( + btcoexist, BTC_MEDIA_CONNECT); + else + halbtc8723d2ant_update_wifi_channel_info( + btcoexist, + BTC_MEDIA_DISCONNECT); + } + + + /* If Ignore_WLanAct && not SetUp_Link or Role_Switch */ + if ((coex_sta->bt_info_ext & BIT(3)) && + (!(coex_sta->bt_info_ext & BIT(2))) && + (!(coex_sta->bt_info_ext & BIT(6)))) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8723d2ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, false); + } else { + if (coex_sta->bt_info_ext & BIT(2)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ignore Wlan active because Re-link!!\n"); + BTC_TRACE(trace_buf); + } else if (coex_sta->bt_info_ext & BIT(6)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ignore Wlan active because Role-Switch!!\n"); + BTC_TRACE(trace_buf); + } + } + } + + } + + if ((coex_sta->bt_info_ext & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit4 check, query BLE Scan type!!\n"); + BTC_TRACE(trace_buf); + coex_sta->bt_ble_scan_type = btcoexist->btc_get_ble_scan_type_from_bt(btcoexist); + + if ((coex_sta->bt_ble_scan_type & 0x1) == 0x1) + coex_sta->bt_ble_scan_para[0] = btcoexist->btc_get_ble_scan_para_from_bt(btcoexist, 0x1); + if ((coex_sta->bt_ble_scan_type & 0x2) == 0x2) + coex_sta->bt_ble_scan_para[1] = btcoexist->btc_get_ble_scan_para_from_bt(btcoexist, 0x2); + if ((coex_sta->bt_ble_scan_type & 0x4) == 0x4) + coex_sta->bt_ble_scan_para[2] = btcoexist->btc_get_ble_scan_para_from_bt(btcoexist, 0x4); + } + + halbtc8723d2ant_update_bt_link_info(btcoexist); + + halbtc8723d2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8723d2ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], RF Status notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_RF_ON == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned ON!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = false; + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, true); + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ONOFF, true); + } else if (BTC_RF_OFF == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned OFF!!\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_2ANT_PHASE_WLAN_OFF); + + halbtc8723d2ant_action_coex_all_off(btcoexist); + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, false); + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ONOFF, false); + btcoexist->stop_coex_dm = true; + + } +} + +void ex_halbtc8723d2ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_2ANT_PHASE_WLAN_OFF); + + ex_halbtc8723d2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, false); + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ONOFF, false); +} + +void ex_halbtc8723d2ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Pnp notify\n"); + BTC_TRACE(trace_buf); + + if ((BTC_WIFI_PNP_SLEEP == pnp_state) || + (BTC_WIFI_PNP_SLEEP_KEEP_ANT == pnp_state)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + + /* Sinda 20150819, workaround for driver skip leave IPS/LPS to speed up sleep time. */ + /* Driver do not leave IPS/LPS when driver is going to sleep, so BTCoexistence think wifi is still under IPS/LPS */ + /* BT should clear UnderIPS/UnderLPS state to avoid mismatch state after wakeup. */ + coex_sta->under_ips = false; + coex_sta->under_lps = false; + + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, false); + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ONOFF, false); + + if (BTC_WIFI_PNP_SLEEP_KEEP_ANT == pnp_state) { + + halbtc8723d2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_2ANT_PHASE_2G_RUNTIME); + } else { + + halbtc8723d2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_2ANT_PHASE_WLAN_OFF); + } + + + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ACTIVE, true); + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_ONOFF, true); + } +} + +void ex_halbtc8723d2ant_periodical(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + boolean wifi_busy = false; + u32 bt_patch_ver; + static u8 cnt = 0; + boolean bt_relink_finish = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ************* Periodical *************\n"); + BTC_TRACE(trace_buf); + +#if (BT_AUTO_REPORT_ONLY_8723D_2ANT == 0) + halbtc8723d2ant_query_bt_info(btcoexist); +#endif + + halbtc8723d2ant_monitor_bt_ctr(btcoexist); + halbtc8723d2ant_monitor_wifi_ctr(btcoexist); + halbtc8723d2ant_monitor_bt_enable_disable(btcoexist); + +# if 1 + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + /* halbtc8723d2ant_read_score_board(btcoexist, &bt_scoreboard_val); */ + + if (wifi_busy) { + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_UNDERTEST, true); + /* + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_WLBUSY, true); + + if (bt_scoreboard_val & BIT(6)) + halbtc8723d2ant_query_bt_info(btcoexist); */ + } else { + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_UNDERTEST, false); + /* + halbtc8723d2ant_post_state_to_bt(btcoexist, + BT_8723D_2ANT_SCOREBOARD_WLBUSY, + false); */ + } +#endif + + if (coex_sta->bt_relink_downcount != 0) { + coex_sta->bt_relink_downcount--; + + if (coex_sta->bt_relink_downcount == 0) + bt_relink_finish = true; + } + + /* for 4-way, DHCP, EAPOL packet */ + if (coex_sta->specific_pkt_period_cnt > 0) { + + coex_sta->specific_pkt_period_cnt--; + + if ((coex_sta->specific_pkt_period_cnt == 0) && + (coex_sta->wifi_is_high_pri_task)) + coex_sta->wifi_is_high_pri_task = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ***************** Hi-Pri Task = %s*****************\n", + (coex_sta->wifi_is_high_pri_task ? "Yes" : + "No")); + BTC_TRACE(trace_buf); + + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->bt_coex_supported_feature == 0) + btcoexist->btc_get(btcoexist, BTC_GET_U4_SUPPORTED_FEATURE, + &coex_sta->bt_coex_supported_feature); + + if ((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) + btcoexist->btc_get(btcoexist, BTC_GET_U4_SUPPORTED_VERSION, + &coex_sta->bt_coex_supported_version); + + if (coex_sta->bt_reg_vendor_ac == 0xffff) + coex_sta->bt_reg_vendor_ac = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, + 0xac) & 0xffff); + + if (coex_sta->bt_reg_vendor_ae == 0xffff) + coex_sta->bt_reg_vendor_ae = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, + 0xae) & 0xffff); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, + &bt_patch_ver); + btcoexist->bt_info.bt_get_fw_ver = bt_patch_ver; + + if (coex_sta->num_of_profile > 0) { + cnt++; + + if (cnt >= 3) { + btcoexist->btc_get_bt_afh_map_from_bt(btcoexist, 0, + &coex_sta->bt_afh_map[0]); + cnt = 0; + } + } + +#if BT_8723D_2ANT_ANTDET_ENABLE + + if (board_info->btdm_ant_det_finish) { + if ((psd_scan->ant_det_result == 12) && + (psd_scan->ant_det_psd_scan_peak_val == 0) + && (!psd_scan->is_AntDet_running)) + psd_scan->ant_det_psd_scan_peak_val = + btcoexist->btc_get_ant_det_val_from_bt( + btcoexist) * 100; + } + +#endif + } + + + if (halbtc8723d2ant_is_wifibt_status_changed(btcoexist)) + halbtc8723d2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8723d2ant_set_antenna_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (type == 2) { /* two antenna */ + board_info->ant_div_cfg = true; + + halbtc8723d2ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI, + FORCE_EXEC, + BT_8723D_2ANT_PHASE_2G_RUNTIME); + + } else { /* one antenna */ + + halbtc8723d2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8723D_2ANT_PHASE_2G_RUNTIME); + + } +} + +#ifdef PLATFORM_WINDOWS +#pragma optimize("", off) +#endif +void ex_halbtc8723d2ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ + + static u32 ant_det_count = 0, ant_det_fail_count = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + u16 u16tmp; + u8 AntDetval = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Ext Call AntennaDetect()!!\n"); + BTC_TRACE(trace_buf); + +#if BT_8723D_2ANT_ANTDET_ENABLE + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Call AntennaDetect()!!\n"); + BTC_TRACE(trace_buf); + + if (seconds == 0) { + psd_scan->ant_det_try_count = 0; + psd_scan->ant_det_fail_count = 0; + ant_det_count = 0; + ant_det_fail_count = 0; + board_info->btdm_ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + return; + } + + if (!board_info->btdm_ant_det_finish) { + psd_scan->ant_det_inteval_count = + psd_scan->ant_det_inteval_count + 2; + + if (psd_scan->ant_det_inteval_count >= + BT_8723D_2ANT_ANTDET_RETRY_INTERVAL) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Timer is up, Try Detect!!\n"); + BTC_TRACE(trace_buf); + + psd_scan->is_AntDet_running = true; + + halbtc8723d2ant_read_score_board(btcoexist, &u16tmp); + + if (u16tmp & BIT( + 2)) { /* Antenna detection is already done before last WL power on */ + board_info->btdm_ant_det_finish = true; + psd_scan->ant_det_try_count = 1; + psd_scan->ant_det_fail_count = 0; + board_info->btdm_ant_num_by_ant_det = (u16tmp & + BIT(3)) ? 1 : 2; + psd_scan->ant_det_result = 12; + + psd_scan->ant_det_psd_scan_peak_val = + btcoexist->btc_get_ant_det_val_from_bt( + btcoexist) * 100; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Result from BT (%d-Ant)\n", + board_info->btdm_ant_num_by_ant_det); + BTC_TRACE(trace_buf); + } else + board_info->btdm_ant_det_finish = + halbtc8723d2ant_psd_antenna_detection_check( + btcoexist); + + btcoexist->bdontenterLPS = false; + + if (board_info->btdm_ant_det_finish) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Success!!\n"); + BTC_TRACE(trace_buf); + + /*for 8723d, btc_set_bt_trx_mask is just used to + notify BT stop le tx and Ant Det Result , not set BT RF TRx Mask */ + if (psd_scan->ant_det_result != 12) { + + AntDetval = (u8)( + psd_scan->ant_det_psd_scan_peak_val + / 100) & 0x7f; + + AntDetval = + (board_info->btdm_ant_num_by_ant_det + == 1) ? (AntDetval | 0x80) : + AntDetval; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Ant Count = %d, PSD Val = %d\n", + ((AntDetval & + 0x80) ? 1 + : 2), AntDetval + & 0x7f); + BTC_TRACE(trace_buf); + + if (btcoexist->btc_set_bt_trx_mask( + btcoexist, AntDetval)) + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Notify BT stop le tx by set_bt_trx_mask ok!\n"); + else + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Notify BT stop le tx by set_bt_trx_mask fail!\n"); + + BTC_TRACE(trace_buf); + } else + board_info->antdetval = + psd_scan->ant_det_psd_scan_peak_val/100; + + board_info->btdm_ant_det_complete_fail = false; + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Fail!!\n"); + BTC_TRACE(trace_buf); + } + + psd_scan->ant_det_inteval_count = 0; + psd_scan->is_AntDet_running = false; + + /* stimulate coex running */ + halbtc8723d2ant_run_coexist_mechanism( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Stimulate Coex running\n!!"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Timer is not up! (%d)\n", + psd_scan->ant_det_inteval_count); + BTC_TRACE(trace_buf); + + if (psd_scan->ant_det_inteval_count == 8) + btcoexist->bdontenterLPS = true; + else + btcoexist->bdontenterLPS = false; + } + + } +#endif + + +} + + +void ex_halbtc8723d2ant_display_ant_detection(IN struct btc_coexist *btcoexist) +{ + +#if BT_8723D_2ANT_ANTDET_ENABLE + struct btc_board_info *board_info = &btcoexist->board_info; + + if (psd_scan->ant_det_try_count != 0) { + halbtc8723d2ant_psd_show_antenna_detect_result(btcoexist); + + if (board_info->btdm_ant_det_finish) + halbtc8723d2ant_psd_showdata(btcoexist); + } +#endif + +} + + +#endif + +#endif /* #if (RTL8723D_SUPPORT == 1) */ + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d2ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d2ant.h new file mode 100644 index 0000000..1472796 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8723d2ant.h @@ -0,0 +1,418 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8723D_SUPPORT == 1) + +/* ******************************************* + * The following is for 8723D 2Ant BT Co-exist definition + * ******************************************* */ +#define BT_8723D_2ANT_COEX_DBG 0 +#define BT_AUTO_REPORT_ONLY_8723D_2ANT 1 + + +#define BT_INFO_8723D_2ANT_B_FTP BIT(7) +#define BT_INFO_8723D_2ANT_B_A2DP BIT(6) +#define BT_INFO_8723D_2ANT_B_HID BIT(5) +#define BT_INFO_8723D_2ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8723D_2ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8723D_2ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8723D_2ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8723D_2ANT_B_CONNECTION BIT(0) + +#define BTC_RSSI_COEX_THRESH_TOL_8723D_2ANT 2 + + +#define BT_8723D_2ANT_WIFI_RSSI_COEXSWITCH_THRES1 80 /* unit: % WiFi RSSI Threshold for 2-Ant free-run/2-Ant TDMA translation, default = 42 */ +#define BT_8723D_2ANT_BT_RSSI_COEXSWITCH_THRES1 80 /* unit: % BT RSSI Threshold for 2-Ant free-run/2-Ant TDMA translation, default = 46 */ +#define BT_8723D_2ANT_WIFI_RSSI_COEXSWITCH_THRES2 80 /* unit: % WiFi RSSI Threshold for 1-Ant TDMA/1-Ant PS-TDMA translation, default = 42 */ +#define BT_8723D_2ANT_BT_RSSI_COEXSWITCH_THRES2 80 /* unit: % BT RSSI Threshold for 1-Ant TDMA/1-Ant PS-TDMA translation, default = 46 */ +#define BT_8723D_2ANT_DEFAULT_ISOLATION 15 /* unit: dB */ +#define BT_8723D_2ANT_WIFI_MAX_TX_POWER 15 /* unit: dBm */ +#define BT_8723D_2ANT_BT_MAX_TX_POWER 3 /* unit: dBm */ +#define BT_8723D_2ANT_WIFI_SIR_THRES1 -15 /* unit: dB */ +#define BT_8723D_2ANT_WIFI_SIR_THRES2 -30 /* unit: dB */ +#define BT_8723D_2ANT_BT_SIR_THRES1 -15 /* unit: dB */ +#define BT_8723D_2ANT_BT_SIR_THRES2 -30 /* unit: dB */ + + +/* for Antenna detection */ +#define BT_8723D_2ANT_ANTDET_PSDTHRES_BACKGROUND 50 +#define BT_8723D_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION 70 +#define BT_8723D_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION 52 +#define BT_8723D_2ANT_ANTDET_PSDTHRES_1ANT 40 +#define BT_8723D_2ANT_ANTDET_RETRY_INTERVAL 10 /* retry timer if ant det is fail, unit: second */ +#define BT_8723D_2ANT_ANTDET_SWEEPPOINT_DELAY 60000 +#define BT_8723D_2ANT_ANTDET_ENABLE 1 +#define BT_8723D_2ANT_ANTDET_BTTXTIME 100 +#define BT_8723D_2ANT_ANTDET_BTTXCHANNEL 39 +#define BT_8723D_2ANT_ANTDET_PSD_SWWEEPCOUNT 50 + + +#define BT_8723D_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT 30000 + +enum bt_8723d_2ant_signal_state { + BT_8723D_2ANT_SIG_STA_SET_TO_LOW = 0x0, + BT_8723D_2ANT_SIG_STA_SET_BY_HW = 0x0, + BT_8723D_2ANT_SIG_STA_SET_TO_HIGH = 0x1, + BT_8723D_2ANT_SIG_STA_MAX +}; + +enum bt_8723d_2ant_path_ctrl_owner { + BT_8723D_2ANT_PCO_BTSIDE = 0x0, + BT_8723D_2ANT_PCO_WLSIDE = 0x1, + BT_8723D_2ANT_PCO_MAX +}; + +enum bt_8723d_2ant_gnt_ctrl_type { + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_PTA = 0x0, + BT_8723D_2ANT_GNT_TYPE_CTRL_BY_SW = 0x1, + BT_8723D_2ANT_GNT_TYPE_MAX +}; + +enum bt_8723d_2ant_gnt_ctrl_block { + BT_8723D_2ANT_GNT_BLOCK_RFC_BB = 0x0, + BT_8723D_2ANT_GNT_BLOCK_RFC = 0x1, + BT_8723D_2ANT_GNT_BLOCK_BB = 0x2, + BT_8723D_2ANT_GNT_BLOCK_MAX +}; + +enum bt_8723d_2ant_lte_coex_table_type { + BT_8723D_2ANT_CTT_WL_VS_LTE = 0x0, + BT_8723D_2ANT_CTT_BT_VS_LTE = 0x1, + BT_8723D_2ANT_CTT_MAX +}; + +enum bt_8723d_2ant_lte_break_table_type { + BT_8723D_2ANT_LBTT_WL_BREAK_LTE = 0x0, + BT_8723D_2ANT_LBTT_BT_BREAK_LTE = 0x1, + BT_8723D_2ANT_LBTT_LTE_BREAK_WL = 0x2, + BT_8723D_2ANT_LBTT_LTE_BREAK_BT = 0x3, + BT_8723D_2ANT_LBTT_MAX +}; + +enum bt_info_src_8723d_2ant { + BT_INFO_SRC_8723D_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8723D_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8723D_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8723D_2ANT_MAX +}; + +enum bt_8723d_2ant_bt_status { + BT_8723D_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723D_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723D_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8723D_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8723D_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8723D_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8723D_2ANT_BT_STATUS_MAX +}; + +enum bt_8723d_2ant_coex_algo { + BT_8723D_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8723D_2ANT_COEX_ALGO_SCO = 0x1, + BT_8723D_2ANT_COEX_ALGO_HID = 0x2, + BT_8723D_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8723D_2ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8723D_2ANT_COEX_ALGO_PANEDR = 0x5, + BT_8723D_2ANT_COEX_ALGO_PANHS = 0x6, + BT_8723D_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8723D_2ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8723D_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8723D_2ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8723D_2ANT_COEX_ALGO_NOPROFILEBUSY = 0xb, + BT_8723D_2ANT_COEX_ALGO_MAX +}; + +enum bt_8723d_2ant_phase { + BT_8723D_2ANT_PHASE_COEX_INIT = 0x0, + BT_8723D_2ANT_PHASE_WLANONLY_INIT = 0x1, + BT_8723D_2ANT_PHASE_WLAN_OFF = 0x2, + BT_8723D_2ANT_PHASE_2G_RUNTIME = 0x3, + BT_8723D_2ANT_PHASE_5G_RUNTIME = 0x4, + BT_8723D_2ANT_PHASE_BTMPMODE = 0x5, + BT_8723D_2ANT_PHASE_ANTENNA_DET = 0x6, + BT_8723D_2ANT_PHASE_COEX_POWERON = 0x7, + BT_8723D_2ANT_PHASE_MAX +}; + +enum bt_8723d_2ant_Scoreboard { + BT_8723D_2ANT_SCOREBOARD_ACTIVE = BIT(0), + BT_8723D_2ANT_SCOREBOARD_ONOFF = BIT(1), + BT_8723D_2ANT_SCOREBOARD_SCAN = BIT(2), + BT_8723D_2ANT_SCOREBOARD_UNDERTEST = BIT(3), + BT_8723D_2ANT_SCOREBOARD_WLBUSY = BIT(6) +}; + + + +struct coex_dm_8723d_2ant { + /* fw mechanism */ + u8 pre_bt_dec_pwr_lvl; + u8 cur_bt_dec_pwr_lvl; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean reset_tdma_adjust; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + + /* sw mechanism */ + boolean pre_rf_rx_lpf_shrink; + boolean cur_rf_rx_lpf_shrink; + u32 bt_rf_0x1e_backup; + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + boolean pre_dac_swing_on; + u32 pre_dac_swing_lvl; + boolean cur_dac_swing_on; + u32 cur_dac_swing_lvl; + boolean pre_adc_back_off; + boolean cur_adc_back_off; + boolean pre_agc_table_en; + boolean cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + boolean limited_dig; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + boolean need_recover0x948; + u32 backup0x948; + + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + boolean is_switch_to_1dot5_ant; + u8 switch_thres_offset; + u32 arp_cnt; + + u8 pre_ant_pos_type; + u8 cur_ant_pos_type; +}; + +struct coex_sta_8723d_2ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + + boolean under_lps; + boolean under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + boolean is_hiPri_rx_overhead; + u8 bt_rssi; + boolean bt_tx_rx_mask; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + u8 bt_info_c2h[BT_INFO_SRC_8723D_2ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8723D_2ANT_MAX]; + boolean bt_whck_test; + boolean c2h_bt_inquiry_page; + boolean c2h_bt_remote_name_req; + u8 bt_retry_cnt; + u8 bt_info_ext; + u8 bt_info_ext2; + u32 pop_event_cnt; + u8 scan_ap_num; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_vht; + + boolean cck_lock; + boolean pre_ccklock; + boolean cck_ever_lock; + u8 coex_table_type; + boolean force_lps_on; + + u8 dis_ver_info_cnt; + + u8 a2dp_bit_pool; + u8 cut_version; + + boolean concurrent_rx_mode_on; + + u16 score_board; + u8 isolation_btween_wb; /* 0~ 50 */ + u8 wifi_coex_thres; + u8 bt_coex_thres; + u8 wifi_coex_thres2; + u8 bt_coex_thres2; + + u8 num_of_profile; + boolean acl_busy; + boolean bt_create_connection; + boolean wifi_is_high_pri_task; + u32 specific_pkt_period_cnt; + u32 bt_coex_supported_feature; + u32 bt_coex_supported_version; + + u8 bt_ble_scan_type; + u32 bt_ble_scan_para[3]; + + boolean run_time_state; + boolean freeze_coexrun_by_btinfo; + + boolean is_A2DP_3M; + boolean voice_over_HOGP; + u8 bt_info; + boolean is_autoslot; + u8 forbidden_slot; + u8 hid_busy_num; + u8 hid_pair_cnt; + + u32 cnt_RemoteNameReq; + u32 cnt_setupLink; + u32 cnt_ReInit; + u32 cnt_IgnWlanAct; + u32 cnt_Page; + u32 cnt_RoleSwitch; + + u16 bt_reg_vendor_ac; + u16 bt_reg_vendor_ae; + + boolean is_setupLink; + boolean wl_noisy_level; + u32 gnt_error_cnt; + + u8 bt_afh_map[10]; + u8 bt_relink_downcount; + boolean is_tdma_btautoslot; + boolean is_tdma_btautoslot_hang; +}; + +#define BT_8723D_2ANT_ANTDET_PSD_POINTS 256 /* MAX:1024 */ +#define BT_8723D_2ANT_ANTDET_PSD_AVGNUM 1 /* MAX:3 */ +#define BT_8723D_2ANT_ANTDET_BUF_LEN 16 + +struct psdscan_sta_8723d_2ant { + + u32 ant_det_bt_le_channel; /* BT LE Channel ex:2412 */ + u32 ant_det_bt_tx_time; + u32 ant_det_pre_psdscan_peak_val; + boolean ant_det_is_ant_det_available; + u32 ant_det_psd_scan_peak_val; + boolean ant_det_is_btreply_available; + u32 ant_det_psd_scan_peak_freq; + + u8 ant_det_result; + u8 ant_det_peak_val[BT_8723D_2ANT_ANTDET_BUF_LEN]; + u8 ant_det_peak_freq[BT_8723D_2ANT_ANTDET_BUF_LEN]; + u32 ant_det_try_count; + u32 ant_det_fail_count; + u32 ant_det_inteval_count; + u32 ant_det_thres_offset; + + u32 real_cent_freq; + s32 real_offset; + u32 real_span; + + u32 psd_band_width; /* unit: Hz */ + u32 psd_point; /* 128/256/512/1024 */ + u32 psd_report[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_report_max_hold[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_start_point; + u32 psd_stop_point; + u32 psd_max_value_point; + u32 psd_max_value; + u32 psd_max_value2; + u32 psd_avg_value; /* filter loop_max_value that below BT_8723D_1ANT_ANTDET_PSDTHRES_1ANT, and average the rest*/ + u32 psd_loop_max_value[BT_8723D_2ANT_ANTDET_PSD_SWWEEPCOUNT]; /*max value in each loop */ + u32 psd_start_base; + u32 psd_avg_num; /* 1/8/16/32 */ + u32 psd_gen_count; + boolean is_AntDet_running; + boolean is_psd_show_max_only; +}; + + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8723d2ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8723d2ant_pre_load_firmware(IN struct btc_coexist *btcoexist); +void ex_halbtc8723d2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8723d2ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8723d2ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d2ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8723d2ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d2ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8723d2ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state); +void ex_halbtc8723d2ant_set_antenna_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8723d2ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8723d2ant_display_coex_info(IN struct btc_coexist *btcoexist); +void ex_halbtc8723d2ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); +void ex_halbtc8723d2ant_display_ant_detection(IN struct btc_coexist *btcoexist); + + +#else +#define ex_halbtc8723d2ant_power_on_setting(btcoexist) +#define ex_halbtc8723d2ant_pre_load_firmware(btcoexist) +#define ex_halbtc8723d2ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8723d2ant_init_coex_dm(btcoexist) +#define ex_halbtc8723d2ant_ips_notify(btcoexist, type) +#define ex_halbtc8723d2ant_lps_notify(btcoexist, type) +#define ex_halbtc8723d2ant_scan_notify(btcoexist, type) +#define ex_halbtc8723d2ant_connect_notify(btcoexist, type) +#define ex_halbtc8723d2ant_media_status_notify(btcoexist, type) +#define ex_halbtc8723d2ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8723d2ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8723d2ant_rf_status_notify(btcoexist, type) +#define ex_halbtc8723d2ant_halt_notify(btcoexist) +#define ex_halbtc8723d2ant_pnp_notify(btcoexist, pnp_state) +#define ex_halbtc8723d2ant_periodical(btcoexist) +#define ex_halbtc8723d2ant_display_coex_info(btcoexist) +#define ex_halbtc8723d2ant_set_antenna_notify(btcoexist, type) +#define ex_halbtc8723d2ant_display_ant_detection(btcoexist) +#define ex_halbtc8723d2ant_antenna_detection(btcoexist, cent_freq, offset, span, seconds) +#endif + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a1ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a1ant.c new file mode 100644 index 0000000..f1cefab --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a1ant.c @@ -0,0 +1,3461 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8812A Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8812A_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8812a_1ant glcoex_dm_8812a_1ant; +static struct coex_dm_8812a_1ant *coex_dm = &glcoex_dm_8812a_1ant; +static struct coex_sta_8812a_1ant glcoex_sta_8812a_1ant; +static struct coex_sta_8812a_1ant *coex_sta = &glcoex_sta_8812a_1ant; + +const char *const glbt_info_src_8812a_1ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u32 glcoex_ver_date_8812a_1ant = 20140708; +u32 glcoex_ver_8812a_1ant = 0x52; + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8812a1ant_ + * ************************************************************ */ +u8 halbtc8812a1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8812a1ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 index, IN u8 level_num, IN u8 rssi_thresh, IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8812a1ant_update_ra_mask(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 dis_rate_mask) +{ + coex_dm->cur_ra_mask = dis_rate_mask; + + if (force_exec || (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_RAMASK, + &coex_dm->cur_ra_mask); + coex_dm->pre_ra_mask = coex_dm->cur_ra_mask; +} + +/* to check 0x430/0x434 is correct?? */ +void halbtc8812a1ant_auto_rate_fallback_retry(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + boolean wifi_under_b_mode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + if (wifi_under_b_mode) { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +/* to check 0x42a ?? */ +void halbtc8812a1ant_retry_limit(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || + (coex_dm->pre_retry_limit_type != + coex_dm->cur_retry_limit_type)) { + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +/* to check 0x456?? */ +void halbtc8812a1ant_ampdu_max_time(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || + (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +void halbtc8812a1ant_limited_tx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ra_mask_type, IN u8 arfr_type, + IN u8 retry_limit_type, IN u8 ampdu_time_type) +{ + switch (ra_mask_type) { + case 0: /* normal mode */ + halbtc8812a1ant_update_ra_mask(btcoexist, force_exec, + 0x0); + break; + case 1: /* disable cck 1/2 */ + halbtc8812a1ant_update_ra_mask(btcoexist, force_exec, + 0x00000003); + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ + halbtc8812a1ant_update_ra_mask(btcoexist, force_exec, + 0x0001f1f7); + break; + default: + break; + } + + halbtc8812a1ant_auto_rate_fallback_retry(btcoexist, force_exec, + arfr_type); + halbtc8812a1ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8812a1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type); +} + +void halbtc8812a1ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +void halbtc8812a1ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 data_len = 3; + u8 buf[5] = {0}; + + if (!coex_sta->bt_disabled) { + if (!coex_sta->bt_info_query_cnt || + (coex_sta->bt_info_c2h_cnt[BT_INFO_SRC_8812A_1ANT_BT_RSP] + - coex_sta->bt_info_query_cnt) > 2) { + buf[0] = data_len; + buf[1] = 0x1; /* polling enable, 1=enable, 0=disable */ + buf[2] = 0x2; /* polling time in seconds */ + buf[3] = 0x1; /* auto report enable, 1=enable, 0=disable */ + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_CTRL_BT_INFO, + (void *)&buf[0]); + } + } + coex_sta->bt_info_query_cnt++; +} + +void halbtc8812a1ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + static u8 num_of_bt_counter_chk = 0; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + if ((coex_sta->low_priority_tx > 1150) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n", + reg_hp_rx, reg_hp_tx, reg_lp_rx, reg_lp_tx); + BTC_TRACE(trace_buf); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + if ((reg_hp_tx == 0) && (reg_hp_rx == 0) && (reg_lp_tx == 0) && + (reg_lp_rx == 0)) { + num_of_bt_counter_chk++; + if (num_of_bt_counter_chk >= 3) { + halbtc8812a1ant_query_bt_info(btcoexist); + num_of_bt_counter_chk = 0; + } + } +} + +/* to check registers */ +void halbtc8812a1ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ + s32 wifi_rssi = 0; + boolean wifi_busy = false, wifi_under_b_mode = false; + static u8 cck_lock_counter = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + if (coex_sta->under_ips) { + coex_sta->crc_ok_cck = 0; + coex_sta->crc_ok_11g = 0; + coex_sta->crc_ok_11n = 0; + coex_sta->crc_ok_11n_agg = 0; + + coex_sta->crc_err_cck = 0; + coex_sta->crc_err_11g = 0; + coex_sta->crc_err_11n = 0; + coex_sta->crc_err_11n_agg = 0; + } else { + coex_sta->crc_ok_cck = btcoexist->btc_read_2byte(btcoexist, + 0xf04); + coex_sta->crc_ok_11g = btcoexist->btc_read_2byte(btcoexist, + 0xf14); + coex_sta->crc_ok_11n = btcoexist->btc_read_2byte(btcoexist, + 0xf10); + coex_sta->crc_ok_11n_agg = btcoexist->btc_read_2byte(btcoexist, + 0xf40); + + coex_sta->crc_err_cck = btcoexist->btc_read_2byte(btcoexist, + 0xf06); + coex_sta->crc_err_11g = btcoexist->btc_read_2byte(btcoexist, + 0xf16); + coex_sta->crc_err_11n = btcoexist->btc_read_2byte(btcoexist, + 0xf12); + coex_sta->crc_err_11n_agg = btcoexist->btc_read_2byte(btcoexist, + 0xf42); + } + + + /* reset counter */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xb58, 0x1, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xb58, 0x1, 0x0); + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + if ((coex_dm->bt_status == BT_8812A_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == + BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY) || + (coex_dm->bt_status == + BT_8812A_1ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > (coex_sta->crc_ok_11g + + coex_sta->crc_ok_11n + + coex_sta->crc_ok_11n_agg)) { + if (cck_lock_counter < 5) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + + if (cck_lock_counter >= 5) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + coex_sta->pre_ccklock = coex_sta->cck_lock; + + +} + +boolean halbtc8812a1ant_is_wifi_status_changed(IN struct btc_coexist *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + } + + return false; +} + +void halbtc8812a1ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + +u8 halbtc8812a1ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8812A_1ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_1ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_1ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_1ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_1ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_1ANT_COEX_ALGO_SCO; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_1ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +void halbtc8812a1ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8812a1ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8812a1ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +/* to check */ +void halbtc8812a1ant_set_sw_penalty_tx_rate_adaptive(IN struct btc_coexist + *btcoexist, IN boolean low_penalty_ra) +{ + u8 tmp_u1; + + tmp_u1 = btcoexist->btc_read_1byte(btcoexist, 0x4fd); + tmp_u1 |= BIT(0); + if (low_penalty_ra) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Tx rate adaptive, set low penalty!!\n"); + BTC_TRACE(trace_buf); + tmp_u1 &= ~BIT(2); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Tx rate adaptive, set normal!!\n"); + BTC_TRACE(trace_buf); + tmp_u1 |= BIT(2); + } + + btcoexist->btc_write_1byte(btcoexist, 0x4fd, tmp_u1); +} + +void halbtc8812a1ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + halbtc8812a1ant_set_sw_penalty_tx_rate_adaptive(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +void halbtc8812a1ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8812a1ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8812a1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8812a1ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** CoexTable(%d) **********\n", type); + BTC_TRACE(trace_buf); + + coex_sta->coex_table_type = type; + + switch (type) { + case 0: + halbtc8812a1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x55555555, 0xffffff, 0x3); + break; + case 1: + halbtc8812a1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8812a1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 3: + halbtc8812a1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 4: + halbtc8812a1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaa5a5a, 0xffffff, 0x3); + break; + case 5: + halbtc8812a1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0xaa5a5a5a, 0xffffff, 0x3); + break; + case 6: + halbtc8812a1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 7: + halbtc8812a1ant_coex_table(btcoexist, force_exec, + 0xaaaaaaaa, 0xaaaaaaaa, 0xffffff, 0x3); + break; + default: + break; + } +} + +void halbtc8812a1ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 data_len = 3; + u8 buf[5] = {0}; + + buf[0] = data_len; + buf[1] = 0x1; /* OP_Code */ + buf[2] = 0x1; /* OP_Code_Length */ + if (enable) + buf[3] = 0x1; /* OP_Code_Content */ + else + buf[3] = 0x0; + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_CTRL_BT_COEX, + (void *)&buf[0]); +} + +void halbtc8812a1ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8812a1ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8812a1ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8812a1ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8812a1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8812a1ant_sw_mechanism(IN struct btc_coexist *btcoexist, + IN boolean low_penalty_ra) +{ + halbtc8812a1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +/* to check force_exec */ +void halbtc8812a1ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean force_exec, IN boolean init_hwcfg, + IN boolean wifi_off) +{ + u8 u8tmp = 0; + + coex_dm->cur_ant_pos_type = ant_pos_type; + + if (init_hwcfg) { + btcoexist->btc_write_1byte(btcoexist, 0xcb3, 0x77); + btcoexist->btc_write_4byte(btcoexist, 0x900, 0x00000400); + btcoexist->btc_write_1byte(btcoexist, 0x76d, 0x1); + } else if (wifi_off) { + btcoexist->btc_write_1byte(btcoexist, 0xcb3, 0x77); + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0xcb7); + u8tmp &= ~BIT(3); + u8tmp |= BIT(2); + btcoexist->btc_write_1byte(btcoexist, 0xcb7, u8tmp); + } + + if (force_exec || + (coex_dm->cur_ant_pos_type != coex_dm->pre_ant_pos_type)) { + /* ext switch setting */ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + u8tmp = btcoexist->btc_read_1byte(btcoexist, + 0xcb7); + u8tmp |= BIT(3); + u8tmp &= ~BIT(2); + btcoexist->btc_write_1byte(btcoexist, 0xcb7, + u8tmp); + break; + case BTC_ANT_PATH_BT: + u8tmp = btcoexist->btc_read_1byte(btcoexist, + 0xcb7); + u8tmp &= ~BIT(3); + u8tmp |= BIT(2); + btcoexist->btc_write_1byte(btcoexist, 0xcb7, + u8tmp); + break; + default: + case BTC_ANT_PATH_PTA: + u8tmp = btcoexist->btc_read_1byte(btcoexist, + 0xcb7); + u8tmp |= BIT(3); + u8tmp &= ~BIT(2); + btcoexist->btc_write_1byte(btcoexist, 0xcb7, + u8tmp); + break; + } + } + + coex_dm->pre_ant_pos_type = coex_dm->cur_ant_pos_type; +} + +void halbtc8812a1ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], FW for 1Ant AP mode\n"); + BTC_TRACE(trace_buf); + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + } + } + + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + + +void halbtc8812a1ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_busy = false; + u8 rssi_adjust_val = 0; + u8 ps_tdma_byte4_val = 0x50, ps_tdma_byte0_val = 0x51, + ps_tdma_byte3_val = 0x10; + s8 wifi_duration_adjust = 0x0; + static boolean pre_wifi_busy = false; + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (wifi_busy != pre_wifi_busy) { + force_exec = true; + pre_wifi_busy = wifi_busy; + } + + if (coex_dm->cur_ps_tdma_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(off, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + + if (coex_sta->scan_ap_num <= 5) + wifi_duration_adjust = 2; + else if (coex_sta->scan_ap_num >= 40) + wifi_duration_adjust = -15; + else if (coex_sta->scan_ap_num >= 20) + wifi_duration_adjust = -10; + + if (!coex_sta->force_lps_on) { /* only for A2DP-only case 1/2/9/11 while wifi noisy threshold > 30 */ + ps_tdma_byte0_val = 0x61; /* no null-pkt */ + ps_tdma_byte3_val = 0x11; /* no tx-pause at BT-slot */ + ps_tdma_byte4_val = 0x10; /* 0x778 = d/1 toggle */ + } + + if ((type == 3) || (type == 13) || (type == 14)) { + ps_tdma_byte4_val = ps_tdma_byte4_val & + 0xbf; /* no dynamic slot for multi-profile */ + + if (!wifi_busy) + ps_tdma_byte4_val = ps_tdma_byte4_val | + 0x1; /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + } + + if (bt_link_info->slave_role == true) + ps_tdma_byte4_val = ps_tdma_byte4_val | + 0x1; /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + + if (turn_on) { + switch (type) { + default: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x1a, 0x1a, 0x0, ps_tdma_byte4_val); + break; + case 1: + halbtc8812a1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x3a + + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 2: + halbtc8812a1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x2d + + wifi_duration_adjust, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 3: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x1d, 0x1d, 0x0, ps_tdma_byte4_val); + break; + case 4: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x93, + 0x15, 0x3, 0x14, 0x0); + break; + case 5: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x61, + 0x15, 0x3, 0x11, 0x11); + break; + case 6: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x61, + 0x20, 0x3, 0x11, 0x11); + break; + case 7: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x13, + 0xc, 0x5, 0x0, 0x0); + break; + case 8: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x93, + 0x25, 0x3, 0x10, 0x0); + break; + case 9: + halbtc8812a1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x21, 0x3, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 10: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x13, + 0xa, 0xa, 0x0, 0x40); + break; + case 11: + halbtc8812a1ant_set_fw_pstdma(btcoexist, + ps_tdma_byte0_val, 0x21, 0x03, + ps_tdma_byte3_val, ps_tdma_byte4_val); + break; + case 12: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x0a, 0x0a, 0x0, 0x50); + break; + case 13: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x12, 0x12, 0x0, ps_tdma_byte4_val); + break; + case 14: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x21, 0x3, 0x10, ps_tdma_byte4_val); + break; + case 15: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x13, + 0xa, 0x3, 0x8, 0x0); + break; + case 16: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x93, + 0x15, 0x3, 0x10, 0x0); + break; + case 18: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x93, + 0x25, 0x3, 0x10, 0x0); + break; + case 20: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x61, + 0x3f, 0x03, 0x11, 0x10); + break; + case 21: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x61, + 0x25, 0x03, 0x11, 0x11); + break; + case 22: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x61, + 0x25, 0x03, 0x11, 0x10); + break; + case 23: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x3, 0x31, 0x18); + break; + case 24: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0xe3, + 0x15, 0x3, 0x31, 0x18); + break; + case 25: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0xe3, + 0xa, 0x3, 0x31, 0x18); + break; + case 26: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0xe3, + 0xa, 0x3, 0x31, 0x18); + break; + case 27: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x3, 0x31, 0x98); + break; + case 28: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x69, + 0x25, 0x3, 0x31, 0x0); + break; + case 29: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0xab, + 0x1a, 0x1a, 0x1, 0x10); + break; + case 30: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x30, 0x3, 0x10, 0x10); + break; + case 31: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0xd3, + 0x1a, 0x1a, 0, 0x58); + break; + case 32: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x61, + 0x35, 0x3, 0x11, 0x11); + break; + case 33: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0xa3, + 0x25, 0x3, 0x30, 0x90); + break; + case 34: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x53, + 0x1a, 0x1a, 0x0, 0x10); + break; + case 35: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x63, + 0x1a, 0x1a, 0x0, 0x10); + break; + case 36: + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0xd3, + 0x12, 0x3, 0x14, 0x50); + break; + case 40: /* SoftAP only with no sta associated,BT disable ,TDMA mode for power saving */ + /* here softap mode screen off will cost 70-80mA for phone */ + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x23, + 0x18, 0x00, 0x10, 0x24); + break; + } + } else { + + /* disable PS tdma */ + switch (type) { + case 8: /* PTA Control */ + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x8, + 0x0, 0x0, 0x0, 0x0); + break; + case 0: + default: /* Software control, Antenna at BT side */ + halbtc8812a1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x0, 0x0); + break; + } + } + rssi_adjust_val = 0; + btcoexist->btc_set(btcoexist, + BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssi_adjust_val); + + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +boolean halbtc8812a1ant_is_common_action(IN struct btc_coexist *btcoexist) +{ + boolean common = false, wifi_connected = false, wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected && + BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + + /* halbtc8812a1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (wifi_connected && + (BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + + /* halbtc8812a1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (!wifi_connected && + (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + + /* halbtc8812a1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (wifi_connected && + (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + + /* halbtc8812a1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (!wifi_connected && + (BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE != coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + + /* halbtc8812a1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else { + if (wifi_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } + + common = false; + } + + return common; +} + + +void halbtc8812a1ant_tdma_duration_adjust_for_acl(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + static s32 up, dn, m, n, wait_count; + s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */ + u8 retry_count = 0, bt_info_ext; + boolean wifi_busy = false; + + if (BT_8812A_1ANT_WIFI_STATUS_CONNECTED_BUSY == wifi_status) + wifi_busy = true; + else + wifi_busy = false; + + if ((BT_8812A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == + wifi_status) || + (BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SCAN == wifi_status) || + (BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SPECIFIC_PKT == + wifi_status)) { + if (coex_dm->cur_ps_tdma != 1 && + coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 3 && + coex_dm->cur_ps_tdma != 9) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 9); + coex_dm->ps_tdma_du_adj_type = 9; + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } + return; + } + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + /* ============ */ + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /* acquire the BT TRx retry count from BT_Info byte2 */ + retry_count = coex_sta->bt_retry_cnt; + bt_info_ext = coex_sta->bt_info_ext; + + if ((coex_sta->low_priority_tx) > 1150 || + (coex_sta->low_priority_rx) > 1250) + retry_count++; + + result = 0; + wait_count++; + + if (retry_count == + 0) { /* no retry in the last 2-second duration */ + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { /* if retry count during continuous n*2 seconds is 0, enlarge WiFi duration */ + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + } + } else if (retry_count <= + 3) { /* <=3 retry in the last 2-second duration */ + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { /* if continuous 2 retry count(every 2 seconds) >0 and < 3, reduce WiFi duration */ + if (wait_count <= 2) + m++; /* to avoid loop between the two levels */ + else + m = 1; + + if (m >= 20) /* maximum of m = 20 ' will recheck if need to adjust wifi duration in maximum time interval 120 seconds */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + } else { /* retry count > 3, once retry count > 3, to reduce WiFi duration */ + if (wait_count == 1) + m++; /* to avoid loop between the two levels */ + else + m = 1; + + if (m >= 20) /* maximum of m = 20 ' will recheck if need to adjust wifi duration in maximum time interval 120 seconds */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + + if (result == -1) { + if ((BT_INFO_8812A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) || + (coex_dm->cur_ps_tdma == 2))) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } + } else if (result == 1) { + if ((BT_INFO_8812A_1ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 1) || + (coex_dm->cur_ps_tdma == 2))) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = 1; + } + } else { /* no change */ + /* Bryant Modify + if(wifi_busy != pre_wifi_busy) + { + pre_wifi_busy = wifi_busy; + halbtc8812a1ant_ps_tdma(btcoexist, FORCE_EXEC, true, coex_dm->cur_ps_tdma); + } + */ + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } + + if (coex_dm->cur_ps_tdma != 1 && + coex_dm->cur_ps_tdma != 2 && + coex_dm->cur_ps_tdma != 9 && + coex_dm->cur_ps_tdma != 11) { + /* recover to previous adjust type */ + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->ps_tdma_du_adj_type); + } + } +} + +void halbtc8812a1ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +void halbtc8812a1ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + case BTC_PS_LPS_ON: + halbtc8812a1ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8812a1ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + coex_sta->force_lps_on = true; + break; + case BTC_PS_LPS_OFF: + halbtc8812a1ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + default: + break; + } +} + +void halbtc8812a1ant_action_wifi_only(IN struct btc_coexist *btcoexist) +{ + halbtc8812a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + halbtc8812a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, FORCE_EXEC, + false, false); +} + +void halbtc8812a1ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false; + + /* This function check if bt is disabled */ + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is enabled !!\n"); + BTC_TRACE(trace_buf); + } else { + bt_disable_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], bt all counters=0, %d times!!\n", + bt_disable_cnt); + BTC_TRACE(trace_buf); + if (bt_disable_cnt >= 2) { + bt_disabled = true; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!\n"); + BTC_TRACE(trace_buf); + halbtc8812a1ant_action_wifi_only(btcoexist); + } + } + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + coex_sta->bt_disabled = bt_disabled; + if (!bt_disabled) { + } else { + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + } + } +} + +/* ********************************************* + * + * Software Coex Mechanism start + * + * ********************************************* */ + +/* SCO only or SCO+PAN(HS) */ + +/* +void halbtc8812a1ant_action_sco(IN struct btc_coexist* btcoexist) +{ + halbtc8812a1ant_sw_mechanism(btcoexist, true); +} + + +void halbtc8812a1ant_action_hid(IN struct btc_coexist* btcoexist) +{ + halbtc8812a1ant_sw_mechanism(btcoexist, true); +} + + +void halbtc8812a1ant_action_a2dp(IN struct btc_coexist* btcoexist) +{ + halbtc8812a1ant_sw_mechanism(btcoexist, false); +} + +void halbtc8812a1ant_action_a2dp_pan_hs(IN struct btc_coexist* btcoexist) +{ + halbtc8812a1ant_sw_mechanism(btcoexist, false); +} + +void halbtc8812a1ant_action_pan_edr(IN struct btc_coexist* btcoexist) +{ + halbtc8812a1ant_sw_mechanism(btcoexist, false); +} + + +void halbtc8812a1ant_action_pan_hs(IN struct btc_coexist* btcoexist) +{ + halbtc8812a1ant_sw_mechanism(btcoexist, false); +} + + +void halbtc8812a1ant_action_pan_edr_a2dp(IN struct btc_coexist* btcoexist) +{ + halbtc8812a1ant_sw_mechanism(btcoexist, false); +} + +void halbtc8812a1ant_action_pan_edr_hid(IN struct btc_coexist* btcoexist) +{ + halbtc8812a1ant_sw_mechanism(btcoexist, true); +} + + +void halbtc8812a1ant_action_hid_a2dp_pan_edr(IN struct btc_coexist* btcoexist) +{ + halbtc8812a1ant_sw_mechanism(btcoexist, true); +} + +void halbtc8812a1ant_action_hid_a2dp(IN struct btc_coexist* btcoexist) +{ + halbtc8812a1ant_sw_mechanism(btcoexist, true); +} + +*/ + +/* ********************************************* + * + * Non-Software Coex Mechanism start + * + * ********************************************* */ +void halbtc8812a1ant_action_wifi_multi_port(IN struct btc_coexist *btcoexist) +{ + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, NORMAL_EXEC, + false, false); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8812a1ant_action_hs(IN struct btc_coexist *btcoexist) +{ + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8812a1ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, ap_enable = false, wifi_busy = false, + bt_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + if ((!wifi_connected) && (!coex_sta->wifi_is_high_pri_task)) { + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + /* SCO/HID/A2DP busy */ + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if ((bt_link_info->pan_exist) || (wifi_busy)) { + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + } +} + +void halbtc8812a1ant_action_bt_sco_hid_only_busy(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* tdma and coex table */ + + if (bt_link_info->sco_exist) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } else { /* HID */ + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } +} + +void halbtc8812a1ant_action_wifi_connected_bt_acl_busy(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + u8 bt_rssi_state; + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + bt_rssi_state = halbtc8812a1ant_bt_rssi_state(2, 28, 0); + + if ((coex_sta->low_priority_rx >= 950) && (!coex_sta->under_ips)) + bt_link_info->slave_role = true; + else + bt_link_info->slave_role = false; + + if (bt_link_info->hid_only) { /* HID */ + halbtc8812a1ant_action_bt_sco_hid_only_busy(btcoexist, + wifi_status); + coex_dm->auto_tdma_adjust = false; + return; + } else if (bt_link_info->a2dp_only) { /* A2DP */ + if (BT_8812A_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8812a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } else { + halbtc8812a1ant_tdma_duration_adjust_for_acl(btcoexist, + wifi_status); + halbtc8812a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = true; + } + } else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { /* A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP) */ + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } else if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { /* HID+A2DP */ + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + coex_dm->auto_tdma_adjust = false; + + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + } else if ((bt_link_info->pan_only) || (bt_link_info->hid_exist && + bt_link_info->pan_exist)) { /* PAN(OPP,FTP), HID+PAN(OPP,FTP) */ + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } else { + /* BT no-profile busy (0x9) */ + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + coex_dm->auto_tdma_adjust = false; + } +} + +void halbtc8812a1ant_action_wifi_not_connected(IN struct btc_coexist *btcoexist) +{ + /* power save state */ + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + halbtc8812a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, NORMAL_EXEC, + false, false); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8812a1ant_action_wifi_not_connected_scan(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + if (BT_8812A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8812a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8812a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8812a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((BT_8812A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8812a1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + /* Bryant Add */ + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8812a1ant_action_wifi_not_connected_asso_auth( + IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8812a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else if (bt_link_info->pan_exist) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8812a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8812a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 2); + } +} + +void halbtc8812a1ant_action_wifi_connected_scan(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + if (BT_8812A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8812a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8812a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8812a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((BT_8812A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8812a1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + /* Bryant Add */ + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8812a1ant_action_wifi_connected_specific_packet( + IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (bt_link_info->pan_exist) { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + NORMAL_EXEC, false, false); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8812a1ant_action_wifi_connected(IN struct btc_coexist *btcoexist) +{ + boolean wifi_busy = false; + boolean scan = false, link = false, roam = false; + boolean under_4way = false, ap_enable = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect()===>\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (under_4way) { + halbtc8812a1ant_action_wifi_connected_specific_packet(btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + if (scan || link || roam) { + if (scan) + halbtc8812a1ant_action_wifi_connected_scan(btcoexist); + else + halbtc8812a1ant_action_wifi_connected_specific_packet( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + /* power save state */ + if (!ap_enable && + BT_8812A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status && + !btcoexist->bt_link_info.hid_only) { + if (btcoexist->bt_link_info.a2dp_only) { /* A2DP */ + if (!wifi_busy) + halbtc8812a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + else { /* busy */ + if (coex_sta->scan_ap_num >= + BT_8812A_1ANT_WIFI_NOISY_THRESH) /* no force LPS, no PS-TDMA, use pure TDMA */ + halbtc8812a1ant_power_save_state( + btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8812a1ant_power_save_state( + btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + } else if ((coex_sta->pan_exist == false) && + (coex_sta->a2dp_exist == false) && + (coex_sta->hid_exist == false)) + halbtc8812a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + else + halbtc8812a1ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + } else + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + /* tdma and coex table */ + if (!wifi_busy) { + if (BT_8812A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8812a1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else if ((BT_8812A_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8812a1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + halbtc8812a1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, NORMAL_EXEC, false, false); + if ((coex_sta->high_priority_tx) + + (coex_sta->high_priority_rx) <= 60) + halbtc8812a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + else + halbtc8812a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } + } else { + if (BT_8812A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8812a1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else if ((BT_8812A_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8812a1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else { + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + halbtc8812a1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, NORMAL_EXEC, false, false); + if ((coex_sta->high_priority_tx) + + (coex_sta->high_priority_rx) <= 60) + halbtc8812a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + else + halbtc8812a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } + } +} + +void halbtc8812a1ant_run_sw_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + algorithm = halbtc8812a1ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + + if (halbtc8812a1ant_is_common_action(btcoexist)) { + + } else { + switch (coex_dm->cur_algorithm) { + case BT_8812A_1ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + /* halbtc8812a1ant_action_sco(btcoexist); */ + break; + case BT_8812A_1ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID.\n"); + BTC_TRACE(trace_buf); + /* halbtc8812a1ant_action_hid(btcoexist); */ + break; + case BT_8812A_1ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + /* halbtc8812a1ant_action_a2dp(btcoexist); */ + break; + case BT_8812A_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + /* halbtc8812a1ant_action_a2dp_pan_hs(btcoexist); */ + break; + case BT_8812A_1ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + /* halbtc8812a1ant_action_pan_edr(btcoexist); */ + break; + case BT_8812A_1ANT_COEX_ALGO_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HS mode.\n"); + BTC_TRACE(trace_buf); + /* halbtc8812a1ant_action_pan_hs(btcoexist); */ + break; + case BT_8812A_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + /* halbtc8812a1ant_action_pan_edr_a2dp(btcoexist); */ + break; + case BT_8812A_1ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + /* halbtc8812a1ant_action_pan_edr_hid(btcoexist); */ + break; + case BT_8812A_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + /* halbtc8812a1ant_action_hid_a2dp_pan_edr(btcoexist); */ + break; + case BT_8812A_1ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + /* halbtc8812a1ant_action_hid_a2dp(btcoexist); */ + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = coexist All Off!!\n"); + BTC_TRACE(trace_buf); + /* halbtc8812a1ant_coex_all_off(btcoexist); */ + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +void halbtc8812a1ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + boolean increase_scan_dev_num = false; + boolean bt_ctrl_agg_buf_size = false; + boolean miracast_plus_bt = false; + u8 agg_buf_size = 5; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0, wifi_bw; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if ((BT_8812A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + increase_scan_dev_num = true; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, + &increase_scan_dev_num); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + BTC_TRACE(trace_buf); + + if (bt_link_info->bt_link_exist) { + halbtc8812a1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, + 0, 1); + miracast_plus_bt = true; + } else { + halbtc8812a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, + 0, 0); + miracast_plus_bt = false; + } + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + halbtc8812a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if ((bt_link_info->a2dp_exist) && + (coex_sta->c2h_bt_inquiry_page)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8812a1ant_action_bt_inquiry(btcoexist); + } else + halbtc8812a1ant_action_wifi_multi_port(btcoexist); + + return; + } + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if ((bt_link_info->bt_link_exist) && (wifi_connected)) { + halbtc8812a1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, 0, 1); + + if (bt_link_info->sco_exist) + halbtc8812a1ant_limited_rx(btcoexist, NORMAL_EXEC, true, + false, 0x5); + else { + if (BTC_WIFI_BW_HT40 == wifi_bw) + halbtc8812a1ant_limited_rx(btcoexist, NORMAL_EXEC, + false, true, 0x10); + else + halbtc8812a1ant_limited_rx(btcoexist, NORMAL_EXEC, + false, true, 0x8); + } + + halbtc8812a1ant_sw_mechanism(btcoexist, true); + halbtc8812a1ant_run_sw_coexist_mechanism( + btcoexist); /* just print debug message */ + } else { + halbtc8812a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + halbtc8812a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x5); + + halbtc8812a1ant_sw_mechanism(btcoexist, false); + halbtc8812a1ant_run_sw_coexist_mechanism( + btcoexist); /* //just print debug message */ + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8812a1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8812a1ant_action_hs(btcoexist); + return; + } + + + if (!wifi_connected) { + boolean scan = false, link = false, roam = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is non connected-idle !!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + if (scan) + halbtc8812a1ant_action_wifi_not_connected_scan( + btcoexist); + else + halbtc8812a1ant_action_wifi_not_connected_asso_auth( + btcoexist); + } else + halbtc8812a1ant_action_wifi_not_connected(btcoexist); + } else /* wifi LPS/Busy */ + halbtc8812a1ant_action_wifi_connected(btcoexist); +} + +void halbtc8812a1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + + /* sw all off */ + halbtc8812a1ant_sw_mechanism(btcoexist, false); + + /* halbtc8812a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); */ + /* halbtc8812a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); */ + + coex_sta->pop_event_cnt = 0; +} + +void halbtc8812a1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean back_up, IN boolean wifi_only) +{ + u8 u8tmp = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 1Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + + /* ant sw control to BT */ + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, FORCE_EXEC, + true, false); + + /* 0x790[5:0]=0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + /* PTA parameter */ + btcoexist->btc_write_1byte(btcoexist, 0x6cc, 0x0); + btcoexist->btc_write_4byte(btcoexist, 0x6c8, 0xffff); + btcoexist->btc_write_4byte(btcoexist, 0x6c4, 0x55555555); + btcoexist->btc_write_4byte(btcoexist, 0x6c0, 0x55555555); + + /* coex parameters */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + + /* enable counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* enable PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x40, 0x20); + + /* bt clock related */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x4); + u8tmp |= BIT(7); + btcoexist->btc_write_1byte(btcoexist, 0x4, u8tmp); + + /* bt clock related */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x7); + u8tmp |= BIT(1); + btcoexist->btc_write_1byte(btcoexist, 0x7, u8tmp); +} + +/* ************************************************************ + * work around function start with wa_halbtc8812a1ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8812a1ant_ + * ************************************************************ */ +void ex_halbtc8812a1ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ +} + +void ex_halbtc8812a1ant_pre_load_firmware(IN struct btc_coexist *btcoexist) +{ +} + +void ex_halbtc8812a1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8812a1ant_init_hw_config(btcoexist, true, wifi_only); + btcoexist->stop_coex_dm = false; +} + +void ex_halbtc8812a1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = false; + + halbtc8812a1ant_init_coex_dm(btcoexist); + + halbtc8812a1ant_query_bt_info(btcoexist); +} + +void ex_halbtc8812a1ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u32 u32tmp[4]; + u32 fw_ver = 0, bt_patch_ver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + if (btcoexist->stop_coex_dm) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "Ant PG number/ Ant mechanism:", + board_info->pg_ant_num, board_info->btdm_ant_num); + CL_PRINTF(cli_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%d/ 0x%x/ 0x%x(%d)", + "CoexVer/ FwVer/ PatchVer", + glcoex_ver_date_8812a_1ant, glcoex_ver_8812a_1ant, fw_ver, + bt_patch_ver, bt_patch_ver); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "Wifi channel informed to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", + "BT [status/ rssi/ retryCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") + : ((BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi, coex_sta->bt_retry_cnt); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + "SCO/HID/PAN/A2DP", + bt_link_info->sco_exist, bt_link_info->hid_exist, + bt_link_info->pan_exist, bt_link_info->a2dp_exist); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext & BIT(0)) ? "Basic rate" : "EDR rate"); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8812A_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8812a_1ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + if (!btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanisms]============"); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d", + "PS TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", + "Latest error condition(should be 0)", + coex_dm->error_condition); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", + "IgnWlanAct", + coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + } + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x778", + u8tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xcb3); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xcb7); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x900); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0xcb3/0xcb7/0x900", + u8tmp[0], u8tmp[1], u32tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x40", + u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", + u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", + u32tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(hp rx[31:16]/tx[15:0])", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(lp rx[31:16]/tx[15:0])", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + + +void ex_halbtc8812a1ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, false, true); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + + halbtc8812a1ant_init_hw_config(btcoexist, false, false); + halbtc8812a1ant_init_coex_dm(btcoexist); + halbtc8812a1ant_query_bt_info(btcoexist); + + coex_sta->under_ips = false; + } +} + +void ex_halbtc8812a1ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8812a1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if (BTC_SCAN_START == type) { + coex_sta->wifi_is_high_pri_task = true; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + + halbtc8812a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 8); /* Force antenna setup for no scan result issue */ + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + } + + if (coex_sta->bt_disabled) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + halbtc8812a1ant_query_bt_info(btcoexist); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + halbtc8812a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8812a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8812a1ant_action_wifi_multi_port(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8812a1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8812a1ant_action_hs(btcoexist); + return; + } + + if (BTC_SCAN_START == type) { + if (!wifi_connected) /* non-connected scan */ + halbtc8812a1ant_action_wifi_not_connected_scan( + btcoexist); + else /* wifi is connected */ + halbtc8812a1ant_action_wifi_connected_scan(btcoexist); + } else if (BTC_SCAN_FINISH == type) { + if (!wifi_connected) /* non-connected scan */ + halbtc8812a1ant_action_wifi_not_connected(btcoexist); + else + halbtc8812a1ant_action_wifi_connected(btcoexist); + } +} + +void ex_halbtc8812a1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + coex_sta->bt_disabled) + return; + + if (BTC_ASSOCIATE_START == type) { + coex_sta->wifi_is_high_pri_task = true; + halbtc8812a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 8); /* Force antenna setup for no scan result issue */ + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify\n"); + BTC_TRACE(trace_buf); + coex_dm->arp_cnt = 0; + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify\n"); + BTC_TRACE(trace_buf); + /* coex_dm->arp_cnt = 0; */ + } + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + halbtc8812a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8812a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8812a1ant_action_wifi_multi_port(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8812a1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8812a1ant_action_hs(btcoexist); + return; + } + + if (BTC_ASSOCIATE_START == type) + halbtc8812a1ant_action_wifi_not_connected_asso_auth(btcoexist); + else if (BTC_ASSOCIATE_FINISH == type) { + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (!wifi_connected) /* non-connected scan */ + halbtc8812a1ant_action_wifi_not_connected(btcoexist); + else + halbtc8812a1ant_action_wifi_connected(btcoexist); + } +} + +/* to check registers... */ +void ex_halbtc8812a1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 data_len = 5; + u8 buf[6] = {0}; + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + boolean wifi_under_b_mode = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + coex_sta->bt_disabled) + return; + + if (BTC_MEDIA_CONNECT == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + halbtc8812a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 8); /* Force antenna setup for no scan result issue */ + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, + FORCE_EXEC, false, false); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); +#if 0 + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x10); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } +#endif + coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, + 0x430); + coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, + 0x434); + coex_dm->backup_retry_limit = btcoexist->btc_read_2byte( + btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = btcoexist->btc_read_1byte( + btcoexist, 0x456); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + coex_dm->arp_cnt = 0; + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + } + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + /* h2c_parameter[0] = 0x1; */ + h2c_parameter[0] = 0x0; + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + buf[0] = data_len; + buf[1] = 0x5; /* OP_Code */ + buf[2] = 0x3; /* OP_Code_Length */ + buf[3] = h2c_parameter[0]; /* OP_Code_Content */ + buf[4] = h2c_parameter[1]; + buf[5] = h2c_parameter[2]; + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_CTRL_BT_COEX, + (void *)&buf[0]); +} + +void ex_halbtc8812a1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + coex_sta->bt_disabled) + return; + + if (BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type || + BTC_PACKET_ARP == type) { + if (BTC_PACKET_ARP == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ARP notify\n"); + BTC_TRACE(trace_buf); + + coex_dm->arp_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ARP Packet Count = %d\n", + coex_dm->arp_cnt); + BTC_TRACE(trace_buf); + + if (coex_dm->arp_cnt >= + 10) /* if APR PKT > 10 after connect, do not go to ActionWifiConnectedSpecificPacket(btcoexist) */ + coex_sta->wifi_is_high_pri_task = false; + else + coex_sta->wifi_is_high_pri_task = true; + } else { + coex_sta->wifi_is_high_pri_task = true; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet DHCP or EAPOL notify\n"); + BTC_TRACE(trace_buf); + } + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet [Type = %d] notify\n", type); + BTC_TRACE(trace_buf); + } + + coex_sta->specific_pkt_period_cnt = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + halbtc8812a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8812a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8812a1ant_action_wifi_multi_port(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8812a1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8812a1ant_action_hs(btcoexist); + return; + } + + if (BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type || + ((BTC_PACKET_ARP == type) && (coex_sta->wifi_is_high_pri_task))) + halbtc8812a1ant_action_wifi_connected_specific_packet(btcoexist); +} + +void ex_halbtc8812a1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + boolean wifi_connected = false; + boolean bt_busy = false; + + coex_sta->c2h_bt_info_req_sent = false; + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8812A_1ANT_MAX) + rsp_source = BT_INFO_SRC_8812A_1ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt info[%d], length=%d, hex data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + if (BT_INFO_SRC_8812A_1ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0] */ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->bt_info_c2h[rsp_source][2] & 0x20) + coex_sta->c2h_bt_page = true; + else + coex_sta->c2h_bt_page = false; + + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3] * 2 - 90; + /* coex_sta->bt_info_c2h[rsp_source][3]*2+10; */ + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rsp_source][4]; + + coex_sta->bt_tx_rx_mask = (coex_sta->bt_info_c2h[rsp_source][2] + & 0x40); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TX_RX_MASK, + &coex_sta->bt_tx_rx_mask); + if (!coex_sta->bt_tx_rx_mask) { + /* BT into is responded by BT FW and BT RF REG 0x3C != 0x15 => Need to switch BT TRx Mask */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x15\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x3c, 0x15); + } + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + if (coex_sta->bt_info_ext & BIT(1)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) + ex_halbtc8812a1ant_media_status_notify( + btcoexist, BTC_MEDIA_CONNECT); + else + ex_halbtc8812a1ant_media_status_notify( + btcoexist, BTC_MEDIA_DISCONNECT); + } + + if (coex_sta->bt_info_ext & BIT(3)) { + if (!btcoexist->manual_control && + !btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8812a1ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, false); + } + } else { + /* BT already NOT ignore Wlan active, do nothing here. */ + } +#if (BT_AUTO_REPORT_ONLY_8812A_1ANT == 0) + if ((coex_sta->bt_info_ext & BIT(4))) { + /* BT auto report already enabled, do nothing */ + } else + halbtc8812a1ant_bt_auto_report(btcoexist, FORCE_EXEC, + true); +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (bt_info & BT_INFO_8812A_1ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status */ + if (!(bt_info & BT_INFO_8812A_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8812A_1ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8812A_1ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8812A_1ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8812A_1ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + } + + halbtc8812a1ant_update_bt_link_info(btcoexist); + + bt_info = bt_info & + 0x1f; /* mask profile bit for connect-ilde identification ( for CSR case: A2DP idle --> 0x41) */ + + if (!(bt_info & BT_INFO_8812A_1ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info == + BT_INFO_8812A_1ANT_B_CONNECTION) { /* connection exists but no busy */ + coex_dm->bt_status = BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + BTC_TRACE(trace_buf); + } else if ((bt_info & BT_INFO_8812A_1ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8812A_1ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8812A_1ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info & BT_INFO_8812A_1ANT_B_ACL_BUSY) { + if (BT_8812A_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status) + coex_dm->auto_tdma_adjust = false; + coex_dm->bt_status = BT_8812A_1ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + BTC_TRACE(trace_buf); + } else { + coex_dm->bt_status = BT_8812A_1ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + BTC_TRACE(trace_buf); + } + + if ((BT_8812A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + halbtc8812a1ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8812a1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], RF Status notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_RF_ON == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned ON!!\n"); + BTC_TRACE(trace_buf); + btcoexist->stop_coex_dm = false; + } else if (BTC_RF_OFF == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned OFF!!\n"); + BTC_TRACE(trace_buf); + + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8812a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, false, true); + + halbtc8812a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + btcoexist->stop_coex_dm = true; + } +} + +void ex_halbtc8812a1ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + halbtc8812a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, FORCE_EXEC, + false, true); + + halbtc8812a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + ex_halbtc8812a1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + btcoexist->stop_coex_dm = true; +} + +void ex_halbtc8812a1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Pnp notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_WIFI_PNP_SLEEP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + + halbtc8812a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8812a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, false, true); + halbtc8812a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + + /* Sinda 20150819, workaround for driver skip leave IPS/LPS to speed up sleep time. */ + /* Driver do not leave IPS/LPS when driver is going to sleep, so BTCoexistence think wifi is still under IPS/LPS */ + /* BT should clear UnderIPS/UnderLPS state to avoid mismatch state after wakeup. */ + coex_sta->under_ips = false; + coex_sta->under_lps = false; + btcoexist->stop_coex_dm = true; + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + btcoexist->stop_coex_dm = false; + halbtc8812a1ant_init_hw_config(btcoexist, false, false); + halbtc8812a1ant_init_coex_dm(btcoexist); + halbtc8812a1ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8812a1ant_coex_dm_reset(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], *****************Coex DM Reset*****************\n"); + BTC_TRACE(trace_buf); + + halbtc8812a1ant_init_hw_config(btcoexist, false, false); + halbtc8812a1ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8812a1ant_periodical(IN struct btc_coexist *btcoexist) +{ +#if (BT_AUTO_REPORT_ONLY_8812A_1ANT == 0) + halbtc8812a1ant_query_bt_info(btcoexist); + halbtc8812a1ant_monitor_bt_enable_disable(btcoexist); +#else + halbtc8812a1ant_monitor_bt_ctr(btcoexist); + halbtc8812a1ant_monitor_wifi_ctr(btcoexist); + + if (halbtc8812a1ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + halbtc8812a1ant_run_coexist_mechanism(btcoexist); + + coex_sta->specific_pkt_period_cnt++; +#endif +} + +void ex_halbtc8812a1ant_dbg_control(IN struct btc_coexist *btcoexist, + IN u8 op_code, IN u8 op_len, IN u8 *pdata) +{ + switch (op_code) { + case BTC_DBG_SET_COEX_NORMAL: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set CoexMode to Normal\n"); + BTC_TRACE(trace_buf); + btcoexist->manual_control = false; + halbtc8812a1ant_init_coex_dm(btcoexist); + break; + case BTC_DBG_SET_COEX_WIFI_ONLY: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set CoexMode to Wifi Only\n"); + BTC_TRACE(trace_buf); + btcoexist->manual_control = true; + halbtc8812a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 9); + break; + case BTC_DBG_SET_COEX_BT_ONLY: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set CoexMode to BT only\n"); + BTC_TRACE(trace_buf); + btcoexist->manual_control = true; + halbtc8812a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + break; + case BTC_DBG_SET_COEX_DEC_BT_PWR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set Dec BT power\n"); + BTC_TRACE(trace_buf); + { + u8 data_len = 4; + u8 buf[6] = {0}; + u8 dec_bt_pwr = 0, pwr_level = 0; + + if (op_len == 2) { + dec_bt_pwr = pdata[0]; + pwr_level = pdata[1]; + + buf[0] = data_len; + buf[1] = 0x3; /* OP_Code */ + buf[2] = 0x2; /* OP_Code_Length */ + + buf[3] = dec_bt_pwr; /* OP_Code_Content */ + buf[4] = pwr_level; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set Dec BT power=%d, pwr_level=%d\n", + dec_bt_pwr, pwr_level); + BTC_TRACE(trace_buf); + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_CTRL_BT_COEX, + (void *)&buf[0]); + } + } + break; + + case BTC_DBG_SET_COEX_BT_AFH_MAP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set BT AFH Map\n"); + BTC_TRACE(trace_buf); + { + u8 data_len = 5; + u8 buf[6] = {0}; + + if (op_len == 3) { + buf[0] = data_len; + buf[1] = 0x5; /* OP_Code */ + buf[2] = 0x3; /* OP_Code_Length */ + + buf[3] = pdata[0]; /* OP_Code_Content */ + buf[4] = pdata[1]; + buf[5] = pdata[2]; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set BT AFH Map = %02x %02x %02x\n", + pdata[0], pdata[1], pdata[2]); + BTC_TRACE(trace_buf); + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_CTRL_BT_COEX, + (void *)&buf[0]); + } + } + break; + + case BTC_DBG_SET_COEX_BT_IGNORE_WLAN_ACT: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set BT Ignore Wlan Active\n"); + BTC_TRACE(trace_buf); + { + u8 data_len = 3; + u8 buf[6] = {0}; + + if (op_len == 1) { + buf[0] = data_len; + buf[1] = 0x1; /* OP_Code */ + buf[2] = 0x1; /* OP_Code_Length */ + + buf[3] = pdata[0]; /* OP_Code_Content */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set BT Ignore Wlan Active = 0x%x\n", + pdata[0]); + BTC_TRACE(trace_buf); + + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_CTRL_BT_COEX, + (void *)&buf[0]); + } + } + break; + default: + break; + } +} + +#endif + +#endif /* #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a1ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a1ant.h new file mode 100644 index 0000000..e786d37 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a1ant.h @@ -0,0 +1,230 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8812A_SUPPORT == 1) + +/* ******************************************* + * The following is for 8812A 1ANT BT Co-exist definition + * ******************************************* */ +#define BT_AUTO_REPORT_ONLY_8812A_1ANT 1 + +#define BT_INFO_8812A_1ANT_B_FTP BIT(7) +#define BT_INFO_8812A_1ANT_B_A2DP BIT(6) +#define BT_INFO_8812A_1ANT_B_HID BIT(5) +#define BT_INFO_8812A_1ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8812A_1ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8812A_1ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8812A_1ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8812A_1ANT_B_CONNECTION BIT(0) + +#define BT_INFO_8812A_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT(0))) ? true : false) + +#define BTC_RSSI_COEX_THRESH_TOL_8812A_1ANT 2 + +#define BT_8812A_1ANT_WIFI_NOISY_THRESH 30 /* max: 255 */ + +enum bt_info_src_8812a_1ant { + BT_INFO_SRC_8812A_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8812A_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8812A_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8812A_1ANT_MAX +}; + +enum bt_8812a_1ant_bt_status { + BT_8812A_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8812A_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8812A_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8812A_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8812A_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8812A_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8812A_1ANT_BT_STATUS_MAX +}; + +enum bt_8812a_1ant_wifi_status { + BT_8812A_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8812A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_SPECIFIC_PKT = 0x3, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8812A_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8812A_1ANT_WIFI_STATUS_MAX +}; + +enum bt_8812a_1ant_coex_algo { + BT_8812A_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8812A_1ANT_COEX_ALGO_SCO = 0x1, + BT_8812A_1ANT_COEX_ALGO_HID = 0x2, + BT_8812A_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8812A_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8812A_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8812A_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8812A_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8812A_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8812A_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8812A_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8812A_1ANT_COEX_ALGO_MAX = 0xb, +}; + +struct coex_dm_8812a_1ant { + /* hw setting */ + u8 pre_ant_pos_type; + u8 cur_ant_pos_type; + /* fw mechanism */ + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean auto_tdma_adjust; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + /* sw mechanism */ + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + boolean limited_dig; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u32 pre_ra_mask; + u32 cur_ra_mask; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; + u32 arp_cnt; + + u8 error_condition; +}; + +struct coex_sta_8812a_1ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + + boolean under_lps; + boolean under_ips; + u32 specific_pkt_period_cnt; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + s8 bt_rssi; + boolean bt_tx_rx_mask; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + boolean c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8812A_1ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8812A_1ANT_MAX]; + u32 bt_info_query_cnt; + boolean c2h_bt_inquiry_page; + boolean c2h_bt_page; /* Add for win8.1 page out issue */ + boolean wifi_is_high_pri_task; /* Add for win8.1 page out issue */ + u8 bt_retry_cnt; + u8 bt_info_ext; + u32 pop_event_cnt; + u8 scan_ap_num; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_agg; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_agg; + + boolean cck_lock; + boolean pre_ccklock; + u8 coex_table_type; + + boolean force_lps_on; +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8812a1ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8812a1ant_pre_load_firmware(IN struct btc_coexist *btcoexist); +void ex_halbtc8812a1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8812a1ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8812a1ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8812a1ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8812a1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8812a1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8812a1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8812a1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8812a1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8812a1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8812a1ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8812a1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state); +void ex_halbtc8812a1ant_coex_dm_reset(IN struct btc_coexist *btcoexist); +void ex_halbtc8812a1ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8812a1ant_dbg_control(IN struct btc_coexist *btcoexist, + IN u8 op_code, IN u8 op_len, IN u8 *pdata); +void ex_halbtc8812a1ant_display_coex_info(IN struct btc_coexist *btcoexist); + +#else +#define ex_halbtc8812a1ant_power_on_setting(btcoexist) +#define ex_halbtc8812a1ant_pre_load_firmware(btcoexist) +#define ex_halbtc8812a1ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8812a1ant_init_coex_dm(btcoexist) +#define ex_halbtc8812a1ant_ips_notify(btcoexist, type) +#define ex_halbtc8812a1ant_lps_notify(btcoexist, type) +#define ex_halbtc8812a1ant_scan_notify(btcoexist, type) +#define ex_halbtc8812a1ant_connect_notify(btcoexist, type) +#define ex_halbtc8812a1ant_media_status_notify(btcoexist, type) +#define ex_halbtc8812a1ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8812a1ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8812a1ant_rf_status_notify(btcoexist, type) +#define ex_halbtc8812a1ant_halt_notify(btcoexist) +#define ex_halbtc8812a1ant_pnp_notify(btcoexist, pnp_state) +#define ex_halbtc8812a1ant_coex_dm_reset(btcoexist) +#define ex_halbtc8812a1ant_periodical(btcoexist) +#define ex_halbtc8812a1ant_dbg_control(btcoexist, op_code, op_len, pdata) +#define ex_halbtc8812a1ant_display_coex_info(btcoexist) + +#endif + +#endif diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a2ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a2ant.c new file mode 100644 index 0000000..038405b --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a2ant.c @@ -0,0 +1,5624 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8812A Co-exist mechanism + * + * History + * 2012/08/22 Cosa first check in. + * 2012/11/14 Cosa Revise for 8812A 2Ant out sourcing. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + + +#if (RTL8812A_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8812a_2ant glcoex_dm_8812a_2ant; +static struct coex_dm_8812a_2ant *coex_dm = &glcoex_dm_8812a_2ant; +static struct coex_sta_8812a_2ant glcoex_sta_8812a_2ant; +static struct coex_sta_8812a_2ant *coex_sta = &glcoex_sta_8812a_2ant; + +const char *const glbt_info_src_8812a_2ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; +/* ************************************************************ + * BtCoex Version Format: + * 1. date : glcoex_ver_date_XXXXX_1ant + * 2. WifiCoexVersion : glcoex_ver_XXXX_1ant + * 3. BtCoexVersion : glcoex_ver_btdesired_XXXXX_1ant + * 4. others : glcoex_ver_XXXXXX_XXXXX_1ant + * + * Variable should be indicated IC and Antenna numbers !!! + * Please strictly follow this order and naming style !!! + * + * ************************************************************ */ +u32 glcoex_ver_date_8812a_2ant = 20160818; +u32 glcoex_ver_8812a_2ant = 0x3c; +u32 glcoex_ver_btdesired_8812a_2ant = 0x3c; +/*1. add coex. log for wifi/BT coex. version*/ + +/* ************************************************************ +* local function proto type if needed +* ************************************************************ +* ************************************************************ +* local function start with halbtc8812a2ant_ +* ************************************************************ */ +u8 halbtc8812a2ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + + +u8 halbtc8812a2ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 index, IN u8 level_num, IN u8 rssi_thresh, IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + + +void halbtc8812a2ant_set_enable_pta(IN struct btc_coexist *btcoexist, + IN boolean enablePTA) +{ + if (enablePTA) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PTA is enable!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte(btcoexist, 0x40, 0x20); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PTA is disable!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte(btcoexist, 0x40, 0x00); + + } +} + +void halbtc8812a2ant_enable_pta(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], %s turn Enable PTA %s\n", + (force_exec ? "force to" : ""), (enable ? "ON" : "OFF")); + BTC_TRACE(trace_buf); + coex_dm->cur_enable_pta = enable; + + if (!force_exec) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], pre_enable_pta = %d, cur_enable_pta = %d!!\n", + coex_dm->pre_enable_pta, coex_dm->cur_enable_pta); + BTC_TRACE(trace_buf); + + if (coex_dm->pre_enable_pta == coex_dm->cur_enable_pta) + return; + } + halbtc8812a2ant_set_enable_pta(btcoexist, enable); + + + coex_dm->pre_enable_pta = coex_dm->cur_enable_pta; +} + +u32 halbtc8812a2ant_decide_ra_mask(IN struct btc_coexist *btcoexist, + IN u32 ra_mask_type) +{ + u32 dis_ra_mask = 0x0; + + switch (ra_mask_type) { + case 0: /* normal mode */ + dis_ra_mask = 0x0; + break; + case 1: /* disable cck 1/2 */ + dis_ra_mask = 0x00000003; + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ + dis_ra_mask = 0x0001f1f7; + break; + default: + break; + } + + return dis_ra_mask; +} + +void halbtc8812a2ant_update_ra_mask(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 dis_rate_mask) +{ + coex_dm->cur_ra_mask = dis_rate_mask; + + if (force_exec || (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_RAMASK, + &coex_dm->cur_ra_mask); + coex_dm->pre_ra_mask = coex_dm->cur_ra_mask; +} + +void halbtc8812a2ant_auto_rate_fallback_retry(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + boolean wifi_under_b_mode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + if (wifi_under_b_mode) { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +void halbtc8812a2ant_retry_limit(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || + (coex_dm->pre_retry_limit_type != + coex_dm->cur_retry_limit_type)) { + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +void halbtc8812a2ant_ampdu_max_time(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || + (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +void halbtc8812a2ant_limited_tx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ra_mask_type, IN u8 arfr_type, + IN u8 retry_limit_type, IN u8 ampdu_time_type) +{ + u32 dis_ra_mask = 0x0; + + coex_dm->cur_ra_mask_type = ra_mask_type; + dis_ra_mask = halbtc8812a2ant_decide_ra_mask(btcoexist, ra_mask_type); + halbtc8812a2ant_update_ra_mask(btcoexist, force_exec, dis_ra_mask); + + halbtc8812a2ant_auto_rate_fallback_retry(btcoexist, force_exec, + arfr_type); + halbtc8812a2ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8812a2ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type); +} + +void halbtc8812a2ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +void halbtc8812a2ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx); + BTC_TRACE(trace_buf); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + + +void halbtc8812a2ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ +#if 1 + + coex_sta->crc_ok_cck = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_CCK); + coex_sta->crc_ok_11g = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_LEGACY); + coex_sta->crc_ok_11n = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_HT); + coex_sta->crc_ok_11n_vht = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_VHT); + + coex_sta->crc_err_cck = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_CCK); + coex_sta->crc_err_11g = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_LEGACY); + coex_sta->crc_err_11n = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_HT); + coex_sta->crc_err_11n_vht = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_VHT); +#endif +} + + +void halbtc8812a2ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 data_len = 3; + u8 buf[5] = {0}; + /* 8812a watch btifo to check BT enable/disable + * if(!btcoexist->bt_info.bt_disabled) */ + { + if (!coex_sta->bt_info_query_cnt || + (coex_sta->bt_info_c2h_cnt[BT_INFO_SRC_8812A_2ANT_BT_RSP] + - coex_sta->bt_info_query_cnt) > 2) { + buf[0] = data_len; + buf[1] = 0x1; /* polling enable, 1=enable, 0=disable */ + buf[2] = 0x2; /* polling time in seconds */ + buf[3] = 0x1; /* auto report enable, 1=enable, 0=disable */ + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_CTRL_BT_INFO, + (void *)&buf[0]); + } + } + coex_sta->bt_info_query_cnt++; +} + +boolean halbtc8812a2ant_is_wifi_status_changed(IN struct btc_coexist *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + } + + return false; +} + +void halbtc8812a2ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + +#if 1/* (BT_AUTO_REPORT_ONLY_8812A_2ANT == 1) / profile from bt patch */ + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + bt_link_info->acl_busy = coex_sta->acl_busy; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } +#else /* profile from bt stack */ + bt_link_info->bt_link_exist = stack_info->bt_link_exist; + bt_link_info->sco_exist = stack_info->sco_exist; + bt_link_info->a2dp_exist = stack_info->a2dp_exist; + bt_link_info->pan_exist = stack_info->pan_exist; + bt_link_info->hid_exist = stack_info->hid_exist; + + /* for win-8 stack HID report error */ + if (!stack_info->hid_exist) + stack_info->hid_exist = + coex_sta->hid_exist; /* sync BTInfo with BT firmware and stack */ + /* when stack HID report error, here we use the info from bt fw. */ + if (!stack_info->bt_link_exist) + stack_info->bt_link_exist = coex_sta->bt_link_exist; +#endif + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + +u8 halbtc8812a2ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8812A_2ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 0) { + if (bt_link_info->acl_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ACL Busy only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_2ANT_COEX_ALGO_PANEDR; + } + } else if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_2ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_2ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_2ANT_COEX_ALGO_SCO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_2ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_2ANT_COEX_ALGO_SCO; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + if (stack_info->num_of_hid >= 2) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID*2 + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_HID_A2DP; + } + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_HID; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_2ANT_COEX_ALGO_PANEDR_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_SCO_HID; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_SCO_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8812A_2ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8812A_2ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +void halbtc8812a2ant_set_fw_dac_swing_level(IN struct btc_coexist *btcoexist, + IN u8 dac_swing_lvl) +{ + u8 h2c_parameter[1] = {0}; + + /* There are several type of dacswing */ + /* 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ + h2c_parameter[0] = dac_swing_lvl; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set Dac Swing Level=0x%x\n", + dac_swing_lvl); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], FW write 0x64=0x%x\n", + h2c_parameter[0]); + BTC_TRACE(trace_buf); + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +void halbtc8812a2ant_set_fw_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN u8 dec_bt_pwr_lvl) +{ + u8 data_len = 4; + u8 buf[6] = {0}; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], decrease Bt Power level = %d\n", + dec_bt_pwr_lvl); + BTC_TRACE(trace_buf); + + buf[0] = data_len; + buf[1] = 0x3; /* OP_Code */ + buf[2] = 0x2; /* OP_Code_Length */ + if (dec_bt_pwr_lvl) + buf[3] = 0x1; /* OP_Code_Content */ + else + buf[3] = 0x0; + buf[4] = dec_bt_pwr_lvl;/* pwr_level */ + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_CTRL_BT_COEX, + (void *)&buf[0]); +} + +void halbtc8812a2ant_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 dec_bt_pwr_lvl) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], %s Dec BT power level = %d\n", + (force_exec ? "force to" : ""), dec_bt_pwr_lvl); + BTC_TRACE(trace_buf); + + coex_dm->cur_bt_dec_pwr_lvl = dec_bt_pwr_lvl; + + if (!force_exec) { + if (coex_dm->pre_bt_dec_pwr_lvl == coex_dm->cur_bt_dec_pwr_lvl) + return; + } + halbtc8812a2ant_set_fw_dec_bt_pwr(btcoexist, + coex_dm->cur_bt_dec_pwr_lvl); + + coex_dm->pre_bt_dec_pwr_lvl = coex_dm->cur_bt_dec_pwr_lvl; +} + +void halbtc8812a2ant_fw_dac_swing_lvl(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 fw_dac_swing_lvl) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], %s set FW Dac Swing level = %d\n", + (force_exec ? "force to" : ""), fw_dac_swing_lvl); + BTC_TRACE(trace_buf); + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + + if (!force_exec) { + if (coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + halbtc8812a2ant_set_fw_dac_swing_level(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +void halbtc8812a2ant_set_sw_rf_rx_lpf_corner(IN struct btc_coexist *btcoexist, + IN boolean rx_rf_shrink_on) +{ + if (rx_rf_shrink_on) { + /* Shrink RF Rx LPF corner */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Shrink RF Rx LPF corner!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff, + 0xffffc); + } else { + /* Resume RF Rx LPF corner */ + /* After initialized, we can use coex_dm->bt_rf_0x1e_backup */ + if (btcoexist->initilized) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Resume RF Rx LPF corner!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, coex_dm->bt_rf_0x1e_backup); + } + } +} + +void halbtc8812a2ant_rf_shrink(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rx_rf_shrink_on) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], %s turn Rx RF Shrink = %s\n", + (force_exec ? "force to" : ""), + ((rx_rf_shrink_on) ? "ON" : "OFF")); + BTC_TRACE(trace_buf); + coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + + if (!force_exec) { + if (coex_dm->pre_rf_rx_lpf_shrink == + coex_dm->cur_rf_rx_lpf_shrink) + return; + } + halbtc8812a2ant_set_sw_rf_rx_lpf_corner(btcoexist, + coex_dm->cur_rf_rx_lpf_shrink); + + coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +void halbtc8812a2ant_set_sw_penalty_tx_rate_adaptive(IN struct btc_coexist + *btcoexist, IN boolean low_penalty_ra) +{ + u8 tmp_u1; + + tmp_u1 = btcoexist->btc_read_1byte(btcoexist, 0x4fd); + tmp_u1 |= BIT(0); + if (low_penalty_ra) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Tx rate adaptive, set low penalty!!\n"); + BTC_TRACE(trace_buf); + tmp_u1 &= ~BIT(2); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Tx rate adaptive, set normal!!\n"); + BTC_TRACE(trace_buf); + tmp_u1 |= BIT(2); + } + + btcoexist->btc_write_1byte(btcoexist, 0x4fd, tmp_u1); +} + +void halbtc8812a2ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ + return; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], %s turn LowPenaltyRA = %s\n", + (force_exec ? "force to" : ""), + ((low_penalty_ra) ? "ON" : "OFF")); + BTC_TRACE(trace_buf); + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + halbtc8812a2ant_set_sw_penalty_tx_rate_adaptive(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +void halbtc8812a2ant_set_dac_swing_reg(IN struct btc_coexist *btcoexist, + IN u32 level) +{ + u8 val = (u8)level; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Write SwDacSwing = 0x%x\n", + level); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc5b, 0x3e, val); +} + +void halbtc8812a2ant_set_sw_full_time_dac_swing(IN struct btc_coexist + *btcoexist, IN boolean sw_dac_swing_on, IN u32 sw_dac_swing_lvl) +{ + if (sw_dac_swing_on) + halbtc8812a2ant_set_dac_swing_reg(btcoexist, sw_dac_swing_lvl); + else + halbtc8812a2ant_set_dac_swing_reg(btcoexist, 0x18); +} + + +void halbtc8812a2ant_dac_swing(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean dac_swing_on, IN u32 dac_swing_lvl) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], %s turn DacSwing=%s, dac_swing_lvl=0x%x\n", + (force_exec ? "force to" : ""), ((dac_swing_on) ? "ON" : "OFF"), + dac_swing_lvl); + BTC_TRACE(trace_buf); + coex_dm->cur_dac_swing_on = dac_swing_on; + coex_dm->cur_dac_swing_lvl = dac_swing_lvl; + + if (!force_exec) { + if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && + (coex_dm->pre_dac_swing_lvl == + coex_dm->cur_dac_swing_lvl)) + return; + } + delay_ms(30); + halbtc8812a2ant_set_sw_full_time_dac_swing(btcoexist, dac_swing_on, + dac_swing_lvl); + + coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; + coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +void halbtc8812a2ant_set_adc_back_off(IN struct btc_coexist *btcoexist, + IN boolean adc_back_off) +{ + if (adc_back_off) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB BackOff Level On!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x3); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB BackOff Level Off!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x1); + } +} + +void halbtc8812a2ant_adc_back_off(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean adc_back_off) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], %s turn AdcBackOff = %s\n", + (force_exec ? "force to" : ""), + ((adc_back_off) ? "ON" : "OFF")); + BTC_TRACE(trace_buf); + + coex_dm->cur_adc_back_off = adc_back_off; + + if (!force_exec) { + if (coex_dm->pre_adc_back_off == coex_dm->cur_adc_back_off) + return; + } + halbtc8812a2ant_set_adc_back_off(btcoexist, coex_dm->cur_adc_back_off); + + coex_dm->pre_adc_back_off = coex_dm->cur_adc_back_off; +} + +void halbtc8812a2ant_set_agc_table(IN struct btc_coexist *btcoexist, + IN boolean agc_table_en) +{ + u8 rssi_adjust_val = 0; + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); + if (agc_table_en) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Agc Table On!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, + 0x28F4B); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, + 0x10AB2); + rssi_adjust_val = 8; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Agc Table Off!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, + 0x2884B); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, + 0x104B2); + } + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); + + /* set rssi_adjust_val for wifi module. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, + &rssi_adjust_val); +} + +void halbtc8812a2ant_agc_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean agc_table_en) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], %s %s Agc Table\n", + (force_exec ? "force to" : ""), + ((agc_table_en) ? "Enable" : "Disable")); + BTC_TRACE(trace_buf); + coex_dm->cur_agc_table_en = agc_table_en; + + if (!force_exec) { + if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en) + return; + } + halbtc8812a2ant_set_agc_table(btcoexist, agc_table_en); + + coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en; +} + +void halbtc8812a2ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], set coex table, set 0x6c0=0x%x\n", val0x6c0); + BTC_TRACE(trace_buf); + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], set coex table, set 0x6c4=0x%x\n", val0x6c4); + BTC_TRACE(trace_buf); + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], set coex table, set 0x6c8=0x%x\n", val0x6c8); + BTC_TRACE(trace_buf); + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], set coex table, set 0x6cc=0x%x\n", val0x6cc); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8812a2ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], %s write Coex Table 0x6c0=0x%x, 0x6c4=0x%x, 0x6c8=0x%x, 0x6cc=0x%x\n", + (force_exec ? "force to" : ""), val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + BTC_TRACE(trace_buf); + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8812a2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8812a2ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + switch (type) { + case 0: + halbtc8812a2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 1: + halbtc8812a2ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8812a2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5ffb5ffb, 0xffffff, 0x3); + break; + case 3: + halbtc8812a2ant_coex_table(btcoexist, force_exec, + 0x5fdf5fdf, 0x5fdb5fdb, 0xffffff, 0x3); + break; + case 4: + halbtc8812a2ant_coex_table(btcoexist, force_exec, + 0xdfffdfff, 0x5fdb5fdb, 0xffffff, 0x3); + break; + case 5: + halbtc8812a2ant_coex_table(btcoexist, force_exec, + 0x5ddd5ddd, 0x5fdb5fdb, 0xffffff, 0x3); + break; + case 6: + halbtc8812a2ant_coex_table(btcoexist, force_exec, + 0x5fff5fff, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 7: + if (coex_sta->scan_ap_num <= 5) + halbtc8812a2ant_coex_table(btcoexist, + force_exec, 0xffffffff, 0xfafafafa, + 0xffffff, 0x3); + else + halbtc8812a2ant_coex_table(btcoexist, + force_exec, 0xffffffff, 0x5a5a5a5a, + 0xffffff, 0x3); + break; + case 8: + halbtc8812a2ant_coex_table(btcoexist, force_exec, + 0x5f5f5f5f, 0x5a5a5a5a, 0xffffff, 0x3); + break; + + default: + break; + } +} + +void halbtc8812a2ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 data_len = 3; + u8 buf[5] = {0}; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], %s BT Ignore Wlan_Act\n", + (enable ? "Enable" : "Disable")); + BTC_TRACE(trace_buf); + + buf[0] = data_len; + buf[1] = 0x1; /* OP_Code */ + buf[2] = 0x1; /* OP_Code_Length */ + if (enable) + buf[3] = 0x1; /* OP_Code_Content */ + else + buf[3] = 0x0; + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_CTRL_BT_COEX, + (void *)&buf[0]); +} + +void halbtc8812a2ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], %s turn Ignore WlanAct %s\n", + (force_exec ? "force to" : ""), (enable ? "ON" : "OFF")); + BTC_TRACE(trace_buf); + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8812a2ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8812a2ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], FW for 1Ant AP mode\n"); + BTC_TRACE(trace_buf); + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + } + } + + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PS-TDMA H2C cmd =0x%x%08x\n", + h2c_parameter[0], + h2c_parameter[1] << 24 | h2c_parameter[2] << 16 | + h2c_parameter[3] << 8 | h2c_parameter[4]); + + BTC_TRACE(trace_buf); + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +void halbtc8812a2ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8812a2ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8812a2ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8812a2ant_sw_mechanism1(IN struct btc_coexist *btcoexist, + IN boolean shrink_rx_lpf, IN boolean low_penalty_ra, + IN boolean limited_dig, IN boolean bt_lna_constrain) +{ + /* + u32 wifi_bw; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 != wifi_bw) + { + if (shrink_rx_lpf) + shrink_rx_lpf = false; + } + */ + + halbtc8812a2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); + /* halbtc8812a2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); */ +} + +void halbtc8812a2ant_sw_mechanism2(IN struct btc_coexist *btcoexist, + IN boolean agc_table_shift, IN boolean adc_back_off, + IN boolean sw_dac_swing, IN u32 dac_swing_lvl) +{ + /* halbtc8812a2ant_agc_table(btcoexist, NORMAL_EXEC, agc_table_shift); */ + halbtc8812a2ant_adc_back_off(btcoexist, NORMAL_EXEC, adc_back_off); + halbtc8812a2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing, + dac_swing_lvl); +} + +void halbtc8812a2ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean init_hwcfg, IN boolean wifi_off) +{ + u8 u8tmp = 0; + + if (init_hwcfg) { + btcoexist->btc_write_4byte(btcoexist, 0x900, 0x00000400); + btcoexist->btc_write_1byte(btcoexist, 0x76d, 0x1); + } else if (wifi_off) { + + } + + /* ext switch setting */ + switch (ant_pos_type) { + case BTC_ANT_WIFI_AT_CPL_MAIN: + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0xcb7); + u8tmp &= ~BIT(2); + u8tmp |= BIT(3); + btcoexist->btc_write_1byte(btcoexist, 0xcb7, u8tmp); + break; + case BTC_ANT_WIFI_AT_CPL_AUX: + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0xcb7); + u8tmp &= ~BIT(3); + u8tmp |= BIT(2); + btcoexist->btc_write_1byte(btcoexist, 0xcb7, u8tmp); + break; + default: + break; + } +} + +void halbtc8812a2ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + s8 wifi_duration_adjust = 0x0; + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + if (!force_exec) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], pre_ps_tdma_on = %d, cur_ps_tdma_on = %d!!\n", + coex_dm->pre_ps_tdma_on, coex_dm->cur_ps_tdma_on); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], pre_ps_tdma = %d, cur_ps_tdma = %d!!\n", + coex_dm->pre_ps_tdma, coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + + if (coex_sta->scan_ap_num >= 40) + wifi_duration_adjust = -15; + else if (coex_sta->scan_ap_num >= 20) + wifi_duration_adjust = -10; + + /* + if (!coex_sta->force_lps_on) + { + ps_tdma_byte0_val = 0x61; + ps_tdma_byte3_val = 0x11; + ps_tdma_byte4_val = 0x10; + } + + + if ( (type == 3) || (type == 13) || (type == 14) ) + { + ps_tdma_byte4_val = ps_tdma_byte4_val & 0xbf; + + if (!wifi_busy) + ps_tdma_byte4_val = ps_tdma_byte4_val | 0x1; + } + + if (bt_link_info->slave_role == true) + ps_tdma_byte4_val = ps_tdma_byte4_val | 0x1; + + */ + if (turn_on) { + switch (type) { + case 1: + default: /* d1,wb */ + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c, 0x03, 0x11, 0x10); + break; + case 2: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x32, 0x03, 0x11, 0x10); + break; + case 3: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x28, 0x03, 0x11, 0x10); + break; + case 4: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1e, 0x03, 0x11, 0x10); + break; + case 5: /* d1,pb,TXpause */ + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x63, + 0x3c, 0x03, 0x90, 0x10); + break; + case 6: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x63, + 0x32, 0x03, 0x90, 0x10); + break; + case 7: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x63, + 0x28, 0x03, 0x90, 0x10); + break; + case 8: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x63, + 0x1e, 0x03, 0x90, 0x10); + break; + case 9: /* d1,bb */ + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c, 0x03, 0x31, 0x10); + break; + case 10: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x32, 0x03, 0x31, 0x10); + break; + case 11: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x28, 0x03, 0x31, 0x10); + break; + case 12: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1e, 0x03, 0x31, 0x10); + break; + case 13: /* d1,bb,TXpause */ + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c, 0x03, 0x30, 0x10); + break; + case 14: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x32, 0x03, 0x30, 0x10); + break; + case 15: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x28, 0x03, 0x30, 0x10); + break; + case 16: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1e, 0x03, 0x30, 0x10); + break; + case 17: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x61, + 0x35, 0x3, 0x11, 0x11); + break; + case 18: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x5, 0x5, 0xe1, 0x90); + break; + case 19: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x25, 0xe1, 0x90); + break; + case 20: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x25, 0x60, 0x90); + break; + case 21: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x15, 0x3, 0x70, 0x90); + break; + case 22: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x61, + 0x1a, 0x1a, 0x21, 0x10); + break; + case 23: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1c, 0x03, 0x31, 0x10); + break; + + case 71: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1a, 0x1a, 0xe1, 0x90); + break; + + /* following cases is for wifi rssi low, started from 81 */ + case 80: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x53, + 0x3c, 0x3, 0x90, 0x50); + break; + case 81: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x53, + 0x3a + wifi_duration_adjust, 0x3, 0x90, + 0x50); + break; + case 82: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x53, + 0x30 + wifi_duration_adjust, 0x03, 0x90, + 0x50); + break; + case 83: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x53, + 0x21, 0x03, 0x90, 0x50); + break; + case 84: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x53, + 0x15, 0x3, 0x90, 0x50); + break; + case 85: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x53, + 0x1d, 0x1d, 0x80, 0x50); + break; + case 86: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x53, + 0x15, 0x15, 0x80, 0x50); + break; + } + } else { + /* disable PS tdma */ + switch (type) { + case 0: /* ANT2PTA, 0x778=0x1 */ + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x8, + 0x0, 0x0, 0x0, 0x0); + break; + case 1: /* ANT2BT, 0x778=3 */ + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x8, 0x0); + delay_ms(5); + halbtc8812a2ant_set_ant_path(btcoexist, + BTC_ANT_WIFI_AT_CPL_AUX, false, false); + break; + case 2: /* ANT2BT, 0x778=3 */ + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x8, 0x0); + delay_ms(5); + halbtc8812a2ant_set_ant_path(btcoexist, + BTC_ANT_WIFI_AT_CPL_MAIN, false, false); + break; + default: + halbtc8812a2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x0, 0x0); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + + +void halbtc8812a2ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + + +void halbtc8812a2ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + boolean ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + ps_type = BTC_PS_WIFI_NATIVE; + lps_val = 0x0; + rpwm_val = 0x0; + } + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + case BTC_PS_LPS_ON: + halbtc8812a2ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8812a2ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + coex_sta->force_lps_on = true; + break; + case BTC_PS_LPS_OFF: + halbtc8812a2ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + default: + break; + } +} + +void halbtc8812a2ant_coex_all_off(IN struct btc_coexist *btcoexist) +{ + /* fw all off */ + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + /* hw all off */ + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8812a2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); + halbtc8812a2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, 0); + + halbtc8812a2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +void halbtc8812a2ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + struct btc_stack_info *stack_info = &btcoexist->stack_info; + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false; + + /* This function check if bt is disabled */ + + /* only 8812a need to consider if core stack is installed. */ + /*if (!stack_info->hci_version)*/ + /*bt_active = false;*/ + + bt_disabled = btcoexist->bt_info.bt_disabled; + + if (coex_sta->pre_bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->pre_bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + coex_sta->pre_bt_disabled = bt_disabled; + + if (bt_disabled) { + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 2); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } + } +} + + +void halbtc8812a2ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + + +boolean halbtc8812a2ant_is_common_action(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean common = false, wifi_connected = false, wifi_busy = false; + boolean bt_hs_on = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_bt_inquiry(btcoexist); + return true; + } + + if (bt_link_info->sco_exist || bt_link_info->hid_exist) + halbtc8812a2ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 0, 0, 0); + else + halbtc8812a2ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + if (!wifi_connected) { + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non-connected idle!!\n"); + BTC_TRACE(trace_buf); + + if ((BT_8812A_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) || + (BT_8812A_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + } else { + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + } + + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, false, + false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + + common = true; + } else { + if (BT_8812A_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, + false, false, 0x8); + + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 6); + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + common = true; + } else if (BT_8812A_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status) { + if (bt_hs_on) + return false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, + false, false, 0x8); + + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 6); + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8812a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + common = true; + } else { + if (wifi_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + BTC_TRACE(trace_buf); + common = false; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + + halbtc8812a2ant_limited_rx(btcoexist, + NORMAL_EXEC, false, false, 0x8); + + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 17); + + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, + NORMAL_EXEC, 6); + halbtc8812a2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, 0); + halbtc8812a2ant_sw_mechanism1(btcoexist, false, + false, false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, + false, false, 0x18); + common = true; + } + } + } + + return common; +} + +void halbtc8812a2ant_tdma_duration_adjust(IN struct btc_coexist *btcoexist, + IN boolean sco_hid, IN boolean tx_pause, IN u8 max_interval) +{ + static s32 up, dn, m, n, wait_count; + s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */ + u8 retry_count = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], TdmaDurationAdjust()\n"); + BTC_TRACE(trace_buf); + + coex_dm->auto_tdma_adjust_low_rssi = false; + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], first run TdmaDurationAdjust()!!\n"); + BTC_TRACE(trace_buf); + { + if (sco_hid) { + if (tx_pause) { + if (max_interval == 1) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = + 13; + } else if (max_interval == 2) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (max_interval == 3) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } + } else { + if (max_interval == 1) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = + 9; + } else if (max_interval == 2) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (max_interval == 3) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } + } + } else { + if (tx_pause) { + if (max_interval == 1) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = + 5; + } else if (max_interval == 2) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (max_interval == 3) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } + } else { + if (max_interval == 1) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (max_interval == 2) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (max_interval == 3) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } + } + } + } + /* ============ */ + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /* acquire the BT TRx retry count from BT_Info byte2 */ + retry_count = coex_sta->bt_retry_cnt; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], retry_count = %d\n", + retry_count); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_count=%d\n", + up, dn, m, n, wait_count); + BTC_TRACE(trace_buf); + + result = 0; + wait_count++; + + if (retry_count == + 0) { /* no retry in the last 2-second duration */ + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { /* if �s�� n ��2�� retry count��0, �h�ռeWiFi duration */ + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Increase wifi duration!!\n"); + BTC_TRACE(trace_buf); + } + } else if (retry_count <= + 3) { /* <=3 retry in the last 2-second duration */ + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { /* if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration */ + if (wait_count <= 2) + m++; /* �קK�@���b���level���Ӧ^ */ + else + m = 1; + + if (m >= 20) /* m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Decrease wifi duration for retry_counter<3!!\n"); + BTC_TRACE(trace_buf); + } + } else { /* retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration */ + if (wait_count == 1) + m++; /* �קK�@���b���level���Ӧ^ */ + else + m = 1; + + if (m >= 20) /* m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Decrease wifi duration for retry_counter>3!!\n"); + BTC_TRACE(trace_buf); + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], max Interval = %d\n", + max_interval); + BTC_TRACE(trace_buf); + + if (max_interval == 1) { + if (tx_pause) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], TxPause = 1\n"); + BTC_TRACE(trace_buf); + + if (coex_dm->cur_ps_tdma == 1) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 13); + coex_dm->ps_tdma_du_adj_type = 13; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = + 5; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = + 13; + } + } + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], TxPause = 0\n"); + BTC_TRACE(trace_buf); + + if (coex_dm->cur_ps_tdma == 5) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 1); + coex_dm->ps_tdma_du_adj_type = 1; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = + 9; + } + } + } + } else if (max_interval == 2) { + if (tx_pause) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], TxPause = 1\n"); + BTC_TRACE(trace_buf); + + if (coex_dm->cur_ps_tdma == 1) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } + } + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], TxPause = 0\n"); + BTC_TRACE(trace_buf); + + if (coex_dm->cur_ps_tdma == 5) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } + } + } + } else if (max_interval == 3) { + if (tx_pause) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], TxPause = 1\n"); + BTC_TRACE(trace_buf); + + if (coex_dm->cur_ps_tdma == 1) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } + } + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], TxPause = 0\n"); + BTC_TRACE(trace_buf); + + if (coex_dm->cur_ps_tdma == 5) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8812a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8812a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } + } + } + } + } + + /* if current PsTdma not match with the recorded one (when scan, dhcp...), */ + /* then we have to adjust it back to the previous record one. */ + if (coex_dm->cur_ps_tdma != coex_dm->ps_tdma_du_adj_type) { + boolean scan = false, link = false, roam = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PsTdma type dismatch!!!, cur_ps_tdma=%d, recordPsTdma=%d\n", + coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (!scan && !link && !roam) + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->ps_tdma_du_adj_type); + else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"); + BTC_TRACE(trace_buf); + } + } +} + +/* ****************** + * pstdma for wifi rssi low + * ****************** */ +void halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + IN struct btc_coexist *btcoexist/* , */ /* IN u8 wifi_status */) +{ + static s32 up, dn, m, n, wait_count; + s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */ + u8 retry_count = 0, bt_info_ext; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low()\n"); + BTC_TRACE(trace_buf); +#if 0 + if ((BT_8812A_2ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN == + wifi_status) || + (BT_8812A_2ANT_WIFI_STATUS_CONNECTED_SCAN == wifi_status) || + (BT_8812A_2ANT_WIFI_STATUS_CONNECTED_SPECIAL_PKT == + wifi_status)) { + if (coex_dm->cur_ps_tdma != 81 && + coex_dm->cur_ps_tdma != 82 && + coex_dm->cur_ps_tdma != 83 && + coex_dm->cur_ps_tdma != 84) { + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 82); + coex_dm->ps_tdma_du_adj_type = 82; + + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } + return; + } +#endif + coex_dm->auto_tdma_adjust = false; + + retry_count = coex_sta->bt_retry_cnt; + bt_info_ext = coex_sta->bt_info_ext; + + if (!coex_dm->auto_tdma_adjust_low_rssi) { + coex_dm->auto_tdma_adjust_low_rssi = true; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], first run TdmaDurationAdjustForWifiRssiLow()!!\n"); + BTC_TRACE(trace_buf); + + if (BT_INFO_8812A_2ANT_A2DP_BASIC_RATE(bt_info_ext)) { + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 83); + coex_dm->ps_tdma_du_adj_type = 83; + } else { + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 82); + coex_dm->ps_tdma_du_adj_type = 82; + } + /* ============ */ + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /* acquire the BT TRx retry count from BT_Info byte2 + * retry_count = coex_sta->bt_retry_cnt; + * bt_info_ext = coex_sta->bt_info_ext; */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], retry_count = %d\n", + retry_count); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_count=%d\n", + up, dn, m, n, wait_count); + BTC_TRACE(trace_buf); + result = 0; + wait_count++; + + if ((coex_sta->low_priority_tx) > 1050 || + (coex_sta->low_priority_rx) > 1250) + retry_count++; + + if (retry_count == + 0) { /* no retry in the last 2-second duration */ + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { /* if �s�� n ��2�� retry count��0, �h�ռeWiFi duration */ + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Increase wifi duration!!\n"); + BTC_TRACE(trace_buf); + } + } else if (retry_count <= + 3) { /* <=3 retry in the last 2-second duration */ + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { /* if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration */ + if (wait_count <= 2) + m++; /* �קK�@���b���level���Ӧ^ */ + else + m = 1; + + if (m >= 20) /* m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Decrease wifi duration for retry_counter<3!!\n"); + BTC_TRACE(trace_buf); + } + } else { /* retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration */ + if (wait_count == 1) + m++; /* �קK�@���b���level���Ӧ^ */ + else + m = 1; + + if (m >= 20) /* m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Decrease wifi duration for retry_counter>3!!\n"); + BTC_TRACE(trace_buf); + } + + if (result == -1) { + /* + if( (BT_INFO_8812A_2ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 81) ||(coex_dm->cur_ps_tdma == 82)) ) + { + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 84); + coex_dm->ps_tdma_du_adj_type = 84; + } + */ + if (coex_dm->cur_ps_tdma == 80) { + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 82); + coex_dm->ps_tdma_du_adj_type = 82; + } else if (coex_dm->cur_ps_tdma == 81) { + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 82); + coex_dm->ps_tdma_du_adj_type = 82; + } else if (coex_dm->cur_ps_tdma == 82) { + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 83); + coex_dm->ps_tdma_du_adj_type = 83; + } else if (coex_dm->cur_ps_tdma == 83) { + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 84); + coex_dm->ps_tdma_du_adj_type = 84; + } + } else if (result == 1) { + /* + if( (BT_INFO_8812A_2ANT_A2DP_BASIC_RATE(bt_info_ext)) && + ((coex_dm->cur_ps_tdma == 81) ||(coex_dm->cur_ps_tdma == 82)) ) + { + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 83); + coex_dm->ps_tdma_du_adj_type = 83; + } + */ + if (coex_dm->cur_ps_tdma == 84) { + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 83); + coex_dm->ps_tdma_du_adj_type = 83; + } else if (coex_dm->cur_ps_tdma == 83) { + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 82); + coex_dm->ps_tdma_du_adj_type = 82; + } else if (coex_dm->cur_ps_tdma == 82) { + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 81); + coex_dm->ps_tdma_du_adj_type = 81; + } else if ((coex_dm->cur_ps_tdma == 81) && + ((coex_sta->scan_ap_num <= 5))) { + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 81); + coex_dm->ps_tdma_du_adj_type = 81; + } + } + + if (coex_dm->cur_ps_tdma != 80 && + coex_dm->cur_ps_tdma != 81 && + coex_dm->cur_ps_tdma != 82 && + coex_dm->cur_ps_tdma != 83 && + coex_dm->cur_ps_tdma != 84) { + /* recover to previous adjust type */ + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->ps_tdma_du_adj_type); + } + } +} + +void halbtc8812a2ant_get_bt_rssi_threshold(IN struct btc_coexist *btcoexist, + IN u8 *pThres0, IN u8 *pThres1) +{ + u8 ant_type; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_ANT_TYPE, &ant_type); + + + switch (ant_type) { + case BTC_ANT_TYPE_0: + *pThres0 = 100; + *pThres1 = 100; + break; + case BTC_ANT_TYPE_1: + *pThres0 = 34; + *pThres1 = 42; + break; + case BTC_ANT_TYPE_2: + *pThres0 = 34; + *pThres1 = 42; + break; + case BTC_ANT_TYPE_3: + *pThres0 = 34; + *pThres1 = 42; + break; + case BTC_ANT_TYPE_4: + *pThres0 = 34; + *pThres1 = 42; + break; + default: + break; + } +} + + + +void halbtc8812a2ant_action_sco(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH, + bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + + /* halbtc8812a2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, &bt_thresh1); */ + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + + wifi_rssi_state = halbtc8812a2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, 34, 42); + + /* power save state */ + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* coex table */ + if (BTC_RSSI_LOW(bt_rssi_state)) + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + else + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + /* pstdma */ + if (BTC_RSSI_LOW(bt_rssi_state)) + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + else + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + + /* decrease BT power */ + if (BTC_RSSI_LOW(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + else if (BTC_RSSI_MEDIUM(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 4); + + /* limited Rx */ + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + /* fw dac swing level */ + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + true, 0x6); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + true, 0x6); + } + } else { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + true, 0x6); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + true, 0x6); + } + } +} + +void halbtc8812a2ant_action_sco_hid(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH, + bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + /* halbtc8812a2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, &bt_thresh1); */ + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + + wifi_rssi_state = halbtc8812a2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, 34, 42); + + /* power save state */ + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* coex table */ + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + /* pstdma */ + if (BTC_RSSI_LOW(bt_rssi_state)) + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 13); + else + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 9); + + /* decrease BT power */ + if (BTC_RSSI_LOW(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + else if (BTC_RSSI_MEDIUM(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 4); + + /* limited Rx */ + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, 0x8); + + /* fw dac swing level */ + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x6); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x6); + } + } else { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x6); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x6); + } + } +} + +void halbtc8812a2ant_action_hid(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH, + bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 anttype = 0; + + + btcoexist->btc_get(btcoexist, BTC_GET_U1_ANT_TYPE, &anttype); + + + /* halbtc8812a2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, &bt_thresh1); + * bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, bt_thresh0, bt_thresh1); */ + + wifi_rssi_state = halbtc8812a2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, 34, 42); + + + if (anttype == 0) { /* ANTTYPE = 0 92E 2ant with SPDT */ + /* power save state & pstdma & coex table */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (anttype == + 1) { /* 92E 2ant with coupler and bad ant. isolation, 92E 3ant with bad ant. isolation */ + /* power save state & pstdma & coex table */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (anttype == + 2) { /* ANTTYPE = 2, 92E 2ant with coupler and normal/good ant. isolation, 92E 3ant with normal ant. isolation */ + /* power save state & pstdma & coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & shielding room */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, true, 9); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 3); + } else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & noisy environment */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, true, 9); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 3); + } else { /* WIFI RSSI || BT RSSI == low */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, true, 9); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 3); + } + } else if (anttype == + 3) { /* ANTTYPE = 3, 92E 3ant with good ant. isolation */ + /* power save state & pstdma & coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & shielding room */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 1); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + } else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & noisy environment */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 1); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + } else { /* WIFI RSSI || BT RSSI == low */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 1); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } + } else { /* ANTTYPE = 4 for test */ + /* power save state & pstdma & coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & shielding room */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & noisy environment */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } else { /* WIFI RSSI || BT RSSI == low */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } + } + + + /* power save state */ + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* coex table */ + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + /* pstdma */ + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + /* decrease BT power */ + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* limited Rx */ + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + /* fw dac swing level */ + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +void halbtc8812a2ant_action_a2dp(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH, + bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 anttype = 0; + boolean ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_ANT_TYPE, &anttype); + + /* halbtc8812a2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, &bt_thresh1); + * bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, bt_thresh0, bt_thresh1); */ + + wifi_rssi_state = halbtc8812a2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, 34, 42); + + /* anttype = 4; */ + + if (anttype == 0) { /* ANTTYPE = 0 92E 2ant with SPDT */ + + if (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A) { + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 0); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } else { + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) { + /* WIFI RSSI = high & BT RSSI = high & shielding room */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } else { /* WIFI RSSI || BT RSSI == low */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } + } + + /* power save state & pstdma & coex table + * + if(BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state)) && (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A)) + { + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low(btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + } + else if (BTC_RSSI_HIGH(wifi_rssi_state)&&(!BTC_RSSI_LOW(bt_rssi_state)) && (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A)) + { + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } + else + { + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low(btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + } + */ + } else if (anttype == + 1) { /* 92E 2ant with coupler and bad ant. isolation, 92E 3ant with bad ant. isolation */ + /* power save state & pstdma & coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & shielding room */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_tdma_duration_adjust(btcoexist, false, + false, 1); /* shielding room */ + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & noisy environment */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 1); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } else { /* WIFI RSSI || BT RSSI == low */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } + + } else if (anttype == + 2) { /* ANTTYPE = 2, 92E 2ant with coupler and normal/good ant. isolation, 92E 3ant with normal ant. isolation */ + /* power save state & pstdma & coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & shielding room */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_tdma_duration_adjust(btcoexist, false, + false, 1); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 5); + } else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & noisy environment */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 1); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } else { /* WIFI RSSI || BT RSSI == low */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } + } else if (anttype == + 3) { /* ANTTYPE = 3, 92E 3ant with good ant. isolation */ + /* power save state & pstdma & coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & shielding room */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 1); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + } else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & noisy environment */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 1); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + } else { /* WIFI RSSI || BT RSSI == low */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 1); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } + } else { /* ANTTYPE = 4 for test */ + /* power save state & pstdma & coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & shielding room */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & noisy environment */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } else { /* WIFI RSSI || BT RSSI == low */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } + } + + /* decrease BT power */ + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* decrease BT power + * + if(BTC_RSSI_LOW(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else if (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 4); + */ + /* limited Rx */ + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + /* fw dac swing level */ + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8812a2ant_action_a2dp_pan_hs(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH, + bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + /* halbtc8812a2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, &bt_thresh1); */ + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + + wifi_rssi_state = halbtc8812a2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, 34, 42); + + /* power save state */ + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + + /* pstdma */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_tdma_duration_adjust(btcoexist, false, false, + 2); + else + halbtc8812a2ant_tdma_duration_adjust(btcoexist, false, true, 2); + + /* decrease BT power */ + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + /* + + if(BTC_RSSI_LOW(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 4); + */ + /* limited Rx */ + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + /* fw dac swing level */ + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + true, 0x6); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + true, 0x6); + } + } else { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + true, 0x6); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + true, 0x6); + } + } +} + +void halbtc8812a2ant_action_pan_edr(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH, + bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + + + halbtc8812a2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, + &bt_thresh1); + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + + wifi_rssi_state = halbtc8812a2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + /* bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, 34, 42); */ + + /* power save state */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + + /* coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + /* pstdma */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); + else + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 85); + + /* decrease BT power */ + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* limited Rx */ + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + /* fw dac swing level */ + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* PAN(HS) only */ +void halbtc8812a2ant_action_pan_hs(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH, + bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + + wifi_rssi_state = halbtc8812a2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, 34, 42); + + /* power save state */ + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* coex table */ + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + + /* pstdma */ + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + /* decrease BT power */ + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* + + if(BTC_RSSI_LOW(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 4); + */ + /* limited Rx */ + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + /* fw dac swing level */ + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* PAN(EDR)+A2DP */ +void halbtc8812a2ant_action_pan_edr_a2dp(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH, + bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + halbtc8812a2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, + &bt_thresh1); + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + + wifi_rssi_state = halbtc8812a2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + /* bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, 34, 42); */ + + /* power save state */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + + /* coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + /* pstdma */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_tdma_duration_adjust(btcoexist, false, false, + 3); + else { + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 86); + } + + /* decrease BT power */ + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* limited Rx */ + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + /* fw dac swing level */ + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + + +void halbtc8812a2ant_action_pan_edr_hid(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH, + bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + + halbtc8812a2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, + &bt_thresh1); + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + + wifi_rssi_state = halbtc8812a2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + /* bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, 34, 42); */ + + /* power save state */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else if (BTC_RSSI_LOW(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + + /* coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + else if (BTC_RSSI_LOW(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + else + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + /* pstdma */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 10); + else if (BTC_RSSI_LOW(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + else + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 85); + + /* decrease BT power */ + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* + + if(BTC_RSSI_LOW(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 4); + */ + /* limited Rx */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + else if (BTC_RSSI_LOW(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + else + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, + 0x8); + + /* fw dac swing level */ + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* HID+A2DP+PAN(EDR) */ +void halbtc8812a2ant_action_hid_a2dp_pan_edr(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH, + bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + halbtc8812a2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, + &bt_thresh1); + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + + wifi_rssi_state = halbtc8812a2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + /* bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, 34, 42); */ + + /* power save state */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else if (BTC_RSSI_LOW(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + + /* coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + else if (BTC_RSSI_LOW(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + else + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + /* pstdma */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_tdma_duration_adjust(btcoexist, true, false, 3); + else if (BTC_RSSI_LOW(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_tdma_duration_adjust(btcoexist, true, true, 3); + else { + coex_dm->auto_tdma_adjust = false; + halbtc8812a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 86); + } + + /* decrease BT power */ + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + /* + + if(BTC_RSSI_LOW(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 4); + */ + /* limited Rx */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + else if (BTC_RSSI_LOW(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + else + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, + 0x8); + + + /* fw dac swing level */ + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8812a2ant_action_hid_a2dp_pan_hs(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH, + bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 bt_thresh0 = 0, bt_thresh1 = 0; + + halbtc8812a2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, + &bt_thresh1); + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, bt_thresh0, + bt_thresh1); + + + wifi_rssi_state = halbtc8812a2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + /* bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, 34, 42); */ + + /* power save state */ + halbtc8812a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + else if (BTC_RSSI_LOW(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + else + halbtc8812a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + /* pstdma */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_tdma_duration_adjust(btcoexist, true, false, 2); + else if (BTC_RSSI_LOW(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_tdma_duration_adjust(btcoexist, true, true, 2); + else + halbtc8812a2ant_tdma_duration_adjust(btcoexist, true, true, 2); + + /* decrease BT power */ + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* + + if(BTC_RSSI_LOW(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 4); + */ + /* limited Rx */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + else if (BTC_RSSI_LOW(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state))) + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + else + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, + 0x8); + + /* fw dac swing level */ + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8812a2ant_action_hid_a2dp(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH, + bt_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_bw; + u8 anttype = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_ANT_TYPE, &anttype); + + + /* halbtc8812a2ant_get_bt_rssi_threshold(btcoexist, &bt_thresh0, &bt_thresh1); + * bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, bt_thresh0, bt_thresh1); */ + + wifi_rssi_state = halbtc8812a2ant_wifi_rssi_state(btcoexist, 0, 2, 34, + 0); + bt_rssi_state = halbtc8812a2ant_bt_rssi_state(3, 34, 42); + + if (anttype == 0) { /* ANTTYPE = 0 92E 2ant with SPDT */ + /* power save state & pstdma & coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A)) { + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, true, + 83); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + + } else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A)) { + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 0); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } else { + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, true, + 83); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + } + } else if (anttype == + 1) { /* 92E 2ant with coupler and bad ant. isolation, 92E 3ant with bad ant. isolation */ + /* power save state & pstdma & coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A)) { + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_tdma_duration_adjust(btcoexist, true, + true, 2); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + } else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A)) { + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 0); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } else { + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, true, + 83); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + } + } else if (anttype == + 2) { /* ANTTYPE = 2, 92E 2ant with coupler and normal/good ant. isolation, 92E 3ant with normal ant. isolation */ + /* power save state & pstdma & coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & shielding room */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_tdma_duration_adjust(btcoexist, true, + true, 2); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + } else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & noisy environment */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 0); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + } else { /* WIFI RSSI || BT RSSI == low */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, true, + 83); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + } + } else if (anttype == + 3) { /* ANTTYPE = 3, 92E 3ant with good ant. isolation */ + /* power save state & pstdma & coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & shielding room */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 1); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + } else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & noisy environment */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 1); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + } else { /* WIFI RSSI || BT RSSI == low */ + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8812a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 1); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } + } else { /* ANTTYPE = 4 for test */ + /* power save state & pstdma & coex table */ + if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & shielding room */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } else if (BTC_RSSI_HIGH(wifi_rssi_state) && + (!BTC_RSSI_LOW(bt_rssi_state)) && + (coex_sta->scan_ap_num > NOISY_AP_NUM_THRESH_8812A)) { + /* WIFI RSSI = high & BT RSSI = high & noisy environment */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } else { /* WIFI RSSI || BT RSSI == low */ + halbtc8812a2ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + halbtc8812a2ant_tdma_duration_adjust_for_wifi_rssi_low( + btcoexist); + halbtc8812a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } + } + + /* decrease BT power */ + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* + + if(BTC_RSSI_LOW(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + else if(BTC_RSSI_MEDIUM(bt_rssi_state)) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else if (coex_sta->scan_ap_num < NOISY_AP_NUM_THRESH_8812A) + halbtc8812a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 4); + */ + /* limited Rx */ + halbtc8812a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + /* fw dac swing level */ + halbtc8812a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if (BTC_RSSI_HIGH(wifi_rssi_state)) { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8812a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8812a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8812a2ant_coex_under_5g(IN struct btc_coexist *btcoexist) +{ + halbtc8812a2ant_coex_all_off(btcoexist); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Under 5G, force set BT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_ignore_wlan_act(btcoexist, NORMAL_EXEC, true); +} +/* **************************************************** */ +void halbtc8812a2ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + boolean wifi_under_5g = false; + u8 algorithm = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), run 5G coex setting!!<===\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_coex_under_5g(btcoexist); + return; + } + + + algorithm = halbtc8812a2ant_action_algorithm(btcoexist); + if (coex_sta->c2h_bt_inquiry_page && + (BT_8812A_2ANT_COEX_ALGO_PANHS != algorithm)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_bt_inquiry(btcoexist); + return; + } + + coex_dm->cur_algorithm = algorithm; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Algorithm = %d\n", + coex_dm->cur_algorithm); + BTC_TRACE(trace_buf); + + if (halbtc8812a2ant_is_common_action(btcoexist)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant common.\n"); + BTC_TRACE(trace_buf); + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + } else { + if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], pre_algorithm=%d, cur_algorithm=%d\n", + coex_dm->pre_algorithm, coex_dm->cur_algorithm); + BTC_TRACE(trace_buf); + coex_dm->auto_tdma_adjust = false; + coex_dm->auto_tdma_adjust_low_rssi = false; + } + switch (coex_dm->cur_algorithm) { + case BT_8812A_2ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_sco(btcoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_SCO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = SCO+HID.\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_sco_hid(btcoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID.\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_hid(btcoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_a2dp(btcoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_pan_edr(btcoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HS mode.\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_pan_hs(btcoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_pan_edr_hid(btcoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_hid_a2dp_pan_edr( + btcoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_hid_a2dp_pan_hs( + btcoexist); + break; + case BT_8812A_2ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_action_hid_a2dp(btcoexist); + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_coex_all_off(btcoexist); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } + +} + +void halbtc8812a2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean back_up) +{ + u8 u8tmp = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 2Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + + if (back_up) { + /* backup rf 0x1e value */ + coex_dm->bt_rf_0x1e_backup = + btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff); + + coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, + 0x430); + coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, + 0x434); + coex_dm->backup_retry_limit = btcoexist->btc_read_2byte( + btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = btcoexist->btc_read_1byte( + btcoexist, 0x456); + } + + /* ant sw control to BT */ + halbtc8812a2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_CPL_AUX, true, + false); + + /* 0x790[5:0]=0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + /* PTA parameter */ + btcoexist->btc_write_1byte(btcoexist, 0x6cc, 0x0); + btcoexist->btc_write_4byte(btcoexist, 0x6c8, 0xffff); + btcoexist->btc_write_4byte(btcoexist, 0x6c4, 0x55555555); + btcoexist->btc_write_4byte(btcoexist, 0x6c0, 0x55555555); + + /* coex parameters */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + + /* enable counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + /* disable PTA to avoid BT insn't on */ + btcoexist->btc_write_1byte(btcoexist, 0x40, 0x00); + + /* bt clock related */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x4); + u8tmp |= BIT(7); + btcoexist->btc_write_1byte(btcoexist, 0x4, u8tmp); + + /* bt clock related */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x7); + u8tmp |= BIT(1); + btcoexist->btc_write_1byte(btcoexist, 0x7, u8tmp); + + /* Give bt_coex_supported_version the default value */ + coex_sta->bt_coex_supported_version = 0; + +} + +/* ************************************************************ + * work around function start with wa_halbtc8812a2ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8812a2ant_ + * ************************************************************ */ +void ex_halbtc8812a2ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ +} + +void ex_halbtc8812a2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8812a2ant_init_hw_config(btcoexist, true); +} + +void ex_halbtc8812a2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + halbtc8812a2ant_init_coex_dm(btcoexist); +} + + +void ex_halbtc8812a2ant_pta_off_on_notify(IN struct btc_coexist *btcoexist, + IN u8 bt_status) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], BToff/on notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_BT_OFF == bt_status) { + /* PTA off */ + btcoexist->bt_info.bt_disabled = true; + halbtc8812a2ant_enable_pta(btcoexist, FORCE_EXEC, false); + + } else { + /* PTA on */ + btcoexist->bt_info.bt_disabled = false; + halbtc8812a2ant_enable_pta(btcoexist, FORCE_EXEC, true); + } + +} + + +void ex_halbtc8812a2ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u16 u16tmp[4]; + u32 u32tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + u32 fw_ver = 0, bt_patch_ver = 0, bt_coex_ver = 0; + u32 phyver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "Ant PG number/ Ant mechanism:", + board_info->pg_ant_num, board_info->btdm_ant_num); + CL_PRINTF(cli_buf); + +#if 0 + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "Antenna type:", + board_info->ant_type); + CL_PRINTF(cli_buf); +#endif + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", + "BT stack/ hci ext ver", + ((stack_info->profile_notified) ? "Yes" : "No"), + stack_info->hci_version); + CL_PRINTF(cli_buf); + + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + bt_coex_ver = coex_sta->bt_coex_supported_version & 0xff; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8812a_2ant, glcoex_ver_8812a_2ant, + glcoex_ver_btdesired_8812a_2ant, bt_coex_ver, + (bt_coex_ver == 0xff ? "Unknown" : (bt_coex_ver >= + glcoex_ver_btdesired_8812a_2ant ? "Match" : + "Mis-Match"))); + CL_PRINTF(cli_buf); + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ v%d", + "W_FW/ B_FW/ Phy", + fw_ver, bt_patch_ver, phyver); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "Wifi channel informed to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", + "BT [status/ rssi/ retryCnt]", + ((btcoexist->bt_info.bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") + : ((BT_8812A_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8812A_2ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi, coex_sta->bt_retry_cnt); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + "SCO/HID/PAN/A2DP", + bt_link_info->sco_exist, bt_link_info->hid_exist, + bt_link_info->pan_exist, bt_link_info->a2dp_exist); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext & BIT(0)) ? "Basic rate" : "EDR rate"); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8812A_2ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8812a_2ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + /* Sw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Sw mechanism]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "SM1[ShRf/ LpRA/ LimDig]", + coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra, + coex_dm->limited_dig); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", + "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", + coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, + coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", "Rate Mask", + btcoexist->bt_info.ra_mask); + CL_PRINTF(cli_buf); + + /* Fw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Fw mechanism]============"); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d/%d)", + "PS TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + coex_dm->auto_tdma_adjust, + coex_dm->auto_tdma_adjust_low_rssi); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "DecBtPwr/ IgnWlanAct", + coex_dm->cur_bt_dec_pwr_lvl, coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + "RF-A, 0x1e initVal", + coex_dm->bt_rf_0x1e_backup); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "backup ARFR1/ARFR2/RL/AMaxTime", + coex_dm->backup_arfr_cnt1, coex_dm->backup_arfr_cnt2, + coex_dm->backup_retry_limit, + coex_dm->backup_ampdu_max_time); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x ", + "0x778 (W_Act)/ 0x6cc (CoTab Sel)", + u8tmp[0], u8tmp[1]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xc5b); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x8db(ADC)/0xc5b[29:25](DAC)", + ((u8tmp[0] & 0x60) >> 5), ((u8tmp[1] & 0x3e) >> 1)); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xcb3); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xcb7); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0xcb3/ 0xcb7", + u8tmp[0], u8tmp[1]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x974); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x40/ 0x4c[24:23]/ 0x974", + u8tmp[0], ((u32tmp[0] & 0x01800000) >> 23), u32tmp[1]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", + u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa0a); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0xc50(DIG)/0xa0a(CCK-TH)", + u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + fa_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_OFDM); + fa_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_CCK); + cca_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_OFDM); + cca_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_CCK); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", + cca_cck, fa_cck, cca_ofdm, fa_ofdm); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11n-agg", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11n-agg", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(high-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(low-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8812A_2ANT == 1) + halbtc8812a2ant_monitor_bt_ctr(btcoexist); +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8812a2ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + boolean wifi_under_5g = false; + + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + + coex_sta->under_ips = true; + halbtc8812a2ant_coex_all_off(btcoexist); + halbtc8812a2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_CPL_AUX, + false, true); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS notify, force set BT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + + halbtc8812a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + ex_halbtc8812a2ant_media_status_notify(btcoexist, + BTC_MEDIA_DISCONNECT); + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + + coex_sta->under_ips = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, + &wifi_under_5g); + if (!wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS notify, force set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + + halbtc8812a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, + false); + } + } +} + +void ex_halbtc8812a2ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + + coex_sta->under_lps = false; + } +} + +void ex_halbtc8812a2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + if (BTC_SCAN_START == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + } else if (BTC_SCAN_FINISH == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + } +} + +void ex_halbtc8812a2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + if (BTC_ASSOCIATE_START == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify\n"); + BTC_TRACE(trace_buf); + } else if (BTC_ASSOCIATE_FINISH == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify\n"); + BTC_TRACE(trace_buf); + } +} + +void ex_halbtc8812a2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 data_len = 5; + u8 buf[6] = {0}; + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + btcoexist->bt_info.bt_disabled) + return; + + if (BTC_MEDIA_CONNECT == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + } + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + h2c_parameter[0] = 0x1; + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + buf[0] = data_len; + buf[1] = 0x5; /* OP_Code */ + buf[2] = 0x3; /* OP_Code_Length */ + buf[3] = h2c_parameter[0]; /* OP_Code_Content */ + buf[4] = h2c_parameter[1]; + buf[5] = h2c_parameter[2]; + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_CTRL_BT_COEX, + (void *)&buf[0]); +} + +void ex_halbtc8812a2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + if (type == BTC_PACKET_DHCP) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], DHCP Packet notify\n"); + BTC_TRACE(trace_buf); + } +} + +void ex_halbtc8812a2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + boolean bt_busy = false, limited_dig = false; + boolean wifi_connected = false, wifi_under_5g = false; + + coex_sta->c2h_bt_info_req_sent = false; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8812A_2ANT_MAX) + rsp_source = BT_INFO_SRC_8812A_2ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt info[%d], length=%d, hex data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + if (BT_INFO_SRC_8812A_2ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0] */ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rsp_source][4]; + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + if ((coex_sta->bt_info_ext & BIT(1))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) + ex_halbtc8812a2ant_media_status_notify( + btcoexist, BTC_MEDIA_CONNECT); + else + ex_halbtc8812a2ant_media_status_notify( + btcoexist, BTC_MEDIA_DISCONNECT); + } + + if ((coex_sta->bt_info_ext & BIT(3)) && !wifi_under_5g) { + /* BT already ignored WlanAct */ + if (!btcoexist->manual_control && + !btcoexist->stop_coex_dm) { + if (!coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_ignore_wlan_act( + btcoexist, FORCE_EXEC, false); + } + } + } else { + /* BT already NOT ignore Wlan active, do nothing here. */ + + if (coex_sta->under_ips) { + /* work around for 8812a combo hw bug => when IPS, wlanAct is always high. */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS, set BT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8812a2ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, true); + } + } + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (bt_info & BT_INFO_8812A_2ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status */ + if (!(bt_info & BT_INFO_8812A_2ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + coex_sta->acl_busy = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8812A_2ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8812A_2ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8812A_2ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8812A_2ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + if (bt_info & BT_INFO_8812A_2ANT_B_ACL_BUSY) + coex_sta->acl_busy = true; + else + coex_sta->acl_busy = false; + + } + + halbtc8812a2ant_update_bt_link_info(btcoexist); + + if (!(bt_info & BT_INFO_8812A_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8812A_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info == + BT_INFO_8812A_2ANT_B_CONNECTION) { /* connection exists but no busy */ + coex_dm->bt_status = BT_8812A_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + BTC_TRACE(trace_buf); + } else if ((bt_info & BT_INFO_8812A_2ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8812A_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8812A_2ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info & BT_INFO_8812A_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8812A_2ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + BTC_TRACE(trace_buf); + } else { + coex_dm->bt_status = BT_8812A_2ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + BTC_TRACE(trace_buf); + } + + if ((BT_8812A_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8812A_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8812A_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { + bt_busy = true; + if (!wifi_under_5g) + limited_dig = true; + } else { + bt_busy = false; + limited_dig = false; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + coex_dm->limited_dig = limited_dig; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + + halbtc8812a2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8812a2ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8812a2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_CPL_AUX, false, + true); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Halt notify, force set BT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + + halbtc8812a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + ex_halbtc8812a2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + /* 0x522=0xff, pause tx */ + btcoexist->btc_write_1byte(btcoexist, 0x522, 0xff); + /* 0x40[7:6]=2'b01, modify BT mode. */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0xc0, 0x2); + /* PTA off. */ +#ifndef CONFIG_PCI_HCI + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x0); +#endif +} + +void ex_halbtc8812a2ant_periodical(IN struct btc_coexist *btcoexist) +{ + static u8 dis_ver_info_cnt = 0; + u32 fw_ver = 0, bt_patch_ver = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ==========================Periodical===========================\n"); + BTC_TRACE(trace_buf); + + if (dis_ver_info_cnt <= 5) { + dis_ver_info_cnt += 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ****************************************************************\n"); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Ant PG Num/ Ant Mech/ Ant Pos = %d/ %d/ %d\n", + board_info->pg_ant_num, board_info->btdm_ant_num, + board_info->btdm_ant_pos); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT stack/ hci ext ver = %s / %d\n", + ((stack_info->profile_notified) ? "Yes" : "No"), + stack_info->hci_version); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, + &bt_patch_ver); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexVer/ FwVer/ PatchVer = %d_%x/ 0x%x/ 0x%x(%d)\n", + glcoex_ver_date_8812a_2ant, glcoex_ver_8812a_2ant, + fw_ver, bt_patch_ver, bt_patch_ver); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ****************************************************************\n"); + BTC_TRACE(trace_buf); + } + + if ((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) + coex_sta->bt_coex_supported_version = + btcoexist->btc_get_bt_coex_supported_version(btcoexist); + +#if (BT_AUTO_REPORT_ONLY_8812A_2ANT == 0) + halbtc8812a2ant_query_bt_info(btcoexist); + halbtc8812a2ant_monitor_bt_ctr(btcoexist); + halbtc8812a2ant_monitor_wifi_ctr(btcoexist); + halbtc8812a2ant_monitor_bt_enable_disable(btcoexist); +#else + halbtc8812a2ant_monitor_wifi_ctr(btcoexist); + + if (halbtc8812a2ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust || + coex_dm->auto_tdma_adjust_low_rssi) + halbtc8812a2ant_run_coexist_mechanism(btcoexist); +#endif +} + +void ex_halbtc8812a2ant_dbg_control(IN struct btc_coexist *btcoexist, + IN u8 op_code, IN u8 op_len, IN u8 *pdata) +{ + switch (op_code) { + case BTC_DBG_SET_COEX_DEC_BT_PWR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set Dec BT power\n"); + BTC_TRACE(trace_buf); + + { + u8 data_len = 4; + u8 buf[6] = {0}; + u8 dec_bt_pwr = 0, pwr_level = 0; + + if (op_len == 2) { + dec_bt_pwr = pdata[0]; + pwr_level = pdata[1]; + + buf[0] = data_len; + buf[1] = 0x3; /* OP_Code */ + buf[2] = 0x2; /* OP_Code_Length */ + + buf[3] = dec_bt_pwr; /* OP_Code_Content */ + buf[4] = pwr_level; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set Dec BT power=%d, pwr_level=%d\n", + dec_bt_pwr, pwr_level); + BTC_TRACE(trace_buf); + + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_CTRL_BT_COEX, + (void *)&buf[0]); + } + } + break; + + case BTC_DBG_SET_COEX_BT_AFH_MAP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set BT AFH Map\n"); + BTC_TRACE(trace_buf); + { + u8 data_len = 5; + u8 buf[6] = {0}; + + if (op_len == 3) { + buf[0] = data_len; + buf[1] = 0x5; /* OP_Code */ + buf[2] = 0x3; /* OP_Code_Length */ + + buf[3] = pdata[0]; /* OP_Code_Content */ + buf[4] = pdata[1]; + buf[5] = pdata[2]; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set BT AFH Map = %02x %02x %02x\n", + pdata[0], pdata[1], pdata[2]); + BTC_TRACE(trace_buf); + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_CTRL_BT_COEX, + (void *)&buf[0]); + } + } + break; + + case BTC_DBG_SET_COEX_BT_IGNORE_WLAN_ACT: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set BT Ignore Wlan Active\n"); + BTC_TRACE(trace_buf); + { + u8 data_len = 3; + u8 buf[6] = {0}; + + if (op_len == 1) { + buf[0] = data_len; + buf[1] = 0x1; /* OP_Code */ + buf[2] = 0x1; /* OP_Code_Length */ + + buf[3] = pdata[0]; /* OP_Code_Content */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set BT Ignore Wlan Active = 0x%x\n", + pdata[0]); + BTC_TRACE(trace_buf); + + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_CTRL_BT_COEX, + (void *)&buf[0]); + } + } + break; + + default: + break; + } +} + +#endif + +#endif /* #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) */ + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a2ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a2ant.h new file mode 100644 index 0000000..fa19aaf --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8812a2ant.h @@ -0,0 +1,227 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8812A_SUPPORT == 1) + +/* ******************************************* + * The following is for 8812A 2Ant BT Co-exist definition + * ******************************************* */ +#define BT_AUTO_REPORT_ONLY_8812A_2ANT 0 + +#define BT_INFO_8812A_2ANT_B_FTP BIT(7) +#define BT_INFO_8812A_2ANT_B_A2DP BIT(6) +#define BT_INFO_8812A_2ANT_B_HID BIT(5) +#define BT_INFO_8812A_2ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8812A_2ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8812A_2ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8812A_2ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8812A_2ANT_B_CONNECTION BIT(0) + +#define BT_INFO_8812A_2ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT(0))) ? true : false) + +#define BTC_RSSI_COEX_THRESH_TOL_8812A_2ANT 2 +#define NOISY_AP_NUM_THRESH_8812A 50 + +enum bt_info_src_8812a_2ant { + BT_INFO_SRC_8812A_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8812A_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8812A_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8812A_2ANT_MAX +}; + +enum bt_8812a_2ant_bt_status { + BT_8812A_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8812A_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8812A_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8812A_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8812A_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8812A_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8812A_2ANT_BT_STATUS_MAX +}; + +enum bt_8812a_2ant_coex_algo { + BT_8812A_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8812A_2ANT_COEX_ALGO_SCO = 0x1, + BT_8812A_2ANT_COEX_ALGO_SCO_HID = 0x2, + BT_8812A_2ANT_COEX_ALGO_HID = 0x3, + BT_8812A_2ANT_COEX_ALGO_A2DP = 0x4, + BT_8812A_2ANT_COEX_ALGO_A2DP_PANHS = 0x5, + BT_8812A_2ANT_COEX_ALGO_PANEDR = 0x6, + BT_8812A_2ANT_COEX_ALGO_PANHS = 0x7, + BT_8812A_2ANT_COEX_ALGO_PANEDR_A2DP = 0x8, + BT_8812A_2ANT_COEX_ALGO_PANEDR_HID = 0x9, + BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0xa, + BT_8812A_2ANT_COEX_ALGO_HID_A2DP_PANHS = 0xb, + BT_8812A_2ANT_COEX_ALGO_HID_A2DP = 0xc, + BT_8812A_2ANT_COEX_ALGO_MAX = 0xd +}; + +struct coex_dm_8812a_2ant { + /* fw mechanism */ + u8 pre_bt_dec_pwr_lvl; + u8 cur_bt_dec_pwr_lvl; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean auto_tdma_adjust; + boolean auto_tdma_adjust_low_rssi; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + /* sw mechanism */ + boolean pre_rf_rx_lpf_shrink; + boolean cur_rf_rx_lpf_shrink; + u32 bt_rf_0x1e_backup; + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + boolean pre_dac_swing_on; + u32 pre_dac_swing_lvl; + boolean cur_dac_swing_on; + u32 cur_dac_swing_lvl; + boolean pre_adc_back_off; + boolean cur_adc_back_off; + boolean pre_agc_table_en; + boolean cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + boolean limited_dig; + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u32 pre_ra_mask; + u32 cur_ra_mask; + u8 cur_ra_mask_type; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; + + boolean cur_enable_pta; + boolean pre_enable_pta; +}; + +struct coex_sta_8812a_2ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + boolean acl_busy; + + boolean under_lps; + boolean under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + boolean c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8812A_2ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8812A_2ANT_MAX]; + u32 bt_info_query_cnt; + boolean c2h_bt_inquiry_page; + u8 bt_retry_cnt; + u8 bt_info_ext; + u8 scan_ap_num; + boolean pre_bt_disabled; + u32 pre_bt_info_c2h_cnt_bt_rsp; + u32 pre_bt_info_c2h_cnt_bt_send; + boolean force_lps_on; + u32 bt_coex_supported_version; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_vht; +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8812a2ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8812a2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8812a2ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8812a2ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8812a2ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8812a2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8812a2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8812a2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8812a2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8812a2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8812a2ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); + +void ex_halbtc8812a2ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8812a2ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8812a2ant_display_coex_info(IN struct btc_coexist *btcoexist); +void ex_halbtc8812a2ant_dbg_control(IN struct btc_coexist *btcoexist, + IN u8 op_code, IN u8 op_len, IN u8 *pdata); +void ex_halbtc8812a2ant_pta_off_on_notify(IN struct btc_coexist *btcoexist, + IN u8 bt_status); + +#else +#define ex_halbtc8812a2ant_power_on_setting(btcoexist) +#define ex_halbtc8812a2ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8812a2ant_init_coex_dm(btcoexist) +#define ex_halbtc8812a2ant_ips_notify(btcoexist, type) +#define ex_halbtc8812a2ant_lps_notify(btcoexist, type) +#define ex_halbtc8812a2ant_scan_notify(btcoexist, type) +#define ex_halbtc8812a2ant_connect_notify(btcoexist, type) +#define ex_halbtc8812a2ant_media_status_notify(btcoexist, type) +#define ex_halbtc8812a2ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8812a2ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8812a2ant_rf_status_notify(btcoexist, type) +#define ex_halbtc8812a2ant_halt_notify(btcoexist) +#define ex_halbtc8812a2ant_periodical(btcoexist) +#define ex_halbtc8812a2ant_display_coex_info(btcoexist) +#define ex_halbtc8812a2ant_dbg_control(btcoexist, op_code, op_len, pdata) +#define ex_halbtc8812a2ant_pta_off_on_notify(btcoexist, bt_status) + +#endif + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a1ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a1ant.c new file mode 100644 index 0000000..bba78ae --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a1ant.c @@ -0,0 +1,3289 @@ +/* ************************************************************ + * Description: + * + * This file is for 8821A_1ANT Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ + * SY modify 2015/04/27 + * ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8821A_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8821a_1ant glcoex_dm_8821a_1ant; +static struct coex_dm_8821a_1ant *coex_dm = &glcoex_dm_8821a_1ant; +static struct coex_sta_8821a_1ant glcoex_sta_8821a_1ant; +static struct coex_sta_8821a_1ant *coex_sta = &glcoex_sta_8821a_1ant; + +const char *const glbt_info_src_8821a_1ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u32 glcoex_ver_date_8821a_1ant = 20160816; +u32 glcoex_ver_8821a_1ant = 0x63; +u32 glcoex_ver_btdesired_8821a_1ant = 0x62; + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8821a1ant_ + * ************************************************************ */ +u8 halbtc8821a1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8821a1ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 index, IN u8 level_num, IN u8 rssi_thresh, IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8821a1ant_update_ra_mask(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 dis_rate_mask) +{ + coex_dm->cur_ra_mask = dis_rate_mask; + + if (force_exec || (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_RAMASK, + &coex_dm->cur_ra_mask); + coex_dm->pre_ra_mask = coex_dm->cur_ra_mask; +} + +void halbtc8821a1ant_auto_rate_fallback_retry(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + boolean wifi_under_b_mode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + if (wifi_under_b_mode) { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +void halbtc8821a1ant_retry_limit(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || + (coex_dm->pre_retry_limit_type != + coex_dm->cur_retry_limit_type)) { + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +void halbtc8821a1ant_ampdu_max_time(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || + (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +void halbtc8821a1ant_limited_tx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ra_mask_type, IN u8 arfr_type, + IN u8 retry_limit_type, IN u8 ampdu_time_type) +{ + switch (ra_mask_type) { + case 0: /* normal mode */ + halbtc8821a1ant_update_ra_mask(btcoexist, force_exec, + 0x0); + break; + case 1: /* disable cck 1/2 */ + halbtc8821a1ant_update_ra_mask(btcoexist, force_exec, + 0x00000003); + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ + halbtc8821a1ant_update_ra_mask(btcoexist, force_exec, + 0x0001f1f7); + break; + default: + break; + } + + halbtc8821a1ant_auto_rate_fallback_retry(btcoexist, force_exec, + arfr_type); + halbtc8821a1ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8821a1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type); +} + + +/* true/xxxx/x:1 + * false/false/x: 64 + * false/true/x:x */ +void halbtc8821a1ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +void halbtc8821a1ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; +#if 0 + /* to avoid 0x76e[3] = 1 (WLAN_Act control by PTA) during IPS */ + if (!(btcoexist->btc_read_1byte(btcoexist, 0x76e) & 0x8)) { + coex_sta->high_priority_tx = 65535; + coex_sta->high_priority_rx = 65535; + coex_sta->low_priority_tx = 65535; + coex_sta->low_priority_rx = 65535; + return; + } +#endif + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +void halbtc8821a1ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ +#if 1 + + coex_sta->crc_ok_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_CCK); + coex_sta->crc_ok_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_LEGACY); + coex_sta->crc_ok_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_HT); + coex_sta->crc_ok_11n_vht = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_VHT); + + coex_sta->crc_err_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_CCK); + coex_sta->crc_err_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_LEGACY); + coex_sta->crc_err_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_HT); + coex_sta->crc_err_11n_vht = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_VHT); + +#endif +} + + +void halbtc8821a1ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +boolean halbtc8821a1ant_is_wifi_status_changed(IN struct btc_coexist *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + } + + return false; +} + +void halbtc8821a1ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + +u8 halbtc8821a1ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8821A_1ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_1ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_1ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_1ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +void halbtc8821a1ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8821a1ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8821a1ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8821a1ant_set_sw_penalty_tx_rate_adaptive(IN struct btc_coexist + *btcoexist, IN boolean low_penalty_ra) +{ + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* op_code, 0x6= Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT(0); + h2c_parameter[2] = + 0x00; /* normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[3] = 0xf5; /* MCS7 or OFDM54 */ + h2c_parameter[4] = 0xa0; /* MCS6 or OFDM48 */ + h2c_parameter[5] = 0xa0; /* MCS5 or OFDM36 */ + } + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +void halbtc8821a1ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + halbtc8821a1ant_set_sw_penalty_tx_rate_adaptive(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +void halbtc8821a1ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8821a1ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8821a1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8821a1ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** CoexTable(%d) **********\n", type); + BTC_TRACE(trace_buf); + + switch (type) { + case 0: + halbtc8821a1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x55555555, 0xffffff, 0x3); + break; + case 1: + halbtc8821a1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 2: + halbtc8821a1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 3: + halbtc8821a1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 4: + halbtc8821a1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 5: + halbtc8821a1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0xaaaa5a5a, 0xffffff, 0x3); + break; + case 6: + halbtc8821a1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaa5a5a, 0xffffff, 0x3); + break; + case 7: + halbtc8821a1ant_coex_table(btcoexist, force_exec, + 0xaaaaaaaa, 0xaaaaaaaa, 0xffffff, 0x3); + break; + default: + break; + } +} + +void halbtc8821a1ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT(0); /* function enable */ + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8821a1ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8821a1ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8821a1ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], FW for 1Ant AP mode\n"); + BTC_TRACE(trace_buf); + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + } + } + + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +void halbtc8821a1ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8821a1ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8821a1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8821a1ant_sw_mechanism(IN struct btc_coexist *btcoexist, + IN boolean low_penalty_ra) +{ + halbtc8821a1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +void halbtc8821a1ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean init_hwcfg, IN boolean wifi_off) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 u32tmp = 0; + u8 h2c_parameter[2] = {0}; + + if (init_hwcfg) { + /* 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT(23); + u32tmp |= BIT(24); + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + + /* 0x765 = 0x18 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3); + + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { + /* tell firmware "antenna inverse" ==> WRONG firmware antenna control code.==>need fw to fix */ + h2c_parameter[0] = 1; + h2c_parameter[1] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + + /* btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, 0x1); */ /*Main Ant to BT for IPS case 0x4c[23]=1 */ + } else { + /* tell firmware "no antenna inverse" ==> WRONG firmware antenna control code.==>need fw to fix */ + h2c_parameter[0] = 0; + h2c_parameter[1] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + + /* btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, 0x0); */ /*Aux Ant to BT for IPS case 0x4c[23]=1 */ + } + } else if (wifi_off) { + /* 0x4c[24:23]=00, Set Antenna control by BT_RFE_CTRL BT Vendor 0xac=0xf002 */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT(23); + u32tmp &= ~BIT(24); + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + + /* 0x765 = 0x18 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x3); + } else { + /* 0x765 = 0x0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x765, 0x18, 0x0); + } + + /* ext switch setting */ + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77); + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0xcb7, 0x30, 0x1); + else + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0xcb7, 0x30, 0x2); + break; + case BTC_ANT_PATH_BT: + btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77); + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0xcb7, 0x30, 0x2); + else + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0xcb7, 0x30, 0x1); + break; + default: + case BTC_ANT_PATH_PTA: + btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x66); + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0xcb7, 0x30, 0x1); + else + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0xcb7, 0x30, 0x2); + break; + } +} + +void halbtc8821a1ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + u8 rssi_adjust_val = 0; + /* u32 fw_ver=0; */ + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + if (coex_dm->cur_ps_tdma_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(off, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + if (turn_on) { + switch (type) { + default: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x1a, 0x1a, 0x0, 0x50); + break; + case 1: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x3a, 0x03, 0x10, 0x50); + rssi_adjust_val = 11; + break; + case 2: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x2b, 0x03, 0x10, 0x50); + rssi_adjust_val = 14; + break; + case 3: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x1d, 0x1d, 0x0, 0x52); + break; + case 4: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, + 0x15, 0x3, 0x14, 0x0); + rssi_adjust_val = 17; + break; + case 5: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, + 0x15, 0x3, 0x11, 0x10); + break; + case 6: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, + 0x20, 0x3, 0x11, 0x13); + break; + case 7: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, + 0xc, 0x5, 0x0, 0x0); + break; + case 8: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, + 0x25, 0x3, 0x10, 0x0); + break; + case 9: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x21, 0x3, 0x10, 0x50); + rssi_adjust_val = 18; + break; + case 10: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, + 0xa, 0xa, 0x0, 0x40); + break; + case 11: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x15, 0x03, 0x10, 0x50); + rssi_adjust_val = 20; + break; + case 12: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x0a, 0x0a, 0x0, 0x50); + break; + case 13: + if (coex_sta->scan_ap_num <= 5) + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x40, 0x3, 0x10, 0x50); + else + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x12, 0x12, 0x0, 0x50); + break; + case 14: + if (coex_sta->scan_ap_num <= 5) + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x30, 0x3, 0x10, 0x50); + else + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x1e, 0x3, 0x10, 0x14); + break; + case 15: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x13, + 0xa, 0x3, 0x8, 0x0); + break; + case 16: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, + 0x15, 0x3, 0x10, 0x0); + rssi_adjust_val = 18; + break; + case 18: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x93, + 0x25, 0x3, 0x10, 0x0); + rssi_adjust_val = 14; + break; + case 20: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, + 0x35, 0x03, 0x11, 0x10); + break; + case 21: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, + 0x25, 0x03, 0x11, 0x11); + break; + case 22: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, + 0x25, 0x03, 0x11, 0x10); + break; + case 23: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 24: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, + 0x15, 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 25: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, + 0xa, 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 26: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, + 0xa, 0x3, 0x31, 0x18); + rssi_adjust_val = 22; + break; + case 27: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x3, 0x31, 0x98); + rssi_adjust_val = 22; + break; + case 28: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x69, + 0x25, 0x3, 0x31, 0x0); + break; + case 29: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xab, + 0x1a, 0x1a, 0x1, 0x10); + break; + case 30: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x30, 0x3, 0x10, 0x10); + break; + case 31: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xd3, + 0x1a, 0x1a, 0, 0x58); + break; + case 32: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x61, + 0x35, 0x3, 0x11, 0x11); + break; + case 33: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xa3, + 0x25, 0x3, 0x30, 0x90); + break; + case 34: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x53, + 0x1a, 0x1a, 0x0, 0x10); + break; + case 35: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x63, + 0x1a, 0x1a, 0x0, 0x10); + break; + case 36: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0xd3, + 0x12, 0x3, 0x14, 0x50); + break; + case 40: /* SoftAP only with no sta associated,BT disable ,TDMA mode for power saving */ + /* here softap mode screen off will cost 70-80mA for phone */ + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x23, + 0x18, 0x00, 0x10, 0x24); + break; + case 41: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x15, 0x3, 0x11, 0x11); + break; + case 42: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x20, 0x3, 0x11, 0x11); + break; + case 43: + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x51, + 0x30, 0x3, 0x10, 0x11); + break; + } + } else { + /* disable PS tdma */ + switch (type) { + case 8: /* PTA Control */ + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x8, + 0x0, 0x0, 0x0, 0x0); + halbtc8821a1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, false, false); + break; + case 0: + default: /* Software control, Antenna at BT side */ + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x0, 0x0); + halbtc8821a1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_BT, false, false); + break; + case 9: /* Software control, Antenna at WiFi side */ + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x0, 0x0); + halbtc8821a1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_WIFI, false, false); + break; + case 10: /* under 5G */ + halbtc8821a1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x8, 0x0); + halbtc8821a1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_BT, false, false); + break; + } + } + rssi_adjust_val = 0; + btcoexist->btc_set(btcoexist, + BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, &rssi_adjust_val); + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void halbtc8821a1ant_coex_all_off(IN struct btc_coexist *btcoexist) +{ + /* sw all off */ + halbtc8821a1ant_sw_mechanism(btcoexist, false); + + /* hw all off */ + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +boolean halbtc8821a1ant_is_common_action(IN struct btc_coexist *btcoexist) +{ + boolean common = false, wifi_connected = false, wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected && + BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_sw_mechanism(btcoexist, false); + + common = true; + } else if (wifi_connected && + (BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_sw_mechanism(btcoexist, false); + + common = true; + } else if (!wifi_connected && + (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_sw_mechanism(btcoexist, false); + + common = true; + } else if (wifi_connected && + (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_sw_mechanism(btcoexist, false); + + common = true; + } else if (!wifi_connected && + (BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE != + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_sw_mechanism(btcoexist, false); + + common = true; + } else { + if (wifi_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } + + common = false; + } + + return common; +} + +void halbtc8821a1ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +void halbtc8821a1ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + break; + case BTC_PS_LPS_ON: + halbtc8821a1ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8821a1ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + break; + case BTC_PS_LPS_OFF: + halbtc8821a1ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + break; + default: + break; + } +} + +void halbtc8821a1ant_coex_under_5g(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + halbtc8821a1ant_ignore_wlan_act(btcoexist, NORMAL_EXEC, true); + + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 10); + + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 5); +} + +void halbtc8821a1ant_action_wifi_only(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 9); +} + +void halbtc8821a1ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false; + + /* This function check if bt is disabled */ + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is enabled !!\n"); + BTC_TRACE(trace_buf); + } else { + bt_disable_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], bt all counters=0, %d times!!\n", + bt_disable_cnt); + BTC_TRACE(trace_buf); + if (bt_disable_cnt >= 10) { + bt_disabled = true; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_action_wifi_only(btcoexist); + } + } + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + coex_sta->bt_disabled = bt_disabled; + if (!bt_disabled) { + } else { + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + } + } +} + +/* ********************************************* + * + * Software Coex Mechanism start + * + * ********************************************* */ + +void halbtc8821a1ant_action_bt_whck_test(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + /* halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, NORMAL_EXEC, false, false); */ + halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, false, false); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} +/* SCO only or SCO+PAN(HS) */ +void halbtc8821a1ant_action_sco(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +void halbtc8821a1ant_action_hid(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +void halbtc8821a1ant_action_a2dp(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +void halbtc8821a1ant_action_a2dp_pan_hs(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +void halbtc8821a1ant_action_pan_edr(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +/* PAN(HS) only */ +void halbtc8821a1ant_action_pan_hs(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +/* PAN(EDR)+A2DP */ +void halbtc8821a1ant_action_pan_edr_a2dp(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, false); +} + +void halbtc8821a1ant_action_pan_edr_hid(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +/* HID+A2DP+PAN(EDR) */ +void halbtc8821a1ant_action_hid_a2dp_pan_edr(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +void halbtc8821a1ant_action_hid_a2dp(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_sw_mechanism(btcoexist, true); +} + +/* ********************************************* + * + * Non-Software Coex Mechanism start + * + * ********************************************* */ +void halbtc8821a1ant_action_wifi_multi_port(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8821a1ant_action_hs(IN struct btc_coexist *btcoexist) +{ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8821a1ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, ap_enable = false, wifi_busy = false, + bt_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + if ((!wifi_connected) && (!coex_sta->wifi_is_high_pri_task)) { + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } + + /* sy modify */ + else if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + /* SCO/HID/A2DP busy */ + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } + + /* sy modify */ + + else if ((bt_link_info->a2dp_exist) && + (bt_link_info->hid_exist)) { + /* A2DP+HID busy */ + halbtc8821a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 14); + + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } + + + else if ((bt_link_info->pan_exist) || (wifi_busy)) { + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + } +} + +void halbtc8821a1ant_action_bt_sco_hid_only_busy(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* tdma and coex table */ + + if (bt_link_info->sco_exist) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 41); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } else { /* HID */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 42); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8821a1ant_action_wifi_connected_bt_acl_busy(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + u8 bt_rssi_state; + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + bt_rssi_state = halbtc8821a1ant_bt_rssi_state(2, 28, 0); + + if (bt_link_info->hid_only) { /* HID */ + halbtc8821a1ant_action_bt_sco_hid_only_busy(btcoexist, + wifi_status); + coex_dm->auto_tdma_adjust = false; + return; + } else if (bt_link_info->a2dp_only) { /* A2DP */ + if (BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) { + /* halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); */ + /* halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } else if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + /* halbtc8821a1ant_tdma_duration_adjust_for_acl(btcoexist, wifi_status); */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 14); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else { /* for low BT RSSI */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 14); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } + } else if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { /* HID+A2DP */ + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 14); + coex_dm->auto_tdma_adjust = false; + } else { /* for low BT RSSI */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 14); + coex_dm->auto_tdma_adjust = false; + } + + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else if ((bt_link_info->pan_only) || (bt_link_info->hid_exist && + bt_link_info->pan_exist)) { /* PAN(OPP,FTP), HID+PAN(OPP,FTP) */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 3); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + coex_dm->auto_tdma_adjust = false; + } else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { /* A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP) */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 43); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } else { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + coex_dm->auto_tdma_adjust = false; + } +} + +void halbtc8821a1ant_action_wifi_not_connected(IN struct btc_coexist *btcoexist) +{ + /* power save state */ + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8821a1ant_action_wifi_not_connected_scan(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist) { + /* sy modify */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 14); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8821a1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + /* halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); */ + /* halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); */ + + /* Bryant Add */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8821a1ant_action_wifi_not_connected_asso_auth( + IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist)) { + /* sy modify */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + } else if ((bt_link_info->a2dp_exist) || (bt_link_info->pan_exist)) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8821a1ant_action_wifi_connected_scan(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist) { + /* sy modify */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 14); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8821a1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + /* halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); */ + /* halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); */ + + /* Bryant Add */ + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8821a1ant_action_wifi_connected_specific_packet( + IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + /* tdma and coex table */ + /* sy modify */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } + + if ((bt_link_info->hid_exist) && (bt_link_info->a2dp_exist)) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 14); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } + + + else if (bt_link_info->pan_exist) { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8821a1ant_action_wifi_connected(IN struct btc_coexist *btcoexist) +{ + boolean wifi_busy = false; + boolean scan = false, link = false, roam = false; + boolean under_4way = false, ap_enable = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect()===>\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (under_4way) { + halbtc8821a1ant_action_wifi_connected_specific_packet( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + if (scan || link || roam) { + if (scan) + halbtc8821a1ant_action_wifi_connected_scan(btcoexist); + else + halbtc8821a1ant_action_wifi_connected_specific_packet( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + /* power save state */ + if (!ap_enable && + BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status && + !btcoexist->bt_link_info.hid_only) { + if (!wifi_busy && btcoexist->bt_link_info.a2dp_only) /* A2DP */ + halbtc8821a1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + else + halbtc8821a1ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, 0x4); + } else + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + /* tdma and coex table */ + if (!wifi_busy) { + if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8821a1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8821a1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + } + } else { + if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8821a1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else if ((BT_8821A_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8821a1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else { + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + halbtc8821a1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + } + } +} + +void halbtc8821a1ant_run_sw_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + algorithm = halbtc8821a1ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + + if (halbtc8821a1ant_is_common_action(btcoexist)) { + + } else { + switch (coex_dm->cur_algorithm) { + case BT_8821A_1ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_action_sco(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID.\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_action_hid(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_action_a2dp(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_action_pan_edr(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HS mode.\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_action_pan_hs(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_action_pan_edr_hid(btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_action_hid_a2dp_pan_edr( + btcoexist); + break; + case BT_8821A_1ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_action_hid_a2dp(btcoexist); + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = coexist All Off!!\n"); + BTC_TRACE(trace_buf); + /* halbtc8821a1ant_coex_all_off(btcoexist); */ + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +void halbtc8821a1ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + boolean increase_scan_dev_num = false; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean wifi_under_5g = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_coex_under_5g(btcoexist); + return; + } + if (coex_sta->bt_whck_test) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under WHCK TEST!!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_action_bt_whck_test(btcoexist); + return; + } + + if ((BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + increase_scan_dev_num = true; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, + &increase_scan_dev_num); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8821a1ant_action_wifi_multi_port(btcoexist); + return; + } + + if (!bt_link_info->sco_exist && !bt_link_info->hid_exist) + halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + else { + if (wifi_connected) { + wifi_rssi_state = halbtc8821a1ant_wifi_rssi_state( + btcoexist, 1, 2, 30, 0); + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + /* halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, 1, 1); */ + halbtc8821a1ant_limited_tx(btcoexist, + NORMAL_EXEC, 1, 1, 0, 1); + } else { + /* halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, 1, 1); */ + halbtc8821a1ant_limited_tx(btcoexist, + NORMAL_EXEC, 1, 1, 0, 1); + } + } else + halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, + 0, 0); + + } + + if (bt_link_info->sco_exist) { + bt_ctrl_agg_buf_size = true; + agg_buf_size = 0x3; + } else if (bt_link_info->hid_exist) { + bt_ctrl_agg_buf_size = true; + agg_buf_size = 0x5; + } else if (bt_link_info->a2dp_exist || bt_link_info->pan_exist) { + bt_ctrl_agg_buf_size = true; + agg_buf_size = 0x8; + } + halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + halbtc8821a1ant_run_sw_coexist_mechanism(btcoexist); + + /* low pelnaty ra in pcr ra */ + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 25); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8821a1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821a1ant_action_hs(btcoexist); + return; + } + + + if (!wifi_connected) { + boolean scan = false, link = false, roam = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is non connected-idle !!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + if (scan) + halbtc8821a1ant_action_wifi_not_connected_scan( + btcoexist); + else + halbtc8821a1ant_action_wifi_not_connected_asso_auth( + btcoexist); + } else + halbtc8821a1ant_action_wifi_not_connected(btcoexist); + } else /* wifi LPS/Busy */ + halbtc8821a1ant_action_wifi_connected(btcoexist); +} + +void halbtc8821a1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + /* sw all off */ + halbtc8821a1ant_sw_mechanism(btcoexist, false); + + /* halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); */ + halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); +} + +void halbtc8821a1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean back_up, IN boolean wifi_only) +{ + u8 u8tmp = 0; + boolean wifi_under_5g = false; + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 1Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + + if (wifi_only) + return; + + if (back_up) { + coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, + 0x430); + coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, + 0x434); + coex_dm->backup_retry_limit = btcoexist->btc_read_2byte( + btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = btcoexist->btc_read_1byte( + btcoexist, 0x456); + } + + /* 0x790[5:0]=0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + /* Give bt_coex_supported_version the default value */ + coex_sta->bt_coex_supported_version = 0; + + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = (btcoexist->btc_read_1byte(btcoexist, + 0xf1) & 0xf0) >> 4; + + /* Antenna config */ + if (wifi_under_5g) + halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, true, + false); + else + halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_PTA, true, + false); + + /* PTA parameter */ + halbtc8821a1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + /* Enable counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, + 0xc); /* 0x76e[3] =1, WLAN_Act control by PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); +} + +/* ************************************************************ + * work around function start with wa_halbtc8821a1ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8821a1ant_ + * ************************************************************ */ +void ex_halbtc8821a1ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ +} + +void ex_halbtc8821a1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8821a1ant_init_hw_config(btcoexist, true, wifi_only); +} + +void ex_halbtc8821a1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = false; + + halbtc8821a1ant_init_coex_dm(btcoexist); + + halbtc8821a1ant_query_bt_info(btcoexist); +} + +void ex_halbtc8821a1ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u16 u16tmp[4]; + u32 u32tmp[4]; + u32 fw_ver = 0, bt_patch_ver = 0; + u32 bt_coex_ver = 0; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + u32 phyver = 0; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + if (btcoexist->stop_coex_dm) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + "Ant PG Num/ Ant Mech/ Ant Pos:", + board_info->pg_ant_num, board_info->btdm_ant_num, + board_info->btdm_ant_pos); + CL_PRINTF(cli_buf); + + /* btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); */ + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + bt_coex_ver = ((coex_sta->bt_coex_supported_version & 0xff00) >> 8); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8821a_1ant, glcoex_ver_8821a_1ant, + glcoex_ver_btdesired_8821a_1ant, + bt_coex_ver, + (bt_coex_ver == 0xff ? "Unknown" : + (bt_coex_ver >= glcoex_ver_btdesired_8821a_1ant ? + "Match" : "Mis-Match"))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ v%d/ %c", + "W_FW/ B_FW/ Phy/ Kt", + fw_ver, bt_patch_ver, phyver, + coex_sta->cut_version + 65); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "Wifi channel informed to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d] ", + "BT [status/ rssi/ retryCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") + : ((BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi, coex_sta->bt_retry_cnt); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + "SCO/HID/PAN/A2DP", + bt_link_info->sco_exist, bt_link_info->hid_exist, + bt_link_info->pan_exist, bt_link_info->a2dp_exist); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_BT_LINK_INFO); + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext & BIT(0)) ? "Basic rate" : "EDR rate"); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8821A_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8821a_1ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + if (!btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "SM[LowPenaltyRA]", + coex_dm->cur_low_penalty_ra); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanisms]============"); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", + "PS TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + coex_dm->auto_tdma_adjust); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", + "IgnWlanAct", + coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x ", + "Latest error condition(should be 0)", + coex_dm->error_condition); + CL_PRINTF(cli_buf); + } + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "backup ARFR1/ARFR2/RL/AMaxTime", + coex_dm->backup_arfr_cnt1, coex_dm->backup_arfr_cnt2, + coex_dm->backup_retry_limit, + coex_dm->backup_ampdu_max_time); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc58); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x778/ 0xc58[29:25]", + u8tmp[0], (u32tmp[0] & 0x3e000000) >> 25); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x8db); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x8db[6:5]", + ((u8tmp[0] & 0x60) >> 5)); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x975); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0xcb4[29:28]/0xcb4[7:0]/0x974[9:8]", + (u32tmp[0] & 0x30000000) >> 28, u32tmp[0] & 0xff, + u8tmp[0] & 0x3); + CL_PRINTF(cli_buf); + + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x64); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x40/0x4c[24:23]/0x64[0]", + u8tmp[0], ((u32tmp[0] & 0x01800000) >> 23), u8tmp[1] & 0x1); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", + u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", + u32tmp[0] & 0xff); + CL_PRINTF(cli_buf); + + fa_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_OFDM); + fa_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_CCK); + cca_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_OFDM); + cca_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_CCK); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", + cca_cck, fa_cck, cca_ofdm, fa_ofdm); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11n-agg", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11n-agg", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + CL_PRINTF(cli_buf); + + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(high-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(low-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 1) + halbtc8821a1ant_monitor_bt_ctr(btcoexist); +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8821a1ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + boolean wifi_under_5g = false; + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, + &wifi_under_5g); + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_coex_under_5g(btcoexist); + return; + } + + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, + true); + /* halbtc8821a1ant_set_ant_path_d_cut(btcoexist, false, false, false, BTC_ANT_PATH_BT, BTC_WIFI_STAT_NORMAL_OFF); */ + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = false; + + halbtc8821a1ant_init_hw_config(btcoexist, false, false); + halbtc8821a1ant_init_coex_dm(btcoexist); + halbtc8821a1ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8821a1ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + + + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8821a1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + boolean wifi_under_5g = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_coex_under_5g(btcoexist); + return; + } + + if (BTC_SCAN_START == type) { + coex_sta->wifi_is_high_pri_task = true; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + + halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 8); /* Force antenna setup for no scan result issue */ + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify\n"); + BTC_TRACE(trace_buf); + } + + if (coex_sta->bt_disabled) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + halbtc8821a1ant_query_bt_info(btcoexist); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8821a1ant_action_wifi_multi_port(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8821a1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821a1ant_action_hs(btcoexist); + return; + } + + if (BTC_SCAN_START == type) { + if (!wifi_connected) /* non-connected scan */ + halbtc8821a1ant_action_wifi_not_connected_scan( + btcoexist); + else /* wifi is connected */ + halbtc8821a1ant_action_wifi_connected_scan(btcoexist); + } else if (BTC_SCAN_FINISH == type) { + if (!wifi_connected) /* non-connected scan */ + halbtc8821a1ant_action_wifi_not_connected(btcoexist); + else + halbtc8821a1ant_action_wifi_connected(btcoexist); + } +} + +/* copy scan notify content to switch band notify */ +void ex_halbtc8821a1ant_switchband_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + boolean wifi_under_5g = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_coex_under_5g(btcoexist); + return; + } + + if (BTC_SCAN_START == type) { + coex_sta->wifi_is_high_pri_task = true; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + + halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, + 8); /* Force antenna setup for no scan result issue */ + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify\n"); + BTC_TRACE(trace_buf); + } + + if (coex_sta->bt_disabled) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + halbtc8821a1ant_query_bt_info(btcoexist); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8821a1ant_action_wifi_multi_port(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8821a1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821a1ant_action_hs(btcoexist); + return; + } + + if (BTC_SCAN_START == type) { + if (!wifi_connected) /* non-connected scan */ + halbtc8821a1ant_action_wifi_not_connected_scan( + btcoexist); + else /* wifi is connected */ + halbtc8821a1ant_action_wifi_connected_scan(btcoexist); + } else if (BTC_SCAN_FINISH == type) { + if (!wifi_connected) /* non-connected scan */ + halbtc8821a1ant_action_wifi_not_connected(btcoexist); + else + halbtc8821a1ant_action_wifi_connected(btcoexist); + } +} +void ex_halbtc8821a1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + boolean wifi_under_5g = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + coex_sta->bt_disabled) + return; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_coex_under_5g(btcoexist); + return; + } + + if (BTC_ASSOCIATE_START == type) { + coex_sta->wifi_is_high_pri_task = true; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify\n"); + BTC_TRACE(trace_buf); + coex_dm->arp_cnt = 0; + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify\n"); + BTC_TRACE(trace_buf); + coex_dm->arp_cnt = 0; + } + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8821a1ant_action_wifi_multi_port(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8821a1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821a1ant_action_hs(btcoexist); + return; + } + + if (BTC_ASSOCIATE_START == type) + halbtc8821a1ant_action_wifi_not_connected_asso_auth(btcoexist); + else if (BTC_ASSOCIATE_FINISH == type) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (!wifi_connected) /* non-connected scan */ + halbtc8821a1ant_action_wifi_not_connected(btcoexist); + else + halbtc8821a1ant_action_wifi_connected(btcoexist); + } +} + +void ex_halbtc8821a1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + boolean wifi_under_5g = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + coex_sta->bt_disabled) + return; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_coex_under_5g(btcoexist); + return; + } + + if (BTC_MEDIA_CONNECT == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + coex_dm->arp_cnt = 0; + } + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + /* h2c_parameter[0] = 0x1; */ + h2c_parameter[0] = 0x0; + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8821a1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + boolean wifi_under_5g = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm || + coex_sta->bt_disabled) + return; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_coex_under_5g(btcoexist); + return; + } + + if (BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type || + BTC_PACKET_ARP == type) { + coex_sta->wifi_is_high_pri_task = true; + + if (BTC_PACKET_ARP == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ARP notify\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet DHCP or EAPOL notify\n"); + BTC_TRACE(trace_buf); + } + } else { + coex_sta->wifi_is_high_pri_task = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet [Type = %d] notify\n", type); + BTC_TRACE(trace_buf); + } + + coex_sta->specific_pkt_period_cnt = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + if (num_of_wifi_link >= 2) { + halbtc8821a1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8821a1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + halbtc8821a1ant_action_wifi_multi_port(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8821a1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821a1ant_action_hs(btcoexist); + return; + } + + if (BTC_PACKET_DHCP == type || + BTC_PACKET_EAPOL == type || + BTC_PACKET_ARP == type) { + if (BTC_PACKET_ARP == type) { + coex_dm->arp_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ARP Packet Count = %d\n", + coex_dm->arp_cnt); + BTC_TRACE(trace_buf); + if (coex_dm->arp_cnt >= + 10) /* if APR PKT > 10 after connect, do not go to ActionWifiConnectedSpecificPacket(btcoexist) */ + return; + } + + halbtc8821a1ant_action_wifi_connected_specific_packet( + btcoexist); + } +} + +void ex_halbtc8821a1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + boolean wifi_connected = false; + boolean bt_busy = false; + boolean wifi_under_5g = false; + + + coex_sta->c2h_bt_info_req_sent = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8821A_1ANT_MAX) + rsp_source = BT_INFO_SRC_8821A_1ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt info[%d], length=%d, hex data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + /* if 0xff, it means BT is under WHCK test */ + if (bt_info == 0xff) + coex_sta->bt_whck_test = true; + else + coex_sta->bt_whck_test = false; + + if (BT_INFO_SRC_8821A_1ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0] */ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + if (coex_sta->bt_info_c2h[rsp_source][2] & 0x20) + coex_sta->c2h_bt_page = true; + else + coex_sta->c2h_bt_page = false; + + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rsp_source][4]; + + coex_sta->bt_tx_rx_mask = (coex_sta->bt_info_c2h[rsp_source][2] + & 0x40); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TX_RX_MASK, + &coex_sta->bt_tx_rx_mask); + if (!coex_sta->bt_tx_rx_mask) { + /* BT into is responded by BT FW and BT RF REG 0x3C != 0x15 => Need to switch BT TRx Mask */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x15\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x3c, 0x15); + } + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + if (coex_sta->bt_info_ext & BIT(1)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) + ex_halbtc8821a1ant_media_status_notify( + btcoexist, BTC_MEDIA_CONNECT); + else + ex_halbtc8821a1ant_media_status_notify( + btcoexist, BTC_MEDIA_DISCONNECT); + } + + if ((coex_sta->bt_info_ext & BIT(3)) && !wifi_under_5g) { + if (!btcoexist->manual_control && + !btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, false); + } + } else { + /* BT already NOT ignore Wlan active, do nothing here. */ + } +#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0) + if ((coex_sta->bt_info_ext & BIT(4))) { + /* BT auto report already enabled, do nothing */ + } else + halbtc8821a1ant_bt_auto_report(btcoexist, FORCE_EXEC, + true); +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (bt_info & BT_INFO_8821A_1ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status */ + if (!(bt_info & BT_INFO_8821A_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8821A_1ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8821A_1ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8821A_1ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8821A_1ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + } + + halbtc8821a1ant_update_bt_link_info(btcoexist); + + bt_info = bt_info & + 0x1f; /* mask profile bit for connect-ilde identification ( for CSR case: A2DP idle --> 0x41) */ + + if (!(bt_info & BT_INFO_8821A_1ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info == + BT_INFO_8821A_1ANT_B_CONNECTION) { /* connection exists but no busy */ + coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + BTC_TRACE(trace_buf); + } else if ((bt_info & BT_INFO_8821A_1ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8821A_1ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info & BT_INFO_8821A_1ANT_B_ACL_BUSY) { + if (BT_8821A_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status) + coex_dm->auto_tdma_adjust = false; + coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + BTC_TRACE(trace_buf); + } else { + coex_dm->bt_status = BT_8821A_1ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + BTC_TRACE(trace_buf); + } + + if ((BT_8821A_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8821A_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + halbtc8821a1ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8821a1ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + boolean wifi_under_5g = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_coex_under_5g(btcoexist); + return; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + halbtc8821a1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, true); + /* halbtc8821a1ant_set_ant_path_d_cut(btcoexist, false, false, false, BTC_ANT_PATH_BT, BTC_WIFI_STAT_NORMAL_OFF); */ + + halbtc8821a1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + ex_halbtc8821a1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + btcoexist->stop_coex_dm = true; +} + +void ex_halbtc8821a1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + boolean wifi_under_5g = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for 5G <===\n"); + BTC_TRACE(trace_buf); + halbtc8821a1ant_coex_under_5g(btcoexist); + return; + } + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Pnp notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_WIFI_PNP_SLEEP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + + halbtc8821a1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8821a1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8821a1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + halbtc8821a1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, false, + true); + /* halbtc8821a1ant_set_ant_path_d_cut(btcoexist, false, false, false, BTC_ANT_PATH_BT, BTC_WIFI_STAT_NORMAL_OFF); */ + + /* Sinda 20150819, workaround for driver skip leave IPS/LPS to speed up sleep time. */ + /* Driver do not leave IPS/LPS when driver is going to sleep, so BTCoexistence think wifi is still under IPS/LPS */ + /* BT should clear UnderIPS/UnderLPS state to avoid mismatch state after wakeup. */ + coex_sta->under_ips = false; + coex_sta->under_lps = false; + btcoexist->stop_coex_dm = true; + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + btcoexist->stop_coex_dm = false; + halbtc8821a1ant_init_hw_config(btcoexist, false, false); + halbtc8821a1ant_init_coex_dm(btcoexist); + halbtc8821a1ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8821a1ant_periodical(IN struct btc_coexist *btcoexist) +{ + + if (((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) && + (!coex_sta->bt_disabled)) + coex_sta->bt_coex_supported_version = + btcoexist->btc_get_bt_coex_supported_version(btcoexist); + +#if (BT_AUTO_REPORT_ONLY_8821A_1ANT == 0) + halbtc8821a1ant_query_bt_info(btcoexist); + halbtc8821a1ant_monitor_bt_enable_disable(btcoexist); +#else + halbtc8821a1ant_monitor_bt_ctr(btcoexist); + halbtc8821a1ant_monitor_wifi_ctr(btcoexist); + halbtc8821a1ant_monitor_bt_enable_disable(btcoexist); + if (halbtc8821a1ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) { + /* if(coex_sta->specific_pkt_period_cnt > 2) */ + /* { */ + halbtc8821a1ant_run_coexist_mechanism(btcoexist); + /* } */ + } + + coex_sta->specific_pkt_period_cnt++; +#endif +} + +#endif + +#endif /* #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) */ + + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a1ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a1ant.h new file mode 100644 index 0000000..53a5313 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a1ant.h @@ -0,0 +1,214 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8821A_SUPPORT == 1) + +/* ******************************************* + * The following is for 8821A 1ANT BT Co-exist definition + * ******************************************* */ +#define BT_AUTO_REPORT_ONLY_8821A_1ANT 1 + +#define BT_INFO_8821A_1ANT_B_FTP BIT(7) +#define BT_INFO_8821A_1ANT_B_A2DP BIT(6) +#define BT_INFO_8821A_1ANT_B_HID BIT(5) +#define BT_INFO_8821A_1ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8821A_1ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8821A_1ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8821A_1ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8821A_1ANT_B_CONNECTION BIT(0) + +#define BT_INFO_8821A_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT(0))) ? true : false) + +#define BTC_RSSI_COEX_THRESH_TOL_8821A_1ANT 2 + +enum bt_info_src_8821a_1ant { + BT_INFO_SRC_8821A_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8821A_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8821A_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8821A_1ANT_MAX +}; + +enum bt_8821a_1ant_bt_status { + BT_8821A_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8821A_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8821A_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8821A_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8821A_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8821A_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8821A_1ANT_BT_STATUS_MAX +}; + +enum bt_8821a_1ant_wifi_status { + BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8821A_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_SPECIFIC_PKT = 0x3, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8821A_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8821A_1ANT_WIFI_STATUS_MAX +}; + +enum bt_8821a_1ant_coex_algo { + BT_8821A_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8821A_1ANT_COEX_ALGO_SCO = 0x1, + BT_8821A_1ANT_COEX_ALGO_HID = 0x2, + BT_8821A_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8821A_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8821A_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8821A_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8821A_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8821A_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8821A_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8821A_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8821A_1ANT_COEX_ALGO_MAX = 0xb, +}; + +struct coex_dm_8821a_1ant { + /* fw mechanism */ + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean auto_tdma_adjust; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + /* sw mechanism */ + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u32 pre_ra_mask; + u32 cur_ra_mask; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; + u32 arp_cnt; + + u8 error_condition; +}; + +struct coex_sta_8821a_1ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + + boolean under_lps; + boolean under_ips; + u32 specific_pkt_period_cnt; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_vht; + + u32 bt_coex_supported_version; + u8 cut_version; + u8 bt_rssi; + u8 scan_ap_num; + boolean bt_tx_rx_mask; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + boolean c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8821A_1ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8821A_1ANT_MAX]; + boolean c2h_bt_inquiry_page; + boolean c2h_bt_page; /* Add for win8.1 page out issue */ + boolean wifi_is_high_pri_task; /* Add for win8.1 page out issue */ + u8 bt_retry_cnt; + u8 bt_info_ext; + boolean bt_whck_test; /* Add for ASUS WHQL TEST that enable wifi test bt */ +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8821a1ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8821a1ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a1ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a1ant_switchband_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8821a1ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state); +void ex_halbtc8821a1ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8821a1ant_display_coex_info(IN struct btc_coexist *btcoexist); + +#else +#define ex_halbtc8821a1ant_power_on_setting(btcoexist) +#define ex_halbtc8821a1ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8821a1ant_init_coex_dm(btcoexist) +#define ex_halbtc8821a1ant_ips_notify(btcoexist, type) +#define ex_halbtc8821a1ant_lps_notify(btcoexist, type) +#define ex_halbtc8821a1ant_scan_notify(btcoexist, type) +#define ex_halbtc8821a1ant_switchband_notify(btcoexist, type) +#define ex_halbtc8821a1ant_connect_notify(btcoexist, type) +#define ex_halbtc8821a1ant_media_status_notify(btcoexist, type) +#define ex_halbtc8821a1ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8821a1ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8821a1ant_halt_notify(btcoexist) +#define ex_halbtc8821a1ant_pnp_notify(btcoexist, pnp_state) +#define ex_halbtc8821a1ant_periodical(btcoexist) +#define ex_halbtc8821a1ant_display_coex_info(btcoexist) + +#endif + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a2ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a2ant.c new file mode 100644 index 0000000..80efc33 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a2ant.c @@ -0,0 +1,4637 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8821A Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8821A_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8821a_2ant glcoex_dm_8821a_2ant; +static struct coex_dm_8821a_2ant *coex_dm = &glcoex_dm_8821a_2ant; +static struct coex_sta_8821a_2ant glcoex_sta_8821a_2ant; +static struct coex_sta_8821a_2ant *coex_sta = &glcoex_sta_8821a_2ant; + +const char *const glbt_info_src_8821a_2ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u32 glcoex_ver_date_8821a_2ant = 20160816; +u32 glcoex_ver_8821a_2ant = 0x5d; +u32 glcoex_ver_btdesired_8821a_2ant = 0x5c; + +/* modify 20140903v43 a2dpandhid tdmaonoff a2dp glitch _ tdma off 778=3(case1)->778=1(case0) + * and to improve tp while a2dphid case23->case25 , case123->case125 for asus spec + * and modify for asus bt WHQL test _ tdma off_ 778=3->1_ + * ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8821a2ant_ + * ************************************************************ */ +u8 halbtc8821a2ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8821a2ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 index, IN u8 level_num, IN u8 rssi_thresh, IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8821a2ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false; + + /* This function check if bt is disabled */ + + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is enabled !!\n"); + BTC_TRACE(trace_buf); + } else { + bt_disable_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], bt all counters=0, %d times!!\n", + bt_disable_cnt); + BTC_TRACE(trace_buf); + if (bt_disable_cnt >= 10) { + bt_disabled = true; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!\n"); + BTC_TRACE(trace_buf); + } + } + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + coex_sta->bt_disabled = bt_disabled; + /* if (!bt_disabled) { + } else { + } */ + } +} + +void halbtc8821a2ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); +} + +void halbtc8821a2ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + if ((coex_sta->low_priority_rx >= 950) && + (coex_sta->low_priority_rx >= coex_sta->low_priority_tx) && + (!coex_sta->under_ips)) + bt_link_info->slave_role = true; + else + bt_link_info->slave_role = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], High Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_hp_txrx, reg_hp_tx, reg_hp_tx, reg_hp_rx, reg_hp_rx); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Low Priority Tx/Rx (reg 0x%x)=0x%x(%d)/0x%x(%d)\n", + reg_lp_txrx, reg_lp_tx, reg_lp_tx, reg_lp_rx, reg_lp_rx); + BTC_TRACE(trace_buf); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); +} + +void halbtc8821a2ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ +#if 1 + + coex_sta->crc_ok_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_CCK); + coex_sta->crc_ok_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_LEGACY); + coex_sta->crc_ok_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_HT); + coex_sta->crc_ok_11n_vht = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_OK_VHT); + + coex_sta->crc_err_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_CCK); + coex_sta->crc_err_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_LEGACY); + coex_sta->crc_err_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_HT); + coex_sta->crc_err_11n_vht = + btcoexist->btc_phydm_query_PHY_counter( + btcoexist, + PHYDM_INFO_CRC32_ERROR_VHT); + +#endif +} + +void halbtc8821a2ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +boolean halbtc8821a2ant_is_wifi_status_changed(IN struct btc_coexist *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + u8 wifi_rssi_state = BTC_RSSI_STATE_HIGH; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 3, + 2, BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + + if ((BTC_RSSI_STATE_HIGH == wifi_rssi_state) || + (BTC_RSSI_STATE_LOW == wifi_rssi_state)) + return true; + + } + + return false; +} + +void halbtc8821a2ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + +u8 halbtc8821a2ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8821A_2ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_2ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_2ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_2ANT_COEX_ALGO_HID_A2DP; + } + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_HID; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(HS) ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(EDR) ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_2ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821A_2ANT_COEX_ALGO_SCO; + } + } + } + } + + return algorithm; +} + +void halbtc8821a2ant_set_fw_dac_swing_level(IN struct btc_coexist *btcoexist, + IN u8 dac_swing_lvl) +{ + u8 h2c_parameter[1] = {0}; + + /* There are several type of dacswing */ + /* 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ + h2c_parameter[0] = dac_swing_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +void halbtc8821a2ant_set_fw_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN u8 dec_bt_pwr_lvl) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = dec_bt_pwr_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +void halbtc8821a2ant_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 dec_bt_pwr_lvl) +{ + coex_dm->cur_bt_dec_pwr_lvl = dec_bt_pwr_lvl; + + if (!force_exec) { + if (coex_dm->pre_bt_dec_pwr_lvl == coex_dm->cur_bt_dec_pwr_lvl) + return; + } + halbtc8821a2ant_set_fw_dec_bt_pwr(btcoexist, + coex_dm->cur_bt_dec_pwr_lvl); + + coex_dm->pre_bt_dec_pwr_lvl = coex_dm->cur_bt_dec_pwr_lvl; +} + +void halbtc8821a2ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8821a2ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8821a2ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8821a2ant_fw_dac_swing_lvl(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 fw_dac_swing_lvl) +{ + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + + if (!force_exec) { + if (coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + halbtc8821a2ant_set_fw_dac_swing_level(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +void halbtc8821a2ant_set_sw_rf_rx_lpf_corner(IN struct btc_coexist *btcoexist, + IN boolean rx_rf_shrink_on) +{ + if (rx_rf_shrink_on) { + /* Shrink RF Rx LPF corner */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Shrink RF Rx LPF corner!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff, + 0xffffc); + } else { + /* Resume RF Rx LPF corner */ + /* After initialized, we can use coex_dm->bt_rf_0x1e_backup */ + if (btcoexist->initilized) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Resume RF Rx LPF corner!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, coex_dm->bt_rf_0x1e_backup); + } + } +} + +void halbtc8821a2ant_rf_shrink(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rx_rf_shrink_on) +{ + coex_dm->cur_rf_rx_lpf_shrink = rx_rf_shrink_on; + + if (!force_exec) { + if (coex_dm->pre_rf_rx_lpf_shrink == + coex_dm->cur_rf_rx_lpf_shrink) + return; + } + halbtc8821a2ant_set_sw_rf_rx_lpf_corner(btcoexist, + coex_dm->cur_rf_rx_lpf_shrink); + + coex_dm->pre_rf_rx_lpf_shrink = coex_dm->cur_rf_rx_lpf_shrink; +} + +void halbtc8821a2ant_set_sw_penalty_tx_rate_adaptive(IN struct btc_coexist + *btcoexist, IN boolean low_penalty_ra) +{ + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* op_code, 0x6= Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT(0); + h2c_parameter[2] = + 0x00; /* normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[3] = 0xf3; /* MCS7 or OFDM54 */ + h2c_parameter[4] = 0xa0; /* MCS6 or OFDM48 */ + h2c_parameter[5] = 0xa0; /* MCS5 or OFDM36 */ + /* h2c_parameter[3] = 0xf7; */ /*MCS7 or OFDM54 */ + /* h2c_parameter[4] = 0xf8; */ /*MCS6 or OFDM48 */ + /* h2c_parameter[5] = 0xf9; /MCS5 or OFDM36 */ + } + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +void halbtc8821a2ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == coex_dm->cur_low_penalty_ra) + return; + } + halbtc8821a2ant_set_sw_penalty_tx_rate_adaptive(btcoexist, + coex_dm->cur_low_penalty_ra); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; +} + +void halbtc8821a2ant_set_dac_swing_reg(IN struct btc_coexist *btcoexist, + IN u32 level) +{ + u8 val = (u8)level; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Write SwDacSwing = 0x%x\n", level); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc5b, 0x3e, val); +} + +void halbtc8821a2ant_set_sw_full_time_dac_swing(IN struct btc_coexist + *btcoexist, IN boolean sw_dac_swing_on, IN u32 sw_dac_swing_lvl) +{ + if (sw_dac_swing_on) + halbtc8821a2ant_set_dac_swing_reg(btcoexist, sw_dac_swing_lvl); + else + halbtc8821a2ant_set_dac_swing_reg(btcoexist, 0x18); +} + + +void halbtc8821a2ant_dac_swing(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean dac_swing_on, IN u32 dac_swing_lvl) +{ + coex_dm->cur_dac_swing_on = dac_swing_on; + coex_dm->cur_dac_swing_lvl = dac_swing_lvl; + + if (!force_exec) { + if ((coex_dm->pre_dac_swing_on == coex_dm->cur_dac_swing_on) && + (coex_dm->pre_dac_swing_lvl == + coex_dm->cur_dac_swing_lvl)) + return; + } + delay_ms(30); + halbtc8821a2ant_set_sw_full_time_dac_swing(btcoexist, dac_swing_on, + dac_swing_lvl); + + coex_dm->pre_dac_swing_on = coex_dm->cur_dac_swing_on; + coex_dm->pre_dac_swing_lvl = coex_dm->cur_dac_swing_lvl; +} + +void halbtc8821a2ant_set_adc_back_off(IN struct btc_coexist *btcoexist, + IN boolean adc_back_off) +{ + if (adc_back_off) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB BackOff Level On!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x3); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB BackOff Level Off!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x8db, 0x60, 0x1); + } +} + +void halbtc8821a2ant_adc_back_off(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean adc_back_off) +{ + coex_dm->cur_adc_back_off = adc_back_off; + + if (!force_exec) { + if (coex_dm->pre_adc_back_off == coex_dm->cur_adc_back_off) + return; + } + halbtc8821a2ant_set_adc_back_off(btcoexist, coex_dm->cur_adc_back_off); + + coex_dm->pre_adc_back_off = coex_dm->cur_adc_back_off; +} + +void halbtc8821a2ant_set_agc_table(IN struct btc_coexist *btcoexist, + IN boolean agc_table_en) +{ + u8 rssi_adjust_val = 0; + + /* =================BB AGC Gain Table */ + if (agc_table_en) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB Agc Table On!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6e1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6d1B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6c1C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6b1D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x6a1E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x691F0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0x68200001); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BB Agc Table Off!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xaa1A0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa91B0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa81C0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa71D0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa61E0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa51F0001); + btcoexist->btc_write_4byte(btcoexist, 0xc78, 0xa4200001); + } + + + /* =================RF Gain */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x02000); + if (agc_table_en) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Agc Table On!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, + 0x38fff); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, + 0x38ffe); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Agc Table Off!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, + 0x380c3); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x3b, 0xfffff, + 0x28ce6); + } + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xef, 0xfffff, 0x0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x1); + if (agc_table_en) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Agc Table On!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, 0xfffff, + 0x38fff); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, 0xfffff, + 0x38ffe); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Agc Table Off!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, 0xfffff, + 0x380c3); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x40, 0xfffff, + 0x28ce6); + } + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xed, 0xfffff, 0x0); + + /* set rssi_adjust_val for wifi module. */ + if (agc_table_en) + rssi_adjust_val = 8; + btcoexist->btc_set(btcoexist, BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, + &rssi_adjust_val); +} + +void halbtc8821a2ant_agc_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean agc_table_en) +{ + coex_dm->cur_agc_table_en = agc_table_en; + + if (!force_exec) { + if (coex_dm->pre_agc_table_en == coex_dm->cur_agc_table_en) + return; + } + halbtc8821a2ant_set_agc_table(btcoexist, agc_table_en); + + coex_dm->pre_agc_table_en = coex_dm->cur_agc_table_en; +} + +void halbtc8821a2ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8821a2ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8821a2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8821a2ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_sta->coex_table_type = type; + + switch (type) { + case 0: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x55555555, 0xffffff, 0x3); + break; + case 1: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5afa5afa, 0xffffff, 0x3); + break; + case 2: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x5ada5ada, 0x5ada5ada, 0xffffff, 0x3); + break; + case 3: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0xaaaaaaaa, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 4: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0xffffffff, 0xffffffff, 0xffffff, 0x3); + break; + case 5: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x5fff5fff, 0x5fff5fff, 0xffffff, 0x3); + break; + case 6: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x55ff55ff, 0x5a5a5a5a, 0xffffff, 0x3); + break; + case 7: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 8: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 9: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 10: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 11: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 12: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0x5ada5ada, 0xffffff, 0x3); + break; + case 13: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x5fff5fff, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 14: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x5fff5fff, 0x5ada5ada, 0xffffff, 0x3); + break; + case 15: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x55dd55dd, 0xaaaaaaaa, 0xffffff, 0x3); + break; + case 16: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x5fdf5fdf, 0x5fdb5fdb, 0xffffff, 0x3); + break; + case 17: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0xfafafafa, 0xfafafafa, 0xffffff, 0x3); + break; + case 18: + halbtc8821a2ant_coex_table(btcoexist, force_exec, + 0x5555555f, 0x5ada5ada, 0xffffff, 0x3); + break; + default: + break; + } +} + +void halbtc8821a2ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT(0); /* function enable */ + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8821a2ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8821a2ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8821a2ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8821a2ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8821a2ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8821a2ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + + h2c_parameter[0] = byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = byte5; + + coex_dm->ps_tdma_para[0] = byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +void halbtc8821a2ant_sw_mechanism1(IN struct btc_coexist *btcoexist, + IN boolean shrink_rx_lpf, IN boolean low_penalty_ra, + IN boolean limited_dig, IN boolean bt_lna_constrain) +{ + /* + u32 wifi_bw; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if(BTC_WIFI_BW_HT40 != wifi_bw) + { + if (shrink_rx_lpf) + shrink_rx_lpf = false; + } + */ + + /* halbtc8821a2ant_rf_shrink(btcoexist, NORMAL_EXEC, shrink_rx_lpf); */ + halbtc8821a2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} + +void halbtc8821a2ant_sw_mechanism2(IN struct btc_coexist *btcoexist, + IN boolean agc_table_shift, IN boolean adc_back_off, + IN boolean sw_dac_swing, IN u32 dac_swing_lvl) +{ + /* halbtc8821a2ant_agc_table(btcoexist, NORMAL_EXEC, agc_table_shift); */ + /* halbtc8821a2ant_adc_back_off(btcoexist, NORMAL_EXEC, adc_back_off); */ + halbtc8821a2ant_dac_swing(btcoexist, NORMAL_EXEC, sw_dac_swing, + dac_swing_lvl); +} + +void halbtc8821a2ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean init_hwcfg, IN boolean wifi_off) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 u32tmp = 0; + u8 h2c_parameter[2] = {0}; + + if (init_hwcfg) { + /* 0x4c[23]=0, 0x4c[24]=1 Antenna control by WL/BT */ + u32tmp = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp &= ~BIT(23); + u32tmp |= BIT(24); + btcoexist->btc_write_4byte(btcoexist, 0x4c, u32tmp); + + btcoexist->btc_write_4byte(btcoexist, 0x974, 0x3ff); + /* btcoexist->btc_write_1byte(btcoexist, 0xcb4, 0x77); */ + + if (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT) { + /* tell firmware "antenna inverse" ==> WRONG firmware antenna control code.==>need fw to fix */ + h2c_parameter[0] = 1; + h2c_parameter[1] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } else { + /* tell firmware "no antenna inverse" ==> WRONG firmware antenna control code.==>need fw to fix */ + h2c_parameter[0] = 0; + h2c_parameter[1] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x65, 2, + h2c_parameter); + } + } + + /* ext switch setting */ + switch (ant_pos_type) { + case BTC_ANT_WIFI_AT_MAIN: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, + 0x30, 0x1); + break; + case BTC_ANT_WIFI_AT_AUX: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, + 0x30, 0x2); + break; + } +} + +void halbtc8821a2ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + u8 wifi_rssi_state1, bt_rssi_state; + + + wifi_rssi_state1 = halbtc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + if (!(BTC_RSSI_HIGH(wifi_rssi_state1) && + BTC_RSSI_HIGH(bt_rssi_state)) && turn_on) { + type = type + 100; /* for WiFi RSSI low or BT RSSI low */ + } + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + if (turn_on) { + switch (type) { + case 1: + default: + /* halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); */ + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c, 0x03, 0xf1, 0x90); + break; + case 2: + /* halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12, 0x12, 0xe1, 0x90); */ + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x2d, 0x03, 0xf1, 0x90); + break; + case 3: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1c, 0x3, 0xf1, 0x90); + break; + case 4: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x10, 0x03, 0xf1, 0x90); + break; + case 5: + /* halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x90); */ + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c, 0x3, 0x70, 0x90); + break; + case 6: + /* halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12, 0x12, 0x60, 0x90); */ + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x2d, 0x3, 0x70, 0x90); + break; + case 7: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1c, 0x3, 0x70, 0x90); + break; + case 8: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xa3, + 0x10, 0x3, 0x70, 0x90); + break; + case 9: + /* halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); */ + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c, 0x03, 0xf1, 0x90); + break; + case 10: + /* halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12, 0x12, 0xe1, 0x90); */ + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x2d, 0x03, 0xf1, 0x90); + break; + case 11: + /* halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0xa, 0xa, 0xe1, 0x90); */ + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1c, 0x3, 0xf1, 0x90); + break; + case 12: + /* halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5, 0x5, 0xe1, 0x90); */ + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x10, 0x3, 0xf1, 0x90); + break; + case 13: + /* halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, 0x1a, 0x60, 0x90); */ + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c, 0x3, 0x70, 0x90); + break; + case 14: + /* halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x12, 0x12, 0x60, 0x90); */ + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x2d, 0x3, 0x70, 0x90); + break; + case 15: + /* halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0xa, 0xa, 0x60, 0x90); */ + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1c, 0x3, 0x70, 0x90); + break; + case 16: + /* halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x5, 0x5, 0x60, 0x90); */ + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x10, 0x3, 0x70, 0x90); + break; + case 17: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xa3, + 0x2f, 0x2f, 0x60, 0x90); + break; + case 18: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x5, 0x5, 0xe1, 0x90); + break; + case 19: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x25, 0xe1, 0x90); + break; + case 20: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x25, 0x60, 0x90); + break; + case 21: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x15, 0x03, 0x70, 0x90); + break; + case 23: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1e, 0x03, 0xf0, 0x14); + break; + case 24: + case 124: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x3c, 0x03, 0x70, 0x50); + break; + /* case25/case125 : for lenovo bt pan tp degrade<30% while wifi downlink */ + case 25: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x14, 0x03, 0xf1, 0x90); + break; + case 26: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x30, 0x03, 0xf1, 0x90); + break; + case 27: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x23, 0x03, 0x70, 0x50); + break; + case 28: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x1e, 0x03, 0x70, 0x50); + break; + case 71: + /* halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, 0x1a, 0x1a, 0xe1, 0x90); */ + + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c, 0x03, 0xf1, 0x90); + break; + case 101: + case 105: + case 171: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x3a, 0x03, 0x70, 0x50); + break; + case 102: + case 106: + case 110: + case 114: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x2d, 0x03, 0x70, 0x50); + break; + case 103: + case 107: + case 111: + case 115: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x1c, 0x03, 0x70, 0x50); + break; + case 104: + case 108: + case 112: + case 116: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x10, 0x03, 0x70, 0x50); + break; + case 109: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c, 0x03, 0xf1, 0x90); + break; + case 113: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3c, 0x03, 0x70, 0x90); + break; + case 121: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x15, 0x03, 0x70, 0x90); + break; + case 22: + case 122: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x35, 0x03, 0x71, 0x11); + break; + case 123: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x1c, 0x03, 0x70, 0x54); + break; + /* case25/case125 : for lenovo bt pan tp degrade<30% while wifi downlink */ + case 125: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x14, 0x03, 0x70, 0x50); + break; + case 126: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x30, 0x03, 0x70, 0x50); + break; + case 127: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x28, 0x03, 0x70, 0x50); + break; + } + } else { + /* disable PS tdma */ + switch (type) { + case 0: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x40, 0x0); + break; + case 1: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x48, 0x0); + break; + default: + halbtc8821a2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x40, 0x0); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void halbtc8821a2ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +void halbtc8821a2ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + case BTC_PS_LPS_ON: + halbtc8821a2ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8821a2ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + coex_sta->force_lps_on = true; + break; + case BTC_PS_LPS_OFF: + halbtc8821a2ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + default: + break; + } +} + + +void halbtc8821a2ant_coex_all_off(IN struct btc_coexist *btcoexist) +{ + /* fw all off */ + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + /* hw all off */ + /* btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); */ + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8821a2ant_coex_under_5g(IN struct btc_coexist *btcoexist) +{ + halbtc8821a2ant_coex_all_off(btcoexist); + + halbtc8821a2ant_ignore_wlan_act(btcoexist, NORMAL_EXEC, true); +} + +void halbtc8821a2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + halbtc8821a2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 1); + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, FORCE_EXEC, 0); + + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); +} + +void halbtc8821a2ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + boolean wifi_connected = false; + boolean low_pwr_disable = true; + boolean scan = false, link = false, roam = false; + + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + wifi_rssi_state1 = halbtc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + if (scan || link || roam) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi link process + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + } else if (wifi_connected) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi no-link + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + } + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + +} + + +void halbtc8821a2ant_action_wifi_link_process(IN struct btc_coexist *btcoexist) +{ + u8 u8tmpa, u8tmpb; + + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + + + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x76e); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], 0x765=0x%x, 0x76e=0x%x\n", u8tmpa, + u8tmpb); + BTC_TRACE(trace_buf); +} + +boolean halbtc8821a2ant_action_wifi_idle_process(IN struct btc_coexist + *btcoexist) +{ + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u8 ap_num = 0; + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + /* wifi_rssi_state1 = halbtc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); */ + wifi_rssi_state1 = halbtc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES - 20, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); + + /* define the office environment */ + if (BTC_RSSI_HIGH(wifi_rssi_state1) && + (coex_sta->hid_exist == true) && + (coex_sta->a2dp_exist == true)) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi idle process for BT HID+A2DP exist!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821a2ant_dac_swing(btcoexist, NORMAL_EXEC, true, 0x6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, false, + false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + return true; + } + + /* */ + else if (coex_sta->pan_exist == true) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi idle process for BT PAN exist!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821a2ant_dac_swing(btcoexist, NORMAL_EXEC, true, 0x6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, false, + false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + return true; + } + + else { + halbtc8821a2ant_dac_swing(btcoexist, NORMAL_EXEC, true, 0x18); + return false; + } + + +} + + + +boolean halbtc8821a2ant_is_common_action(IN struct btc_coexist *btcoexist) +{ + boolean common = false, wifi_connected = false, wifi_busy = false; + boolean bt_hs_on = false, low_pwr_disable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non-connected idle!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, false, + false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, false, + 0x18); + + common = true; + } else { + if (BT_8821A_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, + false, false, 0x8); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + halbtc8821a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + halbtc8821a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 0xb); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, + false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + common = true; + } else if (BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status) { + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + if (bt_hs_on) + return false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, + false, false, 0x8); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + halbtc8821a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + halbtc8821a2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, 0x0); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 1); + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 0xb); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + + common = true; + } else { + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + + if (wifi_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + BTC_TRACE(trace_buf); + common = false; + /* common = halbtc8821a2ant_action_wifi_idle_process(btcoexist); */ + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + /* common = false; */ + common = halbtc8821a2ant_action_wifi_idle_process( + btcoexist); + } + } + } + + return common; +} +void halbtc8821a2ant_tdma_duration_adjust(IN struct btc_coexist *btcoexist, + IN boolean sco_hid, IN boolean tx_pause, IN u8 max_interval) +{ + static s32 up, dn, m, n, wait_count; + s32 result; /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */ + u8 retry_count = 0; + + if (!coex_dm->auto_tdma_adjust) { + coex_dm->auto_tdma_adjust = true; + { + if (sco_hid) { + if (tx_pause) { + if (max_interval == 1) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = + 13; + } else if (max_interval == 2) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (max_interval == 3) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } + } else { + if (max_interval == 1) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = + 9; + } else if (max_interval == 2) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (max_interval == 3) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } + } + } else { + if (tx_pause) { + if (max_interval == 1) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = + 5; + } else if (max_interval == 2) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (max_interval == 3) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } + } else { + if (max_interval == 1) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (max_interval == 2) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (max_interval == 3) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } + } + } + } + /* ============ */ + up = 0; + dn = 0; + m = 1; + n = 3; + result = 0; + wait_count = 0; + } else { + /* acquire the BT TRx retry count from BT_Info byte2 */ + retry_count = coex_sta->bt_retry_cnt; + result = 0; + wait_count++; + + if (retry_count == + 0) { /* no retry in the last 2-second duration */ + up++; + dn--; + + if (dn <= 0) + dn = 0; + + if (up >= n) { /* if �s�� n ��2�� retry count��0, �h�ռeWiFi duration */ + wait_count = 0; + n = 3; + up = 0; + dn = 0; + result = 1; + } + } else if (retry_count <= + 3) { /* <=3 retry in the last 2-second duration */ + up--; + dn++; + + if (up <= 0) + up = 0; + + if (dn == 2) { /* if �s�� 2 ��2�� retry count< 3, �h�կ�WiFi duration */ + if (wait_count <= 2) + m++; /* �קK�@���b���level���Ӧ^ */ + else + m = 1; + + if (m >= 20) /* m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + } else { /* retry count > 3, �u�n1�� retry count > 3, �h�կ�WiFi duration */ + if (wait_count == 1) + m++; /* �קK�@���b���level���Ӧ^ */ + else + m = 1; + + if (m >= 20) /* m �̤j�� = 20 ' �̤j120�� recheck�O�_�վ� WiFi duration. */ + m = 20; + + n = 3 * m; + up = 0; + dn = 0; + wait_count = 0; + result = -1; + } + + if (max_interval == 1) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 71) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 5); + coex_dm->ps_tdma_du_adj_type = 5; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 13); + coex_dm->ps_tdma_du_adj_type = 13; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 5); + coex_dm->ps_tdma_du_adj_type = + 5; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 13); + coex_dm->ps_tdma_du_adj_type = + 13; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 71); + coex_dm->ps_tdma_du_adj_type = 71; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 9); + coex_dm->ps_tdma_du_adj_type = 9; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + + if (result == -1) { + if (coex_dm->cur_ps_tdma == 71) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 1); + coex_dm->ps_tdma_du_adj_type = + 1; + } else if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 71); + coex_dm->ps_tdma_du_adj_type = + 71; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 9); + coex_dm->ps_tdma_du_adj_type = + 9; + } + } + } + } else if (max_interval == 2) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 6); + coex_dm->ps_tdma_du_adj_type = 6; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 14); + coex_dm->ps_tdma_du_adj_type = 14; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 6); + coex_dm->ps_tdma_du_adj_type = + 6; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 14); + coex_dm->ps_tdma_du_adj_type = + 14; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 2); + coex_dm->ps_tdma_du_adj_type = 2; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 10); + coex_dm->ps_tdma_du_adj_type = 10; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 2); + coex_dm->ps_tdma_du_adj_type = + 2; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 10); + coex_dm->ps_tdma_du_adj_type = + 10; + } + } + } + } else if (max_interval == 3) { + if (tx_pause) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + coex_dm->ps_tdma_du_adj_type = 7; + } else if (coex_dm->cur_ps_tdma == 4) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 8); + coex_dm->ps_tdma_du_adj_type = 8; + } + if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 15); + coex_dm->ps_tdma_du_adj_type = 15; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 16); + coex_dm->ps_tdma_du_adj_type = 16; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 8); + coex_dm->ps_tdma_du_adj_type = + 8; + } else if (coex_dm->cur_ps_tdma == 13) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 16); + coex_dm->ps_tdma_du_adj_type = + 16; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 8) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 7); + coex_dm->ps_tdma_du_adj_type = + 7; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 15); + coex_dm->ps_tdma_du_adj_type = + 15; + } + } + } else { + if (coex_dm->cur_ps_tdma == 5) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 6) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 7) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 3); + coex_dm->ps_tdma_du_adj_type = 3; + } else if (coex_dm->cur_ps_tdma == 8) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 4); + coex_dm->ps_tdma_du_adj_type = 4; + } + if (coex_dm->cur_ps_tdma == 13) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 14) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 15) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 11); + coex_dm->ps_tdma_du_adj_type = 11; + } else if (coex_dm->cur_ps_tdma == 16) { + halbtc8821a2ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 12); + coex_dm->ps_tdma_du_adj_type = 12; + } + if (result == -1) { + if (coex_dm->cur_ps_tdma == 1) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 4); + coex_dm->ps_tdma_du_adj_type = + 4; + } else if (coex_dm->cur_ps_tdma == 9) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 12); + coex_dm->ps_tdma_du_adj_type = + 12; + } + } else if (result == 1) { + if (coex_dm->cur_ps_tdma == 4) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 3) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 2) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 3); + coex_dm->ps_tdma_du_adj_type = + 3; + } else if (coex_dm->cur_ps_tdma == 12) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 11) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } else if (coex_dm->cur_ps_tdma == 10) { + halbtc8821a2ant_ps_tdma( + btcoexist, NORMAL_EXEC, + true, 11); + coex_dm->ps_tdma_du_adj_type = + 11; + } + } + } + } + } + + /* if current PsTdma not match with the recorded one (when scan, dhcp...), */ + /* then we have to adjust it back to the previous record one. */ + if (coex_dm->cur_ps_tdma != coex_dm->ps_tdma_du_adj_type) { + boolean scan = false, link = false, roam = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PsTdma type dismatch!!!, cur_ps_tdma=%d, recordPsTdma=%d\n", + coex_dm->cur_ps_tdma, coex_dm->ps_tdma_du_adj_type); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (!scan && !link && !roam) + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + coex_dm->ps_tdma_du_adj_type); + else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"); + BTC_TRACE(trace_buf); + } + } +} + +/* SCO only or SCO+PAN(HS) */ +void halbtc8821a2ant_action_sco(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 4); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_LEGACY == wifi_bw) /* for SCO quality at 11b/g mode */ + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + else { /* for SCO quality & wifi performance balance at 11n mode */ + if (BTC_WIFI_BW_HT40 == wifi_bw) + halbtc8821a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + else { + if (bt_link_info->sco_only) + halbtc8821a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 17); + else + halbtc8821a2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 12); + } + } + + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 0); /* for voice quality */ + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + true, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + true, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + true, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + true, 0x18); + } + } +} + + +void halbtc8821a2ant_action_hid(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, bt_rssi_state; + u32 wifi_bw; + + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 25); + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_LEGACY == wifi_bw) /* for HID at 11b/g mode */ + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + else /* for HID quality & wifi performance balance at 11n mode */ + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 24); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +void halbtc8821a2ant_action_a2dp(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + u8 ap_num = 0; + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + wifi_rssi_state1 = halbtc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); + + /* define the office environment */ + if ((ap_num >= 10) && BTC_RSSI_HIGH(wifi_rssi_state1) && + BTC_RSSI_HIGH(bt_rssi_state)) { + /* dbg_print(" AP#>10(%d)\n", ap_num); */ + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x8); + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + /* halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); */ + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + true, 0x6); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + true, 0x6); + } + return; + + } + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 13); + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + /* halbtc8821a2ant_tdma_duration_adjust(btcoexist, false, false, 1); */ + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + } else { + /* halbtc8821a2ant_tdma_duration_adjust(btcoexist, false, true, 1); */ + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 23); + } + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8821a2ant_action_a2dp_pan_hs(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + wifi_rssi_state1 = halbtc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 13); + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + + halbtc8821a2ant_tdma_duration_adjust(btcoexist, false, true, 2); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8821a2ant_action_pan_edr(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + wifi_rssi_state1 = halbtc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 10); + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 13); + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 26); + else + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 26); + + /* sw mechanism */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + + +/* PAN(HS) only */ +void halbtc8821a2ant_action_pan_hs(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + wifi_rssi_state1 = halbtc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* PAN(EDR)+A2DP */ +void halbtc8821a2ant_action_pan_edr_a2dp(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + wifi_rssi_state1 = halbtc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + else + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 12); + + if (BTC_WIFI_BW_HT40 == wifi_bw) + halbtc8821a2ant_tdma_duration_adjust(btcoexist, false, + true, 3); + else + halbtc8821a2ant_tdma_duration_adjust(btcoexist, false, + false, 3); + } else { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 13); + halbtc8821a2ant_tdma_duration_adjust(btcoexist, false, true, 3); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8821a2ant_action_pan_edr_hid(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 25); + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + wifi_rssi_state1 = halbtc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 14); + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (BTC_WIFI_BW_HT40 == wifi_bw) { + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 3); + /* halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 11); */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x780); + } else { + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, + 6); + /* halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + } + halbtc8821a2ant_tdma_duration_adjust(btcoexist, true, false, 2); + } else { + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + /* halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 14); */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x0); + halbtc8821a2ant_tdma_duration_adjust(btcoexist, true, true, 2); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +/* HID+A2DP+PAN(EDR) */ +void halbtc8821a2ant_action_hid_a2dp_pan_edr(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 25); + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + wifi_rssi_state1 = halbtc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 0); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 0x8); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 14); + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + if (BTC_WIFI_BW_HT40 == wifi_bw) + halbtc8821a2ant_tdma_duration_adjust(btcoexist, true, + true, 3); + else + halbtc8821a2ant_tdma_duration_adjust(btcoexist, true, + false, 3); + } else + halbtc8821a2ant_tdma_duration_adjust(btcoexist, true, true, 3); + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8821a2ant_action_hid_a2dp(IN struct btc_coexist *btcoexist) +{ + u8 wifi_rssi_state, wifi_rssi_state1, bt_rssi_state; + u32 wifi_bw; + u8 ap_num = 0; + + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 25); + + wifi_rssi_state = halbtc8821a2ant_wifi_rssi_state(btcoexist, 0, 2, 15, + 0); + /* bt_rssi_state = halbtc8821a2ant_bt_rssi_state(2, 29, 0); */ + wifi_rssi_state1 = halbtc8821a2ant_wifi_rssi_state(btcoexist, 1, 2, + BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES, 0); + bt_rssi_state = halbtc8821a2ant_bt_rssi_state(3, + BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES, 37); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); + + halbtc8821a2ant_limited_rx(btcoexist, NORMAL_EXEC, false, true, 0x6); + + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_LEGACY == wifi_bw) { + if (BTC_RSSI_HIGH(bt_rssi_state)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else if (BTC_RSSI_MEDIUM(bt_rssi_state)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + } else { + /* only 802.11N mode we have to dec bt power to 4 degree */ + if (BTC_RSSI_HIGH(bt_rssi_state)) { + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &ap_num); + /* need to check ap Number of Not */ + if (ap_num < 10) + halbtc8821a2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, 4); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, + NORMAL_EXEC, 2); + } else if (BTC_RSSI_MEDIUM(bt_rssi_state)) + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + else + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + } + + if (BTC_RSSI_HIGH(wifi_rssi_state1) && BTC_RSSI_HIGH(bt_rssi_state)) { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 18); + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, 0x0); + } else { + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 18); + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } + + if ((bt_rssi_state == BTC_RSSI_STATE_HIGH) || + (bt_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + /* halbtc8821a2ant_tdma_duration_adjust(btcoexist, true, false, 3); */ + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 28); + } else { + /* halbtc8821a2ant_tdma_duration_adjust(btcoexist, true, true, 3); */ + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 28); + } + + /* sw mechanism */ + if (BTC_WIFI_BW_HT40 == wifi_bw) { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, true, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } else { + if ((wifi_rssi_state == BTC_RSSI_STATE_HIGH) || + (wifi_rssi_state == BTC_RSSI_STATE_STAY_HIGH)) { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, true, false, + false, 0x18); + } else { + halbtc8821a2ant_sw_mechanism1(btcoexist, false, true, + false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, + false, 0x18); + } + } +} + +void halbtc8821a2ant_action_bt_whck_test(IN struct btc_coexist *btcoexist) +{ + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8821a2ant_action_wifi_multi_port(IN struct btc_coexist *btcoexist) +{ + halbtc8821a2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 6); + halbtc8821a2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* sw all off */ + halbtc8821a2ant_sw_mechanism1(btcoexist, false, false, false, false); + halbtc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); + + /* hw all off */ + /* btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, 0x0); */ + halbtc8821a2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821a2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + halbtc8821a2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 1); +} + +void halbtc8821a2ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + boolean wifi_under_5g = false; + u8 algorithm = 0; + u32 num_of_wifi_link = 0; + u32 wifi_link_status = 0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean miracast_plus_bt = false; + boolean scan = false, link = false, roam = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), run 5G coex setting!!<===\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_coex_under_5g(btcoexist); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->bt_whck_test) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under WHCK TEST!!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_action_bt_whck_test(btcoexist); + return; + } + + algorithm = halbtc8821a2ant_action_algorithm(btcoexist); + if (coex_sta->c2h_bt_inquiry_page && + (BT_8821A_2ANT_COEX_ALGO_PANHS != algorithm)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_action_bt_inquiry(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under Link Process !!\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_action_wifi_link_process(btcoexist); + return; + } + + /* for P2P */ + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + BTC_TRACE(trace_buf); + + if (bt_link_info->bt_link_exist) + miracast_plus_bt = true; + else + miracast_plus_bt = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + halbtc8821a2ant_action_wifi_multi_port(btcoexist); + + return; + } + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + coex_dm->cur_algorithm = algorithm; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Algorithm = %d\n", + coex_dm->cur_algorithm); + BTC_TRACE(trace_buf); + + if (halbtc8821a2ant_is_common_action(btcoexist)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant common.\n"); + BTC_TRACE(trace_buf); + coex_dm->auto_tdma_adjust = false; + } else { + if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], pre_algorithm=%d, cur_algorithm=%d\n", + coex_dm->pre_algorithm, coex_dm->cur_algorithm); + BTC_TRACE(trace_buf); + coex_dm->auto_tdma_adjust = false; + } + switch (coex_dm->cur_algorithm) { + case BT_8821A_2ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_action_sco(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID.\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_action_hid(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_action_a2dp(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_action_pan_edr(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HS mode.\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_action_pan_hs(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_action_pan_edr_hid(btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_action_hid_a2dp_pan_edr( + btcoexist); + break; + case BT_8821A_2ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_action_hid_a2dp(btcoexist); + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_coex_all_off(btcoexist); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +void halbtc8821a2ant_wifi_off_hw_cfg(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[2] = {0}; + u32 fw_ver = 0; + + /* set wlan_act to low */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0xfffff, + 0x780); /* WiFi goto standby while GNT_BT 0-->1 */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + if (fw_ver >= 0x180000) { + /* Use H2C to set GNT_BT to HIGH */ + h2c_parameter[0] = 1; + btcoexist->btc_fill_h2c(btcoexist, 0x6E, 1, h2c_parameter); + } else + btcoexist->btc_write_1byte(btcoexist, 0x765, 0x18); +} + +void halbtc8821a2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean back_up) +{ + u8 u8tmp = 0; + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 2Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + + /* Give bt_coex_supported_version the default value */ + coex_sta->bt_coex_supported_version = 0; + + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = (btcoexist->btc_read_1byte(btcoexist, + 0xf1) & 0xf0) >> 4; + + /* backup rf 0x1e value */ + coex_dm->bt_rf_0x1e_backup = + btcoexist->btc_get_rf_reg(btcoexist, BTC_RF_A, 0x1e, 0xfffff); + + /* 0x790[5:0]=0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + /* Antenna config */ + halbtc8821a2ant_set_ant_path(btcoexist, BTC_ANT_WIFI_AT_MAIN, true, + false); + coex_sta->dis_ver_info_cnt = 0; + + /* PTA parameter */ + halbtc8821a2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + /* Enable counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, + 0x4); /* 0x76e[3] =1, WLAN_Act control by PTA */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x3); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); +} + +/* ************************************************************ + * work around function start with wa_halbtc8821a2ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8821a2ant_ + * ************************************************************ */ +void ex_halbtc8821a2ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ + +} + +void ex_halbtc8821a2ant_pre_load_firmware(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x4; /* Set BIT2 by default since it's 2ant case */ + + /* */ + /* S0 or S1 setting and Local register setting(By the setting fw can get ant number, S0/S1, ... info) */ + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + u8tmp |= 0x1; /* antenna inverse */ + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + u8tmp |= 0x1; /* antenna inverse */ + } + + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x384, + u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, + u8tmp); + } +} + +void ex_halbtc8821a2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8821a2ant_init_hw_config(btcoexist, true); +} + +void ex_halbtc8821a2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821a2ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8821a2ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u32 u32tmp[4]; + u32 fw_ver = 0, bt_patch_ver = 0; + u32 bt_coex_ver = 0; + u32 phyver = 0; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "Ant PG number/ Ant mechanism:", + board_info->pg_ant_num, board_info->btdm_ant_num); + CL_PRINTF(cli_buf); + + /* btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); */ + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + bt_coex_ver = coex_sta->bt_coex_supported_version & 0xff; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8821a_2ant, glcoex_ver_8821a_2ant, + glcoex_ver_btdesired_8821a_2ant, + bt_coex_ver, + (bt_coex_ver == 0xff ? "Unknown" : + (bt_coex_ver >= glcoex_ver_btdesired_8821a_2ant ? + "Match" : "Mis-Match"))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ v%d/ %c", + "W_FW/ B_FW/ Phy/ Kt", + fw_ver, bt_patch_ver, phyver, + coex_sta->cut_version + 65); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "Wifi channel informed to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %ddBm/ %d] ", + "BT [status/ rssi/ retryCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") + : ((BT_8821A_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi - 100, coex_sta->bt_retry_cnt); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", + "SCO/HID/PAN/A2DP", + bt_link_info->sco_exist, bt_link_info->hid_exist, + bt_link_info->pan_exist, bt_link_info->a2dp_exist); + CL_PRINTF(cli_buf); + + { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Role", + (bt_link_info->slave_role) ? "Slave" : "Master"); + CL_PRINTF(cli_buf); + } + + bt_info_ext = coex_sta->bt_info_ext; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "BT Info A2DP rate", + (bt_info_ext & BIT(0)) ? "Basic rate" : "EDR rate"); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8821A_2ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8821a_2ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + /* Sw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Sw mechanism]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", + "SM1[ShRf/ LpRA/ LimDig]", + coex_dm->cur_rf_rx_lpf_shrink, coex_dm->cur_low_penalty_ra, + coex_dm->limited_dig); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d(0x%x) ", + "SM2[AgcT/ AdcB/ SwDacSwing(lvl)]", + coex_dm->cur_agc_table_en, coex_dm->cur_adc_back_off, + coex_dm->cur_dac_swing_on, coex_dm->cur_dac_swing_lvl); + CL_PRINTF(cli_buf); + + /* Fw mechanism */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Fw mechanism]============"); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (auto:%d)", + "PS TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + coex_dm->auto_tdma_adjust); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "Coex Table Type", + coex_sta->coex_table_type); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d ", + "DecBtPwr/ IgnWlanAct", + coex_dm->cur_bt_dec_pwr_lvl, coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", + "RF-A, 0x1e initVal", + coex_dm->bt_rf_0x1e_backup); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xc5b); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x880); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x778/0x880[29:25]/0xc58[29:25]", + u8tmp[0], (u32tmp[0] & 0x3e000000) >> 25, + ((u8tmp[1] & 0x3e) >> 1)); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x764); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x76e); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x764/ 0x765/ 0x76e", + (u32tmp[0] & 0xff), (u32tmp[0] & 0xff00) >> 8, u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0xcb4[7:0](ctrl)/ 0xcb4[29:28](val)", + u32tmp[0] & 0xff, ((u32tmp[0] & 0x30000000) >> 28)); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x40); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x974); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x40/ 0x4c[24:23]/ 0x974", + u8tmp[0], ((u32tmp[0] & 0x01800000) >> 23), u32tmp[1]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x550(bcn ctrl)/0x522", + u32tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x49c); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0xc50(dig)/0x49c(null-drop)", + u32tmp[0] & 0xff, u8tmp[0]); + CL_PRINTF(cli_buf); + + fa_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_OFDM); + fa_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_CCK); + cca_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_OFDM); + cca_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_CCK); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", + cca_cck, fa_cck, cca_ofdm, fa_ofdm); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11n-agg", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11n-agg", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2], u8tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(high-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(low-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8821A_2ANT == 1) + /* halbtc8821a2ant_monitor_bt_ctr(btcoexist); */ +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8821a2ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + halbtc8821a2ant_wifi_off_hw_cfg(btcoexist); + halbtc8821a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + halbtc8821a2ant_coex_all_off(btcoexist); + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = false; + halbtc8821a2ant_init_hw_config(btcoexist, false); + halbtc8821a2ant_init_coex_dm(btcoexist); + halbtc8821a2ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8821a2ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + } +} + +void ex_halbtc8821a2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 u8tmpa, u8tmpb; + + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x76e); + + if (BTC_SCAN_START == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + } else if (BTC_SCAN_FINISH == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify\n"); + BTC_TRACE(trace_buf); + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], 0x765=0x%x, 0x76e=0x%x\n", u8tmpa, + u8tmpb); + BTC_TRACE(trace_buf); +} + +/* copy scan notify content to switch band notify */ +void ex_halbtc8821a2ant_switchband_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 u8tmpa, u8tmpb; + + u8tmpa = btcoexist->btc_read_1byte(btcoexist, 0x765); + u8tmpb = btcoexist->btc_read_1byte(btcoexist, 0x76e); + + if (BTC_SCAN_START == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + } else if (BTC_SCAN_FINISH == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify\n"); + BTC_TRACE(trace_buf); + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], 0x765=0x%x, 0x76e=0x%x\n", u8tmpa, + u8tmpb); + BTC_TRACE(trace_buf); +} + +void ex_halbtc8821a2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + if (BTC_ASSOCIATE_START == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify\n"); + BTC_TRACE(trace_buf); + } else if (BTC_ASSOCIATE_FINISH == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify\n"); + BTC_TRACE(trace_buf); + } +} + +void ex_halbtc8821a2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + u8 ap_num = 0; + + if (BTC_MEDIA_CONNECT == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + } + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + h2c_parameter[0] = 0x1; + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else { + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &ap_num); + if (ap_num < 10) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); +} + +void ex_halbtc8821a2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + if (type == BTC_PACKET_DHCP) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], DHCP Packet notify\n"); + BTC_TRACE(trace_buf); + } +} + +void ex_halbtc8821a2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + boolean bt_busy = false, limited_dig = false; + boolean wifi_connected = false, wifi_under_5g = false; + + coex_sta->c2h_bt_info_req_sent = false; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8821A_2ANT_MAX) + rsp_source = BT_INFO_SRC_8821A_2ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt info[%d], length=%d, hex data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), return for Manual CTRL<===\n"); + BTC_TRACE(trace_buf); + return; + } + + /* if 0xff, it means BT is under WHCK test */ + if (bt_info == 0xff) + coex_sta->bt_whck_test = true; + else + coex_sta->bt_whck_test = false; + + if (BT_INFO_SRC_8821A_2ANT_WIFI_FW != rsp_source) { + coex_sta->bt_retry_cnt = /* [3:0] */ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + coex_sta->bt_rssi = + coex_sta->bt_info_c2h[rsp_source][3] * 2 + 10; + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rsp_source][4]; + + coex_sta->bt_tx_rx_mask = (coex_sta->bt_info_c2h[rsp_source][2] + & 0x40); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TX_RX_MASK, + &coex_sta->bt_tx_rx_mask); + if (coex_sta->bt_tx_rx_mask) { + /* BT into is responded by BT FW and BT RF REG 0x3C != 0x01 => Need to switch BT TRx Mask */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Switch BT TRx Mask since BT RF REG 0x3C != 0x01\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, + 0x3c, 0x01); + } + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + if ((coex_sta->bt_info_ext & BIT(1))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + if (wifi_connected) + ex_halbtc8821a2ant_media_status_notify( + btcoexist, BTC_MEDIA_CONNECT); + else + ex_halbtc8821a2ant_media_status_notify( + btcoexist, BTC_MEDIA_DISCONNECT); + } + + + if (!btcoexist->manual_control && !wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info = 0x%x!!\n", + coex_sta->bt_info_ext); + BTC_TRACE(trace_buf); + if ((coex_sta->bt_info_ext & BIT(3))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3=1, wifi_connected=%d\n", + wifi_connected); + BTC_TRACE(trace_buf); + if (wifi_connected) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_ignore_wlan_act( + btcoexist, FORCE_EXEC, false); + } + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3=0, wifi_connected=%d\n", + wifi_connected); + BTC_TRACE(trace_buf); + /* BT already NOT ignore Wlan active, do nothing here. */ + if (!wifi_connected) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_ignore_wlan_act( + btcoexist, FORCE_EXEC, true); + } + } + } + +#if (BT_AUTO_REPORT_ONLY_8821A_2ANT == 0) + if ((coex_sta->bt_info_ext & BIT(4))) { + /* BT auto report already enabled, do nothing */ + } else + halbtc8821a2ant_bt_auto_report(btcoexist, FORCE_EXEC, + true); +#endif + } + + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (bt_info & BT_INFO_8821A_2ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + + /* set link exist status */ + if (!(bt_info & BT_INFO_8821A_2ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8821A_2ANT_B_FTP) + coex_sta->pan_exist = true; + else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8821A_2ANT_B_A2DP) + coex_sta->a2dp_exist = true; + else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8821A_2ANT_B_HID) + coex_sta->hid_exist = true; + else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8821A_2ANT_B_SCO_ESCO) + coex_sta->sco_exist = true; + else + coex_sta->sco_exist = false; + + if ((coex_sta->hid_exist == false) && + (coex_sta->c2h_bt_inquiry_page == false) && + (coex_sta->sco_exist == false)) { + if (coex_sta->high_priority_tx + + coex_sta->high_priority_rx >= 160) + coex_sta->hid_exist = true; + } + } + + halbtc8821a2ant_update_bt_link_info(btcoexist); + + if (!(bt_info & BT_INFO_8821A_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info == + BT_INFO_8821A_2ANT_B_CONNECTION) { /* connection exists but no busy */ + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + BTC_TRACE(trace_buf); + } else if ((bt_info & BT_INFO_8821A_2ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8821A_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info & BT_INFO_8821A_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + BTC_TRACE(trace_buf); + } else { + coex_dm->bt_status = BT_8821A_2ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + BTC_TRACE(trace_buf); + } + + if ((BT_8821A_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8821A_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8821A_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) { + bt_busy = true; + limited_dig = true; + } else { + bt_busy = false; + limited_dig = false; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + coex_dm->limited_dig = limited_dig; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_LIMITED_DIG, &limited_dig); + + halbtc8821a2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8821a2ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8821a2ant_wifi_off_hw_cfg(btcoexist); + /* remove due to interrupt is disabled that polling c2h will fail and delay 100ms. */ + /* btcoexist->btc_set_bt_reg(btcoexist, BTC_BT_REG_RF, 0x3c, 0x15); */ /*BT goto standby while GNT_BT 1-->0 */ + halbtc8821a2ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + ex_halbtc8821a2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); +} + +void ex_halbtc8821a2ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Pnp notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_WIFI_PNP_SLEEP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_init_hw_config(btcoexist, false); + halbtc8821a2ant_init_coex_dm(btcoexist); + halbtc8821a2ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8821a2ant_periodical(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ==========================Periodical===========================\n"); + BTC_TRACE(trace_buf); + + if (coex_sta->dis_ver_info_cnt <= 5) { + coex_sta->dis_ver_info_cnt += 1; + if (coex_sta->dis_ver_info_cnt == 3) { + /* Antenna config to set 0x765 = 0x0 (GNT_BT control by PTA) after initial */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Set GNT_BT control by PTA\n"); + BTC_TRACE(trace_buf); + halbtc8821a2ant_set_ant_path(btcoexist, + BTC_ANT_WIFI_AT_MAIN, false, false); + } + } + + if (((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) && + (!coex_sta->bt_disabled)) + coex_sta->bt_coex_supported_version = + btcoexist->btc_get_bt_coex_supported_version(btcoexist); + + +#if (BT_AUTO_REPORT_ONLY_8821A_2ANT == 0) + halbtc8821a2ant_query_bt_info(btcoexist); + halbtc8821a2ant_monitor_bt_enable_disable(btcoexist); +#else + halbtc8821a2ant_monitor_bt_ctr(btcoexist); + halbtc8821a2ant_monitor_wifi_ctr(btcoexist); + halbtc8821a2ant_monitor_bt_enable_disable(btcoexist); + + if (halbtc8821a2ant_is_wifi_status_changed(btcoexist) || + coex_dm->auto_tdma_adjust) + halbtc8821a2ant_run_coexist_mechanism(btcoexist); +#endif +} + +#endif + +#endif /* #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a2ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a2ant.h new file mode 100644 index 0000000..8151397 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821a2ant.h @@ -0,0 +1,211 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8821A_SUPPORT == 1) + +/* ******************************************* + * The following is for 8821A 2Ant BT Co-exist definition + * ******************************************* */ +#define BT_AUTO_REPORT_ONLY_8821A_2ANT 1 + + +#define BT_INFO_8821A_2ANT_B_FTP BIT(7) +#define BT_INFO_8821A_2ANT_B_A2DP BIT(6) +#define BT_INFO_8821A_2ANT_B_HID BIT(5) +#define BT_INFO_8821A_2ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8821A_2ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8821A_2ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8821A_2ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8821A_2ANT_B_CONNECTION BIT(0) + +#define BTC_RSSI_COEX_THRESH_TOL_8821A_2ANT 2 + + +#define BT_8821A_2ANT_WIFI_RSSI_COEXSWITCH_THRES 42 /* WiFi RSSI Threshold for 2-Ant TDMA/1-Ant PS-TDMA translation */ +#define BT_8821A_2ANT_BT_RSSI_COEXSWITCH_THRES 46 /* BT RSSI Threshold for 2-Ant TDMA/1-Ant PS-TDMA translation */ + +enum bt_info_src_8821a_2ant { + BT_INFO_SRC_8821A_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8821A_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8821A_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8821A_2ANT_MAX +}; + +enum bt_8821a_2ant_bt_status { + BT_8821A_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8821A_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8821A_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8821A_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8821A_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8821A_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8821A_2ANT_BT_STATUS_MAX +}; + +enum bt_8821a_2ant_coex_algo { + BT_8821A_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8821A_2ANT_COEX_ALGO_SCO = 0x1, + BT_8821A_2ANT_COEX_ALGO_HID = 0x2, + BT_8821A_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8821A_2ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8821A_2ANT_COEX_ALGO_PANEDR = 0x5, + BT_8821A_2ANT_COEX_ALGO_PANHS = 0x6, + BT_8821A_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8821A_2ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8821A_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8821A_2ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8821A_2ANT_COEX_ALGO_MAX = 0xb, +}; + +struct coex_dm_8821a_2ant { + /* fw mechanism */ + u8 pre_bt_dec_pwr_lvl; + u8 cur_bt_dec_pwr_lvl; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean reset_tdma_adjust; + boolean auto_tdma_adjust; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + + /* sw mechanism */ + boolean pre_rf_rx_lpf_shrink; + boolean cur_rf_rx_lpf_shrink; + u32 bt_rf_0x1e_backup; + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + boolean pre_dac_swing_on; + u32 pre_dac_swing_lvl; + boolean cur_dac_swing_on; + u32 cur_dac_swing_lvl; + boolean pre_adc_back_off; + boolean cur_adc_back_off; + boolean pre_agc_table_en; + boolean cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + boolean limited_dig; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + boolean need_recover0x948; + u32 backup0x948; + + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; +}; + +struct coex_sta_8821a_2ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + + boolean under_lps; + boolean under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + boolean bt_tx_rx_mask; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + boolean c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8821A_2ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8821A_2ANT_MAX]; + boolean bt_whck_test; + boolean c2h_bt_inquiry_page; + u8 bt_retry_cnt; + u8 bt_info_ext; + u8 scan_ap_num; + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_vht; + + u32 bt_coex_supported_version; + u8 cut_version; + u8 coex_table_type; + boolean force_lps_on; + + u8 dis_ver_info_cnt; +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8821a2ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8821a2ant_pre_load_firmware(IN struct btc_coexist *btcoexist); +void ex_halbtc8821a2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8821a2ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8821a2ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a2ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a2ant_switchband_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821a2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8821a2ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8821a2ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state); +void ex_halbtc8821a2ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8821a2ant_display_coex_info(IN struct btc_coexist *btcoexist); + +#else +#define ex_halbtc8821a2ant_power_on_setting(btcoexist) +#define ex_halbtc8821a2ant_pre_load_firmware(btcoexist) +#define ex_halbtc8821a2ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8821a2ant_init_coex_dm(btcoexist) +#define ex_halbtc8821a2ant_ips_notify(btcoexist, type) +#define ex_halbtc8821a2ant_lps_notify(btcoexist, type) +#define ex_halbtc8821a2ant_scan_notify(btcoexist, type) +#define ex_halbtc8821a2ant_switchband_notify(btcoexist, type) +#define ex_halbtc8821a2ant_connect_notify(btcoexist, type) +#define ex_halbtc8821a2ant_media_status_notify(btcoexist, type) +#define ex_halbtc8821a2ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8821a2ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8821a2ant_halt_notify(btcoexist) +#define ex_halbtc8821a2ant_pnp_notify(btcoexist, pnp_state) +#define ex_halbtc8821a2ant_periodical(btcoexist) +#define ex_halbtc8821a2ant_display_coex_info(btcoexist) +#endif + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c1ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c1ant.c new file mode 100644 index 0000000..34b1305 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c1ant.c @@ -0,0 +1,6674 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8821C Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8821C_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8821c_1ant glcoex_dm_8821c_1ant; +static struct coex_dm_8821c_1ant *coex_dm = &glcoex_dm_8821c_1ant; +static struct coex_sta_8821c_1ant glcoex_sta_8821c_1ant; +static struct coex_sta_8821c_1ant *coex_sta = &glcoex_sta_8821c_1ant; +static struct psdscan_sta_8821c_1ant gl_psd_scan_8821c_1ant; +static struct psdscan_sta_8821c_1ant *psd_scan = &gl_psd_scan_8821c_1ant; +static struct rfe_type_8821c_1ant gl_rfe_type_8821c_1ant; +static struct rfe_type_8821c_1ant *rfe_type = &gl_rfe_type_8821c_1ant; + + +const char *const glbt_info_src_8821c_1ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u32 glcoex_ver_date_8821c_1ant = 20160805; +u32 glcoex_ver_8821c_1ant = 0x04; +u32 glcoex_ver_btdesired_8821c_1ant = 0x04; + + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8821c1ant_ + * ************************************************************ */ +u8 halbtc8821c1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821C_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821C_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8821C_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8821c1ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 index, IN u8 level_num, IN u8 rssi_thresh, IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821C_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821C_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8821C_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8821c1ant_update_ra_mask(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 dis_rate_mask) +{ + coex_dm->cur_ra_mask = dis_rate_mask; + + if (force_exec || (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_RAMASK, + &coex_dm->cur_ra_mask); + coex_dm->pre_ra_mask = coex_dm->cur_ra_mask; +} + +void halbtc8821c1ant_auto_rate_fallback_retry(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + boolean wifi_under_b_mode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + if (wifi_under_b_mode) { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +void halbtc8821c1ant_retry_limit(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || + (coex_dm->pre_retry_limit_type != + coex_dm->cur_retry_limit_type)) { + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +void halbtc8821c1ant_ampdu_max_time(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || + (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +void halbtc8821c1ant_limited_tx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ra_mask_type, IN u8 arfr_type, + IN u8 retry_limit_type, IN u8 ampdu_time_type) +{ + switch (ra_mask_type) { + case 0: /* normal mode */ + halbtc8821c1ant_update_ra_mask(btcoexist, force_exec, + 0x0); + break; + case 1: /* disable cck 1/2 */ + halbtc8821c1ant_update_ra_mask(btcoexist, force_exec, + 0x00000003); + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ + halbtc8821c1ant_update_ra_mask(btcoexist, force_exec, + 0x0001f1f7); + break; + default: + break; + } + + halbtc8821c1ant_auto_rate_fallback_retry(btcoexist, force_exec, + arfr_type); + halbtc8821c1ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8821c1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type); +} + +void halbtc8821c1ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +void halbtc8821c1ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WL query BT info!!\n"); + BTC_TRACE(trace_buf); +} + +void halbtc8821c1ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + static u8 num_of_bt_counter_chk = 0, cnt_slave = 0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + /* to avoid 0x76e[3] = 1 (WLAN_Act control by PTA) during IPS */ + /* if (! (btcoexist->btc_read_1byte(btcoexist, 0x76e) & 0x8) ) */ + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n", + reg_hp_rx, reg_hp_tx, reg_lp_rx, reg_lp_tx); + + BTC_TRACE(trace_buf); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + if ((coex_sta->low_priority_tx > 1150) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + + if ((coex_sta->low_priority_rx >= 1150) && + (coex_sta->low_priority_rx >= coex_sta->low_priority_tx) + && (!coex_sta->under_ips) && (!coex_sta->c2h_bt_inquiry_page) && + (coex_sta->bt_link_exist)) { + if (cnt_slave >= 3) { + bt_link_info->slave_role = true; + cnt_slave = 3; + } else + cnt_slave++; + } else { + if (cnt_slave == 0) { + bt_link_info->slave_role = false; + cnt_slave = 0; + } else + cnt_slave--; + + } + + if ((coex_sta->high_priority_tx == 0) && + (coex_sta->high_priority_rx == 0) && + (coex_sta->low_priority_tx == 0) && + (coex_sta->low_priority_rx == 0)) { + num_of_bt_counter_chk++; + if (num_of_bt_counter_chk >= 3) { + halbtc8821c1ant_query_bt_info(btcoexist); + num_of_bt_counter_chk = 0; + } + } + + +} + + + +void halbtc8821c1ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ +#if 1 + s32 wifi_rssi = 0; + boolean wifi_busy = false, wifi_under_b_mode = false; + static u8 cck_lock_counter = 0; + u32 total_cnt, reg_val1, reg_val2; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + coex_sta->crc_ok_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CRC32_OK_CCK); + coex_sta->crc_ok_11g = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CRC32_OK_LEGACY); + coex_sta->crc_ok_11n = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CRC32_OK_HT); + coex_sta->crc_ok_11n_vht = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_VHT); + + coex_sta->crc_err_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_CCK); + coex_sta->crc_err_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_LEGACY); + coex_sta->crc_err_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_HT); + coex_sta->crc_err_11n_vht = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_VHT); + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + total_cnt = coex_sta->crc_ok_cck + coex_sta->crc_ok_11g + + coex_sta->crc_ok_11n + coex_sta->crc_ok_11n_vht; + + if ((coex_dm->bt_status == BT_8821C_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == BT_8821C_1ANT_BT_STATUS_ACL_SCO_BUSY) + || + (coex_dm->bt_status == BT_8821C_1ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > (total_cnt - + coex_sta->crc_ok_cck)) { + if (cck_lock_counter < 3) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + + if (cck_lock_counter >= 3) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + if (coex_sta->cck_lock) + coex_sta->cck_ever_lock = true; + + coex_sta->pre_ccklock = coex_sta->cck_lock; + +#endif +} + +boolean halbtc8821c1ant_is_wifibt_status_changed(IN struct btc_coexist + *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false, pre_bt_off = false; + static u8 pre_hid_busy_num = 0; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (coex_sta->bt_disabled != pre_bt_off) { + pre_bt_off = coex_sta->bt_disabled; + + if (coex_sta->bt_disabled) + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!\n"); + else + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is enabled !!\n"); + + BTC_TRACE(trace_buf); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->bt_reg_vendor_ac = 0xffff; + coex_sta->bt_reg_vendor_ae = 0xffff; + return true; + } + + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + + if (!coex_sta->bt_disabled) { + + if (coex_sta->hid_busy_num != pre_hid_busy_num) { + pre_hid_busy_num = coex_sta->hid_busy_num; + return true; + } + } + } + + return false; +} + +void halbtc8821c1ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + boolean bt_busy = false; + + + coex_sta->num_of_profile = 0; + + /* set link exist status */ + if (!(coex_sta->bt_info & BT_INFO_8821C_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (coex_sta->bt_info & BT_INFO_8821C_1ANT_B_FTP) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->pan_exist = false; + + if (coex_sta->bt_info & BT_INFO_8821C_1ANT_B_A2DP) { + coex_sta->a2dp_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->a2dp_exist = false; + + if (coex_sta->bt_info & BT_INFO_8821C_1ANT_B_HID) { + coex_sta->hid_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->hid_exist = false; + + if (coex_sta->bt_info & BT_INFO_8821C_1ANT_B_SCO_ESCO) { + coex_sta->sco_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->sco_exist = false; + + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + bt_link_info->acl_busy = coex_sta->acl_busy; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; + + if (!(coex_sta->bt_info & BT_INFO_8821C_1ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8821C_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + } else if (coex_sta->bt_info == BT_INFO_8821C_1ANT_B_CONNECTION) { + /* connection exists but no busy */ + coex_dm->bt_status = BT_8821C_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if (((coex_sta->bt_info & BT_INFO_8821C_1ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8821C_1ANT_B_SCO_BUSY)) && + (coex_sta->bt_info & BT_INFO_8821C_1ANT_B_ACL_BUSY)) { + coex_dm->bt_status = BT_8821C_1ANT_BT_STATUS_ACL_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL SCO busy!!!\n"); + } else if ((coex_sta->bt_info & BT_INFO_8821C_1ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8821C_1ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8821C_1ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (coex_sta->bt_info & BT_INFO_8821C_1ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8821C_1ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8821C_1ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + } + + BTC_TRACE(trace_buf); + + if ((BT_8821C_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8821C_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8821C_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); +} + +void halbtc8821c1ant_update_wifi_channel_info(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + h2c_parameter[0] = + 0x1; /* enable BT AFH skip WL channel for 8821c because BT Rx LO interference */ + /* h2c_parameter[0] = 0x0; */ + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); + +} + +u8 halbtc8821c1ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8821C_1ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_1ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_1ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_1ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_1ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_1ANT_COEX_ALGO_SCO; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_1ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_1ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +void halbtc8821c1ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8821c1ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8821c1ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + + +void halbtc8821c1ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ + +#if 1 + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == + coex_dm->cur_low_penalty_ra) + return; + } + + if (low_penalty_ra) + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 15); + else + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 0); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; + +#endif + +} + + +void halbtc8821c1ant_write_score_board( + IN struct btc_coexist *btcoexist, + IN u16 bitpos, + IN boolean state +) +{ + + static u16 originalval = 0x8002; + + if (state) + originalval = originalval | bitpos; + else + originalval = originalval & (~bitpos); + + btcoexist->btc_write_2byte(btcoexist, 0xaa, originalval); +} + +void halbtc8821c1ant_read_score_board( + IN struct btc_coexist *btcoexist, + IN u16 *score_board_val +) +{ + + *score_board_val = (btcoexist->btc_read_2byte(btcoexist, + 0xaa)) & 0x7fff; +} + +void halbtc8821c1ant_post_state_to_bt( + IN struct btc_coexist *btcoexist, + IN u16 type, + IN boolean state +) +{ + + halbtc8821c1ant_write_score_board(btcoexist, (u16) type, state); + +} + +void halbtc8821c1ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false, wifi_under_5g = false; + u16 u16tmp; + + /* This function check if bt is disabled */ +#if 0 + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + + +#else + + /* Read BT on/off status from scoreboard[1], enable this only if BT patch support this feature */ + halbtc8821c1ant_read_score_board(btcoexist, &u16tmp); + + bt_active = u16tmp & BIT(1); + + +#endif + + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } else { + + bt_disable_cnt++; + if (bt_disable_cnt >= 10) { + bt_disabled = true; + bt_disable_cnt = 10; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if ((wifi_under_5g) || (bt_disabled)) + halbtc8821c1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + else + halbtc8821c1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, true); + + + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + coex_sta->bt_disabled = bt_disabled; + } + +} + +void halbtc8821c1ant_enable_gnt_to_gpio(IN struct btc_coexist *btcoexist, + boolean isenable) +{ +#if BT_8821C_1ANT_COEX_DBG + static u8 bitVal[5] = {0, 0, 0, 0, 0}; + static boolean state = false; + /* + if (state ==isenable) + return; + else + state = isenable; + */ + if (isenable) { + + /* enable GNT_WL, GNT_BT to GPIO for debug */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x1); + + /* store original value */ + bitVal[0] = (btcoexist->btc_read_1byte(btcoexist, + 0x66) & BIT(4)) >> 4; /*0x66[4] */ + bitVal[1] = (btcoexist->btc_read_1byte(btcoexist, + 0x67) & BIT(0)); /*0x66[8] */ + bitVal[2] = (btcoexist->btc_read_1byte(btcoexist, + 0x42) & BIT(3)) >> 3; /*0x40[19] */ + bitVal[3] = (btcoexist->btc_read_1byte(btcoexist, + 0x65) & BIT(7)) >> 7; /*0x64[15] */ + bitVal[4] = (btcoexist->btc_read_1byte(btcoexist, + 0x72) & BIT(2)) >> 2; /*0x70[18] */ + + /* switch GPIO Mux */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, BIT(4), + 0x0); /*0x66[4] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, BIT(0), + 0x0); /*0x66[8] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x42, BIT(3), + 0x0); /*0x40[19] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x65, BIT(7), + 0x0); /*0x64[15] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x72, BIT(2), + 0x0); /*0x70[18] = 0 */ + + + } else { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x0); + + /* Restore original value */ + /* switch GPIO Mux */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, BIT(4), + bitVal[0]); /*0x66[4] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, BIT(0), + bitVal[1]); /*0x66[8] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x42, BIT(3), + bitVal[2]); /*0x40[19] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x65, BIT(7), + bitVal[3]); /*0x64[15] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x72, BIT(2), + bitVal[4]); /*0x70[18] = 0 */ + } + +#endif +} + +u32 halbtc8821c1ant_ltecoex_indirect_read_reg(IN struct btc_coexist *btcoexist, + IN u16 reg_addr) +{ + u32 j = 0; + + + /* wait for ready bit before access 0x1700 */ + btcoexist->btc_write_4byte(btcoexist, 0x1700, 0x800F0000 | reg_addr); + + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x1703)&BIT(5)) == 0) && + (j < BT_8821C_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + return btcoexist->btc_read_4byte(btcoexist, + 0x1708); /* get read data */ + +} + +void halbtc8821c1ant_ltecoex_indirect_write_reg(IN struct btc_coexist + *btcoexist, + IN u16 reg_addr, IN u32 bit_mask, IN u32 reg_value) +{ + u32 val, i = 0, j = 0, bitpos = 0; + + + if (bit_mask == 0x0) + return; + if (bit_mask == 0xffffffff) { + btcoexist->btc_write_4byte(btcoexist, 0x1704, + reg_value); /* put write data */ + + /* wait for ready bit before access 0x1700 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x1703)&BIT(5)) == 0) && + (j < BT_8821C_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + btcoexist->btc_write_4byte(btcoexist, 0x1700, + 0xc00F0000 | reg_addr); + } else { + for (i = 0; i <= 31; i++) { + if (((bit_mask >> i) & 0x1) == 0x1) { + bitpos = i; + break; + } + } + + /* read back register value before write */ + val = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, + reg_addr); + val = (val & (~bit_mask)) | (reg_value << bitpos); + + btcoexist->btc_write_4byte(btcoexist, 0x1704, + val); /* put write data */ + + /* wait for ready bit before access 0x1700 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x1703)&BIT(5)) == 0) && + (j < BT_8821C_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + btcoexist->btc_write_4byte(btcoexist, 0x1700, + 0xc00F0000 | reg_addr); + + } + +} + +void halbtc8821c1ant_ltecoex_enable(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 val; + + val = (enable) ? 1 : 0; + halbtc8821c1ant_ltecoex_indirect_write_reg(btcoexist, 0x38, 0x80, + val); /* 0x38[7] */ + +} + +void halbtc8821c1ant_ltecoex_pathcontrol_owner(IN struct btc_coexist *btcoexist, + IN boolean wifi_control) +{ + u8 val; + + val = (wifi_control) ? 1 : 0; + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x4, + val); /* 0x70[26] */ + +} + +void halbtc8821c1ant_ltecoex_set_gnt_bt(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, bit_mask; + + state = state & 0x1; + val = (sw_control) ? ((state << 1) | 0x1) : 0; + + switch (control_block) { + case BT_8821C_1ANT_GNT_BLOCK_RFC_BB: + default: + bit_mask = 0xc000; + halbtc8821c1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[15:14] */ + bit_mask = 0x0c00; + halbtc8821c1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[11:10] */ + break; + case BT_8821C_1ANT_GNT_BLOCK_RFC: + bit_mask = 0xc000; + halbtc8821c1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[15:14] */ + break; + case BT_8821C_1ANT_GNT_BLOCK_BB: + bit_mask = 0x0c00; + halbtc8821c1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[11:10] */ + break; + + } + +} + +void halbtc8821c1ant_ltecoex_set_gnt_wl(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, bit_mask; + + state = state & 0x1; + val = (sw_control) ? ((state << 1) | 0x1) : 0; + + switch (control_block) { + case BT_8821C_1ANT_GNT_BLOCK_RFC_BB: + default: + bit_mask = 0x3000; + halbtc8821c1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[13:12] */ + bit_mask = 0x0300; + halbtc8821c1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[9:8] */ + break; + case BT_8821C_1ANT_GNT_BLOCK_RFC: + bit_mask = 0x3000; + halbtc8821c1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[13:12] */ + break; + case BT_8821C_1ANT_GNT_BLOCK_BB: + bit_mask = 0x0300; + halbtc8821c1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[9:8] */ + break; + + } + +} + +void halbtc8821c1ant_ltecoex_set_coex_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u16 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8821C_1ANT_CTT_WL_VS_LTE: + reg_addr = 0xa0; + break; + case BT_8821C_1ANT_CTT_BT_VS_LTE: + reg_addr = 0xa4; + break; + } + + if (reg_addr != 0x0000) + halbtc8821c1ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xffff, table_content); /* 0xa0[15:0] or 0xa4[15:0] */ + + +} + + +void halbtc8821c1ant_ltecoex_set_break_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u8 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8821C_1ANT_LBTT_WL_BREAK_LTE: + reg_addr = 0xa8; + break; + case BT_8821C_1ANT_LBTT_BT_BREAK_LTE: + reg_addr = 0xac; + break; + case BT_8821C_1ANT_LBTT_LTE_BREAK_WL: + reg_addr = 0xb0; + break; + case BT_8821C_1ANT_LBTT_LTE_BREAK_BT: + reg_addr = 0xb4; + break; + } + + if (reg_addr != 0x0000) + halbtc8821c1ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xff, table_content); /* 0xa8[15:0] or 0xb4[15:0] */ + + +} + +void halbtc8821c1ant_set_wltoggle_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 interval, + IN u8 val0x6c4_b0, IN u8 val0x6c4_b1, IN u8 val0x6c4_b2, + IN u8 val0x6c4_b3) +{ + static u8 pre_h2c_parameter[6] = {0}; + u8 cur_h2c_parameter[6] = {0}; + u8 i, match_cnt = 0; + + cur_h2c_parameter[0] = 0x7; /* op_code, 0x7= wlan toggle slot*/ + + cur_h2c_parameter[1] = interval; + cur_h2c_parameter[2] = val0x6c4_b0; + cur_h2c_parameter[3] = val0x6c4_b1; + cur_h2c_parameter[4] = val0x6c4_b2; + cur_h2c_parameter[5] = val0x6c4_b3; + + if (!force_exec) { + for (i = 1; i <= 5; i++) { + if (cur_h2c_parameter[i] != pre_h2c_parameter[i]) + break; + + match_cnt++; + } + + if (match_cnt == 5) + return; + } + + for (i = 1; i <= 5; i++) + pre_h2c_parameter[i] = cur_h2c_parameter[i]; + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, cur_h2c_parameter); +} + + +void halbtc8821c1ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8821c1ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + + halbtc8821c1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8821c1ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + u32 break_table; + u8 select_table; + + coex_sta->coex_table_type = type; + + if (coex_sta->concurrent_rx_mode_on == true) { + break_table = 0xf0ffffff; /* set WL hi-pri can break BT */ + select_table = + 0xb; /* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */ + } else { + break_table = 0xffffff; + select_table = 0x3; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** Table-%d **********\n", + coex_sta->coex_table_type); + BTC_TRACE(trace_buf); + + switch (type) { + case 0: + halbtc8821c1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x55555555, break_table, + select_table); + break; + case 1: + halbtc8821c1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, break_table, + select_table); + break; + case 2: + halbtc8821c1ant_coex_table(btcoexist, force_exec, + 0xaa5a5a5a, 0xaa5a5a5a, break_table, + select_table); + break; + case 3: + halbtc8821c1ant_coex_table(btcoexist, force_exec, + 0xaa555555, 0xaa5a5a5a, break_table, + select_table); + break; + case 4: + halbtc8821c1ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0xaa5a5a5a, break_table, + select_table); + break; + case 5: + halbtc8821c1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5a5a5a5a, break_table, + select_table); + break; + case 6: + halbtc8821c1ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0x5a5a5a5a, break_table, + select_table); + break; + case 7: + halbtc8821c1ant_coex_table(btcoexist, force_exec, + 0xaaaaaaaa, 0xaaaaaaaa, break_table, + select_table); + break; + case 8: + halbtc8821c1ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0xaaaaaaaa, break_table, + select_table); + break; + case 9: + halbtc8821c1ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0xaaaa5aaa, break_table, + select_table); + break; + default: + break; + } +} + +void halbtc8821c1ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT(0); /* function enable */ + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8821c1ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8821c1ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8821c1ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8821c1ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8821c1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8821c1ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + u8 h2c_parameter[5] = {0x8, 0, 0, 0, 0}; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + /*halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); */ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + /*halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8);*/ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +void halbtc8821c1ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + coex_sta->force_lps_on = false; + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + + break; + case BTC_PS_LPS_ON: + coex_sta->force_lps_on = true; + halbtc8821c1ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8821c1ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + + break; + case BTC_PS_LPS_OFF: + coex_sta->force_lps_on = false; + halbtc8821c1ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + + break; + default: + break; + } +} + + +void halbtc8821c1ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], FW for 1Ant AP mode\n"); + BTC_TRACE(trace_buf); + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + + halbtc8821c1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + } + } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + + halbtc8821c1ant_power_save_state( + btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } else { + halbtc8821c1ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, + 0x0); + } + + + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + + +void halbtc8821c1ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + struct btc_board_info *board_info = &btcoexist->board_info; + boolean wifi_busy = false; + static u8 psTdmaByte4Modify = 0x0, pre_psTdmaByte4Modify = 0x0; + static boolean pre_wifi_busy = false; + + +#if BT_8821C_1ANT_ANTDET_ENABLE + + if (board_info->btdm_ant_num_by_ant_det == 2) { +#if 0 + if (turn_on) + type = type + + 100; +#endif + } + +#endif + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (wifi_busy != pre_wifi_busy) { + force_exec = true; + pre_wifi_busy = wifi_busy; + } + + /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + if ((bt_link_info->slave_role) && (bt_link_info->a2dp_exist)) + psTdmaByte4Modify = 0x1; + else + psTdmaByte4Modify = 0x0; + + if (pre_psTdmaByte4Modify != psTdmaByte4Modify) { + + force_exec = true; + pre_psTdmaByte4Modify = psTdmaByte4Modify; + } + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + + if (coex_dm->cur_ps_tdma_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(off, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } + + + if (turn_on) { + switch (type) { + default: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x61, 0x35, 0x03, 0x11, 0x11); + break; + + case 3: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x51, 0x3a, 0x03, 0x10, 0x50); + break; + case 4: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x51, 0x21, 0x03, 0x10, 0x50); + break; + case 5: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x61, 0x15, 0x03, 0x11, 0x11); + break; + case 6: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x61, 0x20, 0x03, 0x11, 0x11); + break; + case 7: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x51, 0x10, 0x03, 0x10, 0x54 | + psTdmaByte4Modify); + break; + case 8: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x51, 0x10, 0x03, 0x10, 0x54 | + psTdmaByte4Modify); + break; + case 9: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x55, 0x10, 0x03, 0x10, 0x54 | + psTdmaByte4Modify); + break; + case 10: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x61, 0x30, 0x03, 0x11, 0x10); + break; + case 13: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x51, 0x25, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 14: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x51, 0x15, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 15: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x51, 0x20, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 17: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x61, 0x10, 0x03, 0x11, 0x14 | + psTdmaByte4Modify); + break; + case 18: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x51, 0x30, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 19: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x61, 0x15, 0x03, 0x11, 0x10); + break; + case 20: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x61, 0x30, 0x03, 0x11, 0x10); + break; + case 21: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x61, 0x30, 0x03, 0x11, 0x10); + break; + case 22: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x61, 0x25, 0x03, 0x11, 0x10); + break; + case 32: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x61, 0x35, 0x03, 0x11, 0x10); + break; + case 33: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x61, 0x35, 0x03, 0x11, 0x10); + break; + case 57: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x51, 0x10, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 58: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x51, 0x10, 0x03, 0x10, 0x50 | + psTdmaByte4Modify); + break; + case 67: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0x61, 0x10, 0x03, 0x11, 0x10 | + psTdmaByte4Modify); + break; + + /* 1-Ant to 2-Ant TDMA case */ + case 103: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x3a, 0x03, 0x70, 0x10); + break; + case 104: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x21, 0x03, 0x70, 0x10); + break; + case 105: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x15, 0x03, 0x71, 0x11); + break; + case 106: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x20, 0x03, 0x71, 0x11); + break; + case 107: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x10, 0x03, 0x70, 0x14 | + psTdmaByte4Modify); + break; + case 108: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x10, 0x03, 0x70, 0x14 | + psTdmaByte4Modify); + break; + case 113: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x25, 0x03, 0x70, 0x10 | + psTdmaByte4Modify); + break; + case 114: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x15, 0x03, 0x70, 0x10 | + psTdmaByte4Modify); + break; + case 115: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xd3, 0x20, 0x03, 0x70, 0x10 | + psTdmaByte4Modify); + break; + case 117: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x10, 0x03, 0x71, 0x14 | + psTdmaByte4Modify); + break; + case 119: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x15, 0x03, 0x71, 0x10); + break; + case 120: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x30, 0x03, 0x71, 0x10); + break; + case 121: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x30, 0x03, 0x71, 0x10); + break; + case 122: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x25, 0x03, 0x71, 0x10); + break; + case 132: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x35, 0x03, 0x71, 0x11); + break; + case 133: + halbtc8821c1ant_set_fw_pstdma(btcoexist, + 0xe3, 0x35, 0x03, 0x71, 0x10); + break; + + } + } else { + + /* disable PS tdma */ + switch (type) { + case 8: /* PTA Control */ + halbtc8821c1ant_set_fw_pstdma(btcoexist, 0x8, + 0x0, 0x0, 0x0, 0x0); + break; + case 0: + default: /* Software control, Antenna at BT side */ + halbtc8821c1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x0, 0x0); + break; + case 1: /* 2-Ant, 0x778=3, antenna control by antenna diversity */ + halbtc8821c1ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x48, 0x0); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void halbtc8821c1ant_set_int_block(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 pos_type) +{ +#if 0 + u8 regval_0xcba; + u32 u32tmp1 = 0; + + coex_dm->cur_int_block_status = pos_type; + + if (!force_exec) { + if (coex_dm->pre_int_block_status == + coex_dm->cur_int_block_status) + return; + } + + coex_dm->pre_int_block_status = coex_dm->cur_int_block_status; + + regval_0xcba = btcoexist->btc_read_1byte(btcoexist, 0xcba); + + switch (pos_type) { + + case BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLG_OF_BTG: + regval_0xcba = (regval_0xcba | BIT(0)) & (~(BIT( + 2))); /* 0xcb8[16] = 1, 0xcb8[18] = 0, WL_G select BTG */ + regval_0xcba = regval_0xcba & 0x0f; + + /*btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc1d, 0x0f, 0x5); */ /* Gain Table */ + /*btcoexist->btc_write_1byte_bitmask(btcoexist, 0xa9e, 0x0f, 0x2); */ /* CCK Gain Table */ + + break; + case BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLG_OF_WLAG: + regval_0xcba = regval_0xcba & (~(BIT(2) | BIT( + 0))); /* 0xcb8[16] = 0, 0xcb8[18] = 0, WL_G select WLAG */ + + /* regval_0xcba = regval_0xcba | BIT(4) | BIT(5) ; */ /* 0xcb8[21:20] = 2b'11, WL_G @ WLAG on */ + /* regval_0xcba = (regval_0xcba | BIT(6)) & (~(BIT(7)) ) ; */ /* 0xcb8[23:22] = 2b'01, WL_A @ WLAG off */ + /*btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc1d, 0x0f, 0x0); */ /* Gain Table */ + /*btcoexist->btc_write_1byte_bitmask(btcoexist, 0xa9e, 0x0f, 0x6); */ /* CCK Gain Table */ + + break; + case BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLA_OF_WLAG: + regval_0xcba = regval_0xcba & (~(BIT(2) | BIT( + 0))); /* 0xcb8[16] = 0, 0xcb8[18] = 0, WL_G select WLAG */ + /*regval_0xcba = (regval_0xcba | BIT(4)) & (~(BIT(5))); */ /* 0xcb8[21:20] = 2b'01, WL_G @ WLAG off */ + /*regval_0xcba = regval_0xcba | BIT(6) | BIT(7); */ /* 0xcb8[23:22] = 2b'11, WL_A @ WLAG on */ + + break; + } + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcba, 0xff, + regval_0xcba); + + u32tmp1 = btcoexist->btc_read_4byte(btcoexist, 0xcb8); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (After Int Block setup) 0xcb8 = 0x%08x **********\n", + u32tmp1); + BTC_TRACE(trace_buf); + +#endif +} + +void halbtc8821c1ant_set_ext_band_switch(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 pos_type) +{ + +#if 0 + boolean switch_polatiry_inverse = false; + u8 regval_0xcb6; + u32 u32tmp1 = 0, u32tmp2 = 0; + + if (!rfe_type->ext_band_switch_exist) + return; + + coex_dm->cur_ext_band_switch_status = pos_type; + + if (!force_exec) { + if (coex_dm->pre_ext_band_switch_status == + coex_dm->cur_ext_band_switch_status) + return; + } + + coex_dm->pre_ext_band_switch_status = + coex_dm->cur_ext_band_switch_status; + + /* swap control polarity if use different switch control polarity*/ + switch_polatiry_inverse = (rfe_type->ext_band_switch_ctrl_polarity == 1 + ? ~switch_polatiry_inverse : switch_polatiry_inverse); + + /*swap control polarity for WL_A, default polarity 0xcb4[21] = 0 && 0xcb4[23] = 1 is for WL_G */ + switch_polatiry_inverse = (pos_type == + BT_8821C_1ANT_EXT_BAND_SWITCH_TO_WLA ? ~switch_polatiry_inverse + : switch_polatiry_inverse); + + regval_0xcb6 = btcoexist->btc_read_1byte(btcoexist, 0xcb6); + + /* for normal switch polrity, 0xcb4[21] =1 && 0xcb4[23] = 0 for WL_A, vice versa */ + regval_0xcb6 = (switch_polatiry_inverse == 1 ? ((regval_0xcb6 & (~(BIT( + 7)))) | BIT(5)) : ((regval_0xcb6 & (~(BIT(5)))) | BIT(7))); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb6, 0xff, + regval_0xcb6); + + u32tmp1 = btcoexist->btc_read_4byte(btcoexist, 0xcb0); + u32tmp2 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (After Ext Band switch setup) 0xcb0 = 0x%08x, 0xcb4 = 0x%08x**********\n", + u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); +#endif + +} + +void halbtc8821c1ant_set_ext_ant_switch(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ctrl_type, IN u8 pos_type) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + boolean switch_polatiry_inverse = false; + u8 regval_0xcb7 = 0, regval_0x64; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + + if (!rfe_type->ext_ant_switch_exist) + return; + + coex_dm->cur_ext_ant_switch_status = (ctrl_type << 8) + pos_type; + + if (!force_exec) { + if (coex_dm->pre_ext_ant_switch_status == + coex_dm->cur_ext_ant_switch_status) + return; + } + + coex_dm->pre_ext_ant_switch_status = coex_dm->cur_ext_ant_switch_status; + + /* swap control polarity if use different switch control polarity*/ + /* Normal switch polarity for DPDT, 0xcb4[29:28] = 2b'01 => BTG to Main, WLG to Aux, 0xcb4[29:28] = 2b'10 => BTG to Aux, WLG to Main */ + /* Normal switch polarity for SPDT, 0xcb4[29:28] = 2b'01 => Ant to BTG, 0xcb4[29:28] = 2b'10 => Ant to WLG */ + switch_polatiry_inverse = (rfe_type->ext_ant_switch_ctrl_polarity == 1 ? + ~switch_polatiry_inverse : switch_polatiry_inverse); + + /* swap control polarity if 1-Ant at Aux */ + if ((rfe_type->ext_ant_switch_type == + BT_8821C_1ANT_EXT_ANT_SWITCH_USE_DPDT) && + (board_info->single_ant_path == 0)) + switch_polatiry_inverse = ~switch_polatiry_inverse; + + switch (pos_type) { + default: + case BT_8821C_1ANT_EXT_ANT_SWITCH_TO_BT: + case BT_8821C_1ANT_EXT_ANT_SWITCH_TO_NOCARE: + + break; + case BT_8821C_1ANT_EXT_ANT_SWITCH_TO_WLG: + switch_polatiry_inverse = (rfe_type->wlg_Locate_at_btg + == 0 ? ~switch_polatiry_inverse : + switch_polatiry_inverse); + break; + case BT_8821C_1ANT_EXT_ANT_SWITCH_TO_WLA: + /*switch_polatiry_inverse = (rfe_type->ext_band_switch_exist == 1? ~switch_polatiry_inverse: switch_polatiry_inverse);*/ + break; + } + + if (board_info->ant_div_cfg) + ctrl_type = BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV; + + + switch (ctrl_type) { + default: + case BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, + 0xff, 0x77); /* BB SW, DPDT use RFE_ctrl8 and RFE_ctrl9 as control pin */ + + regval_0xcb7 = (switch_polatiry_inverse == false ? + 0x1 : 0x2); /* 0xcb4[29:28] = 2b'01 for no switch_polatiry_inverse, DPDT_SEL_N =1, DPDT_SEL_P =0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, + 0x30, regval_0xcb7); + + break; + case BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_PTA: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, + 0xff, 0x66); /* PTA, DPDT use RFE_ctrl8 and RFE_ctrl9 as control pin */ + + regval_0xcb7 = (switch_polatiry_inverse == false ? + 0x2 : 0x1); /* 0xcb4[29:28] = 2b'10 for no switch_polatiry_inverse, DPDT_SEL_N =1, DPDT_SEL_P =0 @ GNT_BT=1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, + 0x30, regval_0xcb7); + + break; + case BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, + 0xff, 0x88); /* */ + + /* no regval_0xcb7 setup required, because antenna switch control value by antenna diversity */ + + break; + case BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_MAC: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x1); /* 0x4c[23] = 1 */ + + regval_0x64 = (switch_polatiry_inverse == false ? 0x0 : + 0x1); /* 0x64[0] = 1b'0 for no switch_polatiry_inverse, DPDT_SEL_N =1, DPDT_SEL_P =0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, + regval_0x64); + break; + case BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_BT: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x0); /* 0x4c[24] = 0 */ + + /* no setup required, because antenna switch control value by BT vendor 0xac[1:0] */ + break; + } + + /* PAPE, LNA_ON control by BT while WLAN off for current leakage issue */ + if (ctrl_type == BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_BT) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, + 0x0); /* PAPE 0x64[29] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x10, + 0x0); /* LNA_ON 0x64[28] = 0 */ + } else { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, + 0x1); /* PAPE 0x64[29] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x10, + 0x1); /* LNA_ON 0x64[28] = 1 */ + } + +#if BT_8821C_1ANT_COEX_DBG + u32tmp1 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u32tmp2 = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0x64) & 0xff; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], (After Ext Ant switch setup) 0xcb4 = 0x%08x, 0x4c = 0x%08x, 0x64= 0x%02x\n", + u32tmp1, u32tmp2, u32tmp3); + BTC_TRACE(trace_buf); +#endif + +} + +void halbtc8821c1ant_set_rfe_type(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + +#if 0 + rfe_type->ext_band_switch_exist = false; + rfe_type->ext_band_switch_type = + BT_8821C_1ANT_EXT_BAND_SWITCH_USE_SPDT; /* SPDT; */ + rfe_type->ext_band_switch_ctrl_polarity = 0; + + if (rfe_type->ext_band_switch_exist) { + + /* band switch use RFE_ctrl1 (pin name: PAPE_A) and RFE_ctrl3 (pin name: LNAON_A) */ + + /* set RFE_ctrl1 as software control */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb0, 0xf0, 0x7); + + /* set RFE_ctrl3 as software control */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb1, 0xf0, 0x7); + + } +#endif + + /* the following setup should be got from Efuse in the future */ + rfe_type->rfe_module_type = board_info->rfe_type & 0x1f; + + rfe_type->ext_ant_switch_ctrl_polarity = 0; + + switch (rfe_type->rfe_module_type) { + case 0: + default: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_1ANT_EXT_ANT_SWITCH_USE_DPDT; /*2-Ant, DPDT, WLG*/ + rfe_type->wlg_Locate_at_btg = false; + break; + case 1: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_1ANT_EXT_ANT_SWITCH_USE_SPDT; /*1-Ant, Main, DPDT or SPDT, WLG */ + rfe_type->wlg_Locate_at_btg = false; + break; + case 2: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_1ANT_EXT_ANT_SWITCH_USE_SPDT; /*1-Ant, Main, DPDT or SPDT, BTG */ + rfe_type->wlg_Locate_at_btg = true; + break; + case 3: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_1ANT_EXT_ANT_SWITCH_USE_DPDT; /*1-Ant, Aux, DPDT, WLG */ + rfe_type->wlg_Locate_at_btg = false; + break; + case 4: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_1ANT_EXT_ANT_SWITCH_USE_DPDT; /*1-Ant, Aux, DPDT, BTG */; + rfe_type->wlg_Locate_at_btg = true; + break; + case 5: + rfe_type->ext_ant_switch_exist = + false; /*2-Ant, no antenna switch, WLG*/ + rfe_type->ext_ant_switch_type = + BT_8821C_1ANT_EXT_ANT_SWITCH_NONE; + rfe_type->wlg_Locate_at_btg = false; + break; + case 6: + rfe_type->ext_ant_switch_exist = + false; /*2-Ant, no antenna switch, WLG*/ + rfe_type->ext_ant_switch_type = + BT_8821C_1ANT_EXT_ANT_SWITCH_NONE; + rfe_type->wlg_Locate_at_btg = false; + break; + case 7: + rfe_type->ext_ant_switch_exist = + true; /*2-Ant, DPDT, BTG*/ + rfe_type->ext_ant_switch_type = + BT_8821C_1ANT_EXT_ANT_SWITCH_USE_DPDT; + rfe_type->wlg_Locate_at_btg = true; + break; + } + + + if (rfe_type->wlg_Locate_at_btg) + halbtc8821c1ant_set_int_block(btcoexist, FORCE_EXEC, + BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLG_OF_BTG); + else + halbtc8821c1ant_set_int_block(btcoexist, FORCE_EXEC, + BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLG_OF_WLAG); + + +} + + +void halbtc8821c1ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean force_exec, + IN u8 phase) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 cnt_bt_cal_chk = 0; + boolean is_in_mp_mode = false; + u8 u8tmp = 0; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + u16 u16tmp1 = 0; + +#if BT_8821C_1ANT_ANTDET_ENABLE + + if (ant_pos_type == BTC_ANT_PATH_PTA) { + if ((board_info->btdm_ant_det_finish) && + (board_info->btdm_ant_num_by_ant_det == 2)) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = BTC_ANT_PATH_WIFI; + else + ant_pos_type = BTC_ANT_PATH_BT; + } + } + +#endif + +#if 1 + u32tmp1 = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + u32tmp2 = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, + 0x54); + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex],(Before Ant Setup) 0xcb4 = 0x%x, 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x\n", + u32tmp3, u8tmp, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); +#endif + + coex_dm->cur_ant_pos_type = (ant_pos_type << 8) + phase; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex],(Before Ant Setup) pre_ant_pos_type = 0x%x, cur_ant_pos_type = 0x%x\n", + coex_dm->pre_ant_pos_type, + coex_dm->cur_ant_pos_type); + BTC_TRACE(trace_buf); + + + if (!force_exec) { + if (coex_dm->cur_ant_pos_type == coex_dm->pre_ant_pos_type) + return; + } + + coex_dm->pre_ant_pos_type = coex_dm->cur_ant_pos_type; + + + switch (phase) { + case BT_8821C_1ANT_PHASE_COEX_POWERON: + + /* set Path control owner to WL at initial step */ + halbtc8821c1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8821C_1ANT_PCO_BTSIDE); + + /* set GNT_BT to SW high */ + halbtc8821c1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_1ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW high */ + halbtc8821c1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_1ANT_SIG_STA_SET_TO_HIGH); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + coex_sta->run_time_state = false; + + break; + case BT_8821C_1ANT_PHASE_COEX_INIT: + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8821c1ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8821c1ant_ltecoex_set_coex_table( + btcoexist, + BT_8821C_1ANT_CTT_WL_VS_LTE, + 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8821c1ant_ltecoex_set_coex_table( + btcoexist, + BT_8821C_1ANT_CTT_BT_VS_LTE, + 0xffff); + + /* Wait If BT IQK running, because Path control owner is at BT during BT IQK (setup by WiFi firmware) */ + while (cnt_bt_cal_chk <= 20) { + u8tmp = btcoexist->btc_read_1byte( + btcoexist, + 0x49c); + cnt_bt_cal_chk++; + if (u8tmp & BIT(1)) { + BTC_SPRINTF( + trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ########### BT is calibrating (wait cnt=%d) ###########\n", + cnt_bt_cal_chk); + BTC_TRACE( + trace_buf); + delay_ms(50); + } else { + BTC_SPRINTF( + trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ********** BT is NOT calibrating (wait cnt=%d)**********\n", + cnt_bt_cal_chk); + BTC_TRACE( + trace_buf); + break; + } + } + + /* set Path control owner to WL at initial step */ + halbtc8821c1ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8821C_1ANT_PCO_WLSIDE); + + /* set GNT_BT to SW high */ + halbtc8821c1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_1ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW low */ + halbtc8821c1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_1ANT_SIG_STA_SET_TO_LOW); + + coex_sta->run_time_state = false; + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + break; + case BT_8821C_1ANT_PHASE_WLANONLY_INIT: + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8821c1ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8821c1ant_ltecoex_set_coex_table( + btcoexist, + BT_8821C_1ANT_CTT_WL_VS_LTE, + 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8821c1ant_ltecoex_set_coex_table( + btcoexist, + BT_8821C_1ANT_CTT_BT_VS_LTE, + 0xffff); + + /* set Path control owner to WL at initial step */ + halbtc8821c1ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8821C_1ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Low */ + halbtc8821c1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_1ANT_SIG_STA_SET_TO_LOW); + /* Set GNT_WL to SW high */ + halbtc8821c1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_1ANT_SIG_STA_SET_TO_HIGH); + + coex_sta->run_time_state = false; + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_WIFI; + + break; + case BT_8821C_1ANT_PHASE_WLAN_OFF: + /* Disable LTE Coex Function in WiFi side */ + halbtc8821c1ant_ltecoex_enable(btcoexist, 0x0); + + /* set Path control owner to BT */ + halbtc8821c1ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8821C_1ANT_PCO_BTSIDE); + + /* Set Ext Ant Switch to BT control at wifi off step */ + halbtc8821c1ant_set_ext_ant_switch(btcoexist, + FORCE_EXEC, + BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_BT, + BT_8821C_1ANT_EXT_ANT_SWITCH_TO_NOCARE); + + coex_sta->run_time_state = false; + break; + case BT_8821C_1ANT_PHASE_2G_RUNTIME: + + while (cnt_bt_cal_chk <= 20) { + /* 0x49c[0]=1 WL IQK, 0x49c[1]=1 BT IQK*/ + u8tmp = btcoexist->btc_read_1byte( + btcoexist, + 0x49c); + + cnt_bt_cal_chk++; + if (u8tmp & BIT(0)) { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ########### WL is IQK (wait cnt=%d)\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + delay_ms(50); + } else if (u8tmp & BIT(1)) { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ########### BT is IQK (wait cnt=%d)\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + delay_ms(50); + } else { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ********** WL and BT is NOT IQK (wait cnt=%d)\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + break; + } + } + + /* set Path control owner to WL at runtime step */ + halbtc8821c1ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8821C_1ANT_PCO_WLSIDE); + + /* set GNT_BT to PTA */ + halbtc8821c1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8821C_1ANT_SIG_STA_SET_BY_HW); + + halbtc8821c1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8821C_1ANT_SIG_STA_SET_BY_HW); + + coex_sta->run_time_state = true; + + if (BTC_ANT_PATH_AUTO == ant_pos_type) { + if (rfe_type->wlg_Locate_at_btg) + ant_pos_type = + BTC_ANT_PATH_WIFI; + else + ant_pos_type = BTC_ANT_PATH_PTA; + } + + if (rfe_type->wlg_Locate_at_btg) + halbtc8821c1ant_set_int_block(btcoexist, + NORMAL_EXEC, + BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLG_OF_BTG); + else + halbtc8821c1ant_set_int_block(btcoexist, + NORMAL_EXEC, + BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLG_OF_WLAG); + + break; + case BT_8821C_1ANT_PHASE_5G_RUNTIME: + + /* set Path control owner to WL at runtime step */ + halbtc8821c1ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8821C_1ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Hi */ + halbtc8821c1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8821C_1ANT_SIG_STA_SET_BY_HW); + + /* Set GNT_WL to SW Hi */ + halbtc8821c1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_1ANT_SIG_STA_SET_TO_HIGH); + + coex_sta->run_time_state = true; + + if (BTC_ANT_PATH_AUTO == ant_pos_type) { + /* if (rfe_type->ext_band_switch_exist) + ant_pos_type = BTC_ANT_PATH_PTA; + else */ + ant_pos_type = + BTC_ANT_PATH_WIFI5G; + } + + halbtc8821c1ant_set_int_block(btcoexist, + NORMAL_EXEC, + BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLA_OF_WLAG); + + break; + case BT_8821C_1ANT_PHASE_BTMPMODE: + /* Disable LTE Coex Function in WiFi side */ + halbtc8821c1ant_ltecoex_enable(btcoexist, 0x0); + + /* set Path control owner to WL */ + halbtc8821c1ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8821C_1ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Hi */ + halbtc8821c1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_1ANT_SIG_STA_SET_TO_HIGH); + + /* Set GNT_WL to SW Lo */ + halbtc8821c1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_1ANT_SIG_STA_SET_TO_LOW); + + coex_sta->run_time_state = false; + + /* Set Ext Ant Switch to BT side at BT MP mode */ + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + break; + case BT_8821C_1ANT_PHASE_ANTENNA_DET: + halbtc8821c1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8821C_1ANT_PCO_WLSIDE); + + /* set GNT_BT to high */ + halbtc8821c1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_1ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to high */ + halbtc8821c1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8821C_1ANT_GNT_BLOCK_RFC_BB, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_1ANT_SIG_STA_SET_TO_HIGH); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + coex_sta->run_time_state = false; + + break; + } + + if (phase != BT_8821C_1ANT_PHASE_WLAN_OFF) { + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + halbtc8821c1ant_set_ext_ant_switch( + btcoexist, + force_exec, + BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW, + BT_8821C_1ANT_EXT_ANT_SWITCH_TO_WLG); + break; + case BTC_ANT_PATH_WIFI5G + : + halbtc8821c1ant_set_ext_ant_switch( + btcoexist, + force_exec, + BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW, + BT_8821C_1ANT_EXT_ANT_SWITCH_TO_WLA); + break; + case BTC_ANT_PATH_BT: + halbtc8821c1ant_set_ext_ant_switch( + btcoexist, + force_exec, + BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW, + BT_8821C_1ANT_EXT_ANT_SWITCH_TO_BT); + break; + default: + case BTC_ANT_PATH_PTA: + halbtc8821c1ant_set_ext_ant_switch( + btcoexist, + force_exec, + BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_PTA, + BT_8821C_1ANT_EXT_ANT_SWITCH_TO_NOCARE); + break; + } + + } +#if 1 + u32tmp1 = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex],(After Ant-Setup phase---%d) 0xcb4 = 0x%x, 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x\n", + phase, u32tmp3, u8tmp, u32tmp1, u32tmp2); + + BTC_TRACE(trace_buf); +#endif +} + + +boolean halbtc8821c1ant_is_common_action(IN struct btc_coexist *btcoexist) +{ + boolean common = false, wifi_connected = false, wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected && + BT_8821C_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + + common = true; + } else if (wifi_connected && + (BT_8821C_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + + common = true; + } else if (!wifi_connected && + (BT_8821C_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + + common = true; + } else if (wifi_connected && + (BT_8821C_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + + common = true; + } else if (!wifi_connected && + (BT_8821C_1ANT_BT_STATUS_CONNECTED_IDLE != + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + + common = true; + } else { + if (wifi_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } + + common = false; + } + + return common; +} + + +/* ********************************************* + * + * Software Coex Mechanism start + * + * ********************************************* */ + + + +/* ********************************************* + * + * Non-Software Coex Mechanism start + * + * ********************************************* */ +void halbtc8821c1ant_action_bt_whck_test(IN struct btc_coexist *btcoexist) +{ + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8821c1ant_action_wifi_under5g(IN struct btc_coexist *btcoexist) +{ + + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8821C_1ANT_PHASE_5G_RUNTIME); +} + + +void halbtc8821c1ant_action_wifi_only(IN struct btc_coexist *btcoexist) +{ + halbtc8821c1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + halbtc8821c1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 7); +} + +void halbtc8821c1ant_action_wifi_multi_port(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + + if (!bt_link_info->pan_exist) + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + else + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8821c1ant_action_hs(IN struct btc_coexist *btcoexist) +{ + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); +} + +void halbtc8821c1ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, wifi_busy = false, + bt_busy = false; + boolean wifi_scan = false, wifi_link = false, wifi_roam = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &wifi_link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &wifi_roam); + + + if ((wifi_link) || (wifi_roam) || (coex_sta->wifi_is_high_pri_task)) { + + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist)) + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + else + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + + } else if (((wifi_scan) || (wifi_busy)) && + (coex_sta->bt_create_connection)) { + + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist)) + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + else + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + + } else if ((!wifi_connected) && (!wifi_scan)) { + + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist)) { + + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 6); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + + } else if ((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) { + + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + } else if (bt_link_info->a2dp_exist) { + + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (wifi_scan) { + + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + } else if (wifi_busy) { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 21); + + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 19); + + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } +} + +void halbtc8821c1ant_action_bt_sco_hid_only_busy(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, + &wifi_bw); + + if ((wifi_bw == 0) && + ((coex_sta->hid_busy_num >= 2) || + (bt_link_info->sco_exist))) { /* if 11bg mode */ + /*for 4/18 hid or SCO/eSCo */ + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 9); + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 10); + } else { + if (bt_link_info->sco_exist) { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 5); + } else { /* HID */ + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 6); + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 5); + } + } +} + +void halbtc8821c1ant_action_wifi_connected_bt_acl_busy(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_busy = false, wifi_turbo = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); +#if 1 + if ((wifi_busy) && (coex_sta->scan_ap_num <= 4)) + wifi_turbo = true; +#endif + if (bt_link_info->hid_only) { /* HID */ + halbtc8821c1ant_action_bt_sco_hid_only_busy(btcoexist, + wifi_status); + return; + } else if (bt_link_info->a2dp_only) { /* A2DP */ + if (BT_8821C_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + + if (coex_sta->scan_ap_num >= + BT_8821C_1ANT_WIFI_NOISY_THRESH) { + + if (coex_sta->is_setupLink) + halbtc8821c1ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 67); + else + halbtc8821c1ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 17); + } else { + if (coex_sta->is_setupLink) + halbtc8821c1ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 57); + else + halbtc8821c1ant_ps_tdma(btcoexist, + NORMAL_EXEC, true, 7); + } + + if (wifi_turbo) + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + else + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if (((bt_link_info->a2dp_exist) && + (bt_link_info->pan_exist)) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { /* A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP) */ + + if (wifi_busy) { + if (((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) || + (!coex_sta->is_A2DP_3M)) + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 15); + else if (wifi_turbo) + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 18); + else + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 13); + } else + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 14); + + if (bt_link_info->hid_exist) + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + else if (wifi_turbo) + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + else + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { /* HID+A2DP */ + + if (coex_sta->is_setupLink) { + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 1); + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 58); + } else { + + if ((wifi_busy) && (coex_sta->hid_busy_num >= 2)) { /*for 4/18 hid */ + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + halbtc8821c1ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 9); + } else { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 8); + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } + } + + } else if ((bt_link_info->pan_only) || (bt_link_info->hid_exist && + bt_link_info->pan_exist)) { /* PAN(OPP,FTP), HID+PAN(OPP,FTP) */ + if (BT_8821C_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 4); + else + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + + if (bt_link_info->hid_exist) + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + else if (wifi_turbo) + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + else + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + /* BT no-profile busy (0x9) */ + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } +} + +void halbtc8821c1ant_action_wifi_not_connected(IN struct btc_coexist *btcoexist) +{ + /* tdma and coex table */ + halbtc8821c1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8821c1ant_action_wifi_not_connected_scan(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if (num_of_wifi_link >= 2) { + halbtc8821c1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8821c1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8821c1ant_action_bt_inquiry(btcoexist); + } else + halbtc8821c1ant_action_wifi_multi_port(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8821c1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821c1ant_action_hs(btcoexist); + return; + } + + /* tdma and coex table */ + if (BT_8821C_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist) { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((BT_8821C_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8821C_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8821c1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8821C_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8821c1ant_action_wifi_connected_scan(IN struct btc_coexist + *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if (num_of_wifi_link >= 2) { + halbtc8821c1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8821c1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8821c1ant_action_bt_inquiry(btcoexist); + } else + halbtc8821c1ant_action_wifi_multi_port(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8821c1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821c1ant_action_hs(btcoexist); + return; + } + + + /* tdma and coex table */ + if (BT_8821C_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist) { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } else { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } else if ((BT_8821C_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8821C_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8821c1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8821C_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8821c1ant_action_wifi_not_connected_asso_auth( + IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if (num_of_wifi_link >= 2) { + halbtc8821c1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8821c1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8821c1ant_action_bt_inquiry(btcoexist); + } else + halbtc8821c1ant_action_wifi_multi_port(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8821c1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821c1ant_action_hs(btcoexist); + return; + } + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8821c1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else if (bt_link_info->pan_exist) { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8821c1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821c1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 2); + } +} + +void halbtc8821c1ant_action_wifi_connected_specific_packet( + IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + boolean wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if (num_of_wifi_link >= 2) { + halbtc8821c1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8821c1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8821c1ant_action_bt_inquiry(btcoexist); + } else + halbtc8821c1ant_action_wifi_multi_port(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8821c1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821c1ant_action_hs(btcoexist); + return; + } + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + /* no specific packet process for both WiFi and BT very busy */ + if ((wifi_busy) && ((bt_link_info->pan_exist) || + (coex_sta->num_of_profile >= 2))) + return; + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist)) { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } else if (bt_link_info->a2dp_exist) { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (bt_link_info->pan_exist) { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + } +} + +void halbtc8821c1ant_action_wifi_connected(IN struct btc_coexist *btcoexist) +{ + boolean wifi_busy = false; + boolean scan = false, link = false, roam = false; + boolean under_4way = false, wifi_under_5g = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect()===>\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 5G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_action_wifi_under5g(btcoexist); + return; + } + + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (under_4way) { + halbtc8821c1ant_action_wifi_connected_specific_packet( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + if (scan || link || roam) { + if (scan) + halbtc8821c1ant_action_wifi_connected_scan(btcoexist); + else + halbtc8821c1ant_action_wifi_connected_specific_packet( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + + /* tdma and coex table */ + if (!wifi_busy) { + if (BT_8821C_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8821c1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8821C_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else if ((BT_8821C_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8821C_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8821c1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8821C_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else { + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 2); + } + } else { + if (BT_8821C_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8821c1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8821C_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else if ((BT_8821C_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8821C_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8821c1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8821C_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else { + + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8821c1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + } + } +} + +void halbtc8821c1ant_run_sw_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + + algorithm = halbtc8821c1ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + + if (!halbtc8821c1ant_is_common_action(btcoexist)) { + switch (coex_dm->cur_algorithm) { + case BT_8821C_1ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + /* halbtc8821c1ant_action_sco(btcoexist); */ + break; + case BT_8821C_1ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID.\n"); + BTC_TRACE(trace_buf); + /* halbtc8821c1ant_action_hid(btcoexist); */ + break; + case BT_8821C_1ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + /* halbtc8821c1ant_action_a2dp(btcoexist); */ + break; + case BT_8821C_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + /* halbtc8821c1ant_action_a2dp_pan_hs(btcoexist); */ + break; + case BT_8821C_1ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + /* halbtc8821c1ant_action_pan_edr(btcoexist); */ + break; + case BT_8821C_1ANT_COEX_ALGO_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HS mode.\n"); + BTC_TRACE(trace_buf); + /* halbtc8821c1ant_action_pan_hs(btcoexist); */ + break; + case BT_8821C_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + /* halbtc8821c1ant_action_pan_edr_a2dp(btcoexist); */ + break; + case BT_8821C_1ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + /* halbtc8821c1ant_action_pan_edr_hid(btcoexist); */ + break; + case BT_8821C_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + /* halbtc8821c1ant_action_hid_a2dp_pan_edr(btcoexist); */ + break; + case BT_8821C_1ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + /* halbtc8821c1ant_action_hid_a2dp(btcoexist); */ + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = coexist All Off!!\n"); + BTC_TRACE(trace_buf); + /* halbtc8821c1ant_coex_all_off(btcoexist); */ + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + + +void halbtc8821c1ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + boolean increase_scan_dev_num = false; + boolean bt_ctrl_agg_buf_size = false; + boolean miracast_plus_bt = false, wifi_under_5g = false; + u8 agg_buf_size = 5; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0, wifi_bw; + u8 iot_peer = BTC_IOT_PEER_UNKNOWN; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (!coex_sta->run_time_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], return for run_time_state = false !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->freeze_coexrun_by_btinfo) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), return for freeze_coexrun_by_btinfo\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 5G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_action_wifi_under5g(btcoexist); + return; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 2G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + + if (coex_sta->bt_whck_test) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under WHCK TEST!!!\n"); + BTC_TRACE(trace_buf); + halbtc8821c1ant_action_bt_whck_test(btcoexist); + return; + } + + if (coex_sta->bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!!\n"); + halbtc8821c1ant_action_wifi_only(btcoexist); + return; + } + + if ((BT_8821C_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8821C_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8821C_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + increase_scan_dev_num = true; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, + &increase_scan_dev_num); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + BTC_TRACE(trace_buf); + + if (bt_link_info->bt_link_exist) { + halbtc8821c1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, + 0, 1); + miracast_plus_bt = true; + } else { + halbtc8821c1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, + 0, 0); + miracast_plus_bt = false; + } + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + halbtc8821c1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8821c1ant_action_bt_inquiry(btcoexist); + } else + halbtc8821c1ant_action_wifi_multi_port(btcoexist); + + + return; + } + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if ((bt_link_info->bt_link_exist) && (wifi_connected)) { + halbtc8821c1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, 0, 1); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_IOT_PEER, &iot_peer); + + if (BTC_IOT_PEER_CISCO != iot_peer) { + if (bt_link_info->sco_exist) /* if (bt_link_info->bt_hi_pri_link_exist) */ + halbtc8821c1ant_limited_rx(btcoexist, + NORMAL_EXEC, true, false, 0x5); + else + halbtc8821c1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, false, 0x5); + } else { + if (bt_link_info->sco_exist) + halbtc8821c1ant_limited_rx(btcoexist, + NORMAL_EXEC, true, false, 0x5); + else { + if (BTC_WIFI_BW_HT40 == wifi_bw) + halbtc8821c1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, true, 0x10); + else + halbtc8821c1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, true, 0x8); + } + } + + halbtc8821c1ant_run_sw_coexist_mechanism( + btcoexist); /* just print debug message */ + } else { + halbtc8821c1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + halbtc8821c1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x5); + + halbtc8821c1ant_run_sw_coexist_mechanism( + btcoexist); /* just print debug message */ + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8821c1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8821c1ant_action_hs(btcoexist); + return; + } + + + if (!wifi_connected) { + boolean scan = false, link = false, roam = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is non connected-idle !!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], scan = %d, link = %d, roam = %d !!!\n", + scan, link, roam); + BTC_TRACE(trace_buf); + + if (scan) + halbtc8821c1ant_action_wifi_not_connected_scan( + btcoexist); + else + halbtc8821c1ant_action_wifi_not_connected_asso_auth( + btcoexist); + } else + halbtc8821c1ant_action_wifi_not_connected(btcoexist); + } else /* wifi LPS/Busy */ + halbtc8821c1ant_action_wifi_connected(btcoexist); +} + +void halbtc8821c1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + halbtc8821c1ant_low_penalty_ra(btcoexist, FORCE_EXEC, false); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->pop_event_cnt = 0; + coex_sta->cnt_RemoteNameReq = 0; + coex_sta->cnt_ReInit = 0; + coex_sta->cnt_setupLink = 0; + coex_sta->cnt_IgnWlanAct = 0; + coex_sta->cnt_Page = 0; + + halbtc8821c1ant_query_bt_info(btcoexist); +} + +void halbtc8821c1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean back_up, IN boolean wifi_only) +{ + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + u16 u16tmp1 = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 1Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u32tmp1 = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex],(Before Init HW config) 0xcb4 = 0x%x, 0x38= 0x%x, 0x54= 0x%x\n", + u32tmp3, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); + + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->bt_reg_vendor_ac = 0xffff; + coex_sta->bt_reg_vendor_ae = 0xffff; + coex_sta->isolation_btween_wb = BT_8821C_1ANT_DEFAULT_ISOLATION; + + + /* Setup RF front end type */ + halbtc8821c1ant_set_rfe_type(btcoexist); + + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = (btcoexist->btc_read_1byte(btcoexist, + 0xf1) & 0xf0) >> 4; + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + + /* BT report packet sample rate */ + btcoexist->btc_write_1byte(btcoexist, 0x790, 0x5); + + /* Init 0x778 = 0x1 for 1-Ant */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + + /* Enable PTA (3-wire function form BT side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x41, 0x02, 0x1); + + /* Enable PTA (tx/rx signal form WiFi side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4c6, 0x10, 0x1); + + /* set GNT_BT=1 for coex table select both */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x763, 0x10, 0x1); + + halbtc8821c1ant_enable_gnt_to_gpio(btcoexist, true); + + /* check if WL firmware download ok */ + /*if (btcoexist->btc_read_1byte(btcoexist, 0x80) == 0xc6)*/ + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ONOFF, true); + + /* PTA parameter */ + halbtc8821c1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + + halbtc8821c1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + psd_scan->ant_det_is_ant_det_available = true; + + /* Antenna config */ + if (wifi_only) { + coex_sta->concurrent_rx_mode_on = false; + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_WIFI, + FORCE_EXEC, + BT_8821C_1ANT_PHASE_WLANONLY_INIT); + + btcoexist->stop_coex_dm = true; + } else { + /*Set BT polluted packet on for Tx rate adaptive not including Tx retry break by PTA, 0x45c[19] =1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + + coex_sta->concurrent_rx_mode_on = true; + /* btcoexist->btc_write_1byte_bitmask(btcoexist, 0x953, 0x2, 0x1); */ + + /* RF 0x1[1] = 0->Set GNT_WL_RF_Rx always = 1 for con-current Rx, mask Tx only */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0x2, 0x0); + + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_1ANT_PHASE_COEX_INIT); + + btcoexist->stop_coex_dm = false; + } + + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u32tmp1 = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], (After Init HW config) 0xcb4 = 0x%x, 0x38= 0x%x, 0x54= 0x%x\n", + u32tmp3, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); + +} + +#if 0 +u32 halbtc8821c1ant_psd_log2base(IN struct btc_coexist *btcoexist, IN u32 val) +{ + u8 j; + u32 tmp, tmp2, val_integerd_b = 0, tindex, shiftcount = 0; + u32 result, val_fractiond_b = 0, table_fraction[21] = {0, 432, 332, 274, 232, 200, + 174, 151, 132, 115, 100, 86, 74, 62, 51, 42, + 32, 23, 15, 7, 0 + }; + + if (val == 0) + return 0; + + tmp = val; + + while (1) { + if (tmp == 1) + break; + + tmp = (tmp >> 1); + shiftcount++; + } + + + val_integerd_b = shiftcount + 1; + + tmp2 = 1; + for (j = 1; j <= val_integerd_b; j++) + tmp2 = tmp2 * 2; + + tmp = (val * 100) / tmp2; + tindex = tmp / 5; + + if (tindex > 20) + tindex = 20; + + val_fractiond_b = table_fraction[tindex]; + + result = val_integerd_b * 100 - val_fractiond_b; + + return result; + + +} + +void halbtc8821c1ant_psd_show_antenna_detect_result(IN struct btc_coexist + *btcoexist) +{ + u8 *cli_buf = btcoexist->cli_buf; + struct btc_board_info *board_info = &btcoexist->board_info; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n============[Antenna Detection info] ============\n"); + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 12) { /* Get Ant Det from BT */ + + if (board_info->btdm_ant_num_by_ant_det == 1) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "1-Antenna", + BT_8821C_1ANT_ANTDET_PSDTHRES_1ANT, + BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION); + else { + + if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION) + * 100) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (>%d)", + "Ant Det Result", "2-Antenna (Bad-Isolation)", + BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "2-Antenna (Good-Isolation)", + BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION, + BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + } + } else if (psd_scan->ant_det_result == 1) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (>%d)", + "Ant Det Result", "2-Antenna (Bad-Isolation)", + BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else if (psd_scan->ant_det_result == 2) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "2-Antenna (Good-Isolation)", + BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset, + BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "1-Antenna", + BT_8821C_1ANT_ANTDET_PSDTHRES_1ANT, + BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset); + + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s ", + "Antenna Detection Finish", + (board_info->btdm_ant_det_finish + ? "Yes" : "No")); + CL_PRINTF(cli_buf); + + switch (psd_scan->ant_det_result) { + case 0: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is not available)"); + break; + case 1: /* 2-Ant bad-isolation */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 2: /* 2-Ant good-isolation */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 3: /* 1-Ant */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 4: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Uncertainty result)"); + break; + case 5: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "(Pre-Scan fai)"); + break; + case 6: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(WiFi is Scanning)"); + break; + case 7: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is not idle)"); + break; + case 8: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Abort by WiFi Scanning)"); + break; + case 9: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Antenna Init is not ready)"); + break; + case 10: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is Inquiry or page)"); + break; + case 11: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is Disabled)"); + case 12: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available, result from BT"); + break; + } + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 12) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d dB", + "PSD Scan Peak Value", + psd_scan->ant_det_psd_scan_peak_val / 100); + CL_PRINTF(cli_buf); + return; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "Ant Detect Total Count", psd_scan->ant_det_try_count); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "Ant Detect Fail Count", psd_scan->ant_det_fail_count); + CL_PRINTF(cli_buf); + + if ((!board_info->btdm_ant_det_finish) && + (psd_scan->ant_det_result != 5)) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Response", + (psd_scan->ant_det_result ? "ok" : "fail")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ms", "BT Tx Time", + psd_scan->ant_det_bt_tx_time); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "BT Tx Ch", + psd_scan->ant_det_bt_le_channel); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + "WiFi PSD Cent-Ch/Offset/Span", + psd_scan->real_cent_freq, psd_scan->real_offset, + psd_scan->real_span); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d dB", + "PSD Pre-Scan Peak Value", + psd_scan->ant_det_pre_psdscan_peak_val / 100); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (<= %d)", + "PSD Pre-Scan result", + (psd_scan->ant_det_result != 5 ? "ok" : "fail"), + BT_8821C_1ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 5) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s dB", + "PSD Scan Peak Value", psd_scan->ant_det_peak_val); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s MHz", + "PSD Scan Peak Freq", psd_scan->ant_det_peak_freq); + CL_PRINTF(cli_buf); + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "TFBGA Package", + (board_info->tfbga_package) ? "Yes" : "No"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "PSD Threshold Offset", psd_scan->ant_det_thres_offset); + CL_PRINTF(cli_buf); + +} + + + +void halbtc8821c1ant_psd_showdata(IN struct btc_coexist *btcoexist) +{ + u8 *cli_buf = btcoexist->cli_buf; + u32 delta_freq_per_point; + u32 freq, freq1, freq2, n = 0, i = 0, j = 0, m = 0, psd_rep1, psd_rep2; + + if (psd_scan->ant_det_result == 12) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n\n============[PSD info] (%d)============\n", + psd_scan->psd_gen_count); + CL_PRINTF(cli_buf); + + if (psd_scan->psd_gen_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n No data !!\n"); + CL_PRINTF(cli_buf); + return; + } + + if (psd_scan->psd_point == 0) + delta_freq_per_point = 0; + else + delta_freq_per_point = psd_scan->psd_band_width / + psd_scan->psd_point; + + /* if (psd_scan->is_psd_show_max_only) */ + if (0) { + psd_rep1 = psd_scan->psd_max_value / 100; + psd_rep2 = psd_scan->psd_max_value - psd_rep1 * 100; + + freq = ((psd_scan->real_cent_freq - 20) * 1000000 + + psd_scan->psd_max_value_point * delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (freq2 < 100) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n Freq = %d.0%d MHz", + freq1, freq2); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n Freq = %d.%d MHz", + freq1, freq2); + + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + ", Value = %d.0%d dB, (%d)\n", + psd_rep1, psd_rep2, psd_scan->psd_max_value); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + ", Value = %d.%d dB, (%d)\n", + psd_rep1, psd_rep2, psd_scan->psd_max_value); + + CL_PRINTF(cli_buf); + } else { + m = psd_scan->psd_start_point; + n = psd_scan->psd_start_point; + i = 1; + j = 1; + + while (1) { + do { + freq = ((psd_scan->real_cent_freq - 20) * + 1000000 + m * + delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (i == 1) { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.000", + freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.0%2d", + freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.%3d", + freq1, + freq2); + } else if ((i % 8 == 0) || + (m == psd_scan->psd_stop_point)) { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.000\n", freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.0%2d\n", freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.%3d\n", freq1, + freq2); + } else { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.000", freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.0%2d", freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.%3d", freq1, + freq2); + } + + i++; + m++; + CL_PRINTF(cli_buf); + + } while ((i <= 8) && (m <= psd_scan->psd_stop_point)); + + + do { + psd_rep1 = psd_scan->psd_report_max_hold[n] / + 100; + psd_rep2 = psd_scan->psd_report_max_hold[n] - + psd_rep1 * + 100; + + if (j == 1) { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Val %7d.0%d", + psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Val %7d.%d", + psd_rep1, + psd_rep2); + } else if ((j % 8 == 0) || + (n == psd_scan->psd_stop_point)) { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.0%d\n", psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.%d\n", psd_rep1, + psd_rep2); + } else { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.0%d", psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.%d", psd_rep1, + psd_rep2); + } + + j++; + n++; + CL_PRINTF(cli_buf); + + } while ((j <= 8) && (n <= psd_scan->psd_stop_point)); + + if ((m > psd_scan->psd_stop_point) || + (n > psd_scan->psd_stop_point)) + break; + + i = 1; + j = 1; + + } + } + + +} + +#pragma optimize("", off) +void halbtc8821c1ant_psd_maxholddata(IN struct btc_coexist *btcoexist, + IN u32 gen_count) +{ + u32 i = 0; + u32 loop_i_max = 0, loop_val_max = 0; + + if (gen_count == 1) { + memcpy(psd_scan->psd_report_max_hold, + psd_scan->psd_report, + BT_8821C_1ANT_ANTDET_PSD_POINTS * sizeof(u32)); + } + + for (i = psd_scan->psd_start_point; + i <= psd_scan->psd_stop_point; i++) { + + /* update max-hold value at each freq point */ + if (psd_scan->psd_report[i] > psd_scan->psd_report_max_hold[i]) + psd_scan->psd_report_max_hold[i] = + psd_scan->psd_report[i]; + + /* search the max value in this seep */ + if (psd_scan->psd_report[i] > loop_val_max) { + loop_val_max = psd_scan->psd_report[i]; + loop_i_max = i; + } + } + + if (gen_count <= BT_8821C_1ANT_ANTDET_PSD_SWWEEPCOUNT) + psd_scan->psd_loop_max_value[gen_count - 1] = loop_val_max; +} + +#pragma optimize("", off) +u32 halbtc8821c1ant_psd_getdata(IN struct btc_coexist *btcoexist, IN u32 point) +{ + /* reg 0x808[9:0]: FFT data x */ + /* reg 0x808[22]: 0-->1 to get 1 FFT data y */ + /* reg 0x8b4[15:0]: FFT data y report */ + + u32 val = 0, psd_report = 0; + int k = 0; + + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + + val &= 0xffbffc00; + val |= point; + + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + val |= 0x00400000; + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + while (1) { + if (k++ > BT_8821C_1ANT_ANTDET_SWEEPPOINT_DELAY) + break; + } + + val = btcoexist->btc_read_4byte(btcoexist, 0x8b4); + + psd_report = val & 0x0000ffff; + + return psd_report; +} + +#pragma optimize("", off) +boolean halbtc8821c1ant_psd_sweep_point(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN s32 offset, IN u32 span, IN u32 points, + IN u32 avgnum, IN u32 loopcnt) +{ + u32 i = 0, val = 0, n = 0, k = 0, j, point_index = 0; + u32 points1 = 0, psd_report = 0; + u32 start_p = 0, stop_p = 0, delta_freq_per_point = 156250; + u32 psd_center_freq = 20 * 10 ^ 6; + boolean outloop = false, scan , roam, is_sweep_ok = true; + u8 flag = 0; + u32 tmp = 0, u32tmp1 = 0; + u32 wifi_original_channel = 1; + u32 psd_sum = 0, avg_cnt = 0; + u32 i_max = 0, val_max = 0, val_max2 = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx PSD Sweep Start!!\n"); + BTC_TRACE(trace_buf); + + do { + switch (flag) { + case 0: /* Get PSD parameters */ + default: + + psd_scan->psd_band_width = 40 * 1000000; + psd_scan->psd_point = points; + psd_scan->psd_start_base = points / 2; + psd_scan->psd_avg_num = avgnum; + psd_scan->real_cent_freq = cent_freq; + psd_scan->real_offset = offset; + psd_scan->real_span = span; + + + points1 = psd_scan->psd_point; + delta_freq_per_point = psd_scan->psd_band_width / + psd_scan->psd_point; + + /* PSD point setup */ + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + val &= 0xffff0fff; + + switch (psd_scan->psd_point) { + case 128: + val |= 0x0; + break; + case 256: + default: + val |= 0x00004000; + break; + case 512: + val |= 0x00008000; + break; + case 1024: + val |= 0x0000c000; + break; + } + + switch (psd_scan->psd_avg_num) { + case 1: + val |= 0x0; + break; + case 8: + val |= 0x00001000; + break; + case 16: + val |= 0x00002000; + break; + case 32: + default: + val |= 0x00003000; + break; + } + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + flag = 1; + break; + case 1: /* calculate the PSD point index from freq/offset/span */ + psd_center_freq = psd_scan->psd_band_width / 2 + + offset * (1000000); + + start_p = psd_scan->psd_start_base + (psd_center_freq - + span * (1000000) / 2) / delta_freq_per_point; + psd_scan->psd_start_point = start_p - + psd_scan->psd_start_base; + + stop_p = psd_scan->psd_start_base + (psd_center_freq + + span * (1000000) / 2) / delta_freq_per_point; + psd_scan->psd_stop_point = stop_p - + psd_scan->psd_start_base - 1; + + flag = 2; + break; + case 2: /* set RF channel/BW/Mode */ + + /* set 3-wire off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x88c); + val |= 0x00300000; + btcoexist->btc_write_4byte(btcoexist, 0x88c, val); + + /* CCK off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x800); + val &= 0xfeffffff; + btcoexist->btc_write_4byte(btcoexist, 0x800, val); + + /* Tx-pause on */ + btcoexist->btc_write_1byte(btcoexist, 0x522, 0x6f); + + /* store WiFi original channel */ + wifi_original_channel = btcoexist->btc_get_rf_reg( + btcoexist, BTC_RF_A, 0x18, 0x3ff); + + /* Set RF channel */ + if (cent_freq == 2484) + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x18, 0x3ff, 0xe); + else + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x18, 0x3ff, (cent_freq - 2412) / 5 + + 1); /* WiFi TRx Mask on */ + + /* save original RCK value */ + u32tmp1 = btcoexist->btc_get_rf_reg( + btcoexist, BTC_RF_A, 0x1d, 0xfffff); + + /* Enter debug mode */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xde, + 0x2, 0x1); + + /* Set RF Rx filter corner */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1d, + 0xfffff, 0x2e); + + + /* Set RF mode = Rx, RF Gain = 0x320a0 */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x0, + 0xfffff, 0x320a0); + + while (1) { + if (k++ > BT_8821C_1ANT_ANTDET_SWEEPPOINT_DELAY) + break; + } + flag = 3; + break; + case 3: + psd_scan->psd_gen_count = 0; + for (j = 1; j <= loopcnt; j++) { + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || roam) { + is_sweep_ok = false; + break; + } + memset(psd_scan->psd_report, 0, + psd_scan->psd_point * sizeof(u32)); + start_p = psd_scan->psd_start_point + + psd_scan->psd_start_base; + stop_p = psd_scan->psd_stop_point + + psd_scan->psd_start_base + 1; + + i = start_p; + point_index = 0; + + while (i < stop_p) { + if (i >= points1) + psd_report = + halbtc8821c1ant_psd_getdata( + btcoexist, i - points1); + else + psd_report = + halbtc8821c1ant_psd_getdata( + btcoexist, i); + + if (psd_report == 0) + tmp = 0; + else + /* tmp = 20*log10((double)psd_report); */ + /* 20*log2(x)/log2(10), log2Base return theresult of the psd_report*100 */ + tmp = 6 * halbtc8821c1ant_psd_log2base( + btcoexist, psd_report); + + n = i - psd_scan->psd_start_base; + psd_scan->psd_report[n] = tmp; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Point=%d, psd_dB_data = %d\n", + i, psd_scan->psd_report[n]); + BTC_TRACE(trace_buf); + + i++; + + } + + halbtc8821c1ant_psd_maxholddata(btcoexist, j); + + psd_scan->psd_gen_count = j; + + /*Accumulate Max PSD value in this loop if the value > threshold */ + if (psd_scan->psd_loop_max_value[j - 1] >= + 4000) { + psd_sum = psd_sum + + psd_scan->psd_loop_max_value[j - + 1]; + avg_cnt++; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Loop=%d, Max_dB_data = %d\n", + j, psd_scan->psd_loop_max_value[j + - 1]); + BTC_TRACE(trace_buf); + + } + + if (loopcnt == BT_8821C_1ANT_ANTDET_PSD_SWWEEPCOUNT) { + + /* search the Max Value between each-freq-point-max-hold value of all sweep*/ + for (i = 1; + i <= BT_8821C_1ANT_ANTDET_PSD_SWWEEPCOUNT; + i++) { + + if (i == 1) { + i_max = i; + val_max = psd_scan->psd_loop_max_value[i + - 1]; + val_max2 = + psd_scan->psd_loop_max_value[i + - 1]; + } else if ( + psd_scan->psd_loop_max_value[i - + 1] > val_max) { + val_max2 = val_max; + i_max = i; + val_max = psd_scan->psd_loop_max_value[i + - 1]; + } else if ( + psd_scan->psd_loop_max_value[i - + 1] > val_max2) + val_max2 = + psd_scan->psd_loop_max_value[i + - 1]; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "i = %d, val_hold= %d, val_max = %d, val_max2 = %d\n", + i, psd_scan->psd_loop_max_value[i + - 1], + val_max, val_max2); + + BTC_TRACE(trace_buf); + } + + psd_scan->psd_max_value_point = i_max; + psd_scan->psd_max_value = val_max; + psd_scan->psd_max_value2 = val_max2; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "val_max = %d, val_max2 = %d\n", + psd_scan->psd_max_value, + psd_scan->psd_max_value2); + BTC_TRACE(trace_buf); + } + + if (avg_cnt != 0) { + psd_scan->psd_avg_value = (psd_sum / avg_cnt); + if ((psd_sum % avg_cnt) >= (avg_cnt / 2)) + psd_scan->psd_avg_value++; + } else + psd_scan->psd_avg_value = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "AvgLoop=%d, Avg_dB_data = %d\n", + avg_cnt, psd_scan->psd_avg_value); + BTC_TRACE(trace_buf); + + flag = 100; + break; + case 99: /* error */ + + outloop = true; + break; + case 100: /* recovery */ + + /* set 3-wire on */ + val = btcoexist->btc_read_4byte(btcoexist, 0x88c); + val &= 0xffcfffff; + btcoexist->btc_write_4byte(btcoexist, 0x88c, val); + + /* CCK on */ + val = btcoexist->btc_read_4byte(btcoexist, 0x800); + val |= 0x01000000; + btcoexist->btc_write_4byte(btcoexist, 0x800, val); + + /* Tx-pause off */ + btcoexist->btc_write_1byte(btcoexist, 0x522, 0x0); + + /* PSD off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + val &= 0xffbfffff; + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + /* restore RF Rx filter corner */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1d, + 0xfffff, u32tmp1); + + /* Exit debug mode */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xde, + 0x2, 0x0); + + /* restore WiFi original channel */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x18, + 0x3ff, wifi_original_channel); + + outloop = true; + break; + + } + + } while (!outloop); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx PSD Sweep Stop!!\n"); + BTC_TRACE(trace_buf); + return is_sweep_ok; + +} + +#pragma optimize("", off) +boolean halbtc8821c1ant_psd_antenna_detection(IN struct btc_coexist + *btcoexist) +{ + u32 i = 0; + u32 wlpsd_cent_freq = 2484, wlpsd_span = 2; + s32 wlpsd_offset = -4; + u32 bt_tx_time, bt_le_channel; + u8 bt_le_ch[13] = {3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 33}; + + u8 h2c_parameter[3] = {0}, u8tmpa, u8tmpb; + + u8 state = 0; + boolean outloop = false, bt_resp = false, ant_det_finish = false; + u32 freq, freq1, freq2, psd_rep1, psd_rep2, delta_freq_per_point, + u32tmp, u32tmp0, u32tmp1, u32tmp2; + struct btc_board_info *board_info = &btcoexist->board_info; + + memset(psd_scan->ant_det_peak_val, 0, 16 * sizeof(u8)); + memset(psd_scan->ant_det_peak_freq, 0, 16 * sizeof(u8)); + + psd_scan->ant_det_bt_tx_time = + BT_8821C_1ANT_ANTDET_BTTXTIME; /* 0.42ms*50 = 20ms (0.42ms = 1 PSD sweep) */ + psd_scan->ant_det_bt_le_channel = BT_8821C_1ANT_ANTDET_BTTXCHANNEL; + + bt_tx_time = psd_scan->ant_det_bt_tx_time; + bt_le_channel = psd_scan->ant_det_bt_le_channel; + + if (board_info->tfbga_package) /* for TFBGA */ + psd_scan->ant_det_thres_offset = 5; + else + psd_scan->ant_det_thres_offset = 0; + + do { + switch (state) { + case 0: + if (bt_le_channel == 39) + wlpsd_cent_freq = 2484; + else { + for (i = 1; i <= 13; i++) { + if (bt_le_ch[i - 1] == + bt_le_channel) { + wlpsd_cent_freq = 2412 + + (i - 1) * 5; + break; + } + } + + if (i == 14) { + + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Abort!!, Invalid LE channel = %d\n ", + bt_le_channel); + BTC_TRACE(trace_buf); + outloop = true; + break; + } + } +#if 0 + wlpsd_sweep_count = bt_tx_time * 238 / + 100; /* bt_tx_time/0.42 */ + wlpsd_sweep_count = wlpsd_sweep_count / 5; + + if (wlpsd_sweep_count % 5 != 0) + wlpsd_sweep_count = (wlpsd_sweep_count / + 5 + 1) * 5; +#endif + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), BT_LETxTime=%d, BT_LECh = %d\n", + bt_tx_time, bt_le_channel); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), wlpsd_cent_freq=%d, wlpsd_offset = %d, wlpsd_span = %d, wlpsd_sweep_count = %d\n", + wlpsd_cent_freq, + wlpsd_offset, + wlpsd_span, + BT_8821C_1ANT_ANTDET_PSD_SWWEEPCOUNT); + BTC_TRACE(trace_buf); + + state = 1; + break; + case 1: /* stop coex DM & set antenna path */ + /* Stop Coex DM */ + btcoexist->stop_coex_dm = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Stop Coex DM!!\n"); + BTC_TRACE(trace_buf); + + /* Set TDMA off, */ + halbtc8821c1ant_ps_tdma(btcoexist, FORCE_EXEC, + false, 0); + + /* Set coex table */ + halbtc8821c1ant_coex_table_with_type(btcoexist, + FORCE_EXEC, 0); + + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna at Main Port\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna at Aux Port\n"); + BTC_TRACE(trace_buf); + } + + /* Set Antenna path, switch WiFi to un-certain antenna port */ + /* Set Antenna Path, both GNT_WL/GNT_BT = 1, and control by SW */ + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_BT, + FORCE_EXEC, + BT_8821C_1ANT_PHASE_ANTENNA_DET); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set Antenna to BT!!\n"); + BTC_TRACE(trace_buf); + + /* Set AFH mask on at WiFi channel 2472MHz +/- 10MHz */ + h2c_parameter[0] = 0x1; + h2c_parameter[1] = 0xd; + h2c_parameter[2] = 0x14; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set AFH on, Cent-Ch= %d, Mask=%d\n", + h2c_parameter[1], + h2c_parameter[2]); + BTC_TRACE(trace_buf); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, + h2c_parameter); + + u32tmp0 = btcoexist->btc_read_4byte(btcoexist, 0x70); + u32tmp1 = halbtc8821c1ant_ltecoex_indirect_read_reg( + btcoexist, 0x38); + u32tmp2 = halbtc8821c1ant_ltecoex_indirect_read_reg( + btcoexist, 0x54); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** 0x70 = 0x%x, 0x38= 0x%x, 0x54= 0x%x (Before Ant Det)\n", + u32tmp0, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); + + state = 2; + break; + case 2: /* Pre-sweep background psd */ + if (!halbtc8821c1ant_psd_sweep_point(btcoexist, + wlpsd_cent_freq, wlpsd_offset, wlpsd_span, + BT_8821C_1ANT_ANTDET_PSD_POINTS, + BT_8821C_1ANT_ANTDET_PSD_AVGNUM, 3)) { + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 8; + state = 99; + break; + } + + psd_scan->ant_det_pre_psdscan_peak_val = + psd_scan->psd_max_value; + + if (psd_scan->ant_det_pre_psdscan_peak_val > + (BT_8821C_1ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset) * 100) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Abort Antenna Detection!! becaus background = %d > thres (%d)\n", + psd_scan->ant_det_pre_psdscan_peak_val / + 100, + BT_8821C_1ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + BTC_TRACE(trace_buf); + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 5; + state = 99; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Start Antenna Detection!! becaus background = %d <= thres (%d)\n", + psd_scan->ant_det_pre_psdscan_peak_val / + 100, + BT_8821C_1ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + BTC_TRACE(trace_buf); + state = 3; + } + break; + case 3: + + bt_resp = btcoexist->btc_set_bt_ant_detection( + btcoexist, (u8)(bt_tx_time & 0xff), + (u8)(bt_le_channel & 0xff)); + + /* Sync WL Rx PSD with BT Tx time because H2C->Mailbox delay */ + delay_ms(20); + + if (!halbtc8821c1ant_psd_sweep_point(btcoexist, + wlpsd_cent_freq, wlpsd_offset, + wlpsd_span, + BT_8821C_1ANT_ANTDET_PSD_POINTS, + BT_8821C_1ANT_ANTDET_PSD_AVGNUM, + BT_8821C_1ANT_ANTDET_PSD_SWWEEPCOUNT)) { + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 8; + state = 99; + break; + } + +#if 1 + psd_scan->ant_det_psd_scan_peak_val = + psd_scan->psd_max_value; +#endif +#if 0 + psd_scan->ant_det_psd_scan_peak_val = + ((psd_scan->psd_max_value - psd_scan->psd_avg_value) < + 800) ? + psd_scan->psd_max_value : (( + psd_scan->psd_max_value - + psd_scan->psd_max_value2 <= 300) ? + psd_scan->psd_avg_value : + psd_scan->psd_max_value2); +#endif + psd_scan->ant_det_psd_scan_peak_freq = + psd_scan->psd_max_value_point; + state = 4; + break; + case 4: + + if (psd_scan->psd_point == 0) + delta_freq_per_point = 0; + else + delta_freq_per_point = + psd_scan->psd_band_width / + psd_scan->psd_point; + + psd_rep1 = psd_scan->ant_det_psd_scan_peak_val / 100; + psd_rep2 = psd_scan->ant_det_psd_scan_peak_val - + psd_rep1 * + 100; + + freq = ((psd_scan->real_cent_freq - 20) * + 1000000 + psd_scan->psd_max_value_point + * delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (freq2 < 100) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Max Value: Freq = %d.0%d MHz", + freq1, freq2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_freq, + BT_8821C_1ANT_ANTDET_BUF_LEN, + "%d.0%d", freq1, freq2); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Max Value: Freq = %d.%d MHz", + freq1, freq2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_freq, + BT_8821C_1ANT_ANTDET_BUF_LEN, + "%d.%d", freq1, freq2); + } + + if (psd_rep2 < 10) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + ", Value = %d.0%d dB\n", + psd_rep1, psd_rep2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_val, + BT_8821C_1ANT_ANTDET_BUF_LEN, + "%d.0%d", psd_rep1, psd_rep2); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + ", Value = %d.%d dB\n", + psd_rep1, psd_rep2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_val, + BT_8821C_1ANT_ANTDET_BUF_LEN, + "%d.%d", psd_rep1, psd_rep2); + } + + psd_scan->ant_det_is_btreply_available = true; + + if (bt_resp == false) { + psd_scan->ant_det_is_btreply_available = + false; + psd_scan->ant_det_result = 0; + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), BT Response = Fail\n "); + BTC_TRACE(trace_buf); + } else if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION) + * 100) { + psd_scan->ant_det_result = 1; + ant_det_finish = true; + board_info->btdm_ant_num_by_ant_det = 2; + coex_sta->isolation_btween_wb = (u8)(85 - + psd_scan->ant_det_psd_scan_peak_val / + 100) & 0xff; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 2-Ant, Bad-Isolation!!\n"); + BTC_TRACE(trace_buf); + } else if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset) * 100) { + psd_scan->ant_det_result = 2; + ant_det_finish = true; + board_info->btdm_ant_num_by_ant_det = 2; + coex_sta->isolation_btween_wb = (u8)(85 - + psd_scan->ant_det_psd_scan_peak_val / + 100) & 0xff; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 2-Ant, Good-Isolation!!\n"); + BTC_TRACE(trace_buf); + } else if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8821C_1ANT_ANTDET_PSDTHRES_1ANT) * + 100) { + psd_scan->ant_det_result = 3; + ant_det_finish = true; + board_info->btdm_ant_num_by_ant_det = 1; + coex_sta->isolation_btween_wb = (u8)(85 - + psd_scan->ant_det_psd_scan_peak_val / + 100) & 0xff; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 1-Ant!!\n"); + BTC_TRACE(trace_buf); + } else { + psd_scan->ant_det_result = 4; + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 1-Ant, un-certainity!!\n"); + BTC_TRACE(trace_buf); + } + + state = 99; + break; + case 99: /* restore setup */ + + /* Set AFH mask off at WiFi channel 2472MHz +/- 10MHz */ + h2c_parameter[0] = 0x0; + h2c_parameter[1] = 0x0; + h2c_parameter[2] = 0x0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set AFH on, Cent-Ch= %d, Mask=%d\n", + h2c_parameter[1], h2c_parameter[2]); + BTC_TRACE(trace_buf); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, + h2c_parameter); + + /* Set Antenna Path, GNT_WL/GNT_BT control by PTA */ + /* Set Antenna path, switch WiFi to certain antenna port */ + halbtc8821c1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set Antenna to PTA\n!!"); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Resume Coex DM\n!!"); + BTC_TRACE(trace_buf); + + outloop = true; + break; + } + + } while (!outloop); + + return ant_det_finish; + +} + +#pragma optimize("", off) +boolean halbtc8821c1ant_psd_antenna_detection_check(IN struct btc_coexist + *btcoexist) +{ + static u32 ant_det_count = 0, ant_det_fail_count = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + + boolean scan, roam, ant_det_finish = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + ant_det_count++; + + psd_scan->ant_det_try_count = ant_det_count; + + if (scan || roam) { + ant_det_finish = false; + psd_scan->ant_det_result = 6; + } else if (coex_sta->bt_disabled) { + ant_det_finish = false; + psd_scan->ant_det_result = 11; + } else if (coex_sta->num_of_profile >= 1) { + ant_det_finish = false; + psd_scan->ant_det_result = 7; + } else if ( + !psd_scan->ant_det_is_ant_det_available) { /* Antenna initial setup is not ready */ + ant_det_finish = false; + psd_scan->ant_det_result = 9; + } else if (coex_sta->c2h_bt_inquiry_page) { + ant_det_finish = false; + psd_scan->ant_det_result = 10; + } else { + + ant_det_finish = halbtc8821c1ant_psd_antenna_detection( + btcoexist); + + delay_ms(psd_scan->ant_det_bt_tx_time); + } + + + if (!ant_det_finish) + ant_det_fail_count++; + + psd_scan->ant_det_fail_count = ant_det_fail_count; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), result = %d, fail_count = %d, finish = %s\n", + psd_scan->ant_det_result, + psd_scan->ant_det_fail_count, + ant_det_finish == true ? "Yes" : "No"); + BTC_TRACE(trace_buf); + + return ant_det_finish; + +} + +#endif + +/* ************************************************************ + * work around function start with wa_halbtc8821c1ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8821c1ant_ + * ************************************************************ */ +void ex_halbtc8821c1ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + u32 value = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Execute 8821c 1-Ant PowerOn Setting xxxxxxxxxxxxxxxx!!\n"); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Ant Det Finish = %s, Ant Det Number = %d\n", + (board_info->btdm_ant_det_finish ? "Yes" : "No"), + board_info->btdm_ant_num_by_ant_det); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = true; + psd_scan->ant_det_is_ant_det_available = false; + + /* enable BB, REG_SYS_FUNC_EN such that we can write BB Register correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT(0) | BIT(1)); + + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + + /* Set Antenna Path to BT side */ + /* Check efuse 0xc3[6] for Single Antenna Path */ + if (board_info->single_ant_path == 0) { + + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + u8tmp = 1; + } else if (board_info->single_ant_path == 1) { + + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + u8tmp = 0; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (Power On) single_ant_path = %d, btdm_ant_pos = %d\n", + board_info->single_ant_path , board_info->btdm_ant_pos); + BTC_TRACE(trace_buf); + + /* Setup RF front end type */ + halbtc8821c1ant_set_rfe_type(btcoexist); + + /* Set Antenna Path to BT side */ + halbtc8821c1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_1ANT_PHASE_COEX_POWERON); + + /* Save"single antenna position" info in Local register setting for FW reading, because FW may not ready at power on */ + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x3e0, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, u8tmp); + + /* enable GNT_WL/GNT_BT debug signal to GPIO14/15 */ + halbtc8821c1ant_enable_gnt_to_gpio(btcoexist, true); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** LTE coex Reg 0x38 (Power-On) = 0x%x\n", + halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, 0x38)); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** MAC Reg 0x70/ BB Reg 0xcb4 (Power-On) = 0x%x / 0x%x\n", + btcoexist->btc_read_4byte(btcoexist, 0x70), + btcoexist->btc_read_4byte(btcoexist, 0xcb4)); + BTC_TRACE(trace_buf); + +} + +void ex_halbtc8821c1ant_pre_load_firmware(IN struct btc_coexist *btcoexist) +{ +} + +void ex_halbtc8821c1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8821c1ant_init_hw_config(btcoexist, true, wifi_only); +} + +void ex_halbtc8821c1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + halbtc8821c1ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8821c1ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u16 u16tmp[4]; + u32 u32tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + u32 fw_ver = 0, bt_patch_ver = 0, bt_coex_ver = 0; + static u8 pop_report_in_10s = 0; + u32 phyver = 0; + boolean lte_coex_on = false; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + if (btcoexist->stop_coex_dm) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (psd_scan->ant_det_try_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %s / %d", + "Ant PG Num/ Mech/ Pos/ RFE", + board_info->pg_ant_num, board_info->btdm_ant_num, + (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT + ? "Main" : "Aux"), + rfe_type->rfe_module_type); + CL_PRINTF(cli_buf); + } else { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %s/ %d (%d/%d/%d)", + "Ant PG Num/ Mech(Ant_Det)/ Pos/ RFE", + board_info->pg_ant_num, + board_info->btdm_ant_num_by_ant_det, + (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT + ? "Main" : "Aux"), + rfe_type->rfe_module_type, + psd_scan->ant_det_try_count, + psd_scan->ant_det_fail_count, + psd_scan->ant_det_result); + CL_PRINTF(cli_buf); + + if (board_info->btdm_ant_det_finish) { + + if (psd_scan->ant_det_result != 12) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "Ant Det PSD Value", + psd_scan->ant_det_peak_val); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d", + "Ant Det PSD Value", + psd_scan->ant_det_psd_scan_peak_val + / 100); + CL_PRINTF(cli_buf); + } + } + + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + + bt_coex_ver = ((coex_sta->bt_coex_supported_version & 0xff00) >> 8); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8821c_1ant, glcoex_ver_8821c_1ant, + glcoex_ver_btdesired_8821c_1ant, + bt_coex_ver, + (bt_coex_ver == 0xff ? "Unknown" : + (bt_coex_ver >= glcoex_ver_btdesired_8821c_1ant ? + "Match" : "Mis-Match"))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ v%d/ %c", + "W_FW/ B_FW/ Phy/ Kt", + fw_ver, bt_patch_ver, phyver, + coex_sta->cut_version + 65); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "AFH Map to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + pop_report_in_10s++; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = [%s/ %d dBm/ %d/ %d] ", + "BT [status/ rssi/ retryCnt/ popCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page") + : ((BT_8821C_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8821C_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi - 100, coex_sta->bt_retry_cnt, + coex_sta->pop_event_cnt); + CL_PRINTF(cli_buf); + + if (pop_report_in_10s >= 5) { + coex_sta->pop_event_cnt = 0; + pop_report_in_10s = 0; + } + + if (coex_sta->num_of_profile != 0) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s%s%s%s%s", + "Profiles", + ((bt_link_info->a2dp_exist) ? "A2DP," : ""), + ((bt_link_info->sco_exist) ? "SCO," : ""), + ((bt_link_info->hid_exist) ? + ((coex_sta->hid_busy_num >= 2) ? "HID(4/18)," : + "HID(2/18),") : ""), + ((bt_link_info->pan_exist) ? "PAN," : ""), + ((coex_sta->voice_over_HOGP) ? "Voice" : "")); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = None", "Profiles"); + + CL_PRINTF(cli_buf); + + if (bt_link_info->a2dp_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %d/ %s", + "A2DP Rate/Bitpool/Auto_Slot", + ((coex_sta->is_A2DP_3M) ? "3M" : "No_3M"), + coex_sta->a2dp_bit_pool, + ((coex_sta->is_autoslot) ? "On" : "Off") + ); + CL_PRINTF(cli_buf); + } + + if (bt_link_info->hid_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "HID PairNum/Forbid_Slot", + coex_sta->hid_pair_cnt, + coex_sta->forbidden_slot + ); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ 0x%x/ 0x%x", + "Role/IgnWlanAct/Feature/BLEScan", + ((bt_link_info->slave_role) ? "Slave" : "Master"), + ((coex_dm->cur_ignore_wlan_act) ? "Yes" : "No"), + coex_sta->bt_coex_supported_feature, + coex_sta->bt_ble_scan_type); + CL_PRINTF(cli_buf); + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", + "ReInit/ReLink/IgnWlact/Page/NameReq", + coex_sta->cnt_ReInit, + coex_sta->cnt_setupLink, + coex_sta->cnt_IgnWlanAct, + coex_sta->cnt_Page, + coex_sta->cnt_RemoteNameReq + ); + CL_PRINTF(cli_buf); + + halbtc8821c1ant_read_score_board(btcoexist, &u16tmp[0]); + + if ((coex_sta->bt_reg_vendor_ae == 0xffff) || + (coex_sta->bt_reg_vendor_ac == 0xffff)) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = x/ x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", u16tmp[0]); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", + ((coex_sta->bt_reg_vendor_ae & BIT(4)) >> 4), + coex_sta->bt_reg_vendor_ac & 0x3, u16tmp[0]); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8821C_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8821c_1ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + + if (btcoexist->manual_control) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanisms] (before Manual)============"); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Mechanisms]============"); + + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x (case-%d, %s)", + "TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + (coex_dm->cur_ps_tdma_on ? "TDMA On" : "TDMA Off")); + + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ 0x%x/ 0x%x/ 0x%x", + "Table/0x6c0/0x6c4/0x6c8", + coex_sta->coex_table_type, u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x", + "0x778/0x6cc", + u8tmp[0], u32tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s", + "AntDiv/ForceLPS/LPRA", + ((board_info->ant_div_cfg) ? "On" : "Off"), + ((coex_sta->force_lps_on) ? "On" : "Off"), + ((coex_dm->cur_low_penalty_ra) ? "On" : "Off")); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + lte_coex_on = ((u32tmp[0] & BIT(7)) >> 7) ? true : false; + + if (lte_coex_on) { + + u32tmp[0] = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa0); + u32tmp[1] = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa4); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "LTE Coex Table W_L/B_L", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa8); + u32tmp[1] = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, + 0xac); + u32tmp[2] = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, + 0xb0); + u32tmp[3] = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, + 0xb4); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "LTE Break Table W_L/B_L/L_W/L_B", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff, + u32tmp[2] & 0xffff, u32tmp[3] & 0xffff); + CL_PRINTF(cli_buf); + } + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + /* + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + */ + + u32tmp[0] = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp[1] = halbtc8821c1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x73); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s", + "LTE Coex/Path Owner", + ((lte_coex_on) ? "On" : "Off") , + ((u8tmp[0] & BIT(2)) ? "WL" : "BT")); + CL_PRINTF(cli_buf); + + if (lte_coex_on) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "LTE 3Wire/OPMode/UART/UARTMode", + (int)((u32tmp[0] & BIT(6)) >> 6), + (int)((u32tmp[0] & (BIT(5) | BIT(4))) >> 4), + (int)((u32tmp[0] & BIT(3)) >> 3), + (int)(u32tmp[0] & (BIT(2) | BIT(1) | BIT(0)))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "LTE_Busy/UART_Busy", + (int)((u32tmp[1] & BIT(1)) >> 1), (int)(u32tmp[1] & BIT(0))); + CL_PRINTF(cli_buf); + } + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (BB:%s)/ %s (BB:%s)/ %s", + "GNT_WL_Ctrl/GNT_BT_Ctrl/Dbg", + ((u32tmp[0] & BIT(12)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(8)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(14)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(10)) ? "SW" : "HW"), + ((u8tmp[0] & BIT(3)) ? "On" : "Off")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "GNT_WL/GNT_BT", + (int)((u32tmp[1] & BIT(2)) >> 2), + (int)((u32tmp[1] & BIT(3)) >> 3)); + CL_PRINTF(cli_buf); + + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xcba); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%04x/ 0x%04x/ 0x%02x %s", + "0xcb0/0xcb4/0xcb8[23:16]", + u32tmp[0], u32tmp[1], u8tmp[0], + ((u8tmp[0] & 0x1) == 0x1 ? "(BTG)" : "(WL_A+G)")); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x4c6); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x4c[24:23]/0x64[0]/x4c6[4]/0x40[5]", + (u32tmp[0] & (BIT(24) | BIT(23))) >> 23 , u8tmp[2] & 0x1 , + (int)((u8tmp[0] & BIT(4)) >> 4), + (int)((u8tmp[1] & BIT(5)) >> 5)); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x953); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0xc50); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ %s/ 0x%x", + "0x550/0x522/4-RxAGC/0xc50", + u32tmp[0], u8tmp[0], (u8tmp[1] & 0x2) ? "On" : "Off", u8tmp[2]); + CL_PRINTF(cli_buf); + + fa_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_OFDM); + fa_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_CCK); + cca_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_OFDM); + cca_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_CCK); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", + cca_cck, fa_cck, cca_ofdm, fa_ofdm); + CL_PRINTF(cli_buf); + + +#if 1 + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11ac", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11ac", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + CL_PRINTF(cli_buf); +#endif + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s", + "Wifi-HiPri/ Ccklock/ CckEverLock", + (coex_sta->wifi_is_high_pri_task ? "Yes" : "No"), + (coex_sta->cck_lock ? "Yes" : "No"), + (coex_sta->cck_ever_lock ? "Yes" : "No")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(Hi-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(Lo-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8821c1ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + + /* Write WL "Active" in Score-board for LPS off */ + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, false); + + halbtc8821c1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_1ANT_PHASE_WLAN_OFF); + + halbtc8821c1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, true); + + halbtc8821c1ant_init_hw_config(btcoexist, false, false); + halbtc8821c1ant_init_coex_dm(btcoexist); + + coex_sta->under_ips = false; + } +} + +void ex_halbtc8821c1ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + + if (coex_sta->force_lps_on == true) { /* LPS No-32K */ + /* Write WL "Active" in Score-board for PS-TDMA */ + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, true); + + } else { /* LPS-32K, need check if this h2c 0x71 can work?? (2015/08/28) */ + /* Write WL "Non-Active" in Score-board for Native-PS */ + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, false); + + } + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + + /* Write WL "Active" in Score-board for LPS off */ + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, true); + + } +} + +void ex_halbtc8821c1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false; + boolean wifi_under_5g = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + coex_sta->freeze_coexrun_by_btinfo = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (wifi_connected) + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** WL connected before SCAN\n"); + else + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** WL is not connected before SCAN\n"); + + BTC_TRACE(trace_buf); + + halbtc8821c1ant_query_bt_info(btcoexist); + + if (BTC_SCAN_START == type) { + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, + &wifi_under_5g); + + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** SCAN START notify (5g)\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_action_wifi_under5g(btcoexist); + return; + } + + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** SCAN START notify (2g)\n"); + BTC_TRACE(trace_buf); + + /* Force antenna setup for no scan result issue */ + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + + if (!wifi_connected) /* non-connected scan */ + halbtc8821c1ant_action_wifi_not_connected_scan( + btcoexist); + else /* wifi is connected */ + halbtc8821c1ant_action_wifi_connected_scan( + btcoexist); + + return; + } + + if (BTC_SCAN_START_2G == type) { + + if (!wifi_connected) + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify (2G)\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_SCAN, true); + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, true); + + /* Force antenna setup for no scan result issue */ + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + + if (!wifi_connected) /* non-connected scan */ + halbtc8821c1ant_action_wifi_not_connected_scan( + btcoexist); + else /* wifi is connected */ + halbtc8821c1ant_action_wifi_connected_scan(btcoexist); + + } else { + + coex_sta->wifi_is_high_pri_task = false; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify (Scan-AP = %d)\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_SCAN, false); + + if (!wifi_connected) + halbtc8821c1ant_action_wifi_not_connected(btcoexist); + else + halbtc8821c1ant_action_wifi_connected(btcoexist); + } + + +} + +void ex_halbtc8821c1ant_switchband_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + + if (type == BTC_SWITCH_TO_5G) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], switchband_notify --- switch to 5G\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_action_wifi_under5g(btcoexist); + + } else if (type == BTC_SWITCH_TO_24G_NOFORSCAN) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** switchband_notify BTC_SWITCH_TO_2G (no for scan)\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_run_coexist_mechanism(btcoexist); + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], switchband_notify --- switch to 2G\n"); + BTC_TRACE(trace_buf); + + ex_halbtc8821c1ant_scan_notify(btcoexist, + BTC_SCAN_START_2G); + } +} + + +void ex_halbtc8821c1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false; + + + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, true); + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if ((BTC_ASSOCIATE_5G_START == type) || + (BTC_ASSOCIATE_5G_FINISH == type)) { + + if (BTC_ASSOCIATE_5G_START == type) + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], connect_notify --- 5G start\n"); + else + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], connect_notify --- 5G finish\n"); + + BTC_TRACE(trace_buf); + + halbtc8821c1ant_action_wifi_under5g(btcoexist); + return; + } + + if (BTC_ASSOCIATE_START == type) { + + coex_sta->wifi_is_high_pri_task = true; + + /* Force antenna setup for no scan result issue */ + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify (2G)\n"); + BTC_TRACE(trace_buf); + + coex_dm->arp_cnt = 0; + + halbtc8821c1ant_action_wifi_not_connected_asso_auth(btcoexist); + + /* To keep TDMA case during connect process, + to avoid changed by Btinfo and runcoexmechanism */ + coex_sta->freeze_coexrun_by_btinfo = true; + } else { + + coex_sta->wifi_is_high_pri_task = false; + coex_sta->freeze_coexrun_by_btinfo = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify (2G)\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (!wifi_connected) /* non-connected scan */ + halbtc8821c1ant_action_wifi_not_connected(btcoexist); + else + halbtc8821c1ant_action_wifi_connected(btcoexist); + } + +} + +void ex_halbtc8821c1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_under_b_mode = false, wifi_under_5g = false; + + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (BTC_MEDIA_CONNECT == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, true); + + if (wifi_under_5g) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 5G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_action_wifi_under5g(btcoexist); + return; + } + + /* Force antenna setup for no scan result issue */ + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + /* btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x10); */ /*CCK Tx */ + /* btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x10); */ /*CCK Rx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } + + coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, + 0x430); + coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, + 0x434); + coex_dm->backup_retry_limit = btcoexist->btc_read_2byte( + btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = btcoexist->btc_read_1byte( + btcoexist, 0x456); + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, false); + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + + coex_sta->cck_ever_lock = false; + } + + halbtc8821c1ant_update_wifi_channel_info(btcoexist, type); + +} + +void ex_halbtc8821c1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean under_4way = false, wifi_under_5g = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 5G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_action_wifi_under5g(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (under_4way) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ---- under_4way!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } else if (BTC_PACKET_ARP == type) { + + coex_dm->arp_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ARP notify -cnt = %d\n", + coex_dm->arp_cnt); + BTC_TRACE(trace_buf); + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet DHCP or EAPOL notify [Type = %d]\n", + type); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } + + if (coex_sta->wifi_is_high_pri_task) + halbtc8821c1ant_action_wifi_connected_specific_packet( + btcoexist); +} + +void ex_halbtc8821c1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 i, rsp_source = 0; + boolean wifi_connected = false; + + if (psd_scan->is_AntDet_running == true) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], bt_info_notify return for AntDet is running\n"); + BTC_TRACE(trace_buf); + return; + } + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8821C_1ANT_MAX) + rsp_source = BT_INFO_SRC_8821C_1ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt_info[%d], len=%d, data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + coex_sta->bt_info = coex_sta->bt_info_c2h[rsp_source][1]; + coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + coex_sta->bt_info_ext2 = coex_sta->bt_info_c2h[rsp_source][5]; + + if (BT_INFO_SRC_8821C_1ANT_WIFI_FW != rsp_source) { + + /* if 0xff, it means BT is under WHCK test */ + coex_sta->bt_whck_test = ((coex_sta->bt_info == 0xff) ? true : + false); + + coex_sta->bt_create_connection = (( + coex_sta->bt_info_c2h[rsp_source][2] & 0x80) ? true : + false); + + /* unit: %, value-100 to translate to unit: dBm */ + coex_sta->bt_rssi = coex_sta->bt_info_c2h[rsp_source][3] * 2 + + 10; + + coex_sta->c2h_bt_remote_name_req = (( + coex_sta->bt_info_c2h[rsp_source][2] & 0x20) ? true : + false); + + coex_sta->is_A2DP_3M = ((coex_sta->bt_info_c2h[rsp_source][2] & + 0x10) ? true : false); + + coex_sta->acl_busy = ((coex_sta->bt_info_c2h[rsp_source][1] & + 0x9) ? true : false); + + coex_sta->voice_over_HOGP = ((coex_sta->bt_info_ext & 0x10) ? + true : false); + + coex_sta->c2h_bt_inquiry_page = ((coex_sta->bt_info & + BT_INFO_8821C_1ANT_B_INQ_PAGE) ? true : false); + + coex_sta->a2dp_bit_pool = ((( + coex_sta->bt_info_c2h[rsp_source][1] & 0x49) == 0x49) ? + coex_sta->bt_info_c2h[rsp_source][6] : 0); + + coex_sta->bt_retry_cnt = coex_sta->bt_info_c2h[rsp_source][2] & + 0xf; + + coex_sta->is_autoslot = coex_sta->bt_info_ext2 & 0x8; + + coex_sta->forbidden_slot = coex_sta->bt_info_ext2 & 0x7; + + coex_sta->hid_busy_num = (coex_sta->bt_info_ext2 & 0x30) >> 4; + + coex_sta->hid_pair_cnt = (coex_sta->bt_info_ext2 & 0xc0) >> 6; + + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->c2h_bt_remote_name_req) + coex_sta->cnt_RemoteNameReq++; + + if (coex_sta->bt_info_ext & BIT(1)) + coex_sta->cnt_ReInit++; + + if (coex_sta->bt_info_ext & BIT(2)) { + coex_sta->cnt_setupLink++; + coex_sta->is_setupLink = true; + } else + coex_sta->is_setupLink = false; + + if (coex_sta->bt_info_ext & BIT(3)) + coex_sta->cnt_IgnWlanAct++; + + if (coex_sta->bt_create_connection) + coex_sta->cnt_Page++; + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + + if ((!btcoexist->manual_control) && + (!btcoexist->stop_coex_dm)) { + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* Re-Init */ + if ((coex_sta->bt_info_ext & BIT(1))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + if (wifi_connected) + halbtc8821c1ant_update_wifi_channel_info( + btcoexist, BTC_MEDIA_CONNECT); + else + halbtc8821c1ant_update_wifi_channel_info( + btcoexist, + BTC_MEDIA_DISCONNECT); + } + + + /* If Ignore_WLanAct && not SetUp_Link */ + if ((coex_sta->bt_info_ext & BIT(3)) && + (!(coex_sta->bt_info_ext & BIT(2)))) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8821c1ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, false); + } + } + + } + + + halbtc8821c1ant_update_bt_link_info(btcoexist); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), No run_coexist_mechanism for Manual CTRL\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), No run_coexist_mechanism for Stop Coex DM\n"); + BTC_TRACE(trace_buf); + return; + } + + coex_sta->c2h_bt_info_req_sent = false; + + halbtc8821c1ant_run_coexist_mechanism(btcoexist); +} + + + +void ex_halbtc8821c1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], RF Status notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_RF_ON == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned ON!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->wl_rf_off_on_event = true; + btcoexist->stop_coex_dm = false; + + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, true); + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ONOFF, true); + + } else if (BTC_RF_OFF == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned OFF!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ONOFF, false); + + halbtc8821c1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_1ANT_PHASE_WLAN_OFF); + + btcoexist->stop_coex_dm = true; + coex_sta->wl_rf_off_on_event = false; + } +} + +void ex_halbtc8821c1ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ONOFF, false); + + halbtc8821c1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8821C_1ANT_PHASE_WLAN_OFF); + + halbtc8821c1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + ex_halbtc8821c1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + btcoexist->stop_coex_dm = true; +} + +void ex_halbtc8821c1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + boolean wifi_under_5g = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Pnp notify\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if ((BTC_WIFI_PNP_SLEEP == pnp_state) || + (BTC_WIFI_PNP_SLEEP_KEEP_ANT == pnp_state)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ONOFF, false); + + if (BTC_WIFI_PNP_SLEEP_KEEP_ANT == pnp_state) { + + if (wifi_under_5g) + halbtc8821c1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8821C_1ANT_PHASE_5G_RUNTIME); + else + halbtc8821c1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + } else { + + halbtc8821c1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_1ANT_PHASE_WLAN_OFF); + } + + btcoexist->stop_coex_dm = true; + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ACTIVE, true); + halbtc8821c1ant_post_state_to_bt(btcoexist, + BT_8821C_1ANT_SCOREBOARD_ONOFF, true); + + btcoexist->stop_coex_dm = false; + } +} + + +void ex_halbtc8821c1ant_coex_dm_reset(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], *****************Coex DM Reset*****************\n"); + BTC_TRACE(trace_buf); + + halbtc8821c1ant_init_hw_config(btcoexist, false, false); + halbtc8821c1ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8821c1ant_periodical(IN struct btc_coexist *btcoexist) +{ + + struct btc_board_info *board_info = &btcoexist->board_info; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ************* Periodical *************\n"); + BTC_TRACE(trace_buf); + +#if (BT_AUTO_REPORT_ONLY_8821C_1ANT == 0) + halbtc8821c1ant_query_bt_info(btcoexist); + +#endif + + halbtc8821c1ant_monitor_bt_ctr(btcoexist); + halbtc8821c1ant_monitor_wifi_ctr(btcoexist); + + halbtc8821c1ant_monitor_bt_enable_disable(btcoexist); + + /* for 4-way, DHCP, EAPOL packet */ + if (coex_sta->specific_pkt_period_cnt > 0) { + + coex_sta->specific_pkt_period_cnt--; + + if ((coex_sta->specific_pkt_period_cnt == 0) && + (coex_sta->wifi_is_high_pri_task)) + coex_sta->wifi_is_high_pri_task = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ***************** Hi-Pri Task = %s*****************\n", + (coex_sta->wifi_is_high_pri_task ? "Yes" : + "No")); + BTC_TRACE(trace_buf); + + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->bt_coex_supported_feature == 0) + coex_sta->bt_coex_supported_feature = + btcoexist->btc_get_bt_coex_supported_feature( + btcoexist); + + if ((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) + coex_sta->bt_coex_supported_version = + btcoexist->btc_get_bt_coex_supported_version( + btcoexist); + + /*coex_sta->bt_ble_scan_type = btcoexist->btc_get_ble_scan_type_from_bt(btcoexist); */ + + if (coex_sta->bt_reg_vendor_ac == 0xffff) + coex_sta->bt_reg_vendor_ac = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, + 0xac) & 0xffff); + + if (coex_sta->bt_reg_vendor_ae == 0xffff) + coex_sta->bt_reg_vendor_ae = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, + 0xae) & 0xffff); + +#if BT_8821C_1ANT_ANTDET_ENABLE + + if (board_info->btdm_ant_det_finish) { + if ((psd_scan->ant_det_result == 12) && + (psd_scan->ant_det_psd_scan_peak_val == 0) + && (!psd_scan->is_AntDet_running)) + psd_scan->ant_det_psd_scan_peak_val = + btcoexist->btc_get_ant_det_val_from_bt( + btcoexist) * 100; + } + +#endif + } + + if (halbtc8821c1ant_is_wifibt_status_changed(btcoexist)) + halbtc8821c1ant_run_coexist_mechanism(btcoexist); + + +} + +/*#pragma optimize( "", off )*/ +void ex_halbtc8821c1ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ +#if 0 + + static u32 ant_det_count = 0, ant_det_fail_count = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + u16 u16tmp; + u8 AntDetval = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Ext Call AntennaDetect()!!\n"); + BTC_TRACE(trace_buf); + +#if BT_8821C_1ANT_ANTDET_ENABLE + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Call AntennaDetect()!!\n"); + BTC_TRACE(trace_buf); + + if (seconds == 0) { + psd_scan->ant_det_try_count = 0; + psd_scan->ant_det_fail_count = 0; + ant_det_count = 0; + ant_det_fail_count = 0; + board_info->btdm_ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + return; + } + + if (!board_info->btdm_ant_det_finish) { + psd_scan->ant_det_inteval_count = + psd_scan->ant_det_inteval_count + 2; + + if (psd_scan->ant_det_inteval_count >= + BT_8821C_2ANT_ANTDET_RETRY_INTERVAL) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Timer is up, Try Detect!!\n"); + BTC_TRACE(trace_buf); + + psd_scan->is_AntDet_running = true; + + halbtc8821c1ant_read_score_board(btcoexist, &u16tmp); + + if (u16tmp & BIT( + 2)) { /* Antenna detection is already done before last WL power on */ + board_info->btdm_ant_det_finish = true; + psd_scan->ant_det_try_count = 1; + psd_scan->ant_det_fail_count = 0; + board_info->btdm_ant_num_by_ant_det = (u16tmp & + BIT(3)) ? 1 : 2; + psd_scan->ant_det_result = 12; + + psd_scan->ant_det_psd_scan_peak_val = + btcoexist->btc_get_ant_det_val_from_bt( + btcoexist) * 100; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Result from BT (%d-Ant)\n", + board_info->btdm_ant_num_by_ant_det); + BTC_TRACE(trace_buf); + } else + board_info->btdm_ant_det_finish = + halbtc8821c1ant_psd_antenna_detection_check( + btcoexist); + + btcoexist->bdontenterLPS = false; + + if (board_info->btdm_ant_det_finish) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Success!!\n"); + BTC_TRACE(trace_buf); + + if (board_info->btdm_ant_num_by_ant_det == 2) { + board_info->ant_div_cfg = true; + halbtc8821c1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_WIFI, FORCE_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + } else + halbtc8821c1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8821C_1ANT_PHASE_2G_RUNTIME); + + /*for 8821c, btc_set_bt_trx_mask is just used to + notify BT stop le tx and Ant Det Result , not set BT RF TRx Mask */ + if (psd_scan->ant_det_result != 12) { + + AntDetval = (u8)(( + psd_scan->ant_det_psd_scan_peak_val + / 100) & 0x7f); + + AntDetval = + (board_info->btdm_ant_num_by_ant_det + == 1) ? (AntDetval | 0x80) : + AntDetval; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Ant Count = %d, PSD Val = %d\n", + ((AntDetval & + 0x80) ? 1 + : 2), AntDetval + & 0x7f); + BTC_TRACE(trace_buf); + + if (btcoexist->btc_set_bt_trx_mask( + btcoexist, AntDetval)) + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Notify BT stop le tx by set_bt_trx_mask ok!\n"); + else + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Notify BT stop le tx by set_bt_trx_mask fail!\n"); + + BTC_TRACE(trace_buf); + } + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Fail!!\n"); + BTC_TRACE(trace_buf); + } + + psd_scan->ant_det_inteval_count = 0; + psd_scan->is_AntDet_running = false; + /* stimulate coex running */ + halbtc8821c1ant_run_coexist_mechanism( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Stimulate Coex running\n!!"); + BTC_TRACE(trace_buf); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Timer is not up! (%d)\n", + psd_scan->ant_det_inteval_count); + BTC_TRACE(trace_buf); + + if (psd_scan->ant_det_inteval_count == 8) + btcoexist->bdontenterLPS = true; + else + btcoexist->bdontenterLPS = false; + } + + } +#endif + +#endif +} + + +void ex_halbtc8821c1ant_display_ant_detection(IN struct btc_coexist *btcoexist) +{ + +#if 0 +#if BT_8821C_1ANT_ANTDET_ENABLE + struct btc_board_info *board_info = &btcoexist->board_info; + + if (psd_scan->ant_det_try_count != 0) { + halbtc8821c1ant_psd_show_antenna_detect_result(btcoexist); + + if (board_info->btdm_ant_det_finish) + halbtc8821c1ant_psd_showdata(btcoexist); + } +#endif +#endif +} + +void ex_halbtc8821c1ant_antenna_isolation(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ + + +} + +void ex_halbtc8821c1ant_psd_scan(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ + + +} + + +#endif + +#endif /* #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) */ + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c1ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c1ant.h new file mode 100644 index 0000000..f712494 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c1ant.h @@ -0,0 +1,473 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8821C_SUPPORT == 1) + +/* ******************************************* + * The following is for 8821C 1ANT BT Co-exist definition + * ******************************************* */ +#define BT_8821C_1ANT_COEX_DBG 0 +#define BT_AUTO_REPORT_ONLY_8821C_1ANT 1 + +#define BT_INFO_8821C_1ANT_B_FTP BIT(7) +#define BT_INFO_8821C_1ANT_B_A2DP BIT(6) +#define BT_INFO_8821C_1ANT_B_HID BIT(5) +#define BT_INFO_8821C_1ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8821C_1ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8821C_1ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8821C_1ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8821C_1ANT_B_CONNECTION BIT(0) + +#define BT_INFO_8821C_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT(0))) ? true : false) + +#define BTC_RSSI_COEX_THRESH_TOL_8821C_1ANT 2 + +#define BT_8821C_1ANT_WIFI_NOISY_THRESH 30 /* max: 255 */ +#define BT_8821C_1ANT_DEFAULT_ISOLATION 15 /* unit: dB */ + + +/* for Antenna detection */ +#define BT_8821C_1ANT_ANTDET_PSDTHRES_BACKGROUND 50 +#define BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION 70 +#define BT_8821C_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION 55 +#define BT_8821C_1ANT_ANTDET_PSDTHRES_1ANT 35 +#define BT_8821C_1ANT_ANTDET_RETRY_INTERVAL 10 /* retry timer if ant det is fail, unit: second */ +#define BT_8821C_1ANT_ANTDET_SWEEPPOINT_DELAY 60000 +#define BT_8821C_1ANT_ANTDET_ENABLE 0 +#define BT_8821C_1ANT_ANTDET_BTTXTIME 100 +#define BT_8821C_1ANT_ANTDET_BTTXCHANNEL 39 +#define BT_8821C_1ANT_ANTDET_PSD_SWWEEPCOUNT 50 + +#define BT_8821C_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT 30000 + +enum bt_8821c_1ant_signal_state { + BT_8821C_1ANT_SIG_STA_SET_TO_LOW = 0x0, + BT_8821C_1ANT_SIG_STA_SET_BY_HW = 0x0, + BT_8821C_1ANT_SIG_STA_SET_TO_HIGH = 0x1, + BT_8821C_1ANT_SIG_STA_MAX +}; + +enum bt_8821c_1ant_path_ctrl_owner { + BT_8821C_1ANT_PCO_BTSIDE = 0x0, + BT_8821C_1ANT_PCO_WLSIDE = 0x1, + BT_8821C_1ANT_PCO_MAX +}; + +enum bt_8821c_1ant_gnt_ctrl_type { + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_PTA = 0x0, + BT_8821C_1ANT_GNT_TYPE_CTRL_BY_SW = 0x1, + BT_8821C_1ANT_GNT_TYPE_MAX +}; + +enum bt_8821c_1ant_gnt_ctrl_block { + BT_8821C_1ANT_GNT_BLOCK_RFC_BB = 0x0, + BT_8821C_1ANT_GNT_BLOCK_RFC = 0x1, + BT_8821C_1ANT_GNT_BLOCK_BB = 0x2, + BT_8821C_1ANT_GNT_BLOCK_MAX +}; + +enum bt_8821c_1ant_lte_coex_table_type { + BT_8821C_1ANT_CTT_WL_VS_LTE = 0x0, + BT_8821C_1ANT_CTT_BT_VS_LTE = 0x1, + BT_8821C_1ANT_CTT_MAX +}; + +enum bt_8821c_1ant_lte_break_table_type { + BT_8821C_1ANT_LBTT_WL_BREAK_LTE = 0x0, + BT_8821C_1ANT_LBTT_BT_BREAK_LTE = 0x1, + BT_8821C_1ANT_LBTT_LTE_BREAK_WL = 0x2, + BT_8821C_1ANT_LBTT_LTE_BREAK_BT = 0x3, + BT_8821C_1ANT_LBTT_MAX +}; + +enum bt_info_src_8821c_1ant { + BT_INFO_SRC_8821C_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8821C_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8821C_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8821C_1ANT_MAX +}; + +enum bt_8821c_1ant_bt_status { + BT_8821C_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8821C_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8821C_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8821C_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8821C_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8821C_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8821C_1ANT_BT_STATUS_MAX +}; + +enum bt_8821c_1ant_wifi_status { + BT_8821C_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8821C_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8821C_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8821C_1ANT_WIFI_STATUS_CONNECTED_SPECIFIC_PKT = 0x3, + BT_8821C_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8821C_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8821C_1ANT_WIFI_STATUS_MAX +}; + +enum bt_8821c_1ant_coex_algo { + BT_8821C_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8821C_1ANT_COEX_ALGO_SCO = 0x1, + BT_8821C_1ANT_COEX_ALGO_HID = 0x2, + BT_8821C_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8821C_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8821C_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8821C_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8821C_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8821C_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8821C_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8821C_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8821C_1ANT_COEX_ALGO_MAX = 0xb, +}; + +enum bt_8821c_1ant_ext_ant_switch_type { + BT_8821C_1ANT_EXT_ANT_SWITCH_USE_DPDT = 0x0, + BT_8821C_1ANT_EXT_ANT_SWITCH_USE_SPDT = 0x1, + BT_8821C_1ANT_EXT_ANT_SWITCH_NONE = 0x2, + BT_8821C_1ANT_EXT_ANT_SWITCH_MAX +}; + + +enum bt_8821c_1ant_ext_ant_switch_ctrl_type { + BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW = 0x0, + BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_PTA = 0x1, + BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV = 0x2, + BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_MAC = 0x3, + BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_BY_BT = 0x4, + BT_8821C_1ANT_EXT_ANT_SWITCH_CTRL_MAX +}; + +enum bt_8821c_1ant_ext_ant_switch_pos_type { + BT_8821C_1ANT_EXT_ANT_SWITCH_TO_BT = 0x0, + BT_8821C_1ANT_EXT_ANT_SWITCH_TO_WLG = 0x1, + BT_8821C_1ANT_EXT_ANT_SWITCH_TO_WLA = 0x2, + BT_8821C_1ANT_EXT_ANT_SWITCH_TO_NOCARE = 0x3, + BT_8821C_1ANT_EXT_ANT_SWITCH_TO_MAX +}; + +enum bt_8821c_1ant_ext_band_switch_pos_type { + BT_8821C_1ANT_EXT_BAND_SWITCH_TO_WLG = 0x0, + BT_8821C_1ANT_EXT_BAND_SWITCH_TO_WLA = 0x1, + BT_8821C_1ANT_EXT_BAND_SWITCH_TO_MAX +}; + +enum bt_8821c_1ant_int_block { + BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLG_OF_BTG = 0x0, + BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLG_OF_WLAG = 0x1, + BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLA_OF_WLAG = 0x2, + BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_MAX +}; + +enum bt_8821c_1ant_phase { + BT_8821C_1ANT_PHASE_COEX_INIT = 0x0, + BT_8821C_1ANT_PHASE_WLANONLY_INIT = 0x1, + BT_8821C_1ANT_PHASE_WLAN_OFF = 0x2, + BT_8821C_1ANT_PHASE_2G_RUNTIME = 0x3, + BT_8821C_1ANT_PHASE_5G_RUNTIME = 0x4, + BT_8821C_1ANT_PHASE_BTMPMODE = 0x5, + BT_8821C_1ANT_PHASE_ANTENNA_DET = 0x6, + BT_8821C_1ANT_PHASE_COEX_POWERON = 0x7, + BT_8821C_1ANT_PHASE_MAX +}; + +enum bt_8821c_1ant_Scoreboard { + BT_8821C_1ANT_SCOREBOARD_ACTIVE = BIT(0), + BT_8821C_1ANT_SCOREBOARD_ONOFF = BIT(1), + BT_8821C_1ANT_SCOREBOARD_SCAN = BIT(2) +}; + +struct coex_dm_8821c_1ant { + /* hw setting */ + u32 pre_ant_pos_type; + u32 cur_ant_pos_type; + /* fw mechanism */ + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + /* sw mechanism */ + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + boolean limited_dig; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u32 pre_ra_mask; + u32 cur_ra_mask; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; + u32 arp_cnt; + + u32 pre_ext_ant_switch_status; + u32 cur_ext_ant_switch_status; + + u8 pre_ext_band_switch_status; + u8 cur_ext_band_switch_status; + + u8 pre_int_block_status; + u8 cur_int_block_status; + + u8 error_condition; +}; + +struct coex_sta_8821c_1ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + boolean bt_hi_pri_link_exist; + u8 num_of_profile; + + boolean under_lps; + boolean under_ips; + u32 specific_pkt_period_cnt; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + s8 bt_rssi; + boolean bt_tx_rx_mask; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + boolean c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8821C_1ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8821C_1ANT_MAX]; + boolean bt_whck_test; + boolean c2h_bt_inquiry_page; + boolean c2h_bt_remote_name_req; + boolean c2h_bt_page; /* Add for win8.1 page out issue */ + boolean wifi_is_high_pri_task; /* Add for win8.1 page out issue */ + u8 bt_retry_cnt; + u8 bt_info_ext; + u8 bt_info_ext2; + u32 pop_event_cnt; + u8 scan_ap_num; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_vht; + + boolean cck_lock; + boolean pre_ccklock; + boolean cck_ever_lock; + u8 coex_table_type; + + boolean force_lps_on; + u32 wrong_profile_notification; + + boolean concurrent_rx_mode_on; + + u16 score_board; + u8 isolation_btween_wb; /* 0~ 50 */ + + u8 a2dp_bit_pool; + u8 cut_version; + boolean acl_busy; + boolean wl_rf_off_on_event; + boolean bt_create_connection; + + u32 bt_coex_supported_feature; + u32 bt_coex_supported_version; + + u8 bt_ble_scan_type; + u8 bt_ble_scan_para[3]; + + boolean run_time_state; + boolean freeze_coexrun_by_btinfo; + + boolean is_A2DP_3M; + boolean voice_over_HOGP; + u8 bt_info; + boolean is_autoslot; + u8 forbidden_slot; + u8 hid_busy_num; + u8 hid_pair_cnt; + + u32 cnt_RemoteNameReq; + u32 cnt_setupLink; + u32 cnt_ReInit; + u32 cnt_IgnWlanAct; + u32 cnt_Page; + + u16 bt_reg_vendor_ac; + u16 bt_reg_vendor_ae; + + boolean is_setupLink; +}; + + +#define BT_8821C_1ANT_EXT_BAND_SWITCH_USE_DPDT 0 +#define BT_8821C_1ANT_EXT_BAND_SWITCH_USE_SPDT 1 + + +struct rfe_type_8821c_1ant { + + u8 rfe_module_type; + boolean ext_ant_switch_exist; + u8 ext_ant_switch_type; /* 0:DPDT, 1:SPDT */ + u8 ext_ant_switch_ctrl_polarity; /* iF 0: DPDT_P=0, DPDT_N=1 => BTG to Main, WL_A+G to Aux */ + + boolean ext_band_switch_exist; + u8 ext_band_switch_type; /* 0:DPDT, 1:SPDT */ + u8 ext_band_switch_ctrl_polarity; + + boolean wlg_Locate_at_btg; /* If true: WLG at BTG, If false: WLG at WLAG */ + + boolean ext_ant_switch_diversity; /* If diversity on */ +}; + +#define BT_8821C_1ANT_ANTDET_PSD_POINTS 256 /* MAX:1024 */ +#define BT_8821C_1ANT_ANTDET_PSD_AVGNUM 1 /* MAX:3 */ +#define BT_8821C_1ANT_ANTDET_BUF_LEN 16 + +struct psdscan_sta_8821c_1ant { + + u32 ant_det_bt_le_channel; /* BT LE Channel ex:2412 */ + u32 ant_det_bt_tx_time; + u32 ant_det_pre_psdscan_peak_val; + boolean ant_det_is_ant_det_available; + u32 ant_det_psd_scan_peak_val; + boolean ant_det_is_btreply_available; + u32 ant_det_psd_scan_peak_freq; + + u8 ant_det_result; + u8 ant_det_peak_val[BT_8821C_1ANT_ANTDET_BUF_LEN]; + u8 ant_det_peak_freq[BT_8821C_1ANT_ANTDET_BUF_LEN]; + u32 ant_det_try_count; + u32 ant_det_fail_count; + u32 ant_det_inteval_count; + u32 ant_det_thres_offset; + + u32 real_cent_freq; + s32 real_offset; + u32 real_span; + + u32 psd_band_width; /* unit: Hz */ + u32 psd_point; /* 128/256/512/1024 */ + u32 psd_report[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_report_max_hold[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_start_point; + u32 psd_stop_point; + u32 psd_max_value_point; + u32 psd_max_value; + u32 psd_max_value2; + u32 psd_avg_value; /* filter loop_max_value that below BT_8821C_1ANT_ANTDET_PSDTHRES_1ANT, and average the rest*/ + u32 psd_loop_max_value[BT_8821C_1ANT_ANTDET_PSD_SWWEEPCOUNT]; /*max value in each loop */ + u32 psd_start_base; + u32 psd_avg_num; /* 1/8/16/32 */ + u32 psd_gen_count; + boolean is_AntDet_running; + boolean is_psd_show_max_only; +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8821c1ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8821c1ant_pre_load_firmware(IN struct btc_coexist *btcoexist); +void ex_halbtc8821c1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8821c1ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8821c1ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c1ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c1ant_switchband_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8821c1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c1ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8821c1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state); +void ex_halbtc8821c1ant_coex_dm_reset(IN struct btc_coexist *btcoexist); +void ex_halbtc8821c1ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8821c1ant_display_coex_info(IN struct btc_coexist *btcoexist); +void ex_halbtc8821c1ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); +void ex_halbtc8821c1ant_antenna_isolation(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); + +void ex_halbtc8821c1ant_psd_scan(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); +void ex_halbtc8821c1ant_display_ant_detection(IN struct btc_coexist *btcoexist); + +#else +#define ex_halbtc8821c1ant_power_on_setting(btcoexist) +#define ex_halbtc8821c1ant_pre_load_firmware(btcoexist) +#define ex_halbtc8821c1ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8821c1ant_init_coex_dm(btcoexist) +#define ex_halbtc8821c1ant_ips_notify(btcoexist, type) +#define ex_halbtc8821c1ant_lps_notify(btcoexist, type) +#define ex_halbtc8821c1ant_scan_notify(btcoexist, type) +#define ex_halbtc8821c1ant_switchband_notify(btcoexist,type) +#define ex_halbtc8821c1ant_connect_notify(btcoexist, type) +#define ex_halbtc8821c1ant_media_status_notify(btcoexist, type) +#define ex_halbtc8821c1ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8821c1ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8821c1ant_rf_status_notify(btcoexist, type) +#define ex_halbtc8821c1ant_halt_notify(btcoexist) +#define ex_halbtc8821c1ant_pnp_notify(btcoexist, pnp_state) +#define ex_halbtc8821c1ant_coex_dm_reset(btcoexist) +#define ex_halbtc8821c1ant_periodical(btcoexist) +#define ex_halbtc8821c1ant_display_coex_info(btcoexist) +#define ex_halbtc8821c1ant_antenna_detection(btcoexist, cent_freq, offset, span, seconds) +#define ex_halbtc8821c1ant_antenna_isolation(btcoexist, cent_freq, offset, span, seconds) +#define ex_halbtc8821c1ant_psd_scan(btcoexist, cent_freq, offset, span, seconds) +#define ex_halbtc8821c1ant_display_ant_detection(btcoexist) +#endif + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c2ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c2ant.c new file mode 100644 index 0000000..5bae816 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c2ant.c @@ -0,0 +1,6936 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8821C Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8821C_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8821c_2ant glcoex_dm_8821c_2ant; +static struct coex_dm_8821c_2ant *coex_dm = &glcoex_dm_8821c_2ant; +static struct coex_sta_8821c_2ant glcoex_sta_8821c_2ant; +static struct coex_sta_8821c_2ant *coex_sta = &glcoex_sta_8821c_2ant; +static struct psdscan_sta_8821c_2ant gl_psd_scan_8821c_2ant; +static struct psdscan_sta_8821c_2ant *psd_scan = &gl_psd_scan_8821c_2ant; +static struct rfe_type_8821c_2ant gl_rfe_type_8821c_2ant; +static struct rfe_type_8821c_2ant *rfe_type = &gl_rfe_type_8821c_2ant; + +const char *const glbt_info_src_8821c_2ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u32 glcoex_ver_date_8821c_2ant = 20160805; +u32 glcoex_ver_8821c_2ant = 0x04; +u32 glcoex_ver_btdesired_8821c_2ant = 0x04; + + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8821c2ant_ + * ************************************************************ */ +u8 halbtc8821c2ant_bt_rssi_state(u8 *ppre_bt_rssi_state, u8 level_num, + u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = *ppre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821C_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return *ppre_bt_rssi_state; + } + + if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821C_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_MEDIUM) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8821C_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + *ppre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8821c2ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 *pprewifi_rssi_state, IN u8 level_num, IN u8 rssi_thresh, + IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = *pprewifi_rssi_state; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((*pprewifi_rssi_state == BTC_RSSI_STATE_LOW) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821C_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return *pprewifi_rssi_state; + } + + if ((*pprewifi_rssi_state == BTC_RSSI_STATE_LOW) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8821C_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((*pprewifi_rssi_state == BTC_RSSI_STATE_MEDIUM) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8821C_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + *pprewifi_rssi_state = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8821c2ant_coex_switch_threshold(IN struct btc_coexist *btcoexist, + IN u8 isolation_measuared) +{ + s8 interference_wl_tx = 0, interference_bt_tx = 0; + + + interference_wl_tx = BT_8821C_2ANT_WIFI_MAX_TX_POWER - + isolation_measuared; + interference_bt_tx = BT_8821C_2ANT_BT_MAX_TX_POWER - + isolation_measuared; + + + + coex_sta->wifi_coex_thres = BT_8821C_2ANT_WIFI_RSSI_COEXSWITCH_THRES1; + coex_sta->wifi_coex_thres2 = BT_8821C_2ANT_WIFI_RSSI_COEXSWITCH_THRES2; + + coex_sta->bt_coex_thres = BT_8821C_2ANT_BT_RSSI_COEXSWITCH_THRES1; + coex_sta->bt_coex_thres2 = BT_8821C_2ANT_BT_RSSI_COEXSWITCH_THRES2; + + + /* + coex_sta->wifi_coex_thres = interference_wl_tx + BT_8821C_2ANT_WIFI_SIR_THRES1; + coex_sta->wifi_coex_thres2 = interference_wl_tx + BT_8821C_2ANT_WIFI_SIR_THRES2; + + coex_sta->bt_coex_thres = interference_bt_tx + BT_8821C_2ANT_BT_SIR_THRES1; + coex_sta->bt_coex_thres2 = interference_bt_tx + BT_8821C_2ANT_BT_SIR_THRES2; + */ + + + + + + /* + if ( BT_8821C_2ANT_WIFI_RSSI_COEXSWITCH_THRES1 < (isolation_measuared - + BT_8821C_2ANT_DEFAULT_ISOLATION) ) + coex_sta->wifi_coex_thres = BT_8821C_2ANT_WIFI_RSSI_COEXSWITCH_THRES1; + else + coex_sta->wifi_coex_thres = BT_8821C_2ANT_WIFI_RSSI_COEXSWITCH_THRES1 - (isolation_measuared - + BT_8821C_2ANT_DEFAULT_ISOLATION); + + if ( BT_8821C_2ANT_BT_RSSI_COEXSWITCH_THRES1 < (isolation_measuared - + BT_8821C_2ANT_DEFAULT_ISOLATION) ) + coex_sta->bt_coex_thres = BT_8821C_2ANT_BT_RSSI_COEXSWITCH_THRES1; + else + coex_sta->bt_coex_thres = BT_8821C_2ANT_BT_RSSI_COEXSWITCH_THRES1 - (isolation_measuared - + BT_8821C_2ANT_DEFAULT_ISOLATION); + + */ +} + + +void halbtc8821c2ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); +} + +void halbtc8821c2ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +void halbtc8821c2ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + static u8 num_of_bt_counter_chk = 0, cnt_slave = 0; + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + if ((coex_sta->low_priority_tx > 1050) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + + if ((coex_sta->low_priority_rx >= 950) && + (coex_sta->low_priority_rx >= coex_sta->low_priority_tx) + && (!coex_sta->under_ips) && (!coex_sta->c2h_bt_inquiry_page) && + (coex_sta->bt_link_exist)) { + if (cnt_slave >= 2) { + bt_link_info->slave_role = true; + cnt_slave = 2; + } else + cnt_slave++; + } else { + if (cnt_slave == 0) { + bt_link_info->slave_role = false; + cnt_slave = 0; + } else + cnt_slave--; + + } + + if ((coex_sta->high_priority_tx == 0) && + (coex_sta->high_priority_rx == 0) && + (coex_sta->low_priority_tx == 0) && + (coex_sta->low_priority_rx == 0)) { + num_of_bt_counter_chk++; + if (num_of_bt_counter_chk >= 3) { + halbtc8821c2ant_query_bt_info(btcoexist); + num_of_bt_counter_chk = 0; + } + } + +} + +void halbtc8821c2ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ +#if 1 + s32 wifi_rssi = 0; + boolean wifi_busy = false, wifi_under_b_mode = false; + static u8 cck_lock_counter = 0; + u32 total_cnt, reg_val1, reg_val2; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + coex_sta->crc_ok_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_CCK); + coex_sta->crc_ok_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_LEGACY); + coex_sta->crc_ok_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_OK_HT); + coex_sta->crc_ok_11n_vht = + btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CRC32_OK_VHT); + + coex_sta->crc_err_cck = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_CCK); + coex_sta->crc_err_11g = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_LEGACY); + coex_sta->crc_err_11n = btcoexist->btc_phydm_query_PHY_counter( + btcoexist, PHYDM_INFO_CRC32_ERROR_HT); + coex_sta->crc_err_11n_vht = + btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CRC32_ERROR_VHT); + + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + total_cnt = coex_sta->crc_ok_cck + coex_sta->crc_ok_11g + + + coex_sta->crc_ok_11n + + coex_sta->crc_ok_11n_vht; + + if ((coex_dm->bt_status == + BT_8821C_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == + BT_8821C_1ANT_BT_STATUS_ACL_SCO_BUSY) || + (coex_dm->bt_status == + BT_8821C_1ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > (total_cnt - + coex_sta->crc_ok_cck)) { + if (cck_lock_counter < 3) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + + if (cck_lock_counter >= 3) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + if (coex_sta->cck_lock) + coex_sta->cck_ever_lock = true; + + coex_sta->pre_ccklock = coex_sta->cck_lock; + +#endif +} + +boolean halbtc8821c2ant_is_wifibt_status_changed(IN struct btc_coexist + *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false, pre_bt_off = false; + static u8 pre_hid_busy_num = 0; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (coex_sta->bt_disabled != pre_bt_off) { + pre_bt_off = coex_sta->bt_disabled; + + if (coex_sta->bt_disabled) + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!\n"); + else + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is enabled !!\n"); + + BTC_TRACE(trace_buf); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->bt_reg_vendor_ac = 0xffff; + coex_sta->bt_reg_vendor_ae = 0xffff; + return true; + } + + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + + if (!coex_sta->bt_disabled) { + + if (coex_sta->hid_busy_num != pre_hid_busy_num) { + pre_hid_busy_num = coex_sta->hid_busy_num; + return true; + } + } + } + + return false; +} + + +void halbtc8821c2ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + boolean bt_busy = false; + + coex_sta->num_of_profile = 0; + + /* set link exist status */ + if (!(coex_sta->bt_info & BT_INFO_8821C_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (coex_sta->bt_info & BT_INFO_8821C_1ANT_B_FTP) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->pan_exist = false; + + if (coex_sta->bt_info & BT_INFO_8821C_1ANT_B_A2DP) { + coex_sta->a2dp_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->a2dp_exist = false; + + if (coex_sta->bt_info & BT_INFO_8821C_1ANT_B_HID) { + coex_sta->hid_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->hid_exist = false; + + if (coex_sta->bt_info & BT_INFO_8821C_1ANT_B_SCO_ESCO) { + coex_sta->sco_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->sco_exist = false; + + } + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + bt_link_info->acl_busy = coex_sta->acl_busy; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; + + if (!(coex_sta->bt_info & BT_INFO_8821C_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8821C_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + } else if (coex_sta->bt_info == BT_INFO_8821C_2ANT_B_CONNECTION) { + /* connection exists but no busy */ + coex_dm->bt_status = BT_8821C_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if (((coex_sta->bt_info & BT_INFO_8821C_2ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8821C_2ANT_B_SCO_BUSY)) && + (coex_sta->bt_info & BT_INFO_8821C_2ANT_B_ACL_BUSY)) { + coex_dm->bt_status = BT_8821C_2ANT_BT_STATUS_ACL_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL SCO busy!!!\n"); + } else if ((coex_sta->bt_info & BT_INFO_8821C_2ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8821C_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8821C_2ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (coex_sta->bt_info & BT_INFO_8821C_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8821C_2ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8821C_2ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + } + + BTC_TRACE(trace_buf); + + if ((BT_8821C_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8821C_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8821C_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); +} + +void halbtc8821c2ant_update_wifi_channel_info(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + h2c_parameter[0] = + 0x1; /* enable BT AFH skip WL channel for 8821c because BT Rx LO interference */ + /* h2c_parameter[0] = 0x0; */ + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); + +} + +void halbtc8821c2ant_set_fw_dac_swing_level(IN struct btc_coexist *btcoexist, + IN u8 dac_swing_lvl) +{ + u8 h2c_parameter[1] = {0}; + + /* There are several type of dacswing */ + /* 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ + h2c_parameter[0] = dac_swing_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +void halbtc8821c2ant_fw_dac_swing_lvl(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 fw_dac_swing_lvl) +{ + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + + if (!force_exec) { + if (coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + halbtc8821c2ant_set_fw_dac_swing_level(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +void halbtc8821c2ant_set_fw_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN u8 dec_bt_pwr_lvl) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = dec_bt_pwr_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +void halbtc8821c2ant_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 dec_bt_pwr_lvl) +{ + coex_dm->cur_bt_dec_pwr_lvl = dec_bt_pwr_lvl; + + if (!force_exec) { + if (coex_dm->pre_bt_dec_pwr_lvl == coex_dm->cur_bt_dec_pwr_lvl) + return; + } + halbtc8821c2ant_set_fw_dec_bt_pwr(btcoexist, + coex_dm->cur_bt_dec_pwr_lvl); + + coex_dm->pre_bt_dec_pwr_lvl = coex_dm->cur_bt_dec_pwr_lvl; +} + + +void halbtc8821c2ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ + +#if 1 + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == + coex_dm->cur_low_penalty_ra) + return; + } + + if (low_penalty_ra) + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 15); + else + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 0); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; + +#endif + +} + + +void halbtc8821c2ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8821c2ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8821c2ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8821c2ant_write_score_board( + IN struct btc_coexist *btcoexist, + IN u16 bitpos, + IN boolean state +) +{ + + static u16 originalval = 0x8002; + + if (state) + originalval = originalval | bitpos; + else + originalval = originalval & (~bitpos); + + + btcoexist->btc_write_2byte(btcoexist, 0xaa, originalval); + +} + +void halbtc8821c2ant_read_score_board( + IN struct btc_coexist *btcoexist, + IN u16 *score_board_val +) +{ + + *score_board_val = (btcoexist->btc_read_2byte(btcoexist, + 0xaa)) & 0x7fff; +} + + +void halbtc8821c2ant_post_state_to_bt( + IN struct btc_coexist *btcoexist, + IN u16 type, + IN boolean state +) +{ + + halbtc8821c2ant_write_score_board(btcoexist, (u16) type, state); + +} + +void halbtc8821c2ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false, wifi_under_5g = false; + u16 u16tmp; + + /* This function check if bt is disabled */ +#if 0 + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + + +#else + + /* Read BT on/off status from scoreboard[1], enable this only if BT patch support this feature */ + halbtc8821c2ant_read_score_board(btcoexist, &u16tmp); + + bt_active = u16tmp & BIT(1); + + +#endif + + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } else { + + bt_disable_cnt++; + if (bt_disable_cnt >= 10) { + bt_disabled = true; + bt_disable_cnt = 10; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if ((wifi_under_5g) || (bt_disabled)) + halbtc8821c2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + else + halbtc8821c2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, true); + + + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + coex_sta->bt_disabled = bt_disabled; + } + +} + +void halbtc8821c2ant_enable_gnt_to_gpio(IN struct btc_coexist *btcoexist, + boolean isenable) +{ +#if BT_8821C_2ANT_COEX_DBG + static u8 bitVal[5] = {0, 0, 0, 0, 0}; + static boolean state = false; + /* + if (state ==isenable) + return; + else + state = isenable; + */ + if (isenable) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], enable_gnt_to_gpio!!\n"); + BTC_TRACE(trace_buf); + + /* enable GNT_WL, GNT_BT to GPIO for debug */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x1); + + /* store original value */ + bitVal[0] = (btcoexist->btc_read_1byte(btcoexist, + 0x66) & BIT(4)) >> 4; /*0x66[4] */ + bitVal[1] = (btcoexist->btc_read_1byte(btcoexist, + 0x67) & BIT(0)); /*0x66[8] */ + bitVal[2] = (btcoexist->btc_read_1byte(btcoexist, + 0x42) & BIT(3)) >> 3; /*0x40[19] */ + bitVal[3] = (btcoexist->btc_read_1byte(btcoexist, + 0x65) & BIT(7)) >> 7; /*0x64[15] */ + bitVal[4] = (btcoexist->btc_read_1byte(btcoexist, + 0x72) & BIT(2)) >> 2; /*0x70[18] */ + + /* switch GPIO Mux */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, BIT(4), + 0x0); /*0x66[4] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, BIT(0), + 0x0); /*0x66[8] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x42, BIT(3), + 0x0); /*0x40[19] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x65, BIT(7), + 0x0); /*0x64[15] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x72, BIT(2), + 0x0); /*0x70[18] = 0 */ + + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], disable_gnt_to_gpio!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x0); + + /* Restore original value */ + /* switch GPIO Mux */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, BIT(4), + bitVal[0]); /*0x66[4] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, BIT(0), + bitVal[1]); /*0x66[8] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x42, BIT(3), + bitVal[2]); /*0x40[19] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x65, BIT(7), + bitVal[3]); /*0x64[15] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x72, BIT(2), + bitVal[4]); /*0x70[18] = 0 */ + } + +#endif +} + +u32 halbtc8821c2ant_ltecoex_indirect_read_reg(IN struct btc_coexist *btcoexist, + IN u16 reg_addr) +{ + u32 j = 0; + + + /* wait for ready bit before access 0x1700 */ + btcoexist->btc_write_4byte(btcoexist, 0x1700, 0x800F0000 | reg_addr); + + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x1703)&BIT(5)) == 0) && + (j < BT_8821C_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + return btcoexist->btc_read_4byte(btcoexist, + 0x1708); /* get read data */ + +} + +void halbtc8821c2ant_ltecoex_indirect_write_reg(IN struct btc_coexist + *btcoexist, + IN u16 reg_addr, IN u32 bit_mask, IN u32 reg_value) +{ + u32 val, i = 0, j = 0, bitpos = 0; + + + if (bit_mask == 0x0) + return; + if (bit_mask == 0xffffffff) { + btcoexist->btc_write_4byte(btcoexist, 0x1704, + reg_value); /* put write data */ + + /* wait for ready bit before access 0x1700 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x1703)&BIT(5)) == 0) && + (j < BT_8821C_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + btcoexist->btc_write_4byte(btcoexist, 0x1700, + 0xc00F0000 | reg_addr); + } else { + for (i = 0; i <= 31; i++) { + if (((bit_mask >> i) & 0x1) == 0x1) { + bitpos = i; + break; + } + } + + /* read back register value before write */ + val = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, + reg_addr); + val = (val & (~bit_mask)) | (reg_value << bitpos); + + btcoexist->btc_write_4byte(btcoexist, 0x1704, + val); /* put write data */ + + /* wait for ready bit before access 0x7c0 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x1703)&BIT(5)) == 0) && + (j < BT_8821C_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + btcoexist->btc_write_4byte(btcoexist, 0x1700, + 0xc00F0000 | reg_addr); + + } + +} + +void halbtc8821c2ant_ltecoex_enable(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 val; + + val = (enable) ? 1 : 0; + halbtc8821c2ant_ltecoex_indirect_write_reg(btcoexist, 0x38, 0x80, + val); /* 0x38[7] */ + +} + +void halbtc8821c2ant_ltecoex_pathcontrol_owner(IN struct btc_coexist *btcoexist, + IN boolean wifi_control) +{ + u8 val; + + val = (wifi_control) ? 1 : 0; + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x4, + val); /* 0x70[26] */ + +} + +void halbtc8821c2ant_ltecoex_set_gnt_bt(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, bit_mask; + + state = state & 0x1; + val = (sw_control) ? ((state << 1) | 0x1) : 0; + + switch (control_block) { + case BT_8821C_2ANT_GNT_BLOCK_RFC_BB: + default: + bit_mask = 0xc000; + halbtc8821c2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[15:14] */ + bit_mask = 0x0c00; + halbtc8821c2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[11:10] */ + break; + case BT_8821C_2ANT_GNT_BLOCK_RFC: + bit_mask = 0xc000; + halbtc8821c2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[15:14] */ + break; + case BT_8821C_2ANT_GNT_BLOCK_BB: + bit_mask = 0x0c00; + halbtc8821c2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[11:10] */ + break; + + } + +} + +void halbtc8821c2ant_ltecoex_set_gnt_wl(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, bit_mask; + + state = state & 0x1; + val = (sw_control) ? ((state << 1) | 0x1) : 0; + + switch (control_block) { + case BT_8821C_2ANT_GNT_BLOCK_RFC_BB: + default: + bit_mask = 0x3000; + halbtc8821c2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[13:12] */ + bit_mask = 0x0300; + halbtc8821c2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[9:8] */ + break; + case BT_8821C_2ANT_GNT_BLOCK_RFC: + bit_mask = 0x3000; + halbtc8821c2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[13:12] */ + break; + case BT_8821C_2ANT_GNT_BLOCK_BB: + bit_mask = 0x0300; + halbtc8821c2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[9:8] */ + break; + + } + +} + +void halbtc8821c2ant_ltecoex_set_coex_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u16 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8821C_2ANT_CTT_WL_VS_LTE: + reg_addr = 0xa0; + break; + case BT_8821C_2ANT_CTT_BT_VS_LTE: + reg_addr = 0xa4; + break; + } + + if (reg_addr != 0x0000) + halbtc8821c2ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xffff, table_content); /* 0xa0[15:0] or 0xa4[15:0] */ + + +} + + +void halbtc8821c2ant_ltecoex_set_break_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u8 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8821C_2ANT_LBTT_WL_BREAK_LTE: + reg_addr = 0xa8; + break; + case BT_8821C_2ANT_LBTT_BT_BREAK_LTE: + reg_addr = 0xac; + break; + case BT_8821C_2ANT_LBTT_LTE_BREAK_WL: + reg_addr = 0xb0; + break; + case BT_8821C_2ANT_LBTT_LTE_BREAK_BT: + reg_addr = 0xb4; + break; + } + + if (reg_addr != 0x0000) + halbtc8821c2ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xff, table_content); /* 0xa8[15:0] or 0xb4[15:0] */ + + +} + +void halbtc8821c2ant_set_wltoggle_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 interval, + IN u8 val0x6c4_b0, IN u8 val0x6c4_b1, IN u8 val0x6c4_b2, + IN u8 val0x6c4_b3) +{ + static u8 pre_h2c_parameter[6] = {0}; + u8 cur_h2c_parameter[6] = {0}; + u8 i, match_cnt = 0; + + cur_h2c_parameter[0] = 0x7; /* op_code, 0x7= wlan toggle slot*/ + + cur_h2c_parameter[1] = interval; + cur_h2c_parameter[2] = val0x6c4_b0; + cur_h2c_parameter[3] = val0x6c4_b1; + cur_h2c_parameter[4] = val0x6c4_b2; + cur_h2c_parameter[5] = val0x6c4_b3; + + if (!force_exec) { + for (i = 1; i <= 5; i++) { + if (cur_h2c_parameter[i] != pre_h2c_parameter[i]) + break; + + match_cnt++; + } + + if (match_cnt == 5) + return; + } + + for (i = 1; i <= 5; i++) + pre_h2c_parameter[i] = cur_h2c_parameter[i]; + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, cur_h2c_parameter); +} + + + +void halbtc8821c2ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8821c2ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8821c2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8821c2ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + u32 break_table; + u8 select_table; + + coex_sta->coex_table_type = type; + + if (coex_sta->concurrent_rx_mode_on == true) { + break_table = 0xf0ffffff; /* set WL hi-pri can break BT */ + select_table = + 0xb; /* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */ + } else { + break_table = 0xffffff; + select_table = 0x3; + } + + switch (type) { + case 0: + halbtc8821c2ant_coex_table(btcoexist, force_exec, + 0xffffffff, 0xffffffff, break_table, select_table); + break; + case 1: + halbtc8821c2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, break_table, select_table); + break; + case 2: + halbtc8821c2ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5a5a5a5a, break_table, select_table); + break; + case 3: + halbtc8821c2ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5a5a5a5a, break_table, select_table); + break; + case 4: + halbtc8821c2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, break_table, select_table); + break; + case 5: + halbtc8821c2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x55555555, break_table, select_table); + break; + case 6: + halbtc8821c2ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0xaaaaaaaa, break_table, select_table); + break; + case 7: + halbtc8821c2ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0xaa5a5a5a, break_table, select_table); + break; + case 8: + halbtc8821c2ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0x5a5a5a5a, break_table, select_table); + break; + case 9: + halbtc8821c2ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0xaaaa5aaa, break_table, select_table); + break; + default: + break; + } +} + +void halbtc8821c2ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 h2c_parameter[1] = {0}; + + if (enable) { + h2c_parameter[0] |= BIT(0); /* function enable */ + } + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8821c2ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8821c2ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8821c2ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8821c2ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8821c2ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8821c2ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + u8 h2c_parameter[5] = {0, 0, 0, 0x40, 0}; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + /*halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); */ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + /*halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8);*/ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +void halbtc8821c2ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + case BTC_PS_LPS_ON: + halbtc8821c2ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8821c2ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + coex_sta->force_lps_on = true; + break; + case BTC_PS_LPS_OFF: + halbtc8821c2ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + default: + break; + } +} + + + +void halbtc8821c2ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], FW for AP mode\n"); + BTC_TRACE(trace_buf); + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + + halbtc8821c2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + } + } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + + halbtc8821c2ant_power_save_state( + btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } else { + halbtc8821c2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, + 0x0); + } + + + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +void halbtc8821c2ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + + static u8 psTdmaByte4Modify = 0x0, pre_psTdmaByte4Modify = 0x0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + if ((bt_link_info->slave_role) && (bt_link_info->a2dp_exist)) + psTdmaByte4Modify = 0x1; + else + psTdmaByte4Modify = 0x0; + + if (pre_psTdmaByte4Modify != psTdmaByte4Modify) { + + force_exec = true; + pre_psTdmaByte4Modify = psTdmaByte4Modify; + } + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + + if (coex_dm->cur_ps_tdma_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(off, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } + + + if (turn_on) { + switch (type) { + case 1: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x10, 0x03, 0xf1, + 0x54 | psTdmaByte4Modify); + break; + case 2: + default: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x35, 0x03, 0x71, + 0x11 | psTdmaByte4Modify); + break; + case 3: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3a, 0x3, 0xf1, + 0x10 | psTdmaByte4Modify); + break; + case 4: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x21, 0x3, 0xf1, + 0x10 | psTdmaByte4Modify); + break; + case 5: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x3, 0xf1, + 0x10 | psTdmaByte4Modify); + break; + case 6: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x10, 0x3, 0xf1, + 0x10 | psTdmaByte4Modify); + break; + case 7: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x20, 0x3, 0xf1, + 0x10 | psTdmaByte4Modify); + break; + case 10: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0x61, + 0x30, 0x03, 0x11, + 0x10); + break; + case 11: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x30, 0x03, 0x71, + 0x10 | psTdmaByte4Modify); + break; + case 12: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x21, 0x03, 0x71, + 0x11 | psTdmaByte4Modify); + break; + case 13: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1c, 0x03, 0x71, + 0x10 | psTdmaByte4Modify); + break; + case 14: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x30, 0x03, 0x71, + 0x11); + break; + case 51: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x10, 0x03, 0xf1, + 0x10 | psTdmaByte4Modify); + break; + case 101: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x10, 0x03, 0x70, + 0x54 | psTdmaByte4Modify); + break; + case 102: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x35, 0x03, 0x71, + 0x11 | psTdmaByte4Modify); + break; + case 103: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x3a, 0x3, 0x70, + 0x50 | psTdmaByte4Modify); + break; + case 104: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x21, 0x3, 0x70, + 0x50 | psTdmaByte4Modify); + break; + case 105: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x25, 0x3, 0x70, + 0x50 | psTdmaByte4Modify); + break; + case 106: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x10, 0x3, 0x70, + 0x50 | psTdmaByte4Modify); + break; + case 107: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x20, 0x3, 0x70, + 0x50 | psTdmaByte4Modify); + break; + case 108: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x30, 0x3, 0x70, + 0x50 | psTdmaByte4Modify); + break; + case 109: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xd7, + 0x10, 0x03, 0x10, + 0x54 | psTdmaByte4Modify); + break; + case 151: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x10, 0x03, 0x70, + 0x50 | psTdmaByte4Modify); + break; + } + } else { + /* disable PS tdma */ + switch (type) { + case 0: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x40, 0x0); + break; + case 1: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x48, 0x0); + break; + default: + halbtc8821c2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x40, 0x0); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void halbtc8821c2ant_set_int_block(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 pos_type) +{ +#if 0 + u8 regval_0xcba; + u32 u32tmp1 = 0; + + coex_dm->cur_int_block_status = pos_type; + + if (!force_exec) { + if (coex_dm->pre_int_block_status == + coex_dm->cur_int_block_status) + return; + } + + coex_dm->pre_int_block_status = coex_dm->cur_int_block_status; + + regval_0xcba = btcoexist->btc_read_1byte(btcoexist, 0xcba); + + switch (pos_type) { + + case BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLG_OF_BTG: + regval_0xcba = (regval_0xcba | BIT(0)) & (~(BIT( + 2))); /* 0xcb8[16] = 1, 0xcb8[18] = 0, WL_G select BTG */ + regval_0xcba = regval_0xcba & 0x0f; + + /*btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc1d, 0x0f, 0x5); */ /* Gain Table */ + /*btcoexist->btc_write_1byte_bitmask(btcoexist, 0xa9e, 0x0f, 0x2); */ /* CCK Gain Table */ + + break; + case BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLG_OF_WLAG: + regval_0xcba = regval_0xcba & (~(BIT(2) | BIT( + 0))); /* 0xcb8[16] = 0, 0xcb8[18] = 0, WL_G select WLAG */ + + /* regval_0xcba = regval_0xcba | BIT(4) | BIT(5) ; */ /* 0xcb8[21:20] = 2b'11, WL_G @ WLAG on */ + /* regval_0xcba = (regval_0xcba | BIT(6)) & (~(BIT(7)) ) ; */ /* 0xcb8[23:22] = 2b'01, WL_A @ WLAG off */ + /*btcoexist->btc_write_1byte_bitmask(btcoexist, 0xc1d, 0x0f, 0x0); */ /* Gain Table */ + /*btcoexist->btc_write_1byte_bitmask(btcoexist, 0xa9e, 0x0f, 0x6); */ /* CCK Gain Table */ + + break; + case BT_8821C_1ANT_INT_BLOCK_SWITCH_TO_WLA_OF_WLAG: + regval_0xcba = regval_0xcba & (~(BIT(2) | BIT( + 0))); /* 0xcb8[16] = 0, 0xcb8[18] = 0, WL_G select WLAG */ + /*regval_0xcba = (regval_0xcba | BIT(4)) & (~(BIT(5))); */ /* 0xcb8[21:20] = 2b'01, WL_G @ WLAG off */ + /*regval_0xcba = regval_0xcba | BIT(6) | BIT(7); */ /* 0xcb8[23:22] = 2b'11, WL_A @ WLAG on */ + + break; + } + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcba, 0xff, + regval_0xcba); + + u32tmp1 = btcoexist->btc_read_4byte(btcoexist, 0xcb8); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (After Int Block setup) 0xcb8 = 0x%08x **********\n", + u32tmp1); + BTC_TRACE(trace_buf); + +#endif +} + +void halbtc8821c2ant_set_ext_band_switch(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 pos_type) +{ + +#if 0 + boolean switch_polatiry_inverse = false; + u8 regval_0xcb6; + u32 u32tmp1 = 0, u32tmp2 = 0; + + if (!rfe_type->ext_band_switch_exist) + return; + + coex_dm->cur_ext_band_switch_status = pos_type; + + if (!force_exec) { + if (coex_dm->pre_ext_band_switch_status == + coex_dm->cur_ext_band_switch_status) + return; + } + + coex_dm->pre_ext_band_switch_status = + coex_dm->cur_ext_band_switch_status; + + /* swap control polarity if use different switch control polarity*/ + switch_polatiry_inverse = (rfe_type->ext_band_switch_ctrl_polarity == 1 + ? ~switch_polatiry_inverse : switch_polatiry_inverse); + + /*swap control polarity for WL_A, default polarity 0xcb4[21] = 0 && 0xcb4[23] = 1 is for WL_G */ + switch_polatiry_inverse = (pos_type == + BT_8821C_2ANT_EXT_BAND_SWITCH_TO_WLA ? ~switch_polatiry_inverse + : switch_polatiry_inverse); + + regval_0xcb6 = btcoexist->btc_read_1byte(btcoexist, 0xcb6); + + /* for normal switch polrity, 0xcb4[21] =1 && 0xcb4[23] = 0 for WL_A, vice versa */ + regval_0xcb6 = (switch_polatiry_inverse == 1 ? ((regval_0xcb6 & (~(BIT( + 7)))) | BIT(5)) : ((regval_0xcb6 & (~(BIT(5)))) | BIT(7))); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb6, 0xff, + regval_0xcb6); + + u32tmp1 = btcoexist->btc_read_4byte(btcoexist, 0xcb0); + u32tmp2 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (After Ext Band switch setup) 0xcb0 = 0x%08x, 0xcb4 = 0x%08x**********\n", + u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); +#endif + +} + +void halbtc8821c2ant_set_ext_ant_switch(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ctrl_type, IN u8 pos_type) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + boolean switch_polatiry_inverse = false; + u8 regval_0xcb7 = 0, regval_0x64; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + + if (!rfe_type->ext_ant_switch_exist) + return; + + coex_dm->cur_ext_ant_switch_status = (ctrl_type << 8) + pos_type; + + if (!force_exec) { + if (coex_dm->pre_ext_ant_switch_status == + coex_dm->cur_ext_ant_switch_status) + return; + } + + coex_dm->pre_ext_ant_switch_status = coex_dm->cur_ext_ant_switch_status; + + /* swap control polarity if use different switch control polarity*/ + /* Normal switch polarity for DPDT, 0xcb4[29:28] = 2b'01 => BTG to Main, WLG to Aux, 0xcb4[29:28] = 2b'10 => BTG to Aux, WLG to Main */ + /* Normal switch polarity for SPDT, 0xcb4[29:28] = 2b'01 => Ant to BTG, 0xcb4[29:28] = 2b'10 => Ant to WLG */ + switch_polatiry_inverse = (rfe_type->ext_ant_switch_ctrl_polarity == 1 ? + ~switch_polatiry_inverse : switch_polatiry_inverse); + + switch (pos_type) { + default: + case BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_BT: + case BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_NOCARE: + + break; + case BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_WLG: + switch_polatiry_inverse = + (rfe_type->wlg_Locate_at_btg == 0 ? + ~switch_polatiry_inverse : + switch_polatiry_inverse); + break; + case BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_WLA: + + break; + } + + if (board_info->ant_div_cfg) + ctrl_type = BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV; + + + switch (ctrl_type) { + default: + case BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, + 0xff, 0x77); /* BB SW, DPDT use RFE_ctrl8 and RFE_ctrl9 as control pin */ + + regval_0xcb7 = (switch_polatiry_inverse == false ? + 0x1 : 0x2); /* 0xcb4[29:28] = 2b'01 for no switch_polatiry_inverse, DPDT_SEL_N =1, DPDT_SEL_P =0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, + 0x30, regval_0xcb7); + + break; + case BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_PTA: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, + 0xff, 0x66); /* PTA, DPDT use RFE_ctrl8 and RFE_ctrl9 as control pin */ + + regval_0xcb7 = (switch_polatiry_inverse == false ? + 0x2 : 0x1); /* 0xcb4[29:28] = 2b'10 for no switch_polatiry_inverse, DPDT_SEL_N =1, DPDT_SEL_P =0 @ GNT_BT=1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb7, + 0x30, regval_0xcb7); + + break; + case BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, + 0xff, 0x88); /* */ + + /* no regval_0xcb7 setup required, because antenna switch control value by antenna diversity */ + + break; + case BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_MAC: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x1); /* 0x4c[23] = 1 */ + + regval_0x64 = (switch_polatiry_inverse == false ? 0x0 : + 0x1); /* 0x64[0] = 1b'0 for no switch_polatiry_inverse, DPDT_SEL_N =1, DPDT_SEL_P =0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, + regval_0x64); + break; + case BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_BT: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x0); /* 0x4c[24] = 0 */ + + /* no setup required, because antenna switch control value by BT vendor 0x1c[1:0] */ + break; + } + + /* PAPE, LNA_ON control by BT while WLAN off for current leakage issue */ + if (ctrl_type == BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_BT) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, + 0x0); /* PAPE 0x64[29] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x10, + 0x0); /* LNA_ON 0x64[28] = 0 */ + } else { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, + 0x1); /* PAPE 0x64[29] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x10, + 0x1); /* LNA_ON 0x64[28] = 1 */ + } + +#if BT_8821C_2ANT_COEX_DBG + + u32tmp1 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u32tmp2 = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0x64) & 0xff; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], (After Ext Ant switch setup) 0xcb4 = 0x%08x, 0x4c = 0x%08x, 0x64= 0x%02x\n", + u32tmp1, u32tmp2, u32tmp3); + BTC_TRACE(trace_buf); +#endif + +} + +void halbtc8821c2ant_set_rfe_type(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + +#if 0 + rfe_type->ext_band_switch_exist = false; + rfe_type->ext_band_switch_type = + BT_8821C_2ANT_EXT_BAND_SWITCH_USE_SPDT; /* SPDT; */ + rfe_type->ext_band_switch_ctrl_polarity = 0; + + if (rfe_type->ext_band_switch_exist) { + + /* band switch use RFE_ctrl1 (pin name: PAPE_A) and RFE_ctrl3 (pin name: LNAON_A) */ + + /* set RFE_ctrl1 as software control */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb0, 0xf0, 0x7); + + /* set RFE_ctrl3 as software control */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb1, 0xf0, 0x7); + + } +#endif + + /* the following setup should be got from Efuse in the future */ + rfe_type->rfe_module_type = board_info->rfe_type & 0x1f; + + rfe_type->ext_ant_switch_ctrl_polarity = 0; + + switch (rfe_type->rfe_module_type) { + case 0: + default: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_2ANT_EXT_ANT_SWITCH_USE_DPDT; /*2-Ant, DPDT, WLG*/ + rfe_type->wlg_Locate_at_btg = false; + break; + case 1: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_2ANT_EXT_ANT_SWITCH_USE_SPDT; /*1-Ant, Main, DPDT or SPDT, WLG */ + rfe_type->wlg_Locate_at_btg = false; + break; + case 2: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_2ANT_EXT_ANT_SWITCH_USE_SPDT; /*1-Ant, Main, DPDT or SPDT, BTG */ + rfe_type->wlg_Locate_at_btg = true; + break; + case 3: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_2ANT_EXT_ANT_SWITCH_USE_DPDT; /*1-Ant, Aux, DPDT, WLG */ + rfe_type->wlg_Locate_at_btg = false; + break; + case 4: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_2ANT_EXT_ANT_SWITCH_USE_DPDT; /*1-Ant, Aux, DPDT, BTG */; + rfe_type->wlg_Locate_at_btg = true; + break; + case 5: + rfe_type->ext_ant_switch_exist = + false; /*2-Ant, no antenna switch, WLG*/ + rfe_type->ext_ant_switch_type = + BT_8821C_2ANT_EXT_ANT_SWITCH_NONE; + rfe_type->wlg_Locate_at_btg = false; + break; + case 6: + rfe_type->ext_ant_switch_exist = + false; /*2-Ant, no antenna switch, WLG*/ + rfe_type->ext_ant_switch_type = + BT_8821C_2ANT_EXT_ANT_SWITCH_NONE; + rfe_type->wlg_Locate_at_btg = false; + break; + case 7: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_2ANT_EXT_ANT_SWITCH_USE_DPDT; /*2-Ant, DPDT, BTG*/ + rfe_type->wlg_Locate_at_btg = true; + break; + + } + + + if (rfe_type->wlg_Locate_at_btg) + halbtc8821c2ant_set_int_block(btcoexist, FORCE_EXEC, + BT_8821C_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_BTG); + else + halbtc8821c2ant_set_int_block(btcoexist, FORCE_EXEC, + BT_8821C_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_WLAG); + + +} + + +void halbtc8821c2ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean force_exec, + IN u8 phase) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 cnt_bt_cal_chk = 0; + boolean is_in_mp_mode = false; + u8 u8tmp = 0; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + u16 u16tmp1 = 0; + +#if BT_8821C_2ANT_ANTDET_ENABLE + + if (ant_pos_type == BTC_ANT_PATH_AUTO) { + if ((board_info->btdm_ant_det_finish) && + (board_info->btdm_ant_num_by_ant_det == 2)) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = BTC_ANT_WIFI_AT_MAIN; + else + ant_pos_type = BTC_ANT_WIFI_AT_AUX; + } + } + +#endif + + coex_dm->cur_ant_pos_type = (ant_pos_type << 8) + phase; + + if (!force_exec) { + if (coex_dm->cur_ant_pos_type == coex_dm->pre_ant_pos_type) + return; + } + + coex_dm->pre_ant_pos_type = coex_dm->cur_ant_pos_type; + +#if BT_8821C_2ANT_COEX_DBG + u32tmp1 = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + u32tmp2 = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, + 0x54); + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], (Before Ant Setup) 0xcb4 = 0x%x, 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x\n", + u32tmp3, u8tmp, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); +#endif + + switch (phase) { + case BT_8821C_2ANT_PHASE_COEX_POWERON: + + /* set Path control owner to WL at initial step */ + halbtc8821c2ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8821C_2ANT_PCO_BTSIDE); + + /* set GNT_BT to SW high */ + halbtc8821c2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_2ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW high */ + halbtc8821c2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_2ANT_SIG_STA_SET_TO_HIGH); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = + BTC_ANT_WIFI_AT_MAIN; + else + ant_pos_type = + BTC_ANT_WIFI_AT_AUX; + } + + coex_sta->run_time_state = false; + + break; + case BT_8821C_2ANT_PHASE_COEX_INIT: + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8821c2ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8821c2ant_ltecoex_set_coex_table( + btcoexist, + BT_8821C_2ANT_CTT_WL_VS_LTE, + 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8821c2ant_ltecoex_set_coex_table( + btcoexist, + BT_8821C_2ANT_CTT_BT_VS_LTE, + 0xffff); + + + /* Wait If BT IQK running, because Path control owner is at BT during BT IQK (setup by WiFi firmware) */ + while (cnt_bt_cal_chk <= 20) { + u8tmp = btcoexist->btc_read_1byte( + btcoexist, 0x49c); + cnt_bt_cal_chk++; + + if (u8tmp & BIT(1)) { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ########### BT is calibrating (wait cnt=%d) ###########\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + delay_ms(50); + } else { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ********** BT is NOT calibrating (wait cnt=%d)**********\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + break; + } + } + + /* set Path control owner to WL at initial step */ + halbtc8821c2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8821C_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW high */ + halbtc8821c2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_2ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW high */ + halbtc8821c2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_2ANT_SIG_STA_SET_TO_HIGH); + + coex_sta->run_time_state = false; + + if (BTC_ANT_PATH_AUTO == ant_pos_type) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = + BTC_ANT_WIFI_AT_MAIN; + else + ant_pos_type = + BTC_ANT_WIFI_AT_AUX; + } + + break; + case BT_8821C_2ANT_PHASE_WLANONLY_INIT: + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8821c2ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8821c2ant_ltecoex_set_coex_table( + btcoexist, + BT_8821C_2ANT_CTT_WL_VS_LTE, + 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8821c2ant_ltecoex_set_coex_table( + btcoexist, + BT_8821C_2ANT_CTT_BT_VS_LTE, + 0xffff); + + /* set Path control owner to WL at initial step */ + halbtc8821c2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8821C_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Low */ + halbtc8821c2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_2ANT_SIG_STA_SET_TO_LOW); + /* Set GNT_WL to SW high */ + halbtc8821c2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_2ANT_SIG_STA_SET_TO_HIGH); + + coex_sta->run_time_state = false; + + if (BTC_ANT_PATH_AUTO == ant_pos_type) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = + BTC_ANT_WIFI_AT_MAIN; + else + ant_pos_type = + BTC_ANT_WIFI_AT_AUX; + } + + break; + case BT_8821C_2ANT_PHASE_WLAN_OFF: + /* Disable LTE Coex Function in WiFi side */ + halbtc8821c2ant_ltecoex_enable(btcoexist, 0x0); + + /* set Path control owner to BT */ + halbtc8821c2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8821C_2ANT_PCO_BTSIDE); + + /* Set Ext Ant Switch to BT control at wifi off step */ + halbtc8821c2ant_set_ext_ant_switch(btcoexist, + FORCE_EXEC, + BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_BT, + BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_NOCARE); + coex_sta->run_time_state = false; + break; + case BT_8821C_2ANT_PHASE_2G_RUNTIME: + case BT_8821C_2ANT_PHASE_2G_RUNTIME_CONCURRENT: + + while (cnt_bt_cal_chk <= 20) { + /* 0x49c[0]=1 WL IQK, 0x49c[1]=1 BT IQK*/ + u8tmp = btcoexist->btc_read_1byte(btcoexist, + 0x49c); + + cnt_bt_cal_chk++; + if (u8tmp & BIT(0)) { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ########### WL is IQK (wait cnt=%d)\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + delay_ms(50); + } else if (u8tmp & BIT(1)) { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ########### BT is IQK (wait cnt=%d)\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + delay_ms(50); + } else { + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "[BTCoex], ********** WL and BT is NOT IQK (wait cnt=%d)\n", + cnt_bt_cal_chk); + BTC_TRACE(trace_buf); + break; + } + } + + /* set Path control owner to WL at runtime step */ + halbtc8821c2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8821C_2ANT_PCO_WLSIDE); + + if (phase == + BT_8821C_2ANT_PHASE_2G_RUNTIME_CONCURRENT) { + /* set GNT_BT to PTA */ + halbtc8821c2ant_ltecoex_set_gnt_bt( + btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8821C_2ANT_SIG_STA_SET_BY_HW); + + /* Set GNT_WL to SW High */ + halbtc8821c2ant_ltecoex_set_gnt_wl( + btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_2ANT_SIG_STA_SET_TO_HIGH); + } else { + /* set GNT_BT to PTA */ + halbtc8821c2ant_ltecoex_set_gnt_bt( + btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8821C_2ANT_SIG_STA_SET_BY_HW); + + /* Set GNT_WL to PTA */ + halbtc8821c2ant_ltecoex_set_gnt_wl( + btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8821C_2ANT_SIG_STA_SET_BY_HW); + } + coex_sta->run_time_state = true; + + if (rfe_type->wlg_Locate_at_btg) + halbtc8821c2ant_set_int_block(btcoexist, + NORMAL_EXEC, + BT_8821C_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_BTG); + else + halbtc8821c2ant_set_int_block(btcoexist, + NORMAL_EXEC, + BT_8821C_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_WLAG); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = + BTC_ANT_WIFI_AT_MAIN; + else + ant_pos_type = + BTC_ANT_WIFI_AT_AUX; + } + + break; + case BT_8821C_2ANT_PHASE_5G_RUNTIME: + + /* set Path control owner to WL at runtime step */ + halbtc8821c2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8821C_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Hi */ + halbtc8821c2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8821C_2ANT_SIG_STA_SET_BY_HW); + + /* Set GNT_WL to SW Hi */ + halbtc8821c2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_2ANT_SIG_STA_SET_TO_HIGH); + + coex_sta->run_time_state = true; + + halbtc8821c2ant_set_int_block(btcoexist, + NORMAL_EXEC, + BT_8821C_2ANT_INT_BLOCK_SWITCH_TO_WLA_OF_WLAG); + + + if (BTC_ANT_PATH_AUTO == ant_pos_type) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = + BTC_ANT_WIFI_AT_MAIN; + else + ant_pos_type = + BTC_ANT_WIFI_AT_AUX; + } + + + break; + case BT_8821C_2ANT_PHASE_BTMPMODE: + /* Disable LTE Coex Function in WiFi side */ + halbtc8821c2ant_ltecoex_enable(btcoexist, 0x0); + + /* set Path control owner to WL */ + halbtc8821c2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8821C_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Hi */ + halbtc8821c2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_2ANT_SIG_STA_SET_TO_HIGH); + + /* Set GNT_WL to SW Lo */ + halbtc8821c2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_2ANT_SIG_STA_SET_TO_LOW); + + coex_sta->run_time_state = false; + + if (BTC_ANT_PATH_AUTO == ant_pos_type) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = + BTC_ANT_WIFI_AT_MAIN; + else + ant_pos_type = + BTC_ANT_WIFI_AT_AUX; + } + + break; + case BT_8821C_2ANT_PHASE_ANTENNA_DET: + halbtc8821c2ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8821C_2ANT_PCO_WLSIDE); + + /* set GNT_BT to high */ + halbtc8821c2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_2ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to high */ + halbtc8821c2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8821C_2ANT_GNT_BLOCK_RFC_BB, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8821C_2ANT_SIG_STA_SET_TO_HIGH); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) { + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) + ant_pos_type = + BTC_ANT_WIFI_AT_MAIN; + else + ant_pos_type = + BTC_ANT_WIFI_AT_AUX; + } + + coex_sta->run_time_state = false; + + break; + } + + if (phase != BT_8821C_2ANT_PHASE_WLAN_OFF) { + switch (ant_pos_type) { + default: + case BTC_ANT_WIFI_AT_MAIN + : + halbtc8821c2ant_set_ext_ant_switch( + btcoexist, + force_exec, + BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW, + BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_WLG); + break; + case BTC_ANT_WIFI_AT_AUX + : + halbtc8821c2ant_set_ext_ant_switch( + btcoexist, + force_exec, + BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW, + BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_BT); + break; + case BTC_ANT_WIFI_AT_DIVERSITY + : + halbtc8821c2ant_set_ext_ant_switch( + btcoexist, + force_exec, + BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV, + BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_NOCARE); + break; + } + + } + + + +#if BT_8821C_2ANT_COEX_DBG + u32tmp1 = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], (After Ant-Setup phase---%d) 0xcb4 = 0x%x, 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x\n", + phase, u32tmp3, u8tmp, u32tmp1, u32tmp2); + + BTC_TRACE(trace_buf); +#endif + +} + + +u8 halbtc8821c2ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8821C_2ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 0) { + + if (bt_link_info->acl_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No-Profile busy\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_2ANT_COEX_ALGO_NOPROFILEBUSY; + } + } else if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_2ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_2ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_2ANT_COEX_ALGO_SCO; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP ==> A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_2ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_PANEDR; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_HID_A2DP; + } + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_2ANT_COEX_ALGO_HID; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP ==> HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8821C_2ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_PANEDR_HID; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_PANEDR_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8821C_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + + return algorithm; +} + + + +void halbtc8821c2ant_action_coex_all_off(IN struct btc_coexist *btcoexist) +{ + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + /* fw all off */ + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + +} + +void halbtc8821c2ant_action_wifi_under5g(IN struct btc_coexist *btcoexist) +{ + + /* fw all off */ + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8821C_2ANT_PHASE_5G_RUNTIME); +} + + +void halbtc8821c2ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + + boolean wifi_connected = false; + boolean scan = false, link = false, roam = false; + boolean wifi_busy = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (link || roam || coex_sta->wifi_is_high_pri_task) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi link/roam/hi-pri-task process + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 8); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + + } else if (scan) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi scan process + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 8); + + if (coex_sta->bt_create_connection) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 12); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 11); + + } else if (wifi_connected) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 8); + + if (wifi_busy) { + + if ((bt_link_info->a2dp_exist) && + (bt_link_info->acl_busy)) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 13); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + + } else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 13); + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi no-link + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8821c2ant_action_wifi_link_process(IN struct btc_coexist *btcoexist) +{ + u32 u32tmp, u32tmpb; + u8 u8tmpa; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + + if ((bt_link_info->a2dp_exist) && (bt_link_info->acl_busy)) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + +} + + +void halbtc8821c2ant_action_wifi_nonconnected(IN struct btc_coexist *btcoexist) +{ + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + /* fw all off */ + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8821c2ant_action_bt_idle(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + + boolean wifi_connected = false; + boolean scan = false, link = false, roam = false; + boolean wifi_busy = false; + + wifi_rssi_state = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi link process + BT Idle!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + } else if (wifi_connected) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT Idle!!\n"); + BTC_TRACE(trace_buf); + + if (wifi_busy) + halbtc8821c2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + else + halbtc8821c2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi no-link + BT Idle!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + +} + + +/* SCO only or SCO+PAN(HS) */ +void halbtc8821c2ant_action_sco(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, + &wifi_bw); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + if (wifi_bw == 0) { /* if 11bg mode */ + /*for 4/18 hid */ + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 9); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 10); + } else { + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 3); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } + } + +} + + +void halbtc8821c2ant_action_hid(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + u32 wifi_bw = 1; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + wifi_rssi_state = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + if ((wifi_bw == 0) && + (coex_sta->hid_busy_num >= 2)) { /* if 11bg mode */ + /*for 4/18 hid */ + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 9); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 10); + + } else { + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 3); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } + } + +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +void halbtc8821c2ant_action_a2dp(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->scan_ap_num <= 4)) + wifi_turbo = true; +#endif + + wifi_rssi_state = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + if (coex_sta->is_setupLink) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 51); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + } else + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 2); + } else { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (wifi_turbo) + halbtc8821c2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + if (wifi_busy) { + if (coex_sta->is_setupLink) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 151); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 101); + } else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 102); + + } + +} + +void halbtc8821c2ant_action_pan_edr(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->scan_ap_num <= 4)) + wifi_turbo = true; +#endif + + wifi_rssi_state = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + +#if 0 + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +#endif + + +#if 1 + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 4); + } else { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (wifi_turbo) + halbtc8821c2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + if (wifi_busy) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 103); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 104); + + } + +#endif + +} + + +/* PAN(HS) only */ +void halbtc8821c2ant_action_pan_hs(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->scan_ap_num <= 4)) + wifi_turbo = true; +#endif + + + wifi_rssi_state = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + + } else { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } + +} + + +void halbtc8821c2ant_action_hid_a2dp(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + if (coex_sta->is_setupLink) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 51); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + } else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 2); + } else { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + + if (wifi_busy) { + if (coex_sta->hid_busy_num >= 2) { + halbtc8821c2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 8); + halbtc8821c2ant_set_wltoggle_coex_table(btcoexist, + NORMAL_EXEC, + 0x2, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 109); + } else if (coex_sta->is_setupLink) { + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 151); + } else { + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 101); + } + } else { + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 1); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 102); + } + + } + +} + + +void halbtc8821c2ant_action_a2dp_pan_hs(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->scan_ap_num <= 4)) + wifi_turbo = true; +#endif + + + wifi_rssi_state = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + } else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 6); + + } else { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (wifi_turbo) + halbtc8821c2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + if (wifi_busy) { + + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 107); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 105); + } else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 106); + + } + +} + + + +/* PAN(EDR)+A2DP */ +void halbtc8821c2ant_action_pan_edr_a2dp(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->scan_ap_num <= 4)) + wifi_turbo = true; +#endif + + + wifi_rssi_state = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + + if (((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) || + (!coex_sta->is_A2DP_3M)) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + } else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 6); + } else { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (wifi_turbo) + halbtc8821c2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + if (wifi_busy) { + + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 107); + else if (wifi_turbo) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 108); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 105); + } else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 106); + + } + +} + +void halbtc8821c2ant_action_pan_edr_hid(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + else + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 4); + + + } else { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + + if (wifi_busy) + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 103); + else + + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 104); + + } + +} + +/* HID+A2DP+PAN(EDR) */ +void halbtc8821c2ant_action_hid_a2dp_pan_edr(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8821c2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8821c2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + + if (((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) || + (!coex_sta->is_A2DP_3M)) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + } else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 6); + } else { + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + + if (wifi_busy) { + + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 107); + else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 105); + } else + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 106); + } + +} + + + +void halbtc8821c2ant_action_bt_whck_test(IN struct btc_coexist *btcoexist) +{ + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +} + +void halbtc8821c2ant_action_wifi_multi_port(IN struct btc_coexist *btcoexist) +{ + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* hw all off */ + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +} + +void halbtc8821c2ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + u32 num_of_wifi_link = 0; + u32 wifi_link_status = 0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean miracast_plus_bt = false; + boolean scan = false, link = false, roam = false, + wifi_connected = false, wifi_under_5g = false; + + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (!coex_sta->run_time_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], return for run_time_state = false !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->freeze_coexrun_by_btinfo) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), return for freeze_coexrun_by_btinfo\n"); + BTC_TRACE(trace_buf); + return; + } + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 5G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_action_wifi_under5g(btcoexist); + return; + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 2G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8821C_2ANT_PHASE_2G_RUNTIME); + } + + + if (coex_sta->bt_whck_test) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under WHCK TEST!!!\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_bt_whck_test(btcoexist); + return; + } + + if (coex_sta->bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled!!!\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_coex_all_off(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_bt_inquiry(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under Link Process !!\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_wifi_link_process(btcoexist); + return; + } + + /* for P2P */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + BTC_TRACE(trace_buf); + + if (bt_link_info->bt_link_exist) + miracast_plus_bt = true; + else + miracast_plus_bt = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + halbtc8821c2ant_action_wifi_multi_port(btcoexist); + + return; + } else { + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + } + + + algorithm = halbtc8821c2ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Algorithm = %d\n", + coex_dm->cur_algorithm); + BTC_TRACE(trace_buf); + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (!wifi_connected) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, wifi non-connected!!.\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_wifi_nonconnected(btcoexist); + + } else if ((BT_8821C_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) || + (BT_8821C_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, bt idle!!.\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_action_bt_idle(btcoexist); + + } else { + + if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], pre_algorithm=%d, cur_algorithm=%d\n", + coex_dm->pre_algorithm, coex_dm->cur_algorithm); + BTC_TRACE(trace_buf); + } + + switch (coex_dm->cur_algorithm) { + + case BT_8821C_2ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_sco(btcoexist); + break; + case BT_8821C_2ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID.\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_hid(btcoexist); + break; + case BT_8821C_2ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_a2dp(btcoexist); + break; + case BT_8821C_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8821C_2ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_pan_edr(btcoexist); + break; + case BT_8821C_2ANT_COEX_ALGO_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HS mode.\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_pan_hs(btcoexist); + break; + case BT_8821C_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8821C_2ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_pan_edr_hid(btcoexist); + break; + case BT_8821C_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_hid_a2dp_pan_edr( + btcoexist); + break; + case BT_8821C_2ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_hid_a2dp(btcoexist); + break; + case BT_8821C_2ANT_COEX_ALGO_NOPROFILEBUSY: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = No-Profile busy.\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_bt_idle(btcoexist); + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_action_coex_all_off(btcoexist); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +void halbtc8821c2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + + halbtc8821c2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + /* fw all off */ + halbtc8821c2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8821c2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8821c2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_sta->pop_event_cnt = 0; + coex_sta->cnt_RemoteNameReq = 0; + coex_sta->cnt_ReInit = 0; + coex_sta->cnt_setupLink = 0; + coex_sta->cnt_IgnWlanAct = 0; + coex_sta->cnt_Page = 0; + + halbtc8821c2ant_query_bt_info(btcoexist); +} + + +void halbtc8821c2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + u8 u8tmp = 0; + u32 vendor; + u32 u32tmp0 = 0, u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + + + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u32tmp1 = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], (Before Init HW config) 0xcb4 = 0x%x, 0x38= 0x%x, 0x54= 0x%x\n", + u32tmp3, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf);; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 2Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->bt_reg_vendor_ac = 0xffff; + coex_sta->bt_reg_vendor_ae = 0xffff; + coex_sta->isolation_btween_wb = BT_8821C_2ANT_DEFAULT_ISOLATION; + + + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = (btcoexist->btc_read_1byte(btcoexist, + 0xf1) & 0xf0) >> 4; + + coex_sta->dis_ver_info_cnt = 0; + + halbtc8821c2ant_coex_switch_threshold(btcoexist, + coex_sta->isolation_btween_wb); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + + /* BT report packet sample rate */ + btcoexist->btc_write_1byte(btcoexist, 0x790, 0x5); + + /* Init 0x778 = 0x1 for 2-Ant */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + + /* Enable PTA (3-wire function form BT side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x41, 0x02, 0x1); + + /* Enable PTA (tx/rx signal form WiFi side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4c6, 0x10, 0x1); + + /* set GNT_BT=1 for coex table select both */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x763, 0x10, 0x1); + + halbtc8821c2ant_enable_gnt_to_gpio(btcoexist, true); + + /* check if WL firmware download ok */ + /*if (btcoexist->btc_read_1byte(btcoexist, 0x80) == 0xc6)*/ + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ONOFF, true); + + /* Enable counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, + 0x4); /* 0x76e[3] =1, WLAN_Act control by PTA */ + + /* WLAN_Tx by GNT_WL 0x950[29] = 0 */ + /* btcoexist->btc_write_1byte_bitmask(btcoexist, 0x953, 0x20, 0x0); */ + + halbtc8821c2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + halbtc8821c2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + psd_scan->ant_det_is_ant_det_available = true; + + if (wifi_only) { + coex_sta->concurrent_rx_mode_on = false; + /* Path config */ + /* Set Antenna Path */ + halbtc8821c2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_2ANT_PHASE_WLANONLY_INIT); + + btcoexist->stop_coex_dm = true; + } else { + /*Set BT polluted packet on for Tx rate adaptive not including Tx retry break by PTA, 0x45c[19] =1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + + coex_sta->concurrent_rx_mode_on = true; + /* btcoexist->btc_write_1byte_bitmask(btcoexist, 0x953, 0x2, 0x1); */ + + /* RF 0x1[1] = 0->Set GNT_WL_RF_Rx always = 1 for con-current Rx, mask Tx only */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0x2, 0x0); + + /* Set Antenna Path */ + halbtc8821c2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_2ANT_PHASE_COEX_INIT); + + btcoexist->stop_coex_dm = false; + } + + +} + +#if 0 +u32 halbtc8821c2ant_psd_log2base(IN struct btc_coexist *btcoexist, IN u32 val) +{ + u8 j; + u32 tmp, tmp2, val_integerd_b = 0, tindex, shiftcount = 0; + u32 result, val_fractiond_b = 0, table_fraction[21] = {0, 432, 332, 274, 232, 200, + 174, 151, 132, 115, 100, 86, 74, 62, 51, 42, + 32, 23, 15, 7, 0 + }; + + if (val == 0) + return 0; + + tmp = val; + + while (1) { + if (tmp == 1) + break; + else { + tmp = (tmp >> 1); + shiftcount++; + } + } + + + val_integerd_b = shiftcount + 1; + + tmp2 = 1; + for (j = 1; j <= val_integerd_b; j++) + tmp2 = tmp2 * 2; + + tmp = (val * 100) / tmp2; + tindex = tmp / 5; + + if (tindex > 20) + tindex = 20; + + val_fractiond_b = table_fraction[tindex]; + + result = val_integerd_b * 100 - val_fractiond_b; + + return result; + + +} + +void halbtc8821c2ant_psd_show_antenna_detect_result(IN struct btc_coexist + *btcoexist) +{ + u8 *cli_buf = btcoexist->cli_buf; + struct btc_board_info *board_info = &btcoexist->board_info; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n============[Antenna Detection info] ============\n"); + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 12) { /* Get Ant Det from BT */ + + if (board_info->btdm_ant_num_by_ant_det == 1) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "1-Antenna", + BT_8821C_2ANT_ANTDET_PSDTHRES_1ANT, + BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION); + else { + + if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION) + * 100) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (>%d)", + "Ant Det Result", "2-Antenna (Bad-Isolation)", + BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "2-Antenna (Good-Isolation)", + BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset, + BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + } + + } else if (psd_scan->ant_det_result == 1) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (>%d)", + "Ant Det Result", "2-Antenna (Bad-Isolation)", + BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else if (psd_scan->ant_det_result == 2) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "2-Antenna (Good-Isolation)", + BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset, + BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (%d~%d)", + "Ant Det Result", "1-Antenna", + BT_8821C_2ANT_ANTDET_PSDTHRES_1ANT, + BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset); + + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s ", + "Antenna Detection Finish", + (board_info->btdm_ant_det_finish + ? "Yes" : "No")); + CL_PRINTF(cli_buf); + + switch (psd_scan->ant_det_result) { + case 0: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is not available)"); + break; + case 1: /* 2-Ant bad-isolation */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 2: /* 2-Ant good-isolation */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 3: /* 1-Ant */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available)"); + break; + case 4: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Uncertainty result)"); + break; + case 5: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "(Pre-Scan fai)"); + break; + case 6: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(WiFi is Scanning)"); + break; + case 7: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is not idle)"); + break; + case 8: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Abort by WiFi Scanning)"); + break; + case 9: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(Antenna Init is not ready)"); + break; + case 10: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is Inquiry or page)"); + break; + case 11: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is Disabled)"); + break; + case 12: + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "(BT is available, result from BT"); + break; + } + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 12) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d dB", + "PSD Scan Peak Value", + psd_scan->ant_det_psd_scan_peak_val / 100); + CL_PRINTF(cli_buf); + return; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "Ant Detect Total Count", psd_scan->ant_det_try_count); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "Ant Detect Fail Count", psd_scan->ant_det_fail_count); + CL_PRINTF(cli_buf); + + if ((!board_info->btdm_ant_det_finish) && + (psd_scan->ant_det_result != 5)) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "BT Response", + (psd_scan->ant_det_result ? "ok" : "fail")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ms", "BT Tx Time", + psd_scan->ant_det_bt_tx_time); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "BT Tx Ch", + psd_scan->ant_det_bt_le_channel); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", + "WiFi PSD Cent-Ch/Offset/Span", + psd_scan->real_cent_freq, psd_scan->real_offset, + psd_scan->real_span); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d dB", + "PSD Pre-Scan Peak Value", + psd_scan->ant_det_pre_psdscan_peak_val / 100); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s (<= %d)", + "PSD Pre-Scan result", + (psd_scan->ant_det_result != 5 ? "ok" : "fail"), + BT_8821C_2ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + CL_PRINTF(cli_buf); + + if (psd_scan->ant_det_result == 5) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s dB", + "PSD Scan Peak Value", psd_scan->ant_det_peak_val); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s MHz", + "PSD Scan Peak Freq", psd_scan->ant_det_peak_freq); + CL_PRINTF(cli_buf); + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "TFBGA Package", + (board_info->tfbga_package) ? "Yes" : "No"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "PSD Threshold Offset", psd_scan->ant_det_thres_offset); + CL_PRINTF(cli_buf); + +} + +void halbtc8821c2ant_psd_showdata(IN struct btc_coexist *btcoexist) +{ + u8 *cli_buf = btcoexist->cli_buf; + u32 delta_freq_per_point; + u32 freq, freq1, freq2, n = 0, i = 0, j = 0, m = 0, psd_rep1, psd_rep2; + + if (psd_scan->ant_det_result == 12) + return; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n\n============[PSD info] (%d)============\n", + psd_scan->psd_gen_count); + CL_PRINTF(cli_buf); + + if (psd_scan->psd_gen_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n No data !!\n"); + CL_PRINTF(cli_buf); + return; + } + + if (psd_scan->psd_point == 0) + delta_freq_per_point = 0; + else + delta_freq_per_point = psd_scan->psd_band_width / + psd_scan->psd_point; + + /* if (psd_scan->is_psd_show_max_only) */ + if (0) { + psd_rep1 = psd_scan->psd_max_value / 100; + psd_rep2 = psd_scan->psd_max_value - psd_rep1 * 100; + + freq = ((psd_scan->real_cent_freq - 20) * 1000000 + + psd_scan->psd_max_value_point * delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (freq2 < 100) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n Freq = %d.0%d MHz", + freq1, freq2); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n Freq = %d.%d MHz", + freq1, freq2); + + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + ", Value = %d.0%d dB, (%d)\n", + psd_rep1, psd_rep2, psd_scan->psd_max_value); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + ", Value = %d.%d dB, (%d)\n", + psd_rep1, psd_rep2, psd_scan->psd_max_value); + + CL_PRINTF(cli_buf); + } else { + m = psd_scan->psd_start_point; + n = psd_scan->psd_start_point; + i = 1; + j = 1; + + while (1) { + do { + freq = ((psd_scan->real_cent_freq - 20) * + 1000000 + m * + delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (i == 1) { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.000", + freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.0%2d", + freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.%3d", + freq1, + freq2); + } else if ((i % 8 == 0) || + (m == psd_scan->psd_stop_point)) { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.000\n", freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.0%2d\n", freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.%3d\n", freq1, + freq2); + } else { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.000", freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.0%2d", freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.%3d", freq1, + freq2); + } + + i++; + m++; + CL_PRINTF(cli_buf); + + } while ((i <= 8) && (m <= psd_scan->psd_stop_point)); + + + do { + psd_rep1 = psd_scan->psd_report_max_hold[n] / + 100; + psd_rep2 = psd_scan->psd_report_max_hold[n] - + psd_rep1 * + 100; + + if (j == 1) { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Val %7d.0%d", + psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Val %7d.%d", + psd_rep1, + psd_rep2); + } else if ((j % 8 == 0) || + (n == psd_scan->psd_stop_point)) { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.0%d\n", psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.%d\n", psd_rep1, + psd_rep2); + } else { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.0%d", psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.%d", psd_rep1, + psd_rep2); + } + + j++; + n++; + CL_PRINTF(cli_buf); + + } while ((j <= 8) && (n <= psd_scan->psd_stop_point)); + + if ((m > psd_scan->psd_stop_point) || + (n > psd_scan->psd_stop_point)) + break; + else { + i = 1; + j = 1; + } + + } + } + + +} + +#pragma optimize("", off) +void halbtc8821c2ant_psd_maxholddata(IN struct btc_coexist *btcoexist, + IN u32 gen_count) +{ + u32 i = 0; + u32 loop_i_max = 0, loop_val_max = 0; + + if (gen_count == 1) { + memcpy(psd_scan->psd_report_max_hold, + psd_scan->psd_report, + BT_8821C_2ANT_ANTDET_PSD_POINTS * sizeof(u32)); + } + + for (i = psd_scan->psd_start_point; + i <= psd_scan->psd_stop_point; i++) { + + /* update max-hold value at each freq point */ + if (psd_scan->psd_report[i] > psd_scan->psd_report_max_hold[i]) + psd_scan->psd_report_max_hold[i] = + psd_scan->psd_report[i]; + + /* search the max value in this seep */ + if (psd_scan->psd_report[i] > loop_val_max) { + loop_val_max = psd_scan->psd_report[i]; + loop_i_max = i; + } + } + + if (gen_count <= BT_8821C_2ANT_ANTDET_PSD_SWWEEPCOUNT) + psd_scan->psd_loop_max_value[gen_count - 1] = loop_val_max; + +} + + +#pragma optimize("", off) +u32 halbtc8821c2ant_psd_getdata(IN struct btc_coexist *btcoexist, IN u32 point) +{ + /* reg 0x808[9:0]: FFT data x */ + /* reg 0x808[22]: 0-->1 to get 1 FFT data y */ + /* reg 0x8b4[15:0]: FFT data y report */ + + u32 val = 0, psd_report = 0; + int k = 0; + + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + + val &= 0xffbffc00; + val |= point; + + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + val |= 0x00400000; + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + while (1) { + if (k++ > BT_8821C_2ANT_ANTDET_SWEEPPOINT_DELAY) + break; + } + + val = btcoexist->btc_read_4byte(btcoexist, 0x8b4); + + psd_report = val & 0x0000ffff; + + return psd_report; +} + +#pragma optimize("", off) +boolean halbtc8821c2ant_psd_sweep_point(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN s32 offset, IN u32 span, IN u32 points, + IN u32 avgnum, IN u32 loopcnt) +{ + u32 i = 0, val = 0, n = 0, k = 0, j, point_index = 0; + u32 points1 = 0, psd_report = 0; + u32 start_p = 0, stop_p = 0, delta_freq_per_point = 156250; + u32 psd_center_freq = 20 * 10 ^ 6; + boolean outloop = false, scan , roam, is_sweep_ok = true; + u8 flag = 0; + u32 tmp = 0, u32tmp1 = 0; + u32 wifi_original_channel = 1; + u32 psd_sum = 0, avg_cnt = 0; + u32 i_max = 0, val_max = 0, val_max2 = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx PSD Sweep Start!!\n"); + BTC_TRACE(trace_buf); + + do { + switch (flag) { + case 0: /* Get PSD parameters */ + default: + + psd_scan->psd_band_width = 40 * 1000000; + psd_scan->psd_point = points; + psd_scan->psd_start_base = points / 2; + psd_scan->psd_avg_num = avgnum; + psd_scan->real_cent_freq = cent_freq; + psd_scan->real_offset = offset; + psd_scan->real_span = span; + + + points1 = psd_scan->psd_point; + delta_freq_per_point = psd_scan->psd_band_width / + psd_scan->psd_point; + + /* PSD point setup */ + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + val &= 0xffff0fff; + + switch (psd_scan->psd_point) { + case 128: + val |= 0x0; + break; + case 256: + default: + val |= 0x00004000; + break; + case 512: + val |= 0x00008000; + break; + case 1024: + val |= 0x0000c000; + break; + } + + switch (psd_scan->psd_avg_num) { + case 1: + val |= 0x0; + break; + case 8: + val |= 0x00001000; + break; + case 16: + val |= 0x00002000; + break; + case 32: + default: + val |= 0x00003000; + break; + } + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + flag = 1; + break; + case 1: /* calculate the PSD point index from freq/offset/span */ + psd_center_freq = psd_scan->psd_band_width / 2 + + offset * (1000000); + + start_p = psd_scan->psd_start_base + (psd_center_freq - + span * (1000000) / 2) / delta_freq_per_point; + psd_scan->psd_start_point = start_p - + psd_scan->psd_start_base; + + stop_p = psd_scan->psd_start_base + (psd_center_freq + + span * (1000000) / 2) / delta_freq_per_point; + psd_scan->psd_stop_point = stop_p - + psd_scan->psd_start_base - 1; + + flag = 2; + break; + case 2: /* set RF channel/BW/Mode */ + + /* set 3-wire off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x88c); + val |= 0x00300000; + btcoexist->btc_write_4byte(btcoexist, 0x88c, val); + + /* CCK off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x800); + val &= 0xfeffffff; + btcoexist->btc_write_4byte(btcoexist, 0x800, val); + + /* Tx-pause on */ + btcoexist->btc_write_1byte(btcoexist, 0x522, 0x6f); + + /* store WiFi original channel */ + wifi_original_channel = btcoexist->btc_get_rf_reg( + btcoexist, BTC_RF_A, 0x18, 0x3ff); + + /* Set RF channel */ + if (cent_freq == 2484) + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x18, 0x3ff, 0xe); + else + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x18, 0x3ff, (cent_freq - 2412) / 5 + + 1); /* WiFi TRx Mask on */ + + /* save original RCK value */ + u32tmp1 = btcoexist->btc_get_rf_reg( + btcoexist, BTC_RF_A, 0x1d, 0xfffff); + + /* Enter debug mode */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xde, + 0x2, 0x1); + + /* Set RF Rx filter corner */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1d, + 0xfffff, 0x2e); + + + /* Set RF mode = Rx, RF Gain = 0x320a0 */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x0, + 0xfffff, 0x320a0); + + while (1) { + if (k++ > BT_8821C_2ANT_ANTDET_SWEEPPOINT_DELAY) + break; + } + flag = 3; + break; + case 3: + psd_scan->psd_gen_count = 0; + for (j = 1; j <= loopcnt; j++) { + + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || roam) { + is_sweep_ok = false; + break; + } + memset(psd_scan->psd_report, 0, + psd_scan->psd_point * sizeof(u32)); + start_p = psd_scan->psd_start_point + + psd_scan->psd_start_base; + stop_p = psd_scan->psd_stop_point + + psd_scan->psd_start_base + 1; + + i = start_p; + point_index = 0; + + while (i < stop_p) { + if (i >= points1) + psd_report = + halbtc8821c2ant_psd_getdata( + btcoexist, i - points1); + else + psd_report = + halbtc8821c2ant_psd_getdata( + btcoexist, i); + + if (psd_report == 0) + tmp = 0; + else + /* tmp = 20*log10((double)psd_report); */ + /* 20*log2(x)/log2(10), log2Base return theresult of the psd_report*100 */ + tmp = 6 * halbtc8821c2ant_psd_log2base( + btcoexist, psd_report); + + n = i - psd_scan->psd_start_base; + psd_scan->psd_report[n] = tmp; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Point=%d, psd_dB_data = %d\n", + i, psd_scan->psd_report[n]); + BTC_TRACE(trace_buf); + + i++; + + } + + halbtc8821c2ant_psd_maxholddata(btcoexist, j); + + psd_scan->psd_gen_count = j; + + /*Accumulate Max PSD value in this loop if the value > threshold */ + if (psd_scan->psd_loop_max_value[j - 1] >= + 4000) { + psd_sum = psd_sum + + psd_scan->psd_loop_max_value[j - + 1]; + avg_cnt++; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Loop=%d, Max_dB_data = %d\n", + j, psd_scan->psd_loop_max_value[j + - 1]); + BTC_TRACE(trace_buf); + + } + + if (loopcnt == BT_8821C_2ANT_ANTDET_PSD_SWWEEPCOUNT) { + + /* search the Max Value between each-freq-point-max-hold value of all sweep*/ + for (i = 1; + i <= BT_8821C_2ANT_ANTDET_PSD_SWWEEPCOUNT; + i++) { + + if (i == 1) { + i_max = i; + val_max = psd_scan->psd_loop_max_value[i + - 1]; + val_max2 = + psd_scan->psd_loop_max_value[i + - 1]; + } else if ( + psd_scan->psd_loop_max_value[i - + 1] > val_max) { + val_max2 = val_max; + i_max = i; + val_max = psd_scan->psd_loop_max_value[i + - 1]; + } else if ( + psd_scan->psd_loop_max_value[i - + 1] > val_max2) + val_max2 = + psd_scan->psd_loop_max_value[i + - 1]; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "i = %d, val_hold= %d, val_max = %d, val_max2 = %d\n", + i, psd_scan->psd_loop_max_value[i + - 1], + val_max, val_max2); + + BTC_TRACE(trace_buf); + } + + psd_scan->psd_max_value_point = i_max; + psd_scan->psd_max_value = val_max; + psd_scan->psd_max_value2 = val_max2; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "val_max = %d, val_max2 = %d\n", + psd_scan->psd_max_value, + psd_scan->psd_max_value2); + BTC_TRACE(trace_buf); + } + + if (avg_cnt != 0) { + psd_scan->psd_avg_value = (psd_sum / avg_cnt); + if ((psd_sum % avg_cnt) >= (avg_cnt / 2)) + psd_scan->psd_avg_value++; + } else + psd_scan->psd_avg_value = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "AvgLoop=%d, Avg_dB_data = %d\n", + avg_cnt, psd_scan->psd_avg_value); + BTC_TRACE(trace_buf); + + flag = 100; + break; + case 99: /* error */ + + outloop = true; + break; + case 100: /* recovery */ + + /* set 3-wire on */ + val = btcoexist->btc_read_4byte(btcoexist, 0x88c); + val &= 0xffcfffff; + btcoexist->btc_write_4byte(btcoexist, 0x88c, val); + + /* CCK on */ + val = btcoexist->btc_read_4byte(btcoexist, 0x800); + val |= 0x01000000; + btcoexist->btc_write_4byte(btcoexist, 0x800, val); + + /* Tx-pause off */ + btcoexist->btc_write_1byte(btcoexist, 0x522, 0x0); + + /* PSD off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + val &= 0xffbfffff; + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + /* restore RF Rx filter corner */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1d, + 0xfffff, u32tmp1); + + /* Exit debug mode */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xde, + 0x2, 0x0); + + /* restore WiFi original channel */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x18, + 0x3ff, wifi_original_channel); + + outloop = true; + break; + + } + + } while (!outloop); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx PSD Sweep Stop!!\n"); + BTC_TRACE(trace_buf); + return is_sweep_ok; + +} + +#pragma optimize("", off) +boolean halbtc8821c2ant_psd_antenna_detection(IN struct btc_coexist + *btcoexist) +{ + u32 i = 0; + u32 wlpsd_cent_freq = 2484, wlpsd_span = 2; + s32 wlpsd_offset = -4; + u32 bt_tx_time, bt_le_channel; + u8 bt_le_ch[13] = {3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 33}; + + u8 h2c_parameter[3] = {0}, u8tmpa, u8tmpb; + + u8 state = 0; + boolean outloop = false, bt_resp = false, ant_det_finish = false; + u32 freq, freq1, freq2, psd_rep1, psd_rep2, delta_freq_per_point, + u32tmp, u32tmp0, u32tmp1, u32tmp2 ; + struct btc_board_info *board_info = &btcoexist->board_info; + + memset(psd_scan->ant_det_peak_val, 0, 16 * sizeof(u8)); + memset(psd_scan->ant_det_peak_freq, 0, 16 * sizeof(u8)); + + psd_scan->ant_det_bt_tx_time = + BT_8821C_2ANT_ANTDET_BTTXTIME; /* 0.42ms*50 = 20ms (0.42ms = 1 PSD sweep) */ + psd_scan->ant_det_bt_le_channel = BT_8821C_2ANT_ANTDET_BTTXCHANNEL; + + bt_tx_time = psd_scan->ant_det_bt_tx_time; + bt_le_channel = psd_scan->ant_det_bt_le_channel; + + if (board_info->tfbga_package) /* for TFBGA */ + psd_scan->ant_det_thres_offset = 5; + else + psd_scan->ant_det_thres_offset = 0; + + do { + switch (state) { + case 0: + if (bt_le_channel == 39) + wlpsd_cent_freq = 2484; + else { + for (i = 1; i <= 13; i++) { + if (bt_le_ch[i - 1] == + bt_le_channel) { + wlpsd_cent_freq = 2412 + + (i - 1) * 5; + break; + } + } + + if (i == 14) { + + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Abort!!, Invalid LE channel = %d\n ", + bt_le_channel); + BTC_TRACE(trace_buf); + outloop = true; + break; + } + } +#if 0 + wlpsd_sweep_count = bt_tx_time * 238 / + 100; /* bt_tx_time/0.42 */ + wlpsd_sweep_count = wlpsd_sweep_count / 5; + + if (wlpsd_sweep_count % 5 != 0) + wlpsd_sweep_count = (wlpsd_sweep_count / + 5 + 1) * 5; +#endif + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), BT_LETxTime=%d, BT_LECh = %d\n", + bt_tx_time, bt_le_channel); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), wlpsd_cent_freq=%d, wlpsd_offset = %d, wlpsd_span = %d, wlpsd_sweep_count = %d\n", + wlpsd_cent_freq, + wlpsd_offset, + wlpsd_span, + BT_8821C_2ANT_ANTDET_PSD_SWWEEPCOUNT); + BTC_TRACE(trace_buf); + + state = 1; + break; + case 1: /* stop coex DM & set antenna path */ + /* Stop Coex DM */ + btcoexist->stop_coex_dm = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Stop Coex DM!!\n"); + BTC_TRACE(trace_buf); + + /* Set TDMA off, */ + halbtc8821c2ant_ps_tdma(btcoexist, FORCE_EXEC, + false, 0); + + /* Set coex table */ + halbtc8821c2ant_coex_table_with_type(btcoexist, + FORCE_EXEC, 0); + + if (board_info->btdm_ant_pos == + BTC_ANTENNA_AT_MAIN_PORT) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna at Main Port\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna at Aux Port\n"); + BTC_TRACE(trace_buf); + } + + /* Set Antenna path, switch WiFi to un-certain antenna port */ + /* Set Antenna Path, both GNT_WL/GNT_BT = 1, and control by SW */ + halbtc8821c2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8821C_2ANT_PHASE_ANTENNA_DET); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set Antenna to BT!!\n"); + BTC_TRACE(trace_buf); + + /* Set AFH mask on at WiFi channel 2472MHz +/- 10MHz */ + h2c_parameter[0] = 0x1; + h2c_parameter[1] = 0xd; + h2c_parameter[2] = 0x14; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set AFH on, Cent-Ch= %d, Mask=%d\n", + h2c_parameter[1], + h2c_parameter[2]); + BTC_TRACE(trace_buf); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, + h2c_parameter); + + u32tmp0 = btcoexist->btc_read_4byte(btcoexist, 0x70); + u32tmp1 = halbtc8821c2ant_ltecoex_indirect_read_reg( + btcoexist, 0x38); + u32tmp2 = halbtc8821c2ant_ltecoex_indirect_read_reg( + btcoexist, 0x54); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** 0x70 = 0x%x, 0x38= 0x%x, 0x54= 0x%x (Before Ant Det) **********\n", + u32tmp0, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); + + state = 2; + break; + case 2: /* Pre-sweep background psd */ + if (!halbtc8821c2ant_psd_sweep_point(btcoexist, + wlpsd_cent_freq, wlpsd_offset, wlpsd_span, + BT_8821C_2ANT_ANTDET_PSD_POINTS, + BT_8821C_2ANT_ANTDET_PSD_AVGNUM, 3)) { + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 8; + state = 99; + break; + } + + psd_scan->ant_det_pre_psdscan_peak_val = + psd_scan->psd_max_value; + + if (psd_scan->ant_det_pre_psdscan_peak_val > + (BT_8821C_2ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset) * 100) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Abort Antenna Detection!! becaus background = %d > thres (%d)\n", + psd_scan->ant_det_pre_psdscan_peak_val / + 100, + BT_8821C_2ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + BTC_TRACE(trace_buf); + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 5; + state = 99; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Start Antenna Detection!! becaus background = %d <= thres (%d)\n", + psd_scan->ant_det_pre_psdscan_peak_val / + 100, + BT_8821C_2ANT_ANTDET_PSDTHRES_BACKGROUND + + psd_scan->ant_det_thres_offset); + BTC_TRACE(trace_buf); + state = 3; + } + break; + case 3: + bt_resp = btcoexist->btc_set_bt_ant_detection( + btcoexist, (u8)(bt_tx_time & 0xff), + (u8)(bt_le_channel & 0xff)); + + /* Sync WL Rx PSD with BT Tx time because H2C->Mailbox delay */ + delay_ms(20); + + if (!halbtc8821c2ant_psd_sweep_point(btcoexist, + wlpsd_cent_freq, wlpsd_offset, + wlpsd_span, + BT_8821C_2ANT_ANTDET_PSD_POINTS, + BT_8821C_2ANT_ANTDET_PSD_AVGNUM, + BT_8821C_2ANT_ANTDET_PSD_SWWEEPCOUNT)) { + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + psd_scan->ant_det_result = 8; + state = 99; + break; + } + +#if 1 + psd_scan->ant_det_psd_scan_peak_val = + psd_scan->psd_max_value; +#endif +#if 0 + psd_scan->ant_det_psd_scan_peak_val = + ((psd_scan->psd_max_value - psd_scan->psd_avg_value) < + 800) ? + psd_scan->psd_max_value : (( + psd_scan->psd_max_value - + psd_scan->psd_max_value2 <= 300) ? + psd_scan->psd_avg_value : + psd_scan->psd_max_value2); +#endif + psd_scan->ant_det_psd_scan_peak_freq = + psd_scan->psd_max_value_point; + state = 4; + break; + case 4: + + if (psd_scan->psd_point == 0) + delta_freq_per_point = 0; + else + delta_freq_per_point = + psd_scan->psd_band_width / + psd_scan->psd_point; + + psd_rep1 = psd_scan->ant_det_psd_scan_peak_val / 100; + psd_rep2 = psd_scan->ant_det_psd_scan_peak_val - + psd_rep1 * + 100; + + freq = ((psd_scan->real_cent_freq - 20) * + 1000000 + psd_scan->psd_max_value_point + * delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (freq2 < 100) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Max Value: Freq = %d.0%d MHz", + freq1, freq2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_freq, + BT_8821C_2ANT_ANTDET_BUF_LEN, + "%d.0%d", freq1, freq2); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Max Value: Freq = %d.%d MHz", + freq1, freq2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_freq, + BT_8821C_2ANT_ANTDET_BUF_LEN, + "%d.%d", freq1, freq2); + } + + if (psd_rep2 < 10) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + ", Value = %d.0%d dB\n", + psd_rep1, psd_rep2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_val, + BT_8821C_2ANT_ANTDET_BUF_LEN, + "%d.0%d", psd_rep1, psd_rep2); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + ", Value = %d.%d dB\n", + psd_rep1, psd_rep2); + BTC_TRACE(trace_buf); + CL_SPRINTF(psd_scan->ant_det_peak_val, + BT_8821C_2ANT_ANTDET_BUF_LEN, + "%d.%d", psd_rep1, psd_rep2); + } + + psd_scan->ant_det_is_btreply_available = true; + + if (bt_resp == false) { + psd_scan->ant_det_is_btreply_available = + false; + psd_scan->ant_det_result = 0; + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), BT Response = Fail\n "); + BTC_TRACE(trace_buf); + } else if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION) + * 100) { + psd_scan->ant_det_result = 1; + ant_det_finish = true; + board_info->btdm_ant_num_by_ant_det = 2; + coex_sta->isolation_btween_wb = (u8)(85 - + psd_scan->ant_det_psd_scan_peak_val / + 100) & 0xff; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 2-Ant, Bad-Isolation!!\n"); + BTC_TRACE(trace_buf); + } else if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION + + psd_scan->ant_det_thres_offset) * 100) { + psd_scan->ant_det_result = 2; + ant_det_finish = true; + board_info->btdm_ant_num_by_ant_det = 2; + coex_sta->isolation_btween_wb = (u8)(85 - + psd_scan->ant_det_psd_scan_peak_val / + 100) & 0xff; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 2-Ant, Good-Isolation!!\n"); + BTC_TRACE(trace_buf); + } else if (psd_scan->ant_det_psd_scan_peak_val > + (BT_8821C_2ANT_ANTDET_PSDTHRES_1ANT) * + 100) { + psd_scan->ant_det_result = 3; + ant_det_finish = true; + board_info->btdm_ant_num_by_ant_det = 1; + coex_sta->isolation_btween_wb = (u8)(85 - + psd_scan->ant_det_psd_scan_peak_val / + 100) & 0xff; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 1-Ant!!\n"); + BTC_TRACE(trace_buf); + } else { + psd_scan->ant_det_result = 4; + ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Detect Result = 1-Ant, un-certainity!!\n"); + BTC_TRACE(trace_buf); + } + + state = 99; + break; + case 99: /* restore setup */ + + /* Set AFH mask off at WiFi channel 2472MHz +/- 10MHz */ + h2c_parameter[0] = 0x0; + h2c_parameter[1] = 0x0; + h2c_parameter[2] = 0x0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set AFH on, Cent-Ch= %d, Mask=%d\n", + h2c_parameter[1], h2c_parameter[2]); + BTC_TRACE(trace_buf); + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, + h2c_parameter); + + /* Set Antenna Path, GNT_WL/GNT_BT control by PTA */ + /* Set Antenna path, switch WiFi to certain antenna port */ + halbtc8821c2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8821C_2ANT_PHASE_2G_RUNTIME); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Set Antenna to PTA\n!!"); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Resume Coex DM\n!!"); + BTC_TRACE(trace_buf); + + outloop = true; + break; + } + + } while (!outloop); + + return ant_det_finish; + +} + +#pragma optimize("", off) +boolean halbtc8821c2ant_psd_antenna_detection_check(IN struct btc_coexist + *btcoexist) +{ + static u32 ant_det_count = 0, ant_det_fail_count = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + + boolean scan, roam, ant_det_finish = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + ant_det_count++; + + psd_scan->ant_det_try_count = ant_det_count; + + if (scan || roam) { + ant_det_finish = false; + psd_scan->ant_det_result = 6; + } else if (coex_sta->bt_disabled) { + ant_det_finish = false; + psd_scan->ant_det_result = 11; + } else if (coex_sta->num_of_profile >= 1) { + ant_det_finish = false; + psd_scan->ant_det_result = 7; + } else if ( + !psd_scan->ant_det_is_ant_det_available) { /* Antenna initial setup is not ready */ + ant_det_finish = false; + psd_scan->ant_det_result = 9; + } else if (coex_sta->c2h_bt_inquiry_page) { + ant_det_finish = false; + psd_scan->ant_det_result = 10; + } else { + + ant_det_finish = halbtc8821c2ant_psd_antenna_detection( + btcoexist); + + delay_ms(psd_scan->ant_det_bt_tx_time); + } + + + if (!ant_det_finish) + ant_det_fail_count++; + + psd_scan->ant_det_fail_count = ant_det_fail_count; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), result = %d, fail_count = %d, finish = %s\n", + psd_scan->ant_det_result, + psd_scan->ant_det_fail_count, + ant_det_finish == true ? "Yes" : "No"); + BTC_TRACE(trace_buf); + + return ant_det_finish; + +} +#endif + +/* ************************************************************ + * work around function start with wa_halbtc8821c2ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8821c2ant_ + * ************************************************************ */ +void ex_halbtc8821c2ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + u32 value = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Execute 8821c 2-Ant PowerOn Setting xxxxxxxxxxxxxxxx!!\n"); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Ant Det Finish = %s, Ant Det Number = %d\n", + (board_info->btdm_ant_det_finish ? "Yes" : "No"), + board_info->btdm_ant_num_by_ant_det); + BTC_TRACE(trace_buf); + + + btcoexist->stop_coex_dm = true; + psd_scan->ant_det_is_ant_det_available = false; + + /* enable BB, REG_SYS_FUNC_EN such that we can write BB Register correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT(0) | BIT(1)); + + + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + + /* Check efuse 0xc3[6] for Single Antenna Path */ + if (board_info->single_ant_path == 0) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** Single Antenna, Antenna at Aux Port\n"); + BTC_TRACE(trace_buf); + + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + + u8tmp = 7; + } else if (board_info->single_ant_path == 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** Single Antenna, Antenna at Main Port\n"); + BTC_TRACE(trace_buf); + + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + + u8tmp = 6; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (Power On) single_ant_path = %d, btdm_ant_pos = %d\n", + board_info->single_ant_path , board_info->btdm_ant_pos); + BTC_TRACE(trace_buf); + + /* Setup RF front end type */ + halbtc8821c2ant_set_rfe_type(btcoexist); + + /* Set Antenna Path to BT side */ + halbtc8821c2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8821C_2ANT_PHASE_COEX_POWERON); + + /* Save"single antenna position" info in Local register setting for FW reading, because FW may not ready at power on */ + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x3e0, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, u8tmp); + + /* enable GNT_WL/GNT_BT debug signal to GPIO14/15 */ + halbtc8821c2ant_enable_gnt_to_gpio(btcoexist, true); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** LTE coex Reg 0x38 (Power-On) = 0x%x**********\n", + halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, 0x38)); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** MAC Reg 0x70/ BB Reg 0xcb4 (Power-On) = 0x%x / 0x%x\n", + btcoexist->btc_read_4byte(btcoexist, 0x70), + btcoexist->btc_read_4byte(btcoexist, 0xcb4)); + BTC_TRACE(trace_buf); + +} + +void ex_halbtc8821c2ant_pre_load_firmware(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x4; /* Set BIT2 by default since it's 2ant case */ + + /* */ + /* S0 or S1 setting and Local register setting(By the setting fw can get ant number, S0/S1, ... info) */ + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + u8tmp |= 0x1; /* antenna inverse */ + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + u8tmp |= 0x1; /* antenna inverse */ + } + + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x3e0, + u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, + u8tmp); + } +} + + +void ex_halbtc8821c2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8821c2ant_init_hw_config(btcoexist, wifi_only); +} + +void ex_halbtc8821c2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + + halbtc8821c2ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8821c2ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, ps_tdma_case = 0; + u32 u32tmp[4]; + u16 u16tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + u32 fw_ver = 0, bt_patch_ver = 0, bt_coex_ver = 0; + static u8 pop_report_in_10s = 0; + u32 phyver = 0; + boolean lte_coex_on = false; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (psd_scan->ant_det_try_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %s / %d", + "Ant PG Num/ Mech/ Pos/ RFE", + board_info->pg_ant_num, board_info->btdm_ant_num, + (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT + ? "Main" : "Aux"), + rfe_type->rfe_module_type); + CL_PRINTF(cli_buf); + } else { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %s/ %d (%d/%d/%d)", + "Ant PG Num/ Mech(Ant_Det)/ Pos/ RFE", + board_info->pg_ant_num, + board_info->btdm_ant_num_by_ant_det, + (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT + ? "Main" : "Aux"), + rfe_type->rfe_module_type, + psd_scan->ant_det_try_count, + psd_scan->ant_det_fail_count, + psd_scan->ant_det_result); + CL_PRINTF(cli_buf); + + + if (board_info->btdm_ant_det_finish) { + + if (psd_scan->ant_det_result != 12) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "Ant Det PSD Value", + psd_scan->ant_det_peak_val); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d", + "Ant Det PSD Value", + psd_scan->ant_det_psd_scan_peak_val + / 100); + CL_PRINTF(cli_buf); + } + } + + + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + + bt_coex_ver = (coex_sta->bt_coex_supported_version & 0xff); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8821c_2ant, glcoex_ver_8821c_2ant, + glcoex_ver_btdesired_8821c_2ant, + bt_coex_ver, + (bt_coex_ver == 0xff ? "Unknown" : + (bt_coex_ver >= glcoex_ver_btdesired_8821c_2ant ? + "Match" : "Mis-Match"))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ v%d/ %c", + "W_FW/ B_FW/ Phy/ Kt", + fw_ver, bt_patch_ver, phyver, + coex_sta->cut_version + 65); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "AFH Map to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d ", + "Isolation/WL_Thres/BT_Thres", + coex_sta->isolation_btween_wb, + coex_sta->wifi_coex_thres, + coex_sta->bt_coex_thres); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + pop_report_in_10s++; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = [%s/ %d dBm/ %d/ %d] ", + "BT [status/ rssi/ retryCnt/ popCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page") + : ((BT_8821C_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8821C_2ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi - 100, coex_sta->bt_retry_cnt, + coex_sta->pop_event_cnt); + CL_PRINTF(cli_buf); + + if (pop_report_in_10s >= 5) { + coex_sta->pop_event_cnt = 0; + pop_report_in_10s = 0; + } + + + if (coex_sta->num_of_profile != 0) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s%s%s%s%s", + "Profiles", + ((bt_link_info->a2dp_exist) ? "A2DP," : ""), + ((bt_link_info->sco_exist) ? "SCO," : ""), + ((bt_link_info->hid_exist) ? + ((coex_sta->hid_busy_num >= 2) ? "HID(4/18)," : + "HID(2/18),") : ""), + ((bt_link_info->pan_exist) ? "PAN," : ""), + ((coex_sta->voice_over_HOGP) ? "Voice" : "")); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = None", "Profiles"); + + CL_PRINTF(cli_buf); + + + if (bt_link_info->a2dp_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %d/ %s", + "A2DP Rate/Bitpool/Auto_Slot", + ((coex_sta->is_A2DP_3M) ? "3M" : "No_3M"), + coex_sta->a2dp_bit_pool, + ((coex_sta->is_autoslot) ? "On" : "Off") + ); + CL_PRINTF(cli_buf); + } + + if (bt_link_info->hid_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "HID PairNum/Forbid_Slot", + coex_sta->hid_pair_cnt, + coex_sta->forbidden_slot + ); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ 0x%x", + "Role/IgnWlanAct/Feature", + ((bt_link_info->slave_role) ? "Slave" : "Master"), + ((coex_dm->cur_ignore_wlan_act) ? "Yes" : "No"), + coex_sta->bt_coex_supported_feature); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", + "ReInit/ReLink/IgnWlact/Page/NameReq", + coex_sta->cnt_ReInit, + coex_sta->cnt_setupLink, + coex_sta->cnt_IgnWlanAct, + coex_sta->cnt_Page, + coex_sta->cnt_RemoteNameReq + ); + CL_PRINTF(cli_buf); + + halbtc8821c2ant_read_score_board(btcoexist, &u16tmp[0]); + + if ((coex_sta->bt_reg_vendor_ae == 0xffff) || + (coex_sta->bt_reg_vendor_ac == 0xffff)) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = x/ x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", u16tmp[0]); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", + ((coex_sta->bt_reg_vendor_ae & BIT(4)) >> 4), + coex_sta->bt_reg_vendor_ac & 0x3, u16tmp[0]); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8821C_2ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8821c_2ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + /* Sw mechanism */ + if (btcoexist->manual_control) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanism] (before Manual)============"); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Mechanism]============"); + + CL_PRINTF(cli_buf); + + + ps_tdma_case = coex_dm->cur_ps_tdma; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x (case-%d, %s, %s)", + "TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + (coex_dm->cur_ps_tdma_on ? "TDMA On" : "TDMA Off"), + (coex_dm->is_switch_to_1dot5_ant ? "1.5Ant" : "2Ant")); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ 0x%x/ 0x%x/ 0x%x", + "Table/0x6c0/0x6c4/0x6c8", + coex_sta->coex_table_type, u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x", + "0x778/0x6cc", + u8tmp[0], u32tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s", + "AntDiv/ForceLPS/LPRA", + ((board_info->ant_div_cfg) ? "On" : "Off"), + ((coex_sta->force_lps_on) ? "On" : "Off"), + ((coex_dm->cur_low_penalty_ra) ? "On" : "Off")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "WL_DACSwing/ BT_Dec_Pwr", coex_dm->cur_fw_dac_swing_lvl, + coex_dm->cur_bt_dec_pwr_lvl); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + lte_coex_on = ((u32tmp[0] & BIT(7)) >> 7) ? true : false; + + if (lte_coex_on) { + + u32tmp[0] = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, + 0xa0); + u32tmp[1] = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, + 0xa4); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "LTE Coex Table W_L/B_L", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff); + CL_PRINTF(cli_buf); + + + u32tmp[0] = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, + 0xa8); + u32tmp[1] = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, + 0xac); + u32tmp[2] = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, + 0xb0); + u32tmp[3] = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, + 0xb4); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "LTE Break Table W_L/B_L/L_W/L_B", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff, + u32tmp[2] & 0xffff, u32tmp[3] & 0xffff); + CL_PRINTF(cli_buf); + + } + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + /* + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + */ + u32tmp[0] = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp[1] = halbtc8821c2ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x73); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s", + "LTE Coex/Path Owner", + ((lte_coex_on) ? "On" : "Off") , + ((u8tmp[0] & BIT(2)) ? "WL" : "BT")); + CL_PRINTF(cli_buf); + + if (lte_coex_on) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "LTE 3Wire/OPMode/UART/UARTMode", + (int)((u32tmp[0] & BIT(6)) >> 6), + (int)((u32tmp[0] & (BIT(5) | BIT(4))) >> 4), + (int)((u32tmp[0] & BIT(3)) >> 3), + (int)(u32tmp[0] & (BIT(2) | BIT(1) | BIT(0)))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "LTE_Busy/UART_Busy", + (int)((u32tmp[1] & BIT(1)) >> 1), (int)(u32tmp[1] & BIT(0))); + CL_PRINTF(cli_buf); + } + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (BB:%s)/ %s (BB:%s)/ %s", + "GNT_WL_Ctrl/GNT_BT_Ctrl/Dbg", + ((u32tmp[0] & BIT(12)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(8)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(14)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(10)) ? "SW" : "HW"), + ((u8tmp[0] & BIT(3)) ? "On" : "Off")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "GNT_WL/GNT_BT", + (int)((u32tmp[1] & BIT(2)) >> 2), + (int)((u32tmp[1] & BIT(3)) >> 3)); + CL_PRINTF(cli_buf); + + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xcba); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%04x/ 0x%04x/ 0x%02x %s", + "0xcb0/0xcb4/0xcb8[23:16]", + u32tmp[0], u32tmp[1], u8tmp[0], + ((u8tmp[0] & 0x1) == 0x1 ? "(BTG)" : "(WL_A+G)")); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x4c6); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x4c[24:23]/0x64[0]/x4c6[4]/0x40[5]", + (u32tmp[0] & (BIT(24) | BIT(23))) >> 23 , u8tmp[2] & 0x1 , + (int)((u8tmp[0] & BIT(4)) >> 4), + (int)((u8tmp[1] & BIT(5)) >> 5)); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x953); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0xc50); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ %s/ 0x%x", + "0x550/0x522/4-RxAGC/0xc50", + u32tmp[0], u8tmp[0], (u8tmp[1] & 0x2) ? "On" : "Off", u8tmp[2]); + CL_PRINTF(cli_buf); + + fa_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_OFDM); + fa_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_CCK); + cca_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_OFDM); + cca_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_CCK); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", + cca_cck, fa_cck, cca_ofdm, fa_ofdm); + CL_PRINTF(cli_buf); + +#if 1 + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11ac", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11ac", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + CL_PRINTF(cli_buf); +#endif + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(Hi-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(Lo-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8821c2ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + coex_sta->under_lps = false; + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, false); + + halbtc8821c2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_2ANT_PHASE_WLAN_OFF); + + halbtc8821c2ant_action_coex_all_off(btcoexist); + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = false; + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, true); + halbtc8821c2ant_init_hw_config(btcoexist, false); + halbtc8821c2ant_init_coex_dm(btcoexist); + halbtc8821c2ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8821c2ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + coex_sta->under_ips = false; + + if (coex_sta->force_lps_on == true) { /* LPS No-32K */ + /* Write WL "Active" in Score-board for PS-TDMA */ + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, true); + + } else { /* LPS-32K, need check if this h2c 0x71 can work?? (2015/08/28) */ + /* Write WL "Non-Active" in Score-board for Native-PS */ + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, false); + } + + + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, true); + } +} + +void ex_halbtc8821c2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false; + boolean wifi_under_5g = false; + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN notify()\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, true); + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* this can't be removed for RF off_on event, or BT would dis-connect */ + halbtc8821c2ant_query_bt_info(btcoexist); + + if (BTC_SCAN_START == type) { + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, + &wifi_under_5g); + + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** SCAN START notify (5g)\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_action_wifi_under5g(btcoexist); + return; + } + + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** SCAN START notify (2g)\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_2ANT_PHASE_2G_RUNTIME); + + halbtc8821c2ant_run_coexist_mechanism( + btcoexist); + + return; + } + + + if (BTC_SCAN_START_2G == type) { + + if (!wifi_connected) + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify (2G)\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_SCAN, true); + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, true); + + halbtc8821c2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_2ANT_PHASE_2G_RUNTIME); + + halbtc8821c2ant_run_coexist_mechanism(btcoexist); + + } else if (BTC_SCAN_FINISH == type) { + + coex_sta->wifi_is_high_pri_task = false; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify (Scan-AP = %d)\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_SCAN, false); + + halbtc8821c2ant_run_coexist_mechanism(btcoexist); + } + +} + +void ex_halbtc8821c2ant_switchband_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if (type == BTC_SWITCH_TO_5G) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], switchband_notify --- switch to 5G\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_action_wifi_under5g(btcoexist); + + } else if (type == BTC_SWITCH_TO_24G_NOFORSCAN) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** switchband_notify BTC_SWITCH_TO_2G (no for scan)\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_run_coexist_mechanism(btcoexist); + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], switchband_notify --- switch to 2G\n"); + BTC_TRACE(trace_buf); + + ex_halbtc8821c2ant_scan_notify(btcoexist, + BTC_SCAN_START_2G); + } +} + + +void ex_halbtc8821c2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, true); + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if ((BTC_ASSOCIATE_5G_START == type) || + (BTC_ASSOCIATE_5G_FINISH == type)) { + + if (BTC_ASSOCIATE_5G_START == type) + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], connect_notify --- 5G start\n"); + else + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], connect_notify --- 5G finish\n"); + + BTC_TRACE(trace_buf); + + halbtc8821c2ant_action_wifi_under5g(btcoexist); + return; + } + + + if (BTC_ASSOCIATE_START == type) { + + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify (2G)\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_2ANT_PHASE_2G_RUNTIME); + + halbtc8821c2ant_action_wifi_link_process(btcoexist); + + /* To keep TDMA case during connect process, + to avoid changed by Btinfo and runcoexmechanism */ + coex_sta->freeze_coexrun_by_btinfo = true; + + coex_dm->arp_cnt = 0; + + } else if (BTC_ASSOCIATE_FINISH == type) { + + coex_sta->wifi_is_high_pri_task = false; + coex_sta->freeze_coexrun_by_btinfo = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify (2G)\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_run_coexist_mechanism(btcoexist); + } +} + +void ex_halbtc8821c2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + u8 ap_num = 0; + boolean wifi_under_b_mode = false, wifi_under_5g = false; + + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (BTC_MEDIA_CONNECT == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, true); + + if (wifi_under_5g) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 5G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_action_wifi_under5g(btcoexist); + return; + } + + halbtc8821c2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_2ANT_PHASE_2G_RUNTIME); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, false); + } + + + halbtc8821c2ant_update_wifi_channel_info(btcoexist, type); +} + +void ex_halbtc8821c2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean under_4way = false, wifi_under_5g = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 5G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_action_wifi_under5g(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (under_4way) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ---- under_4way!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + + } else if (BTC_PACKET_ARP == type) { + + coex_dm->arp_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ARP notify -cnt = %d\n", + coex_dm->arp_cnt); + BTC_TRACE(trace_buf); + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet DHCP or EAPOL notify [Type = %d]\n", + type); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } + + if (coex_sta->wifi_is_high_pri_task) + halbtc8821c2ant_run_coexist_mechanism(btcoexist); + +} + +void ex_halbtc8821c2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 i, rsp_source = 0; + boolean wifi_connected = false; + + if (psd_scan->is_AntDet_running == true) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], bt_info_notify return for AntDet is running\n"); + BTC_TRACE(trace_buf); + return; + } + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8821C_2ANT_MAX) + rsp_source = BT_INFO_SRC_8821C_2ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt_info[%d], len=%d, data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + coex_sta->bt_info = coex_sta->bt_info_c2h[rsp_source][1]; + coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + coex_sta->bt_info_ext2 = coex_sta->bt_info_c2h[rsp_source][5]; + + if (BT_INFO_SRC_8821C_2ANT_WIFI_FW != rsp_source) { + + /* if 0xff, it means BT is under WHCK test */ + coex_sta->bt_whck_test = ((coex_sta->bt_info == 0xff) ? true : + false); + + coex_sta->bt_create_connection = (( + coex_sta->bt_info_c2h[rsp_source][2] & 0x80) ? true : + false); + + /* unit: %, value-100 to translate to unit: dBm */ + coex_sta->bt_rssi = coex_sta->bt_info_c2h[rsp_source][3] * 2 + + 10; + + coex_sta->c2h_bt_remote_name_req = (( + coex_sta->bt_info_c2h[rsp_source][2] & 0x20) ? true : + false); + + coex_sta->is_A2DP_3M = ((coex_sta->bt_info_c2h[rsp_source][2] & + 0x10) ? true : false); + + coex_sta->acl_busy = ((coex_sta->bt_info_c2h[rsp_source][1] & + 0x9) ? true : false); + + coex_sta->voice_over_HOGP = ((coex_sta->bt_info_ext & 0x10) ? + true : false); + + coex_sta->c2h_bt_inquiry_page = ((coex_sta->bt_info & + BT_INFO_8821C_2ANT_B_INQ_PAGE) ? true : false); + + coex_sta->a2dp_bit_pool = ((( + coex_sta->bt_info_c2h[rsp_source][1] & 0x49) == 0x49) ? + coex_sta->bt_info_c2h[rsp_source][6] : 0); + + coex_sta->bt_retry_cnt = coex_sta->bt_info_c2h[rsp_source][2] & + 0xf; + + coex_sta->is_autoslot = coex_sta->bt_info_ext2 & 0x8; + + coex_sta->forbidden_slot = coex_sta->bt_info_ext2 & 0x7; + + coex_sta->hid_busy_num = (coex_sta->bt_info_ext2 & 0x30) >> 4; + + coex_sta->hid_pair_cnt = (coex_sta->bt_info_ext2 & 0xc0) >> 6; + + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->c2h_bt_remote_name_req) + coex_sta->cnt_RemoteNameReq++; + + if (coex_sta->bt_info_ext & BIT(1)) + coex_sta->cnt_ReInit++; + + if (coex_sta->bt_info_ext & BIT(2)) { + coex_sta->cnt_setupLink++; + coex_sta->is_setupLink = true; + } else + coex_sta->is_setupLink = false; + + if (coex_sta->bt_info_ext & BIT(3)) + coex_sta->cnt_IgnWlanAct++; + + if (coex_sta->bt_create_connection) + coex_sta->cnt_Page++; + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + + if ((!btcoexist->manual_control) && + (!btcoexist->stop_coex_dm)) { + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* Re-Init */ + if ((coex_sta->bt_info_ext & BIT(1))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + if (wifi_connected) + halbtc8821c2ant_update_wifi_channel_info( + btcoexist, BTC_MEDIA_CONNECT); + else + halbtc8821c2ant_update_wifi_channel_info( + btcoexist, + BTC_MEDIA_DISCONNECT); + } + + + /* If Ignore_WLanAct && not SetUp_Link */ + if ((coex_sta->bt_info_ext & BIT(3)) && + (!(coex_sta->bt_info_ext & BIT(2)))) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8821c2ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, false); + } + } + + } + + + halbtc8821c2ant_update_bt_link_info(btcoexist); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), No run_coexist_mechanism for Manual CTRL\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), No run_coexist_mechanism for Stop Coex DM\n"); + BTC_TRACE(trace_buf); + return; + } + + coex_sta->c2h_bt_info_req_sent = false; + + halbtc8821c2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8821c2ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], RF Status notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_RF_ON == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned ON!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->wl_rf_off_on_event = true; + btcoexist->stop_coex_dm = false; + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, true); + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ONOFF, true); + } else if (BTC_RF_OFF == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned OFF!!\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_2ANT_PHASE_WLAN_OFF); + + halbtc8821c2ant_action_coex_all_off(btcoexist); + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, false); + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ONOFF, false); + btcoexist->stop_coex_dm = true; + coex_sta->wl_rf_off_on_event = false; + + } +} + +void ex_halbtc8821c2ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8821C_2ANT_PHASE_WLAN_OFF); + + ex_halbtc8821c2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, false); + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ONOFF, false); +} + +void ex_halbtc8821c2ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + boolean wifi_under_5g = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Pnp notify\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if ((BTC_WIFI_PNP_SLEEP == pnp_state) || + (BTC_WIFI_PNP_SLEEP_KEEP_ANT == pnp_state)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + + /* Sinda 20150819, workaround for driver skip leave IPS/LPS to speed up sleep time. */ + /* Driver do not leave IPS/LPS when driver is going to sleep, so BTCoexistence think wifi is still under IPS/LPS */ + /* BT should clear UnderIPS/UnderLPS state to avoid mismatch state after wakeup. */ + coex_sta->under_ips = false; + coex_sta->under_lps = false; + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, false); + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ONOFF, false); + + + if (BTC_WIFI_PNP_SLEEP_KEEP_ANT == pnp_state) { + + if (wifi_under_5g) + halbtc8821c2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8821C_2ANT_PHASE_5G_RUNTIME); + else + halbtc8821c2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8821C_2ANT_PHASE_2G_RUNTIME); + } else { + + halbtc8821c2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8821C_2ANT_PHASE_WLAN_OFF); + } + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ACTIVE, true); + halbtc8821c2ant_post_state_to_bt(btcoexist, + BT_8821C_2ANT_SCOREBOARD_ONOFF, true); + } +} + +void ex_halbtc8821c2ant_periodical(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ************* Periodical *************\n"); + BTC_TRACE(trace_buf); + +#if (BT_AUTO_REPORT_ONLY_8821C_2ANT == 0) + halbtc8821c2ant_query_bt_info(btcoexist); +#endif + + halbtc8821c2ant_monitor_bt_ctr(btcoexist); + halbtc8821c2ant_monitor_wifi_ctr(btcoexist); + halbtc8821c2ant_monitor_bt_enable_disable(btcoexist); + + /* for 4-way, DHCP, EAPOL packet */ + if (coex_sta->specific_pkt_period_cnt > 0) { + + coex_sta->specific_pkt_period_cnt--; + + if ((coex_sta->specific_pkt_period_cnt == 0) && + (coex_sta->wifi_is_high_pri_task)) + coex_sta->wifi_is_high_pri_task = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ***************** Hi-Pri Task = %s*****************\n", + (coex_sta->wifi_is_high_pri_task ? "Yes" : + "No")); + BTC_TRACE(trace_buf); + + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->bt_coex_supported_feature == 0) + coex_sta->bt_coex_supported_feature = + btcoexist->btc_get_bt_coex_supported_feature( + btcoexist); + + if ((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) + coex_sta->bt_coex_supported_version = + btcoexist->btc_get_bt_coex_supported_version( + btcoexist); + + /*coex_sta->bt_ble_scan_type = btcoexist->btc_get_ble_scan_type_from_bt(btcoexist);*/ + + if (coex_sta->bt_reg_vendor_ac == 0xffff) + coex_sta->bt_reg_vendor_ac = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, + 0xac) & 0xffff); + + if (coex_sta->bt_reg_vendor_ae == 0xffff) + coex_sta->bt_reg_vendor_ae = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, + 0xae) & 0xffff); + +#if BT_8821C_2ANT_ANTDET_ENABLE + + if (board_info->btdm_ant_det_finish) { + if ((psd_scan->ant_det_result == 12) && + (psd_scan->ant_det_psd_scan_peak_val == 0) + && (!psd_scan->is_AntDet_running)) + psd_scan->ant_det_psd_scan_peak_val = + btcoexist->btc_get_ant_det_val_from_bt( + btcoexist) * 100; + } + +#endif + } + + + if (halbtc8821c2ant_is_wifibt_status_changed(btcoexist)) + halbtc8821c2ant_run_coexist_mechanism(btcoexist); +} + + +/*#pragma optimize( "", off )*/ +void ex_halbtc8821c2ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ +#if 0 + static u32 ant_det_count = 0, ant_det_fail_count = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + u16 u16tmp; + u8 AntDetval = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Ext Call AntennaDetect()!!\n"); + BTC_TRACE(trace_buf); + +#if BT_8821C_2ANT_ANTDET_ENABLE + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Call AntennaDetect()!!\n"); + BTC_TRACE(trace_buf); + + if (seconds == 0) { + psd_scan->ant_det_try_count = 0; + psd_scan->ant_det_fail_count = 0; + ant_det_count = 0; + ant_det_fail_count = 0; + board_info->btdm_ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + return; + } + + if (!board_info->btdm_ant_det_finish) { + psd_scan->ant_det_inteval_count = + psd_scan->ant_det_inteval_count + 2; + + if (psd_scan->ant_det_inteval_count >= + BT_8821C_2ANT_ANTDET_RETRY_INTERVAL) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Timer is up, Try Detect!!\n"); + BTC_TRACE(trace_buf); + + psd_scan->is_AntDet_running = true; + + halbtc8821c2ant_read_score_board(btcoexist, &u16tmp); + + if (u16tmp & BIT( + 2)) { /* Antenna detection is already done before last WL power on */ + board_info->btdm_ant_det_finish = true; + psd_scan->ant_det_try_count = 1; + psd_scan->ant_det_fail_count = 0; + board_info->btdm_ant_num_by_ant_det = (u16tmp & + BIT(3)) ? 1 : 2; + psd_scan->ant_det_result = 12; + + psd_scan->ant_det_psd_scan_peak_val = + btcoexist->btc_get_ant_det_val_from_bt( + btcoexist) * 100; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Result from BT (%d-Ant)\n", + board_info->btdm_ant_num_by_ant_det); + BTC_TRACE(trace_buf); + } else + board_info->btdm_ant_det_finish = + halbtc8821c2ant_psd_antenna_detection_check( + btcoexist); + + btcoexist->bdontenterLPS = false; + + if (board_info->btdm_ant_det_finish) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Success!!\n"); + BTC_TRACE(trace_buf); + + /*for 8821c, btc_set_bt_trx_mask is just used to + notify BT stop le tx and Ant Det Result , not set BT RF TRx Mask */ + if (psd_scan->ant_det_result != 12) { + + AntDetval = (u8)(( + psd_scan->ant_det_psd_scan_peak_val + / 100) & 0x7f); + + AntDetval = + (board_info->btdm_ant_num_by_ant_det + == 1) ? (AntDetval | 0x80) : + AntDetval; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Ant Count = %d, PSD Val = %d\n", + ((AntDetval & + 0x80) ? 1 + : 2), AntDetval + & 0x7f); + BTC_TRACE(trace_buf); + + if (btcoexist->btc_set_bt_trx_mask( + btcoexist, AntDetval)) + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Notify BT stop le tx by set_bt_trx_mask ok!\n"); + else + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Notify BT stop le tx by set_bt_trx_mask fail!\n"); + + BTC_TRACE(trace_buf); + } + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Fail!!\n"); + BTC_TRACE(trace_buf); + } + + psd_scan->ant_det_inteval_count = 0; + psd_scan->is_AntDet_running = false; + + /* stimulate coex running */ + halbtc8821c2ant_run_coexist_mechanism( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Stimulate Coex running\n!!"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Timer is not up! (%d)\n", + psd_scan->ant_det_inteval_count); + BTC_TRACE(trace_buf); + + if (psd_scan->ant_det_inteval_count == 8) + btcoexist->bdontenterLPS = true; + else + btcoexist->bdontenterLPS = false; + } + + } +#endif +#endif + +} + + +void ex_halbtc8821c2ant_display_ant_detection(IN struct btc_coexist *btcoexist) +{ +#if 0 +#if BT_8821C_2ANT_ANTDET_ENABLE + struct btc_board_info *board_info = &btcoexist->board_info; + + if (psd_scan->ant_det_try_count != 0) { + halbtc8821c2ant_psd_show_antenna_detect_result(btcoexist); + + if (board_info->btdm_ant_det_finish) + halbtc8821c2ant_psd_showdata(btcoexist); + } +#endif +#endif +} + + +#endif + +#endif /* #if (RTL8821C_SUPPORT == 1) */ + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c2ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c2ant.h new file mode 100644 index 0000000..f89b1fa --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821c2ant.h @@ -0,0 +1,478 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8821C_SUPPORT == 1) + +/* ******************************************* + * The following is for 8821C 2Ant BT Co-exist definition + * ******************************************* */ +#define BT_8821C_2ANT_COEX_DBG 0 +#define BT_AUTO_REPORT_ONLY_8821C_2ANT 1 + + +#define BT_INFO_8821C_2ANT_B_FTP BIT(7) +#define BT_INFO_8821C_2ANT_B_A2DP BIT(6) +#define BT_INFO_8821C_2ANT_B_HID BIT(5) +#define BT_INFO_8821C_2ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8821C_2ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8821C_2ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8821C_2ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8821C_2ANT_B_CONNECTION BIT(0) + +#define BTC_RSSI_COEX_THRESH_TOL_8821C_2ANT 2 + + +#define BT_8821C_2ANT_WIFI_RSSI_COEXSWITCH_THRES1 80 /* unit: % WiFi RSSI Threshold for 2-Ant free-run/2-Ant TDMA translation, default = 42 */ +#define BT_8821C_2ANT_BT_RSSI_COEXSWITCH_THRES1 80 /* unit: % BT RSSI Threshold for 2-Ant free-run/2-Ant TDMA translation, default = 46 */ +#define BT_8821C_2ANT_WIFI_RSSI_COEXSWITCH_THRES2 80 /* unit: % WiFi RSSI Threshold for 1-Ant TDMA/1-Ant PS-TDMA translation, default = 42 */ +#define BT_8821C_2ANT_BT_RSSI_COEXSWITCH_THRES2 80 /* unit: % BT RSSI Threshold for 1-Ant TDMA/1-Ant PS-TDMA translation, default = 46 */ +#define BT_8821C_2ANT_DEFAULT_ISOLATION 15 /* unit: dB */ +#define BT_8821C_2ANT_WIFI_MAX_TX_POWER 15 /* unit: dBm */ +#define BT_8821C_2ANT_BT_MAX_TX_POWER 3 /* unit: dBm */ +#define BT_8821C_2ANT_WIFI_SIR_THRES1 -15 /* unit: dB */ +#define BT_8821C_2ANT_WIFI_SIR_THRES2 -30 /* unit: dB */ +#define BT_8821C_2ANT_BT_SIR_THRES1 -15 /* unit: dB */ +#define BT_8821C_2ANT_BT_SIR_THRES2 -30 /* unit: dB */ + + +/* for Antenna detection */ +#define BT_8821C_2ANT_ANTDET_PSDTHRES_BACKGROUND 50 +#define BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION 70 +#define BT_8821C_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION 52 +#define BT_8821C_2ANT_ANTDET_PSDTHRES_1ANT 40 +#define BT_8821C_2ANT_ANTDET_RETRY_INTERVAL 10 /* retry timer if ant det is fail, unit: second */ +#define BT_8821C_2ANT_ANTDET_SWEEPPOINT_DELAY 60000 +#define BT_8821C_2ANT_ANTDET_ENABLE 0 +#define BT_8821C_2ANT_ANTDET_BTTXTIME 100 +#define BT_8821C_2ANT_ANTDET_BTTXCHANNEL 39 +#define BT_8821C_2ANT_ANTDET_PSD_SWWEEPCOUNT 50 + + +#define BT_8821C_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT 30000 + +enum bt_8821c_2ant_signal_state { + BT_8821C_2ANT_SIG_STA_SET_TO_LOW = 0x0, + BT_8821C_2ANT_SIG_STA_SET_BY_HW = 0x0, + BT_8821C_2ANT_SIG_STA_SET_TO_HIGH = 0x1, + BT_8821C_2ANT_SIG_STA_MAX +}; + +enum bt_8821c_2ant_path_ctrl_owner { + BT_8821C_2ANT_PCO_BTSIDE = 0x0, + BT_8821C_2ANT_PCO_WLSIDE = 0x1, + BT_8821C_2ANT_PCO_MAX +}; + +enum bt_8821c_2ant_gnt_ctrl_type { + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_PTA = 0x0, + BT_8821C_2ANT_GNT_TYPE_CTRL_BY_SW = 0x1, + BT_8821C_2ANT_GNT_TYPE_MAX +}; + +enum bt_8821c_2ant_gnt_ctrl_block { + BT_8821C_2ANT_GNT_BLOCK_RFC_BB = 0x0, + BT_8821C_2ANT_GNT_BLOCK_RFC = 0x1, + BT_8821C_2ANT_GNT_BLOCK_BB = 0x2, + BT_8821C_2ANT_GNT_BLOCK_MAX +}; + +enum bt_8821c_2ant_lte_coex_table_type { + BT_8821C_2ANT_CTT_WL_VS_LTE = 0x0, + BT_8821C_2ANT_CTT_BT_VS_LTE = 0x1, + BT_8821C_2ANT_CTT_MAX +}; + +enum bt_8821c_2ant_lte_break_table_type { + BT_8821C_2ANT_LBTT_WL_BREAK_LTE = 0x0, + BT_8821C_2ANT_LBTT_BT_BREAK_LTE = 0x1, + BT_8821C_2ANT_LBTT_LTE_BREAK_WL = 0x2, + BT_8821C_2ANT_LBTT_LTE_BREAK_BT = 0x3, + BT_8821C_2ANT_LBTT_MAX +}; + +enum bt_info_src_8821c_2ant { + BT_INFO_SRC_8821C_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8821C_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8821C_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8821C_2ANT_MAX +}; + +enum bt_8821c_2ant_bt_status { + BT_8821C_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8821C_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8821C_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8821C_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8821C_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8821C_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8821C_2ANT_BT_STATUS_MAX +}; + +enum bt_8821c_2ant_coex_algo { + BT_8821C_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8821C_2ANT_COEX_ALGO_SCO = 0x1, + BT_8821C_2ANT_COEX_ALGO_HID = 0x2, + BT_8821C_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8821C_2ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8821C_2ANT_COEX_ALGO_PANEDR = 0x5, + BT_8821C_2ANT_COEX_ALGO_PANHS = 0x6, + BT_8821C_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8821C_2ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8821C_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8821C_2ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8821C_2ANT_COEX_ALGO_NOPROFILEBUSY = 0xb, + BT_8821C_2ANT_COEX_ALGO_MAX +}; + +enum bt_8821c_2ant_ext_ant_switch_type { + BT_8821C_2ANT_EXT_ANT_SWITCH_USE_DPDT = 0x0, + BT_8821C_2ANT_EXT_ANT_SWITCH_USE_SPDT = 0x1, + BT_8821C_2ANT_EXT_ANT_SWITCH_NONE = 0x2, + BT_8821C_2ANT_EXT_ANT_SWITCH_MAX +}; + +enum bt_8821c_2ant_ext_ant_switch_ctrl_type { + BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW = 0x0, + BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_PTA = 0x1, + BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV = 0x2, + BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_MAC = 0x3, + BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_BY_BT = 0x4, + BT_8821C_2ANT_EXT_ANT_SWITCH_CTRL_MAX +}; + +enum bt_8821c_2ant_ext_ant_switch_pos_type { + BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_BT = 0x0, + BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_WLG = 0x1, + BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_WLA = 0x2, + BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_NOCARE = 0x3, + BT_8821C_2ANT_EXT_ANT_SWITCH_MAIN_TO_MAX +}; + +enum bt_8821c_2ant_ext_band_switch_pos_type { + BT_8821C_2ANT_EXT_BAND_SWITCH_TO_WLG = 0x0, + BT_8821C_2ANT_EXT_BAND_SWITCH_TO_WLA = 0x1, + BT_8821C_2ANT_EXT_BAND_SWITCH_TO_MAX +}; + +enum bt_8821c_2ant_int_block { + BT_8821C_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_BTG = 0x0, + BT_8821C_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_WLAG = 0x1, + BT_8821C_2ANT_INT_BLOCK_SWITCH_TO_WLA_OF_WLAG = 0x2, + BT_8821C_2ANT_INT_BLOCK_SWITCH_TO_MAX +}; + +enum bt_8821c_2ant_phase { + BT_8821C_2ANT_PHASE_COEX_INIT = 0x0, + BT_8821C_2ANT_PHASE_WLANONLY_INIT = 0x1, + BT_8821C_2ANT_PHASE_WLAN_OFF = 0x2, + BT_8821C_2ANT_PHASE_2G_RUNTIME = 0x3, + BT_8821C_2ANT_PHASE_5G_RUNTIME = 0x4, + BT_8821C_2ANT_PHASE_BTMPMODE = 0x5, + BT_8821C_2ANT_PHASE_ANTENNA_DET = 0x6, + BT_8821C_2ANT_PHASE_COEX_POWERON = 0x7, + BT_8821C_2ANT_PHASE_2G_RUNTIME_CONCURRENT = 0x8, + BT_8821C_2ANT_PHASE_MAX +}; + +enum bt_8821c_2ant_Scoreboard { + BT_8821C_2ANT_SCOREBOARD_ACTIVE = BIT(0), + BT_8821C_2ANT_SCOREBOARD_ONOFF = BIT(1), + BT_8821C_2ANT_SCOREBOARD_SCAN = BIT(2) +}; + + + +struct coex_dm_8821c_2ant { + /* hw setting */ + u32 pre_ant_pos_type; + u32 cur_ant_pos_type; + /* fw mechanism */ + u8 pre_bt_dec_pwr_lvl; + u8 cur_bt_dec_pwr_lvl; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean reset_tdma_adjust; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + + /* sw mechanism */ + boolean pre_rf_rx_lpf_shrink; + boolean cur_rf_rx_lpf_shrink; + u32 bt_rf_0x1e_backup; + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + boolean pre_dac_swing_on; + u32 pre_dac_swing_lvl; + boolean cur_dac_swing_on; + u32 cur_dac_swing_lvl; + boolean pre_adc_back_off; + boolean cur_adc_back_off; + boolean pre_agc_table_en; + boolean cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + boolean limited_dig; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + boolean need_recover0x948; + u32 backup0x948; + + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + boolean is_switch_to_1dot5_ant; + u8 switch_thres_offset; + u32 arp_cnt; + + u32 pre_ext_ant_switch_status; + u32 cur_ext_ant_switch_status; + + u8 pre_ext_band_switch_status; + u8 cur_ext_band_switch_status; + + u8 pre_int_block_status; + u8 cur_int_block_status; +}; + +struct coex_sta_8821c_2ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + + boolean under_lps; + boolean under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + boolean bt_tx_rx_mask; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + boolean c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8821C_2ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8821C_2ANT_MAX]; + boolean bt_whck_test; + boolean c2h_bt_inquiry_page; + boolean c2h_bt_remote_name_req; + u8 bt_retry_cnt; + u8 bt_info_ext; + u8 bt_info_ext2; + u32 pop_event_cnt; + u8 scan_ap_num; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_vht; + + boolean cck_lock; + boolean pre_ccklock; + boolean cck_ever_lock; + + u8 coex_table_type; + boolean force_lps_on; + + u8 dis_ver_info_cnt; + + u8 a2dp_bit_pool; + u8 cut_version; + + boolean concurrent_rx_mode_on; + + u16 score_board; + u8 isolation_btween_wb; /* 0~ 50 */ + u8 wifi_coex_thres; + u8 bt_coex_thres; + u8 wifi_coex_thres2; + u8 bt_coex_thres2; + + u8 num_of_profile; + boolean acl_busy; + boolean wl_rf_off_on_event; + boolean bt_create_connection; + boolean wifi_is_high_pri_task; + u32 specific_pkt_period_cnt; + u32 bt_coex_supported_feature; + u32 bt_coex_supported_version; + + u8 bt_ble_scan_type; + u8 bt_ble_scan_para[3]; + + boolean run_time_state; + boolean freeze_coexrun_by_btinfo; + + boolean is_A2DP_3M; + boolean voice_over_HOGP; + u8 bt_info; + boolean is_autoslot; + u8 forbidden_slot; + u8 hid_busy_num; + u8 hid_pair_cnt; + + u32 cnt_RemoteNameReq; + u32 cnt_setupLink; + u32 cnt_ReInit; + u32 cnt_IgnWlanAct; + u32 cnt_Page; + + u16 bt_reg_vendor_ac; + u16 bt_reg_vendor_ae; + + boolean is_setupLink; +}; + + +#define BT_8821C_2ANT_EXT_BAND_SWITCH_USE_DPDT 0 +#define BT_8821C_2ANT_EXT_BAND_SWITCH_USE_SPDT 1 + + +struct rfe_type_8821c_2ant { + + u8 rfe_module_type; + boolean ext_ant_switch_exist; + u8 ext_ant_switch_type; /* 0:DPDT, 1:SPDT */ + u8 ext_ant_switch_ctrl_polarity; /* iF 0: DPDT_P=0, DPDT_N=1 => BTG to Main, WL_A+G to Aux */ + + boolean ext_band_switch_exist; + u8 ext_band_switch_type; /* 0:DPDT, 1:SPDT */ + u8 ext_band_switch_ctrl_polarity; + + boolean wlg_Locate_at_btg; /* If true: WLG at BTG, If false: WLG at WLAG */ + + boolean ext_ant_switch_diversity; /* If diversity on */ +}; + +#define BT_8821C_2ANT_ANTDET_PSD_POINTS 256 /* MAX:1024 */ +#define BT_8821C_2ANT_ANTDET_PSD_AVGNUM 1 /* MAX:3 */ +#define BT_8821C_2ANT_ANTDET_BUF_LEN 16 + +struct psdscan_sta_8821c_2ant { + + u32 ant_det_bt_le_channel; /* BT LE Channel ex:2412 */ + u32 ant_det_bt_tx_time; + u32 ant_det_pre_psdscan_peak_val; + boolean ant_det_is_ant_det_available; + u32 ant_det_psd_scan_peak_val; + boolean ant_det_is_btreply_available; + u32 ant_det_psd_scan_peak_freq; + + u8 ant_det_result; + u8 ant_det_peak_val[BT_8821C_2ANT_ANTDET_BUF_LEN]; + u8 ant_det_peak_freq[BT_8821C_2ANT_ANTDET_BUF_LEN]; + u32 ant_det_try_count; + u32 ant_det_fail_count; + u32 ant_det_inteval_count; + u32 ant_det_thres_offset; + + u32 real_cent_freq; + s32 real_offset; + u32 real_span; + + u32 psd_band_width; /* unit: Hz */ + u32 psd_point; /* 128/256/512/1024 */ + u32 psd_report[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_report_max_hold[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_start_point; + u32 psd_stop_point; + u32 psd_max_value_point; + u32 psd_max_value; + u32 psd_max_value2; + u32 psd_avg_value; /* filter loop_max_value that below BT_8821C_1ANT_ANTDET_PSDTHRES_1ANT, and average the rest*/ + u32 psd_loop_max_value[BT_8821C_2ANT_ANTDET_PSD_SWWEEPCOUNT]; /*max value in each loop */ + u32 psd_start_base; + u32 psd_avg_num; /* 1/8/16/32 */ + u32 psd_gen_count; + boolean is_AntDet_running; + boolean is_psd_show_max_only; +}; + + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8821c2ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8821c2ant_pre_load_firmware(IN struct btc_coexist *btcoexist); +void ex_halbtc8821c2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8821c2ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8821c2ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c2ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c2ant_switchband_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8821c2ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8821c2ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8821c2ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state); +void ex_halbtc8821c2ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8821c2ant_display_coex_info(IN struct btc_coexist *btcoexist); +void ex_halbtc8821c2ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); +void ex_halbtc8821c2ant_display_ant_detection(IN struct btc_coexist *btcoexist); + + +#else +#define ex_halbtc8821c2ant_power_on_setting(btcoexist) +#define ex_halbtc8821c2ant_pre_load_firmware(btcoexist) +#define ex_halbtc8821c2ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8821c2ant_init_coex_dm(btcoexist) +#define ex_halbtc8821c2ant_ips_notify(btcoexist, type) +#define ex_halbtc8821c2ant_lps_notify(btcoexist, type) +#define ex_halbtc8821c2ant_scan_notify(btcoexist, type) +#define ex_halbtc8821c2ant_switchband_notify(btcoexist,type) +#define ex_halbtc8821c2ant_connect_notify(btcoexist, type) +#define ex_halbtc8821c2ant_media_status_notify(btcoexist, type) +#define ex_halbtc8821c2ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8821c2ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8821c2ant_rf_status_notify(btcoexist, type) +#define ex_halbtc8821c2ant_halt_notify(btcoexist) +#define ex_halbtc8821c2ant_pnp_notify(btcoexist, pnp_state) +#define ex_halbtc8821c2ant_periodical(btcoexist) +#define ex_halbtc8821c2ant_display_coex_info(btcoexist) +#define ex_halbtc8821c2ant_display_ant_detection(btcoexist) +#define ex_halbtc8821c2ant_antenna_detection(btcoexist, cent_freq, offset, span, seconds) +#endif + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821cwifionly.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821cwifionly.c new file mode 100644 index 0000000..6de8db0 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821cwifionly.c @@ -0,0 +1,186 @@ +#include "mp_precomp.h" + +static struct rfe_type_8821c_wifi_only gl_rfe_type_8821c_1ant; +static struct rfe_type_8821c_wifi_only *rfe_type = &gl_rfe_type_8821c_1ant; + + + +VOID hal8821c_wifi_only_switch_antenna( + IN struct wifi_only_cfg *pwifionlycfg, + IN u1Byte is_5g + ) +{ + boolean switch_polatiry_inverse = false; + u8 regval_0xcb7 = 0; + u8 pos_type, ctrl_type; + + if (!rfe_type->ext_ant_switch_exist) + return; + + /* swap control polarity if use different switch control polarity*/ + /* Normal switch polarity for DPDT, 0xcb4[29:28] = 2b'01 => BTG to Main, WLG to Aux, 0xcb4[29:28] = 2b'10 => BTG to Aux, WLG to Main */ + /* Normal switch polarity for SPDT, 0xcb4[29:28] = 2b'01 => Ant to BTG, 0xcb4[29:28] = 2b'10 => Ant to WLG */ + if (rfe_type->ext_ant_switch_ctrl_polarity) + switch_polatiry_inverse = !switch_polatiry_inverse; + + /* swap control polarity if 1-Ant at Aux */ + if (rfe_type->ant_at_main_port == false) + switch_polatiry_inverse = !switch_polatiry_inverse; + + if (is_5g) + pos_type = BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_TO_WLA; + else + pos_type = BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_TO_WLG; + + switch (pos_type) { + default: + case BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_TO_WLA: + + break; + case BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_TO_WLG: + if (!rfe_type->wlg_Locate_at_btg) + switch_polatiry_inverse = !switch_polatiry_inverse; + break; + } + + if (pwifionlycfg->haldata_info.ant_div_cfg) + ctrl_type = BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_CTRL_BY_ANTDIV; + else + ctrl_type = BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_CTRL_BY_BBSW; + + + switch (ctrl_type) { + default: + case BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_CTRL_BY_BBSW: + halwifionly_phy_set_bb_reg(pwifionlycfg, 0x4c, 0x01800000, 0x2); + + /* BB SW, DPDT use RFE_ctrl8 and RFE_ctrl9 as control pin */ + halwifionly_phy_set_bb_reg(pwifionlycfg, 0xcb4, 0x000000ff, 0x77); + + regval_0xcb7 = (switch_polatiry_inverse == false ? 0x1 : 0x2); + + /* 0xcb4[29:28] = 2b'01 for no switch_polatiry_inverse, DPDT_SEL_N =1, DPDT_SEL_P =0 */ + halwifionly_phy_set_bb_reg(pwifionlycfg, 0xcb4, 0x30000000, regval_0xcb7); + break; + + case BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_CTRL_BY_ANTDIV: + halwifionly_phy_set_bb_reg(pwifionlycfg, 0x4c, 0x01800000, 0x2); + + /* BB SW, DPDT use RFE_ctrl8 and RFE_ctrl9 as control pin */ + halwifionly_phy_set_bb_reg(pwifionlycfg, 0xcb4, 0x000000ff, 0x88); + + /* no regval_0xcb7 setup required, because antenna switch control value by antenna diversity */ + + break; + + } + +} + + +VOID halbtc8821c_wifi_only_set_rfe_type( + IN struct wifi_only_cfg *pwifionlycfg + ) +{ + + /* the following setup should be got from Efuse in the future */ + rfe_type->rfe_module_type = (pwifionlycfg->haldata_info.rfe_type) & 0x1f; + + rfe_type->ext_ant_switch_ctrl_polarity = 0; + + switch (rfe_type->rfe_module_type) { + case 0: + default: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_USE_DPDT; /*2-Ant, DPDT, WLG*/ + rfe_type->wlg_Locate_at_btg = false; + rfe_type->ant_at_main_port = true; + break; + case 1: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_USE_SPDT; /*1-Ant, Main, DPDT or SPDT, WLG */ + rfe_type->wlg_Locate_at_btg = false; + rfe_type->ant_at_main_port = true; + break; + case 2: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_USE_SPDT; /*1-Ant, Main, DPDT or SPDT, BTG */ + rfe_type->wlg_Locate_at_btg = true; + rfe_type->ant_at_main_port = true; + break; + case 3: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_USE_DPDT; /*1-Ant, Aux, DPDT, WLG */ + rfe_type->wlg_Locate_at_btg = false; + rfe_type->ant_at_main_port = false; + break; + case 4: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_USE_DPDT; /*1-Ant, Aux, DPDT, BTG */ + rfe_type->wlg_Locate_at_btg = true; + rfe_type->ant_at_main_port = false; + break; + case 5: + rfe_type->ext_ant_switch_exist = false; /*2-Ant, no antenna switch, WLG*/ + rfe_type->ext_ant_switch_type = + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_NONE; + rfe_type->wlg_Locate_at_btg = false; + rfe_type->ant_at_main_port = true; + break; + case 6: + rfe_type->ext_ant_switch_exist = false; /*2-Ant, no antenna switch, WLG*/ + rfe_type->ext_ant_switch_type = + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_NONE; + rfe_type->wlg_Locate_at_btg = false; + rfe_type->ant_at_main_port = true; + break; + case 7: + rfe_type->ext_ant_switch_exist = true; /*2-Ant, DPDT, BTG*/ + rfe_type->ext_ant_switch_type = + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_USE_DPDT; + rfe_type->wlg_Locate_at_btg = true; + rfe_type->ant_at_main_port = true; + break; + } + +} + + +VOID +ex_hal8821c_wifi_only_hw_config( + IN struct wifi_only_cfg *pwifionlycfg + ) +{ + halbtc8821c_wifi_only_set_rfe_type(pwifionlycfg); + + /* set gnt_wl, gnt_bt control owner to WL*/ + halwifionly_phy_set_bb_reg(pwifionlycfg, 0x70, 0x400000, 0x1); + + /*gnt_wl=1 , gnt_bt=0*/ + halwifionly_phy_set_bb_reg(pwifionlycfg, 0x1704, 0xffffffff, 0x7700); + halwifionly_phy_set_bb_reg(pwifionlycfg, 0x1700, 0xffffffff, 0xc00f0038); +} + +VOID +ex_hal8821c_wifi_only_scannotify( + IN struct wifi_only_cfg *pwifionlycfg, + IN u1Byte is_5g + ) +{ + hal8821c_wifi_only_switch_antenna(pwifionlycfg, is_5g); +} + +VOID +ex_hal8821c_wifi_only_switchbandnotify( + IN struct wifi_only_cfg *pwifionlycfg, + IN u1Byte is_5g + ) +{ + hal8821c_wifi_only_switch_antenna(pwifionlycfg, is_5g); +} + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821cwifionly.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821cwifionly.h new file mode 100644 index 0000000..afa2b2f --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8821cwifionly.h @@ -0,0 +1,70 @@ +#ifndef __INC_HAL8821CWIFIONLYHWCFG_H +#define __INC_HAL8821CWIFIONLYHWCFG_H + + +struct rfe_type_8821c_wifi_only { + + u8 rfe_module_type; + boolean ext_ant_switch_exist; + u8 ext_ant_switch_type; /* 0:DPDT, 1:SPDT */ + u8 ext_ant_switch_ctrl_polarity; /* iF 0: DPDT_P=0, DPDT_N=1 => BTG to Main, WL_A+G to Aux */ + + boolean ant_at_main_port; + + boolean wlg_Locate_at_btg; /* If true: WLG at BTG, If false: WLG at WLAG */ + + boolean ext_ant_switch_diversity; /* If diversity on */ +}; + +enum bt_8821c_wifi_only_ext_ant_switch_type { + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_USE_DPDT = 0x0, + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_USE_SPDT = 0x1, + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_NONE = 0x2, + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_MAX +}; + +enum bt_8821c_wifi_only_ext_ant_switch_ctrl_type { + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_CTRL_BY_BBSW = 0x0, + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_CTRL_BY_PTA = 0x1, + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_CTRL_BY_ANTDIV = 0x2, + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_CTRL_BY_MAC = 0x3, + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_CTRL_BY_BT = 0x4, + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_CTRL_MAX +}; + +enum bt_8821c_wifi_only_ext_ant_switch_pos_type { + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_TO_BT = 0x0, + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_TO_WLG = 0x1, + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_TO_WLA = 0x2, + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_TO_NOCARE = 0x3, + BT_8821C_WIFI_ONLY_EXT_ANT_SWITCH_TO_MAX +}; + + +VOID +hal8821c_wifi_only_switch_antenna( + IN struct wifi_only_cfg *pwifionlycfg, + IN u1Byte is_5g + ); + +VOID +halbtc8821c_wifi_only_set_rfe_type( + IN struct wifi_only_cfg *pwifionlycfg + ); + + +VOID +ex_hal8821c_wifi_only_hw_config( + IN struct wifi_only_cfg *pwifionlycfg + ); +VOID +ex_hal8821c_wifi_only_scannotify( + IN struct wifi_only_cfg *pwifionlycfg, + IN u1Byte is_5g + ); +VOID +ex_hal8821c_wifi_only_switchbandnotify( + IN struct wifi_only_cfg *pwifionlycfg, + IN u1Byte is_5g + ); +#endif diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b1ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b1ant.c new file mode 100644 index 0000000..50673e7 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b1ant.c @@ -0,0 +1,6840 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8822B Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8822B_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8822b_1ant glcoex_dm_8822b_1ant; +static struct coex_dm_8822b_1ant *coex_dm = &glcoex_dm_8822b_1ant; +static struct coex_sta_8822b_1ant glcoex_sta_8822b_1ant; +static struct coex_sta_8822b_1ant *coex_sta = &glcoex_sta_8822b_1ant; +static struct psdscan_sta_8822b_1ant gl_psd_scan_8822b_1ant; +static struct psdscan_sta_8822b_1ant *psd_scan = &gl_psd_scan_8822b_1ant; +static struct rfe_type_8822b_1ant gl_rfe_type_8822b_1ant; +static struct rfe_type_8822b_1ant *rfe_type = &gl_rfe_type_8822b_1ant; + + + +const char *const glbt_info_src_8822b_1ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u32 glcoex_ver_date_8822b_1ant = 20161026; +u32 glcoex_ver_8822b_1ant = 0x34; +u32 glcoex_ver_btdesired_8822b_1ant = 0x28; + + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8822b1ant_ + * ************************************************************ */ +u8 halbtc8822b1ant_bt_rssi_state(u8 level_num, u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = coex_sta->pre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8822B_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_bt_rssi_state; + } + + if ((coex_sta->pre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8822B_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_bt_rssi_state == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8822B_1ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8822b1ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 index, IN u8 level_num, IN u8 rssi_thresh, IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = coex_sta->pre_wifi_rssi_state[index]; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8822B_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return coex_sta->pre_wifi_rssi_state[index]; + } + + if ((coex_sta->pre_wifi_rssi_state[index] == BTC_RSSI_STATE_LOW) + || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8822B_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_MEDIUM) || + (coex_sta->pre_wifi_rssi_state[index] == + BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8822B_1ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + coex_sta->pre_wifi_rssi_state[index] = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8822b1ant_update_ra_mask(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 dis_rate_mask) +{ + coex_dm->cur_ra_mask = dis_rate_mask; + + if (force_exec || (coex_dm->pre_ra_mask != coex_dm->cur_ra_mask)) + btcoexist->btc_set(btcoexist, BTC_SET_ACT_UPDATE_RAMASK, + &coex_dm->cur_ra_mask); + coex_dm->pre_ra_mask = coex_dm->cur_ra_mask; +} + +void halbtc8822b1ant_auto_rate_fallback_retry(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + boolean wifi_under_b_mode = false; + + coex_dm->cur_arfr_type = type; + + if (force_exec || (coex_dm->pre_arfr_type != coex_dm->cur_arfr_type)) { + switch (coex_dm->cur_arfr_type) { + case 0: /* normal mode */ + btcoexist->btc_write_4byte(btcoexist, 0x430, + coex_dm->backup_arfr_cnt1); + btcoexist->btc_write_4byte(btcoexist, 0x434, + coex_dm->backup_arfr_cnt2); + break; + case 1: + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + if (wifi_under_b_mode) { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x01010101); + } else { + btcoexist->btc_write_4byte(btcoexist, + 0x430, 0x0); + btcoexist->btc_write_4byte(btcoexist, + 0x434, 0x04030201); + } + break; + default: + break; + } + } + + coex_dm->pre_arfr_type = coex_dm->cur_arfr_type; +} + +void halbtc8822b1ant_retry_limit(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_retry_limit_type = type; + + if (force_exec || + (coex_dm->pre_retry_limit_type != + coex_dm->cur_retry_limit_type)) { + switch (coex_dm->cur_retry_limit_type) { + case 0: /* normal mode */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + coex_dm->backup_retry_limit); + break; + case 1: /* retry limit=8 */ + btcoexist->btc_write_2byte(btcoexist, 0x42a, + 0x0808); + break; + default: + break; + } + } + + coex_dm->pre_retry_limit_type = coex_dm->cur_retry_limit_type; +} + +void halbtc8822b1ant_ampdu_max_time(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + coex_dm->cur_ampdu_time_type = type; + + if (force_exec || + (coex_dm->pre_ampdu_time_type != coex_dm->cur_ampdu_time_type)) { + switch (coex_dm->cur_ampdu_time_type) { + case 0: /* normal mode */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + coex_dm->backup_ampdu_max_time); + break; + case 1: /* AMPDU timw = 0x38 * 32us */ + btcoexist->btc_write_1byte(btcoexist, 0x456, + 0x38); + break; + default: + break; + } + } + + coex_dm->pre_ampdu_time_type = coex_dm->cur_ampdu_time_type; +} + +void halbtc8822b1ant_limited_tx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ra_mask_type, IN u8 arfr_type, + IN u8 retry_limit_type, IN u8 ampdu_time_type) +{ + switch (ra_mask_type) { + case 0: /* normal mode */ + halbtc8822b1ant_update_ra_mask(btcoexist, force_exec, + 0x0); + break; + case 1: /* disable cck 1/2 */ + halbtc8822b1ant_update_ra_mask(btcoexist, force_exec, + 0x00000003); + break; + case 2: /* disable cck 1/2/5.5, ofdm 6/9/12/18/24, mcs 0/1/2/3/4 */ + halbtc8822b1ant_update_ra_mask(btcoexist, force_exec, + 0x0001f1f7); + break; + default: + break; + } + + halbtc8822b1ant_auto_rate_fallback_retry(btcoexist, force_exec, + arfr_type); + halbtc8822b1ant_retry_limit(btcoexist, force_exec, retry_limit_type); + halbtc8822b1ant_ampdu_max_time(btcoexist, force_exec, ampdu_time_type); +} + +/* +rx agg size setting : +1: true / don't care / don't care +max: false / false / don't care +7: false / true / 7 +*/ + +void halbtc8822b1ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); + + +} + +void halbtc8822b1ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +void halbtc8822b1ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + static u8 num_of_bt_counter_chk = 0, cnt_slave = 0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + /* to avoid 0x76e[3] = 1 (WLAN_Act control by PTA) during IPS */ + /* if (! (btcoexist->btc_read_1byte(btcoexist, 0x76e) & 0x8) ) */ + + if (coex_sta->under_ips) { + /* coex_sta->high_priority_tx = 65535; */ + /* coex_sta->high_priority_rx = 65535; */ + /* coex_sta->low_priority_tx = 65535; */ + /* coex_sta->low_priority_rx = 65535; */ + /* return; */ + } + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Hi-Pri Rx/Tx: %d/%d, Lo-Pri Rx/Tx: %d/%d\n", + reg_hp_rx, reg_hp_tx, reg_lp_rx, reg_lp_tx); + BTC_TRACE(trace_buf); + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + if ((coex_sta->low_priority_tx > 1150) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + + if ((coex_sta->low_priority_rx >= 1150) && + (coex_sta->low_priority_rx >= coex_sta->low_priority_tx) + && (!coex_sta->under_ips) && + (!coex_sta->c2h_bt_inquiry_page) && + (coex_sta->bt_link_exist)) { + if (cnt_slave >= 3) { + bt_link_info->slave_role = true; + cnt_slave = 3; + } else + cnt_slave++; + } else { + if (cnt_slave == 0) { + bt_link_info->slave_role = false; + cnt_slave = 0; + } else + cnt_slave--; + + } + + if ((coex_sta->high_priority_tx == 0) && + (coex_sta->high_priority_rx == 0) && + (coex_sta->low_priority_tx == 0) && + (coex_sta->low_priority_rx == 0)) { + num_of_bt_counter_chk++; + + if (num_of_bt_counter_chk >= 3) { + halbtc8822b1ant_query_bt_info( + btcoexist); + num_of_bt_counter_chk = 0; + } + } +#if 0 + /* Add Hi-Pri Tx/Rx counter to avoid false detection */ + if (((coex_sta->hid_exist) || (coex_sta->sco_exist)) && + (coex_sta->high_priority_tx + coex_sta->high_priority_rx + >= 160) + && (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->bt_hi_pri_link_exist = true; + else + coex_sta->bt_hi_pri_link_exist = false; + + if ((coex_sta->acl_busy) && + (coex_sta->num_of_profile == 0)) { + if (coex_sta->low_priority_tx + + coex_sta->low_priority_rx >= 160) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + coex_sta->wrong_profile_notification++; + } + } +#endif + +} + + +void halbtc8822b1ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ + s32 wifi_rssi = 0; + boolean wifi_busy = false, wifi_under_b_mode = false; + static u8 cck_lock_counter = 0; + u32 total_cnt; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + if (coex_sta->under_ips) { + coex_sta->crc_ok_cck = 0; + coex_sta->crc_ok_11g = 0; + coex_sta->crc_ok_11n = 0; + coex_sta->crc_ok_11n_agg = 0; + + coex_sta->crc_err_cck = 0; + coex_sta->crc_err_11g = 0; + coex_sta->crc_err_11n = 0; + coex_sta->crc_err_11n_agg = 0; + } else { + coex_sta->crc_ok_cck = btcoexist->btc_read_2byte( + btcoexist, + 0xf04); + coex_sta->crc_ok_11g = btcoexist->btc_read_2byte( + btcoexist, + 0xf14); + coex_sta->crc_ok_11n = btcoexist->btc_read_2byte( + btcoexist, + 0xf10); + coex_sta->crc_ok_11n_agg = btcoexist->btc_read_2byte( + btcoexist, + 0xf0c); + + coex_sta->crc_err_cck = btcoexist->btc_read_2byte( + btcoexist, 0xf00) + btcoexist->btc_read_2byte( + btcoexist, 0xf06); + + coex_sta->crc_err_11g = btcoexist->btc_read_2byte( + btcoexist, + 0xf16); + coex_sta->crc_err_11n = btcoexist->btc_read_2byte( + btcoexist, + 0xf12); + coex_sta->crc_err_11n_agg = btcoexist->btc_read_2byte( + btcoexist, + 0xf0e); + } + + + /* reset counter */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xb58, 0x1, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xb58, 0x1, 0x0); + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + total_cnt = coex_sta->crc_ok_cck + coex_sta->crc_ok_11g + + + coex_sta->crc_ok_11n + + coex_sta->crc_ok_11n_agg; + + if ((coex_dm->bt_status == + BT_8822B_1ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == + BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY) || + (coex_dm->bt_status == + BT_8822B_1ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > (total_cnt - + coex_sta->crc_ok_cck)) { + if (cck_lock_counter < 3) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + + if (cck_lock_counter >= 3) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + if (coex_sta->cck_lock) + coex_sta->cck_ever_lock = true; + + coex_sta->pre_ccklock = coex_sta->cck_lock; + + +} + + +boolean halbtc8822b1ant_is_wifi_status_changed(IN struct btc_coexist *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false, pre_bt_off = false; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (coex_sta->bt_disabled != pre_bt_off) { + pre_bt_off = coex_sta->bt_disabled; + + if (coex_sta->bt_disabled) + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!\n"); + else + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is enabled !!\n"); + + BTC_TRACE(trace_buf); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + return true; + } + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + } + + return false; +} + +void halbtc8822b1ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + bt_link_info->bt_hi_pri_link_exist = coex_sta->bt_hi_pri_link_exist; + bt_link_info->acl_busy = coex_sta->acl_busy; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; +} + +void halbtc8822b1ant_update_wifi_channel_info(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + + h2c_parameter[0] = + 0x1; /* enable BT AFH skip WL channel for 8822b because BT Rx LO interference */ + h2c_parameter[1] = wifi_central_chnl; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); + +} + +u8 halbtc8822b1ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8822B_1ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_1ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_1ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP ==> SCO\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_1ANT_COEX_ALGO_SCO; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_1ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_1ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_1ANT_COEX_ALGO_HID; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_1ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_1ANT_COEX_ALGO_HID_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_1ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! BT Profile = SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Profile = SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_1ANT_COEX_ALGO_PANEDR_HID; + } + } + } + } + + return algorithm; +} + +void halbtc8822b1ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8822b1ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8822b1ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + + + +void halbtc8822b1ant_set_sw_penalty_tx_rate_adaptive(IN struct btc_coexist + *btcoexist, IN boolean low_penalty_ra) +{ + u8 h2c_parameter[6] = {0}; + + h2c_parameter[0] = 0x6; /* op_code, 0x6= Retry_Penalty */ + + if (low_penalty_ra) { + h2c_parameter[1] |= BIT(0); + h2c_parameter[2] = + 0x00; /* normal rate except MCS7/6/5, OFDM54/48/36 */ + h2c_parameter[3] = 0xf7; /* MCS7 or OFDM54 */ + h2c_parameter[4] = 0xf8; /* MCS6 or OFDM48 */ + h2c_parameter[5] = 0xf9; /* MCS5 or OFDM36 */ + } + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, h2c_parameter); +} + +void halbtc8822b1ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ +#if 1 + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == + coex_dm->cur_low_penalty_ra) + return; + } + + if (low_penalty_ra) + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 25); + else + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 0); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; + +#endif +} + +void halbtc8822b1ant_write_score_board( + IN struct btc_coexist *btcoexist, + IN u16 bitpos, + IN boolean state +) +{ + + static u16 originalval = 0x8002; + + if (state) + originalval = originalval | bitpos; + else + originalval = originalval & (~bitpos); + + btcoexist->btc_write_2byte(btcoexist, 0xaa, originalval); +} + +void halbtc8822b1ant_read_score_board( + IN struct btc_coexist *btcoexist, + IN u16 *score_board_val +) +{ + + *score_board_val = (btcoexist->btc_read_2byte(btcoexist, + 0xaa)) & 0x7fff; +} + +void halbtc8822b1ant_post_state_to_bt( + IN struct btc_coexist *btcoexist, + IN u16 type, + IN boolean state +) +{ + + halbtc8822b1ant_write_score_board(btcoexist, (u16) type, state); + +} + + +void halbtc8822b1ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false, + wifi_under_5g = false; + u16 u16tmp; + + /* This function check if bt is disabled */ +#if 0 + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + + +#else + + /* Read BT on/off status from scoreboard[1], enable this only if BT patch support this feature */ + halbtc8822b1ant_read_score_board(btcoexist, &u16tmp); + + bt_active = u16tmp & BIT(1); + + +#endif + + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } else { + + bt_disable_cnt++; + if (bt_disable_cnt >= 2) { + bt_disabled = true; + bt_disable_cnt = 2; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, + &wifi_under_5g); + + if ((wifi_under_5g) || (bt_disabled)) + halbtc8822b1ant_low_penalty_ra(btcoexist, + NORMAL_EXEC, false); + else + halbtc8822b1ant_low_penalty_ra(btcoexist, + NORMAL_EXEC, true); + + + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : + "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + coex_sta->bt_disabled = bt_disabled; + } + +} + + + +void halbtc8822b1ant_enable_gnt_to_gpio(IN struct btc_coexist *btcoexist, + boolean isenable) +{ + static u8 bitVal[5] = {0, 0, 0, 0, 0}; + static boolean state = false; + + if (state == isenable) + return; + + state = isenable; + + if (isenable) { + + /* enable GNT_WL, GNT_BT to GPIO for debug */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x1); + + /* store original value */ + bitVal[0] = (btcoexist->btc_read_1byte(btcoexist, + 0x66) & BIT(4)) >> 4; /*0x66[4] */ + bitVal[1] = (btcoexist->btc_read_1byte(btcoexist, + 0x67) & BIT(0)); /*0x66[8] */ + bitVal[2] = (btcoexist->btc_read_1byte(btcoexist, + 0x42) & BIT(3)) >> 3; /*0x40[19] */ + bitVal[3] = (btcoexist->btc_read_1byte(btcoexist, + 0x65) & BIT(7)) >> 7; /*0x64[15] */ + bitVal[4] = (btcoexist->btc_read_1byte(btcoexist, + 0x72) & BIT(2)) >> 2; /*0x70[18] */ + + /* switch GPIO Mux */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, BIT(4), + 0x0); /*0x66[4] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, BIT(0), + 0x0); /*0x66[8] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x42, BIT(3), + 0x0); /*0x40[19] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x65, BIT(7), + 0x0); /*0x64[15] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x72, BIT(2), + 0x0); /*0x70[18] = 0 */ + + + } else { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x0); + + /* Restore original value */ + /* switch GPIO Mux */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, BIT(4), + bitVal[0]); /*0x66[4] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, BIT(0), + bitVal[1]); /*0x66[8] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x42, BIT(3), + bitVal[2]); /*0x40[19] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x65, BIT(7), + bitVal[3]); /*0x64[15] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x72, BIT(2), + bitVal[4]); /*0x70[18] = 0 */ + } + +} + + +u32 halbtc8822b1ant_ltecoex_indirect_read_reg(IN struct btc_coexist *btcoexist, + IN u16 reg_addr) +{ + u32 j = 0; + + + /* wait for ready bit before access 0x1700 */ + btcoexist->btc_write_4byte(btcoexist, 0x1700, 0x800F0000 | reg_addr); + + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x1703) & BIT(5)) == 0) && + (j < BT_8822B_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + return btcoexist->btc_read_4byte(btcoexist, + 0x1708); /* get read data */ + +} + +void halbtc8822b1ant_ltecoex_indirect_write_reg(IN struct btc_coexist + *btcoexist, + IN u16 reg_addr, IN u32 bit_mask, IN u32 reg_value) +{ + u32 val, i = 0, j = 0, bitpos = 0; + + + if (bit_mask == 0x0) + return; + if (bit_mask == 0xffffffff) { + btcoexist->btc_write_4byte(btcoexist, 0x1704, + reg_value); /* put write data */ + + /* wait for ready bit before access 0x1700 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x1703) & BIT(5)) == 0) && + (j < BT_8822B_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + btcoexist->btc_write_4byte(btcoexist, 0x1700, + 0xc00F0000 | reg_addr); + } else { + for (i = 0; i <= 31; i++) { + if (((bit_mask >> i) & 0x1) == 0x1) { + bitpos = i; + break; + } + } + + /* read back register value before write */ + val = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + reg_addr); + val = (val & (~bit_mask)) | (reg_value << bitpos); + + /* put write data value */ + btcoexist->btc_write_4byte(btcoexist, 0x1704, + val); /* put write data */ + + /* wait for ready bit before access 0x1700 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x1703) & BIT(5)) == 0) && + (j < BT_8822B_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + /* write data add*/ + + btcoexist->btc_write_4byte(btcoexist, 0x1700, + 0xc00F0000 | reg_addr); + + } + +} + +void halbtc8822b1ant_ltecoex_enable(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 val; + + val = (enable) ? 1 : 0; + /* 0x38[7] */ + halbtc8822b1ant_ltecoex_indirect_write_reg(btcoexist, 0x38, 0x80, + val); /* 0x38[7] */ + +} + + +void halbtc8822b1ant_ltecoex_pathcontrol_owner(IN struct btc_coexist *btcoexist, + IN boolean wifi_control) +{ + u8 val; + + val = (wifi_control) ? 1 : 0; + /* 0x70[26] */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x4, + val); /* 0x70[26] */ + +} + +void halbtc8822b1ant_ltecoex_set_gnt_bt(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, bit_mask; + + state = state & 0x1; + /*LTE indirect 0x38=0xccxx (sw : gnt_wl=1,sw gnt_bt=1) + 0x38=0xddxx (sw : gnt_bt=1 , sw gnt_wl=0) + 0x38=0x55xx(hw pta :gnt_wl /gnt_bt ) */ + val = (sw_control) ? ((state << 1) | 0x1) : 0; + + switch (control_block) { + case BT_8822B_1ANT_GNT_BLOCK_RFC_BB: + default: + bit_mask = 0xc000; + halbtc8822b1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[15:14] */ + bit_mask = 0x0c00; + halbtc8822b1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[11:10] */ + break; + case BT_8822B_1ANT_GNT_BLOCK_RFC: + bit_mask = 0xc000; + halbtc8822b1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[15:14] */ + break; + case BT_8822B_1ANT_GNT_BLOCK_BB: + bit_mask = 0x0c00; + halbtc8822b1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[11:10] */ + break; + + } + +} + +void halbtc8822b1ant_ltecoex_set_gnt_wl(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, bit_mask; + /*LTE indirect 0x38=0xccxx (sw : gnt_wl=1,sw gnt_bt=1) + 0x38=0xddxx (sw : gnt_bt=1 , sw gnt_wl=0) + 0x38=0x55xx(hw pta :gnt_wl /gnt_bt ) */ + + state = state & 0x1; + val = (sw_control) ? ((state << 1) | 0x1) : 0; + + switch (control_block) { + case BT_8822B_1ANT_GNT_BLOCK_RFC_BB: + default: + bit_mask = 0x3000; + halbtc8822b1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[13:12] */ + bit_mask = 0x0300; + halbtc8822b1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[9:8] */ + break; + case BT_8822B_1ANT_GNT_BLOCK_RFC: + bit_mask = 0x3000; + halbtc8822b1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[13:12] */ + break; + case BT_8822B_1ANT_GNT_BLOCK_BB: + bit_mask = 0x0300; + halbtc8822b1ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[9:8] */ + break; + + } + +} + +void halbtc8822b1ant_ltecoex_set_coex_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u16 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8822B_1ANT_CTT_WL_VS_LTE: + reg_addr = 0xa0; + break; + case BT_8822B_1ANT_CTT_BT_VS_LTE: + reg_addr = 0xa4; + break; + } + + if (reg_addr != 0x0000) + halbtc8822b1ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xffff, table_content); /* 0xa0[15:0] or 0xa4[15:0] */ + + +} + + +void halbtc8822b1ant_ltcoex_set_break_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u8 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8822B_1ANT_LBTT_WL_BREAK_LTE: + reg_addr = 0xa8; + break; + case BT_8822B_1ANT_LBTT_BT_BREAK_LTE: + reg_addr = 0xac; + break; + case BT_8822B_1ANT_LBTT_LTE_BREAK_WL: + reg_addr = 0xb0; + break; + case BT_8822B_1ANT_LBTT_LTE_BREAK_BT: + reg_addr = 0xb4; + break; + } + + if (reg_addr != 0x0000) + halbtc8822b1ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xff, table_content); /* 0xa8[15:0] or 0xb4[15:0] */ + + +} + +void halbtc8822b1ant_set_wltoggle_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 interval, + IN u8 val0x6c4_b0, IN u8 val0x6c4_b1, IN u8 val0x6c4_b2, + IN u8 val0x6c4_b3) +{ + static u8 pre_h2c_parameter[6] = {0}; + u8 cur_h2c_parameter[6] = {0}; + u8 i, match_cnt = 0; + + cur_h2c_parameter[0] = 0x7; /* op_code, 0x7= wlan toggle slot*/ + + cur_h2c_parameter[1] = interval; + cur_h2c_parameter[2] = val0x6c4_b0; + cur_h2c_parameter[3] = val0x6c4_b1; + cur_h2c_parameter[4] = val0x6c4_b2; + cur_h2c_parameter[5] = val0x6c4_b3; + + if (!force_exec) { + for (i = 1; i <= 5; i++) { + if (cur_h2c_parameter[i] != pre_h2c_parameter[i]) + break; + + match_cnt++; + } + + if (match_cnt == 5) + return; + } + + for (i = 1; i <= 5; i++) + pre_h2c_parameter[i] = cur_h2c_parameter[i]; + + btcoexist->btc_fill_h2c(btcoexist, 0x69, 6, cur_h2c_parameter); +} + +void halbtc8822b1ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8822b1ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8822b1ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8822b1ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + u32 break_table; + u8 select_table; + + + + coex_sta->coex_table_type = type; + + if (coex_sta->concurrent_rx_mode_on == true) { + break_table = 0xf0ffffff; /* set WL hi-pri can break BT */ + select_table = 0x3; /* set Tx response = Hi-Pri (ex: Transmitting ACK,BA,CTS) */ + } else { + break_table = 0xffffff; + select_table = 0x3; + } + + switch (type) { + case 0: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x55555555, break_table, + select_table); + break; + case 1: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, break_table, + select_table); + break; + case 2: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0xaa5a5a5a, 0xaa5a5a5a, break_table, + select_table); + break; + case 3: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaa5a5a5a, break_table, + select_table); + break; + case 4: + halbtc8822b1ant_coex_table(btcoexist, + force_exec, 0xaa555555, 0xaa5a5a5a, + break_table, select_table); + break; + case 5: + halbtc8822b1ant_coex_table(btcoexist, + force_exec, 0x5a5a5a5a, 0x5a5a5a5a, + break_table, select_table); + break; + case 6: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaaaaaa, break_table, + select_table); + break; + case 7: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0xaaaaaaaa, 0xaaaaaaaa, break_table, + select_table); + break; + case 8: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0xffffffff, 0xffffffff, break_table, + select_table); + break; + case 9: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0x5a5a5555, 0xaaaa5a5a, break_table, + select_table); + break; + case 10: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0xaaaa5aaa, 0xaaaa5aaa, break_table, + select_table); + break; + case 11: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0xaaaaa5aa, 0xaaaaaaaa, break_table, + select_table); + break; + case 12: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0xaaaaa5aa, 0xaaaaa5aa, break_table, + select_table); + break; + case 13: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaa5a5a, break_table, + select_table); + break; + case 14: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0x5a5a555a, 0xaaaa5a5a, break_table, + select_table); + break; + case 15: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaa55aa, break_table, + select_table); + break; + case 16: + halbtc8822b1ant_coex_table(btcoexist, force_exec, + 0x5a5a555a, 0x5a5a555a, break_table, + select_table); + break; + + default: + break; + } +} + +void halbtc8822b1ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + + + u8 h2c_parameter[1] = {0}; + + if (enable) + h2c_parameter[0] |= BIT(0); /* function enable */ + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8822b1ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) { + + coex_dm->pre_ignore_wlan_act = + coex_dm->cur_ignore_wlan_act; + return; + } + } + + halbtc8822b1ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8822b1ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8822b1ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8822b1ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8822b1ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + u8 h2c_parameter[5] = {0x8, 0, 0, 0, 0}; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + + +void halbtc8822b1ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + coex_sta->force_lps_on = false; + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + case BTC_PS_LPS_ON: + + coex_sta->force_lps_on = true; + halbtc8822b1ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8822b1ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + coex_sta->force_lps_on = true; + break; + case BTC_PS_LPS_OFF: + + coex_sta->force_lps_on = false; + halbtc8822b1ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + default: + break; + } +} + + +void halbtc8822b1ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], FW for 1Ant AP mode\n"); + BTC_TRACE(trace_buf); + + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + + halbtc8822b1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + } + } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + + halbtc8822b1ant_power_save_state(btcoexist, + BTC_PS_LPS_ON, 0x50, + 0x4); + } else { + halbtc8822b1ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + } + + + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +void halbtc8822b1ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + struct btc_board_info *board_info = &btcoexist->board_info; + boolean wifi_busy = false; + static u8 psTdmaByte4Modify = 0x0, pre_psTdmaByte4Modify = 0x0; + static boolean pre_wifi_busy = false; + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (wifi_busy != pre_wifi_busy) { + force_exec = true; + pre_wifi_busy = wifi_busy; + } + + /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + if ((bt_link_info->slave_role) && (bt_link_info->a2dp_exist)) + psTdmaByte4Modify = 0x1; + else + psTdmaByte4Modify = 0x0; + + if (pre_psTdmaByte4Modify != psTdmaByte4Modify) { + + force_exec = true; + pre_psTdmaByte4Modify = psTdmaByte4Modify; + } + + if (coex_dm->cur_ps_tdma_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], **********TDMA(off, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], return for no-TDMA case change\n"); + BTC_TRACE(trace_buf); + + return; + } + } + + + if (turn_on) { + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + + switch (type) { + default: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x1a, 0x1a, 0x0, 0x10); + break; + case 1: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x3a, 0x03, 0x11, 0x10); + break; + case 3: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x3a, 0x03, 0x10, 0x10); + break; + case 4: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x21, 0x03, 0x10, 0x10); + break; + case 5: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x15, 0x3, 0x11, 0x11); + break; + case 7: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x10, 0x03, 0x10, 0x14 | + psTdmaByte4Modify); + break; + case 8: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x10, 0x03, 0x10, 0x14 | + psTdmaByte4Modify); + break; + case 13: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x25, 0x03, 0x10, 0x10 | + psTdmaByte4Modify); + break; + case 14: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x15, 0x03, 0x10, 0x10 | + psTdmaByte4Modify); + break; + case 15: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x20, 0x03, 0x10, 0x10 | + psTdmaByte4Modify); + break; + case 17: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x10, 0x03, 0x11, 0x14 | + psTdmaByte4Modify); + break; + + case 20: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x30, 0x03, 0x11, 0x10); + break; + case 22: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x25, 0x03, 0x11, 0x10); + break; + case 32: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x35, 0x3, 0x11, 0x11); + break; + case 33: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x61, 0x35, 0x03, 0x11, 0x10); + break; + case 41: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x45, 0x3, 0x11, 0x11); + break; + case 42: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x1e, 0x3, 0x10, 0x14 | + psTdmaByte4Modify); + break; + case 43: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x45, 0x3, 0x10, 0x14); + break; + case 44: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x25, 0x3, 0x10, 0x10); + break; + case 45: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x29, 0x3, 0x10, 0x10); + break; + case 46: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x1a, 0x3, 0x10, 0x10); + break; + case 47: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x32, 0x3, 0x10, 0x10); + break; + case 48: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x51, 0x29, 0x3, 0x10, 0x10); + break; + case 49: + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x55, 0x1e, 0x3, 0x10, 0x54); + break; + + } + } else { + + switch (type) { + case 0: + default: /* Software control, Antenna at BT side */ + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x0, 0x0, 0x0, 0x0, 0x0); + /* + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_BT, FORCE_EXEC, false, + false); */ + break; + case 8: /* PTA Control */ + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x8, 0x0, 0x0, 0x0, 0x0); + /* + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_PTA, FORCE_EXEC, false, + false); */ + break; + case 9: /* Software control, Antenna at WiFi side */ + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x0, 0x0, 0x0, 0x0, 0x0); + /* + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_WIFI, FORCE_EXEC,false,false); */ + break; + case 10: /* under 5G , 0x778=1*/ + halbtc8822b1ant_set_fw_pstdma(btcoexist, + 0x0, 0x0, 0x0, 0x0, 0x0); + + /* + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_WIFI5G, FORCE_EXEC, false, + false); */ + + break; + } + } + + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + + +void halbtc8822b1ant_sw_mechanism(IN struct btc_coexist *btcoexist, + IN boolean low_penalty_ra) +{ + halbtc8822b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, low_penalty_ra); +} +/*rf4 type by efuse , and for ant at main aux inverse use , because is 2x2 ,and control types are the same ,does not need */ + +void halbtc8822b1ant_set_rfe_type(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + + /* the following setup should be got from Efuse in the future */ + rfe_type->rfe_module_type = board_info->rfe_type; + + rfe_type->ext_ant_switch_ctrl_polarity = 0; + + switch (rfe_type->rfe_module_type) { + case 0: + default: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 1: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 2: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 3: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 4: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SP3T; /* SP3T */; + break; + } + + +} + +/*anttenna control by bb mac bt antdiv pta to write 0x4c 0xcb4,0xcbd*/ + +void halbtc8822b1ant_set_ext_ant_switch(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ctrl_type, IN u8 pos_type) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + boolean switch_polatiry_inverse = false; + u8 regval_0xcbd = 0, regval_0x64; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + + if (!rfe_type->ext_ant_switch_exist) + return; + + coex_dm->cur_ext_ant_switch_status = (ctrl_type << 8) + pos_type; + + if (!force_exec) { + if (coex_dm->pre_ext_ant_switch_status == + coex_dm->cur_ext_ant_switch_status) + return; + } + + coex_dm->pre_ext_ant_switch_status = coex_dm->cur_ext_ant_switch_status; + + /* swap control polarity if use different switch control polarity*/ + /* Normal switch polarity for SPDT, 0xcbd[1:0] = 2b'01 => Ant to BTG, 0xcbd[1:0] = 2b'10 => Ant to WLG */ + switch_polatiry_inverse = (rfe_type->ext_ant_switch_ctrl_polarity == 1 ? + ~switch_polatiry_inverse : switch_polatiry_inverse); + + + switch (pos_type) { + default: + case BT_8822B_1ANT_EXT_ANT_SWITCH_TO_BT: + case BT_8822B_1ANT_EXT_ANT_SWITCH_TO_NOCARE: + + break; + case BT_8822B_1ANT_EXT_ANT_SWITCH_TO_WLG: + break; + case BT_8822B_1ANT_EXT_ANT_SWITCH_TO_WLA: + break; + } + + + if (rfe_type->ext_ant_switch_type == + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT) { + switch (ctrl_type) { + default: + case BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW: + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x4e, 0x80, + 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x4f, 0x01, + 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0xcb4, 0xff, + 0x77); /* BB SW, DPDT use RFE_ctrl8 and RFE_ctrl9 as conctrol pin */ + + regval_0xcbd = (switch_polatiry_inverse + == false ? 0x1 : + 0x2); /* 0xcbd[1:0] = 2b'01 for no switch_polatiry_inverse, ANTSWB =1, ANTSW =0 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0xcbd, 0x3, + regval_0xcbd); + + break; + case BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_PTA: + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x4e, 0x80, + 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x4f, 0x01, + 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0xcb4, 0xff, + 0x66); /* PTA, DPDT use RFE_ctrl8 and RFE_ctrl9 as conctrol pin */ + + regval_0xcbd = (switch_polatiry_inverse + == false ? 0x2 : + 0x1); /* 0xcbd[1:0] = 2b'10 for no switch_polatiry_inverse, ANTSWB =1, ANTSW =0 @ GNT_BT=1 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0xcbd, 0x3, + regval_0xcbd); + + break; + case BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV + : + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x4e, 0x80, + 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x4f, 0x01, + 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0xcb4, 0xff, + 0x88); /* */ + + /* no regval_0xcbd setup required, because antenna switch control value by antenna diversity */ + + break; + case BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_MAC: + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x4e, 0x80, + 0x1); /* 0x4c[23] = 1 */ + + regval_0x64 = (switch_polatiry_inverse + == false ? 0x0 : + 0x1); /* 0x64[0] = 1b'0 for no switch_polatiry_inverse, DPDT_SEL_N =1, DPDT_SEL_P =0 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x64, 0x1, + regval_0x64); + break; + case BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BT: + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x4e, 0x80, + 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x4f, 0x01, + 0x0); /* 0x4c[24] = 0 */ + + /* no setup required, because antenna switch control value by BT vendor 0xac[1:0] */ + break; + } + } + + u32tmp1 = btcoexist->btc_read_4byte(btcoexist, 0xcbc); + u32tmp2 = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0x64) & 0xff; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (After Ext Ant switch setup) 0xcbc = 0x%08x, 0x4c = 0x%08x, 0x64= 0x%02x**********\n", + u32tmp1, u32tmp2, u32tmp3); + BTC_TRACE(trace_buf); + + +} + +/*set gnt_wl gnt_bt control by sw high low , or hwpta while in power on,ini,wlan off,wlan only ,wl2g non-currrent ,wl2g current,wl5g*/ + +void halbtc8822b1ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean force_exec, + IN u8 phase) + +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + + coex_dm->cur_ant_pos_type = (ant_pos_type << 8) + phase; + + if (!force_exec) { + if (coex_dm->cur_ant_pos_type == + coex_dm->pre_ant_pos_type) + return; + } + + coex_dm->pre_ant_pos_type = coex_dm->cur_ant_pos_type; + +#if 1 + u32tmp1 = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + u32tmp2 = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0x54); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (Before Ant Setup) 0xcb4 = 0x%x, 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x**********\n", + u32tmp3, u8tmp, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); +#endif + + switch (phase) { + case BT_8822B_1ANT_PHASE_COEX_INIT: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (set_ant_path - 1ANT_PHASE_COEX_INIT) **********\n"); + BTC_TRACE(trace_buf); + + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8822b1ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8822b1ant_ltecoex_set_coex_table(btcoexist, + BT_8822B_1ANT_CTT_WL_VS_LTE, + 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8822b1ant_ltecoex_set_coex_table(btcoexist, + BT_8822B_1ANT_CTT_BT_VS_LTE, + 0xffff); + + /* set GNT_BT to SW high */ + halbtc8822b1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH); + + /* set GNT_WL to SW low */ + halbtc8822b1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_LOW); + + /* set Path control owner to WL at initial step */ + halbtc8822b1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8822B_1ANT_PCO_WLSIDE); + + coex_sta->run_time_state = false; + + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, + 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, + 0x8, 0x0); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + break; + case BT_8822B_1ANT_PHASE_WLANONLY_INIT: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (set_ant_path - 1ANT_PHASE_WLANONLY_INIT) **********\n"); + BTC_TRACE(trace_buf); + + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8822b1ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8822b1ant_ltecoex_set_coex_table(btcoexist, + BT_8822B_1ANT_CTT_WL_VS_LTE, + 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8822b1ant_ltecoex_set_coex_table(btcoexist, + BT_8822B_1ANT_CTT_BT_VS_LTE, + 0xffff); + + /* set GNT_BT to SW Low */ + halbtc8822b1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_LOW); + + /* Set GNT_WL to SW high */ + halbtc8822b1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH); + + /* set Path control owner to WL at initial step */ + halbtc8822b1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8822B_1ANT_PCO_WLSIDE); + + coex_sta->run_time_state = false; + + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, + 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, + 0x8, 0x0); + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_WIFI; + + break; + case BT_8822B_1ANT_PHASE_WLAN_OFF: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (set_ant_path - 1ANT_PHASE_WLAN_OFF) **********\n"); + BTC_TRACE(trace_buf); + + /* Disable LTE Coex Function in WiFi side */ + halbtc8822b1ant_ltecoex_enable(btcoexist, 0x0); + + /* set Path control owner to BT */ + halbtc8822b1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8822B_1ANT_PCO_BTSIDE); + + /* Set Ext Ant Switch to BT control at wifi off step */ + halbtc8822b1ant_set_ext_ant_switch(btcoexist, + FORCE_EXEC, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BT, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_NOCARE); + + coex_sta->run_time_state = false; + + break; + case BT_8822B_1ANT_PHASE_2G_RUNTIME: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (set_ant_path - 1ANT_PHASE_2G_RUNTIME) **********\n"); + BTC_TRACE(trace_buf); + + /* set GNT_BT to PTA */ + halbtc8822b1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_PTA, + BT_8822B_1ANT_SIG_STA_SET_BY_HW); + + /* Set GNT_WL to PTA */ + halbtc8822b1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_PTA, + BT_8822B_1ANT_SIG_STA_SET_BY_HW); + + /* set Path control owner to WL at runtime step */ + halbtc8822b1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8822B_1ANT_PCO_WLSIDE); + + coex_sta->run_time_state = true; + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_PTA; + + break; + case BT_8822B_1ANT_PHASE_5G_RUNTIME: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (set_ant_path - 1ANT_PHASE_5G_RUNTIME) **********\n"); + BTC_TRACE(trace_buf); + + /* set GNT_BT to SW Hi */ + halbtc8822b1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH); + + /* Set GNT_WL to SW Hi */ + halbtc8822b1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH); + + /* set Path control owner to WL at runtime step */ + halbtc8822b1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8822B_1ANT_PCO_WLSIDE); + + coex_sta->run_time_state = true; + + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = + BTC_ANT_PATH_WIFI5G; + + break; + case BT_8822B_1ANT_PHASE_BTMPMODE: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (set_ant_path - 1ANT_PHASE_BTMPMODE) **********\n"); + BTC_TRACE(trace_buf); + + /* Disable LTE Coex Function in WiFi side */ + halbtc8822b1ant_ltecoex_enable(btcoexist, 0x0); + + /* set GNT_BT to SW Hi */ + halbtc8822b1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH); + + /* Set GNT_WL to SW Lo */ + halbtc8822b1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_LOW); + + /* set Path control owner to WL */ + halbtc8822b1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8822B_1ANT_PCO_WLSIDE); + + coex_sta->run_time_state = false; + + /* Set Ext Ant Switch to BT side at BT MP mode */ + if (BTC_ANT_PATH_AUTO == ant_pos_type) + ant_pos_type = BTC_ANT_PATH_BT; + + break; + } + + + if (phase != BT_8822B_1ANT_PHASE_WLAN_OFF) { + switch (ant_pos_type) { + case BTC_ANT_PATH_WIFI: + halbtc8822b1ant_set_ext_ant_switch( + btcoexist, + force_exec, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_WLG); + break; + case BTC_ANT_PATH_WIFI5G + : + halbtc8822b1ant_set_ext_ant_switch( + btcoexist, + force_exec, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_WLA); + break; + case BTC_ANT_PATH_BT: + halbtc8822b1ant_set_ext_ant_switch( + btcoexist, + force_exec, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_BT); + break; + default: + case BTC_ANT_PATH_PTA: + halbtc8822b1ant_set_ext_ant_switch( + btcoexist, + force_exec, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_PTA, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_NOCARE); + break; + } + + } +#if 1 + u32tmp1 = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (After Ant Setup) 0xcb4 = 0x%x, 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x**********\n", + u32tmp3, u8tmp, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); + +#endif + +} + + +void halbtc8822b1ant_coex_all_off(IN struct btc_coexist *btcoexist) +{ + /* sw all off */ + halbtc8822b1ant_sw_mechanism(btcoexist, false); + + /* hw all off */ + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} +boolean halbtc8822b1ant_is_common_action(IN struct btc_coexist *btcoexist) +{ + boolean common = false, wifi_connected = false, wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + if (!wifi_connected && + BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + + /* halbtc8822b1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (wifi_connected && + (BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT non connected-idle!!\n"); + BTC_TRACE(trace_buf); + + /* halbtc8822b1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (!wifi_connected && + (BT_8822B_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + + /* halbtc8822b1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (wifi_connected && + (BT_8822B_1ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT connected-idle!!\n"); + BTC_TRACE(trace_buf); + + /* halbtc8822b1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else if (!wifi_connected && + (BT_8822B_1ANT_BT_STATUS_CONNECTED_IDLE != + coex_dm->bt_status)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi non connected-idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + + /* halbtc8822b1ant_sw_mechanism(btcoexist, false); */ + + common = true; + } else { + if (wifi_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Busy + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi Connected-Idle + BT Busy!!\n"); + BTC_TRACE(trace_buf); + } + + common = false; + } + + return common; +} + +void halbtc8822b1ant_action_wifi_under5g(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], under 5g start\n"); + BTC_TRACE(trace_buf); + /* for test : s3 bt disappear , fail rate 1/600*/ +/* + halbtc8822b1ant_ignore_wlan_act(btcoexist, NORMAL_EXEC, true); +*/ +/*set sw gnt wl bt high*/ + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_1ANT_PHASE_5G_RUNTIME); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +/* + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, 5); +*/ +} + + + +void halbtc8822b1ant_action_wifi_only(IN struct btc_coexist *btcoexist) +{ + boolean wifi_under_5g = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + halbtc8822b1ant_action_wifi_under5g(btcoexist); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (wlan only -- under 5g ) **********\n"); + BTC_TRACE(trace_buf); + return; + } + + halbtc8822b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + halbtc8822b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (wlan only -- under 2g ) **********\n"); + BTC_TRACE(trace_buf); + +} + +/* ********************************************* + * + * Software Coex Mechanism start + * + * ********************************************* */ + +/* SCO only or SCO+PAN(HS) */ + +/* +void halbtc8822b1ant_action_sco(IN struct btc_coexist* btcoexist) +{ + halbtc8822b1ant_sw_mechanism(btcoexist, true); +} + + +void halbtc8822b1ant_action_hid(IN struct btc_coexist* btcoexist) +{ + halbtc8822b1ant_sw_mechanism(btcoexist, true); +} + + +void halbtc8822b1ant_action_a2dp(IN struct btc_coexist* btcoexist) +{ + halbtc8822b1ant_sw_mechanism(btcoexist, false); +} + +void halbtc8822b1ant_action_a2dp_pan_hs(IN struct btc_coexist* btcoexist) +{ + halbtc8822b1ant_sw_mechanism(btcoexist, false); +} + +void halbtc8822b1ant_action_pan_edr(IN struct btc_coexist* btcoexist) +{ + halbtc8822b1ant_sw_mechanism(btcoexist, false); +} + + +void halbtc8822b1ant_action_pan_hs(IN struct btc_coexist* btcoexist) +{ + halbtc8822b1ant_sw_mechanism(btcoexist, false); +} + + +void halbtc8822b1ant_action_pan_edr_a2dp(IN struct btc_coexist* btcoexist) +{ + halbtc8822b1ant_sw_mechanism(btcoexist, false); +} + +void halbtc8822b1ant_action_pan_edr_hid(IN struct btc_coexist* btcoexist) +{ + halbtc8822b1ant_sw_mechanism(btcoexist, true); +} + + +void halbtc8822b1ant_action_hid_a2dp_pan_edr(IN struct btc_coexist* btcoexist) +{ + halbtc8822b1ant_sw_mechanism(btcoexist, true); +} + +void halbtc8822b1ant_action_hid_a2dp(IN struct btc_coexist* btcoexist) +{ + halbtc8822b1ant_sw_mechanism(btcoexist, true); +} + +*/ + +/* ********************************************* + * + * Non-Software Coex Mechanism start + * + * ********************************************* */ +void halbtc8822b1ant_action_bt_whck_test(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex],action_bt_whck_test\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8822b1ant_action_wifi_multi_port(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex],action_wifi_multi_port\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); +} + +void halbtc8822b1ant_action_hs(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], action_hs\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); +} + +/*"""bt inquiry"""" + wifi any + bt any*/ +void halbtc8822b1ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, ap_enable = false, wifi_busy = false, + bt_busy = false; + + + boolean wifi_scan = false, link = false, roam = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (bt inquiry) **********\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &wifi_scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** scan = %d, link =%d, roam = %d**********\n", + wifi_scan, link, roam); + BTC_TRACE(trace_buf); + + if ((link) || (roam) || (coex_sta->wifi_is_high_pri_task)) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (bt inquiry wifi connect or scan ) **********\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + + } else if ((wifi_scan) && (coex_sta->bt_create_connection)) { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + + } else if ((!wifi_connected) && (!wifi_scan)) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (bt inquiry wifi non connect) **********\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + } else if ((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (bt_link_info->a2dp_exist) { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + } else if (wifi_scan) { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (wifi_busy) { + + /* for BT inquiry/page fail after S4 resume */ + /* halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); */ + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 6); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (bt inquiry wifi connect) **********\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 4); + } + + /* + if ((wifi_link) || (wifi_roam) || (coex_sta->wifi_is_high_pri_task)) { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + + } else if ((wifi_scan) && (coex_sta->bt_create_connection)) { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 6); + + } else if ((!wifi_connected) && (!wifi_scan)) { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if ((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 22); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + } else if (bt_link_info->a2dp_exist) { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else if (wifi_scan) { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + } else if (wifi_busy) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 21); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } else { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 19); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + } + */ +} + +void halbtc8822b1ant_action_bt_sco_hid_only_busy(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (bt sco hid only busy) **********\n"); + BTC_TRACE(trace_buf); + + /*SCO + wifi connected idle or busy / 0x778=1@wifi slot*/ + if (bt_link_info->sco_exist) { + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + /*case16 for connect SCO first then connect a2sp fail issue*/ + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 16); + + } else { /* HID + wifi connected idle or busy / 0x778=1@wifi slot */ + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 5); + /*case16 for connect HID first then connect a2sp fail issue*/ + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 16); + + } +} + +/*wifi connected + bt acl busy*/ +void halbtc8822b1ant_action_wifi_connected_bt_acl_busy(IN struct btc_coexist + *btcoexist, IN u8 wifi_status) +{ + + u8 bt_rssi_state; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_busy = false, wifi_turbo = false; + u32 wifi_bw = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, + &wifi_bw); +btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + bt_rssi_state = halbtc8822b1ant_bt_rssi_state(2, 28, 0); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, +"[BTCoex], ********** (wifi connect acl busy) **********\n"); + BTC_TRACE(trace_buf); + + + + if (bt_link_info->hid_only) { /* HID + wifi connected idle or busy / 0x778=1@wifi slot */ + + + + + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x45e, 0x8, 0x1); + + + + halbtc8822b1ant_action_bt_sco_hid_only_busy(btcoexist, + wifi_status); + return; + } else if ( + bt_link_info->a2dp_only) { /* A2DP + wifi connected idle or busy */ + if (BT_8822B_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) { + + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, + 0x8, 0x1); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + } else { + if (coex_sta->scan_ap_num >= + BT_8822B_1ANT_WIFI_NOISY_THRESH) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, + 17); + } else { + + + + + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x45e, 0x8, 0x1); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, + 42); + + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } +/* + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); +*/ + coex_dm->auto_tdma_adjust = true; + } + + /* A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP) */ + } else if (((bt_link_info->a2dp_exist) && (bt_link_info->pan_exist)) || + (bt_link_info->hid_exist && bt_link_info->a2dp_exist && + bt_link_info->pan_exist)) { /* A2DP+PAN(OPP,FTP), HID+A2DP+PAN(OPP,FTP) */ + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 47); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 6); + } else if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { /* HID+A2DP */ + + btcoexist->btc_write_1byte_bitmask( + btcoexist, 0x45e, 0x8, 0x1); + if (!wifi_busy) { +/*a2dp glitch while wl idle , change the 0x6c0=5a5a5a5a->5555or aaaa55aa*/ + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, + 32); + } else if (wifi_bw == 0) { /* 11bg mode */ + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + halbtc8822b1ant_set_wltoggle_coex_table( + btcoexist, + NORMAL_EXEC, + 0x3, 0xaa, + 0x5a, 0xaa, + 0xaa); + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, + 49); + } else { + /*if in open space , and ask wl tp , 0x60=6135031111,55555555,aaaa55aa*/ + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + halbtc8822b1ant_set_wltoggle_coex_table(btcoexist, NORMAL_EXEC, 0x2, 0xaa, 0x5a, 0xaa, 0xaa); + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 49); +} + /* + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 1); + */ + + + + + } else if ((bt_link_info->pan_only) || (bt_link_info->hid_exist && + bt_link_info->pan_exist)) { /* PAN(OPP,FTP), HID+PAN(OPP,FTP)*/ + /* + if (BT_8723D_1ANT_WIFI_STATUS_CONNECTED_IDLE == wifi_status) + halbtc8723d1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 4); + else + */ + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 47); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 1); + } else { + /* BT no-profile busy (0x9) */ + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 33); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 1); + } +} + +/*wifi not connected + bt action*/ +void halbtc8822b1ant_action_wifi_not_connected(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (wifi not connect) **********\n"); + BTC_TRACE(trace_buf); + + /* tdma and coex table */ + halbtc8822b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); +} + +/*""""wl not connected scan"""" + bt action*/ +void halbtc8822b1ant_action_wifi_not_connected_scan(IN struct btc_coexist + *btcoexist) +{ + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (wifi non connect scan) **********\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if (num_of_wifi_link >= 2) { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_action_bt_inquiry(btcoexist); + } else + halbtc8822b1ant_action_wifi_multi_port(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8822b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8822b1ant_action_hs(btcoexist); + return; + } + + /* tdma and coex table */ + if (BT_8822B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } + } else if ((BT_8822B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8822b1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 5); + } +} + +/*""""wl not connected asso"""" + bt action*/ +void halbtc8822b1ant_action_wifi_not_connected_asso_auth( + IN struct btc_coexist *btcoexist) +{ + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (wifi non connect asso_auth) **********\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if (num_of_wifi_link >= 2) { + + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, + agg_buf_size); + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_action_bt_inquiry(btcoexist); + } else + halbtc8822b1ant_action_wifi_multi_port( + btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8822b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8822b1ant_action_hs(btcoexist); + return; + } + + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist) || + (bt_link_info->a2dp_exist)) { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8822b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else if (bt_link_info->pan_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8822b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 4); + } else { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 2); + } +} + +/*""""wl connected scan"""" + bt action*/ +void halbtc8822b1ant_action_wifi_connected_scan(IN struct btc_coexist + *btcoexist) +{ + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (wifi connect scan) **********\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if (num_of_wifi_link >= 2) { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_action_bt_inquiry(btcoexist); + } else + halbtc8822b1ant_action_wifi_multi_port(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8822b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8822b1ant_action_hs(btcoexist); + return; + } + + /* tdma and coex table */ + if (BT_8822B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + if (bt_link_info->a2dp_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else if (bt_link_info->a2dp_exist && + bt_link_info->pan_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 22); + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } else { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 20); + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } + } else if ((BT_8822B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8822b1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_SCAN); + } else { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 6); + } +} + +/*""""wl connected specific packet"""" + bt action*/ +void halbtc8822b1ant_action_wifi_connected_specific_packet( + IN struct btc_coexist *btcoexist) +{ + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + boolean wifi_busy = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (wifi connect specific packet) **********\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + + num_of_wifi_link = wifi_link_status >> 16; + + if (num_of_wifi_link >= 2) { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_action_bt_inquiry(btcoexist); + } else + halbtc8822b1ant_action_wifi_multi_port(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + halbtc8822b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8822b1ant_action_hs(btcoexist); + return; + } + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + /* no specific packet process for both WiFi and BT very busy */ + if ((wifi_busy) && ((bt_link_info->pan_exist) || + (coex_sta->num_of_profile >= 2))) + return; + + /* tdma and coex table */ + if ((bt_link_info->sco_exist) || (bt_link_info->hid_exist)) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 5); + } else if (bt_link_info->a2dp_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 32); + /*for a2dp glitch,change from 1 to 15*/ + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 15); + } else if (bt_link_info->pan_exist) { + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 20); + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 1); + } else { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 8); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 5); + } +} + +/*wifi connected input point : to set different ps and tdma case (+bt different case)*/ +void halbtc8822b1ant_action_wifi_connected(IN struct btc_coexist *btcoexist) +{ + + boolean wifi_busy = false; + boolean scan = false, link = false, roam = false; + boolean under_4way = false, ap_enable = false, wifi_under_5g = false; + u8 wifi_rssi_state; + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect()===>\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under 5g<===\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_action_wifi_under5g(btcoexist); + + return; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under 2g<===\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (under_4way) { + halbtc8822b1ant_action_wifi_connected_specific_packet( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under 4way<===\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + if (scan || link || roam) { + if (scan) + halbtc8822b1ant_action_wifi_connected_scan(btcoexist); + else + halbtc8822b1ant_action_wifi_connected_specific_packet( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CoexForWifiConnect(), return for wifi is under scan<===\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + /* tdma and coex table */ + if (!wifi_busy) { + if (BT_8822B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8822b1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else if ((BT_8822B_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8822b1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_IDLE); + } else { + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + if ((coex_sta->high_priority_tx) + + (coex_sta->high_priority_rx) <= 60) + /*sy modify case16 -> case17*/ + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + else + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + } + } else { + if (BT_8822B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) { + halbtc8822b1ant_action_wifi_connected_bt_acl_busy( + btcoexist, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else if ((BT_8822B_1ANT_BT_STATUS_SCO_BUSY == + coex_dm->bt_status) || + (BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY == + coex_dm->bt_status)) { + halbtc8822b1ant_action_bt_sco_hid_only_busy(btcoexist, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_BUSY); + } else { + + + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + /* + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 32); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, NORMAL_EXEC, BT_8822B_1ANT_PHASE_2G_RUNTIME); + */ + + + + wifi_rssi_state = halbtc8822b1ant_wifi_rssi_state( + btcoexist, 1, 2, 25, 0); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** before **********\n"); + BTC_TRACE(trace_buf); +/* + if ((BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) && + (coex_sta->scan_ap_num <= 3) && + (wifi_rssi_state == BTC_RSSI_STATE_LOW || + wifi_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { +*/ + if (BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** scan ap <3 coex table=0xaaaaaaaa **********\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 7); + } else + + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + + + + /* + else if ((coex_sta->high_priority_tx + + coex_sta->high_priority_rx) <= 60) + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 1); + else + halbtc8822b1ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + */ + } + } +} + +void halbtc8822b1ant_run_sw_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + + u8 algorithm = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (runswcoexmech) **********\n"); + BTC_TRACE(trace_buf); + algorithm = halbtc8822b1ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + + if (halbtc8822b1ant_is_common_action(btcoexist)) { + + } else { + switch (coex_dm->cur_algorithm) { + case BT_8822B_1ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + /* halbtc8822b1ant_action_sco(btcoexist); */ + break; + case BT_8822B_1ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID.\n"); + BTC_TRACE(trace_buf); + /* halbtc8822b1ant_action_hid(btcoexist); */ + break; + case BT_8822B_1ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + /* halbtc8822b1ant_action_a2dp(btcoexist); */ + break; + case BT_8822B_1ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + /* halbtc8822b1ant_action_a2dp_pan_hs(btcoexist); */ + break; + case BT_8822B_1ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + /* halbtc8822b1ant_action_pan_edr(btcoexist); */ + break; + case BT_8822B_1ANT_COEX_ALGO_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HS mode.\n"); + BTC_TRACE(trace_buf); + /* halbtc8822b1ant_action_pan_hs(btcoexist); */ + break; + case BT_8822B_1ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + /* halbtc8822b1ant_action_pan_edr_a2dp(btcoexist); */ + break; + case BT_8822B_1ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + /* halbtc8822b1ant_action_pan_edr_hid(btcoexist); */ + break; + case BT_8822B_1ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + /* halbtc8822b1ant_action_hid_a2dp_pan_edr(btcoexist); */ + break; + case BT_8822B_1ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + /* halbtc8822b1ant_action_hid_a2dp(btcoexist); */ + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action algorithm = coexist All Off!!\n"); + BTC_TRACE(trace_buf); + /* halbtc8822b1ant_coex_all_off(btcoexist); */ + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +void halbtc8822b1ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean wifi_connected = false, bt_hs_on = false; + boolean increase_scan_dev_num = false; + boolean bt_ctrl_agg_buf_size = false; + boolean miracast_plus_bt = false; + u8 agg_buf_size = 5; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0, wifi_bw; + u8 iot_peer = BTC_IOT_PEER_UNKNOWN; + boolean wifi_under_5g = false; + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (!coex_sta->run_time_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], return for run_time_state = false !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + halbtc8822b1ant_action_wifi_under5g(btcoexist); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 5G!!!\n"); + BTC_TRACE(trace_buf); + return; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 2G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + if (coex_sta->bt_whck_test) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under WHCK TEST!!!\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_action_bt_whck_test(btcoexist); + return; + } + + if (coex_sta->bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!!\n"); + halbtc8822b1ant_action_wifi_only(btcoexist); + return; + } + + if ((BT_8822B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8822B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + increase_scan_dev_num = true; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_INC_SCAN_DEV_NUM, + &increase_scan_dev_num); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + BTC_TRACE(trace_buf); + + if (bt_link_info->bt_link_exist) { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, + 0, 1); + miracast_plus_bt = true; + } else { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, + 0, 0); + miracast_plus_bt = false; + } + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, + bt_ctrl_agg_buf_size, agg_buf_size); + + if ((bt_link_info->a2dp_exist) && + (coex_sta->c2h_bt_inquiry_page)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_action_bt_inquiry(btcoexist); + } else + halbtc8822b1ant_action_wifi_multi_port(btcoexist); + + return; + } + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + + if ((bt_link_info->bt_link_exist) && (wifi_connected)) { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 1, 1, 0, 1); + + btcoexist->btc_get(btcoexist, BTC_GET_U1_IOT_PEER, &iot_peer); + + if (BTC_IOT_PEER_CISCO != iot_peer) { + if (bt_link_info->sco_exist) /* if (bt_link_info->bt_hi_pri_link_exist) */ + halbtc8822b1ant_limited_rx(btcoexist, + NORMAL_EXEC, true, false, 0x5); + else + halbtc8822b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, false, 0x5); + } else { + if (bt_link_info->sco_exist) + halbtc8822b1ant_limited_rx(btcoexist, + NORMAL_EXEC, true, false, 0x5); + else { + if (BTC_WIFI_BW_HT40 == wifi_bw) + halbtc8822b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, true, 0x10); + else + halbtc8822b1ant_limited_rx(btcoexist, + NORMAL_EXEC, false, true, 0x8); + } + } + + halbtc8822b1ant_sw_mechanism(btcoexist, true); + halbtc8822b1ant_run_sw_coexist_mechanism( + btcoexist); /* just print debug message */ + } else { + halbtc8822b1ant_limited_tx(btcoexist, NORMAL_EXEC, 0, 0, 0, 0); + + halbtc8822b1ant_limited_rx(btcoexist, NORMAL_EXEC, false, false, + 0x5); + + halbtc8822b1ant_sw_mechanism(btcoexist, false); + halbtc8822b1ant_run_sw_coexist_mechanism( + btcoexist); /* just print debug message */ + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], BT Is Inquirying\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_action_bt_inquiry(btcoexist); + return; + } else if (bt_hs_on) { + halbtc8822b1ant_action_hs(btcoexist); + return; + } + + + if (!wifi_connected) { + boolean scan = false, link = false, roam = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is non connected-idle !!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + if (scan) + halbtc8822b1ant_action_wifi_not_connected_scan( + btcoexist); + else + halbtc8822b1ant_action_wifi_not_connected_asso_auth( + btcoexist); + } else + halbtc8822b1ant_action_wifi_not_connected(btcoexist); + } else /* wifi LPS/Busy */ + halbtc8822b1ant_action_wifi_connected(btcoexist); +} + +u32 halbtc8822b1ant_psd_log2base(IN struct btc_coexist *btcoexist, IN u32 val) +{ + u8 j; + u32 tmp, tmp2, val_integerd_b = 0, tindex, shiftcount = 0; + u32 result, val_fractiond_b = 0, table_fraction[21] = {0, 432, 332, 274, 232, 200, + 174, 151, 132, 115, 100, 86, 74, 62, 51, 42, + 32, 23, 15, 7, 0 + }; + + if (val == 0) + return 0; + + tmp = val; + + while (1) { + if (tmp == 1) + break; + + tmp = (tmp >> 1); + shiftcount++; + } + + + val_integerd_b = shiftcount + 1; + + tmp2 = 1; + for (j = 1; j <= val_integerd_b; j++) + tmp2 = tmp2 * 2; + + tmp = (val * 100) / tmp2; + tindex = tmp / 5; + + if (tindex > 20) + tindex = 20; + + val_fractiond_b = table_fraction[tindex]; + + result = val_integerd_b * 100 - val_fractiond_b; + + return result; + + +} + +void halbtc8822b1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + /* force to reset coex mechanism */ + + halbtc8822b1ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + + /* sw all off */ + halbtc8822b1ant_sw_mechanism(btcoexist, false); + + /* halbtc8822b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 8); */ + /* halbtc8822b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); */ + + coex_sta->pop_event_cnt = 0; +} + +void halbtc8822b1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean back_up, IN boolean wifi_only) +{ + + u8 u8tmp = 0; + boolean wifi_under_5g = false; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + + + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u32tmp1 = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (Before Init HW config) 0xcb4 = 0x%x, 0x38= 0x%x, 0x54= 0x%x**********\n", + u32tmp3, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 1Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + + /* Setup RF front end type */ + halbtc8822b1ant_set_rfe_type(btcoexist); + + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = (btcoexist->btc_read_1byte(btcoexist, + 0xf1) & 0xf0) >> 4; + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + + /* BT report packet sample rate */ + /* 0x790[5:0]=0x5 */ + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x790); + u8tmp &= 0xc0; + u8tmp |= 0x5; + btcoexist->btc_write_1byte(btcoexist, 0x790, u8tmp); + + /* Enable BT counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + + /* Enable PTA (3-wire function form BT side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x41, 0x02, 0x1); + + /* Enable PTA (tx/rx signal form WiFi side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4c6, 0x10, 0x1); + /*GNT_BT=1 while select both */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x763, 0x10, 0x1); + + /* enable GNT_WL/GNT_BT debug signal to GPIO14/15 */ + /*btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x1);*/ + + /* enable GNT_WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x40, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x1, 0x0); + + if (btcoexist->btc_read_1byte(btcoexist, 0x80) == 0xc6) + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ONOFF, true); + + /* Antenna config */ + if (wifi_only) { + + coex_sta->concurrent_rx_mode_on = false; + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_WIFI, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_WLANONLY_INIT); + } else { + + coex_sta->concurrent_rx_mode_on = true; + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_COEX_INIT); + } + + + /* PTA parameter */ + halbtc8822b1ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + halbtc8822b1ant_enable_gnt_to_gpio(btcoexist, true); + +} + + +void halbtc8822b1ant_init_hw_config_without_bt(IN struct btc_coexist *btcoexist, + IN boolean back_up, IN boolean wifi_only) +{ + + u8 u8tmp = 0; + boolean wifi_under_5g = false; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + + + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = (btcoexist->btc_read_1byte(btcoexist, + 0xf1) & 0xf0) >> 4; + + /* enable TBTT interrupt */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); + + /* enable GNT_WL */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x40, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x1, 0x0); + + /* Antenna config */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, 0x80, + 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, 0x01, + 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, 0xff, + 0x77); /* BB SW, DPDT use RFE_ctrl8 and RFE_ctrl9 as conctrol pin */ + + + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + + /*enable sw control gnt_wl=1 / gnt_bt=1 */ + btcoexist->btc_write_1byte(btcoexist, 0x73, 0x0e); + + btcoexist->btc_write_4byte(btcoexist, 0x1704, 0x0000ff00); + + btcoexist->btc_write_4byte(btcoexist, 0x1700, 0xc00f0038); + + + /* ant switch WL2G or WL5G*/ + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, + &wifi_under_5g); + if (wifi_under_5g) + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x3, 1); + + else + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x3, 2); + +} + +void halbtc8822b1ant_psd_showdata(IN struct btc_coexist *btcoexist) +{ + u8 *cli_buf = btcoexist->cli_buf; + u32 delta_freq_per_point; + u32 freq, freq1, freq2, n = 0, i = 0, j = 0, m = 0, psd_rep1, psd_rep2; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n\n============[PSD info] (%d)============\n", + psd_scan->psd_gen_count); + CL_PRINTF(cli_buf); + + if (psd_scan->psd_gen_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n No data !!\n"); + CL_PRINTF(cli_buf); + return; + } + + if (psd_scan->psd_point == 0) + delta_freq_per_point = 0; + else + delta_freq_per_point = psd_scan->psd_band_width / + psd_scan->psd_point; + + /* if (psd_scan->is_psd_show_max_only) */ + if (0) { + psd_rep1 = psd_scan->psd_max_value / 100; + psd_rep2 = psd_scan->psd_max_value - psd_rep1 * 100; + + freq = ((psd_scan->real_cent_freq - 20) * 1000000 + + psd_scan->psd_max_value_point * delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (freq2 < 100) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n Freq = %d.0%d MHz", + freq1, freq2); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n Freq = %d.%d MHz", + freq1, freq2); + + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + ", Value = %d.0%d dB, (%d)\n", + psd_rep1, psd_rep2, psd_scan->psd_max_value); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + ", Value = %d.%d dB, (%d)\n", + psd_rep1, psd_rep2, psd_scan->psd_max_value); + + CL_PRINTF(cli_buf); + } else { + m = psd_scan->psd_start_point; + n = psd_scan->psd_start_point; + i = 1; + j = 1; + + while (1) { + do { + freq = ((psd_scan->real_cent_freq - 20) * + 1000000 + m * + delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + if (i == 1) { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.000", + freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.0%2d", + freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Freq%6d.%3d", + freq1, + freq2); + } else if ((i % 8 == 0) || + (m == psd_scan->psd_stop_point)) { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.000\n", freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.0%2d\n", freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.%3d\n", freq1, + freq2); + } else { + if (freq2 == 0) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.000", freq1); + else if (freq2 < 100) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.0%2d", freq1, + freq2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%6d.%3d", freq1, + freq2); + } + + i++; + m++; + CL_PRINTF(cli_buf); + + } while ((i <= 8) && (m <= psd_scan->psd_stop_point)); + + + do { + psd_rep1 = psd_scan->psd_report_max_hold[n] / + 100; + psd_rep2 = psd_scan->psd_report_max_hold[n] - + psd_rep1 * + 100; + + if (j == 1) { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Val %7d.0%d", + psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "\r\n Val %7d.%d", + psd_rep1, + psd_rep2); + } else if ((j % 8 == 0) || + (n == psd_scan->psd_stop_point)) { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.0%d\n", psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.%d\n", psd_rep1, + psd_rep2); + } else { + if (psd_rep2 < 10) + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.0%d", psd_rep1, + psd_rep2); + else + CL_SPRINTF(cli_buf, + BT_TMP_BUF_SIZE, + "%7d.%d", psd_rep1, + psd_rep2); + } + + j++; + n++; + CL_PRINTF(cli_buf); + + } while ((j <= 8) && (n <= psd_scan->psd_stop_point)); + + if ((m > psd_scan->psd_stop_point) || + (n > psd_scan->psd_stop_point)) + break; + + i = 1; + j = 1; + + } + } + + +} + +void halbtc8822b1ant_psd_max_holddata(IN struct btc_coexist *btcoexist, + IN u32 gen_count) +{ + u32 i = 0, i_max = 0, val_max = 0; + + if (gen_count == 1) { + memcpy(psd_scan->psd_report_max_hold, + psd_scan->psd_report, + BT_8822B_1ANT_ANTDET_PSD_POINTS * sizeof(u32)); + + for (i = psd_scan->psd_start_point; + i <= psd_scan->psd_stop_point; i++) { + + } + + psd_scan->psd_max_value_point = 0; + psd_scan->psd_max_value = 0; + + } else { + for (i = psd_scan->psd_start_point; + i <= psd_scan->psd_stop_point; i++) { + if (psd_scan->psd_report[i] > + psd_scan->psd_report_max_hold[i]) + psd_scan->psd_report_max_hold[i] = + psd_scan->psd_report[i]; + + /* search Max Value */ + if (i == psd_scan->psd_start_point) { + i_max = i; + val_max = psd_scan->psd_report_max_hold[i]; + } else { + if (psd_scan->psd_report_max_hold[i] > + val_max) { + i_max = i; + val_max = psd_scan->psd_report_max_hold[i]; + } + } + + + + } + + psd_scan->psd_max_value_point = i_max; + psd_scan->psd_max_value = val_max; + + } + + +} + +u32 halbtc8822b1ant_psd_getdata(IN struct btc_coexist *btcoexist, IN u32 point) +{ + /* reg 0x808[9:0]: FFT data x */ + /* reg 0x808[22]: 0-->1 to get 1 FFT data y */ + /* reg 0x8b4[15:0]: FFT data y report */ + + u32 val = 0, psd_report = 0; + + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + + val &= 0xffbffc00; + val |= point; + + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + val |= 0x00400000; + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + + val = btcoexist->btc_read_4byte(btcoexist, 0x8b4); + + psd_report = val & 0x0000ffff; + + return psd_report; +} + + +void halbtc8822b1ant_psd_sweep_point(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN s32 offset, IN u32 span, IN u32 points, + IN u32 avgnum) +{ + u32 i, val, n, k = 0; + u32 points1 = 0, psd_report = 0; + u32 start_p = 0, stop_p = 0, delta_freq_per_point = 156250; + u32 psd_center_freq = 20 * 10 ^ 6, freq, freq1, freq2; + boolean outloop = false; + u8 flag = 0; + u32 tmp, psd_rep1, psd_rep2; + u32 wifi_original_channel = 1; + + psd_scan->is_psd_running = true; + + do { + switch (flag) { + case 0: /* Get PSD parameters */ + default: + + psd_scan->psd_band_width = 40 * 1000000; + psd_scan->psd_point = points; + psd_scan->psd_start_base = points / 2; + psd_scan->psd_avg_num = avgnum; + psd_scan->real_cent_freq = cent_freq; + psd_scan->real_offset = offset; + psd_scan->real_span = span; + + + points1 = psd_scan->psd_point; + delta_freq_per_point = psd_scan->psd_band_width / + psd_scan->psd_point; + + /* PSD point setup */ + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + val &= 0xffff0fff; + + switch (psd_scan->psd_point) { + case 128: + val |= 0x0; + break; + case 256: + default: + val |= 0x00004000; + break; + case 512: + val |= 0x00008000; + break; + case 1024: + val |= 0x0000c000; + break; + } + + switch (psd_scan->psd_avg_num) { + case 1: + val |= 0x0; + break; + case 8: + val |= 0x00001000; + break; + case 16: + val |= 0x00002000; + break; + case 32: + default: + val |= 0x00003000; + break; + } + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + flag = 1; + break; + case 1: /* calculate the PSD point index from freq/offset/span */ + psd_center_freq = psd_scan->psd_band_width / 2 + + offset * (1000000); + + start_p = psd_scan->psd_start_base + (psd_center_freq - + span * (1000000) / 2) / delta_freq_per_point; + psd_scan->psd_start_point = start_p - + psd_scan->psd_start_base; + + stop_p = psd_scan->psd_start_base + (psd_center_freq + + span * (1000000) / 2) / delta_freq_per_point; + psd_scan->psd_stop_point = stop_p - + psd_scan->psd_start_base - 1; + + flag = 2; + break; + case 2: /* set RF channel/BW/Mode */ + + /* set 3-wire off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x88c); + val |= 0x00300000; + btcoexist->btc_write_4byte(btcoexist, 0x88c, val); + + /* CCK off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x800); + val &= 0xfeffffff; + btcoexist->btc_write_4byte(btcoexist, 0x800, val); + + /* store WiFi original channel */ + wifi_original_channel = btcoexist->btc_get_rf_reg( + btcoexist, BTC_RF_A, 0x18, 0x3ff); + + /* Set RF channel */ + if (cent_freq == 2484) + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x18, 0x3ff, 0xe); + else + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, + 0x18, 0x3ff, (cent_freq - 2412) / 5 + + 1); /* WiFi TRx Mask on */ + + /* Set RF mode = Rx, RF Gain = 0x8a0 */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x0, + 0xfffff, 0x308a0); + + /* Set RF Rx filter corner */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, 0x3e4); + + /* Set TRx mask off */ + /* un-lock TRx Mask setup */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xdd, + 0x80, 0x1); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xdf, + 0x1, 0x1); + + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x0); + + flag = 3; + break; + case 3: + memset(psd_scan->psd_report, 0, + psd_scan->psd_point * sizeof(u32)); + start_p = psd_scan->psd_start_point + + psd_scan->psd_start_base; + stop_p = psd_scan->psd_stop_point + + psd_scan->psd_start_base + 1; + + i = start_p; + + while (i < stop_p) { + if (i >= points1) + psd_report = + halbtc8822b1ant_psd_getdata( + btcoexist, i - points1); + else + psd_report = + halbtc8822b1ant_psd_getdata( + btcoexist, i); + + if (psd_report == 0) + tmp = 0; + else + /* tmp = 20*log10((double)psd_report); */ + /* 20*log2(x)/log2(10), log2Base return theresult of the psd_report*100 */ + tmp = 6 * halbtc8822b1ant_psd_log2base( + btcoexist, psd_report); + + n = i - psd_scan->psd_start_base; + psd_scan->psd_report[n] = tmp; + psd_rep1 = psd_scan->psd_report[n] / 100; + psd_rep2 = psd_scan->psd_report[n] - psd_rep1 * + 100; + + freq = ((cent_freq - 20) * 1000000 + n * + delta_freq_per_point); + freq1 = freq / 1000000; + freq2 = freq / 1000 - freq1 * 1000; + + i++; + + k = 0; + + /* Add Delay between PSD point */ + while (1) { + if (k++ > 20000) + break; + } + + } + + flag = 100; + break; + case 99: /* error */ + + outloop = true; + break; + case 100: /* recovery */ + + /* set 3-wire on */ + val = btcoexist->btc_read_4byte(btcoexist, 0x88c); + val &= 0xffcfffff; + btcoexist->btc_write_4byte(btcoexist, 0x88c, val); + + /* CCK on */ + val = btcoexist->btc_read_4byte(btcoexist, 0x800); + val |= 0x01000000; + btcoexist->btc_write_4byte(btcoexist, 0x800, val); + + /* PSD off */ + val = btcoexist->btc_read_4byte(btcoexist, 0x808); + val &= 0xffbfffff; + btcoexist->btc_write_4byte(btcoexist, 0x808, val); + + /* TRx Mask on */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, + 0xfffff, 0x780); + + /* lock TRx Mask setup */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xdd, + 0x80, 0x0); + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0xdf, + 0x1, 0x0); + + /* Set RF Rx filter corner */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1e, + 0xfffff, 0x0); + + /* restore WiFi original channel */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x18, + 0x3ff, wifi_original_channel); + + outloop = true; + break; + + } + + } while (!outloop); + + + + psd_scan->is_psd_running = false; + + +} + +#if (BTC_COEX_OFFLOAD == 1) +void halbtc8822b1ant_wifi_info_notify(IN struct btc_coexist *btcoexist) +{ + u8 h2c_para[4] = {0}; + u8 opcode_ver = 0; + u8 ap_num = 0; + s32 wifi_rssi = 0; + boolean wifi_busy = false; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, &ap_num); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + h2c_para[0] = ap_num; /* AP number */ + h2c_para[1] = (u8)wifi_busy; /* Busy */ + h2c_para[2] = (u8)wifi_rssi; /* RSSI */ + + btcoexist->btc_coex_h2c_process(btcoexist, COL_OP_WIFI_INFO_NOTIFY, + opcode_ver, &h2c_para[0], 3); +} + +void halbtc8822b1ant_setManual(IN struct btc_coexist *btcoexist, + IN boolean manual) +{ + u8 h2c_para[4] = {0}; + u8 opcode_ver = 0; + u8 set_type = 0; + + if (manual) + set_type = 1; + else + set_type = 0; + + h2c_para[0] = set_type; /* set_type */ + + btcoexist->btc_coex_h2c_process(btcoexist, COL_OP_SET_CONTROL, + opcode_ver, + &h2c_para[0], 1); +} + +/* ************************************************************ + * work around function start with wa_halbtc8822b1ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8822b1ant_ + * ************************************************************ */ + +void ex_halbtc8822b1ant_power_on_setting(IN struct btc_coexist *btcoexist) +{} +void ex_halbtc8822b1ant_pre_load_firmware(IN struct btc_coexist *btcoexist) +{} +void ex_halbtc8822b1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{} +void ex_halbtc8822b1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{} +void ex_halbtc8822b1ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + u8 h2c_para[4] = {0}; + u8 opcode_ver = 0; + u8 ips_notify = 0; + + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + ips_notify = 1; + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + } + + h2c_para[0] = ips_notify; /* IPS notify */ + h2c_para[1] = 0xff; /* LPS notify */ + h2c_para[2] = 0xff; /* RF state notify */ + h2c_para[3] = 0xff; /* pnp notify */ + + btcoexist->btc_coex_h2c_process(btcoexist, + COL_OP_WIFI_POWER_STATE_NOTIFY, + opcode_ver, &h2c_para[0], 4); +} +void ex_halbtc8822b1ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + u8 h2c_para[4] = {0}; + u8 opcode_ver = 0; + u8 lps_notify = 0; + + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + lps_notify = 1; + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + } + + h2c_para[0] = 0xff; /* IPS notify */ + h2c_para[1] = lps_notify; /* LPS notify */ + h2c_para[2] = 0xff; /* RF state notify */ + h2c_para[3] = 0xff; /* pnp notify */ + + btcoexist->btc_coex_h2c_process(btcoexist, + COL_OP_WIFI_POWER_STATE_NOTIFY, + opcode_ver, &h2c_para[0], 4); +} + +void ex_halbtc8822b1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_para[4] = {0}; + u8 opcode_ver = 0; + u8 scan_start = 0; + boolean under_4way = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (BTC_SCAN_START == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify\n"); + BTC_TRACE(trace_buf); + scan_start = 1; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify\n"); + BTC_TRACE(trace_buf); + } + + h2c_para[0] = scan_start; /* scan notify */ + h2c_para[1] = 0xff; /* connect notify */ + h2c_para[2] = 0xff; /* specific packet notify */ + if (under_4way) + h2c_para[3] = 1; /* under 4way progress */ + else + h2c_para[3] = 0; + + btcoexist->btc_coex_h2c_process(btcoexist, COL_OP_WIFI_PROGRESS_NOTIFY, + opcode_ver, &h2c_para[0], 4); +} + +void ex_halbtc8822b1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_para[4] = {0}; + u8 opcode_ver = 0; + u8 connect_start = 0; + boolean under_4way = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + if (BTC_ASSOCIATE_START == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify\n"); + BTC_TRACE(trace_buf); + connect_start = 1; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify\n"); + BTC_TRACE(trace_buf); + } + + h2c_para[0] = 0xff; /* scan notify */ + h2c_para[1] = connect_start; /* connect notify */ + h2c_para[2] = 0xff; /* specific packet notify */ + if (under_4way) + h2c_para[3] = 1; /* under 4way progress */ + else + h2c_para[3] = 0; + + btcoexist->btc_coex_h2c_process(btcoexist, COL_OP_WIFI_PROGRESS_NOTIFY, + opcode_ver, &h2c_para[0], 4); +} + +void ex_halbtc8822b1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u32 wifi_bw; + u8 wifi_central_chnl; + u8 h2c_para[5] = {0}; + u8 opcode_ver = 0; + u8 port = 0, connected = 0, freq = 0, bandwidth = 0, iot_peer = 0; + boolean wifi_under_5g = false; + + if (BTC_MEDIA_CONNECT == type) + connected = 1; + + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + bandwidth = (u8)wifi_bw; + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) + freq = 1; + else + freq = 0; + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + btcoexist->btc_get(btcoexist, BTC_GET_U1_IOT_PEER, &iot_peer); + + h2c_para[0] = (connected << 4) | + port; /* port need to be implemented in the future (p2p port, ...) */ + h2c_para[1] = (freq << 4) | bandwidth; + h2c_para[2] = wifi_central_chnl; + h2c_para[3] = iot_peer; + btcoexist->btc_coex_h2c_process(btcoexist, COL_OP_WIFI_STATUS_NOTIFY, + opcode_ver, &h2c_para[0], 4); +} + +void ex_halbtc8822b1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_para[4] = {0}; + u8 opcode_ver = 0; + u8 connect_start = 0; + boolean under_4way = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + h2c_para[0] = 0xff; /* scan notify */ + h2c_para[1] = 0xff; /* connect notify */ + h2c_para[2] = type; /* specific packet notify */ + if (under_4way) + h2c_para[3] = 1; /* under 4way progress */ + else + h2c_para[3] = 0; + + btcoexist->btc_coex_h2c_process(btcoexist, COL_OP_WIFI_PROGRESS_NOTIFY, + opcode_ver, &h2c_para[0], 4); +} + +void ex_halbtc8822b1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{} +void ex_halbtc8822b1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_para[4] = {0}; + u8 opcode_ver = 0; + u8 rfstate_notify = 0; + + if (BTC_RF_ON == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned ON!!\n"); + BTC_TRACE(trace_buf); + rfstate_notify = 1; + } else if (BTC_RF_OFF == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned OFF!!\n"); + BTC_TRACE(trace_buf); + } + + h2c_para[0] = 0xff; /* IPS notify */ + h2c_para[1] = 0xff; /* LPS notify */ + h2c_para[2] = rfstate_notify; /* RF state notify */ + h2c_para[3] = 0xff; /* pnp notify */ + + btcoexist->btc_coex_h2c_process(btcoexist, + COL_OP_WIFI_POWER_STATE_NOTIFY, + opcode_ver, &h2c_para[0], 4); +} + +void ex_halbtc8822b1ant_halt_notify(IN struct btc_coexist *btcoexist) +{} +void ex_halbtc8822b1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + u8 h2c_para[4] = {0}; + u8 opcode_ver = 0; + u8 pnp_notify = 0; + + if (BTC_WIFI_PNP_SLEEP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + pnp_notify = 1; + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + } + + h2c_para[0] = 0xff; /* IPS notify */ + h2c_para[1] = 0xff; /* LPS notify */ + h2c_para[2] = 0xff; /* RF state notify */ + h2c_para[3] = pnp_notify; /* pnp notify */ + + btcoexist->btc_coex_h2c_process(btcoexist, + COL_OP_WIFI_POWER_STATE_NOTIFY, + opcode_ver, &h2c_para[0], 4); +} + +void ex_halbtc8822b1ant_coex_dm_reset(IN struct btc_coexist *btcoexist) +{} +void ex_halbtc8822b1ant_periodical(IN struct btc_coexist *btcoexist) +{ + + halbtc8822b1ant_wifi_info_notify(btcoexist); +} + +void ex_halbtc8822b1ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_stack_info *stack_info = &btcoexist->stack_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u16 u16tmp[4]; + u32 u32tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + u32 fw_ver = 0, bt_patch_ver = 0, bt_coex_ver = 0; + static u8 pop_report_in_10s = 0; + u32 phyver = 0; + boolean lte_coex_on = false; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + if (btcoexist->stop_coex_dm) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (psd_scan->ant_det_try_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %s / %d", + "Ant PG Num/ Mech/ Pos/ RFE", + board_info->pg_ant_num, board_info->btdm_ant_num, + (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT + ? "Main" : "Aux"), + rfe_type->rfe_module_type); + CL_PRINTF(cli_buf); + } else { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %s/ %d (%d/%d/%d)", + "Ant PG Num/ Mech(Ant_Det)/ Pos/ RFE", + board_info->pg_ant_num, + board_info->btdm_ant_num_by_ant_det, + (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT + ? "Main" : "Aux"), + rfe_type->rfe_module_type, + psd_scan->ant_det_try_count, + psd_scan->ant_det_fail_count, + psd_scan->ant_det_result); + CL_PRINTF(cli_buf); + + if (board_info->btdm_ant_det_finish) { + if (psd_scan->ant_det_result != 12) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "Ant Det PSD Value", + psd_scan->ant_det_peak_val); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d", + "Ant Det PSD Value", + psd_scan->ant_det_psd_scan_peak_val / 100); + + CL_PRINTF(cli_buf); + } + } + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%x/ 0x%x/ 0x%x(%d)", + "CoexVer/ FwVer/ PatchVer", + glcoex_ver_date_8822b_1ant, glcoex_ver_8822b_1ant, fw_ver, + bt_patch_ver, bt_patch_ver); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "Wifi channel informed to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s", + "WifibHiPri/ Ccklock/ CckEverLock", + (coex_sta->wifi_is_high_pri_task ? "Yes" : "No"), + (coex_sta->cck_lock ? "Yes" : "No"), + (coex_sta->cck_ever_lock ? "Yes" : "No")); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + pop_report_in_10s++; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d/ %d] ", + "BT [status/ rssi/ retryCnt/ popCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") + : ((BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8822B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi - 100, coex_sta->bt_retry_cnt, + coex_sta->pop_event_cnt); + CL_PRINTF(cli_buf); + + if (pop_report_in_10s >= 5) { + coex_sta->pop_event_cnt = 0; + pop_report_in_10s = 0; + } + + if (coex_sta->num_of_profile != 0) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s%s%s%s%s", + "Profiles", + ((bt_link_info->a2dp_exist) ? "A2DP," : ""), + ((bt_link_info->sco_exist) ? "SCO," : ""), + ((bt_link_info->hid_exist) ? + ((coex_sta->hid_busy_num >= 2) ? "HID(4/18)," : "HID(2/18),") : ""), + ((bt_link_info->pan_exist) ? "PAN," : ""), + ((coex_sta->voice_over_HOGP) ? "Voice" : "")); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = None", "Profiles"); + + CL_PRINTF(cli_buf); + + if (bt_link_info->a2dp_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %d/ %s", + "A2DP Rate/Bitpool/Auto_Slot", + ((coex_sta->is_A2DP_3M) ? "3M" : "No_3M"), + coex_sta->a2dp_bit_pool, + ((coex_sta->is_autoslot) ? "On" : "Off")); + CL_PRINTF(cli_buf); + } + + if (bt_link_info->hid_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "HID PairNum/Forbid_Slot", + coex_sta->hid_pair_cnt, + coex_sta->forbidden_slot + ); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ 0x%x/ 0x%x", + "Role/IgnWlanAct/Feature/BLEScan", + ((bt_link_info->slave_role) ? "Slave" : "Master"), + ((coex_dm->cur_ignore_wlan_act) ? "Yes":"No"), + coex_sta->bt_coex_supported_feature, + coex_sta->bt_ble_scan_type); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", + "ReInit/ReLink/IgnWlact/Page/NameReq", + coex_sta->cnt_ReInit, + coex_sta->cnt_setupLink, + coex_sta->cnt_IgnWlanAct, + coex_sta->cnt_Page, + coex_sta->cnt_RemoteNameReq + ); + CL_PRINTF(cli_buf); + + halbtc8822b1ant_read_score_board(btcoexist, &u16tmp[0]); + + if ((coex_sta->bt_reg_vendor_ae == 0xffff) || + (coex_sta->bt_reg_vendor_ac == 0xffff)) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = x/ x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", u16tmp[0]); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", + ((coex_sta->bt_reg_vendor_ae & BIT(4))>>4), + coex_sta->bt_reg_vendor_ac & 0x3, u16tmp[0]); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8822B_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8822b_1ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + + if (btcoexist->manual_control) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanisms] (before Manual)============"); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanisms]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "SM[LowPenaltyRA]", + coex_dm->cur_low_penalty_ra); + CL_PRINTF(cli_buf); + + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (%s,%s)", + "PS TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + (coex_dm->cur_ps_tdma_on ? "On" : "Off"), + (coex_dm->auto_tdma_adjust ? "Adj" : "Fix")); + + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "WL/BT Coex Table Type", + coex_sta->coex_table_type); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x778/0x6cc/IgnWlanAct", + u8tmp[0], u32tmp[0], coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa0); + u32tmp[1] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa4); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "LTE Coex Table W_L/B_L", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa8); + u32tmp[1] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xac); + u32tmp[2] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xb0); + u32tmp[3] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xb4); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "LTE Break Table W_L/B_L/L_W/L_B", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff, + u32tmp[2] & 0xffff, u32tmp[3] & 0xffff); + CL_PRINTF(cli_buf); + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); +/* + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); +*/ + + u32tmp[0] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp[1] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x73); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %s", + "LTE CoexOn/Path Ctrl Owner", + (int)((u32tmp[0]&BIT(7)) >> 7), + ((u8tmp[0]&BIT(2)) ? "WL" : "BT")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "LTE 3Wire/OPMode/UART/UARTMode", + (int)((u32tmp[0]&BIT(6)) >> 6), + (int)((u32tmp[0] & (BIT(5) | BIT(4))) >> 4), + (int)((u32tmp[0]&BIT(3)) >> 3), + (int)(u32tmp[0] & (BIT(2) | BIT(1) | BIT(0)))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %s", + "GNT_WL_SWCtrl/GNT_BT_SWCtrl/Dbg", + (int)((u32tmp[0]&BIT(12)) >> 12), + (int)((u32tmp[0]&BIT(14)) >> 14), + ((u8tmp[0]&BIT(3)) ? "On" : "Off")); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "GNT_WL/GNT_BT/LTE_Busy/UART_Busy", + (int)((u32tmp[0]&BIT(2)) >> 2), + (int)((u32tmp[0]&BIT(3)) >> 3), + (int)((u32tmp[0]&BIT(1)) >> 1), (int)(u32tmp[0]&BIT(0))); + CL_PRINTF(cli_buf); + + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x4c6); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x4c6[4]/0x40[5] (WL/BT PTA)", + (int)((u8tmp[0] & BIT(4)) >> 4), + (int)((u8tmp[1] & BIT(5)) >> 5)); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x953); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ %s", + "0x550(bcn ctrl)/0x522/4-RxAGC", + u32tmp[0], u8tmp[0], (u8tmp[1] & 0x2) ? "On" : "Off"); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xda0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xda4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0xda8); + u32tmp[3] = btcoexist->btc_read_4byte(btcoexist, 0xcf0); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xa5b); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xa5c); + + fa_ofdm = ((u32tmp[0] & 0xffff0000) >> 16) + ((u32tmp[1] & 0xffff0000) + >> 16) + (u32tmp[1] & 0xffff) + (u32tmp[2] & 0xffff) + + ((u32tmp[3] & 0xffff0000) >> 16) + (u32tmp[3] & + 0xffff); + fa_cck = (u8tmp[0] << 8) + u8tmp[1]; + + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xc50); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0xc50/OFDM-CCA/OFDM-FA/CCK-FA", + u32tmp[1] & 0xff, u32tmp[0] & 0xffff, fa_ofdm, fa_cck); + CL_PRINTF(cli_buf); + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11n-Agg", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_agg); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11n-Agg", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_agg); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(high-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(low-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); +#if (BT_AUTO_REPORT_ONLY_8822B_1ANT == 1) + /* halbtc8822b1ant_monitor_bt_ctr(btcoexist); */ +#endif + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} +void ex_halbtc8822b1ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{} +void ex_halbtc8822b1ant_display_ant_detection(IN struct btc_coexist *btcoexist) +{} +void ex_halbtc8822b1ant_dbg_control(IN struct btc_coexist *btcoexist, + IN u8 op_code, IN u8 op_len, IN u8 *pdata) +{ + switch (op_code) { + case BTC_DBG_SET_COEX_MANUAL_CTRL: { + boolean manual = (boolean) *pdata; + + halbtc8822b1ant_setManual(btcoexist, manual); + } + break; + default: + break; + } +} + +#else +void ex_halbtc8822b1ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Execute 8822b 1-Ant PowerOn Setting!! xxxxxxxxxxxxxxxx\n"); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Ant Det Finish = %s, Ant Det Number = %d\n", + board_info->btdm_ant_det_finish ? "Yes" : "No", + board_info->btdm_ant_num_by_ant_det); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = true; + + /* enable BB, REG_SYS_FUNC_EN such that we can write 0x948 correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT(0) | BIT(1)); + + /* set Path control owner to WiFi */ + halbtc8822b1ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8822B_1ANT_PCO_WLSIDE); + + /* set GNT_BT to high */ + halbtc8822b1ant_ltecoex_set_gnt_bt(btcoexist, + BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to low */ + halbtc8822b1ant_ltecoex_set_gnt_wl(btcoexist, + BT_8822B_1ANT_GNT_BLOCK_RFC_BB, + BT_8822B_1ANT_GNT_CTRL_BY_SW, + BT_8822B_1ANT_SIG_STA_SET_TO_LOW); + + /* set WLAN_ACT = 0 */ + /* btcoexist->btc_write_1byte(btcoexist, 0x76e, 0x4); */ + + /* SD1 Chunchu red x issue */ + btcoexist->btc_write_1byte(btcoexist, 0xff1a, 0x0); + + halbtc8822b1ant_enable_gnt_to_gpio(btcoexist, true); + + /* */ + /* S0 or S1 setting and Local register setting(By the setting fw can get ant number, S0/S1, ... info) */ + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + + u8tmp = 0; + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + + if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, u8tmp); + + BTC_TRACE(trace_buf); + + +} + +void ex_halbtc8822b1ant_power_on_setting_without_bt(IN struct btc_coexist + *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + " 8822b 1-Ant PowerOn Setting without bt\n"); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = true; + + /* enable BB, REG_SYS_FUNC_EN such that we can write 0x948 correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT(0) | BIT(1)); + + + /* SD1 Chunchu red x issue */ + btcoexist->btc_write_1byte(btcoexist, 0xff1a, 0x0); + + u8tmp = 0; + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + + if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, u8tmp); + + + +} + + +void ex_halbtc8822b1ant_pre_load_firmware(IN struct btc_coexist *btcoexist) +{ +} + +void ex_halbtc8822b1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (ini hw config) **********\n"); + + halbtc8822b1ant_init_hw_config(btcoexist, true, wifi_only); + btcoexist->stop_coex_dm = false; +} + +void ex_halbtc8822b1ant_init_hw_config_without_bt(IN struct btc_coexist + *btcoexist, + IN boolean wifi_only) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (ini hw config) **********\n"); + + halbtc8822b1ant_init_hw_config_without_bt(btcoexist, true, wifi_only); + btcoexist->stop_coex_dm = true; +} + +void ex_halbtc8822b1ant_antenna_switch_without_bt(IN struct btc_coexist + *btcoexist) +{ + + boolean wifi_under_5g = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x3, 1); + + else + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0xcbd, 0x3, 2); + + +} + +void ex_halbtc8822b1ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->stop_coex_dm = false; + + halbtc8822b1ant_init_coex_dm(btcoexist); + + halbtc8822b1ant_query_bt_info(btcoexist); +} + +void ex_halbtc8822b1ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, bt_info_ext, ps_tdma_case = 0; + u16 u16tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + u32 u32tmp[4]; + u32 fa_of_dm; + u32 fw_ver = 0, bt_patch_ver = 0; + static u8 pop_report_in_10s = 0; + u32 phyver = 0; + /*u32 pnp_wake_cnt=0;*/ + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (display coexinfo) **********\n"); + BTC_TRACE(trace_buf); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** displaycoexinfostart, 0xcb4/0xcbd = 0x%x/0x%x\n", + btcoexist->btc_read_1byte(btcoexist, 0xcb4), + btcoexist->btc_read_1byte(btcoexist, 0xcbd)); + BTC_TRACE(trace_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (btcoexist->stop_coex_dm) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Coex is STOPPED]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (psd_scan->ant_det_try_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %d/ %d", + "Ant PG Num/ Mech/ Pos/ RFE", + board_info->pg_ant_num, board_info->btdm_ant_num, + board_info->btdm_ant_pos, + rfe_type->rfe_module_type); + CL_PRINTF(cli_buf); + } else { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %d/ %d (%d/%d/%d)", + "Ant PG Num/ Mech(Ant_Det)/ Pos/ RFE", + board_info->pg_ant_num, + board_info->btdm_ant_num_by_ant_det, + board_info->btdm_ant_pos, + rfe_type->rfe_module_type, + psd_scan->ant_det_try_count, + psd_scan->ant_det_fail_count, + psd_scan->ant_det_result); + CL_PRINTF(cli_buf); + + if (board_info->btdm_ant_det_finish) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "Ant Det PSD Value", + psd_scan->ant_det_peak_val); + CL_PRINTF(cli_buf); + } + } + /*btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver);*/ + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8822b_1ant, glcoex_ver_8822b_1ant, + glcoex_ver_btdesired_8822b_1ant, + ((coex_sta->bt_coex_supported_version & 0xff00) >> + 8), + (((coex_sta->bt_coex_supported_version & 0xff00) >> + 8) >= + glcoex_ver_btdesired_8822b_1ant ? "Match" : + "Mis-Match")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ v%d/ %c", + "W_FW/ B_FW/ Phy/ Kt", + fw_ver, bt_patch_ver, phyver, + coex_sta->cut_version + 65); + CL_PRINTF(cli_buf); + + + + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "Wifi channel informed to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s", + "WifibHiPri/ Ccklock/ CckEverLock", + (coex_sta->wifi_is_high_pri_task ? "Yes" : "No"), + (coex_sta->cck_lock ? "Yes" : "No"), + (coex_sta->cck_ever_lock ? "Yes" : "No")); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + pop_report_in_10s++; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s/ %d/ %d/ %d] ", + "BT [status/ rssi/ retryCnt/ popCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page scan") + : ((BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8822B_1ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi - 100, coex_sta->bt_retry_cnt, + coex_sta->pop_event_cnt); + CL_PRINTF(cli_buf); + /*bt rssi */ + /*bt pop_even_cnt : bt retry*/ + + if (pop_report_in_10s >= 5) { + coex_sta->pop_event_cnt = 0; + pop_report_in_10s = 0; + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d / %d / %d / %d / %d", + "SCO/HID/PAN/A2DP/Hi-Pri", + bt_link_info->sco_exist, bt_link_info->hid_exist, + bt_link_info->pan_exist, bt_link_info->a2dp_exist, + bt_link_info->bt_hi_pri_link_exist); + CL_PRINTF(cli_buf); + + { + bt_info_ext = coex_sta->bt_info_ext; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s / %s / %d/ %x/ %02x", + "Role/A2DP Rate/Bitpool/Feature/Ver", + ((bt_link_info->slave_role) ? "Slave" : "Master"), + (bt_info_ext & BIT(0)) ? "BR" : "EDR", + coex_sta->a2dp_bit_pool, + coex_sta->bt_coex_supported_feature, + ((coex_sta->bt_coex_supported_version & 0xff00) >> 8)); + CL_PRINTF(cli_buf); + } + + /*bt info*/ + for (i = 0; i < BT_INFO_SRC_8822B_1ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8822b_1ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + + if (btcoexist->manual_control) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanisms] (before Manual)============"); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanisms]============"); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "SM[LowPenaltyRA]", + coex_dm->cur_low_penalty_ra); + CL_PRINTF(cli_buf); + + /*(ps)tdma*/ + ps_tdma_case = coex_dm->cur_ps_tdma; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x case-%d (%s,%s)", + "PS TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + (coex_dm->cur_ps_tdma_on ? "On" : "Off"), + (coex_dm->auto_tdma_adjust ? "Adj" : "Fix")); + + CL_PRINTF(cli_buf); + + /*coex table type*/ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", + "WL/BT Coex Table Type", + coex_sta->coex_table_type); + CL_PRINTF(cli_buf); + + /*coex table :0x6c0 0x6c4 , break table: 0x6c8*/ + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x6c0/0x6c4/0x6c8(coexTable)", + u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + /*PTA : 0x778=1/3/d , WL BA,RTS,CTS :0x6cc H/L pri */ + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x778/0x6cc/IgnWlanAct", + u8tmp[0], u32tmp[0], coex_dm->cur_ignore_wlan_act); + CL_PRINTF(cli_buf); + + + /*LTE : WL/LTE coex table : 0xa0 */ + + u32tmp[0] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa0); + + /*LTE : BT/LTE coex table : 0xa4 */ + u32tmp[1] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa4); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "LTE Coex Table W_L/B_L", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff); + CL_PRINTF(cli_buf); + + /*LTE : WL/LTE break table : 0xa8 */ + u32tmp[0] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xa8); + /*LTE : WL/LTE break table : 0xac */ + u32tmp[1] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xac); + /*LTE : LTE/WL break table : 0xb0 */ + u32tmp[2] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xb0); + /*LTE : LTE/BT break table : 0xb4 */ + u32tmp[3] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, + 0xb4); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "LTE Break Table W_L/B_L/L_W/L_B", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff, + u32tmp[2] & 0xffff, u32tmp[3] & 0xffff); + CL_PRINTF(cli_buf); + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + + /*ANT setting*/ + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0xcb4); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0xcbd); + u8tmp[3] = btcoexist->btc_read_1byte(btcoexist, 0x1991); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0xcb4/0xcbd/0x1991", + u8tmp[1], u8tmp[2], u8tmp[3]); + CL_PRINTF(cli_buf); + + /*LTE on/off , Path ctrl owner*/ + /*sy add*/ + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x73); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x64); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", + "0x73/ 0x4c/ 0x64[0]", u8tmp[0], + (u32tmp[0] & (BIT(24) | BIT(23))) >> 23, + u8tmp[1] & 0x1); + CL_PRINTF(cli_buf); + + + u32tmp[0] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %s", + "LTE CoexOn/Path Ctrl Owner", + (int)((u32tmp[0]&BIT(7)) >> 7), + ((u8tmp[0]&BIT(2)) ? "WL" : "BT")); + CL_PRINTF(cli_buf); + + /*LTE mode*/ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "LTE 3Wire/OPMode/UART/UARTMode", + (int)((u32tmp[0]&BIT(6)) >> 6), + (int)((u32tmp[0] & (BIT(5) | BIT(4))) >> 4), + (int)((u32tmp[0]&BIT(3)) >> 3), + (int)(u32tmp[0] & (BIT(2) | BIT(1) | BIT(0)))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %s", + "GNT_WL_SWCtrl/GNT_BT_SWCtrl/Dbg", + (int)((u32tmp[0]&BIT(12)) >> 12), + (int)((u32tmp[0]&BIT(14)) >> 14), + ((u8tmp[0]&BIT(3)) ? "On" : "Off")); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8822b1ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "GNT_WL/GNT_BT/LTE_Busy/UART_Busy", + (int)((u32tmp[0]&BIT(2)) >> 2), + (int)((u32tmp[0]&BIT(3)) >> 3), + (int)((u32tmp[0]&BIT(1)) >> 1), (int)(u32tmp[0]&BIT(0))); + CL_PRINTF(cli_buf); + + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x4c6); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "0x4c6[4]/0x40[5] (WL/BT PTA)", + (int)((u8tmp[0] & BIT(4)) >> 4), + (int)((u8tmp[1] & BIT(5)) >> 5)); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x953); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0xc50); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ %s/ 0x%x", + "0x550/0x522/4-RxAGC/0xc50", + u32tmp[0], u8tmp[0], (u8tmp[1] & 0x2) ? "On" : "Off", u8tmp[2]); + CL_PRINTF(cli_buf); + + fa_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_OFDM); + fa_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_CCK); + cca_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_OFDM); + cca_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_CCK); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", + cca_cck, fa_cck, cca_ofdm, fa_ofdm); + CL_PRINTF(cli_buf); + + +#if 1 + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11ac", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11ac", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + CL_PRINTF(cli_buf); +#endif + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s", + "Wifi-HiPri/ Ccklock/ CckEverLock", + (coex_sta->wifi_is_high_pri_task ? "Yes" : "No"), + (coex_sta->cck_lock ? "Yes" : "No"), + (coex_sta->cck_ever_lock ? "Yes" : "No")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(high-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + /*0x774:bt low pri trx*/ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(low-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); + + halbtc8822b1ant_read_score_board(btcoexist, &u16tmp[0]); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %04x", + "ScoreBoard[14:0] (from BT)", u16tmp[0]); + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** displaycoexinfo end, 0xcb4/0xcbd = 0x%x/0x%x\n", + btcoexist->btc_read_1byte(btcoexist, 0xcb4), + btcoexist->btc_read_1byte(btcoexist, 0xcbd)); + BTC_TRACE(trace_buf); + /* + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** pnp_wake_cnt = %d\n", pnp_wake_cnt); + BTC_TRACE(trace_buf); + */ +} + + +void ex_halbtc8822b1ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + + if (BTC_IPS_ENTER == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + + /* Write WL "Active" in Score-board for LPS off */ + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ACTIVE, false); + + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ONOFF, false); + + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_WLAN_OFF); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + } else if (BTC_IPS_LEAVE == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ACTIVE, true); + + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ONOFF, true); + + /*leave IPS : run ini hw config (exclude wifi only)*/ + halbtc8822b1ant_init_hw_config(btcoexist, false, false); + /*sw all off*/ + halbtc8822b1ant_init_coex_dm(btcoexist); + /*leave IPS : Query bt info*/ + halbtc8822b1ant_query_bt_info(btcoexist); + + coex_sta->under_ips = false; + } +} + +void ex_halbtc8822b1ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + + if (coex_sta->force_lps_on == true) { /* LPS No-32K */ + /* Write WL "Active" in Score-board for PS-TDMA */ + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ACTIVE, true); + + } else { /* LPS-32K, need check if this h2c 0x71 can work?? (2015/08/28) */ + /* Write WL "Non-Active" in Score-board for Native-PS */ + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ACTIVE, false); + + } + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + + /* Write WL "Active" in Score-board for LPS off */ + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ACTIVE, true); + + } +} + + +void ex_halbtc8822b1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false; + boolean wifi_under_5g = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN notify()\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if (BTC_SCAN_START == type) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (scan_notify_5g_scan_start) **********\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_action_wifi_under5g(btcoexist); + return; + } + + /* under 2.4G */ + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (scan_notify_2g_scan_start) **********\n"); + BTC_TRACE(trace_buf); + + if (!wifi_connected) { /* non-connected scan */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** wifi is not connected scan **********\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_action_wifi_not_connected_scan( + btcoexist); + } else { /* wifi is connected */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** wifi is connected scan **********\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_action_wifi_connected_scan( + btcoexist); + } + + return; + } + + if (BTC_SCAN_START_2G == type) { + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (scan_notify_2g_sacn_start_for_switch_band_used) **********\n"); + BTC_TRACE(trace_buf); + + if (!wifi_connected) { /* non-connected scan */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** wifi is not connected **********\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_action_wifi_not_connected_scan( + btcoexist); + } else { /* wifi is connected */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** wifi is connected **********\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_action_wifi_connected_scan(btcoexist); + } + } else { + coex_sta->wifi_is_high_pri_task = false; + + /*WL scan finish , then get and update sacn ap numbers */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (scan_finish_notify) **********\n"); + BTC_TRACE(trace_buf); + + if (!wifi_connected) /* non-connected scan */ + halbtc8822b1ant_action_wifi_not_connected(btcoexist); + else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** scan_finish_notify wifi is connected **********\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_action_wifi_connected(btcoexist); + } + } +} + + + +void ex_halbtc8822b1ant_scan_notify_without_bt(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + + boolean wifi_under_5g = false; + + if (BTC_SCAN_START == type) { + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x3, 1); + return; + } + + /* under 2.4G */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x3, 2); + return; + } + if (BTC_SCAN_START_2G == type) + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, 0x3, 2); +} + +void ex_halbtc8822b1ant_switchband_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + + boolean wifi_connected = false; + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (switchband_notify) **********\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + + if (type == BTC_SWITCH_TO_5G) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (switchband_notify BTC_SWITCH_TO_5G) **********\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_action_wifi_under5g(btcoexist); + return; + } else if (type == BTC_SWITCH_TO_24G_NOFORSCAN) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (switchband_notify BTC_SWITCH_TO_2G (no for scan)) **********\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_run_coexist_mechanism(btcoexist); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (switchband_notify BTC_SWITCH_TO_2G) **********\n"); + BTC_TRACE(trace_buf); + + ex_halbtc8822b1ant_scan_notify(btcoexist, + BTC_SCAN_START_2G); + } + +} + + +void ex_halbtc8822b1ant_switchband_notify_without_bt(IN struct btc_coexist + *btcoexist, + IN u8 type) +{ + boolean wifi_under_5g = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (type == BTC_SWITCH_TO_5G) { + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x3, 1); + return; + } else if (type == BTC_SWITCH_TO_24G_NOFORSCAN) { + + if (wifi_under_5g) + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x3, 1); + + else + btcoexist->btc_write_1byte_bitmask(btcoexist, + 0xcbd, 0x3, 2); + } else { + + ex_halbtc8822b1ant_scan_notify_without_bt(btcoexist, + BTC_SCAN_START_2G); + } + +} + +void ex_halbtc8822b1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (connect notify) **********\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_SCAN, true); + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + + if ((BTC_ASSOCIATE_5G_START == type) || + (BTC_ASSOCIATE_5G_FINISH == type)) { + + if (BTC_ASSOCIATE_5G_START == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (5G associate start notify) **********\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_action_wifi_under5g(btcoexist); + + } else if (BTC_ASSOCIATE_5G_FINISH == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (5G associate finish notify) **********\n"); + BTC_TRACE(trace_buf); + + } + + return; + + } + + + if (BTC_ASSOCIATE_START == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 2G CONNECT START notify\n"); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + coex_dm->arp_cnt = 0; + + halbtc8822b1ant_action_wifi_not_connected_asso_auth(btcoexist); + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 2G CONNECT Finish notify\n"); + BTC_TRACE(trace_buf); + coex_sta->wifi_is_high_pri_task = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (!wifi_connected) /* non-connected scan */ + halbtc8822b1ant_action_wifi_not_connected(btcoexist); + else + halbtc8822b1ant_action_wifi_connected(btcoexist); + } + +} + +void ex_halbtc8822b1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_under_b_mode = false; + boolean wifi_under_5g = false; + u32 cnt_bt_cal_chk = 0; + boolean is_in_mp_mode = false; + u8 u8tmp = 0; + u32 u32tmp1 = 0, u32tmp2 = 0; + + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + + + + if (BTC_MEDIA_CONNECT == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 2g media connect notify"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ACTIVE, true); + + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 5g media notify\n"); +BTC_TRACE(trace_buf); + + halbtc8822b1ant_action_wifi_under5g(btcoexist); + return; + } + /* Force antenna setup for no scan result issue */ + halbtc8822b1ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_2G_RUNTIME); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (media status notity under b mode) **********\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + /* btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x10); */ /*CCK Tx */ + /* btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x10); */ /*CCK Rx */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (media status notity not under b mode) **********\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } + + coex_dm->backup_arfr_cnt1 = btcoexist->btc_read_4byte(btcoexist, + 0x430); + coex_dm->backup_arfr_cnt2 = btcoexist->btc_read_4byte(btcoexist, + 0x434); + coex_dm->backup_retry_limit = btcoexist->btc_read_2byte( + btcoexist, 0x42a); + coex_dm->backup_ampdu_max_time = btcoexist->btc_read_1byte( + btcoexist, 0x456); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 2g media disconnect notify\n"); + BTC_TRACE(trace_buf); + coex_dm->arp_cnt = 0; + + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ACTIVE, false); + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + + coex_sta->cck_ever_lock = false; + } + + halbtc8822b1ant_update_wifi_channel_info(btcoexist, type); + +} + +void ex_halbtc8822b1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean under_4way = false, wifi_under_5g = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 5g special packet notify\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_action_wifi_under5g(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (under_4way) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ---- under_4way!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } else if (BTC_PACKET_ARP == type) { + + coex_dm->arp_cnt++; + + if (coex_sta->wifi_is_high_pri_task) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ARP notify -cnt = %d\n", + coex_dm->arp_cnt); + BTC_TRACE(trace_buf); + } + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet DHCP or EAPOL notify [Type = %d]\n", + type); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } + + if (coex_sta->wifi_is_high_pri_task) + halbtc8822b1ant_action_wifi_connected_specific_packet( + btcoexist); + +} + +void ex_halbtc8822b1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 bt_info = 0; + u8 i, rsp_source = 0; + boolean bt_busy = false; + boolean wifi_connected = false; + boolean wifi_under_5g = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + coex_sta->c2h_bt_info_req_sent = false; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (BtInfo Notify) **********\n"); + BTC_TRACE(trace_buf); + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8822B_1ANT_MAX) + rsp_source = BT_INFO_SRC_8822B_1ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt info[%d], length=%d, hex data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + if (i == 1) + bt_info = tmp_buf[i]; + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + + if (BT_INFO_SRC_8822B_1ANT_WIFI_FW != rsp_source) { + + /* if 0xff, it means BT is under WHCK test */ + if (bt_info == 0xff) + coex_sta->bt_whck_test = true; + else + coex_sta->bt_whck_test = false; + + coex_sta->bt_retry_cnt = /* [3:0] */ + coex_sta->bt_info_c2h[rsp_source][2] & 0xf; + + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->bt_info_c2h[rsp_source][2] & 0x20) + coex_sta->c2h_bt_page = true; + else + coex_sta->c2h_bt_page = false; + + if (coex_sta->bt_info_c2h[rsp_source][2] & 0x80) + coex_sta->bt_create_connection = true; + else + coex_sta->bt_create_connection = false; + + /* unit: %, value-100 to translate to unit: dBm */ + coex_sta->bt_rssi = coex_sta->bt_info_c2h[rsp_source][3] * 2 + + 10; + + /* coex_sta->bt_info_c2h[rsp_source][3] * 2 - 90; */ + + if ((coex_sta->bt_info_c2h[rsp_source][1] & 0x49) == 0x49) { + coex_sta->a2dp_bit_pool = + coex_sta->bt_info_c2h[rsp_source][6]; + } else + coex_sta->a2dp_bit_pool = 0; + + if (coex_sta->bt_info_c2h[rsp_source][1] & 0x9) + coex_sta->acl_busy = true; + else + coex_sta->acl_busy = false; + + coex_sta->bt_info_ext = + coex_sta->bt_info_c2h[rsp_source][4]; + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + + if ((!btcoexist->manual_control) && + (!btcoexist->stop_coex_dm)) { + + /* Re-Init */ + if (coex_sta->bt_info_ext & BIT(1)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + btcoexist->btc_get(btcoexist, + BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + if (wifi_connected) + halbtc8822b1ant_update_wifi_channel_info( + btcoexist, + BTC_MEDIA_CONNECT); + else + halbtc8822b1ant_update_wifi_channel_info( + btcoexist, + BTC_MEDIA_DISCONNECT); + } + + /* If Ignore_WLanAct && not SetUp_Link */ + if ((coex_sta->bt_info_ext & BIT(3)) && + (!(coex_sta->bt_info_ext & BIT(2)))) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8822b1ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, + false); + } + } + /* check BIT2 first ==> check if bt is under inquiry or page scan */ + if (bt_info & BT_INFO_8822B_1ANT_B_INQ_PAGE) + coex_sta->c2h_bt_inquiry_page = true; + else + coex_sta->c2h_bt_inquiry_page = false; + } + + coex_sta->num_of_profile = 0; + + /* set link exist status */ + if (!(bt_info & BT_INFO_8822B_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + + coex_sta->bt_hi_pri_link_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (bt_info & BT_INFO_8822B_1ANT_B_FTP) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->pan_exist = false; + if (bt_info & BT_INFO_8822B_1ANT_B_A2DP) { + coex_sta->a2dp_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->a2dp_exist = false; + if (bt_info & BT_INFO_8822B_1ANT_B_HID) { + coex_sta->hid_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->hid_exist = false; + if (bt_info & BT_INFO_8822B_1ANT_B_SCO_ESCO) { + coex_sta->sco_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->sco_exist = false; + + } + + halbtc8822b1ant_update_bt_link_info(btcoexist); + + bt_info = bt_info & + 0x1f; /* mask profile bit for connect-ilde identification ( for CSR case: A2DP idle --> 0x41) */ + + if (!(bt_info & BT_INFO_8822B_1ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info == + BT_INFO_8822B_1ANT_B_CONNECTION) { /* connection exists but no busy */ + coex_dm->bt_status = BT_8822B_1ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + BTC_TRACE(trace_buf); + } else if ((bt_info & BT_INFO_8822B_1ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8822B_1ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8822B_1ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + BTC_TRACE(trace_buf); + } else if (bt_info & BT_INFO_8822B_1ANT_B_ACL_BUSY) { + if (BT_8822B_1ANT_BT_STATUS_ACL_BUSY != coex_dm->bt_status) + coex_dm->bt_status = BT_8822B_1ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + BTC_TRACE(trace_buf); + } else { + coex_dm->bt_status = BT_8822B_1ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + BTC_TRACE(trace_buf); + } + + if ((BT_8822B_1ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8822B_1ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); + + halbtc8822b1ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8822b1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], RF Status notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_RF_ON == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned ON!!\n"); + BTC_TRACE(trace_buf); + btcoexist->stop_coex_dm = false; + + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ACTIVE, true); + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ONOFF, true); + + } else if (BTC_RF_OFF == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned OFF!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ONOFF, false); + halbtc8822b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_WLAN_OFF); + /* for test : s3 bt disppear , fail rate 1/600*/ + + halbtc8822b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + btcoexist->stop_coex_dm = true; + } +} + +void ex_halbtc8822b1ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ONOFF, false); + + halbtc8822b1ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_WLAN_OFF); + /* for test : s3 bt disppear , fail rate 1/600*/ + + halbtc8822b1ant_ignore_wlan_act(btcoexist, FORCE_EXEC, true); + + ex_halbtc8822b1ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + halbtc8822b1ant_enable_gnt_to_gpio(btcoexist, false); + + btcoexist->stop_coex_dm = true; +} + + +void ex_halbtc8822b1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + boolean wifi_under_5g = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Pnp notify\n"); + BTC_TRACE(trace_buf); + +btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + if (BTC_WIFI_PNP_SLEEP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ACTIVE, false); + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ONOFF, false); + /* + halbtc8822b1ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8822b1ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_1ANT_PHASE_WLAN_OFF); + + halbtc8822b1ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 5); + + halbtc8822b1ant_enable_gnt_to_gpio(btcoexist, false); + */ + btcoexist->stop_coex_dm = true; + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + /*pnp_wake_cnt++;*/ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ACTIVE, true); + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_ONOFF, true); + + btcoexist->stop_coex_dm = false; + } +} + +void ex_halbtc8822b1ant_coex_dm_reset(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], *****************Coex DM Reset*****************\n"); + BTC_TRACE(trace_buf); + + halbtc8822b1ant_init_hw_config(btcoexist, false, false); + halbtc8822b1ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8822b1ant_periodical(IN struct btc_coexist *btcoexist) +{ + + struct btc_board_info *board_info = &btcoexist->board_info; + boolean wifi_busy = false; + u16 bt_scoreboard_val = 0; + u32 bt_patch_ver; + static u8 cnt = 0; + boolean bt_relink_finish = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ==========================Periodical===========================\n"); + BTC_TRACE(trace_buf); + +#if (BT_AUTO_REPORT_ONLY_8822B_1ANT == 0) + halbtc8822b1ant_query_bt_info(btcoexist); +#endif + + halbtc8822b1ant_monitor_bt_ctr(btcoexist); + halbtc8822b1ant_monitor_wifi_ctr(btcoexist); + + halbtc8822b1ant_monitor_bt_enable_disable(btcoexist); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + halbtc8822b1ant_read_score_board(btcoexist, &bt_scoreboard_val); + + if (wifi_busy) { + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_WLBUSY, true); + if (bt_scoreboard_val & BIT(6)) + halbtc8822b1ant_query_bt_info(btcoexist); + } else { + halbtc8822b1ant_post_state_to_bt(btcoexist, + BT_8822B_1ANT_SCOREBOARD_WLBUSY, false); + } + + /* for 4-way, DHCP, EAPOL packet */ + if (coex_sta->specific_pkt_period_cnt > 0) { + + coex_sta->specific_pkt_period_cnt--; + + if ((coex_sta->specific_pkt_period_cnt == 0) && + (coex_sta->wifi_is_high_pri_task)) + coex_sta->wifi_is_high_pri_task = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ***************** Hi-Pri Task = %s*****************\n", + (coex_sta->wifi_is_high_pri_task ? "Yes" : + "No")); + BTC_TRACE(trace_buf); + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->bt_coex_supported_feature == 0) + btcoexist->btc_get(btcoexist, BTC_GET_U4_SUPPORTED_FEATURE, &coex_sta->bt_coex_supported_feature); + + if ((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) + btcoexist->btc_get(btcoexist, BTC_GET_U4_SUPPORTED_VERSION, &coex_sta->bt_coex_supported_version); + + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + btcoexist->bt_info.bt_get_fw_ver = bt_patch_ver; + + if (halbtc8822b1ant_is_wifi_status_changed(btcoexist)) + halbtc8822b1ant_run_coexist_mechanism(btcoexist); + + } +} + +void ex_halbtc8822b1ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ +} + +void ex_halbtc8822b1ant_antenna_isolation(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ + + +} + +void ex_halbtc8822b1ant_psd_scan(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ + + +} + +void ex_halbtc8822b1ant_display_ant_detection(IN struct btc_coexist *btcoexist) +{ + +} + +void ex_halbtc8822b1ant_dbg_control(IN struct btc_coexist *btcoexist, + IN u8 op_code, IN u8 op_len, IN u8 *pdata) +{} +#endif /* #if(BTC_COEX_OFFLOAD == 1) */ + +#endif + +#else + +void ex_halbtc8822b1ant_switch_band_without_bt(IN struct btc_coexist *btcoexist, + IN boolean wifi_only_5g) +{ + /* ant switch WL2G or WL5G*/ + if (wifi_only_5g) + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, 0x3, 1); + + else + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, 0x3, 2); + +} + +void ex_halbtc8822b1ant_init_hw_config_without_bt(IN struct btc_coexist + *btcoexist) +{ + /* enable GNT_WL */ + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x1, + 0x0); + + /* Antenna config */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, + 0xff, 0x77); /* BB SW, DPDT use RFE_ctrl8 and RFE_ctrl9 as conctrol pin */ + + + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, + 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, + 0x8, 0x0); + + /*enable sw control gnt_wl=1 / gnt_bt=1 */ + btcoexist->btc_write_1byte(btcoexist, 0x73, 0x0e); + + btcoexist->btc_write_4byte(btcoexist, 0x1704, + 0x0000ff00); + + btcoexist->btc_write_4byte(btcoexist, 0x1700, + 0xc00f0038); +} + +#endif /* #if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) */ + + + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b1ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b1ant.h new file mode 100644 index 0000000..e84a27e --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b1ant.h @@ -0,0 +1,433 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8822B_SUPPORT == 1) + +/* ******************************************* + * The following is for 8822B 1ANT BT Co-exist definition + * ******************************************* */ +#define BT_AUTO_REPORT_ONLY_8822B_1ANT 1 + +#define BT_INFO_8822B_1ANT_B_FTP BIT(7) +#define BT_INFO_8822B_1ANT_B_A2DP BIT(6) +#define BT_INFO_8822B_1ANT_B_HID BIT(5) +#define BT_INFO_8822B_1ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8822B_1ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8822B_1ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8822B_1ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8822B_1ANT_B_CONNECTION BIT(0) + +#define BT_INFO_8822B_1ANT_A2DP_BASIC_RATE(_BT_INFO_EXT_) \ + (((_BT_INFO_EXT_&BIT(0))) ? true : false) + +#define BTC_RSSI_COEX_THRESH_TOL_8822B_1ANT 2 + +#define BT_8822B_1ANT_WIFI_NOISY_THRESH 150 /* max: 255 */ + +/* for Antenna detection */ +#define BT_8822B_1ANT_ANTDET_PSDTHRES_BACKGROUND 50 +#define BT_8822B_1ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION 70 +#define BT_8822B_1ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION 55 +#define BT_8822B_1ANT_ANTDET_PSDTHRES_1ANT 35 +#define BT_8822B_1ANT_ANTDET_RETRY_INTERVAL 10 /* retry timer if ant det is fail, unit: second */ +#define BT_8822B_1ANT_ANTDET_ENABLE 0 +#define BT_8822B_1ANT_ANTDET_COEXMECHANISMSWITCH_ENABLE 0 + +#define BT_8822B_1ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT 30000 + + + +enum bt_8822b_1ant_signal_state { + BT_8822B_1ANT_SIG_STA_SET_TO_LOW = 0x0, + BT_8822B_1ANT_SIG_STA_SET_BY_HW = 0x0, + BT_8822B_1ANT_SIG_STA_SET_TO_HIGH = 0x1, + BT_8822B_1ANT_SIG_STA_MAX +}; + +enum bt_8822b_1ant_path_ctrl_owner { + BT_8822B_1ANT_PCO_BTSIDE = 0x0, + BT_8822B_1ANT_PCO_WLSIDE = 0x1, + BT_8822B_1ANT_PCO_MAX +}; + +enum bt_8822b_1ant_gnt_ctrl_type { + BT_8822B_1ANT_GNT_CTRL_BY_PTA = 0x0, + BT_8822B_1ANT_GNT_CTRL_BY_SW = 0x1, + BT_8822B_1ANT_GNT_CTRL_MAX +}; + +enum bt_8822b_1ant_gnt_ctrl_block { + BT_8822B_1ANT_GNT_BLOCK_RFC_BB = 0x0, + BT_8822B_1ANT_GNT_BLOCK_RFC = 0x1, + BT_8822B_1ANT_GNT_BLOCK_BB = 0x2, + BT_8822B_1ANT_GNT_BLOCK_MAX +}; + +enum bt_8822b_1ant_lte_coex_table_type { + BT_8822B_1ANT_CTT_WL_VS_LTE = 0x0, + BT_8822B_1ANT_CTT_BT_VS_LTE = 0x1, + BT_8822B_1ANT_CTT_MAX +}; + +enum bt_8822b_1ant_lte_break_table_type { + BT_8822B_1ANT_LBTT_WL_BREAK_LTE = 0x0, + BT_8822B_1ANT_LBTT_BT_BREAK_LTE = 0x1, + BT_8822B_1ANT_LBTT_LTE_BREAK_WL = 0x2, + BT_8822B_1ANT_LBTT_LTE_BREAK_BT = 0x3, + BT_8822B_1ANT_LBTT_MAX +}; + +enum bt_info_src_8822b_1ant { + BT_INFO_SRC_8822B_1ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8822B_1ANT_BT_RSP = 0x1, + BT_INFO_SRC_8822B_1ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8822B_1ANT_MAX +}; + +enum bt_8822b_1ant_bt_status { + BT_8822B_1ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8822B_1ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8822B_1ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8822B_1ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8822B_1ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8822B_1ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8822B_1ANT_BT_STATUS_MAX +}; + +enum bt_8822b_1ant_wifi_status { + BT_8822B_1ANT_WIFI_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8822B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN = 0x1, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_SCAN = 0x2, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_SPECIFIC_PKT = 0x3, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_IDLE = 0x4, + BT_8822B_1ANT_WIFI_STATUS_CONNECTED_BUSY = 0x5, + BT_8822B_1ANT_WIFI_STATUS_MAX +}; + +enum bt_8822b_1ant_coex_algo { + BT_8822B_1ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8822B_1ANT_COEX_ALGO_SCO = 0x1, + BT_8822B_1ANT_COEX_ALGO_HID = 0x2, + BT_8822B_1ANT_COEX_ALGO_A2DP = 0x3, + BT_8822B_1ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8822B_1ANT_COEX_ALGO_PANEDR = 0x5, + BT_8822B_1ANT_COEX_ALGO_PANHS = 0x6, + BT_8822B_1ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8822B_1ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8822B_1ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8822B_1ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8822B_1ANT_COEX_ALGO_MAX = 0xb, +}; + +enum bt_8822b_1ant_ext_ant_switch_type { + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SPDT = 0x0, + BT_8822B_1ANT_EXT_ANT_SWITCH_USE_SP3T = 0x1, + BT_8822B_1ANT_EXT_ANT_SWITCH_MAX +}; + +enum bt_8822b_1ant_ext_ant_switch_ctrl_type { + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW = 0x0, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_PTA = 0x1, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV = 0x2, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_MAC = 0x3, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_BY_BT = 0x4, + BT_8822B_1ANT_EXT_ANT_SWITCH_CTRL_MAX +}; + +enum bt_8822b_1ant_ext_ant_switch_pos_type { + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_BT = 0x0, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_WLG = 0x1, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_WLA = 0x2, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_NOCARE = 0x3, + BT_8822B_1ANT_EXT_ANT_SWITCH_TO_MAX +}; + +enum bt_8822b_1ant_phase { + BT_8822B_1ANT_PHASE_COEX_INIT = 0x0, + BT_8822B_1ANT_PHASE_WLANONLY_INIT = 0x1, + BT_8822B_1ANT_PHASE_WLAN_OFF = 0x2, + BT_8822B_1ANT_PHASE_2G_RUNTIME = 0x3, + BT_8822B_1ANT_PHASE_5G_RUNTIME = 0x4, + BT_8822B_1ANT_PHASE_BTMPMODE = 0x5, + BT_8822B_1ANT_PHASE_MAX +}; + +/*ADD SCOREBOARD TO FIX BT LPS 32K ISSUE WHILE WL BUSY*/ +enum bt_8822b_1ant_Scoreboard { + BT_8822B_1ANT_SCOREBOARD_ACTIVE = BIT(0), + BT_8822B_1ANT_SCOREBOARD_ONOFF = BIT(1), + BT_8822B_1ANT_SCOREBOARD_SCAN = BIT(2), + BT_8822B_1ANT_SCOREBOARD_UNDERTEST = BIT(3), + BT_8822B_1ANT_SCOREBOARD_WLBUSY = BIT(6) +}; + +struct coex_dm_8822b_1ant { + /* hw setting */ + u32 pre_ant_pos_type; + u32 cur_ant_pos_type; + /* fw mechanism */ + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean auto_tdma_adjust; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + /* sw mechanism */ + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + boolean limited_dig; + + u32 backup_arfr_cnt1; /* Auto Rate Fallback Retry cnt */ + u32 backup_arfr_cnt2; /* Auto Rate Fallback Retry cnt */ + u16 backup_retry_limit; + u8 backup_ampdu_max_time; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + u32 pre_ra_mask; + u32 cur_ra_mask; + u8 pre_arfr_type; + u8 cur_arfr_type; + u8 pre_retry_limit_type; + u8 cur_retry_limit_type; + u8 pre_ampdu_time_type; + u8 cur_ampdu_time_type; + u32 arp_cnt; + + u32 pre_ext_ant_switch_status; + u32 cur_ext_ant_switch_status; + + u8 error_condition; +}; + +struct coex_sta_8822b_1ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + boolean bt_hi_pri_link_exist; + u8 num_of_profile; + + boolean under_lps; + boolean under_ips; + u32 specific_pkt_period_cnt; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + s8 bt_rssi; + boolean bt_tx_rx_mask; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + boolean c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8822B_1ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8822B_1ANT_MAX]; + boolean bt_whck_test; + boolean c2h_bt_inquiry_page; + boolean c2h_bt_page; /* Add for win8.1 page out issue */ + boolean wifi_is_high_pri_task; /* Add for win8.1 page out issue */ + u8 bt_retry_cnt; + u8 bt_info_ext; + u32 pop_event_cnt; + u8 scan_ap_num; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_agg; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_agg; + u32 crc_err_11n_vht; + + boolean cck_lock; + boolean pre_ccklock; + boolean cck_ever_lock; + u8 coex_table_type; + + boolean force_lps_on; + u32 wrong_profile_notification; + + boolean concurrent_rx_mode_on; + + u32 special_pkt_period_cnt; + + u16 score_board; + + u8 a2dp_bit_pool; + u8 cut_version; + boolean acl_busy; + boolean wl_rf_off_on_event; + boolean bt_create_connection; + boolean run_time_state; + + u32 bt_coex_supported_feature; + u32 bt_coex_supported_version; +}; + +struct rfe_type_8822b_1ant { + + u8 rfe_module_type; + boolean ext_ant_switch_exist; + u8 ext_ant_switch_type; + u8 ext_ant_switch_ctrl_polarity; /* iF 0: ANTSW(rfe_sel9)=0, ANTSWB(rfe_sel8)=1 => Ant to BT/5G */ +}; + + +#define BT_8822B_1ANT_ANTDET_PSD_POINTS 256 /* MAX:1024 */ +#define BT_8822B_1ANT_ANTDET_PSD_AVGNUM 1 /* MAX:3 */ +#define BT_8822B_1ANT_ANTDET_BUF_LEN 16 + +struct psdscan_sta_8822b_1ant { + + u32 ant_det_bt_le_channel; /* BT LE Channel ex:2412 */ + u32 ant_det_bt_tx_time; + u32 ant_det_pre_psdscan_peak_val; + boolean ant_det_is_ant_det_available; + u32 ant_det_psd_scan_peak_val; + boolean ant_det_is_btreply_available; + u32 ant_det_psd_scan_peak_freq; + + u8 ant_det_result; + u8 ant_det_peak_val[BT_8822B_1ANT_ANTDET_BUF_LEN]; + u8 ant_det_peak_freq[BT_8822B_1ANT_ANTDET_BUF_LEN]; + u32 ant_det_try_count; + u32 ant_det_fail_count; + u32 ant_det_inteval_count; + u32 ant_det_thres_offset; + + u32 real_cent_freq; + s32 real_offset; + u32 real_span; + + u32 psd_band_width; /* unit: Hz */ + u32 psd_point; /* 128/256/512/1024 */ + u32 psd_report[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_report_max_hold[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_start_point; + u32 psd_stop_point; + u32 psd_max_value_point; + u32 psd_max_value; + u32 psd_start_base; + u32 psd_avg_num; /* 1/8/16/32 */ + u32 psd_gen_count; + boolean is_psd_running; + boolean is_psd_show_max_only; +}; + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8822b1ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8822b1ant_pre_load_firmware(IN struct btc_coexist *btcoexist); +void ex_halbtc8822b1ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8822b1ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8822b1ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b1ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b1ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b1ant_scan_notify_without_bt(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b1ant_switchband_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b1ant_switchband_notify_without_bt(IN struct btc_coexist + *btcoexist, + IN u8 type); +void ex_halbtc8822b1ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b1ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b1ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b1ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8822b1ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b1ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8822b1ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state); +void ex_halbtc8822b1ant_ScoreBoardStatusNotify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8822b1ant_coex_dm_reset(IN struct btc_coexist *btcoexist); +void ex_halbtc8822b1ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8822b1ant_display_coex_info(IN struct btc_coexist *btcoexist); +void ex_halbtc8822b1ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); +void ex_halbtc8822b1ant_antenna_isolation(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); + +void ex_halbtc8822b1ant_psd_scan(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); +void ex_halbtc8822b1ant_display_ant_detection(IN struct btc_coexist *btcoexist); + +void ex_halbtc8822b1ant_dbg_control(IN struct btc_coexist *btcoexist, + IN u8 op_code, IN u8 op_len, IN u8 *pdata); + +#else +#define ex_halbtc8822b1ant_power_on_setting(btcoexist) +#define ex_halbtc8822b1ant_pre_load_firmware(btcoexist) +#define ex_halbtc8822b1ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8822b1ant_init_coex_dm(btcoexist) +#define ex_halbtc8822b1ant_ips_notify(btcoexist, type) +#define ex_halbtc8822b1ant_lps_notify(btcoexist, type) +#define ex_halbtc8822b1ant_scan_notify(btcoexist, type) +#define ex_halbtc8822b1ant_scan_notify_without_bt(btcoexist, type) +#define ex_halbtc8822b1ant_switchband_notify(btcoexist, type) +#define ex_halbtc8822b1ant_switchband_notify_without_bt(btcoexist, type) +#define ex_halbtc8822b1ant_connect_notify(btcoexist, type) +#define ex_halbtc8822b1ant_media_status_notify(btcoexist, type) +#define ex_halbtc8822b1ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8822b1ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8822b1ant_rf_status_notify(btcoexist, type) +#define ex_halbtc8822b1ant_halt_notify(btcoexist) +#define ex_halbtc8822b1ant_pnp_notify(btcoexist, pnp_state) +#define ex_halbtc8822b1ant_ScoreBoardStatusNotify(btcoexist, tmp_buf, length) +#define ex_halbtc8822b1ant_coex_dm_reset(btcoexist) +#define ex_halbtc8822b1ant_periodical(btcoexist) +#define ex_halbtc8822b1ant_display_coex_info(btcoexist) +#define ex_halbtc8822b1ant_antenna_detection(btcoexist, cent_freq, offset, span, seconds) +#define ex_halbtc8822b1ant_antenna_isolation(btcoexist, cent_freq, offset, span, seconds) +#define ex_halbtc8822b1ant_psd_scan(btcoexist, cent_freq, offset, span, seconds) +#define ex_halbtc8822b1ant_display_ant_detection(btcoexist) +#define ex_halbtc8822b1ant_dbg_control(btcoexist, op_code, op_len, pdata) +#endif +#else + +void ex_halbtc8822b1ant_init_hw_config_without_bt(IN struct btc_coexist + *btcoexist); +void ex_halbtc8822b1ant_switch_band_without_bt(IN struct btc_coexist *btcoexist, + IN boolean wifi_only_5g); + + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b2ant.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b2ant.c new file mode 100644 index 0000000..6f3d6b5 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b2ant.c @@ -0,0 +1,5543 @@ +/* ************************************************************ + * Description: + * + * This file is for RTL8822B Co-exist mechanism + * + * History + * 2012/11/15 Cosa first check in. + * + * ************************************************************ */ + +/* ************************************************************ + * include files + * ************************************************************ */ +#include "mp_precomp.h" + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8822B_SUPPORT == 1) +/* ************************************************************ + * Global variables, these are static variables + * ************************************************************ */ +static u8 *trace_buf = &gl_btc_trace_buf[0]; +static struct coex_dm_8822b_2ant glcoex_dm_8822b_2ant; +static struct coex_dm_8822b_2ant *coex_dm = &glcoex_dm_8822b_2ant; +static struct coex_sta_8822b_2ant glcoex_sta_8822b_2ant; +static struct coex_sta_8822b_2ant *coex_sta = &glcoex_sta_8822b_2ant; +static struct psdscan_sta_8822b_2ant gl_psd_scan_8822b_2ant; +static struct psdscan_sta_8822b_2ant *psd_scan = &gl_psd_scan_8822b_2ant; +static struct rfe_type_8822b_2ant gl_rfe_type_8822b_2ant; +static struct rfe_type_8822b_2ant *rfe_type = &gl_rfe_type_8822b_2ant; + +const char *const glbt_info_src_8822b_2ant[] = { + "BT Info[wifi fw]", + "BT Info[bt rsp]", + "BT Info[bt auto report]", +}; + +u32 glcoex_ver_date_8822b_2ant = 20161026; +u32 glcoex_ver_8822b_2ant = 0x34; +u32 glcoex_ver_btdesired_8822b_2ant = 0x28; + +/* ************************************************************ + * local function proto type if needed + * ************************************************************ + * ************************************************************ + * local function start with halbtc8822b2ant_ + * ************************************************************ */ +u8 halbtc8822b2ant_bt_rssi_state(u8 *ppre_bt_rssi_state, u8 level_num, + u8 rssi_thresh, u8 rssi_thresh1) +{ + s32 bt_rssi = 0; + u8 bt_rssi_state = *ppre_bt_rssi_state; + + bt_rssi = coex_sta->bt_rssi; + + if (level_num == 2) { + if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT Rssi thresh error!!\n"); + BTC_TRACE(trace_buf); + return *ppre_bt_rssi_state; + } + + if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_LOW) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (bt_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((*ppre_bt_rssi_state == BTC_RSSI_STATE_MEDIUM) || + (*ppre_bt_rssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + if (bt_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT)) + bt_rssi_state = BTC_RSSI_STATE_HIGH; + else if (bt_rssi < rssi_thresh) + bt_rssi_state = BTC_RSSI_STATE_LOW; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (bt_rssi < rssi_thresh1) + bt_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + bt_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + *ppre_bt_rssi_state = bt_rssi_state; + + return bt_rssi_state; +} + +u8 halbtc8822b2ant_wifi_rssi_state(IN struct btc_coexist *btcoexist, + IN u8 *pprewifi_rssi_state, IN u8 level_num, IN u8 rssi_thresh, + IN u8 rssi_thresh1) +{ + s32 wifi_rssi = 0; + u8 wifi_rssi_state = *pprewifi_rssi_state; + + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + + if (level_num == 2) { + if ((*pprewifi_rssi_state == BTC_RSSI_STATE_LOW) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else { + if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } else if (level_num == 3) { + if (rssi_thresh > rssi_thresh1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi RSSI thresh error!!\n"); + BTC_TRACE(trace_buf); + return *pprewifi_rssi_state; + } + + if ((*pprewifi_rssi_state == BTC_RSSI_STATE_LOW) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_LOW)) { + if (wifi_rssi >= (rssi_thresh + + BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_LOW; + } else if ((*pprewifi_rssi_state == BTC_RSSI_STATE_MEDIUM) || + (*pprewifi_rssi_state == BTC_RSSI_STATE_STAY_MEDIUM)) { + if (wifi_rssi >= (rssi_thresh1 + + BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT)) + wifi_rssi_state = BTC_RSSI_STATE_HIGH; + else if (wifi_rssi < rssi_thresh) + wifi_rssi_state = BTC_RSSI_STATE_LOW; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_MEDIUM; + } else { + if (wifi_rssi < rssi_thresh1) + wifi_rssi_state = BTC_RSSI_STATE_MEDIUM; + else + wifi_rssi_state = BTC_RSSI_STATE_STAY_HIGH; + } + } + + *pprewifi_rssi_state = wifi_rssi_state; + + return wifi_rssi_state; +} + +void halbtc8822b2ant_coex_switch_threshold(IN struct btc_coexist *btcoexist, + IN u8 isolation_measuared) +{ + s8 interference_wl_tx = 0, interference_bt_tx = 0; + + + interference_wl_tx = BT_8822B_2ANT_WIFI_MAX_TX_POWER - + isolation_measuared; + interference_bt_tx = BT_8822B_2ANT_BT_MAX_TX_POWER - + isolation_measuared; + + + + coex_sta->wifi_coex_thres = BT_8822B_2ANT_WIFI_RSSI_COEXSWITCH_THRES1; + coex_sta->wifi_coex_thres2 = BT_8822B_2ANT_WIFI_RSSI_COEXSWITCH_THRES2; + + coex_sta->bt_coex_thres = BT_8822B_2ANT_BT_RSSI_COEXSWITCH_THRES1; + coex_sta->bt_coex_thres2 = BT_8822B_2ANT_BT_RSSI_COEXSWITCH_THRES2; + + + /* + coex_sta->wifi_coex_thres = interference_wl_tx + BT_8822B_2ANT_WIFI_SIR_THRES1; + coex_sta->wifi_coex_thres2 = interference_wl_tx + BT_8822B_2ANT_WIFI_SIR_THRES2; + + coex_sta->bt_coex_thres = interference_bt_tx + BT_8822B_2ANT_BT_SIR_THRES1; + coex_sta->bt_coex_thres2 = interference_bt_tx + BT_8822B_2ANT_BT_SIR_THRES2; + */ + + + + + + /* + if ( BT_8822B_2ANT_WIFI_RSSI_COEXSWITCH_THRES1 < (isolation_measuared - + BT_8822B_2ANT_DEFAULT_ISOLATION) ) + coex_sta->wifi_coex_thres = BT_8822B_2ANT_WIFI_RSSI_COEXSWITCH_THRES1; + else + coex_sta->wifi_coex_thres = BT_8822B_2ANT_WIFI_RSSI_COEXSWITCH_THRES1 - (isolation_measuared - + BT_8822B_2ANT_DEFAULT_ISOLATION); + + if ( BT_8822B_2ANT_BT_RSSI_COEXSWITCH_THRES1 < (isolation_measuared - + BT_8822B_2ANT_DEFAULT_ISOLATION) ) + coex_sta->bt_coex_thres = BT_8822B_2ANT_BT_RSSI_COEXSWITCH_THRES1; + else + coex_sta->bt_coex_thres = BT_8822B_2ANT_BT_RSSI_COEXSWITCH_THRES1 - (isolation_measuared - + BT_8822B_2ANT_DEFAULT_ISOLATION); + + */ +} + + +void halbtc8822b2ant_limited_rx(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean rej_ap_agg_pkt, + IN boolean bt_ctrl_agg_buf_size, IN u8 agg_buf_size) +{ + boolean reject_rx_agg = rej_ap_agg_pkt; + boolean bt_ctrl_rx_agg_size = bt_ctrl_agg_buf_size; + u8 rx_agg_size = agg_buf_size; + + /* ============================================ */ + /* Rx Aggregation related setting */ + /* ============================================ */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_TO_REJ_AP_AGG_PKT, + &reject_rx_agg); + /* decide BT control aggregation buf size or not */ + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_CTRL_AGG_SIZE, + &bt_ctrl_rx_agg_size); + /* aggregation buf size, only work when BT control Rx aggregation size. */ + btcoexist->btc_set(btcoexist, BTC_SET_U1_AGG_BUF_SIZE, &rx_agg_size); + /* real update aggregation setting */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_AGGREGATE_CTRL, NULL); +} + +void halbtc8822b2ant_query_bt_info(IN struct btc_coexist *btcoexist) +{ + u8 h2c_parameter[1] = {0}; + boolean RTL97F_8822B = false; + + if (RTL97F_8822B == true) + return; + + coex_sta->c2h_bt_info_req_sent = true; + + h2c_parameter[0] |= BIT(0); /* trigger */ + + btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); +} + +void halbtc8822b2ant_monitor_bt_ctr(IN struct btc_coexist *btcoexist) +{ + u32 reg_hp_txrx, reg_lp_txrx, u32tmp; + u32 reg_hp_tx = 0, reg_hp_rx = 0, reg_lp_tx = 0, reg_lp_rx = 0; + static u8 num_of_bt_counter_chk = 0, cnt_slave = 0; + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + reg_hp_txrx = 0x770; + reg_lp_txrx = 0x774; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_hp_txrx); + reg_hp_tx = u32tmp & MASKLWORD; + reg_hp_rx = (u32tmp & MASKHWORD) >> 16; + + u32tmp = btcoexist->btc_read_4byte(btcoexist, reg_lp_txrx); + reg_lp_tx = u32tmp & MASKLWORD; + reg_lp_rx = (u32tmp & MASKHWORD) >> 16; + + coex_sta->high_priority_tx = reg_hp_tx; + coex_sta->high_priority_rx = reg_hp_rx; + coex_sta->low_priority_tx = reg_lp_tx; + coex_sta->low_priority_rx = reg_lp_rx; + + + /* reset counter */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, 0xc); + + if ((coex_sta->low_priority_tx > 1050) && + (!coex_sta->c2h_bt_inquiry_page)) + coex_sta->pop_event_cnt++; + + if ((coex_sta->low_priority_rx >= 950) && + (coex_sta->low_priority_rx >= coex_sta->low_priority_tx) + && (!coex_sta->under_ips) && (!coex_sta->c2h_bt_inquiry_page) && + (coex_sta->bt_link_exist)) { + if (cnt_slave >= 2) { + bt_link_info->slave_role = true; + cnt_slave = 2; + } else + cnt_slave++; + } else { + if (cnt_slave == 0) { + bt_link_info->slave_role = false; + cnt_slave = 0; + } else + cnt_slave--; + + } + + if ((coex_sta->high_priority_tx == 0) && + (coex_sta->high_priority_rx == 0) && + (coex_sta->low_priority_tx == 0) && + (coex_sta->low_priority_rx == 0)) { + num_of_bt_counter_chk++; + if (num_of_bt_counter_chk >= 3) { + halbtc8822b2ant_query_bt_info(btcoexist); + num_of_bt_counter_chk = 0; + } + } + +} + +void halbtc8822b2ant_monitor_wifi_ctr(IN struct btc_coexist *btcoexist) +{ +#if 0 + s32 wifi_rssi = 0; + boolean wifi_busy = false, wifi_under_b_mode = false; + static u8 cck_lock_counter = 0; + u32 total_cnt, reg_val1, reg_val2; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_S4_WIFI_RSSI, &wifi_rssi); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + if (coex_sta->under_ips) { + coex_sta->crc_ok_cck = 0; + coex_sta->crc_ok_11g = 0; + coex_sta->crc_ok_11n = 0; + coex_sta->crc_ok_11n_agg = 0; + + coex_sta->crc_err_cck = 0; + coex_sta->crc_err_11g = 0; + coex_sta->crc_err_11n = 0; + coex_sta->crc_err_11n_agg = 0; + } else { + + reg_val1 = btcoexist->btc_read_4byte(btcoexist, 0xf00); + reg_val2 = btcoexist->btc_read_4byte(btcoexist, 0xf04); + coex_sta->crc_ok_cck = reg_val2 & 0xffff; + coex_sta->crc_err_cck = (reg_val1 & 0xffff) + ((reg_val2 + & 0xffff0000) >> 16); + + reg_val1 = btcoexist->btc_read_4byte(btcoexist, 0xf0c); + coex_sta->crc_ok_11n_agg = reg_val1 & 0xffff; + coex_sta->crc_err_11n_agg = (reg_val1 & 0xffff0000) >> + 16; + + reg_val1 = btcoexist->btc_read_4byte(btcoexist, 0xf10); + coex_sta->crc_ok_11n = reg_val1 & 0xffff; + coex_sta->crc_err_11n = (reg_val1 & 0xffff0000) >> 16; + + reg_val1 = btcoexist->btc_read_4byte(btcoexist, 0xf14); + coex_sta->crc_ok_11g = reg_val1 & 0xffff; + coex_sta->crc_err_11n = (reg_val1 & 0xffff0000) >> 16; + } + + + /* reset counter */ + /*btcoexist->btc_write_1byte_bitmask(btcoexist, 0xb58, 0x1, 0x1);*/ + /*btcoexist->btc_write_1byte_bitmask(btcoexist, 0xb58, 0x1, 0x0);*/ + + if ((wifi_busy) && (wifi_rssi >= 30) && (!wifi_under_b_mode)) { + total_cnt = coex_sta->crc_ok_cck + coex_sta->crc_ok_11g + + + coex_sta->crc_ok_11n + + coex_sta->crc_ok_11n_agg; + + if ((coex_dm->bt_status == + BT_8822B_2ANT_BT_STATUS_ACL_BUSY) || + (coex_dm->bt_status == + BT_8822B_2ANT_BT_STATUS_ACL_SCO_BUSY) || + (coex_dm->bt_status == + BT_8822B_2ANT_BT_STATUS_SCO_BUSY)) { + if (coex_sta->crc_ok_cck > (total_cnt - + coex_sta->crc_ok_cck)) { + if (cck_lock_counter < 3) + cck_lock_counter++; + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + } else { + if (cck_lock_counter > 0) + cck_lock_counter--; + } + + if (!coex_sta->pre_ccklock) { + + if (cck_lock_counter >= 3) + coex_sta->cck_lock = true; + else + coex_sta->cck_lock = false; + } else { + if (cck_lock_counter == 0) + coex_sta->cck_lock = false; + else + coex_sta->cck_lock = true; + } + + if (coex_sta->cck_lock) + coex_sta->cck_ever_lock = true; + + coex_sta->pre_ccklock = coex_sta->cck_lock; + +#endif +} + +boolean halbtc8822b2ant_is_wifibt_status_changed(IN struct btc_coexist + *btcoexist) +{ + static boolean pre_wifi_busy = false, pre_under_4way = false, + pre_bt_hs_on = false, pre_bt_off = false; + static u8 pre_hid_busy_num = 0; + boolean wifi_busy = false, under_4way = false, bt_hs_on = false; + boolean wifi_connected = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (coex_sta->bt_disabled != pre_bt_off) { + pre_bt_off = coex_sta->bt_disabled; + + if (coex_sta->bt_disabled) + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled !!\n"); + else + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is enabled !!\n"); + + BTC_TRACE(trace_buf); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->bt_reg_vendor_ac = 0xffff; + coex_sta->bt_reg_vendor_ae = 0xffff; + return true; + } + + + if (wifi_connected) { + if (wifi_busy != pre_wifi_busy) { + pre_wifi_busy = wifi_busy; + return true; + } + if (under_4way != pre_under_4way) { + pre_under_4way = under_4way; + return true; + } + if (bt_hs_on != pre_bt_hs_on) { + pre_bt_hs_on = bt_hs_on; + return true; + } + + if (!coex_sta->bt_disabled) { + + if (coex_sta->hid_busy_num != pre_hid_busy_num) { + pre_hid_busy_num = coex_sta->hid_busy_num; + return true; + } + } + } + + return false; +} + + +void halbtc8822b2ant_update_bt_link_info(IN struct btc_coexist *btcoexist) +{ + + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + boolean bt_busy = false; + + coex_sta->num_of_profile = 0; + + /* set link exist status */ + if (!(coex_sta->bt_info & BT_INFO_8822B_1ANT_B_CONNECTION)) { + coex_sta->bt_link_exist = false; + coex_sta->pan_exist = false; + coex_sta->a2dp_exist = false; + coex_sta->hid_exist = false; + coex_sta->sco_exist = false; + } else { /* connection exists */ + coex_sta->bt_link_exist = true; + if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_FTP) { + coex_sta->pan_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->pan_exist = false; + + if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_A2DP) { + coex_sta->a2dp_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->a2dp_exist = false; + + if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_HID) { + coex_sta->hid_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->hid_exist = false; + + if (coex_sta->bt_info & BT_INFO_8822B_1ANT_B_SCO_ESCO) { + coex_sta->sco_exist = true; + coex_sta->num_of_profile++; + } else + coex_sta->sco_exist = false; + + } + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + bt_link_info->bt_link_exist = coex_sta->bt_link_exist; + bt_link_info->sco_exist = coex_sta->sco_exist; + bt_link_info->a2dp_exist = coex_sta->a2dp_exist; + bt_link_info->pan_exist = coex_sta->pan_exist; + bt_link_info->hid_exist = coex_sta->hid_exist; + bt_link_info->acl_busy = coex_sta->acl_busy; + + /* work around for HS mode. */ + if (bt_hs_on) { + bt_link_info->pan_exist = true; + bt_link_info->bt_link_exist = true; + } + + /* check if Sco only */ + if (bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->sco_only = true; + else + bt_link_info->sco_only = false; + + /* check if A2dp only */ + if (!bt_link_info->sco_exist && + bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->a2dp_only = true; + else + bt_link_info->a2dp_only = false; + + /* check if Pan only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + bt_link_info->pan_exist && + !bt_link_info->hid_exist) + bt_link_info->pan_only = true; + else + bt_link_info->pan_only = false; + + /* check if Hid only */ + if (!bt_link_info->sco_exist && + !bt_link_info->a2dp_exist && + !bt_link_info->pan_exist && + bt_link_info->hid_exist) + bt_link_info->hid_only = true; + else + bt_link_info->hid_only = false; + + if (!(coex_sta->bt_info & BT_INFO_8822B_2ANT_B_CONNECTION)) { + coex_dm->bt_status = BT_8822B_2ANT_BT_STATUS_NON_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Connected idle!!!\n"); + } else if (coex_sta->bt_info == BT_INFO_8822B_2ANT_B_CONNECTION) { + /* connection exists but no busy */ + coex_dm->bt_status = BT_8822B_2ANT_BT_STATUS_CONNECTED_IDLE; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Connected-idle!!!\n"); + } else if (((coex_sta->bt_info & BT_INFO_8822B_2ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8822B_2ANT_B_SCO_BUSY)) && + (coex_sta->bt_info & BT_INFO_8822B_2ANT_B_ACL_BUSY)) { + coex_dm->bt_status = BT_8822B_2ANT_BT_STATUS_ACL_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL SCO busy!!!\n"); + } else if ((coex_sta->bt_info & BT_INFO_8822B_2ANT_B_SCO_ESCO) || + (coex_sta->bt_info & BT_INFO_8822B_2ANT_B_SCO_BUSY)) { + coex_dm->bt_status = BT_8822B_2ANT_BT_STATUS_SCO_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT SCO busy!!!\n"); + } else if (coex_sta->bt_info & BT_INFO_8822B_2ANT_B_ACL_BUSY) { + coex_dm->bt_status = BT_8822B_2ANT_BT_STATUS_ACL_BUSY; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT ACL busy!!!\n"); + } else { + coex_dm->bt_status = BT_8822B_2ANT_BT_STATUS_MAX; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), BT Non-Defined state!!!\n"); + } + + BTC_TRACE(trace_buf); + + if ((BT_8822B_2ANT_BT_STATUS_ACL_BUSY == coex_dm->bt_status) || + (BT_8822B_2ANT_BT_STATUS_SCO_BUSY == coex_dm->bt_status) || + (BT_8822B_2ANT_BT_STATUS_ACL_SCO_BUSY == coex_dm->bt_status)) + bt_busy = true; + else + bt_busy = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_TRAFFIC_BUSY, &bt_busy); +} + +void halbtc8822b2ant_update_wifi_channel_info(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + u32 RTL97F_8822B = 0; + + if (RTL97F_8822B == true) + return; + + /* only 2.4G we need to inform bt the chnl mask */ + btcoexist->btc_get(btcoexist, BTC_GET_U1_WIFI_CENTRAL_CHNL, + &wifi_central_chnl); + if ((BTC_MEDIA_CONNECT == type) && + (wifi_central_chnl <= 14)) { + h2c_parameter[0] = + 0x1; /* enable BT AFH skip WL channel for 8822b because BT Rx LO interference */ + /* h2c_parameter[0] = 0x0; */ + h2c_parameter[1] = wifi_central_chnl; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_BW, &wifi_bw); + if (BTC_WIFI_BW_HT40 == wifi_bw) + h2c_parameter[2] = 0x30; + else + h2c_parameter[2] = 0x20; + } + + coex_dm->wifi_chnl_info[0] = h2c_parameter[0]; + coex_dm->wifi_chnl_info[1] = h2c_parameter[1]; + coex_dm->wifi_chnl_info[2] = h2c_parameter[2]; + + btcoexist->btc_fill_h2c(btcoexist, 0x66, 3, h2c_parameter); + +} + +void halbtc8822b2ant_set_fw_dac_swing_level(IN struct btc_coexist *btcoexist, + IN u8 dac_swing_lvl) +{ + u8 h2c_parameter[1] = {0}; + u32 RTL97F_8822B = 0; + + if (RTL97F_8822B == true) + return; + + /* There are several type of dacswing */ + /* 0x18/ 0x10/ 0xc/ 0x8/ 0x4/ 0x6 */ + h2c_parameter[0] = dac_swing_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x64, 1, h2c_parameter); +} + +void halbtc8822b2ant_fw_dac_swing_lvl(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 fw_dac_swing_lvl) +{ + u32 RTL97F_8822B = 0; + + if (RTL97F_8822B == true) + return; + + coex_dm->cur_fw_dac_swing_lvl = fw_dac_swing_lvl; + + if (!force_exec) { + if (coex_dm->pre_fw_dac_swing_lvl == + coex_dm->cur_fw_dac_swing_lvl) + return; + } + + halbtc8822b2ant_set_fw_dac_swing_level(btcoexist, + coex_dm->cur_fw_dac_swing_lvl); + + coex_dm->pre_fw_dac_swing_lvl = coex_dm->cur_fw_dac_swing_lvl; +} + +void halbtc8822b2ant_set_fw_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN u8 dec_bt_pwr_lvl) +{ + u32 RTL97F_8822B = 0; + u8 h2c_parameter[1] = {0}; + + if (RTL97F_8822B == true) + return; + + h2c_parameter[0] = dec_bt_pwr_lvl; + + btcoexist->btc_fill_h2c(btcoexist, 0x62, 1, h2c_parameter); +} + +void halbtc8822b2ant_dec_bt_pwr(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 dec_bt_pwr_lvl) +{ + coex_dm->cur_bt_dec_pwr_lvl = dec_bt_pwr_lvl; + + if (!force_exec) { + if (coex_dm->pre_bt_dec_pwr_lvl == coex_dm->cur_bt_dec_pwr_lvl) + return; + } + halbtc8822b2ant_set_fw_dec_bt_pwr(btcoexist, + coex_dm->cur_bt_dec_pwr_lvl); + + coex_dm->pre_bt_dec_pwr_lvl = coex_dm->cur_bt_dec_pwr_lvl; +} + + +void halbtc8822b2ant_low_penalty_ra(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean low_penalty_ra) +{ + +#if 1 + coex_dm->cur_low_penalty_ra = low_penalty_ra; + + if (!force_exec) { + if (coex_dm->pre_low_penalty_ra == + coex_dm->cur_low_penalty_ra) + return; + } + + if (low_penalty_ra) + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 50); + else + btcoexist->btc_phydm_modify_RA_PCR_threshold(btcoexist, 0, 0); + + coex_dm->pre_low_penalty_ra = coex_dm->cur_low_penalty_ra; + +#endif + +} + + +void halbtc8822b2ant_set_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean enable_auto_report) +{ + u8 h2c_parameter[1] = {0}; + u32 RTL97F_8822B = 0; + + if (RTL97F_8822B == true) + return; + + h2c_parameter[0] = 0; + + if (enable_auto_report) + h2c_parameter[0] |= BIT(0); + + btcoexist->btc_fill_h2c(btcoexist, 0x68, 1, h2c_parameter); +} + +void halbtc8822b2ant_bt_auto_report(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable_auto_report) +{ + coex_dm->cur_bt_auto_report = enable_auto_report; + + if (!force_exec) { + if (coex_dm->pre_bt_auto_report == coex_dm->cur_bt_auto_report) + return; + } + halbtc8822b2ant_set_bt_auto_report(btcoexist, + coex_dm->cur_bt_auto_report); + + coex_dm->pre_bt_auto_report = coex_dm->cur_bt_auto_report; +} + +void halbtc8822b2ant_write_score_board( + IN struct btc_coexist *btcoexist, + IN u16 bitpos, + IN boolean state +) +{ + + static u16 originalval = 0x8002; + + if (state) + originalval = originalval | bitpos; + else + originalval = originalval & (~bitpos); + + + btcoexist->btc_write_2byte(btcoexist, 0xaa, originalval); + +} + +void halbtc8822b2ant_read_score_board( + IN struct btc_coexist *btcoexist, + IN u16 *score_board_val +) +{ + + *score_board_val = (btcoexist->btc_read_2byte(btcoexist, + 0xaa)) & 0x7fff; +} + +void halbtc8822b2ant_post_state_to_bt( + IN struct btc_coexist *btcoexist, + IN u16 type, + IN BOOLEAN state +) +{ + + halbtc8822b2ant_write_score_board(btcoexist, (u16) type, state); + +} + + + +void halbtc8822b2ant_monitor_bt_enable_disable(IN struct btc_coexist *btcoexist) +{ + static u32 bt_disable_cnt = 0; + boolean bt_active = true, bt_disabled = false, wifi_under_5g = false; + u16 u16tmp; + + /* This function check if bt is disabled */ +#if 0 + if (coex_sta->high_priority_tx == 0 && + coex_sta->high_priority_rx == 0 && + coex_sta->low_priority_tx == 0 && + coex_sta->low_priority_rx == 0) + bt_active = false; + if (coex_sta->high_priority_tx == 0xffff && + coex_sta->high_priority_rx == 0xffff && + coex_sta->low_priority_tx == 0xffff && + coex_sta->low_priority_rx == 0xffff) + bt_active = false; + + +#else + + /* Read BT on/off status from scoreboard[1], enable this only if BT patch support this feature */ + halbtc8822b2ant_read_score_board(btcoexist, &u16tmp); + + bt_active = u16tmp & BIT(1); + + +#endif + + if (bt_active) { + bt_disable_cnt = 0; + bt_disabled = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } else { + + bt_disable_cnt++; + if (bt_disable_cnt >= 10) { + bt_disabled = true; + bt_disable_cnt = 10; + } + + btcoexist->btc_set(btcoexist, BTC_SET_BL_BT_DISABLE, + &bt_disabled); + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if ((wifi_under_5g) || (bt_disabled)) + halbtc8822b2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + else + halbtc8822b2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, true); + + + if (coex_sta->bt_disabled != bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is from %s to %s!!\n", + (coex_sta->bt_disabled ? "disabled" : "enabled"), + (bt_disabled ? "disabled" : "enabled")); + BTC_TRACE(trace_buf); + coex_sta->bt_disabled = bt_disabled; + } + +} + +void halbtc8822b2ant_enable_gnt_to_gpio(IN struct btc_coexist *btcoexist, + boolean isenable) +{ +#if BT_8822B_2ANT_COEX_DBG + static u8 bitVal[5] = {0, 0, 0, 0, 0}; + static boolean state = false; + /* + if (state ==isenable) + return; + else + state = isenable; + */ + if (isenable) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], enable_gnt_to_gpio!!\n"); + BTC_TRACE(trace_buf); + + /* enable GNT_WL, GNT_BT to GPIO for debug */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x1); + + /* store original value */ + bitVal[0] = (btcoexist->btc_read_1byte(btcoexist, + 0x66) & BIT(4)) >> 4; /*0x66[4] */ + bitVal[1] = (btcoexist->btc_read_1byte(btcoexist, + 0x67) & BIT(0)); /*0x66[8] */ + bitVal[2] = (btcoexist->btc_read_1byte(btcoexist, + 0x42) & BIT(3)) >> 3; /*0x40[19] */ + bitVal[3] = (btcoexist->btc_read_1byte(btcoexist, + 0x65) & BIT(7)) >> 7; /*0x64[15] */ + bitVal[4] = (btcoexist->btc_read_1byte(btcoexist, + 0x72) & BIT(2)) >> 2; /*0x70[18] */ + + /* switch GPIO Mux */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, BIT(4), + 0x0); /*0x66[4] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, BIT(0), + 0x0); /*0x66[8] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x42, BIT(3), + 0x0); /*0x40[19] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x65, BIT(7), + 0x0); /*0x64[15] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x72, BIT(2), + 0x0); /*0x70[18] = 0 */ + + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], disable_gnt_to_gpio!!\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x8, 0x0); + + /* Restore original value */ + /* switch GPIO Mux */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, BIT(4), + bitVal[0]); /*0x66[4] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, BIT(0), + bitVal[1]); /*0x66[8] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x42, BIT(3), + bitVal[2]); /*0x40[19] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x65, BIT(7), + bitVal[3]); /*0x64[15] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x72, BIT(2), + bitVal[4]); /*0x70[18] = 0 */ + } + +#endif +} + +u32 halbtc8822b2ant_ltecoex_indirect_read_reg(IN struct btc_coexist *btcoexist, + IN u16 reg_addr) +{ + u32 j = 0; + + + /* wait for ready bit before access 0x1700 */ + btcoexist->btc_write_4byte(btcoexist, 0x1700, 0x800F0000 | reg_addr); + + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x1703)&BIT(5)) == 0) && + (j < BT_8822B_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + return btcoexist->btc_read_4byte(btcoexist, + 0x1708); /* get read data */ + +} + +void halbtc8822b2ant_ltecoex_indirect_write_reg(IN struct btc_coexist + *btcoexist, + IN u16 reg_addr, IN u32 bit_mask, IN u32 reg_value) +{ + u32 val, i = 0, j = 0, bitpos = 0; + + + if (bit_mask == 0x0) + return; + if (bit_mask == 0xffffffff) { + btcoexist->btc_write_4byte(btcoexist, 0x1704, + reg_value); /* put write data */ + + /* wait for ready bit before access 0x1700 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x1703)&BIT(5)) == 0) && + (j < BT_8822B_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + btcoexist->btc_write_4byte(btcoexist, 0x1700, + 0xc00F0000 | reg_addr); + } else { + for (i = 0; i <= 31; i++) { + if (((bit_mask >> i) & 0x1) == 0x1) { + bitpos = i; + break; + } + } + + /* read back register value before write */ + val = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + reg_addr); + val = (val & (~bit_mask)) | (reg_value << bitpos); + + btcoexist->btc_write_4byte(btcoexist, 0x1704, + val); /* put write data */ + + /* wait for ready bit before access 0x7c0 */ + do { + j++; + } while (((btcoexist->btc_read_1byte(btcoexist, + 0x1703)&BIT(5)) == 0) && + (j < BT_8822B_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT)); + + + btcoexist->btc_write_4byte(btcoexist, 0x1700, + 0xc00F0000 | reg_addr); + + } + +} + +void halbtc8822b2ant_ltecoex_enable(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 val; + + val = (enable) ? 1 : 0; + halbtc8822b2ant_ltecoex_indirect_write_reg(btcoexist, 0x38, 0x80, + val); /* 0x38[7] */ + +} + +void halbtc8822b2ant_ltecoex_pathcontrol_owner(IN struct btc_coexist *btcoexist, + IN boolean wifi_control) +{ + u8 val; + + val = (wifi_control) ? 1 : 0; + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x73, 0x4, + val); /* 0x70[26] */ + +} + +void halbtc8822b2ant_ltecoex_set_gnt_bt(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, bit_mask; + + state = state & 0x1; + val = (sw_control) ? ((state << 1) | 0x1) : 0; + + switch (control_block) { + case BT_8822B_2ANT_GNT_BLOCK_RFC_BB: + default: + bit_mask = 0xc000; + halbtc8822b2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[15:14] */ + bit_mask = 0x0c00; + halbtc8822b2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[11:10] */ + break; + case BT_8822B_2ANT_GNT_BLOCK_RFC: + bit_mask = 0xc000; + halbtc8822b2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[15:14] */ + break; + case BT_8822B_2ANT_GNT_BLOCK_BB: + bit_mask = 0x0c00; + halbtc8822b2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[11:10] */ + break; + + } + +} + +void halbtc8822b2ant_ltecoex_set_gnt_wl(IN struct btc_coexist *btcoexist, + IN u8 control_block, IN boolean sw_control, IN u8 state) +{ + u32 val = 0, bit_mask; + + state = state & 0x1; + val = (sw_control) ? ((state << 1) | 0x1) : 0; + + switch (control_block) { + case BT_8822B_2ANT_GNT_BLOCK_RFC_BB: + default: + bit_mask = 0x3000; + halbtc8822b2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[13:12] */ + bit_mask = 0x0300; + halbtc8822b2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[9:8] */ + break; + case BT_8822B_2ANT_GNT_BLOCK_RFC: + bit_mask = 0x3000; + halbtc8822b2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[13:12] */ + break; + case BT_8822B_2ANT_GNT_BLOCK_BB: + bit_mask = 0x0300; + halbtc8822b2ant_ltecoex_indirect_write_reg(btcoexist, + 0x38, bit_mask, val); /* 0x38[9:8] */ + break; + + } + +} + +void halbtc8822b2ant_ltecoex_set_coex_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u16 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8822B_2ANT_CTT_WL_VS_LTE: + reg_addr = 0xa0; + break; + case BT_8822B_2ANT_CTT_BT_VS_LTE: + reg_addr = 0xa4; + break; + } + + if (reg_addr != 0x0000) + halbtc8822b2ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xffff, table_content); /* 0xa0[15:0] or 0xa4[15:0] */ + + +} + + +void halbtc8822b2ant_ltecoex_set_break_table(IN struct btc_coexist *btcoexist, + IN u8 table_type, IN u8 table_content) +{ + u16 reg_addr = 0x0000; + + switch (table_type) { + case BT_8822B_2ANT_LBTT_WL_BREAK_LTE: + reg_addr = 0xa8; + break; + case BT_8822B_2ANT_LBTT_BT_BREAK_LTE: + reg_addr = 0xac; + break; + case BT_8822B_2ANT_LBTT_LTE_BREAK_WL: + reg_addr = 0xb0; + break; + case BT_8822B_2ANT_LBTT_LTE_BREAK_BT: + reg_addr = 0xb4; + break; + } + + if (reg_addr != 0x0000) + halbtc8822b2ant_ltecoex_indirect_write_reg(btcoexist, reg_addr, + 0xff, table_content); /* 0xa8[15:0] or 0xb4[15:0] */ + + +} + + +void halbtc8822b2ant_set_coex_table(IN struct btc_coexist *btcoexist, + IN u32 val0x6c0, IN u32 val0x6c4, IN u32 val0x6c8, IN u8 val0x6cc) +{ + btcoexist->btc_write_4byte(btcoexist, 0x6c0, val0x6c0); + + btcoexist->btc_write_4byte(btcoexist, 0x6c4, val0x6c4); + + btcoexist->btc_write_4byte(btcoexist, 0x6c8, val0x6c8); + + btcoexist->btc_write_1byte(btcoexist, 0x6cc, val0x6cc); +} + +void halbtc8822b2ant_coex_table(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u32 val0x6c0, IN u32 val0x6c4, + IN u32 val0x6c8, IN u8 val0x6cc) +{ + coex_dm->cur_val0x6c0 = val0x6c0; + coex_dm->cur_val0x6c4 = val0x6c4; + coex_dm->cur_val0x6c8 = val0x6c8; + coex_dm->cur_val0x6cc = val0x6cc; + + if (!force_exec) { + if ((coex_dm->pre_val0x6c0 == coex_dm->cur_val0x6c0) && + (coex_dm->pre_val0x6c4 == coex_dm->cur_val0x6c4) && + (coex_dm->pre_val0x6c8 == coex_dm->cur_val0x6c8) && + (coex_dm->pre_val0x6cc == coex_dm->cur_val0x6cc)) + return; + } + halbtc8822b2ant_set_coex_table(btcoexist, val0x6c0, val0x6c4, val0x6c8, + val0x6cc); + + coex_dm->pre_val0x6c0 = coex_dm->cur_val0x6c0; + coex_dm->pre_val0x6c4 = coex_dm->cur_val0x6c4; + coex_dm->pre_val0x6c8 = coex_dm->cur_val0x6c8; + coex_dm->pre_val0x6cc = coex_dm->cur_val0x6cc; +} + +void halbtc8822b2ant_coex_table_with_type(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 type) +{ + u32 break_table; + u8 select_table; + + coex_sta->coex_table_type = type; + + if (coex_sta->concurrent_rx_mode_on == true) { + break_table = 0xf0ffffff; /* set WL hi-pri can break BT */ + select_table = + 0x3; /* 0xb/0x3,set Tx response = Hi-Pri/LO-Pri (ex: Transmitting ACK,BA,CTS) */ + } else { + break_table = 0xffffff; + select_table = 0x3; + } + + switch (type) { + case 0: + halbtc8822b2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x55555555, break_table, select_table); + break; + case 1: + halbtc8822b2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, break_table, select_table); + break; + case 2: + halbtc8822b2ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5a5a5a5a, break_table, select_table); + break; + case 3: + halbtc8822b2ant_coex_table(btcoexist, force_exec, + 0x5a5a5a5a, 0x5a5a5a5a, break_table, select_table); + break; + case 4: + halbtc8822b2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, break_table, select_table); + break; + case 5: + halbtc8822b2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, break_table, select_table); + break; + case 6: + halbtc8822b2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaa5aaa, break_table, select_table); + break; + case 7: + halbtc8822b2ant_coex_table(btcoexist, force_exec, + 0xa5555555, 0xaa5a5a5a, break_table, select_table); + break; + case 8: + halbtc8822b2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0x5a5a5a5a, break_table, select_table); + break; + case 9: + halbtc8822b2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaa555a, break_table, select_table); + break; + case 10: + halbtc8822b2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaa5aaa, break_table, select_table); + break; + case 11: + halbtc8822b2ant_coex_table(btcoexist, force_exec, + 0x55555555, 0xaaaaa5aa, break_table, select_table); + break; + default: + break; + } +} + +void halbtc8822b2ant_set_fw_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean enable) +{ + u8 h2c_parameter[1] = {0}; + u32 RTL97F_8822B = 0; + + if (RTL97F_8822B == true) + return; + + if (enable) + h2c_parameter[0] |= BIT(0); /* function enable */ + + btcoexist->btc_fill_h2c(btcoexist, 0x63, 1, h2c_parameter); +} + +void halbtc8822b2ant_ignore_wlan_act(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean enable) +{ + coex_dm->cur_ignore_wlan_act = enable; + + if (!force_exec) { + if (coex_dm->pre_ignore_wlan_act == + coex_dm->cur_ignore_wlan_act) + return; + } + halbtc8822b2ant_set_fw_ignore_wlan_act(btcoexist, enable); + + coex_dm->pre_ignore_wlan_act = coex_dm->cur_ignore_wlan_act; +} + +void halbtc8822b2ant_set_lps_rpwm(IN struct btc_coexist *btcoexist, + IN u8 lps_val, IN u8 rpwm_val) +{ + u8 lps = lps_val; + u8 rpwm = rpwm_val; + + btcoexist->btc_set(btcoexist, BTC_SET_U1_LPS_VAL, &lps); + btcoexist->btc_set(btcoexist, BTC_SET_U1_RPWM_VAL, &rpwm); +} + +void halbtc8822b2ant_lps_rpwm(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 lps_val, IN u8 rpwm_val) +{ + coex_dm->cur_lps = lps_val; + coex_dm->cur_rpwm = rpwm_val; + + if (!force_exec) { + if ((coex_dm->pre_lps == coex_dm->cur_lps) && + (coex_dm->pre_rpwm == coex_dm->cur_rpwm)) + return; + } + halbtc8822b2ant_set_lps_rpwm(btcoexist, lps_val, rpwm_val); + + coex_dm->pre_lps = coex_dm->cur_lps; + coex_dm->pre_rpwm = coex_dm->cur_rpwm; +} + +void halbtc8822b2ant_ps_tdma_check_for_power_save_state( + IN struct btc_coexist *btcoexist, IN boolean new_ps_state) +{ + u8 lps_mode = 0x0; + u8 h2c_parameter[5] = {0, 0, 0, 0x40, 0}; + u32 RTL97F_8822B = 0; + + if (RTL97F_8822B == true) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_LPS_MODE, &lps_mode); + + if (lps_mode) { /* already under LPS state */ + if (new_ps_state) { + /* keep state under LPS, do nothing. */ + } else { + /* will leave LPS state, turn off psTdma first */ + /*halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8); */ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } + } else { /* NO PS state */ + if (new_ps_state) { + /* will enter LPS state, turn off psTdma first */ + /*halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, + 8);*/ + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, + h2c_parameter); + } else { + /* keep state under NO PS state, do nothing. */ + } + } +} + +void halbtc8822b2ant_power_save_state(IN struct btc_coexist *btcoexist, + IN u8 ps_type, IN u8 lps_val, IN u8 rpwm_val) +{ + boolean low_pwr_disable = false; + + switch (ps_type) { + case BTC_PS_WIFI_NATIVE: + /* recover to original 32k low power setting */ + low_pwr_disable = false; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_NORMAL_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + case BTC_PS_LPS_ON: + halbtc8822b2ant_ps_tdma_check_for_power_save_state( + btcoexist, true); + halbtc8822b2ant_lps_rpwm(btcoexist, NORMAL_EXEC, + lps_val, rpwm_val); + /* when coex force to enter LPS, do not enter 32k low power. */ + low_pwr_disable = true; + btcoexist->btc_set(btcoexist, + BTC_SET_ACT_DISABLE_LOW_POWER, + &low_pwr_disable); + /* power save must executed before psTdma. */ + btcoexist->btc_set(btcoexist, BTC_SET_ACT_ENTER_LPS, + NULL); + coex_sta->force_lps_on = true; + break; + case BTC_PS_LPS_OFF: + halbtc8822b2ant_ps_tdma_check_for_power_save_state( + btcoexist, false); + btcoexist->btc_set(btcoexist, BTC_SET_ACT_LEAVE_LPS, + NULL); + coex_sta->force_lps_on = false; + break; + default: + break; + } +} + + + +void halbtc8822b2ant_set_fw_pstdma(IN struct btc_coexist *btcoexist, + IN u8 byte1, IN u8 byte2, IN u8 byte3, IN u8 byte4, IN u8 byte5) +{ + u8 h2c_parameter[5] = {0}; + u8 real_byte1 = byte1, real_byte5 = byte5; + boolean ap_enable = false; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_AP_MODE_ENABLE, + &ap_enable); + + if (ap_enable) { + if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], FW for AP mode\n"); + BTC_TRACE(trace_buf); + real_byte1 &= ~BIT(4); + real_byte1 |= BIT(5); + + real_byte5 |= BIT(5); + real_byte5 &= ~BIT(6); + + halbtc8822b2ant_power_save_state(btcoexist, + BTC_PS_WIFI_NATIVE, 0x0, + 0x0); + } + } else if (byte1 & BIT(4) && !(byte1 & BIT(5))) { + + halbtc8822b2ant_power_save_state( + btcoexist, BTC_PS_LPS_ON, 0x50, + 0x4); + } else { + halbtc8822b2ant_power_save_state(btcoexist, BTC_PS_WIFI_NATIVE, + 0x0, + 0x0); + } + + + h2c_parameter[0] = real_byte1; + h2c_parameter[1] = byte2; + h2c_parameter[2] = byte3; + h2c_parameter[3] = byte4; + h2c_parameter[4] = real_byte5; + + coex_dm->ps_tdma_para[0] = real_byte1; + coex_dm->ps_tdma_para[1] = byte2; + coex_dm->ps_tdma_para[2] = byte3; + coex_dm->ps_tdma_para[3] = byte4; + coex_dm->ps_tdma_para[4] = real_byte5; + + btcoexist->btc_fill_h2c(btcoexist, 0x60, 5, h2c_parameter); +} + +void halbtc8822b2ant_ps_tdma(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN boolean turn_on, IN u8 type) +{ + + static u8 psTdmaByte4Modify = 0x0, pre_psTdmaByte4Modify = 0x0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + + coex_dm->cur_ps_tdma_on = turn_on; + coex_dm->cur_ps_tdma = type; + + /* 0x778 = 0x1 at wifi slot (no blocking BT Low-Pri pkts) */ + if ((bt_link_info->slave_role) && (bt_link_info->a2dp_exist)) + psTdmaByte4Modify = 0x1; + else + psTdmaByte4Modify = 0x0; + + if (pre_psTdmaByte4Modify != psTdmaByte4Modify) { + + force_exec = true; + pre_psTdmaByte4Modify = psTdmaByte4Modify; + } + + if (!force_exec) { + if ((coex_dm->pre_ps_tdma_on == coex_dm->cur_ps_tdma_on) && + (coex_dm->pre_ps_tdma == coex_dm->cur_ps_tdma)) + return; + } + + if (coex_dm->cur_ps_tdma_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(on, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** TDMA(off, %d) **********\n", + coex_dm->cur_ps_tdma); + BTC_TRACE(trace_buf); + } + + + if (turn_on) { + switch (type) { + case 1: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x10, 0x03, 0xf1, + 0x54 | psTdmaByte4Modify); + break; + case 2: + default: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x35, 0x03, 0x71, + 0x11 | psTdmaByte4Modify); + break; + case 3: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x3a, 0x3, 0xf1, + 0x10 | psTdmaByte4Modify); + break; + case 4: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x21, 0x3, 0xf1, + 0x10 | psTdmaByte4Modify); + break; + case 5: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x25, 0x3, 0xf1, + 0x10 | psTdmaByte4Modify); + break; + case 6: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x10, 0x3, 0xf1, + 0x10 | psTdmaByte4Modify); + break; + case 7: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x20, 0x3, 0xf1, + 0x10 | psTdmaByte4Modify); + break; + case 11: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x30, 0x03, 0x71, + 0x10 | psTdmaByte4Modify); + break; + case 12: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x21, 0x03, 0x71, + 0x11 | psTdmaByte4Modify); + break; + case 13: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x1c, 0x03, 0x71, + 0x10 | psTdmaByte4Modify); + break; + case 14: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x30, 0x03, 0x71, + 0x11); + break; + case 51: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x10, 0x03, 0xf1, + 0x10 | psTdmaByte4Modify); + break; + case 101: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x10, 0x03, 0x70, + 0x54 | psTdmaByte4Modify); + break; + case 102: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xe3, + 0x35, 0x03, 0x71, + 0x11 | psTdmaByte4Modify); + break; + case 103: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x3a, 0x3, 0x70, + 0x50 | psTdmaByte4Modify); + break; + case 104: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x21, 0x3, 0x70, + 0x50 | psTdmaByte4Modify); + break; + case 105: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x25, 0x3, 0x70, + 0x50 | psTdmaByte4Modify); + break; + case 106: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x10, 0x3, 0x70, + 0x50 | psTdmaByte4Modify); + break; + case 107: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x20, 0x3, 0x70, + 0x50 | psTdmaByte4Modify); + break; + case 151: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0xd3, + 0x10, 0x03, 0x70, + 0x50 | psTdmaByte4Modify); + break; + } + } else { + /* disable PS tdma */ + switch (type) { + case 0: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x40, 0x0); + break; + case 1: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x48, 0x0); + break; + default: + halbtc8822b2ant_set_fw_pstdma(btcoexist, 0x0, + 0x0, 0x0, 0x40, 0x0); + break; + } + } + + /* update pre state */ + coex_dm->pre_ps_tdma_on = coex_dm->cur_ps_tdma_on; + coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; +} + +void halbtc8822b2ant_set_ext_band_switch(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 pos_type) +{ + +#if 0 + boolean switch_polatiry_inverse = false; + u8 regval_0xcb6; + u32 u32tmp1 = 0, u32tmp2 = 0; + + if (!rfe_type->ext_band_switch_exist) + return; + + coex_dm->cur_ext_band_switch_status = pos_type; + + if (!force_exec) { + if (coex_dm->pre_ext_band_switch_status == + coex_dm->cur_ext_band_switch_status) + return; + } + + coex_dm->pre_ext_band_switch_status = + coex_dm->cur_ext_band_switch_status; + + /* swap control polarity if use different switch control polarity*/ + switch_polatiry_inverse = (rfe_type->ext_band_switch_ctrl_polarity == 1 + ? ~switch_polatiry_inverse : switch_polatiry_inverse); + + /*swap control polarity for WL_A, default polarity 0xcb4[21] = 0 && 0xcb4[23] = 1 is for WL_G */ + switch_polatiry_inverse = (pos_type == + BT_8822B_2ANT_EXT_BAND_SWITCH_TO_WLA ? ~switch_polatiry_inverse + : switch_polatiry_inverse); + + regval_0xcb6 = btcoexist->btc_read_1byte(btcoexist, 0xcb6); + + /* for normal switch polrity, 0xcb4[21] =1 && 0xcb4[23] = 0 for WL_A, vice versa */ + regval_0xcb6 = (switch_polatiry_inverse == 1 ? ((regval_0xcb6 & (~(BIT( + 7)))) | BIT(5)) : ((regval_0xcb6 & (~(BIT(5)))) | BIT(7))); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb6, 0xff, + regval_0xcb6); + + u32tmp1 = btcoexist->btc_read_4byte(btcoexist, 0xcb0); + u32tmp2 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (After Ext Band switch setup) 0xcb0 = 0x%08x, 0xcb4 = 0x%08x**********\n", + u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); +#endif + +} + +/*anttenna control by bb mac bt antdiv pta to write 0x4c 0xcb4,0xcbd*/ +void halbtc8822b2ant_set_ext_ant_switch(IN struct btc_coexist *btcoexist, + IN boolean force_exec, IN u8 ctrl_type, IN u8 pos_type) +{ + + struct btc_board_info *board_info = &btcoexist->board_info; + boolean switch_polatiry_inverse = false; + u8 regval_0xcbc = 0, regval_0x64; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + + if (!rfe_type->ext_ant_switch_exist) + return; + + coex_dm->cur_ext_ant_switch_status = (ctrl_type << 8) + pos_type; + + if (!force_exec) { + if (coex_dm->pre_ext_ant_switch_status == + coex_dm->cur_ext_ant_switch_status) + return; +} + coex_dm->pre_ext_ant_switch_status = coex_dm->cur_ext_ant_switch_status; + /* + switch (pos_type) { + default: + case BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_BT: + case BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_NOCARE: + break; + case BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_WLG: + break; + case BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_WLA: + break; + } +*/ + if (board_info->ant_div_cfg) + /*ctrl_type = BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV;*/ + + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + + + switch (ctrl_type) { + default: + case BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, + 0xff, 0x77); /* BB SW, DPDT use RFE_ctrl8 and RFE_ctrl9 as conctrol pin */ + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x03, 01); + + break; + case BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_PTA: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); /* 0x4c[24] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, + 0xff, 0x66); /* PTA, DPDT use RFE_ctrl8 and RFE_ctrl9 as conctrol pin */ + + regval_0xcbc = (switch_polatiry_inverse == false ? + 0x2 : 0x1); /* 0xcb4[29:28] = 2b'10 for no switch_polatiry_inverse, DPDT_SEL_N =1, DPDT_SEL_P =0 @ GNT_BT=1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbc, + 0x03, regval_0xcbc); + + break; + case BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1);/* 0x4c[24] = 1 */ +btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb4, 0xff, 0x88); +break; + case BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_MAC: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x1); /* 0x4c[23] = 1 */ + + regval_0x64 = (switch_polatiry_inverse == false ? 0x0 : + 0x1); /* 0x64[0] = 1b'0 for no switch_polatiry_inverse, DPDT_SEL_N =1, DPDT_SEL_P =0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x64, 0x1, + regval_0x64); + break; + case BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_BT: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x0); /* 0x4c[24] = 0 */ + + /* no setup required, because antenna switch control value by BT vendor 0x1c[1:0] */ + break; + } + + /* PAPE, LNA_ON control by BT while WLAN off for current leakage issue */ + if (ctrl_type == BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_BT) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, + 0x0); /* PAPE 0x64[29] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x10, + 0x0); /* LNA_ON 0x64[28] = 0 */ + } else { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x20, + 0x1); /* PAPE 0x64[29] = 1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x67, 0x10, + 0x1); /* LNA_ON 0x64[28] = 1 */ + } + +#if BT_8822B_2ANT_COEX_DBG + + u32tmp1 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u32tmp2 = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0x64) & 0xff; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], (After Ext Ant switch setup) 0xcb4 = 0x%08x, 0x4c = 0x%08x, 0x64= 0x%02x\n", + u32tmp1, u32tmp2, u32tmp3); + BTC_TRACE(trace_buf); +#endif + + + +} +/*rf4 type by efuse , and for ant at main aux inverse use , because is 2x2 ,and control types are the same ,does not need */ +void halbtc8822b2ant_set_rfe_type(IN struct btc_coexist *btcoexist) +{ + + struct btc_board_info *board_info = &btcoexist->board_info; + + + rfe_type->ext_band_switch_exist = false; + rfe_type->ext_band_switch_type = + BT_8822B_2ANT_EXT_BAND_SWITCH_USE_SPDT; /* SPDT; */ + rfe_type->ext_band_switch_ctrl_polarity = 0; + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + + if (rfe_type->ext_band_switch_exist) { + + /* band switch use RFE_ctrl1 (pin name: PAPE_A) and RFE_ctrl3 (pin name: LNAON_A) */ + + /* set RFE_ctrl1 as software control */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb0, 0xf0, 0x7); + + /* set RFE_ctrl3 as software control */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcb1, 0xf0, 0x7); + + } + + + /* the following setup should be got from Efuse in the future */ + rfe_type->rfe_module_type = board_info->rfe_type; + + rfe_type->ext_ant_switch_ctrl_polarity = 0; + + switch (rfe_type->rfe_module_type) { + case 0: + default: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 1: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 2: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 3: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 4: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = + BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 5: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 6: + rfe_type->ext_ant_switch_exist = true; + rfe_type->ext_ant_switch_type = BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + case 7: + rfe_type->ext_ant_switch_exist = true; +rfe_type->ext_ant_switch_type = BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT; + break; + } + +#if 0 + + if (rfe_type->wlg_Locate_at_btg) + halbtc8822b2ant_set_int_block(btcoexist, FORCE_EXEC, + BT_8822B_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_BTG); + else + halbtc8822b2ant_set_int_block(btcoexist, FORCE_EXEC, + BT_8822B_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_WLAG); +#endif + +} + +/*set gnt_wl gnt_bt control by sw high low , or hwpta while in power on,ini,wlan off,wlan only ,wl2g non-currrent ,wl2g current,wl5g*/ +void halbtc8822b2ant_set_ant_path(IN struct btc_coexist *btcoexist, + IN u8 ant_pos_type, IN boolean force_exec, + IN u8 phase) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u32 cnt_bt_cal_chk = 0; + boolean is_in_mp_mode = false; + u8 u8tmp = 0; + u32 u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + u16 u16tmp1 = 0; + /* Ext switch buffer mux */ + btcoexist->btc_write_1byte(btcoexist, 0x974, 0xff); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x1991, 0x3, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbe, 0x8, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); /* 0x4c[24] = 1 */ + + coex_dm->cur_ant_pos_type = (ant_pos_type << 8) + phase; + + if (!force_exec) { + if (coex_dm->cur_ant_pos_type == coex_dm->pre_ant_pos_type) + return; + } + + coex_dm->pre_ant_pos_type = coex_dm->cur_ant_pos_type; + +#if BT_8822B_2ANT_COEX_DBG + u32tmp1 = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0x38); + u32tmp2 = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0x54); + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], (Before Ant Setup) 0xcb4 = 0x%x, 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x\n", + u32tmp3, u8tmp, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); +#endif + + switch (phase) { + case BT_8822B_2ANT_PHASE_COEX_POWERON: + + /* set Path control owner to WL at initial step */ + halbtc8822b2ant_ltecoex_pathcontrol_owner(btcoexist, + BT_8822B_2ANT_PCO_BTSIDE); + + /* set GNT_BT to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + + coex_sta->run_time_state = false; + + break; + case BT_8822B_2ANT_PHASE_COEX_INIT: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x1); /* 0x4c[24] = 1 */ + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8822b2ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8822b2ant_ltecoex_set_coex_table( + btcoexist, + BT_8822B_2ANT_CTT_WL_VS_LTE, + 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8822b2ant_ltecoex_set_coex_table( + btcoexist, + BT_8822B_2ANT_CTT_BT_VS_LTE, + 0xffff); + + /* set Path control owner to WL at initial step */ + halbtc8822b2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8822B_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + + coex_sta->run_time_state = false; + + break; + case BT_8822B_2ANT_PHASE_WLANONLY_INIT: + /* Disable LTE Coex Function in WiFi side (this should be on if LTE coex is required) */ + halbtc8822b2ant_ltecoex_enable(btcoexist, 0x0); + + /* GNT_WL_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8822b2ant_ltecoex_set_coex_table( + btcoexist, + BT_8822B_2ANT_CTT_WL_VS_LTE, + 0xffff); + + /* GNT_BT_LTE always = 1 (this should be config if LTE coex is required) */ + halbtc8822b2ant_ltecoex_set_coex_table( + btcoexist, + BT_8822B_2ANT_CTT_BT_VS_LTE, + 0xffff); + + /* set Path control owner to WL at initial step */ + halbtc8822b2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8822B_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Low */ + halbtc8822b2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_LOW); + /* Set GNT_WL to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + + coex_sta->run_time_state = false; + + + break; + case BT_8822B_2ANT_PHASE_WLAN_OFF: + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4e, + 0x80, 0x0); /* 0x4c[23] = 0 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4f, + 0x01, 0x0); /* 0x4c[24] = 0 */ + /* Disable LTE Coex Function in WiFi side */ + halbtc8822b2ant_ltecoex_enable(btcoexist, 0x0); + + /* set Path control owner to BT */ + halbtc8822b2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8822B_2ANT_PCO_BTSIDE); + + /* Set Ext Ant Switch to BT control at wifi off step */ + halbtc8822b2ant_set_ext_ant_switch(btcoexist, + FORCE_EXEC, + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_BT, + BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_NOCARE); + coex_sta->run_time_state = false; + break; + case BT_8822B_2ANT_PHASE_2G_RUNTIME: + case BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT: + + /* set Path control owner to WL at runtime step */ + halbtc8822b2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8822B_2ANT_PCO_WLSIDE); + + if (phase == + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT) { + /* set GNT_BT to PTA */ + halbtc8822b2ant_ltecoex_set_gnt_bt( + btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8822B_2ANT_SIG_STA_SET_BY_HW); + + /* Set GNT_WL to SW High */ + halbtc8822b2ant_ltecoex_set_gnt_wl( + btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ************* under2g 0xcbd setting =2 *************\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x03, 02); + } else { + /* set GNT_BT to PTA */ + halbtc8822b2ant_ltecoex_set_gnt_bt( + btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8822B_2ANT_SIG_STA_SET_BY_HW); + + /* Set GNT_WL to PTA */ + halbtc8822b2ant_ltecoex_set_gnt_wl( + btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_PTA, + BT_8822B_2ANT_SIG_STA_SET_BY_HW); + } + coex_sta->run_time_state = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ************* under2g 0xcbd setting =2 *************\n"); + BTC_TRACE(trace_buf); + +btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, 0x03, 02); + break; + case BT_8822B_2ANT_PHASE_5G_RUNTIME: + + /* set Path control owner to WL at runtime step */ + halbtc8822b2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8822B_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Hi */ + halbtc8822b2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW Hi */ + halbtc8822b2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + coex_sta->run_time_state = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ************* under5g 0xcbd setting =1 *************\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0xcbd, + 0x03, 01); + + break; + case BT_8822B_2ANT_PHASE_BTMPMODE: + /* Disable LTE Coex Function in WiFi side */ + halbtc8822b2ant_ltecoex_enable(btcoexist, 0x0); + + /* set Path control owner to WL */ + halbtc8822b2ant_ltecoex_pathcontrol_owner( + btcoexist, + BT_8822B_2ANT_PCO_WLSIDE); + + /* set GNT_BT to SW Hi */ + halbtc8822b2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + + /* Set GNT_WL to SW Lo */ + halbtc8822b2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_LOW); + +coex_sta->run_time_state = false; + break; + } +#if BT_8822B_2ANT_COEX_DBG + u32tmp1 = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u8tmp = btcoexist->btc_read_1byte(btcoexist, 0x73); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], (After Ant-Setup phase---%d) 0xcb4 = 0x%x, 0x73 = 0x%x, 0x38= 0x%x, 0x54= 0x%x\n", + phase, u32tmp3, u8tmp, u32tmp1, u32tmp2); + + BTC_TRACE(trace_buf); +#endif + +} + + +u8 halbtc8822b2ant_action_algorithm(IN struct btc_coexist *btcoexist) +{ + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean bt_hs_on = false; + u8 algorithm = BT_8822B_2ANT_COEX_ALGO_UNDEFINED; + u8 num_of_diff_profile = 0; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); + + if (!bt_link_info->bt_link_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No BT link exists!!!\n"); + BTC_TRACE(trace_buf); + return algorithm; + } + + if (bt_link_info->sco_exist) + num_of_diff_profile++; + if (bt_link_info->hid_exist) + num_of_diff_profile++; + if (bt_link_info->pan_exist) + num_of_diff_profile++; + if (bt_link_info->a2dp_exist) + num_of_diff_profile++; + + if (num_of_diff_profile == 0) { + + if (bt_link_info->acl_busy) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], No-Profile busy\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_2ANT_COEX_ALGO_NOPROFILEBUSY; + } + } else if (num_of_diff_profile == 1) { + if (bt_link_info->sco_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_2ANT_COEX_ALGO_SCO; + } else { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_2ANT_COEX_ALGO_HID; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP only\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(HS) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], PAN(EDR) only\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR; + } + } + } + } else if (num_of_diff_profile == 2) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_2ANT_COEX_ALGO_SCO; + } else if (bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP ==> A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_2ANT_COEX_ALGO_A2DP; + } else if (bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_2ANT_COEX_ALGO_SCO; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_HID_A2DP; + } + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_2ANT_COEX_ALGO_HID; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_A2DP_PANHS; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } + } else if (num_of_diff_profile == 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->a2dp_exist) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP ==> HID + A2DP\n"); + BTC_TRACE(trace_buf); + algorithm = BT_8822B_2ANT_COEX_ALGO_HID_A2DP; + } else if (bt_link_info->hid_exist && + bt_link_info->pan_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR_HID; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR_HID; + } + } else if (bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR_A2DP; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + A2DP + PAN(EDR) ==> HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_PANEDR_A2DP; + } + } + } else { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], HID + A2DP + PAN(EDR)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } else if (num_of_diff_profile >= 3) { + if (bt_link_info->sco_exist) { + if (bt_link_info->hid_exist && + bt_link_info->pan_exist && + bt_link_info->a2dp_exist) { + if (bt_hs_on) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCO + HID + A2DP + PAN(EDR)==>PAN(EDR)+HID\n"); + BTC_TRACE(trace_buf); + algorithm = + BT_8822B_2ANT_COEX_ALGO_HID_A2DP_PANEDR; + } + } + } + } + + return algorithm; +} + + + +void halbtc8822b2ant_action_coex_all_off(IN struct btc_coexist *btcoexist) +{ + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + /* fw all off */ + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + +} + +void halbtc8822b2ant_action_wifi_under5g(IN struct btc_coexist *btcoexist) +{ + + /* fw all off */ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ************* under5g *************\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_2ANT_PHASE_5G_RUNTIME); +} + + +void halbtc8822b2ant_action_bt_inquiry(IN struct btc_coexist *btcoexist) +{ + + boolean wifi_connected = false; + boolean scan = false, link = false, roam = false; + boolean wifi_busy = false; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (link || roam || coex_sta->wifi_is_high_pri_task) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi link/roam/hi-pri-task process + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 8); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + + } else if (scan) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi scan process + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 8); + + if (coex_sta->bt_create_connection) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 12); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 11); + + } else if (wifi_connected) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 8); + + if (wifi_busy) { + + if ((bt_link_info->a2dp_exist) && + (bt_link_info->acl_busy)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 13); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 11); + + } else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 13); + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi no-link + BT Inq/Page!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8822b2ant_action_wifi_link_process(IN struct btc_coexist *btcoexist) +{ + u32 u32tmp, u32tmpb; + u8 u8tmpa; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 7); + + if ((bt_link_info->a2dp_exist) && (bt_link_info->acl_busy)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 14); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + +} + + +void halbtc8822b2ant_action_wifi_nonconnected(IN struct btc_coexist *btcoexist) +{ + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + /* fw all off */ + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); +} + +void halbtc8822b2ant_action_bt_idle(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + + boolean wifi_connected = false; + boolean scan = false, link = false, roam = false; + boolean wifi_busy = false; + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi link process + BT Idle!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 11); + } else if (wifi_connected) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi connected + BT Idle!!\n"); + BTC_TRACE(trace_buf); + + if (wifi_busy) { + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + /* + if (!BTC_RSSI_HIGH(bt_rssi_state2)) + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 2); + else { + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + } + */ + } else { + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + } + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Wifi no-link + BT Idle!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, FORCE_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + +} + + +/* SCO only or SCO+PAN(HS) */ +void halbtc8822b2ant_action_sco(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } + +} + + +void halbtc8822b2ant_action_hid(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; +/* + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); +*/ + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 3); + +/* + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 10); +*/ + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } + +} + +/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */ +void halbtc8822b2ant_action_a2dp(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->scan_ap_num <= 4)) + wifi_turbo = true; +#endif + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + if (coex_sta->is_setupLink) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 51); + else { + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 1); + } + } else + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 2); + } else { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (wifi_turbo) + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + if (wifi_busy) { + if (coex_sta->is_setupLink) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 151); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 101); + } else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 102); + + } + +} + +void halbtc8822b2ant_action_pan_edr(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->scan_ap_num <= 4)) + wifi_turbo = true; +#endif + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + +#if 0 + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +#endif + + +#if 1 + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + } else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 4); + } else { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (wifi_turbo) + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + if (wifi_busy) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 103); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 104); + + } + +#endif + +} + + +/* PAN(HS) only */ +void halbtc8822b2ant_action_pan_hs(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->scan_ap_num <= 4)) + wifi_turbo = true; +#endif + + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + + } else { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } + +} + + +void halbtc8822b2ant_action_hid_a2dp(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + + + + if (wifi_busy) { + if (coex_sta->is_setupLink) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 51); + else + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + /* + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, 1); + */ + } else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 2); + + + } else { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if ((wifi_busy) && (coex_sta->hid_busy_num >= 2)) + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + /* + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 9); + */ + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 4); + + if (wifi_busy) { + if (coex_sta->is_setupLink) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 151); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 101); + } else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 102); + + } + +} + + +void halbtc8822b2ant_action_a2dp_pan_hs(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->scan_ap_num <= 4)) + wifi_turbo = true; +#endif + + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + } else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 6); + + } else { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (wifi_turbo) + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + if (wifi_busy) { + + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 107); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 105); + } else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 106); + + } + +} + + + +/* PAN(EDR)+A2DP */ +void halbtc8822b2ant_action_pan_edr_a2dp(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false, wifi_turbo = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], scan_ap_num = %d\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + +#if 1 + if ((wifi_busy) && (coex_sta->scan_ap_num <= 4)) + wifi_turbo = true; +#endif + + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + + if (((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) || + (!coex_sta->is_A2DP_3M)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + else + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + } else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 6); + } else { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + if (wifi_turbo) + halbtc8822b2ant_coex_table_with_type(btcoexist, + NORMAL_EXEC, 6); + else + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, + 7); + + if (wifi_busy) { + + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 107); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 105); + } else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 106); + + } + +} + +void halbtc8822b2ant_action_pan_edr_hid(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 3); + else + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 4); + + + } else { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + + if (wifi_busy) + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 103); + else + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 104); + + } + +} + +/* HID+A2DP+PAN(EDR) */ +void halbtc8822b2ant_action_hid_a2dp_pan_edr(IN struct btc_coexist *btcoexist) +{ + static u8 prewifi_rssi_state = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state, bt_rssi_state; + + static u8 prewifi_rssi_state2 = BTC_RSSI_STATE_LOW; + static u8 pre_bt_rssi_state2 = BTC_RSSI_STATE_LOW; + u8 wifi_rssi_state2, bt_rssi_state2; + boolean wifi_busy = false; + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + + wifi_rssi_state = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state, 2, + coex_sta->wifi_coex_thres , 0); + + wifi_rssi_state2 = halbtc8822b2ant_wifi_rssi_state(btcoexist, + &prewifi_rssi_state2, 2, + coex_sta->wifi_coex_thres2 , 0); + + bt_rssi_state = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state, 2, + coex_sta->bt_coex_thres , 0); + + bt_rssi_state2 = halbtc8822b2ant_bt_rssi_state(&pre_bt_rssi_state2, 2, + coex_sta->bt_coex_thres2 , 0); + + + if (BTC_RSSI_HIGH(wifi_rssi_state) && + BTC_RSSI_HIGH(bt_rssi_state)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + } else if (BTC_RSSI_HIGH(wifi_rssi_state2) && + BTC_RSSI_HIGH(bt_rssi_state2)) { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xc8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 2); + + coex_dm->is_switch_to_1dot5_ant = false; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 4); + + if (wifi_busy) { + + if (((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) || + (!coex_sta->is_A2DP_3M)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 7); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 5); + } else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 6); + } else { + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_dm->is_switch_to_1dot5_ant = true; + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 1); + + if (wifi_busy) { + + if ((coex_sta->a2dp_bit_pool > 40) && + (coex_sta->a2dp_bit_pool < 255)) + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 107); + else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, + true, 105); + } else + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, true, + 106); + } + +} + + + +void halbtc8822b2ant_action_bt_whck_test(IN struct btc_coexist *btcoexist) +{ + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +} + +void halbtc8822b2ant_action_wifi_multi_port(IN struct btc_coexist *btcoexist) +{ + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + /* hw all off */ + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); +} + +void halbtc8822b2ant_run_coexist_mechanism(IN struct btc_coexist *btcoexist) +{ + u8 algorithm = 0; + u32 num_of_wifi_link = 0; + u32 wifi_link_status = 0; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + boolean miracast_plus_bt = false; + boolean scan = false, link = false, roam = false, + wifi_connected = false, wifi_under_5g = false; + + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism()===>\n"); + BTC_TRACE(trace_buf); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Manual CTRL <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RunCoexistMechanism(), return for Stop Coex DM <===\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->under_ips) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], wifi is under IPS !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (!coex_sta->run_time_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], return for run_time_state = false !!!\n"); + BTC_TRACE(trace_buf); + return; + } + + if (coex_sta->freeze_coexrun_by_btinfo) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), return for freeze_coexrun_by_btinfo\n"); + BTC_TRACE(trace_buf); + return; + } + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 5G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_action_wifi_under5g(btcoexist); + return; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 2G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME); + + + if (coex_sta->bt_whck_test) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under WHCK TEST!!!\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_bt_whck_test(btcoexist); + return; + } + + if (coex_sta->bt_disabled) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is disabled!!!\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_coex_all_off(btcoexist); + return; + } + + if (coex_sta->c2h_bt_inquiry_page) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT is under inquiry/page scan !!\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_bt_inquiry(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_SCAN, &scan); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_LINK, &link); + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_ROAM, &roam); + + if (scan || link || roam) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under Link Process !!\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_wifi_link_process(btcoexist); + return; + } + + /* for P2P */ + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_LINK_STATUS, + &wifi_link_status); + num_of_wifi_link = wifi_link_status >> 16; + + if ((num_of_wifi_link >= 2) || + (wifi_link_status & WIFI_P2P_GO_CONNECTED)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "############# [BTCoex], Multi-Port num_of_wifi_link = %d, wifi_link_status = 0x%x\n", + num_of_wifi_link, wifi_link_status); + BTC_TRACE(trace_buf); + + if (bt_link_info->bt_link_exist) + miracast_plus_bt = true; + else + miracast_plus_bt = false; + + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + halbtc8822b2ant_action_wifi_multi_port(btcoexist); + + return; + } + + miracast_plus_bt = false; + btcoexist->btc_set(btcoexist, BTC_SET_BL_MIRACAST_PLUS_BT, + &miracast_plus_bt); + + + algorithm = halbtc8822b2ant_action_algorithm(btcoexist); + coex_dm->cur_algorithm = algorithm; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Algorithm = %d\n", + coex_dm->cur_algorithm); + BTC_TRACE(trace_buf); + + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + if (!wifi_connected) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, wifi non-connected!!.\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_wifi_nonconnected(btcoexist); + + } else if ((BT_8822B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) || + (BT_8822B_2ANT_BT_STATUS_CONNECTED_IDLE == + coex_dm->bt_status)) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, bt idle!!.\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_action_bt_idle(btcoexist); + + } else { + + if (coex_dm->cur_algorithm != coex_dm->pre_algorithm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], pre_algorithm=%d, cur_algorithm=%d\n", + coex_dm->pre_algorithm, coex_dm->cur_algorithm); + BTC_TRACE(trace_buf); + } + + switch (coex_dm->cur_algorithm) { + + case BT_8822B_2ANT_COEX_ALGO_SCO: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = SCO.\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_sco(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID.\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_hid(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_a2dp(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_A2DP_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = A2DP+PAN(HS).\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_a2dp_pan_hs(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR).\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_pan_edr(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_PANHS: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HS mode.\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_pan_hs(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_PANEDR_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_pan_edr_a2dp(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_PANEDR_HID: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = PAN(EDR)+HID.\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_pan_edr_hid(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_HID_A2DP_PANEDR: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP+PAN.\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_hid_a2dp_pan_edr( + btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_HID_A2DP: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = HID+A2DP.\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_hid_a2dp(btcoexist); + break; + case BT_8822B_2ANT_COEX_ALGO_NOPROFILEBUSY: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = No-Profile busy.\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_bt_idle(btcoexist); + break; + default: + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Action 2-Ant, algorithm = coexist All Off!!\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_action_coex_all_off(btcoexist); + break; + } + coex_dm->pre_algorithm = coex_dm->cur_algorithm; + } +} + +void halbtc8822b2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Coex Mechanism Init!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_low_penalty_ra(btcoexist, NORMAL_EXEC, false); + + halbtc8822b2ant_coex_table_with_type(btcoexist, NORMAL_EXEC, 0); + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, NORMAL_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT); + + /* fw all off */ + halbtc8822b2ant_ps_tdma(btcoexist, NORMAL_EXEC, false, 0); + + halbtc8822b2ant_fw_dac_swing_lvl(btcoexist, NORMAL_EXEC, 0xd8); + halbtc8822b2ant_dec_bt_pwr(btcoexist, NORMAL_EXEC, 0); + + coex_sta->pop_event_cnt = 0; + coex_sta->cnt_RemoteNameReq = 0; + coex_sta->cnt_ReInit = 0; + coex_sta->cnt_setupLink = 0; + coex_sta->cnt_IgnWlanAct = 0; + coex_sta->cnt_Page = 0; + + halbtc8822b2ant_query_bt_info(btcoexist); +} + + +void halbtc8822b2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + u8 u8tmp = 0; + u32 vendor; + u32 u32tmp0 = 0, u32tmp1 = 0, u32tmp2 = 0, u32tmp3 = 0; + u32 RTL97F_8822B = 0; + + + u32tmp3 = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u32tmp1 = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp2 = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + + if (RTL97F_8822B == true) { + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x66, 0x04, 0x0); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x41, 0x02, 0x0); + + /* set GNT_BT to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_bt(btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + /* Set GNT_WL to SW high */ + halbtc8822b2ant_ltecoex_set_gnt_wl(btcoexist, + BT_8822B_2ANT_GNT_BLOCK_RFC_BB, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH); + return; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], (Before Init HW config) 0xcb4 = 0x%x, 0x38= 0x%x, 0x54= 0x%x\n", + u32tmp3, u32tmp1, u32tmp2); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], 2Ant Init HW Config!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->bt_coex_supported_feature = 0; + coex_sta->bt_coex_supported_version = 0; + coex_sta->bt_ble_scan_type = 0; + coex_sta->bt_ble_scan_para[0] = 0; + coex_sta->bt_ble_scan_para[1] = 0; + coex_sta->bt_ble_scan_para[2] = 0; + coex_sta->bt_reg_vendor_ac = 0xffff; + coex_sta->bt_reg_vendor_ae = 0xffff; + coex_sta->isolation_btween_wb = BT_8822B_2ANT_DEFAULT_ISOLATION; + + /* 0xf0[15:12] --> Chip Cut information */ + coex_sta->cut_version = (btcoexist->btc_read_1byte(btcoexist, + 0xf1) & 0xf0) >> 4; + + coex_sta->dis_ver_info_cnt = 0; + + halbtc8822b2ant_coex_switch_threshold(btcoexist, + coex_sta->isolation_btween_wb); + + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x550, 0x8, + 0x1); /* enable TBTT nterrupt */ + + /* BT report packet sample rate */ + btcoexist->btc_write_1byte(btcoexist, 0x790, 0x5); + + /* Init 0x778 = 0x1 for 2-Ant */ + btcoexist->btc_write_1byte(btcoexist, 0x778, 0x1); + + /* Enable PTA (3-wire function form BT side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x40, 0x20, 0x1); + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x41, 0x02, 0x1); + + /* Enable PTA (tx/rx signal form WiFi side) */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x4c6, 0x10, 0x1); + + halbtc8822b2ant_enable_gnt_to_gpio(btcoexist, true); + + /*GNT_BT=1 while select both */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x763, 0x10, 0x1); + + + /* check if WL firmware download ok */ + /*if (btcoexist->btc_read_1byte(btcoexist, 0x80) == 0xc6)*/ + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ONOFF, true); + + /* Enable counter statistics */ + btcoexist->btc_write_1byte(btcoexist, 0x76e, + 0x4); /* 0x76e[3] =1, WLAN_Act control by PTA */ + + /* WLAN_Tx by GNT_WL 0x950[29] = 0 */ + /* btcoexist->btc_write_1byte_bitmask(btcoexist, 0x953, 0x20, 0x0); */ + + halbtc8822b2ant_coex_table_with_type(btcoexist, FORCE_EXEC, 0); + + halbtc8822b2ant_ps_tdma(btcoexist, FORCE_EXEC, false, 0); + + psd_scan->ant_det_is_ant_det_available = true; + + if (wifi_only) { + coex_sta->concurrent_rx_mode_on = false; + /* Path config */ + /* Set Antenna Path */ + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_WLANONLY_INIT); + + btcoexist->stop_coex_dm = true; + } else { + /*Set BT polluted packet on for Tx rate adaptive not including Tx retry break by PTA, 0x45c[19] =1 */ + btcoexist->btc_write_1byte_bitmask(btcoexist, 0x45e, 0x8, 0x1); + + coex_sta->concurrent_rx_mode_on = true; + /* btcoexist->btc_write_1byte_bitmask(btcoexist, 0x953, 0x2, 0x1); */ + + /* RF 0x1[1] = 0->Set GNT_WL_RF_Rx always = 1 for con-current Rx, mask Tx only */ + btcoexist->btc_set_rf_reg(btcoexist, BTC_RF_A, 0x1, 0x2, 0x0); + + /* Set Antenna Path */ + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_COEX_INIT); + + btcoexist->stop_coex_dm = false; + } +} + + + +/* ************************************************************ + * work around function start with wa_halbtc8822b2ant_ + * ************************************************************ + * ************************************************************ + * extern function start with ex_halbtc8822b2ant_ + * ************************************************************ */ +void ex_halbtc8822b2ant_power_on_setting(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x0; + u16 u16tmp = 0x0; + u32 value = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Execute 8822b 2-Ant PowerOn Setting xxxxxxxxxxxxxxxx!!\n"); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "Ant Det Finish = %s, Ant Det Number = %d\n", + (board_info->btdm_ant_det_finish ? "Yes" : "No"), + board_info->btdm_ant_num_by_ant_det); + BTC_TRACE(trace_buf); + + + btcoexist->stop_coex_dm = true; + psd_scan->ant_det_is_ant_det_available = false; + + /* enable BB, REG_SYS_FUNC_EN such that we can write BB Register correctly. */ + u16tmp = btcoexist->btc_read_2byte(btcoexist, 0x2); + btcoexist->btc_write_2byte(btcoexist, 0x2, u16tmp | BIT(0) | BIT(1)); + + + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + + /* Check efuse 0xc3[6] for Single Antenna Path */ + if (board_info->single_ant_path == 0) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** Single Antenna, Antenna at Aux Port\n"); + BTC_TRACE(trace_buf); + + board_info->btdm_ant_pos = BTC_ANTENNA_AT_AUX_PORT; + + u8tmp = 7; + } else if (board_info->single_ant_path == 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** Single Antenna, Antenna at Main Port\n"); + BTC_TRACE(trace_buf); + + board_info->btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + + u8tmp = 6; + } + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** (Power On) single_ant_path = %d, btdm_ant_pos = %d\n", + board_info->single_ant_path , board_info->btdm_ant_pos); + BTC_TRACE(trace_buf); + + /* Setup RF front end type */ + halbtc8822b2ant_set_rfe_type(btcoexist); + + /* Set Antenna Path to BT side */ + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_2ANT_PHASE_COEX_POWERON); + + /* Save"single antenna position" info in Local register setting for FW reading, because FW may not ready at power on */ + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x3e0, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_USB) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, u8tmp); + + /* enable GNT_WL/GNT_BT debug signal to GPIO14/15 */ + halbtc8822b2ant_enable_gnt_to_gpio(btcoexist, true); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** LTE coex Reg 0x38 (Power-On) = 0x%x**********\n", + halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x38)); + BTC_TRACE(trace_buf); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** MAC Reg 0x70/ BB Reg 0xcb4 (Power-On) = 0x%x / 0x%x\n", + btcoexist->btc_read_4byte(btcoexist, 0x70), + btcoexist->btc_read_4byte(btcoexist, 0xcb4)); + BTC_TRACE(trace_buf); + +} + +void ex_halbtc8822b2ant_pre_load_firmware(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + u8 u8tmp = 0x4; /* Set BIT2 by default since it's 2ant case */ + + /* */ + /* S0 or S1 setting and Local register setting(By the setting fw can get ant number, S0/S1, ... info) */ + /* Local setting bit define */ + /* BIT0: "0" for no antenna inverse; "1" for antenna inverse */ + /* BIT1: "0" for internal switch; "1" for external switch */ + /* BIT2: "0" for one antenna; "1" for two antenna */ + /* NOTE: here default all internal switch and 1-antenna ==> BIT1=0 and BIT2=0 */ + if (btcoexist->chip_interface == BTC_INTF_USB) { + /* fixed at S0 for USB interface */ + u8tmp |= 0x1; /* antenna inverse */ + btcoexist->btc_write_local_reg_1byte(btcoexist, 0xfe08, u8tmp); + } else { + /* for PCIE and SDIO interface, we check efuse 0xc3[6] */ + if (board_info->single_ant_path == 0) { + } else if (board_info->single_ant_path == 1) { + /* set to S0 */ + u8tmp |= 0x1; /* antenna inverse */ + } + + if (btcoexist->chip_interface == BTC_INTF_PCI) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x3e0, + u8tmp); + else if (btcoexist->chip_interface == BTC_INTF_SDIO) + btcoexist->btc_write_local_reg_1byte(btcoexist, 0x60, + u8tmp); + } +} + + +void ex_halbtc8822b2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only) +{ + halbtc8822b2ant_init_hw_config(btcoexist, wifi_only); +} + +void ex_halbtc8822b2ant_init_coex_dm(IN struct btc_coexist *btcoexist) +{ + + halbtc8822b2ant_init_coex_dm(btcoexist); +} + +void ex_halbtc8822b2ant_display_coex_info(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; + + u8 *cli_buf = btcoexist->cli_buf; + u8 u8tmp[4], i, ps_tdma_case = 0; + u32 u32tmp[4]; + u16 u16tmp[4]; + u32 fa_ofdm, fa_cck, cca_ofdm, cca_cck; + u32 fw_ver = 0, bt_patch_ver = 0, bt_coex_ver = 0; + static u8 pop_report_in_10s = 0; + u32 phyver = 0; + boolean lte_coex_on = false; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[BT Coexist info]============"); + CL_PRINTF(cli_buf); + + if (btcoexist->manual_control) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n ============[Under Manual Control]============"); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n =========================================="); + CL_PRINTF(cli_buf); + } + + if (psd_scan->ant_det_try_count == 0) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %s / %d", + "Ant PG Num/ Mech/ Pos/ RFE", + board_info->pg_ant_num, board_info->btdm_ant_num, + (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT + ? "Main" : "Aux"), + rfe_type->rfe_module_type); + CL_PRINTF(cli_buf); + } else { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ %d/ %s/ %d (%d/%d/%d)", + "Ant PG Num/ Mech(Ant_Det)/ Pos/ RFE", + board_info->pg_ant_num, + board_info->btdm_ant_num_by_ant_det, + (board_info->btdm_ant_pos == BTC_ANTENNA_AT_MAIN_PORT + ? "Main" : "Aux"), + rfe_type->rfe_module_type, + psd_scan->ant_det_try_count, + psd_scan->ant_det_fail_count, + psd_scan->ant_det_result); + CL_PRINTF(cli_buf); + + + if (board_info->btdm_ant_det_finish) { + + if (psd_scan->ant_det_result != 12) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", + "Ant Det PSD Value", + psd_scan->ant_det_peak_val); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d", + "Ant Det PSD Value", + psd_scan->ant_det_psd_scan_peak_val + / 100); + CL_PRINTF(cli_buf); + } + } + + + /*bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver;*/ + bt_patch_ver = btcoexist->bt_info.bt_get_fw_ver; + btcoexist->btc_get(btcoexist, BTC_GET_U4_WIFI_FW_VER, &fw_ver); + phyver = btcoexist->btc_get_bt_phydm_version(btcoexist); + + bt_coex_ver = (coex_sta->bt_coex_supported_version & 0xff); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d_%02x/ 0x%02x/ 0x%02x (%s)", + "CoexVer WL/ BT_Desired/ BT_Report", + glcoex_ver_date_8822b_2ant, glcoex_ver_8822b_2ant, + glcoex_ver_btdesired_8822b_2ant, + bt_coex_ver, + (bt_coex_ver == 0xff ? "Unknown" : + (bt_coex_ver >= glcoex_ver_btdesired_8822b_2ant ? + "Match" : "Mis-Match"))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ v%d/ %c", + "W_FW/ B_FW/ Phy/ Kt", + fw_ver, bt_patch_ver, phyver, + coex_sta->cut_version + 65); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x ", + "AFH Map to BT", + coex_dm->wifi_chnl_info[0], coex_dm->wifi_chnl_info[1], + coex_dm->wifi_chnl_info[2]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d ", + "Isolation/WL_Thres/BT_Thres", + coex_sta->isolation_btween_wb, + coex_sta->wifi_coex_thres, + coex_sta->bt_coex_thres); + CL_PRINTF(cli_buf); + + /* wifi status */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Wifi Status]============"); + CL_PRINTF(cli_buf); + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_WIFI_STATUS); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[BT Status]============"); + CL_PRINTF(cli_buf); + + pop_report_in_10s++; + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = [%s/ %d dBm/ %d/ %d] ", + "BT [status/ rssi/ retryCnt/ popCnt]", + ((coex_sta->bt_disabled) ? ("disabled") : (( + coex_sta->c2h_bt_inquiry_page) ? ("inquiry/page") + : ((BT_8822B_2ANT_BT_STATUS_NON_CONNECTED_IDLE == + coex_dm->bt_status) ? "non-connected idle" : + ((BT_8822B_2ANT_BT_STATUS_CONNECTED_IDLE == coex_dm->bt_status) + ? "connected-idle" : "busy")))), + coex_sta->bt_rssi - 100, coex_sta->bt_retry_cnt, + coex_sta->pop_event_cnt); + CL_PRINTF(cli_buf); + + if (pop_report_in_10s >= 5) { + coex_sta->pop_event_cnt = 0; + pop_report_in_10s = 0; + } + + + if (coex_sta->num_of_profile != 0) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s%s%s%s%s", + "Profiles", + ((bt_link_info->a2dp_exist) ? "A2DP," : ""), + ((bt_link_info->sco_exist) ? "SCO," : ""), + ((bt_link_info->hid_exist) ? + ((coex_sta->hid_busy_num >= 2) ? "HID(4/18)," : + "HID(2/18),") : ""), + ((bt_link_info->pan_exist) ? "PAN," : ""), + ((coex_sta->voice_over_HOGP) ? "Voice" : "")); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = None", "Profiles"); + + CL_PRINTF(cli_buf); + + + if (bt_link_info->a2dp_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %d/ %s", + "A2DP Rate/Bitpool/Auto_Slot", + ((coex_sta->is_A2DP_3M) ? "3M" : "No_3M"), + coex_sta->a2dp_bit_pool, + ((coex_sta->is_autoslot) ? "On" : "Off") + ); + CL_PRINTF(cli_buf); + } + + if (bt_link_info->hid_exist) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "HID PairNum/Forbid_Slot", + coex_sta->hid_pair_cnt, + coex_sta->forbidden_slot + ); + CL_PRINTF(cli_buf); + } + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ 0x%x", + "Role/IgnWlanAct/Feature", + ((bt_link_info->slave_role) ? "Slave" : "Master"), + ((coex_dm->cur_ignore_wlan_act) ? "Yes" : "No"), + coex_sta->bt_coex_supported_feature); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", + "ReInit/ReLink/IgnWlact/Page/NameReq", + coex_sta->cnt_ReInit, + coex_sta->cnt_setupLink, + coex_sta->cnt_IgnWlanAct, + coex_sta->cnt_Page, + coex_sta->cnt_RemoteNameReq + ); + CL_PRINTF(cli_buf); + + halbtc8822b2ant_read_score_board(btcoexist, &u16tmp[0]); + + if ((coex_sta->bt_reg_vendor_ae == 0xffff) || + (coex_sta->bt_reg_vendor_ac == 0xffff)) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = x/ x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", u16tmp[0]); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ %04x", + "0xae[4]/0xac[1:0]/Scoreboard", + ((coex_sta->bt_reg_vendor_ae & BIT(4)) >> 4), + coex_sta->bt_reg_vendor_ac & 0x3, u16tmp[0]); + CL_PRINTF(cli_buf); + + for (i = 0; i < BT_INFO_SRC_8822B_2ANT_MAX; i++) { + if (coex_sta->bt_info_c2h_cnt[i]) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x %02x %02x(%d)", + glbt_info_src_8822b_2ant[i], + coex_sta->bt_info_c2h[i][0], + coex_sta->bt_info_c2h[i][1], + coex_sta->bt_info_c2h[i][2], + coex_sta->bt_info_c2h[i][3], + coex_sta->bt_info_c2h[i][4], + coex_sta->bt_info_c2h[i][5], + coex_sta->bt_info_c2h[i][6], + coex_sta->bt_info_c2h_cnt[i]); + CL_PRINTF(cli_buf); + } + } + + /* Sw mechanism */ + if (btcoexist->manual_control) + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[mechanism] (before Manual)============"); + else + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Mechanism]============"); + + CL_PRINTF(cli_buf); + + + ps_tdma_case = coex_dm->cur_ps_tdma; + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %02x %02x %02x %02x %02x (case-%d, %s, %s)", + "TDMA", + coex_dm->ps_tdma_para[0], coex_dm->ps_tdma_para[1], + coex_dm->ps_tdma_para[2], coex_dm->ps_tdma_para[3], + coex_dm->ps_tdma_para[4], ps_tdma_case, + (coex_dm->cur_ps_tdma_on ? "TDMA On" : "TDMA Off"), + (coex_dm->is_switch_to_1dot5_ant ? "1.5Ant" : "2Ant")); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6c0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x6c4); + u32tmp[2] = btcoexist->btc_read_4byte(btcoexist, 0x6c8); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %d/ 0x%x/ 0x%x/ 0x%x", + "Table/0x6c0/0x6c4/0x6c8", + coex_sta->coex_table_type, u32tmp[0], u32tmp[1], u32tmp[2]); + CL_PRINTF(cli_buf); + + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x778); + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x6cc); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x", + "0x778/0x6cc", + u8tmp[0], u32tmp[0]); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s", + "AntDiv/ForceLPS/LPRA", + ((board_info->ant_div_cfg) ? "On" : "Off"), + ((coex_sta->force_lps_on) ? "On" : "Off"), + ((coex_dm->cur_low_penalty_ra) ? "On" : "Off")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "WL_DACSwing/ BT_Dec_Pwr", coex_dm->cur_fw_dac_swing_lvl, + coex_dm->cur_bt_dec_pwr_lvl); + CL_PRINTF(cli_buf); + + u32tmp[0] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + lte_coex_on = ((u32tmp[0] & BIT(7)) >> 7) ? true : false; + + if (lte_coex_on) { + + u32tmp[0] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0xa0); + u32tmp[1] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0xa4); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", + "LTE Coex Table W_L/B_L", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff); + CL_PRINTF(cli_buf); + + + u32tmp[0] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0xa8); + u32tmp[1] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0xac); + u32tmp[2] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0xb0); + u32tmp[3] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, + 0xb4); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "LTE Break Table W_L/B_L/L_W/L_B", + u32tmp[0] & 0xffff, u32tmp[1] & 0xffff, + u32tmp[2] & 0xffff, u32tmp[3] & 0xffff); + CL_PRINTF(cli_buf); + + } + + /* Hw setting */ + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s", + "============[Hw setting]============"); + CL_PRINTF(cli_buf); + /* + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x430); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0x434); + u16tmp[0] = btcoexist->btc_read_2byte(btcoexist, 0x42a); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x456); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x/0x%x/0x%x", + "0x430/0x434/0x42a/0x456", + u32tmp[0], u32tmp[1], u16tmp[0], u8tmp[0]); + CL_PRINTF(cli_buf); + */ + u32tmp[0] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x38); + u32tmp[1] = halbtc8822b2ant_ltecoex_indirect_read_reg(btcoexist, 0x54); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x73); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s", + "LTE Coex/Path Owner", + ((lte_coex_on) ? "On" : "Off") , + ((u8tmp[0] & BIT(2)) ? "WL" : "BT")); + CL_PRINTF(cli_buf); + + if (lte_coex_on) { + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "LTE 3Wire/OPMode/UART/UARTMode", + (int)((u32tmp[0] & BIT(6)) >> 6), + (int)((u32tmp[0] & (BIT(5) | BIT(4))) >> 4), + (int)((u32tmp[0] & BIT(3)) >> 3), + (int)(u32tmp[0] & (BIT(2) | BIT(1) | BIT(0)))); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "LTE_Busy/UART_Busy", + (int)((u32tmp[1] & BIT(1)) >> 1), (int)(u32tmp[1] & BIT(0))); + CL_PRINTF(cli_buf); + } + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = %s (BB:%s)/ %s (BB:%s)/ %s", + "GNT_WL_Ctrl/GNT_BT_Ctrl/Dbg", + ((u32tmp[0] & BIT(12)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(8)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(14)) ? "SW" : "HW"), + ((u32tmp[0] & BIT(10)) ? "SW" : "HW"), + ((u8tmp[0] & BIT(3)) ? "On" : "Off")); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "GNT_WL/GNT_BT", + (int)((u32tmp[1] & BIT(2)) >> 2), + (int)((u32tmp[1] & BIT(3)) >> 3)); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0xcb0); + u32tmp[1] = btcoexist->btc_read_4byte(btcoexist, 0xcb4); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0xcbd); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%04x/ 0x%04x/ 0x%x", + "0xcb0/0xcb4/0xcbd", + u32tmp[0], u32tmp[1], u8tmp[0]); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x4c); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0x64); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x4c6); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x40); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "0x4c[24:23]/0x64[0]/x4c6[4]/0x40[5]", + (u32tmp[0] & (BIT(24) | BIT(23))) >> 23 , u8tmp[2] & 0x1 , + (int)((u8tmp[0] & BIT(4)) >> 4), + (int)((u8tmp[1] & BIT(5)) >> 5)); + CL_PRINTF(cli_buf); + + u32tmp[0] = btcoexist->btc_read_4byte(btcoexist, 0x550); + u8tmp[0] = btcoexist->btc_read_1byte(btcoexist, 0x522); + u8tmp[1] = btcoexist->btc_read_1byte(btcoexist, 0x953); + u8tmp[2] = btcoexist->btc_read_1byte(btcoexist, 0xc50); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ %s/ 0x%x", + "0x550/0x522/4-RxAGC/0xc50", + u32tmp[0], u8tmp[0], (u8tmp[1] & 0x2) ? "On" : "Off", u8tmp[2]); + CL_PRINTF(cli_buf); + + fa_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_OFDM); + fa_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_FA_CCK); + cca_ofdm = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_OFDM); + cca_cck = btcoexist->btc_phydm_query_PHY_counter(btcoexist, + PHYDM_INFO_CCA_CCK); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, + "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", + "CCK-CCA/CCK-FA/OFDM-CCA/OFDM-FA", + cca_cck, fa_cck, cca_ofdm, fa_ofdm); + CL_PRINTF(cli_buf); + +#if 1 + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_OK CCK/11g/11n/11ac", + coex_sta->crc_ok_cck, coex_sta->crc_ok_11g, + coex_sta->crc_ok_11n, coex_sta->crc_ok_11n_vht); + CL_PRINTF(cli_buf); + + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", + "CRC_Err CCK/11g/11n/11ac", + coex_sta->crc_err_cck, coex_sta->crc_err_11g, + coex_sta->crc_err_11n, coex_sta->crc_err_11n_vht); + CL_PRINTF(cli_buf); +#endif + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x770(Hi-pri rx/tx)", + coex_sta->high_priority_rx, coex_sta->high_priority_tx); + CL_PRINTF(cli_buf); + CL_SPRINTF(cli_buf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", + "0x774(Lo-pri rx/tx)", + coex_sta->low_priority_rx, coex_sta->low_priority_tx); + CL_PRINTF(cli_buf); + + btcoexist->btc_disp_dbg_msg(btcoexist, BTC_DBG_DISP_COEX_STATISTICS); +} + + +void ex_halbtc8822b2ant_ips_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_IPS_ENTER == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS ENTER notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = true; + coex_sta->under_lps = false; + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, false); + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ONOFF, false); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_WLAN_OFF); + + halbtc8822b2ant_action_coex_all_off(btcoexist); + } else if (BTC_IPS_LEAVE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], IPS LEAVE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_ips = false; + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ONOFF, true); + halbtc8822b2ant_init_hw_config(btcoexist, false); + halbtc8822b2ant_init_coex_dm(btcoexist); + halbtc8822b2ant_query_bt_info(btcoexist); + } +} + +void ex_halbtc8822b2ant_lps_notify(IN struct btc_coexist *btcoexist, IN u8 type) +{ + if (btcoexist->manual_control || btcoexist->stop_coex_dm) + return; + + if (BTC_LPS_ENABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS ENABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = true; + coex_sta->under_ips = false; + + if (coex_sta->force_lps_on == true) { /* LPS No-32K */ + /* Write WL "Active" in Score-board for PS-TDMA */ + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + + } else { /* LPS-32K, need check if this h2c 0x71 can work?? (2015/08/28) */ + /* Write WL "Non-Active" in Score-board for Native-PS */ + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, false); + } + + + } else if (BTC_LPS_DISABLE == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], LPS DISABLE notify\n"); + BTC_TRACE(trace_buf); + coex_sta->under_lps = false; + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + } +} + +void ex_halbtc8822b2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean wifi_connected = false; + boolean wifi_under_5g = false; + + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN notify()\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* this can't be removed for RF off_on event, or BT would dis-connect */ + halbtc8822b2ant_query_bt_info(btcoexist); + + if (BTC_SCAN_START == type) { + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, + &wifi_under_5g); + + if (wifi_under_5g) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** SCAN START notify (5g)\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_action_wifi_under5g(btcoexist); + return; + } + + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** SCAN START notify (2g)\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_run_coexist_mechanism( + btcoexist); + + return; + } + + + if (BTC_SCAN_START_2G == type) { + + if (!wifi_connected) + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN START notify (2G)\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_SCAN, true); + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME); + + halbtc8822b2ant_run_coexist_mechanism(btcoexist); + + } else if (BTC_SCAN_FINISH == type) { + + coex_sta->wifi_is_high_pri_task = false; + + btcoexist->btc_get(btcoexist, BTC_GET_U1_AP_NUM, + &coex_sta->scan_ap_num); + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], SCAN FINISH notify (Scan-AP = %d)\n", + coex_sta->scan_ap_num); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_SCAN, false); + + halbtc8822b2ant_run_coexist_mechanism(btcoexist); + } + +} + +void ex_halbtc8822b2ant_switchband_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + + boolean wifi_connected = false, bt_hs_on = false; + u32 wifi_link_status = 0; + u32 num_of_wifi_link = 0; + boolean bt_ctrl_agg_buf_size = false; + u8 agg_buf_size = 5; + + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if (type == BTC_SWITCH_TO_5G) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], switchband_notify --- switch to 5G\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_action_wifi_under5g(btcoexist); + + } else if (type == BTC_SWITCH_TO_24G_NOFORSCAN) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ********** switchband_notify BTC_SWITCH_TO_2G (no for scan)\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_run_coexist_mechanism(btcoexist); + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], switchband_notify --- switch to 2G\n"); + BTC_TRACE(trace_buf); + + ex_halbtc8822b2ant_scan_notify(btcoexist, + BTC_SCAN_START_2G); + } +} + + +void ex_halbtc8822b2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + if ((BTC_ASSOCIATE_5G_START == type) || + (BTC_ASSOCIATE_5G_FINISH == type)) { + + if (BTC_ASSOCIATE_5G_START == type) + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], connect_notify --- 5G start\n"); + else + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], connect_notify --- 5G finish\n"); + + BTC_TRACE(trace_buf); + + halbtc8822b2ant_action_wifi_under5g(btcoexist); + return; + } + + + if (BTC_ASSOCIATE_START == type) { + + coex_sta->wifi_is_high_pri_task = true; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT START notify (2G)\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME); + + halbtc8822b2ant_action_wifi_link_process(btcoexist); + + /* To keep TDMA case during connect process, + to avoid changed by Btinfo and runcoexmechanism */ + coex_sta->freeze_coexrun_by_btinfo = true; + + coex_dm->arp_cnt = 0; + + } else if (BTC_ASSOCIATE_FINISH == type) { + + coex_sta->wifi_is_high_pri_task = false; + coex_sta->freeze_coexrun_by_btinfo = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], CONNECT FINISH notify (2G)\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_run_coexist_mechanism(btcoexist); + } +} + +void ex_halbtc8822b2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + u8 h2c_parameter[3] = {0}; + u32 wifi_bw; + u8 wifi_central_chnl; + u8 ap_num = 0; + boolean wifi_under_b_mode = false, wifi_under_5g = false; + + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (BTC_MEDIA_CONNECT == type) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA connect notify\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + + if (wifi_under_5g) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 5G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_action_wifi_under5g(btcoexist); + return; + } + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, + &wifi_under_b_mode); + + /* Set CCK Tx/Rx high Pri except 11b mode */ + if (wifi_under_b_mode) { + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x00); /* CCK Rx */ + } else { + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, + 0x00); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, + 0x10); /* CCK Rx */ + } + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], MEDIA disconnect notify\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_write_1byte(btcoexist, 0x6cd, 0x0); /* CCK Tx */ + btcoexist->btc_write_1byte(btcoexist, 0x6cf, 0x0); /* CCK Rx */ + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, false); + } + + + halbtc8822b2ant_update_wifi_channel_info(btcoexist, type); +} + +void ex_halbtc8822b2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + boolean under_4way = false, wifi_under_5g = false; + + if (btcoexist->manual_control || + btcoexist->stop_coex_dm) + return; + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (wifi_under_5g) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], WiFi is under 5G!!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_action_wifi_under5g(btcoexist); + return; + } + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, + &under_4way); + + if (under_4way) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ---- under_4way!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + + } else if (BTC_PACKET_ARP == type) { + + coex_dm->arp_cnt++; + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet ARP notify -cnt = %d\n", + coex_dm->arp_cnt); + BTC_TRACE(trace_buf); + + } else { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], specific Packet DHCP or EAPOL notify [Type = %d]\n", + type); + BTC_TRACE(trace_buf); + + coex_sta->wifi_is_high_pri_task = true; + coex_sta->specific_pkt_period_cnt = 2; + } + + if (coex_sta->wifi_is_high_pri_task) + halbtc8822b2ant_run_coexist_mechanism(btcoexist); + +} + +void ex_halbtc8822b2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length) +{ + u8 i, rsp_source = 0; + boolean wifi_connected = false; + + if (psd_scan->is_AntDet_running == true) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], bt_info_notify return for AntDet is running\n"); + BTC_TRACE(trace_buf); + return; + } + + rsp_source = tmp_buf[0] & 0xf; + if (rsp_source >= BT_INFO_SRC_8822B_2ANT_MAX) + rsp_source = BT_INFO_SRC_8822B_2ANT_WIFI_FW; + coex_sta->bt_info_c2h_cnt[rsp_source]++; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Bt_info[%d], len=%d, data=[", rsp_source, + length); + BTC_TRACE(trace_buf); + + for (i = 0; i < length; i++) { + coex_sta->bt_info_c2h[rsp_source][i] = tmp_buf[i]; + + if (i == length - 1) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x]\n", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "0x%02x, ", + tmp_buf[i]); + BTC_TRACE(trace_buf); + } + } + + coex_sta->bt_info = coex_sta->bt_info_c2h[rsp_source][1]; + coex_sta->bt_info_ext = coex_sta->bt_info_c2h[rsp_source][4]; + coex_sta->bt_info_ext2 = coex_sta->bt_info_c2h[rsp_source][5]; + + if (BT_INFO_SRC_8822B_2ANT_WIFI_FW != rsp_source) { + + /* if 0xff, it means BT is under WHCK test */ + coex_sta->bt_whck_test = ((coex_sta->bt_info == 0xff) ? true : + false); + + coex_sta->bt_create_connection = (( + coex_sta->bt_info_c2h[rsp_source][2] & 0x80) ? true : + false); + + /* unit: %, value-100 to translate to unit: dBm */ + coex_sta->bt_rssi = coex_sta->bt_info_c2h[rsp_source][3] * 2 + + 10; + + coex_sta->c2h_bt_remote_name_req = (( + coex_sta->bt_info_c2h[rsp_source][2] & 0x20) ? true : + false); + + coex_sta->is_A2DP_3M = ((coex_sta->bt_info_c2h[rsp_source][2] & + 0x10) ? true : false); + + coex_sta->acl_busy = ((coex_sta->bt_info_c2h[rsp_source][1] & + 0x9) ? true : false); + + coex_sta->voice_over_HOGP = ((coex_sta->bt_info_ext & 0x10) ? + true : false); + + coex_sta->c2h_bt_inquiry_page = ((coex_sta->bt_info & + BT_INFO_8822B_2ANT_B_INQ_PAGE) ? true : false); + + coex_sta->a2dp_bit_pool = ((( + coex_sta->bt_info_c2h[rsp_source][1] & 0x49) == 0x49) ? + coex_sta->bt_info_c2h[rsp_source][6] : 0); + + coex_sta->bt_retry_cnt = coex_sta->bt_info_c2h[rsp_source][2] & + 0xf; + + coex_sta->is_autoslot = coex_sta->bt_info_ext2 & 0x8; + + coex_sta->forbidden_slot = coex_sta->bt_info_ext2 & 0x7; + + coex_sta->hid_busy_num = (coex_sta->bt_info_ext2 & 0x30) >> 4; + + coex_sta->hid_pair_cnt = (coex_sta->bt_info_ext2 & 0xc0) >> 6; + + if (coex_sta->bt_retry_cnt >= 1) + coex_sta->pop_event_cnt++; + + if (coex_sta->c2h_bt_remote_name_req) + coex_sta->cnt_RemoteNameReq++; + + if (coex_sta->bt_info_ext & BIT(1)) + coex_sta->cnt_ReInit++; + + if (coex_sta->bt_info_ext & BIT(2)) { + coex_sta->cnt_setupLink++; + coex_sta->is_setupLink = true; + } else + coex_sta->is_setupLink = false; + + if (coex_sta->bt_info_ext & BIT(3)) + coex_sta->cnt_IgnWlanAct++; + + if (coex_sta->bt_create_connection) + coex_sta->cnt_Page++; + + /* Here we need to resend some wifi info to BT */ + /* because bt is reset and loss of the info. */ + + if ((!btcoexist->manual_control) && + (!btcoexist->stop_coex_dm)) { + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, + &wifi_connected); + + /* Re-Init */ + if ((coex_sta->bt_info_ext & BIT(1))) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit1 check, send wifi BW&Chnl to BT!!\n"); + BTC_TRACE(trace_buf); + if (wifi_connected) + halbtc8822b2ant_update_wifi_channel_info( + btcoexist, BTC_MEDIA_CONNECT); + else + halbtc8822b2ant_update_wifi_channel_info( + btcoexist, + BTC_MEDIA_DISCONNECT); + } + + + /* If Ignore_WLanAct && not SetUp_Link */ + if ((coex_sta->bt_info_ext & BIT(3)) && + (!(coex_sta->bt_info_ext & BIT(2)))) { + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BT ext info bit3 check, set BT NOT to ignore Wlan active!!\n"); + BTC_TRACE(trace_buf); + halbtc8822b2ant_ignore_wlan_act(btcoexist, + FORCE_EXEC, false); + } + } + + } + + + halbtc8822b2ant_update_bt_link_info(btcoexist); + + if (btcoexist->manual_control) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), No run_coexist_mechanism for Manual CTRL\n"); + BTC_TRACE(trace_buf); + return; + } + + if (btcoexist->stop_coex_dm) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], BtInfoNotify(), No run_coexist_mechanism for Stop Coex DM\n"); + BTC_TRACE(trace_buf); + return; + } + + coex_sta->c2h_bt_info_req_sent = false; + + halbtc8822b2ant_run_coexist_mechanism(btcoexist); +} + +void ex_halbtc8822b2ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], RF Status notify\n"); + BTC_TRACE(trace_buf); + + if (BTC_RF_ON == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned ON!!\n"); + BTC_TRACE(trace_buf); + + coex_sta->wl_rf_off_on_event = true; + btcoexist->stop_coex_dm = false; + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ONOFF, true); + } else if (BTC_RF_OFF == type) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], RF is turned OFF!!\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_WLAN_OFF); + + halbtc8822b2ant_action_coex_all_off(btcoexist); + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, false); + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ONOFF, false); + btcoexist->stop_coex_dm = true; + coex_sta->wl_rf_off_on_event = false; + + } +} + +void ex_halbtc8822b2ant_halt_notify(IN struct btc_coexist *btcoexist) +{ + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Halt notify\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_2ANT_PHASE_WLAN_OFF); + + ex_halbtc8822b2ant_media_status_notify(btcoexist, BTC_MEDIA_DISCONNECT); + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, false); + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ONOFF, false); +} + +void ex_halbtc8822b2ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state) +{ + boolean wifi_under_5g = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, "[BTCoex], Pnp notify\n"); + BTC_TRACE(trace_buf); + + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if ((BTC_WIFI_PNP_SLEEP == pnp_state) || + (BTC_WIFI_PNP_SLEEP_KEEP_ANT == pnp_state)) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to SLEEP\n"); + BTC_TRACE(trace_buf); + + /* Sinda 20150819, workaround for driver skip leave IPS/LPS to speed up sleep time. */ + /* Driver do not leave IPS/LPS when driver is going to sleep, so BTCoexistence think wifi is still under IPS/LPS */ + /* BT should clear UnderIPS/UnderLPS state to avoid mismatch state after wakeup. */ + coex_sta->under_ips = false; + coex_sta->under_lps = false; + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, false); + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ONOFF, false); + + + if (BTC_WIFI_PNP_SLEEP_KEEP_ANT == pnp_state) { + + if (wifi_under_5g) + halbtc8822b2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_2ANT_PHASE_5G_RUNTIME); + else + halbtc8822b2ant_set_ant_path(btcoexist, + BTC_ANT_PATH_AUTO, FORCE_EXEC, + BT_8822B_2ANT_PHASE_2G_RUNTIME); + } else { + + halbtc8822b2ant_set_ant_path(btcoexist, BTC_ANT_PATH_AUTO, + FORCE_EXEC, + BT_8822B_2ANT_PHASE_WLAN_OFF); + } + } else if (BTC_WIFI_PNP_WAKE_UP == pnp_state) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], Pnp notify to WAKE UP\n"); + BTC_TRACE(trace_buf); + + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ACTIVE, true); + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_ONOFF, true); + } +} + +void ex_halbtc8822b2ant_periodical(IN struct btc_coexist *btcoexist) +{ + struct btc_board_info *board_info = &btcoexist->board_info; + boolean wifi_busy = false; + u32 bt_patch_ver; + u16 bt_scoreboard_val = 0; + static u8 cnt = 0; + boolean bt_relink_finish = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ************* Periodical *************\n"); + BTC_TRACE(trace_buf); + +#if (BT_AUTO_REPORT_ONLY_8822B_2ANT == 0) + halbtc8822b2ant_query_bt_info(btcoexist); +#endif + + halbtc8822b2ant_monitor_bt_ctr(btcoexist); + halbtc8822b2ant_monitor_wifi_ctr(btcoexist); + halbtc8822b2ant_monitor_bt_enable_disable(btcoexist); + +#if 1 + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); + halbtc8822b2ant_read_score_board(btcoexist, &bt_scoreboard_val); + + if (wifi_busy) { + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_UNDERTEST, true); + /*for bt lps32 clock offset*/ + if (bt_scoreboard_val & BIT(6)) + halbtc8822b2ant_query_bt_info(btcoexist); + } else { + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_UNDERTEST, false); + /* + halbtc8822b2ant_post_state_to_bt(btcoexist, + BT_8822B_2ANT_SCOREBOARD_WLBUSY, + false); */ + } +#endif + + if (coex_sta->bt_relink_downcount != 0) { + coex_sta->bt_relink_downcount--; + + if (coex_sta->bt_relink_downcount == 0) + bt_relink_finish = true; + } + + /* for 4-way, DHCP, EAPOL packet */ + if (coex_sta->specific_pkt_period_cnt > 0) { + + coex_sta->specific_pkt_period_cnt--; + + if ((coex_sta->specific_pkt_period_cnt == 0) && + (coex_sta->wifi_is_high_pri_task)) + coex_sta->wifi_is_high_pri_task = false; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "[BTCoex], ***************** Hi-Pri Task = %s*****************\n", + (coex_sta->wifi_is_high_pri_task ? "Yes" : + "No")); + BTC_TRACE(trace_buf); + + } + + if (!coex_sta->bt_disabled) { + if (coex_sta->bt_coex_supported_feature == 0) + btcoexist->btc_get(btcoexist, BTC_GET_U4_SUPPORTED_FEATURE, &coex_sta->bt_coex_supported_feature); + + if ((coex_sta->bt_coex_supported_version == 0) || + (coex_sta->bt_coex_supported_version == 0xffff)) + btcoexist->btc_get(btcoexist, BTC_GET_U4_SUPPORTED_VERSION, &coex_sta->bt_coex_supported_version); + + /*coex_sta->bt_ble_scan_type = btcoexist->btc_get_ble_scan_type_from_bt(btcoexist);*/ + btcoexist->btc_get(btcoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + btcoexist->bt_info.bt_get_fw_ver = bt_patch_ver; + + if (coex_sta->bt_reg_vendor_ac == 0xffff) + coex_sta->bt_reg_vendor_ac = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, + 0xac) & 0xffff); + + if (coex_sta->bt_reg_vendor_ae == 0xffff) + coex_sta->bt_reg_vendor_ae = (u16)( + btcoexist->btc_get_bt_reg(btcoexist, 3, + 0xae) & 0xffff); + } + if (halbtc8822b2ant_is_wifibt_status_changed(btcoexist)) + halbtc8822b2ant_run_coexist_mechanism(btcoexist); +} + + +/*#pragma optimize( "", off )*/ +void ex_halbtc8822b2ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds) +{ +#if 0 + static u32 ant_det_count = 0, ant_det_fail_count = 0; + struct btc_board_info *board_info = &btcoexist->board_info; + u16 u16tmp; + u8 AntDetval = 0; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Ext Call AntennaDetect()!!\n"); + BTC_TRACE(trace_buf); + +#if BT_8822B_2ANT_ANTDET_ENABLE + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx Call AntennaDetect()!!\n"); + BTC_TRACE(trace_buf); + + if (seconds == 0) { + psd_scan->ant_det_try_count = 0; + psd_scan->ant_det_fail_count = 0; + ant_det_count = 0; + ant_det_fail_count = 0; + board_info->btdm_ant_det_finish = false; + board_info->btdm_ant_num_by_ant_det = 1; + return; + } + + if (!board_info->btdm_ant_det_finish) { + psd_scan->ant_det_inteval_count = + psd_scan->ant_det_inteval_count + 2; + + if (psd_scan->ant_det_inteval_count >= + BT_8822B_2ANT_ANTDET_RETRY_INTERVAL) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Timer is up, Try Detect!!\n"); + BTC_TRACE(trace_buf); + + psd_scan->is_AntDet_running = true; + + halbtc8822b2ant_read_score_board(btcoexist, &u16tmp); + + if (u16tmp & BIT( + 2)) { /* Antenna detection is already done before last WL power on */ + board_info->btdm_ant_det_finish = true; + psd_scan->ant_det_try_count = 1; + psd_scan->ant_det_fail_count = 0; + board_info->btdm_ant_num_by_ant_det = (u16tmp & + BIT(3)) ? 1 : 2; + psd_scan->ant_det_result = 12; + + psd_scan->ant_det_psd_scan_peak_val = + btcoexist->btc_get_ant_det_val_from_bt( + btcoexist) * 100; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Result from BT (%d-Ant)\n", + board_info->btdm_ant_num_by_ant_det); + BTC_TRACE(trace_buf); + } else + board_info->btdm_ant_det_finish = + halbtc8822b2ant_psd_antenna_detection_check( + btcoexist); + + btcoexist->bdontenterLPS = false; + + if (board_info->btdm_ant_det_finish) { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Success!!\n"); + BTC_TRACE(trace_buf); + + /*for 8822b, btc_set_bt_trx_mask is just used to + notify BT stop le tx and Ant Det Result , not set BT RF TRx Mask */ + if (psd_scan->ant_det_result != 12) { + + AntDetval = (u8)(( + psd_scan->ant_det_psd_scan_peak_val + / 100) & 0x7f); + + AntDetval = + (board_info->btdm_ant_num_by_ant_det + == 1) ? (AntDetval | 0x80) : + AntDetval; + + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Ant Count = %d, PSD Val = %d\n", + ((AntDetval & + 0x80) ? 1 + : 2), AntDetval + & 0x7f); + BTC_TRACE(trace_buf); + + if (btcoexist->btc_set_bt_trx_mask( + btcoexist, AntDetval)) + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Notify BT stop le tx by set_bt_trx_mask ok!\n"); + else + BTC_SPRINTF(trace_buf, + BT_TMP_BUF_SIZE, + "xxxxxx AntennaDetect(), Notify BT stop le tx by set_bt_trx_mask fail!\n"); + + BTC_TRACE(trace_buf); + } + + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Fail!!\n"); + BTC_TRACE(trace_buf); + } + + psd_scan->ant_det_inteval_count = 0; + psd_scan->is_AntDet_running = false; + + /* stimulate coex running */ + halbtc8822b2ant_run_coexist_mechanism( + btcoexist); + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Stimulate Coex running\n!!"); + BTC_TRACE(trace_buf); + } else { + BTC_SPRINTF(trace_buf, BT_TMP_BUF_SIZE, + "xxxxxxxxxxxxxxxx AntennaDetect(), Antenna Det Timer is not up! (%d)\n", + psd_scan->ant_det_inteval_count); + BTC_TRACE(trace_buf); + + if (psd_scan->ant_det_inteval_count == 8) + btcoexist->bdontenterLPS = true; + else + btcoexist->bdontenterLPS = false; + } + + } +#endif +#endif + +} + + +void ex_halbtc8822b2ant_display_ant_detection(IN struct btc_coexist *btcoexist) +{ +#if 0 +#if BT_8822B_2ANT_ANTDET_ENABLE + struct btc_board_info *board_info = &btcoexist->board_info; + + if (psd_scan->ant_det_try_count != 0) { + halbtc8822b2ant_psd_show_antenna_detect_result(btcoexist); + + if (board_info->btdm_ant_det_finish) + halbtc8822b2ant_psd_showdata(btcoexist); + } +#endif +#endif +} + + +#endif + +#endif /* #if (RTL8822B_SUPPORT == 1) */ + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b2ant.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b2ant.h new file mode 100644 index 0000000..8757334 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822b2ant.h @@ -0,0 +1,493 @@ + +#if (BT_SUPPORT == 1 && COEX_SUPPORT == 1) + +#if (RTL8822B_SUPPORT == 1) + +/* ******************************************* + * The following is for 8822B 2Ant BT Co-exist definition + * ******************************************* */ +#define BT_8822B_2ANT_COEX_DBG 1 +#define BT_AUTO_REPORT_ONLY_8822B_2ANT 1 + + + + +#define BT_INFO_8822B_2ANT_B_FTP BIT(7) +#define BT_INFO_8822B_2ANT_B_A2DP BIT(6) +#define BT_INFO_8822B_2ANT_B_HID BIT(5) +#define BT_INFO_8822B_2ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8822B_2ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8822B_2ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8822B_2ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8822B_2ANT_B_CONNECTION BIT(0) + +#define BTC_RSSI_COEX_THRESH_TOL_8822B_2ANT 2 + + +#define BT_8822B_2ANT_WIFI_RSSI_COEXSWITCH_THRES1 80 /* unit: % WiFi RSSI Threshold for 2-Ant free-run/2-Ant TDMA translation, default = 42 */ +#define BT_8822B_2ANT_BT_RSSI_COEXSWITCH_THRES1 80 /* unit: % BT RSSI Threshold for 2-Ant free-run/2-Ant TDMA translation, default = 46 */ +#define BT_8822B_2ANT_WIFI_RSSI_COEXSWITCH_THRES2 40 /* unit: % WiFi RSSI Threshold for 1-Ant TDMA/1-Ant PS-TDMA translation, default = 42 */ +#define BT_8822B_2ANT_BT_RSSI_COEXSWITCH_THRES2 35 /* unit: % BT RSSI Threshold for 1-Ant TDMA/1-Ant PS-TDMA translation, default = 46 */ +#define BT_8822B_2ANT_DEFAULT_ISOLATION 15 /* unit: dB */ +#define BT_8822B_2ANT_WIFI_MAX_TX_POWER 15 /* unit: dBm */ +#define BT_8822B_2ANT_BT_MAX_TX_POWER 3 /* unit: dBm */ +#define BT_8822B_2ANT_WIFI_SIR_THRES1 -15 /* unit: dB */ +#define BT_8822B_2ANT_WIFI_SIR_THRES2 -30 /* unit: dB */ +#define BT_8822B_2ANT_BT_SIR_THRES1 -15 /* unit: dB */ +#define BT_8822B_2ANT_BT_SIR_THRES2 -30 /* unit: dB */ + + +/* for Antenna detection */ +#define BT_8822B_2ANT_ANTDET_PSDTHRES_BACKGROUND 50 +#define BT_8822B_2ANT_ANTDET_PSDTHRES_2ANT_BADISOLATION 70 +#define BT_8822B_2ANT_ANTDET_PSDTHRES_2ANT_GOODISOLATION 52 +#define BT_8822B_2ANT_ANTDET_PSDTHRES_1ANT 40 +#define BT_8822B_2ANT_ANTDET_RETRY_INTERVAL 10 /* retry timer if ant det is fail, unit: second */ +#define BT_8822B_2ANT_ANTDET_SWEEPPOINT_DELAY 60000 +#define BT_8822B_2ANT_ANTDET_ENABLE 0 +#define BT_8822B_2ANT_ANTDET_BTTXTIME 100 +#define BT_8822B_2ANT_ANTDET_BTTXCHANNEL 39 +#define BT_8822B_2ANT_ANTDET_PSD_SWWEEPCOUNT 50 + + +#define BT_8822B_2ANT_LTECOEX_INDIRECTREG_ACCESS_TIMEOUT 30000 + +enum bt_8822b_2ant_signal_state { + BT_8822B_2ANT_SIG_STA_SET_TO_LOW = 0x0, + BT_8822B_2ANT_SIG_STA_SET_BY_HW = 0x0, + BT_8822B_2ANT_SIG_STA_SET_TO_HIGH = 0x1, + BT_8822B_2ANT_SIG_STA_MAX +}; + +enum bt_8822b_2ant_path_ctrl_owner { + BT_8822B_2ANT_PCO_BTSIDE = 0x0, + BT_8822B_2ANT_PCO_WLSIDE = 0x1, + BT_8822B_2ANT_PCO_MAX +}; + +enum bt_8822b_2ant_gnt_ctrl_type { + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_PTA = 0x0, + BT_8822B_2ANT_GNT_TYPE_CTRL_BY_SW = 0x1, + BT_8822B_2ANT_GNT_TYPE_MAX +}; + +enum bt_8822b_2ant_gnt_ctrl_block { + BT_8822B_2ANT_GNT_BLOCK_RFC_BB = 0x0, + BT_8822B_2ANT_GNT_BLOCK_RFC = 0x1, + BT_8822B_2ANT_GNT_BLOCK_BB = 0x2, + BT_8822B_2ANT_GNT_BLOCK_MAX +}; + +enum bt_8822b_2ant_lte_coex_table_type { + BT_8822B_2ANT_CTT_WL_VS_LTE = 0x0, + BT_8822B_2ANT_CTT_BT_VS_LTE = 0x1, + BT_8822B_2ANT_CTT_MAX +}; + +enum bt_8822b_2ant_lte_break_table_type { + BT_8822B_2ANT_LBTT_WL_BREAK_LTE = 0x0, + BT_8822B_2ANT_LBTT_BT_BREAK_LTE = 0x1, + BT_8822B_2ANT_LBTT_LTE_BREAK_WL = 0x2, + BT_8822B_2ANT_LBTT_LTE_BREAK_BT = 0x3, + BT_8822B_2ANT_LBTT_MAX +}; + +enum bt_info_src_8822b_2ant { + BT_INFO_SRC_8822B_2ANT_WIFI_FW = 0x0, + BT_INFO_SRC_8822B_2ANT_BT_RSP = 0x1, + BT_INFO_SRC_8822B_2ANT_BT_ACTIVE_SEND = 0x2, + BT_INFO_SRC_8822B_2ANT_MAX +}; + +enum bt_8822b_2ant_bt_status { + BT_8822B_2ANT_BT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8822B_2ANT_BT_STATUS_CONNECTED_IDLE = 0x1, + BT_8822B_2ANT_BT_STATUS_INQ_PAGE = 0x2, + BT_8822B_2ANT_BT_STATUS_ACL_BUSY = 0x3, + BT_8822B_2ANT_BT_STATUS_SCO_BUSY = 0x4, + BT_8822B_2ANT_BT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8822B_2ANT_BT_STATUS_MAX +}; + +enum bt_8822b_2ant_coex_algo { + BT_8822B_2ANT_COEX_ALGO_UNDEFINED = 0x0, + BT_8822B_2ANT_COEX_ALGO_SCO = 0x1, + BT_8822B_2ANT_COEX_ALGO_HID = 0x2, + BT_8822B_2ANT_COEX_ALGO_A2DP = 0x3, + BT_8822B_2ANT_COEX_ALGO_A2DP_PANHS = 0x4, + BT_8822B_2ANT_COEX_ALGO_PANEDR = 0x5, + BT_8822B_2ANT_COEX_ALGO_PANHS = 0x6, + BT_8822B_2ANT_COEX_ALGO_PANEDR_A2DP = 0x7, + BT_8822B_2ANT_COEX_ALGO_PANEDR_HID = 0x8, + BT_8822B_2ANT_COEX_ALGO_HID_A2DP_PANEDR = 0x9, + BT_8822B_2ANT_COEX_ALGO_HID_A2DP = 0xa, + BT_8822B_2ANT_COEX_ALGO_NOPROFILEBUSY = 0xb, + BT_8822B_2ANT_COEX_ALGO_MAX +}; + +enum bt_8822b_2ant_ext_ant_switch_type { + BT_8822B_2ANT_EXT_ANT_SWITCH_USE_DPDT = 0x0, + BT_8822B_2ANT_EXT_ANT_SWITCH_USE_SPDT = 0x1, + BT_8822B_2ANT_EXT_ANT_SWITCH_NONE = 0x2, + BT_8822B_2ANT_EXT_ANT_SWITCH_MAX +}; + +enum bt_8822b_2ant_ext_ant_switch_ctrl_type { + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_BBSW = 0x0, + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_PTA = 0x1, + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_ANTDIV = 0x2, + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_MAC = 0x3, + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_BY_BT = 0x4, + BT_8822B_2ANT_EXT_ANT_SWITCH_CTRL_MAX +}; + +enum bt_8822b_2ant_ext_ant_switch_pos_type { + BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_BT = 0x0, + BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_WLG = 0x1, + BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_WLA = 0x2, + BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_NOCARE = 0x3, + BT_8822B_2ANT_EXT_ANT_SWITCH_MAIN_TO_MAX +}; + +enum bt_8822b_2ant_ext_band_switch_pos_type { + BT_8822B_2ANT_EXT_BAND_SWITCH_TO_WLG = 0x0, + BT_8822B_2ANT_EXT_BAND_SWITCH_TO_WLA = 0x1, + BT_8822B_2ANT_EXT_BAND_SWITCH_TO_MAX +}; + +enum bt_8822b_2ant_int_block { + BT_8822B_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_BTG = 0x0, + BT_8822B_2ANT_INT_BLOCK_SWITCH_TO_WLG_OF_WLAG = 0x1, + BT_8822B_2ANT_INT_BLOCK_SWITCH_TO_WLA_OF_WLAG = 0x2, + BT_8822B_2ANT_INT_BLOCK_SWITCH_TO_MAX +}; + +enum bt_8822b_2ant_phase { + BT_8822B_2ANT_PHASE_COEX_INIT = 0x0, + BT_8822B_2ANT_PHASE_WLANONLY_INIT = 0x1, + BT_8822B_2ANT_PHASE_WLAN_OFF = 0x2, + BT_8822B_2ANT_PHASE_2G_RUNTIME = 0x3, + BT_8822B_2ANT_PHASE_5G_RUNTIME = 0x4, + BT_8822B_2ANT_PHASE_BTMPMODE = 0x5, + BT_8822B_2ANT_PHASE_ANTENNA_DET = 0x6, + BT_8822B_2ANT_PHASE_COEX_POWERON = 0x7, + BT_8822B_2ANT_PHASE_2G_RUNTIME_CONCURRENT = 0x8, + BT_8822B_2ANT_PHASE_MAX +}; + +/*ADD SCOREBOARD TO FIX BT LPS 32K ISSUE WHILE WL BUSY*/ + +enum bt_8822b_2ant_Scoreboard { + BT_8822B_2ANT_SCOREBOARD_ACTIVE = BIT(0), + BT_8822B_2ANT_SCOREBOARD_ONOFF = BIT(1), + BT_8822B_2ANT_SCOREBOARD_SCAN = BIT(2), + BT_8822B_2ANT_SCOREBOARD_UNDERTEST = BIT(3), + BT_8822B_2ANT_SCOREBOARD_WLBUSY = BIT(6) +}; + + + + + +struct coex_dm_8822b_2ant { + /* hw setting */ + u32 pre_ant_pos_type; + u32 cur_ant_pos_type; + /* fw mechanism */ + u8 pre_bt_dec_pwr_lvl; + u8 cur_bt_dec_pwr_lvl; + u8 pre_fw_dac_swing_lvl; + u8 cur_fw_dac_swing_lvl; + boolean cur_ignore_wlan_act; + boolean pre_ignore_wlan_act; + u8 pre_ps_tdma; + u8 cur_ps_tdma; + u8 ps_tdma_para[5]; + u8 ps_tdma_du_adj_type; + boolean reset_tdma_adjust; + boolean pre_ps_tdma_on; + boolean cur_ps_tdma_on; + boolean pre_bt_auto_report; + boolean cur_bt_auto_report; + + /* sw mechanism */ + boolean pre_rf_rx_lpf_shrink; + boolean cur_rf_rx_lpf_shrink; + u32 bt_rf_0x1e_backup; + boolean pre_low_penalty_ra; + boolean cur_low_penalty_ra; + boolean pre_dac_swing_on; + u32 pre_dac_swing_lvl; + boolean cur_dac_swing_on; + u32 cur_dac_swing_lvl; + boolean pre_adc_back_off; + boolean cur_adc_back_off; + boolean pre_agc_table_en; + boolean cur_agc_table_en; + u32 pre_val0x6c0; + u32 cur_val0x6c0; + u32 pre_val0x6c4; + u32 cur_val0x6c4; + u32 pre_val0x6c8; + u32 cur_val0x6c8; + u8 pre_val0x6cc; + u8 cur_val0x6cc; + boolean limited_dig; + + /* algorithm related */ + u8 pre_algorithm; + u8 cur_algorithm; + u8 bt_status; + u8 wifi_chnl_info[3]; + + boolean need_recover0x948; + u32 backup0x948; + + u8 pre_lps; + u8 cur_lps; + u8 pre_rpwm; + u8 cur_rpwm; + + boolean is_switch_to_1dot5_ant; + u8 switch_thres_offset; + u32 arp_cnt; + + u32 pre_ext_ant_switch_status; + u32 cur_ext_ant_switch_status; + + u8 pre_ext_band_switch_status; + u8 cur_ext_band_switch_status; + + u8 pre_int_block_status; + u8 cur_int_block_status; +}; + +struct coex_sta_8822b_2ant { + boolean bt_disabled; + boolean bt_link_exist; + boolean sco_exist; + boolean a2dp_exist; + boolean hid_exist; + boolean pan_exist; + + boolean under_lps; + boolean under_ips; + u32 high_priority_tx; + u32 high_priority_rx; + u32 low_priority_tx; + u32 low_priority_rx; + u8 bt_rssi; + boolean bt_tx_rx_mask; + u8 pre_bt_rssi_state; + u8 pre_wifi_rssi_state[4]; + boolean c2h_bt_info_req_sent; + u8 bt_info_c2h[BT_INFO_SRC_8822B_2ANT_MAX][10]; + u32 bt_info_c2h_cnt[BT_INFO_SRC_8822B_2ANT_MAX]; + boolean bt_whck_test; + boolean c2h_bt_inquiry_page; + boolean c2h_bt_remote_name_req; + u8 bt_retry_cnt; + u8 bt_info_ext; + u8 bt_info_ext2; + u32 pop_event_cnt; + u8 scan_ap_num; + + u32 crc_ok_cck; + u32 crc_ok_11g; + u32 crc_ok_11n; + u32 crc_ok_11n_agg; + u32 crc_ok_11n_vht; + + u32 crc_err_cck; + u32 crc_err_11g; + u32 crc_err_11n; + u32 crc_err_11n_agg; + u32 crc_err_11n_vht; + + boolean cck_lock; + boolean pre_ccklock; + boolean cck_ever_lock; + + u8 coex_table_type; + boolean force_lps_on; + + u8 dis_ver_info_cnt; + + u8 a2dp_bit_pool; + u8 cut_version; + + boolean concurrent_rx_mode_on; + + u16 score_board; + u8 isolation_btween_wb; /* 0~ 50 */ + u8 wifi_coex_thres; + u8 bt_coex_thres; + u8 wifi_coex_thres2; + u8 bt_coex_thres2; + + u8 num_of_profile; + boolean acl_busy; + boolean wl_rf_off_on_event; + boolean bt_create_connection; + boolean wifi_is_high_pri_task; + u32 specific_pkt_period_cnt; + u32 bt_coex_supported_feature; + u32 bt_coex_supported_version; + + u8 bt_ble_scan_type; + u8 bt_ble_scan_para[3]; + + boolean run_time_state; + boolean freeze_coexrun_by_btinfo; + + boolean is_A2DP_3M; + boolean voice_over_HOGP; + u8 bt_info; + boolean is_autoslot; + u8 forbidden_slot; + u8 hid_busy_num; + u8 hid_pair_cnt; + + u32 cnt_RemoteNameReq; + u32 cnt_setupLink; + u32 cnt_ReInit; + u32 cnt_IgnWlanAct; + u32 cnt_Page; + + u16 bt_reg_vendor_ac; + u16 bt_reg_vendor_ae; + + boolean is_setupLink; + u8 wl_noisy_level; + u32 gnt_error_cnt; + + u8 bt_afh_map[10]; + u8 bt_relink_downcount; +}; + + +#define BT_8822B_2ANT_EXT_BAND_SWITCH_USE_DPDT 0 +#define BT_8822B_2ANT_EXT_BAND_SWITCH_USE_SPDT 1 + + +struct rfe_type_8822b_2ant { + + u8 rfe_module_type; + boolean ext_ant_switch_exist; + u8 ext_ant_switch_type; /* 0:DPDT, 1:SPDT */ + u8 ext_ant_switch_ctrl_polarity; /* iF 0: DPDT_P=0, DPDT_N=1 => BTG to Main, WL_A+G to Aux */ + + boolean ext_band_switch_exist; + u8 ext_band_switch_type; /* 0:DPDT, 1:SPDT */ + u8 ext_band_switch_ctrl_polarity; + + boolean wlg_Locate_at_btg; /* If true: WLG at BTG, If false: WLG at WLAG */ + + boolean ext_ant_switch_diversity; /* If diversity on */ +}; + +#define BT_8822B_2ANT_ANTDET_PSD_POINTS 256 /* MAX:1024 */ +#define BT_8822B_2ANT_ANTDET_PSD_AVGNUM 1 /* MAX:3 */ +#define BT_8822B_2ANT_ANTDET_BUF_LEN 16 + +struct psdscan_sta_8822b_2ant { + + u32 ant_det_bt_le_channel; /* BT LE Channel ex:2412 */ + u32 ant_det_bt_tx_time; + u32 ant_det_pre_psdscan_peak_val; + boolean ant_det_is_ant_det_available; + u32 ant_det_psd_scan_peak_val; + boolean ant_det_is_btreply_available; + u32 ant_det_psd_scan_peak_freq; + + u8 ant_det_result; + u8 ant_det_peak_val[BT_8822B_2ANT_ANTDET_BUF_LEN]; + u8 ant_det_peak_freq[BT_8822B_2ANT_ANTDET_BUF_LEN]; + u32 ant_det_try_count; + u32 ant_det_fail_count; + u32 ant_det_inteval_count; + u32 ant_det_thres_offset; + + u32 real_cent_freq; + s32 real_offset; + u32 real_span; + + u32 psd_band_width; /* unit: Hz */ + u32 psd_point; /* 128/256/512/1024 */ + u32 psd_report[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_report_max_hold[1024]; /* unit:dB (20logx), 0~255 */ + u32 psd_start_point; + u32 psd_stop_point; + u32 psd_max_value_point; + u32 psd_max_value; + u32 psd_max_value2; + u32 psd_avg_value; /* filter loop_max_value that below BT_8822B_1ANT_ANTDET_PSDTHRES_1ANT, and average the rest*/ + u32 psd_loop_max_value[BT_8822B_2ANT_ANTDET_PSD_SWWEEPCOUNT]; /*max value in each loop */ + u32 psd_start_base; + u32 psd_avg_num; /* 1/8/16/32 */ + u32 psd_gen_count; + boolean is_AntDet_running; + boolean is_psd_show_max_only; +}; + + +/* ******************************************* + * The following is interface which will notify coex module. + * ******************************************* */ +void ex_halbtc8822b2ant_power_on_setting(IN struct btc_coexist *btcoexist); +void ex_halbtc8822b2ant_pre_load_firmware(IN struct btc_coexist *btcoexist); +void ex_halbtc8822b2ant_init_hw_config(IN struct btc_coexist *btcoexist, + IN boolean wifi_only); +void ex_halbtc8822b2ant_init_coex_dm(IN struct btc_coexist *btcoexist); +void ex_halbtc8822b2ant_ips_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b2ant_lps_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b2ant_scan_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b2ant_switchband_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b2ant_connect_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b2ant_media_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b2ant_specific_packet_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b2ant_bt_info_notify(IN struct btc_coexist *btcoexist, + IN u8 *tmp_buf, IN u8 length); +void ex_halbtc8822b2ant_rf_status_notify(IN struct btc_coexist *btcoexist, + IN u8 type); +void ex_halbtc8822b2ant_halt_notify(IN struct btc_coexist *btcoexist); +void ex_halbtc8822b2ant_pnp_notify(IN struct btc_coexist *btcoexist, + IN u8 pnp_state); +void ex_halbtc8822b2ant_periodical(IN struct btc_coexist *btcoexist); +void ex_halbtc8822b2ant_display_coex_info(IN struct btc_coexist *btcoexist); +void ex_halbtc8822b2ant_antenna_detection(IN struct btc_coexist *btcoexist, + IN u32 cent_freq, IN u32 offset, IN u32 span, IN u32 seconds); +void ex_halbtc8822b2ant_display_ant_detection(IN struct btc_coexist *btcoexist); + + +#else +#define ex_halbtc8822b2ant_power_on_setting(btcoexist) +#define ex_halbtc8822b2ant_pre_load_firmware(btcoexist) +#define ex_halbtc8822b2ant_init_hw_config(btcoexist, wifi_only) +#define ex_halbtc8822b2ant_init_coex_dm(btcoexist) +#define ex_halbtc8822b2ant_ips_notify(btcoexist, type) +#define ex_halbtc8822b2ant_lps_notify(btcoexist, type) +#define ex_halbtc8822b2ant_scan_notify(btcoexist, type) +#define ex_halbtc8822b2ant_switchband_notify(btcoexist, type) +#define ex_halbtc8822b2ant_connect_notify(btcoexist, type) +#define ex_halbtc8822b2ant_media_status_notify(btcoexist, type) +#define ex_halbtc8822b2ant_specific_packet_notify(btcoexist, type) +#define ex_halbtc8822b2ant_bt_info_notify(btcoexist, tmp_buf, length) +#define ex_halbtc8822b2ant_rf_status_notify(btcoexist, type) +#define ex_halbtc8822b2ant_halt_notify(btcoexist) +#define ex_halbtc8822b2ant_pnp_notify(btcoexist, pnp_state) +#define ex_halbtc8822b2ant_periodical(btcoexist) +#define ex_halbtc8822b2ant_display_coex_info(btcoexist) +#define ex_halbtc8822b2ant_display_ant_detection(btcoexist) +#define ex_halbtc8822b2ant_antenna_detection(btcoexist, cent_freq, offset, span, seconds) +#endif + +#endif + diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822bwifionly.c b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822bwifionly.c new file mode 100644 index 0000000..35004d7 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822bwifionly.c @@ -0,0 +1,54 @@ +#include "mp_precomp.h" + + +VOID +ex_hal8822b_wifi_only_hw_config( + IN struct wifi_only_cfg *pwifionlycfg + ) +{ + /*BB control*/ + halwifionly_phy_set_bb_reg(pwifionlycfg, 0x4c, 0x01800000, 0x2); + /*SW control*/ + halwifionly_phy_set_bb_reg(pwifionlycfg, 0xcb4, 0xff, 0x77); + /*antenna mux switch */ + halwifionly_phy_set_bb_reg(pwifionlycfg, 0x974, 0x300, 0x3); + + halwifionly_phy_set_bb_reg(pwifionlycfg, 0x1990, 0x300, 0x0); + + halwifionly_phy_set_bb_reg(pwifionlycfg, 0xcbc, 0x80000, 0x0); + /*switch to WL side controller and gnt_wl gnt_bt debug signal */ + halwifionly_phy_set_bb_reg(pwifionlycfg, 0x70, 0xff000000, 0x0e); + /*gnt_wl=1 , gnt_bt=0*/ + halwifionly_phy_set_bb_reg(pwifionlycfg, 0x1704, 0xffffffff, 0x7700); + halwifionly_phy_set_bb_reg(pwifionlycfg, 0x1700, 0xffffffff, 0xc00f0038); +} + +VOID +ex_hal8822b_wifi_only_scannotify( + IN struct wifi_only_cfg *pwifionlycfg, + IN u1Byte is_5g + ) +{ + hal8822b_wifi_only_switch_antenna(pwifionlycfg, is_5g); +} + +VOID +ex_hal8822b_wifi_only_switchbandnotify( + IN struct wifi_only_cfg *pwifionlycfg, + IN u1Byte is_5g + ) +{ + hal8822b_wifi_only_switch_antenna(pwifionlycfg, is_5g); +} + +VOID +hal8822b_wifi_only_switch_antenna(IN struct wifi_only_cfg *pwifionlycfg, + IN u1Byte is_5g + ) +{ + + if (is_5g) + halwifionly_phy_set_bb_reg(pwifionlycfg, 0xcbc, 0x300, 0x1); + else + halwifionly_phy_set_bb_reg(pwifionlycfg, 0xcbc, 0x300, 0x2); +} diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822bwifionly.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822bwifionly.h new file mode 100644 index 0000000..3f5ef3b --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtc8822bwifionly.h @@ -0,0 +1,22 @@ +#ifndef __INC_HAL8822BWIFIONLYHWCFG_H +#define __INC_HAL8822BWIFIONLYHWCFG_H + +VOID +ex_hal8822b_wifi_only_hw_config( + IN struct wifi_only_cfg *pwifionlycfg + ); +VOID +ex_hal8822b_wifi_only_scannotify( + IN struct wifi_only_cfg *pwifionlycfg, + IN u1Byte is_5g + ); +VOID +ex_hal8822b_wifi_only_switchbandnotify( + IN struct wifi_only_cfg *pwifionlycfg, + IN u1Byte is_5g + ); +VOID +hal8822b_wifi_only_switch_antenna(IN struct wifi_only_cfg *pwifionlycfg, + IN u1Byte is_5g + ); +#endif diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/halbtcoutsrc.h b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtcoutsrc.h new file mode 100644 index 0000000..14a56de --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/halbtcoutsrc.h @@ -0,0 +1,1003 @@ +#ifndef __HALBTC_OUT_SRC_H__ +#define __HALBTC_OUT_SRC_H__ + + +#define BTC_COEX_OFFLOAD 0 +#define BTC_TMP_BUF_SHORT 20 + +extern u1Byte gl_btc_trace_buf[]; +#define BTC_SPRINTF rsprintf +#define BTC_TRACE(_MSG_)\ +do {\ + if (GLBtcDbgType[COMP_COEX] & BIT(DBG_LOUD)) {\ + RTW_INFO("%s", _MSG_);\ + } \ +} while (0) +#define BT_PrintData(adapter, _MSG_, len, data) RTW_DBG_DUMP((_MSG_), data, len) + + +#define NORMAL_EXEC FALSE +#define FORCE_EXEC TRUE + +#define BTC_RF_OFF 0x0 +#define BTC_RF_ON 0x1 + +#define BTC_RF_A 0x0 +#define BTC_RF_B 0x1 +#define BTC_RF_C 0x2 +#define BTC_RF_D 0x3 + +#define BTC_SMSP SINGLEMAC_SINGLEPHY +#define BTC_DMDP DUALMAC_DUALPHY +#define BTC_DMSP DUALMAC_SINGLEPHY +#define BTC_MP_UNKNOWN 0xff + +#define BT_COEX_ANT_TYPE_PG 0 +#define BT_COEX_ANT_TYPE_ANTDIV 1 +#define BT_COEX_ANT_TYPE_DETECTED 2 + +#define BTC_MIMO_PS_STATIC 0 /* 1ss */ +#define BTC_MIMO_PS_DYNAMIC 1 /* 2ss */ + +#define BTC_RATE_DISABLE 0 +#define BTC_RATE_ENABLE 1 + +/* single Antenna definition */ +#define BTC_ANT_PATH_WIFI 0 +#define BTC_ANT_PATH_BT 1 +#define BTC_ANT_PATH_PTA 2 +#define BTC_ANT_PATH_WIFI5G 3 +#define BTC_ANT_PATH_AUTO 4 +/* dual Antenna definition */ +#define BTC_ANT_WIFI_AT_MAIN 0 +#define BTC_ANT_WIFI_AT_AUX 1 +#define BTC_ANT_WIFI_AT_DIVERSITY 2 +/* coupler Antenna definition */ +#define BTC_ANT_WIFI_AT_CPL_MAIN 0 +#define BTC_ANT_WIFI_AT_CPL_AUX 1 + +typedef enum _BTC_POWERSAVE_TYPE { + BTC_PS_WIFI_NATIVE = 0, /* wifi original power save behavior */ + BTC_PS_LPS_ON = 1, + BTC_PS_LPS_OFF = 2, + BTC_PS_MAX +} BTC_POWERSAVE_TYPE, *PBTC_POWERSAVE_TYPE; + +typedef enum _BTC_BT_REG_TYPE { + BTC_BT_REG_RF = 0, + BTC_BT_REG_MODEM = 1, + BTC_BT_REG_BLUEWIZE = 2, + BTC_BT_REG_VENDOR = 3, + BTC_BT_REG_LE = 4, + BTC_BT_REG_MAX +} BTC_BT_REG_TYPE, *PBTC_BT_REG_TYPE; + +typedef enum _BTC_CHIP_INTERFACE { + BTC_INTF_UNKNOWN = 0, + BTC_INTF_PCI = 1, + BTC_INTF_USB = 2, + BTC_INTF_SDIO = 3, + BTC_INTF_MAX +} BTC_CHIP_INTERFACE, *PBTC_CHIP_INTERFACE; + +typedef enum _BTC_CHIP_TYPE { + BTC_CHIP_UNDEF = 0, + BTC_CHIP_CSR_BC4 = 1, + BTC_CHIP_CSR_BC8 = 2, + BTC_CHIP_RTL8723A = 3, + BTC_CHIP_RTL8821 = 4, + BTC_CHIP_RTL8723B = 5, + BTC_CHIP_MAX +} BTC_CHIP_TYPE, *PBTC_CHIP_TYPE; + +/* following is for wifi link status */ +#define WIFI_STA_CONNECTED BIT0 +#define WIFI_AP_CONNECTED BIT1 +#define WIFI_HS_CONNECTED BIT2 +#define WIFI_P2P_GO_CONNECTED BIT3 +#define WIFI_P2P_GC_CONNECTED BIT4 + +/* following is for command line utility */ +#define CL_SPRINTF rsprintf +#define CL_PRINTF DCMD_Printf + +struct btc_board_info { + /* The following is some board information */ + u8 bt_chip_type; + u8 pg_ant_num; /* pg ant number */ + u8 btdm_ant_num; /* ant number for btdm */ + u8 btdm_ant_num_by_ant_det; /* ant number for btdm after antenna detection */ + u8 btdm_ant_pos; /* Bryant Add to indicate Antenna Position for (pg_ant_num = 2) && (btdm_ant_num =1) (DPDT+1Ant case) */ + u8 single_ant_path; /* current used for 8723b only, 1=>s0, 0=>s1 */ + boolean tfbga_package; /* for Antenna detect threshold */ + boolean btdm_ant_det_finish; + boolean btdm_ant_det_already_init_phydm; + u8 ant_type; + u8 rfe_type; + u8 ant_div_cfg; + boolean btdm_ant_det_complete_fail; + u8 ant_det_result; + boolean ant_det_result_five_complete; + u32 antdetval; +}; + +typedef enum _BTC_DBG_OPCODE { + BTC_DBG_SET_COEX_NORMAL = 0x0, + BTC_DBG_SET_COEX_WIFI_ONLY = 0x1, + BTC_DBG_SET_COEX_BT_ONLY = 0x2, + BTC_DBG_SET_COEX_DEC_BT_PWR = 0x3, + BTC_DBG_SET_COEX_BT_AFH_MAP = 0x4, + BTC_DBG_SET_COEX_BT_IGNORE_WLAN_ACT = 0x5, + BTC_DBG_SET_COEX_MANUAL_CTRL = 0x6, + BTC_DBG_MAX +} BTC_DBG_OPCODE, *PBTC_DBG_OPCODE; + +typedef enum _BTC_RSSI_STATE { + BTC_RSSI_STATE_HIGH = 0x0, + BTC_RSSI_STATE_MEDIUM = 0x1, + BTC_RSSI_STATE_LOW = 0x2, + BTC_RSSI_STATE_STAY_HIGH = 0x3, + BTC_RSSI_STATE_STAY_MEDIUM = 0x4, + BTC_RSSI_STATE_STAY_LOW = 0x5, + BTC_RSSI_MAX +} BTC_RSSI_STATE, *PBTC_RSSI_STATE; +#define BTC_RSSI_HIGH(_rssi_) ((_rssi_ == BTC_RSSI_STATE_HIGH || _rssi_ == BTC_RSSI_STATE_STAY_HIGH) ? TRUE:FALSE) +#define BTC_RSSI_MEDIUM(_rssi_) ((_rssi_ == BTC_RSSI_STATE_MEDIUM || _rssi_ == BTC_RSSI_STATE_STAY_MEDIUM) ? TRUE:FALSE) +#define BTC_RSSI_LOW(_rssi_) ((_rssi_ == BTC_RSSI_STATE_LOW || _rssi_ == BTC_RSSI_STATE_STAY_LOW) ? TRUE:FALSE) + +typedef enum _BTC_WIFI_ROLE { + BTC_ROLE_STATION = 0x0, + BTC_ROLE_AP = 0x1, + BTC_ROLE_IBSS = 0x2, + BTC_ROLE_HS_MODE = 0x3, + BTC_ROLE_MAX +} BTC_WIFI_ROLE, *PBTC_WIFI_ROLE; + +typedef enum _BTC_WIRELESS_FREQ { + BTC_FREQ_2_4G = 0x0, + BTC_FREQ_5G = 0x1, + BTC_FREQ_MAX +} BTC_WIRELESS_FREQ, *PBTC_WIRELESS_FREQ; + +typedef enum _BTC_WIFI_BW_MODE { + BTC_WIFI_BW_LEGACY = 0x0, + BTC_WIFI_BW_HT20 = 0x1, + BTC_WIFI_BW_HT40 = 0x2, + BTC_WIFI_BW_HT80 = 0x3, + BTC_WIFI_BW_HT160 = 0x4, + BTC_WIFI_BW_MAX +} BTC_WIFI_BW_MODE, *PBTC_WIFI_BW_MODE; + +typedef enum _BTC_WIFI_TRAFFIC_DIR { + BTC_WIFI_TRAFFIC_TX = 0x0, + BTC_WIFI_TRAFFIC_RX = 0x1, + BTC_WIFI_TRAFFIC_MAX +} BTC_WIFI_TRAFFIC_DIR, *PBTC_WIFI_TRAFFIC_DIR; + +typedef enum _BTC_WIFI_PNP { + BTC_WIFI_PNP_WAKE_UP = 0x0, + BTC_WIFI_PNP_SLEEP = 0x1, + BTC_WIFI_PNP_SLEEP_KEEP_ANT = 0x2, + BTC_WIFI_PNP_MAX +} BTC_WIFI_PNP, *PBTC_WIFI_PNP; + +typedef enum _BTC_IOT_PEER { + BTC_IOT_PEER_UNKNOWN = 0, + BTC_IOT_PEER_REALTEK = 1, + BTC_IOT_PEER_REALTEK_92SE = 2, + BTC_IOT_PEER_BROADCOM = 3, + BTC_IOT_PEER_RALINK = 4, + BTC_IOT_PEER_ATHEROS = 5, + BTC_IOT_PEER_CISCO = 6, + BTC_IOT_PEER_MERU = 7, + BTC_IOT_PEER_MARVELL = 8, + BTC_IOT_PEER_REALTEK_SOFTAP = 9, /* peer is RealTek SOFT_AP, by Bohn, 2009.12.17 */ + BTC_IOT_PEER_SELF_SOFTAP = 10, /* Self is SoftAP */ + BTC_IOT_PEER_AIRGO = 11, + BTC_IOT_PEER_INTEL = 12, + BTC_IOT_PEER_RTK_APCLIENT = 13, + BTC_IOT_PEER_REALTEK_81XX = 14, + BTC_IOT_PEER_REALTEK_WOW = 15, + BTC_IOT_PEER_REALTEK_JAGUAR_BCUTAP = 16, + BTC_IOT_PEER_REALTEK_JAGUAR_CCUTAP = 17, + BTC_IOT_PEER_MAX, +} BTC_IOT_PEER, *PBTC_IOT_PEER; + +/* for 8723b-d cut large current issue */ +typedef enum _BTC_WIFI_COEX_STATE { + BTC_WIFI_STAT_INIT, + BTC_WIFI_STAT_IQK, + BTC_WIFI_STAT_NORMAL_OFF, + BTC_WIFI_STAT_MP_OFF, + BTC_WIFI_STAT_NORMAL, + BTC_WIFI_STAT_ANT_DIV, + BTC_WIFI_STAT_MAX +} BTC_WIFI_COEX_STATE, *PBTC_WIFI_COEX_STATE; + +typedef enum _BTC_ANT_TYPE { + BTC_ANT_TYPE_0, + BTC_ANT_TYPE_1, + BTC_ANT_TYPE_2, + BTC_ANT_TYPE_3, + BTC_ANT_TYPE_4, + BTC_ANT_TYPE_MAX +} BTC_ANT_TYPE, *PBTC_ANT_TYPE; + +typedef enum _BTC_VENDOR { + BTC_VENDOR_LENOVO, + BTC_VENDOR_ASUS, + BTC_VENDOR_OTHER +} BTC_VENDOR, *PBTC_VENDOR; + + +/* defined for BFP_BTC_GET */ +typedef enum _BTC_GET_TYPE { + /* type BOOLEAN */ + BTC_GET_BL_HS_OPERATION, + BTC_GET_BL_HS_CONNECTING, + BTC_GET_BL_WIFI_FW_READY, + BTC_GET_BL_WIFI_CONNECTED, + BTC_GET_BL_WIFI_BUSY, + BTC_GET_BL_WIFI_SCAN, + BTC_GET_BL_WIFI_LINK, + BTC_GET_BL_WIFI_ROAM, + BTC_GET_BL_WIFI_4_WAY_PROGRESS, + BTC_GET_BL_WIFI_UNDER_5G, + BTC_GET_BL_WIFI_AP_MODE_ENABLE, + BTC_GET_BL_WIFI_ENABLE_ENCRYPTION, + BTC_GET_BL_WIFI_UNDER_B_MODE, + BTC_GET_BL_EXT_SWITCH, + BTC_GET_BL_WIFI_IS_IN_MP_MODE, + BTC_GET_BL_IS_ASUS_8723B, + + /* type s4Byte */ + BTC_GET_S4_WIFI_RSSI, + BTC_GET_S4_HS_RSSI, + + /* type u4Byte */ + BTC_GET_U4_WIFI_BW, + BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, + BTC_GET_U4_WIFI_FW_VER, + BTC_GET_U4_WIFI_LINK_STATUS, + BTC_GET_U4_BT_PATCH_VER, + BTC_GET_U4_VENDOR, + BTC_GET_U4_SUPPORTED_VERSION, + BTC_GET_U4_SUPPORTED_FEATURE, + BTC_GET_U4_WIFI_IQK_TOTAL, + BTC_GET_U4_WIFI_IQK_OK, + BTC_GET_U4_WIFI_IQK_FAIL, + + /* type u1Byte */ + BTC_GET_U1_WIFI_DOT11_CHNL, + BTC_GET_U1_WIFI_CENTRAL_CHNL, + BTC_GET_U1_WIFI_HS_CHNL, + BTC_GET_U1_WIFI_P2P_CHNL, + BTC_GET_U1_MAC_PHY_MODE, + BTC_GET_U1_AP_NUM, + BTC_GET_U1_ANT_TYPE, + BTC_GET_U1_IOT_PEER, + + /*===== for 1Ant ======*/ + BTC_GET_U1_LPS_MODE, + + BTC_GET_MAX +} BTC_GET_TYPE, *PBTC_GET_TYPE; + +/* defined for BFP_BTC_SET */ +typedef enum _BTC_SET_TYPE { + /* type BOOLEAN */ + BTC_SET_BL_BT_DISABLE, + BTC_SET_BL_BT_ENABLE_DISABLE_CHANGE, + BTC_SET_BL_BT_TRAFFIC_BUSY, + BTC_SET_BL_BT_LIMITED_DIG, + BTC_SET_BL_FORCE_TO_ROAM, + BTC_SET_BL_TO_REJ_AP_AGG_PKT, + BTC_SET_BL_BT_CTRL_AGG_SIZE, + BTC_SET_BL_INC_SCAN_DEV_NUM, + BTC_SET_BL_BT_TX_RX_MASK, + BTC_SET_BL_MIRACAST_PLUS_BT, + + /* type u1Byte */ + BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON, + BTC_SET_U1_AGG_BUF_SIZE, + + /* type trigger some action */ + BTC_SET_ACT_GET_BT_RSSI, + BTC_SET_ACT_AGGREGATE_CTRL, + BTC_SET_ACT_ANTPOSREGRISTRY_CTRL, + /*===== for 1Ant ======*/ + /* type BOOLEAN */ + + /* type u1Byte */ + BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE, + BTC_SET_U1_LPS_VAL, + BTC_SET_U1_RPWM_VAL, + /* type trigger some action */ + BTC_SET_ACT_LEAVE_LPS, + BTC_SET_ACT_ENTER_LPS, + BTC_SET_ACT_NORMAL_LPS, + BTC_SET_ACT_DISABLE_LOW_POWER, + BTC_SET_ACT_UPDATE_RAMASK, + BTC_SET_ACT_SEND_MIMO_PS, + /* BT Coex related */ + BTC_SET_ACT_CTRL_BT_INFO, + BTC_SET_ACT_CTRL_BT_COEX, + BTC_SET_ACT_CTRL_8723B_ANT, + /*=================*/ + BTC_SET_MAX +} BTC_SET_TYPE, *PBTC_SET_TYPE; + +typedef enum _BTC_DBG_DISP_TYPE { + BTC_DBG_DISP_COEX_STATISTICS = 0x0, + BTC_DBG_DISP_BT_LINK_INFO = 0x1, + BTC_DBG_DISP_WIFI_STATUS = 0x2, + BTC_DBG_DISP_MAX +} BTC_DBG_DISP_TYPE, *PBTC_DBG_DISP_TYPE; + +typedef enum _BTC_NOTIFY_TYPE_IPS { + BTC_IPS_LEAVE = 0x0, + BTC_IPS_ENTER = 0x1, + BTC_IPS_MAX +} BTC_NOTIFY_TYPE_IPS, *PBTC_NOTIFY_TYPE_IPS; +typedef enum _BTC_NOTIFY_TYPE_LPS { + BTC_LPS_DISABLE = 0x0, + BTC_LPS_ENABLE = 0x1, + BTC_LPS_MAX +} BTC_NOTIFY_TYPE_LPS, *PBTC_NOTIFY_TYPE_LPS; +typedef enum _BTC_NOTIFY_TYPE_SCAN { + BTC_SCAN_FINISH = 0x0, + BTC_SCAN_START = 0x1, + BTC_SCAN_START_2G = 0x2, + BTC_SCAN_MAX +} BTC_NOTIFY_TYPE_SCAN, *PBTC_NOTIFY_TYPE_SCAN; +typedef enum _BTC_NOTIFY_TYPE_SWITCHBAND { + BTC_NOT_SWITCH = 0x0, + BTC_SWITCH_TO_24G = 0x1, + BTC_SWITCH_TO_5G = 0x2, + BTC_SWITCH_TO_24G_NOFORSCAN = 0x3, + BTC_SWITCH_MAX +} BTC_NOTIFY_TYPE_SWITCHBAND, *PBTC_NOTIFY_TYPE_SWITCHBAND; +typedef enum _BTC_NOTIFY_TYPE_ASSOCIATE { + BTC_ASSOCIATE_FINISH = 0x0, + BTC_ASSOCIATE_START = 0x1, + BTC_ASSOCIATE_5G_FINISH = 0x2, + BTC_ASSOCIATE_5G_START = 0x3, + BTC_ASSOCIATE_MAX +} BTC_NOTIFY_TYPE_ASSOCIATE, *PBTC_NOTIFY_TYPE_ASSOCIATE; +typedef enum _BTC_NOTIFY_TYPE_MEDIA_STATUS { + BTC_MEDIA_DISCONNECT = 0x0, + BTC_MEDIA_CONNECT = 0x1, + BTC_MEDIA_MAX +} BTC_NOTIFY_TYPE_MEDIA_STATUS, *PBTC_NOTIFY_TYPE_MEDIA_STATUS; +typedef enum _BTC_NOTIFY_TYPE_SPECIFIC_PACKET { + BTC_PACKET_UNKNOWN = 0x0, + BTC_PACKET_DHCP = 0x1, + BTC_PACKET_ARP = 0x2, + BTC_PACKET_EAPOL = 0x3, + BTC_PACKET_MAX +} BTC_NOTIFY_TYPE_SPECIFIC_PACKET, *PBTC_NOTIFY_TYPE_SPECIFIC_PACKET; +typedef enum _BTC_NOTIFY_TYPE_STACK_OPERATION { + BTC_STACK_OP_NONE = 0x0, + BTC_STACK_OP_INQ_PAGE_PAIR_START = 0x1, + BTC_STACK_OP_INQ_PAGE_PAIR_FINISH = 0x2, + BTC_STACK_OP_MAX +} BTC_NOTIFY_TYPE_STACK_OPERATION, *PBTC_NOTIFY_TYPE_STACK_OPERATION; + +/* Bryant Add */ +typedef enum _BTC_ANTENNA_POS { + BTC_ANTENNA_AT_MAIN_PORT = 0x1, + BTC_ANTENNA_AT_AUX_PORT = 0x2, +} BTC_ANTENNA_POS, *PBTC_ANTENNA_POS; + +/* Bryant Add */ +typedef enum _BTC_BT_OFFON { + BTC_BT_OFF = 0x0, + BTC_BT_ON = 0x1, +} BTC_BTOFFON, *PBTC_BT_OFFON; + +/*================================================== +For following block is for coex offload +==================================================*/ +typedef struct _COL_H2C { + u1Byte opcode; + u1Byte opcode_ver:4; + u1Byte req_num:4; + u1Byte buf[1]; +} COL_H2C, *PCOL_H2C; + +#define COL_C2H_ACK_HDR_LEN 3 +typedef struct _COL_C2H_ACK { + u1Byte status; + u1Byte opcode_ver:4; + u1Byte req_num:4; + u1Byte ret_len; + u1Byte buf[1]; +} COL_C2H_ACK, *PCOL_C2H_ACK; + +#define COL_C2H_IND_HDR_LEN 3 +typedef struct _COL_C2H_IND { + u1Byte type; + u1Byte version; + u1Byte length; + u1Byte data[1]; +} COL_C2H_IND, *PCOL_C2H_IND; + +/*============================================ +NOTE: for debug message, the following define should match +the strings in coexH2cResultString. +============================================*/ +typedef enum _COL_H2C_STATUS { + /* c2h status */ + COL_STATUS_C2H_OK = 0x00, /* Wifi received H2C request and check content ok. */ + COL_STATUS_C2H_UNKNOWN = 0x01, /* Not handled routine */ + COL_STATUS_C2H_UNKNOWN_OPCODE = 0x02, /* Invalid OP code, It means that wifi firmware received an undefiend OP code. */ + COL_STATUS_C2H_OPCODE_VER_MISMATCH = 0x03, /* Wifi firmware and wifi driver mismatch, need to update wifi driver or wifi or. */ + COL_STATUS_C2H_PARAMETER_ERROR = 0x04, /* Error paraneter.(ex: parameters = NULL but it should have values) */ + COL_STATUS_C2H_PARAMETER_OUT_OF_RANGE = 0x05, /* Wifi firmware needs to check the parameters from H2C request and return the status.(ex: ch = 500, it's wrong) */ + /* other COL status start from here */ + COL_STATUS_C2H_REQ_NUM_MISMATCH , /* c2h req_num mismatch, means this c2h is not we expected. */ + COL_STATUS_H2C_HALMAC_FAIL , /* HALMAC return fail. */ + COL_STATUS_H2C_TIMTOUT , /* not received the c2h response from fw */ + COL_STATUS_INVALID_C2H_LEN , /* invalid coex offload c2h ack length, must >= 3 */ + COL_STATUS_COEX_DATA_OVERFLOW , /* coex returned length over the c2h ack length. */ + COL_STATUS_MAX +} COL_H2C_STATUS, *PCOL_H2C_STATUS; + +#define COL_MAX_H2C_REQ_NUM 16 + +#define COL_H2C_BUF_LEN 20 +typedef enum _COL_OPCODE { + COL_OP_WIFI_STATUS_NOTIFY = 0x0, + COL_OP_WIFI_PROGRESS_NOTIFY = 0x1, + COL_OP_WIFI_INFO_NOTIFY = 0x2, + COL_OP_WIFI_POWER_STATE_NOTIFY = 0x3, + COL_OP_SET_CONTROL = 0x4, + COL_OP_GET_CONTROL = 0x5, + COL_OP_WIFI_OPCODE_MAX +} COL_OPCODE, *PCOL_OPCODE; + +typedef enum _COL_IND_TYPE { + COL_IND_BT_INFO = 0x0, + COL_IND_PSTDMA = 0x1, + COL_IND_LIMITED_TX_RX = 0x2, + COL_IND_COEX_TABLE = 0x3, + COL_IND_REQ = 0x4, + COL_IND_MAX +} COL_IND_TYPE, *PCOL_IND_TYPE; + +typedef struct _COL_SINGLE_H2C_RECORD { + u1Byte h2c_buf[COL_H2C_BUF_LEN]; /* the latest sent h2c buffer */ + u4Byte h2c_len; + u1Byte c2h_ack_buf[COL_H2C_BUF_LEN]; /* the latest received c2h buffer */ + u4Byte c2h_ack_len; + u4Byte count; /* the total number of the sent h2c command */ + u4Byte status[COL_STATUS_MAX]; /* the c2h status for the sent h2c command */ +} COL_SINGLE_H2C_RECORD, *PCOL_SINGLE_H2C_RECORD; + +typedef struct _COL_SINGLE_C2H_IND_RECORD { + u1Byte ind_buf[COL_H2C_BUF_LEN]; /* the latest received c2h indication buffer */ + u4Byte ind_len; + u4Byte count; /* the total number of the rcvd c2h indication */ + u4Byte status[COL_STATUS_MAX]; /* the c2h indication verified status */ +} COL_SINGLE_C2H_IND_RECORD, *PCOL_SINGLE_C2H_IND_RECORD; + +typedef struct _BTC_OFFLOAD { + /* H2C command related */ + u1Byte h2c_req_num; + u4Byte cnt_h2c_sent; + COL_SINGLE_H2C_RECORD h2c_record[COL_OP_WIFI_OPCODE_MAX]; + + /* C2H Ack related */ + u4Byte cnt_c2h_ack; + u4Byte status[COL_STATUS_MAX]; + struct completion c2h_event[COL_MAX_H2C_REQ_NUM]; /* for req_num = 1~COL_MAX_H2C_REQ_NUM */ + u1Byte c2h_ack_buf[COL_MAX_H2C_REQ_NUM][COL_H2C_BUF_LEN]; + u1Byte c2h_ack_len[COL_MAX_H2C_REQ_NUM]; + + /* C2H Indication related */ + u4Byte cnt_c2h_ind; + COL_SINGLE_C2H_IND_RECORD c2h_ind_record[COL_IND_MAX]; + u4Byte c2h_ind_status[COL_STATUS_MAX]; + u1Byte c2h_ind_buf[COL_H2C_BUF_LEN]; + u1Byte c2h_ind_len; +} BTC_OFFLOAD, *PBTC_OFFLOAD; +extern BTC_OFFLOAD gl_coex_offload; +/*==================================================*/ + +typedef u1Byte +(*BFP_BTC_R1)( + IN PVOID pBtcContext, + IN u4Byte RegAddr + ); +typedef u2Byte +(*BFP_BTC_R2)( + IN PVOID pBtcContext, + IN u4Byte RegAddr + ); +typedef u4Byte +(*BFP_BTC_R4)( + IN PVOID pBtcContext, + IN u4Byte RegAddr + ); +typedef VOID +(*BFP_BTC_W1)( + IN PVOID pBtcContext, + IN u4Byte RegAddr, + IN u1Byte Data + ); +typedef VOID +(*BFP_BTC_W1_BIT_MASK)( + IN PVOID pBtcContext, + IN u4Byte regAddr, + IN u1Byte bitMask, + IN u1Byte data1b + ); +typedef VOID +(*BFP_BTC_W2)( + IN PVOID pBtcContext, + IN u4Byte RegAddr, + IN u2Byte Data + ); +typedef VOID +(*BFP_BTC_W4)( + IN PVOID pBtcContext, + IN u4Byte RegAddr, + IN u4Byte Data + ); +typedef VOID +(*BFP_BTC_LOCAL_REG_W1)( + IN PVOID pBtcContext, + IN u4Byte RegAddr, + IN u1Byte Data + ); +typedef VOID +(*BFP_BTC_SET_BB_REG)( + IN PVOID pBtcContext, + IN u4Byte RegAddr, + IN u4Byte BitMask, + IN u4Byte Data + ); +typedef u4Byte +(*BFP_BTC_GET_BB_REG)( + IN PVOID pBtcContext, + IN u4Byte RegAddr, + IN u4Byte BitMask + ); +typedef VOID +(*BFP_BTC_SET_RF_REG)( + IN PVOID pBtcContext, + IN u1Byte eRFPath, + IN u4Byte RegAddr, + IN u4Byte BitMask, + IN u4Byte Data + ); +typedef u4Byte +(*BFP_BTC_GET_RF_REG)( + IN PVOID pBtcContext, + IN u1Byte eRFPath, + IN u4Byte RegAddr, + IN u4Byte BitMask + ); +typedef VOID +(*BFP_BTC_FILL_H2C)( + IN PVOID pBtcContext, + IN u1Byte elementId, + IN u4Byte cmdLen, + IN pu1Byte pCmdBuffer + ); + +typedef BOOLEAN +(*BFP_BTC_GET)( + IN PVOID pBtCoexist, + IN u1Byte getType, + OUT PVOID pOutBuf + ); + +typedef BOOLEAN +(*BFP_BTC_SET)( + IN PVOID pBtCoexist, + IN u1Byte setType, + OUT PVOID pInBuf + ); +typedef u2Byte +(*BFP_BTC_SET_BT_REG)( + IN PVOID pBtcContext, + IN u1Byte regType, + IN u4Byte offset, + IN u4Byte value + ); +typedef BOOLEAN +(*BFP_BTC_SET_BT_ANT_DETECTION)( + IN PVOID pBtcContext, + IN u1Byte txTime, + IN u1Byte btChnl + ); + +typedef BOOLEAN +(*BFP_BTC_SET_BT_TRX_MASK)( + IN PVOID pBtcContext, + IN u1Byte bt_trx_mask + ); + +typedef u4Byte +(*BFP_BTC_GET_BT_REG)( + IN PVOID pBtcContext, + IN u1Byte regType, + IN u4Byte offset + ); +typedef VOID +(*BFP_BTC_DISP_DBG_MSG)( + IN PVOID pBtCoexist, + IN u1Byte dispType + ); + +typedef COL_H2C_STATUS +(*BFP_BTC_COEX_H2C_PROCESS)( + IN PVOID pBtCoexist, + IN u1Byte opcode, + IN u1Byte opcode_ver, + IN pu1Byte ph2c_par, + IN u1Byte h2c_par_len + ); + +typedef u4Byte +(*BFP_BTC_GET_BT_COEX_SUPPORTED_FEATURE)( + IN PVOID pBtcContext + ); + +typedef u4Byte +(*BFP_BTC_GET_BT_COEX_SUPPORTED_VERSION)( + IN PVOID pBtcContext + ); + +typedef u4Byte +(*BFP_BTC_GET_PHYDM_VERSION)( + IN PVOID pBtcContext + ); + +typedef VOID +(*BTC_PHYDM_MODIFY_RA_PCR_THRESHLOD)( + IN PVOID pDM_Odm, + IN u1Byte RA_offset_direction, + IN u1Byte RA_threshold_offset + ); + +typedef u4Byte +(*BTC_PHYDM_CMNINFOQUERY)( + IN PVOID pDM_Odm, + IN u1Byte info_type + ); + +typedef u1Byte +(*BFP_BTC_GET_ANT_DET_VAL_FROM_BT)( + + IN PVOID pBtcContext + ); + +typedef u1Byte +(*BFP_BTC_GET_BLE_SCAN_TYPE_FROM_BT)( + IN PVOID pBtcContext + ); + +typedef u4Byte +(*BFP_BTC_GET_BLE_SCAN_PARA_FROM_BT)( + IN PVOID pBtcContext, + IN u1Byte scanType + ); + +typedef BOOLEAN +(*BFP_BTC_GET_BT_AFH_MAP_FROM_BT)( + IN PVOID pBtcContext, + IN u1Byte mapType, + OUT pu1Byte afhMap + ); + +struct btc_bt_info { + boolean bt_disabled; + boolean bt_enable_disable_change; + u8 rssi_adjust_for_agc_table_on; + u8 rssi_adjust_for_1ant_coex_type; + boolean pre_bt_ctrl_agg_buf_size; + boolean bt_ctrl_agg_buf_size; + boolean pre_reject_agg_pkt; + boolean reject_agg_pkt; + boolean increase_scan_dev_num; + boolean bt_tx_rx_mask; + u8 pre_agg_buf_size; + u8 agg_buf_size; + boolean bt_busy; + boolean limited_dig; + u16 bt_hci_ver; + u16 bt_real_fw_ver; + u8 bt_fw_ver; + u32 get_bt_fw_ver_cnt; + u32 bt_get_fw_ver; + boolean miracast_plus_bt; + + boolean bt_disable_low_pwr; + + boolean bt_ctrl_lps; + boolean bt_lps_on; + boolean force_to_roam; /* for 1Ant solution */ + u8 lps_val; + u8 rpwm_val; + u32 ra_mask; +}; + +struct btc_stack_info { + boolean profile_notified; + u16 hci_version; /* stack hci version */ + u8 num_of_link; + boolean bt_link_exist; + boolean sco_exist; + boolean acl_exist; + boolean a2dp_exist; + boolean hid_exist; + u8 num_of_hid; + boolean pan_exist; + boolean unknown_acl_exist; + s8 min_bt_rssi; +}; + +struct btc_bt_link_info { + boolean bt_link_exist; + boolean bt_hi_pri_link_exist; + boolean sco_exist; + boolean sco_only; + boolean a2dp_exist; + boolean a2dp_only; + boolean hid_exist; + boolean hid_only; + boolean pan_exist; + boolean pan_only; + boolean slave_role; + boolean acl_busy; +}; + +struct btc_statistics { + u32 cnt_bind; + u32 cnt_power_on; + u32 cnt_pre_load_firmware; + u32 cnt_init_hw_config; + u32 cnt_init_coex_dm; + u32 cnt_ips_notify; + u32 cnt_lps_notify; + u32 cnt_scan_notify; + u32 cnt_connect_notify; + u32 cnt_media_status_notify; + u32 cnt_specific_packet_notify; + u32 cnt_bt_info_notify; + u32 cnt_rf_status_notify; + u32 cnt_periodical; + u32 cnt_coex_dm_switch; + u32 cnt_stack_operation_notify; + u32 cnt_dbg_ctrl; +}; + +struct btc_coexist { + BOOLEAN bBinded; /*make sure only one adapter can bind the data context*/ + PVOID Adapter; /*default adapter*/ + struct btc_board_info board_info; + struct btc_bt_info bt_info; /*some bt info referenced by non-bt module*/ + struct btc_stack_info stack_info; + struct btc_bt_link_info bt_link_info; + BTC_CHIP_INTERFACE chip_interface; + PVOID odm_priv; + + BOOLEAN initilized; + BOOLEAN stop_coex_dm; + BOOLEAN manual_control; + BOOLEAN bdontenterLPS; + pu1Byte cli_buf; + struct btc_statistics statistics; + u1Byte pwrModeVal[10]; + + /* function pointers */ + /* io related */ + BFP_BTC_R1 btc_read_1byte; + BFP_BTC_W1 btc_write_1byte; + BFP_BTC_W1_BIT_MASK btc_write_1byte_bitmask; + BFP_BTC_R2 btc_read_2byte; + BFP_BTC_W2 btc_write_2byte; + BFP_BTC_R4 btc_read_4byte; + BFP_BTC_W4 btc_write_4byte; + BFP_BTC_LOCAL_REG_W1 btc_write_local_reg_1byte; + /* read/write bb related */ + BFP_BTC_SET_BB_REG btc_set_bb_reg; + BFP_BTC_GET_BB_REG btc_get_bb_reg; + + /* read/write rf related */ + BFP_BTC_SET_RF_REG btc_set_rf_reg; + BFP_BTC_GET_RF_REG btc_get_rf_reg; + + /* fill h2c related */ + BFP_BTC_FILL_H2C btc_fill_h2c; + /* other */ + BFP_BTC_DISP_DBG_MSG btc_disp_dbg_msg; + /* normal get/set related */ + BFP_BTC_GET btc_get; + BFP_BTC_SET btc_set; + + BFP_BTC_GET_BT_REG btc_get_bt_reg; + BFP_BTC_SET_BT_REG btc_set_bt_reg; + + BFP_BTC_SET_BT_ANT_DETECTION btc_set_bt_ant_detection; + + BFP_BTC_COEX_H2C_PROCESS btc_coex_h2c_process; + BFP_BTC_SET_BT_TRX_MASK btc_set_bt_trx_mask; + BFP_BTC_GET_BT_COEX_SUPPORTED_FEATURE btc_get_bt_coex_supported_feature; + BFP_BTC_GET_BT_COEX_SUPPORTED_VERSION btc_get_bt_coex_supported_version; + BFP_BTC_GET_PHYDM_VERSION btc_get_bt_phydm_version; + BTC_PHYDM_MODIFY_RA_PCR_THRESHLOD btc_phydm_modify_RA_PCR_threshold; + BTC_PHYDM_CMNINFOQUERY btc_phydm_query_PHY_counter; + BFP_BTC_GET_ANT_DET_VAL_FROM_BT btc_get_ant_det_val_from_bt; + BFP_BTC_GET_BLE_SCAN_TYPE_FROM_BT btc_get_ble_scan_type_from_bt; + BFP_BTC_GET_BLE_SCAN_PARA_FROM_BT btc_get_ble_scan_para_from_bt; + BFP_BTC_GET_BT_AFH_MAP_FROM_BT btc_get_bt_afh_map_from_bt; +}; +typedef struct btc_coexist *PBTC_COEXIST; + +extern struct btc_coexist GLBtCoexist; + +BOOLEAN +EXhalbtcoutsrc_InitlizeVariables( + IN PVOID Adapter + ); +VOID +EXhalbtcoutsrc_PowerOnSetting( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtcoutsrc_PreLoadFirmware( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtcoutsrc_InitHwConfig( + IN PBTC_COEXIST pBtCoexist, + IN BOOLEAN bWifiOnly + ); +VOID +EXhalbtcoutsrc_InitCoexDm( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtcoutsrc_IpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtcoutsrc_LpsNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtcoutsrc_ScanNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtcoutsrc_SetAntennaPathNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtcoutsrc_ConnectNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte action + ); +VOID +EXhalbtcoutsrc_MediaStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN RT_MEDIA_STATUS mediaStatus + ); +VOID +EXhalbtcoutsrc_SpecificPacketNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pktType + ); +VOID +EXhalbtcoutsrc_BtInfoNotify( + IN PBTC_COEXIST pBtCoexist, + IN pu1Byte tmpBuf, + IN u1Byte length + ); +VOID +EXhalbtcoutsrc_RfStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtcoutsrc_StackOperationNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type + ); +VOID +EXhalbtcoutsrc_HaltNotify( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtcoutsrc_PnpNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte pnpState + ); +VOID +EXhalbtcoutsrc_CoexDmSwitch( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtcoutsrc_Periodical( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtcoutsrc_DbgControl( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte opCode, + IN u1Byte opLen, + IN pu1Byte pData + ); +VOID +EXhalbtcoutsrc_AntennaDetection( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte centFreq, + IN u4Byte offset, + IN u4Byte span, + IN u4Byte seconds + ); +VOID +EXhalbtcoutsrc_StackUpdateProfileInfo( + VOID + ); +VOID +EXhalbtcoutsrc_SetHciVersion( + IN u2Byte hciVersion + ); +VOID +EXhalbtcoutsrc_SetBtPatchVersion( + IN u2Byte btHciVersion, + IN u2Byte btPatchVersion + ); +VOID +EXhalbtcoutsrc_UpdateMinBtRssi( + IN s1Byte btRssi + ); +#if 0 +VOID +EXhalbtcoutsrc_SetBtExist( + IN BOOLEAN bBtExist + ); +#endif +VOID +EXhalbtcoutsrc_SetChipType( + IN u1Byte chipType + ); +VOID +EXhalbtcoutsrc_SetAntNum( + IN u1Byte type, + IN u1Byte antNum + ); +VOID +EXhalbtcoutsrc_SetSingleAntPath( + IN u1Byte singleAntPath + ); +VOID +EXhalbtcoutsrc_DisplayBtCoexInfo( + IN PBTC_COEXIST pBtCoexist + ); +VOID +EXhalbtcoutsrc_DisplayAntDetection( + IN PBTC_COEXIST pBtCoexist + ); + +#define MASKBYTE0 0xff +#define MASKBYTE1 0xff00 +#define MASKBYTE2 0xff0000 +#define MASKBYTE3 0xff000000 +#define MASKHWORD 0xffff0000 +#define MASKLWORD 0x0000ffff +#define MASKDWORD 0xffffffff +#define MASK12BITS 0xfff +#define MASKH4BITS 0xf0000000 +#define MASKOFDM_D 0xffc00000 +#define MASKCCK 0x3f3f3f3f + +#endif diff --git a/linux-bsp/drivers/rtl8188eus/hal/btc/mp_precomp.h b/linux-bsp/drivers/rtl8188eus/hal/btc/mp_precomp.h new file mode 100644 index 0000000..54125b1 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/btc/mp_precomp.h @@ -0,0 +1,90 @@ +/****************************************************************************** + * + * Copyright(c) 2013 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __MP_PRECOMP_H__ +#define __MP_PRECOMP_H__ + +#include <drv_types.h> +#include <hal_data.h> + +#define BT_TMP_BUF_SIZE 100 + +#ifdef PLATFORM_LINUX +#define rsprintf snprintf +#elif defined(PLATFORM_WINDOWS) +#define rsprintf sprintf_s +#endif + +#define DCMD_Printf DBG_BT_INFO + +#define delay_ms(ms) rtw_mdelay_os(ms) + +#ifdef bEnable +#undef bEnable +#endif + +#define WPP_SOFTWARE_TRACE 0 + +typedef enum _BTC_MSG_COMP_TYPE { + COMP_COEX = 0, + COMP_MAX +} BTC_MSG_COMP_TYPE; +extern u4Byte GLBtcDbgType[]; + +#define DBG_OFF 0 +#define DBG_SEC 1 +#define DBG_SERIOUS 2 +#define DBG_WARNING 3 +#define DBG_LOUD 4 +#define DBG_TRACE 5 + +#ifdef CONFIG_BT_COEXIST +#define BT_SUPPORT 1 +#define COEX_SUPPORT 1 +#define HS_SUPPORT 1 +#else +#define BT_SUPPORT 0 +#define COEX_SUPPORT 0 +#define HS_SUPPORT 0 +#endif + +#include "halbtcoutsrc.h" +#include "halbtc8192e1ant.h" +#include "halbtc8192e2ant.h" +#include "halbtc8723b1ant.h" +#include "halbtc8723b2ant.h" +#include "halbtc8812a1ant.h" +#include "halbtc8812a2ant.h" +#include "halbtc8821a1ant.h" +#include "halbtc8821a2ant.h" +#include "halbtc8703b1ant.h" +#include "halbtc8723d1ant.h" +#include "halbtc8723d2ant.h" +#include "halbtc8822b1ant.h" +#include "halbtc8822b2ant.h" +#include "halbtc8821c1ant.h" +#include "halbtc8821c2ant.h" + +/* for wifi only mode */ +#include "hal_btcoex_wifionly.h" +#include "halbtc8723bwifionly.h" +#include "halbtc8822bwifionly.h" +#include "halbtc8821cwifionly.h" + +#endif /* __MP_PRECOMP_H__ */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/efuse/efuse_mask.h b/linux-bsp/drivers/rtl8188eus/hal/efuse/efuse_mask.h new file mode 100644 index 0000000..faafed4 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/efuse/efuse_mask.h @@ -0,0 +1,106 @@ + +#if DEV_BUS_TYPE == RT_USB_INTERFACE + +#if defined(CONFIG_RTL8188E) + #include "rtl8188e/HalEfuseMask8188E_USB.h" +#endif + +#if defined(CONFIG_RTL8812A) + #include "rtl8812a/HalEfuseMask8812A_USB.h" +#endif + +#if defined(CONFIG_RTL8821A) + #include "rtl8812a/HalEfuseMask8821A_USB.h" +#endif + +#if defined(CONFIG_RTL8192E) + #include "rtl8192e/HalEfuseMask8192E_USB.h" +#endif + +#if defined(CONFIG_RTL8723B) + #include "rtl8723b/HalEfuseMask8723B_USB.h" +#endif + +#if defined(CONFIG_RTL8814A) + #include "rtl8814a/HalEfuseMask8814A_USB.h" +#endif + +#if defined(CONFIG_RTL8703B) + #include "rtl8703b/HalEfuseMask8703B_USB.h" +#endif + +#if defined(CONFIG_RTL8723D) + #include "rtl8723d/HalEfuseMask8723D_USB.h" +#endif + +#if defined(CONFIG_RTL8188F) + #include "rtl8188f/HalEfuseMask8188F_USB.h" +#endif + +#if defined(CONFIG_RTL8822B) + #include "rtl8822b/HalEfuseMask8822B_USB.h" +#endif + +#elif DEV_BUS_TYPE == RT_PCI_INTERFACE + +#if defined(CONFIG_RTL8188E) + #include "rtl8188e/HalEfuseMask8188E_PCIE.h" +#endif + +#if defined(CONFIG_RTL8812A) + #include "rtl8812a/HalEfuseMask8812A_PCIE.h" +#endif + +#if defined(CONFIG_RTL8821A) + #include "rtl8812a/HalEfuseMask8821A_PCIE.h" +#endif + +#if defined(CONFIG_RTL8192E) + #include "rtl8192e/HalEfuseMask8192E_PCIE.h" +#endif + +#if defined(CONFIG_RTL8723B) + #include "rtl8723b/HalEfuseMask8723B_PCIE.h" +#endif + +#if defined(CONFIG_RTL8814A) + #include "rtl8814a/HalEfuseMask8814A_PCIE.h" +#endif + +#if defined(CONFIG_RTL8703B) + #include "rtl8703b/HalEfuseMask8703B_PCIE.h" +#endif + +#if defined(CONFIG_RTL8822B) + #include "rtl8822b/HalEfuseMask8822B_PCIE.h" +#endif +#if defined(CONFIG_RTL8723D) + #include "rtl8723d/HalEfuseMask8723D_PCIE.h" +#endif + +#elif DEV_BUS_TYPE == RT_SDIO_INTERFACE + +#if defined(CONFIG_RTL8188E) + #include "rtl8188e/HalEfuseMask8188E_SDIO.h" +#endif + +#if defined(CONFIG_RTL8703B) + #include "rtl8703b/HalEfuseMask8703B_SDIO.h" +#endif + +#if defined(CONFIG_RTL8188F) + #include "rtl8188f/HalEfuseMask8188F_SDIO.h" +#endif + +#if defined(CONFIG_RTL8723D) + #include "rtl8723d/HalEfuseMask8723D_SDIO.h" +#endif + +#if defined(CONFIG_RTL8821C) + #include "rtl8821c/HalEfuseMask8821C_SDIO.h" +#endif + +#if defined(CONFIG_RTL8822B) + #include "rtl8822b/HalEfuseMask8822B_SDIO.h" +#endif +#endif diff --git a/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_PCIE.c b/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_PCIE.c new file mode 100644 index 0000000..bdbd717 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_PCIE.c @@ -0,0 +1,101 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + +/* #include "Mp_Precomp.h" */ +/* #include "../odm_precomp.h" */ + +#include <drv_types.h> + +#include "HalEfuseMask8188E_PCIE.h" + + + +/****************************************************************************** +* MPCIE.TXT +******************************************************************************/ + +u1Byte Array_MP_8188E_MPCIE[] = { + 0xFF, + 0xF3, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x0F, + 0xF1, + 0xFF, + 0xFF, + 0x70, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + +}; + +u2Byte +EFUSE_GetArrayLen_MP_8188E_MPCIE(VOID) +{ + return sizeof(Array_MP_8188E_MPCIE) / sizeof(u1Byte); +} + +VOID +EFUSE_GetMaskArray_MP_8188E_MPCIE( + IN OUT pu1Byte Array +) +{ + u2Byte len = EFUSE_GetArrayLen_MP_8188E_MPCIE(), i = 0; + + for (i = 0; i < len; ++i) + Array[i] = Array_MP_8188E_MPCIE[i]; +} +BOOLEAN +EFUSE_IsAddressMasked_MP_8188E_MPCIE( + IN u2Byte Offset +) +{ + int r = Offset / 16; + int c = (Offset % 16) / 2; + int result = 0; + + if (c < 4) /* Upper double word */ + result = (Array_MP_8188E_MPCIE[r] & (0x10 << c)); + else + result = (Array_MP_8188E_MPCIE[r] & (0x01 << (c - 4))); + + return (result > 0) ? 0 : 1; +} diff --git a/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_PCIE.h b/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_PCIE.h new file mode 100644 index 0000000..f4f15f3 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_PCIE.h @@ -0,0 +1,39 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + + + +/****************************************************************************** +* MPCIE.TXT +******************************************************************************/ + + +u2Byte +EFUSE_GetArrayLen_MP_8188E_MPCIE(VOID); + +VOID +EFUSE_GetMaskArray_MP_8188E_MPCIE( + IN OUT pu1Byte Array +); + +BOOLEAN +EFUSE_IsAddressMasked_MP_8188E_MPCIE(/* TC: Test Chip, MP: MP Chip */ + IN u2Byte Offset +); diff --git a/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_SDIO.c b/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_SDIO.c new file mode 100644 index 0000000..d2b4ba1 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_SDIO.c @@ -0,0 +1,101 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + +/* #include "Mp_Precomp.h" */ +/* #include "../odm_precomp.h" */ + +#include <drv_types.h> + +#include "HalEfuseMask8188E_SDIO.h" + + + +/****************************************************************************** +* MSDIO.TXT +******************************************************************************/ + +u1Byte Array_MP_8188E_MSDIO[] = { + 0xFF, + 0xF3, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x0F, + 0xF1, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + +}; + +u2Byte +EFUSE_GetArrayLen_MP_8188E_MSDIO(VOID) +{ + return sizeof(Array_MP_8188E_MSDIO) / sizeof(u1Byte); +} + +VOID +EFUSE_GetMaskArray_MP_8188E_MSDIO( + IN OUT pu1Byte Array +) +{ + u2Byte len = EFUSE_GetArrayLen_MP_8188E_MSDIO(), i = 0; + + for (i = 0; i < len; ++i) + Array[i] = Array_MP_8188E_MSDIO[i]; +} +BOOLEAN +EFUSE_IsAddressMasked_MP_8188E_MSDIO( + IN u2Byte Offset +) +{ + int r = Offset / 16; + int c = (Offset % 16) / 2; + int result = 0; + + if (c < 4) /* Upper double word */ + result = (Array_MP_8188E_MSDIO[r] & (0x10 << c)); + else + result = (Array_MP_8188E_MSDIO[r] & (0x01 << (c - 4))); + + return (result > 0) ? 0 : 1; +} diff --git a/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_SDIO.h b/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_SDIO.h new file mode 100644 index 0000000..f1f2ac2 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_SDIO.h @@ -0,0 +1,39 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + + + +/****************************************************************************** +* MSDIO.TXT +******************************************************************************/ + + +u2Byte +EFUSE_GetArrayLen_MP_8188E_MSDIO(VOID); + +VOID +EFUSE_GetMaskArray_MP_8188E_MSDIO( + IN OUT pu1Byte Array +); + +BOOLEAN +EFUSE_IsAddressMasked_MP_8188E_MSDIO(/* TC: Test Chip, MP: MP Chip */ + IN u2Byte Offset +); diff --git a/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_USB.c b/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_USB.c new file mode 100644 index 0000000..7bf0444 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_USB.c @@ -0,0 +1,100 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + +/* #include "Mp_Precomp.h" */ +/* #include "../odm_precomp.h" */ + +#include <drv_types.h> + +#include "HalEfuseMask8188E_USB.h" + + +/****************************************************************************** +* MUSB.TXT +******************************************************************************/ + +u1Byte Array_MP_8188E_MUSB[] = { + 0xFF, + 0xF3, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x0F, + 0xF1, + 0xFF, + 0xFF, + 0xFF, + 0x00, + 0x00, + 0x00, + 0xF7, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + +}; + +u2Byte +EFUSE_GetArrayLen_MP_8188E_MUSB(VOID) +{ + return sizeof(Array_MP_8188E_MUSB) / sizeof(u1Byte); +} + +VOID +EFUSE_GetMaskArray_MP_8188E_MUSB( + IN OUT pu1Byte Array +) +{ + u2Byte len = EFUSE_GetArrayLen_MP_8188E_MUSB(), i = 0; + + for (i = 0; i < len; ++i) + Array[i] = Array_MP_8188E_MUSB[i]; +} +BOOLEAN +EFUSE_IsAddressMasked_MP_8188E_MUSB( + IN u2Byte Offset +) +{ + int r = Offset / 16; + int c = (Offset % 16) / 2; + int result = 0; + + if (c < 4) /* Upper double word */ + result = (Array_MP_8188E_MUSB[r] & (0x10 << c)); + else + result = (Array_MP_8188E_MUSB[r] & (0x01 << (c - 4))); + + return (result > 0) ? 0 : 1; +} diff --git a/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_USB.h b/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_USB.h new file mode 100644 index 0000000..8b70454 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/efuse/rtl8188e/HalEfuseMask8188E_USB.h @@ -0,0 +1,39 @@ +/****************************************************************************** +* +* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of version 2 of the GNU General Public License as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +* +* +******************************************************************************/ + + + +/****************************************************************************** +* MUSB.TXT +******************************************************************************/ + + +u2Byte +EFUSE_GetArrayLen_MP_8188E_MUSB(VOID); + +VOID +EFUSE_GetMaskArray_MP_8188E_MUSB( + IN OUT pu1Byte Array +); + +BOOLEAN +EFUSE_IsAddressMasked_MP_8188E_MUSB(/* TC: Test Chip, MP: MP Chip */ + IN u2Byte Offset +); diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_btcoex.c b/linux-bsp/drivers/rtl8188eus/hal/hal_btcoex.c new file mode 100644 index 0000000..492f73f --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_btcoex.c @@ -0,0 +1,4474 @@ +/****************************************************************************** + * + * Copyright(c) 2013 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define __HAL_BTCOEX_C__ + +#ifdef CONFIG_BT_COEXIST + +#include <hal_data.h> +#include <hal_btcoex.h> +#include "btc/mp_precomp.h" + +/* ************************************ + * Global variables + * ************************************ */ +const char *const BtProfileString[] = { + "NONE", + "A2DP", + "PAN", + "HID", + "SCO", +}; + +const char *const BtSpecString[] = { + "1.0b", + "1.1", + "1.2", + "2.0+EDR", + "2.1+EDR", + "3.0+HS", + "4.0", +}; + +const char *const BtLinkRoleString[] = { + "Master", + "Slave", +}; + +const char *const h2cStaString[] = { + "successful", + "h2c busy", + "rf off", + "fw not read", +}; + +const char *const ioStaString[] = { + "success", + "can not IO", + "rf off", + "fw not read", + "wait io timeout", + "invalid len", + "idle Q empty", + "insert waitQ fail", + "unknown fail", + "wrong level", + "h2c stopped", +}; + +const char *const GLBtcWifiBwString[] = { + "11bg", + "HT20", + "HT40", + "HT80", + "HT160" +}; + +const char *const GLBtcWifiFreqString[] = { + "2.4G", + "5G" +}; + +const char *const GLBtcIotPeerString[] = { + "UNKNOWN", + "REALTEK", + "REALTEK_92SE", + "BROADCOM", + "RALINK", + "ATHEROS", + "CISCO", + "MERU", + "MARVELL", + "REALTEK_SOFTAP", /* peer is RealTek SOFT_AP, by Bohn, 2009.12.17 */ + "SELF_SOFTAP", /* Self is SoftAP */ + "AIRGO", + "INTEL", + "RTK_APCLIENT", + "REALTEK_81XX", + "REALTEK_WOW", + "REALTEK_JAGUAR_BCUTAP", + "REALTEK_JAGUAR_CCUTAP" +}; + +const char *const coexOpcodeString[] = { + "Wifi status notify", + "Wifi progress", + "Wifi info", + "Power state", + "Set Control", + "Get Control" +}; + +const char *const coexIndTypeString[] = { + "bt info", + "pstdma", + "limited tx/rx", + "coex table", + "request" +}; + +const char *const coexH2cResultString[] = { + "ok", + "unknown", + "un opcode", + "opVer MM", + "par Err", + "par OoR", + "reqNum MM", + "halMac Fail", + "h2c TimeOut", + "Invalid c2h Len", + "data overflow" +}; + +#define HALBTCOUTSRC_AGG_CHK_WINDOW_IN_MS 8000 + +struct btc_coexist GLBtCoexist; +BTC_OFFLOAD gl_coex_offload; +u8 GLBtcWiFiInScanState; +u8 GLBtcWiFiInIQKState; +u8 GLBtcWiFiInIPS; +u8 GLBtcWiFiInLPS; +u8 GLBtcBtCoexAliveRegistered; + +/* + * BT control H2C/C2H + */ +/* EXT_EID */ +typedef enum _bt_ext_eid { + C2H_WIFI_FW_ACTIVE_RSP = 0, + C2H_TRIG_BY_BT_FW +} BT_EXT_EID; + +/* C2H_STATUS */ +typedef enum _bt_c2h_status { + BT_STATUS_OK = 0, + BT_STATUS_VERSION_MISMATCH, + BT_STATUS_UNKNOWN_OPCODE, + BT_STATUS_ERROR_PARAMETER +} BT_C2H_STATUS; + +/* C2H BT OP CODES */ +typedef enum _bt_op_code { + BT_OP_GET_BT_VERSION = 0x00, + BT_OP_WRITE_REG_ADDR = 0x0c, + BT_OP_WRITE_REG_VALUE = 0x0d, + + BT_OP_READ_REG = 0x11, + + BT_LO_OP_GET_AFH_MAP_L = 0x1e, + BT_LO_OP_GET_AFH_MAP_M = 0x1f, + BT_LO_OP_GET_AFH_MAP_H = 0x20, + + BT_OP_GET_BT_COEX_SUPPORTED_FEATURE = 0x2a, + BT_OP_GET_BT_COEX_SUPPORTED_VERSION = 0x2b, + BT_OP_GET_BT_ANT_DET_VAL = 0x2c, + BT_OP_GET_BT_BLE_SCAN_PARA = 0x2d, + BT_OP_GET_BT_BLE_SCAN_TYPE = 0x2e, + BT_OP_MAX +} BT_OP_CODE; + +#define BTC_MPOPER_TIMEOUT 50 /* unit: ms */ + +#define C2H_MAX_SIZE 16 +u8 GLBtcBtMpOperSeq; +_mutex GLBtcBtMpOperLock; +_timer GLBtcBtMpOperTimer; +_sema GLBtcBtMpRptSema; +u8 GLBtcBtMpRptSeq; +u8 GLBtcBtMpRptStatus; +u8 GLBtcBtMpRptRsp[C2H_MAX_SIZE]; +u8 GLBtcBtMpRptRspSize; +u8 GLBtcBtMpRptWait; +u8 GLBtcBtMpRptWiFiOK; +u8 GLBtcBtMpRptBTOK; + +/* + * Debug + */ +u32 GLBtcDbgType[COMP_MAX]; +u8 GLBtcDbgBuf[BT_TMP_BUF_SIZE]; +u1Byte gl_btc_trace_buf[BT_TMP_BUF_SIZE]; + +typedef struct _btcoexdbginfo { + u8 *info; + u32 size; /* buffer total size */ + u32 len; /* now used length */ +} BTCDBGINFO, *PBTCDBGINFO; + +BTCDBGINFO GLBtcDbgInfo; + +#define BT_Operation(Adapter) _FALSE + +static void DBG_BT_INFO_INIT(PBTCDBGINFO pinfo, u8 *pbuf, u32 size) +{ + if (NULL == pinfo) + return; + + _rtw_memset(pinfo, 0, sizeof(BTCDBGINFO)); + + if (pbuf && size) { + pinfo->info = pbuf; + pinfo->size = size; + } +} + +void DBG_BT_INFO(u8 *dbgmsg) +{ + PBTCDBGINFO pinfo; + u32 msglen, buflen; + u8 *pbuf; + + + pinfo = &GLBtcDbgInfo; + + if (NULL == pinfo->info) + return; + + msglen = strlen(dbgmsg); + if (pinfo->len + msglen > pinfo->size) + return; + + pbuf = pinfo->info + pinfo->len; + _rtw_memcpy(pbuf, dbgmsg, msglen); + pinfo->len += msglen; +} + +/* ************************************ + * Debug related function + * ************************************ */ +static u8 halbtcoutsrc_IsBtCoexistAvailable(PBTC_COEXIST pBtCoexist) +{ + if (!pBtCoexist->bBinded || + NULL == pBtCoexist->Adapter) + return _FALSE; + return _TRUE; +} + +static void halbtcoutsrc_DbgInit(void) +{ + u8 i; + + for (i = 0; i < COMP_MAX; i++) + GLBtcDbgType[i] = 0; +} + +static u8 halbtcoutsrc_IsCsrBtCoex(PBTC_COEXIST pBtCoexist) +{ + if (pBtCoexist->board_info.bt_chip_type == BTC_CHIP_CSR_BC4 + || pBtCoexist->board_info.bt_chip_type == BTC_CHIP_CSR_BC8 + ) + return _TRUE; + return _FALSE; +} + +static u8 halbtcoutsrc_IsHwMailboxExist(PBTC_COEXIST pBtCoexist) +{ + if (pBtCoexist->board_info.bt_chip_type == BTC_CHIP_CSR_BC4 + || pBtCoexist->board_info.bt_chip_type == BTC_CHIP_CSR_BC8 + ) + return _FALSE; + else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) + return _FALSE; + else + return _TRUE; +} + +static void halbtcoutsrc_LeaveLps(PBTC_COEXIST pBtCoexist) +{ + PADAPTER padapter; + + + padapter = pBtCoexist->Adapter; + + pBtCoexist->bt_info.bt_ctrl_lps = _TRUE; + pBtCoexist->bt_info.bt_lps_on = _FALSE; + + rtw_btcoex_LPS_Leave(padapter); +} + +void halbtcoutsrc_EnterLps(PBTC_COEXIST pBtCoexist) +{ + PADAPTER padapter; + + + padapter = pBtCoexist->Adapter; + + if (pBtCoexist->bdontenterLPS == _FALSE) { + pBtCoexist->bt_info.bt_ctrl_lps = _TRUE; + pBtCoexist->bt_info.bt_lps_on = _TRUE; + + rtw_btcoex_LPS_Enter(padapter); + } +} + +void halbtcoutsrc_NormalLps(PBTC_COEXIST pBtCoexist) +{ + PADAPTER padapter; + + + + padapter = pBtCoexist->Adapter; + + if (pBtCoexist->bt_info.bt_ctrl_lps) { + pBtCoexist->bt_info.bt_lps_on = _FALSE; + rtw_btcoex_LPS_Leave(padapter); + pBtCoexist->bt_info.bt_ctrl_lps = _FALSE; + + /* recover the LPS state to the original */ +#if 0 + padapter->hal_func.UpdateLPSStatusHandler( + padapter, + pPSC->RegLeisurePsMode, + pPSC->RegPowerSaveMode); +#endif + } +} + +/* + * Constraint: + * 1. this function will request pwrctrl->lock + */ +void halbtcoutsrc_LeaveLowPower(PBTC_COEXIST pBtCoexist) +{ +#ifdef CONFIG_LPS_LCLK + PADAPTER padapter; + PHAL_DATA_TYPE pHalData; + struct pwrctrl_priv *pwrctrl; + s32 ready; + u32 stime; + s32 utime; + u32 timeout; /* unit: ms */ + + + padapter = pBtCoexist->Adapter; + pHalData = GET_HAL_DATA(padapter); + pwrctrl = adapter_to_pwrctl(padapter); + ready = _FAIL; +#ifdef LPS_RPWM_WAIT_MS + timeout = LPS_RPWM_WAIT_MS; +#else /* !LPS_RPWM_WAIT_MS */ + timeout = 30; +#endif /* !LPS_RPWM_WAIT_MS */ + + if (GLBtcBtCoexAliveRegistered == _TRUE) + return; + + stime = rtw_get_current_time(); + do { + ready = rtw_register_task_alive(padapter, BTCOEX_ALIVE); + if (_SUCCESS == ready) + break; + + utime = rtw_get_passing_time_ms(stime); + if (utime > timeout) + break; + + rtw_msleep_os(1); + } while (1); + + GLBtcBtCoexAliveRegistered = _TRUE; +#endif /* CONFIG_LPS_LCLK */ +} + +/* + * Constraint: + * 1. this function will request pwrctrl->lock + */ +void halbtcoutsrc_NormalLowPower(PBTC_COEXIST pBtCoexist) +{ +#ifdef CONFIG_LPS_LCLK + PADAPTER padapter; + + if (GLBtcBtCoexAliveRegistered == _FALSE) + return; + + padapter = pBtCoexist->Adapter; + rtw_unregister_task_alive(padapter, BTCOEX_ALIVE); + + GLBtcBtCoexAliveRegistered = _FALSE; +#endif /* CONFIG_LPS_LCLK */ +} + +void halbtcoutsrc_DisableLowPower(PBTC_COEXIST pBtCoexist, u8 bLowPwrDisable) +{ + pBtCoexist->bt_info.bt_disable_low_pwr = bLowPwrDisable; + if (bLowPwrDisable) + halbtcoutsrc_LeaveLowPower(pBtCoexist); /* leave 32k low power. */ + else + halbtcoutsrc_NormalLowPower(pBtCoexist); /* original 32k low power behavior. */ +} + +void halbtcoutsrc_AggregationCheck(PBTC_COEXIST pBtCoexist) +{ + PADAPTER padapter; + BOOLEAN bNeedToAct = _FALSE; + static u32 preTime = 0; + u32 curTime = 0; + + padapter = pBtCoexist->Adapter; + + /* ===================================== */ + /* To void continuous deleteBA=>addBA=>deleteBA=>addBA */ + /* This function is not allowed to continuous called. */ + /* It can only be called after 8 seconds. */ + /* ===================================== */ + + curTime = rtw_systime_to_ms(rtw_get_current_time()); + if ((curTime - preTime) < HALBTCOUTSRC_AGG_CHK_WINDOW_IN_MS) /* over 8 seconds you can execute this function again. */ + return; + else + preTime = curTime; + + if (pBtCoexist->bt_info.reject_agg_pkt) { + bNeedToAct = _TRUE; + pBtCoexist->bt_info.pre_reject_agg_pkt = pBtCoexist->bt_info.reject_agg_pkt; + } else { + if (pBtCoexist->bt_info.pre_reject_agg_pkt) { + bNeedToAct = _TRUE; + pBtCoexist->bt_info.pre_reject_agg_pkt = pBtCoexist->bt_info.reject_agg_pkt; + } + + if (pBtCoexist->bt_info.pre_bt_ctrl_agg_buf_size != + pBtCoexist->bt_info.bt_ctrl_agg_buf_size) { + bNeedToAct = _TRUE; + pBtCoexist->bt_info.pre_bt_ctrl_agg_buf_size = pBtCoexist->bt_info.bt_ctrl_agg_buf_size; + } + + if (pBtCoexist->bt_info.bt_ctrl_agg_buf_size) { + if (pBtCoexist->bt_info.pre_agg_buf_size != + pBtCoexist->bt_info.agg_buf_size) + bNeedToAct = _TRUE; + pBtCoexist->bt_info.pre_agg_buf_size = pBtCoexist->bt_info.agg_buf_size; + } + } + + if (bNeedToAct) + rtw_btcoex_rx_ampdu_apply(padapter); +} + +u8 halbtcoutsrc_is_autoload_fail(PBTC_COEXIST pBtCoexist) +{ + PADAPTER padapter; + PHAL_DATA_TYPE pHalData; + + padapter = pBtCoexist->Adapter; + pHalData = GET_HAL_DATA(padapter); + + return pHalData->bautoload_fail_flag; +} + +u8 halbtcoutsrc_is_fw_ready(PBTC_COEXIST pBtCoexist) +{ + PADAPTER padapter; + + padapter = pBtCoexist->Adapter; + + return padapter->bFWReady; +} + +u8 halbtcoutsrc_IsWifiBusy(PADAPTER padapter) +{ + if (rtw_mi_check_status(padapter, MI_AP_MODE)) + return _TRUE; + if (rtw_mi_busy_traffic_check(padapter, _FALSE)) + return _TRUE; + + return _FALSE; +} + +static u32 _halbtcoutsrc_GetWifiLinkStatus(PADAPTER padapter) +{ + struct mlme_priv *pmlmepriv; + u8 bp2p; + u32 portConnectedStatus; + + + pmlmepriv = &padapter->mlmepriv; + bp2p = _FALSE; + portConnectedStatus = 0; + +#ifdef CONFIG_P2P + if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE)) + bp2p = _TRUE; +#endif /* CONFIG_P2P */ + + if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE) == _TRUE) { + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { + if (_TRUE == bp2p) + portConnectedStatus |= WIFI_P2P_GO_CONNECTED; + else + portConnectedStatus |= WIFI_AP_CONNECTED; + } else { + if (_TRUE == bp2p) + portConnectedStatus |= WIFI_P2P_GC_CONNECTED; + else + portConnectedStatus |= WIFI_STA_CONNECTED; + } + } + + return portConnectedStatus; +} + +u32 halbtcoutsrc_GetWifiLinkStatus(PBTC_COEXIST pBtCoexist) +{ + /* ================================= */ + /* return value: */ + /* [31:16]=> connected port number */ + /* [15:0]=> port connected bit define */ + /* ================================ */ + + PADAPTER padapter; + u32 retVal; + u32 portConnectedStatus, numOfConnectedPort; + struct dvobj_priv *dvobj; + _adapter *iface; + int i; + + padapter = pBtCoexist->Adapter; + retVal = 0; + portConnectedStatus = 0; + numOfConnectedPort = 0; + dvobj = adapter_to_dvobj(padapter); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if ((iface) && rtw_is_adapter_up(iface)) { + retVal = _halbtcoutsrc_GetWifiLinkStatus(iface); + if (retVal) { + portConnectedStatus |= retVal; + numOfConnectedPort++; + } + } + } + retVal = (numOfConnectedPort << 16) | portConnectedStatus; + + return retVal; +} + +static void _btmpoper_timer_hdl(void *p) +{ + if (GLBtcBtMpRptWait) { + GLBtcBtMpRptWait = 0; + _rtw_up_sema(&GLBtcBtMpRptSema); + } +} + +/* + * !IMPORTANT! + * Before call this function, caller should acquire "GLBtcBtMpOperLock"! + * Othrewise there will be racing problem and something may go wrong. + */ +static u8 _btmpoper_cmd(PBTC_COEXIST pBtCoexist, u8 opcode, u8 opcodever, u8 *cmd, u8 size) +{ + PADAPTER padapter; + u8 buf[H2C_BTMP_OPER_LEN] = {0}; + u8 buflen; + u8 seq; + u8 timer_cancelled; + s32 ret; + + + if (!cmd && size) + size = 0; + if ((size + 2) > H2C_BTMP_OPER_LEN) + return BT_STATUS_H2C_LENGTH_EXCEEDED; + buflen = size + 2; + + seq = GLBtcBtMpOperSeq & 0xF; + GLBtcBtMpOperSeq++; + + buf[0] = (opcodever & 0xF) | (seq << 4); + buf[1] = opcode; + if (cmd && size) + _rtw_memcpy(buf + 2, cmd, size); + + GLBtcBtMpRptWait = 1; + GLBtcBtMpRptWiFiOK = 0; + GLBtcBtMpRptBTOK = 0; + GLBtcBtMpRptStatus = 0; + padapter = pBtCoexist->Adapter; + _set_timer(&GLBtcBtMpOperTimer, BTC_MPOPER_TIMEOUT); + if (rtw_hal_fill_h2c_cmd(padapter, H2C_BT_MP_OPER, buflen, buf) == _FAIL) { + _cancel_timer(&GLBtcBtMpOperTimer, &timer_cancelled); + ret = BT_STATUS_H2C_FAIL; + goto exit; + } + + _rtw_down_sema(&GLBtcBtMpRptSema); + /* GLBtcBtMpRptWait should be 0 here*/ + + if (!GLBtcBtMpRptWiFiOK) { + RTW_ERR("%s: Didn't get H2C Rsp Event!\n", __FUNCTION__); + ret = BT_STATUS_H2C_TIMTOUT; + goto exit; + } + if (!GLBtcBtMpRptBTOK) { + RTW_ERR("%s: Didn't get BT response!\n", __FUNCTION__); + ret = BT_STATUS_H2C_BT_NO_RSP; + goto exit; + } + if (seq != GLBtcBtMpRptSeq) { + RTW_ERR("%s: Sequence number not match!(%d!=%d)!\n", + __FUNCTION__, seq, GLBtcBtMpRptSeq); + ret = BT_STATUS_C2H_REQNUM_MISMATCH; + goto exit; + } + + switch (GLBtcBtMpRptStatus) { + /* Examine the status reported from C2H */ + case BT_STATUS_OK: + ret = BT_STATUS_BT_OP_SUCCESS; + RTW_DBG("%s: C2H status = BT_STATUS_BT_OP_SUCCESS\n", __FUNCTION__); + break; + case BT_STATUS_VERSION_MISMATCH: + ret = BT_STATUS_OPCODE_L_VERSION_MISMATCH; + RTW_DBG("%s: C2H status = BT_STATUS_OPCODE_L_VERSION_MISMATCH\n", __FUNCTION__); + break; + case BT_STATUS_UNKNOWN_OPCODE: + ret = BT_STATUS_UNKNOWN_OPCODE_L; + RTW_DBG("%s: C2H status = MP_BT_STATUS_UNKNOWN_OPCODE_L\n", __FUNCTION__); + break; + case BT_STATUS_ERROR_PARAMETER: + ret = BT_STATUS_PARAMETER_FORMAT_ERROR_L; + RTW_DBG("%s: C2H status = MP_BT_STATUS_PARAMETER_FORMAT_ERROR_L\n", __FUNCTION__); + break; + default: + ret = BT_STATUS_UNKNOWN_STATUS_L; + RTW_DBG("%s: C2H status = MP_BT_STATUS_UNKNOWN_STATUS_L\n", __FUNCTION__); + break; + } + +exit: + return ret; +} + +u32 halbtcoutsrc_GetBtPatchVer(PBTC_COEXIST pBtCoexist) +{ + if (pBtCoexist->bt_info.get_bt_fw_ver_cnt <= 5) { + if (halbtcoutsrc_IsHwMailboxExist(pBtCoexist) == _TRUE) { + _irqL irqL; + u8 ret; + + _enter_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + ret = _btmpoper_cmd(pBtCoexist, BT_OP_GET_BT_VERSION, 0, NULL, 0); + if (BT_STATUS_BT_OP_SUCCESS == ret) { + pBtCoexist->bt_info.bt_real_fw_ver = le16_to_cpu(*(u16 *)GLBtcBtMpRptRsp); + pBtCoexist->bt_info.bt_fw_ver = *(GLBtcBtMpRptRsp + 2); + pBtCoexist->bt_info.get_bt_fw_ver_cnt++; + } + + _exit_critical_mutex(&GLBtcBtMpOperLock, &irqL); + } else { +#ifdef CONFIG_BT_COEXIST_SOCKET_TRX + u1Byte dataLen = 2; + u1Byte buf[4] = {0}; + + buf[0] = 0x0; /* OP_Code */ + buf[1] = 0x0; /* OP_Code_Length */ + BT_SendEventExtBtCoexControl(pBtCoexist->Adapter, _FALSE, dataLen, &buf[0]); +#endif /* !CONFIG_BT_COEXIST_SOCKET_TRX */ + } + } + +exit: + return pBtCoexist->bt_info.bt_real_fw_ver; +} + +s32 halbtcoutsrc_GetWifiRssi(PADAPTER padapter) +{ + PHAL_DATA_TYPE pHalData; + s32 undecorated_smoothed_pwdb = 0; + + pHalData = GET_HAL_DATA(padapter); + + undecorated_smoothed_pwdb = pHalData->entry_min_undecorated_smoothed_pwdb; + + return undecorated_smoothed_pwdb; +} + +u32 halbtcoutsrc_GetBtCoexSupportedFeature(void *pBtcContext) +{ + PBTC_COEXIST pBtCoexist; + u32 ret = BT_STATUS_BT_OP_SUCCESS; + u32 data = 0; + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + + if (halbtcoutsrc_IsHwMailboxExist(pBtCoexist) == _TRUE) { + u8 buf[3] = {0}; + _irqL irqL; + u8 op_code; + u8 status; + + _enter_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + op_code = BT_OP_GET_BT_COEX_SUPPORTED_FEATURE; + status = _btmpoper_cmd(pBtCoexist, op_code, 0, buf, 0); + if (status == BT_STATUS_BT_OP_SUCCESS) + data = le16_to_cpu(*(u16 *)GLBtcBtMpRptRsp); + else + ret = SET_BT_MP_OPER_RET(op_code, status); + + _exit_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + } else + ret = BT_STATUS_NOT_IMPLEMENT; + + return data; +} + +u32 halbtcoutsrc_GetBtCoexSupportedVersion(void *pBtcContext) +{ + PBTC_COEXIST pBtCoexist; + u32 ret = BT_STATUS_BT_OP_SUCCESS; + u32 data = 0xFFFF; + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + + if (halbtcoutsrc_IsHwMailboxExist(pBtCoexist) == _TRUE) { + u8 buf[3] = {0}; + _irqL irqL; + u8 op_code; + u8 status; + + _enter_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + op_code = BT_OP_GET_BT_COEX_SUPPORTED_VERSION; + status = _btmpoper_cmd(pBtCoexist, op_code, 0, buf, 0); + if (status == BT_STATUS_BT_OP_SUCCESS) + data = le16_to_cpu(*(u16 *)GLBtcBtMpRptRsp); + else + ret = SET_BT_MP_OPER_RET(op_code, status); + + _exit_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + } else + ret = BT_STATUS_NOT_IMPLEMENT; + + return data; +} + +static u8 halbtcoutsrc_GetWifiScanAPNum(PADAPTER padapter) +{ + struct mlme_priv *pmlmepriv; + struct mlme_ext_priv *pmlmeext; + static u8 scan_AP_num = 0; + + + pmlmepriv = &padapter->mlmepriv; + pmlmeext = &padapter->mlmeextpriv; + + if (GLBtcWiFiInScanState == _FALSE) { + if (pmlmepriv->num_of_scanned > 0xFF) + scan_AP_num = 0xFF; + else + scan_AP_num = (u8)pmlmepriv->num_of_scanned; + } + + return scan_AP_num; +} + +u8 halbtcoutsrc_Get(void *pBtcContext, u8 getType, void *pOutBuf) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + PHAL_DATA_TYPE pHalData; + struct mlme_ext_priv *mlmeext; + u8 bSoftApExist, bVwifiExist; + u8 *pu8; + s32 *pS4Tmp; + u32 *pU4Tmp; + u8 *pU1Tmp; + u8 ret; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return _FALSE; + + padapter = pBtCoexist->Adapter; + pHalData = GET_HAL_DATA(padapter); + mlmeext = &padapter->mlmeextpriv; + bSoftApExist = _FALSE; + bVwifiExist = _FALSE; + pu8 = (u8 *)pOutBuf; + pS4Tmp = (s32 *)pOutBuf; + pU4Tmp = (u32 *)pOutBuf; + pU1Tmp = (u8 *)pOutBuf; + ret = _TRUE; + + switch (getType) { + case BTC_GET_BL_HS_OPERATION: + *pu8 = _FALSE; + ret = _FALSE; + break; + + case BTC_GET_BL_HS_CONNECTING: + *pu8 = _FALSE; + ret = _FALSE; + break; + + case BTC_GET_BL_WIFI_FW_READY: + *pu8 = halbtcoutsrc_is_fw_ready(pBtCoexist); + break; + + case BTC_GET_BL_WIFI_CONNECTED: + *pu8 = (rtw_mi_check_status(padapter, MI_LINKED)) ? _TRUE : _FALSE; + break; + + case BTC_GET_BL_WIFI_BUSY: + *pu8 = halbtcoutsrc_IsWifiBusy(padapter); + break; + + case BTC_GET_BL_WIFI_SCAN: +#if 0 + *pu8 = (rtw_mi_check_fwstate(padapter, WIFI_SITE_MONITOR)) ? _TRUE : _FALSE; +#else + /* Use the value of the new variable GLBtcWiFiInScanState to judge whether WiFi is in scan state or not, since the originally used flag + WIFI_SITE_MONITOR in fwstate may not be cleared in time */ + *pu8 = GLBtcWiFiInScanState; +#endif + break; + + case BTC_GET_BL_WIFI_LINK: + *pu8 = (rtw_mi_check_status(padapter, MI_STA_LINKING)) ? _TRUE : _FALSE; + break; + + case BTC_GET_BL_WIFI_ROAM: + *pu8 = (rtw_mi_check_status(padapter, MI_STA_LINKING)) ? _TRUE : _FALSE; + break; + + case BTC_GET_BL_WIFI_4_WAY_PROGRESS: + *pu8 = _FALSE; + break; + + case BTC_GET_BL_WIFI_UNDER_5G: + *pu8 = (pHalData->current_band_type == 1) ? _TRUE : _FALSE; + break; + + case BTC_GET_BL_WIFI_AP_MODE_ENABLE: + *pu8 = (rtw_mi_check_status(padapter, MI_AP_MODE)) ? _TRUE : _FALSE; + break; + + case BTC_GET_BL_WIFI_ENABLE_ENCRYPTION: + *pu8 = padapter->securitypriv.dot11PrivacyAlgrthm == 0 ? _FALSE : _TRUE; + break; + + case BTC_GET_BL_WIFI_UNDER_B_MODE: + if (mlmeext->cur_wireless_mode == WIRELESS_11B) + *pu8 = _TRUE; + else + *pu8 = _FALSE; + break; + + case BTC_GET_BL_WIFI_IS_IN_MP_MODE: + if (padapter->registrypriv.mp_mode == 0) + *pu8 = _FALSE; + else + *pu8 = _TRUE; + break; + + case BTC_GET_BL_EXT_SWITCH: + *pu8 = _FALSE; + break; + case BTC_GET_BL_IS_ASUS_8723B: + /* Always return FALSE in linux driver since this case is added only for windows driver */ + *pu8 = _FALSE; + break; + + case BTC_GET_S4_WIFI_RSSI: + *pS4Tmp = halbtcoutsrc_GetWifiRssi(padapter); + break; + + case BTC_GET_S4_HS_RSSI: + *pS4Tmp = 0; + ret = _FALSE; + break; + + case BTC_GET_U4_WIFI_BW: + if (IsLegacyOnly(mlmeext->cur_wireless_mode)) + *pU4Tmp = BTC_WIFI_BW_LEGACY; + else { + switch (pHalData->current_channel_bw) { + case CHANNEL_WIDTH_20: + *pU4Tmp = BTC_WIFI_BW_HT20; + break; + case CHANNEL_WIDTH_40: + *pU4Tmp = BTC_WIFI_BW_HT40; + break; + case CHANNEL_WIDTH_80: + *pU4Tmp = BTC_WIFI_BW_HT80; + break; + case CHANNEL_WIDTH_160: + *pU4Tmp = BTC_WIFI_BW_HT160; + break; + default: + RTW_INFO("[BTCOEX] unknown bandwidth(%d)\n", pHalData->current_channel_bw); + *pU4Tmp = BTC_WIFI_BW_HT40; + break; + } + + } + break; + + case BTC_GET_U4_WIFI_TRAFFIC_DIRECTION: { + PRT_LINK_DETECT_T plinkinfo; + plinkinfo = &padapter->mlmepriv.LinkDetectInfo; + + if (plinkinfo->NumTxOkInPeriod > plinkinfo->NumRxOkInPeriod) + *pU4Tmp = BTC_WIFI_TRAFFIC_TX; + else + *pU4Tmp = BTC_WIFI_TRAFFIC_RX; + } + break; + + case BTC_GET_U4_WIFI_FW_VER: + *pU4Tmp = pHalData->firmware_version << 16; + *pU4Tmp |= pHalData->firmware_sub_version; + break; + + case BTC_GET_U4_WIFI_LINK_STATUS: + *pU4Tmp = halbtcoutsrc_GetWifiLinkStatus(pBtCoexist); + break; + + case BTC_GET_U4_BT_PATCH_VER: + *pU4Tmp = halbtcoutsrc_GetBtPatchVer(pBtCoexist); + break; + + case BTC_GET_U4_VENDOR: + *pU4Tmp = BTC_VENDOR_OTHER; + break; + + case BTC_GET_U4_SUPPORTED_VERSION: + *pU4Tmp = halbtcoutsrc_GetBtCoexSupportedVersion(pBtCoexist); + break; + case BTC_GET_U4_SUPPORTED_FEATURE: + *pU4Tmp = halbtcoutsrc_GetBtCoexSupportedFeature(pBtCoexist); + break; + + case BTC_GET_U4_WIFI_IQK_TOTAL: + *pU4Tmp = pHalData->odmpriv.n_iqk_cnt; + break; + + case BTC_GET_U4_WIFI_IQK_OK: + *pU4Tmp = pHalData->odmpriv.n_iqk_ok_cnt; + break; + + case BTC_GET_U4_WIFI_IQK_FAIL: + *pU4Tmp = pHalData->odmpriv.n_iqk_fail_cnt; + break; + + case BTC_GET_U1_WIFI_DOT11_CHNL: + *pU1Tmp = padapter->mlmeextpriv.cur_channel; + break; + + case BTC_GET_U1_WIFI_CENTRAL_CHNL: + *pU1Tmp = pHalData->current_channel; + break; + + case BTC_GET_U1_WIFI_HS_CHNL: + *pU1Tmp = 0; + ret = _FALSE; + break; + + case BTC_GET_U1_WIFI_P2P_CHNL: +#ifdef CONFIG_P2P + { + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + + *pU1Tmp = pwdinfo->operating_channel; + } +#else + *pU1Tmp = 0; +#endif + break; + + case BTC_GET_U1_MAC_PHY_MODE: + /* *pU1Tmp = BTC_SMSP; + * *pU1Tmp = BTC_DMSP; + * *pU1Tmp = BTC_DMDP; + * *pU1Tmp = BTC_MP_UNKNOWN; */ + break; + + case BTC_GET_U1_AP_NUM: + *pU1Tmp = halbtcoutsrc_GetWifiScanAPNum(padapter); + break; + case BTC_GET_U1_ANT_TYPE: + switch (pHalData->bt_coexist.btAntisolation) { + case 0: + *pU1Tmp = (u1Byte)BTC_ANT_TYPE_0; + pBtCoexist->board_info.ant_type = (u1Byte)BTC_ANT_TYPE_0; + break; + case 1: + *pU1Tmp = (u1Byte)BTC_ANT_TYPE_1; + pBtCoexist->board_info.ant_type = (u1Byte)BTC_ANT_TYPE_1; + break; + case 2: + *pU1Tmp = (u1Byte)BTC_ANT_TYPE_2; + pBtCoexist->board_info.ant_type = (u1Byte)BTC_ANT_TYPE_2; + break; + case 3: + *pU1Tmp = (u1Byte)BTC_ANT_TYPE_3; + pBtCoexist->board_info.ant_type = (u1Byte)BTC_ANT_TYPE_3; + break; + case 4: + *pU1Tmp = (u1Byte)BTC_ANT_TYPE_4; + pBtCoexist->board_info.ant_type = (u1Byte)BTC_ANT_TYPE_4; + break; + } + break; + case BTC_GET_U1_IOT_PEER: + *pU1Tmp = mlmeext->mlmext_info.assoc_AP_vendor; + break; + + /* =======1Ant=========== */ + case BTC_GET_U1_LPS_MODE: + *pU1Tmp = padapter->dvobj->pwrctl_priv.pwr_mode; + break; + + default: + ret = _FALSE; + break; + } + + return ret; +} + +u8 halbtcoutsrc_Set(void *pBtcContext, u8 setType, void *pInBuf) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + PHAL_DATA_TYPE pHalData; + u8 *pu8; + u8 *pU1Tmp; + u32 *pU4Tmp; + u8 ret; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + padapter = pBtCoexist->Adapter; + pHalData = GET_HAL_DATA(padapter); + pu8 = (u8 *)pInBuf; + pU1Tmp = (u8 *)pInBuf; + pU4Tmp = (u32 *)pInBuf; + ret = _TRUE; + + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return _FALSE; + + switch (setType) { + /* set some u8 type variables. */ + case BTC_SET_BL_BT_DISABLE: + pBtCoexist->bt_info.bt_disabled = *pu8; + break; + + case BTC_SET_BL_BT_ENABLE_DISABLE_CHANGE: + pBtCoexist->bt_info.bt_enable_disable_change = *pu8; + break; + + case BTC_SET_BL_BT_TRAFFIC_BUSY: + pBtCoexist->bt_info.bt_busy = *pu8; + break; + + case BTC_SET_BL_BT_LIMITED_DIG: + pBtCoexist->bt_info.limited_dig = *pu8; + break; + + case BTC_SET_BL_FORCE_TO_ROAM: + pBtCoexist->bt_info.force_to_roam = *pu8; + break; + + case BTC_SET_BL_TO_REJ_AP_AGG_PKT: + pBtCoexist->bt_info.reject_agg_pkt = *pu8; + break; + + case BTC_SET_BL_BT_CTRL_AGG_SIZE: + pBtCoexist->bt_info.bt_ctrl_agg_buf_size = *pu8; + break; + + case BTC_SET_BL_INC_SCAN_DEV_NUM: + pBtCoexist->bt_info.increase_scan_dev_num = *pu8; + break; + + case BTC_SET_BL_BT_TX_RX_MASK: + pBtCoexist->bt_info.bt_tx_rx_mask = *pu8; + break; + + case BTC_SET_BL_MIRACAST_PLUS_BT: + pBtCoexist->bt_info.miracast_plus_bt = *pu8; + break; + + /* set some u8 type variables. */ + case BTC_SET_U1_RSSI_ADJ_VAL_FOR_AGC_TABLE_ON: + pBtCoexist->bt_info.rssi_adjust_for_agc_table_on = *pU1Tmp; + break; + + case BTC_SET_U1_AGG_BUF_SIZE: + pBtCoexist->bt_info.agg_buf_size = *pU1Tmp; + break; + + /* the following are some action which will be triggered */ + case BTC_SET_ACT_GET_BT_RSSI: +#if 0 + BT_SendGetBtRssiEvent(padapter); +#else + ret = _FALSE; +#endif + break; + + case BTC_SET_ACT_AGGREGATE_CTRL: + halbtcoutsrc_AggregationCheck(pBtCoexist); + break; + + /* =======1Ant=========== */ + /* set some u8 type variables. */ + case BTC_SET_U1_RSSI_ADJ_VAL_FOR_1ANT_COEX_TYPE: + pBtCoexist->bt_info.rssi_adjust_for_1ant_coex_type = *pU1Tmp; + break; + + case BTC_SET_U1_LPS_VAL: + pBtCoexist->bt_info.lps_val = *pU1Tmp; + break; + + case BTC_SET_U1_RPWM_VAL: + pBtCoexist->bt_info.rpwm_val = *pU1Tmp; + break; + + /* the following are some action which will be triggered */ + case BTC_SET_ACT_LEAVE_LPS: + halbtcoutsrc_LeaveLps(pBtCoexist); + break; + + case BTC_SET_ACT_ENTER_LPS: + halbtcoutsrc_EnterLps(pBtCoexist); + break; + + case BTC_SET_ACT_NORMAL_LPS: + halbtcoutsrc_NormalLps(pBtCoexist); + break; + + case BTC_SET_ACT_DISABLE_LOW_POWER: + halbtcoutsrc_DisableLowPower(pBtCoexist, *pu8); + break; + + case BTC_SET_ACT_UPDATE_RAMASK: + pBtCoexist->bt_info.ra_mask = *pU4Tmp; + + if (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE) == _TRUE) { + struct sta_info *psta; + PWLAN_BSSID_EX cur_network; + + cur_network = &padapter->mlmeextpriv.mlmext_info.network; + psta = rtw_get_stainfo(&padapter->stapriv, cur_network->MacAddress); + rtw_hal_update_ra_mask(psta, psta->rssi_level, _FALSE); + } + break; + + case BTC_SET_ACT_SEND_MIMO_PS: { + u8 newMimoPsMode = 3; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + /* *pU1Tmp = 0 use SM_PS static type */ + /* *pU1Tmp = 1 disable SM_PS */ + if (*pU1Tmp == 0) + newMimoPsMode = WLAN_HT_CAP_SM_PS_STATIC; + else if (*pU1Tmp == 1) + newMimoPsMode = WLAN_HT_CAP_SM_PS_DISABLED; + + if (check_fwstate(&padapter->mlmepriv , WIFI_ASOC_STATE) == _TRUE) { + /* issue_action_SM_PS(padapter, get_my_bssid(&(pmlmeinfo->network)), newMimoPsMode); */ + issue_action_SM_PS_wait_ack(padapter , get_my_bssid(&(pmlmeinfo->network)) , newMimoPsMode, 3 , 1); + } + } + break; + + case BTC_SET_ACT_CTRL_BT_INFO: +#ifdef CONFIG_BT_COEXIST_SOCKET_TRX + { + u8 dataLen = *pU1Tmp; + u8 tmpBuf[BTC_TMP_BUF_SHORT]; + if (dataLen) + _rtw_memcpy(tmpBuf, pU1Tmp + 1, dataLen); + BT_SendEventExtBtInfoControl(padapter, dataLen, &tmpBuf[0]); + } +#else /* !CONFIG_BT_COEXIST_SOCKET_TRX */ + ret = _FALSE; +#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ + break; + + case BTC_SET_ACT_CTRL_BT_COEX: +#ifdef CONFIG_BT_COEXIST_SOCKET_TRX + { + u8 dataLen = *pU1Tmp; + u8 tmpBuf[BTC_TMP_BUF_SHORT]; + if (dataLen) + _rtw_memcpy(tmpBuf, pU1Tmp + 1, dataLen); + BT_SendEventExtBtCoexControl(padapter, _FALSE, dataLen, &tmpBuf[0]); + } +#else /* !CONFIG_BT_COEXIST_SOCKET_TRX */ + ret = _FALSE; +#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ + break; + case BTC_SET_ACT_CTRL_8723B_ANT: +#if 0 + { + u1Byte dataLen = *pU1Tmp; + u1Byte tmpBuf[BTC_TMP_BUF_SHORT]; + if (dataLen) + PlatformMoveMemory(&tmpBuf[0], pU1Tmp + 1, dataLen); + BT_Set8723bAnt(Adapter, dataLen, &tmpBuf[0]); + } +#else + ret = _FALSE; +#endif + break; + /* ===================== */ + default: + ret = _FALSE; + break; + } + + return ret; +} + +u8 halbtcoutsrc_UnderIps(PBTC_COEXIST pBtCoexist) +{ + PADAPTER padapter; + struct pwrctrl_priv *pwrpriv; + u8 bMacPwrCtrlOn; + + padapter = pBtCoexist->Adapter; + pwrpriv = &padapter->dvobj->pwrctl_priv; + bMacPwrCtrlOn = _FALSE; + + if ((_TRUE == pwrpriv->bips_processing) + && (IPS_NONE != pwrpriv->ips_mode_req) + ) + return _TRUE; + + if (rf_off == pwrpriv->rf_pwrstate) + return _TRUE; + + rtw_hal_get_hwreg(padapter, HW_VAR_APFM_ON_MAC, &bMacPwrCtrlOn); + if (_FALSE == bMacPwrCtrlOn) + return _TRUE; + + return _FALSE; +} + +u8 halbtcoutsrc_UnderLps(PBTC_COEXIST pBtCoexist) +{ + return GLBtcWiFiInLPS; +} + +u8 halbtcoutsrc_Under32K(PBTC_COEXIST pBtCoexist) +{ + /* todo: the method to check whether wifi is under 32K or not */ + return _FALSE; +} + +void halbtcoutsrc_DisplayCoexStatistics(PBTC_COEXIST pBtCoexist) +{ +#if 0 + PADAPTER padapter = (PADAPTER)pBtCoexist->Adapter; + PBT_MGNT pBtMgnt = &padapter->MgntInfo.BtInfo.BtMgnt; + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + u8 *cliBuf = pBtCoexist->cliBuf; + u1Byte i, j; + u1Byte tmpbuf[BTC_TMP_BUF_SHORT]; + + + if (gl_coex_offload.cnt_h2c_sent) { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Coex h2c notify]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = H2c(%d)/Ack(%d)", "Coex h2c/c2h overall statistics", + gl_coex_offload.cnt_h2c_sent, gl_coex_offload.cnt_c2h_ack); + for (j = 0; j < COL_STATUS_MAX; j++) { + if (gl_coex_offload.status[j]) { + CL_SPRINTF(tmpbuf, BTC_TMP_BUF_SHORT, ", %s:%d", coexH2cResultString[j], gl_coex_offload.status[j]); + CL_STRNCAT(cliBuf, BT_TMP_BUF_SIZE, tmpbuf, BTC_TMP_BUF_SHORT); + } + } + CL_PRINTF(cliBuf); + } + for (i = 0; i < COL_OP_WIFI_OPCODE_MAX; i++) { + if (gl_coex_offload.h2c_record[i].count) { + /*==========================================*/ + /* H2C result statistics*/ + /*==========================================*/ + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = total:%d", coexOpcodeString[i], gl_coex_offload.h2c_record[i].count); + for (j = 0; j < COL_STATUS_MAX; j++) { + if (gl_coex_offload.h2c_record[i].status[j]) { + CL_SPRINTF(tmpbuf, BTC_TMP_BUF_SHORT, ", %s:%d", coexH2cResultString[j], gl_coex_offload.h2c_record[i].status[j]); + CL_STRNCAT(cliBuf, BT_TMP_BUF_SIZE, tmpbuf, BTC_TMP_BUF_SHORT); + } + } + CL_PRINTF(cliBuf); + /*==========================================*/ + /* H2C/C2H content*/ + /*==========================================*/ + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = ", "H2C / C2H content"); + for (j = 0; j < gl_coex_offload.h2c_record[i].h2c_len; j++) { + CL_SPRINTF(tmpbuf, BTC_TMP_BUF_SHORT, "%02x ", gl_coex_offload.h2c_record[i].h2c_buf[j]); + CL_STRNCAT(cliBuf, BT_TMP_BUF_SIZE, tmpbuf, 3); + } + if (gl_coex_offload.h2c_record[i].c2h_ack_len) { + CL_STRNCAT(cliBuf, BT_TMP_BUF_SIZE, "/ ", 2); + for (j = 0; j < gl_coex_offload.h2c_record[i].c2h_ack_len; j++) { + CL_SPRINTF(tmpbuf, BTC_TMP_BUF_SHORT, "%02x ", gl_coex_offload.h2c_record[i].c2h_ack_buf[j]); + CL_STRNCAT(cliBuf, BT_TMP_BUF_SIZE, tmpbuf, 3); + } + } + CL_PRINTF(cliBuf); + /*==========================================*/ + } + } + + if (gl_coex_offload.cnt_c2h_ind) { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Coex c2h indication]============"); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = Ind(%d)", "C2H indication statistics", + gl_coex_offload.cnt_c2h_ind); + for (j = 0; j < COL_STATUS_MAX; j++) { + if (gl_coex_offload.c2h_ind_status[j]) { + CL_SPRINTF(tmpbuf, BTC_TMP_BUF_SHORT, ", %s:%d", coexH2cResultString[j], gl_coex_offload.c2h_ind_status[j]); + CL_STRNCAT(cliBuf, BT_TMP_BUF_SIZE, tmpbuf, BTC_TMP_BUF_SHORT); + } + } + CL_PRINTF(cliBuf); + } + for (i = 0; i < COL_IND_MAX; i++) { + if (gl_coex_offload.c2h_ind_record[i].count) { + /*==========================================*/ + /* H2C result statistics*/ + /*==========================================*/ + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = total:%d", coexIndTypeString[i], gl_coex_offload.c2h_ind_record[i].count); + for (j = 0; j < COL_STATUS_MAX; j++) { + if (gl_coex_offload.c2h_ind_record[i].status[j]) { + CL_SPRINTF(tmpbuf, BTC_TMP_BUF_SHORT, ", %s:%d", coexH2cResultString[j], gl_coex_offload.c2h_ind_record[i].status[j]); + CL_STRNCAT(cliBuf, BT_TMP_BUF_SIZE, tmpbuf, BTC_TMP_BUF_SHORT); + } + } + CL_PRINTF(cliBuf); + /*==========================================*/ + /* content*/ + /*==========================================*/ + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = ", "C2H indication content"); + for (j = 0; j < gl_coex_offload.c2h_ind_record[i].ind_len; j++) { + CL_SPRINTF(tmpbuf, BTC_TMP_BUF_SHORT, "%02x ", gl_coex_offload.c2h_ind_record[i].ind_buf[j]); + CL_STRNCAT(cliBuf, BT_TMP_BUF_SIZE, tmpbuf, 3); + } + CL_PRINTF(cliBuf); + /*==========================================*/ + } + } + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Statistics]============"); + CL_PRINTF(cliBuf); + +#if (H2C_USE_IO_THREAD != 1) + for (i = 0; i < H2C_STATUS_MAX; i++) { + if (pHalData->h2cStatistics[i]) { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s] = %d", "H2C statistics", \ + h2cStaString[i], pHalData->h2cStatistics[i]); + CL_PRINTF(cliBuf); + } + } +#else + for (i = 0; i < IO_STATUS_MAX; i++) { + if (Adapter->ioComStr.ioH2cStatistics[i]) { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = [%s] = %d", "H2C statistics", \ + ioStaString[i], Adapter->ioComStr.ioH2cStatistics[i]); + CL_PRINTF(cliBuf); + } + } +#endif +#if 0 + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "lastHMEBoxNum", \ + pHalData->LastHMEBoxNum); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x / 0x%x", "LastOkH2c/FirstFailH2c(fwNotRead)", \ + pHalData->lastSuccessH2cEid, pHalData->firstFailedH2cEid); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", "c2hIsr/c2hIntr/clr1AF/noRdy/noBuf", \ + pHalData->InterruptLog.nIMR_C2HCMD, DBG_Var.c2hInterruptCnt, DBG_Var.c2hClrReadC2hCnt, + DBG_Var.c2hNotReadyCnt, DBG_Var.c2hBufAlloFailCnt); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d", "c2hPacket", \ + DBG_Var.c2hPacketCnt); + CL_PRINTF(cliBuf); +#endif + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d", "Periodical/ DbgCtrl", \ + pBtCoexist->statistics.cntPeriodical, pBtCoexist->statistics.cntDbgCtrl); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d", "PowerOn/InitHw/InitCoexDm/RfStatus", \ + pBtCoexist->statistics.cntPowerOn, pBtCoexist->statistics.cntInitHwConfig, pBtCoexist->statistics.cntInitCoexDm, + pBtCoexist->statistics.cntRfStatusNotify); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", "Ips/Lps/Scan/Connect/Mstatus", \ + pBtCoexist->statistics.cntIpsNotify, pBtCoexist->statistics.cntLpsNotify, + pBtCoexist->statistics.cntScanNotify, pBtCoexist->statistics.cntConnectNotify, + pBtCoexist->statistics.cntMediaStatusNotify); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d", "Special pkt/Bt info/ bind", + pBtCoexist->statistics.cntSpecialPacketNotify, pBtCoexist->statistics.cntBtInfoNotify, + pBtCoexist->statistics.cntBind); + CL_PRINTF(cliBuf); +#endif + PADAPTER padapter = pBtCoexist->Adapter; + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + u8 *cliBuf = pBtCoexist->cli_buf; + + if (pHalData->EEPROMBluetoothCoexist == 1) { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Coex Status]============"); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "IsBtDisabled", rtw_btcoex_IsBtDisabled(padapter)); + CL_PRINTF(cliBuf); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "IsBtControlLps", rtw_btcoex_IsBtControlLps(padapter)); + CL_PRINTF(cliBuf); + } +} + +void halbtcoutsrc_DisplayBtLinkInfo(PBTC_COEXIST pBtCoexist) +{ +#if 0 + PADAPTER padapter = (PADAPTER)pBtCoexist->Adapter; + PBT_MGNT pBtMgnt = &padapter->MgntInfo.BtInfo.BtMgnt; + u8 *cliBuf = pBtCoexist->cliBuf; + u8 i; + + + if (pBtCoexist->stack_info.profile_notified) { + for (i = 0; i < pBtMgnt->ExtConfig.NumberOfACL; i++) { + if (pBtMgnt->ExtConfig.HCIExtensionVer >= 1) { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s", "Bt link type/spec/role", \ + BtProfileString[pBtMgnt->ExtConfig.aclLink[i].BTProfile], + BtSpecString[pBtMgnt->ExtConfig.aclLink[i].BTCoreSpec], + BtLinkRoleString[pBtMgnt->ExtConfig.aclLink[i].linkRole]); + CL_PRINTF(cliBuf); + } else { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s", "Bt link type/spec", \ + BtProfileString[pBtMgnt->ExtConfig.aclLink[i].BTProfile], + BtSpecString[pBtMgnt->ExtConfig.aclLink[i].BTCoreSpec]); + CL_PRINTF(cliBuf); + } + } + } +#endif +} + +void halbtcoutsrc_DisplayWifiStatus(PBTC_COEXIST pBtCoexist) +{ + PADAPTER padapter = pBtCoexist->Adapter; + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + u8 *cliBuf = pBtCoexist->cli_buf; + s32 wifiRssi = 0, btHsRssi = 0; + BOOLEAN bScan = _FALSE, bLink = _FALSE, bRoam = _FALSE, bWifiBusy = _FALSE, bWifiUnderBMode = _FALSE; + u32 wifiBw = BTC_WIFI_BW_HT20, wifiTrafficDir = BTC_WIFI_TRAFFIC_TX, wifiFreq = BTC_FREQ_2_4G; + u32 wifiLinkStatus = 0x0; + BOOLEAN bBtHsOn = _FALSE, bLowPower = _FALSE; + u8 wifiChnl = 0, wifiP2PChnl = 0, nScanAPNum = 0, FwPSState; + u32 iqk_cnt_total = 0, iqk_cnt_ok = 0, iqk_cnt_fail = 0; + + wifiLinkStatus = halbtcoutsrc_GetWifiLinkStatus(pBtCoexist); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d/ %d/ %d", "STA/vWifi/HS/p2pGo/p2pGc", \ + ((wifiLinkStatus & WIFI_STA_CONNECTED) ? 1 : 0), ((wifiLinkStatus & WIFI_AP_CONNECTED) ? 1 : 0), + ((wifiLinkStatus & WIFI_HS_CONNECTED) ? 1 : 0), ((wifiLinkStatus & WIFI_P2P_GO_CONNECTED) ? 1 : 0), + ((wifiLinkStatus & WIFI_P2P_GC_CONNECTED) ? 1 : 0)); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_SCAN, &bScan); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_LINK, &bLink); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_ROAM, &bRoam); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d ", "Link/ Roam/ Scan", \ + bLink, bRoam, bScan); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_IQK_TOTAL, &iqk_cnt_total); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_IQK_OK, &iqk_cnt_ok); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_IQK_FAIL, &iqk_cnt_fail); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/ %d/ %d %s %s", + "IQK All/ OK/ Fail/AutoLoad/FWDL", iqk_cnt_total, iqk_cnt_ok, iqk_cnt_fail, + ((halbtcoutsrc_is_autoload_fail(pBtCoexist) == _TRUE) ? "fail":"ok"), ((halbtcoutsrc_is_fw_ready(pBtCoexist) == _TRUE) ? "ok":"fail")); + CL_PRINTF(cliBuf); + + if (wifiLinkStatus & WIFI_STA_CONNECTED) { + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "IOT Peer", GLBtcIotPeerString[padapter->mlmeextpriv.mlmext_info.assoc_AP_vendor]); + CL_PRINTF(cliBuf); + } + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_S4_WIFI_RSSI, &wifiRssi); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U1_WIFI_DOT11_CHNL, &wifiChnl); + if ((wifiLinkStatus & WIFI_P2P_GO_CONNECTED) || (wifiLinkStatus & WIFI_P2P_GC_CONNECTED)) + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U1_WIFI_P2P_CHNL, &wifiP2PChnl); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d dBm/ %d/ %d", "RSSI/ STA_Chnl/ P2P_Chnl", \ + wifiRssi -100, wifiChnl, wifiP2PChnl); + CL_PRINTF(cliBuf); + + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifiFreq); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_BW, &wifiBw); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_BUSY, &bWifiBusy); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U4_WIFI_TRAFFIC_DIRECTION, &wifiTrafficDir); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_BL_WIFI_UNDER_B_MODE, &bWifiUnderBMode); + pBtCoexist->btc_get(pBtCoexist, BTC_GET_U1_AP_NUM, &nScanAPNum); + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %s/ %s/ %d ", "Band/ BW/ Traffic/ APCnt", \ + GLBtcWifiFreqString[wifiFreq], ((bWifiUnderBMode) ? "11b" : GLBtcWifiBwString[wifiBw]), + ((!bWifiBusy) ? "idle" : ((BTC_WIFI_TRAFFIC_TX == wifiTrafficDir) ? "uplink" : "downlink")), + nScanAPNum); + CL_PRINTF(cliBuf); + + /* power status */ + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s%s%s", "Power Status", \ + ((halbtcoutsrc_UnderIps(pBtCoexist) == _TRUE) ? "IPS ON" : "IPS OFF"), + ((halbtcoutsrc_UnderLps(pBtCoexist) == _TRUE) ? ", LPS ON" : ", LPS OFF"), + ((halbtcoutsrc_Under32K(pBtCoexist) == _TRUE) ? ", 32k" : "")); + CL_PRINTF(cliBuf); + + CL_SPRINTF(cliBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x %02x (0x%x/0x%x)", "Power mode cmd(lps/rpwm)", \ + pBtCoexist->pwrModeVal[0], pBtCoexist->pwrModeVal[1], + pBtCoexist->pwrModeVal[2], pBtCoexist->pwrModeVal[3], + pBtCoexist->pwrModeVal[4], pBtCoexist->pwrModeVal[5], + pBtCoexist->bt_info.lps_val, + pBtCoexist->bt_info.rpwm_val); + CL_PRINTF(cliBuf); +} + +void halbtcoutsrc_DisplayDbgMsg(void *pBtcContext, u8 dispType) +{ + PBTC_COEXIST pBtCoexist; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + switch (dispType) { + case BTC_DBG_DISP_COEX_STATISTICS: + halbtcoutsrc_DisplayCoexStatistics(pBtCoexist); + break; + case BTC_DBG_DISP_BT_LINK_INFO: + halbtcoutsrc_DisplayBtLinkInfo(pBtCoexist); + break; + case BTC_DBG_DISP_WIFI_STATUS: + halbtcoutsrc_DisplayWifiStatus(pBtCoexist); + break; + default: + break; + } +} + +/* ************************************ + * IO related function + * ************************************ */ +u8 halbtcoutsrc_Read1Byte(void *pBtcContext, u32 RegAddr) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + padapter = pBtCoexist->Adapter; + + return rtw_read8(padapter, RegAddr); +} + +u16 halbtcoutsrc_Read2Byte(void *pBtcContext, u32 RegAddr) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + padapter = pBtCoexist->Adapter; + + return rtw_read16(padapter, RegAddr); +} + +u32 halbtcoutsrc_Read4Byte(void *pBtcContext, u32 RegAddr) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + padapter = pBtCoexist->Adapter; + + return rtw_read32(padapter, RegAddr); +} + +void halbtcoutsrc_Write1Byte(void *pBtcContext, u32 RegAddr, u8 Data) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + padapter = pBtCoexist->Adapter; + + rtw_write8(padapter, RegAddr, Data); +} + +void halbtcoutsrc_BitMaskWrite1Byte(void *pBtcContext, u32 regAddr, u8 bitMask, u8 data1b) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + u8 originalValue, bitShift; + u8 i; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + padapter = pBtCoexist->Adapter; + originalValue = 0; + bitShift = 0; + + if (bitMask != 0xff) { + originalValue = rtw_read8(padapter, regAddr); + + for (i = 0; i <= 7; i++) { + if ((bitMask >> i) & 0x1) + break; + } + bitShift = i; + + data1b = (originalValue & ~bitMask) | ((data1b << bitShift) & bitMask); + } + + rtw_write8(padapter, regAddr, data1b); +} + +void halbtcoutsrc_Write2Byte(void *pBtcContext, u32 RegAddr, u16 Data) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + padapter = pBtCoexist->Adapter; + + rtw_write16(padapter, RegAddr, Data); +} + +void halbtcoutsrc_Write4Byte(void *pBtcContext, u32 RegAddr, u32 Data) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + padapter = pBtCoexist->Adapter; + + rtw_write32(padapter, RegAddr, Data); +} + +void halbtcoutsrc_WriteLocalReg1Byte(void *pBtcContext, u32 RegAddr, u8 Data) +{ + PBTC_COEXIST pBtCoexist = (PBTC_COEXIST)pBtcContext; + PADAPTER Adapter = pBtCoexist->Adapter; + + if (BTC_INTF_SDIO == pBtCoexist->chip_interface) + rtw_write8(Adapter, SDIO_LOCAL_BASE | RegAddr, Data); + else + rtw_write8(Adapter, RegAddr, Data); +} + +void halbtcoutsrc_SetBbReg(void *pBtcContext, u32 RegAddr, u32 BitMask, u32 Data) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + padapter = pBtCoexist->Adapter; + + phy_set_bb_reg(padapter, RegAddr, BitMask, Data); +} + + +u32 halbtcoutsrc_GetBbReg(void *pBtcContext, u32 RegAddr, u32 BitMask) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + padapter = pBtCoexist->Adapter; + + return phy_query_bb_reg(padapter, RegAddr, BitMask); +} + +void halbtcoutsrc_SetRfReg(void *pBtcContext, u8 eRFPath, u32 RegAddr, u32 BitMask, u32 Data) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + padapter = pBtCoexist->Adapter; + + phy_set_rf_reg(padapter, eRFPath, RegAddr, BitMask, Data); +} + +u32 halbtcoutsrc_GetRfReg(void *pBtcContext, u8 eRFPath, u32 RegAddr, u32 BitMask) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + padapter = pBtCoexist->Adapter; + + return phy_query_rf_reg(padapter, eRFPath, RegAddr, BitMask); +} + +u16 halbtcoutsrc_SetBtReg(void *pBtcContext, u8 RegType, u32 RegAddr, u32 Data) +{ + PBTC_COEXIST pBtCoexist; + u16 ret = BT_STATUS_BT_OP_SUCCESS; + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + + if (halbtcoutsrc_IsHwMailboxExist(pBtCoexist) == _TRUE) { + u8 buf[3] = {0}; + _irqL irqL; + u8 op_code; + u8 status; + + _enter_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + Data = cpu_to_le32(Data); + op_code = BT_OP_WRITE_REG_VALUE; + status = _btmpoper_cmd(pBtCoexist, op_code, 0, (u8 *)&Data, 3); + if (status != BT_STATUS_BT_OP_SUCCESS) + ret = SET_BT_MP_OPER_RET(op_code, status); + else { + buf[0] = RegType; + *(u16 *)(buf + 1) = cpu_to_le16((u16)RegAddr); + op_code = BT_OP_WRITE_REG_ADDR; + status = _btmpoper_cmd(pBtCoexist, op_code, 0, buf, 3); + if (status != BT_STATUS_BT_OP_SUCCESS) + ret = SET_BT_MP_OPER_RET(op_code, status); + } + + _exit_critical_mutex(&GLBtcBtMpOperLock, &irqL); + } else + ret = BT_STATUS_NOT_IMPLEMENT; + + return ret; +} + +u8 halbtcoutsrc_SetBtAntDetection(void *pBtcContext, u8 txTime, u8 btChnl) +{ + /* Always return _FALSE since we don't implement this yet */ +#if 0 + PBTC_COEXIST pBtCoexist = (PBTC_COEXIST)pBtcContext; + PADAPTER Adapter = pBtCoexist->Adapter; + u1Byte btCanTx = 0; + BOOLEAN bStatus = FALSE; + + bStatus = NDBG_SetBtAntDetection(Adapter, txTime, btChnl, &btCanTx); + if (bStatus && btCanTx) + return _TRUE; + else + return _FALSE; +#else + return _FALSE; +#endif +} + +BOOLEAN +halbtcoutsrc_SetBtTRXMASK( + IN PVOID pBtcContext, + IN u1Byte bt_trx_mask + ) +{ + /* Always return _FALSE since we don't implement this yet */ +#if 0 + struct btc_coexist *pBtCoexist = (struct btc_coexist *)pBtcContext; + PADAPTER Adapter = pBtCoexist->Adapter; + BOOLEAN bStatus = FALSE; + u1Byte btCanTx = 0; + + if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter) || IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter) + || IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + + if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) + bStatus = NDBG_SetBtTRXMASK(Adapter, 1, bt_trx_mask, &btCanTx); + else + bStatus = NDBG_SetBtTRXMASK(Adapter, 2, bt_trx_mask, &btCanTx); + } + + + if (bStatus) + return TRUE; + else + return FALSE; +#else + return _FALSE; +#endif +} + +u16 halbtcoutsrc_GetBtReg_with_status(void *pBtcContext, u8 RegType, u32 RegAddr, u32 *data) +{ + PBTC_COEXIST pBtCoexist; + u16 ret = BT_STATUS_BT_OP_SUCCESS; + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + + if (halbtcoutsrc_IsHwMailboxExist(pBtCoexist) == _TRUE) { + u8 buf[3] = {0}; + _irqL irqL; + u8 op_code; + u8 status; + + buf[0] = RegType; + *(u16 *)(buf + 1) = cpu_to_le16((u16)RegAddr); + + _enter_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + op_code = BT_OP_READ_REG; + status = _btmpoper_cmd(pBtCoexist, op_code, 0, buf, 3); + if (status == BT_STATUS_BT_OP_SUCCESS) + *data = le16_to_cpu(*(u16 *)GLBtcBtMpRptRsp); + else + ret = SET_BT_MP_OPER_RET(op_code, status); + + _exit_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + } else + ret = BT_STATUS_NOT_IMPLEMENT; + + return ret; +} + +u32 halbtcoutsrc_GetBtReg(void *pBtcContext, u8 RegType, u32 RegAddr) +{ + u32 regVal; + + return (BT_STATUS_BT_OP_SUCCESS == halbtcoutsrc_GetBtReg_with_status(pBtcContext, RegType, RegAddr, ®Val)) ? regVal : 0xffffffff; +} + +void halbtcoutsrc_FillH2cCmd(void *pBtcContext, u8 elementId, u32 cmdLen, u8 *pCmdBuffer) +{ + PBTC_COEXIST pBtCoexist; + PADAPTER padapter; + + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + padapter = pBtCoexist->Adapter; + + rtw_hal_fill_h2c_cmd(padapter, elementId, cmdLen, pCmdBuffer); +} + +static void halbtcoutsrc_coex_offload_init(void) +{ + u1Byte i; + + gl_coex_offload.h2c_req_num = 0; + gl_coex_offload.cnt_h2c_sent = 0; + gl_coex_offload.cnt_c2h_ack = 0; + gl_coex_offload.cnt_c2h_ind = 0; + + for (i = 0; i < COL_MAX_H2C_REQ_NUM; i++) + init_completion(&gl_coex_offload.c2h_event[i]); +} + +static COL_H2C_STATUS halbtcoutsrc_send_h2c(PADAPTER Adapter, PCOL_H2C pcol_h2c, u16 h2c_cmd_len) +{ + COL_H2C_STATUS h2c_status = COL_STATUS_C2H_OK; + u8 i; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + reinit_completion(&gl_coex_offload.c2h_event[pcol_h2c->req_num]); /* set event to un signaled state */ +#else + INIT_COMPLETION(gl_coex_offload.c2h_event[pcol_h2c->req_num]); +#endif + + if (TRUE) { +#if 0 /*(USE_HAL_MAC_API == 1) */ + if (RT_STATUS_SUCCESS == HAL_MAC_Send_BT_COEX(&GET_HAL_MAC_INFO(Adapter), (pu1Byte)(pcol_h2c), (u4Byte)h2c_cmd_len, 1)) { + if (!wait_for_completion_timeout(&gl_coex_offload.c2h_event[pcol_h2c->req_num], 20)) { + h2c_status = COL_STATUS_H2C_TIMTOUT; + } + } else { + h2c_status = COL_STATUS_H2C_HALMAC_FAIL; + } +#endif + } + + return h2c_status; +} + +static COL_H2C_STATUS halbtcoutsrc_check_c2h_ack(PADAPTER Adapter, PCOL_SINGLE_H2C_RECORD pH2cRecord) +{ + COL_H2C_STATUS c2h_status = COL_STATUS_C2H_OK; + PCOL_H2C p_h2c_cmd = (PCOL_H2C)&pH2cRecord->h2c_buf[0]; + u8 req_num = p_h2c_cmd->req_num; + PCOL_C2H_ACK p_c2h_ack = (PCOL_C2H_ACK)&gl_coex_offload.c2h_ack_buf[req_num]; + + + if ((COL_C2H_ACK_HDR_LEN + p_c2h_ack->ret_len) > gl_coex_offload.c2h_ack_len[req_num]) { + c2h_status = COL_STATUS_COEX_DATA_OVERFLOW; + return c2h_status; + } + /* else */ + { + _rtw_memmove(&pH2cRecord->c2h_ack_buf[0], &gl_coex_offload.c2h_ack_buf[req_num], gl_coex_offload.c2h_ack_len[req_num]); + pH2cRecord->c2h_ack_len = gl_coex_offload.c2h_ack_len[req_num]; + } + + + if (p_c2h_ack->req_num != p_h2c_cmd->req_num) { + c2h_status = COL_STATUS_C2H_REQ_NUM_MISMATCH; + } else if (p_c2h_ack->opcode_ver != p_h2c_cmd->opcode_ver) { + c2h_status = COL_STATUS_C2H_OPCODE_VER_MISMATCH; + } else { + c2h_status = p_c2h_ack->status; + } + + return c2h_status; +} + +COL_H2C_STATUS halbtcoutsrc_CoexH2cProcess(void *pBtCoexist, + u8 opcode, u8 opcode_ver, u8 *ph2c_par, u8 h2c_par_len) +{ + PADAPTER Adapter = ((struct btc_coexist *)pBtCoexist)->Adapter; + u8 H2C_Parameter[BTC_TMP_BUF_SHORT] = {0}; + PCOL_H2C pcol_h2c = (PCOL_H2C)&H2C_Parameter[0]; + u16 paraLen = 0; + COL_H2C_STATUS h2c_status = COL_STATUS_C2H_OK, c2h_status = COL_STATUS_C2H_OK; + COL_H2C_STATUS ret_status = COL_STATUS_C2H_OK; + u16 i, col_h2c_len = 0; + + pcol_h2c->opcode = opcode; + pcol_h2c->opcode_ver = opcode_ver; + pcol_h2c->req_num = gl_coex_offload.h2c_req_num; + gl_coex_offload.h2c_req_num++; + gl_coex_offload.h2c_req_num %= 16; + + _rtw_memmove(&pcol_h2c->buf[0], ph2c_par, h2c_par_len); + + + col_h2c_len = h2c_par_len + 2; /* 2=sizeof(OPCode, OPCode_version and Request number) */ + BT_PrintData(Adapter, "[COL], H2C cmd: ", col_h2c_len, H2C_Parameter); + + gl_coex_offload.cnt_h2c_sent++; + + gl_coex_offload.h2c_record[opcode].count++; + gl_coex_offload.h2c_record[opcode].h2c_len = col_h2c_len; + _rtw_memmove((PVOID)&gl_coex_offload.h2c_record[opcode].h2c_buf[0], (PVOID)pcol_h2c, col_h2c_len); + + h2c_status = halbtcoutsrc_send_h2c(Adapter, pcol_h2c, col_h2c_len); + + gl_coex_offload.h2c_record[opcode].c2h_ack_len = 0; + + if (COL_STATUS_C2H_OK == h2c_status) { + /* if reach here, it means H2C get the correct c2h response, */ + c2h_status = halbtcoutsrc_check_c2h_ack(Adapter, &gl_coex_offload.h2c_record[opcode]); + ret_status = c2h_status; + } else { + /* check h2c status error, return error status code to upper layer. */ + ret_status = h2c_status; + } + gl_coex_offload.h2c_record[opcode].status[ret_status]++; + gl_coex_offload.status[ret_status]++; + + return ret_status; +} + +u8 halbtcoutsrc_GetAntDetValFromBt(void *pBtcContext) +{ + /* Always return 0 since we don't implement this yet */ +#if 0 + struct btc_coexist *pBtCoexist = (struct btc_coexist *)pBtcContext; + PADAPTER Adapter = pBtCoexist->Adapter; + u1Byte AntDetVal = 0x0; + u1Byte opcodeVer = 1; + BOOLEAN status = false; + + status = NDBG_GetAntDetValFromBt(Adapter, opcodeVer, &AntDetVal); + + RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$ halbtcoutsrc_GetAntDetValFromBt(): status = %d, feature = %x\n", status, AntDetVal)); + + return AntDetVal; +#else + return 0; +#endif +} + +u8 halbtcoutsrc_GetBleScanTypeFromBt(void *pBtcContext) +{ + PBTC_COEXIST pBtCoexist; + u32 ret = BT_STATUS_BT_OP_SUCCESS; + u8 data = 0; + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + + if (halbtcoutsrc_IsHwMailboxExist(pBtCoexist) == _TRUE) { + u8 buf[3] = {0}; + _irqL irqL; + u8 op_code; + u8 status; + + + _enter_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + op_code = BT_OP_GET_BT_BLE_SCAN_TYPE; + status = _btmpoper_cmd(pBtCoexist, op_code, 0, buf, 0); + if (status == BT_STATUS_BT_OP_SUCCESS) + data = *(u8 *)GLBtcBtMpRptRsp; + else + ret = SET_BT_MP_OPER_RET(op_code, status); + + _exit_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + } else + ret = BT_STATUS_NOT_IMPLEMENT; + + return data; +} + +u32 halbtcoutsrc_GetBleScanParaFromBt(void *pBtcContext, u8 scanType) +{ + PBTC_COEXIST pBtCoexist; + u32 ret = BT_STATUS_BT_OP_SUCCESS; + u32 data = 0; + + pBtCoexist = (PBTC_COEXIST)pBtcContext; + + if (halbtcoutsrc_IsHwMailboxExist(pBtCoexist) == _TRUE) { + u8 buf[3] = {0}; + _irqL irqL; + u8 op_code; + u8 status; + + + _enter_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + op_code = BT_OP_GET_BT_BLE_SCAN_PARA; + status = _btmpoper_cmd(pBtCoexist, op_code, 0, buf, 0); + if (status == BT_STATUS_BT_OP_SUCCESS) + data = le32_to_cpu(*(u32 *)GLBtcBtMpRptRsp); + else + ret = SET_BT_MP_OPER_RET(op_code, status); + + _exit_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + } else + ret = BT_STATUS_NOT_IMPLEMENT; + + return data; +} + +u8 halbtcoutsrc_GetBtAFHMapFromBt(void *pBtcContext, u8 mapType, u8 *afhMap) +{ + struct btc_coexist *pBtCoexist = (struct btc_coexist *)pBtcContext; + u8 buf[2] = {0}; + _irqL irqL; + u8 op_code; + u32 *AfhMapL = (u32 *)&(afhMap[0]); + u32 *AfhMapM = (u32 *)&(afhMap[4]); + u16 *AfhMapH = (u16 *)&(afhMap[8]); + u8 status; + u32 ret = BT_STATUS_BT_OP_SUCCESS; + + if (halbtcoutsrc_IsHwMailboxExist(pBtCoexist) == _FALSE) + return _FALSE; + + buf[0] = 0; + buf[1] = mapType; + + _enter_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + op_code = BT_LO_OP_GET_AFH_MAP_L; + status = _btmpoper_cmd(pBtCoexist, op_code, 0, buf, 0); + if (status == BT_STATUS_BT_OP_SUCCESS) + *AfhMapL = le32_to_cpu(*(u32 *)GLBtcBtMpRptRsp); + else { + ret = SET_BT_MP_OPER_RET(op_code, status); + goto exit; + } + + op_code = BT_LO_OP_GET_AFH_MAP_M; + status = _btmpoper_cmd(pBtCoexist, op_code, 0, buf, 0); + if (status == BT_STATUS_BT_OP_SUCCESS) + *AfhMapM = le32_to_cpu(*(u32 *)GLBtcBtMpRptRsp); + else { + ret = SET_BT_MP_OPER_RET(op_code, status); + goto exit; + } + + op_code = BT_LO_OP_GET_AFH_MAP_H; + status = _btmpoper_cmd(pBtCoexist, op_code, 0, buf, 0); + if (status == BT_STATUS_BT_OP_SUCCESS) + *AfhMapH = le16_to_cpu(*(u16 *)GLBtcBtMpRptRsp); + else { + ret = SET_BT_MP_OPER_RET(op_code, status); + goto exit; + } + +exit: + + _exit_critical_mutex(&GLBtcBtMpOperLock, &irqL); + + return (ret == BT_STATUS_BT_OP_SUCCESS) ? _TRUE : _FALSE; +} + +u32 halbtcoutsrc_GetPhydmVersion(void *pBtcContext) +{ + struct btc_coexist *pBtCoexist = (struct btc_coexist *)pBtcContext; + PADAPTER Adapter = pBtCoexist->Adapter; + +#ifdef CONFIG_RTL8192E + return RELEASE_VERSION_8192E; +#endif + +#ifdef CONFIG_RTL8821A + return RELEASE_VERSION_8821A; +#endif + +#ifdef CONFIG_RTL8723B + return RELEASE_VERSION_8723B; +#endif + +#ifdef CONFIG_RTL8812A + return RELEASE_VERSION_8812A; +#endif + +#ifdef CONFIG_RTL8703B + return RELEASE_VERSION_8703B; +#endif + +#ifdef CONFIG_RTL8822B + return RELEASE_VERSION_8822B; +#endif + +#ifdef CONFIG_RTL8723D + return RELEASE_VERSION_8723D; +#endif + +#ifdef CONFIG_RTL8821C + return RELEASE_VERSION_8821C; +#endif +} + +void halbtcoutsrc_phydm_modify_RA_PCR_threshold(void *pBtcContext, u8 RA_offset_direction, u8 RA_threshold_offset) +{ + struct btc_coexist *pBtCoexist = (struct btc_coexist *)pBtcContext; + +/* switch to #if 0 in case the phydm version does not provide the function */ +#if 1 + phydm_modify_RA_PCR_threshold(pBtCoexist->odm_priv, RA_offset_direction, RA_threshold_offset); +#endif +} + +u32 halbtcoutsrc_phydm_query_PHY_counter(void *pBtcContext, u8 info_type) +{ + struct btc_coexist *pBtCoexist = (struct btc_coexist *)pBtcContext; + +/* switch to #if 0 in case the phydm version does not provide the function */ +#if 1 + return phydm_cmn_info_query((struct PHY_DM_STRUCT *)pBtCoexist->odm_priv, (enum phydm_info_query_e)info_type); +#else + return 0; +#endif +} + +#if 0 +static void BT_CoexOffloadRecordErrC2hAck(PADAPTER Adapter) +{ + PADAPTER pDefaultAdapter = GetDefaultAdapter(Adapter); + + if (pDefaultAdapter != Adapter) + return; + + if (!hal_btcoex_IsBtExist(Adapter)) + return; + + gl_coex_offload.cnt_c2h_ack++; + + gl_coex_offload.status[COL_STATUS_INVALID_C2H_LEN]++; +} + +static void BT_CoexOffloadC2hAckCheck(PADAPTER Adapter, u8 *tmpBuf, u8 length) +{ + PADAPTER pDefaultAdapter = GetDefaultAdapter(Adapter); + PCOL_C2H_ACK p_c2h_ack = NULL; + u8 req_num = 0xff; + + if (pDefaultAdapter != Adapter) + return; + + if (!hal_btcoex_IsBtExist(Adapter)) + return; + + gl_coex_offload.cnt_c2h_ack++; + + if (length < COL_C2H_ACK_HDR_LEN) { /* c2h ack length must >= 3 (status, opcode_ver, req_num and ret_len) */ + gl_coex_offload.status[COL_STATUS_INVALID_C2H_LEN]++; + } else { + BT_PrintData(Adapter, "[COL], c2h ack:", length, tmpBuf); + + p_c2h_ack = (PCOL_C2H_ACK)tmpBuf; + req_num = p_c2h_ack->req_num; + + _rtw_memmove(&gl_coex_offload.c2h_ack_buf[req_num][0], tmpBuf, length); + gl_coex_offload.c2h_ack_len[req_num] = length; + + complete(&gl_coex_offload.c2h_event[req_num]); + } +} + +static void BT_CoexOffloadC2hIndCheck(PADAPTER Adapter, u8 *tmpBuf, u8 length) +{ + PADAPTER pDefaultAdapter = GetDefaultAdapter(Adapter); + PCOL_C2H_IND p_c2h_ind = NULL; + u8 ind_type = 0, ind_version = 0, ind_length = 0; + + if (pDefaultAdapter != Adapter) + return; + + if (!hal_btcoex_IsBtExist(Adapter)) + return; + + gl_coex_offload.cnt_c2h_ind++; + + if (length < COL_C2H_IND_HDR_LEN) { /* c2h indication length must >= 3 (type, version and length) */ + gl_coex_offload.c2h_ind_status[COL_STATUS_INVALID_C2H_LEN]++; + } else { + BT_PrintData(Adapter, "[COL], c2h indication:", length, tmpBuf); + + p_c2h_ind = (PCOL_C2H_IND)tmpBuf; + ind_type = p_c2h_ind->type; + ind_version = p_c2h_ind->version; + ind_length = p_c2h_ind->length; + + _rtw_memmove(&gl_coex_offload.c2h_ind_buf[0], tmpBuf, length); + gl_coex_offload.c2h_ind_len = length; + + /* log */ + gl_coex_offload.c2h_ind_record[ind_type].count++; + gl_coex_offload.c2h_ind_record[ind_type].status[COL_STATUS_C2H_OK]++; + _rtw_memmove(&gl_coex_offload.c2h_ind_record[ind_type].ind_buf[0], tmpBuf, length); + gl_coex_offload.c2h_ind_record[ind_type].ind_len = length; + + gl_coex_offload.c2h_ind_status[COL_STATUS_C2H_OK]++; + /*TODO: need to check c2h indication length*/ + /* TODO: Notification */ + } +} + +void BT_CoexOffloadC2hCheck(PADAPTER Adapter, u8 *Buffer, u8 Length) +{ +#if 0 /*(USE_HAL_MAC_API == 1)*/ + u8 c2hSubCmdId = 0, c2hAckLen = 0, h2cCmdId = 0, h2cSubCmdId = 0, c2hIndLen = 0; + + BT_PrintData(Adapter, "[COL], c2h packet:", Length - 2, Buffer + 2); + c2hSubCmdId = (u1Byte)C2H_HDR_GET_C2H_SUB_CMD_ID(Buffer); + + if (c2hSubCmdId == C2H_SUB_CMD_ID_H2C_ACK_HDR || + c2hSubCmdId == C2H_SUB_CMD_ID_BT_COEX_INFO) { + if (c2hSubCmdId == C2H_SUB_CMD_ID_H2C_ACK_HDR) { + /* coex c2h ack */ + h2cCmdId = (u1Byte)H2C_ACK_HDR_GET_H2C_CMD_ID(Buffer); + h2cSubCmdId = (u1Byte)H2C_ACK_HDR_GET_H2C_SUB_CMD_ID(Buffer); + if (h2cCmdId == 0xff && h2cSubCmdId == 0x60) { + c2hAckLen = (u1Byte)C2H_HDR_GET_LEN(Buffer); + if (c2hAckLen >= 8) + BT_CoexOffloadC2hAckCheck(Adapter, &Buffer[12], (u1Byte)(c2hAckLen - 8)); + else + BT_CoexOffloadRecordErrC2hAck(Adapter); + } + } else if (c2hSubCmdId == C2H_SUB_CMD_ID_BT_COEX_INFO) { + /* coex c2h indication */ + c2hIndLen = (u1Byte)C2H_HDR_GET_LEN(Buffer); + BT_CoexOffloadC2hIndCheck(Adapter, &Buffer[4], (u1Byte)c2hIndLen); + } + } +#endif +} +#endif + +/* ************************************ + * Extern functions called by other module + * ************************************ */ +u8 EXhalbtcoutsrc_BindBtCoexWithAdapter(void *padapter) +{ + PBTC_COEXIST pBtCoexist = &GLBtCoexist; + u8 antNum = 1, chipType = 0, singleAntPath = 0; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA((PADAPTER)padapter); + + if (pBtCoexist->bBinded) + return _FALSE; + else + pBtCoexist->bBinded = _TRUE; + + pBtCoexist->statistics.cnt_bind++; + + pBtCoexist->Adapter = padapter; + pBtCoexist->odm_priv = (PVOID)&(pHalData->odmpriv); + + pBtCoexist->stack_info.profile_notified = _FALSE; + + pBtCoexist->bt_info.bt_ctrl_agg_buf_size = _FALSE; + pBtCoexist->bt_info.agg_buf_size = 5; + + pBtCoexist->bt_info.increase_scan_dev_num = _FALSE; + pBtCoexist->bt_info.miracast_plus_bt = _FALSE; + + antNum = rtw_btcoex_get_pg_ant_num((PADAPTER)padapter); + EXhalbtcoutsrc_SetAntNum(BT_COEX_ANT_TYPE_PG, antNum); + + if (antNum == 1) { + singleAntPath = rtw_btcoex_get_pg_single_ant_path((PADAPTER)padapter); + EXhalbtcoutsrc_SetSingleAntPath(singleAntPath); + } + + /* set default antenna position to main port */ + pBtCoexist->board_info.btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + + pBtCoexist->board_info.btdm_ant_det_finish = _FALSE; + pBtCoexist->board_info.btdm_ant_num_by_ant_det = 1; + + pBtCoexist->board_info.tfbga_package = rtw_btcoex_is_tfbga_package_type((PADAPTER)padapter); + + pBtCoexist->board_info.rfe_type = rtw_btcoex_get_pg_rfe_type((PADAPTER)padapter); + + pBtCoexist->board_info.ant_div_cfg = rtw_btcoex_get_ant_div_cfg((PADAPTER)padapter); + + return _TRUE; +} + +u8 EXhalbtcoutsrc_InitlizeVariables(void *padapter) +{ + PBTC_COEXIST pBtCoexist = &GLBtCoexist; + + /* pBtCoexist->statistics.cntBind++; */ + + halbtcoutsrc_DbgInit(); + + halbtcoutsrc_coex_offload_init(); + +#ifdef CONFIG_PCI_HCI + pBtCoexist->chip_interface = BTC_INTF_PCI; +#elif defined(CONFIG_USB_HCI) + pBtCoexist->chip_interface = BTC_INTF_USB; +#elif defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + pBtCoexist->chip_interface = BTC_INTF_SDIO; +#else + pBtCoexist->chip_interface = BTC_INTF_UNKNOWN; +#endif + + EXhalbtcoutsrc_BindBtCoexWithAdapter(padapter); + + pBtCoexist->btc_read_1byte = halbtcoutsrc_Read1Byte; + pBtCoexist->btc_write_1byte = halbtcoutsrc_Write1Byte; + pBtCoexist->btc_write_1byte_bitmask = halbtcoutsrc_BitMaskWrite1Byte; + pBtCoexist->btc_read_2byte = halbtcoutsrc_Read2Byte; + pBtCoexist->btc_write_2byte = halbtcoutsrc_Write2Byte; + pBtCoexist->btc_read_4byte = halbtcoutsrc_Read4Byte; + pBtCoexist->btc_write_4byte = halbtcoutsrc_Write4Byte; + pBtCoexist->btc_write_local_reg_1byte = halbtcoutsrc_WriteLocalReg1Byte; + + pBtCoexist->btc_set_bb_reg = halbtcoutsrc_SetBbReg; + pBtCoexist->btc_get_bb_reg = halbtcoutsrc_GetBbReg; + + pBtCoexist->btc_set_rf_reg = halbtcoutsrc_SetRfReg; + pBtCoexist->btc_get_rf_reg = halbtcoutsrc_GetRfReg; + + pBtCoexist->btc_fill_h2c = halbtcoutsrc_FillH2cCmd; + pBtCoexist->btc_disp_dbg_msg = halbtcoutsrc_DisplayDbgMsg; + + pBtCoexist->btc_get = halbtcoutsrc_Get; + pBtCoexist->btc_set = halbtcoutsrc_Set; + pBtCoexist->btc_get_bt_reg = halbtcoutsrc_GetBtReg; + pBtCoexist->btc_set_bt_reg = halbtcoutsrc_SetBtReg; + pBtCoexist->btc_set_bt_ant_detection = halbtcoutsrc_SetBtAntDetection; + pBtCoexist->btc_set_bt_trx_mask = halbtcoutsrc_SetBtTRXMASK; + pBtCoexist->btc_coex_h2c_process = halbtcoutsrc_CoexH2cProcess; + pBtCoexist->btc_get_bt_coex_supported_feature = halbtcoutsrc_GetBtCoexSupportedFeature; + pBtCoexist->btc_get_bt_coex_supported_version= halbtcoutsrc_GetBtCoexSupportedVersion; + pBtCoexist->btc_get_ant_det_val_from_bt = halbtcoutsrc_GetAntDetValFromBt; + pBtCoexist->btc_get_ble_scan_type_from_bt = halbtcoutsrc_GetBleScanTypeFromBt; + pBtCoexist->btc_get_ble_scan_para_from_bt = halbtcoutsrc_GetBleScanParaFromBt; + pBtCoexist->btc_get_bt_afh_map_from_bt = halbtcoutsrc_GetBtAFHMapFromBt; + pBtCoexist->btc_get_bt_phydm_version = halbtcoutsrc_GetPhydmVersion; + pBtCoexist->btc_phydm_modify_RA_PCR_threshold = halbtcoutsrc_phydm_modify_RA_PCR_threshold; + pBtCoexist->btc_phydm_query_PHY_counter = halbtcoutsrc_phydm_query_PHY_counter; + + pBtCoexist->cli_buf = &GLBtcDbgBuf[0]; + + GLBtcWiFiInScanState = _FALSE; + + GLBtcWiFiInIQKState = _FALSE; + + GLBtcWiFiInIPS = _FALSE; + + GLBtcWiFiInLPS = _FALSE; + + GLBtcBtCoexAliveRegistered = _FALSE; + + /* BT Control H2C/C2H*/ + GLBtcBtMpOperSeq = 0; + _rtw_mutex_init(&GLBtcBtMpOperLock); + _init_timer(&GLBtcBtMpOperTimer, ((PADAPTER)padapter)->pnetdev, _btmpoper_timer_hdl, pBtCoexist); + _rtw_init_sema(&GLBtcBtMpRptSema, 0); + GLBtcBtMpRptSeq = 0; + GLBtcBtMpRptStatus = 0; + _rtw_memset(GLBtcBtMpRptRsp, 0, C2H_MAX_SIZE); + GLBtcBtMpRptRspSize = 0; + GLBtcBtMpRptWait = 0; + GLBtcBtMpRptWiFiOK = 0; + GLBtcBtMpRptBTOK = 0; + + return _TRUE; +} + +void EXhalbtcoutsrc_PowerOnSetting(PBTC_COEXIST pBtCoexist) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + /* Power on setting function is only added in 8723B currently */ + if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_power_on_setting(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_power_on_setting(pBtCoexist); + } + + if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_power_on_setting(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_power_on_setting(pBtCoexist); + } + + if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_power_on_setting(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_power_on_setting(pBtCoexist); + } + + if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_power_on_setting(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_power_on_setting(pBtCoexist); + } +} + +void EXhalbtcoutsrc_PreLoadFirmware(PBTC_COEXIST pBtCoexist) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + pBtCoexist->statistics.cnt_pre_load_firmware++; + + if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_pre_load_firmware(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_pre_load_firmware(pBtCoexist); + } + + if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_pre_load_firmware(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_pre_load_firmware(pBtCoexist); + } + + if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_pre_load_firmware(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_pre_load_firmware(pBtCoexist); + } +} + +void EXhalbtcoutsrc_init_hw_config(PBTC_COEXIST pBtCoexist, u8 bWifiOnly) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + pBtCoexist->statistics.cnt_init_hw_config++; + + if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { +#if 0 + if (halbtcoutsrc_IsCsrBtCoex(pBtCoexist) == _TRUE) + ex_halbtc8821aCsr2ant_init_hw_config(pBtCoexist, bWifiOnly); + else +#endif + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821a2ant_init_hw_config(pBtCoexist, bWifiOnly); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821a1ant_init_hw_config(pBtCoexist, bWifiOnly); + } else if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_init_hw_config(pBtCoexist, bWifiOnly); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_init_hw_config(pBtCoexist, bWifiOnly); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_init_hw_config(pBtCoexist, bWifiOnly); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_init_hw_config(pBtCoexist, bWifiOnly); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_init_hw_config(pBtCoexist, bWifiOnly); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8192e2ant_init_hw_config(pBtCoexist, bWifiOnly); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_init_hw_config(pBtCoexist, bWifiOnly); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_init_hw_config(pBtCoexist, bWifiOnly); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_init_hw_config(pBtCoexist, bWifiOnly); + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_init_hw_config(pBtCoexist, bWifiOnly); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_init_hw_config(pBtCoexist, bWifiOnly); + #ifdef CONFIG_FW_MULTI_PORT_SUPPORT + rtw_hal_set_default_port_id_cmd(pBtCoexist->Adapter, 0); + rtw_hal_set_wifi_port_id_cmd(pBtCoexist->Adapter); + #endif + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_init_hw_config(pBtCoexist, bWifiOnly); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_init_hw_config(pBtCoexist, bWifiOnly); + #ifdef CONFIG_FW_MULTI_PORT_SUPPORT + rtw_hal_set_default_port_id_cmd(pBtCoexist->Adapter, 0); + rtw_hal_set_wifi_port_id_cmd(pBtCoexist->Adapter); + #endif + } +} + +void EXhalbtcoutsrc_init_coex_dm(PBTC_COEXIST pBtCoexist) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + pBtCoexist->statistics.cnt_init_coex_dm++; + + if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { +#if 0 + if (halbtcoutsrc_IsCsrBtCoex(pBtCoexist) == _TRUE) + ex_halbtc8821aCsr2ant_init_coex_dm(pBtCoexist); + else +#endif + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821a2ant_init_coex_dm(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821a1ant_init_coex_dm(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_init_coex_dm(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_init_coex_dm(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_init_coex_dm(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_init_coex_dm(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_init_coex_dm(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8192e2ant_init_coex_dm(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_init_coex_dm(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_init_coex_dm(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_init_coex_dm(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_init_coex_dm(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_init_coex_dm(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_init_coex_dm(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_init_coex_dm(pBtCoexist); + } + + pBtCoexist->initilized = _TRUE; +} + +void EXhalbtcoutsrc_ips_notify(PBTC_COEXIST pBtCoexist, u8 type) +{ + u8 ipsType; + + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + pBtCoexist->statistics.cnt_ips_notify++; + if (pBtCoexist->manual_control) + return; + + if (IPS_NONE == type) { + ipsType = BTC_IPS_LEAVE; + GLBtcWiFiInIPS = _FALSE; + } else { + ipsType = BTC_IPS_ENTER; + GLBtcWiFiInIPS = _TRUE; + } + + /* All notify is called in cmd thread, don't need to leave low power again + * halbtcoutsrc_LeaveLowPower(pBtCoexist); */ + + if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { +#if 0 + if (halbtcoutsrc_IsCsrBtCoex(pBtCoexist) == _TRUE) + ex_halbtc8821aCsr2ant_ips_notify(pBtCoexist, ipsType); + else +#endif + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821a2ant_ips_notify(pBtCoexist, ipsType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821a1ant_ips_notify(pBtCoexist, ipsType); + } else if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_ips_notify(pBtCoexist, ipsType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_ips_notify(pBtCoexist, ipsType); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_ips_notify(pBtCoexist, ipsType); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_ips_notify(pBtCoexist, ipsType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_ips_notify(pBtCoexist, ipsType); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8192e2ant_ips_notify(pBtCoexist, ipsType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_ips_notify(pBtCoexist, ipsType); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_ips_notify(pBtCoexist, ipsType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_ips_notify(pBtCoexist, ipsType); + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_ips_notify(pBtCoexist, ipsType); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_ips_notify(pBtCoexist, ipsType); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_ips_notify(pBtCoexist, ipsType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_ips_notify(pBtCoexist, ipsType); + } + + /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ +} + +void EXhalbtcoutsrc_lps_notify(PBTC_COEXIST pBtCoexist, u8 type) +{ + u8 lpsType; + + + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + pBtCoexist->statistics.cnt_lps_notify++; + if (pBtCoexist->manual_control) + return; + + if (PS_MODE_ACTIVE == type) { + lpsType = BTC_LPS_DISABLE; + GLBtcWiFiInLPS = _FALSE; + } else { + lpsType = BTC_LPS_ENABLE; + GLBtcWiFiInLPS = _TRUE; + } + + if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { +#if 0 + if (halbtcoutsrc_IsCsrBtCoex(pBtCoexist) == _TRUE) + ex_halbtc8821aCsr2ant_lps_notify(pBtCoexist, lpsType); + else +#endif + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821a2ant_lps_notify(pBtCoexist, lpsType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821a1ant_lps_notify(pBtCoexist, lpsType); + } else if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_lps_notify(pBtCoexist, lpsType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_lps_notify(pBtCoexist, lpsType); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_lps_notify(pBtCoexist, lpsType); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_lps_notify(pBtCoexist, lpsType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_lps_notify(pBtCoexist, lpsType); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8192e2ant_lps_notify(pBtCoexist, lpsType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_lps_notify(pBtCoexist, lpsType); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_lps_notify(pBtCoexist, lpsType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_lps_notify(pBtCoexist, lpsType); + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_lps_notify(pBtCoexist, lpsType); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_lps_notify(pBtCoexist, lpsType); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_lps_notify(pBtCoexist, lpsType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_lps_notify(pBtCoexist, lpsType); + } +} + +void EXhalbtcoutsrc_scan_notify(PBTC_COEXIST pBtCoexist, u8 type) +{ + u8 scanType; + + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + pBtCoexist->statistics.cnt_scan_notify++; + if (pBtCoexist->manual_control) + return; + + if (type) { + scanType = BTC_SCAN_START; + GLBtcWiFiInScanState = _TRUE; + } else { + scanType = BTC_SCAN_FINISH; + GLBtcWiFiInScanState = _FALSE; + } + + /* All notify is called in cmd thread, don't need to leave low power again + * halbtcoutsrc_LeaveLowPower(pBtCoexist); */ + + if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { +#if 0 + if (halbtcoutsrc_IsCsrBtCoex(pBtCoexist) == _TRUE) + ex_halbtc8821aCsr2ant_scan_notify(pBtCoexist, scanType); + else +#endif + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821a2ant_scan_notify(pBtCoexist, scanType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821a1ant_scan_notify(pBtCoexist, scanType); + } else if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_scan_notify(pBtCoexist, scanType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_scan_notify(pBtCoexist, scanType); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_scan_notify(pBtCoexist, scanType); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_scan_notify(pBtCoexist, scanType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_scan_notify(pBtCoexist, scanType); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8192e2ant_scan_notify(pBtCoexist, scanType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_scan_notify(pBtCoexist, scanType); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_scan_notify(pBtCoexist, scanType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_scan_notify(pBtCoexist, scanType); + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_scan_notify(pBtCoexist, scanType); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_scan_notify(pBtCoexist, scanType); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_scan_notify(pBtCoexist, scanType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_scan_notify(pBtCoexist, scanType); + } + + /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ +} + +void EXhalbtcoutsrc_SetAntennaPathNotify(PBTC_COEXIST pBtCoexist, u8 type) +{ +#if 0 + u8 switchType; + + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + if (pBtCoexist->manual_control) + return; + + halbtcoutsrc_LeaveLowPower(pBtCoexist); + + switchType = type; + + if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_set_antenna_notify(pBtCoexist, type); + } + if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_set_antenna_notify(pBtCoexist, type); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_set_antenna_notify(pBtCoexist, type); + } + + halbtcoutsrc_NormalLowPower(pBtCoexist); +#endif +} + +void EXhalbtcoutsrc_connect_notify(PBTC_COEXIST pBtCoexist, u8 action) +{ + u8 assoType; + + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + pBtCoexist->statistics.cnt_connect_notify++; + if (pBtCoexist->manual_control) + return; + + if (action) + assoType = BTC_ASSOCIATE_START; + else + assoType = BTC_ASSOCIATE_FINISH; + + /* All notify is called in cmd thread, don't need to leave low power again + * halbtcoutsrc_LeaveLowPower(pBtCoexist); */ + + if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { +#if 0 + if (halbtcoutsrc_IsCsrBtCoex(pBtCoexist) == _TRUE) + ex_halbtc8821aCsr2ant_connect_notify(pBtCoexist, assoType); + else +#endif + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821a2ant_connect_notify(pBtCoexist, assoType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821a1ant_connect_notify(pBtCoexist, assoType); + } else if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_connect_notify(pBtCoexist, assoType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_connect_notify(pBtCoexist, assoType); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_connect_notify(pBtCoexist, assoType); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_connect_notify(pBtCoexist, assoType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_connect_notify(pBtCoexist, assoType); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8192e2ant_connect_notify(pBtCoexist, assoType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_connect_notify(pBtCoexist, assoType); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_connect_notify(pBtCoexist, assoType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_connect_notify(pBtCoexist, assoType); + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_connect_notify(pBtCoexist, assoType); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_connect_notify(pBtCoexist, assoType); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_connect_notify(pBtCoexist, assoType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_connect_notify(pBtCoexist, assoType); + } + + /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ +} + +void EXhalbtcoutsrc_media_status_notify(PBTC_COEXIST pBtCoexist, RT_MEDIA_STATUS mediaStatus) +{ + u8 mStatus; + + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + pBtCoexist->statistics.cnt_media_status_notify++; + if (pBtCoexist->manual_control) + return; + + if (RT_MEDIA_CONNECT == mediaStatus) + mStatus = BTC_MEDIA_CONNECT; + else + mStatus = BTC_MEDIA_DISCONNECT; + + /* All notify is called in cmd thread, don't need to leave low power again + * halbtcoutsrc_LeaveLowPower(pBtCoexist); */ + + if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { +#if 0 + if (halbtcoutsrc_IsCsrBtCoex(pBtCoexist) == _TRUE) + ex_halbtc8821aCsr2ant_media_status_notify(pBtCoexist, mStatus); + else +#endif + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821a2ant_media_status_notify(pBtCoexist, mStatus); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821a1ant_media_status_notify(pBtCoexist, mStatus); + } else if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_media_status_notify(pBtCoexist, mStatus); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_media_status_notify(pBtCoexist, mStatus); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_media_status_notify(pBtCoexist, mStatus); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_media_status_notify(pBtCoexist, mStatus); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_media_status_notify(pBtCoexist, mStatus); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8192e2ant_media_status_notify(pBtCoexist, mStatus); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_media_status_notify(pBtCoexist, mStatus); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_media_status_notify(pBtCoexist, mStatus); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_media_status_notify(pBtCoexist, mStatus); + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_media_status_notify(pBtCoexist, mStatus); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_media_status_notify(pBtCoexist, mStatus); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_media_status_notify(pBtCoexist, mStatus); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_media_status_notify(pBtCoexist, mStatus); + } + + /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ +} + +void EXhalbtcoutsrc_specific_packet_notify(PBTC_COEXIST pBtCoexist, u8 pktType) +{ + u8 packetType; + + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + pBtCoexist->statistics.cnt_specific_packet_notify++; + if (pBtCoexist->manual_control) + return; + + if (PACKET_DHCP == pktType) + packetType = BTC_PACKET_DHCP; + else if (PACKET_EAPOL == pktType) + packetType = BTC_PACKET_EAPOL; + else if (PACKET_ARP == pktType) + packetType = BTC_PACKET_ARP; + else { + packetType = BTC_PACKET_UNKNOWN; + return; + } + + /* All notify is called in cmd thread, don't need to leave low power again + * halbtcoutsrc_LeaveLowPower(pBtCoexist); */ + + if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { +#if 0 + if (halbtcoutsrc_IsCsrBtCoex(pBtCoexist) == _TRUE) + ex_halbtc8821aCsr2ant_specific_packet_notify(pBtCoexist, packetType); + else +#endif + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821a2ant_specific_packet_notify(pBtCoexist, packetType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821a1ant_specific_packet_notify(pBtCoexist, packetType); + } else if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_specific_packet_notify(pBtCoexist, packetType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_specific_packet_notify(pBtCoexist, packetType); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_specific_packet_notify(pBtCoexist, packetType); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_specific_packet_notify(pBtCoexist, packetType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_specific_packet_notify(pBtCoexist, packetType); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8192e2ant_specific_packet_notify(pBtCoexist, packetType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_specific_packet_notify(pBtCoexist, packetType); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_specific_packet_notify(pBtCoexist, packetType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_specific_packet_notify(pBtCoexist, packetType); + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_specific_packet_notify(pBtCoexist, packetType); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_specific_packet_notify(pBtCoexist, packetType); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_specific_packet_notify(pBtCoexist, packetType); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_specific_packet_notify(pBtCoexist, packetType); + } + + /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ +} + +void EXhalbtcoutsrc_bt_info_notify(PBTC_COEXIST pBtCoexist, u8 *tmpBuf, u8 length) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + pBtCoexist->statistics.cnt_bt_info_notify++; + + /* All notify is called in cmd thread, don't need to leave low power again + * halbtcoutsrc_LeaveLowPower(pBtCoexist); */ + + if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { +#if 0 + if (halbtcoutsrc_IsCsrBtCoex(pBtCoexist) == _TRUE) + ex_halbtc8821aCsr2ant_bt_info_notify(pBtCoexist, tmpBuf, length); + else +#endif + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821a2ant_bt_info_notify(pBtCoexist, tmpBuf, length); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821a1ant_bt_info_notify(pBtCoexist, tmpBuf, length); + } else if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_bt_info_notify(pBtCoexist, tmpBuf, length); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_bt_info_notify(pBtCoexist, tmpBuf, length); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_bt_info_notify(pBtCoexist, tmpBuf, length); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_bt_info_notify(pBtCoexist, tmpBuf, length); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_bt_info_notify(pBtCoexist, tmpBuf, length); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8192e2ant_bt_info_notify(pBtCoexist, tmpBuf, length); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_bt_info_notify(pBtCoexist, tmpBuf, length); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_bt_info_notify(pBtCoexist, tmpBuf, length); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_bt_info_notify(pBtCoexist, tmpBuf, length); + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_bt_info_notify(pBtCoexist, tmpBuf, length); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_bt_info_notify(pBtCoexist, tmpBuf, length); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_bt_info_notify(pBtCoexist, tmpBuf, length); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_bt_info_notify(pBtCoexist, tmpBuf, length); + } + + /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ +} + +VOID +EXhalbtcoutsrc_RfStatusNotify( + IN PBTC_COEXIST pBtCoexist, + IN u1Byte type +) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + pBtCoexist->statistics.cnt_rf_status_notify++; + + if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { + } else if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_rf_status_notify(pBtCoexist, type); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_rf_status_notify(pBtCoexist, type); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_rf_status_notify(pBtCoexist, type); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_rf_status_notify(pBtCoexist, type); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_rf_status_notify(pBtCoexist, type); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_rf_status_notify(pBtCoexist, type); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_rf_status_notify(pBtCoexist, type); + } +} + +void EXhalbtcoutsrc_StackOperationNotify(PBTC_COEXIST pBtCoexist, u8 type) +{ +#if 0 + u8 stackOpType; + + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + pBtCoexist->statistics.cntStackOperationNotify++; + if (pBtCoexist->manual_control) + return; + + if ((HCI_BT_OP_INQUIRY_START == type) || + (HCI_BT_OP_PAGING_START == type) || + (HCI_BT_OP_PAIRING_START == type)) + stackOpType = BTC_STACK_OP_INQ_PAGE_PAIR_START; + else if ((HCI_BT_OP_INQUIRY_FINISH == type) || + (HCI_BT_OP_PAGING_SUCCESS == type) || + (HCI_BT_OP_PAGING_UNSUCCESS == type) || + (HCI_BT_OP_PAIRING_FINISH == type)) + stackOpType = BTC_STACK_OP_INQ_PAGE_PAIR_FINISH; + else + stackOpType = BTC_STACK_OP_NONE; + +#endif +} + +void EXhalbtcoutsrc_halt_notify(PBTC_COEXIST pBtCoexist) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { +#if 0 + if (halbtcoutsrc_IsCsrBtCoex(pBtCoexist) == _TRUE) + ex_halbtc8821aCsr2ant_halt_notify(pBtCoexist); + else +#endif + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821a2ant_halt_notify(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821a1ant_halt_notify(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_halt_notify(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_halt_notify(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_halt_notify(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_halt_notify(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_halt_notify(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8192e2ant_halt_notify(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_halt_notify(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_halt_notify(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_halt_notify(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_halt_notify(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_halt_notify(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_halt_notify(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_halt_notify(pBtCoexist); + } +} + +void EXhalbtcoutsrc_SwitchBtTRxMask(PBTC_COEXIST pBtCoexist) +{ + if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) { + halbtcoutsrc_SetBtReg(pBtCoexist, 0, 0x3c, 0x01); /* BT goto standby while GNT_BT 1-->0 */ + } else if (pBtCoexist->board_info.btdm_ant_num == 1) { + halbtcoutsrc_SetBtReg(pBtCoexist, 0, 0x3c, 0x15); /* BT goto standby while GNT_BT 1-->0 */ + } + } +} + +void EXhalbtcoutsrc_pnp_notify(PBTC_COEXIST pBtCoexist, u8 pnpState) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + /* */ + /* currently only 1ant we have to do the notification, */ + /* once pnp is notified to sleep state, we have to leave LPS that we can sleep normally. */ + /* */ + + if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_pnp_notify(pBtCoexist, pnpState); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_pnp_notify(pBtCoexist, pnpState); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_pnp_notify(pBtCoexist, pnpState); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_pnp_notify(pBtCoexist, pnpState); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_pnp_notify(pBtCoexist, pnpState); + } else if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { +#if 0 + if (halbtcoutsrc_IsCsrBtCoex(pBtCoexist) == _TRUE) + ex_halbtc8821aCsr2ant_pnp_notify(pBtCoexist, pnpState); + else +#endif + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821a1ant_pnp_notify(pBtCoexist, pnpState); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821a2ant_pnp_notify(pBtCoexist, pnpState); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_pnp_notify(pBtCoexist, pnpState); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_pnp_notify(pBtCoexist, pnpState); + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_pnp_notify(pBtCoexist, pnpState); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_pnp_notify(pBtCoexist, pnpState); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_pnp_notify(pBtCoexist, pnpState); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_pnp_notify(pBtCoexist, pnpState); + } +} + +void EXhalbtcoutsrc_CoexDmSwitch(PBTC_COEXIST pBtCoexist) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + pBtCoexist->statistics.cnt_coex_dm_switch++; + + halbtcoutsrc_LeaveLowPower(pBtCoexist); + + if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) { + pBtCoexist->stop_coex_dm = TRUE; + ex_halbtc8723b1ant_coex_dm_reset(pBtCoexist); + EXhalbtcoutsrc_SetAntNum(BT_COEX_ANT_TYPE_DETECTED, 2); + ex_halbtc8723b2ant_init_hw_config(pBtCoexist, FALSE); + ex_halbtc8723b2ant_init_coex_dm(pBtCoexist); + pBtCoexist->stop_coex_dm = FALSE; + } + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) { + pBtCoexist->stop_coex_dm = TRUE; + ex_halbtc8723d1ant_coex_dm_reset(pBtCoexist); + EXhalbtcoutsrc_SetAntNum(BT_COEX_ANT_TYPE_DETECTED, 2); + ex_halbtc8723d2ant_init_hw_config(pBtCoexist, FALSE); + ex_halbtc8723d2ant_init_coex_dm(pBtCoexist); + pBtCoexist->stop_coex_dm = FALSE; + } + } + + halbtcoutsrc_NormalLowPower(pBtCoexist); +} + +void EXhalbtcoutsrc_periodical(PBTC_COEXIST pBtCoexist) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + pBtCoexist->statistics.cnt_periodical++; + + /* Periodical should be called in cmd thread, */ + /* don't need to leave low power again + * halbtcoutsrc_LeaveLowPower(pBtCoexist); */ + + if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { +#if 0 + if (halbtcoutsrc_IsCsrBtCoex(pBtCoexist) == _TRUE) + ex_halbtc8821aCsr2ant_periodical(pBtCoexist); + else +#endif + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821a2ant_periodical(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) { + if (!halbtcoutsrc_UnderIps(pBtCoexist)) + ex_halbtc8821a1ant_periodical(pBtCoexist); + } + } else if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_periodical(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_periodical(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_periodical(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_periodical(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_periodical(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8192e2ant_periodical(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_periodical(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_periodical(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_periodical(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_periodical(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_periodical(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_periodical(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_periodical(pBtCoexist); + } + + /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ +} + +void EXhalbtcoutsrc_dbg_control(PBTC_COEXIST pBtCoexist, u8 opCode, u8 opLen, u8 *pData) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + pBtCoexist->statistics.cnt_dbg_ctrl++; + + /* This function doesn't be called yet, */ + /* default no need to leave low power to avoid deadlock + * halbtcoutsrc_LeaveLowPower(pBtCoexist); */ + + if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_dbg_control(pBtCoexist, opCode, opLen, pData); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_dbg_control(pBtCoexist, opCode, opLen, pData); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_dbg_control(pBtCoexist, opCode, opLen, pData); + } else if(IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) + if(pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_dbg_control(pBtCoexist, opCode, opLen, pData); + + /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ +} + +#if 0 +VOID +EXhalbtcoutsrc_AntennaDetection( + IN PBTC_COEXIST pBtCoexist, + IN u4Byte centFreq, + IN u4Byte offset, + IN u4Byte span, + IN u4Byte seconds +) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + /* Need to refine the following power save operations to enable this function in the future */ +#if 0 + IPSDisable(pBtCoexist->Adapter, FALSE, 0); + LeisurePSLeave(pBtCoexist->Adapter, LPS_DISABLE_BT_COEX); +#endif + + if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_AntennaDetection(pBtCoexist, centFreq, offset, span, seconds); + } + + /* IPSReturn(pBtCoexist->Adapter, 0xff); */ +} +#endif + +void EXhalbtcoutsrc_StackUpdateProfileInfo(void) +{ +#ifdef CONFIG_BT_COEXIST_SOCKET_TRX + PBTC_COEXIST pBtCoexist = &GLBtCoexist; + PADAPTER padapter = (PADAPTER)GLBtCoexist.Adapter; + PBT_MGNT pBtMgnt = &padapter->coex_info.BtMgnt; + u8 i; + + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + pBtCoexist->stack_info.profile_notified = _TRUE; + + pBtCoexist->stack_info.num_of_link = + pBtMgnt->ExtConfig.NumberOfACL + pBtMgnt->ExtConfig.NumberOfSCO; + + /* reset first */ + pBtCoexist->stack_info.bt_link_exist = _FALSE; + pBtCoexist->stack_info.sco_exist = _FALSE; + pBtCoexist->stack_info.acl_exist = _FALSE; + pBtCoexist->stack_info.a2dp_exist = _FALSE; + pBtCoexist->stack_info.hid_exist = _FALSE; + pBtCoexist->stack_info.num_of_hid = 0; + pBtCoexist->stack_info.pan_exist = _FALSE; + + if (!pBtMgnt->ExtConfig.NumberOfACL) + pBtCoexist->stack_info.min_bt_rssi = 0; + + if (pBtCoexist->stack_info.num_of_link) { + pBtCoexist->stack_info.bt_link_exist = _TRUE; + if (pBtMgnt->ExtConfig.NumberOfSCO) + pBtCoexist->stack_info.sco_exist = _TRUE; + if (pBtMgnt->ExtConfig.NumberOfACL) + pBtCoexist->stack_info.acl_exist = _TRUE; + } + + for (i = 0; i < pBtMgnt->ExtConfig.NumberOfACL; i++) { + if (BT_PROFILE_A2DP == pBtMgnt->ExtConfig.aclLink[i].BTProfile) + pBtCoexist->stack_info.a2dp_exist = _TRUE; + else if (BT_PROFILE_PAN == pBtMgnt->ExtConfig.aclLink[i].BTProfile) + pBtCoexist->stack_info.pan_exist = _TRUE; + else if (BT_PROFILE_HID == pBtMgnt->ExtConfig.aclLink[i].BTProfile) { + pBtCoexist->stack_info.hid_exist = _TRUE; + pBtCoexist->stack_info.num_of_hid++; + } else + pBtCoexist->stack_info.unknown_acl_exist = _TRUE; + } +#endif /* CONFIG_BT_COEXIST_SOCKET_TRX */ +} + +void EXhalbtcoutsrc_UpdateMinBtRssi(s8 btRssi) +{ + PBTC_COEXIST pBtCoexist = &GLBtCoexist; + + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + pBtCoexist->stack_info.min_bt_rssi = btRssi; +} + +void EXhalbtcoutsrc_SetHciVersion(u16 hciVersion) +{ + PBTC_COEXIST pBtCoexist = &GLBtCoexist; + + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + pBtCoexist->stack_info.hci_version = hciVersion; +} + +void EXhalbtcoutsrc_SetBtPatchVersion(u16 btHciVersion, u16 btPatchVersion) +{ + PBTC_COEXIST pBtCoexist = &GLBtCoexist; + + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + pBtCoexist->bt_info.bt_real_fw_ver = btPatchVersion; + pBtCoexist->bt_info.bt_hci_ver = btHciVersion; +} + +#if 0 +void EXhalbtcoutsrc_SetBtExist(u8 bBtExist) +{ + GLBtCoexist.boardInfo.bBtExist = bBtExist; +} +#endif +void EXhalbtcoutsrc_SetChipType(u8 chipType) +{ + switch (chipType) { + default: + case BT_2WIRE: + case BT_ISSC_3WIRE: + case BT_ACCEL: + case BT_RTL8756: + GLBtCoexist.board_info.bt_chip_type = BTC_CHIP_UNDEF; + break; + case BT_CSR_BC4: + GLBtCoexist.board_info.bt_chip_type = BTC_CHIP_CSR_BC4; + break; + case BT_CSR_BC8: + GLBtCoexist.board_info.bt_chip_type = BTC_CHIP_CSR_BC8; + break; + case BT_RTL8723A: + GLBtCoexist.board_info.bt_chip_type = BTC_CHIP_RTL8723A; + break; + case BT_RTL8821: + GLBtCoexist.board_info.bt_chip_type = BTC_CHIP_RTL8821; + break; + case BT_RTL8723B: + GLBtCoexist.board_info.bt_chip_type = BTC_CHIP_RTL8723B; + break; + } +} + +void EXhalbtcoutsrc_SetAntNum(u8 type, u8 antNum) +{ + if (BT_COEX_ANT_TYPE_PG == type) { + GLBtCoexist.board_info.pg_ant_num = antNum; + GLBtCoexist.board_info.btdm_ant_num = antNum; +#if 0 + /* The antenna position: Main (default) or Aux for pgAntNum=2 && btdmAntNum =1 */ + /* The antenna position should be determined by auto-detect mechanism */ + /* The following is assumed to main, and those must be modified if y auto-detect mechanism is ready */ + if ((GLBtCoexist.board_info.pg_ant_num == 2) && (GLBtCoexist.board_info.btdm_ant_num == 1)) + GLBtCoexist.board_info.btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; + else + GLBtCoexist.board_info.btdm_ant_pos = BTC_ANTENNA_AT_MAIN_PORT; +#endif + } else if (BT_COEX_ANT_TYPE_ANTDIV == type) { + GLBtCoexist.board_info.btdm_ant_num = antNum; + /* GLBtCoexist.boardInfo.btdmAntPos = BTC_ANTENNA_AT_MAIN_PORT; */ + } else if (BT_COEX_ANT_TYPE_DETECTED == type) { + GLBtCoexist.board_info.btdm_ant_num = antNum; + /* GLBtCoexist.boardInfo.btdmAntPos = BTC_ANTENNA_AT_MAIN_PORT; */ + } +} + +/* + * Currently used by 8723b only, S0 or S1 + * */ +void EXhalbtcoutsrc_SetSingleAntPath(u8 singleAntPath) +{ + GLBtCoexist.board_info.single_ant_path = singleAntPath; +} + +void EXhalbtcoutsrc_DisplayBtCoexInfo(PBTC_COEXIST pBtCoexist) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + halbtcoutsrc_LeaveLowPower(pBtCoexist); + + if (IS_HARDWARE_TYPE_8821(pBtCoexist->Adapter)) { +#if 0 + if (halbtcoutsrc_IsCsrBtCoex(pBtCoexist) == _TRUE) + ex_halbtc8821aCsr2ant_display_coex_info(pBtCoexist); + else +#endif + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821a2ant_display_coex_info(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821a1ant_display_coex_info(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723b2ant_display_coex_info(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_display_coex_info(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8703B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8703b1ant_display_coex_info(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8723D(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8723d2ant_display_coex_info(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723d1ant_display_coex_info(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8192E(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8192e2ant_display_coex_info(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8192e1ant_display_coex_info(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_display_coex_info(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8812a1ant_display_coex_info(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_display_coex_info(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_display_coex_info(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_display_coex_info(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_display_coex_info(pBtCoexist); + } + + halbtcoutsrc_NormalLowPower(pBtCoexist); +} + +void EXhalbtcoutsrc_DisplayAntDetection(PBTC_COEXIST pBtCoexist) +{ + if (!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + halbtcoutsrc_LeaveLowPower(pBtCoexist); + + if (IS_HARDWARE_TYPE_8723B(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8723b1ant_display_ant_detection(pBtCoexist); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_display_ant_detection(pBtCoexist); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_display_ant_detection(pBtCoexist); + } + + halbtcoutsrc_NormalLowPower(pBtCoexist); +} + +void ex_halbtcoutsrc_pta_off_on_notify(PBTC_COEXIST pBtCoexist, u8 bBTON) +{ + if (IS_HARDWARE_TYPE_8812(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8812a2ant_pta_off_on_notify(pBtCoexist, (bBTON == _TRUE) ? BTC_BT_ON : BTC_BT_OFF); + } +} + +void EXhalbtcoutsrc_set_rfe_type(u8 type) +{ + GLBtCoexist.board_info.rfe_type= type; +} + +void EXhalbtcoutsrc_switchband_notify(struct btc_coexist *pBtCoexist, u8 type) +{ + if(!halbtcoutsrc_IsBtCoexistAvailable(pBtCoexist)) + return; + + if(pBtCoexist->manual_control) + return; + + /* Driver should guarantee that the HW status isn't in low power mode */ + /* halbtcoutsrc_LeaveLowPower(pBtCoexist); */ + + if(IS_HARDWARE_TYPE_8822B(pBtCoexist->Adapter)) { + if(pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8822b1ant_switchband_notify(pBtCoexist, type); + else if(pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8822b2ant_switchband_notify(pBtCoexist, type); + } else if (IS_HARDWARE_TYPE_8821C(pBtCoexist->Adapter)) { + if (pBtCoexist->board_info.btdm_ant_num == 2) + ex_halbtc8821c2ant_switchband_notify(pBtCoexist, type); + else if (pBtCoexist->board_info.btdm_ant_num == 1) + ex_halbtc8821c1ant_switchband_notify(pBtCoexist, type); + } + + /* halbtcoutsrc_NormalLowPower(pBtCoexist); */ +} + +static void halbt_init_hw_config92C(PADAPTER padapter) +{ + PHAL_DATA_TYPE pHalData; + u8 u1Tmp; + + + pHalData = GET_HAL_DATA(padapter); + if ((pHalData->bt_coexist.btChipType == BT_CSR_BC4) || + (pHalData->bt_coexist.btChipType == BT_CSR_BC8)) { + if (pHalData->rf_type == RF_1T1R) { + /* Config to 1T1R */ + u1Tmp = rtw_read8(padapter, rOFDM0_TRxPathEnable); + u1Tmp &= ~BIT(1); + rtw_write8(padapter, rOFDM0_TRxPathEnable, u1Tmp); + RT_DISP(FBT, BT_TRACE, ("[BTCoex], BT write 0xC04 = 0x%x\n", u1Tmp)); + + u1Tmp = rtw_read8(padapter, rOFDM1_TRxPathEnable); + u1Tmp &= ~BIT(1); + rtw_write8(padapter, rOFDM1_TRxPathEnable, u1Tmp); + RT_DISP(FBT, BT_TRACE, ("[BTCoex], BT write 0xD04 = 0x%x\n", u1Tmp)); + } + } +} + +static void halbt_init_hw_config92D(PADAPTER padapter) +{ + PHAL_DATA_TYPE pHalData; + u8 u1Tmp; + + pHalData = GET_HAL_DATA(padapter); + if ((pHalData->bt_coexist.btChipType == BT_CSR_BC4) || + (pHalData->bt_coexist.btChipType == BT_CSR_BC8)) { + if (pHalData->rf_type == RF_1T1R) { + /* Config to 1T1R */ + u1Tmp = rtw_read8(padapter, rOFDM0_TRxPathEnable); + u1Tmp &= ~BIT(1); + rtw_write8(padapter, rOFDM0_TRxPathEnable, u1Tmp); + RT_DISP(FBT, BT_TRACE, ("[BTCoex], BT write 0xC04 = 0x%x\n", u1Tmp)); + + u1Tmp = rtw_read8(padapter, rOFDM1_TRxPathEnable); + u1Tmp &= ~BIT(1); + rtw_write8(padapter, rOFDM1_TRxPathEnable, u1Tmp); + RT_DISP(FBT, BT_TRACE, ("[BTCoex], BT write 0xD04 = 0x%x\n", u1Tmp)); + } + } +} + +/* + * Description: + * Run BT-Coexist mechansim or not + * + */ +void hal_btcoex_SetBTCoexist(PADAPTER padapter, u8 bBtExist) +{ + PHAL_DATA_TYPE pHalData; + + + pHalData = GET_HAL_DATA(padapter); + pHalData->bt_coexist.bBtExist = bBtExist; +} + +/* + * Dewcription: + * Check is co-exist mechanism enabled or not + * + * Return: + * _TRUE Enable BT co-exist mechanism + * _FALSE Disable BT co-exist mechanism + */ +u8 hal_btcoex_IsBtExist(PADAPTER padapter) +{ + PHAL_DATA_TYPE pHalData; + + + pHalData = GET_HAL_DATA(padapter); + return pHalData->bt_coexist.bBtExist; +} + +u8 hal_btcoex_IsBtDisabled(PADAPTER padapter) +{ + if (!hal_btcoex_IsBtExist(padapter)) + return _TRUE; + + if (GLBtCoexist.bt_info.bt_disabled) + return _TRUE; + else + return _FALSE; +} + +void hal_btcoex_SetChipType(PADAPTER padapter, u8 chipType) +{ + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + pHalData->bt_coexist.btChipType = chipType; +} + +void hal_btcoex_SetPgAntNum(PADAPTER padapter, u8 antNum) +{ + PHAL_DATA_TYPE pHalData; + + pHalData = GET_HAL_DATA(padapter); + + pHalData->bt_coexist.btTotalAntNum = antNum; +} + +u8 hal_btcoex_Initialize(PADAPTER padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + u8 ret; + + _rtw_memset(&GLBtCoexist, 0, sizeof(GLBtCoexist)); + + hal_btcoex_SetBTCoexist(padapter, rtw_btcoex_get_bt_coexist(padapter)); + hal_btcoex_SetChipType(padapter, rtw_btcoex_get_chip_type(padapter)); + hal_btcoex_SetPgAntNum(padapter, rtw_btcoex_get_pg_ant_num(padapter)); + + ret = EXhalbtcoutsrc_InitlizeVariables((void *)padapter); + + return ret; +} + +void hal_btcoex_PowerOnSetting(PADAPTER padapter) +{ + EXhalbtcoutsrc_PowerOnSetting(&GLBtCoexist); +} + +void hal_btcoex_PreLoadFirmware(PADAPTER padapter) +{ + EXhalbtcoutsrc_PreLoadFirmware(&GLBtCoexist); +} + +void hal_btcoex_InitHwConfig(PADAPTER padapter, u8 bWifiOnly) +{ + if (!hal_btcoex_IsBtExist(padapter)) + return; + + EXhalbtcoutsrc_init_hw_config(&GLBtCoexist, bWifiOnly); + EXhalbtcoutsrc_init_coex_dm(&GLBtCoexist); +} + +void hal_btcoex_IpsNotify(PADAPTER padapter, u8 type) +{ + EXhalbtcoutsrc_ips_notify(&GLBtCoexist, type); +} + +void hal_btcoex_LpsNotify(PADAPTER padapter, u8 type) +{ + EXhalbtcoutsrc_lps_notify(&GLBtCoexist, type); +} + +void hal_btcoex_ScanNotify(PADAPTER padapter, u8 type) +{ + EXhalbtcoutsrc_scan_notify(&GLBtCoexist, type); +} + +void hal_btcoex_ConnectNotify(PADAPTER padapter, u8 action) +{ + EXhalbtcoutsrc_connect_notify(&GLBtCoexist, action); +} + +void hal_btcoex_MediaStatusNotify(PADAPTER padapter, u8 mediaStatus) +{ + EXhalbtcoutsrc_media_status_notify(&GLBtCoexist, mediaStatus); +} + +void hal_btcoex_SpecialPacketNotify(PADAPTER padapter, u8 pktType) +{ + EXhalbtcoutsrc_specific_packet_notify(&GLBtCoexist, pktType); +} + +void hal_btcoex_IQKNotify(PADAPTER padapter, u8 state) +{ + GLBtcWiFiInIQKState = state; +} + +void hal_btcoex_BtInfoNotify(PADAPTER padapter, u8 length, u8 *tmpBuf) +{ + if (GLBtcWiFiInIQKState == _TRUE) + return; + + EXhalbtcoutsrc_bt_info_notify(&GLBtCoexist, tmpBuf, length); +} + +void hal_btcoex_BtMpRptNotify(PADAPTER padapter, u8 length, u8 *tmpBuf) +{ + u8 extid, status, len, seq; + + + if (!GLBtcBtMpRptWait) + return; + + if ((length < 3) || (!tmpBuf)) + return; + + extid = tmpBuf[0]; + /* not response from BT FW then exit*/ + switch (extid) { + case C2H_WIFI_FW_ACTIVE_RSP: + GLBtcBtMpRptWiFiOK = 1; + return; + + case C2H_TRIG_BY_BT_FW: + _cancel_timer_ex(&GLBtcBtMpOperTimer); + GLBtcBtMpRptWait = 0; + GLBtcBtMpRptBTOK = 1; + break; + + default: + return; + } + + status = tmpBuf[1] & 0xF; + len = length - 3; + seq = tmpBuf[2] >> 4; + + GLBtcBtMpRptSeq = seq; + GLBtcBtMpRptStatus = status; + _rtw_memcpy(GLBtcBtMpRptRsp, tmpBuf + 3, len); + GLBtcBtMpRptRspSize = len; + _rtw_up_sema(&GLBtcBtMpRptSema); +} + +void hal_btcoex_SuspendNotify(PADAPTER padapter, u8 state) +{ + switch (state) { + case BTCOEX_SUSPEND_STATE_SUSPEND: + EXhalbtcoutsrc_pnp_notify(&GLBtCoexist, BTC_WIFI_PNP_SLEEP); + break; + case BTCOEX_SUSPEND_STATE_SUSPEND_KEEP_ANT: + /* should switch to "#if 1" once all ICs' coex. revision are upgraded to support the KEEP_ANT case */ +#if 0 + EXhalbtcoutsrc_pnp_notify(&GLBtCoexist, BTC_WIFI_PNP_SLEEP_KEEP_ANT); +#else + EXhalbtcoutsrc_pnp_notify(&GLBtCoexist, BTC_WIFI_PNP_SLEEP); + EXhalbtcoutsrc_pnp_notify(&GLBtCoexist, BTC_WIFI_PNP_SLEEP_KEEP_ANT); +#endif + break; + case BTCOEX_SUSPEND_STATE_RESUME: + EXhalbtcoutsrc_pnp_notify(&GLBtCoexist, BTC_WIFI_PNP_WAKE_UP); + break; + } +} + +void hal_btcoex_HaltNotify(PADAPTER padapter, u8 do_halt) +{ + if (do_halt == 1) + EXhalbtcoutsrc_halt_notify(&GLBtCoexist); + + GLBtCoexist.bBinded = _FALSE; + GLBtCoexist.Adapter = NULL; +} + +void hal_btcoex_SwitchBtTRxMask(PADAPTER padapter) +{ + EXhalbtcoutsrc_SwitchBtTRxMask(&GLBtCoexist); +} + +void hal_btcoex_Hanlder(PADAPTER padapter) +{ + u32 bt_patch_ver; + + EXhalbtcoutsrc_periodical(&GLBtCoexist); + + if (GLBtCoexist.bt_info.bt_get_fw_ver == 0) { + GLBtCoexist.btc_get(&GLBtCoexist, BTC_GET_U4_BT_PATCH_VER, &bt_patch_ver); + GLBtCoexist.bt_info.bt_get_fw_ver = bt_patch_ver; + } +} + +s32 hal_btcoex_IsBTCoexRejectAMPDU(PADAPTER padapter) +{ + return (s32)GLBtCoexist.bt_info.reject_agg_pkt; +} + +s32 hal_btcoex_IsBTCoexCtrlAMPDUSize(PADAPTER padapter) +{ + return (s32)GLBtCoexist.bt_info.bt_ctrl_agg_buf_size; +} + +u32 hal_btcoex_GetAMPDUSize(PADAPTER padapter) +{ + return (u32)GLBtCoexist.bt_info.agg_buf_size; +} + +void hal_btcoex_SetManualControl(PADAPTER padapter, u8 bmanual) +{ + GLBtCoexist.manual_control = bmanual; +} + +u8 hal_btcoex_1Ant(PADAPTER padapter) +{ + if (hal_btcoex_IsBtExist(padapter) == _FALSE) + return _FALSE; + + if (GLBtCoexist.board_info.btdm_ant_num == 1) + return _TRUE; + + return _FALSE; +} + +u8 hal_btcoex_IsBtControlLps(PADAPTER padapter) +{ + if (GLBtCoexist.bdontenterLPS == _TRUE) + return _TRUE; + + if (hal_btcoex_IsBtExist(padapter) == _FALSE) + return _FALSE; + + if (GLBtCoexist.bt_info.bt_disabled) + return _FALSE; + + if (GLBtCoexist.bt_info.bt_ctrl_lps) + return _TRUE; + + return _FALSE; +} + +u8 hal_btcoex_IsLpsOn(PADAPTER padapter) +{ + if (GLBtCoexist.bdontenterLPS == _TRUE) + return _FALSE; + + if (hal_btcoex_IsBtExist(padapter) == _FALSE) + return _FALSE; + + if (GLBtCoexist.bt_info.bt_disabled) + return _FALSE; + + if (GLBtCoexist.bt_info.bt_lps_on) + return _TRUE; + + return _FALSE; +} + +u8 hal_btcoex_RpwmVal(PADAPTER padapter) +{ + return GLBtCoexist.bt_info.rpwm_val; +} + +u8 hal_btcoex_LpsVal(PADAPTER padapter) +{ + return GLBtCoexist.bt_info.lps_val; +} + +u32 hal_btcoex_GetRaMask(PADAPTER padapter) +{ + if (!hal_btcoex_IsBtExist(padapter)) + return 0; + + if (GLBtCoexist.bt_info.bt_disabled) + return 0; + + /* Modify by YiWei , suggest by Cosa and Jenyu + * Remove the limit antenna number , because 2 antenna case (ex: 8192eu)also want to get BT coex report rate mask. + */ + /*if (GLBtCoexist.board_info.btdm_ant_num != 1) + return 0;*/ + + return GLBtCoexist.bt_info.ra_mask; +} + +void hal_btcoex_RecordPwrMode(PADAPTER padapter, u8 *pCmdBuf, u8 cmdLen) +{ + + _rtw_memcpy(GLBtCoexist.pwrModeVal, pCmdBuf, cmdLen); +} + +void hal_btcoex_DisplayBtCoexInfo(PADAPTER padapter, u8 *pbuf, u32 bufsize) +{ + PBTCDBGINFO pinfo; + + + pinfo = &GLBtcDbgInfo; + DBG_BT_INFO_INIT(pinfo, pbuf, bufsize); + EXhalbtcoutsrc_DisplayBtCoexInfo(&GLBtCoexist); + DBG_BT_INFO_INIT(pinfo, NULL, 0); +} + +void hal_btcoex_SetDBG(PADAPTER padapter, u32 *pDbgModule) +{ + u32 i; + + + if (NULL == pDbgModule) + return; + + for (i = 0; i < COMP_MAX; i++) + GLBtcDbgType[i] = pDbgModule[i]; +} + +u32 hal_btcoex_GetDBG(PADAPTER padapter, u8 *pStrBuf, u32 bufSize) +{ + s32 count; + u8 *pstr; + u32 leftSize; + + + if ((NULL == pStrBuf) || (0 == bufSize)) + return 0; + + count = 0; + pstr = pStrBuf; + leftSize = bufSize; + /* RTW_INFO(FUNC_ADPT_FMT ": bufsize=%d\n", FUNC_ADPT_ARG(padapter), bufSize); */ + + count = rtw_sprintf(pstr, leftSize, "#define DBG\t%d\n", DBG); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + + count = rtw_sprintf(pstr, leftSize, "BTCOEX Debug Setting:\n"); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + + count = rtw_sprintf(pstr, leftSize, + "COMP_COEX: 0x%08X\n\n", + GLBtcDbgType[COMP_COEX]); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + +#if 0 + count = rtw_sprintf(pstr, leftSize, "INTERFACE Debug Setting Definition:\n"); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + count = rtw_sprintf(pstr, leftSize, "\tbit[0]=%d for INTF_INIT\n", + GLBtcDbgType[BTC_MSG_INTERFACE] & INTF_INIT ? 1 : 0); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + count = rtw_sprintf(pstr, leftSize, "\tbit[2]=%d for INTF_NOTIFY\n\n", + GLBtcDbgType[BTC_MSG_INTERFACE] & INTF_NOTIFY ? 1 : 0); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + + count = rtw_sprintf(pstr, leftSize, "ALGORITHM Debug Setting Definition:\n"); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + count = rtw_sprintf(pstr, leftSize, "\tbit[0]=%d for BT_RSSI_STATE\n", + GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_BT_RSSI_STATE ? 1 : 0); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + count = rtw_sprintf(pstr, leftSize, "\tbit[1]=%d for WIFI_RSSI_STATE\n", + GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_WIFI_RSSI_STATE ? 1 : 0); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + count = rtw_sprintf(pstr, leftSize, "\tbit[2]=%d for BT_MONITOR\n", + GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_BT_MONITOR ? 1 : 0); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + count = rtw_sprintf(pstr, leftSize, "\tbit[3]=%d for TRACE\n", + GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE ? 1 : 0); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + count = rtw_sprintf(pstr, leftSize, "\tbit[4]=%d for TRACE_FW\n", + GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_FW ? 1 : 0); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + count = rtw_sprintf(pstr, leftSize, "\tbit[5]=%d for TRACE_FW_DETAIL\n", + GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_FW_DETAIL ? 1 : 0); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + count = rtw_sprintf(pstr, leftSize, "\tbit[6]=%d for TRACE_FW_EXEC\n", + GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_FW_EXEC ? 1 : 0); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + count = rtw_sprintf(pstr, leftSize, "\tbit[7]=%d for TRACE_SW\n", + GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_SW ? 1 : 0); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + count = rtw_sprintf(pstr, leftSize, "\tbit[8]=%d for TRACE_SW_DETAIL\n", + GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_SW_DETAIL ? 1 : 0); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; + count = rtw_sprintf(pstr, leftSize, "\tbit[9]=%d for TRACE_SW_EXEC\n", + GLBtcDbgType[BTC_MSG_ALGORITHM] & ALGO_TRACE_SW_EXEC ? 1 : 0); + if ((count < 0) || (count >= leftSize)) + goto exit; + pstr += count; + leftSize -= count; +#endif + +exit: + count = pstr - pStrBuf; + /* RTW_INFO(FUNC_ADPT_FMT ": usedsize=%d\n", FUNC_ADPT_ARG(padapter), count); */ + + return count; +} + +u8 hal_btcoex_IncreaseScanDeviceNum(PADAPTER padapter) +{ + if (!hal_btcoex_IsBtExist(padapter)) + return _FALSE; + + if (GLBtCoexist.bt_info.increase_scan_dev_num) + return _TRUE; + + return _FALSE; +} + +u8 hal_btcoex_IsBtLinkExist(PADAPTER padapter) +{ + if (GLBtCoexist.bt_link_info.bt_link_exist) + return _TRUE; + + return _FALSE; +} + +void hal_btcoex_SetBtPatchVersion(PADAPTER padapter, u16 btHciVer, u16 btPatchVer) +{ + EXhalbtcoutsrc_SetBtPatchVersion(btHciVer, btPatchVer); +} + +void hal_btcoex_SetHciVersion(PADAPTER padapter, u16 hciVersion) +{ + EXhalbtcoutsrc_SetHciVersion(hciVersion); +} + +void hal_btcoex_StackUpdateProfileInfo(void) +{ + EXhalbtcoutsrc_StackUpdateProfileInfo(); +} + +void hal_btcoex_pta_off_on_notify(PADAPTER padapter, u8 bBTON) +{ + ex_halbtcoutsrc_pta_off_on_notify(&GLBtCoexist, bBTON); +} + +/* + * Description: + * Setting BT coex antenna isolation type . + * coex mechanisn/ spital stream/ best throughput + * anttype = 0 , PSTDMA / 2SS / 0.5T , bad isolation , WiFi/BT ANT Distance<15cm , (<20dB) for 2,3 antenna + * anttype = 1 , PSTDMA / 1SS / 0.5T , normal isolaiton , 50cm>WiFi/BT ANT Distance>15cm , (>20dB) for 2 antenna + * anttype = 2 , TDMA / 2SS / T , normal isolaiton , 50cm>WiFi/BT ANT Distance>15cm , (>20dB) for 3 antenna + * anttype = 3 , no TDMA / 1SS / 0.5T , good isolation , WiFi/BT ANT Distance >50cm , (>40dB) for 2 antenna + * anttype = 4 , no TDMA / 2SS / T , good isolation , WiFi/BT ANT Distance >50cm , (>40dB) for 3 antenna + * wifi only throughput ~ T + * wifi/BT share one antenna with SPDT + */ +void hal_btcoex_SetAntIsolationType(PADAPTER padapter, u8 anttype) +{ + PHAL_DATA_TYPE pHalData; + PBTC_COEXIST pBtCoexist = &GLBtCoexist; + + /*RTW_INFO("####%s , anttype = %d , %d\n" , __func__ , anttype , __LINE__); */ + pHalData = GET_HAL_DATA(padapter); + + + pHalData->bt_coexist.btAntisolation = anttype; + + switch (pHalData->bt_coexist.btAntisolation) { + case 0: + pBtCoexist->board_info.ant_type = (u1Byte)BTC_ANT_TYPE_0; + break; + case 1: + pBtCoexist->board_info.ant_type = (u1Byte)BTC_ANT_TYPE_1; + break; + case 2: + pBtCoexist->board_info.ant_type = (u1Byte)BTC_ANT_TYPE_2; + break; + case 3: + pBtCoexist->board_info.ant_type = (u1Byte)BTC_ANT_TYPE_3; + break; + case 4: + pBtCoexist->board_info.ant_type = (u1Byte)BTC_ANT_TYPE_4; + break; + } + +} + +#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE +int +hal_btcoex_ParseAntIsolationConfigFile( + PADAPTER Adapter, + char *buffer +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + u32 i = 0 , j = 0; + char *szLine , *ptmp; + int rtStatus = _SUCCESS; + char param_value_string[10]; + u8 param_value; + u8 anttype = 4; + + u8 ant_num = 3 , ant_distance = 50 , rfe_type = 1; + + typedef struct ant_isolation { + char *param_name; /* antenna isolation config parameter name */ + u8 *value; /* antenna isolation config parameter value */ + } ANT_ISOLATION; + + ANT_ISOLATION ant_isolation_param[] = { + {"ANT_NUMBER" , &ant_num}, + {"ANT_DISTANCE" , &ant_distance}, + {"RFE_TYPE" , &rfe_type}, + {NULL , 0} + }; + + + + /* RTW_INFO("===>Hal_ParseAntIsolationConfigFile()\n" ); */ + + ptmp = buffer; + for (szLine = GetLineFromBuffer(ptmp) ; szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { + /* skip comment */ + if (IsCommentString(szLine)) + continue; + + /* RTW_INFO("%s : szLine = %s , strlen(szLine) = %d\n" , __func__ , szLine , strlen(szLine));*/ + for (j = 0 ; ant_isolation_param[j].param_name != NULL ; j++) { + if (strstr(szLine , ant_isolation_param[j].param_name) != NULL) { + i = 0; + while (i < strlen(szLine)) { + if (szLine[i] != '"') + ++i; + else { + /* skip only has one " */ + if (strpbrk(szLine , "\"") == strrchr(szLine , '"')) { + RTW_INFO("Fail to parse parameters , format error!\n"); + break; + } + _rtw_memset((PVOID)param_value_string , 0 , 10); + if (!ParseQualifiedString(szLine , &i , param_value_string , '"' , '"')) { + RTW_INFO("Fail to parse parameters\n"); + return _FAIL; + } else if (!GetU1ByteIntegerFromStringInDecimal(param_value_string , ant_isolation_param[j].value)) + RTW_INFO("Fail to GetU1ByteIntegerFromStringInDecimal\n"); + + break; + } + } + } + } + } + + /* YiWei 20140716 , for BT coex antenna isolation control */ + /* rfe_type = 0 was SPDT , rfe_type = 1 was coupler */ + if (ant_num == 3 && ant_distance >= 50) + anttype = 3; + else if (ant_num == 2 && ant_distance >= 50 && rfe_type == 1) + anttype = 2; + else if (ant_num == 3 && ant_distance >= 15 && ant_distance < 50) + anttype = 2; + else if (ant_num == 2 && ant_distance >= 15 && ant_distance < 50 && rfe_type == 1) + anttype = 2; + else if ((ant_num == 2 && ant_distance < 15 && rfe_type == 1) || (ant_num == 3 && ant_distance < 15)) + anttype = 1; + else if (ant_num == 2 && rfe_type == 0) + anttype = 0; + else + anttype = 0; + + hal_btcoex_SetAntIsolationType(Adapter, anttype); + + RTW_INFO("%s : ant_num = %d\n" , __func__ , ant_num); + RTW_INFO("%s : ant_distance = %d\n" , __func__ , ant_distance); + RTW_INFO("%s : rfe_type = %d\n" , __func__ , rfe_type); + /* RTW_INFO("<===Hal_ParseAntIsolationConfigFile()\n"); */ + return rtStatus; +} + + +int +hal_btcoex_AntIsolationConfig_ParaFile( + IN PADAPTER Adapter, + IN char *pFileName +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + int rlen = 0 , rtStatus = _FAIL; + + _rtw_memset(pHalData->para_file_buf , 0 , MAX_PARA_FILE_BUF_LEN); + + rtw_get_phy_file_path(Adapter, pFileName); + if (rtw_is_file_readable(rtw_phy_para_file_path) == _TRUE) { + rlen = rtw_retrieve_from_file(rtw_phy_para_file_path, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); + if (rlen > 0) + rtStatus = _SUCCESS; + } + + + if (rtStatus == _SUCCESS) { + /*RTW_INFO("%s(): read %s ok\n", __func__ , pFileName);*/ + rtStatus = hal_btcoex_ParseAntIsolationConfigFile(Adapter , pHalData->para_file_buf); + } else + RTW_INFO("%s(): No File %s, Load from *** Array!\n" , __func__ , pFileName); + + return rtStatus; +} +#endif /* CONFIG_LOAD_PHY_PARA_FROM_FILE */ + +u16 hal_btcoex_btreg_read(PADAPTER padapter, u8 type, u16 addr, u32 *data) +{ + u16 ret = 0; + + halbtcoutsrc_LeaveLowPower(&GLBtCoexist); + + ret = halbtcoutsrc_GetBtReg_with_status(&GLBtCoexist, type, addr, data); + + halbtcoutsrc_NormalLowPower(&GLBtCoexist); + + return ret; +} + +u16 hal_btcoex_btreg_write(PADAPTER padapter, u8 type, u16 addr, u16 val) +{ + u16 ret = 0; + + halbtcoutsrc_LeaveLowPower(&GLBtCoexist); + + ret = halbtcoutsrc_SetBtReg(&GLBtCoexist, type, addr, val); + + halbtcoutsrc_NormalLowPower(&GLBtCoexist); + + return ret; +} + +void hal_btcoex_set_rfe_type(u8 type) +{ + EXhalbtcoutsrc_set_rfe_type(type); +} +void hal_btcoex_switchband_notify(u8 under_scan, u8 band_type) +{ + switch (band_type) { + case BAND_ON_2_4G: + if (under_scan) + EXhalbtcoutsrc_switchband_notify(&GLBtCoexist, BTC_SWITCH_TO_24G); + else + EXhalbtcoutsrc_switchband_notify(&GLBtCoexist, BTC_SWITCH_TO_24G_NOFORSCAN); + break; + case BAND_ON_5G: + EXhalbtcoutsrc_switchband_notify(&GLBtCoexist, BTC_SWITCH_TO_5G); + break; + default: + RTW_INFO("[BTCOEX] unkown switch band type\n"); + break; + } +} +#endif /* CONFIG_BT_COEXIST */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_btcoex_wifionly.c b/linux-bsp/drivers/rtl8188eus/hal/hal_btcoex_wifionly.c new file mode 100644 index 0000000..861bcfb --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_btcoex_wifionly.c @@ -0,0 +1,156 @@ +#include "btc/mp_precomp.h" +#include <hal_btcoex_wifionly.h> + +struct wifi_only_cfg GLBtCoexistWifiOnly; + +void halwifionly_write1byte(PVOID pwifionlyContext, u32 RegAddr, u8 Data) +{ + struct wifi_only_cfg *pwifionlycfg = (struct wifi_only_cfg *)pwifionlyContext; + PADAPTER Adapter = pwifionlycfg->Adapter; + + rtw_write8(Adapter, RegAddr, Data); +} + +void halwifionly_write2byte(PVOID pwifionlyContext, u32 RegAddr, u16 Data) +{ + struct wifi_only_cfg *pwifionlycfg = (struct wifi_only_cfg *)pwifionlyContext; + PADAPTER Adapter = pwifionlycfg->Adapter; + + rtw_write16(Adapter, RegAddr, Data); +} + +void halwifionly_write4byte(PVOID pwifionlyContext, u32 RegAddr, u32 Data) +{ + struct wifi_only_cfg *pwifionlycfg = (struct wifi_only_cfg *)pwifionlyContext; + PADAPTER Adapter = pwifionlycfg->Adapter; + + rtw_write32(Adapter, RegAddr, Data); +} + +u8 halwifionly_read1byte(PVOID pwifionlyContext, u32 RegAddr) +{ + struct wifi_only_cfg *pwifionlycfg = (struct wifi_only_cfg *)pwifionlyContext; + PADAPTER Adapter = pwifionlycfg->Adapter; + + return rtw_read8(Adapter, RegAddr); +} + +u16 halwifionly_read2byte(PVOID pwifionlyContext, u32 RegAddr) +{ + struct wifi_only_cfg *pwifionlycfg = (struct wifi_only_cfg *)pwifionlyContext; + PADAPTER Adapter = pwifionlycfg->Adapter; + + return rtw_read16(Adapter, RegAddr); +} + +u32 halwifionly_read4byte(PVOID pwifionlyContext, u32 RegAddr) +{ + struct wifi_only_cfg *pwifionlycfg = (struct wifi_only_cfg *)pwifionlyContext; + PADAPTER Adapter = pwifionlycfg->Adapter; + + return rtw_read32(Adapter, RegAddr); +} + +void halwifionly_bitmaskwrite1byte(PVOID pwifionlyContext, u32 regAddr, u8 bitMask, u8 data) +{ + u8 originalValue, bitShift = 0; + u8 i; + + struct wifi_only_cfg *pwifionlycfg = (struct wifi_only_cfg *)pwifionlyContext; + PADAPTER Adapter = pwifionlycfg->Adapter; + + if (bitMask != 0xff) { + originalValue = rtw_read8(Adapter, regAddr); + for (i = 0; i <= 7; i++) { + if ((bitMask >> i) & 0x1) + break; + } + bitShift = i; + data = ((originalValue) & (~bitMask)) | (((data << bitShift)) & bitMask); + } + rtw_write8(Adapter, regAddr, data); +} + +void halwifionly_phy_set_rf_reg(PVOID pwifionlyContext, u8 eRFPath, u32 RegAddr, u32 BitMask, u32 Data) +{ + struct wifi_only_cfg *pwifionlycfg = (struct wifi_only_cfg *)pwifionlyContext; + PADAPTER Adapter = pwifionlycfg->Adapter; + + phy_set_rf_reg(Adapter, eRFPath, RegAddr, BitMask, Data); +} + +void halwifionly_phy_set_bb_reg(PVOID pwifionlyContext, u32 RegAddr, u32 BitMask, u32 Data) +{ + struct wifi_only_cfg *pwifionlycfg = (struct wifi_only_cfg *)pwifionlyContext; + PADAPTER Adapter = pwifionlycfg->Adapter; + + phy_set_bb_reg(Adapter, RegAddr, BitMask, Data); +} + +void hal_btcoex_wifionly_switchband_notify(PADAPTER padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + u8 is_5g = _FALSE; + + if (pHalData->current_band_type == BAND_ON_5G) + is_5g = _TRUE; + + if (IS_HARDWARE_TYPE_8822B(padapter)) + ex_hal8822b_wifi_only_switchbandnotify(&GLBtCoexistWifiOnly, is_5g); + else if (IS_HARDWARE_TYPE_8821C(padapter)) + ex_hal8821c_wifi_only_switchbandnotify(&GLBtCoexistWifiOnly, is_5g); +} + +void hal_btcoex_wifionly_scan_notify(PADAPTER padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + u8 is_5g = _FALSE; + + if (pHalData->current_band_type == BAND_ON_5G) + is_5g = _TRUE; + + if (IS_HARDWARE_TYPE_8822B(padapter)) + ex_hal8822b_wifi_only_scannotify(&GLBtCoexistWifiOnly, is_5g); + else if (IS_HARDWARE_TYPE_8821C(padapter)) + ex_hal8821c_wifi_only_scannotify(&GLBtCoexistWifiOnly, is_5g); +} + +void hal_btcoex_wifionly_hw_config(PADAPTER padapter) +{ + struct wifi_only_cfg *pwifionlycfg = &GLBtCoexistWifiOnly; + + if (IS_HARDWARE_TYPE_8723B(padapter)) + ex_hal8723b_wifi_only_hw_config(pwifionlycfg); + else if (IS_HARDWARE_TYPE_8822B(padapter)) + ex_hal8822b_wifi_only_hw_config(pwifionlycfg); + else if (IS_HARDWARE_TYPE_8821C(padapter)) + ex_hal8821c_wifi_only_hw_config(pwifionlycfg); +} + +void hal_btcoex_wifionly_initlizevariables(PADAPTER padapter) +{ + struct wifi_only_cfg *pwifionlycfg = &GLBtCoexistWifiOnly; + struct wifi_only_haldata *pwifionly_haldata = &pwifionlycfg->haldata_info; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + _rtw_memset(&GLBtCoexistWifiOnly, 0, sizeof(GLBtCoexistWifiOnly)); + + pwifionlycfg->Adapter = padapter; + +#ifdef CONFIG_PCI_HCI + pwifionlycfg->chip_interface = WIFIONLY_INTF_PCI; +#elif defined(CONFIG_USB_HCI) + pwifionlycfg->chip_interface = WIFIONLY_INTF_USB; +#elif defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + pwifionlycfg->chip_interface = WIFIONLY_INTF_SDIO; +#else + pwifionlycfg->chip_interface = WIFIONLY_INTF_UNKNOWN; +#endif + + pwifionly_haldata->customer_id = CUSTOMER_NORMAL; + pwifionly_haldata->efuse_pg_antnum = pHalData->EEPROMBluetoothAntNum; + pwifionly_haldata->efuse_pg_antpath = pHalData->ant_path; + pwifionly_haldata->rfe_type = pHalData->rfe_type; + pwifionly_haldata->ant_div_cfg = pHalData->AntDivCfg; +} + diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_com.c b/linux-bsp/drivers/rtl8188eus/hal/hal_com.c new file mode 100644 index 0000000..61c2b98 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_com.c @@ -0,0 +1,11422 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _HAL_COM_C_ + +#include <drv_types.h> +#include "hal_com_h2c.h" + +#include "hal_data.h" + +#ifdef RTW_HALMAC +#include "../../hal/hal_halmac.h" +#endif + +void rtw_dump_fw_info(void *sel, _adapter *adapter) +{ + HAL_DATA_TYPE *hal_data = NULL; + + if (!adapter) + return; + + hal_data = GET_HAL_DATA(adapter); + if (adapter->bFWReady) + RTW_PRINT_SEL(sel, "FW VER -%d.%d\n", hal_data->firmware_version, hal_data->firmware_sub_version); + else + RTW_PRINT_SEL(sel, "FW not ready\n"); +} + +/* #define CONFIG_GTK_OL_DBG */ + +/*#define DBG_SEC_CAM_MOVE*/ +#ifdef DBG_SEC_CAM_MOVE +void rtw_hal_move_sta_gk_to_dk(_adapter *adapter) +{ + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + int cam_id, index = 0; + u8 *addr = NULL; + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) + return; + + addr = get_bssid(pmlmepriv); + + if (addr == NULL) { + RTW_INFO("%s: get bssid MAC addr fail!!\n", __func__); + return; + } + + rtw_clean_dk_section(adapter); + + do { + cam_id = rtw_camid_search(adapter, addr, index, 1); + + if (cam_id == -1) + RTW_INFO("%s: cam_id: %d, key_id:%d\n", __func__, cam_id, index); + else + rtw_sec_cam_swap(adapter, cam_id, index); + + index++; + } while (index < 4); + +} + +void rtw_hal_read_sta_dk_key(_adapter *adapter, u8 key_id) +{ + struct security_priv *psecuritypriv = &adapter->securitypriv; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + u8 get_key[16]; + + _rtw_memset(get_key, 0, sizeof(get_key)); + + if (key_id > 4) { + RTW_INFO("%s [ERROR] gtk_keyindex:%d invalid\n", __func__, key_id); + rtw_warn_on(1); + return; + } + rtw_sec_read_cam_ent(adapter, key_id, NULL, NULL, get_key); + + /*update key into related sw variable*/ + _enter_critical_bh(&cam_ctl->lock, &irqL); + if (_rtw_camid_is_gk(adapter, key_id)) { + RTW_INFO("[HW KEY] -Key-id:%d "KEY_FMT"\n", key_id, KEY_ARG(get_key)); + RTW_INFO("[cam_cache KEY] - Key-id:%d "KEY_FMT"\n", key_id, KEY_ARG(&dvobj->cam_cache[key_id].key)); + } + _exit_critical_bh(&cam_ctl->lock, &irqL); + +} +#endif + + +#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE + char rtw_phy_para_file_path[PATH_LENGTH_MAX]; +#endif + +void dump_chip_info(HAL_VERSION ChipVersion) +{ + int cnt = 0; + u8 buf[128] = {0}; + + if (IS_8188E(ChipVersion)) + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8188E_"); + else if (IS_8188F(ChipVersion)) + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8188F_"); + else if (IS_8812_SERIES(ChipVersion)) + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8812_"); + else if (IS_8192E(ChipVersion)) + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8192E_"); + else if (IS_8821_SERIES(ChipVersion)) + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8821_"); + else if (IS_8723B_SERIES(ChipVersion)) + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8723B_"); + else if (IS_8703B_SERIES(ChipVersion)) + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8703B_"); + else if (IS_8723D_SERIES(ChipVersion)) + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8723D_"); + else if (IS_8814A_SERIES(ChipVersion)) + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8814A_"); + else if (IS_8822B_SERIES(ChipVersion)) + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8822B_"); + else if (IS_8821C_SERIES(ChipVersion)) + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8821C_"); + else + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_UNKNOWN_"); + + cnt += sprintf((buf + cnt), "%s_", IS_NORMAL_CHIP(ChipVersion) ? "Normal_Chip" : "Test_Chip"); + if (IS_CHIP_VENDOR_TSMC(ChipVersion)) + cnt += sprintf((buf + cnt), "%s_", "TSMC"); + else if (IS_CHIP_VENDOR_UMC(ChipVersion)) + cnt += sprintf((buf + cnt), "%s_", "UMC"); + else if (IS_CHIP_VENDOR_SMIC(ChipVersion)) + cnt += sprintf((buf + cnt), "%s_", "SMIC"); + + if (IS_A_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "A_CUT_"); + else if (IS_B_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "B_CUT_"); + else if (IS_C_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "C_CUT_"); + else if (IS_D_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "D_CUT_"); + else if (IS_E_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "E_CUT_"); + else if (IS_F_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "F_CUT_"); + else if (IS_I_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "I_CUT_"); + else if (IS_J_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "J_CUT_"); + else if (IS_K_CUT(ChipVersion)) + cnt += sprintf((buf + cnt), "K_CUT_"); + else + cnt += sprintf((buf + cnt), "UNKNOWN_CUT(%d)_", ChipVersion.CUTVersion); + + if (IS_1T1R(ChipVersion)) + cnt += sprintf((buf + cnt), "1T1R_"); + else if (IS_1T2R(ChipVersion)) + cnt += sprintf((buf + cnt), "1T2R_"); + else if (IS_2T2R(ChipVersion)) + cnt += sprintf((buf + cnt), "2T2R_"); + else if (IS_3T3R(ChipVersion)) + cnt += sprintf((buf + cnt), "3T3R_"); + else if (IS_3T4R(ChipVersion)) + cnt += sprintf((buf + cnt), "3T4R_"); + else if (IS_4T4R(ChipVersion)) + cnt += sprintf((buf + cnt), "4T4R_"); + else + cnt += sprintf((buf + cnt), "UNKNOWN_RFTYPE(%d)_", ChipVersion.RFType); + + cnt += sprintf((buf + cnt), "RomVer(%d)\n", ChipVersion.ROMVer); + + RTW_INFO("%s", buf); +} +void rtw_hal_config_rftype(PADAPTER padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + if (IS_1T1R(pHalData->version_id)) { + pHalData->rf_type = RF_1T1R; + pHalData->NumTotalRFPath = 1; + } else if (IS_2T2R(pHalData->version_id)) { + pHalData->rf_type = RF_2T2R; + pHalData->NumTotalRFPath = 2; + } else if (IS_1T2R(pHalData->version_id)) { + pHalData->rf_type = RF_1T2R; + pHalData->NumTotalRFPath = 2; + } else if (IS_3T3R(pHalData->version_id)) { + pHalData->rf_type = RF_3T3R; + pHalData->NumTotalRFPath = 3; + } else if (IS_4T4R(pHalData->version_id)) { + pHalData->rf_type = RF_4T4R; + pHalData->NumTotalRFPath = 4; + } else { + pHalData->rf_type = RF_1T1R; + pHalData->NumTotalRFPath = 1; + } + + RTW_INFO("%s RF_Type is %d TotalTxPath is %d\n", __FUNCTION__, pHalData->rf_type, pHalData->NumTotalRFPath); +} + +#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80 + +/* + * Description: + * Use hardware(efuse), driver parameter(registry) and default channel plan + * to decide which one should be used. + * + * Parameters: + * padapter pointer of adapter + * hw_alpha2 country code from HW (efuse/eeprom/mapfile) + * hw_chplan channel plan from HW (efuse/eeprom/mapfile) + * BIT[7] software configure mode; 0:Enable, 1:disable + * BIT[6:0] Channel Plan + * sw_alpha2 country code from HW (registry/module param) + * sw_chplan channel plan from SW (registry/module param) + * def_chplan channel plan used when HW/SW both invalid + * AutoLoadFail efuse autoload fail or not + * + * Return: + * Final channel plan decision + * + */ +u8 hal_com_config_channel_plan( + IN PADAPTER padapter, + IN char *hw_alpha2, + IN u8 hw_chplan, + IN char *sw_alpha2, + IN u8 sw_chplan, + IN u8 def_chplan, + IN BOOLEAN AutoLoadFail +) +{ + PHAL_DATA_TYPE pHalData; + u8 force_hw_chplan = _FALSE; + int chplan = -1; + const struct country_chplan *country_ent = NULL, *ent; + + pHalData = GET_HAL_DATA(padapter); + + /* treat 0xFF as invalid value, bypass hw_chplan & force_hw_chplan parsing */ + if (hw_chplan == 0xFF) + goto chk_hw_country_code; + + if (AutoLoadFail == _TRUE) + goto chk_sw_config; + +#ifndef CONFIG_FORCE_SW_CHANNEL_PLAN + if (hw_chplan & EEPROM_CHANNEL_PLAN_BY_HW_MASK) + force_hw_chplan = _TRUE; +#endif + + hw_chplan &= (~EEPROM_CHANNEL_PLAN_BY_HW_MASK); + +chk_hw_country_code: + if (hw_alpha2 && !IS_ALPHA2_NO_SPECIFIED(hw_alpha2)) { + ent = rtw_get_chplan_from_country(hw_alpha2); + if (ent) { + /* get chplan from hw country code, by pass hw chplan setting */ + country_ent = ent; + chplan = ent->chplan; + goto chk_sw_config; + } else + RTW_PRINT("%s unsupported hw_alpha2:\"%c%c\"\n", __func__, hw_alpha2[0], hw_alpha2[1]); + } + + if (rtw_is_channel_plan_valid(hw_chplan)) + chplan = hw_chplan; + else if (force_hw_chplan == _TRUE) { + RTW_PRINT("%s unsupported hw_chplan:0x%02X\n", __func__, hw_chplan); + /* hw infomaton invalid, refer to sw information */ + force_hw_chplan = _FALSE; + } + +chk_sw_config: + if (force_hw_chplan == _TRUE) + goto done; + + if (sw_alpha2 && !IS_ALPHA2_NO_SPECIFIED(sw_alpha2)) { + ent = rtw_get_chplan_from_country(sw_alpha2); + if (ent) { + /* get chplan from sw country code, by pass sw chplan setting */ + country_ent = ent; + chplan = ent->chplan; + goto done; + } else + RTW_PRINT("%s unsupported sw_alpha2:\"%c%c\"\n", __func__, sw_alpha2[0], sw_alpha2[1]); + } + + if (rtw_is_channel_plan_valid(sw_chplan)) { + /* cancel hw_alpha2 because chplan is specified by sw_chplan*/ + country_ent = NULL; + chplan = sw_chplan; + } else if (sw_chplan != RTW_CHPLAN_MAX) + RTW_PRINT("%s unsupported sw_chplan:0x%02X\n", __func__, sw_chplan); + +done: + if (chplan == -1) { + RTW_PRINT("%s use def_chplan:0x%02X\n", __func__, def_chplan); + chplan = def_chplan; + } else if (country_ent) { + RTW_PRINT("%s country code:\"%c%c\" with chplan:0x%02X\n", __func__ + , country_ent->alpha2[0], country_ent->alpha2[1], country_ent->chplan); + } else + RTW_PRINT("%s chplan:0x%02X\n", __func__, chplan); + + padapter->mlmepriv.country_ent = country_ent; + pHalData->bDisableSWChannelPlan = force_hw_chplan; + + return chplan; +} + +BOOLEAN +HAL_IsLegalChannel( + IN PADAPTER Adapter, + IN u32 Channel +) +{ + BOOLEAN bLegalChannel = _TRUE; + + if (Channel > 14) { + if (is_supported_5g(Adapter->registrypriv.wireless_mode) == _FALSE) { + bLegalChannel = _FALSE; + RTW_INFO("Channel > 14 but wireless_mode do not support 5G\n"); + } + } else if ((Channel <= 14) && (Channel >= 1)) { + if (IsSupported24G(Adapter->registrypriv.wireless_mode) == _FALSE) { + bLegalChannel = _FALSE; + RTW_INFO("(Channel <= 14) && (Channel >=1) but wireless_mode do not support 2.4G\n"); + } + } else { + bLegalChannel = _FALSE; + RTW_INFO("Channel is Invalid !!!\n"); + } + + return bLegalChannel; +} + +u8 MRateToHwRate(u8 rate) +{ + u8 ret = DESC_RATE1M; + + switch (rate) { + case MGN_1M: + ret = DESC_RATE1M; + break; + case MGN_2M: + ret = DESC_RATE2M; + break; + case MGN_5_5M: + ret = DESC_RATE5_5M; + break; + case MGN_11M: + ret = DESC_RATE11M; + break; + case MGN_6M: + ret = DESC_RATE6M; + break; + case MGN_9M: + ret = DESC_RATE9M; + break; + case MGN_12M: + ret = DESC_RATE12M; + break; + case MGN_18M: + ret = DESC_RATE18M; + break; + case MGN_24M: + ret = DESC_RATE24M; + break; + case MGN_36M: + ret = DESC_RATE36M; + break; + case MGN_48M: + ret = DESC_RATE48M; + break; + case MGN_54M: + ret = DESC_RATE54M; + break; + + case MGN_MCS0: + ret = DESC_RATEMCS0; + break; + case MGN_MCS1: + ret = DESC_RATEMCS1; + break; + case MGN_MCS2: + ret = DESC_RATEMCS2; + break; + case MGN_MCS3: + ret = DESC_RATEMCS3; + break; + case MGN_MCS4: + ret = DESC_RATEMCS4; + break; + case MGN_MCS5: + ret = DESC_RATEMCS5; + break; + case MGN_MCS6: + ret = DESC_RATEMCS6; + break; + case MGN_MCS7: + ret = DESC_RATEMCS7; + break; + case MGN_MCS8: + ret = DESC_RATEMCS8; + break; + case MGN_MCS9: + ret = DESC_RATEMCS9; + break; + case MGN_MCS10: + ret = DESC_RATEMCS10; + break; + case MGN_MCS11: + ret = DESC_RATEMCS11; + break; + case MGN_MCS12: + ret = DESC_RATEMCS12; + break; + case MGN_MCS13: + ret = DESC_RATEMCS13; + break; + case MGN_MCS14: + ret = DESC_RATEMCS14; + break; + case MGN_MCS15: + ret = DESC_RATEMCS15; + break; + case MGN_MCS16: + ret = DESC_RATEMCS16; + break; + case MGN_MCS17: + ret = DESC_RATEMCS17; + break; + case MGN_MCS18: + ret = DESC_RATEMCS18; + break; + case MGN_MCS19: + ret = DESC_RATEMCS19; + break; + case MGN_MCS20: + ret = DESC_RATEMCS20; + break; + case MGN_MCS21: + ret = DESC_RATEMCS21; + break; + case MGN_MCS22: + ret = DESC_RATEMCS22; + break; + case MGN_MCS23: + ret = DESC_RATEMCS23; + break; + case MGN_MCS24: + ret = DESC_RATEMCS24; + break; + case MGN_MCS25: + ret = DESC_RATEMCS25; + break; + case MGN_MCS26: + ret = DESC_RATEMCS26; + break; + case MGN_MCS27: + ret = DESC_RATEMCS27; + break; + case MGN_MCS28: + ret = DESC_RATEMCS28; + break; + case MGN_MCS29: + ret = DESC_RATEMCS29; + break; + case MGN_MCS30: + ret = DESC_RATEMCS30; + break; + case MGN_MCS31: + ret = DESC_RATEMCS31; + break; + + case MGN_VHT1SS_MCS0: + ret = DESC_RATEVHTSS1MCS0; + break; + case MGN_VHT1SS_MCS1: + ret = DESC_RATEVHTSS1MCS1; + break; + case MGN_VHT1SS_MCS2: + ret = DESC_RATEVHTSS1MCS2; + break; + case MGN_VHT1SS_MCS3: + ret = DESC_RATEVHTSS1MCS3; + break; + case MGN_VHT1SS_MCS4: + ret = DESC_RATEVHTSS1MCS4; + break; + case MGN_VHT1SS_MCS5: + ret = DESC_RATEVHTSS1MCS5; + break; + case MGN_VHT1SS_MCS6: + ret = DESC_RATEVHTSS1MCS6; + break; + case MGN_VHT1SS_MCS7: + ret = DESC_RATEVHTSS1MCS7; + break; + case MGN_VHT1SS_MCS8: + ret = DESC_RATEVHTSS1MCS8; + break; + case MGN_VHT1SS_MCS9: + ret = DESC_RATEVHTSS1MCS9; + break; + case MGN_VHT2SS_MCS0: + ret = DESC_RATEVHTSS2MCS0; + break; + case MGN_VHT2SS_MCS1: + ret = DESC_RATEVHTSS2MCS1; + break; + case MGN_VHT2SS_MCS2: + ret = DESC_RATEVHTSS2MCS2; + break; + case MGN_VHT2SS_MCS3: + ret = DESC_RATEVHTSS2MCS3; + break; + case MGN_VHT2SS_MCS4: + ret = DESC_RATEVHTSS2MCS4; + break; + case MGN_VHT2SS_MCS5: + ret = DESC_RATEVHTSS2MCS5; + break; + case MGN_VHT2SS_MCS6: + ret = DESC_RATEVHTSS2MCS6; + break; + case MGN_VHT2SS_MCS7: + ret = DESC_RATEVHTSS2MCS7; + break; + case MGN_VHT2SS_MCS8: + ret = DESC_RATEVHTSS2MCS8; + break; + case MGN_VHT2SS_MCS9: + ret = DESC_RATEVHTSS2MCS9; + break; + case MGN_VHT3SS_MCS0: + ret = DESC_RATEVHTSS3MCS0; + break; + case MGN_VHT3SS_MCS1: + ret = DESC_RATEVHTSS3MCS1; + break; + case MGN_VHT3SS_MCS2: + ret = DESC_RATEVHTSS3MCS2; + break; + case MGN_VHT3SS_MCS3: + ret = DESC_RATEVHTSS3MCS3; + break; + case MGN_VHT3SS_MCS4: + ret = DESC_RATEVHTSS3MCS4; + break; + case MGN_VHT3SS_MCS5: + ret = DESC_RATEVHTSS3MCS5; + break; + case MGN_VHT3SS_MCS6: + ret = DESC_RATEVHTSS3MCS6; + break; + case MGN_VHT3SS_MCS7: + ret = DESC_RATEVHTSS3MCS7; + break; + case MGN_VHT3SS_MCS8: + ret = DESC_RATEVHTSS3MCS8; + break; + case MGN_VHT3SS_MCS9: + ret = DESC_RATEVHTSS3MCS9; + break; + case MGN_VHT4SS_MCS0: + ret = DESC_RATEVHTSS4MCS0; + break; + case MGN_VHT4SS_MCS1: + ret = DESC_RATEVHTSS4MCS1; + break; + case MGN_VHT4SS_MCS2: + ret = DESC_RATEVHTSS4MCS2; + break; + case MGN_VHT4SS_MCS3: + ret = DESC_RATEVHTSS4MCS3; + break; + case MGN_VHT4SS_MCS4: + ret = DESC_RATEVHTSS4MCS4; + break; + case MGN_VHT4SS_MCS5: + ret = DESC_RATEVHTSS4MCS5; + break; + case MGN_VHT4SS_MCS6: + ret = DESC_RATEVHTSS4MCS6; + break; + case MGN_VHT4SS_MCS7: + ret = DESC_RATEVHTSS4MCS7; + break; + case MGN_VHT4SS_MCS8: + ret = DESC_RATEVHTSS4MCS8; + break; + case MGN_VHT4SS_MCS9: + ret = DESC_RATEVHTSS4MCS9; + break; + default: + break; + } + + return ret; +} + +u8 hw_rate_to_m_rate(u8 rate) +{ + u8 ret_rate = MGN_1M; + + switch (rate) { + + case DESC_RATE1M: + ret_rate = MGN_1M; + break; + case DESC_RATE2M: + ret_rate = MGN_2M; + break; + case DESC_RATE5_5M: + ret_rate = MGN_5_5M; + break; + case DESC_RATE11M: + ret_rate = MGN_11M; + break; + case DESC_RATE6M: + ret_rate = MGN_6M; + break; + case DESC_RATE9M: + ret_rate = MGN_9M; + break; + case DESC_RATE12M: + ret_rate = MGN_12M; + break; + case DESC_RATE18M: + ret_rate = MGN_18M; + break; + case DESC_RATE24M: + ret_rate = MGN_24M; + break; + case DESC_RATE36M: + ret_rate = MGN_36M; + break; + case DESC_RATE48M: + ret_rate = MGN_48M; + break; + case DESC_RATE54M: + ret_rate = MGN_54M; + break; + case DESC_RATEMCS0: + ret_rate = MGN_MCS0; + break; + case DESC_RATEMCS1: + ret_rate = MGN_MCS1; + break; + case DESC_RATEMCS2: + ret_rate = MGN_MCS2; + break; + case DESC_RATEMCS3: + ret_rate = MGN_MCS3; + break; + case DESC_RATEMCS4: + ret_rate = MGN_MCS4; + break; + case DESC_RATEMCS5: + ret_rate = MGN_MCS5; + break; + case DESC_RATEMCS6: + ret_rate = MGN_MCS6; + break; + case DESC_RATEMCS7: + ret_rate = MGN_MCS7; + break; + case DESC_RATEMCS8: + ret_rate = MGN_MCS8; + break; + case DESC_RATEMCS9: + ret_rate = MGN_MCS9; + break; + case DESC_RATEMCS10: + ret_rate = MGN_MCS10; + break; + case DESC_RATEMCS11: + ret_rate = MGN_MCS11; + break; + case DESC_RATEMCS12: + ret_rate = MGN_MCS12; + break; + case DESC_RATEMCS13: + ret_rate = MGN_MCS13; + break; + case DESC_RATEMCS14: + ret_rate = MGN_MCS14; + break; + case DESC_RATEMCS15: + ret_rate = MGN_MCS15; + break; + case DESC_RATEMCS16: + ret_rate = MGN_MCS16; + break; + case DESC_RATEMCS17: + ret_rate = MGN_MCS17; + break; + case DESC_RATEMCS18: + ret_rate = MGN_MCS18; + break; + case DESC_RATEMCS19: + ret_rate = MGN_MCS19; + break; + case DESC_RATEMCS20: + ret_rate = MGN_MCS20; + break; + case DESC_RATEMCS21: + ret_rate = MGN_MCS21; + break; + case DESC_RATEMCS22: + ret_rate = MGN_MCS22; + break; + case DESC_RATEMCS23: + ret_rate = MGN_MCS23; + break; + case DESC_RATEMCS24: + ret_rate = MGN_MCS24; + break; + case DESC_RATEMCS25: + ret_rate = MGN_MCS25; + break; + case DESC_RATEMCS26: + ret_rate = MGN_MCS26; + break; + case DESC_RATEMCS27: + ret_rate = MGN_MCS27; + break; + case DESC_RATEMCS28: + ret_rate = MGN_MCS28; + break; + case DESC_RATEMCS29: + ret_rate = MGN_MCS29; + break; + case DESC_RATEMCS30: + ret_rate = MGN_MCS30; + break; + case DESC_RATEMCS31: + ret_rate = MGN_MCS31; + break; + case DESC_RATEVHTSS1MCS0: + ret_rate = MGN_VHT1SS_MCS0; + break; + case DESC_RATEVHTSS1MCS1: + ret_rate = MGN_VHT1SS_MCS1; + break; + case DESC_RATEVHTSS1MCS2: + ret_rate = MGN_VHT1SS_MCS2; + break; + case DESC_RATEVHTSS1MCS3: + ret_rate = MGN_VHT1SS_MCS3; + break; + case DESC_RATEVHTSS1MCS4: + ret_rate = MGN_VHT1SS_MCS4; + break; + case DESC_RATEVHTSS1MCS5: + ret_rate = MGN_VHT1SS_MCS5; + break; + case DESC_RATEVHTSS1MCS6: + ret_rate = MGN_VHT1SS_MCS6; + break; + case DESC_RATEVHTSS1MCS7: + ret_rate = MGN_VHT1SS_MCS7; + break; + case DESC_RATEVHTSS1MCS8: + ret_rate = MGN_VHT1SS_MCS8; + break; + case DESC_RATEVHTSS1MCS9: + ret_rate = MGN_VHT1SS_MCS9; + break; + case DESC_RATEVHTSS2MCS0: + ret_rate = MGN_VHT2SS_MCS0; + break; + case DESC_RATEVHTSS2MCS1: + ret_rate = MGN_VHT2SS_MCS1; + break; + case DESC_RATEVHTSS2MCS2: + ret_rate = MGN_VHT2SS_MCS2; + break; + case DESC_RATEVHTSS2MCS3: + ret_rate = MGN_VHT2SS_MCS3; + break; + case DESC_RATEVHTSS2MCS4: + ret_rate = MGN_VHT2SS_MCS4; + break; + case DESC_RATEVHTSS2MCS5: + ret_rate = MGN_VHT2SS_MCS5; + break; + case DESC_RATEVHTSS2MCS6: + ret_rate = MGN_VHT2SS_MCS6; + break; + case DESC_RATEVHTSS2MCS7: + ret_rate = MGN_VHT2SS_MCS7; + break; + case DESC_RATEVHTSS2MCS8: + ret_rate = MGN_VHT2SS_MCS8; + break; + case DESC_RATEVHTSS2MCS9: + ret_rate = MGN_VHT2SS_MCS9; + break; + case DESC_RATEVHTSS3MCS0: + ret_rate = MGN_VHT3SS_MCS0; + break; + case DESC_RATEVHTSS3MCS1: + ret_rate = MGN_VHT3SS_MCS1; + break; + case DESC_RATEVHTSS3MCS2: + ret_rate = MGN_VHT3SS_MCS2; + break; + case DESC_RATEVHTSS3MCS3: + ret_rate = MGN_VHT3SS_MCS3; + break; + case DESC_RATEVHTSS3MCS4: + ret_rate = MGN_VHT3SS_MCS4; + break; + case DESC_RATEVHTSS3MCS5: + ret_rate = MGN_VHT3SS_MCS5; + break; + case DESC_RATEVHTSS3MCS6: + ret_rate = MGN_VHT3SS_MCS6; + break; + case DESC_RATEVHTSS3MCS7: + ret_rate = MGN_VHT3SS_MCS7; + break; + case DESC_RATEVHTSS3MCS8: + ret_rate = MGN_VHT3SS_MCS8; + break; + case DESC_RATEVHTSS3MCS9: + ret_rate = MGN_VHT3SS_MCS9; + break; + case DESC_RATEVHTSS4MCS0: + ret_rate = MGN_VHT4SS_MCS0; + break; + case DESC_RATEVHTSS4MCS1: + ret_rate = MGN_VHT4SS_MCS1; + break; + case DESC_RATEVHTSS4MCS2: + ret_rate = MGN_VHT4SS_MCS2; + break; + case DESC_RATEVHTSS4MCS3: + ret_rate = MGN_VHT4SS_MCS3; + break; + case DESC_RATEVHTSS4MCS4: + ret_rate = MGN_VHT4SS_MCS4; + break; + case DESC_RATEVHTSS4MCS5: + ret_rate = MGN_VHT4SS_MCS5; + break; + case DESC_RATEVHTSS4MCS6: + ret_rate = MGN_VHT4SS_MCS6; + break; + case DESC_RATEVHTSS4MCS7: + ret_rate = MGN_VHT4SS_MCS7; + break; + case DESC_RATEVHTSS4MCS8: + ret_rate = MGN_VHT4SS_MCS8; + break; + case DESC_RATEVHTSS4MCS9: + ret_rate = MGN_VHT4SS_MCS9; + break; + + default: + RTW_INFO("hw_rate_to_m_rate(): Non supported Rate [%x]!!!\n", rate); + break; + } + + return ret_rate; +} + +void HalSetBrateCfg( + IN PADAPTER Adapter, + IN u8 *mBratesOS, + OUT u16 *pBrateCfg) +{ + u8 i, is_brate, brate; + + for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) { + is_brate = mBratesOS[i] & IEEE80211_BASIC_RATE_MASK; + brate = mBratesOS[i] & 0x7f; + + if (is_brate) { + switch (brate) { + case IEEE80211_CCK_RATE_1MB: + *pBrateCfg |= RATE_1M; + break; + case IEEE80211_CCK_RATE_2MB: + *pBrateCfg |= RATE_2M; + break; + case IEEE80211_CCK_RATE_5MB: + *pBrateCfg |= RATE_5_5M; + break; + case IEEE80211_CCK_RATE_11MB: + *pBrateCfg |= RATE_11M; + break; + case IEEE80211_OFDM_RATE_6MB: + *pBrateCfg |= RATE_6M; + break; + case IEEE80211_OFDM_RATE_9MB: + *pBrateCfg |= RATE_9M; + break; + case IEEE80211_OFDM_RATE_12MB: + *pBrateCfg |= RATE_12M; + break; + case IEEE80211_OFDM_RATE_18MB: + *pBrateCfg |= RATE_18M; + break; + case IEEE80211_OFDM_RATE_24MB: + *pBrateCfg |= RATE_24M; + break; + case IEEE80211_OFDM_RATE_36MB: + *pBrateCfg |= RATE_36M; + break; + case IEEE80211_OFDM_RATE_48MB: + *pBrateCfg |= RATE_48M; + break; + case IEEE80211_OFDM_RATE_54MB: + *pBrateCfg |= RATE_54M; + break; + } + } + } +} + +static VOID +_OneOutPipeMapping( + IN PADAPTER pAdapter +) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter); + + pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ + pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ + pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[0];/* BE */ + pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */ + + pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ + pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ + pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ + pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ +} + +static VOID +_TwoOutPipeMapping( + IN PADAPTER pAdapter, + IN BOOLEAN bWIFICfg +) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter); + + if (bWIFICfg) { /* WMM */ + + /* BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA */ + /* { 0, 1, 0, 1, 0, 0, 0, 0, 0 }; */ + /* 0:ep_0 num, 1:ep_1 num */ + + pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[1];/* VO */ + pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ + pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */ + pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];/* BK */ + + pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ + pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ + pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ + pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ + + } else { /* typical setting */ + + + /* BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA */ + /* { 1, 1, 0, 0, 0, 0, 0, 0, 0 }; */ + /* 0:ep_0 num, 1:ep_1 num */ + + pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ + pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];/* VI */ + pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1];/* BE */ + pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */ + + pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ + pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ + pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ + pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ + + } + +} + +static VOID _ThreeOutPipeMapping( + IN PADAPTER pAdapter, + IN BOOLEAN bWIFICfg +) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter); + + if (bWIFICfg) { /* for WMM */ + + /* BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA */ + /* { 1, 2, 1, 0, 0, 0, 0, 0, 0 }; */ + /* 0:H, 1:N, 2:L */ + + pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ + pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ + pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ + pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */ + + pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ + pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ + pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ + pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ + + } else { /* typical setting */ + + + /* BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA */ + /* { 2, 2, 1, 0, 0, 0, 0, 0, 0 }; */ + /* 0:H, 1:N, 2:L */ + + pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ + pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ + pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ + pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2];/* BK */ + + pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ + pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ + pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];/* HIGH */ + pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ + } + +} +static VOID _FourOutPipeMapping( + IN PADAPTER pAdapter, + IN BOOLEAN bWIFICfg +) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter); + + if (bWIFICfg) { /* for WMM */ + + /* BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA */ + /* { 1, 2, 1, 0, 0, 0, 0, 0, 0 }; */ + /* 0:H, 1:N, 2:L ,3:E */ + + pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ + pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ + pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ + pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1];/* BK */ + + pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ + pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ + pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[3];/* HIGH */ + pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ + + } else { /* typical setting */ + + + /* BK, BE, VI, VO, BCN, CMD,MGT,HIGH,HCCA */ + /* { 2, 2, 1, 0, 0, 0, 0, 0, 0 }; */ + /* 0:H, 1:N, 2:L */ + + pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];/* VO */ + pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1];/* VI */ + pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2];/* BE */ + pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2];/* BK */ + + pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];/* BCN */ + pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];/* MGT */ + pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[3];/* HIGH */ + pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];/* TXCMD */ + } + +} +BOOLEAN +Hal_MappingOutPipe( + IN PADAPTER pAdapter, + IN u8 NumOutPipe +) +{ + struct registry_priv *pregistrypriv = &pAdapter->registrypriv; + + BOOLEAN bWIFICfg = (pregistrypriv->wifi_spec) ? _TRUE : _FALSE; + + BOOLEAN result = _TRUE; + + switch (NumOutPipe) { + case 2: + _TwoOutPipeMapping(pAdapter, bWIFICfg); + break; + case 3: + case 4: + _ThreeOutPipeMapping(pAdapter, bWIFICfg); + break; + case 1: + _OneOutPipeMapping(pAdapter); + break; + default: + result = _FALSE; + break; + } + + return result; + +} + +void rtw_hal_reqtxrpt(_adapter *padapter, u8 macid) +{ + if (padapter->hal_func.reqtxrpt) + padapter->hal_func.reqtxrpt(padapter, macid); +} + +void rtw_hal_dump_macaddr(void *sel, _adapter *adapter) +{ + int i; + _adapter *iface; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + u8 mac_addr[ETH_ALEN]; + +#ifdef CONFIG_MI_WITH_MBSSID_CAM + rtw_mbid_cam_dump(sel, __func__, adapter); +#else + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (iface) { + rtw_hal_get_macaddr_port(iface, mac_addr); + RTW_PRINT_SEL(sel, ADPT_FMT"- hw port(%d) mac_addr ="MAC_FMT"\n", + ADPT_ARG(iface), iface->hw_port, MAC_ARG(mac_addr)); + } + } +#endif +} + +void rtw_restore_mac_addr(_adapter *adapter) +{ +#ifdef CONFIG_MI_WITH_MBSSID_CAM + _adapter *iface; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + + rtw_mbid_cam_restore(adapter); +#else + int i; + _adapter *iface; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (iface) + rtw_hal_set_macaddr_port(iface, adapter_mac_addr(iface)); + } +#endif + if (1) + rtw_hal_dump_macaddr(RTW_DBGDUMP, adapter); +} + +void rtw_init_hal_com_default_value(PADAPTER Adapter) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); + struct registry_priv *regsty = adapter_to_regsty(Adapter); + + pHalData->AntDetection = 1; + pHalData->antenna_test = _FALSE; + pHalData->u1ForcedIgiLb = regsty->force_igi_lb; +} + +#ifdef CONFIG_FW_C2H_REG +void c2h_evt_clear(_adapter *adapter) +{ + rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); +} + +s32 c2h_evt_read_88xx(_adapter *adapter, u8 *buf) +{ + s32 ret = _FAIL; + int i; + u8 trigger; + + if (buf == NULL) + goto exit; + + trigger = rtw_read8(adapter, REG_C2HEVT_CLEAR); + + if (trigger == C2H_EVT_HOST_CLOSE) { + goto exit; /* Not ready */ + } else if (trigger != C2H_EVT_FW_CLOSE) { + goto clear_evt; /* Not a valid value */ + } + + _rtw_memset(buf, 0, C2H_REG_LEN); + + /* Read ID, LEN, SEQ */ + SET_C2H_ID_88XX(buf, rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL)); + SET_C2H_SEQ_88XX(buf, rtw_read8(adapter, REG_C2HEVT_CMD_SEQ_88XX)); + SET_C2H_PLEN_88XX(buf, rtw_read8(adapter, REG_C2HEVT_CMD_LEN_88XX)); + + if (0) { + RTW_INFO("%s id=0x%02x, seq=%u, plen=%u, trigger=0x%02x\n", __func__ + , C2H_ID_88XX(buf), C2H_SEQ_88XX(buf), C2H_PLEN_88XX(buf), trigger); + } + + /* Read the content */ + for (i = 0; i < C2H_PLEN_88XX(buf); i++) + *(C2H_PAYLOAD_88XX(buf) + i) = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 2 + i); + + RTW_DBG_DUMP("payload:\n", C2H_PAYLOAD_88XX(buf), C2H_PLEN_88XX(buf)); + + ret = _SUCCESS; + +clear_evt: + /* + * Clear event to notify FW we have read the command. + * If this field isn't clear, the FW won't update the next command message. + */ + c2h_evt_clear(adapter); + +exit: + return ret; +} +#endif /* CONFIG_FW_C2H_REG */ + +#ifdef CONFIG_FW_C2H_PKT +#ifndef DBG_C2H_PKT_PRE_HDL +#define DBG_C2H_PKT_PRE_HDL 0 +#endif +#ifndef DBG_C2H_PKT_HDL +#define DBG_C2H_PKT_HDL 0 +#endif +void rtw_hal_c2h_pkt_pre_hdl(_adapter *adapter, u8 *buf, u16 len) +{ +#ifdef RTW_HALMAC + /* TODO: extract hal_mac IC's code here*/ +#else + u8 parse_fail = 0; + u8 hdl_here = 0; + s32 ret = _FAIL; + u8 id, seq, plen; + u8 *payload; + + if (rtw_hal_c2h_pkt_hdr_parse(adapter, buf, len, &id, &seq, &plen, &payload) != _SUCCESS) { + parse_fail = 1; + goto exit; + } + + hdl_here = rtw_hal_c2h_id_handle_directly(adapter, id, seq, plen, payload) == _TRUE ? 1 : 0; + if (hdl_here) + ret = rtw_hal_c2h_handler(adapter, id, seq, plen, payload); + else + ret = rtw_c2h_packet_wk_cmd(adapter, buf, len); + +exit: + if (parse_fail) + RTW_ERR("%s parse fail, buf=%p, len=:%u\n", __func__, buf, len); + else if (ret != _SUCCESS || DBG_C2H_PKT_PRE_HDL > 0) { + RTW_PRINT("%s: id=0x%02x, seq=%u, plen=%u, %s %s\n", __func__, id, seq, plen + , hdl_here ? "handle" : "enqueue" + , ret == _SUCCESS ? "ok" : "fail" + ); + if (DBG_C2H_PKT_PRE_HDL >= 2) + RTW_PRINT_DUMP("dump: ", buf, len); + } +#endif +} + +void rtw_hal_c2h_pkt_hdl(_adapter *adapter, u8 *buf, u16 len) +{ +#ifdef RTW_HALMAC + adapter->hal_func.hal_mac_c2h_handler(adapter, buf, len); +#else + u8 parse_fail = 0; + u8 bypass = 0; + s32 ret = _FAIL; + u8 id, seq, plen; + u8 *payload; + + if (rtw_hal_c2h_pkt_hdr_parse(adapter, buf, len, &id, &seq, &plen, &payload) != _SUCCESS) { + parse_fail = 1; + goto exit; + } + +#ifdef CONFIG_WOWLAN + if (adapter_to_pwrctl(adapter)->wowlan_mode == _TRUE) { + bypass = 1; + ret = _SUCCESS; + goto exit; + } +#endif + + ret = rtw_hal_c2h_handler(adapter, id, seq, plen, payload); + +exit: + if (parse_fail) + RTW_ERR("%s parse fail, buf=%p, len=:%u\n", __func__, buf, len); + else if (ret != _SUCCESS || bypass || DBG_C2H_PKT_HDL > 0) { + RTW_PRINT("%s: id=0x%02x, seq=%u, plen=%u, %s %s\n", __func__, id, seq, plen + , !bypass ? "handle" : "bypass" + , ret == _SUCCESS ? "ok" : "fail" + ); + if (DBG_C2H_PKT_HDL >= 2) + RTW_PRINT_DUMP("dump: ", buf, len); + } +#endif +} +#endif /* CONFIG_FW_C2H_PKT */ + +void c2h_iqk_offload(_adapter *adapter, u8 *data, u8 len) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct submit_ctx *iqk_sctx = &hal_data->iqk_sctx; + + RTW_INFO("IQK offload finish in %dms\n", rtw_get_passing_time_ms(iqk_sctx->submit_time)); + if (0) + RTW_INFO_DUMP("C2H_IQK_FINISH: ", data, len); + + rtw_sctx_done(&iqk_sctx); +} + +int c2h_iqk_offload_wait(_adapter *adapter, u32 timeout_ms) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct submit_ctx *iqk_sctx = &hal_data->iqk_sctx; + + iqk_sctx->submit_time = rtw_get_current_time(); + iqk_sctx->timeout_ms = timeout_ms; + iqk_sctx->status = RTW_SCTX_SUBMITTED; + + return rtw_sctx_wait(iqk_sctx, __func__); +} + +#define GET_C2H_MAC_HIDDEN_RPT_UUID_X(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 0, 0, 8) +#define GET_C2H_MAC_HIDDEN_RPT_UUID_Y(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 1, 0, 8) +#define GET_C2H_MAC_HIDDEN_RPT_UUID_Z(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 2, 0, 5) +#define GET_C2H_MAC_HIDDEN_RPT_UUID_CRC(_data) LE_BITS_TO_2BYTE(((u8 *)(_data)) + 2, 5, 11) +#define GET_C2H_MAC_HIDDEN_RPT_HCI_TYPE(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 4, 0, 4) +#define GET_C2H_MAC_HIDDEN_RPT_PACKAGE_TYPE(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 4, 4, 3) +#define GET_C2H_MAC_HIDDEN_RPT_TR_SWITCH(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 4, 7, 1) +#define GET_C2H_MAC_HIDDEN_RPT_WL_FUNC(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 5, 0, 4) +#define GET_C2H_MAC_HIDDEN_RPT_HW_STYPE(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 5, 4, 4) +#define GET_C2H_MAC_HIDDEN_RPT_BW(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 6, 0, 3) +#define GET_C2H_MAC_HIDDEN_RPT_FAB(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 6, 3, 2) +#define GET_C2H_MAC_HIDDEN_RPT_ANT_NUM(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 6, 5, 3) +#define GET_C2H_MAC_HIDDEN_RPT_80211_PROTOCOL(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 7, 2, 2) +#define GET_C2H_MAC_HIDDEN_RPT_NIC_ROUTER(_data) LE_BITS_TO_1BYTE(((u8 *)(_data)) + 7, 6, 2) + +#ifndef DBG_C2H_MAC_HIDDEN_RPT_HANDLE +#define DBG_C2H_MAC_HIDDEN_RPT_HANDLE 0 +#endif + +#ifdef CONFIG_RTW_MAC_HIDDEN_RPT +int c2h_mac_hidden_rpt_hdl(_adapter *adapter, u8 *data, u8 len) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + int ret = _FAIL; + + u32 uuid; + u8 uuid_x; + u8 uuid_y; + u8 uuid_z; + u16 uuid_crc; + + u8 hci_type; + u8 package_type; + u8 tr_switch; + u8 wl_func; + u8 hw_stype; + u8 bw; + u8 fab; + u8 ant_num; + u8 protocol; + u8 nic; + + int i; + + if (len < MAC_HIDDEN_RPT_LEN) { + RTW_WARN("%s len(%u) < %d\n", __func__, len, MAC_HIDDEN_RPT_LEN); + goto exit; + } + + uuid_x = GET_C2H_MAC_HIDDEN_RPT_UUID_X(data); + uuid_y = GET_C2H_MAC_HIDDEN_RPT_UUID_Y(data); + uuid_z = GET_C2H_MAC_HIDDEN_RPT_UUID_Z(data); + uuid_crc = GET_C2H_MAC_HIDDEN_RPT_UUID_CRC(data); + + hci_type = GET_C2H_MAC_HIDDEN_RPT_HCI_TYPE(data); + package_type = GET_C2H_MAC_HIDDEN_RPT_PACKAGE_TYPE(data); + + tr_switch = GET_C2H_MAC_HIDDEN_RPT_TR_SWITCH(data); + + wl_func = GET_C2H_MAC_HIDDEN_RPT_WL_FUNC(data); + hw_stype = GET_C2H_MAC_HIDDEN_RPT_HW_STYPE(data); + + bw = GET_C2H_MAC_HIDDEN_RPT_BW(data); + fab = GET_C2H_MAC_HIDDEN_RPT_FAB(data); + ant_num = GET_C2H_MAC_HIDDEN_RPT_ANT_NUM(data); + + protocol = GET_C2H_MAC_HIDDEN_RPT_80211_PROTOCOL(data); + nic = GET_C2H_MAC_HIDDEN_RPT_NIC_ROUTER(data); + + if (DBG_C2H_MAC_HIDDEN_RPT_HANDLE) { + for (i = 0; i < len; i++) + RTW_PRINT("%s: 0x%02X\n", __func__, *(data + i)); + + RTW_PRINT("uuid x:0x%02x y:0x%02x z:0x%x crc:0x%x\n", uuid_x, uuid_y, uuid_z, uuid_crc); + RTW_PRINT("hci_type:0x%x\n", hci_type); + RTW_PRINT("package_type:0x%x\n", package_type); + RTW_PRINT("tr_switch:0x%x\n", tr_switch); + RTW_PRINT("wl_func:0x%x\n", wl_func); + RTW_PRINT("hw_stype:0x%x\n", hw_stype); + RTW_PRINT("bw:0x%x\n", bw); + RTW_PRINT("fab:0x%x\n", fab); + RTW_PRINT("ant_num:0x%x\n", ant_num); + RTW_PRINT("protocol:0x%x\n", protocol); + RTW_PRINT("nic:0x%x\n", nic); + } + + /* + * NOTICE: + * for now, the following is common info/format + * if there is any hal difference need to export + * some IC dependent code will need to be implement + */ + hal_data->PackageType = package_type; + hal_spec->wl_func &= mac_hidden_wl_func_to_hal_wl_func(wl_func); + hal_spec->bw_cap &= mac_hidden_max_bw_to_hal_bw_cap(bw); + hal_spec->tx_nss_num = rtw_min(hal_spec->tx_nss_num, ant_num); + hal_spec->rx_nss_num = rtw_min(hal_spec->rx_nss_num, ant_num); + hal_spec->proto_cap &= mac_hidden_proto_to_hal_proto_cap(protocol); + hal_spec->hci_type = hci_type; + + /* TODO: tr_switch */ + /* TODO: fab */ + + ret = _SUCCESS; + +exit: + return ret; +} + +int c2h_mac_hidden_rpt_2_hdl(_adapter *adapter, u8 *data, u8 len) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + int ret = _FAIL; + + int i; + + if (len < MAC_HIDDEN_RPT_2_LEN) { + RTW_WARN("%s len(%u) < %d\n", __func__, len, MAC_HIDDEN_RPT_2_LEN); + goto exit; + } + + if (DBG_C2H_MAC_HIDDEN_RPT_HANDLE) { + for (i = 0; i < len; i++) + RTW_PRINT("%s: 0x%02X\n", __func__, *(data + i)); + } + + ret = _SUCCESS; + +exit: + return ret; +} + +int hal_read_mac_hidden_rpt(_adapter *adapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); + int ret = _FAIL; + int ret_fwdl; + u8 mac_hidden_rpt[MAC_HIDDEN_RPT_LEN + MAC_HIDDEN_RPT_2_LEN] = {0}; + u32 start = rtw_get_current_time(); + u32 cnt = 0; + u32 timeout_ms = 800; + u32 min_cnt = 10; + u8 id = C2H_DEFEATURE_RSVD; + int i; + +#if defined(CONFIG_USB_HCI) || defined(CONFIG_PCI_HCI) + u8 hci_type = rtw_get_intf_type(adapter); + + if ((hci_type == RTW_USB || hci_type == RTW_PCIE) + && !rtw_is_hw_init_completed(adapter)) + rtw_hal_power_on(adapter); +#endif + + /* inform FW mac hidden rpt from reg is needed */ + rtw_write8(adapter, REG_C2HEVT_MSG_NORMAL, C2H_DEFEATURE_RSVD); + + /* download FW */ + pHalData->not_xmitframe_fw_dl = 1; + ret_fwdl = rtw_hal_fw_dl(adapter, _FALSE); + pHalData->not_xmitframe_fw_dl = 0; + if (ret_fwdl != _SUCCESS) + goto mac_hidden_rpt_hdl; + + /* polling for data ready */ + start = rtw_get_current_time(); + do { + cnt++; + id = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL); + if (id == C2H_MAC_HIDDEN_RPT || RTW_CANNOT_IO(adapter)) + break; + rtw_msleep_os(10); + } while (rtw_get_passing_time_ms(start) < timeout_ms || cnt < min_cnt); + + if (id == C2H_MAC_HIDDEN_RPT) { + /* read data */ + for (i = 0; i < MAC_HIDDEN_RPT_LEN + MAC_HIDDEN_RPT_2_LEN; i++) + mac_hidden_rpt[i] = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 2 + i); + } + + /* inform FW mac hidden rpt has read */ + rtw_write8(adapter, REG_C2HEVT_MSG_NORMAL, C2H_DBG); + +mac_hidden_rpt_hdl: + c2h_mac_hidden_rpt_hdl(adapter, mac_hidden_rpt, MAC_HIDDEN_RPT_LEN); + c2h_mac_hidden_rpt_2_hdl(adapter, mac_hidden_rpt + MAC_HIDDEN_RPT_LEN, MAC_HIDDEN_RPT_2_LEN); + + if (ret_fwdl == _SUCCESS && id == C2H_MAC_HIDDEN_RPT) + ret = _SUCCESS; + +exit: + +#if defined(CONFIG_USB_HCI) || defined(CONFIG_PCI_HCI) + if ((hci_type == RTW_USB || hci_type == RTW_PCIE) + && !rtw_is_hw_init_completed(adapter)) + rtw_hal_power_off(adapter); +#endif + + RTW_INFO("%s %s! (%u, %dms), fwdl:%d, id:0x%02x\n", __func__ + , (ret == _SUCCESS) ? "OK" : "Fail", cnt, rtw_get_passing_time_ms(start), ret_fwdl, id); + + return ret; +} +#endif /* CONFIG_RTW_MAC_HIDDEN_RPT */ + +int c2h_defeature_dbg_hdl(_adapter *adapter, u8 *data, u8 len) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + int ret = _FAIL; + + int i; + + if (len < DEFEATURE_DBG_LEN) { + RTW_WARN("%s len(%u) < %d\n", __func__, len, DEFEATURE_DBG_LEN); + goto exit; + } + + for (i = 0; i < len; i++) + RTW_PRINT("%s: 0x%02X\n", __func__, *(data + i)); + + ret = _SUCCESS; + +exit: + return ret; +} + +#ifndef DBG_CUSTOMER_STR_RPT_HANDLE +#define DBG_CUSTOMER_STR_RPT_HANDLE 0 +#endif + +#ifdef CONFIG_RTW_CUSTOMER_STR +s32 rtw_hal_h2c_customer_str_req(_adapter *adapter) +{ + u8 h2c_data[H2C_CUSTOMER_STR_REQ_LEN] = {0}; + + SET_H2CCMD_CUSTOMER_STR_REQ_EN(h2c_data, 1); + return rtw_hal_fill_h2c_cmd(adapter, H2C_CUSTOMER_STR_REQ, H2C_CUSTOMER_STR_REQ_LEN, h2c_data); +} + +#define C2H_CUSTOMER_STR_RPT_BYTE0(_data) ((u8 *)(_data)) +#define C2H_CUSTOMER_STR_RPT_2_BYTE8(_data) ((u8 *)(_data)) + +int c2h_customer_str_rpt_hdl(_adapter *adapter, u8 *data, u8 len) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + int ret = _FAIL; + int i; + + if (len < CUSTOMER_STR_RPT_LEN) { + RTW_WARN("%s len(%u) < %d\n", __func__, len, CUSTOMER_STR_RPT_LEN); + goto exit; + } + + if (DBG_CUSTOMER_STR_RPT_HANDLE) + RTW_PRINT_DUMP("customer_str_rpt: ", data, CUSTOMER_STR_RPT_LEN); + + _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); + + if (dvobj->customer_str_sctx != NULL) { + if (dvobj->customer_str_sctx->status != RTW_SCTX_SUBMITTED) + RTW_WARN("%s invalid sctx.status:%d\n", __func__, dvobj->customer_str_sctx->status); + _rtw_memcpy(dvobj->customer_str, C2H_CUSTOMER_STR_RPT_BYTE0(data), CUSTOMER_STR_RPT_LEN); + dvobj->customer_str_sctx->status = RTX_SCTX_CSTR_WAIT_RPT2; + } else + RTW_WARN("%s sctx not set\n", __func__); + + _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); + + ret = _SUCCESS; + +exit: + return ret; +} + +int c2h_customer_str_rpt_2_hdl(_adapter *adapter, u8 *data, u8 len) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + int ret = _FAIL; + int i; + + if (len < CUSTOMER_STR_RPT_2_LEN) { + RTW_WARN("%s len(%u) < %d\n", __func__, len, CUSTOMER_STR_RPT_2_LEN); + goto exit; + } + + if (DBG_CUSTOMER_STR_RPT_HANDLE) + RTW_PRINT_DUMP("customer_str_rpt_2: ", data, CUSTOMER_STR_RPT_2_LEN); + + _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); + + if (dvobj->customer_str_sctx != NULL) { + if (dvobj->customer_str_sctx->status != RTX_SCTX_CSTR_WAIT_RPT2) + RTW_WARN("%s rpt not ready\n", __func__); + _rtw_memcpy(dvobj->customer_str + CUSTOMER_STR_RPT_LEN, C2H_CUSTOMER_STR_RPT_2_BYTE8(data), CUSTOMER_STR_RPT_2_LEN); + rtw_sctx_done(&dvobj->customer_str_sctx); + } else + RTW_WARN("%s sctx not set\n", __func__); + + _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); + + ret = _SUCCESS; + +exit: + return ret; +} + +/* read customer str */ +s32 rtw_hal_customer_str_read(_adapter *adapter, u8 *cs) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct submit_ctx sctx; + s32 ret = _SUCCESS; + + _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); + if (dvobj->customer_str_sctx != NULL) + ret = _FAIL; + else { + rtw_sctx_init(&sctx, 2 * 1000); + dvobj->customer_str_sctx = &sctx; + } + _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); + + if (ret == _FAIL) { + RTW_WARN("%s another handle ongoing\n", __func__); + goto exit; + } + + ret = rtw_customer_str_req_cmd(adapter); + if (ret != _SUCCESS) { + RTW_WARN("%s read cmd fail\n", __func__); + _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); + dvobj->customer_str_sctx = NULL; + _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); + goto exit; + } + + /* wait till rpt done or timeout */ + rtw_sctx_wait(&sctx, __func__); + + _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); + dvobj->customer_str_sctx = NULL; + if (sctx.status == RTW_SCTX_DONE_SUCCESS) + _rtw_memcpy(cs, dvobj->customer_str, RTW_CUSTOMER_STR_LEN); + else + ret = _FAIL; + _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); + +exit: + return ret; +} + +s32 rtw_hal_h2c_customer_str_write(_adapter *adapter, const u8 *cs) +{ + u8 h2c_data_w1[H2C_CUSTOMER_STR_W1_LEN] = {0}; + u8 h2c_data_w2[H2C_CUSTOMER_STR_W2_LEN] = {0}; + u8 h2c_data_w3[H2C_CUSTOMER_STR_W3_LEN] = {0}; + s32 ret; + + SET_H2CCMD_CUSTOMER_STR_W1_EN(h2c_data_w1, 1); + _rtw_memcpy(H2CCMD_CUSTOMER_STR_W1_BYTE0(h2c_data_w1), cs, 6); + + SET_H2CCMD_CUSTOMER_STR_W2_EN(h2c_data_w2, 1); + _rtw_memcpy(H2CCMD_CUSTOMER_STR_W2_BYTE6(h2c_data_w2), cs + 6, 6); + + SET_H2CCMD_CUSTOMER_STR_W3_EN(h2c_data_w3, 1); + _rtw_memcpy(H2CCMD_CUSTOMER_STR_W3_BYTE12(h2c_data_w3), cs + 6 + 6, 4); + + ret = rtw_hal_fill_h2c_cmd(adapter, H2C_CUSTOMER_STR_W1, H2C_CUSTOMER_STR_W1_LEN, h2c_data_w1); + if (ret != _SUCCESS) { + RTW_WARN("%s w1 fail\n", __func__); + goto exit; + } + + ret = rtw_hal_fill_h2c_cmd(adapter, H2C_CUSTOMER_STR_W2, H2C_CUSTOMER_STR_W2_LEN, h2c_data_w2); + if (ret != _SUCCESS) { + RTW_WARN("%s w2 fail\n", __func__); + goto exit; + } + + ret = rtw_hal_fill_h2c_cmd(adapter, H2C_CUSTOMER_STR_W3, H2C_CUSTOMER_STR_W3_LEN, h2c_data_w3); + if (ret != _SUCCESS) { + RTW_WARN("%s w3 fail\n", __func__); + goto exit; + } + +exit: + return ret; +} + +/* write customer str and check if value reported is the same as requested */ +s32 rtw_hal_customer_str_write(_adapter *adapter, const u8 *cs) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct submit_ctx sctx; + s32 ret = _SUCCESS; + + _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); + if (dvobj->customer_str_sctx != NULL) + ret = _FAIL; + else { + rtw_sctx_init(&sctx, 2 * 1000); + dvobj->customer_str_sctx = &sctx; + } + _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); + + if (ret == _FAIL) { + RTW_WARN("%s another handle ongoing\n", __func__); + goto exit; + } + + ret = rtw_customer_str_write_cmd(adapter, cs); + if (ret != _SUCCESS) { + RTW_WARN("%s write cmd fail\n", __func__); + _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); + dvobj->customer_str_sctx = NULL; + _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); + goto exit; + } + + ret = rtw_customer_str_req_cmd(adapter); + if (ret != _SUCCESS) { + RTW_WARN("%s read cmd fail\n", __func__); + _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); + dvobj->customer_str_sctx = NULL; + _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); + goto exit; + } + + /* wait till rpt done or timeout */ + rtw_sctx_wait(&sctx, __func__); + + _enter_critical_mutex(&dvobj->customer_str_mutex, NULL); + dvobj->customer_str_sctx = NULL; + if (sctx.status == RTW_SCTX_DONE_SUCCESS) { + if (_rtw_memcmp(cs, dvobj->customer_str, RTW_CUSTOMER_STR_LEN) != _TRUE) { + RTW_WARN("%s read back check fail\n", __func__); + RTW_INFO_DUMP("write req: ", cs, RTW_CUSTOMER_STR_LEN); + RTW_INFO_DUMP("read back: ", dvobj->customer_str, RTW_CUSTOMER_STR_LEN); + ret = _FAIL; + } + } else + ret = _FAIL; + _exit_critical_mutex(&dvobj->customer_str_mutex, NULL); + +exit: + return ret; +} +#endif /* CONFIG_RTW_CUSTOMER_STR */ + +u8 rtw_hal_networktype_to_raid(_adapter *adapter, struct sta_info *psta) +{ +#ifdef CONFIG_GET_RAID_BY_DRV /*Just for 8188E now*/ + if (IS_NEW_GENERATION_IC(adapter)) + return networktype_to_raid_ex(adapter, psta); + else + return networktype_to_raid(adapter, psta); +#else + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); + u8 bw; + + bw = rtw_get_tx_bw_mode(adapter, psta); + + return phydm_rate_id_mapping(&pHalData->odmpriv, psta->wireless_mode, pHalData->rf_type, bw); +#endif +} +u8 rtw_get_mgntframe_raid(_adapter *adapter, unsigned char network_type) +{ + + u8 raid; + if (IS_NEW_GENERATION_IC(adapter)) { + + raid = (network_type & WIRELESS_11B) ? RATEID_IDX_B + : RATEID_IDX_G; + } else { + raid = (network_type & WIRELESS_11B) ? RATR_INX_WIRELESS_B + : RATR_INX_WIRELESS_G; + } + return raid; +} + +void rtw_hal_update_sta_rate_mask(PADAPTER padapter, struct sta_info *psta) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); + u8 i, rf_type, tx_nss; + u64 tx_ra_bitmap; + + if (psta == NULL) + return; + + tx_ra_bitmap = 0; + + /* b/g mode ra_bitmap */ + for (i = 0; i < sizeof(psta->bssrateset); i++) { + if (psta->bssrateset[i]) + tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i] & 0x7f); + } + +#ifdef CONFIG_80211N_HT + rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); + tx_nss = rtw_min(rf_type_to_rf_tx_cnt(rf_type), hal_spec->tx_nss_num); +#ifdef CONFIG_80211AC_VHT + if (psta->vhtpriv.vht_option) { + /* AC mode ra_bitmap */ + tx_ra_bitmap |= (rtw_vht_mcs_map_to_bitmap(psta->vhtpriv.vht_mcs_map, tx_nss) << 12); + } else +#endif /* CONFIG_80211AC_VHT */ + if (psta->htpriv.ht_option) { + /* n mode ra_bitmap */ + + /* Handling SMPS mode for AP MODE only*/ + if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) { + /*0:static SMPS, 1:dynamic SMPS, 3:SMPS disabled, 2:reserved*/ + if (psta->htpriv.smps_cap == 0 || psta->htpriv.smps_cap == 1) { + /*operate with only one active receive chain // 11n-MCS rate <= MSC7*/ + tx_nss = rtw_min(tx_nss, 1); + } + } + + tx_ra_bitmap |= (rtw_ht_mcs_set_to_bitmap(psta->htpriv.ht_cap.supp_mcs_set, tx_nss) << 12); + } +#endif /* CONFIG_80211N_HT */ + psta->ra_mask = tx_ra_bitmap; + psta->init_rate = get_highest_rate_idx(tx_ra_bitmap) & 0x3f; +} + +#ifndef SEC_CAM_ACCESS_TIMEOUT_MS + #define SEC_CAM_ACCESS_TIMEOUT_MS 200 +#endif + +#ifndef DBG_SEC_CAM_ACCESS + #define DBG_SEC_CAM_ACCESS 0 +#endif + +u32 rtw_sec_read_cam(_adapter *adapter, u8 addr) +{ + _mutex *mutex = &adapter_to_dvobj(adapter)->cam_ctl.sec_cam_access_mutex; + u32 rdata; + u32 cnt = 0; + u32 start = 0, end = 0; + u8 timeout = 0; + u8 sr = 0; + + _enter_critical_mutex(mutex, NULL); + + rtw_write32(adapter, REG_CAMCMD, CAM_POLLINIG | addr); + + start = rtw_get_current_time(); + while (1) { + if (rtw_is_surprise_removed(adapter)) { + sr = 1; + break; + } + + cnt++; + if (0 == (rtw_read32(adapter, REG_CAMCMD) & CAM_POLLINIG)) + break; + + if (rtw_get_passing_time_ms(start) > SEC_CAM_ACCESS_TIMEOUT_MS) { + timeout = 1; + break; + } + } + end = rtw_get_current_time(); + + rdata = rtw_read32(adapter, REG_CAMREAD); + + _exit_critical_mutex(mutex, NULL); + + if (DBG_SEC_CAM_ACCESS || timeout) { + RTW_INFO(FUNC_ADPT_FMT" addr:0x%02x, rdata:0x%08x, to:%u, polling:%u, %d ms\n" + , FUNC_ADPT_ARG(adapter), addr, rdata, timeout, cnt, rtw_get_time_interval_ms(start, end)); + } + + return rdata; +} + +void rtw_sec_write_cam(_adapter *adapter, u8 addr, u32 wdata) +{ + _mutex *mutex = &adapter_to_dvobj(adapter)->cam_ctl.sec_cam_access_mutex; + u32 cnt = 0; + u32 start = 0, end = 0; + u8 timeout = 0; + u8 sr = 0; + + _enter_critical_mutex(mutex, NULL); + + rtw_write32(adapter, REG_CAMWRITE, wdata); + rtw_write32(adapter, REG_CAMCMD, CAM_POLLINIG | CAM_WRITE | addr); + + start = rtw_get_current_time(); + while (1) { + if (rtw_is_surprise_removed(adapter)) { + sr = 1; + break; + } + + cnt++; + if (0 == (rtw_read32(adapter, REG_CAMCMD) & CAM_POLLINIG)) + break; + + if (rtw_get_passing_time_ms(start) > SEC_CAM_ACCESS_TIMEOUT_MS) { + timeout = 1; + break; + } + } + end = rtw_get_current_time(); + + _exit_critical_mutex(mutex, NULL); + + if (DBG_SEC_CAM_ACCESS || timeout) { + RTW_INFO(FUNC_ADPT_FMT" addr:0x%02x, wdata:0x%08x, to:%u, polling:%u, %d ms\n" + , FUNC_ADPT_ARG(adapter), addr, wdata, timeout, cnt, rtw_get_time_interval_ms(start, end)); + } +} + +void rtw_sec_read_cam_ent(_adapter *adapter, u8 id, u8 *ctrl, u8 *mac, u8 *key) +{ + unsigned int val, addr; + u8 i; + u32 rdata; + u8 begin = 0; + u8 end = 5; /* TODO: consider other key length accordingly */ + + if (!ctrl && !mac && !key) { + rtw_warn_on(1); + goto exit; + } + + /* TODO: check id range */ + + if (!ctrl && !mac) + begin = 2; /* read from key */ + + if (!key && !mac) + end = 0; /* read to ctrl */ + else if (!key) + end = 2; /* read to mac */ + + for (i = begin; i <= end; i++) { + rdata = rtw_sec_read_cam(adapter, (id << 3) | i); + + switch (i) { + case 0: + if (ctrl) + _rtw_memcpy(ctrl, (u8 *)(&rdata), 2); + if (mac) + _rtw_memcpy(mac, ((u8 *)(&rdata)) + 2, 2); + break; + case 1: + if (mac) + _rtw_memcpy(mac + 2, (u8 *)(&rdata), 4); + break; + default: + if (key) + _rtw_memcpy(key + (i - 2) * 4, (u8 *)(&rdata), 4); + break; + } + } + +exit: + return; +} + + +void rtw_sec_write_cam_ent(_adapter *adapter, u8 id, u16 ctrl, u8 *mac, u8 *key) +{ + unsigned int i; + int j; + u8 addr; + u32 wdata; + + /* TODO: consider other key length accordingly */ +#if 0 + switch ((ctrl & 0x1c) >> 2) { + case _WEP40_: + case _TKIP_: + case _AES_: + case _WEP104_: + + } +#else + j = 7; +#endif + + for (; j >= 0; j--) { + switch (j) { + case 0: + wdata = (ctrl | (mac[0] << 16) | (mac[1] << 24)); + break; + case 1: + wdata = (mac[2] | (mac[3] << 8) | (mac[4] << 16) | (mac[5] << 24)); + break; + case 6: + case 7: + wdata = 0; + break; + default: + i = (j - 2) << 2; + wdata = (key[i] | (key[i + 1] << 8) | (key[i + 2] << 16) | (key[i + 3] << 24)); + break; + } + + addr = (id << 3) + j; + + rtw_sec_write_cam(adapter, addr, wdata); + } +} + +void rtw_sec_clr_cam_ent(_adapter *adapter, u8 id) +{ + u8 addr; + + addr = (id << 3); + rtw_sec_write_cam(adapter, addr, 0); +} + +bool rtw_sec_read_cam_is_gk(_adapter *adapter, u8 id) +{ + bool res; + u16 ctrl; + + rtw_sec_read_cam_ent(adapter, id, (u8 *)&ctrl, NULL, NULL); + + res = (ctrl & BIT6) ? _TRUE : _FALSE; + return res; +} +#ifdef CONFIG_MBSSID_CAM +void rtw_mbid_cam_init(struct dvobj_priv *dvobj) +{ + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + + _rtw_spinlock_init(&mbid_cam_ctl->lock); + mbid_cam_ctl->bitmap = 0; + ATOMIC_SET(&mbid_cam_ctl->mbid_entry_num, 0); + _rtw_memset(&dvobj->mbid_cam_cache, 0, sizeof(dvobj->mbid_cam_cache)); +} + +void rtw_mbid_cam_deinit(struct dvobj_priv *dvobj) +{ + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + + _rtw_spinlock_free(&mbid_cam_ctl->lock); +} + +void rtw_mbid_cam_reset(_adapter *adapter) +{ + _irqL irqL; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + + _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); + mbid_cam_ctl->bitmap = 0; + _rtw_memset(&dvobj->mbid_cam_cache, 0, sizeof(dvobj->mbid_cam_cache)); + _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); + + ATOMIC_SET(&mbid_cam_ctl->mbid_entry_num, 0); +} +static u8 _rtw_mbid_cam_search_by_macaddr(_adapter *adapter, u8 *mac_addr) +{ + u8 i; + u8 cam_id = INVALID_CAM_ID; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + + for (i = 0; i < TOTAL_MBID_CAM_NUM; i++) { + if (mac_addr && _rtw_memcmp(dvobj->mbid_cam_cache[i].mac_addr, mac_addr, ETH_ALEN) == _TRUE) { + cam_id = i; + break; + } + } + + RTW_INFO("%s mac:"MAC_FMT" - cam_id:%d\n", __func__, MAC_ARG(mac_addr), cam_id); + return cam_id; +} + +u8 rtw_mbid_cam_search_by_macaddr(_adapter *adapter, u8 *mac_addr) +{ + _irqL irqL; + + u8 cam_id = INVALID_CAM_ID; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + + _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); + cam_id = _rtw_mbid_cam_search_by_macaddr(adapter, mac_addr); + _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); + + return cam_id; +} +static u8 _rtw_mbid_cam_search_by_ifaceid(_adapter *adapter, u8 iface_id) +{ + u8 i; + u8 cam_id = INVALID_CAM_ID; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + + for (i = 0; i < TOTAL_MBID_CAM_NUM; i++) { + if (iface_id == dvobj->mbid_cam_cache[i].iface_id) { + cam_id = i; + break; + } + } + if (cam_id != INVALID_CAM_ID) + RTW_INFO("%s iface_id:%d mac:"MAC_FMT" - cam_id:%d\n", + __func__, iface_id, MAC_ARG(dvobj->mbid_cam_cache[cam_id].mac_addr), cam_id); + + return cam_id; +} + +u8 rtw_mbid_cam_search_by_ifaceid(_adapter *adapter, u8 iface_id) +{ + _irqL irqL; + u8 cam_id = INVALID_CAM_ID; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + + _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); + cam_id = _rtw_mbid_cam_search_by_ifaceid(adapter, iface_id); + _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); + + return cam_id; +} +u8 rtw_get_max_mbid_cam_id(_adapter *adapter) +{ + _irqL irqL; + s8 i; + u8 cam_id = INVALID_CAM_ID; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + + _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); + for (i = (TOTAL_MBID_CAM_NUM - 1); i >= 0; i--) { + if (mbid_cam_ctl->bitmap & BIT(i)) { + cam_id = i; + break; + } + } + _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); + /*RTW_INFO("%s max cam_id:%d\n", __func__, cam_id);*/ + return cam_id; +} + +inline u8 rtw_get_mbid_cam_entry_num(_adapter *adapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + + return ATOMIC_READ(&mbid_cam_ctl->mbid_entry_num); +} + +static inline void mbid_cam_cache_init(_adapter *adapter, struct mbid_cam_cache *pmbid_cam, u8 *mac_addr) +{ + if (adapter && pmbid_cam && mac_addr) { + _rtw_memcpy(pmbid_cam->mac_addr, mac_addr, ETH_ALEN); + pmbid_cam->iface_id = adapter->iface_id; + } +} +static inline void mbid_cam_cache_clr(struct mbid_cam_cache *pmbid_cam) +{ + if (pmbid_cam) { + _rtw_memset(pmbid_cam->mac_addr, 0, ETH_ALEN); + pmbid_cam->iface_id = CONFIG_IFACE_NUMBER; + } +} + +u8 rtw_mbid_camid_alloc(_adapter *adapter, u8 *mac_addr) +{ + _irqL irqL; + u8 cam_id = INVALID_CAM_ID, i; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + u8 entry_num = ATOMIC_READ(&mbid_cam_ctl->mbid_entry_num); + + if (entry_num >= TOTAL_MBID_CAM_NUM) { + RTW_INFO(FUNC_ADPT_FMT" failed !! MBSSID number :%d over TOTAL_CAM_ENTRY(8)\n", FUNC_ADPT_ARG(adapter), entry_num); + rtw_warn_on(1); + } + + if (INVALID_CAM_ID != rtw_mbid_cam_search_by_macaddr(adapter, mac_addr)) + goto exit; + + _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); + for (i = 0; i < TOTAL_MBID_CAM_NUM; i++) { + if (!(mbid_cam_ctl->bitmap & BIT(i))) { + mbid_cam_ctl->bitmap |= BIT(i); + cam_id = i; + break; + } + } + if ((cam_id != INVALID_CAM_ID) && (mac_addr)) + mbid_cam_cache_init(adapter, &dvobj->mbid_cam_cache[cam_id], mac_addr); + _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); + + if (cam_id != INVALID_CAM_ID) { + ATOMIC_INC(&mbid_cam_ctl->mbid_entry_num); + RTW_INFO("%s mac:"MAC_FMT" - cam_id:%d\n", __func__, MAC_ARG(mac_addr), cam_id); +#ifdef DBG_MBID_CAM_DUMP + rtw_mbid_cam_cache_dump(RTW_DBGDUMP, __func__, adapter); +#endif + } else + RTW_INFO("%s [WARN] "MAC_FMT" - invalid cam_id:%d\n", __func__, MAC_ARG(mac_addr), cam_id); +exit: + return cam_id; +} + +u8 rtw_mbid_cam_info_change(_adapter *adapter, u8 *mac_addr) +{ + _irqL irqL; + u8 entry_id = INVALID_CAM_ID; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + + _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); + entry_id = _rtw_mbid_cam_search_by_ifaceid(adapter, adapter->iface_id); + if (entry_id != INVALID_CAM_ID) + mbid_cam_cache_init(adapter, &dvobj->mbid_cam_cache[entry_id], mac_addr); + + _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); + + return entry_id; +} + +u8 rtw_mbid_cam_assign(_adapter *adapter, u8 *mac_addr, u8 camid) +{ + _irqL irqL; + u8 ret = _FALSE; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + + if ((camid >= TOTAL_MBID_CAM_NUM) || (camid == INVALID_CAM_ID)) { + RTW_INFO(FUNC_ADPT_FMT" failed !! invlaid mbid_canid :%d\n", FUNC_ADPT_ARG(adapter), camid); + rtw_warn_on(1); + } + if (INVALID_CAM_ID != rtw_mbid_cam_search_by_macaddr(adapter, mac_addr)) + goto exit; + + _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); + if (!(mbid_cam_ctl->bitmap & BIT(camid))) { + if (mac_addr) { + mbid_cam_ctl->bitmap |= BIT(camid); + mbid_cam_cache_init(adapter, &dvobj->mbid_cam_cache[camid], mac_addr); + ret = _TRUE; + } + } + _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); + + if (ret == _TRUE) { + ATOMIC_INC(&mbid_cam_ctl->mbid_entry_num); + RTW_INFO("%s mac:"MAC_FMT" - cam_id:%d\n", __func__, MAC_ARG(mac_addr), camid); +#ifdef DBG_MBID_CAM_DUMP + rtw_mbid_cam_cache_dump(RTW_DBGDUMP, __func__, adapter); +#endif + } else + RTW_INFO("%s [WARN] mac:"MAC_FMT" - cam_id:%d assigned failed\n", __func__, MAC_ARG(mac_addr), camid); + +exit: + return ret; +} + +void rtw_mbid_camid_clean(_adapter *adapter, u8 mbss_canid) +{ + _irqL irqL; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + + if ((mbss_canid >= TOTAL_MBID_CAM_NUM) || (mbss_canid == INVALID_CAM_ID)) { + RTW_INFO(FUNC_ADPT_FMT" failed !! invlaid mbid_canid :%d\n", FUNC_ADPT_ARG(adapter), mbss_canid); + rtw_warn_on(1); + } + _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); + mbid_cam_cache_clr(&dvobj->mbid_cam_cache[mbss_canid]); + mbid_cam_ctl->bitmap &= (~BIT(mbss_canid)); + _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); + ATOMIC_DEC(&mbid_cam_ctl->mbid_entry_num); + RTW_INFO("%s - cam_id:%d\n", __func__, mbss_canid); +} +int rtw_mbid_cam_cache_dump(void *sel, const char *fun_name, _adapter *adapter) +{ + _irqL irqL; + u8 i; + _adapter *iface; + u8 iface_id; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + u8 entry_num = ATOMIC_READ(&mbid_cam_ctl->mbid_entry_num); + u8 max_cam_id = rtw_get_max_mbid_cam_id(adapter); + + RTW_PRINT_SEL(sel, "== MBSSID CAM DUMP (%s)==\n", fun_name); + + _enter_critical_bh(&mbid_cam_ctl->lock, &irqL); + RTW_PRINT_SEL(sel, "Entry numbers:%d, max_camid:%d, bitmap:0x%08x\n", entry_num, max_cam_id, mbid_cam_ctl->bitmap); + for (i = 0; i < TOTAL_MBID_CAM_NUM; i++) { + RTW_PRINT_SEL(sel, "CAM_ID = %d\t", i); + + if (mbid_cam_ctl->bitmap & BIT(i)) { + iface_id = dvobj->mbid_cam_cache[i].iface_id; + RTW_PRINT_SEL(sel, "IF_ID:%d\t", iface_id); + RTW_PRINT_SEL(sel, "MAC Addr:"MAC_FMT"\t", MAC_ARG(dvobj->mbid_cam_cache[i].mac_addr)); + + iface = dvobj->padapters[iface_id]; + if (iface) { + if (check_fwstate(&iface->mlmepriv, WIFI_STATION_STATE) == _TRUE) + RTW_PRINT_SEL(sel, "ROLE:%s\n", "STA"); + else if (check_fwstate(&iface->mlmepriv, WIFI_AP_STATE) == _TRUE) + RTW_PRINT_SEL(sel, "ROLE:%s\n", "AP"); + else + RTW_PRINT_SEL(sel, "ROLE:%s\n", "NONE"); + } + + } else + RTW_PRINT_SEL(sel, "N/A\n"); + } + _exit_critical_bh(&mbid_cam_ctl->lock, &irqL); + return 0; +} + +static void read_mbssid_cam(_adapter *padapter, u8 cam_addr, u8 *mac) +{ + u8 poll = 1; + u8 cam_ready = _FALSE; + u32 cam_data1 = 0; + u16 cam_data2 = 0; + + if (RTW_CANNOT_RUN(padapter)) + return; + + rtw_write32(padapter, REG_MBIDCAMCFG_2, BIT_MBIDCAM_POLL | ((cam_addr & MBIDCAM_ADDR_MASK) << MBIDCAM_ADDR_SHIFT)); + + do { + if (0 == (rtw_read32(padapter, REG_MBIDCAMCFG_2) & BIT_MBIDCAM_POLL)) { + cam_ready = _TRUE; + break; + } + poll++; + } while ((poll % 10) != 0 && !RTW_CANNOT_RUN(padapter)); + + if (cam_ready) { + cam_data1 = rtw_read32(padapter, REG_MBIDCAMCFG_1); + mac[0] = cam_data1 & 0xFF; + mac[1] = (cam_data1 >> 8) & 0xFF; + mac[2] = (cam_data1 >> 16) & 0xFF; + mac[3] = (cam_data1 >> 24) & 0xFF; + + cam_data2 = rtw_read16(padapter, REG_MBIDCAMCFG_2); + mac[4] = cam_data2 & 0xFF; + mac[5] = (cam_data2 >> 8) & 0xFF; + } + +} +int rtw_mbid_cam_dump(void *sel, const char *fun_name, _adapter *adapter) +{ + /*_irqL irqL;*/ + u8 i; + u8 mac_addr[ETH_ALEN]; + + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + + RTW_PRINT_SEL(sel, "\n== MBSSID HW-CAM DUMP (%s)==\n", fun_name); + + /*_enter_critical_bh(&mbid_cam_ctl->lock, &irqL);*/ + for (i = 0; i < TOTAL_MBID_CAM_NUM; i++) { + RTW_PRINT_SEL(sel, "CAM_ID = %d\t", i); + _rtw_memset(mac_addr, 0, ETH_ALEN); + read_mbssid_cam(adapter, i, mac_addr); + RTW_PRINT_SEL(sel, "MAC Addr:"MAC_FMT"\n", MAC_ARG(mac_addr)); + } + /*_exit_critical_bh(&mbid_cam_ctl->lock, &irqL);*/ + return 0; +} + +static void write_mbssid_cam(_adapter *padapter, u8 cam_addr, u8 *mac) +{ + u32 cam_val[2] = {0}; + + cam_val[0] = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]; + cam_val[1] = ((cam_addr & MBIDCAM_ADDR_MASK) << MBIDCAM_ADDR_SHIFT) | (mac[5] << 8) | mac[4]; + + rtw_hal_set_hwreg(padapter, HW_VAR_MBSSID_CAM_WRITE, (u8 *)cam_val); +} + +static void clear_mbssid_cam(_adapter *padapter, u8 cam_addr) +{ + rtw_hal_set_hwreg(padapter, HW_VAR_MBSSID_CAM_CLEAR, &cam_addr); +} +static void enable_mbssid_cam(_adapter *adapter) +{ + u8 max_cam_id = rtw_get_max_mbid_cam_id(adapter); + /*enable MBSSID*/ + rtw_write32(adapter, REG_RCR, rtw_read32(adapter, REG_RCR) | RCR_ENMBID); + if (max_cam_id != INVALID_CAM_ID) { + rtw_write8(adapter, REG_MBID_NUM, + ((rtw_read8(adapter, REG_MBID_NUM) & 0xF8) | (max_cam_id & 0x07))); + } +} +void rtw_mbid_cam_restore(_adapter *adapter) +{ + u8 i; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mbid_cam_ctl_t *mbid_cam_ctl = &dvobj->mbid_cam_ctl; + +#ifdef DBG_MBID_CAM_DUMP + rtw_mbid_cam_cache_dump(RTW_DBGDUMP, __func__, adapter); +#endif + + for (i = 0; i < TOTAL_MBID_CAM_NUM; i++) { + if (mbid_cam_ctl->bitmap & BIT(i)) { + write_mbssid_cam(adapter, i, dvobj->mbid_cam_cache[i].mac_addr); + RTW_INFO("%s - cam_id:%d => mac:"MAC_FMT"\n", __func__, i, MAC_ARG(dvobj->mbid_cam_cache[i].mac_addr)); + } + } + enable_mbssid_cam(adapter); +} +#endif /*CONFIG_MBSSID_CAM*/ + +#ifdef CONFIG_MI_WITH_MBSSID_CAM +void rtw_hal_set_macaddr_mbid(_adapter *adapter, u8 *mac_addr) +{ + +#if 0 /*TODO - modify for more flexible*/ + u8 idx = 0; + + if ((check_fwstate(&adapter->mlmepriv, WIFI_STATION_STATE) == _TRUE) && + (DEV_STA_NUM(adapter_to_dvobj(adapter)) == 1)) { + for (idx = 0; idx < 6; idx++) + rtw_write8(GET_PRIMARY_ADAPTER(adapter), (REG_MACID + idx), val[idx]); + } else { + /*MBID entry_id = 0~7 ,0 for root AP, 1~7 for VAP*/ + u8 entry_id; + + if ((check_fwstate(&adapter->mlmepriv, WIFI_AP_STATE) == _TRUE) && + (DEV_AP_NUM(adapter_to_dvobj(adapter)) == 1)) { + entry_id = 0; + if (rtw_mbid_cam_assign(adapter, val, entry_id)) { + RTW_INFO(FUNC_ADPT_FMT" Root AP assigned success\n", FUNC_ADPT_ARG(adapter)); + write_mbssid_cam(adapter, entry_id, val); + } + } else { + entry_id = rtw_mbid_camid_alloc(adapter, val); + if (entry_id != INVALID_CAM_ID) + write_mbssid_cam(adapter, entry_id, val); + } + } +#else + { + /* + MBID entry_id = 0~7 ,for IFACE_ID0 ~ IFACE_IDx + */ + u8 entry_id = rtw_mbid_camid_alloc(adapter, mac_addr); + + + if (entry_id != INVALID_CAM_ID) { + write_mbssid_cam(adapter, entry_id, mac_addr); + enable_mbssid_cam(adapter); + } + } +#endif +} + +void rtw_hal_change_macaddr_mbid(_adapter *adapter, u8 *mac_addr) +{ + u8 idx = 0; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + u8 entry_id; + + if (!mac_addr) { + rtw_warn_on(1); + return; + } + + + entry_id = rtw_mbid_cam_info_change(adapter, mac_addr); + + if (entry_id != INVALID_CAM_ID) + write_mbssid_cam(adapter, entry_id, mac_addr); +} + + +#endif/*#ifdef CONFIG_MI_WITH_MBSSID_CAM*/ + +void rtw_hal_set_macaddr_port(_adapter *adapter, u8 *val) +{ + u8 idx = 0; + u32 reg_macid = 0; + + if (val == NULL) + return; + + RTW_INFO("%s "ADPT_FMT"- hw port(%d) mac_addr ="MAC_FMT"\n", __func__, + ADPT_ARG(adapter), adapter->hw_port, MAC_ARG(val)); + + switch (adapter->hw_port) { + case HW_PORT0: + default: + reg_macid = REG_MACID; + break; + case HW_PORT1: + reg_macid = REG_MACID1; + break; +#if defined(CONFIG_RTL8814A) + case HW_PORT2: + reg_macid = REG_MACID2; + break; + case HW_PORT3: + reg_macid = REG_MACID3; + break; + case HW_PORT4: + reg_macid = REG_MACID4; + break; +#endif/*defined(CONFIG_RTL8814A)*/ + } + + for (idx = 0; idx < 6; idx++) + rtw_write8(GET_PRIMARY_ADAPTER(adapter), (reg_macid + idx), val[idx]); +} +void rtw_hal_get_macaddr_port(_adapter *adapter, u8 *mac_addr) +{ + u8 idx = 0; + u32 reg_macid = 0; + + if (mac_addr == NULL) + return; + + _rtw_memset(mac_addr, 0, ETH_ALEN); + switch (adapter->hw_port) { + case HW_PORT0: + default: + reg_macid = REG_MACID; + break; + case HW_PORT1: + reg_macid = REG_MACID1; + break; +#if defined(CONFIG_RTL8814A) + case HW_PORT2: + reg_macid = REG_MACID2; + break; + case HW_PORT3: + reg_macid = REG_MACID3; + break; + case HW_PORT4: + reg_macid = REG_MACID4; + break; +#endif /*defined(CONFIG_RTL8814A)*/ + } + + for (idx = 0; idx < 6; idx++) + mac_addr[idx] = rtw_read8(GET_PRIMARY_ADAPTER(adapter), (reg_macid + idx)); + + RTW_INFO("%s "ADPT_FMT"- hw port(%d) mac_addr ="MAC_FMT"\n", __func__, + ADPT_ARG(adapter), adapter->hw_port, MAC_ARG(mac_addr)); +} + +void rtw_hal_set_bssid(_adapter *adapter, u8 *val) +{ + u8 idx = 0; + u32 reg_bssid = 0; + + switch (adapter->hw_port) { + case HW_PORT0: + default: + reg_bssid = REG_BSSID; + break; + case HW_PORT1: + reg_bssid = REG_BSSID1; + break; +#if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) + case HW_PORT2: + reg_bssid = REG_BSSID2; + break; + case HW_PORT3: + reg_bssid = REG_BSSID3; + break; + case HW_PORT4: + reg_bssid = REG_BSSID4; + break; +#endif/*defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B)*/ + } + + for (idx = 0 ; idx < 6; idx++) + rtw_write8(adapter, (reg_bssid + idx), val[idx]); + + RTW_INFO("%s "ADPT_FMT"- hw port -%d BSSID: "MAC_FMT"\n", __func__, ADPT_ARG(adapter), adapter->hw_port, MAC_ARG(val)); +} + +void rtw_hal_get_msr(_adapter *adapter, u8 *net_type) +{ + switch (adapter->hw_port) { + case HW_PORT0: + /*REG_CR - BIT[17:16]-Network Type for port 1*/ + *net_type = rtw_read8(adapter, MSR) & 0x03; + break; + case HW_PORT1: + /*REG_CR - BIT[19:18]-Network Type for port 1*/ + *net_type = (rtw_read8(adapter, MSR) & 0x0C) >> 2; + break; +#if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) + case HW_PORT2: + /*REG_CR_EXT- BIT[1:0]-Network Type for port 2*/ + *net_type = rtw_read8(adapter, MSR1) & 0x03; + break; + case HW_PORT3: + /*REG_CR_EXT- BIT[3:2]-Network Type for port 3*/ + *net_type = (rtw_read8(adapter, MSR1) & 0x0C) >> 2; + break; + case HW_PORT4: + /*REG_CR_EXT- BIT[5:4]-Network Type for port 4*/ + *net_type = (rtw_read8(adapter, MSR1) & 0x30) >> 4; + break; +#endif /*#if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B)*/ + default: + RTW_INFO("[WARN] "ADPT_FMT"- invalid hw port -%d\n", + ADPT_ARG(adapter), adapter->hw_port); + rtw_warn_on(1); + break; + } +} + +void rtw_hal_set_msr(_adapter *adapter, u8 net_type) +{ + u8 val8 = 0; + + switch (adapter->hw_port) { + case HW_PORT0: +#if defined(CONFIG_MI_WITH_MBSSID_CAM) && defined(CONFIG_MBSSID_CAM) /*For 2 hw ports - 88E/92E/8812/8821/8723B*/ + if (rtw_get_mbid_cam_entry_num(adapter)) { + if (net_type != _HW_STATE_NOLINK_) + net_type = _HW_STATE_AP_; + } +#endif + /*REG_CR - BIT[17:16]-Network Type for port 0*/ + val8 = rtw_read8(adapter, MSR) & 0x0C; + val8 |= net_type; + rtw_write8(adapter, MSR, val8); + break; + case HW_PORT1: + /*REG_CR - BIT[19:18]-Network Type for port 1*/ + val8 = rtw_read8(adapter, MSR) & 0x03; + val8 |= net_type << 2; + rtw_write8(adapter, MSR, val8); + break; +#if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) + case HW_PORT2: + /*REG_CR_EXT- BIT[1:0]-Network Type for port 2*/ + val8 = rtw_read8(adapter, MSR1) & 0xFC; + val8 |= net_type; + rtw_write8(adapter, MSR1, val8); + break; + case HW_PORT3: + /*REG_CR_EXT- BIT[3:2]-Network Type for port 3*/ + val8 = rtw_read8(adapter, MSR1) & 0xF3; + val8 |= net_type << 2; + rtw_write8(adapter, MSR1, val8); + break; + case HW_PORT4: + /*REG_CR_EXT- BIT[5:4]-Network Type for port 4*/ + val8 = rtw_read8(adapter, MSR1) & 0xCF; + val8 |= net_type << 4; + rtw_write8(adapter, MSR1, val8); + break; +#endif /* CONFIG_RTL8814A | CONFIG_RTL8822B */ + default: + RTW_INFO("[WARN] "ADPT_FMT"- invalid hw port -%d\n", + ADPT_ARG(adapter), adapter->hw_port); + rtw_warn_on(1); + break; + } +} + +void hw_var_port_switch(_adapter *adapter) +{ +#ifdef CONFIG_CONCURRENT_MODE +#ifdef CONFIG_RUNTIME_PORT_SWITCH + /* + 0x102: MSR + 0x550: REG_BCN_CTRL + 0x551: REG_BCN_CTRL_1 + 0x55A: REG_ATIMWND + 0x560: REG_TSFTR + 0x568: REG_TSFTR1 + 0x570: REG_ATIMWND_1 + 0x610: REG_MACID + 0x618: REG_BSSID + 0x700: REG_MACID1 + 0x708: REG_BSSID1 + */ + + int i; + u8 msr; + u8 bcn_ctrl; + u8 bcn_ctrl_1; + u8 atimwnd[2]; + u8 atimwnd_1[2]; + u8 tsftr[8]; + u8 tsftr_1[8]; + u8 macid[6]; + u8 bssid[6]; + u8 macid_1[6]; + u8 bssid_1[6]; + + u8 hw_port; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + _adapter *iface = NULL; + + msr = rtw_read8(adapter, MSR); + bcn_ctrl = rtw_read8(adapter, REG_BCN_CTRL); + bcn_ctrl_1 = rtw_read8(adapter, REG_BCN_CTRL_1); + + for (i = 0; i < 2; i++) + atimwnd[i] = rtw_read8(adapter, REG_ATIMWND + i); + for (i = 0; i < 2; i++) + atimwnd_1[i] = rtw_read8(adapter, REG_ATIMWND_1 + i); + + for (i = 0; i < 8; i++) + tsftr[i] = rtw_read8(adapter, REG_TSFTR + i); + for (i = 0; i < 8; i++) + tsftr_1[i] = rtw_read8(adapter, REG_TSFTR1 + i); + + for (i = 0; i < 6; i++) + macid[i] = rtw_read8(adapter, REG_MACID + i); + + for (i = 0; i < 6; i++) + bssid[i] = rtw_read8(adapter, REG_BSSID + i); + + for (i = 0; i < 6; i++) + macid_1[i] = rtw_read8(adapter, REG_MACID1 + i); + + for (i = 0; i < 6; i++) + bssid_1[i] = rtw_read8(adapter, REG_BSSID1 + i); + +#ifdef DBG_RUNTIME_PORT_SWITCH + RTW_INFO(FUNC_ADPT_FMT" before switch\n" + "msr:0x%02x\n" + "bcn_ctrl:0x%02x\n" + "bcn_ctrl_1:0x%02x\n" + "atimwnd:0x%04x\n" + "atimwnd_1:0x%04x\n" + "tsftr:%llu\n" + "tsftr1:%llu\n" + "macid:"MAC_FMT"\n" + "bssid:"MAC_FMT"\n" + "macid_1:"MAC_FMT"\n" + "bssid_1:"MAC_FMT"\n" + , FUNC_ADPT_ARG(adapter) + , msr + , bcn_ctrl + , bcn_ctrl_1 + , *((u16 *)atimwnd) + , *((u16 *)atimwnd_1) + , *((u64 *)tsftr) + , *((u64 *)tsftr_1) + , MAC_ARG(macid) + , MAC_ARG(bssid) + , MAC_ARG(macid_1) + , MAC_ARG(bssid_1) + ); +#endif /* DBG_RUNTIME_PORT_SWITCH */ + + /* disable bcn function, disable update TSF */ + rtw_write8(adapter, REG_BCN_CTRL, (bcn_ctrl & (~EN_BCN_FUNCTION)) | DIS_TSF_UDT); + rtw_write8(adapter, REG_BCN_CTRL_1, (bcn_ctrl_1 & (~EN_BCN_FUNCTION)) | DIS_TSF_UDT); + + /* switch msr */ + msr = (msr & 0xf0) | ((msr & 0x03) << 2) | ((msr & 0x0c) >> 2); + rtw_write8(adapter, MSR, msr); + + /* write port0 */ + rtw_write8(adapter, REG_BCN_CTRL, bcn_ctrl_1 & ~EN_BCN_FUNCTION); + for (i = 0; i < 2; i++) + rtw_write8(adapter, REG_ATIMWND + i, atimwnd_1[i]); + for (i = 0; i < 8; i++) + rtw_write8(adapter, REG_TSFTR + i, tsftr_1[i]); + for (i = 0; i < 6; i++) + rtw_write8(adapter, REG_MACID + i, macid_1[i]); + for (i = 0; i < 6; i++) + rtw_write8(adapter, REG_BSSID + i, bssid_1[i]); + + /* write port1 */ + rtw_write8(adapter, REG_BCN_CTRL_1, bcn_ctrl & ~EN_BCN_FUNCTION); + for (i = 0; i < 2; i++) + rtw_write8(adapter, REG_ATIMWND_1 + i, atimwnd[i]); + for (i = 0; i < 8; i++) + rtw_write8(adapter, REG_TSFTR1 + i, tsftr[i]); + for (i = 0; i < 6; i++) + rtw_write8(adapter, REG_MACID1 + i, macid[i]); + for (i = 0; i < 6; i++) + rtw_write8(adapter, REG_BSSID1 + i, bssid[i]); + + /* write bcn ctl */ +#ifdef CONFIG_BT_COEXIST + /* always enable port0 beacon function for PSTDMA */ + if (IS_HARDWARE_TYPE_8723B(adapter) || IS_HARDWARE_TYPE_8703B(adapter) + || IS_HARDWARE_TYPE_8723D(adapter)) + bcn_ctrl_1 |= EN_BCN_FUNCTION; + /* always disable port1 beacon function for PSTDMA */ + if (IS_HARDWARE_TYPE_8723B(adapter) || IS_HARDWARE_TYPE_8703B(adapter)) + bcn_ctrl &= ~EN_BCN_FUNCTION; +#endif + rtw_write8(adapter, REG_BCN_CTRL, bcn_ctrl_1); + rtw_write8(adapter, REG_BCN_CTRL_1, bcn_ctrl); + + if (adapter->iface_id == IFACE_ID0) + iface = dvobj->padapters[IFACE_ID1]; + else if (adapter->iface_id == IFACE_ID1) + iface = dvobj->padapters[IFACE_ID0]; + + + if (adapter->hw_port == HW_PORT0) { + adapter->hw_port = HW_PORT1; + iface->hw_port = HW_PORT0; + RTW_PRINT("port switch - port0("ADPT_FMT"), port1("ADPT_FMT")\n", + ADPT_ARG(iface), ADPT_ARG(adapter)); + } else { + adapter->hw_port = HW_PORT0; + iface->hw_port = HW_PORT1; + RTW_PRINT("port switch - port0("ADPT_FMT"), port1("ADPT_FMT")\n", + ADPT_ARG(adapter), ADPT_ARG(iface)); + } + +#ifdef DBG_RUNTIME_PORT_SWITCH + msr = rtw_read8(adapter, MSR); + bcn_ctrl = rtw_read8(adapter, REG_BCN_CTRL); + bcn_ctrl_1 = rtw_read8(adapter, REG_BCN_CTRL_1); + + for (i = 0; i < 2; i++) + atimwnd[i] = rtw_read8(adapter, REG_ATIMWND + i); + for (i = 0; i < 2; i++) + atimwnd_1[i] = rtw_read8(adapter, REG_ATIMWND_1 + i); + + for (i = 0; i < 8; i++) + tsftr[i] = rtw_read8(adapter, REG_TSFTR + i); + for (i = 0; i < 8; i++) + tsftr_1[i] = rtw_read8(adapter, REG_TSFTR1 + i); + + for (i = 0; i < 6; i++) + macid[i] = rtw_read8(adapter, REG_MACID + i); + + for (i = 0; i < 6; i++) + bssid[i] = rtw_read8(adapter, REG_BSSID + i); + + for (i = 0; i < 6; i++) + macid_1[i] = rtw_read8(adapter, REG_MACID1 + i); + + for (i = 0; i < 6; i++) + bssid_1[i] = rtw_read8(adapter, REG_BSSID1 + i); + + RTW_INFO(FUNC_ADPT_FMT" after switch\n" + "msr:0x%02x\n" + "bcn_ctrl:0x%02x\n" + "bcn_ctrl_1:0x%02x\n" + "atimwnd:%u\n" + "atimwnd_1:%u\n" + "tsftr:%llu\n" + "tsftr1:%llu\n" + "macid:"MAC_FMT"\n" + "bssid:"MAC_FMT"\n" + "macid_1:"MAC_FMT"\n" + "bssid_1:"MAC_FMT"\n" + , FUNC_ADPT_ARG(adapter) + , msr + , bcn_ctrl + , bcn_ctrl_1 + , *((u16 *)atimwnd) + , *((u16 *)atimwnd_1) + , *((u64 *)tsftr) + , *((u64 *)tsftr_1) + , MAC_ARG(macid) + , MAC_ARG(bssid) + , MAC_ARG(macid_1) + , MAC_ARG(bssid_1) + ); +#endif /* DBG_RUNTIME_PORT_SWITCH */ + +#endif /* CONFIG_RUNTIME_PORT_SWITCH */ +#endif /* CONFIG_CONCURRENT_MODE */ +} + +const char *const _h2c_msr_role_str[] = { + "RSVD", + "STA", + "AP", + "GC", + "GO", + "TDLS", + "ADHOC", + "INVALID", +}; + +#ifdef CONFIG_FW_MULTI_PORT_SUPPORT +s32 rtw_hal_set_default_port_id_cmd(_adapter *adapter, u8 mac_id) +{ + s32 ret = _SUCCESS; + u8 parm[H2C_DEFAULT_PORT_ID_LEN] = {0}; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + + SET_H2CCMD_DFTPID_PORT_ID(parm, adapter->hw_port); + SET_H2CCMD_DFTPID_MAC_ID(parm, mac_id); + + RTW_DBG_DUMP("DFT port id parm:", parm, H2C_DEFAULT_PORT_ID_LEN); + RTW_INFO("%s port_id :%d, mad_id:%d\n", __func__, adapter->hw_port, mac_id); + + ret = rtw_hal_fill_h2c_cmd(adapter, H2C_DEFAULT_PORT_ID, H2C_DEFAULT_PORT_ID_LEN, parm); + dvobj->default_port_id = adapter->hw_port; + + return ret; +} +s32 rtw_set_default_port_id(_adapter *adapter) +{ + s32 ret = _SUCCESS; + struct sta_info *psta; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + + if (adapter->hw_port == dvobj->default_port_id) + return ret; + + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) { + psta = rtw_get_stainfo(&adapter->stapriv, get_bssid(pmlmepriv)); + if (psta) + ret = rtw_hal_set_default_port_id_cmd(adapter, psta->mac_id); + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) { + + } else { + } + + return ret; +} +s32 rtw_set_ps_rsvd_page(_adapter *adapter) +{ + s32 ret = _SUCCESS; + u16 media_status_rpt = RT_MEDIA_CONNECT; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + + if (adapter->hw_port == dvobj->default_port_id) + return ret; + + rtw_hal_set_hwreg(adapter, HW_VAR_H2C_FW_JOINBSSRPT, + (u8 *)&media_status_rpt); + + return ret; +} + +#endif +/* +* rtw_hal_set_FwMediaStatusRpt_cmd - +* +* @adapter: +* @opmode: 0:disconnect, 1:connect +* @miracast: 0:it's not in miracast scenario. 1:it's in miracast scenario +* @miracast_sink: 0:source. 1:sink +* @role: The role of this macid. 0:rsvd. 1:STA. 2:AP. 3:GC. 4:GO. 5:TDLS +* @macid: +* @macid_ind: 0:update Media Status to macid. 1:update Media Status from macid to macid_end +* @macid_end: +*/ +s32 rtw_hal_set_FwMediaStatusRpt_cmd(_adapter *adapter, bool opmode, bool miracast, bool miracast_sink, u8 role, u8 macid, bool macid_ind, u8 macid_end) +{ + struct macid_ctl_t *macid_ctl = &adapter->dvobj->macid_ctl; + u8 parm[H2C_MEDIA_STATUS_RPT_LEN] = {0}; + int i; + s32 ret; + + SET_H2CCMD_MSRRPT_PARM_OPMODE(parm, opmode); + SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, macid_ind); + SET_H2CCMD_MSRRPT_PARM_MIRACAST(parm, miracast); + SET_H2CCMD_MSRRPT_PARM_MIRACAST_SINK(parm, miracast_sink); + SET_H2CCMD_MSRRPT_PARM_ROLE(parm, role); + SET_H2CCMD_MSRRPT_PARM_MACID(parm, macid); + SET_H2CCMD_MSRRPT_PARM_MACID_END(parm, macid_end); +#ifdef CONFIG_FW_MULTI_PORT_SUPPORT + SET_H2CCMD_MSRRPT_PARM_PORT_NUM(parm, adapter->hw_port); +#endif + RTW_DBG_DUMP("MediaStatusRpt parm:", parm, H2C_MEDIA_STATUS_RPT_LEN); + +#ifdef CONFIG_DFS_MASTER + /* workaround for TXPAUSE cleared issue by FW's MediaStatusRpt handling */ + if (macid_ind == 0 && macid == 1 + && !rtw_odm_dfs_domain_unknown(adapter) + ) { + u8 parm0_bak = parm[0]; + + SET_H2CCMD_MSRRPT_PARM_MACID_IND(&parm0_bak, 0); + if (macid_ctl->h2c_msr[macid] == parm0_bak) { + ret = _SUCCESS; + goto post_action; + } + } +#endif + + ret = rtw_hal_fill_h2c_cmd(adapter, H2C_MEDIA_STATUS_RPT, H2C_MEDIA_STATUS_RPT_LEN, parm); + if (ret != _SUCCESS) + goto exit; + +#ifdef CONFIG_DFS_MASTER +post_action: +#endif + +#if defined(CONFIG_RTL8188E) + if (rtw_get_chip_type(adapter) == RTL8188E) { + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + + /* 8188E FW doesn't set macid no link, driver does it by self */ + if (opmode) + rtw_hal_set_hwreg(adapter, HW_VAR_MACID_LINK, &macid); + else + rtw_hal_set_hwreg(adapter, HW_VAR_MACID_NOLINK, &macid); + + /* for 8188E RA */ +#if (RATE_ADAPTIVE_SUPPORT == 1) + if (hal_data->fw_ractrl == _FALSE) { + u8 max_macid; + + max_macid = rtw_search_max_mac_id(adapter); + rtw_hal_set_hwreg(adapter, HW_VAR_TX_RPT_MAX_MACID, &max_macid); + } +#endif + } +#endif + +#if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) + /* TODO: this should move to IOT issue area */ + if (rtw_get_chip_type(adapter) == RTL8812 + || rtw_get_chip_type(adapter) == RTL8821 + ) { + if (MLME_IS_STA(adapter)) + Hal_PatchwithJaguar_8812(adapter, opmode); + } +#endif + + SET_H2CCMD_MSRRPT_PARM_MACID_IND(parm, 0); + if (macid_ind == 0) + macid_end = macid; + + for (i = macid; macid <= macid_end; macid++) { + rtw_macid_ctl_set_h2c_msr(macid_ctl, macid, parm[0]); + if (!opmode) { + rtw_macid_ctl_set_bw(macid_ctl, macid, CHANNEL_WIDTH_20); + rtw_macid_ctl_set_vht_en(macid_ctl, macid, 0); + rtw_macid_ctl_set_rate_bmp0(macid_ctl, macid, 0); + rtw_macid_ctl_set_rate_bmp1(macid_ctl, macid, 0); + } + } + if (!opmode) + rtw_update_tx_rate_bmp(adapter_to_dvobj(adapter)); + +exit: + return ret; +} + +inline s32 rtw_hal_set_FwMediaStatusRpt_single_cmd(_adapter *adapter, bool opmode, bool miracast, bool miracast_sink, u8 role, u8 macid) +{ + return rtw_hal_set_FwMediaStatusRpt_cmd(adapter, opmode, miracast, miracast_sink, role, macid, 0, 0); +} + +inline s32 rtw_hal_set_FwMediaStatusRpt_range_cmd(_adapter *adapter, bool opmode, bool miracast, bool miracast_sink, u8 role, u8 macid, u8 macid_end) +{ + return rtw_hal_set_FwMediaStatusRpt_cmd(adapter, opmode, miracast, miracast_sink, role, macid, 1, macid_end); +} + +void rtw_hal_set_FwRsvdPage_cmd(PADAPTER padapter, PRSVDPAGE_LOC rsvdpageloc) +{ + struct hal_ops *pHalFunc = &padapter->hal_func; + u8 u1H2CRsvdPageParm[H2C_RSVDPAGE_LOC_LEN] = {0}; + u8 ret = 0; + + RTW_INFO("RsvdPageLoc: ProbeRsp=%d PsPoll=%d Null=%d QoSNull=%d BTNull=%d\n", + rsvdpageloc->LocProbeRsp, rsvdpageloc->LocPsPoll, + rsvdpageloc->LocNullData, rsvdpageloc->LocQosNull, + rsvdpageloc->LocBTQosNull); + + SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1H2CRsvdPageParm, rsvdpageloc->LocProbeRsp); + SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1H2CRsvdPageParm, rsvdpageloc->LocPsPoll); + SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocNullData); + SET_H2CCMD_RSVDPAGE_LOC_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocQosNull); + SET_H2CCMD_RSVDPAGE_LOC_BT_QOS_NULL_DATA(u1H2CRsvdPageParm, rsvdpageloc->LocBTQosNull); + + ret = rtw_hal_fill_h2c_cmd(padapter, + H2C_RSVD_PAGE, + H2C_RSVDPAGE_LOC_LEN, + u1H2CRsvdPageParm); + +} + +#ifdef CONFIG_GPIO_WAKEUP +void rtw_hal_switch_gpio_wl_ctrl(_adapter *padapter, u8 index, u8 enable) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + + if (IS_8723D_SERIES(pHalData->version_id) || IS_8822B_SERIES(pHalData->version_id)) + rtw_hal_set_hwreg(padapter, HW_SET_GPIO_WL_CTRL, (u8 *)(&enable)); + /* + * Switch GPIO_13, GPIO_14 to wlan control, or pull GPIO_13,14 MUST fail. + * It happended at 8723B/8192E/8821A. New IC will check multi function GPIO, + * and implement HAL function. + * TODO: GPIO_8 multi function? + */ + + if (index == 13 || index == 14) + rtw_hal_set_hwreg(padapter, HW_SET_GPIO_WL_CTRL, (u8 *)(&enable)); +} + +void rtw_hal_set_output_gpio(_adapter *padapter, u8 index, u8 outputval) +{ + if (index <= 7) { + /* config GPIO mode */ + rtw_write8(padapter, REG_GPIO_PIN_CTRL + 3, + rtw_read8(padapter, REG_GPIO_PIN_CTRL + 3) & ~BIT(index)); + + /* config GPIO Sel */ + /* 0: input */ + /* 1: output */ + rtw_write8(padapter, REG_GPIO_PIN_CTRL + 2, + rtw_read8(padapter, REG_GPIO_PIN_CTRL + 2) | BIT(index)); + + /* set output value */ + if (outputval) { + rtw_write8(padapter, REG_GPIO_PIN_CTRL + 1, + rtw_read8(padapter, REG_GPIO_PIN_CTRL + 1) | BIT(index)); + } else { + rtw_write8(padapter, REG_GPIO_PIN_CTRL + 1, + rtw_read8(padapter, REG_GPIO_PIN_CTRL + 1) & ~BIT(index)); + } + } else if (index <= 15) { + /* 88C Series: */ + /* index: 11~8 transform to 3~0 */ + /* 8723 Series: */ + /* index: 12~8 transform to 4~0 */ + + index -= 8; + + /* config GPIO mode */ + rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 3, + rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 3) & ~BIT(index)); + + /* config GPIO Sel */ + /* 0: input */ + /* 1: output */ + rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 2, + rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 2) | BIT(index)); + + /* set output value */ + if (outputval) { + rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 1, + rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 1) | BIT(index)); + } else { + rtw_write8(padapter, REG_GPIO_PIN_CTRL_2 + 1, + rtw_read8(padapter, REG_GPIO_PIN_CTRL_2 + 1) & ~BIT(index)); + } + } else { + RTW_INFO("%s: invalid GPIO%d=%d\n", + __FUNCTION__, index, outputval); + } +} +#endif + +void rtw_hal_set_FwAoacRsvdPage_cmd(PADAPTER padapter, PRSVDPAGE_LOC rsvdpageloc) +{ + struct hal_ops *pHalFunc = &padapter->hal_func; + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(padapter); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + u8 res = 0, count = 0, ret = 0; +#ifdef CONFIG_WOWLAN + u8 u1H2CAoacRsvdPageParm[H2C_AOAC_RSVDPAGE_LOC_LEN] = {0}; + + RTW_INFO("AOACRsvdPageLoc: RWC=%d ArpRsp=%d NbrAdv=%d GtkRsp=%d GtkInfo=%d ProbeReq=%d NetworkList=%d\n", + rsvdpageloc->LocRemoteCtrlInfo, rsvdpageloc->LocArpRsp, + rsvdpageloc->LocNbrAdv, rsvdpageloc->LocGTKRsp, + rsvdpageloc->LocGTKInfo, rsvdpageloc->LocProbeReq, + rsvdpageloc->LocNetList); + + if (check_fwstate(pmlmepriv, _FW_LINKED)) { + SET_H2CCMD_AOAC_RSVDPAGE_LOC_REMOTE_WAKE_CTRL_INFO(u1H2CAoacRsvdPageParm, rsvdpageloc->LocRemoteCtrlInfo); + SET_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(u1H2CAoacRsvdPageParm, rsvdpageloc->LocArpRsp); + /* SET_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(u1H2CAoacRsvdPageParm, rsvdpageloc->LocNbrAdv); */ +#ifdef CONFIG_GTK_OL + SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(u1H2CAoacRsvdPageParm, rsvdpageloc->LocGTKRsp); + SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(u1H2CAoacRsvdPageParm, rsvdpageloc->LocGTKInfo); + SET_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_EXT_MEM(u1H2CAoacRsvdPageParm, rsvdpageloc->LocGTKEXTMEM); +#endif /* CONFIG_GTK_OL */ + ret = rtw_hal_fill_h2c_cmd(padapter, + H2C_AOAC_RSVD_PAGE, + H2C_AOAC_RSVDPAGE_LOC_LEN, + u1H2CAoacRsvdPageParm); + + RTW_INFO("AOAC Report=%d\n", rsvdpageloc->LocAOACReport); + _rtw_memset(&u1H2CAoacRsvdPageParm, 0, sizeof(u1H2CAoacRsvdPageParm)); + SET_H2CCMD_AOAC_RSVDPAGE_LOC_AOAC_REPORT(u1H2CAoacRsvdPageParm, + rsvdpageloc->LocAOACReport); + ret = rtw_hal_fill_h2c_cmd(padapter, + H2C_AOAC_RSVDPAGE3, + H2C_AOAC_RSVDPAGE_LOC_LEN, + u1H2CAoacRsvdPageParm); + pwrpriv->wowlan_aoac_rpt_loc = rsvdpageloc->LocAOACReport; + } +#ifdef CONFIG_PNO_SUPPORT + else { + + if (!pwrpriv->wowlan_in_resume) { + RTW_INFO("NLO_INFO=%d\n", rsvdpageloc->LocPNOInfo); + _rtw_memset(&u1H2CAoacRsvdPageParm, 0, + sizeof(u1H2CAoacRsvdPageParm)); + SET_H2CCMD_AOAC_RSVDPAGE_LOC_NLO_INFO(u1H2CAoacRsvdPageParm, + rsvdpageloc->LocPNOInfo); + ret = rtw_hal_fill_h2c_cmd(padapter, + H2C_AOAC_RSVDPAGE3, + H2C_AOAC_RSVDPAGE_LOC_LEN, + u1H2CAoacRsvdPageParm); + } + } +#endif /* CONFIG_PNO_SUPPORT */ +#endif /* CONFIG_WOWLAN */ +} + +/*#define DBG_GET_RSVD_PAGE*/ +int rtw_hal_get_rsvd_page(_adapter *adapter, u32 page_offset, + u32 page_num, u8 *buffer, u32 buffer_size) +{ + u32 addr = 0, size = 0, count = 0; + u32 page_size = 0, data_low = 0, data_high = 0; + u16 txbndy = 0, offset = 0; + u8 i = 0; + bool rst = _FALSE; + + rtw_hal_get_def_var(adapter, HAL_DEF_TX_PAGE_SIZE, &page_size); + + addr = page_offset * page_size; + size = page_num * page_size; + + if (buffer_size < size) { + RTW_ERR("%s buffer_size(%d) < get page total size(%d)\n", + __func__, buffer_size, size); + return rst; + } +#ifdef RTW_HALMAC + if (rtw_halmac_dump_fifo(adapter_to_dvobj(adapter), 2, addr, size, buffer) < 0) + rst = _FALSE; + else + rst = _TRUE; +#else + txbndy = rtw_read8(adapter, REG_TDECTRL + 1); + + offset = (txbndy + page_offset) << 4; + count = (buffer_size / 8) + 1; + + rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, 0x69); + + for (i = 0 ; i < count ; i++) { + rtw_write32(adapter, REG_PKTBUF_DBG_CTRL, offset + i); + data_low = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_L); + data_high = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_H); + _rtw_memcpy(buffer + (i * 8), + &data_low, sizeof(data_low)); + _rtw_memcpy(buffer + ((i * 8) + 4), + &data_high, sizeof(data_high)); + } + rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, 0x0); + rst = _TRUE; +#endif /*RTW_HALMAC*/ + +#ifdef DBG_GET_RSVD_PAGE + RTW_INFO("%s [page_offset:%d , page_num:%d][start_addr:0x%04x , size:%d]\n", + __func__, page_offset, page_num, addr, size); + RTW_INFO_DUMP("\n", buffer, size); + RTW_INFO(" ==================================================\n"); +#endif + return rst; +} + +void rtw_dump_rsvd_page(void *sel, _adapter *adapter, u8 page_offset, u8 page_num) +{ + u32 page_size = 0; + u8 *buffer = NULL; + u32 buf_size = 0; + + if (page_num == 0) + return; + + RTW_PRINT_SEL(sel, "======= RSVG PAGE DUMP =======\n"); + RTW_PRINT_SEL(sel, "page_offset:%d, page_num:%d\n", page_offset, page_num); + + rtw_hal_get_def_var(adapter, HAL_DEF_TX_PAGE_SIZE, &page_size); + if (page_size) { + buf_size = page_size * page_num; + buffer = rtw_zvmalloc(buf_size); + + if (buffer) { + rtw_hal_get_rsvd_page(adapter, page_offset, page_num, buffer, buf_size); + _RTW_DUMP_SEL(sel, buffer, buf_size); + rtw_vmfree(buffer, buf_size); + } else + RTW_PRINT_SEL(sel, "ERROR - rsvd_buf mem allocate failed\n"); + } else + RTW_PRINT_SEL(sel, "ERROR - Tx page size is zero ??\n"); + + RTW_PRINT_SEL(sel, "==========================\n"); +} + +#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) +static void rtw_hal_force_enable_rxdma(_adapter *adapter) +{ + RTW_INFO("%s: Set 0x690=0x00\n", __func__); + rtw_write8(adapter, REG_WOW_CTRL, + (rtw_read8(adapter, REG_WOW_CTRL) & 0xf0)); + RTW_PRINT("%s: Release RXDMA\n", __func__); + rtw_write32(adapter, REG_RXPKT_NUM, + (rtw_read32(adapter, REG_RXPKT_NUM) & (~RW_RELEASE_EN))); +} +#if defined(CONFIG_RTL8188E) +static void rtw_hal_disable_tx_report(_adapter *adapter) +{ + rtw_write8(adapter, REG_TX_RPT_CTRL, + ((rtw_read8(adapter, REG_TX_RPT_CTRL) & ~BIT(1))) & ~BIT(5)); + RTW_INFO("disable TXRPT:0x%02x\n", rtw_read8(adapter, REG_TX_RPT_CTRL)); +} + +static void rtw_hal_enable_tx_report(_adapter *adapter) +{ + rtw_write8(adapter, REG_TX_RPT_CTRL, + ((rtw_read8(adapter, REG_TX_RPT_CTRL) | BIT(1))) | BIT(5)); + RTW_INFO("enable TX_RPT:0x%02x\n", rtw_read8(adapter, REG_TX_RPT_CTRL)); +} +#endif +static void rtw_hal_release_rx_dma(_adapter *adapter) +{ + u32 val32 = 0; + + val32 = rtw_read32(adapter, REG_RXPKT_NUM); + + rtw_write32(adapter, REG_RXPKT_NUM, (val32 & (~RW_RELEASE_EN))); + + RTW_INFO("%s, [0x%04x]: 0x%08x\n", + __func__, REG_RXPKT_NUM, (val32 & (~RW_RELEASE_EN))); +} + +static u8 rtw_hal_pause_rx_dma(_adapter *adapter) +{ + PHAL_DATA_TYPE hal = GET_HAL_DATA(adapter); + u8 ret = 0; + s8 trycnt = 100; + u32 tmp = 0; + int res = 0; + /* RX DMA stop */ + RTW_PRINT("Pause DMA\n"); + rtw_write32(adapter, REG_RXPKT_NUM, + (rtw_read32(adapter, REG_RXPKT_NUM) | RW_RELEASE_EN)); + do { + if ((rtw_read32(adapter, REG_RXPKT_NUM) & RXDMA_IDLE)) { +#ifdef CONFIG_USB_HCI + /* stop interface before leave */ + if (_TRUE == hal->usb_intf_start) { + rtw_intf_stop(adapter); + RTW_ENABLE_FUNC(adapter, DF_RX_BIT); + RTW_ENABLE_FUNC(adapter, DF_TX_BIT); + } +#endif /* CONFIG_USB_HCI */ + + RTW_PRINT("RX_DMA_IDLE is true\n"); + ret = _SUCCESS; + break; + } +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + else { + res = RecvOnePkt(adapter); + RTW_PRINT("RecvOnePkt Result: %d\n", res); + } +#endif /* CONFIG_SDIO_HCI || CONFIG_GSPI_HCI */ + +#ifdef CONFIG_USB_HCI + else { + /* to avoid interface start repeatedly */ + if (_FALSE == hal->usb_intf_start) + rtw_intf_start(adapter); + } +#endif /* CONFIG_USB_HCI */ + } while (trycnt--); + + if (trycnt < 0) { + tmp = rtw_read16(adapter, REG_RXPKT_NUM + 3); + + RTW_PRINT("Stop RX DMA failed......\n"); + RTW_PRINT("%s, RXPKT_NUM: 0x%04x\n", + __func__, tmp); + tmp = rtw_read16(adapter, REG_RXPKT_NUM + 2); + if (tmp & BIT(3)) + RTW_PRINT("%s, RX DMA has req\n", + __func__); + else + RTW_PRINT("%s, RX DMA no req\n", + __func__); + ret = _FAIL; + } + + return ret; +} + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) +#ifndef RTW_HALMAC +static u8 rtw_hal_enable_cpwm2(_adapter *adapter) +{ + u8 ret = 0; + int res = 0; + u32 tmp = 0; +#ifdef CONFIG_GPIO_WAKEUP + return _SUCCESS; +#else + RTW_PRINT("%s\n", __func__); + + res = sdio_local_read(adapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); + if (!res) + RTW_INFO("read SDIO_REG_HIMR: 0x%08x\n", tmp); + else + RTW_INFO("sdio_local_read fail\n"); + + tmp = SDIO_HIMR_CPWM2_MSK; + + res = sdio_local_write(adapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); + + if (!res) { + res = sdio_local_read(adapter, SDIO_REG_HIMR, 4, (u8 *)&tmp); + RTW_INFO("read again SDIO_REG_HIMR: 0x%08x\n", tmp); + ret = _SUCCESS; + } else { + RTW_INFO("sdio_local_write fail\n"); + ret = _FAIL; + } + return ret; +#endif /* CONFIG_CPIO_WAKEUP */ +} +#endif +#endif /* CONFIG_SDIO_HCI, CONFIG_GSPI_HCI */ +#endif /* CONFIG_WOWLAN || CONFIG_AP_WOWLAN */ + +#ifdef CONFIG_WOWLAN +/* + * rtw_hal_check_wow_ctrl + * chk_type: _TRUE means to check enable, if 0x690 & bit1, WOW enable successful + * _FALSE means to check disable, if 0x690 & bit1, WOW disable fail + */ +static u8 rtw_hal_check_wow_ctrl(_adapter *adapter, u8 chk_type) +{ + u8 mstatus = 0; + u8 trycnt = 25; + u8 res = _FALSE; + + mstatus = rtw_read8(adapter, REG_WOW_CTRL); + RTW_INFO("%s mstatus:0x%02x\n", __func__, mstatus); + + if (chk_type) { + while (!(mstatus & BIT1) && trycnt > 1) { + mstatus = rtw_read8(adapter, REG_WOW_CTRL); + RTW_PRINT("Loop index: %d :0x%02x\n", + trycnt, mstatus); + trycnt--; + rtw_msleep_os(20); + } + if (mstatus & BIT1) + res = _TRUE; + else + res = _FALSE; + } else { + while (mstatus & BIT1 && trycnt > 1) { + mstatus = rtw_read8(adapter, REG_WOW_CTRL); + RTW_PRINT("Loop index: %d :0x%02x\n", + trycnt, mstatus); + trycnt--; + rtw_msleep_os(20); + } + + if (mstatus & BIT1) + res = _FALSE; + else + res = _TRUE; + } + RTW_PRINT("%s check_type: %d res: %d trycnt: %d\n", + __func__, chk_type, res, (25 - trycnt)); + return res; +} + +#ifdef CONFIG_PNO_SUPPORT +static u8 rtw_hal_check_pno_enabled(_adapter *adapter) +{ + struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(adapter); + u8 res = 0, count = 0; + u8 ret = _FALSE; + + if (ppwrpriv->wowlan_pno_enable && ppwrpriv->wowlan_in_resume == _FALSE) { + res = rtw_read8(adapter, REG_PNO_STATUS); + while (!(res & BIT(7)) && count < 25) { + RTW_INFO("[%d] cmd: 0x81 REG_PNO_STATUS: 0x%02x\n", + count, res); + res = rtw_read8(adapter, REG_PNO_STATUS); + count++; + rtw_msleep_os(2); + } + if (res & BIT(7)) + ret = _TRUE; + else + ret = _FALSE; + RTW_INFO("cmd: 0x81 REG_PNO_STATUS: ret(%d)\n", ret); + } + return ret; +} +#endif + +static void rtw_hal_backup_rate(_adapter *adapter) +{ + RTW_INFO("%s\n", __func__); + /* backup data rate to register 0x8b for wowlan FW */ + rtw_write8(adapter, 0x8d, 1); + rtw_write8(adapter, 0x8c, 0); + rtw_write8(adapter, 0x8f, 0x40); + rtw_write8(adapter, 0x8b, rtw_read8(adapter, 0x2f0)); +} + +#ifdef CONFIG_GTK_OL +static void rtw_hal_fw_sync_cam_id(_adapter *adapter) +{ + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + int cam_id, index = 0; + u8 *addr = NULL; + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) + return; + + addr = get_bssid(pmlmepriv); + + if (addr == NULL) { + RTW_INFO("%s: get bssid MAC addr fail!!\n", __func__); + return; + } + + rtw_clean_dk_section(adapter); + + do { + cam_id = rtw_camid_search(adapter, addr, index, 1); + + if (cam_id == -1) + RTW_INFO("%s: cam_id: %d, key_id:%d\n", __func__, cam_id, index); + else + rtw_sec_cam_swap(adapter, cam_id, index); + + index++; + } while (index < 4); + + rtw_write8(adapter, REG_SECCFG, 0xcc); +} + +static void rtw_dump_aoac_rpt(_adapter *adapter) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); + struct aoac_report *paoac_rpt = &pwrctl->wowlan_aoac_rpt; + + RTW_INFO_DUMP("[AOAC-RPT] IV -", paoac_rpt->iv, 8); + RTW_INFO_DUMP("[AOAC-RPT] Replay counter of EAPOL key - ", + paoac_rpt->replay_counter_eapol_key, 8); + RTW_INFO_DUMP("[AOAC-RPT] Group key - ", paoac_rpt->group_key, 32); + RTW_INFO("[AOAC-RPT] Key Index - %d\n", paoac_rpt->key_index); + RTW_INFO("[AOAC-RPT] Security Type - %d\n", paoac_rpt->security_type); +} + +static void rtw_hal_get_aoac_rpt(_adapter *adapter) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); + struct aoac_report *paoac_rpt = &pwrctl->wowlan_aoac_rpt; + u32 page_offset = 0, page_number = 0; + u32 page_size = 0, buf_size = 0; + u8 *buffer = NULL; + u8 i = 0, tmp = 0; + int ret = -1; + + /* read aoac report from rsvd page */ + page_offset = pwrctl->wowlan_aoac_rpt_loc; + page_number = 1; + + rtw_hal_get_def_var(adapter, HAL_DEF_TX_PAGE_SIZE, &page_size); + buf_size = page_size * page_number; + + buffer = rtw_zvmalloc(buf_size); + + if (NULL == buffer) { + RTW_ERR("%s buffer allocate failed size(%d)\n", + __func__, buf_size); + return; + } + + RTW_INFO("Get AOAC Report from rsvd page_offset:%d\n", page_offset); + + ret = rtw_hal_get_rsvd_page(adapter, page_offset, + page_number, buffer, buf_size); + + if (ret == _FALSE) { + RTW_ERR("%s get aoac report failed\n", __func__); + rtw_warn_on(1); + goto _exit; + } + + _rtw_memset(paoac_rpt, 0, sizeof(struct aoac_report)); + _rtw_memcpy(paoac_rpt, buffer, sizeof(struct aoac_report)); + + for (i = 0 ; i < 4 ; i++) { + tmp = paoac_rpt->replay_counter_eapol_key[i]; + paoac_rpt->replay_counter_eapol_key[i] = + paoac_rpt->replay_counter_eapol_key[7 - i]; + paoac_rpt->replay_counter_eapol_key[7 - i] = tmp; + } + + /* rtw_dump_aoac_rpt(adapter); */ + +_exit: + if (buffer) + rtw_vmfree(buffer, buf_size); +} + +static void rtw_hal_update_gtk_offload_info(_adapter *adapter) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); + struct aoac_report *paoac_rpt = &pwrctl->wowlan_aoac_rpt; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct security_priv *psecuritypriv = &adapter->securitypriv; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; + _irqL irqL; + u8 get_key[16]; + u8 gtk_id = 0, offset = 0, i = 0, sz = 0; + u64 replay_count = 0; + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) + return; + + _rtw_memset(get_key, 0, sizeof(get_key)); + _rtw_memcpy(&replay_count, + paoac_rpt->replay_counter_eapol_key, 8); + + /*read gtk key index*/ + gtk_id = paoac_rpt->key_index; + + if (gtk_id == 5 || gtk_id == 0) { + RTW_INFO("%s no rekey event happened.\n", __func__); + } else if (gtk_id > 0 && gtk_id < 4) { + RTW_INFO("%s update security key.\n", __func__); + /*read key from sec-cam,for DK ,keyindex is equal to cam-id*/ + rtw_sec_read_cam_ent(adapter, gtk_id, + NULL, NULL, get_key); + rtw_clean_hw_dk_cam(adapter); + + if (_rtw_camid_is_gk(adapter, gtk_id)) { + _enter_critical_bh(&cam_ctl->lock, &irqL); + _rtw_memcpy(&dvobj->cam_cache[gtk_id].key, + get_key, 16); + _exit_critical_bh(&cam_ctl->lock, &irqL); + } else { + struct setkey_parm parm_gtk; + + parm_gtk.algorithm = paoac_rpt->security_type; + parm_gtk.keyid = gtk_id; + _rtw_memcpy(parm_gtk.key, get_key, 16); + setkey_hdl(adapter, (u8 *)&parm_gtk); + } + + /*update key into related sw variable and sec-cam cache*/ + psecuritypriv->dot118021XGrpKeyid = gtk_id; + _rtw_memcpy(&psecuritypriv->dot118021XGrpKey[gtk_id], + get_key, 16); + /* update SW TKIP TX/RX MIC value */ + if (psecuritypriv->dot118021XGrpPrivacy == _TKIP_) { + offset = RTW_KEK_LEN + RTW_TKIP_MIC_LEN; + _rtw_memcpy( + &psecuritypriv->dot118021XGrptxmickey[gtk_id], + &(paoac_rpt->group_key[offset]), + RTW_TKIP_MIC_LEN); + + offset = RTW_KEK_LEN; + _rtw_memcpy( + &psecuritypriv->dot118021XGrprxmickey[gtk_id], + &(paoac_rpt->group_key[offset]), + RTW_TKIP_MIC_LEN); + } + /* Update broadcast RX IV */ + if (psecuritypriv->dot118021XGrpPrivacy == _AES_) { + sz = sizeof(psecuritypriv->iv_seq[0]); + for (i = 0 ; i < 4 ; i++) + _rtw_memset(psecuritypriv->iv_seq[i], 0, sz); + } + + RTW_PRINT("GTK (%d) "KEY_FMT"\n", gtk_id, + KEY_ARG(psecuritypriv->dot118021XGrpKey[gtk_id].skey)); + } + + rtw_clean_dk_section(adapter); + + rtw_write8(adapter, REG_SECCFG, 0x0c); + + #ifdef CONFIG_GTK_OL_DBG + /* if (gtk_keyindex != 5) */ + dump_sec_cam(RTW_DBGDUMP, adapter); + dump_sec_cam_cache(RTW_DBGDUMP, adapter); + #endif +} + +static void rtw_hal_update_tx_iv(_adapter *adapter) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); + struct aoac_report *paoac_rpt = &pwrctl->wowlan_aoac_rpt; + struct sta_info *psta; + struct mlme_ext_priv *pmlmeext = &(adapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct security_priv *psecpriv = &adapter->securitypriv; + + u16 val16 = 0; + u32 val32 = 0; + u64 txiv = 0; + u8 *pval = NULL; + + psta = rtw_get_stainfo(&adapter->stapriv, + get_my_bssid(&pmlmeinfo->network)); + + /* Update TX iv data. */ + pval = (u8 *)&paoac_rpt->iv; + + if (psecpriv->dot11PrivacyAlgrthm == _TKIP_) { + val16 = ((u16)(paoac_rpt->iv[2]) << 0) + + ((u16)(paoac_rpt->iv[0]) << 8); + val32 = ((u32)(paoac_rpt->iv[4]) << 0) + + ((u32)(paoac_rpt->iv[5]) << 8) + + ((u32)(paoac_rpt->iv[6]) << 16) + + ((u32)(paoac_rpt->iv[7]) << 24); + } else if (psecpriv->dot11PrivacyAlgrthm == _AES_) { + val16 = ((u16)(paoac_rpt->iv[0]) << 0) + + ((u16)(paoac_rpt->iv[1]) << 8); + val32 = ((u32)(paoac_rpt->iv[4]) << 0) + + ((u32)(paoac_rpt->iv[5]) << 8) + + ((u32)(paoac_rpt->iv[6]) << 16) + + ((u32)(paoac_rpt->iv[7]) << 24); + } + + if (psta) { + txiv = val16 + ((u64)val32 << 16); + if (txiv != 0) + psta->dot11txpn.val = txiv; + } +} + +static void rtw_hal_update_sw_security_info(_adapter *adapter) +{ + rtw_hal_update_tx_iv(adapter); + rtw_hal_update_gtk_offload_info(adapter); +} +#endif /*CONFIG_GTK_OL*/ + +static u8 rtw_hal_set_keep_alive_cmd(_adapter *adapter, u8 enable, u8 pkt_type) +{ + struct hal_ops *pHalFunc = &adapter->hal_func; + + u8 u1H2CKeepAliveParm[H2C_KEEP_ALIVE_CTRL_LEN] = {0}; + u8 adopt = 1, check_period = 5; + u8 ret = _FAIL; + + SET_H2CCMD_KEEPALIVE_PARM_ENABLE(u1H2CKeepAliveParm, enable); + SET_H2CCMD_KEEPALIVE_PARM_ADOPT(u1H2CKeepAliveParm, adopt); + SET_H2CCMD_KEEPALIVE_PARM_PKT_TYPE(u1H2CKeepAliveParm, pkt_type); + SET_H2CCMD_KEEPALIVE_PARM_CHECK_PERIOD(u1H2CKeepAliveParm, check_period); +#ifdef CONFIG_FW_MULTI_PORT_SUPPORT + SET_H2CCMD_KEEPALIVE_PARM_PORT_NUM(u1H2CKeepAliveParm, adapter->hw_port); + RTW_INFO("%s(): enable = %d, port = %d\n", __func__, enable, adapter->hw_port); +#else + RTW_INFO("%s(): enable = %d\n", __func__, enable); +#endif + ret = rtw_hal_fill_h2c_cmd(adapter, + H2C_KEEP_ALIVE, + H2C_KEEP_ALIVE_CTRL_LEN, + u1H2CKeepAliveParm); + + return ret; +} + +static u8 rtw_hal_set_disconnect_decision_cmd(_adapter *adapter, u8 enable) +{ + struct hal_ops *pHalFunc = &adapter->hal_func; + u8 u1H2CDisconDecisionParm[H2C_DISCON_DECISION_LEN] = {0}; + u8 adopt = 1, check_period = 10, trypkt_num = 0; + u8 ret = _FAIL; + + SET_H2CCMD_DISCONDECISION_PARM_ENABLE(u1H2CDisconDecisionParm, enable); + SET_H2CCMD_DISCONDECISION_PARM_ADOPT(u1H2CDisconDecisionParm, adopt); + SET_H2CCMD_DISCONDECISION_PARM_CHECK_PERIOD(u1H2CDisconDecisionParm, check_period); + SET_H2CCMD_DISCONDECISION_PARM_TRY_PKT_NUM(u1H2CDisconDecisionParm, trypkt_num); +#ifdef CONFIG_FW_MULTI_PORT_SUPPORT + SET_H2CCMD_DISCONDECISION_PORT_NUM(u1H2CDisconDecisionParm, adapter->hw_port); + RTW_INFO("%s(): enable = %d, port = %d\n", __func__, enable, adapter->hw_port); +#else + RTW_INFO("%s(): enable = %d\n", __func__, enable); +#endif + + ret = rtw_hal_fill_h2c_cmd(adapter, + H2C_DISCON_DECISION, + H2C_DISCON_DECISION_LEN, + u1H2CDisconDecisionParm); + return ret; +} + +static u8 rtw_hal_set_wowlan_ctrl_cmd(_adapter *adapter, u8 enable, u8 change_unit) +{ + struct security_priv *psecpriv = &adapter->securitypriv; + struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(adapter); + struct hal_ops *pHalFunc = &adapter->hal_func; + + u8 u1H2CWoWlanCtrlParm[H2C_WOWLAN_LEN] = {0}; + u8 discont_wake = 1, gpionum = 0, gpio_dur = 0; + u8 hw_unicast = 0, gpio_pulse_cnt = 0, gpio_pulse_en = 0; + u8 sdio_wakeup_enable = 1; + u8 gpio_high_active = 0; + u8 magic_pkt = 0; + u8 gpio_unit = 0; /*0: 64ns, 1: 8ms*/ + u8 ret = _FAIL; + +#ifdef CONFIG_GPIO_WAKEUP + gpio_high_active = ppwrpriv->is_high_active; + gpionum = WAKEUP_GPIO_IDX; + sdio_wakeup_enable = 0; +#endif /* CONFIG_GPIO_WAKEUP */ + + if (!ppwrpriv->wowlan_pno_enable) + magic_pkt = enable; + + if (psecpriv->dot11PrivacyAlgrthm == _WEP40_ || psecpriv->dot11PrivacyAlgrthm == _WEP104_) + hw_unicast = 1; + else + hw_unicast = 0; + + RTW_INFO("%s(): enable=%d change_unit=%d\n", __func__, + enable, change_unit); + + /* time = (gpio_dur/2) * gpio_unit, default:256 ms */ + if (enable && change_unit) { + gpio_dur = 0x40; + gpio_unit = 1; + gpio_pulse_en = 1; + } + +#ifdef CONFIG_PLATFORM_ARM_RK3188 + if (enable) { + gpio_pulse_en = 1; + gpio_pulse_cnt = 0x04; + } +#endif + + SET_H2CCMD_WOWLAN_FUNC_ENABLE(u1H2CWoWlanCtrlParm, enable); + SET_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(u1H2CWoWlanCtrlParm, enable); + SET_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(u1H2CWoWlanCtrlParm, magic_pkt); + SET_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(u1H2CWoWlanCtrlParm, hw_unicast); + SET_H2CCMD_WOWLAN_ALL_PKT_DROP(u1H2CWoWlanCtrlParm, 0); + SET_H2CCMD_WOWLAN_GPIO_ACTIVE(u1H2CWoWlanCtrlParm, gpio_high_active); + +#ifdef CONFIG_GTK_OL + /* GTK rekey only for AES, if GTK rekey is TKIP, then wake up*/ + if (psecpriv->binstallKCK_KEK == _TRUE) + SET_H2CCMD_WOWLAN_REKEY_WAKE_UP(u1H2CWoWlanCtrlParm, 0); + else + SET_H2CCMD_WOWLAN_REKEY_WAKE_UP(u1H2CWoWlanCtrlParm, 1); +#else + SET_H2CCMD_WOWLAN_REKEY_WAKE_UP(u1H2CWoWlanCtrlParm, enable); +#endif + SET_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(u1H2CWoWlanCtrlParm, discont_wake); + SET_H2CCMD_WOWLAN_GPIONUM(u1H2CWoWlanCtrlParm, gpionum); + SET_H2CCMD_WOWLAN_DATAPIN_WAKE_UP(u1H2CWoWlanCtrlParm, sdio_wakeup_enable); + + SET_H2CCMD_WOWLAN_GPIO_DURATION(u1H2CWoWlanCtrlParm, gpio_dur); + SET_H2CCMD_WOWLAN_CHANGE_UNIT(u1H2CWoWlanCtrlParm, gpio_unit); + + SET_H2CCMD_WOWLAN_GPIO_PULSE_EN(u1H2CWoWlanCtrlParm, gpio_pulse_en); + SET_H2CCMD_WOWLAN_GPIO_PULSE_COUNT(u1H2CWoWlanCtrlParm, gpio_pulse_cnt); + + ret = rtw_hal_fill_h2c_cmd(adapter, + H2C_WOWLAN, + H2C_WOWLAN_LEN, + u1H2CWoWlanCtrlParm); + return ret; +} + +static u8 rtw_hal_set_remote_wake_ctrl_cmd(_adapter *adapter, u8 enable) +{ + struct hal_ops *pHalFunc = &adapter->hal_func; + struct security_priv *psecuritypriv = &(adapter->securitypriv); + struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(adapter); + struct registry_priv *pregistrypriv = &adapter->registrypriv; + u8 u1H2CRemoteWakeCtrlParm[H2C_REMOTE_WAKE_CTRL_LEN] = {0}; + u8 ret = _FAIL, count = 0; + + RTW_INFO("%s(): enable=%d\n", __func__, enable); + + if (!ppwrpriv->wowlan_pno_enable) { + SET_H2CCMD_REMOTE_WAKECTRL_ENABLE( + u1H2CRemoteWakeCtrlParm, enable); + SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN( + u1H2CRemoteWakeCtrlParm, 1); +#ifdef CONFIG_GTK_OL + if (psecuritypriv->binstallKCK_KEK == _TRUE) { + SET_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN( + u1H2CRemoteWakeCtrlParm, 1); + } else { + RTW_INFO("no kck kek\n"); + SET_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN( + u1H2CRemoteWakeCtrlParm, 0); + } +#endif /* CONFIG_GTK_OL */ + + if (pregistrypriv->default_patterns_en == _FALSE) { + SET_H2CCMD_REMOTE_WAKE_CTRL_FW_UNICAST_EN( + u1H2CRemoteWakeCtrlParm, enable); + /* + * filter NetBios name service pkt to avoid being waked-up + * by this kind of unicast pkt this exceptional modification + * is used for match competitor's behavior + */ + SET_H2CCMD_REMOTE_WAKE_CTRL_NBNS_FILTER_EN( + u1H2CRemoteWakeCtrlParm, enable); + } + + if ((psecuritypriv->dot11PrivacyAlgrthm == _AES_) || + (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_) || + (psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_)) { + SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_ACTION( + u1H2CRemoteWakeCtrlParm, 0); + } else { + SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_ACTION( + u1H2CRemoteWakeCtrlParm, 1); + } + + if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_) { + SET_H2CCMD_REMOTE_WAKE_CTRL_TKIP_OFFLOAD_EN( + u1H2CRemoteWakeCtrlParm, enable); + + if (IS_HARDWARE_TYPE_8188E(adapter) || + IS_HARDWARE_TYPE_8812(adapter)) { + SET_H2CCMD_REMOTE_WAKE_CTRL_TKIP_OFFLOAD_EN( + u1H2CRemoteWakeCtrlParm, 0); + SET_H2CCMD_REMOTE_WAKE_CTRL_ARP_ACTION( + u1H2CRemoteWakeCtrlParm, 1); + } + } + + SET_H2CCMD_REMOTE_WAKE_CTRL_FW_PARSING_UNTIL_WAKEUP( + u1H2CRemoteWakeCtrlParm, 1); + } +#ifdef CONFIG_PNO_SUPPORT + else { + SET_H2CCMD_REMOTE_WAKECTRL_ENABLE( + u1H2CRemoteWakeCtrlParm, enable); + SET_H2CCMD_REMOTE_WAKE_CTRL_NLO_OFFLOAD_EN( + u1H2CRemoteWakeCtrlParm, enable); + } +#endif + +#ifdef CONFIG_P2P_WOWLAN + if (_TRUE == ppwrpriv->wowlan_p2p_mode) { + RTW_INFO("P2P OFFLOAD ENABLE\n"); + SET_H2CCMD_REMOTE_WAKE_CTRL_P2P_OFFLAD_EN(u1H2CRemoteWakeCtrlParm, 1); + } else { + RTW_INFO("P2P OFFLOAD DISABLE\n"); + SET_H2CCMD_REMOTE_WAKE_CTRL_P2P_OFFLAD_EN(u1H2CRemoteWakeCtrlParm, 0); + } +#endif /* CONFIG_P2P_WOWLAN */ + + + ret = rtw_hal_fill_h2c_cmd(adapter, + H2C_REMOTE_WAKE_CTRL, + H2C_REMOTE_WAKE_CTRL_LEN, + u1H2CRemoteWakeCtrlParm); + return ret; +} + +static u8 rtw_hal_set_global_info_cmd(_adapter *adapter, u8 group_alg, u8 pairwise_alg) +{ + struct hal_ops *pHalFunc = &adapter->hal_func; + u8 ret = _FAIL; + u8 u1H2CAOACGlobalInfoParm[H2C_AOAC_GLOBAL_INFO_LEN] = {0}; + + RTW_INFO("%s(): group_alg=%d pairwise_alg=%d\n", + __func__, group_alg, pairwise_alg); + SET_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(u1H2CAOACGlobalInfoParm, + pairwise_alg); + SET_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(u1H2CAOACGlobalInfoParm, + group_alg); + + ret = rtw_hal_fill_h2c_cmd(adapter, + H2C_AOAC_GLOBAL_INFO, + H2C_AOAC_GLOBAL_INFO_LEN, + u1H2CAOACGlobalInfoParm); + + return ret; +} + +#ifdef CONFIG_PNO_SUPPORT +static u8 rtw_hal_set_scan_offload_info_cmd(_adapter *adapter, + PRSVDPAGE_LOC rsvdpageloc, u8 enable) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); + struct hal_ops *pHalFunc = &adapter->hal_func; + + u8 u1H2CScanOffloadInfoParm[H2C_SCAN_OFFLOAD_CTRL_LEN] = {0}; + u8 res = 0, count = 0, ret = _FAIL; + + RTW_INFO("%s: loc_probe_packet:%d, loc_scan_info: %d loc_ssid_info:%d\n", + __func__, rsvdpageloc->LocProbePacket, + rsvdpageloc->LocScanInfo, rsvdpageloc->LocSSIDInfo); + + SET_H2CCMD_AOAC_NLO_FUN_EN(u1H2CScanOffloadInfoParm, enable); + SET_H2CCMD_AOAC_NLO_IPS_EN(u1H2CScanOffloadInfoParm, enable); + SET_H2CCMD_AOAC_RSVDPAGE_LOC_SCAN_INFO(u1H2CScanOffloadInfoParm, + rsvdpageloc->LocScanInfo); + SET_H2CCMD_AOAC_RSVDPAGE_LOC_PROBE_PACKET(u1H2CScanOffloadInfoParm, + rsvdpageloc->LocProbePacket); + /* + SET_H2CCMD_AOAC_RSVDPAGE_LOC_SSID_INFO(u1H2CScanOffloadInfoParm, + rsvdpageloc->LocSSIDInfo); + */ + ret = rtw_hal_fill_h2c_cmd(adapter, + H2C_D0_SCAN_OFFLOAD_INFO, + H2C_SCAN_OFFLOAD_CTRL_LEN, + u1H2CScanOffloadInfoParm); + return ret; +} +#endif /* CONFIG_PNO_SUPPORT */ + +void rtw_hal_set_fw_wow_related_cmd(_adapter *padapter, u8 enable) +{ + struct security_priv *psecpriv = &padapter->securitypriv; + struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(padapter); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct sta_info *psta = NULL; + u16 media_status_rpt; + u8 pkt_type = 0; + u8 ret = _SUCCESS; + + RTW_PRINT("+%s()+: enable=%d\n", __func__, enable); + + rtw_hal_set_wowlan_ctrl_cmd(padapter, enable, _FALSE); + + if (enable) { + rtw_hal_set_global_info_cmd(padapter, + psecpriv->dot118021XGrpPrivacy, + psecpriv->dot11PrivacyAlgrthm); + + if (!(ppwrpriv->wowlan_pno_enable)) { + rtw_hal_set_disconnect_decision_cmd(padapter, enable); +#ifdef CONFIG_ARP_KEEP_ALIVE + if ((psecpriv->dot11PrivacyAlgrthm == _WEP40_) || + (psecpriv->dot11PrivacyAlgrthm == _WEP104_)) + pkt_type = 0; + else + pkt_type = 1; +#else + pkt_type = 0; +#endif /* CONFIG_ARP_KEEP_ALIVE */ + rtw_hal_set_keep_alive_cmd(padapter, enable, pkt_type); + } + rtw_hal_set_remote_wake_ctrl_cmd(padapter, enable); +#ifdef CONFIG_PNO_SUPPORT + rtw_hal_check_pno_enabled(padapter); +#endif /* CONFIG_PNO_SUPPORT */ + } else { +#if 0 + { + u32 PageSize = 0; + rtw_hal_get_def_var(padapter, HAL_DEF_TX_PAGE_SIZE, (u8 *)&PageSize); + dump_TX_FIFO(padapter, 4, PageSize); + } +#endif + + rtw_hal_set_remote_wake_ctrl_cmd(padapter, enable); + } + RTW_PRINT("-%s()-\n", __func__); +} +#endif /* CONFIG_WOWLAN */ + +#ifdef CONFIG_AP_WOWLAN +static u8 rtw_hal_set_ap_wowlan_ctrl_cmd(_adapter *adapter, u8 enable) +{ + struct security_priv *psecpriv = &adapter->securitypriv; + struct pwrctrl_priv *ppwrpriv = adapter_to_pwrctl(adapter); + struct hal_ops *pHalFunc = &adapter->hal_func; + + u8 u1H2CAPWoWlanCtrlParm[H2C_AP_WOW_GPIO_CTRL_LEN] = {0}; + u8 gpionum = 0, gpio_dur = 0; + u8 gpio_pulse = enable; + u8 sdio_wakeup_enable = 1; + u8 gpio_high_active = 0; + u8 ret = _FAIL; + +#ifdef CONFIG_GPIO_WAKEUP + gpio_high_active = ppwrpriv->is_high_active; + gpionum = WAKEUP_GPIO_IDX; + sdio_wakeup_enable = 0; +#endif /*CONFIG_GPIO_WAKEUP*/ + + RTW_INFO("%s(): enable=%d\n", __func__, enable); + + SET_H2CCMD_AP_WOW_GPIO_CTRL_INDEX(u1H2CAPWoWlanCtrlParm, + gpionum); + SET_H2CCMD_AP_WOW_GPIO_CTRL_PLUS(u1H2CAPWoWlanCtrlParm, + gpio_pulse); + SET_H2CCMD_AP_WOW_GPIO_CTRL_HIGH_ACTIVE(u1H2CAPWoWlanCtrlParm, + gpio_high_active); + SET_H2CCMD_AP_WOW_GPIO_CTRL_EN(u1H2CAPWoWlanCtrlParm, + enable); + SET_H2CCMD_AP_WOW_GPIO_CTRL_DURATION(u1H2CAPWoWlanCtrlParm, + gpio_dur); + + ret = rtw_hal_fill_h2c_cmd(adapter, + H2C_AP_WOW_GPIO_CTRL, + H2C_AP_WOW_GPIO_CTRL_LEN, + u1H2CAPWoWlanCtrlParm); + + return ret; +} + +static u8 rtw_hal_set_ap_offload_ctrl_cmd(_adapter *adapter, u8 enable) +{ + struct hal_ops *pHalFunc = &adapter->hal_func; + u8 u1H2CAPOffloadCtrlParm[H2C_WOWLAN_LEN] = {0}; + u8 ret = _FAIL; + + RTW_INFO("%s(): bFuncEn=%d\n", __func__, enable); + + SET_H2CCMD_AP_WOWLAN_EN(u1H2CAPOffloadCtrlParm, enable); + + ret = rtw_hal_fill_h2c_cmd(adapter, + H2C_AP_OFFLOAD, + H2C_AP_OFFLOAD_LEN, + u1H2CAPOffloadCtrlParm); + + return ret; +} + +static u8 rtw_hal_set_ap_ps_cmd(_adapter *adapter, u8 enable) +{ + struct hal_ops *pHalFunc = &adapter->hal_func; + u8 ap_ps_parm[H2C_AP_PS_LEN] = {0}; + u8 ret = _FAIL; + + RTW_INFO("%s(): enable=%d\n" , __func__ , enable); + + SET_H2CCMD_AP_WOW_PS_EN(ap_ps_parm, enable); +#ifndef CONFIG_USB_HCI + SET_H2CCMD_AP_WOW_PS_32K_EN(ap_ps_parm, enable); +#endif /*CONFIG_USB_HCI*/ + SET_H2CCMD_AP_WOW_PS_RF(ap_ps_parm, enable); + + if (enable) + SET_H2CCMD_AP_WOW_PS_DURATION(ap_ps_parm, 0x32); + else + SET_H2CCMD_AP_WOW_PS_DURATION(ap_ps_parm, 0x0); + + ret = rtw_hal_fill_h2c_cmd(adapter, H2C_SAP_PS_, + H2C_AP_PS_LEN, ap_ps_parm); + + return ret; +} + +static void rtw_hal_set_ap_rsvdpage_loc_cmd(PADAPTER padapter, + PRSVDPAGE_LOC rsvdpageloc) +{ + struct hal_ops *pHalFunc = &padapter->hal_func; + u8 rsvdparm[H2C_AOAC_RSVDPAGE_LOC_LEN] = {0}; + u8 ret = _FAIL, header = 0; + + if (pHalFunc->fill_h2c_cmd == NULL) { + RTW_INFO("%s: Please hook fill_h2c_cmd first!\n", __func__); + return; + } + + header = rtw_read8(padapter, REG_BCNQ_BDNY); + + RTW_INFO("%s: beacon: %d, probeRsp: %d, header:0x%02x\n", __func__, + rsvdpageloc->LocApOffloadBCN, + rsvdpageloc->LocProbeRsp, + header); + + SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_BCN(rsvdparm, + rsvdpageloc->LocApOffloadBCN + header); + + ret = rtw_hal_fill_h2c_cmd(padapter, H2C_BCN_RSVDPAGE, + H2C_BCN_RSVDPAGE_LEN, rsvdparm); + + if (ret == _FAIL) + RTW_INFO("%s: H2C_BCN_RSVDPAGE cmd fail\n", __func__); + + rtw_msleep_os(10); + + _rtw_memset(&rsvdparm, 0, sizeof(rsvdparm)); + + SET_H2CCMD_AP_WOWLAN_RSVDPAGE_LOC_ProbeRsp(rsvdparm, + rsvdpageloc->LocProbeRsp + header); + + ret = rtw_hal_fill_h2c_cmd(padapter, H2C_PROBERSP_RSVDPAGE, + H2C_PROBERSP_RSVDPAGE_LEN, rsvdparm); + + if (ret == _FAIL) + RTW_INFO("%s: H2C_PROBERSP_RSVDPAGE cmd fail\n", __func__); + + rtw_msleep_os(10); +} + +static void rtw_hal_set_fw_ap_wow_related_cmd(_adapter *padapter, u8 enable) +{ + rtw_hal_set_ap_offload_ctrl_cmd(padapter, enable); + rtw_hal_set_ap_wowlan_ctrl_cmd(padapter, enable); + rtw_hal_set_ap_ps_cmd(padapter, enable); +} + +static void rtw_hal_ap_wow_enable(_adapter *padapter) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct hal_ops *pHalFunc = &padapter->hal_func; + struct sta_info *psta = NULL; + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); +#ifdef DBG_CHECK_FW_PS_STATE + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; +#endif /*DBG_CHECK_FW_PS_STATE*/ + int res; + u16 media_status_rpt; + + RTW_INFO("%s, WOWLAN_AP_ENABLE\n", __func__); +#ifdef DBG_CHECK_FW_PS_STATE + if (rtw_fw_ps_state(padapter) == _FAIL) { + pdbgpriv->dbg_enwow_dload_fw_fail_cnt++; + RTW_PRINT("wowlan enable no leave 32k\n"); + } +#endif /*DBG_CHECK_FW_PS_STATE*/ + + /* 1. Download WOWLAN FW*/ + rtw_hal_fw_dl(padapter, _TRUE); + + media_status_rpt = RT_MEDIA_CONNECT; + rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, + (u8 *)&media_status_rpt); + + issue_beacon(padapter, 0); + + rtw_msleep_os(2); + #if defined(CONFIG_RTL8188E) + if (IS_HARDWARE_TYPE_8188E(padapter)) + rtw_hal_disable_tx_report(padapter); + #endif + /* RX DMA stop */ + res = rtw_hal_pause_rx_dma(padapter); + if (res == _FAIL) + RTW_PRINT("[WARNING] pause RX DMA fail\n"); + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + /* Enable CPWM2 only. */ + res = rtw_hal_enable_cpwm2(padapter); + if (res == _FAIL) + RTW_PRINT("[WARNING] enable cpwm2 fail\n"); +#endif + +#ifdef CONFIG_GPIO_WAKEUP + rtw_hal_switch_gpio_wl_ctrl(padapter, WAKEUP_GPIO_IDX, _TRUE); +#endif + /* 5. Set Enable WOWLAN H2C command. */ + RTW_PRINT("Set Enable AP WOWLan cmd\n"); + rtw_hal_set_fw_ap_wow_related_cmd(padapter, 1); + + rtw_write8(padapter, REG_MCUTST_WOWLAN, 0); +#ifdef CONFIG_USB_HCI + rtw_mi_intf_stop(padapter); + /* Invoid SE0 reset signal during suspending*/ + rtw_write8(padapter, REG_RSV_CTRL, 0x20); + if (IS_8188F(pHalData->version_id) == FALSE) + rtw_write8(padapter, REG_RSV_CTRL, 0x60); +#endif /*CONFIG_USB_HCI*/ +} + +static void rtw_hal_ap_wow_disable(_adapter *padapter) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); + struct hal_ops *pHalFunc = &padapter->hal_func; +#ifdef DBG_CHECK_FW_PS_STATE + struct dvobj_priv *psdpriv = padapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; +#endif /*DBG_CHECK_FW_PS_STATE*/ + u16 media_status_rpt; + u8 val8; + + RTW_INFO("%s, WOWLAN_AP_DISABLE\n", __func__); + /* 1. Read wakeup reason*/ + pwrctl->wowlan_wake_reason = rtw_read8(padapter, REG_MCUTST_WOWLAN); + + RTW_PRINT("wakeup_reason: 0x%02x\n", + pwrctl->wowlan_wake_reason); + + rtw_hal_set_fw_ap_wow_related_cmd(padapter, 0); + + rtw_msleep_os(2); +#ifdef DBG_CHECK_FW_PS_STATE + if (rtw_fw_ps_state(padapter) == _FAIL) { + pdbgpriv->dbg_diswow_dload_fw_fail_cnt++; + RTW_PRINT("wowlan enable no leave 32k\n"); + } +#endif /*DBG_CHECK_FW_PS_STATE*/ + + #if defined(CONFIG_RTL8188E) + if (IS_HARDWARE_TYPE_8188E(padapter)) + rtw_hal_enable_tx_report(padapter); + #endif + + rtw_hal_force_enable_rxdma(padapter); + + rtw_hal_fw_dl(padapter, _FALSE); + +#ifdef CONFIG_GPIO_WAKEUP + val8 = (pwrctl->is_high_active == 0) ? 1 : 0; + RTW_PRINT("Set Wake GPIO to default(%d).\n", val8); + rtw_hal_set_output_gpio(padapter, WAKEUP_GPIO_IDX, val8); + + rtw_hal_switch_gpio_wl_ctrl(padapter, WAKEUP_GPIO_IDX, _FALSE); +#endif + media_status_rpt = RT_MEDIA_CONNECT; + + rtw_hal_set_hwreg(padapter, HW_VAR_H2C_FW_JOINBSSRPT, + (u8 *)&media_status_rpt); + + issue_beacon(padapter, 0); +} +#endif /*CONFIG_AP_WOWLAN*/ + +#ifdef CONFIG_P2P_WOWLAN +static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode) +{ + u8 *ssid_ie; + sint ssid_len_ori; + int len_diff = 0; + + ssid_ie = rtw_get_ie(ies, WLAN_EID_SSID, &ssid_len_ori, ies_len); + + /* RTW_INFO("%s hidden_ssid_mode:%u, ssid_ie:%p, ssid_len_ori:%d\n", __FUNCTION__, hidden_ssid_mode, ssid_ie, ssid_len_ori); */ + + if (ssid_ie && ssid_len_ori > 0) { + switch (hidden_ssid_mode) { + case 1: { + u8 *next_ie = ssid_ie + 2 + ssid_len_ori; + u32 remain_len = 0; + + remain_len = ies_len - (next_ie - ies); + + ssid_ie[1] = 0; + _rtw_memcpy(ssid_ie + 2, next_ie, remain_len); + len_diff -= ssid_len_ori; + + break; + } + case 2: + _rtw_memset(&ssid_ie[2], 0, ssid_len_ori); + break; + default: + break; + } + } + + return len_diff; +} + +static void rtw_hal_construct_P2PBeacon(_adapter *padapter, u8 *pframe, u32 *pLength) +{ + /* struct xmit_frame *pmgntframe; */ + /* struct pkt_attrib *pattrib; */ + /* unsigned char *pframe; */ + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned int rate_len; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + u32 pktlen; + /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ + /* _irqL irqL; + * struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + * #endif */ /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +#ifdef CONFIG_P2P + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); +#endif /* CONFIG_P2P */ + + /* for debug */ + u8 *dbgbuf = pframe; + u8 dbgbufLen = 0, index = 0; + + RTW_INFO("%s\n", __FUNCTION__); + /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ + /* _enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); + * #endif */ /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); + + SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); + /* pmlmeext->mgnt_seq++; */ + set_frame_sub_type(pframe, WIFI_BEACON); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { + /* RTW_INFO("ie len=%d\n", cur_network->IELength); */ +#ifdef CONFIG_P2P + /* for P2P : Primary Device Type & Device Name */ + u32 wpsielen = 0, insert_len = 0; + u8 *wpsie = NULL; + wpsie = rtw_get_wps_ie(cur_network->IEs + _FIXED_IE_LENGTH_, cur_network->IELength - _FIXED_IE_LENGTH_, NULL, &wpsielen); + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && wpsie && wpsielen > 0) { + uint wps_offset, remainder_ielen; + u8 *premainder_ie, *pframe_wscie; + + wps_offset = (uint)(wpsie - cur_network->IEs); + + premainder_ie = wpsie + wpsielen; + + remainder_ielen = cur_network->IELength - wps_offset - wpsielen; + +#ifdef CONFIG_IOCTL_CFG80211 + if (pwdinfo->driver_interface == DRIVER_CFG80211) { + if (pmlmepriv->wps_beacon_ie && pmlmepriv->wps_beacon_ie_len > 0) { + _rtw_memcpy(pframe, cur_network->IEs, wps_offset); + pframe += wps_offset; + pktlen += wps_offset; + + _rtw_memcpy(pframe, pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len); + pframe += pmlmepriv->wps_beacon_ie_len; + pktlen += pmlmepriv->wps_beacon_ie_len; + + /* copy remainder_ie to pframe */ + _rtw_memcpy(pframe, premainder_ie, remainder_ielen); + pframe += remainder_ielen; + pktlen += remainder_ielen; + } else { + _rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength); + pframe += cur_network->IELength; + pktlen += cur_network->IELength; + } + } else +#endif /* CONFIG_IOCTL_CFG80211 */ + { + pframe_wscie = pframe + wps_offset; + _rtw_memcpy(pframe, cur_network->IEs, wps_offset + wpsielen); + pframe += (wps_offset + wpsielen); + pktlen += (wps_offset + wpsielen); + + /* now pframe is end of wsc ie, insert Primary Device Type & Device Name */ + /* Primary Device Type */ + /* Type: */ + *(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); + insert_len += 2; + + /* Length: */ + *(u16 *)(pframe + insert_len) = cpu_to_be16(0x0008); + insert_len += 2; + + /* Value: */ + /* Category ID */ + *(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + insert_len += 2; + + /* OUI */ + *(u32 *)(pframe + insert_len) = cpu_to_be32(WPSOUI); + insert_len += 4; + + /* Sub Category ID */ + *(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + insert_len += 2; + + + /* Device Name */ + /* Type: */ + *(u16 *)(pframe + insert_len) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + insert_len += 2; + + /* Length: */ + *(u16 *)(pframe + insert_len) = cpu_to_be16(pwdinfo->device_name_len); + insert_len += 2; + + /* Value: */ + _rtw_memcpy(pframe + insert_len, pwdinfo->device_name, pwdinfo->device_name_len); + insert_len += pwdinfo->device_name_len; + + + /* update wsc ie length */ + *(pframe_wscie + 1) = (wpsielen - 2) + insert_len; + + /* pframe move to end */ + pframe += insert_len; + pktlen += insert_len; + + /* copy remainder_ie to pframe */ + _rtw_memcpy(pframe, premainder_ie, remainder_ielen); + pframe += remainder_ielen; + pktlen += remainder_ielen; + } + } else +#endif /* CONFIG_P2P */ + { + int len_diff; + _rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength); + len_diff = update_hidden_ssid( + pframe + _BEACON_IE_OFFSET_ + , cur_network->IELength - _BEACON_IE_OFFSET_ + , pmlmeinfo->hidden_ssid_mode + ); + pframe += (cur_network->IELength + len_diff); + pktlen += (cur_network->IELength + len_diff); + } +#if 0 + { + u8 *wps_ie; + uint wps_ielen; + u8 sr = 0; + wps_ie = rtw_get_wps_ie(pmgntframe->buf_addr + TXDESC_OFFSET + sizeof(struct rtw_ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_, + pattrib->pktlen - sizeof(struct rtw_ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_, NULL, &wps_ielen); + if (wps_ie && wps_ielen > 0) + rtw_get_wps_attr_content(wps_ie, wps_ielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL); + if (sr != 0) + set_fwstate(pmlmepriv, WIFI_UNDER_WPS); + else + _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS); + } +#endif +#ifdef CONFIG_P2P + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + u32 len; +#ifdef CONFIG_IOCTL_CFG80211 + if (pwdinfo->driver_interface == DRIVER_CFG80211) { + len = pmlmepriv->p2p_beacon_ie_len; + if (pmlmepriv->p2p_beacon_ie && len > 0) + _rtw_memcpy(pframe, pmlmepriv->p2p_beacon_ie, len); + } else +#endif /* CONFIG_IOCTL_CFG80211 */ + { + len = build_beacon_p2p_ie(pwdinfo, pframe); + } + + pframe += len; + pktlen += len; + + #ifdef CONFIG_WFD + len = rtw_append_beacon_wfd_ie(padapter, pframe); + pframe += len; + pktlen += len; + #endif + + } +#endif /* CONFIG_P2P */ + + goto _issue_bcn; + + } + + /* below for ad-hoc mode */ + + /* timestamp will be inserted by hardware */ + pframe += 8; + pktlen += 8; + + /* beacon interval: 2 bytes */ + + _rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); + + pframe += 2; + pktlen += 2; + + /* capability info: 2 bytes */ + + _rtw_memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); + + pframe += 2; + pktlen += 2; + + /* SSID */ + pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen); + + /* supported rates... */ + rate_len = rtw_get_rateset_len(cur_network->SupportedRates); + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pktlen); + + /* DS parameter set */ + pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen); + + /* if( (pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) */ + { + u8 erpinfo = 0; + u32 ATIMWindow; + /* IBSS Parameter Set... */ + /* ATIMWindow = cur->Configuration.ATIMWindow; */ + ATIMWindow = 0; + pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen); + + /* ERP IE */ + pframe = rtw_set_ie(pframe, _ERPINFO_IE_, 1, &erpinfo, &pktlen); + } + + + /* EXTERNDED SUPPORTED RATE */ + if (rate_len > 8) + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen); + + + /* todo:HT for adhoc */ + +_issue_bcn: + + /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ + /* pmlmepriv->update_bcn = _FALSE; + * + * _exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); + * #endif */ /* #if defined (CONFIG_AP_MODE) && defined (CONFIG_NATIVEAP_MLME) */ + + *pLength = pktlen; +#if 0 + /* printf dbg msg */ + dbgbufLen = pktlen; + RTW_INFO("======> DBG MSG FOR CONSTRAUCT P2P BEACON\n"); + + for (index = 0; index < dbgbufLen; index++) + printk("%x ", *(dbgbuf + index)); + + printk("\n"); + RTW_INFO("<====== DBG MSG FOR CONSTRAUCT P2P BEACON\n"); + +#endif +} + +static int get_reg_classes_full_count(struct p2p_channels channel_list) +{ + int cnt = 0; + int i; + + for (i = 0; i < channel_list.reg_classes; i++) + cnt += channel_list.reg_class[i].channels; + + return cnt; +} + +static void rtw_hal_construct_P2PProbeRsp(_adapter *padapter, u8 *pframe, u32 *pLength) +{ + /* struct xmit_frame *pmgntframe; */ + /* struct pkt_attrib *pattrib; */ + /* unsigned char *pframe; */ + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + unsigned char *mac; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + /* WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); */ + u16 beacon_interval = 100; + u16 capInfo = 0; + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + u8 wpsie[255] = { 0x00 }; + u32 wpsielen = 0, p2pielen = 0; + u32 pktlen; +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif +#ifdef CONFIG_INTEL_WIDI + u8 zero_array_check[L2SDTA_SERVICE_VE_LEN] = { 0x00 }; +#endif /* CONFIG_INTEL_WIDI */ + + /* for debug */ + u8 *dbgbuf = pframe; + u8 dbgbufLen = 0, index = 0; + + RTW_INFO("%s\n", __FUNCTION__); + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + mac = adapter_mac_addr(padapter); + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + /* DA filled by FW */ + _rtw_memset(pwlanhdr->addr1, 0, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); + + /* Use the device address for BSSID field. */ + _rtw_memcpy(pwlanhdr->addr3, mac, ETH_ALEN); + + SetSeqNum(pwlanhdr, 0); + set_frame_sub_type(fctrl, WIFI_PROBERSP); + + pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + pframe += pktlen; + + + /* timestamp will be inserted by hardware */ + pframe += 8; + pktlen += 8; + + /* beacon interval: 2 bytes */ + _rtw_memcpy(pframe, (unsigned char *) &beacon_interval, 2); + pframe += 2; + pktlen += 2; + + /* capability info: 2 bytes */ + /* ESS and IBSS bits must be 0 (defined in the 3.1.2.1.1 of WiFi Direct Spec) */ + capInfo |= cap_ShortPremble; + capInfo |= cap_ShortSlot; + + _rtw_memcpy(pframe, (unsigned char *) &capInfo, 2); + pframe += 2; + pktlen += 2; + + + /* SSID */ + pframe = rtw_set_ie(pframe, _SSID_IE_, 7, pwdinfo->p2p_wildcard_ssid, &pktlen); + + /* supported rates... */ + /* Use the OFDM rate in the P2P probe response frame. ( 6(B), 9(B), 12, 18, 24, 36, 48, 54 ) */ + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, 8, pwdinfo->support_rate, &pktlen); + + /* DS parameter set */ + pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&pwdinfo->listen_channel, &pktlen); + +#ifdef CONFIG_IOCTL_CFG80211 + if (pwdinfo->driver_interface == DRIVER_CFG80211) { + if (pmlmepriv->wps_probe_resp_ie != NULL && pmlmepriv->p2p_probe_resp_ie != NULL) { + /* WPS IE */ + _rtw_memcpy(pframe, pmlmepriv->wps_probe_resp_ie, pmlmepriv->wps_probe_resp_ie_len); + pktlen += pmlmepriv->wps_probe_resp_ie_len; + pframe += pmlmepriv->wps_probe_resp_ie_len; + + /* P2P IE */ + _rtw_memcpy(pframe, pmlmepriv->p2p_probe_resp_ie, pmlmepriv->p2p_probe_resp_ie_len); + pktlen += pmlmepriv->p2p_probe_resp_ie_len; + pframe += pmlmepriv->p2p_probe_resp_ie_len; + } + } else +#endif /* CONFIG_IOCTL_CFG80211 */ + { + + /* Todo: WPS IE */ + /* Noted by Albert 20100907 */ + /* According to the WPS specification, all the WPS attribute is presented by Big Endian. */ + + wpsielen = 0; + /* WPS OUI */ + *(u32 *)(wpsie) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* WPS version */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ + +#ifdef CONFIG_INTEL_WIDI + /* Commented by Kurt */ + /* Appended WiDi info. only if we did issued_probereq_widi(), and then we saved ven. ext. in pmlmepriv->sa_ext. */ + if (_rtw_memcmp(pmlmepriv->sa_ext, zero_array_check, L2SDTA_SERVICE_VE_LEN) == _FALSE + || pmlmepriv->num_p2p_sdt != 0) { + /* Sec dev type */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SEC_DEV_TYPE_LIST); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008); + wpsielen += 2; + + /* Value: */ + /* Category ID */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_DISPLAYS); + wpsielen += 2; + + /* OUI */ + *(u32 *)(wpsie + wpsielen) = cpu_to_be32(INTEL_DEV_TYPE_OUI); + wpsielen += 4; + + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_WIDI_CONSUMER_SINK); + wpsielen += 2; + + if (_rtw_memcmp(pmlmepriv->sa_ext, zero_array_check, L2SDTA_SERVICE_VE_LEN) == _FALSE) { + /* Vendor Extension */ + _rtw_memcpy(wpsie + wpsielen, pmlmepriv->sa_ext, L2SDTA_SERVICE_VE_LEN); + wpsielen += L2SDTA_SERVICE_VE_LEN; + } + } +#endif /* CONFIG_INTEL_WIDI */ + + /* WiFi Simple Config State */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SIMPLE_CONF_STATE); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_WSC_STATE_NOT_CONFIG; /* Not Configured. */ + + /* Response Type */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_RESP_TYPE); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_RESPONSE_TYPE_8021X; + + /* UUID-E */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0010); + wpsielen += 2; + + /* Value: */ + if (pwdinfo->external_uuid == 0) { + _rtw_memset(wpsie + wpsielen, 0x0, 16); + _rtw_memcpy(wpsie + wpsielen, mac, ETH_ALEN); + } else + _rtw_memcpy(wpsie + wpsielen, pwdinfo->uuid, 0x10); + wpsielen += 0x10; + + /* Manufacturer */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MANUFACTURER); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0007); + wpsielen += 2; + + /* Value: */ + _rtw_memcpy(wpsie + wpsielen, "Realtek", 7); + wpsielen += 7; + + /* Model Name */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NAME); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0006); + wpsielen += 2; + + /* Value: */ + _rtw_memcpy(wpsie + wpsielen, "8192CU", 6); + wpsielen += 6; + + /* Model Number */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NUMBER); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = 0x31; /* character 1 */ + + /* Serial Number */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_SERIAL_NUMBER); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(ETH_ALEN); + wpsielen += 2; + + /* Value: */ + _rtw_memcpy(wpsie + wpsielen, "123456" , ETH_ALEN); + wpsielen += ETH_ALEN; + + /* Primary Device Type */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0008); + wpsielen += 2; + + /* Value: */ + /* Category ID */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + wpsielen += 2; + + /* OUI */ + *(u32 *)(wpsie + wpsielen) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* Sub Category ID */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + wpsielen += 2; + + /* Device Name */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->device_name_len); + wpsielen += 2; + + /* Value: */ + _rtw_memcpy(wpsie + wpsielen, pwdinfo->device_name, pwdinfo->device_name_len); + wpsielen += pwdinfo->device_name_len; + + /* Config Method */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(pwdinfo->supported_wps_cm); + wpsielen += 2; + + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pktlen); + + + p2pielen = build_probe_resp_p2p_ie(pwdinfo, pframe); + pframe += p2pielen; + pktlen += p2pielen; + } + +#ifdef CONFIG_WFD + wfdielen = rtw_append_probe_resp_wfd_ie(padapter, pframe); + pframe += wfdielen; + pktlen += wfdielen; +#endif + + *pLength = pktlen; + +#if 0 + /* printf dbg msg */ + dbgbufLen = pktlen; + RTW_INFO("======> DBG MSG FOR CONSTRAUCT P2P Probe Rsp\n"); + + for (index = 0; index < dbgbufLen; index++) + printk("%x ", *(dbgbuf + index)); + + printk("\n"); + RTW_INFO("<====== DBG MSG FOR CONSTRAUCT P2P Probe Rsp\n"); +#endif +} +static void rtw_hal_construct_P2PNegoRsp(_adapter *padapter, u8 *pframe, u32 *pLength) +{ + unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_GO_NEGO_RESP; + u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 }; + u8 p2pielen = 0, i; + uint wpsielen = 0; + u16 wps_devicepassword_id = 0x0000; + uint wps_devicepassword_id_len = 0; + u8 channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh; + u16 len_channellist_attr = 0; + u32 pktlen; + u8 dialogToken = 0; + + /* struct xmit_frame *pmgntframe; */ + /* struct pkt_attrib *pattrib; */ + /* unsigned char *pframe; */ + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + /* WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); */ + +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif + + /* for debug */ + u8 *dbgbuf = pframe; + u8 dbgbufLen = 0, index = 0; + + RTW_INFO("%s\n", __FUNCTION__); + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + /* RA, filled by FW */ + _rtw_memset(pwlanhdr->addr1, 0, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN); + + SetSeqNum(pwlanhdr, 0); + set_frame_sub_type(pframe, WIFI_ACTION); + + pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + pframe += pktlen; + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pktlen)); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pktlen)); + + /* dialog token, filled by FW */ + pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pktlen)); + + _rtw_memset(wpsie, 0x00, 255); + wpsielen = 0; + + /* WPS Section */ + wpsielen = 0; + /* WPS OUI */ + *(u32 *)(wpsie) = cpu_to_be32(WPSOUI); + wpsielen += 4; + + /* WPS version */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ + + /* Device Password ID */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002); + wpsielen += 2; + + /* Value: */ + if (wps_devicepassword_id == WPS_DPID_USER_SPEC) + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC); + else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC); + else + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC); + wpsielen += 2; + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pktlen); + + + /* P2P IE Section. */ + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20100908 */ + /* According to the P2P Specification, the group negoitation response frame should contain 9 P2P attributes */ + /* 1. Status */ + /* 2. P2P Capability */ + /* 3. Group Owner Intent */ + /* 4. Configuration Timeout */ + /* 5. Operating Channel */ + /* 6. Intended P2P Interface Address */ + /* 7. Channel List */ + /* 8. Device Info */ + /* 9. Group ID ( Only GO ) */ + + + /* ToDo: */ + + /* P2P Status */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_STATUS; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value, filled by FW */ + p2pie[p2pielen++] = 1; + + /* P2P Capability */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CAPABILITY; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + /* Device Capability Bitmap, 1 byte */ + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) { + /* Commented by Albert 2011/03/08 */ + /* According to the P2P specification */ + /* if the sending device will be client, the P2P Capability should be reserved of group negotation response frame */ + p2pie[p2pielen++] = 0; + } else { + /* Be group owner or meet the error case */ + p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT; + } + + /* Group Capability Bitmap, 1 byte */ + if (pwdinfo->persistent_supported) + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP; + else + p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN; + + /* Group Owner Intent */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GO_INTENT; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: */ + if (pwdinfo->peer_intent & 0x01) { + /* Peer's tie breaker bit is 1, our tie breaker bit should be 0 */ + p2pie[p2pielen++] = (pwdinfo->intent << 1); + } else { + /* Peer's tie breaker bit is 0, our tie breaker bit should be 1 */ + p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0)); + } + + + /* Configuration Timeout */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ + + /* Operating Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + if (pwdinfo->operating_channel <= 14) { + /* Operating Class */ + p2pie[p2pielen++] = 0x51; + } else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48)) { + /* Operating Class */ + p2pie[p2pielen++] = 0x73; + } else { + /* Operating Class */ + p2pie[p2pielen++] = 0x7c; + } + + /* Channel Number */ + p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ + + /* Intended P2P Interface Address */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_INTENDED_IF_ADDR; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); + p2pielen += 2; + + /* Value: */ + _rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Channel List */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CH_LIST; + + /* Country String(3) */ + /* + ( Operating Class (1) + Number of Channels(1) ) * Operation Classes (?) */ + /* + number of channels in all classes */ + len_channellist_attr = 3 + + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes + + get_reg_classes_full_count(pmlmeext->channel_list); + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_buddy_check_fwstate(padapter, _FW_LINKED)) + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(5 + 1); + else + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); + +#else + + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); + +#endif + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Channel Entry List */ + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED)) { + u8 union_ch = rtw_mi_get_union_chan(padapter); + + /* Operating Class */ + if (union_ch > 14) { + if (union_ch >= 149) + p2pie[p2pielen++] = 0x7c; + else + p2pie[p2pielen++] = 0x73; + } else + p2pie[p2pielen++] = 0x51; + + + /* Number of Channels */ + /* Just support 1 channel and this channel is AP's channel */ + p2pie[p2pielen++] = 1; + + /* Channel List */ + p2pie[p2pielen++] = union_ch; + } else { + int i, j; + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } +#else /* CONFIG_CONCURRENT_MODE */ + { + int i, j; + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } +#endif /* CONFIG_CONCURRENT_MODE */ + + + /* Device Info */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO; + + /* Length: */ + /* 21->P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */ + /* + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address */ + _rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN); + p2pielen += ETH_ALEN; + + /* Config Method */ + /* This field should be big endian. Noted by P2P specification. */ + + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); + + p2pielen += 2; + + /* Primary Device Type */ + /* Category ID */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); + p2pielen += 2; + + /* OUI */ + *(u32 *)(p2pie + p2pielen) = cpu_to_be32(WPSOUI); + p2pielen += 4; + + /* Sub Category ID */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); + p2pielen += 2; + + /* Number of Secondary Device Types */ + p2pie[p2pielen++] = 0x00; /* No Secondary Device Type List */ + + /* Device Name */ + /* Type: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); + p2pielen += 2; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); + p2pielen += 2; + + /* Value: */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->device_name , pwdinfo->device_name_len); + p2pielen += pwdinfo->device_name_len; + + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + /* Group ID Attribute */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GROUP_ID; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen); + p2pielen += 2; + + /* Value: */ + /* p2P Device Address */ + _rtw_memcpy(p2pie + p2pielen , pwdinfo->device_addr, ETH_ALEN); + p2pielen += ETH_ALEN; + + /* SSID */ + _rtw_memcpy(p2pie + p2pielen, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen); + p2pielen += pwdinfo->nego_ssidlen; + + } + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pktlen); + +#ifdef CONFIG_WFD + wfdielen = build_nego_resp_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pktlen += wfdielen; +#endif + + *pLength = pktlen; +#if 0 + /* printf dbg msg */ + dbgbufLen = pktlen; + RTW_INFO("======> DBG MSG FOR CONSTRAUCT Nego Rsp\n"); + + for (index = 0; index < dbgbufLen; index++) + printk("%x ", *(dbgbuf + index)); + + printk("\n"); + RTW_INFO("<====== DBG MSG FOR CONSTRAUCT Nego Rsp\n"); +#endif +} + +static void rtw_hal_construct_P2PInviteRsp(_adapter *padapter, u8 *pframe, u32 *pLength) +{ + unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_INVIT_RESP; + u8 p2pie[255] = { 0x00 }; + u8 p2pielen = 0, i; + u8 channel_cnt_24g = 0, channel_cnt_5gl = 0, channel_cnt_5gh = 0; + u16 len_channellist_attr = 0; + u32 pktlen; + u8 dialogToken = 0; +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif + + /* struct xmit_frame *pmgntframe; */ + /* struct pkt_attrib *pattrib; */ + /* unsigned char *pframe; */ + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + + /* for debug */ + u8 *dbgbuf = pframe; + u8 dbgbufLen = 0, index = 0; + + + RTW_INFO("%s\n", __FUNCTION__); + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + /* RA fill by FW */ + _rtw_memset(pwlanhdr->addr1, 0, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + + /* BSSID fill by FW */ + _rtw_memset(pwlanhdr->addr3, 0, ETH_ALEN); + + SetSeqNum(pwlanhdr, 0); + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pktlen)); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pktlen)); + + /* dialog token, filled by FW */ + pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pktlen)); + + /* P2P IE Section. */ + + /* P2P OUI */ + p2pielen = 0; + p2pie[p2pielen++] = 0x50; + p2pie[p2pielen++] = 0x6F; + p2pie[p2pielen++] = 0x9A; + p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ + + /* Commented by Albert 20101005 */ + /* According to the P2P Specification, the P2P Invitation response frame should contain 5 P2P attributes */ + /* 1. Status */ + /* 2. Configuration Timeout */ + /* 3. Operating Channel ( Only GO ) */ + /* 4. P2P Group BSSID ( Only GO ) */ + /* 5. Channel List */ + + /* P2P Status */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_STATUS; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0001); + p2pielen += 2; + + /* Value: filled by FW, defult value is FAIL INFO UNAVAILABLE */ + p2pie[p2pielen++] = P2P_STATUS_FAIL_INFO_UNAVAILABLE; + + /* Configuration Timeout */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0002); + p2pielen += 2; + + /* Value: */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P GO */ + p2pie[p2pielen++] = 200; /* 2 seconds needed to be the P2P Client */ + + /* due to defult value is FAIL INFO UNAVAILABLE, so the following IE is not needed */ +#if 0 + if (status_code == P2P_STATUS_SUCCESS) { + if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) { + /* The P2P Invitation request frame asks this Wi-Fi device to be the P2P GO */ + /* In this case, the P2P Invitation response frame should carry the two more P2P attributes. */ + /* First one is operating channel attribute. */ + /* Second one is P2P Group BSSID attribute. */ + + /* Operating Channel */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(0x0005); + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Operating Class */ + p2pie[p2pielen++] = 0x51; /* Copy from SD7 */ + + /* Channel Number */ + p2pie[p2pielen++] = pwdinfo->operating_channel; /* operating channel number */ + + + /* P2P Group BSSID */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID; + + /* Length: */ + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(ETH_ALEN); + p2pielen += 2; + + /* Value: */ + /* P2P Device Address for GO */ + _rtw_memcpy(p2pie + p2pielen, adapter_mac_addr(padapter), ETH_ALEN); + p2pielen += ETH_ALEN; + + } + + /* Channel List */ + /* Type: */ + p2pie[p2pielen++] = P2P_ATTR_CH_LIST; + + /* Length: */ + /* Country String(3) */ + /* + ( Operating Class (1) + Number of Channels(1) ) * Operation Classes (?) */ + /* + number of channels in all classes */ + len_channellist_attr = 3 + + (1 + 1) * (u16)pmlmeext->channel_list.reg_classes + + get_reg_classes_full_count(pmlmeext->channel_list); + +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED)) + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(5 + 1); + else + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); + +#else + + *(u16 *)(p2pie + p2pielen) = cpu_to_le16(len_channellist_attr); + +#endif + p2pielen += 2; + + /* Value: */ + /* Country String */ + p2pie[p2pielen++] = 'X'; + p2pie[p2pielen++] = 'X'; + + /* The third byte should be set to 0x04. */ + /* Described in the "Operating Channel Attribute" section. */ + p2pie[p2pielen++] = 0x04; + + /* Channel Entry List */ +#ifdef CONFIG_CONCURRENT_MODE + if (rtw_mi_check_status(padapter, MI_LINKED)) { + u8 union_ch = rtw_mi_get_union_chan(padapter); + + /* Operating Class */ + if (union_ch > 14) { + if (union_ch >= 149) + p2pie[p2pielen++] = 0x7c; + else + p2pie[p2pielen++] = 0x73; + + } else + p2pie[p2pielen++] = 0x51; + + + /* Number of Channels */ + /* Just support 1 channel and this channel is AP's channel */ + p2pie[p2pielen++] = 1; + + /* Channel List */ + p2pie[p2pielen++] = union_ch; + } else { + int i, j; + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } +#else /* CONFIG_CONCURRENT_MODE */ + { + int i, j; + for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) { + /* Operating Class */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class; + + /* Number of Channels */ + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels; + + /* Channel List */ + for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) + p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i]; + } + } +#endif /* CONFIG_CONCURRENT_MODE */ + } +#endif + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pktlen); + +#ifdef CONFIG_WFD + wfdielen = build_invitation_resp_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pktlen += wfdielen; +#endif + + *pLength = pktlen; + +#if 0 + /* printf dbg msg */ + dbgbufLen = pktlen; + RTW_INFO("======> DBG MSG FOR CONSTRAUCT Invite Rsp\n"); + + for (index = 0; index < dbgbufLen; index++) + printk("%x ", *(dbgbuf + index)); + + printk("\n"); + RTW_INFO("<====== DBG MSG FOR CONSTRAUCT Invite Rsp\n"); +#endif +} + + +static void rtw_hal_construct_P2PProvisionDisRsp(_adapter *padapter, u8 *pframe, u32 *pLength) +{ + unsigned char category = RTW_WLAN_CATEGORY_PUBLIC; + u8 action = P2P_PUB_ACTION_ACTION; + u8 dialogToken = 0; + u32 p2poui = cpu_to_be32(P2POUI); + u8 oui_subtype = P2P_PROVISION_DISC_RESP; + u8 wpsie[100] = { 0x00 }; + u8 wpsielen = 0; + u32 pktlen; +#ifdef CONFIG_WFD + u32 wfdielen = 0; +#endif + + /* struct xmit_frame *pmgntframe; */ + /* struct pkt_attrib *pattrib; */ + /* unsigned char *pframe; */ + struct rtw_ieee80211_hdr *pwlanhdr; + unsigned short *fctrl; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct wifidirect_info *pwdinfo = &(padapter->wdinfo); + + /* for debug */ + u8 *dbgbuf = pframe; + u8 dbgbufLen = 0, index = 0; + + RTW_INFO("%s\n", __FUNCTION__); + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + /* RA filled by FW */ + _rtw_memset(pwlanhdr->addr1, 0, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN); + + SetSeqNum(pwlanhdr, 0); + set_frame_sub_type(pframe, WIFI_ACTION); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + pframe = rtw_set_fixed_ie(pframe, 1, &(category), &(pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(action), &(pktlen)); + pframe = rtw_set_fixed_ie(pframe, 4, (unsigned char *) &(p2poui), &(pktlen)); + pframe = rtw_set_fixed_ie(pframe, 1, &(oui_subtype), &(pktlen)); + /* dialog token, filled by FW */ + pframe = rtw_set_fixed_ie(pframe, 1, &(dialogToken), &(pktlen)); + + wpsielen = 0; + /* WPS OUI */ + /* *(u32*) ( wpsie ) = cpu_to_be32( WPSOUI ); */ + RTW_PUT_BE32(wpsie, WPSOUI); + wpsielen += 4; + +#if 0 + /* WPS version */ + /* Type: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1); + wpsielen += 2; + + /* Length: */ + *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001); + wpsielen += 2; + + /* Value: */ + wpsie[wpsielen++] = WPS_VERSION_1; /* Version 1.0 */ +#endif + + /* Config Method */ + /* Type: */ + /* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( WPS_ATTR_CONF_METHOD ); */ + RTW_PUT_BE16(wpsie + wpsielen, WPS_ATTR_CONF_METHOD); + wpsielen += 2; + + /* Length: */ + /* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( 0x0002 ); */ + RTW_PUT_BE16(wpsie + wpsielen, 0x0002); + wpsielen += 2; + + /* Value: filled by FW, default value is PBC */ + /* *(u16*) ( wpsie + wpsielen ) = cpu_to_be16( config_method ); */ + RTW_PUT_BE16(wpsie + wpsielen, WPS_CM_PUSH_BUTTON); + wpsielen += 2; + + pframe = rtw_set_ie(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pktlen); + +#ifdef CONFIG_WFD + wfdielen = build_provdisc_resp_wfd_ie(pwdinfo, pframe); + pframe += wfdielen; + pktlen += wfdielen; +#endif + + *pLength = pktlen; + + /* printf dbg msg */ +#if 0 + dbgbufLen = pktlen; + RTW_INFO("======> DBG MSG FOR CONSTRAUCT ProvisionDis Rsp\n"); + + for (index = 0; index < dbgbufLen; index++) + printk("%x ", *(dbgbuf + index)); + + printk("\n"); + RTW_INFO("<====== DBG MSG FOR CONSTRAUCT ProvisionDis Rsp\n"); +#endif +} + +u8 rtw_hal_set_FwP2PRsvdPage_cmd(_adapter *adapter, PRSVDPAGE_LOC rsvdpageloc) +{ + u8 u1H2CP2PRsvdPageParm[H2C_P2PRSVDPAGE_LOC_LEN] = {0}; + struct hal_ops *pHalFunc = &adapter->hal_func; + u8 ret = _FAIL; + + RTW_INFO("P2PRsvdPageLoc: P2PBeacon=%d P2PProbeRsp=%d NegoRsp=%d InviteRsp=%d PDRsp=%d\n", + rsvdpageloc->LocP2PBeacon, rsvdpageloc->LocP2PProbeRsp, + rsvdpageloc->LocNegoRsp, rsvdpageloc->LocInviteRsp, + rsvdpageloc->LocPDRsp); + + SET_H2CCMD_RSVDPAGE_LOC_P2P_BCN(u1H2CP2PRsvdPageParm, rsvdpageloc->LocProbeRsp); + SET_H2CCMD_RSVDPAGE_LOC_P2P_PROBE_RSP(u1H2CP2PRsvdPageParm, rsvdpageloc->LocPsPoll); + SET_H2CCMD_RSVDPAGE_LOC_P2P_NEGO_RSP(u1H2CP2PRsvdPageParm, rsvdpageloc->LocNullData); + SET_H2CCMD_RSVDPAGE_LOC_P2P_INVITE_RSP(u1H2CP2PRsvdPageParm, rsvdpageloc->LocQosNull); + SET_H2CCMD_RSVDPAGE_LOC_P2P_PD_RSP(u1H2CP2PRsvdPageParm, rsvdpageloc->LocBTQosNull); + + /* FillH2CCmd8723B(padapter, H2C_8723B_P2P_OFFLOAD_RSVD_PAGE, H2C_P2PRSVDPAGE_LOC_LEN, u1H2CP2PRsvdPageParm); */ + ret = rtw_hal_fill_h2c_cmd(adapter, + H2C_P2P_OFFLOAD_RSVD_PAGE, + H2C_P2PRSVDPAGE_LOC_LEN, + u1H2CP2PRsvdPageParm); + + return ret; +} + +u8 rtw_hal_set_p2p_wowlan_offload_cmd(_adapter *adapter) +{ + + u8 offload_cmd[H2C_P2P_OFFLOAD_LEN] = {0}; + struct wifidirect_info *pwdinfo = &(adapter->wdinfo); + struct P2P_WoWlan_Offload_t *p2p_wowlan_offload = (struct P2P_WoWlan_Offload_t *)offload_cmd; + struct hal_ops *pHalFunc = &adapter->hal_func; + u8 ret = _FAIL; + + _rtw_memset(p2p_wowlan_offload, 0 , sizeof(struct P2P_WoWlan_Offload_t)); + RTW_INFO("%s\n", __func__); + switch (pwdinfo->role) { + case P2P_ROLE_DEVICE: + RTW_INFO("P2P_ROLE_DEVICE\n"); + p2p_wowlan_offload->role = 0; + break; + case P2P_ROLE_CLIENT: + RTW_INFO("P2P_ROLE_CLIENT\n"); + p2p_wowlan_offload->role = 1; + break; + case P2P_ROLE_GO: + RTW_INFO("P2P_ROLE_GO\n"); + p2p_wowlan_offload->role = 2; + break; + default: + RTW_INFO("P2P_ROLE_DISABLE\n"); + break; + } + p2p_wowlan_offload->Wps_Config[0] = pwdinfo->supported_wps_cm >> 8; + p2p_wowlan_offload->Wps_Config[1] = pwdinfo->supported_wps_cm; + offload_cmd = (u8 *)p2p_wowlan_offload; + RTW_INFO("p2p_wowlan_offload: %x:%x:%x\n", offload_cmd[0], offload_cmd[1], offload_cmd[2]); + + ret = rtw_hal_fill_h2c_cmd(adapter, + H2C_P2P_OFFLOAD, + H2C_P2P_OFFLOAD_LEN, + offload_cmd); + return ret; + + /* FillH2CCmd8723B(adapter, H2C_8723B_P2P_OFFLOAD, sizeof(struct P2P_WoWlan_Offload_t), (u8 *)p2p_wowlan_offload); */ +} +#endif /* CONFIG_P2P_WOWLAN */ + +static void rtw_hal_construct_beacon(_adapter *padapter, + u8 *pframe, u32 *pLength) +{ + struct rtw_ieee80211_hdr *pwlanhdr; + u16 *fctrl; + u32 rate_len, pktlen; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + + /* RTW_INFO("%s\n", __FUNCTION__); */ + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN); + + SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/); + /* pmlmeext->mgnt_seq++; */ + set_frame_sub_type(pframe, WIFI_BEACON); + + pframe += sizeof(struct rtw_ieee80211_hdr_3addr); + pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + + /* timestamp will be inserted by hardware */ + pframe += 8; + pktlen += 8; + + /* beacon interval: 2 bytes */ + _rtw_memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval_from_ie(cur_network->IEs)), 2); + + pframe += 2; + pktlen += 2; + + /* capability info: 2 bytes */ + _rtw_memcpy(pframe, (unsigned char *)(rtw_get_capability_from_ie(cur_network->IEs)), 2); + + pframe += 2; + pktlen += 2; + + if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { + /* RTW_INFO("ie len=%d\n", cur_network->IELength); */ + pktlen += cur_network->IELength - sizeof(NDIS_802_11_FIXED_IEs); + _rtw_memcpy(pframe, cur_network->IEs + sizeof(NDIS_802_11_FIXED_IEs), pktlen); + + goto _ConstructBeacon; + } + + /* below for ad-hoc mode */ + + /* SSID */ + pframe = rtw_set_ie(pframe, _SSID_IE_, cur_network->Ssid.SsidLength, cur_network->Ssid.Ssid, &pktlen); + + /* supported rates... */ + rate_len = rtw_get_rateset_len(cur_network->SupportedRates); + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ? 8 : rate_len), cur_network->SupportedRates, &pktlen); + + /* DS parameter set */ + pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen); + + if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) { + u32 ATIMWindow; + /* IBSS Parameter Set... */ + /* ATIMWindow = cur->Configuration.ATIMWindow; */ + ATIMWindow = 0; + pframe = rtw_set_ie(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen); + } + + + /* todo: ERP IE */ + + + /* EXTERNDED SUPPORTED RATE */ + if (rate_len > 8) + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen); + + + /* todo:HT for adhoc */ + +_ConstructBeacon: + + if ((pktlen + TXDESC_SIZE) > 512) { + RTW_INFO("beacon frame too large\n"); + return; + } + + *pLength = pktlen; + + /* RTW_INFO("%s bcn_sz=%d\n", __FUNCTION__, pktlen); */ + +} + +static void rtw_hal_construct_PSPoll(_adapter *padapter, + u8 *pframe, u32 *pLength) +{ + struct rtw_ieee80211_hdr *pwlanhdr; + u16 *fctrl; + u32 pktlen; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + /* RTW_INFO("%s\n", __FUNCTION__); */ + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + /* Frame control. */ + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + SetPwrMgt(fctrl); + set_frame_sub_type(pframe, WIFI_PSPOLL); + + /* AID. */ + set_duration(pframe, (pmlmeinfo->aid | 0xc000)); + + /* BSSID. */ + _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + /* TA. */ + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + + *pLength = 16; +} + +void rtw_hal_construct_NullFunctionData( + PADAPTER padapter, + u8 *pframe, + u32 *pLength, + u8 *StaAddr, + u8 bQoS, + u8 AC, + u8 bEosp, + u8 bForcePowerSave) +{ + struct rtw_ieee80211_hdr *pwlanhdr; + u16 *fctrl; + u32 pktlen; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + + /* RTW_INFO("%s:%d\n", __FUNCTION__, bForcePowerSave); */ + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_ctl; + *(fctrl) = 0; + if (bForcePowerSave) + SetPwrMgt(fctrl); + + switch (cur_network->network.InfrastructureMode) { + case Ndis802_11Infrastructure: + SetToDs(fctrl); + _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN); + break; + case Ndis802_11APMode: + SetFrDs(fctrl); + _rtw_memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, adapter_mac_addr(padapter), ETH_ALEN); + break; + case Ndis802_11IBSS: + default: + _rtw_memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + break; + } + + SetSeqNum(pwlanhdr, 0); + + if (bQoS == _TRUE) { + struct rtw_ieee80211_hdr_3addr_qos *pwlanqoshdr; + + set_frame_sub_type(pframe, WIFI_QOS_DATA_NULL); + + pwlanqoshdr = (struct rtw_ieee80211_hdr_3addr_qos *)pframe; + SetPriority(&pwlanqoshdr->qc, AC); + SetEOSP(&pwlanqoshdr->qc, bEosp); + + pktlen = sizeof(struct rtw_ieee80211_hdr_3addr_qos); + } else { + set_frame_sub_type(pframe, WIFI_DATA_NULL); + + pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + } + + *pLength = pktlen; +} + +void rtw_hal_construct_ProbeRsp(_adapter *padapter, u8 *pframe, u32 *pLength, + u8 *StaAddr, BOOLEAN bHideSSID) +{ + struct rtw_ieee80211_hdr *pwlanhdr; + u16 *fctrl; + u8 *mac, *bssid; + u32 pktlen; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + WLAN_BSSID_EX *cur_network = &(pmlmeinfo->network); + + /*RTW_INFO("%s\n", __FUNCTION__);*/ + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + mac = adapter_mac_addr(padapter); + bssid = cur_network->MacAddress; + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + _rtw_memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); + + SetSeqNum(pwlanhdr, 0); + set_frame_sub_type(fctrl, WIFI_PROBERSP); + + pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + pframe += pktlen; + + if (cur_network->IELength > MAX_IE_SZ) + return; + + _rtw_memcpy(pframe, cur_network->IEs, cur_network->IELength); + pframe += cur_network->IELength; + pktlen += cur_network->IELength; + + *pLength = pktlen; +} + +#ifdef CONFIG_WOWLAN +static void rtw_hal_append_tkip_mic(PADAPTER padapter, + u8 *pframe, u32 offset) +{ + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct rtw_ieee80211_hdr *pwlanhdr; + struct mic_data micdata; + struct sta_info *psta = NULL; + int res = 0; + + u8 *payload = (u8 *)(pframe + offset); + + u8 mic[8]; + u8 priority[4] = {0x0}; + u8 null_key[16] = {0x0}; + + RTW_INFO("%s(): Add MIC, offset: %d\n", __func__, offset); + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + psta = rtw_get_stainfo(&padapter->stapriv, + get_my_bssid(&(pmlmeinfo->network))); + if (psta != NULL) { + res = _rtw_memcmp(&psta->dot11tkiptxmickey.skey[0], + null_key, 16); + if (res == _TRUE) + RTW_INFO("%s(): STA dot11tkiptxmickey==0\n", __func__); + rtw_secmicsetkey(&micdata, &psta->dot11tkiptxmickey.skey[0]); + } + + rtw_secmicappend(&micdata, pwlanhdr->addr3, 6); /* DA */ + + rtw_secmicappend(&micdata, pwlanhdr->addr2, 6); /* SA */ + + priority[0] = 0; + + rtw_secmicappend(&micdata, &priority[0], 4); + + rtw_secmicappend(&micdata, payload, 36); /* payload length = 8 + 28 */ + + rtw_secgetmic(&micdata, &(mic[0])); + + payload += 36; + + _rtw_memcpy(payload, &(mic[0]), 8); +} +/* + * Description: + * Construct the ARP response packet to support ARP offload. + * */ +static void rtw_hal_construct_ARPRsp( + PADAPTER padapter, + u8 *pframe, + u32 *pLength, + u8 *pIPAddress +) +{ + struct rtw_ieee80211_hdr *pwlanhdr; + u16 *fctrl; + u32 pktlen; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct security_priv *psecuritypriv = &padapter->securitypriv; + static u8 ARPLLCHeader[8] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06}; + u8 *pARPRspPkt = pframe; + /* for TKIP Cal MIC */ + u8 *payload = pframe; + u8 EncryptionHeadOverhead = 0, arp_offset = 0; + /* RTW_INFO("%s:%d\n", __FUNCTION__, bForcePowerSave); */ + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_ctl; + *(fctrl) = 0; + + /* ------------------------------------------------------------------------- */ + /* MAC Header. */ + /* ------------------------------------------------------------------------- */ + SetFrameType(fctrl, WIFI_DATA); + /* set_frame_sub_type(fctrl, 0); */ + SetToDs(fctrl); + _rtw_memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr2, adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + SetSeqNum(pwlanhdr, 0); + set_duration(pwlanhdr, 0); + /* SET_80211_HDR_FRAME_CONTROL(pARPRspPkt, 0); */ + /* SET_80211_HDR_TYPE_AND_SUBTYPE(pARPRspPkt, Type_Data); */ + /* SET_80211_HDR_TO_DS(pARPRspPkt, 1); */ + /* SET_80211_HDR_ADDRESS1(pARPRspPkt, pMgntInfo->Bssid); */ + /* SET_80211_HDR_ADDRESS2(pARPRspPkt, Adapter->CurrentAddress); */ + /* SET_80211_HDR_ADDRESS3(pARPRspPkt, pMgntInfo->Bssid); */ + + /* SET_80211_HDR_DURATION(pARPRspPkt, 0); */ + /* SET_80211_HDR_FRAGMENT_SEQUENCE(pARPRspPkt, 0); */ +#ifdef CONFIG_WAPI_SUPPORT + *pLength = sMacHdrLng; +#else + *pLength = 24; +#endif + switch (psecuritypriv->dot11PrivacyAlgrthm) { + case _WEP40_: + case _WEP104_: + EncryptionHeadOverhead = 4; + break; + case _TKIP_: + EncryptionHeadOverhead = 8; + break; + case _AES_: + EncryptionHeadOverhead = 8; + break; +#ifdef CONFIG_WAPI_SUPPORT + case _SMS4_: + EncryptionHeadOverhead = 18; + break; +#endif + default: + EncryptionHeadOverhead = 0; + } + + if (EncryptionHeadOverhead > 0) { + _rtw_memset(&(pframe[*pLength]), 0, EncryptionHeadOverhead); + *pLength += EncryptionHeadOverhead; + /* SET_80211_HDR_WEP(pARPRspPkt, 1); */ /* Suggested by CCW. */ + SetPrivacy(fctrl); + } + + /* ------------------------------------------------------------------------- */ + /* Frame Body. */ + /* ------------------------------------------------------------------------- */ + arp_offset = *pLength; + pARPRspPkt = (u8 *)(pframe + arp_offset); + payload = pARPRspPkt; /* Get Payload pointer */ + /* LLC header */ + _rtw_memcpy(pARPRspPkt, ARPLLCHeader, 8); + *pLength += 8; + + /* ARP element */ + pARPRspPkt += 8; + SET_ARP_PKT_HW(pARPRspPkt, 0x0100); + SET_ARP_PKT_PROTOCOL(pARPRspPkt, 0x0008); /* IP protocol */ + SET_ARP_PKT_HW_ADDR_LEN(pARPRspPkt, 6); + SET_ARP_PKT_PROTOCOL_ADDR_LEN(pARPRspPkt, 4); + SET_ARP_PKT_OPERATION(pARPRspPkt, 0x0200); /* ARP response */ + SET_ARP_PKT_SENDER_MAC_ADDR(pARPRspPkt, adapter_mac_addr(padapter)); + SET_ARP_PKT_SENDER_IP_ADDR(pARPRspPkt, pIPAddress); +#ifdef CONFIG_ARP_KEEP_ALIVE + if (!is_zero_mac_addr(pmlmepriv->gw_mac_addr)) { + SET_ARP_PKT_TARGET_MAC_ADDR(pARPRspPkt, pmlmepriv->gw_mac_addr); + SET_ARP_PKT_TARGET_IP_ADDR(pARPRspPkt, pmlmepriv->gw_ip); + } else +#endif + { + SET_ARP_PKT_TARGET_MAC_ADDR(pARPRspPkt, + get_my_bssid(&(pmlmeinfo->network))); + SET_ARP_PKT_TARGET_IP_ADDR(pARPRspPkt, + pIPAddress); + RTW_INFO("%s Target Mac Addr:" MAC_FMT "\n", __FUNCTION__, + MAC_ARG(get_my_bssid(&(pmlmeinfo->network)))); + RTW_INFO("%s Target IP Addr" IP_FMT "\n", __FUNCTION__, + IP_ARG(pIPAddress)); + } + + *pLength += 28; + + if (psecuritypriv->dot11PrivacyAlgrthm == _TKIP_) { + if (IS_HARDWARE_TYPE_8188E(padapter) || + IS_HARDWARE_TYPE_8812(padapter)) { + rtw_hal_append_tkip_mic(padapter, pframe, arp_offset); + } + *pLength += 8; + } +} + +#ifdef CONFIG_PNO_SUPPORT +static void rtw_hal_construct_ProbeReq(_adapter *padapter, u8 *pframe, + u32 *pLength, pno_ssid_t *ssid) +{ + struct rtw_ieee80211_hdr *pwlanhdr; + u16 *fctrl; + u32 pktlen; + unsigned char *mac; + unsigned char bssrate[NumRates]; + struct xmit_priv *pxmitpriv = &(padapter->xmitpriv); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + int bssrate_len = 0; + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + mac = adapter_mac_addr(padapter); + + fctrl = &(pwlanhdr->frame_ctl); + *(fctrl) = 0; + + _rtw_memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN); + _rtw_memcpy(pwlanhdr->addr3, bc_addr, ETH_ALEN); + + _rtw_memcpy(pwlanhdr->addr2, mac, ETH_ALEN); + + SetSeqNum(pwlanhdr, 0); + set_frame_sub_type(pframe, WIFI_PROBEREQ); + + pktlen = sizeof(struct rtw_ieee80211_hdr_3addr); + pframe += pktlen; + + if (ssid == NULL) + pframe = rtw_set_ie(pframe, _SSID_IE_, 0, NULL, &pktlen); + else { + /* RTW_INFO("%s len:%d\n", ssid->SSID, ssid->SSID_len); */ + pframe = rtw_set_ie(pframe, _SSID_IE_, ssid->SSID_len, ssid->SSID, &pktlen); + } + + get_rate_set(padapter, bssrate, &bssrate_len); + + if (bssrate_len > 8) { + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , 8, bssrate, &pktlen); + pframe = rtw_set_ie(pframe, _EXT_SUPPORTEDRATES_IE_ , (bssrate_len - 8), (bssrate + 8), &pktlen); + } else + pframe = rtw_set_ie(pframe, _SUPPORTEDRATES_IE_ , bssrate_len , bssrate, &pktlen); + + *pLength = pktlen; +} + +static void rtw_hal_construct_PNO_info(_adapter *padapter, + u8 *pframe, u32 *pLength) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); + int i; + + u8 *pPnoInfoPkt = pframe; + pPnoInfoPkt = (u8 *)(pframe + *pLength); + _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_num, 1); + + pPnoInfoPkt += 1; + _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->hidden_ssid_num, 1); + + pPnoInfoPkt += 3; + _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->fast_scan_period, 1); + + pPnoInfoPkt += 4; + _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->fast_scan_iterations, 4); + + pPnoInfoPkt += 4; + _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->slow_scan_period, 4); + + pPnoInfoPkt += 4; + _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_length, MAX_PNO_LIST_COUNT); + + pPnoInfoPkt += MAX_PNO_LIST_COUNT; + _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_cipher_info, MAX_PNO_LIST_COUNT); + + pPnoInfoPkt += MAX_PNO_LIST_COUNT; + _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->ssid_channel_info, MAX_PNO_LIST_COUNT); + + pPnoInfoPkt += MAX_PNO_LIST_COUNT; + _rtw_memcpy(pPnoInfoPkt, &pwrctl->pnlo_info->loc_probe_req, MAX_HIDDEN_AP); + + pPnoInfoPkt += MAX_HIDDEN_AP; + + /* + SSID is located at 128th Byte in NLO info Page + */ + + *pLength += 128; + pPnoInfoPkt = pframe + 128; + + for (i = 0; i < pwrctl->pnlo_info->ssid_num ; i++) { + _rtw_memcpy(pPnoInfoPkt, &pwrctl->pno_ssid_list->node[i].SSID, + pwrctl->pnlo_info->ssid_length[i]); + *pLength += WLAN_SSID_MAXLEN; + pPnoInfoPkt += WLAN_SSID_MAXLEN; + } +} + +static void rtw_hal_construct_ssid_list(_adapter *padapter, + u8 *pframe, u32 *pLength) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); + u8 *pSSIDListPkt = pframe; + int i; + + pSSIDListPkt = (u8 *)(pframe + *pLength); + + for (i = 0; i < pwrctl->pnlo_info->ssid_num ; i++) { + _rtw_memcpy(pSSIDListPkt, &pwrctl->pno_ssid_list->node[i].SSID, + pwrctl->pnlo_info->ssid_length[i]); + + *pLength += WLAN_SSID_MAXLEN; + pSSIDListPkt += WLAN_SSID_MAXLEN; + } +} + +static void rtw_hal_construct_scan_info(_adapter *padapter, + u8 *pframe, u32 *pLength) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); + u8 *pScanInfoPkt = pframe; + int i; + + pScanInfoPkt = (u8 *)(pframe + *pLength); + + _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->channel_num, 1); + + *pLength += 1; + pScanInfoPkt += 1; + _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_ch, 1); + + + *pLength += 1; + pScanInfoPkt += 1; + _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_bw, 1); + + + *pLength += 1; + pScanInfoPkt += 1; + _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_40_offset, 1); + + *pLength += 1; + pScanInfoPkt += 1; + _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->orig_80_offset, 1); + + *pLength += 1; + pScanInfoPkt += 1; + _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->periodScan, 1); + + *pLength += 1; + pScanInfoPkt += 1; + _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->period_scan_time, 1); + + *pLength += 1; + pScanInfoPkt += 1; + _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->enableRFE, 1); + + *pLength += 1; + pScanInfoPkt += 1; + _rtw_memcpy(pScanInfoPkt, &pwrctl->pscan_info->rfe_type, 8); + + *pLength += 8; + pScanInfoPkt += 8; + + for (i = 0 ; i < MAX_SCAN_LIST_COUNT ; i++) { + _rtw_memcpy(pScanInfoPkt, + &pwrctl->pscan_info->ssid_channel_info[i], 4); + *pLength += 4; + pScanInfoPkt += 4; + } +} +#endif /* CONFIG_PNO_SUPPORT */ + +#ifdef CONFIG_GTK_OL +static void rtw_hal_construct_GTKRsp( + PADAPTER padapter, + u8 *pframe, + u32 *pLength +) +{ + struct rtw_ieee80211_hdr *pwlanhdr; + u16 *fctrl; + u32 pktlen; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct wlan_network *cur_network = &pmlmepriv->cur_network; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct security_priv *psecuritypriv = &padapter->securitypriv; + static u8 LLCHeader[8] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8E}; + static u8 GTKbody_a[11] = {0x01, 0x03, 0x00, 0x5F, 0x02, 0x03, 0x12, 0x00, 0x10, 0x42, 0x0B}; + u8 *pGTKRspPkt = pframe; + u8 EncryptionHeadOverhead = 0; + /* RTW_INFO("%s:%d\n", __FUNCTION__, bForcePowerSave); */ + + pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; + + fctrl = &pwlanhdr->frame_ctl; + *(fctrl) = 0; + + /* ------------------------------------------------------------------------- */ + /* MAC Header. */ + /* ------------------------------------------------------------------------- */ + SetFrameType(fctrl, WIFI_DATA); + /* set_frame_sub_type(fctrl, 0); */ + SetToDs(fctrl); + + _rtw_memcpy(pwlanhdr->addr1, + get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + _rtw_memcpy(pwlanhdr->addr2, + adapter_mac_addr(padapter), ETH_ALEN); + + _rtw_memcpy(pwlanhdr->addr3, + get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); + + SetSeqNum(pwlanhdr, 0); + set_duration(pwlanhdr, 0); + +#ifdef CONFIG_WAPI_SUPPORT + *pLength = sMacHdrLng; +#else + *pLength = 24; +#endif /* CONFIG_WAPI_SUPPORT */ + + /* ------------------------------------------------------------------------- */ + /* Security Header: leave space for it if necessary. */ + /* ------------------------------------------------------------------------- */ + switch (psecuritypriv->dot11PrivacyAlgrthm) { + case _WEP40_: + case _WEP104_: + EncryptionHeadOverhead = 4; + break; + case _TKIP_: + EncryptionHeadOverhead = 8; + break; + case _AES_: + EncryptionHeadOverhead = 8; + break; +#ifdef CONFIG_WAPI_SUPPORT + case _SMS4_: + EncryptionHeadOverhead = 18; + break; +#endif /* CONFIG_WAPI_SUPPORT */ + default: + EncryptionHeadOverhead = 0; + } + + if (EncryptionHeadOverhead > 0) { + _rtw_memset(&(pframe[*pLength]), 0, EncryptionHeadOverhead); + *pLength += EncryptionHeadOverhead; + /* SET_80211_HDR_WEP(pGTKRspPkt, 1); */ /* Suggested by CCW. */ + /* GTK's privacy bit is done by FW */ + /* SetPrivacy(fctrl); */ + } + /* ------------------------------------------------------------------------- */ + /* Frame Body. */ + /* ------------------------------------------------------------------------- */ + pGTKRspPkt = (u8 *)(pframe + *pLength); + /* LLC header */ + _rtw_memcpy(pGTKRspPkt, LLCHeader, 8); + *pLength += 8; + + /* GTK element */ + pGTKRspPkt += 8; + + /* GTK frame body after LLC, part 1 */ + /* TKIP key_length = 32, AES key_length = 16 */ + if (psecuritypriv->dot118021XGrpPrivacy == _TKIP_) + GTKbody_a[8] = 0x20; + + /* GTK frame body after LLC, part 1 */ + _rtw_memcpy(pGTKRspPkt, GTKbody_a, 11); + *pLength += 11; + pGTKRspPkt += 11; + /* GTK frame body after LLC, part 2 */ + _rtw_memset(&(pframe[*pLength]), 0, 88); + *pLength += 88; + pGTKRspPkt += 88; + + if (psecuritypriv->dot118021XGrpPrivacy == _TKIP_) + *pLength += 8; +} +#endif /* CONFIG_GTK_OL */ + +void rtw_hal_set_wow_fw_rsvd_page(_adapter *adapter, u8 *pframe, u16 index, + u8 tx_desc, u32 page_size, u8 *page_num, u32 *total_pkt_len, + RSVDPAGE_LOC *rsvd_page_loc) +{ + struct security_priv *psecuritypriv = &adapter->securitypriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); + struct mlme_ext_priv *pmlmeext; + struct mlme_ext_info *pmlmeinfo; + u32 ARPLength = 0, GTKLength = 0, PNOLength = 0, ScanInfoLength = 0; + u32 SSIDLegnth = 0, ProbeReqLength = 0; + u8 CurtPktPageNum = 0; + u8 currentip[4]; + u8 cur_dot11txpn[8]; + +#ifdef CONFIG_GTK_OL + struct sta_priv *pstapriv = &adapter->stapriv; + struct sta_info *psta; + struct security_priv *psecpriv = &adapter->securitypriv; + u8 kek[RTW_KEK_LEN]; + u8 kck[RTW_KCK_LEN]; +#endif /* CONFIG_GTK_OL */ +#ifdef CONFIG_PNO_SUPPORT + int pno_index; + u8 ssid_num; +#endif /* CONFIG_PNO_SUPPORT */ + + pmlmeext = &adapter->mlmeextpriv; + pmlmeinfo = &pmlmeext->mlmext_info; + + if (pwrctl->wowlan_pno_enable == _FALSE) { + /* ARP RSP * 1 page */ + rtw_get_current_ip_address(adapter, currentip); + + rsvd_page_loc->LocArpRsp = *page_num; + + RTW_INFO("LocArpRsp: %d\n", rsvd_page_loc->LocArpRsp); + + rtw_hal_construct_ARPRsp(adapter, &pframe[index], + &ARPLength, currentip); + + rtw_hal_fill_fake_txdesc(adapter, + &pframe[index - tx_desc], + ARPLength, _FALSE, _FALSE, _TRUE); + + CurtPktPageNum = (u8)PageNum(tx_desc + ARPLength, page_size); + + *page_num += CurtPktPageNum; + + index += (CurtPktPageNum * page_size); + + /* 3 SEC IV * 1 page */ + rtw_get_sec_iv(adapter, cur_dot11txpn, + get_my_bssid(&pmlmeinfo->network)); + + rsvd_page_loc->LocRemoteCtrlInfo = *page_num; + + RTW_INFO("LocRemoteCtrlInfo: %d\n", rsvd_page_loc->LocRemoteCtrlInfo); + + _rtw_memcpy(pframe + index - tx_desc, cur_dot11txpn, _AES_IV_LEN_); + + CurtPktPageNum = (u8)PageNum(_AES_IV_LEN_, page_size); + + *page_num += CurtPktPageNum; + + *total_pkt_len = index + _AES_IV_LEN_; +#ifdef CONFIG_GTK_OL + index += (CurtPktPageNum * page_size); + + /* if the ap staion info. exists, get the kek, kck from staion info. */ + psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); + if (psta == NULL) { + _rtw_memset(kek, 0, RTW_KEK_LEN); + _rtw_memset(kck, 0, RTW_KCK_LEN); + RTW_INFO("%s, KEK, KCK download rsvd page all zero\n", + __func__); + } else { + _rtw_memcpy(kek, psta->kek, RTW_KEK_LEN); + _rtw_memcpy(kck, psta->kck, RTW_KCK_LEN); + } + + /* 3 KEK, KCK */ + rsvd_page_loc->LocGTKInfo = *page_num; + RTW_INFO("LocGTKInfo: %d\n", rsvd_page_loc->LocGTKInfo); + + if (IS_HARDWARE_TYPE_8188E(adapter) || IS_HARDWARE_TYPE_8812(adapter)) { + struct security_priv *psecpriv = NULL; + + psecpriv = &adapter->securitypriv; + _rtw_memcpy(pframe + index - tx_desc, + &psecpriv->dot11PrivacyAlgrthm, 1); + _rtw_memcpy(pframe + index - tx_desc + 1, + &psecpriv->dot118021XGrpPrivacy, 1); + _rtw_memcpy(pframe + index - tx_desc + 2, + kck, RTW_KCK_LEN); + _rtw_memcpy(pframe + index - tx_desc + 2 + RTW_KCK_LEN, + kek, RTW_KEK_LEN); + CurtPktPageNum = (u8)PageNum(tx_desc + 2 + RTW_KCK_LEN + RTW_KEK_LEN, page_size); + } else { + + _rtw_memcpy(pframe + index - tx_desc, kck, RTW_KCK_LEN); + _rtw_memcpy(pframe + index - tx_desc + RTW_KCK_LEN, + kek, RTW_KEK_LEN); + GTKLength = tx_desc + RTW_KCK_LEN + RTW_KEK_LEN; + + if (psta != NULL && + psecuritypriv->dot118021XGrpPrivacy == _TKIP_) { + _rtw_memcpy(pframe + index - tx_desc + 56, + &psta->dot11tkiptxmickey, RTW_TKIP_MIC_LEN); + GTKLength += RTW_TKIP_MIC_LEN; + } + CurtPktPageNum = (u8)PageNum(GTKLength, page_size); + } +#if 0 + { + int i; + printk("\ntoFW KCK: "); + for (i = 0; i < 16; i++) + printk(" %02x ", kck[i]); + printk("\ntoFW KEK: "); + for (i = 0; i < 16; i++) + printk(" %02x ", kek[i]); + printk("\n"); + } + + RTW_INFO("%s(): HW_VAR_SET_TX_CMD: KEK KCK %p %d\n", + __FUNCTION__, &pframe[index - tx_desc], + (tx_desc + RTW_KCK_LEN + RTW_KEK_LEN)); +#endif + + *page_num += CurtPktPageNum; + + index += (CurtPktPageNum * page_size); + + /* 3 GTK Response */ + rsvd_page_loc->LocGTKRsp = *page_num; + RTW_INFO("LocGTKRsp: %d\n", rsvd_page_loc->LocGTKRsp); + rtw_hal_construct_GTKRsp(adapter, &pframe[index], >KLength); + + rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], + GTKLength, _FALSE, _FALSE, _TRUE); +#if 0 + { + int gj; + printk("123GTK pkt=>\n"); + for (gj = 0; gj < GTKLength + tx_desc; gj++) { + printk(" %02x ", pframe[index - tx_desc + gj]); + if ((gj + 1) % 16 == 0) + printk("\n"); + } + printk(" <=end\n"); + } + + RTW_INFO("%s(): HW_VAR_SET_TX_CMD: GTK RSP %p %d\n", + __FUNCTION__, &pframe[index - tx_desc], + (tx_desc + GTKLength)); +#endif + + CurtPktPageNum = (u8)PageNum(tx_desc + GTKLength, page_size); + + *page_num += CurtPktPageNum; + + index += (CurtPktPageNum * page_size); + + /* below page is empty for GTK extension memory */ + /* 3(11) GTK EXT MEM */ + rsvd_page_loc->LocGTKEXTMEM = *page_num; + RTW_INFO("LocGTKEXTMEM: %d\n", rsvd_page_loc->LocGTKEXTMEM); + CurtPktPageNum = 2; + + if (page_size >= 256) + CurtPktPageNum = 1; + + *page_num += CurtPktPageNum; + /* extension memory for FW */ + *total_pkt_len = index + (page_size * CurtPktPageNum); +#endif /* CONFIG_GTK_OL */ + + index += (CurtPktPageNum * page_size); + + /*Reserve 1 page for AOAC report*/ + rsvd_page_loc->LocAOACReport = *page_num; + RTW_INFO("LocAOACReport: %d\n", rsvd_page_loc->LocAOACReport); + *page_num += 1; + *total_pkt_len = index + (page_size * 1); + } else { +#ifdef CONFIG_PNO_SUPPORT + if (pwrctl->wowlan_in_resume == _FALSE && + pwrctl->pno_inited == _TRUE) { + + /* Broadcast Probe Request */ + rsvd_page_loc->LocProbePacket = *page_num; + + RTW_INFO("loc_probe_req: %d\n", + rsvd_page_loc->LocProbePacket); + + rtw_hal_construct_ProbeReq( + adapter, + &pframe[index], + &ProbeReqLength, + NULL); + + rtw_hal_fill_fake_txdesc(adapter, + &pframe[index - tx_desc], + ProbeReqLength, _FALSE, _FALSE, _FALSE); + + CurtPktPageNum = + (u8)PageNum(tx_desc + ProbeReqLength, page_size); + + *page_num += CurtPktPageNum; + + index += (CurtPktPageNum * page_size); + + /* Hidden SSID Probe Request */ + ssid_num = pwrctl->pnlo_info->hidden_ssid_num; + + for (pno_index = 0 ; pno_index < ssid_num ; pno_index++) { + pwrctl->pnlo_info->loc_probe_req[pno_index] = + *page_num; + + rtw_hal_construct_ProbeReq( + adapter, + &pframe[index], + &ProbeReqLength, + &pwrctl->pno_ssid_list->node[pno_index]); + + rtw_hal_fill_fake_txdesc(adapter, + &pframe[index - tx_desc], + ProbeReqLength, _FALSE, _FALSE, _FALSE); + + CurtPktPageNum = + (u8)PageNum(tx_desc + ProbeReqLength, page_size); + + *page_num += CurtPktPageNum; + + index += (CurtPktPageNum * page_size); + } + + /* PNO INFO Page */ + rsvd_page_loc->LocPNOInfo = *page_num; + RTW_INFO("LocPNOInfo: %d\n", rsvd_page_loc->LocPNOInfo); + rtw_hal_construct_PNO_info(adapter, + &pframe[index - tx_desc], + &PNOLength); + + CurtPktPageNum = (u8)PageNum(PNOLength, page_size); + *page_num += CurtPktPageNum; + index += (CurtPktPageNum * page_size); + + /* Scan Info Page */ + rsvd_page_loc->LocScanInfo = *page_num; + RTW_INFO("LocScanInfo: %d\n", rsvd_page_loc->LocScanInfo); + rtw_hal_construct_scan_info(adapter, + &pframe[index - tx_desc], + &ScanInfoLength); + + CurtPktPageNum = (u8)PageNum(ScanInfoLength, page_size); + *page_num += CurtPktPageNum; + *total_pkt_len = index + ScanInfoLength; + index += (CurtPktPageNum * page_size); + } +#endif /* CONFIG_PNO_SUPPORT */ + } +} + +static void rtw_hal_gate_bb(_adapter *adapter, bool stop) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); + u8 val8 = 0; + u16 val16 = 0; + + if (stop) { + /* Pause TX*/ + pwrpriv->wowlan_txpause_status = rtw_read8(adapter, REG_TXPAUSE); + rtw_write8(adapter, REG_TXPAUSE, 0xff); + val8 = rtw_read8(adapter, REG_SYS_FUNC_EN); + val8 &= ~BIT(0); + rtw_write8(adapter, REG_SYS_FUNC_EN, val8); + RTW_INFO("%s: BB gated: 0x%02x, store TXPAUSE: %02x\n", + __func__, + rtw_read8(adapter, REG_SYS_FUNC_EN), + pwrpriv->wowlan_txpause_status); + } else { + val8 = rtw_read8(adapter, REG_SYS_FUNC_EN); + val8 |= BIT(0); + rtw_write8(adapter, REG_SYS_FUNC_EN, val8); + RTW_INFO("%s: BB release: 0x%02x, recover TXPAUSE:%02x\n", + __func__, rtw_read8(adapter, REG_SYS_FUNC_EN), + pwrpriv->wowlan_txpause_status); + /* release TX*/ + rtw_write8(adapter, REG_TXPAUSE, pwrpriv->wowlan_txpause_status); + } +} + +static void rtw_hal_reset_mac_rx(_adapter *adapter) +{ + u8 val8 = 0; + /* Set REG_CR bit1, bit3, bit7 to 0*/ + val8 = rtw_read8(adapter, REG_CR); + val8 &= 0x75; + rtw_write8(adapter, REG_CR, val8); + val8 = rtw_read8(adapter, REG_CR); + /* Set REG_CR bit1, bit3, bit7 to 1*/ + val8 |= 0x8a; + rtw_write8(adapter, REG_CR, val8); + RTW_INFO("0x%04x: %02x\n", REG_CR, rtw_read8(adapter, REG_CR)); +} + +static u8 rtw_hal_wow_pattern_generate(_adapter *adapter, u8 idx, struct rtl_wow_pattern *pwow_pattern) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); + u8 *pattern; + u8 len = 0; + u8 *mask; + + u8 mask_hw[MAX_WKFM_SIZE] = {0}; + u8 content[MAX_WKFM_PATTERN_SIZE] = {0}; + u8 broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 multicast_addr1[2] = {0x33, 0x33}; + u8 multicast_addr2[3] = {0x01, 0x00, 0x5e}; + u8 mask_len = 0; + u8 mac_addr[ETH_ALEN] = {0}; + u16 count = 0; + int i, j; + + if (pwrctl->wowlan_pattern_idx > MAX_WKFM_CAM_NUM) { + RTW_INFO("%s pattern_idx is more than MAX_FMC_NUM: %d\n", + __func__, MAX_WKFM_CAM_NUM); + return _FAIL; + } + + pattern = pwrctl->patterns[idx].content; + len = pwrctl->patterns[idx].len; + mask = pwrctl->patterns[idx].mask; + + _rtw_memcpy(mac_addr, adapter_mac_addr(adapter), ETH_ALEN); + _rtw_memset(pwow_pattern, 0, sizeof(struct rtl_wow_pattern)); + + mask_len = DIV_ROUND_UP(len, 8); + + /* 1. setup A1 table */ + if (memcmp(pattern, broadcast_addr, ETH_ALEN) == 0) + pwow_pattern->type = PATTERN_BROADCAST; + else if (memcmp(pattern, multicast_addr1, 2) == 0) + pwow_pattern->type = PATTERN_MULTICAST; + else if (memcmp(pattern, multicast_addr2, 3) == 0) + pwow_pattern->type = PATTERN_MULTICAST; + else if (memcmp(pattern, mac_addr, ETH_ALEN) == 0) + pwow_pattern->type = PATTERN_UNICAST; + else + pwow_pattern->type = PATTERN_INVALID; + + /* translate mask from os to mask for hw */ + + /****************************************************************************** + * pattern from OS uses 'ethenet frame', like this: + + | 6 | 6 | 2 | 20 | Variable | 4 | + |--------+--------+------+-----------+------------+-----| + | 802.3 Mac Header | IP Header | TCP Packet | FCS | + | DA | SA | Type | + + * BUT, packet catched by our HW is in '802.11 frame', begin from LLC, + + | 24 or 30 | 6 | 2 | 20 | Variable | 4 | + |-------------------+--------+------+-----------+------------+-----| + | 802.11 MAC Header | LLC | IP Header | TCP Packet | FCS | + | Others | Tpye | + + * Therefore, we need translate mask_from_OS to mask_to_hw. + * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0, + * because new mask[0~5] means 'SA', but our HW packet begins from LLC, + * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match. + ******************************************************************************/ + /* Shift 6 bits */ + for (i = 0; i < mask_len - 1; i++) { + mask_hw[i] = mask[i] >> 6; + mask_hw[i] |= (mask[i + 1] & 0x3F) << 2; + } + + mask_hw[i] = (mask[i] >> 6) & 0x3F; + /* Set bit 0-5 to zero */ + mask_hw[0] &= 0xC0; + + for (i = 0; i < (MAX_WKFM_SIZE / 4); i++) { + pwow_pattern->mask[i] = mask_hw[i * 4]; + pwow_pattern->mask[i] |= (mask_hw[i * 4 + 1] << 8); + pwow_pattern->mask[i] |= (mask_hw[i * 4 + 2] << 16); + pwow_pattern->mask[i] |= (mask_hw[i * 4 + 3] << 24); + } + + /* To get the wake up pattern from the mask. + * We do not count first 12 bits which means + * DA[6] and SA[6] in the pattern to match HW design. */ + count = 0; + for (i = 12; i < len; i++) { + if ((mask[i / 8] >> (i % 8)) & 0x01) { + content[count] = pattern[i]; + count++; + } + } + + pwow_pattern->crc = rtw_calc_crc(content, count); + + if (pwow_pattern->crc != 0) { + if (pwow_pattern->type == PATTERN_INVALID) + pwow_pattern->type = PATTERN_VALID; + } + + return _SUCCESS; +} + +#ifndef CONFIG_WOW_PATTERN_HW_CAM +static void rtw_hal_set_wow_rxff_boundary(_adapter *adapter, bool wow_mode) +{ + u8 val8 = 0; + u16 rxff_bndy = 0; + u32 rx_dma_buff_sz = 0; + + val8 = rtw_read8(adapter, REG_FIFOPAGE + 3); + if (val8 != 0) + RTW_INFO("%s:[%04x]some PKTs in TXPKTBUF\n", + __func__, (REG_FIFOPAGE + 3)); + + rtw_hal_reset_mac_rx(adapter); + + if (wow_mode) { + rtw_hal_get_def_var(adapter, HAL_DEF_RX_DMA_SZ_WOW, + (u8 *)&rx_dma_buff_sz); + rxff_bndy = rx_dma_buff_sz - 1; + + rtw_write16(adapter, (REG_TRXFF_BNDY + 2), rxff_bndy); + RTW_INFO("%s: wow mode, 0x%04x: 0x%04x\n", __func__, + REG_TRXFF_BNDY + 2, + rtw_read16(adapter, (REG_TRXFF_BNDY + 2))); + } else { + rtw_hal_get_def_var(adapter, HAL_DEF_RX_DMA_SZ, + (u8 *)&rx_dma_buff_sz); + rxff_bndy = rx_dma_buff_sz - 1; + rtw_write16(adapter, (REG_TRXFF_BNDY + 2), rxff_bndy); + RTW_INFO("%s: normal mode, 0x%04x: 0x%04x\n", __func__, + REG_TRXFF_BNDY + 2, + rtw_read16(adapter, (REG_TRXFF_BNDY + 2))); + } +} + +bool rtw_read_from_frame_mask(_adapter *adapter, u8 idx) +{ + u32 data_l = 0, data_h = 0, rx_dma_buff_sz = 0, page_sz = 0; + u16 offset, rx_buf_ptr = 0; + u16 cam_start_offset = 0; + u16 ctrl_l = 0, ctrl_h = 0; + u8 count = 0, tmp = 0; + int i = 0; + bool res = _TRUE; + + if (idx > MAX_WKFM_CAM_NUM) { + RTW_INFO("[Error]: %s, pattern index is out of range\n", + __func__); + return _FALSE; + } + + rtw_hal_get_def_var(adapter, HAL_DEF_RX_DMA_SZ_WOW, + (u8 *)&rx_dma_buff_sz); + + if (rx_dma_buff_sz == 0) { + RTW_INFO("[Error]: %s, rx_dma_buff_sz is 0!!\n", __func__); + return _FALSE; + } + + rtw_hal_get_def_var(adapter, HAL_DEF_RX_PAGE_SIZE, (u8 *)&page_sz); + + if (page_sz == 0) { + RTW_INFO("[Error]: %s, page_sz is 0!!\n", __func__); + return _FALSE; + } + + offset = (u16)PageNum(rx_dma_buff_sz, page_sz); + cam_start_offset = offset * page_sz; + + ctrl_l = 0x0; + ctrl_h = 0x0; + + /* Enable RX packet buffer access */ + rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, RXPKT_BUF_SELECT); + + /* Read the WKFM CAM */ + for (i = 0; i < (WKFMCAM_ADDR_NUM / 2); i++) { + /* + * Set Rx packet buffer offset. + * RxBufer pointer increases 1, we can access 8 bytes in Rx packet buffer. + * CAM start offset (unit: 1 byte) = Index*WKFMCAM_SIZE + * RxBufer pointer addr = (CAM start offset + per entry offset of a WKFMCAM)/8 + * * Index: The index of the wake up frame mask + * * WKFMCAM_SIZE: the total size of one WKFM CAM + * * per entry offset of a WKFM CAM: Addr i * 4 bytes + */ + rx_buf_ptr = + (cam_start_offset + idx * WKFMCAM_SIZE + i * 8) >> 3; + rtw_write16(adapter, REG_PKTBUF_DBG_CTRL, rx_buf_ptr); + + rtw_write16(adapter, REG_RXPKTBUF_CTRL, ctrl_l); + data_l = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_L); + data_h = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_H); + + RTW_INFO("[%d]: %08x %08x\n", i, data_h, data_l); + + count = 0; + + do { + tmp = rtw_read8(adapter, REG_RXPKTBUF_CTRL); + rtw_udelay_os(2); + count++; + } while (!tmp && count < 100); + + if (count >= 100) { + RTW_INFO("%s count:%d\n", __func__, count); + res = _FALSE; + } + } + + /* Disable RX packet buffer access */ + rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, + DISABLE_TRXPKT_BUF_ACCESS); + return res; +} + +bool rtw_write_to_frame_mask(_adapter *adapter, u8 idx, + struct rtl_wow_pattern *context) +{ + u32 data = 0, rx_dma_buff_sz = 0, page_sz = 0; + u16 offset, rx_buf_ptr = 0; + u16 cam_start_offset = 0; + u16 ctrl_l = 0, ctrl_h = 0; + u8 count = 0, tmp = 0; + int res = 0, i = 0; + + if (idx > MAX_WKFM_CAM_NUM) { + RTW_INFO("[Error]: %s, pattern index is out of range\n", + __func__); + return _FALSE; + } + + rtw_hal_get_def_var(adapter, HAL_DEF_RX_DMA_SZ_WOW, + (u8 *)&rx_dma_buff_sz); + + if (rx_dma_buff_sz == 0) { + RTW_INFO("[Error]: %s, rx_dma_buff_sz is 0!!\n", __func__); + return _FALSE; + } + + rtw_hal_get_def_var(adapter, HAL_DEF_RX_PAGE_SIZE, (u8 *)&page_sz); + + if (page_sz == 0) { + RTW_INFO("[Error]: %s, page_sz is 0!!\n", __func__); + return _FALSE; + } + + offset = (u16)PageNum(rx_dma_buff_sz, page_sz); + + cam_start_offset = offset * page_sz; + + if (IS_HARDWARE_TYPE_8188E(adapter)) { + ctrl_l = 0x0001; + ctrl_h = 0x0001; + } else { + ctrl_l = 0x0f01; + ctrl_h = 0xf001; + } + + /* Enable RX packet buffer access */ + rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, RXPKT_BUF_SELECT); + + /* Write the WKFM CAM */ + for (i = 0; i < WKFMCAM_ADDR_NUM; i++) { + /* + * Set Rx packet buffer offset. + * RxBufer pointer increases 1, we can access 8 bytes in Rx packet buffer. + * CAM start offset (unit: 1 byte) = Index*WKFMCAM_SIZE + * RxBufer pointer addr = (CAM start offset + per entry offset of a WKFMCAM)/8 + * * Index: The index of the wake up frame mask + * * WKFMCAM_SIZE: the total size of one WKFM CAM + * * per entry offset of a WKFM CAM: Addr i * 4 bytes + */ + rx_buf_ptr = + (cam_start_offset + idx * WKFMCAM_SIZE + i * 4) >> 3; + rtw_write16(adapter, REG_PKTBUF_DBG_CTRL, rx_buf_ptr); + + if (i == 0) { + if (context->type == PATTERN_VALID) + data = BIT(31); + else if (context->type == PATTERN_BROADCAST) + data = BIT(31) | BIT(26); + else if (context->type == PATTERN_MULTICAST) + data = BIT(31) | BIT(25); + else if (context->type == PATTERN_UNICAST) + data = BIT(31) | BIT(24); + + if (context->crc != 0) + data |= context->crc; + + rtw_write32(adapter, REG_PKTBUF_DBG_DATA_L, data); + rtw_write16(adapter, REG_RXPKTBUF_CTRL, ctrl_l); + } else if (i == 1) { + data = 0; + rtw_write32(adapter, REG_PKTBUF_DBG_DATA_H, data); + rtw_write16(adapter, REG_RXPKTBUF_CTRL, ctrl_h); + } else if (i == 2 || i == 4) { + data = context->mask[i - 2]; + rtw_write32(adapter, REG_PKTBUF_DBG_DATA_L, data); + /* write to RX packet buffer*/ + rtw_write16(adapter, REG_RXPKTBUF_CTRL, ctrl_l); + } else if (i == 3 || i == 5) { + data = context->mask[i - 2]; + rtw_write32(adapter, REG_PKTBUF_DBG_DATA_H, data); + /* write to RX packet buffer*/ + rtw_write16(adapter, REG_RXPKTBUF_CTRL, ctrl_h); + } + + count = 0; + do { + tmp = rtw_read8(adapter, REG_RXPKTBUF_CTRL); + rtw_udelay_os(2); + count++; + } while (tmp && count < 100); + + if (count >= 100) + res = _FALSE; + else + res = _TRUE; + } + + /* Disable RX packet buffer access */ + rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, + DISABLE_TRXPKT_BUF_ACCESS); + + return res; +} +void rtw_clean_pattern(_adapter *adapter) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); + struct rtl_wow_pattern zero_pattern; + int i = 0; + + _rtw_memset(&zero_pattern, 0, sizeof(struct rtl_wow_pattern)); + + zero_pattern.type = PATTERN_INVALID; + + for (i = 0; i < MAX_WKFM_CAM_NUM; i++) + rtw_write_to_frame_mask(adapter, i, &zero_pattern); + + rtw_write8(adapter, REG_WKFMCAM_NUM, 0); +} +static int rtw_hal_set_pattern(_adapter *adapter, u8 *pattern, + u8 len, u8 *mask, u8 idx) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); + struct mlme_ext_priv *pmlmeext = NULL; + struct mlme_ext_info *pmlmeinfo = NULL; + struct rtl_wow_pattern wow_pattern; + u8 mask_hw[MAX_WKFM_SIZE] = {0}; + u8 content[MAX_WKFM_PATTERN_SIZE] = {0}; + u8 broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 multicast_addr1[2] = {0x33, 0x33}; + u8 multicast_addr2[3] = {0x01, 0x00, 0x5e}; + u8 res = _FALSE, index = 0, mask_len = 0; + u8 mac_addr[ETH_ALEN] = {0}; + u16 count = 0; + int i, j; + + if (pwrctl->wowlan_pattern_idx > MAX_WKFM_CAM_NUM) { + RTW_INFO("%s pattern_idx is more than MAX_FMC_NUM: %d\n", + __func__, MAX_WKFM_CAM_NUM); + return _FALSE; + } + + pmlmeext = &adapter->mlmeextpriv; + pmlmeinfo = &pmlmeext->mlmext_info; + _rtw_memcpy(mac_addr, adapter_mac_addr(adapter), ETH_ALEN); + _rtw_memset(&wow_pattern, 0, sizeof(struct rtl_wow_pattern)); + + mask_len = DIV_ROUND_UP(len, 8); + + /* 1. setup A1 table */ + if (memcmp(pattern, broadcast_addr, ETH_ALEN) == 0) + wow_pattern.type = PATTERN_BROADCAST; + else if (memcmp(pattern, multicast_addr1, 2) == 0) + wow_pattern.type = PATTERN_MULTICAST; + else if (memcmp(pattern, multicast_addr2, 3) == 0) + wow_pattern.type = PATTERN_MULTICAST; + else if (memcmp(pattern, mac_addr, ETH_ALEN) == 0) + wow_pattern.type = PATTERN_UNICAST; + else + wow_pattern.type = PATTERN_INVALID; + + /* translate mask from os to mask for hw */ + +/****************************************************************************** + * pattern from OS uses 'ethenet frame', like this: + + | 6 | 6 | 2 | 20 | Variable | 4 | + |--------+--------+------+-----------+------------+-----| + | 802.3 Mac Header | IP Header | TCP Packet | FCS | + | DA | SA | Type | + + * BUT, packet catched by our HW is in '802.11 frame', begin from LLC, + + | 24 or 30 | 6 | 2 | 20 | Variable | 4 | + |-------------------+--------+------+-----------+------------+-----| + | 802.11 MAC Header | LLC | IP Header | TCP Packet | FCS | + | Others | Tpye | + + * Therefore, we need translate mask_from_OS to mask_to_hw. + * We should left-shift mask by 6 bits, then set the new bit[0~5] = 0, + * because new mask[0~5] means 'SA', but our HW packet begins from LLC, + * bit[0~5] corresponds to first 6 Bytes in LLC, they just don't match. + ******************************************************************************/ + /* Shift 6 bits */ + for (i = 0; i < mask_len - 1; i++) { + mask_hw[i] = mask[i] >> 6; + mask_hw[i] |= (mask[i + 1] & 0x3F) << 2; + } + + mask_hw[i] = (mask[i] >> 6) & 0x3F; + /* Set bit 0-5 to zero */ + mask_hw[0] &= 0xC0; + + for (i = 0; i < (MAX_WKFM_SIZE / 4); i++) { + wow_pattern.mask[i] = mask_hw[i * 4]; + wow_pattern.mask[i] |= (mask_hw[i * 4 + 1] << 8); + wow_pattern.mask[i] |= (mask_hw[i * 4 + 2] << 16); + wow_pattern.mask[i] |= (mask_hw[i * 4 + 3] << 24); + } + + /* To get the wake up pattern from the mask. + * We do not count first 12 bits which means + * DA[6] and SA[6] in the pattern to match HW design. */ + count = 0; + for (i = 12; i < len; i++) { + if ((mask[i / 8] >> (i % 8)) & 0x01) { + content[count] = pattern[i]; + count++; + } + } + + wow_pattern.crc = rtw_calc_crc(content, count); + + if (wow_pattern.crc != 0) { + if (wow_pattern.type == PATTERN_INVALID) + wow_pattern.type = PATTERN_VALID; + } + + index = idx; + + if (!pwrctl->bInSuspend) + index += 2; + + /* write pattern */ + res = rtw_write_to_frame_mask(adapter, index, &wow_pattern); + + if (res == _FALSE) + RTW_INFO("%s: ERROR!! idx: %d write_to_frame_mask_cam fail\n", + __func__, idx); + + return res; +} +void rtw_fill_pattern(_adapter *adapter) +{ + int i = 0, total = 0, index; + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); + struct rtl_wow_pattern wow_pattern; + + total = pwrpriv->wowlan_pattern_idx; + + if (total > MAX_WKFM_CAM_NUM) + total = MAX_WKFM_CAM_NUM; + + for (i = 0 ; i < total ; i++) { + if (_SUCCESS == rtw_hal_wow_pattern_generate(adapter, i, &wow_pattern)) { + + index = i; + if (!pwrpriv->bInSuspend) + index += 2; + + if (rtw_write_to_frame_mask(adapter, index, &wow_pattern) == _FALSE) + RTW_INFO("%s: ERROR!! idx: %d write_to_frame_mask_cam fail\n", __func__, i); + } + + } + rtw_write8(adapter, REG_WKFMCAM_NUM, total); + +} + +#else /*CONFIG_WOW_PATTERN_HW_CAM*/ + +#define WOW_CAM_ACCESS_TIMEOUT_MS 200 +#define WOW_VALID_BIT BIT31 +#define WOW_BC_BIT BIT26 +#define WOW_MC_BIT BIT25 +#define WOW_UC_BIT BIT24 + +static u32 _rtw_wow_pattern_read_cam(_adapter *adapter, u8 addr) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); + _mutex *mutex = &pwrpriv->wowlan_pattern_cam_mutex; + + u32 rdata = 0; + u32 cnt = 0; + u32 start = 0; + u8 timeout = 0; + u8 rst = _FALSE; + + _enter_critical_mutex(mutex, NULL); + + rtw_write32(adapter, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1 | BIT_WKFCAM_ADDR_V2(addr)); + + start = rtw_get_current_time(); + while (1) { + if (rtw_is_surprise_removed(adapter)) + break; + + cnt++; + if (0 == (rtw_read32(adapter, REG_WKFMCAM_CMD) & BIT_WKFCAM_POLLING_V1)) { + rst = _SUCCESS; + break; + } + if (rtw_get_passing_time_ms(start) > WOW_CAM_ACCESS_TIMEOUT_MS) { + timeout = 1; + break; + } + } + + rdata = rtw_read32(adapter, REG_WKFMCAM_RWD); + + _exit_critical_mutex(mutex, NULL); + + /*RTW_INFO("%s ==> addr:0x%02x , rdata:0x%08x\n", __func__, addr, rdata);*/ + + if (timeout) + RTW_ERR(FUNC_ADPT_FMT" failed due to polling timeout\n", FUNC_ADPT_ARG(adapter)); + + return rdata; +} +void rtw_wow_pattern_read_cam_ent(_adapter *adapter, u8 id, struct rtl_wow_pattern *context) +{ + int i; + u32 rdata; + + _rtw_memset(context, 0, sizeof(struct rtl_wow_pattern)); + + for (i = 4; i >= 0; i--) { + rdata = _rtw_wow_pattern_read_cam(adapter, (id << 3) | i); + + switch (i) { + case 4: + if (rdata & WOW_BC_BIT) + context->type = PATTERN_BROADCAST; + else if (rdata & WOW_MC_BIT) + context->type = PATTERN_MULTICAST; + else if (rdata & WOW_UC_BIT) + context->type = PATTERN_UNICAST; + else + context->type = PATTERN_INVALID; + + context->crc = rdata & 0xFFFF; + break; + default: + _rtw_memcpy(&context->mask[i], (u8 *)(&rdata), 4); + break; + } + } +} + +static void _rtw_wow_pattern_write_cam(_adapter *adapter, u8 addr, u32 wdata) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); + _mutex *mutex = &pwrpriv->wowlan_pattern_cam_mutex; + u32 cnt = 0; + u32 start = 0, end = 0; + u8 timeout = 0; + + /*RTW_INFO("%s ==> addr:0x%02x , wdata:0x%08x\n", __func__, addr, wdata);*/ + _enter_critical_mutex(mutex, NULL); + + rtw_write32(adapter, REG_WKFMCAM_RWD, wdata); + rtw_write32(adapter, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1 | BIT_WKFCAM_WE | BIT_WKFCAM_ADDR_V2(addr)); + + start = rtw_get_current_time(); + while (1) { + if (rtw_is_surprise_removed(adapter)) + break; + + cnt++; + if (0 == (rtw_read32(adapter, REG_WKFMCAM_CMD) & BIT_WKFCAM_POLLING_V1)) + break; + + if (rtw_get_passing_time_ms(start) > WOW_CAM_ACCESS_TIMEOUT_MS) { + timeout = 1; + break; + } + } + end = rtw_get_current_time(); + + _exit_critical_mutex(mutex, NULL); + + if (timeout) { + RTW_ERR(FUNC_ADPT_FMT" addr:0x%02x, wdata:0x%08x, to:%u, polling:%u, %d ms\n" + , FUNC_ADPT_ARG(adapter), addr, wdata, timeout, cnt, rtw_get_time_interval_ms(start, end)); + } +} + +void rtw_wow_pattern_write_cam_ent(_adapter *adapter, u8 id, struct rtl_wow_pattern *context) +{ + int j; + u8 addr; + u32 wdata = 0; + + for (j = 4; j >= 0; j--) { + switch (j) { + case 4: + wdata = context->crc; + + if (PATTERN_BROADCAST == context->type) + wdata |= WOW_BC_BIT; + if (PATTERN_MULTICAST == context->type) + wdata |= WOW_MC_BIT; + if (PATTERN_UNICAST == context->type) + wdata |= WOW_UC_BIT; + if (PATTERN_INVALID != context->type) + wdata |= WOW_VALID_BIT; + break; + default: + wdata = context->mask[j]; + break; + } + + addr = (id << 3) + j; + + _rtw_wow_pattern_write_cam(adapter, addr, wdata); + } +} + +static u8 _rtw_wow_pattern_clean_cam(_adapter *adapter) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); + _mutex *mutex = &pwrpriv->wowlan_pattern_cam_mutex; + u32 cnt = 0; + u32 start = 0; + u8 timeout = 0; + u8 rst = _FAIL; + + _enter_critical_mutex(mutex, NULL); + rtw_write32(adapter, REG_WKFMCAM_CMD, BIT_WKFCAM_POLLING_V1 | BIT_WKFCAM_CLR_V1); + + start = rtw_get_current_time(); + while (1) { + if (rtw_is_surprise_removed(adapter)) + break; + + cnt++; + if (0 == (rtw_read32(adapter, REG_WKFMCAM_CMD) & BIT_WKFCAM_POLLING_V1)) { + rst = _SUCCESS; + break; + } + if (rtw_get_passing_time_ms(start) > WOW_CAM_ACCESS_TIMEOUT_MS) { + timeout = 1; + break; + } + } + _exit_critical_mutex(mutex, NULL); + + if (timeout) + RTW_ERR(FUNC_ADPT_FMT" falied ,polling timeout\n", FUNC_ADPT_ARG(adapter)); + + return rst; +} + +void rtw_clean_pattern(_adapter *adapter) +{ + if (_FAIL == _rtw_wow_pattern_clean_cam(adapter)) + RTW_ERR("rtw_clean_pattern failed\n"); +} + +void rtw_dump_wow_pattern(void *sel, struct rtl_wow_pattern *pwow_pattern, u8 idx) +{ + int j; + + RTW_PRINT_SEL(sel, "=======WOW CAM-ID[%d]=======\n", idx); + RTW_PRINT_SEL(sel, "[WOW CAM] type:%d\n", pwow_pattern->type); + RTW_PRINT_SEL(sel, "[WOW CAM] crc:0x%04x\n", pwow_pattern->crc); + for (j = 0; j < 4; j++) + RTW_PRINT_SEL(sel, "[WOW CAM] Mask:0x%08x\n", pwow_pattern->mask[j]); +} + +void rtw_fill_pattern(_adapter *adapter) +{ + int i = 0, total = 0; + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); + struct rtl_wow_pattern wow_pattern; + + total = pwrpriv->wowlan_pattern_idx; + + if (total > MAX_WKFM_CAM_NUM) + total = MAX_WKFM_CAM_NUM; + + for (i = 0 ; i < total ; i++) { + if (_SUCCESS == rtw_hal_wow_pattern_generate(adapter, i, &wow_pattern)) { + rtw_dump_wow_pattern(RTW_DBGDUMP, &wow_pattern, i); + rtw_wow_pattern_write_cam_ent(adapter, i, &wow_pattern); + } + } +} + +#endif +void rtw_wow_pattern_cam_dump(_adapter *adapter) +{ + +#ifndef CONFIG_WOW_PATTERN_HW_CAM + int i; + + for (i = 0 ; i < MAX_WKFM_CAM_NUM; i++) { + RTW_INFO("=======[%d]=======\n", i); + rtw_read_from_frame_mask(adapter, i); + } +#else + struct rtl_wow_pattern context; + int i; + + for (i = 0 ; i < MAX_WKFM_CAM_NUM; i++) { + rtw_wow_pattern_read_cam_ent(adapter, i, &context); + rtw_dump_wow_pattern(RTW_DBGDUMP, &context, i); + } + +#endif +} + + +static void rtw_hal_dl_pattern(_adapter *adapter, u8 mode) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); + + switch (mode) { + case 0: + rtw_clean_pattern(adapter); + RTW_INFO("%s: total patterns: %d\n", __func__, pwrpriv->wowlan_pattern_idx); + break; + case 1: + rtw_set_default_pattern(adapter); + rtw_fill_pattern(adapter); + RTW_INFO("%s: pattern total: %d downloaded\n", __func__, pwrpriv->wowlan_pattern_idx); + break; + case 2: + rtw_clean_pattern(adapter); + rtw_wow_pattern_sw_reset(adapter); + RTW_INFO("%s: clean patterns\n", __func__); + break; + default: + RTW_INFO("%s: unknown mode\n", __func__); + break; + } +} + +static void rtw_hal_wow_enable(_adapter *adapter) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); + struct security_priv *psecuritypriv = &adapter->securitypriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct hal_ops *pHalFunc = &adapter->hal_func; + struct sta_info *psta = NULL; + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(adapter); + int res; + u16 media_status_rpt; + + + RTW_PRINT("%s, WOWLAN_ENABLE\n", __func__); + rtw_hal_gate_bb(adapter, _TRUE); +#ifdef CONFIG_GTK_OL + if (psecuritypriv->binstallKCK_KEK == _TRUE) + rtw_hal_fw_sync_cam_id(adapter); +#endif + if (IS_HARDWARE_TYPE_8723B(adapter)) + rtw_hal_backup_rate(adapter); + + /* RX DMA stop */ + #if defined(CONFIG_RTL8188E) + if (IS_HARDWARE_TYPE_8188E(adapter)) + rtw_hal_disable_tx_report(adapter); + #endif + + res = rtw_hal_pause_rx_dma(adapter); + if (res == _FAIL) + RTW_PRINT("[WARNING] pause RX DMA fail\n"); + + #ifndef CONFIG_WOW_PATTERN_HW_CAM + /* Reconfig RX_FF Boundary */ + rtw_hal_set_wow_rxff_boundary(adapter, _TRUE); + #endif + + /* redownload wow pattern */ + rtw_hal_dl_pattern(adapter, 1); + + rtw_hal_fw_dl(adapter, _TRUE); + media_status_rpt = RT_MEDIA_CONNECT; + rtw_hal_set_hwreg(adapter, HW_VAR_H2C_FW_JOINBSSRPT, + (u8 *)&media_status_rpt); + + if (!pwrctl->wowlan_pno_enable) { + psta = rtw_get_stainfo(&adapter->stapriv, get_bssid(pmlmepriv)); + + if (psta != NULL) { + #ifdef CONFIG_FW_MULTI_PORT_SUPPORT + rtw_hal_set_default_port_id_cmd(adapter, psta->mac_id); + #endif + + rtw_sta_media_status_rpt(adapter, psta, 1); + } + } + +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + /* Enable CPWM2 only. */ + res = rtw_hal_enable_cpwm2(adapter); + if (res == _FAIL) + RTW_PRINT("[WARNING] enable cpwm2 fail\n"); +#endif +#ifdef CONFIG_GPIO_WAKEUP + rtw_hal_switch_gpio_wl_ctrl(adapter, WAKEUP_GPIO_IDX, _TRUE); +#endif + /* Set WOWLAN H2C command. */ + RTW_PRINT("Set WOWLan cmd\n"); + rtw_hal_set_fw_wow_related_cmd(adapter, 1); + + res = rtw_hal_check_wow_ctrl(adapter, _TRUE); + + if (res == _FALSE) + RTW_INFO("[Error]%s: set wowlan CMD fail!!\n", __func__); + + pwrctl->wowlan_wake_reason = + rtw_read8(adapter, REG_WOWLAN_WAKE_REASON); + + RTW_PRINT("wowlan_wake_reason: 0x%02x\n", + pwrctl->wowlan_wake_reason); +#ifdef CONFIG_GTK_OL_DBG + dump_sec_cam(RTW_DBGDUMP, adapter); + dump_sec_cam_cache(RTW_DBGDUMP, adapter); +#endif +#ifdef CONFIG_USB_HCI + /* free adapter's resource */ + rtw_mi_intf_stop(adapter); + + /* Invoid SE0 reset signal during suspending*/ + rtw_write8(adapter, REG_RSV_CTRL, 0x20); + if (IS_8188F(pHalData->version_id) == FALSE) + rtw_write8(adapter, REG_RSV_CTRL, 0x60); +#endif /*CONFIG_USB_HCI*/ + + rtw_hal_gate_bb(adapter, _FALSE); +} + +#define DBG_WAKEUP_REASON +#ifdef DBG_WAKEUP_REASON +void _dbg_wake_up_reason_string(_adapter *adapter, const char *srt_res) +{ + RTW_INFO(ADPT_FMT "- wake up reason - %s\n", ADPT_ARG(adapter), srt_res); +} +void _dbg_rtw_wake_up_reason(_adapter *adapter, u8 reason) +{ + if (RX_PAIRWISEKEY == reason) + _dbg_wake_up_reason_string(adapter, "Rx pairwise key"); + else if (RX_GTK == reason) + _dbg_wake_up_reason_string(adapter, "Rx GTK"); + else if (RX_FOURWAY_HANDSHAKE == reason) + _dbg_wake_up_reason_string(adapter, "Rx four way handshake"); + else if (RX_DISASSOC == reason) + _dbg_wake_up_reason_string(adapter, "Rx disassoc"); + else if (RX_DEAUTH == reason) + _dbg_wake_up_reason_string(adapter, "Rx deauth"); + else if (RX_ARP_REQUEST == reason) + _dbg_wake_up_reason_string(adapter, "Rx ARP request"); + else if (FW_DECISION_DISCONNECT == reason) + _dbg_wake_up_reason_string(adapter, "FW detect disconnect"); + else if (RX_MAGIC_PKT == reason) + _dbg_wake_up_reason_string(adapter, "Rx magic packet"); + else if (RX_UNICAST_PKT == reason) + _dbg_wake_up_reason_string(adapter, "Rx unicast packet"); + else if (RX_PATTERN_PKT == reason) + _dbg_wake_up_reason_string(adapter, "Rx pattern packet"); + else if (RTD3_SSID_MATCH == reason) + _dbg_wake_up_reason_string(adapter, "RTD3 SSID match"); + else if (RX_REALWOW_V2_WAKEUP_PKT == reason) + _dbg_wake_up_reason_string(adapter, "Rx real WOW V2 wakeup packet"); + else if (RX_REALWOW_V2_ACK_LOST == reason) + _dbg_wake_up_reason_string(adapter, "Rx real WOW V2 ack lost"); + else if (ENABLE_FAIL_DMA_IDLE == reason) + _dbg_wake_up_reason_string(adapter, "enable fail DMA idle"); + else if (ENABLE_FAIL_DMA_PAUSE == reason) + _dbg_wake_up_reason_string(adapter, "enable fail DMA pause"); + else if (AP_OFFLOAD_WAKEUP == reason) + _dbg_wake_up_reason_string(adapter, "AP offload wakeup"); + else if (CLK_32K_UNLOCK == reason) + _dbg_wake_up_reason_string(adapter, "clk 32k unlock"); + else if (RTIME_FAIL_DMA_IDLE == reason) + _dbg_wake_up_reason_string(adapter, "RTIME fail DMA idle"); + else if (CLK_32K_LOCK == reason) + _dbg_wake_up_reason_string(adapter, "clk 32k lock"); + else + _dbg_wake_up_reason_string(adapter, "unknown reasoen"); +} +#endif + +static void rtw_hal_wow_disable(_adapter *adapter) +{ + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); + struct security_priv *psecuritypriv = &adapter->securitypriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct hal_ops *pHalFunc = &adapter->hal_func; + struct sta_info *psta = NULL; + int res; + u16 media_status_rpt; + u8 val8; + + RTW_PRINT("%s, WOWLAN_DISABLE\n", __func__); + + if (!pwrctl->wowlan_pno_enable) { + psta = rtw_get_stainfo(&adapter->stapriv, get_bssid(pmlmepriv)); + if (psta != NULL) + rtw_sta_media_status_rpt(adapter, psta, 0); + else + RTW_INFO("%s: psta is null\n", __func__); + } + + if (0) { + RTW_INFO("0x630:0x%02x\n", rtw_read8(adapter, 0x630)); + RTW_INFO("0x631:0x%02x\n", rtw_read8(adapter, 0x631)); + RTW_INFO("0x634:0x%02x\n", rtw_read8(adapter, 0x634)); + RTW_INFO("0x1c7:0x%02x\n", rtw_read8(adapter, 0x1c7)); + } + + pwrctl->wowlan_wake_reason = rtw_read8(adapter, REG_WOWLAN_WAKE_REASON); + + RTW_PRINT("wakeup_reason: 0x%02x\n", + pwrctl->wowlan_wake_reason); + #ifdef DBG_WAKEUP_REASON + _dbg_rtw_wake_up_reason(adapter, pwrctl->wowlan_wake_reason); + #endif + + rtw_hal_set_fw_wow_related_cmd(adapter, 0); + + res = rtw_hal_check_wow_ctrl(adapter, _FALSE); + + if (res == _FALSE) { + RTW_INFO("[Error]%s: disable WOW cmd fail\n!!", __func__); + rtw_hal_force_enable_rxdma(adapter); + } + + rtw_hal_gate_bb(adapter, _TRUE); + + res = rtw_hal_pause_rx_dma(adapter); + if (res == _FAIL) + RTW_PRINT("[WARNING] pause RX DMA fail\n"); + + /* clean HW pattern match */ + rtw_hal_dl_pattern(adapter, 0); + + #ifndef CONFIG_WOW_PATTERN_HW_CAM + /* config RXFF boundary to original */ + rtw_hal_set_wow_rxff_boundary(adapter, _FALSE); + #endif + rtw_hal_release_rx_dma(adapter); + + #if defined(CONFIG_RTL8188E) + if (IS_HARDWARE_TYPE_8188E(adapter)) + rtw_hal_enable_tx_report(adapter); + #endif + +#ifdef CONFIG_GTK_OL + if (((pwrctl->wowlan_wake_reason != RX_DISASSOC) || + (pwrctl->wowlan_wake_reason != RX_DEAUTH) || + (pwrctl->wowlan_wake_reason != FW_DECISION_DISCONNECT)) && + psecuritypriv->binstallKCK_KEK == _TRUE) { + rtw_hal_get_aoac_rpt(adapter); + rtw_hal_update_sw_security_info(adapter); + } +#endif /*CONFIG_GTK_OL*/ + + rtw_hal_fw_dl(adapter, _FALSE); + +#ifdef CONFIG_GPIO_WAKEUP + val8 = (pwrctl->is_high_active == 0) ? 1 : 0; + RTW_PRINT("Set Wake GPIO to default(%d).\n", val8); + rtw_hal_set_output_gpio(adapter, WAKEUP_GPIO_IDX, val8); + + rtw_hal_switch_gpio_wl_ctrl(adapter, WAKEUP_GPIO_IDX, _FALSE); +#endif + + if ((pwrctl->wowlan_wake_reason != FW_DECISION_DISCONNECT) && + (pwrctl->wowlan_wake_reason != RX_PAIRWISEKEY) && + (pwrctl->wowlan_wake_reason != RX_DISASSOC) && + (pwrctl->wowlan_wake_reason != RX_DEAUTH)) { + + media_status_rpt = RT_MEDIA_CONNECT; + rtw_hal_set_hwreg(adapter, HW_VAR_H2C_FW_JOINBSSRPT, + (u8 *)&media_status_rpt); + + if (psta != NULL) { + #ifdef CONFIG_FW_MULTI_PORT_SUPPORT + rtw_hal_set_default_port_id_cmd(adapter, psta->mac_id); + #endif + rtw_sta_media_status_rpt(adapter, psta, 1); + } + } + rtw_hal_gate_bb(adapter, _FALSE); +} +#endif /*CONFIG_WOWLAN*/ + +#ifdef CONFIG_P2P_WOWLAN +void rtw_hal_set_p2p_wow_fw_rsvd_page(_adapter *adapter, u8 *pframe, u16 index, + u8 tx_desc, u32 page_size, u8 *page_num, u32 *total_pkt_len, + RSVDPAGE_LOC *rsvd_page_loc) +{ + u32 P2PNegoRspLength = 0, P2PInviteRspLength = 0; + u32 P2PPDRspLength = 0, P2PProbeRspLength = 0, P2PBCNLength = 0; + u8 CurtPktPageNum = 0; + + /* P2P Beacon */ + rsvd_page_loc->LocP2PBeacon = *page_num; + rtw_hal_construct_P2PBeacon(adapter, &pframe[index], &P2PBCNLength); + rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], + P2PBCNLength, _FALSE, _FALSE, _FALSE); + +#if 0 + RTW_INFO("%s(): HW_VAR_SET_TX_CMD: PROBE RSP %p %d\n", + __FUNCTION__, &pframe[index - tx_desc], (P2PBCNLength + tx_desc)); +#endif + + CurtPktPageNum = (u8)PageNum(tx_desc + P2PBCNLength, page_size); + + *page_num += CurtPktPageNum; + + index += (CurtPktPageNum * page_size); + + /* P2P Probe rsp */ + rsvd_page_loc->LocP2PProbeRsp = *page_num; + rtw_hal_construct_P2PProbeRsp(adapter, &pframe[index], + &P2PProbeRspLength); + rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], + P2PProbeRspLength, _FALSE, _FALSE, _FALSE); + + /* RTW_INFO("%s(): HW_VAR_SET_TX_CMD: PROBE RSP %p %d\n", */ + /* __FUNCTION__, &pframe[index-tx_desc], (P2PProbeRspLength+tx_desc)); */ + + CurtPktPageNum = (u8)PageNum(tx_desc + P2PProbeRspLength, page_size); + + *page_num += CurtPktPageNum; + + index += (CurtPktPageNum * page_size); + + /* P2P nego rsp */ + rsvd_page_loc->LocNegoRsp = *page_num; + rtw_hal_construct_P2PNegoRsp(adapter, &pframe[index], + &P2PNegoRspLength); + rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], + P2PNegoRspLength, _FALSE, _FALSE, _FALSE); + + /* RTW_INFO("%s(): HW_VAR_SET_TX_CMD: QOS NULL DATA %p %d\n", */ + /* __FUNCTION__, &pframe[index-tx_desc], (NegoRspLength+tx_desc)); */ + + CurtPktPageNum = (u8)PageNum(tx_desc + P2PNegoRspLength, page_size); + + *page_num += CurtPktPageNum; + + index += (CurtPktPageNum * page_size); + + /* P2P invite rsp */ + rsvd_page_loc->LocInviteRsp = *page_num; + rtw_hal_construct_P2PInviteRsp(adapter, &pframe[index], + &P2PInviteRspLength); + rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], + P2PInviteRspLength, _FALSE, _FALSE, _FALSE); + + /* RTW_INFO("%s(): HW_VAR_SET_TX_CMD: QOS NULL DATA %p %d\n", */ + /* __FUNCTION__, &pframe[index-tx_desc], (InviteRspLength+tx_desc)); */ + + CurtPktPageNum = (u8)PageNum(tx_desc + P2PInviteRspLength, page_size); + + *page_num += CurtPktPageNum; + + index += (CurtPktPageNum * page_size); + + /* P2P provision discovery rsp */ + rsvd_page_loc->LocPDRsp = *page_num; + rtw_hal_construct_P2PProvisionDisRsp(adapter, + &pframe[index], &P2PPDRspLength); + + rtw_hal_fill_fake_txdesc(adapter, &pframe[index - tx_desc], + P2PPDRspLength, _FALSE, _FALSE, _FALSE); + + /* RTW_INFO("%s(): HW_VAR_SET_TX_CMD: QOS NULL DATA %p %d\n", */ + /* __FUNCTION__, &pframe[index-tx_desc], (PDRspLength+tx_desc)); */ + + CurtPktPageNum = (u8)PageNum(tx_desc + P2PPDRspLength, page_size); + + *page_num += CurtPktPageNum; + + *total_pkt_len = index + P2PPDRspLength; + + index += (CurtPktPageNum * page_size); + + +} +#endif /* CONFIG_P2P_WOWLAN */ + +#ifdef CONFIG_LPS_PG +#include "hal_halmac.h" + +#define DBG_LPSPG_SEC_DUMP +#define LPS_PG_INFO_RSVD_LEN 16 +#define LPS_PG_INFO_RSVD_PAGE_NUM 1 + +#define DBG_LPSPG_INFO_DUMP +static void rtw_hal_set_lps_pg_info_rsvd_page(_adapter *adapter) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); + struct sta_info *psta = rtw_get_stainfo(&adapter->stapriv, get_bssid(&adapter->mlmepriv)); + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + PHAL_DATA_TYPE phal_data = GET_HAL_DATA(adapter); + u8 lps_pg_info[LPS_PG_INFO_RSVD_LEN] = {0}; +#ifdef CONFIG_MBSSID_CAM + u8 cam_id = INVALID_CAM_ID; +#endif + u8 *psec_cam_id = lps_pg_info + 8; + u8 sec_cam_num = 0; + + if (!psta) { + RTW_ERR("%s [ERROR] sta is NULL\n", __func__); + rtw_warn_on(1); + return; + } + + /*Byte 0 - used macid*/ + LPSPG_RSVD_PAGE_SET_MACID(lps_pg_info, psta->mac_id); + RTW_INFO("[LPSPG-INFO] mac_id:%d\n", psta->mac_id); + +#ifdef CONFIG_MBSSID_CAM + /*Byte 1 - used BSSID CAM entry*/ + cam_id = rtw_mbid_cam_search_by_ifaceid(adapter, adapter->iface_id); + if (cam_id != INVALID_CAM_ID) + LPSPG_RSVD_PAGE_SET_MBSSCAMID(lps_pg_info, cam_id); + RTW_INFO("[LPSPG-INFO] mbss_cam_id:%d\n", cam_id); +#endif + +#ifdef CONFIG_WOWLAN /*&& pattern match cam used*/ + /*Btye 2 - Max used Pattern Match CAM entry*/ + if (pwrpriv->wowlan_mode == _TRUE && + check_fwstate(&adapter->mlmepriv, _FW_LINKED) == _TRUE) { + LPSPG_RSVD_PAGE_SET_PMC_NUM(lps_pg_info, pwrpriv->wowlan_pattern_idx); + RTW_INFO("[LPSPG-INFO] Max Pattern Match CAM entry :%d\n", pwrpriv->wowlan_pattern_idx); + } +#endif +#ifdef CONFIG_BEAMFORMING /*&& MU BF*/ + /*Btye 3 - Max MU rate table Group ID*/ + LPSPG_RSVD_PAGE_SET_MU_RAID_GID(lps_pg_info, _value); + RTW_INFO("[LPSPG-INFO] Max MU rate table Group ID :%d\n", _value); +#endif + + /*Btye 8 ~15 - used Security CAM entry */ + sec_cam_num = rtw_get_sec_camid(adapter, 8, psec_cam_id); + + /*Btye 4 - used Security CAM entry number*/ + if (sec_cam_num < 8) + LPSPG_RSVD_PAGE_SET_SEC_CAM_NUM(lps_pg_info, sec_cam_num); + RTW_INFO("[LPSPG-INFO] Security CAM entry number :%d\n", sec_cam_num); + + /*Btye 5 - Txbuf used page number for fw offload*/ + LPSPG_RSVD_PAGE_SET_DRV_RSVDPAGE_NUM(lps_pg_info, phal_data->drv_rsvd_page_number); + RTW_INFO("[LPSPG-INFO] DRV's rsvd page numbers :%d\n", phal_data->drv_rsvd_page_number); + +#ifdef DBG_LPSPG_SEC_DUMP + { + int i; + + for (i = 0; i < sec_cam_num; i++) + RTW_INFO("%d = sec_cam_id:%d\n", i, psec_cam_id[i]); + } +#endif + +#ifdef DBG_LPSPG_INFO_DUMP + RTW_INFO("==== DBG_LPSPG_INFO_RSVD_PAGE_DUMP====\n"); + RTW_INFO(" %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + *(lps_pg_info), *(lps_pg_info + 1), *(lps_pg_info + 2), *(lps_pg_info + 3), + *(lps_pg_info + 4), *(lps_pg_info + 5), *(lps_pg_info + 6), *(lps_pg_info + 7)); + RTW_INFO(" %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", + *(lps_pg_info + 8), *(lps_pg_info + 9), *(lps_pg_info + 10), *(lps_pg_info + 11), + *(lps_pg_info + 12), *(lps_pg_info + 13), *(lps_pg_info + 14), *(lps_pg_info + 15)); + RTW_INFO("==== DBG_LPSPG_INFO_RSVD_PAGE_DUMP====\n"); +#endif + + rtw_halmac_download_rsvd_page(dvobj, pwrpriv->lpspg_rsvd_page_locate, lps_pg_info, LPS_PG_INFO_RSVD_LEN); + +#ifdef DBG_LPSPG_INFO_DUMP + RTW_INFO("Get LPS-PG INFO from rsvd page_offset:%d\n", pwrpriv->lpspg_rsvd_page_locate); + rtw_dump_rsvd_page(RTW_DBGDUMP, adapter, pwrpriv->lpspg_rsvd_page_locate, 1); +#endif +} + + +static u8 rtw_hal_set_lps_pg_info_cmd(_adapter *adapter) +{ + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + u8 lpspg_info[H2C_LPS_PG_INFO_LEN] = {0}; + u8 ret = _FAIL; + + RTW_INFO("%s: loc_lpspg_info:%d\n", __func__, pwrpriv->lpspg_rsvd_page_locate); + + if (_NO_PRIVACY_ != adapter->securitypriv.dot11PrivacyAlgrthm) + SET_H2CCMD_LPSPG_SEC_CAM_EN(lpspg_info, 1); /*SecurityCAM_En*/ +#ifdef CONFIG_MBSSID_CAM + SET_H2CCMD_LPSPG_MBID_CAM_EN(lpspg_info, 1); /*BSSIDCAM_En*/ +#endif + +#if defined(CONFIG_WOWLAN) && defined(CONFIG_WOW_PATTERN_HW_CAM) + if (pwrpriv->wowlan_mode == _TRUE && + check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + + SET_H2CCMD_LPSPG_PMC_CAM_EN(lpspg_info, 1); /*PatternMatchCAM_En*/ + } +#endif + +#ifdef CONFIG_MACID_SEARCH + SET_H2CCMD_LPSPG_MACID_SEARCH_EN(lpspg_info, 1); /*MACIDSearch_En*/ +#endif + +#ifdef CONFIG_TX_SC + SET_H2CCMD_LPSPG_TXSC_EN(lpspg_info, 1); /*TXSC_En*/ +#endif + +#ifdef CONFIG_BEAMFORMING /*&& MU BF*/ + SET_H2CCMD_LPSPG_MU_RATE_TB_EN(lpspg_info, 1); /*MURateTable_En*/ +#endif + + SET_H2CCMD_LPSPG_LOC(lpspg_info, pwrpriv->lpspg_rsvd_page_locate); + +#ifdef DBG_LPSPG_INFO_DUMP + RTW_INFO("==== DBG_LPSPG_INFO_CMD_DUMP====\n"); + RTW_INFO(" H2C_CMD: 0x%02x, H2C_LEN: %d\n", H2C_LPS_PG_INFO, H2C_LPS_PG_INFO_LEN); + RTW_INFO(" %02X:%02X\n", *(lpspg_info), *(lpspg_info + 1)); + RTW_INFO("==== DBG_LPSPG_INFO_CMD_DUMP====\n"); +#endif + + ret = rtw_hal_fill_h2c_cmd(adapter, + H2C_LPS_PG_INFO, + H2C_LPS_PG_INFO_LEN, + lpspg_info); + return ret; +} +u8 rtw_hal_set_lps_pg_info(_adapter *adapter) +{ + u8 ret = _FAIL; + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); + + if (pwrpriv->lpspg_rsvd_page_locate == 0) { + RTW_ERR("%s [ERROR] lpspg_rsvd_page_locate = 0\n", __func__); + rtw_warn_on(1); + return ret; + } + + rtw_hal_set_lps_pg_info_rsvd_page(adapter); + ret = rtw_hal_set_lps_pg_info_cmd(adapter); + if (_SUCCESS == ret) + pwrpriv->blpspg_info_up = _FALSE; + + return ret; +} + +void rtw_hal_lps_pg_handler(_adapter *adapter, enum lps_pg_hdl_id hdl_id) +{ + switch (hdl_id) { + case LPS_PG_INFO_CFG: + rtw_hal_set_lps_pg_info(adapter); + break; + case LPS_PG_REDLEMEM: + /*rtw_halmac_redl_fw();*/ + break; + + case LPS_PG_RESEND_H2C: + { + struct macid_ctl_t *macid_ctl = &adapter->dvobj->macid_ctl; + struct sta_info *sta; + PHAL_DATA_TYPE hal_data = GET_HAL_DATA(adapter); + int i; + + for (i = 0; i < MACID_NUM_SW_LIMIT; i++) { + sta = macid_ctl->sta[i]; + if (sta && !is_broadcast_mac_addr(sta->hwaddr)) { + /*rtw_dm_ra_mask_hdl(adapter, sta);*/ + /*phydm_rssi_report(hal_data->odmpriv, sta->mac_id);*/ + } + } + } + break; + + default: + break; + } +} + +#endif /*CONFIG_LPS_PG*/ + +/* + * Description: Fill the reserved packets that FW will use to RSVD page. + * Now we just send 4 types packet to rsvd page. + * (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. + * Input: + * finished - FALSE:At the first time we will send all the packets as a large packet to Hw, + * so we need to set the packet length to total lengh. + * TRUE: At the second time, we should send the first packet (default:beacon) + * to Hw again and set the lengh in descriptor to the real beacon lengh. + * 2009.10.15 by tynli. + * + * Page Size = 128: 8188e, 8723a/b, 8192c/d, + * Page Size = 256: 8192e, 8821a + * Page Size = 512: 8812a + */ + +/*#define DBG_DUMP_SET_RSVD_PAGE*/ +void rtw_hal_set_fw_rsvd_page(_adapter *adapter, bool finished) +{ + PHAL_DATA_TYPE pHalData; + struct xmit_frame *pcmdframe; + struct pkt_attrib *pattrib; + struct xmit_priv *pxmitpriv; + struct mlme_ext_priv *pmlmeext; + struct mlme_ext_info *pmlmeinfo; + struct pwrctrl_priv *pwrctl; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct hal_ops *pHalFunc = &adapter->hal_func; + u32 BeaconLength = 0, ProbeRspLength = 0, PSPollLength = 0; + u32 NullDataLength = 0, QosNullLength = 0, BTQosNullLength = 0; + u32 ProbeReqLength = 0, NullFunctionDataLength = 0; + u8 TxDescLen = TXDESC_SIZE, TxDescOffset = TXDESC_OFFSET; + u8 TotalPageNum = 0 , CurtPktPageNum = 0 , RsvdPageNum = 0; + u8 *ReservedPagePacket; + u16 BufIndex = 0; + u32 TotalPacketLen = 0, MaxRsvdPageBufSize = 0, PageSize = 0; + RSVDPAGE_LOC RsvdPageLoc; + +#ifdef DBG_CONFIG_ERROR_DETECT + struct sreset_priv *psrtpriv; +#endif /* DBG_CONFIG_ERROR_DETECT */ + +#ifdef CONFIG_MCC_MODE + u8 dl_mcc_page = _FAIL; +#endif /* CONFIG_MCC_MODE */ + + pHalData = GET_HAL_DATA(adapter); +#ifdef DBG_CONFIG_ERROR_DETECT + psrtpriv = &pHalData->srestpriv; +#endif + pxmitpriv = &adapter->xmitpriv; + pmlmeext = &adapter->mlmeextpriv; + pmlmeinfo = &pmlmeext->mlmext_info; + pwrctl = adapter_to_pwrctl(adapter); + + rtw_hal_get_def_var(adapter, HAL_DEF_TX_PAGE_SIZE, (u8 *)&PageSize); + + if (PageSize == 0) { + RTW_INFO("[Error]: %s, PageSize is zero!!\n", __func__); + return; + } + + if (pwrctl->wowlan_mode == _TRUE || pwrctl->wowlan_ap_mode == _TRUE) + RsvdPageNum = rtw_hal_get_txbuff_rsvd_page_num(adapter, _TRUE); + else + RsvdPageNum = rtw_hal_get_txbuff_rsvd_page_num(adapter, _FALSE); + + RTW_INFO("%s PageSize: %d, RsvdPageNUm: %d\n", __func__, PageSize, RsvdPageNum); + + MaxRsvdPageBufSize = RsvdPageNum * PageSize; + + if (MaxRsvdPageBufSize > MAX_CMDBUF_SZ) { + RTW_INFO("%s MaxRsvdPageBufSize(%d) is larger than MAX_CMDBUF_SZ(%d)", + __func__, MaxRsvdPageBufSize, MAX_CMDBUF_SZ); + rtw_warn_on(1); + return; + } + + pcmdframe = rtw_alloc_cmdxmitframe(pxmitpriv); + + if (pcmdframe == NULL) { + RTW_INFO("%s: alloc ReservedPagePacket fail!\n", __FUNCTION__); + return; + } + + ReservedPagePacket = pcmdframe->buf_addr; + _rtw_memset(&RsvdPageLoc, 0, sizeof(RSVDPAGE_LOC)); + + /* beacon * 2 pages */ + BufIndex = TxDescOffset; + rtw_hal_construct_beacon(adapter, + &ReservedPagePacket[BufIndex], &BeaconLength); + + /* + * When we count the first page size, we need to reserve description size for the RSVD + * packet, it will be filled in front of the packet in TXPKTBUF. + */ + CurtPktPageNum = (u8)PageNum((TxDescLen + BeaconLength), PageSize); + /* If we don't add 1 more page, ARP offload function will fail at 8723bs.*/ + if (CurtPktPageNum == 1) + CurtPktPageNum += 1; + + TotalPageNum += CurtPktPageNum; + + BufIndex += (CurtPktPageNum * PageSize); + + if (pwrctl->wowlan_ap_mode == _TRUE) { + /* (4) probe response*/ + RsvdPageLoc.LocProbeRsp = TotalPageNum; + rtw_hal_construct_ProbeRsp( + adapter, &ReservedPagePacket[BufIndex], + &ProbeRspLength, + get_my_bssid(&pmlmeinfo->network), _FALSE); + rtw_hal_fill_fake_txdesc(adapter, + &ReservedPagePacket[BufIndex - TxDescLen], + ProbeRspLength, _FALSE, _FALSE, _FALSE); + + CurtPktPageNum = (u8)PageNum(TxDescLen + ProbeRspLength, PageSize); + TotalPageNum += CurtPktPageNum; + TotalPacketLen = BufIndex + ProbeRspLength; + BufIndex += (CurtPktPageNum * PageSize); + goto download_page; + } + + /* ps-poll * 1 page */ + RsvdPageLoc.LocPsPoll = TotalPageNum; + RTW_INFO("LocPsPoll: %d\n", RsvdPageLoc.LocPsPoll); + rtw_hal_construct_PSPoll(adapter, + &ReservedPagePacket[BufIndex], &PSPollLength); + rtw_hal_fill_fake_txdesc(adapter, + &ReservedPagePacket[BufIndex - TxDescLen], + PSPollLength, _TRUE, _FALSE, _FALSE); + + CurtPktPageNum = (u8)PageNum((TxDescLen + PSPollLength), PageSize); + + TotalPageNum += CurtPktPageNum; + + BufIndex += (CurtPktPageNum * PageSize); + +#ifdef CONFIG_BT_COEXIST + /* BT Qos null data * 1 page */ + RsvdPageLoc.LocBTQosNull = TotalPageNum; + RTW_INFO("LocBTQosNull: %d\n", RsvdPageLoc.LocBTQosNull); + rtw_hal_construct_NullFunctionData( + adapter, + &ReservedPagePacket[BufIndex], + &BTQosNullLength, + get_my_bssid(&pmlmeinfo->network), + _TRUE, 0, 0, _FALSE); + rtw_hal_fill_fake_txdesc(adapter, + &ReservedPagePacket[BufIndex - TxDescLen], + BTQosNullLength, _FALSE, _TRUE, _FALSE); + + CurtPktPageNum = (u8)PageNum(TxDescLen + BTQosNullLength, PageSize); + + TotalPageNum += CurtPktPageNum; + + BufIndex += (CurtPktPageNum * PageSize); +#endif /* CONFIG_BT_COEXIT */ + +#ifdef CONFIG_MCC_MODE + if (MCC_EN(adapter)) { + dl_mcc_page = rtw_hal_dl_mcc_fw_rsvd_page(adapter, ReservedPagePacket, + &BufIndex, TxDescLen, PageSize, + &TotalPageNum, &TotalPacketLen, &RsvdPageLoc); + } else + dl_mcc_page = _FAIL; + + if (dl_mcc_page == _FAIL) { +#endif /* CONFIG_MCC_MODE */ + + /* null data * 1 page */ + RsvdPageLoc.LocNullData = TotalPageNum; + RTW_INFO("LocNullData: %d\n", RsvdPageLoc.LocNullData); + rtw_hal_construct_NullFunctionData( + adapter, + &ReservedPagePacket[BufIndex], + &NullDataLength, + get_my_bssid(&pmlmeinfo->network), + _FALSE, 0, 0, _FALSE); + rtw_hal_fill_fake_txdesc(adapter, + &ReservedPagePacket[BufIndex - TxDescLen], + NullDataLength, _FALSE, _FALSE, _FALSE); + + CurtPktPageNum = (u8)PageNum(TxDescLen + NullDataLength, PageSize); + + TotalPageNum += CurtPktPageNum; + + BufIndex += (CurtPktPageNum * PageSize); +#ifdef CONFIG_MCC_MODE + } +#endif /* CONFIG_MCC_MODE */ + + /* Qos null data * 1 page */ + RsvdPageLoc.LocQosNull = TotalPageNum; + RTW_INFO("LocQosNull: %d\n", RsvdPageLoc.LocQosNull); + rtw_hal_construct_NullFunctionData( + adapter, + &ReservedPagePacket[BufIndex], + &QosNullLength, + get_my_bssid(&pmlmeinfo->network), + _TRUE, 0, 0, _FALSE); + rtw_hal_fill_fake_txdesc(adapter, + &ReservedPagePacket[BufIndex - TxDescLen], + QosNullLength, _FALSE, _FALSE, _FALSE); + + CurtPktPageNum = (u8)PageNum(TxDescLen + QosNullLength, PageSize); + + TotalPageNum += CurtPktPageNum; + + TotalPacketLen = BufIndex + QosNullLength; + + BufIndex += (CurtPktPageNum * PageSize); + +#ifdef CONFIG_WOWLAN + if (pwrctl->wowlan_mode == _TRUE && + pwrctl->wowlan_in_resume == _FALSE) { + rtw_hal_set_wow_fw_rsvd_page(adapter, ReservedPagePacket, + BufIndex, TxDescLen, PageSize, + &TotalPageNum, &TotalPacketLen, &RsvdPageLoc); + } +#endif /* CONFIG_WOWLAN */ + +#ifdef CONFIG_P2P_WOWLAN + if (_TRUE == pwrctl->wowlan_p2p_mode) { + rtw_hal_set_p2p_wow_fw_rsvd_page(adapter, ReservedPagePacket, + BufIndex, TxDescLen, PageSize, + &TotalPageNum, &TotalPacketLen, &RsvdPageLoc); + } +#endif /* CONFIG_P2P_WOWLAN */ + +#ifdef CONFIG_LPS_PG + /* must reserved last 1 x page for LPS PG Info*/ + pwrctl->lpspg_rsvd_page_locate = TotalPageNum; + pwrctl->blpspg_info_up = _TRUE; +#endif + +download_page: + /* RTW_INFO("%s BufIndex(%d), TxDescLen(%d), PageSize(%d)\n",__func__, BufIndex, TxDescLen, PageSize);*/ + RTW_INFO("%s PageNum(%d), pktlen(%d)\n", + __func__, TotalPageNum, TotalPacketLen); + +#ifdef CONFIG_LPS_PG + if ((TotalPacketLen + (LPS_PG_INFO_RSVD_PAGE_NUM * PageSize)) > MaxRsvdPageBufSize) { + pwrctl->lpspg_rsvd_page_locate = 0; + pwrctl->blpspg_info_up = _FALSE; + + RTW_ERR("%s rsvd page size is not enough!!TotalPacketLen+LPS_PG_INFO_LEN %d, MaxRsvdPageBufSize %d\n", + __func__, (TotalPacketLen + (LPS_PG_INFO_RSVD_PAGE_NUM * PageSize)), MaxRsvdPageBufSize); + rtw_warn_on(1); + } +#endif + + if (TotalPacketLen > MaxRsvdPageBufSize) { + RTW_ERR("%s(ERROR): rsvd page size is not enough!!TotalPacketLen %d, MaxRsvdPageBufSize %d\n", + __FUNCTION__, TotalPacketLen, MaxRsvdPageBufSize); + rtw_warn_on(1); + goto error; + } else { + /* update attribute */ + pattrib = &pcmdframe->attrib; + update_mgntframe_attrib(adapter, pattrib); + pattrib->qsel = QSLT_BEACON; + pattrib->pktlen = TotalPacketLen - TxDescOffset; + pattrib->last_txcmdsz = TotalPacketLen - TxDescOffset; +#ifdef CONFIG_PCI_HCI + dump_mgntframe(adapter, pcmdframe); +#else + dump_mgntframe_and_wait(adapter, pcmdframe, 100); +#endif + } + + RTW_INFO("%s: Set RSVD page location to Fw ,TotalPacketLen(%d), TotalPageNum(%d)\n", + __func__, TotalPacketLen, TotalPageNum); +#ifdef DBG_DUMP_SET_RSVD_PAGE + RTW_INFO(" ==================================================\n"); + RTW_INFO_DUMP("\n", ReservedPagePacket, TotalPacketLen); + RTW_INFO(" ==================================================\n"); +#endif + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + rtw_hal_set_FwRsvdPage_cmd(adapter, &RsvdPageLoc); +#ifdef CONFIG_WOWLAN + if (pwrctl->wowlan_mode == _TRUE && + pwrctl->wowlan_in_resume == _FALSE) + rtw_hal_set_FwAoacRsvdPage_cmd(adapter, &RsvdPageLoc); +#endif /* CONFIG_WOWLAN */ +#ifdef CONFIG_AP_WOWLAN + if (pwrctl->wowlan_ap_mode == _TRUE) + rtw_hal_set_ap_rsvdpage_loc_cmd(adapter, &RsvdPageLoc); +#endif /* CONFIG_AP_WOWLAN */ + } else if (pwrctl->wowlan_pno_enable) { +#ifdef CONFIG_PNO_SUPPORT + rtw_hal_set_FwAoacRsvdPage_cmd(adapter, &RsvdPageLoc); + if (pwrctl->wowlan_in_resume) + rtw_hal_set_scan_offload_info_cmd(adapter, + &RsvdPageLoc, 0); + else + rtw_hal_set_scan_offload_info_cmd(adapter, + &RsvdPageLoc, 1); +#endif /* CONFIG_PNO_SUPPORT */ + } +#ifdef CONFIG_P2P_WOWLAN + if (_TRUE == pwrctl->wowlan_p2p_mode) + rtw_hal_set_FwP2PRsvdPage_cmd(adapter, &RsvdPageLoc); +#endif /* CONFIG_P2P_WOWLAN */ + return; +error: + rtw_free_xmitframe(pxmitpriv, pcmdframe); +} +static void rtw_hal_set_hw_update_tsf(PADAPTER padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + +#if defined(CONFIG_RTL8822B) || defined(CONFIG_MI_WITH_MBSSID_CAM) + RTW_INFO("[Warn] %s "ADPT_FMT" enter func\n", __func__, ADPT_ARG(padapter)); + rtw_warn_on(1); + return; +#endif + + if (!pmlmeext->en_hw_update_tsf) + return; + + /* check REG_RCR bit is set */ + if (!(rtw_read32(padapter, REG_RCR) & RCR_CBSSID_BCN)) + return; + + /* enable hw update tsf function for non-AP */ + if (rtw_linked_check(padapter) && + check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE) { +#ifdef CONFIG_CONCURRENT_MODE + if (padapter->hw_port == HW_PORT1) + rtw_write8(padapter, REG_BCN_CTRL_1, rtw_read8(padapter, REG_BCN_CTRL_1) & (~DIS_TSF_UDT)); + else +#endif + rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL) & (~DIS_TSF_UDT)); + } + pmlmeext->en_hw_update_tsf = _FALSE; +} + +#ifdef CONFIG_TDLS +#ifdef CONFIG_TDLS_CH_SW +s32 rtw_hal_ch_sw_oper_offload(_adapter *padapter, u8 channel, u8 channel_offset, u16 bwmode) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + u8 ch_sw_h2c_buf[4] = {0x00, 0x00, 0x00, 0x00}; + + + SET_H2CCMD_CH_SW_OPER_OFFLOAD_CH_NUM(ch_sw_h2c_buf, channel); + SET_H2CCMD_CH_SW_OPER_OFFLOAD_BW_MODE(ch_sw_h2c_buf, bwmode); + switch (bwmode) { + case CHANNEL_WIDTH_40: + SET_H2CCMD_CH_SW_OPER_OFFLOAD_BW_40M_SC(ch_sw_h2c_buf, channel_offset); + break; + case CHANNEL_WIDTH_80: + SET_H2CCMD_CH_SW_OPER_OFFLOAD_BW_80M_SC(ch_sw_h2c_buf, channel_offset); + break; + case CHANNEL_WIDTH_20: + default: + break; + } + SET_H2CCMD_CH_SW_OPER_OFFLOAD_RFE_TYPE(ch_sw_h2c_buf, pHalData->rfe_type); + + return rtw_hal_fill_h2c_cmd(padapter, H2C_CHNL_SWITCH_OPER_OFFLOAD, sizeof(ch_sw_h2c_buf), ch_sw_h2c_buf); +} +#endif +#endif + +#ifdef CONFIG_WMMPS +void rtw_hal_update_uapsd_tid(_adapter *adapter) +{ + rtw_write8(adapter, REG_WMMPS_UAPSD_TID, 0xFF); +} +#endif + +#if defined(CONFIG_BT_COEXIST) && defined(CONFIG_FW_MULTI_PORT_SUPPORT) +/* For multi-port support, driver needs to inform the port ID to FW for btc operations */ +s32 rtw_hal_set_wifi_port_id_cmd(_adapter *adapter) +{ + u8 port_id = 0; + u8 h2c_buf[H2C_BTC_WL_PORT_ID_LEN] = {0}; + + SET_H2CCMD_BTC_WL_PORT_ID(h2c_buf, adapter->hw_port); + return rtw_hal_fill_h2c_cmd(adapter, H2C_BTC_WL_PORT_ID, H2C_BTC_WL_PORT_ID_LEN, h2c_buf); +} +#endif + +void SetHwReg(_adapter *adapter, u8 variable, u8 *val) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + + switch (variable) { + case HW_VAR_MEDIA_STATUS: { + u8 net_type = *((u8 *)val); + + rtw_hal_set_msr(adapter, net_type); + } + break; + case HW_VAR_MAC_ADDR: +#ifdef CONFIG_MI_WITH_MBSSID_CAM + rtw_hal_set_macaddr_mbid(adapter, val); +#else + rtw_hal_set_macaddr_port(adapter, val); +#endif + break; + case HW_VAR_BSSID: + rtw_hal_set_bssid(adapter, val); + break; +#ifdef CONFIG_MBSSID_CAM + case HW_VAR_MBSSID_CAM_WRITE: { + u32 cmd = 0; + u32 *cam_val = (u32 *)val; + + rtw_write32(adapter, REG_MBIDCAMCFG_1, cam_val[0]); + cmd = BIT_MBIDCAM_POLL | BIT_MBIDCAM_WT_EN | BIT_MBIDCAM_VALID | cam_val[1]; + rtw_write32(adapter, REG_MBIDCAMCFG_2, cmd); + } + break; + case HW_VAR_MBSSID_CAM_CLEAR: { + u32 cmd; + u8 entry_id = *(u8 *)val; + + rtw_write32(adapter, REG_MBIDCAMCFG_1, 0); + + cmd = BIT_MBIDCAM_POLL | BIT_MBIDCAM_WT_EN | ((entry_id & MBIDCAM_ADDR_MASK) << MBIDCAM_ADDR_SHIFT); + rtw_write32(adapter, REG_MBIDCAMCFG_2, cmd); + } + break; + case HW_VAR_RCR_MBSSID_EN: + if (*((u8 *)val)) + rtw_write32(adapter, REG_RCR, rtw_read32(adapter, REG_RCR) | RCR_ENMBID); + else { + u32 val32; + + val32 = rtw_read32(adapter, REG_RCR); + val32 &= ~(RCR_ENMBID); + rtw_write32(adapter, REG_RCR, val32); + } + break; +#endif + case HW_VAR_PORT_SWITCH: + hw_var_port_switch(adapter); + break; + case HW_VAR_INIT_RTS_RATE: { + u16 brate_cfg = *((u16 *)val); + u8 rate_index = 0; + HAL_VERSION *hal_ver = &hal_data->version_id; + + if (IS_8188E(*hal_ver)) { + + while (brate_cfg > 0x1) { + brate_cfg = (brate_cfg >> 1); + rate_index++; + } + rtw_write8(adapter, REG_INIRTS_RATE_SEL, rate_index); + } else + rtw_warn_on(1); + } + break; + case HW_VAR_SEC_CFG: { + u16 reg_scr_ori; + u16 reg_scr; + + reg_scr = reg_scr_ori = rtw_read16(adapter, REG_SECCFG); + reg_scr |= (SCR_CHK_KEYID | SCR_RxDecEnable | SCR_TxEncEnable); + + if (_rtw_camctl_chk_cap(adapter, SEC_CAP_CHK_BMC)) + reg_scr |= SCR_CHK_BMC; + + if (_rtw_camctl_chk_flags(adapter, SEC_STATUS_STA_PK_GK_CONFLICT_DIS_BMC_SEARCH)) + reg_scr |= SCR_NoSKMC; + + if (reg_scr != reg_scr_ori) + rtw_write16(adapter, REG_SECCFG, reg_scr); + } + break; + case HW_VAR_SEC_DK_CFG: { + struct security_priv *sec = &adapter->securitypriv; + u8 reg_scr = rtw_read8(adapter, REG_SECCFG); + + if (val) { /* Enable default key related setting */ + reg_scr |= SCR_TXBCUSEDK; + if (sec->dot11AuthAlgrthm != dot11AuthAlgrthm_8021X) + reg_scr |= (SCR_RxUseDK | SCR_TxUseDK); + } else /* Disable default key related setting */ + reg_scr &= ~(SCR_RXBCUSEDK | SCR_TXBCUSEDK | SCR_RxUseDK | SCR_TxUseDK); + + rtw_write8(adapter, REG_SECCFG, reg_scr); + } + break; + + case HW_VAR_ASIX_IOT: + /* enable ASIX IOT function */ + if (*((u8 *)val) == _TRUE) { + /* 0xa2e[0]=0 (disable rake receiver) */ + rtw_write8(adapter, rCCK0_FalseAlarmReport + 2, + rtw_read8(adapter, rCCK0_FalseAlarmReport + 2) & ~(BIT0)); + /* 0xa1c=0xa0 (reset channel estimation if signal quality is bad) */ + rtw_write8(adapter, rCCK0_DSPParameter2, 0xa0); + } else { + /* restore reg:0xa2e, reg:0xa1c */ + rtw_write8(adapter, rCCK0_FalseAlarmReport + 2, + rtw_read8(adapter, rCCK0_FalseAlarmReport + 2) | (BIT0)); + rtw_write8(adapter, rCCK0_DSPParameter2, 0x00); + } + break; +#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) + case HW_VAR_WOWLAN: { + struct wowlan_ioctl_param *poidparam; + + poidparam = (struct wowlan_ioctl_param *)val; + switch (poidparam->subcode) { +#ifdef CONFIG_WOWLAN + case WOWLAN_PATTERN_CLEAN: + rtw_hal_dl_pattern(adapter, 2); + break; + case WOWLAN_ENABLE: + rtw_hal_wow_enable(adapter); + break; + case WOWLAN_DISABLE: + rtw_hal_wow_disable(adapter); + break; +#endif /*CONFIG_WOWLAN*/ +#ifdef CONFIG_AP_WOWLAN + case WOWLAN_AP_ENABLE: + rtw_hal_ap_wow_enable(adapter); + break; + case WOWLAN_AP_DISABLE: + rtw_hal_ap_wow_disable(adapter); + break; +#endif /*CONFIG_AP_WOWLAN*/ + default: + break; + } + } + break; +#endif /*defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN)*/ + + case HW_VAR_EN_HW_UPDATE_TSF: + rtw_hal_set_hw_update_tsf(adapter); + break; + + case HW_VAR_APFM_ON_MAC: + hal_data->bMacPwrCtrlOn = *val; + RTW_INFO("%s: bMacPwrCtrlOn=%d\n", __func__, hal_data->bMacPwrCtrlOn); + break; +#ifdef CONFIG_WMMPS + case HW_VAR_UAPSD_TID: + rtw_hal_update_uapsd_tid(adapter); + break; +#endif +#ifdef CONFIG_LPS_PG + case HW_VAR_LPS_PG_HANDLE: + rtw_hal_lps_pg_handler(adapter, *val); + break; +#endif + + default: + if (0) + RTW_PRINT(FUNC_ADPT_FMT" variable(%d) not defined!\n", + FUNC_ADPT_ARG(adapter), variable); + break; + } + +} + +void GetHwReg(_adapter *adapter, u8 variable, u8 *val) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + + + switch (variable) { + case HW_VAR_BASIC_RATE: + *((u16 *)val) = hal_data->BasicRateSet; + break; + case HW_VAR_RF_TYPE: + *((u8 *)val) = hal_data->rf_type; + break; + case HW_VAR_MEDIA_STATUS: + rtw_hal_get_msr(adapter, val); + break; + case HW_VAR_DO_IQK: + *val = hal_data->bNeedIQK; + break; + case HW_VAR_CH_SW_NEED_TO_TAKE_CARE_IQK_INFO: + if (hal_is_band_support(adapter, BAND_ON_5G)) + *val = _TRUE; + else + *val = _FALSE; + break; + case HW_VAR_APFM_ON_MAC: + *val = hal_data->bMacPwrCtrlOn; + break; + default: + if (0) + RTW_PRINT(FUNC_ADPT_FMT" variable(%d) not defined!\n", + FUNC_ADPT_ARG(adapter), variable); + break; + } + +} + +u8 +SetHalDefVar(_adapter *adapter, HAL_DEF_VARIABLE variable, void *value) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + u8 bResult = _SUCCESS; + + switch (variable) { + + case HAL_DEF_DBG_DUMP_RXPKT: + hal_data->bDumpRxPkt = *((u8 *)value); + break; + case HAL_DEF_DBG_DUMP_TXPKT: + hal_data->bDumpTxPkt = *((u8 *)value); + break; + case HAL_DEF_ANT_DETECT: + hal_data->AntDetection = *((u8 *)value); + break; + case HAL_DEF_DBG_DIS_PWT: + hal_data->bDisableTXPowerTraining = *((u8 *)value); + break; + default: + RTW_PRINT("%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n", __FUNCTION__, variable); + bResult = _FAIL; + break; + } + + return bResult; +} + +#ifdef CONFIG_BEAMFORMING +u8 rtw_hal_query_txbfer_rf_num(_adapter *adapter) +{ + struct registry_priv *pregistrypriv = &adapter->registrypriv; + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + + if ((pregistrypriv->beamformer_rf_num) && (IS_HARDWARE_TYPE_8814AE(adapter) || IS_HARDWARE_TYPE_8814AU(adapter) || IS_HARDWARE_TYPE_8822BU(adapter) || IS_HARDWARE_TYPE_8821C(adapter))) + return pregistrypriv->beamformer_rf_num; + else if (IS_HARDWARE_TYPE_8814AE(adapter) +#if 0 +#if defined(CONFIG_USB_HCI) + || (IS_HARDWARE_TYPE_8814AU(adapter) && (pUsbModeMech->CurUsbMode == 2 || pUsbModeMech->HubUsbMode == 2)) /* for USB3.0 */ +#endif +#endif + ) { + /*BF cap provided by Yu Chen, Sean, 2015, 01 */ + if (hal_data->rf_type == RF_3T3R) + return 2; + else if (hal_data->rf_type == RF_4T4R) + return 3; + else + return 1; + } else + return 1; + +} +u8 rtw_hal_query_txbfee_rf_num(_adapter *adapter) +{ + struct registry_priv *pregistrypriv = &adapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + + if ((pregistrypriv->beamformee_rf_num) && (IS_HARDWARE_TYPE_8814AE(adapter) || IS_HARDWARE_TYPE_8814AU(adapter) || IS_HARDWARE_TYPE_8822BU(adapter) || IS_HARDWARE_TYPE_8821C(adapter))) + return pregistrypriv->beamformee_rf_num; + else if (IS_HARDWARE_TYPE_8814AE(adapter) || IS_HARDWARE_TYPE_8814AU(adapter)) { + if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_BROADCOM) + return 2; + else + return 2;/*TODO: May be 3 in the future, by ChenYu. */ + } else + return 1; + +} +#endif + +u8 +GetHalDefVar(_adapter *adapter, HAL_DEF_VARIABLE variable, void *value) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + u8 bResult = _SUCCESS; + + switch (variable) { + case HAL_DEF_UNDERCORATEDSMOOTHEDPWDB: { + struct mlme_priv *pmlmepriv; + struct sta_priv *pstapriv; + struct sta_info *psta; + + pmlmepriv = &adapter->mlmepriv; + pstapriv = &adapter->stapriv; + psta = rtw_get_stainfo(pstapriv, pmlmepriv->cur_network.network.MacAddress); + if (psta) + *((int *)value) = psta->rssi_stat.undecorated_smoothed_pwdb; + } + break; + case HAL_DEF_DBG_DUMP_RXPKT: + *((u8 *)value) = hal_data->bDumpRxPkt; + break; + case HAL_DEF_DBG_DUMP_TXPKT: + *((u8 *)value) = hal_data->bDumpTxPkt; + break; + case HAL_DEF_ANT_DETECT: + *((u8 *)value) = hal_data->AntDetection; + break; + case HAL_DEF_MACID_SLEEP: + *(u8 *)value = _FALSE; + break; + case HAL_DEF_TX_PAGE_SIZE: + *((u32 *)value) = PAGE_SIZE_128; + break; + case HAL_DEF_DBG_DIS_PWT: + *(u8 *)value = hal_data->bDisableTXPowerTraining; + break; + case HAL_DEF_EXPLICIT_BEAMFORMER: + case HAL_DEF_EXPLICIT_BEAMFORMEE: + case HAL_DEF_VHT_MU_BEAMFORMER: + case HAL_DEF_VHT_MU_BEAMFORMEE: + *(u8 *)value = _FALSE; + break; +#ifdef CONFIG_BEAMFORMING + case HAL_DEF_BEAMFORMER_CAP: + *(u8 *)value = rtw_hal_query_txbfer_rf_num(adapter); + break; + case HAL_DEF_BEAMFORMEE_CAP: + *(u8 *)value = rtw_hal_query_txbfee_rf_num(adapter); + break; +#endif + default: + RTW_PRINT("%s: [WARNING] HAL_DEF_VARIABLE(%d) not defined!\n", __FUNCTION__, variable); + bResult = _FAIL; + break; + } + + return bResult; +} + +void SetHalODMVar( + PADAPTER Adapter, + HAL_ODM_VARIABLE eVariable, + PVOID pValue1, + BOOLEAN bSet) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + struct PHY_DM_STRUCT *podmpriv = &pHalData->odmpriv; + /* _irqL irqL; */ + switch (eVariable) { + case HAL_ODM_STA_INFO: { + struct sta_info *psta = (struct sta_info *)pValue1; + if (bSet) { + RTW_INFO("### Set STA_(%d) info ###\n", psta->mac_id); + odm_cmn_info_ptr_array_hook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, psta); + } else { + RTW_INFO("### Clean STA_(%d) info ###\n", psta->mac_id); + /* _enter_critical_bh(&pHalData->odm_stainfo_lock, &irqL); */ + psta->rssi_level = 0; + odm_cmn_info_ptr_array_hook(podmpriv, ODM_CMNINFO_STA_STATUS, psta->mac_id, NULL); + + /* _exit_critical_bh(&pHalData->odm_stainfo_lock, &irqL); */ + } + } + break; + case HAL_ODM_P2P_STATE: + odm_cmn_info_update(podmpriv, ODM_CMNINFO_WIFI_DIRECT, bSet); + break; + case HAL_ODM_WIFI_DISPLAY_STATE: + odm_cmn_info_update(podmpriv, ODM_CMNINFO_WIFI_DISPLAY, bSet); + break; + case HAL_ODM_REGULATION: + odm_cmn_info_init(podmpriv, ODM_CMNINFO_DOMAIN_CODE_2G, pHalData->Regulation2_4G); + odm_cmn_info_init(podmpriv, ODM_CMNINFO_DOMAIN_CODE_5G, pHalData->Regulation5G); + break; +#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) + case HAL_ODM_NOISE_MONITOR: { + struct noise_info *pinfo = (struct noise_info *)pValue1; + +#ifdef DBG_NOISE_MONITOR + RTW_INFO("### Noise monitor chan(%d)-bPauseDIG:%d,IGIValue:0x%02x,max_time:%d (ms) ###\n", + pinfo->chan, pinfo->bPauseDIG, pinfo->IGIValue, pinfo->max_time); +#endif + + pHalData->noise[pinfo->chan] = odm_inband_noise_monitor(podmpriv, pinfo->is_pause_dig, pinfo->igi_value, pinfo->max_time); + RTW_INFO("chan_%d, noise = %d (dBm)\n", pinfo->chan, pHalData->noise[pinfo->chan]); +#ifdef DBG_NOISE_MONITOR + RTW_INFO("noise_a = %d, noise_b = %d noise_all:%d\n", + podmpriv->noise_level.noise[ODM_RF_PATH_A], + podmpriv->noise_level.noise[ODM_RF_PATH_B], + podmpriv->noise_level.noise_all); +#endif + } + break; +#endif/*#ifdef CONFIG_BACKGROUND_NOISE_MONITOR*/ + + case HAL_ODM_INITIAL_GAIN: { + u8 rx_gain = *((u8 *)(pValue1)); + /*printk("rx_gain:%x\n",rx_gain);*/ + if (rx_gain == 0xff) {/*restore rx gain*/ + /*odm_write_dig(podmpriv,pDigTable->backup_ig_value);*/ + odm_pause_dig(podmpriv, PHYDM_RESUME, PHYDM_PAUSE_LEVEL_0, rx_gain); + } else { + /*pDigTable->backup_ig_value = pDigTable->cur_ig_value;*/ + /*odm_write_dig(podmpriv,rx_gain);*/ + odm_pause_dig(podmpriv, PHYDM_PAUSE, PHYDM_PAUSE_LEVEL_0, rx_gain); + } + } + break; + case HAL_ODM_FA_CNT_DUMP: + if (*((u8 *)pValue1)) + podmpriv->debug_components |= (ODM_COMP_DIG | ODM_COMP_FA_CNT); + else + podmpriv->debug_components &= ~(ODM_COMP_DIG | ODM_COMP_FA_CNT); + break; + case HAL_ODM_DBG_FLAG: + odm_cmn_info_update(podmpriv, ODM_CMNINFO_DBG_COMP, *((u8Byte *)pValue1)); + break; + case HAL_ODM_DBG_LEVEL: + odm_cmn_info_update(podmpriv, ODM_CMNINFO_DBG_LEVEL, *((u4Byte *)pValue1)); + break; + case HAL_ODM_RX_INFO_DUMP: { + struct _FALSE_ALARM_STATISTICS *false_alm_cnt = (struct _FALSE_ALARM_STATISTICS *)phydm_get_structure(podmpriv , PHYDM_FALSEALMCNT); + struct _dynamic_initial_gain_threshold_ *pDM_DigTable = &podmpriv->dm_dig_table; + void *sel; + + sel = pValue1; + + _RTW_PRINT_SEL(sel , "============ Rx Info dump ===================\n"); + _RTW_PRINT_SEL(sel , "is_linked = %d, rssi_min = %d(%%), current_igi = 0x%x\n", podmpriv->is_linked, podmpriv->rssi_min, pDM_DigTable->cur_ig_value); + _RTW_PRINT_SEL(sel , "cnt_cck_fail = %d, cnt_ofdm_fail = %d, Total False Alarm = %d\n", false_alm_cnt->cnt_cck_fail, false_alm_cnt->cnt_ofdm_fail, false_alm_cnt->cnt_all); + + if (podmpriv->is_linked) { + _RTW_PRINT_SEL(sel , "rx_rate = %s", HDATA_RATE(podmpriv->rx_rate)); + _RTW_PRINT_SEL(sel , " RSSI_A = %d(%%), RSSI_B = %d(%%)\n", podmpriv->RSSI_A, podmpriv->RSSI_B); +#ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA + rtw_dump_raw_rssi_info(Adapter, sel); +#endif + } + } + break; + case HAL_ODM_RX_Dframe_INFO: { + void *sel; + + sel = pValue1; + + /*_RTW_PRINT_SEL(sel , "HAL_ODM_RX_Dframe_INFO\n");*/ +#ifdef DBG_RX_DFRAME_RAW_DATA + rtw_dump_rx_dframe_info(Adapter, sel); +#endif + } + break; + +#ifdef CONFIG_AUTO_CHNL_SEL_NHM + case HAL_ODM_AUTO_CHNL_SEL: { + ACS_OP acs_op = *(ACS_OP *)pValue1; + + rtw_phydm_func_set(Adapter, ODM_BB_NHM_CNT); + + if (ACS_INIT == acs_op) { +#ifdef DBG_AUTO_CHNL_SEL_NHM + RTW_INFO("[ACS-"ADPT_FMT"] HAL_ODM_AUTO_CHNL_SEL: ACS_INIT\n", ADPT_ARG(Adapter)); +#endif + odm_AutoChannelSelectInit(podmpriv); + } else if (ACS_RESET == acs_op) { + /* Reset statistics for auto channel selection mechanism.*/ +#ifdef DBG_AUTO_CHNL_SEL_NHM + RTW_INFO("[ACS-"ADPT_FMT"] HAL_ODM_AUTO_CHNL_SEL: ACS_RESET\n", ADPT_ARG(Adapter)); +#endif + odm_auto_channel_select_reset(podmpriv); + + } else if (ACS_SELECT == acs_op) { + /* Collect NHM measurement result after current channel */ +#ifdef DBG_AUTO_CHNL_SEL_NHM + RTW_INFO("[ACS-"ADPT_FMT"] HAL_ODM_AUTO_CHNL_SEL: ACS_SELECT, CH(%d)\n", ADPT_ARG(Adapter), rtw_get_acs_channel(Adapter)); +#endif + odm_AutoChannelSelect(podmpriv, rtw_get_acs_channel(Adapter)); + } else + RTW_INFO("[ACS-"ADPT_FMT"] HAL_ODM_AUTO_CHNL_SEL: Unexpected OP\n", ADPT_ARG(Adapter)); + + } + break; +#endif +#ifdef CONFIG_ANTENNA_DIVERSITY + case HAL_ODM_ANTDIV_SELECT: { + u8 antenna = (*(u8 *)pValue1); + + /*switch antenna*/ + odm_update_rx_idle_ant(&pHalData->odmpriv, antenna); + /*RTW_INFO("==> HAL_ODM_ANTDIV_SELECT, Ant_(%s)\n", (antenna == MAIN_ANT) ? "MAIN_ANT" : "AUX_ANT");*/ + + } + break; +#endif + + default: + break; + } +} + +void GetHalODMVar( + PADAPTER Adapter, + HAL_ODM_VARIABLE eVariable, + PVOID pValue1, + PVOID pValue2) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + struct PHY_DM_STRUCT *podmpriv = &pHalData->odmpriv; + + switch (eVariable) { +#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) + case HAL_ODM_NOISE_MONITOR: { + u8 chan = *(u8 *)pValue1; + *(s16 *)pValue2 = pHalData->noise[chan]; +#ifdef DBG_NOISE_MONITOR + RTW_INFO("### Noise monitor chan(%d)-noise:%d (dBm) ###\n", + chan, pHalData->noise[chan]); +#endif + } + break; +#endif/*#ifdef CONFIG_BACKGROUND_NOISE_MONITOR*/ + case HAL_ODM_DBG_FLAG: + *((u8Byte *)pValue1) = podmpriv->debug_components; + break; + case HAL_ODM_DBG_LEVEL: + *((u4Byte *)pValue1) = podmpriv->debug_level; + break; + +#ifdef CONFIG_AUTO_CHNL_SEL_NHM + case HAL_ODM_AUTO_CHNL_SEL: { +#ifdef DBG_AUTO_CHNL_SEL_NHM + RTW_INFO("[ACS-"ADPT_FMT"] HAL_ODM_AUTO_CHNL_SEL: GET_BEST_CHAN\n", ADPT_ARG(Adapter)); +#endif + /* Retrieve better channel from NHM mechanism */ + if (IsSupported24G(Adapter->registrypriv.wireless_mode)) + *((u8 *)(pValue1)) = odm_get_auto_channel_select_result(podmpriv, BAND_ON_2_4G); + if (is_supported_5g(Adapter->registrypriv.wireless_mode)) + *((u8 *)(pValue2)) = odm_get_auto_channel_select_result(podmpriv, BAND_ON_5G); + } + break; +#endif +#ifdef CONFIG_ANTENNA_DIVERSITY + case HAL_ODM_ANTDIV_SELECT: { + struct _FAST_ANTENNA_TRAINNING_ *pDM_FatTable = &podmpriv->dm_fat_table; + *((u8 *)pValue1) = pDM_FatTable->rx_idle_ant; + } + break; +#endif + case HAL_ODM_INITIAL_GAIN: { + struct _dynamic_initial_gain_threshold_ *pDM_DigTable = &podmpriv->dm_dig_table; + *((u8 *)pValue1) = pDM_DigTable->cur_ig_value; + } + break; + default: + break; + } +} + + +u32 rtw_phydm_ability_ops(_adapter *adapter, HAL_PHYDM_OPS ops, u32 ability) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); + struct PHY_DM_STRUCT *podmpriv = &pHalData->odmpriv; + u32 result = 0; + + switch (ops) { + case HAL_PHYDM_DIS_ALL_FUNC: + podmpriv->support_ability = DYNAMIC_FUNC_DISABLE; + break; + case HAL_PHYDM_FUNC_SET: + podmpriv->support_ability |= ability; + break; + case HAL_PHYDM_FUNC_CLR: + podmpriv->support_ability &= ~(ability); + break; + case HAL_PHYDM_ABILITY_BK: + /* dm flag backup*/ + podmpriv->bk_support_ability = podmpriv->support_ability; + break; + case HAL_PHYDM_ABILITY_RESTORE: + /* restore dm flag */ + podmpriv->support_ability = podmpriv->bk_support_ability; + break; + case HAL_PHYDM_ABILITY_SET: + podmpriv->support_ability = ability; + break; + case HAL_PHYDM_ABILITY_GET: + result = podmpriv->support_ability; + break; + } + return result; +} + + +BOOLEAN +eqNByte( + u8 *str1, + u8 *str2, + u32 num +) +{ + if (num == 0) + return _FALSE; + while (num > 0) { + num--; + if (str1[num] != str2[num]) + return _FALSE; + } + return _TRUE; +} + +/* + * Description: + * Translate a character to hex digit. + * */ +u32 +MapCharToHexDigit( + IN char chTmp +) +{ + if (chTmp >= '0' && chTmp <= '9') + return chTmp - '0'; + else if (chTmp >= 'a' && chTmp <= 'f') + return 10 + (chTmp - 'a'); + else if (chTmp >= 'A' && chTmp <= 'F') + return 10 + (chTmp - 'A'); + else + return 0; +} + + + +/* + * Description: + * Parse hex number from the string pucStr. + * */ +BOOLEAN +GetHexValueFromString( + IN char *szStr, + IN OUT u32 *pu4bVal, + IN OUT u32 *pu4bMove +) +{ + char *szScan = szStr; + + /* Check input parameter. */ + if (szStr == NULL || pu4bVal == NULL || pu4bMove == NULL) { + RTW_INFO("GetHexValueFromString(): Invalid inpur argumetns! szStr: %p, pu4bVal: %p, pu4bMove: %p\n", szStr, pu4bVal, pu4bMove); + return _FALSE; + } + + /* Initialize output. */ + *pu4bMove = 0; + *pu4bVal = 0; + + /* Skip leading space. */ + while (*szScan != '\0' && + (*szScan == ' ' || *szScan == '\t')) { + szScan++; + (*pu4bMove)++; + } + + /* Skip leading '0x' or '0X'. */ + if (*szScan == '0' && (*(szScan + 1) == 'x' || *(szScan + 1) == 'X')) { + szScan += 2; + (*pu4bMove) += 2; + } + + /* Check if szScan is now pointer to a character for hex digit, */ + /* if not, it means this is not a valid hex number. */ + if (!IsHexDigit(*szScan)) + return _FALSE; + + /* Parse each digit. */ + do { + (*pu4bVal) <<= 4; + *pu4bVal += MapCharToHexDigit(*szScan); + + szScan++; + (*pu4bMove)++; + } while (IsHexDigit(*szScan)); + + return _TRUE; +} + +BOOLEAN +GetFractionValueFromString( + IN char *szStr, + IN OUT u8 *pInteger, + IN OUT u8 *pFraction, + IN OUT u32 *pu4bMove +) +{ + char *szScan = szStr; + + /* Initialize output. */ + *pu4bMove = 0; + *pInteger = 0; + *pFraction = 0; + + /* Skip leading space. */ + while (*szScan != '\0' && (*szScan == ' ' || *szScan == '\t')) { + ++szScan; + ++(*pu4bMove); + } + + /* Parse each digit. */ + do { + (*pInteger) *= 10; + *pInteger += (*szScan - '0'); + + ++szScan; + ++(*pu4bMove); + + if (*szScan == '.') { + ++szScan; + ++(*pu4bMove); + + if (*szScan < '0' || *szScan > '9') + return _FALSE; + else { + *pFraction = *szScan - '0'; + ++szScan; + ++(*pu4bMove); + return _TRUE; + } + } + } while (*szScan >= '0' && *szScan <= '9'); + + return _TRUE; +} + +/* + * Description: + * Return TRUE if szStr is comment out with leading " */ /* ". + * */ +BOOLEAN +IsCommentString( + IN char *szStr +) +{ + if (*szStr == '/' && *(szStr + 1) == '/') + return _TRUE; + else + return _FALSE; +} + +BOOLEAN +GetU1ByteIntegerFromStringInDecimal( + IN char *Str, + IN OUT u8 *pInt +) +{ + u16 i = 0; + *pInt = 0; + + while (Str[i] != '\0') { + if (Str[i] >= '0' && Str[i] <= '9') { + *pInt *= 10; + *pInt += (Str[i] - '0'); + } else + return _FALSE; + ++i; + } + + return _TRUE; +} + +/* <20121004, Kordan> For example, + * ParseQualifiedString(inString, 0, outString, '[', ']') gets "Kordan" from a string "Hello [Kordan]". + * If RightQualifier does not exist, it will hang on in the while loop */ +BOOLEAN +ParseQualifiedString( + IN char *In, + IN OUT u32 *Start, + OUT char *Out, + IN char LeftQualifier, + IN char RightQualifier +) +{ + u32 i = 0, j = 0; + char c = In[(*Start)++]; + + if (c != LeftQualifier) + return _FALSE; + + i = (*Start); + while ((c = In[(*Start)++]) != RightQualifier) + ; /* find ']' */ + j = (*Start) - 2; + strncpy((char *)Out, (const char *)(In + i), j - i + 1); + + return _TRUE; +} + +BOOLEAN +isAllSpaceOrTab( + u8 *data, + u8 size +) +{ + u8 cnt = 0, NumOfSpaceAndTab = 0; + + while (size > cnt) { + if (data[cnt] == ' ' || data[cnt] == '\t' || data[cnt] == '\0') + ++NumOfSpaceAndTab; + + ++cnt; + } + + return size == NumOfSpaceAndTab; +} + + +void rtw_hal_check_rxfifo_full(_adapter *adapter) +{ + struct dvobj_priv *psdpriv = adapter->dvobj; + struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); + struct registry_priv *regsty = &adapter->registrypriv; + int save_cnt = _FALSE; + + if (regsty->check_hw_status == 1) { + /* switch counter to RX fifo */ + if (IS_8188E(pHalData->version_id) || + IS_8188F(pHalData->version_id) || + IS_8812_SERIES(pHalData->version_id) || + IS_8821_SERIES(pHalData->version_id) || + IS_8723B_SERIES(pHalData->version_id) || + IS_8192E(pHalData->version_id) || + IS_8703B_SERIES(pHalData->version_id) || + IS_8723D_SERIES(pHalData->version_id)) { + rtw_write8(adapter, REG_RXERR_RPT + 3, rtw_read8(adapter, REG_RXERR_RPT + 3) | 0xa0); + save_cnt = _TRUE; + } else { + /* todo: other chips */ + } + + + if (save_cnt) { + pdbgpriv->dbg_rx_fifo_last_overflow = pdbgpriv->dbg_rx_fifo_curr_overflow; + pdbgpriv->dbg_rx_fifo_curr_overflow = rtw_read16(adapter, REG_RXERR_RPT); + pdbgpriv->dbg_rx_fifo_diff_overflow = pdbgpriv->dbg_rx_fifo_curr_overflow - pdbgpriv->dbg_rx_fifo_last_overflow; + } else { + /* special value to indicate no implementation */ + pdbgpriv->dbg_rx_fifo_last_overflow = 1; + pdbgpriv->dbg_rx_fifo_curr_overflow = 1; + pdbgpriv->dbg_rx_fifo_diff_overflow = 1; + } + } +} + +void linked_info_dump(_adapter *padapter, u8 benable) +{ + struct pwrctrl_priv *pwrctrlpriv = adapter_to_pwrctl(padapter); + + if (padapter->bLinkInfoDump == benable) + return; + + RTW_INFO("%s %s\n", __FUNCTION__, (benable) ? "enable" : "disable"); + + if (benable) { +#ifdef CONFIG_LPS + pwrctrlpriv->org_power_mgnt = pwrctrlpriv->power_mgnt;/* keep org value */ + rtw_pm_set_lps(padapter, PS_MODE_ACTIVE); +#endif + +#ifdef CONFIG_IPS + pwrctrlpriv->ips_org_mode = pwrctrlpriv->ips_mode;/* keep org value */ + rtw_pm_set_ips(padapter, IPS_NONE); +#endif + } else { +#ifdef CONFIG_IPS + rtw_pm_set_ips(padapter, pwrctrlpriv->ips_org_mode); +#endif /* CONFIG_IPS */ + +#ifdef CONFIG_LPS + rtw_pm_set_lps(padapter, pwrctrlpriv->org_power_mgnt); +#endif /* CONFIG_LPS */ + } + padapter->bLinkInfoDump = benable ; +} + +#ifdef DBG_RX_SIGNAL_DISPLAY_RAW_DATA +void rtw_get_raw_rssi_info(void *sel, _adapter *padapter) +{ + u8 isCCKrate, rf_path; + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info; + RTW_PRINT_SEL(sel, "RxRate = %s, PWDBALL = %d(%%), rx_pwr_all = %d(dBm)\n", + HDATA_RATE(psample_pkt_rssi->data_rate), psample_pkt_rssi->pwdball, psample_pkt_rssi->pwr_all); + isCCKrate = (psample_pkt_rssi->data_rate <= DESC_RATE11M) ? TRUE : FALSE; + + if (isCCKrate) + psample_pkt_rssi->mimo_signal_strength[0] = psample_pkt_rssi->pwdball; + + for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { + RTW_PRINT_SEL(sel, "RF_PATH_%d=>signal_strength:%d(%%),signal_quality:%d(%%)\n" + , rf_path, psample_pkt_rssi->mimo_signal_strength[rf_path], psample_pkt_rssi->mimo_signal_quality[rf_path]); + + if (!isCCKrate) { + RTW_PRINT_SEL(sel, "\trx_ofdm_pwr:%d(dBm),rx_ofdm_snr:%d(dB)\n", + psample_pkt_rssi->ofdm_pwr[rf_path], psample_pkt_rssi->ofdm_snr[rf_path]); + } + } +} + +void rtw_dump_raw_rssi_info(_adapter *padapter, void *sel) +{ + u8 isCCKrate, rf_path; + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info; + _RTW_PRINT_SEL(sel, "============ RAW Rx Info dump ===================\n"); + _RTW_PRINT_SEL(sel, "RxRate = %s, PWDBALL = %d(%%), rx_pwr_all = %d(dBm)\n", HDATA_RATE(psample_pkt_rssi->data_rate), psample_pkt_rssi->pwdball, psample_pkt_rssi->pwr_all); + + isCCKrate = (psample_pkt_rssi->data_rate <= DESC_RATE11M) ? TRUE : FALSE; + + if (isCCKrate) + psample_pkt_rssi->mimo_signal_strength[0] = psample_pkt_rssi->pwdball; + + for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { + _RTW_PRINT_SEL(sel , "RF_PATH_%d=>signal_strength:%d(%%),signal_quality:%d(%%)" + , rf_path, psample_pkt_rssi->mimo_signal_strength[rf_path], psample_pkt_rssi->mimo_signal_quality[rf_path]); + + if (!isCCKrate) + _RTW_PRINT_SEL(sel , ",rx_ofdm_pwr:%d(dBm),rx_ofdm_snr:%d(dB)\n", psample_pkt_rssi->ofdm_pwr[rf_path], psample_pkt_rssi->ofdm_snr[rf_path]); + else + _RTW_PRINT_SEL(sel , "\n"); + + } +} +#endif + +#ifdef DBG_RX_DFRAME_RAW_DATA +void rtw_dump_rx_dframe_info(_adapter *padapter, void *sel) +{ + _irqL irqL; + u8 isCCKrate, rf_path; + struct recv_priv *precvpriv = &(padapter->recvpriv); + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta; + struct sta_recv_dframe_info *psta_dframe_info; + int i; + _list *plist, *phead; + char *BW; + u8 bc_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 null_addr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + if (precvpriv->store_law_data_flag) { + + _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); + + for (i = 0; i < NUM_STA; i++) { + phead = &(pstapriv->sta_hash[i]); + plist = get_next(phead); + + while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) { + + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + plist = get_next(plist); + + if (psta) { + psta_dframe_info = &psta->sta_dframe_info; + if ((_rtw_memcmp(psta->hwaddr, bc_addr, 6) != _TRUE) + && (_rtw_memcmp(psta->hwaddr, null_addr, 6) != _TRUE) + && (_rtw_memcmp(psta->hwaddr, adapter_mac_addr(padapter), 6) != _TRUE)) { + + + isCCKrate = (psta_dframe_info->sta_data_rate <= DESC_RATE11M) ? TRUE : FALSE; + + switch (psta_dframe_info->sta_bw_mode) { + + case CHANNEL_WIDTH_20: + BW = "20M"; + break; + + case CHANNEL_WIDTH_40: + BW = "40M"; + break; + + case CHANNEL_WIDTH_80: + BW = "80M"; + break; + + case CHANNEL_WIDTH_160: + BW = "160M"; + break; + + default: + BW = ""; + break; + } + + RTW_PRINT_SEL(sel, "==============================\n"); + _RTW_PRINT_SEL(sel, "macaddr =" MAC_FMT "\n", MAC_ARG(psta->hwaddr)); + _RTW_PRINT_SEL(sel, "BW=%s, sgi =%d\n", BW, psta_dframe_info->sta_sgi); + _RTW_PRINT_SEL(sel, "Rx_Data_Rate = %s\n", HDATA_RATE(psta_dframe_info->sta_data_rate)); + + for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { + + if (!isCCKrate) { + + _RTW_PRINT_SEL(sel , "RF_PATH_%d RSSI:%d(dBm)", rf_path, psta_dframe_info->sta_RxPwr[rf_path]); + _RTW_PRINT_SEL(sel , ",rx_ofdm_snr:%d(dB)\n", psta_dframe_info->sta_ofdm_snr[rf_path]); + + } else + + _RTW_PRINT_SEL(sel , "RF_PATH_%d RSSI:%d(dBm)\n", rf_path, (psta_dframe_info->sta_mimo_signal_strength[rf_path]) - 100); + } + } + } + } + } + _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); + } +} +#endif +void rtw_store_phy_info(_adapter *padapter, union recv_frame *prframe) +{ + u8 isCCKrate, rf_path , dframe_type; + u8 *ptr; + u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +#ifdef DBG_RX_DFRAME_RAW_DATA + struct sta_recv_dframe_info *psta_dframe_info; +#endif + struct recv_priv *precvpriv = &(padapter->recvpriv); + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; + struct sta_info *psta = prframe->u.hdr.psta; + struct _odm_phy_status_info_ *p_phy_info = (struct _odm_phy_status_info_ *)(&pattrib->phy_info); + struct rx_raw_rssi *psample_pkt_rssi = &padapter->recvpriv.raw_rssi_info; + psample_pkt_rssi->data_rate = pattrib->data_rate; + ptr = prframe->u.hdr.rx_data; + dframe_type = GetFrameType(ptr); + /*RTW_INFO("=>%s\n", __FUNCTION__);*/ + + + if (precvpriv->store_law_data_flag) { + isCCKrate = (pattrib->data_rate <= DESC_RATE11M) ? TRUE : FALSE; + + psample_pkt_rssi->pwdball = p_phy_info->rx_pwdb_all; + psample_pkt_rssi->pwr_all = p_phy_info->recv_signal_power; + + for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { + psample_pkt_rssi->mimo_signal_strength[rf_path] = p_phy_info->rx_mimo_signal_strength[rf_path]; + psample_pkt_rssi->mimo_signal_quality[rf_path] = p_phy_info->rx_mimo_signal_quality[rf_path]; + if (!isCCKrate) { + psample_pkt_rssi->ofdm_pwr[rf_path] = p_phy_info->rx_pwr[rf_path]; + psample_pkt_rssi->ofdm_snr[rf_path] = p_phy_info->rx_snr[rf_path]; + } + } +#ifdef DBG_RX_DFRAME_RAW_DATA + if ((dframe_type == WIFI_DATA_TYPE) || (dframe_type == WIFI_QOS_DATA_TYPE) || (padapter->registrypriv.mp_mode == 1)) { + + /*RTW_INFO("=>%s WIFI_DATA_TYPE or WIFI_QOS_DATA_TYPE\n", __FUNCTION__);*/ + if (psta) { + psta_dframe_info = &psta->sta_dframe_info; + /*RTW_INFO("=>%s psta->hwaddr="MAC_FMT" !\n", __FUNCTION__, MAC_ARG(psta->hwaddr));*/ + if ((_rtw_memcmp(psta->hwaddr, bc_addr, ETH_ALEN) != _TRUE) || (padapter->registrypriv.mp_mode == 1)) { + psta_dframe_info->sta_data_rate = pattrib->data_rate; + psta_dframe_info->sta_sgi = pattrib->sgi; + psta_dframe_info->sta_bw_mode = pattrib->bw; + for (rf_path = 0; rf_path < pHalData->NumTotalRFPath; rf_path++) { + + psta_dframe_info->sta_mimo_signal_strength[rf_path] = (p_phy_info->rx_mimo_signal_strength[rf_path]);/*Percentage to dbm*/ + + if (!isCCKrate) { + psta_dframe_info->sta_ofdm_snr[rf_path] = p_phy_info->rx_snr[rf_path]; + psta_dframe_info->sta_RxPwr[rf_path] = p_phy_info->rx_pwr[rf_path]; + } + } + } + } + } +#endif + } + +} + + +int check_phy_efuse_tx_power_info_valid(PADAPTER padapter) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + u8 *pContent = pHalData->efuse_eeprom_data; + int index = 0; + u16 tx_index_offset = 0x0000; + + switch (rtw_get_chip_type(padapter)) { + case RTL8723B: + tx_index_offset = EEPROM_TX_PWR_INX_8723B; + break; + case RTL8703B: + tx_index_offset = EEPROM_TX_PWR_INX_8703B; + break; + case RTL8723D: + tx_index_offset = EEPROM_TX_PWR_INX_8723D; + break; + case RTL8188E: + tx_index_offset = EEPROM_TX_PWR_INX_88E; + break; + case RTL8188F: + tx_index_offset = EEPROM_TX_PWR_INX_8188F; + break; + case RTL8192E: + tx_index_offset = EEPROM_TX_PWR_INX_8192E; + break; + case RTL8821: + tx_index_offset = EEPROM_TX_PWR_INX_8821; + break; + case RTL8812: + tx_index_offset = EEPROM_TX_PWR_INX_8812; + break; + case RTL8814A: + tx_index_offset = EEPROM_TX_PWR_INX_8814; + break; + case RTL8822B: + tx_index_offset = EEPROM_TX_PWR_INX_8822B; + break; + case RTL8821C: + tx_index_offset = EEPROM_TX_PWR_INX_8821C; + break; + default: + tx_index_offset = 0x0010; + break; + } + + /* TODO: chacking length by ICs */ + for (index = 0 ; index < 11 ; index++) { + if (pContent[tx_index_offset + index] == 0xFF) + return _FALSE; + } + return _TRUE; +} + +int hal_efuse_macaddr_offset(_adapter *adapter) +{ + u8 interface_type = 0; + int addr_offset = -1; + + interface_type = rtw_get_intf_type(adapter); + + switch (rtw_get_chip_type(adapter)) { +#ifdef CONFIG_RTL8723B + case RTL8723B: + if (interface_type == RTW_USB) + addr_offset = EEPROM_MAC_ADDR_8723BU; + else if (interface_type == RTW_SDIO) + addr_offset = EEPROM_MAC_ADDR_8723BS; + else if (interface_type == RTW_PCIE) + addr_offset = EEPROM_MAC_ADDR_8723BE; + break; +#endif +#ifdef CONFIG_RTL8703B + case RTL8703B: + if (interface_type == RTW_USB) + addr_offset = EEPROM_MAC_ADDR_8703BU; + else if (interface_type == RTW_SDIO) + addr_offset = EEPROM_MAC_ADDR_8703BS; + break; +#endif +#ifdef CONFIG_RTL8723D + case RTL8723D: + if (interface_type == RTW_USB) + addr_offset = EEPROM_MAC_ADDR_8723DU; + else if (interface_type == RTW_SDIO) + addr_offset = EEPROM_MAC_ADDR_8723DS; + else if (interface_type == RTW_PCIE) + addr_offset = EEPROM_MAC_ADDR_8723DE; + break; +#endif + +#ifdef CONFIG_RTL8188E + case RTL8188E: + if (interface_type == RTW_USB) + addr_offset = EEPROM_MAC_ADDR_88EU; + else if (interface_type == RTW_SDIO) + addr_offset = EEPROM_MAC_ADDR_88ES; + else if (interface_type == RTW_PCIE) + addr_offset = EEPROM_MAC_ADDR_88EE; + break; +#endif +#ifdef CONFIG_RTL8188F + case RTL8188F: + if (interface_type == RTW_USB) + addr_offset = EEPROM_MAC_ADDR_8188FU; + else if (interface_type == RTW_SDIO) + addr_offset = EEPROM_MAC_ADDR_8188FS; + break; +#endif +#ifdef CONFIG_RTL8812A + case RTL8812: + if (interface_type == RTW_USB) + addr_offset = EEPROM_MAC_ADDR_8812AU; + else if (interface_type == RTW_PCIE) + addr_offset = EEPROM_MAC_ADDR_8812AE; + break; +#endif +#ifdef CONFIG_RTL8821A + case RTL8821: + if (interface_type == RTW_USB) + addr_offset = EEPROM_MAC_ADDR_8821AU; + else if (interface_type == RTW_SDIO) + addr_offset = EEPROM_MAC_ADDR_8821AS; + else if (interface_type == RTW_PCIE) + addr_offset = EEPROM_MAC_ADDR_8821AE; + break; +#endif +#ifdef CONFIG_RTL8192E + case RTL8192E: + if (interface_type == RTW_USB) + addr_offset = EEPROM_MAC_ADDR_8192EU; + else if (interface_type == RTW_SDIO) + addr_offset = EEPROM_MAC_ADDR_8192ES; + else if (interface_type == RTW_PCIE) + addr_offset = EEPROM_MAC_ADDR_8192EE; + break; +#endif +#ifdef CONFIG_RTL8814A + case RTL8814A: + if (interface_type == RTW_USB) + addr_offset = EEPROM_MAC_ADDR_8814AU; + else if (interface_type == RTW_PCIE) + addr_offset = EEPROM_MAC_ADDR_8814AE; + break; +#endif + +#ifdef CONFIG_RTL8822B + case RTL8822B: + if (interface_type == RTW_USB) + addr_offset = EEPROM_MAC_ADDR_8822BU; + else if (interface_type == RTW_SDIO) + addr_offset = EEPROM_MAC_ADDR_8822BS; + else if (interface_type == RTW_PCIE) + addr_offset = EEPROM_MAC_ADDR_8822BE; + break; +#endif /* CONFIG_RTL8822B */ + +#ifdef CONFIG_RTL8821C + case RTL8821C: + if (interface_type == RTW_USB) + addr_offset = EEPROM_MAC_ADDR_8821CU; + else if (interface_type == RTW_SDIO) + addr_offset = EEPROM_MAC_ADDR_8821CS; + else if (interface_type == RTW_PCIE) + addr_offset = EEPROM_MAC_ADDR_8821CE; + break; +#endif /* CONFIG_RTL8821C */ + } + + if (addr_offset == -1) { + RTW_ERR("%s: unknown combination - chip_type:%u, interface:%u\n" + , __func__, rtw_get_chip_type(adapter), rtw_get_intf_type(adapter)); + } + + return addr_offset; +} + +int Hal_GetPhyEfuseMACAddr(PADAPTER padapter, u8 *mac_addr) +{ + int ret = _FAIL; + int addr_offset; + + addr_offset = hal_efuse_macaddr_offset(padapter); + if (addr_offset == -1) + goto exit; + + ret = rtw_efuse_map_read(padapter, addr_offset, ETH_ALEN, mac_addr); + +exit: + return ret; +} + +void rtw_dump_cur_efuse(PADAPTER padapter) +{ + int i =0; + int mapsize =0; + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter); + + EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN , (void *)&mapsize, _FALSE); + + if (mapsize <= 0 || mapsize > EEPROM_MAX_SIZE) { + RTW_ERR("wrong map size %d\n", mapsize); + return; + } + + if (hal_data->efuse_file_status == EFUSE_FILE_LOADED) + RTW_INFO("EFUSE FILE\n"); + else + RTW_INFO("HW EFUSE\n"); + +#ifdef CONFIG_RTW_DEBUG + for (i = 0; i < mapsize; i++) { + if (i % 16 == 0) + RTW_PRINT_SEL(RTW_DBGDUMP, "0x%03x: ", i); + + _RTW_PRINT_SEL(RTW_DBGDUMP, "%02X%s" + , hal_data->efuse_eeprom_data[i] + , ((i + 1) % 16 == 0) ? "\n" : (((i + 1) % 8 == 0) ? " " : " ") + ); + } + _RTW_PRINT_SEL(RTW_DBGDUMP, "\n"); +#endif +} + + +#ifdef CONFIG_EFUSE_CONFIG_FILE +u32 Hal_readPGDataFromConfigFile(PADAPTER padapter) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter); + u32 ret = _FALSE; + u32 maplen = 0; + + EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN , (void *)&maplen, _FALSE); + + if (maplen < 256 || maplen > EEPROM_MAX_SIZE) { + RTW_ERR("eFuse length error :%d\n", maplen); + return _FALSE; + } + + ret = rtw_read_efuse_from_file(EFUSE_MAP_PATH, hal_data->efuse_eeprom_data, maplen); + + hal_data->efuse_file_status = ((ret == _FAIL) ? EFUSE_FILE_FAILED : EFUSE_FILE_LOADED); + + if (hal_data->efuse_file_status == EFUSE_FILE_LOADED) + rtw_dump_cur_efuse(padapter); + + return ret; +} + +u32 Hal_ReadMACAddrFromFile(PADAPTER padapter, u8 *mac_addr) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter); + u32 ret = _FAIL; + + if (rtw_read_macaddr_from_file(WIFIMAC_PATH, mac_addr) == _SUCCESS + && rtw_check_invalid_mac_address(mac_addr, _TRUE) == _FALSE + ) { + hal_data->macaddr_file_status = MACADDR_FILE_LOADED; + ret = _SUCCESS; + } else + hal_data->macaddr_file_status = MACADDR_FILE_FAILED; + + return ret; +} +#endif /* CONFIG_EFUSE_CONFIG_FILE */ + +int hal_config_macaddr(_adapter *adapter, bool autoload_fail) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + u8 addr[ETH_ALEN]; + int addr_offset = hal_efuse_macaddr_offset(adapter); + u8 *hw_addr = NULL; + int ret = _SUCCESS; + + if (autoload_fail) + goto bypass_hw_pg; + + if (addr_offset != -1) + hw_addr = &hal_data->efuse_eeprom_data[addr_offset]; + +#ifdef CONFIG_EFUSE_CONFIG_FILE + /* if the hw_addr is written by efuse file, set to NULL */ + if (hal_data->efuse_file_status == EFUSE_FILE_LOADED) + hw_addr = NULL; +#endif + + if (!hw_addr) { + /* try getting hw pg data */ + if (Hal_GetPhyEfuseMACAddr(adapter, addr) == _SUCCESS) + hw_addr = addr; + } + + /* check hw pg data */ + if (hw_addr && rtw_check_invalid_mac_address(hw_addr, _TRUE) == _FALSE) { + _rtw_memcpy(hal_data->EEPROMMACAddr, hw_addr, ETH_ALEN); + goto exit; + } + +bypass_hw_pg: + +#ifdef CONFIG_EFUSE_CONFIG_FILE + /* check wifi mac file */ + if (Hal_ReadMACAddrFromFile(adapter, addr) == _SUCCESS) { + _rtw_memcpy(hal_data->EEPROMMACAddr, addr, ETH_ALEN); + goto exit; + } +#endif + + _rtw_memset(hal_data->EEPROMMACAddr, 0, ETH_ALEN); + ret = _FAIL; + +exit: + return ret; +} + +#ifdef CONFIG_RF_POWER_TRIM +u32 Array_kfreemap[] = { + 0x08, 0xe, + 0x06, 0xc, + 0x04, 0xa, + 0x02, 0x8, + 0x00, 0x6, + 0x03, 0x4, + 0x05, 0x2, + 0x07, 0x0, + 0x09, 0x0, + 0x0c, 0x0, +}; + +void rtw_bb_rf_gain_offset(_adapter *padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct registry_priv *registry_par = &padapter->registrypriv; + struct kfree_data_t *kfree_data = &pHalData->kfree_data; + u8 value = pHalData->EEPROMRFGainOffset; + u8 tmp = 0x3e; + u32 res, i = 0; + u4Byte ArrayLen = sizeof(Array_kfreemap) / sizeof(u32); + pu4Byte Array = Array_kfreemap; + u4Byte v1 = 0, v2 = 0, GainValue = 0, target = 0; + + if (registry_par->RegPwrTrimEnable == 2) { + RTW_INFO("Registry kfree default force disable.\n"); + return; + } + +#if defined(CONFIG_RTL8723B) + if (value & BIT4 || (registry_par->RegPwrTrimEnable == 1)) { + RTW_INFO("Offset RF Gain.\n"); + RTW_INFO("Offset RF Gain. pHalData->EEPROMRFGainVal=0x%x\n", pHalData->EEPROMRFGainVal); + + if (pHalData->EEPROMRFGainVal != 0xff) { + + if (pHalData->ant_path == ODM_RF_PATH_A) + GainValue = (pHalData->EEPROMRFGainVal & 0x0f); + + else + GainValue = (pHalData->EEPROMRFGainVal & 0xf0) >> 4; + RTW_INFO("Ant PATH_%d GainValue Offset = 0x%x\n", (pHalData->ant_path == ODM_RF_PATH_A) ? (ODM_RF_PATH_A) : (ODM_RF_PATH_B), GainValue); + + for (i = 0; i < ArrayLen; i += 2) { + /* RTW_INFO("ArrayLen in =%d ,Array 1 =0x%x ,Array2 =0x%x\n",i,Array[i],Array[i]+1); */ + v1 = Array[i]; + v2 = Array[i + 1]; + if (v1 == GainValue) { + RTW_INFO("Offset RF Gain. got v1 =0x%x ,v2 =0x%x\n", v1, v2); + target = v2; + break; + } + } + RTW_INFO("pHalData->EEPROMRFGainVal=0x%x ,Gain offset Target Value=0x%x\n", pHalData->EEPROMRFGainVal, target); + + res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff); + RTW_INFO("Offset RF Gain. before reg 0x7f=0x%08x\n", res); + phy_set_rf_reg(padapter, RF_PATH_A, REG_RF_BB_GAIN_OFFSET, BIT18 | BIT17 | BIT16 | BIT15, target); + res = rtw_hal_read_rfreg(padapter, RF_PATH_A, 0x7f, 0xffffffff); + + RTW_INFO("Offset RF Gain. After reg 0x7f=0x%08x\n", res); + + } else + + RTW_INFO("Offset RF Gain. pHalData->EEPROMRFGainVal=0x%x != 0xff, didn't run Kfree\n", pHalData->EEPROMRFGainVal); + } else + RTW_INFO("Using the default RF gain.\n"); + +#elif defined(CONFIG_RTL8188E) + if (value & BIT4 || (registry_par->RegPwrTrimEnable == 1)) { + RTW_INFO("8188ES Offset RF Gain.\n"); + RTW_INFO("8188ES Offset RF Gain. EEPROMRFGainVal=0x%x\n", + pHalData->EEPROMRFGainVal); + + if (pHalData->EEPROMRFGainVal != 0xff) { + res = rtw_hal_read_rfreg(padapter, RF_PATH_A, + REG_RF_BB_GAIN_OFFSET, 0xffffffff); + + RTW_INFO("Offset RF Gain. reg 0x55=0x%x\n", res); + res &= 0xfff87fff; + + res |= (pHalData->EEPROMRFGainVal & 0x0f) << 15; + RTW_INFO("Offset RF Gain. res=0x%x\n", res); + + rtw_hal_write_rfreg(padapter, RF_PATH_A, + REG_RF_BB_GAIN_OFFSET, + RF_GAIN_OFFSET_MASK, res); + } else { + RTW_INFO("Offset RF Gain. EEPROMRFGainVal=0x%x == 0xff, didn't run Kfree\n", + pHalData->EEPROMRFGainVal); + } + } else + RTW_INFO("Using the default RF gain.\n"); +#else + /* TODO: call this when channel switch */ + if (kfree_data->flag & KFREE_FLAG_ON) + rtw_rf_apply_tx_gain_offset(padapter, 6); /* input ch6 to select BB_GAIN_2G */ +#endif + +} +#endif /*CONFIG_RF_POWER_TRIM */ + +bool kfree_data_is_bb_gain_empty(struct kfree_data_t *data) +{ +#ifdef CONFIG_RF_POWER_TRIM + int i, j; + + for (i = 0; i < BB_GAIN_NUM; i++) + for (j = 0; j < RF_PATH_MAX; j++) + if (data->bb_gain[i][j] != 0) + return 0; +#endif + return 1; +} + +#ifdef CONFIG_USB_RX_AGGREGATION +void rtw_set_usb_agg_by_mode_normal(_adapter *padapter, u8 cur_wireless_mode) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + if (cur_wireless_mode < WIRELESS_11_24N + && cur_wireless_mode > 0) { /* ABG mode */ +#ifdef CONFIG_PREALLOC_RX_SKB_BUFFER + u32 remainder = 0; + u8 quotient = 0; + + remainder = MAX_RECVBUF_SZ % (4 * 1024); + quotient = (u8)(MAX_RECVBUF_SZ >> 12); + + if (quotient > 5) { + pHalData->rxagg_usb_size = 0x6; + pHalData->rxagg_usb_timeout = 0x10; + } else { + if (remainder >= 2048) { + pHalData->rxagg_usb_size = quotient; + pHalData->rxagg_usb_timeout = 0x10; + } else { + pHalData->rxagg_usb_size = (quotient - 1); + pHalData->rxagg_usb_timeout = 0x10; + } + } +#else /* !CONFIG_PREALLOC_RX_SKB_BUFFER */ + if (0x6 != pHalData->rxagg_usb_size || 0x10 != pHalData->rxagg_usb_timeout) { + pHalData->rxagg_usb_size = 0x6; + pHalData->rxagg_usb_timeout = 0x10; + rtw_write16(padapter, REG_RXDMA_AGG_PG_TH, + pHalData->rxagg_usb_size | (pHalData->rxagg_usb_timeout << 8)); + } +#endif /* CONFIG_PREALLOC_RX_SKB_BUFFER */ + + } else if (cur_wireless_mode >= WIRELESS_11_24N + && cur_wireless_mode <= WIRELESS_MODE_MAX) { /* N AC mode */ +#ifdef CONFIG_PREALLOC_RX_SKB_BUFFER + u32 remainder = 0; + u8 quotient = 0; + + remainder = MAX_RECVBUF_SZ % (4 * 1024); + quotient = (u8)(MAX_RECVBUF_SZ >> 12); + + if (quotient > 5) { + pHalData->rxagg_usb_size = 0x5; + pHalData->rxagg_usb_timeout = 0x20; + } else { + if (remainder >= 2048) { + pHalData->rxagg_usb_size = quotient; + pHalData->rxagg_usb_timeout = 0x10; + } else { + pHalData->rxagg_usb_size = (quotient - 1); + pHalData->rxagg_usb_timeout = 0x10; + } + } +#else /* !CONFIG_PREALLOC_RX_SKB_BUFFER */ + if ((0x5 != pHalData->rxagg_usb_size) || (0x20 != pHalData->rxagg_usb_timeout)) { + pHalData->rxagg_usb_size = 0x5; + pHalData->rxagg_usb_timeout = 0x20; + rtw_write16(padapter, REG_RXDMA_AGG_PG_TH, + pHalData->rxagg_usb_size | (pHalData->rxagg_usb_timeout << 8)); + } +#endif /* CONFIG_PREALLOC_RX_SKB_BUFFER */ + + } else { + /* RTW_INFO("%s: Unknow wireless mode(0x%x)\n",__func__,padapter->mlmeextpriv.cur_wireless_mode); */ + } +} + +void rtw_set_usb_agg_by_mode_customer(_adapter *padapter, u8 cur_wireless_mode, u8 UsbDmaSize, u8 Legacy_UsbDmaSize) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + if (cur_wireless_mode < WIRELESS_11_24N + && cur_wireless_mode > 0) { /* ABG mode */ + if (Legacy_UsbDmaSize != pHalData->rxagg_usb_size + || 0x10 != pHalData->rxagg_usb_timeout) { + pHalData->rxagg_usb_size = Legacy_UsbDmaSize; + pHalData->rxagg_usb_timeout = 0x10; + rtw_write16(padapter, REG_RXDMA_AGG_PG_TH, + pHalData->rxagg_usb_size | (pHalData->rxagg_usb_timeout << 8)); + } + } else if (cur_wireless_mode >= WIRELESS_11_24N + && cur_wireless_mode <= WIRELESS_MODE_MAX) { /* N AC mode */ + if (UsbDmaSize != pHalData->rxagg_usb_size + || 0x20 != pHalData->rxagg_usb_timeout) { + pHalData->rxagg_usb_size = UsbDmaSize; + pHalData->rxagg_usb_timeout = 0x20; + rtw_write16(padapter, REG_RXDMA_AGG_PG_TH, + pHalData->rxagg_usb_size | (pHalData->rxagg_usb_timeout << 8)); + } + } else { + /* RTW_INFO("%s: Unknown wireless mode(0x%x)\n",__func__,padapter->mlmeextpriv.cur_wireless_mode); */ + } +} + +void rtw_set_usb_agg_by_mode(_adapter *padapter, u8 cur_wireless_mode) +{ +#ifdef CONFIG_PLATFORM_NOVATEK_NT72668 + rtw_set_usb_agg_by_mode_customer(padapter, cur_wireless_mode, 0x3, 0x3); + return; +#endif /* CONFIG_PLATFORM_NOVATEK_NT72668 */ + + rtw_set_usb_agg_by_mode_normal(padapter, cur_wireless_mode); +} +#endif /* CONFIG_USB_RX_AGGREGATION */ + +/* To avoid RX affect TX throughput */ +void dm_DynamicUsbTxAgg(_adapter *padapter, u8 from_timer) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + u8 cur_wireless_mode = WIRELESS_INVALID; + +#ifdef CONFIG_USB_RX_AGGREGATION + if (IS_HARDWARE_TYPE_8821U(padapter)) { /* || IS_HARDWARE_TYPE_8192EU(padapter)) */ + /* This AGG_PH_TH only for UsbRxAggMode == USB_RX_AGG_USB */ + if ((pHalData->rxagg_mode == RX_AGG_USB) && (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) { + if (pdvobjpriv->traffic_stat.cur_tx_tp > 2 && pdvobjpriv->traffic_stat.cur_rx_tp < 30) + rtw_write16(padapter , REG_RXDMA_AGG_PG_TH , 0x1010); + else if (pdvobjpriv->traffic_stat.last_tx_bytes > 220000 && pdvobjpriv->traffic_stat.cur_rx_tp < 30) + rtw_write16(padapter , REG_RXDMA_AGG_PG_TH , 0x1006); + else + rtw_write16(padapter, REG_RXDMA_AGG_PG_TH, 0x2005); /* dmc agg th 20K */ + + /* RTW_INFO("TX_TP=%u, RX_TP=%u\n", pdvobjpriv->traffic_stat.cur_tx_tp, pdvobjpriv->traffic_stat.cur_rx_tp); */ + } + } else if (IS_HARDWARE_TYPE_8812(padapter)) { +#ifdef CONFIG_CONCURRENT_MODE + u8 i; + _adapter *iface; + u8 bassocaed = _FALSE; + struct mlme_ext_priv *mlmeext; + + for (i = 0; i < pdvobjpriv->iface_nums; i++) { + iface = pdvobjpriv->padapters[i]; + mlmeext = &iface->mlmeextpriv; + if (rtw_linked_check(iface) == _TRUE) { + if (mlmeext->cur_wireless_mode >= cur_wireless_mode) + cur_wireless_mode = mlmeext->cur_wireless_mode; + bassocaed = _TRUE; + } + } + if (bassocaed) +#endif + rtw_set_usb_agg_by_mode(padapter, cur_wireless_mode); +#ifdef CONFIG_PLATFORM_NOVATEK_NT72668 + } else { + rtw_set_usb_agg_by_mode(padapter, cur_wireless_mode); +#endif /* CONFIG_PLATFORM_NOVATEK_NT72668 */ + } +#endif +} + +/* bus-agg check for SoftAP mode */ +inline u8 rtw_hal_busagg_qsel_check(_adapter *padapter, u8 pre_qsel, u8 next_qsel) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u8 chk_rst = _SUCCESS; + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE) + return chk_rst; + + /* if((pre_qsel == 0xFF)||(next_qsel== 0xFF)) */ + /* return chk_rst; */ + + if (((pre_qsel == QSLT_HIGH) || ((next_qsel == QSLT_HIGH))) + && (pre_qsel != next_qsel)) { + /* RTW_INFO("### bus-agg break cause of qsel misatch, pre_qsel=0x%02x,next_qsel=0x%02x ###\n", */ + /* pre_qsel,next_qsel); */ + chk_rst = _FAIL; + } + return chk_rst; +} + +/* + * Description: + * dump_TX_FIFO: This is only used to dump TX_FIFO for debug WoW mode offload + * contant. + * + * Input: + * adapter: adapter pointer. + * page_num: The max. page number that user want to dump. + * page_size: page size of each page. eg. 128 bytes, 256 bytes, 512byte. + */ +void dump_TX_FIFO(_adapter *padapter, u8 page_num, u16 page_size) +{ + + int i; + u8 val = 0; + u8 base = 0; + u32 addr = 0; + u32 count = (page_size / 8); + + if (page_num <= 0) { + RTW_INFO("!!%s: incorrect input page_num paramter!\n", __func__); + return; + } + + if (page_size < 128 || page_size > 512) { + RTW_INFO("!!%s: incorrect input page_size paramter!\n", __func__); + return; + } + + RTW_INFO("+%s+\n", __func__); + val = rtw_read8(padapter, 0x106); + rtw_write8(padapter, 0x106, 0x69); + RTW_INFO("0x106: 0x%02x\n", val); + base = rtw_read8(padapter, 0x209); + RTW_INFO("0x209: 0x%02x\n", base); + + addr = ((base)*page_size) / 8; + for (i = 0 ; i < page_num * count ; i += 2) { + rtw_write32(padapter, 0x140, addr + i); + printk(" %08x %08x ", rtw_read32(padapter, 0x144), rtw_read32(padapter, 0x148)); + rtw_write32(padapter, 0x140, addr + i + 1); + printk(" %08x %08x\n", rtw_read32(padapter, 0x144), rtw_read32(padapter, 0x148)); + } +} + +#ifdef CONFIG_GPIO_API +u8 rtw_hal_get_gpio(_adapter *adapter, u8 gpio_num) +{ + u8 value = 0; + u8 direction = 0; + u32 gpio_ctrl_reg_to_set = REG_GPIO_PIN_CTRL + 2; + u8 gpio_num_to_set = gpio_num; + struct pwrctrl_priv *pwrpriv = adapter_to_pwrctl(adapter); + + if (rtw_hal_gpio_func_check(adapter, gpio_num) == _FAIL) + return value; + + rtw_ps_deny(adapter, PS_DENY_IOCTL); + + RTW_INFO("rf_pwrstate=0x%02x\n", pwrpriv->rf_pwrstate); + LeaveAllPowerSaveModeDirect(adapter); + + if (gpio_num > 7) { + gpio_ctrl_reg_to_set = REG_GPIO_PIN_CTRL_2 + 2; + gpio_num_to_set = gpio_num - 8; + } + + /* Read GPIO Direction */ + direction = (rtw_read8(adapter, gpio_ctrl_reg_to_set) & BIT(gpio_num_to_set)) >> gpio_num; + + /* According the direction to read register value */ + if (direction) + value = (rtw_read8(adapter, gpio_ctrl_reg_to_set) & BIT(gpio_num_to_set)) >> gpio_num; + else + value = (rtw_read8(adapter, gpio_ctrl_reg_to_set) & BIT(gpio_num_to_set)) >> gpio_num; + + rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); + RTW_INFO("%s direction=%d value=%d\n", __FUNCTION__, direction, value); + + return value; +} + +int rtw_hal_set_gpio_output_value(_adapter *adapter, u8 gpio_num, bool isHigh) +{ + u8 direction = 0; + u8 res = -1; + u32 gpio_ctrl_reg_to_set = REG_GPIO_PIN_CTRL + 2; + u8 gpio_num_to_set = gpio_num; + + if (rtw_hal_gpio_func_check(adapter, gpio_num) == _FAIL) + return -1; + + rtw_ps_deny(adapter, PS_DENY_IOCTL); + + LeaveAllPowerSaveModeDirect(adapter); + + if (gpio_num > 7) { + gpio_ctrl_reg_to_set = REG_GPIO_PIN_CTRL_2 + 2; + gpio_num_to_set = gpio_num - 8; + } + + /* Read GPIO direction */ + direction = (rtw_read8(adapter, REG_GPIO_PIN_CTRL + 2) & BIT(gpio_num)) >> gpio_num; + + /* If GPIO is output direction, setting value. */ + if (direction) { + if (isHigh) + rtw_write8(adapter, gpio_ctrl_reg_to_set, rtw_read8(adapter, gpio_ctrl_reg_to_set) | BIT(gpio_num_to_set)); + else + rtw_write8(adapter, gpio_ctrl_reg_to_set, rtw_read8(adapter, gpio_ctrl_reg_to_set) & ~BIT(gpio_num_to_set)); + + RTW_INFO("%s Set gpio %x[%d]=%d\n", __FUNCTION__, REG_GPIO_PIN_CTRL + 1, gpio_num, isHigh); + res = 0; + } else { + RTW_INFO("%s The gpio is input,not be set!\n", __FUNCTION__); + res = -1; + } + + rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); + return res; +} + +int rtw_hal_config_gpio(_adapter *adapter, u8 gpio_num, bool isOutput) +{ + u32 gpio_ctrl_reg_to_set = REG_GPIO_PIN_CTRL + 2; + u8 gpio_num_to_set = gpio_num; + + if (rtw_hal_gpio_func_check(adapter, gpio_num) == _FAIL) + return -1; + + RTW_INFO("%s gpio_num =%d direction=%d\n", __FUNCTION__, gpio_num, isOutput); + + rtw_ps_deny(adapter, PS_DENY_IOCTL); + + LeaveAllPowerSaveModeDirect(adapter); + + rtw_hal_gpio_multi_func_reset(adapter, gpio_num); + + if (gpio_num > 7) { + gpio_ctrl_reg_to_set = REG_GPIO_PIN_CTRL_2 + 2; + gpio_num_to_set = gpio_num - 8; + } + + if (isOutput) + rtw_write8(adapter, gpio_ctrl_reg_to_set, rtw_read8(adapter, gpio_ctrl_reg_to_set) | BIT(gpio_num_to_set)); + else + rtw_write8(adapter, gpio_ctrl_reg_to_set, rtw_read8(adapter, gpio_ctrl_reg_to_set) & ~BIT(gpio_num_to_set)); + + rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); + + return 0; +} +int rtw_hal_register_gpio_interrupt(_adapter *adapter, int gpio_num, void(*callback)(u8 level)) +{ + u8 value; + u8 direction; + PHAL_DATA_TYPE phal = GET_HAL_DATA(adapter); + + if (IS_HARDWARE_TYPE_8188E(adapter)) { + if (gpio_num > 7 || gpio_num < 4) { + RTW_PRINT("%s The gpio number does not included 4~7.\n", __FUNCTION__); + return -1; + } + } + + rtw_ps_deny(adapter, PS_DENY_IOCTL); + + LeaveAllPowerSaveModeDirect(adapter); + + /* Read GPIO direction */ + direction = (rtw_read8(adapter, REG_GPIO_PIN_CTRL + 2) & BIT(gpio_num)) >> gpio_num; + if (direction) { + RTW_PRINT("%s Can't register output gpio as interrupt.\n", __FUNCTION__); + return -1; + } + + /* Config GPIO Mode */ + rtw_write8(adapter, REG_GPIO_PIN_CTRL + 3, rtw_read8(adapter, REG_GPIO_PIN_CTRL + 3) | BIT(gpio_num)); + + /* Register GPIO interrupt handler*/ + adapter->gpiointpriv.callback[gpio_num] = callback; + + /* Set GPIO interrupt mode, 0:positive edge, 1:negative edge */ + value = rtw_read8(adapter, REG_GPIO_PIN_CTRL) & BIT(gpio_num); + adapter->gpiointpriv.interrupt_mode = rtw_read8(adapter, REG_HSIMR + 2) ^ value; + rtw_write8(adapter, REG_GPIO_INTM, adapter->gpiointpriv.interrupt_mode); + + /* Enable GPIO interrupt */ + adapter->gpiointpriv.interrupt_enable_mask = rtw_read8(adapter, REG_HSIMR + 2) | BIT(gpio_num); + rtw_write8(adapter, REG_HSIMR + 2, adapter->gpiointpriv.interrupt_enable_mask); + + rtw_hal_update_hisr_hsisr_ind(adapter, 1); + + rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); + + return 0; +} +int rtw_hal_disable_gpio_interrupt(_adapter *adapter, int gpio_num) +{ + u8 value; + u8 direction; + PHAL_DATA_TYPE phal = GET_HAL_DATA(adapter); + + if (IS_HARDWARE_TYPE_8188E(adapter)) { + if (gpio_num > 7 || gpio_num < 4) { + RTW_INFO("%s The gpio number does not included 4~7.\n", __FUNCTION__); + return -1; + } + } + + rtw_ps_deny(adapter, PS_DENY_IOCTL); + + LeaveAllPowerSaveModeDirect(adapter); + + /* Config GPIO Mode */ + rtw_write8(adapter, REG_GPIO_PIN_CTRL + 3, rtw_read8(adapter, REG_GPIO_PIN_CTRL + 3) & ~BIT(gpio_num)); + + /* Unregister GPIO interrupt handler*/ + adapter->gpiointpriv.callback[gpio_num] = NULL; + + /* Reset GPIO interrupt mode, 0:positive edge, 1:negative edge */ + adapter->gpiointpriv.interrupt_mode = rtw_read8(adapter, REG_GPIO_INTM) & ~BIT(gpio_num); + rtw_write8(adapter, REG_GPIO_INTM, 0x00); + + /* Disable GPIO interrupt */ + adapter->gpiointpriv.interrupt_enable_mask = rtw_read8(adapter, REG_HSIMR + 2) & ~BIT(gpio_num); + rtw_write8(adapter, REG_HSIMR + 2, adapter->gpiointpriv.interrupt_enable_mask); + + if (!adapter->gpiointpriv.interrupt_enable_mask) + rtw_hal_update_hisr_hsisr_ind(adapter, 0); + + rtw_ps_deny_cancel(adapter, PS_DENY_IOCTL); + + return 0; +} +#endif + +s8 rtw_hal_ch_sw_iqk_info_search(_adapter *padapter, u8 central_chnl, u8 bw_mode) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + u8 i; + + for (i = 0; i < MAX_IQK_INFO_BACKUP_CHNL_NUM; i++) { + if ((pHalData->iqk_reg_backup[i].central_chnl != 0)) { + if ((pHalData->iqk_reg_backup[i].central_chnl == central_chnl) + && (pHalData->iqk_reg_backup[i].bw_mode == bw_mode)) + return i; + } + } + + return -1; +} + +void rtw_hal_ch_sw_iqk_info_backup(_adapter *padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + s8 res; + u8 i; + + /* If it's an existed record, overwrite it */ + res = rtw_hal_ch_sw_iqk_info_search(padapter, pHalData->current_channel, pHalData->current_channel_bw); + if ((res >= 0) && (res < MAX_IQK_INFO_BACKUP_CHNL_NUM)) { + rtw_hal_set_hwreg(padapter, HW_VAR_CH_SW_IQK_INFO_BACKUP, (u8 *)&(pHalData->iqk_reg_backup[res])); + return; + } + + /* Search for the empty record to use */ + for (i = 0; i < MAX_IQK_INFO_BACKUP_CHNL_NUM; i++) { + if (pHalData->iqk_reg_backup[i].central_chnl == 0) { + rtw_hal_set_hwreg(padapter, HW_VAR_CH_SW_IQK_INFO_BACKUP, (u8 *)&(pHalData->iqk_reg_backup[i])); + return; + } + } + + /* Else, overwrite the oldest record */ + for (i = 1; i < MAX_IQK_INFO_BACKUP_CHNL_NUM; i++) + _rtw_memcpy(&(pHalData->iqk_reg_backup[i - 1]), &(pHalData->iqk_reg_backup[i]), sizeof(struct hal_iqk_reg_backup)); + + rtw_hal_set_hwreg(padapter, HW_VAR_CH_SW_IQK_INFO_BACKUP, (u8 *)&(pHalData->iqk_reg_backup[MAX_IQK_INFO_BACKUP_CHNL_NUM - 1])); +} + +void rtw_hal_ch_sw_iqk_info_restore(_adapter *padapter, u8 ch_sw_use_case) +{ + rtw_hal_set_hwreg(padapter, HW_VAR_CH_SW_IQK_INFO_RESTORE, &ch_sw_use_case); +} + +void rtw_dump_mac_rx_counters(_adapter *padapter, struct dbg_rx_counter *rx_counter) +{ + u32 mac_cck_ok = 0, mac_ofdm_ok = 0, mac_ht_ok = 0, mac_vht_ok = 0; + u32 mac_cck_err = 0, mac_ofdm_err = 0, mac_ht_err = 0, mac_vht_err = 0; + u32 mac_cck_fa = 0, mac_ofdm_fa = 0, mac_ht_fa = 0; + u32 DropPacket = 0; + + if (!rx_counter) { + rtw_warn_on(1); + return; + } + if (IS_HARDWARE_TYPE_JAGUAR(padapter) || IS_HARDWARE_TYPE_JAGUAR2(padapter)) + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT26, 0x0);/*clear bit-26*/ + + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x3); + mac_cck_ok = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x0); + mac_ofdm_ok = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x6); + mac_ht_ok = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ + mac_vht_ok = 0; + if (IS_HARDWARE_TYPE_JAGUAR(padapter) || IS_HARDWARE_TYPE_JAGUAR2(padapter)) { + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x0); + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT26, 0x1); + mac_vht_ok = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0]*/ + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT26, 0x0);/*clear bit-26*/ + } + + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x4); + mac_cck_err = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x1); + mac_ofdm_err = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x7); + mac_ht_err = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ + mac_vht_err = 0; + if (IS_HARDWARE_TYPE_JAGUAR(padapter) || IS_HARDWARE_TYPE_JAGUAR2(padapter)) { + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x1); + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT26, 0x1); + mac_vht_err = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0]*/ + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT26, 0x0);/*clear bit-26*/ + } + + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x5); + mac_cck_fa = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x2); + mac_ofdm_fa = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT28 | BIT29 | BIT30 | BIT31, 0x9); + mac_ht_fa = phy_query_mac_reg(padapter, REG_RXERR_RPT, bMaskLWord);/* [15:0] */ + + /* Mac_DropPacket */ + rtw_write32(padapter, REG_RXERR_RPT, (rtw_read32(padapter, REG_RXERR_RPT) & 0x0FFFFFFF) | Mac_DropPacket); + DropPacket = rtw_read32(padapter, REG_RXERR_RPT) & 0x0000FFFF; + + rx_counter->rx_pkt_ok = mac_cck_ok + mac_ofdm_ok + mac_ht_ok + mac_vht_ok; + rx_counter->rx_pkt_crc_error = mac_cck_err + mac_ofdm_err + mac_ht_err + mac_vht_err; + rx_counter->rx_cck_fa = mac_cck_fa; + rx_counter->rx_ofdm_fa = mac_ofdm_fa; + rx_counter->rx_ht_fa = mac_ht_fa; + rx_counter->rx_pkt_drop = DropPacket; +} +void rtw_reset_mac_rx_counters(_adapter *padapter) +{ + + /* If no packet rx, MaxRx clock be gating ,BIT_DISGCLK bit19 set 1 for fix*/ + if (IS_HARDWARE_TYPE_8703B(padapter) || + IS_HARDWARE_TYPE_8723D(padapter) || + IS_HARDWARE_TYPE_8188F(padapter)) + phy_set_mac_reg(padapter, REG_RCR, BIT19, 0x1); + + /* reset mac counter */ + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT27, 0x1); + phy_set_mac_reg(padapter, REG_RXERR_RPT, BIT27, 0x0); +} + +void rtw_dump_phy_rx_counters(_adapter *padapter, struct dbg_rx_counter *rx_counter) +{ + u32 cckok = 0, cckcrc = 0, ofdmok = 0, ofdmcrc = 0, htok = 0, htcrc = 0, OFDM_FA = 0, CCK_FA = 0, vht_ok = 0, vht_err = 0; + if (!rx_counter) { + rtw_warn_on(1); + return; + } + if (IS_HARDWARE_TYPE_JAGUAR(padapter) || IS_HARDWARE_TYPE_JAGUAR2(padapter)) { + cckok = phy_query_bb_reg(padapter, 0xF04, 0x3FFF); /* [13:0] */ + ofdmok = phy_query_bb_reg(padapter, 0xF14, 0x3FFF); /* [13:0] */ + htok = phy_query_bb_reg(padapter, 0xF10, 0x3FFF); /* [13:0] */ + vht_ok = phy_query_bb_reg(padapter, 0xF0C, 0x3FFF); /* [13:0] */ + cckcrc = phy_query_bb_reg(padapter, 0xF04, 0x3FFF0000); /* [29:16] */ + ofdmcrc = phy_query_bb_reg(padapter, 0xF14, 0x3FFF0000); /* [29:16] */ + htcrc = phy_query_bb_reg(padapter, 0xF10, 0x3FFF0000); /* [29:16] */ + vht_err = phy_query_bb_reg(padapter, 0xF0C, 0x3FFF0000); /* [29:16] */ + CCK_FA = phy_query_bb_reg(padapter, 0xA5C, bMaskLWord); + OFDM_FA = phy_query_bb_reg(padapter, 0xF48, bMaskLWord); + } else { + cckok = phy_query_bb_reg(padapter, 0xF88, bMaskDWord); + ofdmok = phy_query_bb_reg(padapter, 0xF94, bMaskLWord); + htok = phy_query_bb_reg(padapter, 0xF90, bMaskLWord); + vht_ok = 0; + cckcrc = phy_query_bb_reg(padapter, 0xF84, bMaskDWord); + ofdmcrc = phy_query_bb_reg(padapter, 0xF94, bMaskHWord); + htcrc = phy_query_bb_reg(padapter, 0xF90, bMaskHWord); + vht_err = 0; + OFDM_FA = phy_query_bb_reg(padapter, 0xCF0, bMaskLWord) + phy_query_bb_reg(padapter, 0xCF2, bMaskLWord) + + phy_query_bb_reg(padapter, 0xDA2, bMaskLWord) + phy_query_bb_reg(padapter, 0xDA4, bMaskLWord) + + phy_query_bb_reg(padapter, 0xDA6, bMaskLWord) + phy_query_bb_reg(padapter, 0xDA8, bMaskLWord); + + CCK_FA = (rtw_read8(padapter, 0xA5B) << 8) | (rtw_read8(padapter, 0xA5C)); + } + + rx_counter->rx_pkt_ok = cckok + ofdmok + htok + vht_ok; + rx_counter->rx_pkt_crc_error = cckcrc + ofdmcrc + htcrc + vht_err; + rx_counter->rx_ofdm_fa = OFDM_FA; + rx_counter->rx_cck_fa = CCK_FA; + +} + +void rtw_reset_phy_trx_ok_counters(_adapter *padapter) +{ + if (IS_HARDWARE_TYPE_JAGUAR(padapter) || IS_HARDWARE_TYPE_JAGUAR2(padapter)) { + phy_set_bb_reg(padapter, 0xB58, BIT0, 0x1); + phy_set_bb_reg(padapter, 0xB58, BIT0, 0x0); + } +} +void rtw_reset_phy_rx_counters(_adapter *padapter) +{ + /* reset phy counter */ + if (IS_HARDWARE_TYPE_JAGUAR(padapter) || IS_HARDWARE_TYPE_JAGUAR2(padapter)) { + rtw_reset_phy_trx_ok_counters(padapter); + + phy_set_bb_reg(padapter, 0x9A4, BIT17, 0x1);/* reset OFDA FA counter */ + phy_set_bb_reg(padapter, 0x9A4, BIT17, 0x0); + + phy_set_bb_reg(padapter, 0xA2C, BIT15, 0x0);/* reset CCK FA counter */ + phy_set_bb_reg(padapter, 0xA2C, BIT15, 0x1); + } else { + phy_set_bb_reg(padapter, 0xF14, BIT16, 0x1); + rtw_msleep_os(10); + phy_set_bb_reg(padapter, 0xF14, BIT16, 0x0); + + phy_set_bb_reg(padapter, 0xD00, BIT27, 0x1);/* reset OFDA FA counter */ + phy_set_bb_reg(padapter, 0xC0C, BIT31, 0x1);/* reset OFDA FA counter */ + phy_set_bb_reg(padapter, 0xD00, BIT27, 0x0); + phy_set_bb_reg(padapter, 0xC0C, BIT31, 0x0); + + phy_set_bb_reg(padapter, 0xA2C, BIT15, 0x0);/* reset CCK FA counter */ + phy_set_bb_reg(padapter, 0xA2C, BIT15, 0x1); + } +} +#ifdef DBG_RX_COUNTER_DUMP +void rtw_dump_drv_rx_counters(_adapter *padapter, struct dbg_rx_counter *rx_counter) +{ + struct recv_priv *precvpriv = &padapter->recvpriv; + if (!rx_counter) { + rtw_warn_on(1); + return; + } + rx_counter->rx_pkt_ok = padapter->drv_rx_cnt_ok; + rx_counter->rx_pkt_crc_error = padapter->drv_rx_cnt_crcerror; + rx_counter->rx_pkt_drop = precvpriv->rx_drop - padapter->drv_rx_cnt_drop; +} +void rtw_reset_drv_rx_counters(_adapter *padapter) +{ + struct recv_priv *precvpriv = &padapter->recvpriv; + padapter->drv_rx_cnt_ok = 0; + padapter->drv_rx_cnt_crcerror = 0; + padapter->drv_rx_cnt_drop = precvpriv->rx_drop; +} +void rtw_dump_phy_rxcnts_preprocess(_adapter *padapter, u8 rx_cnt_mode) +{ + u8 initialgain; + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter); + + if ((!(padapter->dump_rx_cnt_mode & DUMP_PHY_RX_COUNTER)) && (rx_cnt_mode & DUMP_PHY_RX_COUNTER)) { + rtw_hal_get_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &initialgain, NULL); + RTW_INFO("%s CurIGValue:0x%02x\n", __FUNCTION__, initialgain); + rtw_hal_set_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &initialgain, _FALSE); + /*disable dynamic functions, such as high power, DIG*/ + rtw_phydm_ability_backup(padapter); + rtw_phydm_func_clr(padapter, (ODM_BB_DIG | ODM_BB_FA_CNT)); + } else if ((padapter->dump_rx_cnt_mode & DUMP_PHY_RX_COUNTER) && (!(rx_cnt_mode & DUMP_PHY_RX_COUNTER))) { + /* turn on phy-dynamic functions */ + rtw_phydm_ability_restore(padapter); + initialgain = 0xff; /* restore RX GAIN */ + rtw_hal_set_odm_var(padapter, HAL_ODM_INITIAL_GAIN, &initialgain, _FALSE); + + } +} + +void rtw_dump_rx_counters(_adapter *padapter) +{ + struct dbg_rx_counter rx_counter; + + if (padapter->dump_rx_cnt_mode & DUMP_DRV_RX_COUNTER) { + _rtw_memset(&rx_counter, 0, sizeof(struct dbg_rx_counter)); + rtw_dump_drv_rx_counters(padapter, &rx_counter); + RTW_INFO("Drv Received packet OK:%d CRC error:%d Drop Packets: %d\n", + rx_counter.rx_pkt_ok, rx_counter.rx_pkt_crc_error, rx_counter.rx_pkt_drop); + rtw_reset_drv_rx_counters(padapter); + } + + if (padapter->dump_rx_cnt_mode & DUMP_MAC_RX_COUNTER) { + _rtw_memset(&rx_counter, 0, sizeof(struct dbg_rx_counter)); + rtw_dump_mac_rx_counters(padapter, &rx_counter); + RTW_INFO("Mac Received packet OK:%d CRC error:%d FA Counter: %d Drop Packets: %d\n", + rx_counter.rx_pkt_ok, rx_counter.rx_pkt_crc_error, + rx_counter.rx_cck_fa + rx_counter.rx_ofdm_fa + rx_counter.rx_ht_fa, + rx_counter.rx_pkt_drop); + rtw_reset_mac_rx_counters(padapter); + } + + if (padapter->dump_rx_cnt_mode & DUMP_PHY_RX_COUNTER) { + _rtw_memset(&rx_counter, 0, sizeof(struct dbg_rx_counter)); + rtw_dump_phy_rx_counters(padapter, &rx_counter); + /* RTW_INFO("%s: OFDM_FA =%d\n", __FUNCTION__, rx_counter.rx_ofdm_fa); */ + /* RTW_INFO("%s: CCK_FA =%d\n", __FUNCTION__, rx_counter.rx_cck_fa); */ + RTW_INFO("Phy Received packet OK:%d CRC error:%d FA Counter: %d\n", rx_counter.rx_pkt_ok, rx_counter.rx_pkt_crc_error, + rx_counter.rx_ofdm_fa + rx_counter.rx_cck_fa); + rtw_reset_phy_rx_counters(padapter); + } +} +#endif +void rtw_get_noise(_adapter *padapter) +{ +#if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR) + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct noise_info info; + if (rtw_linked_check(padapter)) { + info.bPauseDIG = _TRUE; + info.IGIValue = 0x1e; + info.max_time = 100;/* ms */ + info.chan = pmlmeext->cur_channel ;/* rtw_get_oper_ch(padapter); */ + rtw_ps_deny(padapter, PS_DENY_IOCTL); + LeaveAllPowerSaveModeDirect(padapter); + + rtw_hal_set_odm_var(padapter, HAL_ODM_NOISE_MONITOR, &info, _FALSE); + /* odm_inband_noise_monitor(podmpriv,_TRUE,0x20,100); */ + rtw_ps_deny_cancel(padapter, PS_DENY_IOCTL); + rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR, &(info.chan), &(padapter->recvpriv.noise)); +#ifdef DBG_NOISE_MONITOR + RTW_INFO("chan:%d,noise_level:%d\n", info.chan, padapter->recvpriv.noise); +#endif + } +#endif + +} +u8 rtw_get_current_tx_sgi(_adapter *padapter, u8 macid) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + struct _rate_adaptive_table_ *pRA_Table = &pDM_Odm->dm_ra_table; + u8 curr_tx_sgi = 0; + +#if defined(CONFIG_RTL8188E) + curr_tx_sgi = odm_ra_get_decision_rate_8188e(pDM_Odm, macid); +#else + curr_tx_sgi = ((pRA_Table->link_tx_rate[macid]) & 0x80) >> 7; +#endif + + return curr_tx_sgi; + +} +u8 rtw_get_current_tx_rate(_adapter *padapter, u8 macid) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + struct _rate_adaptive_table_ *pRA_Table = &pDM_Odm->dm_ra_table; + u8 rate_id = 0; + +#if (RATE_ADAPTIVE_SUPPORT == 1) + rate_id = odm_ra_get_decision_rate_8188e(pDM_Odm, macid); +#else + rate_id = (pRA_Table->link_tx_rate[macid]) & 0x7f; +#endif + + return rate_id; + +} + +void update_IOT_info(_adapter *padapter) +{ + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + + switch (pmlmeinfo->assoc_AP_vendor) { + case HT_IOT_PEER_MARVELL: + pmlmeinfo->turboMode_cts2self = 1; + pmlmeinfo->turboMode_rtsen = 0; + break; + + case HT_IOT_PEER_RALINK: + pmlmeinfo->turboMode_cts2self = 0; + pmlmeinfo->turboMode_rtsen = 1; + /* disable high power */ + rtw_phydm_func_clr(padapter, ODM_BB_DYNAMIC_TXPWR); + break; + case HT_IOT_PEER_REALTEK: + /* rtw_write16(padapter, 0x4cc, 0xffff); */ + /* rtw_write16(padapter, 0x546, 0x01c0); */ + /* disable high power */ + rtw_phydm_func_clr(padapter, ODM_BB_DYNAMIC_TXPWR); + break; + default: + pmlmeinfo->turboMode_cts2self = 0; + pmlmeinfo->turboMode_rtsen = 1; + break; + } + +} +#ifdef CONFIG_AUTO_CHNL_SEL_NHM +void rtw_acs_start(_adapter *padapter, bool bStart) +{ + if (_TRUE == bStart) { + ACS_OP acs_op = ACS_INIT; + + rtw_hal_set_odm_var(padapter, HAL_ODM_AUTO_CHNL_SEL, &acs_op, _TRUE); + rtw_set_acs_channel(padapter, 0); + SET_ACS_STATE(padapter, ACS_ENABLE); + } else { + SET_ACS_STATE(padapter, ACS_DISABLE); +#ifdef DBG_AUTO_CHNL_SEL_NHM + if (1) { + u8 best_24g_ch = 0; + u8 best_5g_ch = 0; + + rtw_hal_get_odm_var(padapter, HAL_ODM_AUTO_CHNL_SEL, &(best_24g_ch), &(best_5g_ch)); + RTW_INFO("[ACS-"ADPT_FMT"] Best 2.4G CH:%u\n", ADPT_ARG(padapter), best_24g_ch); + RTW_INFO("[ACS-"ADPT_FMT"] Best 5G CH:%u\n", ADPT_ARG(padapter), best_5g_ch); + } +#endif + } +} +#endif + +/* TODO: merge with phydm, see odm_SetCrystalCap() */ +void hal_set_crystal_cap(_adapter *adapter, u8 crystal_cap) +{ + crystal_cap = crystal_cap & 0x3F; + + switch (rtw_get_chip_type(adapter)) { +#if defined(CONFIG_RTL8188E) || defined(CONFIG_RTL8188F) + case RTL8188E: + case RTL8188F: + /* write 0x24[16:11] = 0x24[22:17] = CrystalCap */ + phy_set_bb_reg(adapter, REG_AFE_XTAL_CTRL, 0x007FF800, (crystal_cap | (crystal_cap << 6))); + break; +#endif +#if defined(CONFIG_RTL8812A) + case RTL8812: + /* write 0x2C[30:25] = 0x2C[24:19] = CrystalCap */ + phy_set_bb_reg(adapter, REG_MAC_PHY_CTRL, 0x7FF80000, (crystal_cap | (crystal_cap << 6))); + break; +#endif +#if defined(CONFIG_RTL8723B) || defined(CONFIG_RTL8703B) || \ + defined(CONFIG_RTL8723D) || defined(CONFIG_RTL8821A) || \ + defined(CONFIG_RTL8192E) + case RTL8723B: + case RTL8703B: + case RTL8723D: + case RTL8821: + case RTL8192E: + /* write 0x2C[23:18] = 0x2C[17:12] = CrystalCap */ + phy_set_bb_reg(adapter, REG_MAC_PHY_CTRL, 0x00FFF000, (crystal_cap | (crystal_cap << 6))); + break; +#endif +#if defined(CONFIG_RTL8814A) + case RTL8814A: + /* write 0x2C[26:21] = 0x2C[20:15] = CrystalCap*/ + phy_set_bb_reg(adapter, REG_MAC_PHY_CTRL, 0x07FF8000, (crystal_cap | (crystal_cap << 6))); + break; +#endif +#if defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) + + case RTL8822B: + case RTL8821C: + /* write 0x28[6:1] = 0x24[30:25] = CrystalCap */ + crystal_cap = crystal_cap & 0x3F; + phy_set_bb_reg(adapter, REG_AFE_XTAL_CTRL, 0x7E000000, crystal_cap); + phy_set_bb_reg(adapter, REG_AFE_PLL_CTRL, 0x7E, crystal_cap); + break; +#endif + default: + rtw_warn_on(1); + } +} + +int hal_spec_init(_adapter *adapter) +{ + u8 interface_type = 0; + int ret = _SUCCESS; + + interface_type = rtw_get_intf_type(adapter); + + switch (rtw_get_chip_type(adapter)) { +#ifdef CONFIG_RTL8723B + case RTL8723B: + init_hal_spec_8723b(adapter); + break; +#endif +#ifdef CONFIG_RTL8703B + case RTL8703B: + init_hal_spec_8703b(adapter); + break; +#endif +#ifdef CONFIG_RTL8723D + case RTL8723D: + init_hal_spec_8723d(adapter); + break; +#endif +#ifdef CONFIG_RTL8188E + case RTL8188E: + init_hal_spec_8188e(adapter); + break; +#endif +#ifdef CONFIG_RTL8188F + case RTL8188F: + init_hal_spec_8188f(adapter); + break; +#endif +#ifdef CONFIG_RTL8812A + case RTL8812: + init_hal_spec_8812a(adapter); + break; +#endif +#ifdef CONFIG_RTL8821A + case RTL8821: + init_hal_spec_8821a(adapter); + break; +#endif +#ifdef CONFIG_RTL8192E + case RTL8192E: + init_hal_spec_8192e(adapter); + break; +#endif +#ifdef CONFIG_RTL8814A + case RTL8814A: + init_hal_spec_8814a(adapter); + break; +#endif +#ifdef CONFIG_RTL8822B + case RTL8822B: + rtl8822b_init_hal_spec(adapter); + break; +#endif +#ifdef CONFIG_RTL8821C + case RTL8821C: + init_hal_spec_rtl8821c(adapter); + break; +#endif + default: + RTW_ERR("%s: unknown chip_type:%u\n" + , __func__, rtw_get_chip_type(adapter)); + ret = _FAIL; + break; + } + + return ret; +} + +static const char *const _band_cap_str[] = { + /* BIT0 */"2G", + /* BIT1 */"5G", +}; + +static const char *const _bw_cap_str[] = { + /* BIT0 */"5M", + /* BIT1 */"10M", + /* BIT2 */"20M", + /* BIT3 */"40M", + /* BIT4 */"80M", + /* BIT5 */"160M", + /* BIT6 */"80_80M", +}; + +static const char *const _proto_cap_str[] = { + /* BIT0 */"b", + /* BIT1 */"g", + /* BIT2 */"n", + /* BIT3 */"ac", +}; + +static const char *const _wl_func_str[] = { + /* BIT0 */"P2P", + /* BIT1 */"MIRACAST", + /* BIT2 */"TDLS", + /* BIT3 */"FTM", +}; + +void dump_hal_spec(void *sel, _adapter *adapter) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + int i; + + RTW_PRINT_SEL(sel, "macid_num:%u\n", hal_spec->macid_num); + RTW_PRINT_SEL(sel, "sec_cap:0x%02x\n", hal_spec->sec_cap); + RTW_PRINT_SEL(sel, "sec_cam_ent_num:%u\n", hal_spec->sec_cam_ent_num); + RTW_PRINT_SEL(sel, "rfpath_num_2g:%u\n", hal_spec->rfpath_num_2g); + RTW_PRINT_SEL(sel, "rfpath_num_5g:%u\n", hal_spec->rfpath_num_5g); + RTW_PRINT_SEL(sel, "max_tx_cnt:%u\n", hal_spec->max_tx_cnt); + RTW_PRINT_SEL(sel, "tx_nss_num:%u\n", hal_spec->tx_nss_num); + RTW_PRINT_SEL(sel, "rx_nss_num:%u\n", hal_spec->rx_nss_num); + + RTW_PRINT_SEL(sel, "band_cap:"); + for (i = 0; i < BAND_CAP_BIT_NUM; i++) { + if (((hal_spec->band_cap) >> i) & BIT0 && _band_cap_str[i]) + _RTW_PRINT_SEL(sel, "%s ", _band_cap_str[i]); + } + _RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "bw_cap:"); + for (i = 0; i < BW_CAP_BIT_NUM; i++) { + if (((hal_spec->bw_cap) >> i) & BIT0 && _bw_cap_str[i]) + _RTW_PRINT_SEL(sel, "%s ", _bw_cap_str[i]); + } + _RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "proto_cap:"); + for (i = 0; i < PROTO_CAP_BIT_NUM; i++) { + if (((hal_spec->proto_cap) >> i) & BIT0 && _proto_cap_str[i]) + _RTW_PRINT_SEL(sel, "%s ", _proto_cap_str[i]); + } + _RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "wl_func:"); + for (i = 0; i < WL_FUNC_BIT_NUM; i++) { + if (((hal_spec->wl_func) >> i) & BIT0 && _wl_func_str[i]) + _RTW_PRINT_SEL(sel, "%s ", _wl_func_str[i]); + } + _RTW_PRINT_SEL(sel, "\n"); +} + +inline bool hal_chk_band_cap(_adapter *adapter, u8 cap) +{ + return GET_HAL_SPEC(adapter)->band_cap & cap; +} + +inline bool hal_chk_bw_cap(_adapter *adapter, u8 cap) +{ + return GET_HAL_SPEC(adapter)->bw_cap & cap; +} + +inline bool hal_chk_proto_cap(_adapter *adapter, u8 cap) +{ + return GET_HAL_SPEC(adapter)->proto_cap & cap; +} + +inline bool hal_chk_wl_func(_adapter *adapter, u8 func) +{ + return GET_HAL_SPEC(adapter)->wl_func & func; +} + +inline bool hal_is_band_support(_adapter *adapter, u8 band) +{ + return GET_HAL_SPEC(adapter)->band_cap & band_to_band_cap(band); +} + +inline bool hal_is_bw_support(_adapter *adapter, u8 bw) +{ + return GET_HAL_SPEC(adapter)->bw_cap & ch_width_to_bw_cap(bw); +} + +inline bool hal_is_wireless_mode_support(_adapter *adapter, u8 mode) +{ + u8 proto_cap = GET_HAL_SPEC(adapter)->proto_cap; + + if (mode == WIRELESS_11B) + if ((proto_cap & PROTO_CAP_11B) && hal_chk_band_cap(adapter, BAND_CAP_2G)) + return 1; + + if (mode == WIRELESS_11G) + if ((proto_cap & PROTO_CAP_11G) && hal_chk_band_cap(adapter, BAND_CAP_2G)) + return 1; + + if (mode == WIRELESS_11A) + if ((proto_cap & PROTO_CAP_11G) && hal_chk_band_cap(adapter, BAND_CAP_5G)) + return 1; + + if (mode == WIRELESS_11_24N) + if ((proto_cap & PROTO_CAP_11N) && hal_chk_band_cap(adapter, BAND_CAP_2G)) + return 1; + + if (mode == WIRELESS_11_5N) + if ((proto_cap & PROTO_CAP_11N) && hal_chk_band_cap(adapter, BAND_CAP_5G)) + return 1; + + if (mode == WIRELESS_11AC) + if ((proto_cap & PROTO_CAP_11AC) && hal_chk_band_cap(adapter, BAND_CAP_5G)) + return 1; + + return 0; +} + +/* +* hal_largest_bw - starting from in_bw, get largest bw supported by HAL +* @adapter: +* @in_bw: starting bw, value of CHANNEL_WIDTH +* +* Returns: value of CHANNEL_WIDTH +*/ +u8 hal_largest_bw(_adapter *adapter, u8 in_bw) +{ + for (; in_bw > CHANNEL_WIDTH_20; in_bw--) { + if (hal_is_bw_support(adapter, in_bw)) + break; + } + + if (!hal_is_bw_support(adapter, in_bw)) + rtw_warn_on(1); + + return in_bw; +} + +void rtw_hal_correct_tsf(_adapter *padapter, u8 hw_port, u64 tsf) +{ + if (hw_port == HW_PORT0) { + /*disable related TSF function*/ + rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL) & (~EN_BCN_FUNCTION)); + + rtw_write32(padapter, REG_TSFTR, tsf); + rtw_write32(padapter, REG_TSFTR + 4, tsf >> 32); + + /*enable related TSF function*/ + rtw_write8(padapter, REG_BCN_CTRL, rtw_read8(padapter, REG_BCN_CTRL) | EN_BCN_FUNCTION); + } else if (hw_port == HW_PORT1) { + /*disable related TSF function*/ + rtw_write8(padapter, REG_BCN_CTRL_1, rtw_read8(padapter, REG_BCN_CTRL_1) & (~EN_BCN_FUNCTION)); + + rtw_write32(padapter, REG_TSFTR1, tsf); + rtw_write32(padapter, REG_TSFTR1 + 4, tsf >> 32); + + /*enable related TSF function*/ + rtw_write8(padapter, REG_BCN_CTRL_1, rtw_read8(padapter, REG_BCN_CTRL_1) | EN_BCN_FUNCTION); + } else + RTW_INFO("%s-[WARN] "ADPT_FMT" invalid hw_port:%d\n", __func__, ADPT_ARG(padapter), hw_port); +} + +void ResumeTxBeacon(_adapter *padapter) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + + + /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ + /* which should be read from register to a global variable. */ + + + pHalData->RegFwHwTxQCtrl |= BIT(6); + rtw_write8(padapter, REG_FWHW_TXQ_CTRL + 2, pHalData->RegFwHwTxQCtrl); + /*TBTT hold time :4ms 0x540[19:8]*/ + rtw_write8(padapter, REG_TBTT_PROHIBIT + 1, + TBTT_PROBIHIT_HOLD_TIME & 0xFF); + rtw_write8(padapter, REG_TBTT_PROHIBIT + 2, + (rtw_read8(padapter, REG_TBTT_PROHIBIT + 2) & 0xF0) | (TBTT_PROBIHIT_HOLD_TIME >> 8)); +} + +void StopTxBeacon(_adapter *padapter) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + + + /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ + /* which should be read from register to a global variable. */ + + + pHalData->RegFwHwTxQCtrl &= ~BIT(6); + rtw_write8(padapter, REG_FWHW_TXQ_CTRL + 2, pHalData->RegFwHwTxQCtrl); + rtw_write8(padapter, REG_TBTT_PROHIBIT + 1, 0x64); + rtw_write8(padapter, REG_TBTT_PROHIBIT + 2, + (rtw_read8(padapter, REG_TBTT_PROHIBIT + 2) & 0xF0)); + + /*CheckFwRsvdPageContent(padapter);*/ /* 2010.06.23. Added by tynli. */ +} + +#ifdef CONFIG_MI_WITH_MBSSID_CAM /*HW port0 - MBSS*/ +void hw_var_set_opmode_mbid(_adapter *Adapter, u8 mode) +{ + RTW_INFO("%s()-"ADPT_FMT" mode = %d\n", __func__, ADPT_ARG(Adapter), mode); + + rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR) & (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN))); + + /* disable Port0 TSF update*/ + rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) | DIS_TSF_UDT); + + /* set net_type */ + Set_MSR(Adapter, mode); + + if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) { + if (!rtw_mi_check_status(Adapter, MI_AP_MODE)) + StopTxBeacon(Adapter); + + rtw_write8(Adapter, REG_BCN_CTRL, DIS_TSF_UDT | EN_BCN_FUNCTION | DIS_ATIM);/*disable atim wnd*/ + } else if (mode == _HW_STATE_ADHOC_) { + ResumeTxBeacon(Adapter); + rtw_write8(Adapter, REG_BCN_CTRL, DIS_TSF_UDT | EN_BCN_FUNCTION | DIS_BCNQ_SUB); + + } else if (mode == _HW_STATE_AP_) { + ResumeTxBeacon(Adapter); + + rtw_write8(Adapter, REG_BCN_CTRL, DIS_TSF_UDT | DIS_BCNQ_SUB); + + /*enable to rx data frame*/ + rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); + + /*Beacon Control related register for first time*/ + rtw_write8(Adapter, REG_BCNDMATIM, 0x02); /* 2ms */ + + /*rtw_write8(Adapter, REG_BCN_MAX_ERR, 0xFF);*/ + rtw_write8(Adapter, REG_ATIMWND, 0x0a); /* 10ms */ + rtw_write16(Adapter, REG_BCNTCFG, 0x00); + rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0xff04); + rtw_write16(Adapter, REG_TSFTR_SYN_OFFSET, 0x7fff);/* +32767 (~32ms) */ + + /*reset TSF*/ + rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(0)); + + /*enable BCN0 Function for if1*/ + /*don't enable update TSF0 for if1 (due to TSF update when beacon,probe rsp are received)*/ + rtw_write8(Adapter, REG_BCN_CTRL, (DIS_TSF_UDT | EN_BCN_FUNCTION | EN_TXBCN_RPT | DIS_BCNQ_SUB)); + + if (IS_HARDWARE_TYPE_8821(Adapter) || IS_HARDWARE_TYPE_8192E(Adapter))/* select BCN on port 0 for DualBeacon*/ + rtw_write8(Adapter, REG_CCK_CHECK, rtw_read8(Adapter, REG_CCK_CHECK) & (~BIT_BCN_PORT_SEL)); + + } + +} +#endif + +#ifdef CONFIG_ANTENNA_DIVERSITY +u8 rtw_hal_antdiv_before_linked(_adapter *padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + u8 cur_ant, change_ant; + + if (!pHalData->AntDivCfg) + return _FALSE; + + if (pHalData->sw_antdiv_bl_state == 0) { + pHalData->sw_antdiv_bl_state = 1; + + rtw_hal_get_odm_var(padapter, HAL_ODM_ANTDIV_SELECT, &cur_ant, NULL); + change_ant = (cur_ant == MAIN_ANT) ? AUX_ANT : MAIN_ANT; + + return rtw_antenna_select_cmd(padapter, change_ant, _FALSE); + } + + pHalData->sw_antdiv_bl_state = 0; + return _FALSE; +} + +void rtw_hal_antdiv_rssi_compared(_adapter *padapter, WLAN_BSSID_EX *dst, WLAN_BSSID_EX *src) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + if (pHalData->AntDivCfg) { + /*RTW_INFO("update_network=> org-RSSI(%d), new-RSSI(%d)\n", dst->Rssi, src->Rssi);*/ + /*select optimum_antenna for before linked =>For antenna diversity*/ + if (dst->Rssi >= src->Rssi) {/*keep org parameter*/ + src->Rssi = dst->Rssi; + src->PhyInfo.Optimum_antenna = dst->PhyInfo.Optimum_antenna; + } + } +} +#endif + +#ifdef CONFIG_PHY_CAPABILITY_QUERY +void rtw_dump_phy_cap_by_phydmapi(void *sel, _adapter *adapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(adapter); + struct phy_spec_t *phy_spec = &pHalData->phy_spec; + + RTW_PRINT_SEL(sel, "[PHY SPEC] TRx Capability : 0x%08x\n", phy_spec->trx_cap); + RTW_PRINT_SEL(sel, "[PHY SPEC] Tx Stream Num Index : %d\n", (phy_spec->trx_cap >> 24) & 0xFF); /*Tx Stream Num Index [31:24]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] Rx Stream Num Index : %d\n", (phy_spec->trx_cap >> 16) & 0xFF); /*Rx Stream Num Index [23:16]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] Tx Path Num Index : %d\n", (phy_spec->trx_cap >> 8) & 0xFF);/*Tx Path Num Index [15:8]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] Rx Path Num Index : %d\n\n", (phy_spec->trx_cap & 0xFF));/*Rx Path Num Index [7:0]*/ + + RTW_PRINT_SEL(sel, "[PHY SPEC] STBC Capability : 0x%08x\n", phy_spec->stbc_cap); + RTW_PRINT_SEL(sel, "[PHY SPEC] VHT STBC Tx : %s\n", ((phy_spec->stbc_cap >> 24) & 0xFF) ? "Supported" : "N/A"); /*VHT STBC Tx [31:24]*/ + /*VHT STBC Rx [23:16] + 0 = not support + 1 = support for 1 spatial stream + 2 = support for 1 or 2 spatial streams + 3 = support for 1 or 2 or 3 spatial streams + 4 = support for 1 or 2 or 3 or 4 spatial streams*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] VHT STBC Rx :%d\n", ((phy_spec->stbc_cap >> 16) & 0xFF)); + RTW_PRINT_SEL(sel, "[PHY SPEC] HT STBC Tx : %s\n", ((phy_spec->stbc_cap >> 8) & 0xFF) ? "Supported" : "N/A"); /*HT STBC Tx [15:8]*/ + /*HT STBC Rx [7:0] + 0 = not support + 1 = support for 1 spatial stream + 2 = support for 1 or 2 spatial streams + 3 = support for 1 or 2 or 3 spatial streams*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] HT STBC Rx : %d\n\n", (phy_spec->stbc_cap & 0xFF)); + + RTW_PRINT_SEL(sel, "[PHY SPEC] LDPC Capability : 0x%08x\n", phy_spec->ldpc_cap); + RTW_PRINT_SEL(sel, "[PHY SPEC] VHT LDPC Tx : %s\n", ((phy_spec->ldpc_cap >> 24) & 0xFF) ? "Supported" : "N/A"); /*VHT LDPC Tx [31:24]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] VHT LDPC Rx : %s\n", ((phy_spec->ldpc_cap >> 16) & 0xFF) ? "Supported" : "N/A"); /*VHT LDPC Rx [23:16]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] HT LDPC Tx : %s\n", ((phy_spec->ldpc_cap >> 8) & 0xFF) ? "Supported" : "N/A"); /*HT LDPC Tx [15:8]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] HT LDPC Rx : %s\n\n", (phy_spec->ldpc_cap & 0xFF) ? "Supported" : "N/A"); /*HT LDPC Rx [7:0]*/ + #ifdef CONFIG_BEAMFORMING + RTW_PRINT_SEL(sel, "[PHY SPEC] TxBF Capability : 0x%08x\n", phy_spec->txbf_cap); + RTW_PRINT_SEL(sel, "[PHY SPEC] VHT MU Bfer : %s\n", ((phy_spec->txbf_cap >> 28) & 0xF) ? "Supported" : "N/A"); /*VHT MU Bfer [31:28]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] VHT MU Bfee : %s\n", ((phy_spec->txbf_cap >> 24) & 0xF) ? "Supported" : "N/A"); /*VHT MU Bfee [27:24]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] VHT SU Bfer : %s\n", ((phy_spec->txbf_cap >> 20) & 0xF) ? "Supported" : "N/A"); /*VHT SU Bfer [23:20]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] VHT SU Bfee : %s\n", ((phy_spec->txbf_cap >> 16) & 0xF) ? "Supported" : "N/A"); /*VHT SU Bfee [19:16]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] HT Bfer : %s\n", ((phy_spec->txbf_cap >> 4) & 0xF) ? "Supported" : "N/A"); /*HT Bfer [7:4]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] HT Bfee : %s\n\n", (phy_spec->txbf_cap & 0xF) ? "Supported" : "N/A"); /*HT Bfee [3:0]*/ + + RTW_PRINT_SEL(sel, "[PHY SPEC] TxBF parameter : 0x%08x\n", phy_spec->txbf_param); + RTW_PRINT_SEL(sel, "[PHY SPEC] VHT Sounding Dim : %d\n", (phy_spec->txbf_param >> 24) & 0xFF); /*VHT Sounding Dim [31:24]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] VHT Steering Ant : %d\n", (phy_spec->txbf_param >> 16) & 0xFF); /*VHT Steering Ant [23:16]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] HT Sounding Dim : %d\n", (phy_spec->txbf_param >> 8) & 0xFF); /*HT Sounding Dim [15:8]*/ + RTW_PRINT_SEL(sel, "[PHY SPEC] HT Steering Ant : %d\n", phy_spec->txbf_param & 0xFF); /*HT Steering Ant [7:0]*/ + #endif +} +#else +void rtw_dump_phy_cap_by_hal(void *sel, _adapter *adapter) +{ + u8 phy_cap = _FALSE; + + /* STBC */ + rtw_hal_get_def_var(adapter, HAL_DEF_TX_STBC, (u8 *)&phy_cap); + RTW_PRINT_SEL(sel, "[HAL] STBC Tx : %s\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); + + phy_cap = _FALSE; + rtw_hal_get_def_var(adapter, HAL_DEF_RX_STBC, (u8 *)&phy_cap); + RTW_PRINT_SEL(sel, "[HAL] STBC Rx : %s\n\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); + + /* LDPC support */ + phy_cap = _FALSE; + rtw_hal_get_def_var(adapter, HAL_DEF_TX_LDPC, (u8 *)&phy_cap); + RTW_PRINT_SEL(sel, "[HAL] LDPC Tx : %s\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); + + phy_cap = _FALSE; + rtw_hal_get_def_var(adapter, HAL_DEF_RX_LDPC, (u8 *)&phy_cap); + RTW_PRINT_SEL(sel, "[HAL] LDPC Rx : %s\n\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); + + #ifdef CONFIG_BEAMFORMING + phy_cap = _FALSE; + rtw_hal_get_def_var(adapter, HAL_DEF_EXPLICIT_BEAMFORMER, (u8 *)&phy_cap); + RTW_PRINT_SEL(sel, "[HAL] Beamformer: %s\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); + + phy_cap = _FALSE; + rtw_hal_get_def_var(adapter, HAL_DEF_EXPLICIT_BEAMFORMEE, (u8 *)&phy_cap); + RTW_PRINT_SEL(sel, "[HAL] Beamformee: %s\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); + + phy_cap = _FALSE; + rtw_hal_get_def_var(adapter, HAL_DEF_VHT_MU_BEAMFORMER, &phy_cap); + RTW_PRINT_SEL(sel, "[HAL] VHT MU Beamformer: %s\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); + + phy_cap = _FALSE; + rtw_hal_get_def_var(adapter, HAL_DEF_VHT_MU_BEAMFORMEE, &phy_cap); + RTW_PRINT_SEL(sel, "[HAL] VHT MU Beamformee: %s\n", (_TRUE == phy_cap) ? "Supported" : "N/A"); + #endif +} +#endif +void rtw_dump_phy_cap(void *sel, _adapter *adapter) +{ + RTW_PRINT_SEL(sel, "\n ======== PHY Capability ========\n"); +#ifdef CONFIG_PHY_CAPABILITY_QUERY + rtw_dump_phy_cap_by_phydmapi(sel, adapter); +#else + rtw_dump_phy_cap_by_hal(sel, adapter); +#endif +} + diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_com_c2h.h b/linux-bsp/drivers/rtl8188eus/hal/hal_com_c2h.h new file mode 100644 index 0000000..6b7e987 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_com_c2h.h @@ -0,0 +1,119 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __COMMON_C2H_H__ +#define __COMMON_C2H_H__ + +#define C2H_TYPE_REG 0 +#define C2H_TYPE_PKT 1 + +/* +* C2H event format: +* Fields TRIGGER PAYLOAD SEQ PLEN ID +* BITS [127:120] [119:16] [15:8] [7:4] [3:0] +*/ +#define C2H_ID(_c2h) LE_BITS_TO_1BYTE(((u8*)(_c2h)), 0, 4) +#define C2H_PLEN(_c2h) LE_BITS_TO_1BYTE(((u8*)(_c2h)), 4, 4) +#define C2H_SEQ(_c2h) LE_BITS_TO_1BYTE(((u8*)(_c2h)) + 1, 0, 8) +#define C2H_PAYLOAD(_c2h) (((u8*)(_c2h)) + 2) + +#define SET_C2H_ID(_c2h, _val) SET_BITS_TO_LE_1BYTE(((u8*)(_c2h)), 0, 4, _val) +#define SET_C2H_PLEN(_c2h, _val) SET_BITS_TO_LE_1BYTE(((u8*)(_c2h)), 4, 4, _val) +#define SET_C2H_SEQ(_c2h, _val) SET_BITS_TO_LE_1BYTE(((u8*)(_c2h)) + 1 , 0, 8, _val) + +/* +* C2H event format: +* Fields TRIGGER PLEN PAYLOAD SEQ ID +* BITS [127:120] [119:112] [111:16] [15:8] [7:0] +*/ +#define C2H_ID_88XX(_c2h) LE_BITS_TO_1BYTE(((u8*)(_c2h)), 0, 8) +#define C2H_SEQ_88XX(_c2h) LE_BITS_TO_1BYTE(((u8*)(_c2h)) + 1, 0, 8) +#define C2H_PAYLOAD_88XX(_c2h) (((u8*)(_c2h)) + 2) +#define C2H_PLEN_88XX(_c2h) LE_BITS_TO_1BYTE(((u8*)(_c2h)) + 14, 0, 8) +#define C2H_TRIGGER_88XX(_c2h) LE_BITS_TO_1BYTE(((u8*)(_c2h)) + 15, 0, 8) + +#define SET_C2H_ID_88XX(_c2h, _val) SET_BITS_TO_LE_1BYTE(((u8*)(_c2h)), 0, 8, _val) +#define SET_C2H_SEQ_88XX(_c2h, _val) SET_BITS_TO_LE_1BYTE(((u8*)(_c2h)) + 1, 0, 8, _val) +#define SET_C2H_PLEN_88XX(_c2h, _val) SET_BITS_TO_LE_1BYTE(((u8*)(_c2h)) + 14, 0, 8, _val) + +typedef enum _C2H_EVT { + C2H_DBG = 0x00, + C2H_LB = 0x01, + C2H_TXBF = 0x02, + C2H_CCX_TX_RPT = 0x03, + C2H_AP_REQ_TXRPT = 0x04, + C2H_FW_SCAN_COMPLETE = 0x7, + C2H_BT_INFO = 0x09, + C2H_BT_MP_INFO = 0x0B, + C2H_RA_RPT = 0x0C, + C2H_SPC_STAT = 0x0D, + C2H_RA_PARA_RPT = 0x0E, + C2H_FW_CHNL_SWITCH_COMPLETE = 0x10, + C2H_IQK_FINISH = 0x11, + C2H_MAILBOX_STATUS = 0x15, + C2H_P2P_RPORT = 0x16, + C2H_MCC = 0x17, + C2H_MAC_HIDDEN_RPT = 0x19, + C2H_MAC_HIDDEN_RPT_2 = 0x1A, + C2H_BCN_EARLY_RPT = 0x1E, + C2H_DEFEATURE_DBG = 0x22, + C2H_CUSTOMER_STR_RPT = 0x24, + C2H_CUSTOMER_STR_RPT_2 = 0x25, + C2H_DEFEATURE_RSVD = 0xFD, + C2H_EXTEND = 0xff, +} C2H_EVT; + +typedef enum _EXTEND_C2H_EVT { + EXTEND_C2H_DBG_PRINT = 0 +} EXTEND_C2H_EVT; + +#define C2H_REG_LEN 16 + +/* C2H_IQK_FINISH, 0x11 */ +#define IQK_OFFLOAD_LEN 1 +void c2h_iqk_offload(_adapter *adapter, u8 *data, u8 len); +int c2h_iqk_offload_wait(_adapter *adapter, u32 timeout_ms); +#define rtl8812_iqk_wait c2h_iqk_offload_wait /* TODO: remove this after phydm call c2h_iqk_offload_wait instead */ + +#ifdef CONFIG_RTW_MAC_HIDDEN_RPT +/* C2H_MAC_HIDDEN_RPT, 0x19 */ +#define MAC_HIDDEN_RPT_LEN 8 +int c2h_mac_hidden_rpt_hdl(_adapter *adapter, u8 *data, u8 len); + +/* C2H_MAC_HIDDEN_RPT_2, 0x1A */ +#define MAC_HIDDEN_RPT_2_LEN 5 +int c2h_mac_hidden_rpt_2_hdl(_adapter *adapter, u8 *data, u8 len); +int hal_read_mac_hidden_rpt(_adapter *adapter); +#endif /* CONFIG_RTW_MAC_HIDDEN_RPT */ + +/* C2H_DEFEATURE_DBG, 0x22 */ +#define DEFEATURE_DBG_LEN 1 +int c2h_defeature_dbg_hdl(_adapter *adapter, u8 *data, u8 len); + +#ifdef CONFIG_RTW_CUSTOMER_STR +/* C2H_CUSTOMER_STR_RPT, 0x24 */ +#define CUSTOMER_STR_RPT_LEN 8 +int c2h_customer_str_rpt_hdl(_adapter *adapter, u8 *data, u8 len); + +/* C2H_CUSTOMER_STR_RPT_2, 0x25 */ +#define CUSTOMER_STR_RPT_2_LEN 8 +int c2h_customer_str_rpt_2_hdl(_adapter *adapter, u8 *data, u8 len); +#endif /* CONFIG_RTW_CUSTOMER_STR */ + +#endif /* __COMMON_C2H_H__ */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_com_phycfg.c b/linux-bsp/drivers/rtl8188eus/hal/hal_com_phycfg.c new file mode 100644 index 0000000..40f733b --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_com_phycfg.c @@ -0,0 +1,5452 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _HAL_COM_PHYCFG_C_ + +#include <drv_types.h> +#include <hal_data.h> + +#define PG_TXPWR_MSB_DIFF_S4BIT(_pg_v) (((_pg_v) & 0xf0) >> 4) +#define PG_TXPWR_LSB_DIFF_S4BIT(_pg_v) ((_pg_v) & 0x0f) +#define PG_TXPWR_MSB_DIFF_TO_S8BIT(_pg_v) ((PG_TXPWR_MSB_DIFF_S4BIT(_pg_v) & BIT3) ? (PG_TXPWR_MSB_DIFF_S4BIT(_pg_v) | 0xF0) : PG_TXPWR_MSB_DIFF_S4BIT(_pg_v)) +#define PG_TXPWR_LSB_DIFF_TO_S8BIT(_pg_v) ((PG_TXPWR_LSB_DIFF_S4BIT(_pg_v) & BIT3) ? (PG_TXPWR_LSB_DIFF_S4BIT(_pg_v) | 0xF0) : PG_TXPWR_LSB_DIFF_S4BIT(_pg_v)) +#define IS_PG_TXPWR_BASE_INVALID(_base) ((_base) > 63) +#define IS_PG_TXPWR_DIFF_INVALID(_diff) ((_diff) > 7 || (_diff) < -8) +#define PG_TXPWR_INVALID_BASE 255 +#define PG_TXPWR_INVALID_DIFF 8 + +#if !IS_PG_TXPWR_BASE_INVALID(PG_TXPWR_INVALID_BASE) +#error "PG_TXPWR_BASE definition has problem" +#endif + +#if !IS_PG_TXPWR_DIFF_INVALID(PG_TXPWR_INVALID_DIFF) +#error "PG_TXPWR_DIFF definition has problem" +#endif + +#define PG_TXPWR_SRC_PG_DATA 0 +#define PG_TXPWR_SRC_IC_DEF 1 +#define PG_TXPWR_SRC_DEF 2 +#define PG_TXPWR_SRC_NUM 3 + +const char *const _pg_txpwr_src_str[] = { + "PG_DATA", + "IC_DEF", + "DEF", + "UNKNOWN" +}; + +#define pg_txpwr_src_str(src) (((src) >= PG_TXPWR_SRC_NUM) ? _pg_txpwr_src_str[PG_TXPWR_SRC_NUM] : _pg_txpwr_src_str[(src)]) + +#ifndef DBG_PG_TXPWR_READ +#define DBG_PG_TXPWR_READ 0 +#endif + +void dump_pg_txpwr_info_2g(void *sel, TxPowerInfo24G *txpwr_info, u8 rfpath_num, u8 max_tx_cnt) +{ + int path, group, tx_idx; + + RTW_PRINT_SEL(sel, "2.4G\n"); + RTW_PRINT_SEL(sel, "CCK-1T base:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (group = 0; group < MAX_CHNL_GROUP_24G; group++) + _RTW_PRINT_SEL(sel, "G%02d ", group); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (group = 0; group < MAX_CHNL_GROUP_24G; group++) + _RTW_PRINT_SEL(sel, "%3u ", txpwr_info->IndexCCK_Base[path][group]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "CCK diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) + _RTW_PRINT_SEL(sel, "%dT ", path + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", txpwr_info->CCK_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "BW40-1S base:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (group = 0; group < MAX_CHNL_GROUP_24G - 1; group++) + _RTW_PRINT_SEL(sel, "G%02d ", group); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (group = 0; group < MAX_CHNL_GROUP_24G - 1; group++) + _RTW_PRINT_SEL(sel, "%3u ", txpwr_info->IndexBW40_Base[path][group]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "OFDM diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) + _RTW_PRINT_SEL(sel, "%dT ", path + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", txpwr_info->OFDM_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "BW20 diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) + _RTW_PRINT_SEL(sel, "%dS ", path + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", txpwr_info->BW20_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "BW40 diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) + _RTW_PRINT_SEL(sel, "%dS ", path + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", txpwr_info->BW40_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); +} + +void dump_pg_txpwr_info_5g(void *sel, TxPowerInfo5G *txpwr_info, u8 rfpath_num, u8 max_tx_cnt) +{ + int path, group, tx_idx; + + RTW_PRINT_SEL(sel, "5G\n"); + RTW_PRINT_SEL(sel, "BW40-1S base:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (group = 0; group < MAX_CHNL_GROUP_5G; group++) + _RTW_PRINT_SEL(sel, "G%02d ", group); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (group = 0; group < MAX_CHNL_GROUP_5G; group++) + _RTW_PRINT_SEL(sel, "%3u ", txpwr_info->IndexBW40_Base[path][group]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "OFDM diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) + _RTW_PRINT_SEL(sel, "%dT ", path + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", txpwr_info->OFDM_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "BW20 diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) + _RTW_PRINT_SEL(sel, "%dS ", path + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", txpwr_info->BW20_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "BW40 diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) + _RTW_PRINT_SEL(sel, "%dS ", path + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", txpwr_info->BW40_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "BW80 diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) + _RTW_PRINT_SEL(sel, "%dS ", path + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", txpwr_info->BW80_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "BW160 diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) + _RTW_PRINT_SEL(sel, "%dS ", path + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", txpwr_info->BW160_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); +} + +const struct map_t pg_txpwr_def_info = + MAP_ENT(0xB8, 1, 0xFF + , MAPSEG_ARRAY_ENT(0x10, 168, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x24, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x04, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x24, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x04, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x24, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x04, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x2D, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x24, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x04, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE) + ); + +#ifdef CONFIG_RTL8188E +static const struct map_t rtl8188e_pg_txpwr_def_info = + MAP_ENT(0xB8, 1, 0xFF + , MAPSEG_ARRAY_ENT(0x10, 12, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x24) + ); +#endif + +#ifdef CONFIG_RTL8188F +static const struct map_t rtl8188f_pg_txpwr_def_info = + MAP_ENT(0xB8, 1, 0xFF + , MAPSEG_ARRAY_ENT(0x10, 12, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x27, 0x27, 0x27, 0x27, 0x27, 0x24) + ); +#endif + +#ifdef CONFIG_RTL8723B +static const struct map_t rtl8723b_pg_txpwr_def_info = + MAP_ENT(0xB8, 2, 0xFF + , MAPSEG_ARRAY_ENT(0x10, 12, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0xE0) + , MAPSEG_ARRAY_ENT(0x3A, 12, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0xE0) + ); +#endif + +#ifdef CONFIG_RTL8703B +static const struct map_t rtl8703b_pg_txpwr_def_info = + MAP_ENT(0xB8, 1, 0xFF + , MAPSEG_ARRAY_ENT(0x10, 12, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02) + ); +#endif + +#ifdef CONFIG_RTL8723D +static const struct map_t rtl8723d_pg_txpwr_def_info = + MAP_ENT(0xB8, 2, 0xFF + , MAPSEG_ARRAY_ENT(0x10, 12, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02) + , MAPSEG_ARRAY_ENT(0x3A, 12, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x02) + ); +#endif + +#ifdef CONFIG_RTL8192E +static const struct map_t rtl8192e_pg_txpwr_def_info = + MAP_ENT(0xB8, 2, 0xFF + , MAPSEG_ARRAY_ENT(0x10, 14, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x24, 0xEE, 0xEE) + , MAPSEG_ARRAY_ENT(0x3A, 14, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x24, 0xEE, 0xEE) + ); +#endif + +#ifdef CONFIG_RTL8821A +static const struct map_t rtl8821a_pg_txpwr_def_info = + MAP_ENT(0xB8, 1, 0xFF + , MAPSEG_ARRAY_ENT(0x10, 39, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x24, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00) + ); +#endif + +#ifdef CONFIG_RTL8821C +static const struct map_t rtl8821c_pg_txpwr_def_info = + MAP_ENT(0xB8, 1, 0xFF + , MAPSEG_ARRAY_ENT(0x10, 54, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEC, 0xFF, 0xFF, 0xFF, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02) + ); +#endif + +#ifdef CONFIG_RTL8812A +static const struct map_t rtl8812a_pg_txpwr_def_info = + MAP_ENT(0xB8, 1, 0xFF + , MAPSEG_ARRAY_ENT(0x10, 82, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, 0xEE, 0xEE, 0xFF, 0xFF, + 0xFF, 0xFF, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x02, 0xEE, 0xFF, 0xFF, 0xEE, 0xFF, 0x00, 0xEE, 0xFF, 0xFF, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, 0xEE, 0xEE, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x02, 0xEE, 0xFF, 0xFF, 0xEE, 0xFF, + 0x00, 0xEE) + ); +#endif + +#ifdef CONFIG_RTL8822B +static const struct map_t rtl8822b_pg_txpwr_def_info = + MAP_ENT(0xB8, 1, 0xFF + , MAPSEG_ARRAY_ENT(0x10, 82, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, 0xEE, 0xEE, 0xFF, 0xFF, + 0xFF, 0xFF, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x02, 0xEE, 0xFF, 0xFF, 0xEE, 0xFF, 0xEC, 0xEC, 0xFF, 0xFF, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, 0xEE, 0xEE, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x02, 0xEE, 0xFF, 0xFF, 0xEE, 0xFF, + 0xEC, 0xEC) + ); +#endif + +#ifdef CONFIG_RTL8814A +static const struct map_t rtl8814a_pg_txpwr_def_info = + MAP_ENT(0xB8, 1, 0xFF + , MAPSEG_ARRAY_ENT(0x10, 168, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, 0xEE, 0xEE, 0xEE, 0xEE, + 0xEE, 0xEE, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x02, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0xEE, 0xEE, 0xEE, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x02, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0x00, 0xEE, 0xEE, 0xEE, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x2A, 0x02, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0xEE, 0xEE, 0xEE, 0x2D, 0x2D, + 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2D, 0x02, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x02, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0x00, 0xEE, 0xEE, 0xEE) + ); +#endif + +const struct map_t *hal_pg_txpwr_def_info(_adapter *adapter) +{ + u8 interface_type = 0; + const struct map_t *map = NULL; + + interface_type = rtw_get_intf_type(adapter); + + switch (rtw_get_chip_type(adapter)) { +#ifdef CONFIG_RTL8723B + case RTL8723B: + map = &rtl8723b_pg_txpwr_def_info; + break; +#endif +#ifdef CONFIG_RTL8703B + case RTL8703B: + map = &rtl8703b_pg_txpwr_def_info; + break; +#endif +#ifdef CONFIG_RTL8723D + case RTL8723D: + map = &rtl8723d_pg_txpwr_def_info; + break; +#endif +#ifdef CONFIG_RTL8188E + case RTL8188E: + map = &rtl8188e_pg_txpwr_def_info; + break; +#endif +#ifdef CONFIG_RTL8188F + case RTL8188F: + map = &rtl8188f_pg_txpwr_def_info; + break; +#endif +#ifdef CONFIG_RTL8812A + case RTL8812: + map = &rtl8812a_pg_txpwr_def_info; + break; +#endif +#ifdef CONFIG_RTL8821A + case RTL8821: + map = &rtl8821a_pg_txpwr_def_info; + break; +#endif +#ifdef CONFIG_RTL8192E + case RTL8192E: + map = &rtl8192e_pg_txpwr_def_info; + break; +#endif +#ifdef CONFIG_RTL8814A + case RTL8814A: + map = &rtl8814a_pg_txpwr_def_info; + break; +#endif +#ifdef CONFIG_RTL8822B + case RTL8822B: + map = &rtl8822b_pg_txpwr_def_info; + break; +#endif +#ifdef CONFIG_RTL8821C + case RTL8821C: + map = &rtl8821c_pg_txpwr_def_info; + break; +#endif + } + + if (map == NULL) { + RTW_ERR("%s: unknown chip_type:%u\n" + , __func__, rtw_get_chip_type(adapter)); + rtw_warn_on(1); + } + + return map; +} + +static u8 hal_chk_pg_txpwr_info_2g(_adapter *adapter, TxPowerInfo24G *pwr_info) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + u8 path, group, tx_idx; + + if (pwr_info == NULL || !hal_chk_band_cap(adapter, BAND_CAP_2G)) + return _SUCCESS; + + for (path = 0; path < MAX_RF_PATH; path++) { + if (!HAL_SPEC_CHK_RF_PATH_2G(hal_spec, path)) + continue; + for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { + if (IS_PG_TXPWR_BASE_INVALID(pwr_info->IndexCCK_Base[path][group]) + || IS_PG_TXPWR_BASE_INVALID(pwr_info->IndexBW40_Base[path][group])) + return _FAIL; + } + for (tx_idx = 0; tx_idx < MAX_TX_COUNT; tx_idx++) { + if (!HAL_SPEC_CHK_TX_CNT(hal_spec, tx_idx)) + continue; + if (IS_PG_TXPWR_DIFF_INVALID(pwr_info->CCK_Diff[path][tx_idx]) + || IS_PG_TXPWR_DIFF_INVALID(pwr_info->OFDM_Diff[path][tx_idx]) + || IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW20_Diff[path][tx_idx]) + || IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW40_Diff[path][tx_idx])) + return _FAIL; + } + } + + return _SUCCESS; +} + +static u8 hal_chk_pg_txpwr_info_5g(_adapter *adapter, TxPowerInfo5G *pwr_info) +{ +#ifdef CONFIG_IEEE80211_BAND_5GHZ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + u8 path, group, tx_idx; + + if (pwr_info == NULL || !hal_chk_band_cap(adapter, BAND_CAP_5G)) + return _SUCCESS; + + for (path = 0; path < MAX_RF_PATH; path++) { + if (!HAL_SPEC_CHK_RF_PATH_5G(hal_spec, path)) + continue; + for (group = 0; group < MAX_CHNL_GROUP_5G; group++) + if (IS_PG_TXPWR_BASE_INVALID(pwr_info->IndexBW40_Base[path][group])) + return _FAIL; + for (tx_idx = 0; tx_idx < MAX_TX_COUNT; tx_idx++) { + if (!HAL_SPEC_CHK_TX_CNT(hal_spec, tx_idx)) + continue; + if (IS_PG_TXPWR_DIFF_INVALID(pwr_info->OFDM_Diff[path][tx_idx]) + || IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW20_Diff[path][tx_idx]) + || IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW40_Diff[path][tx_idx]) + || IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW80_Diff[path][tx_idx]) + || IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW160_Diff[path][tx_idx])) + return _FAIL; + } + } +#endif /* CONFIG_IEEE80211_BAND_5GHZ */ + return _SUCCESS; +} + +static inline void hal_init_pg_txpwr_info_2g(_adapter *adapter, TxPowerInfo24G *pwr_info) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + u8 path, group, tx_idx; + + if (pwr_info == NULL) + return; + + _rtw_memset(pwr_info, 0, sizeof(TxPowerInfo24G)); + + /* init with invalid value */ + for (path = 0; path < MAX_RF_PATH; path++) { + for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { + pwr_info->IndexCCK_Base[path][group] = PG_TXPWR_INVALID_BASE; + pwr_info->IndexBW40_Base[path][group] = PG_TXPWR_INVALID_BASE; + } + for (tx_idx = 0; tx_idx < MAX_TX_COUNT; tx_idx++) { + pwr_info->CCK_Diff[path][tx_idx] = PG_TXPWR_INVALID_DIFF; + pwr_info->OFDM_Diff[path][tx_idx] = PG_TXPWR_INVALID_DIFF; + pwr_info->BW20_Diff[path][tx_idx] = PG_TXPWR_INVALID_DIFF; + pwr_info->BW40_Diff[path][tx_idx] = PG_TXPWR_INVALID_DIFF; + } + } + + /* init for dummy base and diff */ + for (path = 0; path < MAX_RF_PATH; path++) { + if (!HAL_SPEC_CHK_RF_PATH_2G(hal_spec, path)) + break; + /* 2.4G BW40 base has 1 less group than CCK base*/ + pwr_info->IndexBW40_Base[path][MAX_CHNL_GROUP_24G - 1] = 0; + + /* dummy diff */ + pwr_info->CCK_Diff[path][0] = 0; /* 2.4G CCK-1TX */ + pwr_info->BW40_Diff[path][0] = 0; /* 2.4G BW40-1S */ + } +} + +static inline void hal_init_pg_txpwr_info_5g(_adapter *adapter, TxPowerInfo5G *pwr_info) +{ +#ifdef CONFIG_IEEE80211_BAND_5GHZ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + u8 path, group, tx_idx; + + if (pwr_info == NULL) + return; + + _rtw_memset(pwr_info, 0, sizeof(TxPowerInfo5G)); + + /* init with invalid value */ + for (path = 0; path < MAX_RF_PATH; path++) { + for (group = 0; group < MAX_CHNL_GROUP_5G; group++) + pwr_info->IndexBW40_Base[path][group] = PG_TXPWR_INVALID_BASE; + for (tx_idx = 0; tx_idx < MAX_TX_COUNT; tx_idx++) { + pwr_info->OFDM_Diff[path][tx_idx] = PG_TXPWR_INVALID_DIFF; + pwr_info->BW20_Diff[path][tx_idx] = PG_TXPWR_INVALID_DIFF; + pwr_info->BW40_Diff[path][tx_idx] = PG_TXPWR_INVALID_DIFF; + pwr_info->BW80_Diff[path][tx_idx] = PG_TXPWR_INVALID_DIFF; + pwr_info->BW160_Diff[path][tx_idx] = PG_TXPWR_INVALID_DIFF; + } + } + + for (path = 0; path < MAX_RF_PATH; path++) { + if (!HAL_SPEC_CHK_RF_PATH_5G(hal_spec, path)) + break; + /* dummy diff */ + pwr_info->BW40_Diff[path][0] = 0; /* 5G BW40-1S */ + } +#endif /* CONFIG_IEEE80211_BAND_5GHZ */ +} + +#if DBG_PG_TXPWR_READ +#define LOAD_PG_TXPWR_WARN_COND(_txpwr_src) 1 +#else +#define LOAD_PG_TXPWR_WARN_COND(_txpwr_src) (_txpwr_src > PG_TXPWR_SRC_PG_DATA) +#endif + +u16 hal_load_pg_txpwr_info_path_2g( + _adapter *adapter, + TxPowerInfo24G *pwr_info, + u32 path, + u8 txpwr_src, + const struct map_t *txpwr_map, + u16 pg_offset) +{ +#define PG_TXPWR_1PATH_BYTE_NUM_2G 18 + + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + u16 offset = pg_offset; + u8 group, tx_idx; + u8 val; + u8 tmp_base; + s8 tmp_diff; + + if (pwr_info == NULL || !hal_chk_band_cap(adapter, BAND_CAP_2G)) { + offset += PG_TXPWR_1PATH_BYTE_NUM_2G; + goto exit; + } + + if (DBG_PG_TXPWR_READ) + RTW_INFO("%s [%c] offset:0x%03x\n", __func__, rf_path_char(path), offset); + + for (group = 0; group < MAX_CHNL_GROUP_24G; group++) { + if (HAL_SPEC_CHK_RF_PATH_2G(hal_spec, path)) { + tmp_base = map_read8(txpwr_map, offset); + if (!IS_PG_TXPWR_BASE_INVALID(tmp_base) + && IS_PG_TXPWR_BASE_INVALID(pwr_info->IndexCCK_Base[path][group]) + ) { + pwr_info->IndexCCK_Base[path][group] = tmp_base; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 2G G%02d CCK-1T base:%u from %s\n", rf_path_char(path), group, tmp_base, pg_txpwr_src_str(txpwr_src)); + } + } + offset++; + } + + for (group = 0; group < MAX_CHNL_GROUP_24G - 1; group++) { + if (HAL_SPEC_CHK_RF_PATH_2G(hal_spec, path)) { + tmp_base = map_read8(txpwr_map, offset); + if (!IS_PG_TXPWR_BASE_INVALID(tmp_base) + && IS_PG_TXPWR_BASE_INVALID(pwr_info->IndexBW40_Base[path][group]) + ) { + pwr_info->IndexBW40_Base[path][group] = tmp_base; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 2G G%02d BW40-1S base:%u from %s\n", rf_path_char(path), group, tmp_base, pg_txpwr_src_str(txpwr_src)); + } + } + offset++; + } + + for (tx_idx = 0; tx_idx < MAX_TX_COUNT; tx_idx++) { + if (tx_idx == 0) { + if (HAL_SPEC_CHK_RF_PATH_2G(hal_spec, path) && HAL_SPEC_CHK_TX_CNT(hal_spec, tx_idx)) { + val = map_read8(txpwr_map, offset); + tmp_diff = PG_TXPWR_MSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW20_Diff[path][tx_idx]) + ) { + pwr_info->BW20_Diff[path][tx_idx] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 2G BW20-%dS diff:%d from %s\n", rf_path_char(path), tx_idx + 1, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + tmp_diff = PG_TXPWR_LSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->OFDM_Diff[path][tx_idx]) + ) { + pwr_info->OFDM_Diff[path][tx_idx] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 2G OFDM-%dT diff:%d from %s\n", rf_path_char(path), tx_idx + 1, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + } + offset++; + } else { + if (HAL_SPEC_CHK_RF_PATH_2G(hal_spec, path) && HAL_SPEC_CHK_TX_CNT(hal_spec, tx_idx)) { + val = map_read8(txpwr_map, offset); + tmp_diff = PG_TXPWR_MSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW40_Diff[path][tx_idx]) + ) { + pwr_info->BW40_Diff[path][tx_idx] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 2G BW40-%dS diff:%d from %s\n", rf_path_char(path), tx_idx + 1, tmp_diff, pg_txpwr_src_str(txpwr_src)); + + } + tmp_diff = PG_TXPWR_LSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW20_Diff[path][tx_idx]) + ) { + pwr_info->BW20_Diff[path][tx_idx] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 2G BW20-%dS diff:%d from %s\n", rf_path_char(path), tx_idx + 1, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + } + offset++; + + if (HAL_SPEC_CHK_RF_PATH_2G(hal_spec, path) && HAL_SPEC_CHK_TX_CNT(hal_spec, tx_idx)) { + val = map_read8(txpwr_map, offset); + tmp_diff = PG_TXPWR_MSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->OFDM_Diff[path][tx_idx]) + ) { + pwr_info->OFDM_Diff[path][tx_idx] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 2G OFDM-%dT diff:%d from %s\n", rf_path_char(path), tx_idx + 1, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + tmp_diff = PG_TXPWR_LSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->CCK_Diff[path][tx_idx]) + ) { + pwr_info->CCK_Diff[path][tx_idx] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 2G CCK-%dT diff:%d from %s\n", rf_path_char(path), tx_idx + 1, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + } + offset++; + } + } + + if (offset != pg_offset + PG_TXPWR_1PATH_BYTE_NUM_2G) { + RTW_ERR("%s parse %d bytes != %d\n", __func__, offset - pg_offset, PG_TXPWR_1PATH_BYTE_NUM_2G); + rtw_warn_on(1); + } + +exit: + return offset; +} + +u16 hal_load_pg_txpwr_info_path_5g( + _adapter *adapter, + TxPowerInfo5G *pwr_info, + u32 path, + u8 txpwr_src, + const struct map_t *txpwr_map, + u16 pg_offset) +{ +#define PG_TXPWR_1PATH_BYTE_NUM_5G 24 + + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + u16 offset = pg_offset; + u8 group, tx_idx; + u8 val; + u8 tmp_base; + s8 tmp_diff; + +#ifdef CONFIG_IEEE80211_BAND_5GHZ + if (pwr_info == NULL || !hal_chk_band_cap(adapter, BAND_CAP_5G)) +#endif + { + offset += PG_TXPWR_1PATH_BYTE_NUM_5G; + goto exit; + } + +#ifdef CONFIG_IEEE80211_BAND_5GHZ + if (DBG_PG_TXPWR_READ) + RTW_INFO("%s[%c] eaddr:0x%03x\n", __func__, rf_path_char(path), offset); + + for (group = 0; group < MAX_CHNL_GROUP_5G; group++) { + if (HAL_SPEC_CHK_RF_PATH_5G(hal_spec, path)) { + tmp_base = map_read8(txpwr_map, offset); + if (!IS_PG_TXPWR_BASE_INVALID(tmp_base) + && IS_PG_TXPWR_BASE_INVALID(pwr_info->IndexBW40_Base[path][group]) + ) { + pwr_info->IndexBW40_Base[path][group] = tmp_base; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 5G G%02d BW40-1S base:%u from %s\n", rf_path_char(path), group, tmp_base, pg_txpwr_src_str(txpwr_src)); + } + } + offset++; + } + + for (tx_idx = 0; tx_idx < MAX_TX_COUNT; tx_idx++) { + if (tx_idx == 0) { + if (HAL_SPEC_CHK_RF_PATH_5G(hal_spec, path) && HAL_SPEC_CHK_TX_CNT(hal_spec, tx_idx)) { + val = map_read8(txpwr_map, offset); + tmp_diff = PG_TXPWR_MSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW20_Diff[path][tx_idx]) + ) { + pwr_info->BW20_Diff[path][tx_idx] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 5G BW20-%dS diff:%d from %s\n", rf_path_char(path), tx_idx + 1, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + tmp_diff = PG_TXPWR_LSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->OFDM_Diff[path][tx_idx]) + ) { + pwr_info->OFDM_Diff[path][tx_idx] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 5G OFDM-%dT diff:%d from %s\n", rf_path_char(path), tx_idx + 1, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + } + offset++; + } else { + if (HAL_SPEC_CHK_RF_PATH_5G(hal_spec, path) && HAL_SPEC_CHK_TX_CNT(hal_spec, tx_idx)) { + val = map_read8(txpwr_map, offset); + tmp_diff = PG_TXPWR_MSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW40_Diff[path][tx_idx]) + ) { + pwr_info->BW40_Diff[path][tx_idx] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 5G BW40-%dS diff:%d from %s\n", rf_path_char(path), tx_idx + 1, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + tmp_diff = PG_TXPWR_LSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW20_Diff[path][tx_idx]) + ) { + pwr_info->BW20_Diff[path][tx_idx] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 5G BW20-%dS diff:%d from %s\n", rf_path_char(path), tx_idx + 1, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + } + offset++; + } + } + + /* OFDM diff 2T ~ 3T */ + if (HAL_SPEC_CHK_RF_PATH_5G(hal_spec, path) && HAL_SPEC_CHK_TX_CNT(hal_spec, 1)) { + val = map_read8(txpwr_map, offset); + tmp_diff = PG_TXPWR_MSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->OFDM_Diff[path][1]) + ) { + pwr_info->OFDM_Diff[path][1] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 5G OFDM-%dT diff:%d from %s\n", rf_path_char(path), 2, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + if (HAL_SPEC_CHK_TX_CNT(hal_spec, 2)) { + tmp_diff = PG_TXPWR_LSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->OFDM_Diff[path][2]) + ) { + pwr_info->OFDM_Diff[path][2] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 5G OFDM-%dT diff:%d from %s\n", rf_path_char(path), 3, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + } + } + offset++; + + /* OFDM diff 4T */ + if (HAL_SPEC_CHK_RF_PATH_5G(hal_spec, path) && HAL_SPEC_CHK_TX_CNT(hal_spec, 3)) { + val = map_read8(txpwr_map, offset); + tmp_diff = PG_TXPWR_LSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->OFDM_Diff[path][3]) + ) { + pwr_info->OFDM_Diff[path][3] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 5G OFDM-%dT diff:%d from %s\n", rf_path_char(path), 4, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + } + offset++; + + for (tx_idx = 0; tx_idx < MAX_TX_COUNT; tx_idx++) { + if (HAL_SPEC_CHK_RF_PATH_5G(hal_spec, path) && HAL_SPEC_CHK_TX_CNT(hal_spec, tx_idx)) { + val = map_read8(txpwr_map, offset); + tmp_diff = PG_TXPWR_MSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW80_Diff[path][tx_idx]) + ) { + pwr_info->BW80_Diff[path][tx_idx] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 5G BW80-%dS diff:%d from %s\n", rf_path_char(path), tx_idx + 1, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + tmp_diff = PG_TXPWR_LSB_DIFF_TO_S8BIT(val); + if (!IS_PG_TXPWR_DIFF_INVALID(tmp_diff) + && IS_PG_TXPWR_DIFF_INVALID(pwr_info->BW160_Diff[path][tx_idx]) + ) { + pwr_info->BW160_Diff[path][tx_idx] = tmp_diff; + if (LOAD_PG_TXPWR_WARN_COND(txpwr_src)) + RTW_INFO("[%c] 5G BW160-%dS diff:%d from %s\n", rf_path_char(path), tx_idx + 1, tmp_diff, pg_txpwr_src_str(txpwr_src)); + } + } + offset++; + } + + if (offset != pg_offset + PG_TXPWR_1PATH_BYTE_NUM_5G) { + RTW_ERR("%s parse %d bytes != %d\n", __func__, offset - pg_offset, PG_TXPWR_1PATH_BYTE_NUM_5G); + rtw_warn_on(1); + } + +#endif /* #ifdef CONFIG_IEEE80211_BAND_5GHZ */ + +exit: + return offset; +} + +void hal_load_pg_txpwr_info( + _adapter *adapter, + TxPowerInfo24G *pwr_info_2g, + TxPowerInfo5G *pwr_info_5g, + u8 *pg_data, + BOOLEAN AutoLoadFail +) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + u8 path; + u16 pg_offset; + u8 txpwr_src = PG_TXPWR_SRC_PG_DATA; + struct map_t pg_data_map = MAP_ENT(184, 1, 0xFF, MAPSEG_PTR_ENT(0x00, 184, pg_data)); + const struct map_t *txpwr_map = NULL; + + /* init with invalid value and some dummy base and diff */ + hal_init_pg_txpwr_info_2g(adapter, pwr_info_2g); + hal_init_pg_txpwr_info_5g(adapter, pwr_info_5g); + +select_src: + pg_offset = 0x10; + + switch (txpwr_src) { + case PG_TXPWR_SRC_PG_DATA: + txpwr_map = &pg_data_map; + break; + case PG_TXPWR_SRC_IC_DEF: + txpwr_map = hal_pg_txpwr_def_info(adapter); + break; + case PG_TXPWR_SRC_DEF: + default: + txpwr_map = &pg_txpwr_def_info; + break; + }; + + if (txpwr_map == NULL) + goto end_parse; + + for (path = 0; path < MAX_RF_PATH ; path++) { + if (!HAL_SPEC_CHK_RF_PATH_2G(hal_spec, path) && !HAL_SPEC_CHK_RF_PATH_5G(hal_spec, path)) + break; + pg_offset = hal_load_pg_txpwr_info_path_2g(adapter, pwr_info_2g, path, txpwr_src, txpwr_map, pg_offset); + pg_offset = hal_load_pg_txpwr_info_path_5g(adapter, pwr_info_5g, path, txpwr_src, txpwr_map, pg_offset); + } + + if (hal_chk_pg_txpwr_info_2g(adapter, pwr_info_2g) == _SUCCESS + && hal_chk_pg_txpwr_info_5g(adapter, pwr_info_5g) == _SUCCESS) + goto exit; + +end_parse: + txpwr_src++; + if (txpwr_src < PG_TXPWR_SRC_NUM) + goto select_src; + + if (hal_chk_pg_txpwr_info_2g(adapter, pwr_info_2g) != _SUCCESS + || hal_chk_pg_txpwr_info_5g(adapter, pwr_info_5g) != _SUCCESS) + rtw_warn_on(1); + +exit: + if (DBG_PG_TXPWR_READ) { + if (pwr_info_2g) + dump_pg_txpwr_info_2g(RTW_DBGDUMP, pwr_info_2g, 4, 4); + if (pwr_info_5g) + dump_pg_txpwr_info_5g(RTW_DBGDUMP, pwr_info_5g, 4, 4); + } + + return; +} + +void hal_load_txpwr_info( + _adapter *adapter, + TxPowerInfo24G *pwr_info_2g, + TxPowerInfo5G *pwr_info_5g, + u8 *pg_data +) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + u8 max_tx_cnt = hal_spec->max_tx_cnt; + u8 rfpath, ch_idx, group, tx_idx; + + /* load from pg data (or default value) */ + hal_load_pg_txpwr_info(adapter, pwr_info_2g, pwr_info_5g, pg_data, _FALSE); + + /* transform to hal_data */ + for (rfpath = 0; rfpath < MAX_RF_PATH; rfpath++) { + + if (!pwr_info_2g || !HAL_SPEC_CHK_RF_PATH_2G(hal_spec, rfpath)) + goto bypass_2g; + + /* 2.4G base */ + for (ch_idx = 0; ch_idx < CENTER_CH_2G_NUM; ch_idx++) { + u8 cck_group; + + if (rtw_get_ch_group(ch_idx + 1, &group, &cck_group) != BAND_ON_2_4G) + continue; + + hal_data->Index24G_CCK_Base[rfpath][ch_idx] = pwr_info_2g->IndexCCK_Base[rfpath][cck_group]; + hal_data->Index24G_BW40_Base[rfpath][ch_idx] = pwr_info_2g->IndexBW40_Base[rfpath][group]; + } + + /* 2.4G diff */ + for (tx_idx = 0; tx_idx < MAX_TX_COUNT; tx_idx++) { + if (tx_idx >= max_tx_cnt) + break; + + hal_data->CCK_24G_Diff[rfpath][tx_idx] = pwr_info_2g->CCK_Diff[rfpath][tx_idx]; + hal_data->OFDM_24G_Diff[rfpath][tx_idx] = pwr_info_2g->OFDM_Diff[rfpath][tx_idx]; + hal_data->BW20_24G_Diff[rfpath][tx_idx] = pwr_info_2g->BW20_Diff[rfpath][tx_idx]; + hal_data->BW40_24G_Diff[rfpath][tx_idx] = pwr_info_2g->BW40_Diff[rfpath][tx_idx]; + } +bypass_2g: + ; + +#ifdef CONFIG_IEEE80211_BAND_5GHZ + if (!pwr_info_5g || !HAL_SPEC_CHK_RF_PATH_5G(hal_spec, rfpath)) + goto bypass_5g; + + /* 5G base */ + for (ch_idx = 0; ch_idx < CENTER_CH_5G_ALL_NUM; ch_idx++) { + if (rtw_get_ch_group(center_ch_5g_all[ch_idx], &group, NULL) != BAND_ON_5G) + continue; + hal_data->Index5G_BW40_Base[rfpath][ch_idx] = pwr_info_5g->IndexBW40_Base[rfpath][group]; + } + + for (ch_idx = 0 ; ch_idx < CENTER_CH_5G_80M_NUM; ch_idx++) { + u8 upper, lower; + + if (rtw_get_ch_group(center_ch_5g_80m[ch_idx], &group, NULL) != BAND_ON_5G) + continue; + + upper = pwr_info_5g->IndexBW40_Base[rfpath][group]; + lower = pwr_info_5g->IndexBW40_Base[rfpath][group + 1]; + hal_data->Index5G_BW80_Base[rfpath][ch_idx] = (upper + lower) / 2; + } + + /* 5G diff */ + for (tx_idx = 0; tx_idx < MAX_TX_COUNT; tx_idx++) { + if (tx_idx >= max_tx_cnt) + break; + + hal_data->OFDM_5G_Diff[rfpath][tx_idx] = pwr_info_5g->OFDM_Diff[rfpath][tx_idx]; + hal_data->BW20_5G_Diff[rfpath][tx_idx] = pwr_info_5g->BW20_Diff[rfpath][tx_idx]; + hal_data->BW40_5G_Diff[rfpath][tx_idx] = pwr_info_5g->BW40_Diff[rfpath][tx_idx]; + hal_data->BW80_5G_Diff[rfpath][tx_idx] = pwr_info_5g->BW80_Diff[rfpath][tx_idx]; + } +bypass_5g: + ; +#endif /* CONFIG_IEEE80211_BAND_5GHZ */ + } +} + +void dump_hal_txpwr_info_2g(void *sel, _adapter *adapter, u8 rfpath_num, u8 max_tx_cnt) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + int path, ch_idx, tx_idx; + + RTW_PRINT_SEL(sel, "2.4G\n"); + RTW_PRINT_SEL(sel, "CCK-1T base:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (ch_idx = 0; ch_idx < CENTER_CH_2G_NUM; ch_idx++) + _RTW_PRINT_SEL(sel, "%2d ", center_ch_2g[ch_idx]); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (ch_idx = 0; ch_idx < CENTER_CH_2G_NUM; ch_idx++) + _RTW_PRINT_SEL(sel, "%2u ", hal_data->Index24G_CCK_Base[path][ch_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "CCK diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%dT ", tx_idx + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", hal_data->CCK_24G_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "BW40-1S base:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (ch_idx = 0; ch_idx < CENTER_CH_2G_NUM; ch_idx++) + _RTW_PRINT_SEL(sel, "%2d ", center_ch_2g[ch_idx]); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (ch_idx = 0; ch_idx < CENTER_CH_2G_NUM; ch_idx++) + _RTW_PRINT_SEL(sel, "%2u ", hal_data->Index24G_BW40_Base[path][ch_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "OFDM diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%dT ", tx_idx + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", hal_data->OFDM_24G_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "BW20 diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%dS ", tx_idx + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", hal_data->BW20_24G_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "BW40 diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%dS ", tx_idx + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", hal_data->BW40_24G_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); +} + +void dump_hal_txpwr_info_5g(void *sel, _adapter *adapter, u8 rfpath_num, u8 max_tx_cnt) +{ +#ifdef CONFIG_IEEE80211_BAND_5GHZ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + int path, ch_idx, tx_idx; + u8 dump_section = 0; + u8 ch_idx_s = 0; + + RTW_PRINT_SEL(sel, "5G\n"); + RTW_PRINT_SEL(sel, "BW40-1S base:\n"); + do { + #define DUMP_5G_BW40_BASE_SECTION_NUM 3 + u8 end[DUMP_5G_BW40_BASE_SECTION_NUM] = {64, 144, 177}; + + RTW_PRINT_SEL(sel, "%4s ", ""); + for (ch_idx = ch_idx_s; ch_idx < CENTER_CH_5G_ALL_NUM; ch_idx++) { + _RTW_PRINT_SEL(sel, "%3d ", center_ch_5g_all[ch_idx]); + if (end[dump_section] == center_ch_5g_all[ch_idx]) + break; + } + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (ch_idx = ch_idx_s; ch_idx < CENTER_CH_5G_ALL_NUM; ch_idx++) { + _RTW_PRINT_SEL(sel, "%3u ", hal_data->Index5G_BW40_Base[path][ch_idx]); + if (end[dump_section] == center_ch_5g_all[ch_idx]) + break; + } + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + ch_idx_s = ch_idx + 1; + dump_section++; + if (dump_section >= DUMP_5G_BW40_BASE_SECTION_NUM) + break; + } while (1); + + RTW_PRINT_SEL(sel, "BW80-1S base:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (ch_idx = 0; ch_idx < CENTER_CH_5G_80M_NUM; ch_idx++) + _RTW_PRINT_SEL(sel, "%3d ", center_ch_5g_80m[ch_idx]); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (ch_idx = 0; ch_idx < CENTER_CH_5G_80M_NUM; ch_idx++) + _RTW_PRINT_SEL(sel, "%3u ", hal_data->Index5G_BW80_Base[path][ch_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "OFDM diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%dT ", tx_idx + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", hal_data->OFDM_5G_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "BW20 diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%dS ", tx_idx + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", hal_data->BW20_5G_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "BW40 diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%dS ", tx_idx + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", hal_data->BW40_5G_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); + + RTW_PRINT_SEL(sel, "BW80 diff:\n"); + RTW_PRINT_SEL(sel, "%4s ", ""); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%dS ", tx_idx + 1); + _RTW_PRINT_SEL(sel, "\n"); + for (path = 0; path < MAX_RF_PATH && path < rfpath_num; path++) { + RTW_PRINT_SEL(sel, "[%c]: ", rf_path_char(path)); + for (tx_idx = RF_1TX; tx_idx < MAX_TX_COUNT && tx_idx < max_tx_cnt; tx_idx++) + _RTW_PRINT_SEL(sel, "%2d ", hal_data->BW80_5G_Diff[path][tx_idx]); + _RTW_PRINT_SEL(sel, "\n"); + } + RTW_PRINT_SEL(sel, "\n"); +#endif /* CONFIG_IEEE80211_BAND_5GHZ */ +} + +/* +* rtw_regsty_get_target_tx_power - +* +* Return dBm or -1 for undefined +*/ +s8 rtw_regsty_get_target_tx_power( + IN PADAPTER Adapter, + IN u8 Band, + IN u8 RfPath, + IN RATE_SECTION RateSection +) +{ + struct registry_priv *regsty = adapter_to_regsty(Adapter); + s8 value = 0; + + if (RfPath > RF_PATH_D) { + RTW_PRINT("%s invalid RfPath:%d\n", __func__, RfPath); + return -1; + } + + if (Band != BAND_ON_2_4G + #ifdef CONFIG_IEEE80211_BAND_5GHZ + && Band != BAND_ON_5G + #endif + ) { + RTW_PRINT("%s invalid Band:%d\n", __func__, Band); + return -1; + } + + if (RateSection >= RATE_SECTION_NUM + #ifdef CONFIG_IEEE80211_BAND_5GHZ + || (Band == BAND_ON_5G && RateSection == CCK) + #endif + ) { + RTW_PRINT("%s invalid RateSection:%d in Band:%d, RfPath:%d\n", __func__ + , RateSection, Band, RfPath); + return -1; + } + + if (Band == BAND_ON_2_4G) + value = regsty->target_tx_pwr_2g[RfPath][RateSection]; +#ifdef CONFIG_IEEE80211_BAND_5GHZ + else /* BAND_ON_5G */ + value = regsty->target_tx_pwr_5g[RfPath][RateSection - 1]; +#endif + + return value; +} + +bool rtw_regsty_chk_target_tx_power_valid(_adapter *adapter) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + int path, tx_num, band, rs; + s8 target; + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) { + if (!hal_is_band_support(adapter, band)) + continue; + + for (path = 0; path < RF_PATH_MAX; path++) { + if (!HAL_SPEC_CHK_RF_PATH(hal_spec, band, path)) + break; + + for (rs = 0; rs < RATE_SECTION_NUM; rs++) { + tx_num = rate_section_to_tx_num(rs); + if (tx_num >= hal_spec->tx_nss_num) + continue; + + if (band == BAND_ON_5G && IS_CCK_RATE_SECTION(rs)) + continue; + + if (IS_VHT_RATE_SECTION(rs) && !IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(adapter)) + continue; + + target = rtw_regsty_get_target_tx_power(adapter, band, path, rs); + if (target == -1) { + RTW_PRINT("%s return _FALSE for band:%d, path:%d, rs:%d, t:%d\n", __func__, band, path, rs, target); + return _FALSE; + } + } + } + } + + return _TRUE; +} + +/* +* PHY_GetTxPowerByRateBase - +* +* Return 2 times of dBm +*/ +u8 +PHY_GetTxPowerByRateBase( + IN PADAPTER Adapter, + IN u8 Band, + IN u8 RfPath, + IN u8 TxNum, + IN RATE_SECTION RateSection +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + u8 value = 0; + + if (RfPath > RF_PATH_D) { + RTW_PRINT("%s invalid RfPath:%d\n", __func__, RfPath); + return 0; + } + + if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) { + RTW_PRINT("%s invalid Band:%d\n", __func__, Band); + return 0; + } + + if (RateSection >= RATE_SECTION_NUM + || (Band == BAND_ON_5G && RateSection == CCK) + ) { + RTW_PRINT("%s invalid RateSection:%d in Band:%d, RfPath:%d, TxNum:%d\n", __func__ + , RateSection, Band, RfPath, TxNum); + return 0; + } + + if (Band == BAND_ON_2_4G) + value = pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][RateSection]; + else /* BAND_ON_5G */ + value = pHalData->TxPwrByRateBase5G[RfPath][TxNum][RateSection - 1]; + + return value; +} + +VOID +phy_SetTxPowerByRateBase( + IN PADAPTER Adapter, + IN u8 Band, + IN u8 RfPath, + IN RATE_SECTION RateSection, + IN u8 TxNum, + IN u8 Value +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + + if (RfPath > RF_PATH_D) { + RTW_PRINT("%s invalid RfPath:%d\n", __func__, RfPath); + return; + } + + if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) { + RTW_PRINT("%s invalid Band:%d\n", __func__, Band); + return; + } + + if (RateSection >= RATE_SECTION_NUM + || (Band == BAND_ON_5G && RateSection == CCK) + ) { + RTW_PRINT("%s invalid RateSection:%d in %sG, RfPath:%d, TxNum:%d\n", __func__ + , RateSection, (Band == BAND_ON_2_4G) ? "2.4" : "5", RfPath, TxNum); + return; + } + + if (Band == BAND_ON_2_4G) + pHalData->TxPwrByRateBase2_4G[RfPath][TxNum][RateSection] = Value; + else /* BAND_ON_5G */ + pHalData->TxPwrByRateBase5G[RfPath][TxNum][RateSection - 1] = Value; +} + +static inline BOOLEAN phy_is_txpwr_by_rate_undefined_of_band_path(_adapter *adapter, u8 band, u8 path) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + u8 tx_num = 0, rate_idx = 0; + + for (tx_num = 0; tx_num < TX_PWR_BY_RATE_NUM_RF; tx_num++) { + if (tx_num >= hal_spec->max_tx_cnt || tx_num >= hal_spec->tx_nss_num) + goto exit; + for (rate_idx = 0; rate_idx < TX_PWR_BY_RATE_NUM_RATE; rate_idx++) { + if (hal_data->TxPwrByRateOffset[band][path][tx_num][rate_idx] != 0) + goto exit; + } + } + +exit: + return (tx_num >= hal_spec->max_tx_cnt || tx_num >= hal_spec->tx_nss_num) ? _TRUE : _FALSE; +} + +static inline void phy_txpwr_by_rate_duplicate_band_path(_adapter *adapter, u8 band, u8 s_path, u8 t_path) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + u8 tx_num = 0, rate_idx = 0; + + for (tx_num = 0; tx_num < TX_PWR_BY_RATE_NUM_RF; tx_num++) + for (rate_idx = 0; rate_idx < TX_PWR_BY_RATE_NUM_RATE; rate_idx++) + hal_data->TxPwrByRateOffset[band][t_path][tx_num][rate_idx] = hal_data->TxPwrByRateOffset[band][s_path][tx_num][rate_idx]; +} + +static void phy_txpwr_by_rate_chk_for_path_dup(_adapter *adapter) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + u8 band, path; + s8 src_path; + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) + for (path = RF_PATH_A; path < RF_PATH_MAX; path++) + hal_data->txpwr_by_rate_undefined_band_path[band][path] = 0; + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) { + if (!hal_is_band_support(adapter, band)) + continue; + + for (path = RF_PATH_A; path < RF_PATH_MAX; path++) { + if (!HAL_SPEC_CHK_RF_PATH(hal_spec, band, path)) + continue; + + if (phy_is_txpwr_by_rate_undefined_of_band_path(adapter, band, path)) + hal_data->txpwr_by_rate_undefined_band_path[band][path] = 1; + } + } + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) { + if (!hal_is_band_support(adapter, band)) + continue; + + src_path = -1; + for (path = RF_PATH_A; path < RF_PATH_MAX; path++) { + if (!HAL_SPEC_CHK_RF_PATH(hal_spec, band, path)) + continue; + + /* find src */ + if (src_path == -1 && hal_data->txpwr_by_rate_undefined_band_path[band][path] == 0) + src_path = path; + } + + if (src_path == -1) { + RTW_ERR("%s all power by rate undefined\n", __func__); + continue; + } + + for (path = RF_PATH_A; path < RF_PATH_MAX; path++) { + if (!HAL_SPEC_CHK_RF_PATH(hal_spec, band, path)) + continue; + + /* duplicate src to undefined one */ + if (hal_data->txpwr_by_rate_undefined_band_path[band][path] == 1) { + RTW_INFO("%s duplicate %s [%c] to [%c]\n", __func__ + , band_str(band), rf_path_char(src_path), rf_path_char(path)); + phy_txpwr_by_rate_duplicate_band_path(adapter, band, src_path, path); + } + } + } +} + +VOID +phy_StoreTxPowerByRateBase( + IN PADAPTER pAdapter +) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(pAdapter); + struct registry_priv *regsty = adapter_to_regsty(pAdapter); + + u8 rate_sec_base[RATE_SECTION_NUM] = { + MGN_11M, + MGN_54M, + MGN_MCS7, + MGN_MCS15, + MGN_MCS23, + MGN_MCS31, + MGN_VHT1SS_MCS7, + MGN_VHT2SS_MCS7, + MGN_VHT3SS_MCS7, + MGN_VHT4SS_MCS7, + }; + + u8 band, path, rs, tx_num, base, index; + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) { + if (!hal_is_band_support(pAdapter, band)) + continue; + + for (path = RF_PATH_A; path < RF_PATH_MAX; path++) { + if (!HAL_SPEC_CHK_RF_PATH(hal_spec, band, path)) + break; + + for (rs = 0; rs < RATE_SECTION_NUM; rs++) { + tx_num = rate_section_to_tx_num(rs); + if (tx_num >= hal_spec->tx_nss_num) + continue; + + if (band == BAND_ON_5G && IS_CCK_RATE_SECTION(rs)) + continue; + + if (IS_VHT_RATE_SECTION(rs) && !IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(pAdapter)) + continue; + + if (regsty->target_tx_pwr_valid == _TRUE) + base = 2 * rtw_regsty_get_target_tx_power(pAdapter, band, path, rs); + else + base = _PHY_GetTxPowerByRate(pAdapter, band, path, tx_num, rate_sec_base[rs]); + phy_SetTxPowerByRateBase(pAdapter, band, path, rs, tx_num, base); + } + } + } +} + +VOID +PHY_GetRateValuesOfTxPowerByRate( + IN PADAPTER pAdapter, + IN u32 RegAddr, + IN u32 BitMask, + IN u32 Value, + OUT u8 *Rate, + OUT s8 *PwrByRateVal, + OUT u8 *RateNum +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + u8 index = 0, i = 0; + + switch (RegAddr) { + case rTxAGC_A_Rate18_06: + case rTxAGC_B_Rate18_06: + Rate[0] = MGN_6M; + Rate[1] = MGN_9M; + Rate[2] = MGN_12M; + Rate[3] = MGN_18M; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case rTxAGC_A_Rate54_24: + case rTxAGC_B_Rate54_24: + Rate[0] = MGN_24M; + Rate[1] = MGN_36M; + Rate[2] = MGN_48M; + Rate[3] = MGN_54M; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case rTxAGC_A_CCK1_Mcs32: + Rate[0] = MGN_1M; + PwrByRateVal[0] = (s8)((((Value >> (8 + 4)) & 0xF)) * 10 + + ((Value >> 8) & 0xF)); + *RateNum = 1; + break; + + case rTxAGC_B_CCK11_A_CCK2_11: + if (BitMask == 0xffffff00) { + Rate[0] = MGN_2M; + Rate[1] = MGN_5_5M; + Rate[2] = MGN_11M; + for (i = 1; i < 4; ++i) { + PwrByRateVal[i - 1] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 3; + } else if (BitMask == 0x000000ff) { + Rate[0] = MGN_11M; + PwrByRateVal[0] = (s8)((((Value >> 4) & 0xF)) * 10 + + (Value & 0xF)); + *RateNum = 1; + } + break; + + case rTxAGC_A_Mcs03_Mcs00: + case rTxAGC_B_Mcs03_Mcs00: + Rate[0] = MGN_MCS0; + Rate[1] = MGN_MCS1; + Rate[2] = MGN_MCS2; + Rate[3] = MGN_MCS3; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case rTxAGC_A_Mcs07_Mcs04: + case rTxAGC_B_Mcs07_Mcs04: + Rate[0] = MGN_MCS4; + Rate[1] = MGN_MCS5; + Rate[2] = MGN_MCS6; + Rate[3] = MGN_MCS7; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case rTxAGC_A_Mcs11_Mcs08: + case rTxAGC_B_Mcs11_Mcs08: + Rate[0] = MGN_MCS8; + Rate[1] = MGN_MCS9; + Rate[2] = MGN_MCS10; + Rate[3] = MGN_MCS11; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case rTxAGC_A_Mcs15_Mcs12: + case rTxAGC_B_Mcs15_Mcs12: + Rate[0] = MGN_MCS12; + Rate[1] = MGN_MCS13; + Rate[2] = MGN_MCS14; + Rate[3] = MGN_MCS15; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + + break; + + case rTxAGC_B_CCK1_55_Mcs32: + Rate[0] = MGN_1M; + Rate[1] = MGN_2M; + Rate[2] = MGN_5_5M; + for (i = 1; i < 4; ++i) { + PwrByRateVal[i - 1] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 3; + break; + + case 0xC20: + case 0xE20: + case 0x1820: + case 0x1a20: + Rate[0] = MGN_1M; + Rate[1] = MGN_2M; + Rate[2] = MGN_5_5M; + Rate[3] = MGN_11M; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xC24: + case 0xE24: + case 0x1824: + case 0x1a24: + Rate[0] = MGN_6M; + Rate[1] = MGN_9M; + Rate[2] = MGN_12M; + Rate[3] = MGN_18M; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xC28: + case 0xE28: + case 0x1828: + case 0x1a28: + Rate[0] = MGN_24M; + Rate[1] = MGN_36M; + Rate[2] = MGN_48M; + Rate[3] = MGN_54M; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xC2C: + case 0xE2C: + case 0x182C: + case 0x1a2C: + Rate[0] = MGN_MCS0; + Rate[1] = MGN_MCS1; + Rate[2] = MGN_MCS2; + Rate[3] = MGN_MCS3; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xC30: + case 0xE30: + case 0x1830: + case 0x1a30: + Rate[0] = MGN_MCS4; + Rate[1] = MGN_MCS5; + Rate[2] = MGN_MCS6; + Rate[3] = MGN_MCS7; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xC34: + case 0xE34: + case 0x1834: + case 0x1a34: + Rate[0] = MGN_MCS8; + Rate[1] = MGN_MCS9; + Rate[2] = MGN_MCS10; + Rate[3] = MGN_MCS11; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xC38: + case 0xE38: + case 0x1838: + case 0x1a38: + Rate[0] = MGN_MCS12; + Rate[1] = MGN_MCS13; + Rate[2] = MGN_MCS14; + Rate[3] = MGN_MCS15; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xC3C: + case 0xE3C: + case 0x183C: + case 0x1a3C: + Rate[0] = MGN_VHT1SS_MCS0; + Rate[1] = MGN_VHT1SS_MCS1; + Rate[2] = MGN_VHT1SS_MCS2; + Rate[3] = MGN_VHT1SS_MCS3; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xC40: + case 0xE40: + case 0x1840: + case 0x1a40: + Rate[0] = MGN_VHT1SS_MCS4; + Rate[1] = MGN_VHT1SS_MCS5; + Rate[2] = MGN_VHT1SS_MCS6; + Rate[3] = MGN_VHT1SS_MCS7; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xC44: + case 0xE44: + case 0x1844: + case 0x1a44: + Rate[0] = MGN_VHT1SS_MCS8; + Rate[1] = MGN_VHT1SS_MCS9; + Rate[2] = MGN_VHT2SS_MCS0; + Rate[3] = MGN_VHT2SS_MCS1; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xC48: + case 0xE48: + case 0x1848: + case 0x1a48: + Rate[0] = MGN_VHT2SS_MCS2; + Rate[1] = MGN_VHT2SS_MCS3; + Rate[2] = MGN_VHT2SS_MCS4; + Rate[3] = MGN_VHT2SS_MCS5; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xC4C: + case 0xE4C: + case 0x184C: + case 0x1a4C: + Rate[0] = MGN_VHT2SS_MCS6; + Rate[1] = MGN_VHT2SS_MCS7; + Rate[2] = MGN_VHT2SS_MCS8; + Rate[3] = MGN_VHT2SS_MCS9; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xCD8: + case 0xED8: + case 0x18D8: + case 0x1aD8: + Rate[0] = MGN_MCS16; + Rate[1] = MGN_MCS17; + Rate[2] = MGN_MCS18; + Rate[3] = MGN_MCS19; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xCDC: + case 0xEDC: + case 0x18DC: + case 0x1aDC: + Rate[0] = MGN_MCS20; + Rate[1] = MGN_MCS21; + Rate[2] = MGN_MCS22; + Rate[3] = MGN_MCS23; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xCE0: + case 0xEE0: + case 0x18E0: + case 0x1aE0: + Rate[0] = MGN_VHT3SS_MCS0; + Rate[1] = MGN_VHT3SS_MCS1; + Rate[2] = MGN_VHT3SS_MCS2; + Rate[3] = MGN_VHT3SS_MCS3; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xCE4: + case 0xEE4: + case 0x18E4: + case 0x1aE4: + Rate[0] = MGN_VHT3SS_MCS4; + Rate[1] = MGN_VHT3SS_MCS5; + Rate[2] = MGN_VHT3SS_MCS6; + Rate[3] = MGN_VHT3SS_MCS7; + for (i = 0; i < 4; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 4; + break; + + case 0xCE8: + case 0xEE8: + case 0x18E8: + case 0x1aE8: + Rate[0] = MGN_VHT3SS_MCS8; + Rate[1] = MGN_VHT3SS_MCS9; + for (i = 0; i < 2; ++i) { + PwrByRateVal[i] = (s8)((((Value >> (i * 8 + 4)) & 0xF)) * 10 + + ((Value >> (i * 8)) & 0xF)); + } + *RateNum = 2; + break; + + default: + RTW_PRINT("Invalid RegAddr 0x%x in %s()\n", RegAddr, __func__); + break; + }; +} + +void +PHY_StoreTxPowerByRateNew( + IN PADAPTER pAdapter, + IN u32 Band, + IN u32 RfPath, + IN u32 TxNum, + IN u32 RegAddr, + IN u32 BitMask, + IN u32 Data +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + u8 i = 0, rates[4] = {0}, rateNum = 0; + s8 PwrByRateVal[4] = {0}; + + PHY_GetRateValuesOfTxPowerByRate(pAdapter, RegAddr, BitMask, Data, rates, PwrByRateVal, &rateNum); + + if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) { + RTW_PRINT("Invalid Band %d\n", Band); + return; + } + + if (RfPath > ODM_RF_PATH_D) { + RTW_PRINT("Invalid RfPath %d\n", RfPath); + return; + } + + if (TxNum > ODM_RF_PATH_D) { + RTW_PRINT("Invalid TxNum %d\n", TxNum); + return; + } + + for (i = 0; i < rateNum; ++i) { + u8 rate_idx = PHY_GetRateIndexOfTxPowerByRate(rates[i]); + + if (IS_1T_RATE(rates[i])) + pHalData->TxPwrByRateOffset[Band][RfPath][RF_1TX][rate_idx] = PwrByRateVal[i]; + else if (IS_2T_RATE(rates[i])) + pHalData->TxPwrByRateOffset[Band][RfPath][RF_2TX][rate_idx] = PwrByRateVal[i]; + else if (IS_3T_RATE(rates[i])) + pHalData->TxPwrByRateOffset[Band][RfPath][RF_3TX][rate_idx] = PwrByRateVal[i]; + else if (IS_4T_RATE(rates[i])) + pHalData->TxPwrByRateOffset[Band][RfPath][RF_4TX][rate_idx] = PwrByRateVal[i]; + else + rtw_warn_on(1); + } +} + +VOID +PHY_InitTxPowerByRate( + IN PADAPTER pAdapter +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + u8 band = 0, rfPath = 0, TxNum = 0, rate = 0, i = 0, j = 0; + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band) + for (rfPath = 0; rfPath < TX_PWR_BY_RATE_NUM_RF; ++rfPath) + for (TxNum = 0; TxNum < TX_PWR_BY_RATE_NUM_RF; ++TxNum) + for (rate = 0; rate < TX_PWR_BY_RATE_NUM_RATE; ++rate) + pHalData->TxPwrByRateOffset[band][rfPath][TxNum][rate] = 0; +} + +VOID +phy_store_tx_power_by_rate( + IN PADAPTER pAdapter, + IN u32 Band, + IN u32 RfPath, + IN u32 TxNum, + IN u32 RegAddr, + IN u32 BitMask, + IN u32 Data +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + + if (pDM_Odm->phy_reg_pg_version > 0) + PHY_StoreTxPowerByRateNew(pAdapter, Band, RfPath, TxNum, RegAddr, BitMask, Data); + else + RTW_INFO("Invalid PHY_REG_PG.txt version %d\n", pDM_Odm->phy_reg_pg_version); + +} + +VOID +phy_ConvertTxPowerByRateInDbmToRelativeValues( + IN PADAPTER pAdapter +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + u8 base = 0, i = 0, value = 0, + band = 0, path = 0, txNum = 0, index = 0, + startIndex = 0, endIndex = 0; + u8 cckRates[4] = {MGN_1M, MGN_2M, MGN_5_5M, MGN_11M}, + ofdmRates[8] = {MGN_6M, MGN_9M, MGN_12M, MGN_18M, MGN_24M, MGN_36M, MGN_48M, MGN_54M}, + mcs0_7Rates[8] = {MGN_MCS0, MGN_MCS1, MGN_MCS2, MGN_MCS3, MGN_MCS4, MGN_MCS5, MGN_MCS6, MGN_MCS7}, + mcs8_15Rates[8] = {MGN_MCS8, MGN_MCS9, MGN_MCS10, MGN_MCS11, MGN_MCS12, MGN_MCS13, MGN_MCS14, MGN_MCS15}, + mcs16_23Rates[8] = {MGN_MCS16, MGN_MCS17, MGN_MCS18, MGN_MCS19, MGN_MCS20, MGN_MCS21, MGN_MCS22, MGN_MCS23}, + vht1ssRates[10] = {MGN_VHT1SS_MCS0, MGN_VHT1SS_MCS1, MGN_VHT1SS_MCS2, MGN_VHT1SS_MCS3, MGN_VHT1SS_MCS4, + MGN_VHT1SS_MCS5, MGN_VHT1SS_MCS6, MGN_VHT1SS_MCS7, MGN_VHT1SS_MCS8, MGN_VHT1SS_MCS9}, + vht2ssRates[10] = {MGN_VHT2SS_MCS0, MGN_VHT2SS_MCS1, MGN_VHT2SS_MCS2, MGN_VHT2SS_MCS3, MGN_VHT2SS_MCS4, + MGN_VHT2SS_MCS5, MGN_VHT2SS_MCS6, MGN_VHT2SS_MCS7, MGN_VHT2SS_MCS8, MGN_VHT2SS_MCS9}, + vht3ssRates[10] = {MGN_VHT3SS_MCS0, MGN_VHT3SS_MCS1, MGN_VHT3SS_MCS2, MGN_VHT3SS_MCS3, MGN_VHT3SS_MCS4, + MGN_VHT3SS_MCS5, MGN_VHT3SS_MCS6, MGN_VHT3SS_MCS7, MGN_VHT3SS_MCS8, MGN_VHT3SS_MCS9}; + + /* RTW_INFO("===>PHY_ConvertTxPowerByRateInDbmToRelativeValues()\n" ); */ + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; ++band) { + for (path = ODM_RF_PATH_A; path <= ODM_RF_PATH_D; ++path) { + for (txNum = RF_1TX; txNum < RF_MAX_TX_NUM; ++txNum) { + /* CCK */ + if (band == BAND_ON_2_4G) { + base = PHY_GetTxPowerByRateBase(pAdapter, band, path, txNum, CCK); + for (i = 0; i < sizeof(cckRates); ++i) { + value = PHY_GetTxPowerByRate(pAdapter, band, path, txNum, cckRates[i]); + PHY_SetTxPowerByRate(pAdapter, band, path, txNum, cckRates[i], value - base); + } + } + + /* OFDM */ + base = PHY_GetTxPowerByRateBase(pAdapter, band, path, txNum, OFDM); + for (i = 0; i < sizeof(ofdmRates); ++i) { + value = PHY_GetTxPowerByRate(pAdapter, band, path, txNum, ofdmRates[i]); + PHY_SetTxPowerByRate(pAdapter, band, path, txNum, ofdmRates[i], value - base); + } + + /* HT MCS0~7 */ + base = PHY_GetTxPowerByRateBase(pAdapter, band, path, txNum, HT_1SS); + for (i = 0; i < sizeof(mcs0_7Rates); ++i) { + value = PHY_GetTxPowerByRate(pAdapter, band, path, txNum, mcs0_7Rates[i]); + PHY_SetTxPowerByRate(pAdapter, band, path, txNum, mcs0_7Rates[i], value - base); + } + + /* HT MCS8~15 */ + base = PHY_GetTxPowerByRateBase(pAdapter, band, path, txNum, HT_2SS); + for (i = 0; i < sizeof(mcs8_15Rates); ++i) { + value = PHY_GetTxPowerByRate(pAdapter, band, path, txNum, mcs8_15Rates[i]); + PHY_SetTxPowerByRate(pAdapter, band, path, txNum, mcs8_15Rates[i], value - base); + } + + /* HT MCS16~23 */ + base = PHY_GetTxPowerByRateBase(pAdapter, band, path, txNum, HT_3SS); + for (i = 0; i < sizeof(mcs16_23Rates); ++i) { + value = PHY_GetTxPowerByRate(pAdapter, band, path, txNum, mcs16_23Rates[i]); + PHY_SetTxPowerByRate(pAdapter, band, path, txNum, mcs16_23Rates[i], value - base); + } + + /* VHT 1SS */ + base = PHY_GetTxPowerByRateBase(pAdapter, band, path, txNum, VHT_1SS); + for (i = 0; i < sizeof(vht1ssRates); ++i) { + value = PHY_GetTxPowerByRate(pAdapter, band, path, txNum, vht1ssRates[i]); + PHY_SetTxPowerByRate(pAdapter, band, path, txNum, vht1ssRates[i], value - base); + } + + /* VHT 2SS */ + base = PHY_GetTxPowerByRateBase(pAdapter, band, path, txNum, VHT_2SS); + for (i = 0; i < sizeof(vht2ssRates); ++i) { + value = PHY_GetTxPowerByRate(pAdapter, band, path, txNum, vht2ssRates[i]); + PHY_SetTxPowerByRate(pAdapter, band, path, txNum, vht2ssRates[i], value - base); + } + + /* VHT 3SS */ + base = PHY_GetTxPowerByRateBase(pAdapter, band, path, txNum, VHT_3SS); + for (i = 0; i < sizeof(vht3ssRates); ++i) { + value = PHY_GetTxPowerByRate(pAdapter, band, path, txNum, vht3ssRates[i]); + PHY_SetTxPowerByRate(pAdapter, band, path, txNum, vht3ssRates[i], value - base); + } + } + } + } + + /* RTW_INFO("<===PHY_ConvertTxPowerByRateInDbmToRelativeValues()\n" ); */ +} + +/* + * This function must be called if the value in the PHY_REG_PG.txt(or header) + * is exact dBm values + */ +VOID +PHY_TxPowerByRateConfiguration( + IN PADAPTER pAdapter +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + phy_txpwr_by_rate_chk_for_path_dup(pAdapter); + phy_StoreTxPowerByRateBase(pAdapter); + phy_ConvertTxPowerByRateInDbmToRelativeValues(pAdapter); +} + +VOID +phy_set_tx_power_index_by_rate_section( + IN PADAPTER pAdapter, + IN u8 RFPath, + IN u8 Channel, + IN u8 RateSection +) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); + + if (RateSection >= RATE_SECTION_NUM) { + RTW_INFO("Invalid RateSection %d in %s", RateSection, __func__); + rtw_warn_on(1); + goto exit; + } + + if (RateSection == CCK && pHalData->current_band_type != BAND_ON_2_4G) + goto exit; + + PHY_SetTxPowerIndexByRateArray(pAdapter, RFPath, pHalData->current_channel_bw, Channel, + rates_by_sections[RateSection].rates, rates_by_sections[RateSection].rate_num); + +exit: + return; +} + +BOOLEAN +phy_GetChnlIndex( + IN u8 Channel, + OUT u8 *ChannelIdx +) +{ + u8 i = 0; + BOOLEAN bIn24G = _TRUE; + + if (Channel <= 14) { + bIn24G = _TRUE; + *ChannelIdx = Channel - 1; + } else { + bIn24G = _FALSE; + + for (i = 0; i < CENTER_CH_5G_ALL_NUM; ++i) { + if (center_ch_5g_all[i] == Channel) { + *ChannelIdx = i; + return bIn24G; + } + } + } + + return bIn24G; +} + +u8 +PHY_GetTxPowerIndexBase( + IN PADAPTER pAdapter, + IN u8 RFPath, + IN u8 Rate, + IN CHANNEL_WIDTH BandWidth, + IN u8 Channel, + OUT PBOOLEAN bIn24G +) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + u8 i = 0; /* default set to 1S */ + u8 txPower = 0; + u8 chnlIdx = (Channel - 1); + + if (HAL_IsLegalChannel(pAdapter, Channel) == _FALSE) { + chnlIdx = 0; + RTW_INFO("Illegal channel!!\n"); + } + + *bIn24G = phy_GetChnlIndex(Channel, &chnlIdx); + + /* RTW_INFO("[%s] Channel Index: %d\n", (*bIn24G?"2.4G":"5G"), chnlIdx); */ + + if (*bIn24G) { /* 3 ============================== 2.4 G ============================== */ + if (IS_CCK_RATE(Rate)) + txPower = pHalData->Index24G_CCK_Base[RFPath][chnlIdx]; + else if (MGN_6M <= Rate) + txPower = pHalData->Index24G_BW40_Base[RFPath][chnlIdx]; + else + RTW_INFO("PHY_GetTxPowerIndexBase: INVALID Rate(0x%02x).\n", Rate); + + /* RTW_INFO("Base Tx power(RF-%c, Rate #%d, Channel Index %d) = 0x%X\n", */ + /* ((RFPath==0)?'A':'B'), Rate, chnlIdx, txPower); */ + + /* OFDM-1T */ + if ((MGN_6M <= Rate && Rate <= MGN_54M) && !IS_CCK_RATE(Rate)) { + txPower += pHalData->OFDM_24G_Diff[RFPath][TX_1S]; + /* RTW_INFO("+PowerDiff 2.4G (RF-%c): (OFDM-1T) = (%d)\n", ((RFPath==0)?'A':'B'), pHalData->OFDM_24G_Diff[RFPath][TX_1S]); */ + } + /* BW20-1S, BW20-2S */ + if (BandWidth == CHANNEL_WIDTH_20) { + if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW20_24G_Diff[RFPath][TX_1S]; + if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW20_24G_Diff[RFPath][TX_2S]; + if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW20_24G_Diff[RFPath][TX_3S]; + if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW20_24G_Diff[RFPath][TX_4S]; + + /* RTW_INFO("+PowerDiff 2.4G (RF-%c): (BW20-1S, BW20-2S, BW20-3S, BW20-4S) = (%d, %d, %d, %d)\n", ((RFPath==0)?'A':(RFPath==1)?'B':(RFPath==2)?'C':'D'), */ + /* pHalData->BW20_24G_Diff[RFPath][TX_1S], pHalData->BW20_24G_Diff[RFPath][TX_2S], */ + /* pHalData->BW20_24G_Diff[RFPath][TX_3S], pHalData->BW20_24G_Diff[RFPath][TX_4S]); */ + } + /* BW40-1S, BW40-2S */ + else if (BandWidth == CHANNEL_WIDTH_40) { + if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW40_24G_Diff[RFPath][TX_1S]; + if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW40_24G_Diff[RFPath][TX_2S]; + if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW40_24G_Diff[RFPath][TX_3S]; + if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW40_24G_Diff[RFPath][TX_4S]; + + /* RTW_INFO("+PowerDiff 2.4G (RF-%c): (BW40-1S, BW40-2S, BW40-3S, BW40-4S) = (%d, %d, %d, %d)\n", ((RFPath==0)?'A':(RFPath==1)?'B':(RFPath==2)?'C':'D'), */ + /* pHalData->BW40_24G_Diff[RFPath][TX_1S], pHalData->BW40_24G_Diff[RFPath][TX_2S], */ + /* pHalData->BW40_24G_Diff[RFPath][TX_3S], pHalData->BW40_24G_Diff[RFPath][TX_4S]); */ + } + /* Willis suggest adopt BW 40M power index while in BW 80 mode */ + else if (BandWidth == CHANNEL_WIDTH_80) { + if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW40_24G_Diff[RFPath][TX_1S]; + if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW40_24G_Diff[RFPath][TX_2S]; + if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW40_24G_Diff[RFPath][TX_3S]; + if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW40_24G_Diff[RFPath][TX_4S]; + + /* RTW_INFO("+PowerDiff 2.4G (RF-%c): (BW40-1S, BW40-2S, BW40-3S, BW40-4T) = (%d, %d, %d, %d) P.S. Current is in BW 80MHz\n", ((RFPath==0)?'A':(RFPath==1)?'B':(RFPath==2)?'C':'D'), */ + /* pHalData->BW40_24G_Diff[RFPath][TX_1S], pHalData->BW40_24G_Diff[RFPath][TX_2S], */ + /* pHalData->BW40_24G_Diff[RFPath][TX_3S], pHalData->BW40_24G_Diff[RFPath][TX_4S]); */ + } + } +#ifdef CONFIG_IEEE80211_BAND_5GHZ + else { /* 3 ============================== 5 G ============================== */ + if (MGN_6M <= Rate) + txPower = pHalData->Index5G_BW40_Base[RFPath][chnlIdx]; + else + RTW_INFO("===>PHY_GetTxPowerIndexBase: INVALID Rate(0x%02x).\n", Rate); + + /* RTW_INFO("Base Tx power(RF-%c, Rate #%d, Channel Index %d) = 0x%X\n", */ + /* ((RFPath==0)?'A':'B'), Rate, chnlIdx, txPower); */ + + /* OFDM-1T */ + if ((MGN_6M <= Rate && Rate <= MGN_54M) && !IS_CCK_RATE(Rate)) { + txPower += pHalData->OFDM_5G_Diff[RFPath][TX_1S]; + /* RTW_INFO("+PowerDiff 5G (RF-%c): (OFDM-1T) = (%d)\n", ((RFPath==0)?'A':'B'), pHalData->OFDM_5G_Diff[RFPath][TX_1S]); */ + } + + /* BW20-1S, BW20-2S */ + if (BandWidth == CHANNEL_WIDTH_20) { + if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW20_5G_Diff[RFPath][TX_1S]; + if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW20_5G_Diff[RFPath][TX_2S]; + if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW20_5G_Diff[RFPath][TX_3S]; + if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW20_5G_Diff[RFPath][TX_4S]; + + /* RTW_INFO("+PowerDiff 5G (RF-%c): (BW20-1S, BW20-2S, BW20-3S, BW20-4S) = (%d, %d, %d, %d)\n", ((RFPath==0)?'A':(RFPath==1)?'B':(RFPath==2)?'C':'D'), */ + /* pHalData->BW20_5G_Diff[RFPath][TX_1S], pHalData->BW20_5G_Diff[RFPath][TX_2S], */ + /* pHalData->BW20_5G_Diff[RFPath][TX_3S], pHalData->BW20_5G_Diff[RFPath][TX_4S]); */ + } + /* BW40-1S, BW40-2S */ + else if (BandWidth == CHANNEL_WIDTH_40) { + if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW40_5G_Diff[RFPath][TX_1S]; + if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW40_5G_Diff[RFPath][TX_2S]; + if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW40_5G_Diff[RFPath][TX_3S]; + if ((MGN_MCS24 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW40_5G_Diff[RFPath][TX_4S]; + + /* RTW_INFO("+PowerDiff 5G(RF-%c): (BW40-1S, BW40-2S) = (%d, %d, %d, %d)\n", ((RFPath==0)?'A':(RFPath==1)?'B':(RFPath==2)?'C':'D'), */ + /* pHalData->BW40_5G_Diff[RFPath][TX_1S], pHalData->BW40_5G_Diff[RFPath][TX_2S], */ + /* pHalData->BW40_5G_Diff[RFPath][TX_3S], pHalData->BW40_5G_Diff[RFPath][TX_4S]); */ + } + /* BW80-1S, BW80-2S */ + else if (BandWidth == CHANNEL_WIDTH_80) { + /* <20121220, Kordan> Get the index of array "Index5G_BW80_Base". */ + for (i = 0; i < CENTER_CH_5G_80M_NUM; ++i) + if (center_ch_5g_80m[i] == Channel) + chnlIdx = i; + + txPower = pHalData->Index5G_BW80_Base[RFPath][chnlIdx]; + + if ((MGN_MCS0 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT1SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += + pHalData->BW80_5G_Diff[RFPath][TX_1S]; + if ((MGN_MCS8 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT2SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW80_5G_Diff[RFPath][TX_2S]; + if ((MGN_MCS16 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT3SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW80_5G_Diff[RFPath][TX_3S]; + if ((MGN_MCS23 <= Rate && Rate <= MGN_MCS31) || (MGN_VHT4SS_MCS0 <= Rate && Rate <= MGN_VHT4SS_MCS9)) + txPower += pHalData->BW80_5G_Diff[RFPath][TX_4S]; + + /* RTW_INFO("+PowerDiff 5G(RF-%c): (BW80-1S, BW80-2S, BW80-3S, BW80-4S) = (%d, %d, %d, %d)\n",((RFPath==0)?'A':(RFPath==1)?'B':(RFPath==2)?'C':'D'), */ + /* pHalData->BW80_5G_Diff[RFPath][TX_1S], pHalData->BW80_5G_Diff[RFPath][TX_2S], */ + /* pHalData->BW80_5G_Diff[RFPath][TX_3S], pHalData->BW80_5G_Diff[RFPath][TX_4S]); */ + } + } +#endif /* CONFIG_IEEE80211_BAND_5GHZ */ + + return txPower; +} + +s8 +PHY_GetTxPowerTrackingOffset( + PADAPTER pAdapter, + u8 RFPath, + u8 Rate +) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(pAdapter); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + s8 offset = 0; + + if (pDM_Odm->rf_calibrate_info.txpowertrack_control == _FALSE) + return offset; + + if ((Rate == MGN_1M) || (Rate == MGN_2M) || (Rate == MGN_5_5M) || (Rate == MGN_11M)) { + offset = pDM_Odm->rf_calibrate_info.remnant_cck_swing_idx; + /*RTW_INFO("+Remnant_CCKSwingIdx = 0x%x\n", RFPath, Rate, pRFCalibrateInfo->Remnant_CCKSwingIdx);*/ + } else { + offset = pDM_Odm->rf_calibrate_info.remnant_ofdm_swing_idx[RFPath]; + /*RTW_INFO("+Remanant_OFDMSwingIdx[RFPath %u][Rate 0x%x] = 0x%x\n", RFPath, Rate, pRFCalibrateInfo->Remnant_OFDMSwingIdx[RFPath]); */ + + } + + return offset; +} + +/*The same as MRateToHwRate in hal_com.c*/ +u8 +PHY_GetRateIndexOfTxPowerByRate( + IN u8 Rate +) +{ + u8 index = 0; + switch (Rate) { + case MGN_1M: + index = 0; + break; + case MGN_2M: + index = 1; + break; + case MGN_5_5M: + index = 2; + break; + case MGN_11M: + index = 3; + break; + case MGN_6M: + index = 4; + break; + case MGN_9M: + index = 5; + break; + case MGN_12M: + index = 6; + break; + case MGN_18M: + index = 7; + break; + case MGN_24M: + index = 8; + break; + case MGN_36M: + index = 9; + break; + case MGN_48M: + index = 10; + break; + case MGN_54M: + index = 11; + break; + case MGN_MCS0: + index = 12; + break; + case MGN_MCS1: + index = 13; + break; + case MGN_MCS2: + index = 14; + break; + case MGN_MCS3: + index = 15; + break; + case MGN_MCS4: + index = 16; + break; + case MGN_MCS5: + index = 17; + break; + case MGN_MCS6: + index = 18; + break; + case MGN_MCS7: + index = 19; + break; + case MGN_MCS8: + index = 20; + break; + case MGN_MCS9: + index = 21; + break; + case MGN_MCS10: + index = 22; + break; + case MGN_MCS11: + index = 23; + break; + case MGN_MCS12: + index = 24; + break; + case MGN_MCS13: + index = 25; + break; + case MGN_MCS14: + index = 26; + break; + case MGN_MCS15: + index = 27; + break; + case MGN_MCS16: + index = 28; + break; + case MGN_MCS17: + index = 29; + break; + case MGN_MCS18: + index = 30; + break; + case MGN_MCS19: + index = 31; + break; + case MGN_MCS20: + index = 32; + break; + case MGN_MCS21: + index = 33; + break; + case MGN_MCS22: + index = 34; + break; + case MGN_MCS23: + index = 35; + break; + case MGN_MCS24: + index = 36; + break; + case MGN_MCS25: + index = 37; + break; + case MGN_MCS26: + index = 38; + break; + case MGN_MCS27: + index = 39; + break; + case MGN_MCS28: + index = 40; + break; + case MGN_MCS29: + index = 41; + break; + case MGN_MCS30: + index = 42; + break; + case MGN_MCS31: + index = 43; + break; + case MGN_VHT1SS_MCS0: + index = 44; + break; + case MGN_VHT1SS_MCS1: + index = 45; + break; + case MGN_VHT1SS_MCS2: + index = 46; + break; + case MGN_VHT1SS_MCS3: + index = 47; + break; + case MGN_VHT1SS_MCS4: + index = 48; + break; + case MGN_VHT1SS_MCS5: + index = 49; + break; + case MGN_VHT1SS_MCS6: + index = 50; + break; + case MGN_VHT1SS_MCS7: + index = 51; + break; + case MGN_VHT1SS_MCS8: + index = 52; + break; + case MGN_VHT1SS_MCS9: + index = 53; + break; + case MGN_VHT2SS_MCS0: + index = 54; + break; + case MGN_VHT2SS_MCS1: + index = 55; + break; + case MGN_VHT2SS_MCS2: + index = 56; + break; + case MGN_VHT2SS_MCS3: + index = 57; + break; + case MGN_VHT2SS_MCS4: + index = 58; + break; + case MGN_VHT2SS_MCS5: + index = 59; + break; + case MGN_VHT2SS_MCS6: + index = 60; + break; + case MGN_VHT2SS_MCS7: + index = 61; + break; + case MGN_VHT2SS_MCS8: + index = 62; + break; + case MGN_VHT2SS_MCS9: + index = 63; + break; + case MGN_VHT3SS_MCS0: + index = 64; + break; + case MGN_VHT3SS_MCS1: + index = 65; + break; + case MGN_VHT3SS_MCS2: + index = 66; + break; + case MGN_VHT3SS_MCS3: + index = 67; + break; + case MGN_VHT3SS_MCS4: + index = 68; + break; + case MGN_VHT3SS_MCS5: + index = 69; + break; + case MGN_VHT3SS_MCS6: + index = 70; + break; + case MGN_VHT3SS_MCS7: + index = 71; + break; + case MGN_VHT3SS_MCS8: + index = 72; + break; + case MGN_VHT3SS_MCS9: + index = 73; + break; + case MGN_VHT4SS_MCS0: + index = 74; + break; + case MGN_VHT4SS_MCS1: + index = 75; + break; + case MGN_VHT4SS_MCS2: + index = 76; + break; + case MGN_VHT4SS_MCS3: + index = 77; + break; + case MGN_VHT4SS_MCS4: + index = 78; + break; + case MGN_VHT4SS_MCS5: + index = 79; + break; + case MGN_VHT4SS_MCS6: + index = 80; + break; + case MGN_VHT4SS_MCS7: + index = 81; + break; + case MGN_VHT4SS_MCS8: + index = 82; + break; + case MGN_VHT4SS_MCS9: + index = 83; + break; + default: + RTW_INFO("Invalid rate 0x%x in %s\n", Rate, __FUNCTION__); + break; + }; + + return index; +} + +s8 +_PHY_GetTxPowerByRate( + IN PADAPTER pAdapter, + IN u8 Band, + IN u8 RFPath, + IN u8 TxNum, + IN u8 Rate +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + s8 value = 0; + u8 rateIndex = PHY_GetRateIndexOfTxPowerByRate(Rate); + + if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) { + RTW_INFO("Invalid band %d in %s\n", Band, __func__); + goto exit; + } + if (RFPath > ODM_RF_PATH_D) { + RTW_INFO("Invalid RfPath %d in %s\n", RFPath, __func__); + goto exit; + } + if (TxNum >= RF_MAX_TX_NUM) { + RTW_INFO("Invalid TxNum %d in %s\n", TxNum, __func__); + goto exit; + } + if (rateIndex >= TX_PWR_BY_RATE_NUM_RATE) { + RTW_INFO("Invalid RateIndex %d in %s\n", rateIndex, __func__); + goto exit; + } + + value = pHalData->TxPwrByRateOffset[Band][RFPath][TxNum][rateIndex]; + +exit: + return value; +} + + +s8 +PHY_GetTxPowerByRate( + IN PADAPTER pAdapter, + IN u8 Band, + IN u8 RFPath, + IN u8 TxNum, + IN u8 Rate +) +{ + if (!phy_is_tx_power_by_rate_needed(pAdapter)) + return 0; + + return _PHY_GetTxPowerByRate(pAdapter, Band, RFPath, TxNum, Rate); +} + +#ifdef CONFIG_PHYDM_POWERTRACK_BY_TSSI +s8 +PHY_GetTxPowerByRateOriginal( + IN PADAPTER pAdapter, + IN u8 Band, + IN u8 RFPath, + IN u8 TxNum, + IN u8 Rate +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + s8 value = 0, limit = 0; + u8 rateIndex = PHY_GetRateIndexOfTxPowerByRate(Rate); + + if ((pAdapter->registrypriv.RegEnableTxPowerByRate == 2 && pHalData->EEPROMRegulatory == 2) || + pAdapter->registrypriv.RegEnableTxPowerByRate == 0) + return 0; + + if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) { + DBG_871X("Invalid band %d in %s\n", Band, __func__); + return value; + } + if (RFPath > ODM_RF_PATH_D) { + DBG_871X("Invalid RfPath %d in %s\n", RFPath, __func__); + return value; + } + if (TxNum >= RF_MAX_TX_NUM) { + DBG_871X("Invalid TxNum %d in %s\n", TxNum, __func__); + return value; + } + if (rateIndex >= TX_PWR_BY_RATE_NUM_RATE) { + DBG_871X("Invalid RateIndex %d in %s\n", rateIndex, __func__); + return value; + } + + value = pHalData->TxPwrByRate[Band][RFPath][TxNum][rateIndex]; + + return value; +} + +#endif + + +VOID +PHY_SetTxPowerByRate( + IN PADAPTER pAdapter, + IN u8 Band, + IN u8 RFPath, + IN u8 TxNum, + IN u8 Rate, + IN s8 Value +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + u8 rateIndex = PHY_GetRateIndexOfTxPowerByRate(Rate); + + if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) { + RTW_INFO("Invalid band %d in %s\n", Band, __FUNCTION__); + return; + } + if (RFPath > ODM_RF_PATH_D) { + RTW_INFO("Invalid RfPath %d in %s\n", RFPath, __FUNCTION__); + return; + } + if (TxNum >= RF_MAX_TX_NUM) { + RTW_INFO("Invalid TxNum %d in %s\n", TxNum, __FUNCTION__); + return; + } + if (rateIndex >= TX_PWR_BY_RATE_NUM_RATE) { + RTW_INFO("Invalid RateIndex %d in %s\n", rateIndex, __FUNCTION__); + return; + } + + pHalData->TxPwrByRateOffset[Band][RFPath][TxNum][rateIndex] = Value; +} + +VOID +phy_set_tx_power_level_by_path( + IN PADAPTER Adapter, + IN u8 channel, + IN u8 path +) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); + BOOLEAN bIsIn24G = (pHalData->current_band_type == BAND_ON_2_4G); + + /* if ( pMgntInfo->RegNByteAccess == 0 ) */ + { + if (bIsIn24G) + phy_set_tx_power_index_by_rate_section(Adapter, path, channel, CCK); + + phy_set_tx_power_index_by_rate_section(Adapter, path, channel, OFDM); + phy_set_tx_power_index_by_rate_section(Adapter, path, channel, HT_MCS0_MCS7); + + if (IS_HARDWARE_TYPE_JAGUAR(Adapter) || IS_HARDWARE_TYPE_8814A(Adapter)) + phy_set_tx_power_index_by_rate_section(Adapter, path, channel, VHT_1SSMCS0_1SSMCS9); + + if (pHalData->NumTotalRFPath >= 2) { + phy_set_tx_power_index_by_rate_section(Adapter, path, channel, HT_MCS8_MCS15); + + if (IS_HARDWARE_TYPE_JAGUAR(Adapter) || IS_HARDWARE_TYPE_8814A(Adapter)) + phy_set_tx_power_index_by_rate_section(Adapter, path, channel, VHT_2SSMCS0_2SSMCS9); + + if (IS_HARDWARE_TYPE_8814A(Adapter)) { + phy_set_tx_power_index_by_rate_section(Adapter, path, channel, HT_MCS16_MCS23); + phy_set_tx_power_index_by_rate_section(Adapter, path, channel, VHT_3SSMCS0_3SSMCS9); + } + } + } +} + +#ifndef DBG_TX_POWER_IDX +#define DBG_TX_POWER_IDX 0 +#endif + +VOID +PHY_SetTxPowerIndexByRateArray( + IN PADAPTER pAdapter, + IN u8 RFPath, + IN CHANNEL_WIDTH BandWidth, + IN u8 Channel, + IN u8 *Rates, + IN u8 RateArraySize +) +{ + u32 powerIndex = 0; + int i = 0; + + for (i = 0; i < RateArraySize; ++i) { +#if DBG_TX_POWER_IDX + struct txpwr_idx_comp tic; + + powerIndex = rtw_hal_get_tx_power_index(pAdapter, RFPath, Rates[i], BandWidth, Channel, &tic); + RTW_INFO("TXPWR: [%c][%s]ch:%u, %s, pwr_idx:%u = %u + (%d=%d:%d) + (%d) + (%d)\n" + , rf_path_char(RFPath), ch_width_str(BandWidth), Channel, MGN_RATE_STR(Rates[i]) + , powerIndex, tic.base, (tic.by_rate > tic.limit ? tic.limit : tic.by_rate), tic.by_rate, tic.limit, tic.tpt, tic.ebias); +#else + powerIndex = phy_get_tx_power_index(pAdapter, RFPath, Rates[i], BandWidth, Channel); +#endif + PHY_SetTxPowerIndex(pAdapter, powerIndex, RFPath, Rates[i]); + } +} + +s8 +phy_GetWorldWideLimit( + s8 *LimitTable +) +{ + s8 min = LimitTable[0]; + u8 i = 0; + + for (i = 0; i < MAX_REGULATION_NUM; ++i) { + if (LimitTable[i] < min) + min = LimitTable[i]; + } + + return min; +} + +s8 +phy_GetChannelIndexOfTxPowerLimit( + IN u8 Band, + IN u8 Channel +) +{ + s8 channelIndex = -1; + u8 i = 0; + + if (Band == BAND_ON_2_4G) + channelIndex = Channel - 1; + else if (Band == BAND_ON_5G) { + for (i = 0; i < CENTER_CH_5G_ALL_NUM; ++i) { + if (center_ch_5g_all[i] == Channel) + channelIndex = i; + } + } else + RTW_PRINT("Invalid Band %d in %s\n", Band, __func__); + + if (channelIndex == -1) + RTW_PRINT("Invalid Channel %d of Band %d in %s\n", Channel, Band, __func__); + + return channelIndex; +} + +static s8 _phy_get_txpwr_lmt( + IN PADAPTER Adapter, + IN u32 RegPwrTblSel, + IN BAND_TYPE Band, + IN CHANNEL_WIDTH Bandwidth, + IN u8 RfPath, + IN u8 DataRate, + IN u8 Channel, + BOOLEAN no_sc +) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(Adapter); + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(Adapter); + s8 regulation = -1, bw = -1, rs = -1; + u8 cch = 0; + u8 bw_bmp = 0; + s8 min_lmt = MAX_POWER_INDEX; + s8 tmp_lmt; + u8 final_bw = Bandwidth, final_cch = Channel; + + if ((Adapter->registrypriv.RegEnableTxPowerLimit == 2 && hal_data->EEPROMRegulatory != 1) || + Adapter->registrypriv.RegEnableTxPowerLimit == 0) + goto exit; + + switch (RegPwrTblSel) { + case 1: + regulation = TXPWR_LMT_ETSI; + break; + case 2: + regulation = TXPWR_LMT_MKK; + break; + case 3: + regulation = TXPWR_LMT_FCC; + break; + case 4: + regulation = TXPWR_LMT_WW; + break; + default: + regulation = (Band == BAND_ON_2_4G) ? hal_data->Regulation2_4G : hal_data->Regulation5G; + break; + } + + if (Band != BAND_ON_2_4G && Band != BAND_ON_5G) { + RTW_ERR("%s invalid band:%u\n", __func__, Band); + rtw_warn_on(1); + goto exit; + } + + if (IS_CCK_RATE(DataRate)) + rs = CCK; + else if (IS_OFDM_RATE(DataRate)) + rs = OFDM; + else if (IS_HT1SS_RATE(DataRate)) + rs = HT_1SS; + else if (IS_HT2SS_RATE(DataRate)) + rs = HT_2SS; + else if (IS_HT3SS_RATE(DataRate)) + rs = HT_3SS; + else if (IS_HT4SS_RATE(DataRate)) + rs = HT_4SS; + else if (IS_VHT1SS_RATE(DataRate)) + rs = VHT_1SS; + else if (IS_VHT2SS_RATE(DataRate)) + rs = VHT_2SS; + else if (IS_VHT3SS_RATE(DataRate)) + rs = VHT_3SS; + else if (IS_VHT4SS_RATE(DataRate)) + rs = VHT_4SS; + else { + RTW_ERR("%s invalid rate 0x%x\n", __func__, DataRate); + rtw_warn_on(1); + goto exit; + } + + if (Band == BAND_ON_5G && rs == CCK) { + RTW_ERR("Wrong rate No CCK(0x%x) in 5G Band\n", DataRate); + goto exit; + } + + if (no_sc == _TRUE) { + /* use the input center channel and bandwidth directly */ + cch = Channel; + bw_bmp = ch_width_to_bw_cap(Bandwidth); + } else { + /* + * find the possible tx bandwidth bmp for this rate, and then will get center channel for each bandwidth + * if no possible tx bandwidth bmp, select valid bandwidth up to current RF bandwidth into bmp + */ + if (rs == CCK || rs == OFDM) + bw_bmp = BW_CAP_20M; /* CCK, OFDM only BW 20M */ + else if (IS_HT_RATE_SECTION(rs)) { + bw_bmp = rtw_get_tx_bw_bmp_of_ht_rate(dvobj, DataRate, Bandwidth); + if (bw_bmp == 0) + bw_bmp = ch_width_to_bw_cap(Bandwidth > CHANNEL_WIDTH_40 ? CHANNEL_WIDTH_40 : Bandwidth); + } else if (IS_VHT_RATE_SECTION(rs)) { + bw_bmp = rtw_get_tx_bw_bmp_of_vht_rate(dvobj, DataRate, Bandwidth); + if (bw_bmp == 0) + bw_bmp = ch_width_to_bw_cap(Bandwidth > CHANNEL_WIDTH_160 ? CHANNEL_WIDTH_160 : Bandwidth); + } else + rtw_warn_on(1); + } + + if (bw_bmp == 0) + goto exit; + + /* loop for each possible tx bandwidth to find minimum limit */ + for (bw = CHANNEL_WIDTH_20; bw <= Bandwidth; bw++) { + s8 ch_idx; + + if (!(ch_width_to_bw_cap(bw) & bw_bmp)) + continue; + + if (no_sc == _FALSE) { + if (bw == CHANNEL_WIDTH_20) + cch = hal_data->cch_20; + else if (bw == CHANNEL_WIDTH_40) + cch = hal_data->cch_40; + else if (bw == CHANNEL_WIDTH_80) + cch = hal_data->cch_80; + else { + cch = 0; + rtw_warn_on(1); + } + } + + ch_idx = phy_GetChannelIndexOfTxPowerLimit(Band, cch); + if (ch_idx == -1) + continue; + + if (Band == BAND_ON_2_4G) { + s8 limits[MAX_REGULATION_NUM] = {0}; + u8 i = 0; + + for (i = 0; i < MAX_REGULATION_NUM; ++i) + limits[i] = hal_data->TxPwrLimit_2_4G[i][bw][rs][ch_idx][RfPath]; + + tmp_lmt = (regulation == TXPWR_LMT_WW) ? phy_GetWorldWideLimit(limits) : + hal_data->TxPwrLimit_2_4G[regulation][bw][rs][ch_idx][RfPath]; + + } else if (Band == BAND_ON_5G) { + s8 limits[MAX_REGULATION_NUM] = {0}; + u8 i = 0; + + for (i = 0; i < MAX_REGULATION_NUM; ++i) + limits[i] = hal_data->TxPwrLimit_5G[i][bw][rs][ch_idx][RfPath]; + + tmp_lmt = (regulation == TXPWR_LMT_WW) ? phy_GetWorldWideLimit(limits) : + hal_data->TxPwrLimit_5G[regulation][bw][rs][ch_idx][RfPath]; + } else + continue; + + if (min_lmt >= tmp_lmt) { + min_lmt = tmp_lmt; + final_cch = cch; + final_bw = bw; + } + } + +exit: + return min_lmt; +} + +inline s8 +PHY_GetTxPowerLimit( + IN PADAPTER Adapter, + IN u32 RegPwrTblSel, + IN BAND_TYPE Band, + IN CHANNEL_WIDTH Bandwidth, + IN u8 RfPath, + IN u8 DataRate, + IN u8 Channel +) +{ + BOOLEAN no_sc = _FALSE; + + /* MP mode channel don't use secondary channel */ + if (rtw_mi_mp_mode_check(Adapter) == _TRUE) + no_sc = _TRUE; + + return _phy_get_txpwr_lmt(Adapter, RegPwrTblSel, Band, Bandwidth, RfPath, DataRate, Channel, no_sc); +} + +inline s8 +PHY_GetTxPowerLimit_no_sc( + IN PADAPTER Adapter, + IN u32 RegPwrTblSel, + IN BAND_TYPE Band, + IN CHANNEL_WIDTH Bandwidth, + IN u8 RfPath, + IN u8 DataRate, + IN u8 Channel +) +{ + return _phy_get_txpwr_lmt(Adapter, RegPwrTblSel, Band, Bandwidth, RfPath, DataRate, Channel, _TRUE); +} + +#ifdef CONFIG_PHYDM_POWERTRACK_BY_TSSI +s8 +PHY_GetTxPowerLimitOriginal( + IN PADAPTER Adapter, + IN u32 RegPwrTblSel, + IN BAND_TYPE Band, + IN CHANNEL_WIDTH Bandwidth, + IN u8 RfPath, + IN u8 DataRate, + IN u8 Channel +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + s16 band = -1, regulation = -1, bandwidth = -1, + rateSection = -1, channel = -1; + s8 powerLimit = MAX_POWER_INDEX; + + if ((Adapter->registrypriv.RegEnableTxPowerLimit == 2 && pHalData->EEPROMRegulatory != 1) || + Adapter->registrypriv.RegEnableTxPowerLimit == 0) + return MAX_POWER_INDEX; + + switch (Adapter->registrypriv.RegPwrTblSel) { + case 1: + regulation = TXPWR_LMT_ETSI; + break; + + case 2: + regulation = TXPWR_LMT_MKK; + break; + + case 3: + regulation = TXPWR_LMT_FCC; + break; + + case 4: + regulation = TXPWR_LMT_WW; + break; + + default: + regulation = (Band == BAND_ON_2_4G) ? pHalData->Regulation2_4G + : pHalData->Regulation5G; + break; + } + + /*DBG_871X("pMgntInfo->RegPwrTblSel %d, final regulation %d\n", Adapter->registrypriv.RegPwrTblSel, regulation );*/ + + + if (Band == BAND_ON_2_4G) + band = 0; + else if (Band == BAND_ON_5G) + band = 1; + + if (Bandwidth == CHANNEL_WIDTH_20) + bandwidth = 0; + else if (Bandwidth == CHANNEL_WIDTH_40) + bandwidth = 1; + else if (Bandwidth == CHANNEL_WIDTH_80) + bandwidth = 2; + else if (Bandwidth == CHANNEL_WIDTH_160) + bandwidth = 3; + + switch (DataRate) { + case MGN_1M: + case MGN_2M: + case MGN_5_5M: + case MGN_11M: + rateSection = 0; + break; + + case MGN_6M: + case MGN_9M: + case MGN_12M: + case MGN_18M: + case MGN_24M: + case MGN_36M: + case MGN_48M: + case MGN_54M: + rateSection = 1; + break; + + case MGN_MCS0: + case MGN_MCS1: + case MGN_MCS2: + case MGN_MCS3: + case MGN_MCS4: + case MGN_MCS5: + case MGN_MCS6: + case MGN_MCS7: + rateSection = 2; + break; + + case MGN_MCS8: + case MGN_MCS9: + case MGN_MCS10: + case MGN_MCS11: + case MGN_MCS12: + case MGN_MCS13: + case MGN_MCS14: + case MGN_MCS15: + rateSection = 3; + break; + + case MGN_MCS16: + case MGN_MCS17: + case MGN_MCS18: + case MGN_MCS19: + case MGN_MCS20: + case MGN_MCS21: + case MGN_MCS22: + case MGN_MCS23: + rateSection = 4; + break; + + case MGN_MCS24: + case MGN_MCS25: + case MGN_MCS26: + case MGN_MCS27: + case MGN_MCS28: + case MGN_MCS29: + case MGN_MCS30: + case MGN_MCS31: + rateSection = 5; + break; + + case MGN_VHT1SS_MCS0: + case MGN_VHT1SS_MCS1: + case MGN_VHT1SS_MCS2: + case MGN_VHT1SS_MCS3: + case MGN_VHT1SS_MCS4: + case MGN_VHT1SS_MCS5: + case MGN_VHT1SS_MCS6: + case MGN_VHT1SS_MCS7: + case MGN_VHT1SS_MCS8: + case MGN_VHT1SS_MCS9: + rateSection = 6; + break; + + case MGN_VHT2SS_MCS0: + case MGN_VHT2SS_MCS1: + case MGN_VHT2SS_MCS2: + case MGN_VHT2SS_MCS3: + case MGN_VHT2SS_MCS4: + case MGN_VHT2SS_MCS5: + case MGN_VHT2SS_MCS6: + case MGN_VHT2SS_MCS7: + case MGN_VHT2SS_MCS8: + case MGN_VHT2SS_MCS9: + rateSection = 7; + break; + + case MGN_VHT3SS_MCS0: + case MGN_VHT3SS_MCS1: + case MGN_VHT3SS_MCS2: + case MGN_VHT3SS_MCS3: + case MGN_VHT3SS_MCS4: + case MGN_VHT3SS_MCS5: + case MGN_VHT3SS_MCS6: + case MGN_VHT3SS_MCS7: + case MGN_VHT3SS_MCS8: + case MGN_VHT3SS_MCS9: + rateSection = 8; + break; + + case MGN_VHT4SS_MCS0: + case MGN_VHT4SS_MCS1: + case MGN_VHT4SS_MCS2: + case MGN_VHT4SS_MCS3: + case MGN_VHT4SS_MCS4: + case MGN_VHT4SS_MCS5: + case MGN_VHT4SS_MCS6: + case MGN_VHT4SS_MCS7: + case MGN_VHT4SS_MCS8: + case MGN_VHT4SS_MCS9: + rateSection = 9; + break; + + default: + DBG_871X("Wrong rate 0x%x\n", DataRate); + break; + } + + if (Band == BAND_ON_5G && rateSection == 0) + DBG_871X("Wrong rate 0x%x: No CCK in 5G Band\n", DataRate); + + /*workaround for wrong index combination to obtain tx power limit,*/ + /*OFDM only exists in BW 20M*/ + if (rateSection == 1) + bandwidth = 0; + + /*workaround for wrong index combination to obtain tx power limit,*/ + /*CCK table will only be given in BW 20M*/ + if (rateSection == 0) + bandwidth = 0; + + /*workaround for wrong indxe combination to obtain tx power limit,*/ + /*HT on 80M will reference to HT on 40M*/ + if ((rateSection == 2 || rateSection == 3) && Band == BAND_ON_5G && bandwidth == 2) + bandwidth = 1; + + if (Band == BAND_ON_2_4G) + channel = phy_GetChannelIndexOfTxPowerLimit(BAND_ON_2_4G, Channel); + else if (Band == BAND_ON_5G) + channel = phy_GetChannelIndexOfTxPowerLimit(BAND_ON_5G, Channel); + else if (Band == BAND_ON_BOTH) + /*BAND_ON_BOTH don't care temporarily*/ + + if (band == -1 || regulation == -1 || bandwidth == -1 || + rateSection == -1 || channel == -1) { + /*DBG_871X("Wrong index value to access power limit table [band %d][regulation %d][bandwidth %d][rf_path %d][rate_section %d][chnlGroup %d]\n",*/ + /* band, regulation, bandwidth, RfPath, rateSection, channelGroup );*/ + + return MAX_POWER_INDEX; + } + + if (Band == BAND_ON_2_4G) { + s8 limits[10] = {0}; + u8 i = 0; + + if (bandwidth >= MAX_2_4G_BANDWIDTH_NUM) + bandwidth = MAX_2_4G_BANDWIDTH_NUM - 1; + + for (i = 0; i < MAX_REGULATION_NUM; ++i) + limits[i] = pHalData->TxPwrLimit_2_4G_Original[i][bandwidth][rateSection][channel][RfPath]; + + powerLimit = (regulation == TXPWR_LMT_WW) ? phy_GetWorldWideLimit(limits) : + pHalData->TxPwrLimit_2_4G_Original[regulation][bandwidth][rateSection][channel][RfPath]; + + } else if (Band == BAND_ON_5G) { + s8 limits[10] = {0}; + u8 i = 0; + + for (i = 0; i < MAX_REGULATION_NUM; ++i) + limits[i] = pHalData->TxPwrLimit_5G_Original[i][bandwidth][rateSection][channel][RfPath]; + + powerLimit = (regulation == TXPWR_LMT_WW) ? phy_GetWorldWideLimit(limits) : + pHalData->TxPwrLimit_5G_Original[regulation][bandwidth][rateSection][channel][RfPath]; + } else + DBG_871X("No power limit table of the specified band\n"); + + /*combine 5G VHT & HT rate*/ + /*5G 20M and 40M HT and VHT can cross reference*/ + /* + if (Band == BAND_ON_5G && powerLimit == MAX_POWER_INDEX) { + if (bandwidth == 0 || bandwidth == 1) { + if (rateSection == 2) + powerLimit = pHalData->TxPwrLimit_5G_Original[regulation] + [bandwidth][4][channelGroup][RfPath]; + else if (rateSection == 4) + powerLimit = pHalData->TxPwrLimit_5G_Original[regulation] + [bandwidth][2][channelGroup][RfPath]; + else if (rateSection == 3) + powerLimit = pHalData->TxPwrLimit_5G_Original[regulation] + [bandwidth][5][channelGroup][RfPath]; + else if (rateSection == 5) + powerLimit = pHalData->TxPwrLimit_5G_Original[regulation] + [bandwidth][3][channelGroup][RfPath]; + } + } + */ + /*DBG_871X("TxPwrLmt[Regulation %d][Band %d][BW %d][RFPath %d][Rate 0x%x][Chnl %d] = %d\n",*/ + /* regulation, pHalData->current_band_type, Bandwidth, RfPath, DataRate, Channel, powerLimit);*/ + return powerLimit; +} +#endif + + +VOID +phy_CrossReferenceHTAndVHTTxPowerLimit( + IN PADAPTER pAdapter +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + u8 regulation, bw, channel, rs, ref_rs; + int ht_ref_vht_5g_20_40 = 0; + int vht_ref_ht_5g_20_40 = 0; + int ht_has_ref_5g_20_40 = 0; + int vht_has_ref_5g_20_40 = 0; + + pHalData->tx_pwr_lmt_5g_20_40_ref = 0; + + for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) { + + for (bw = 0; bw < MAX_5G_BANDWIDTH_NUM; ++bw) { + + for (channel = 0; channel < CENTER_CH_5G_ALL_NUM; ++channel) { + + for (rs = 0; rs < MAX_RATE_SECTION_NUM; ++rs) { + + /* 5G 20M 40M VHT and HT can cross reference */ + if (bw == CHANNEL_WIDTH_20 || bw == CHANNEL_WIDTH_40) { + if (rs == HT_1SS) + ref_rs = VHT_1SS; + else if (rs == HT_2SS) + ref_rs = VHT_2SS; + else if (rs == HT_3SS) + ref_rs = VHT_3SS; + else if (rs == HT_4SS) + ref_rs = VHT_4SS; + else if (rs == VHT_1SS) + ref_rs = HT_1SS; + else if (rs == VHT_2SS) + ref_rs = HT_2SS; + else if (rs == VHT_3SS) + ref_rs = HT_3SS; + else if (rs == VHT_4SS) + ref_rs = HT_4SS; + else + continue; + + if (pHalData->TxPwrLimit_5G[regulation][bw][ref_rs][channel][RF_PATH_A] == MAX_POWER_INDEX) + continue; + + if (IS_HT_RATE_SECTION(rs)) + ht_has_ref_5g_20_40++; + else if (IS_VHT_RATE_SECTION(rs)) + vht_has_ref_5g_20_40++; + else + continue; + + if (pHalData->TxPwrLimit_5G[regulation][bw][rs][channel][RF_PATH_A] != MAX_POWER_INDEX) + continue; + + if (IS_HT_RATE_SECTION(rs) && IS_VHT_RATE_SECTION(ref_rs)) + ht_ref_vht_5g_20_40++; + else if (IS_VHT_RATE_SECTION(rs) && IS_HT_RATE_SECTION(ref_rs)) + vht_ref_ht_5g_20_40++; + + if (0) + RTW_INFO("reg:%u, bw:%u, ch:%u, %s ref %s\n" + , regulation, bw, channel + , rate_section_str(rs), rate_section_str(ref_rs)); + + pHalData->TxPwrLimit_5G[regulation][bw][rs][channel][RF_PATH_A] = + pHalData->TxPwrLimit_5G[regulation][bw][ref_rs][channel][RF_PATH_A]; + } + + } + } + } + } + + if (0) { + RTW_INFO("ht_ref_vht_5g_20_40:%d, ht_has_ref_5g_20_40:%d\n", ht_ref_vht_5g_20_40, ht_has_ref_5g_20_40); + RTW_INFO("vht_ref_hht_5g_20_40:%d, vht_has_ref_5g_20_40:%d\n", vht_ref_ht_5g_20_40, vht_has_ref_5g_20_40); + } + + /* 5G 20M&40M HT all come from VHT*/ + if (ht_ref_vht_5g_20_40 && ht_has_ref_5g_20_40 == ht_ref_vht_5g_20_40) + pHalData->tx_pwr_lmt_5g_20_40_ref |= TX_PWR_LMT_REF_HT_FROM_VHT; + + /* 5G 20M&40M VHT all come from HT*/ + if (vht_ref_ht_5g_20_40 && vht_has_ref_5g_20_40 == vht_ref_ht_5g_20_40) + pHalData->tx_pwr_lmt_5g_20_40_ref |= TX_PWR_LMT_REF_VHT_FROM_HT; +} + +VOID +PHY_ConvertTxPowerLimitToPowerIndex( + IN PADAPTER Adapter +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + u8 base; + u8 regulation, bw, channel, rateSection; + s8 tempValue = 0, tempPwrLmt = 0; + u8 rfPath = 0; + + if (pHalData->odmpriv.phy_reg_pg_value_type != PHY_REG_PG_EXACT_VALUE) { + rtw_warn_on(1); + return; + } + + phy_CrossReferenceHTAndVHTTxPowerLimit(Adapter); + + for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) { + + for (bw = 0; bw < MAX_2_4G_BANDWIDTH_NUM; ++bw) { + + for (channel = 0; channel < CENTER_CH_2G_NUM; ++channel) { + + for (rateSection = CCK; rateSection <= HT_4SS; ++rateSection) { + tempPwrLmt = pHalData->TxPwrLimit_2_4G[regulation][bw][rateSection][channel][RF_PATH_A]; + + if (tempPwrLmt != MAX_POWER_INDEX) { + + for (rfPath = RF_PATH_A; rfPath < MAX_RF_PATH; ++rfPath) { + base = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_2_4G, rfPath, rate_section_to_tx_num(rateSection), rateSection); + tempValue = tempPwrLmt - base; + pHalData->TxPwrLimit_2_4G[regulation][bw][rateSection][channel][rfPath] = tempValue; + } + } + } + } + } + } + + if (IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(Adapter)) { + + for (regulation = 0; regulation < MAX_REGULATION_NUM; ++regulation) { + + for (bw = 0; bw < MAX_5G_BANDWIDTH_NUM; ++bw) { + + for (channel = 0; channel < CENTER_CH_5G_ALL_NUM; ++channel) { + + for (rateSection = OFDM; rateSection <= VHT_4SS; ++rateSection) { + tempPwrLmt = pHalData->TxPwrLimit_5G[regulation][bw][rateSection][channel][RF_PATH_A]; + + if (tempPwrLmt != MAX_POWER_INDEX) { + + for (rfPath = RF_PATH_A; rfPath < MAX_RF_PATH; ++rfPath) { + base = PHY_GetTxPowerByRateBase(Adapter, BAND_ON_5G, rfPath, rate_section_to_tx_num(rateSection), rateSection); + tempValue = tempPwrLmt - base; + pHalData->TxPwrLimit_5G[regulation][bw][rateSection][channel][rfPath] = tempValue; + } + } + } + } + } + } + } +} + +/* +* PHY_InitTxPowerLimit - Set all hal_data.TxPwrLimit_2_4G, TxPwrLimit_5G array to MAX_POWER_INDEX +*/ +VOID +PHY_InitTxPowerLimit( + IN PADAPTER Adapter +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + u8 i, j, k, l, m; + + for (i = 0; i < MAX_REGULATION_NUM; ++i) + for (j = 0; j < MAX_2_4G_BANDWIDTH_NUM; ++j) + for (k = 0; k < MAX_RATE_SECTION_NUM; ++k) + for (m = 0; m < CENTER_CH_2G_NUM; ++m) + for (l = 0; l < MAX_RF_PATH; ++l) + pHalData->TxPwrLimit_2_4G[i][j][k][m][l] = MAX_POWER_INDEX; + + for (i = 0; i < MAX_REGULATION_NUM; ++i) + for (j = 0; j < MAX_5G_BANDWIDTH_NUM; ++j) + for (k = 0; k < MAX_RATE_SECTION_NUM; ++k) + for (m = 0; m < CENTER_CH_5G_ALL_NUM; ++m) + for (l = 0; l < MAX_RF_PATH; ++l) + pHalData->TxPwrLimit_5G[i][j][k][m][l] = MAX_POWER_INDEX; +} + +/* +* phy_set_tx_power_limit - Parsing TX power limit from phydm array, called by odm_ConfigBB_TXPWR_LMT_XXX in phydm +*/ +VOID +phy_set_tx_power_limit( + IN struct PHY_DM_STRUCT *pDM_Odm, + IN u8 *Regulation, + IN u8 *Band, + IN u8 *Bandwidth, + IN u8 *RateSection, + IN u8 *RfPath, + IN u8 *Channel, + IN u8 *PowerLimit +) +{ + PADAPTER Adapter = pDM_Odm->adapter; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + u8 regulation = 0, bandwidth = 0, rateSection = 0, channel; + s8 powerLimit = 0, prevPowerLimit, channelIndex; + + if (0) + RTW_INFO("Index of power limit table [band %s][regulation %s][bw %s][rate section %s][rf path %s][chnl %s][val %s]\n" + , Band, Regulation, Bandwidth, RateSection, RfPath, Channel, PowerLimit); + + if (GetU1ByteIntegerFromStringInDecimal((s8 *)Channel, &channel) == _FALSE + || GetU1ByteIntegerFromStringInDecimal((s8 *)PowerLimit, &powerLimit) == _FALSE + ) { + RTW_PRINT("Illegal index of power limit table [ch %s][val %s]\n", Channel, PowerLimit); + return; + } + + powerLimit = powerLimit > MAX_POWER_INDEX ? MAX_POWER_INDEX : powerLimit; + + if (eqNByte(Regulation, (u8 *)("FCC"), 3)) + regulation = TXPWR_LMT_FCC; + else if (eqNByte(Regulation, (u8 *)("MKK"), 3)) + regulation = TXPWR_LMT_MKK; + else if (eqNByte(Regulation, (u8 *)("ETSI"), 4)) + regulation = TXPWR_LMT_ETSI; + else if (eqNByte(Regulation, (u8 *)("WW13"), 4)) + regulation = TXPWR_LMT_WW; + else { + RTW_PRINT("unknown regulation:%s", Regulation); + return; + } + + if (eqNByte(RateSection, (u8 *)("CCK"), 3) && eqNByte(RfPath, (u8 *)("1T"), 2)) + rateSection = CCK; + else if (eqNByte(RateSection, (u8 *)("OFDM"), 4) && eqNByte(RfPath, (u8 *)("1T"), 2)) + rateSection = OFDM; + else if (eqNByte(RateSection, (u8 *)("HT"), 2) && eqNByte(RfPath, (u8 *)("1T"), 2)) + rateSection = HT_1SS; + else if (eqNByte(RateSection, (u8 *)("HT"), 2) && eqNByte(RfPath, (u8 *)("2T"), 2)) + rateSection = HT_2SS; + else if (eqNByte(RateSection, (u8 *)("HT"), 2) && eqNByte(RfPath, (u8 *)("3T"), 2)) + rateSection = HT_3SS; + else if (eqNByte(RateSection, (u8 *)("HT"), 2) && eqNByte(RfPath, (u8 *)("4T"), 2)) + rateSection = HT_4SS; + else if (eqNByte(RateSection, (u8 *)("VHT"), 3) && eqNByte(RfPath, (u8 *)("1T"), 2)) + rateSection = VHT_1SS; + else if (eqNByte(RateSection, (u8 *)("VHT"), 3) && eqNByte(RfPath, (u8 *)("2T"), 2)) + rateSection = VHT_2SS; + else if (eqNByte(RateSection, (u8 *)("VHT"), 3) && eqNByte(RfPath, (u8 *)("3T"), 2)) + rateSection = VHT_3SS; + else if (eqNByte(RateSection, (u8 *)("VHT"), 3) && eqNByte(RfPath, (u8 *)("4T"), 2)) + rateSection = VHT_4SS; + else { + RTW_PRINT("Wrong rate section: (%s,%s)\n", RateSection, RfPath); + return; + } + + if (eqNByte(Bandwidth, (u8 *)("20M"), 3)) + bandwidth = CHANNEL_WIDTH_20; + else if (eqNByte(Bandwidth, (u8 *)("40M"), 3)) + bandwidth = CHANNEL_WIDTH_40; + else if (eqNByte(Bandwidth, (u8 *)("80M"), 3)) + bandwidth = CHANNEL_WIDTH_80; + else { + RTW_PRINT("unknown bandwidth: %s\n", Bandwidth); + return; + } + + if (eqNByte(Band, (u8 *)("2.4G"), 4)) { + channelIndex = phy_GetChannelIndexOfTxPowerLimit(BAND_ON_2_4G, channel); + + if (channelIndex == -1) { + RTW_PRINT("unsupported channel: %d at 2.4G\n", channel); + return; + } + + if (bandwidth >= MAX_2_4G_BANDWIDTH_NUM) { + RTW_PRINT("unsupported bandwidth: %s at 2.4G\n", Bandwidth); + return; + } + + prevPowerLimit = pHalData->TxPwrLimit_2_4G[regulation][bandwidth][rateSection][channelIndex][RF_PATH_A]; + + if (prevPowerLimit != MAX_POWER_INDEX) + RTW_PRINT("duplicate tx power limit combination [band %s][regulation %s][bw %s][rate section %s][rf path %s][chnl %s]\n" + , Band, Regulation, Bandwidth, RateSection, RfPath, Channel); + + if (powerLimit < prevPowerLimit) + pHalData->TxPwrLimit_2_4G[regulation][bandwidth][rateSection][channelIndex][RF_PATH_A] = powerLimit; + + if (0) + RTW_INFO("2.4G Band value : [regulation %d][bw %d][rate_section %d][chnl %d][val %d]\n" + , regulation, bandwidth, rateSection, channelIndex, pHalData->TxPwrLimit_2_4G[regulation][bandwidth][rateSection][channelIndex][ODM_RF_PATH_A]); + } else if (eqNByte(Band, (u8 *)("5G"), 2)) { + + channelIndex = phy_GetChannelIndexOfTxPowerLimit(BAND_ON_5G, channel); + + if (channelIndex == -1) { + RTW_PRINT("unsupported channel: %d at 5G\n", channel); + return; + } + + prevPowerLimit = pHalData->TxPwrLimit_5G[regulation][bandwidth][rateSection][channelIndex][RF_PATH_A]; + + if (prevPowerLimit != MAX_POWER_INDEX) + RTW_PRINT("duplicate tx power limit combination [band %s][regulation %s][bw %s][rate section %s][rf path %s][chnl %s]\n" + , Band, Regulation, Bandwidth, RateSection, RfPath, Channel); + + if (powerLimit < prevPowerLimit) + pHalData->TxPwrLimit_5G[regulation][bandwidth][rateSection][channelIndex][RF_PATH_A] = powerLimit; + + if (0) + RTW_INFO("5G Band value : [regulation %d][bw %d][rate_section %d][chnl %d][val %d]\n" + , regulation, bandwidth, rateSection, channel, pHalData->TxPwrLimit_5G[regulation][bandwidth][rateSection][channelIndex][RF_PATH_A]); + } else { + RTW_PRINT("Cannot recognize the band info in %s\n", Band); + return; + } +} + +u8 +phy_get_tx_power_index( + IN PADAPTER pAdapter, + IN u8 RFPath, + IN u8 Rate, + IN CHANNEL_WIDTH BandWidth, + IN u8 Channel +) +{ + return rtw_hal_get_tx_power_index(pAdapter, RFPath, Rate, BandWidth, Channel, NULL); +} + +VOID +PHY_SetTxPowerIndex( + IN PADAPTER pAdapter, + IN u32 PowerIndex, + IN u8 RFPath, + IN u8 Rate +) +{ + if (IS_HARDWARE_TYPE_8814A(pAdapter)) { +#if (RTL8814A_SUPPORT == 1) + PHY_SetTxPowerIndex_8814A(pAdapter, PowerIndex, RFPath, Rate); +#endif + } else if (IS_HARDWARE_TYPE_JAGUAR(pAdapter)) { +#if ((RTL8812A_SUPPORT == 1) || (RTL8821A_SUPPORT == 1)) + PHY_SetTxPowerIndex_8812A(pAdapter, PowerIndex, RFPath, Rate); +#endif + } else if (IS_HARDWARE_TYPE_8723B(pAdapter)) { +#if (RTL8723B_SUPPORT == 1) + PHY_SetTxPowerIndex_8723B(pAdapter, PowerIndex, RFPath, Rate); +#endif + } else if (IS_HARDWARE_TYPE_8703B(pAdapter)) { +#if (RTL8703B_SUPPORT == 1) + PHY_SetTxPowerIndex_8703B(pAdapter, PowerIndex, RFPath, Rate); +#endif + } else if (IS_HARDWARE_TYPE_8723D(pAdapter)) { +#if (RTL8723D_SUPPORT == 1) + PHY_SetTxPowerIndex_8723D(pAdapter, PowerIndex, RFPath, Rate); +#endif + } else if (IS_HARDWARE_TYPE_8192E(pAdapter)) { +#if (RTL8192E_SUPPORT == 1) + PHY_SetTxPowerIndex_8192E(pAdapter, PowerIndex, RFPath, Rate); +#endif + } else if (IS_HARDWARE_TYPE_8188E(pAdapter)) { +#if (RTL8188E_SUPPORT == 1) + PHY_SetTxPowerIndex_8188E(pAdapter, PowerIndex, RFPath, Rate); +#endif + } else if (IS_HARDWARE_TYPE_8188F(pAdapter)) { +#if (RTL8188F_SUPPORT == 1) + PHY_SetTxPowerIndex_8188F(pAdapter, PowerIndex, RFPath, Rate); +#endif + } else if (IS_HARDWARE_TYPE_8822B(pAdapter)) + rtw_hal_set_tx_power_index(pAdapter, PowerIndex, RFPath, Rate); + else if (IS_HARDWARE_TYPE_8821C(pAdapter)) + rtw_hal_set_tx_power_index(pAdapter, PowerIndex, RFPath, Rate); +} + +void dump_tx_power_idx_title(void *sel, _adapter *adapter) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + u8 bw = hal_data->current_channel_bw; + + RTW_PRINT_SEL(sel, "%s", ch_width_str(bw)); + if (bw >= CHANNEL_WIDTH_80) + _RTW_PRINT_SEL(sel, ", cch80:%u", hal_data->cch_80); + if (bw >= CHANNEL_WIDTH_40) + _RTW_PRINT_SEL(sel, ", cch40:%u", hal_data->cch_40); + _RTW_PRINT_SEL(sel, ", cch20:%u\n", hal_data->cch_20); + + RTW_PRINT_SEL(sel, "%-4s %-9s %-3s %-4s %-3s %-4s %-4s %-3s %-5s\n" + , "path", "rate", "pwr", "base", "", "(byr", "lmt)", "tpt", "ebias"); +} + +void dump_tx_power_idx_by_path_rs(void *sel, _adapter *adapter, u8 rfpath, u8 rs) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + u8 power_idx; + struct txpwr_idx_comp tic; + u8 tx_num, i; + u8 band = hal_data->current_band_type; + u8 cch = hal_data->current_channel; + u8 bw = hal_data->current_channel_bw; + + if (!HAL_SPEC_CHK_RF_PATH(hal_spec, band, rfpath)) + return; + + if (rs >= RATE_SECTION_NUM) + return; + + tx_num = rate_section_to_tx_num(rs); + if (tx_num >= hal_spec->tx_nss_num || tx_num >= hal_spec->max_tx_cnt) + return; + + if (band == BAND_ON_5G && IS_CCK_RATE_SECTION(rs)) + return; + + if (IS_VHT_RATE_SECTION(rs) && !IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(adapter)) + return; + + for (i = 0; i < rates_by_sections[rs].rate_num; i++) { + power_idx = rtw_hal_get_tx_power_index(adapter, rfpath, rates_by_sections[rs].rates[i], bw, cch, &tic); + + RTW_PRINT_SEL(sel, "%4c %9s %3u %4u %3d (%3d %3d) %3d %5d\n" + , rf_path_char(rfpath), MGN_RATE_STR(rates_by_sections[rs].rates[i]) + , power_idx, tic.base, (tic.by_rate > tic.limit ? tic.limit : tic.by_rate), tic.by_rate, tic.limit, tic.tpt, tic.ebias); + } +} + +void dump_tx_power_idx(void *sel, _adapter *adapter) +{ + u8 rfpath, rs; + + dump_tx_power_idx_title(sel, adapter); + for (rfpath = RF_PATH_A; rfpath < RF_PATH_MAX; rfpath++) + for (rs = CCK; rs < RATE_SECTION_NUM; rs++) + dump_tx_power_idx_by_path_rs(sel, adapter, rfpath, rs); +} + +bool phy_is_tx_power_limit_needed(_adapter *adapter) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct registry_priv *regsty = dvobj_to_regsty(adapter_to_dvobj(adapter)); + + if (regsty->RegEnableTxPowerLimit == 1 + || (regsty->RegEnableTxPowerLimit == 2 && hal_data->EEPROMRegulatory == 1)) + return _TRUE; + return _FALSE; +} + +bool phy_is_tx_power_by_rate_needed(_adapter *adapter) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct registry_priv *regsty = dvobj_to_regsty(adapter_to_dvobj(adapter)); + + if (regsty->RegEnableTxPowerByRate == 1 + || (regsty->RegEnableTxPowerByRate == 2 && hal_data->EEPROMRegulatory != 2)) + return _TRUE; + return _FALSE; +} + +int phy_load_tx_power_by_rate(_adapter *adapter, u8 chk_file) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct registry_priv *regsty = dvobj_to_regsty(adapter_to_dvobj(adapter)); + int ret = _FAIL; + + hal_data->txpwr_by_rate_loaded = 0; + PHY_InitTxPowerByRate(adapter); + + /* tx power limit is based on tx power by rate */ + hal_data->txpwr_limit_loaded = 0; + +#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE + if (chk_file + && phy_ConfigBBWithPgParaFile(adapter, PHY_FILE_PHY_REG_PG) == _SUCCESS + ) { + hal_data->txpwr_by_rate_from_file = 1; + goto post_hdl; + } +#endif + +#ifdef CONFIG_EMBEDDED_FWIMG + if (HAL_STATUS_SUCCESS == odm_config_bb_with_header_file(&hal_data->odmpriv, CONFIG_BB_PHY_REG_PG)) { + RTW_INFO("default power by rate loaded\n"); + hal_data->txpwr_by_rate_from_file = 0; + goto post_hdl; + } +#endif + + RTW_ERR("%s():Read Tx power by rate fail\n", __func__); + goto exit; + +post_hdl: + if (hal_data->odmpriv.phy_reg_pg_value_type != PHY_REG_PG_EXACT_VALUE) { + rtw_warn_on(1); + goto exit; + } + + PHY_TxPowerByRateConfiguration(adapter); + hal_data->txpwr_by_rate_loaded = 1; + + ret = _SUCCESS; + +exit: + return ret; +} + +int phy_load_tx_power_limit(_adapter *adapter, u8 chk_file) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct registry_priv *regsty = dvobj_to_regsty(adapter_to_dvobj(adapter)); + int ret = _FAIL; + + hal_data->txpwr_limit_loaded = 0; + PHY_InitTxPowerLimit(adapter); + + if (!hal_data->txpwr_by_rate_loaded && regsty->target_tx_pwr_valid != _TRUE) { + RTW_ERR("%s():Read Tx power limit before target tx power is specify\n", __func__); + goto exit; + } + +#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE + if (chk_file + && PHY_ConfigRFWithPowerLimitTableParaFile(adapter, PHY_FILE_TXPWR_LMT) == _SUCCESS + ) { + hal_data->txpwr_limit_from_file = 1; + goto post_hdl; + } +#endif + +#ifdef CONFIG_EMBEDDED_FWIMG + if (HAL_STATUS_SUCCESS == odm_config_rf_with_header_file(&hal_data->odmpriv, CONFIG_RF_TXPWR_LMT, (enum odm_rf_radio_path_e)0)) { + RTW_INFO("default power limit loaded\n"); + hal_data->txpwr_limit_from_file = 0; + goto post_hdl; + } +#endif + + RTW_ERR("%s():Read Tx power limit fail\n", __func__); + goto exit; + +post_hdl: + PHY_ConvertTxPowerLimitToPowerIndex(adapter); + hal_data->txpwr_limit_loaded = 1; + ret = _SUCCESS; + +exit: + return ret; +} + +void phy_load_tx_power_ext_info(_adapter *adapter, u8 chk_file) +{ + struct registry_priv *regsty = adapter_to_regsty(adapter); + + /* check registy target tx power */ + regsty->target_tx_pwr_valid = rtw_regsty_chk_target_tx_power_valid(adapter); + + /* power by rate and limit */ + if (phy_is_tx_power_by_rate_needed(adapter) + || (phy_is_tx_power_limit_needed(adapter) && regsty->target_tx_pwr_valid != _TRUE) + ) + phy_load_tx_power_by_rate(adapter, chk_file); + + if (phy_is_tx_power_limit_needed(adapter)) + phy_load_tx_power_limit(adapter, chk_file); +} + +inline void phy_reload_tx_power_ext_info(_adapter *adapter) +{ + phy_load_tx_power_ext_info(adapter, 1); +} + +inline void phy_reload_default_tx_power_ext_info(_adapter *adapter) +{ + phy_load_tx_power_ext_info(adapter, 0); +} + +void dump_tx_power_ext_info(void *sel, _adapter *adapter) +{ + struct registry_priv *regsty = adapter_to_regsty(adapter); + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + + if (regsty->target_tx_pwr_valid == _TRUE) + RTW_PRINT_SEL(sel, "target_tx_power: from registry\n"); + else if (phy_is_tx_power_by_rate_needed(adapter)) + RTW_PRINT_SEL(sel, "target_tx_power: from power by rate\n"); + else + RTW_PRINT_SEL(sel, "target_tx_power: unavailable\n"); + + RTW_PRINT_SEL(sel, "tx_power_by_rate: %s, %s, %s\n" + , phy_is_tx_power_by_rate_needed(adapter) ? "enabled" : "disabled" + , hal_data->txpwr_by_rate_loaded ? "loaded" : "unloaded" + , hal_data->txpwr_by_rate_from_file ? "file" : "default" + ); + + RTW_PRINT_SEL(sel, "tx_power_limit: %s, %s, %s\n" + , phy_is_tx_power_limit_needed(adapter) ? "enabled" : "disabled" + , hal_data->txpwr_limit_loaded ? "loaded" : "unloaded" + , hal_data->txpwr_limit_from_file ? "file" : "default" + ); +} + +void dump_target_tx_power(void *sel, _adapter *adapter) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct registry_priv *regsty = adapter_to_regsty(adapter); + int path, tx_num, band, rs; + u8 target; + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) { + if (!hal_is_band_support(adapter, band)) + continue; + + for (path = 0; path < RF_PATH_MAX; path++) { + if (!HAL_SPEC_CHK_RF_PATH(hal_spec, band, path)) + break; + + RTW_PRINT_SEL(sel, "[%s][%c]%s\n", band_str(band), rf_path_char(path) + , (regsty->target_tx_pwr_valid == _FALSE && hal_data->txpwr_by_rate_undefined_band_path[band][path]) ? "(dup)" : ""); + + for (rs = 0; rs < RATE_SECTION_NUM; rs++) { + tx_num = rate_section_to_tx_num(rs); + if (tx_num >= hal_spec->tx_nss_num) + continue; + + if (band == BAND_ON_5G && IS_CCK_RATE_SECTION(rs)) + continue; + + if (IS_VHT_RATE_SECTION(rs) && !IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(adapter)) + continue; + + target = PHY_GetTxPowerByRateBase(adapter, band, path, rate_section_to_tx_num(rs), rs); + + if (target % 2) + _RTW_PRINT_SEL(sel, "%7s: %2d.5\n", rate_section_str(rs), target / 2); + else + _RTW_PRINT_SEL(sel, "%7s: %4d\n", rate_section_str(rs), target / 2); + } + } + } + +exit: + return; +} + +void dump_tx_power_by_rate(void *sel, _adapter *adapter) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + int path, tx_num, band, n, rs; + u8 rate_num, max_rate_num, base; + s8 by_rate_offset; + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) { + if (!hal_is_band_support(adapter, band)) + continue; + + for (path = 0; path < RF_PATH_MAX; path++) { + if (!HAL_SPEC_CHK_RF_PATH(hal_spec, band, path)) + break; + + RTW_PRINT_SEL(sel, "[%s][%c]%s\n", band_str(band), rf_path_char(path) + , hal_data->txpwr_by_rate_undefined_band_path[band][path] ? "(dup)" : ""); + + for (rs = 0; rs < RATE_SECTION_NUM; rs++) { + tx_num = rate_section_to_tx_num(rs); + if (tx_num >= hal_spec->tx_nss_num) + continue; + + if (band == BAND_ON_5G && IS_CCK_RATE_SECTION(rs)) + continue; + + if (IS_VHT_RATE_SECTION(rs) && !IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(adapter)) + continue; + + if (IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(adapter)) + max_rate_num = 10; + else + max_rate_num = 8; + rate_num = rate_section_rate_num(rs); + base = PHY_GetTxPowerByRateBase(adapter, band, path, tx_num, rs); + + RTW_PRINT_SEL(sel, "%7s: ", rate_section_str(rs)); + + /* dump power by rate in db */ + for (n = rate_num - 1; n >= 0; n--) { + by_rate_offset = PHY_GetTxPowerByRate(adapter, band, path, tx_num, rates_by_sections[rs].rates[n]); + + if ((base + by_rate_offset) % 2) + _RTW_PRINT_SEL(sel, "%2d.5 ", (base + by_rate_offset) / 2); + else + _RTW_PRINT_SEL(sel, "%4d ", (base + by_rate_offset) / 2); + } + for (n = 0; n < max_rate_num - rate_num; n++) + _RTW_PRINT_SEL(sel, "%4s ", ""); + + _RTW_PRINT_SEL(sel, "|"); + + /* dump power by rate in offset */ + for (n = rate_num - 1; n >= 0; n--) { + by_rate_offset = PHY_GetTxPowerByRate(adapter, band, path, tx_num, rates_by_sections[rs].rates[n]); + _RTW_PRINT_SEL(sel, "%3d ", by_rate_offset); + } + RTW_PRINT_SEL(sel, "\n"); + + } + } + } +} + +void dump_tx_power_limit(void *sel, _adapter *adapter) +{ + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct registry_priv *regsty = dvobj_to_regsty(adapter_to_dvobj(adapter)); + + int bw, band, ch_num, rs, i, path; + u8 ch, n, rd, rfpath_num; + + if (IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(adapter)) + RTW_PRINT_SEL(sel, "tx_pwr_lmt_5g_20_40_ref:0x%02x\n", hal_data->tx_pwr_lmt_5g_20_40_ref); + + for (band = BAND_ON_2_4G; band <= BAND_ON_5G; band++) { + if (!hal_is_band_support(adapter, band)) + continue; + + rd = (band == BAND_ON_2_4G ? hal_data->Regulation2_4G : hal_data->Regulation5G); + rfpath_num = (band == BAND_ON_2_4G ? hal_spec->rfpath_num_2g : hal_spec->rfpath_num_5g); + + for (bw = 0; bw < MAX_5G_BANDWIDTH_NUM; bw++) { + + if (bw >= CHANNEL_WIDTH_160) + break; + if (band == BAND_ON_2_4G && bw >= CHANNEL_WIDTH_80) + break; + + if (band == BAND_ON_2_4G) + ch_num = CENTER_CH_2G_NUM; + else + ch_num = center_chs_5g_num(bw); + + if (ch_num == 0) { + rtw_warn_on(1); + break; + } + + for (rs = 0; rs < RATE_SECTION_NUM; rs++) { + if (band == BAND_ON_2_4G && IS_VHT_RATE_SECTION(rs)) + continue; + if (band == BAND_ON_5G && IS_CCK_RATE_SECTION(rs)) + continue; + if (bw > CHANNEL_WIDTH_20 && (IS_CCK_RATE_SECTION(rs) || IS_OFDM_RATE_SECTION(rs))) + continue; + if (bw > CHANNEL_WIDTH_40 && IS_HT_RATE_SECTION(rs)) + continue; + + if (rate_section_to_tx_num(rs) >= hal_spec->tx_nss_num) + continue; + + if (IS_VHT_RATE_SECTION(rs) && !IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(adapter)) + continue; + + /* by pass 5G 20M, 40M pure reference */ + if (band == BAND_ON_5G && (bw == CHANNEL_WIDTH_20 || bw == CHANNEL_WIDTH_40)) { + if (hal_data->tx_pwr_lmt_5g_20_40_ref == TX_PWR_LMT_REF_HT_FROM_VHT) { + if (IS_HT_RATE_SECTION(rs)) + continue; + } else if (hal_data->tx_pwr_lmt_5g_20_40_ref == TX_PWR_LMT_REF_VHT_FROM_HT) { + if (IS_VHT_RATE_SECTION(rs) && bw <= CHANNEL_WIDTH_40) + continue; + } + } + + RTW_PRINT_SEL(sel, "[%s][%s][%s]\n" + , band_str(band) + , ch_width_str(bw) + , rate_section_str(rs) + ); + + /* header for limit in db */ + RTW_PRINT_SEL(sel, "%3s %5s %5s %5s %5s " + , "ch" + , (rd == TXPWR_LMT_FCC ? "*FCC" : "FCC") + , (rd == TXPWR_LMT_ETSI ? "*ETSI" : "ETSI") + , (rd == TXPWR_LMT_MKK ? "*MKK" : "MKK") + , (rd == TXPWR_LMT_WW ? "*WW" : "WW") + ); + + /* header for limit offset */ + for (path = 0; path < RF_PATH_MAX; path++) { + if (path >= rfpath_num) + break; + _RTW_PRINT_SEL(sel, "|%3c %3c %3c %3c " + , (rd == TXPWR_LMT_FCC ? rf_path_char(path) : ' ') + , (rd == TXPWR_LMT_ETSI ? rf_path_char(path) : ' ') + , (rd == TXPWR_LMT_MKK ? rf_path_char(path) : ' ') + , (rd == TXPWR_LMT_WW ? rf_path_char(path) : ' ') + ); + } + _RTW_PRINT_SEL(sel, "\n"); + + for (n = 0; n < ch_num; n++) { + s8 limit_idx[RF_PATH_MAX][MAX_REGULATION_NUM]; + s8 limit_offset[MAX_REGULATION_NUM]; + u8 base; + + if (band == BAND_ON_2_4G) + ch = n + 1; + else + ch = center_chs_5g(bw, n); + + if (ch == 0) { + rtw_warn_on(1); + break; + } + + /* dump limit in db (calculate from path A) */ + limit_offset[0] = PHY_GetTxPowerLimit_no_sc(adapter, 3, band, bw, RF_PATH_A, rates_by_sections[rs].rates[0], ch); /* FCC */ + limit_offset[1] = PHY_GetTxPowerLimit_no_sc(adapter, 1, band, bw, RF_PATH_A, rates_by_sections[rs].rates[0], ch); /* ETSI */ + limit_offset[2] = PHY_GetTxPowerLimit_no_sc(adapter, 2, band, bw, RF_PATH_A, rates_by_sections[rs].rates[0], ch); /* MKK */ + limit_offset[3] = PHY_GetTxPowerLimit_no_sc(adapter, 4, band, bw, RF_PATH_A, rates_by_sections[rs].rates[0], ch); /* WW */ + + base = PHY_GetTxPowerByRateBase(adapter, band, RF_PATH_A, rate_section_to_tx_num(rs), rs); + + RTW_PRINT_SEL(sel, "%3u ", ch); + for (i = 0; i < MAX_REGULATION_NUM; i++) { + if (limit_offset[i] == MAX_POWER_INDEX) { + limit_idx[0][i] = MAX_POWER_INDEX; + _RTW_PRINT_SEL(sel, "%5s ", "NA"); + } else { + limit_idx[0][i] = limit_offset[i] + base; + if ((limit_offset[i] + base) % 2) + _RTW_PRINT_SEL(sel, "%3d.5 ", (limit_offset[i] + base) / 2); + else + _RTW_PRINT_SEL(sel, "%5d ", (limit_offset[i] + base) / 2); + } + } + + /* dump limit offset of each path */ + for (path = 0; path < RF_PATH_MAX; path++) { + if (path >= rfpath_num) + break; + limit_offset[0] = PHY_GetTxPowerLimit_no_sc(adapter, 3, band, bw, path, rates_by_sections[rs].rates[0], ch); /* FCC */ + limit_offset[1] = PHY_GetTxPowerLimit_no_sc(adapter, 1, band, bw, path, rates_by_sections[rs].rates[0], ch); /* ETSI */ + limit_offset[2] = PHY_GetTxPowerLimit_no_sc(adapter, 2, band, bw, path, rates_by_sections[rs].rates[0], ch); /* MKK */ + limit_offset[3] = PHY_GetTxPowerLimit_no_sc(adapter, 4, band, bw, path, rates_by_sections[rs].rates[0], ch); /* WW */ + + base = PHY_GetTxPowerByRateBase(adapter, band, path, rate_section_to_tx_num(rs), rs); + + _RTW_PRINT_SEL(sel, "|"); + for (i = 0; i < MAX_REGULATION_NUM; i++) { + if (limit_offset[i] == MAX_POWER_INDEX) { + limit_idx[path][i] = MAX_POWER_INDEX; + _RTW_PRINT_SEL(sel, "%3s ", "NA"); + } else { + limit_idx[path][i] = limit_offset[i] + base; + _RTW_PRINT_SEL(sel, "%3d ", limit_offset[i]); + } + } + } + + /* compare limit_idx of each path, print 'x' when mismatch */ + if (rfpath_num > 1) { + for (i = 0; i < MAX_REGULATION_NUM; i++) { + for (path = 0; path < RF_PATH_MAX; path++) { + if (path >= rfpath_num) + break; + if (limit_idx[path][i] != limit_idx[(path + 1) % rfpath_num][i]) + break; + } + if (path >= rfpath_num) + _RTW_PRINT_SEL(sel, " "); + else + _RTW_PRINT_SEL(sel, "x"); + } + } + _RTW_PRINT_SEL(sel, "\n"); + + } + RTW_PRINT_SEL(sel, "\n"); + } /* loop for rate sections */ + } /* loop for bandwidths */ + } /* loop for bands */ +} + +/* + * phy file path is stored in global char array rtw_phy_para_file_path + * need to care about racing + */ +int rtw_get_phy_file_path(_adapter *adapter, const char *file_name) +{ +#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE + struct hal_spec_t *hal_spec = GET_HAL_SPEC(adapter); + int len = 0; + + if (file_name) { + len += snprintf(rtw_phy_para_file_path, PATH_LENGTH_MAX, "%s", rtw_phy_file_path); + #if defined(CONFIG_MULTIDRV) || defined(REALTEK_CONFIG_PATH_WITH_IC_NAME_FOLDER) + len += snprintf(rtw_phy_para_file_path + len, PATH_LENGTH_MAX - len, "%s/", hal_spec->ic_name); + #endif + len += snprintf(rtw_phy_para_file_path + len, PATH_LENGTH_MAX - len, "%s", file_name); + + return _TRUE; + } +#endif + return _FALSE; +} + +#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE +int +phy_ConfigMACWithParaFile( + IN PADAPTER Adapter, + IN char *pFileName +) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(Adapter); + int rlen = 0, rtStatus = _FAIL; + char *szLine, *ptmp; + u32 u4bRegOffset, u4bRegValue, u4bMove; + + if (!(Adapter->registrypriv.load_phy_file & LOAD_MAC_PARA_FILE)) + return rtStatus; + + _rtw_memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); + + if ((pHalData->mac_reg_len == 0) && (pHalData->mac_reg == NULL)) { + rtw_get_phy_file_path(Adapter, pFileName); + if (rtw_is_file_readable(rtw_phy_para_file_path) == _TRUE) { + rlen = rtw_retrieve_from_file(rtw_phy_para_file_path, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); + if (rlen > 0) { + rtStatus = _SUCCESS; + pHalData->mac_reg = rtw_zvmalloc(rlen); + if (pHalData->mac_reg) { + _rtw_memcpy(pHalData->mac_reg, pHalData->para_file_buf, rlen); + pHalData->mac_reg_len = rlen; + } else + RTW_INFO("%s mac_reg alloc fail !\n", __FUNCTION__); + } + } + } else { + if ((pHalData->mac_reg_len != 0) && (pHalData->mac_reg != NULL)) { + _rtw_memcpy(pHalData->para_file_buf, pHalData->mac_reg, pHalData->mac_reg_len); + rtStatus = _SUCCESS; + } else + RTW_INFO("%s(): Critical Error !!!\n", __FUNCTION__); + } + + if (rtStatus == _SUCCESS) { + ptmp = pHalData->para_file_buf; + for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { + if (!IsCommentString(szLine)) { + /* Get 1st hex value as register offset */ + if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) { + if (u4bRegOffset == 0xffff) { + /* Ending. */ + break; + } + + /* Get 2nd hex value as register value. */ + szLine += u4bMove; + if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) + rtw_write8(Adapter, u4bRegOffset, (u8)u4bRegValue); + } + } + } + } else + RTW_INFO("%s(): No File %s, Load from HWImg Array!\n", __FUNCTION__, pFileName); + + return rtStatus; +} + +int +phy_ConfigBBWithParaFile( + IN PADAPTER Adapter, + IN char *pFileName, + IN u32 ConfigType +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + int rlen = 0, rtStatus = _FAIL; + char *szLine, *ptmp; + u32 u4bRegOffset, u4bRegValue, u4bMove; + char *pBuf = NULL; + u32 *pBufLen = NULL; + + if (!(Adapter->registrypriv.load_phy_file & LOAD_BB_PARA_FILE)) + return rtStatus; + + switch (ConfigType) { + case CONFIG_BB_PHY_REG: + pBuf = pHalData->bb_phy_reg; + pBufLen = &pHalData->bb_phy_reg_len; + break; + case CONFIG_BB_AGC_TAB: + pBuf = pHalData->bb_agc_tab; + pBufLen = &pHalData->bb_agc_tab_len; + break; + default: + RTW_INFO("Unknown ConfigType!! %d\r\n", ConfigType); + break; + } + + _rtw_memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); + + if ((pBufLen != NULL) && (*pBufLen == 0) && (pBuf == NULL)) { + rtw_get_phy_file_path(Adapter, pFileName); + if (rtw_is_file_readable(rtw_phy_para_file_path) == _TRUE) { + rlen = rtw_retrieve_from_file(rtw_phy_para_file_path, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); + if (rlen > 0) { + rtStatus = _SUCCESS; + pBuf = rtw_zvmalloc(rlen); + if (pBuf) { + _rtw_memcpy(pBuf, pHalData->para_file_buf, rlen); + *pBufLen = rlen; + + switch (ConfigType) { + case CONFIG_BB_PHY_REG: + pHalData->bb_phy_reg = pBuf; + break; + case CONFIG_BB_AGC_TAB: + pHalData->bb_agc_tab = pBuf; + break; + } + } else + RTW_INFO("%s(): ConfigType %d alloc fail !\n", __FUNCTION__, ConfigType); + } + } + } else { + if ((pBufLen != NULL) && (*pBufLen != 0) && (pBuf != NULL)) { + _rtw_memcpy(pHalData->para_file_buf, pBuf, *pBufLen); + rtStatus = _SUCCESS; + } else + RTW_INFO("%s(): Critical Error !!!\n", __FUNCTION__); + } + + if (rtStatus == _SUCCESS) { + ptmp = pHalData->para_file_buf; + for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { + if (!IsCommentString(szLine)) { + /* Get 1st hex value as register offset. */ + if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) { + if (u4bRegOffset == 0xffff) { + /* Ending. */ + break; + } else if (u4bRegOffset == 0xfe || u4bRegOffset == 0xffe) { +#ifdef CONFIG_LONG_DELAY_ISSUE + rtw_msleep_os(50); +#else + rtw_mdelay_os(50); +#endif + } else if (u4bRegOffset == 0xfd) + rtw_mdelay_os(5); + else if (u4bRegOffset == 0xfc) + rtw_mdelay_os(1); + else if (u4bRegOffset == 0xfb) + rtw_udelay_os(50); + else if (u4bRegOffset == 0xfa) + rtw_udelay_os(5); + else if (u4bRegOffset == 0xf9) + rtw_udelay_os(1); + + /* Get 2nd hex value as register value. */ + szLine += u4bMove; + if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) { + /* RTW_INFO("[BB-ADDR]%03lX=%08lX\n", u4bRegOffset, u4bRegValue); */ + phy_set_bb_reg(Adapter, u4bRegOffset, bMaskDWord, u4bRegValue); + + if (u4bRegOffset == 0xa24) + pHalData->odmpriv.rf_calibrate_info.rega24 = u4bRegValue; + + /* Add 1us delay between BB/RF register setting. */ + rtw_udelay_os(1); + } + } + } + } + } else + RTW_INFO("%s(): No File %s, Load from HWImg Array!\n", __FUNCTION__, pFileName); + + return rtStatus; +} + +VOID +phy_DecryptBBPgParaFile( + PADAPTER Adapter, + char *buffer +) +{ + u32 i = 0, j = 0; + u8 map[95] = {0}; + u8 currentChar; + char *BufOfLines, *ptmp; + + /* RTW_INFO("=====>phy_DecryptBBPgParaFile()\n"); */ + /* 32 the ascii code of the first visable char, 126 the last one */ + for (i = 0; i < 95; ++i) + map[i] = (u8)(94 - i); + + ptmp = buffer; + i = 0; + for (BufOfLines = GetLineFromBuffer(ptmp); BufOfLines != NULL; BufOfLines = GetLineFromBuffer(ptmp)) { + /* RTW_INFO("Encrypted Line: %s\n", BufOfLines); */ + + for (j = 0; j < strlen(BufOfLines); ++j) { + currentChar = BufOfLines[j]; + + if (currentChar == '\0') + break; + + currentChar -= (u8)((((i + j) * 3) % 128)); + + BufOfLines[j] = map[currentChar - 32] + 32; + } + /* RTW_INFO("Decrypted Line: %s\n", BufOfLines ); */ + if (strlen(BufOfLines) != 0) + i++; + BufOfLines[strlen(BufOfLines)] = '\n'; + } +} + +int +phy_ParseBBPgParaFile( + PADAPTER Adapter, + char *buffer +) +{ + int rtStatus = _SUCCESS; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + char *szLine, *ptmp; + u32 u4bRegOffset, u4bRegMask, u4bRegValue; + u32 u4bMove; + BOOLEAN firstLine = _TRUE; + u8 tx_num = 0; + u8 band = 0, rf_path = 0; + + /* RTW_INFO("=====>phy_ParseBBPgParaFile()\n"); */ + + if (Adapter->registrypriv.RegDecryptCustomFile == 1) + phy_DecryptBBPgParaFile(Adapter, buffer); + + ptmp = buffer; + for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { + if (isAllSpaceOrTab(szLine, sizeof(*szLine))) + continue; + + if (!IsCommentString(szLine)) { + /* Get header info (relative value or exact value) */ + if (firstLine) { + if (eqNByte(szLine, (u8 *)("#[v1]"), 5)) { + + pHalData->odmpriv.phy_reg_pg_version = szLine[3] - '0'; + /* RTW_INFO("This is a new format PHY_REG_PG.txt\n"); */ + } else if (eqNByte(szLine, (u8 *)("#[v0]"), 5)) { + pHalData->odmpriv.phy_reg_pg_version = szLine[3] - '0'; + /* RTW_INFO("This is a old format PHY_REG_PG.txt ok\n"); */ + } else { + RTW_INFO("The format in PHY_REG_PG are invalid %s\n", szLine); + return _FAIL; + } + + if (eqNByte(szLine + 5, (u8 *)("[Exact]#"), 8)) { + pHalData->odmpriv.phy_reg_pg_value_type = PHY_REG_PG_EXACT_VALUE; + /* RTW_INFO("The values in PHY_REG_PG are exact values ok\n"); */ + firstLine = _FALSE; + continue; + } else if (eqNByte(szLine + 5, (pu1Byte)("[Relative]#"), 11)) { + pHalData->odmpriv.phy_reg_pg_value_type = PHY_REG_PG_RELATIVE_VALUE; + /* RTW_INFO("The values in PHY_REG_PG are relative values ok\n"); */ + firstLine = _FALSE; + continue; + } else { + RTW_INFO("The values in PHY_REG_PG are invalid %s\n", szLine); + return _FAIL; + } + } + + if (pHalData->odmpriv.phy_reg_pg_version == 0) { + /* Get 1st hex value as register offset. */ + if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) { + szLine += u4bMove; + if (u4bRegOffset == 0xffff) { + /* Ending. */ + break; + } + + /* Get 2nd hex value as register mask. */ + if (GetHexValueFromString(szLine, &u4bRegMask, &u4bMove)) + szLine += u4bMove; + else + return _FAIL; + + if (pHalData->odmpriv.phy_reg_pg_value_type == PHY_REG_PG_RELATIVE_VALUE) { + /* Get 3rd hex value as register value. */ + if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) { + phy_store_tx_power_by_rate(Adapter, 0, 0, 1, u4bRegOffset, u4bRegMask, u4bRegValue); + /* RTW_INFO("[ADDR] %03X=%08X Mask=%08x\n", u4bRegOffset, u4bRegValue, u4bRegMask); */ + } else + return _FAIL; + } else if (pHalData->odmpriv.phy_reg_pg_value_type == PHY_REG_PG_EXACT_VALUE) { + u32 combineValue = 0; + u8 integer = 0, fraction = 0; + + if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) + szLine += u4bMove; + else + return _FAIL; + + integer *= 2; + if (fraction == 5) + integer += 1; + combineValue |= (((integer / 10) << 4) + (integer % 10)); + /* RTW_INFO(" %d", integer ); */ + + if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) + szLine += u4bMove; + else + return _FAIL; + + integer *= 2; + if (fraction == 5) + integer += 1; + combineValue <<= 8; + combineValue |= (((integer / 10) << 4) + (integer % 10)); + /* RTW_INFO(" %d", integer ); */ + + if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) + szLine += u4bMove; + else + return _FAIL; + + integer *= 2; + if (fraction == 5) + integer += 1; + combineValue <<= 8; + combineValue |= (((integer / 10) << 4) + (integer % 10)); + /* RTW_INFO(" %d", integer ); */ + + if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) + szLine += u4bMove; + else + return _FAIL; + + integer *= 2; + if (fraction == 5) + integer += 1; + combineValue <<= 8; + combineValue |= (((integer / 10) << 4) + (integer % 10)); + /* RTW_INFO(" %d", integer ); */ + phy_store_tx_power_by_rate(Adapter, 0, 0, 1, u4bRegOffset, u4bRegMask, combineValue); + + /* RTW_INFO("[ADDR] 0x%3x = 0x%4x\n", u4bRegOffset, combineValue ); */ + } + } + } else if (pHalData->odmpriv.phy_reg_pg_version > 0) { + u32 index = 0, cnt = 0; + + if (eqNByte(szLine, "0xffff", 6)) + break; + + if (!eqNByte("#[END]#", szLine, 7)) { + /* load the table label info */ + if (szLine[0] == '#') { + index = 0; + if (eqNByte(szLine, "#[2.4G]" , 7)) { + band = BAND_ON_2_4G; + index += 8; + } else if (eqNByte(szLine, "#[5G]", 5)) { + band = BAND_ON_5G; + index += 6; + } else { + RTW_INFO("Invalid band %s in PHY_REG_PG.txt\n", szLine); + return _FAIL; + } + + rf_path = szLine[index] - 'A'; + /* RTW_INFO(" Table label Band %d, RfPath %d\n", band, rf_path ); */ + } else { /* load rows of tables */ + if (szLine[1] == '1') + tx_num = RF_1TX; + else if (szLine[1] == '2') + tx_num = RF_2TX; + else if (szLine[1] == '3') + tx_num = RF_3TX; + else if (szLine[1] == '4') + tx_num = RF_4TX; + else { + RTW_INFO("Invalid row in PHY_REG_PG.txt '%c'(%d)\n", szLine[1], szLine[1]); + return _FAIL; + } + + while (szLine[index] != ']') + ++index; + ++index;/* skip ] */ + + /* Get 2nd hex value as register offset. */ + szLine += index; + if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) + szLine += u4bMove; + else + return _FAIL; + + /* Get 2nd hex value as register mask. */ + if (GetHexValueFromString(szLine, &u4bRegMask, &u4bMove)) + szLine += u4bMove; + else + return _FAIL; + + if (pHalData->odmpriv.phy_reg_pg_value_type == PHY_REG_PG_RELATIVE_VALUE) { + /* Get 3rd hex value as register value. */ + if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) { + phy_store_tx_power_by_rate(Adapter, band, rf_path, tx_num, u4bRegOffset, u4bRegMask, u4bRegValue); + /* RTW_INFO("[ADDR] %03X (tx_num %d) =%08X Mask=%08x\n", u4bRegOffset, tx_num, u4bRegValue, u4bRegMask); */ + } else + return _FAIL; + } else if (pHalData->odmpriv.phy_reg_pg_value_type == PHY_REG_PG_EXACT_VALUE) { + u32 combineValue = 0; + u8 integer = 0, fraction = 0; + + if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) + szLine += u4bMove; + else + return _FAIL; + + integer *= 2; + if (fraction == 5) + integer += 1; + combineValue |= (((integer / 10) << 4) + (integer % 10)); + /* RTW_INFO(" %d", integer ); */ + + if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) + szLine += u4bMove; + else + return _FAIL; + + integer *= 2; + if (fraction == 5) + integer += 1; + combineValue <<= 8; + combineValue |= (((integer / 10) << 4) + (integer % 10)); + /* RTW_INFO(" %d", integer ); */ + + if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) + szLine += u4bMove; + else + return _FAIL; + + integer *= 2; + if (fraction == 5) + integer += 1; + combineValue <<= 8; + combineValue |= (((integer / 10) << 4) + (integer % 10)); + /* RTW_INFO(" %d", integer ); */ + + if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) + szLine += u4bMove; + else + return _FAIL; + + integer *= 2; + if (fraction == 5) + integer += 1; + combineValue <<= 8; + combineValue |= (((integer / 10) << 4) + (integer % 10)); + /* RTW_INFO(" %d", integer ); */ + phy_store_tx_power_by_rate(Adapter, band, rf_path, tx_num, u4bRegOffset, u4bRegMask, combineValue); + + /* RTW_INFO("[ADDR] 0x%3x (tx_num %d) = 0x%4x\n", u4bRegOffset, tx_num, combineValue ); */ + } + } + } + } + } + } + /* RTW_INFO("<=====phy_ParseBBPgParaFile()\n"); */ + return rtStatus; +} + +int +phy_ConfigBBWithPgParaFile( + IN PADAPTER Adapter, + IN const char *pFileName) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + int rlen = 0, rtStatus = _FAIL; + + if (!(Adapter->registrypriv.load_phy_file & LOAD_BB_PG_PARA_FILE)) + return rtStatus; + + _rtw_memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); + + if (pHalData->bb_phy_reg_pg == NULL) { + rtw_get_phy_file_path(Adapter, pFileName); + if (rtw_is_file_readable(rtw_phy_para_file_path) == _TRUE) { + rlen = rtw_retrieve_from_file(rtw_phy_para_file_path, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); + if (rlen > 0) { + rtStatus = _SUCCESS; + pHalData->bb_phy_reg_pg = rtw_zvmalloc(rlen); + if (pHalData->bb_phy_reg_pg) { + _rtw_memcpy(pHalData->bb_phy_reg_pg, pHalData->para_file_buf, rlen); + pHalData->bb_phy_reg_pg_len = rlen; + } else + RTW_INFO("%s bb_phy_reg_pg alloc fail !\n", __FUNCTION__); + } + } + } else { + if ((pHalData->bb_phy_reg_pg_len != 0) && (pHalData->bb_phy_reg_pg != NULL)) { + _rtw_memcpy(pHalData->para_file_buf, pHalData->bb_phy_reg_pg, pHalData->bb_phy_reg_pg_len); + rtStatus = _SUCCESS; + } else + RTW_INFO("%s(): Critical Error !!!\n", __FUNCTION__); + } + + if (rtStatus == _SUCCESS) { + /* RTW_INFO("phy_ConfigBBWithPgParaFile(): read %s ok\n", pFileName); */ + phy_ParseBBPgParaFile(Adapter, pHalData->para_file_buf); + } else + RTW_INFO("%s(): No File %s, Load from HWImg Array!\n", __FUNCTION__, pFileName); + + return rtStatus; +} + +#if (MP_DRIVER == 1) + +int +phy_ConfigBBWithMpParaFile( + IN PADAPTER Adapter, + IN char *pFileName +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + int rlen = 0, rtStatus = _FAIL; + char *szLine, *ptmp; + u32 u4bRegOffset, u4bRegValue, u4bMove; + + if (!(Adapter->registrypriv.load_phy_file & LOAD_BB_MP_PARA_FILE)) + return rtStatus; + + _rtw_memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); + + if ((pHalData->bb_phy_reg_mp_len == 0) && (pHalData->bb_phy_reg_mp == NULL)) { + rtw_get_phy_file_path(Adapter, pFileName); + if (rtw_is_file_readable(rtw_phy_para_file_path) == _TRUE) { + rlen = rtw_retrieve_from_file(rtw_phy_para_file_path, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); + if (rlen > 0) { + rtStatus = _SUCCESS; + pHalData->bb_phy_reg_mp = rtw_zvmalloc(rlen); + if (pHalData->bb_phy_reg_mp) { + _rtw_memcpy(pHalData->bb_phy_reg_mp, pHalData->para_file_buf, rlen); + pHalData->bb_phy_reg_mp_len = rlen; + } else + RTW_INFO("%s bb_phy_reg_mp alloc fail !\n", __FUNCTION__); + } + } + } else { + if ((pHalData->bb_phy_reg_mp_len != 0) && (pHalData->bb_phy_reg_mp != NULL)) { + _rtw_memcpy(pHalData->para_file_buf, pHalData->bb_phy_reg_mp, pHalData->bb_phy_reg_mp_len); + rtStatus = _SUCCESS; + } else + RTW_INFO("%s(): Critical Error !!!\n", __FUNCTION__); + } + + if (rtStatus == _SUCCESS) { + /* RTW_INFO("phy_ConfigBBWithMpParaFile(): read %s ok\n", pFileName); */ + + ptmp = pHalData->para_file_buf; + for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { + if (!IsCommentString(szLine)) { + /* Get 1st hex value as register offset. */ + if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) { + if (u4bRegOffset == 0xffff) { + /* Ending. */ + break; + } else if (u4bRegOffset == 0xfe || u4bRegOffset == 0xffe) { +#ifdef CONFIG_LONG_DELAY_ISSUE + rtw_msleep_os(50); +#else + rtw_mdelay_os(50); +#endif + } else if (u4bRegOffset == 0xfd) + rtw_mdelay_os(5); + else if (u4bRegOffset == 0xfc) + rtw_mdelay_os(1); + else if (u4bRegOffset == 0xfb) + rtw_udelay_os(50); + else if (u4bRegOffset == 0xfa) + rtw_udelay_os(5); + else if (u4bRegOffset == 0xf9) + rtw_udelay_os(1); + + /* Get 2nd hex value as register value. */ + szLine += u4bMove; + if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) { + /* RTW_INFO("[ADDR]%03lX=%08lX\n", u4bRegOffset, u4bRegValue); */ + phy_set_bb_reg(Adapter, u4bRegOffset, bMaskDWord, u4bRegValue); + + /* Add 1us delay between BB/RF register setting. */ + rtw_udelay_os(1); + } + } + } + } + } else + RTW_INFO("%s(): No File %s, Load from HWImg Array!\n", __FUNCTION__, pFileName); + + return rtStatus; +} + +#endif + +int +PHY_ConfigRFWithParaFile( + IN PADAPTER Adapter, + IN char *pFileName, + IN u8 eRFPath +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + int rlen = 0, rtStatus = _FAIL; + char *szLine, *ptmp; + u32 u4bRegOffset, u4bRegValue, u4bMove; + u16 i; + char *pBuf = NULL; + u32 *pBufLen = NULL; + + if (!(Adapter->registrypriv.load_phy_file & LOAD_RF_PARA_FILE)) + return rtStatus; + + switch (eRFPath) { + case ODM_RF_PATH_A: + pBuf = pHalData->rf_radio_a; + pBufLen = &pHalData->rf_radio_a_len; + break; + case ODM_RF_PATH_B: + pBuf = pHalData->rf_radio_b; + pBufLen = &pHalData->rf_radio_b_len; + break; + default: + RTW_INFO("Unknown RF path!! %d\r\n", eRFPath); + break; + } + + _rtw_memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); + + if ((pBufLen != NULL) && (*pBufLen == 0) && (pBuf == NULL)) { + rtw_get_phy_file_path(Adapter, pFileName); + if (rtw_is_file_readable(rtw_phy_para_file_path) == _TRUE) { + rlen = rtw_retrieve_from_file(rtw_phy_para_file_path, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); + if (rlen > 0) { + rtStatus = _SUCCESS; + pBuf = rtw_zvmalloc(rlen); + if (pBuf) { + _rtw_memcpy(pBuf, pHalData->para_file_buf, rlen); + *pBufLen = rlen; + + switch (eRFPath) { + case ODM_RF_PATH_A: + pHalData->rf_radio_a = pBuf; + break; + case ODM_RF_PATH_B: + pHalData->rf_radio_b = pBuf; + break; + } + } else + RTW_INFO("%s(): eRFPath=%d alloc fail !\n", __FUNCTION__, eRFPath); + } + } + } else { + if ((pBufLen != NULL) && (*pBufLen != 0) && (pBuf != NULL)) { + _rtw_memcpy(pHalData->para_file_buf, pBuf, *pBufLen); + rtStatus = _SUCCESS; + } else + RTW_INFO("%s(): Critical Error !!!\n", __FUNCTION__); + } + + if (rtStatus == _SUCCESS) { + /* RTW_INFO("%s(): read %s successfully\n", __FUNCTION__, pFileName); */ + + ptmp = pHalData->para_file_buf; + for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { + if (!IsCommentString(szLine)) { + /* Get 1st hex value as register offset. */ + if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) { + if (u4bRegOffset == 0xfe || u4bRegOffset == 0xffe) { + /* Deay specific ms. Only RF configuration require delay. */ +#ifdef CONFIG_LONG_DELAY_ISSUE + rtw_msleep_os(50); +#else + rtw_mdelay_os(50); +#endif + } else if (u4bRegOffset == 0xfd) { + /* delay_ms(5); */ + for (i = 0; i < 100; i++) + rtw_udelay_os(MAX_STALL_TIME); + } else if (u4bRegOffset == 0xfc) { + /* delay_ms(1); */ + for (i = 0; i < 20; i++) + rtw_udelay_os(MAX_STALL_TIME); + } else if (u4bRegOffset == 0xfb) + rtw_udelay_os(50); + else if (u4bRegOffset == 0xfa) + rtw_udelay_os(5); + else if (u4bRegOffset == 0xf9) + rtw_udelay_os(1); + else if (u4bRegOffset == 0xffff) + break; + + /* Get 2nd hex value as register value. */ + szLine += u4bMove; + if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) { + phy_set_rf_reg(Adapter, eRFPath, u4bRegOffset, bRFRegOffsetMask, u4bRegValue); + + /* Temp add, for frequency lock, if no delay, that may cause */ + /* frequency shift, ex: 2412MHz => 2417MHz */ + /* If frequency shift, the following action may works. */ + /* Fractional-N table in radio_a.txt */ + /* 0x2a 0x00001 */ /* channel 1 */ + /* 0x2b 0x00808 frequency divider. */ + /* 0x2b 0x53333 */ + /* 0x2c 0x0000c */ + rtw_udelay_os(1); + } + } + } + } + } else + RTW_INFO("%s(): No File %s, Load from HWImg Array!\n", __FUNCTION__, pFileName); + + return rtStatus; +} + +VOID +initDeltaSwingIndexTables( + PADAPTER Adapter, + char *Band, + char *Path, + char *Sign, + char *Channel, + char *Rate, + char *Data +) +{ +#define STR_EQUAL_5G(_band, _path, _sign, _rate, _chnl) \ + ((strcmp(Band, _band) == 0) && (strcmp(Path, _path) == 0) && (strcmp(Sign, _sign) == 0) &&\ + (strcmp(Rate, _rate) == 0) && (strcmp(Channel, _chnl) == 0)\ + ) +#define STR_EQUAL_2G(_band, _path, _sign, _rate) \ + ((strcmp(Band, _band) == 0) && (strcmp(Path, _path) == 0) && (strcmp(Sign, _sign) == 0) &&\ + (strcmp(Rate, _rate) == 0)\ + ) + +#define STORE_SWING_TABLE(_array, _iteratedIdx) \ + do { \ + for (token = strsep(&Data, delim); token != NULL; token = strsep(&Data, delim)) {\ + sscanf(token, "%d", &idx);\ + _array[_iteratedIdx++] = (u8)idx;\ + } } while (0)\ + + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + struct odm_rf_calibration_structure *pRFCalibrateInfo = &(pDM_Odm->rf_calibrate_info); + u32 j = 0; + char *token; + char delim[] = ","; + u32 idx = 0; + + /* RTW_INFO("===>initDeltaSwingIndexTables(): Band: %s;\nPath: %s;\nSign: %s;\nChannel: %s;\nRate: %s;\n, Data: %s;\n", */ + /* Band, Path, Sign, Channel, Rate, Data); */ + + if (STR_EQUAL_2G("2G", "A", "+", "CCK")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_2g_cck_a_p, j); + else if (STR_EQUAL_2G("2G", "A", "-", "CCK")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_2g_cck_a_n, j); + else if (STR_EQUAL_2G("2G", "B", "+", "CCK")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_2g_cck_b_p, j); + else if (STR_EQUAL_2G("2G", "B", "-", "CCK")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_2g_cck_b_n, j); + else if (STR_EQUAL_2G("2G", "A", "+", "ALL")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_2ga_p, j); + else if (STR_EQUAL_2G("2G", "A", "-", "ALL")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_2ga_n, j); + else if (STR_EQUAL_2G("2G", "B", "+", "ALL")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_2gb_p, j); + else if (STR_EQUAL_2G("2G", "B", "-", "ALL")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_2gb_n, j); + else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "0")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5ga_p[0], j); + else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "0")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5ga_n[0], j); + else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "0")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5gb_p[0], j); + else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "0")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5gb_n[0], j); + else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "1")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5ga_p[1], j); + else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "1")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5ga_n[1], j); + else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "1")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5gb_p[1], j); + else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "1")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5gb_n[1], j); + else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "2")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5ga_p[2], j); + else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "2")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5ga_n[2], j); + else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "2")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5gb_p[2], j); + else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "2")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5gb_n[2], j); + else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "3")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5ga_p[3], j); + else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "3")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5ga_n[3], j); + else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "3")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5gb_p[3], j); + else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "3")) + STORE_SWING_TABLE(pRFCalibrateInfo->delta_swing_table_idx_5gb_n[3], j); + else + RTW_INFO("===>initDeltaSwingIndexTables(): The input is invalid!!\n"); +} + +int +PHY_ConfigRFWithTxPwrTrackParaFile( + IN PADAPTER Adapter, + IN char *pFileName +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + struct odm_rf_calibration_structure *pRFCalibrateInfo = &(pDM_Odm->rf_calibrate_info); + int rlen = 0, rtStatus = _FAIL; + char *szLine, *ptmp; + u32 i = 0, j = 0; + char c = 0; + + if (!(Adapter->registrypriv.load_phy_file & LOAD_RF_TXPWR_TRACK_PARA_FILE)) + return rtStatus; + + _rtw_memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); + + if ((pHalData->rf_tx_pwr_track_len == 0) && (pHalData->rf_tx_pwr_track == NULL)) { + rtw_get_phy_file_path(Adapter, pFileName); + if (rtw_is_file_readable(rtw_phy_para_file_path) == _TRUE) { + rlen = rtw_retrieve_from_file(rtw_phy_para_file_path, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); + if (rlen > 0) { + rtStatus = _SUCCESS; + pHalData->rf_tx_pwr_track = rtw_zvmalloc(rlen); + if (pHalData->rf_tx_pwr_track) { + _rtw_memcpy(pHalData->rf_tx_pwr_track, pHalData->para_file_buf, rlen); + pHalData->rf_tx_pwr_track_len = rlen; + } else + RTW_INFO("%s rf_tx_pwr_track alloc fail !\n", __FUNCTION__); + } + } + } else { + if ((pHalData->rf_tx_pwr_track_len != 0) && (pHalData->rf_tx_pwr_track != NULL)) { + _rtw_memcpy(pHalData->para_file_buf, pHalData->rf_tx_pwr_track, pHalData->rf_tx_pwr_track_len); + rtStatus = _SUCCESS; + } else + RTW_INFO("%s(): Critical Error !!!\n", __FUNCTION__); + } + + if (rtStatus == _SUCCESS) { + /* RTW_INFO("%s(): read %s successfully\n", __FUNCTION__, pFileName); */ + + ptmp = pHalData->para_file_buf; + for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { + if (!IsCommentString(szLine)) { + char band[5] = "", path[5] = "", sign[5] = ""; + char chnl[5] = "", rate[10] = ""; + char data[300] = ""; /* 100 is too small */ + + if (strlen(szLine) < 10 || szLine[0] != '[') + continue; + + strncpy(band, szLine + 1, 2); + strncpy(path, szLine + 5, 1); + strncpy(sign, szLine + 8, 1); + + i = 10; /* szLine+10 */ + if (!ParseQualifiedString(szLine, &i, rate, '[', ']')) { + /* RTW_INFO("Fail to parse rate!\n"); */ + } + if (!ParseQualifiedString(szLine, &i, chnl, '[', ']')) { + /* RTW_INFO("Fail to parse channel group!\n"); */ + } + while (szLine[i] != '{' && i < strlen(szLine)) + i++; + if (!ParseQualifiedString(szLine, &i, data, '{', '}')) { + /* RTW_INFO("Fail to parse data!\n"); */ + } + + initDeltaSwingIndexTables(Adapter, band, path, sign, chnl, rate, data); + } + } + } else + RTW_INFO("%s(): No File %s, Load from HWImg Array!\n", __FUNCTION__, pFileName); +#if 0 + for (i = 0; i < DELTA_SWINGIDX_SIZE; ++i) { + RTW_INFO("pRFCalibrateInfo->delta_swing_table_idx_2ga_p[%d] = %d\n", i, pRFCalibrateInfo->delta_swing_table_idx_2ga_p[i]); + RTW_INFO("pRFCalibrateInfo->delta_swing_table_idx_2ga_n[%d] = %d\n", i, pRFCalibrateInfo->delta_swing_table_idx_2ga_n[i]); + RTW_INFO("pRFCalibrateInfo->delta_swing_table_idx_2gb_p[%d] = %d\n", i, pRFCalibrateInfo->delta_swing_table_idx_2gb_p[i]); + RTW_INFO("pRFCalibrateInfo->delta_swing_table_idx_2gb_n[%d] = %d\n", i, pRFCalibrateInfo->delta_swing_table_idx_2gb_n[i]); + RTW_INFO("pRFCalibrateInfo->delta_swing_table_idx_2g_cck_a_p[%d] = %d\n", i, pRFCalibrateInfo->delta_swing_table_idx_2g_cck_a_p[i]); + RTW_INFO("pRFCalibrateInfo->delta_swing_table_idx_2g_cck_a_n[%d] = %d\n", i, pRFCalibrateInfo->delta_swing_table_idx_2g_cck_a_n[i]); + RTW_INFO("pRFCalibrateInfo->delta_swing_table_idx_2g_cck_b_p[%d] = %d\n", i, pRFCalibrateInfo->delta_swing_table_idx_2g_cck_b_p[i]); + RTW_INFO("pRFCalibrateInfo->delta_swing_table_idx_2g_cck_b_n[%d] = %d\n", i, pRFCalibrateInfo->delta_swing_table_idx_2g_cck_b_n[i]); + + for (j = 0; j < 3; ++j) { + RTW_INFO("pRFCalibrateInfo->delta_swing_table_idx_5ga_p[%d][%d] = %d\n", j, i, pRFCalibrateInfo->delta_swing_table_idx_5ga_p[j][i]); + RTW_INFO("pRFCalibrateInfo->delta_swing_table_idx_5ga_n[%d][%d] = %d\n", j, i, pRFCalibrateInfo->delta_swing_table_idx_5ga_n[j][i]); + RTW_INFO("pRFCalibrateInfo->delta_swing_table_idx_5gb_p[%d][%d] = %d\n", j, i, pRFCalibrateInfo->delta_swing_table_idx_5gb_p[j][i]); + RTW_INFO("pRFCalibrateInfo->delta_swing_table_idx_5gb_n[%d][%d] = %d\n", j, i, pRFCalibrateInfo->delta_swing_table_idx_5gb_n[j][i]); + } + } +#endif + return rtStatus; +} + +int +phy_ParsePowerLimitTableFile( + PADAPTER Adapter, + char *buffer +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + struct PHY_DM_STRUCT *pDM_Odm = &(pHalData->odmpriv); + u32 i = 0, forCnt = 0; + u8 loadingStage = 0, limitValue = 0, fraction = 0; + char *szLine, *ptmp; + int rtStatus = _SUCCESS; + char band[10], bandwidth[10], rateSection[10], + regulation[TXPWR_LMT_MAX_REGULATION_NUM][10], rfPath[10], colNumBuf[10]; + u8 colNum = 0; + + RTW_INFO("===>phy_ParsePowerLimitTableFile()\n"); + + if (Adapter->registrypriv.RegDecryptCustomFile == 1) + phy_DecryptBBPgParaFile(Adapter, buffer); + + ptmp = buffer; + for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { + if (isAllSpaceOrTab(szLine, sizeof(*szLine))) + continue; + + /* skip comment */ + if (IsCommentString(szLine)) + continue; + + if (loadingStage == 0) { + for (forCnt = 0; forCnt < TXPWR_LMT_MAX_REGULATION_NUM; ++forCnt) + _rtw_memset((PVOID) regulation[forCnt], 0, 10); + _rtw_memset((PVOID) band, 0, 10); + _rtw_memset((PVOID) bandwidth, 0, 10); + _rtw_memset((PVOID) rateSection, 0, 10); + _rtw_memset((PVOID) rfPath, 0, 10); + _rtw_memset((PVOID) colNumBuf, 0, 10); + + if (szLine[0] != '#' || szLine[1] != '#') + continue; + + /* skip the space */ + i = 2; + while (szLine[i] == ' ' || szLine[i] == '\t') + ++i; + + szLine[--i] = ' '; /* return the space in front of the regulation info */ + + /* Parse the label of the table */ + if (!ParseQualifiedString(szLine, &i, band, ' ', ',')) { + RTW_INFO("Fail to parse band!\n"); + return _FAIL; + } + if (!ParseQualifiedString(szLine, &i, bandwidth, ' ', ',')) { + RTW_INFO("Fail to parse bandwidth!\n"); + return _FAIL; + } + if (!ParseQualifiedString(szLine, &i, rfPath, ' ', ',')) { + RTW_INFO("Fail to parse rf path!\n"); + return _FAIL; + } + if (!ParseQualifiedString(szLine, &i, rateSection, ' ', ',')) { + RTW_INFO("Fail to parse rate!\n"); + return _FAIL; + } + + loadingStage = 1; + } else if (loadingStage == 1) { + if (szLine[0] != '#' || szLine[1] != '#') + continue; + + /* skip the space */ + i = 2; + while (szLine[i] == ' ' || szLine[i] == '\t') + ++i; + + if (!eqNByte((u8 *)(szLine + i), (u8 *)("START"), 5)) { + RTW_INFO("Lost \"## START\" label\n"); + return _FAIL; + } + + loadingStage = 2; + } else if (loadingStage == 2) { + if (szLine[0] != '#' || szLine[1] != '#') + continue; + + /* skip the space */ + i = 2; + while (szLine[i] == ' ' || szLine[i] == '\t') + ++i; + + if (!ParseQualifiedString(szLine, &i, colNumBuf, '#', '#')) { + RTW_INFO("Fail to parse column number!\n"); + return _FAIL; + } + + if (!GetU1ByteIntegerFromStringInDecimal(colNumBuf, &colNum)) + return _FAIL; + + if (colNum > TXPWR_LMT_MAX_REGULATION_NUM) { + RTW_INFO("unvalid col number %d (greater than max %d)\n", + colNum, TXPWR_LMT_MAX_REGULATION_NUM); + return _FAIL; + } + + for (forCnt = 0; forCnt < colNum; ++forCnt) { + u8 regulation_name_cnt = 0; + + /* skip the space */ + while (szLine[i] == ' ' || szLine[i] == '\t') + ++i; + + while (szLine[i] != ' ' && szLine[i] != '\t' && szLine[i] != '\0') + regulation[forCnt][regulation_name_cnt++] = szLine[i++]; + /* RTW_INFO("regulation %s!\n", regulation[forCnt]); */ + + if (regulation_name_cnt == 0) { + RTW_INFO("unvalid number of regulation!\n"); + return _FAIL; + } + } + + loadingStage = 3; + } else if (loadingStage == 3) { + char channel[10] = {0}, powerLimit[10] = {0}; + u8 cnt = 0; + + /* the table ends */ + if (szLine[0] == '#' && szLine[1] == '#') { + i = 2; + while (szLine[i] == ' ' || szLine[i] == '\t') + ++i; + + if (eqNByte((u8 *)(szLine + i), (u8 *)("END"), 3)) { + loadingStage = 0; + continue; + } else { + RTW_INFO("Wrong format\n"); + RTW_INFO("<===== phy_ParsePowerLimitTableFile()\n"); + return _FAIL; + } + } + + if ((szLine[0] != 'c' && szLine[0] != 'C') || + (szLine[1] != 'h' && szLine[1] != 'H')) { + RTW_INFO("Meet wrong channel => power limt pair '%c','%c'(%d,%d)\n", szLine[0], szLine[1], szLine[0], szLine[1]); + continue; + } + i = 2;/* move to the location behind 'h' */ + + /* load the channel number */ + cnt = 0; + while (szLine[i] >= '0' && szLine[i] <= '9') { + channel[cnt] = szLine[i]; + ++cnt; + ++i; + } + /* RTW_INFO("chnl %s!\n", channel); */ + + for (forCnt = 0; forCnt < colNum; ++forCnt) { + /* skip the space between channel number and the power limit value */ + while (szLine[i] == ' ' || szLine[i] == '\t') + ++i; + + /* load the power limit value */ + cnt = 0; + fraction = 0; + _rtw_memset((PVOID) powerLimit, 0, 10); + while ((szLine[i] >= '0' && szLine[i] <= '9') || szLine[i] == '.') { + if (szLine[i] == '.') { + if ((szLine[i + 1] >= '0' && szLine[i + 1] <= '9')) { + fraction = szLine[i + 1]; + i += 2; + } else { + RTW_INFO("Wrong fraction in TXPWR_LMT.txt\n"); + return _FAIL; + } + + break; + } + + powerLimit[cnt] = szLine[i]; + ++cnt; + ++i; + } + + if (powerLimit[0] == '\0') { + powerLimit[0] = '6'; + powerLimit[1] = '3'; + i += 2; + } else { + if (!GetU1ByteIntegerFromStringInDecimal(powerLimit, &limitValue)) + return _FAIL; + + limitValue *= 2; + cnt = 0; + if (fraction == '5') + ++limitValue; + + /* the value is greater or equal to 100 */ + if (limitValue >= 100) { + powerLimit[cnt++] = limitValue / 100 + '0'; + limitValue %= 100; + + if (limitValue >= 10) { + powerLimit[cnt++] = limitValue / 10 + '0'; + limitValue %= 10; + } else + powerLimit[cnt++] = '0'; + + powerLimit[cnt++] = limitValue + '0'; + } + /* the value is greater or equal to 10 */ + else if (limitValue >= 10) { + powerLimit[cnt++] = limitValue / 10 + '0'; + limitValue %= 10; + powerLimit[cnt++] = limitValue + '0'; + } + /* the value is less than 10 */ + else + powerLimit[cnt++] = limitValue + '0'; + + powerLimit[cnt] = '\0'; + } + + /* RTW_INFO("ch%s => %s\n", channel, powerLimit); */ + + /* store the power limit value */ + phy_set_tx_power_limit(pDM_Odm, (u8 *)regulation[forCnt], (u8 *)band, + (u8 *)bandwidth, (u8 *)rateSection, (u8 *)rfPath, (u8 *)channel, (u8 *)powerLimit); + + } + } else { + RTW_INFO("Abnormal loading stage in phy_ParsePowerLimitTableFile()!\n"); + rtStatus = _FAIL; + break; + } + } + + RTW_INFO("<===phy_ParsePowerLimitTableFile()\n"); + return rtStatus; +} + +int +PHY_ConfigRFWithPowerLimitTableParaFile( + IN PADAPTER Adapter, + IN const char *pFileName +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + int rlen = 0, rtStatus = _FAIL; + + if (!(Adapter->registrypriv.load_phy_file & LOAD_RF_TXPWR_LMT_PARA_FILE)) + return rtStatus; + + _rtw_memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); + + if (pHalData->rf_tx_pwr_lmt == NULL) { + rtw_get_phy_file_path(Adapter, pFileName); + if (rtw_is_file_readable(rtw_phy_para_file_path) == _TRUE) { + rlen = rtw_retrieve_from_file(rtw_phy_para_file_path, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); + if (rlen > 0) { + rtStatus = _SUCCESS; + pHalData->rf_tx_pwr_lmt = rtw_zvmalloc(rlen); + if (pHalData->rf_tx_pwr_lmt) { + _rtw_memcpy(pHalData->rf_tx_pwr_lmt, pHalData->para_file_buf, rlen); + pHalData->rf_tx_pwr_lmt_len = rlen; + } else + RTW_INFO("%s rf_tx_pwr_lmt alloc fail !\n", __FUNCTION__); + } + } + } else { + if ((pHalData->rf_tx_pwr_lmt_len != 0) && (pHalData->rf_tx_pwr_lmt != NULL)) { + _rtw_memcpy(pHalData->para_file_buf, pHalData->rf_tx_pwr_lmt, pHalData->rf_tx_pwr_lmt_len); + rtStatus = _SUCCESS; + } else + RTW_INFO("%s(): Critical Error !!!\n", __FUNCTION__); + } + + if (rtStatus == _SUCCESS) { + /* RTW_INFO("%s(): read %s ok\n", __FUNCTION__, pFileName); */ + rtStatus = phy_ParsePowerLimitTableFile(Adapter, pHalData->para_file_buf); + } else + RTW_INFO("%s(): No File %s, Load from HWImg Array!\n", __FUNCTION__, pFileName); + + return rtStatus; +} + +void phy_free_filebuf_mask(_adapter *padapter, u8 mask) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + + if (pHalData->mac_reg && (mask & LOAD_MAC_PARA_FILE)) { + rtw_vmfree(pHalData->mac_reg, pHalData->mac_reg_len); + pHalData->mac_reg = NULL; + } + if (mask & LOAD_BB_PARA_FILE) { + if (pHalData->bb_phy_reg) { + rtw_vmfree(pHalData->bb_phy_reg, pHalData->bb_phy_reg_len); + pHalData->bb_phy_reg = NULL; + } + if (pHalData->bb_agc_tab) { + rtw_vmfree(pHalData->bb_agc_tab, pHalData->bb_agc_tab_len); + pHalData->bb_agc_tab = NULL; + } + } + if (pHalData->bb_phy_reg_pg && (mask & LOAD_BB_PG_PARA_FILE)) { + rtw_vmfree(pHalData->bb_phy_reg_pg, pHalData->bb_phy_reg_pg_len); + pHalData->bb_phy_reg_pg = NULL; + } + if (pHalData->bb_phy_reg_mp && (mask & LOAD_BB_MP_PARA_FILE)) { + rtw_vmfree(pHalData->bb_phy_reg_mp, pHalData->bb_phy_reg_mp_len); + pHalData->bb_phy_reg_mp = NULL; + } + if (mask & LOAD_RF_PARA_FILE) { + if (pHalData->rf_radio_a) { + rtw_vmfree(pHalData->rf_radio_a, pHalData->rf_radio_a_len); + pHalData->rf_radio_a = NULL; + } + if (pHalData->rf_radio_b) { + rtw_vmfree(pHalData->rf_radio_b, pHalData->rf_radio_b_len); + pHalData->rf_radio_b = NULL; + } + } + if (pHalData->rf_tx_pwr_track && (mask & LOAD_RF_TXPWR_TRACK_PARA_FILE)) { + rtw_vmfree(pHalData->rf_tx_pwr_track, pHalData->rf_tx_pwr_track_len); + pHalData->rf_tx_pwr_track = NULL; + } + if (pHalData->rf_tx_pwr_lmt && (mask & LOAD_RF_TXPWR_LMT_PARA_FILE)) { + rtw_vmfree(pHalData->rf_tx_pwr_lmt, pHalData->rf_tx_pwr_lmt_len); + pHalData->rf_tx_pwr_lmt = NULL; + } +} + +inline void phy_free_filebuf(_adapter *padapter) +{ + phy_free_filebuf_mask(padapter, 0xFF); +} + +#endif diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_dm.c b/linux-bsp/drivers/rtl8188eus/hal/hal_dm.c new file mode 100644 index 0000000..2198617 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_dm.c @@ -0,0 +1,224 @@ +/****************************************************************************** + * + * Copyright(c) 2014 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#include <drv_types.h> +#include <hal_data.h> + +/* A mapping from HalData to ODM. */ +enum odm_board_type_e boardType(u8 InterfaceSel) +{ + enum odm_board_type_e board = ODM_BOARD_DEFAULT; + +#ifdef CONFIG_PCI_HCI + INTERFACE_SELECT_PCIE pcie = (INTERFACE_SELECT_PCIE)InterfaceSel; + switch (pcie) { + case INTF_SEL0_SOLO_MINICARD: + board |= ODM_BOARD_MINICARD; + break; + case INTF_SEL1_BT_COMBO_MINICARD: + board |= ODM_BOARD_BT; + board |= ODM_BOARD_MINICARD; + break; + default: + board = ODM_BOARD_DEFAULT; + break; + } + +#elif defined(CONFIG_USB_HCI) + INTERFACE_SELECT_USB usb = (INTERFACE_SELECT_USB)InterfaceSel; + switch (usb) { + case INTF_SEL1_USB_High_Power: + board |= ODM_BOARD_EXT_LNA; + board |= ODM_BOARD_EXT_PA; + break; + case INTF_SEL2_MINICARD: + board |= ODM_BOARD_MINICARD; + break; + case INTF_SEL4_USB_Combo: + board |= ODM_BOARD_BT; + break; + case INTF_SEL5_USB_Combo_MF: + board |= ODM_BOARD_BT; + break; + case INTF_SEL0_USB: + case INTF_SEL3_USB_Solo: + default: + board = ODM_BOARD_DEFAULT; + break; + } + +#endif + /* RTW_INFO("===> boardType(): (pHalData->InterfaceSel, pDM_Odm->BoardType) = (%d, %d)\n", InterfaceSel, board); */ + + return board; +} + +void Init_ODM_ComInfo(_adapter *adapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(adapter); + struct PHY_DM_STRUCT *pDM_Odm = &(pHalData->odmpriv); + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(adapter); + int i; + + _rtw_memset(pDM_Odm, 0, sizeof(*pDM_Odm)); + + pDM_Odm->adapter = adapter; + + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_PLATFORM, ODM_CE); + + rtw_odm_init_ic_type(adapter); + + if (rtw_get_intf_type(adapter) == RTW_GSPI) + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_INTERFACE, ODM_ITRF_SDIO); + else + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_INTERFACE, rtw_get_intf_type(adapter)); + + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_MP_TEST_CHIP, IS_NORMAL_CHIP(pHalData->version_id)); + + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_PATCH_ID, pHalData->CustomerID); + + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_BWIFI_TEST, adapter->registrypriv.wifi_spec); + + + if (pHalData->rf_type == RF_1T1R) + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_1T1R); + else if (pHalData->rf_type == RF_1T2R) + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_1T2R); + else if (pHalData->rf_type == RF_2T2R) + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_2T2R); + else if (pHalData->rf_type == RF_2T2R_GREEN) + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_2T2R_GREEN); + else if (pHalData->rf_type == RF_2T3R) + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_2T3R); + else if (pHalData->rf_type == RF_2T4R) + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_2T4R); + else if (pHalData->rf_type == RF_3T3R) + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_3T3R); + else if (pHalData->rf_type == RF_3T4R) + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_3T4R); + else if (pHalData->rf_type == RF_4T4R) + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_4T4R); + else + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_XTXR); + + + { + /* 1 ======= BoardType: ODM_CMNINFO_BOARD_TYPE ======= */ + u8 odm_board_type = ODM_BOARD_DEFAULT; + + if (pHalData->ExternalLNA_2G != 0) { + odm_board_type |= ODM_BOARD_EXT_LNA; + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_EXT_LNA, 1); + } + if (pHalData->external_lna_5g != 0) { + odm_board_type |= ODM_BOARD_EXT_LNA_5G; + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_5G_EXT_LNA, 1); + } + if (pHalData->ExternalPA_2G != 0) { + odm_board_type |= ODM_BOARD_EXT_PA; + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_EXT_PA, 1); + } + if (pHalData->external_pa_5g != 0) { + odm_board_type |= ODM_BOARD_EXT_PA_5G; + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_5G_EXT_PA, 1); + } + if (pHalData->EEPROMBluetoothCoexist) + odm_board_type |= ODM_BOARD_BT; + + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_BOARD_TYPE, odm_board_type); + /* 1 ============== End of BoardType ============== */ + } + + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_DOMAIN_CODE_2G, pHalData->Regulation2_4G); + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_DOMAIN_CODE_5G, pHalData->Regulation5G); + +#ifdef CONFIG_DFS_MASTER + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_DFS_REGION_DOMAIN, adapter->registrypriv.dfs_region_domain); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_DFS_MASTER_ENABLE, &(adapter_to_rfctl(adapter)->dfs_master_enabled)); +#endif + + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_GPA, pHalData->TypeGPA); + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_APA, pHalData->TypeAPA); + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_GLNA, pHalData->TypeGLNA); + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_ALNA, pHalData->TypeALNA); + + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RFE_TYPE, pHalData->rfe_type); + + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_EXT_TRSW, 0); + + /*Add by YuChen for kfree init*/ + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_REGRFKFREEENABLE, adapter->registrypriv.RegPwrTrimEnable); + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RFKFREEENABLE, pHalData->RfKFreeEnable); + + /*Antenna diversity relative parameters*/ + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_ANT_DIV, &(pHalData->AntDivCfg)); + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_RF_ANTENNA_TYPE, pHalData->TRxAntDivType); + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_BE_FIX_TX_ANT, pHalData->b_fix_tx_ant); + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_WITH_EXT_ANTENNA_SWITCH, pHalData->with_extenal_ant_switch); + + /*Add by YuChen for adaptivity init*/ + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_ADAPTIVITY, &(adapter->registrypriv.adaptivity_en)); + phydm_adaptivity_info_init(pDM_Odm, PHYDM_ADAPINFO_CARRIER_SENSE_ENABLE, (adapter->registrypriv.adaptivity_mode != 0) ? TRUE : FALSE); + phydm_adaptivity_info_init(pDM_Odm, PHYDM_ADAPINFO_DCBACKOFF, adapter->registrypriv.adaptivity_dc_backoff); + phydm_adaptivity_info_init(pDM_Odm, PHYDM_ADAPINFO_DYNAMICLINKADAPTIVITY, (adapter->registrypriv.adaptivity_dml != 0) ? TRUE : FALSE); + phydm_adaptivity_info_init(pDM_Odm, PHYDM_ADAPINFO_TH_L2H_INI, adapter->registrypriv.adaptivity_th_l2h_ini); + phydm_adaptivity_info_init(pDM_Odm, PHYDM_ADAPINFO_TH_EDCCA_HL_DIFF, adapter->registrypriv.adaptivity_th_edcca_hl_diff); + +#ifdef CONFIG_IQK_PA_OFF + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_IQKPAOFF, 1); +#endif + odm_cmn_info_init(pDM_Odm, ODM_CMNINFO_IQKFWOFFLOAD, pHalData->RegIQKFWOffload); + + /* Pointer reference */ + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_TX_UNI, &(dvobj->traffic_stat.tx_bytes)); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_RX_UNI, &(dvobj->traffic_stat.rx_bytes)); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_WM_MODE, &(pmlmeext->cur_wireless_mode)); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_BAND, &(pHalData->current_band_type)); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_FORCED_RATE, &(pHalData->ForcedDataRate)); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_FORCED_IGI_LB, &(pHalData->u1ForcedIgiLb)); + + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_SEC_CHNL_OFFSET, &(pHalData->nCur40MhzPrimeSC)); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_SEC_MODE, &(adapter->securitypriv.dot11PrivacyAlgrthm)); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_BW, &(pHalData->current_channel_bw)); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_CHNL, &(pHalData->current_channel)); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_NET_CLOSED, &(adapter->net_closed)); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_FORCED_IGI_LB, &(pHalData->u1ForcedIgiLb)); + + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_SCAN, &(pmlmepriv->bScanInProcess)); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_POWER_SAVING, &(pwrctl->bpower_saving)); + /*Add by Yuchen for phydm beamforming*/ + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_TX_TP, &(dvobj->traffic_stat.cur_tx_tp)); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_RX_TP, &(dvobj->traffic_stat.cur_rx_tp)); + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_ANT_TEST, &(pHalData->antenna_test)); +#ifdef CONFIG_USB_HCI + odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_HUBUSBMODE, &(dvobj->usb_speed)); +#endif + for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) + odm_cmn_info_ptr_array_hook(pDM_Odm, ODM_CMNINFO_STA_STATUS, i, NULL); + + phydm_init_debug_setting(pDM_Odm); + + /* TODO */ + /* odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_BT_OPERATION, _FALSE); */ + /* odm_cmn_info_hook(pDM_Odm, ODM_CMNINFO_BT_DISABLE_EDCA, _FALSE); */ +} diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_dm.h b/linux-bsp/drivers/rtl8188eus/hal/hal_dm.h new file mode 100644 index 0000000..1232708 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_dm.h @@ -0,0 +1,25 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef __HAL_DM_H__ +#define __HAL_DM_H__ + +void Init_ODM_ComInfo(_adapter *adapter); + +#endif /* __HAL_DM_H__ */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_halmac.c b/linux-bsp/drivers/rtl8188eus/hal/hal_halmac.c new file mode 100644 index 0000000..fb0b73d --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_halmac.c @@ -0,0 +1,2635 @@ +/****************************************************************************** + * + * Copyright(c) 2015 - 2016 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _HAL_HALMAC_C_ + +#include <drv_types.h> /* PADAPTER, struct dvobj_priv, SDIO_ERR_VAL8 and etc. */ +#include <hal_data.h> /* efuse, PHAL_DATA_TYPE and etc. */ +#include "halmac/halmac_api.h" /* HALMAC_FW_SIZE_MAX_88XX and etc. */ +#include "hal_halmac.h" /* dvobj_to_halmac() and ect. */ + +#define DEFAULT_INDICATOR_TIMELMT 1000 /* ms */ +#define FIRMWARE_MAX_SIZE HALMAC_FW_SIZE_MAX_88XX + +/* + * Driver API for HALMAC operations + */ + +#ifdef CONFIG_SDIO_HCI +#include <rtw_sdio.h> + +static u8 _halmac_mac_reg_page0_chk(const char *func, struct dvobj_priv *dvobj, u32 offset) +{ +#if defined(CONFIG_IO_CHECK_IN_ANA_LOW_CLK) && defined(CONFIG_LPS_LCLK) + struct pwrctrl_priv *pwrpriv = &dvobj->pwrctl_priv; + u32 mac_reg_offset = 0; + + if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) + return _TRUE; + + if (pwrpriv->rpwm >= PS_STATE_S2) + return _TRUE; + + if (offset & (WLAN_IOREG_DEVICE_ID << 13)) { /*WLAN_IOREG_OFFSET*/ + mac_reg_offset = offset & HALMAC_WLAN_MAC_REG_MSK; + if (mac_reg_offset < 0x100) { + RTW_ERR(FUNC_ADPT_FMT "access MAC REG -0x%04x in PS-mode:0x%02x\n", + FUNC_ADPT_ARG(dvobj_get_primary_adapter(dvobj)), mac_reg_offset, pwrpriv->pwr_mode); + rtw_warn_on(1); + return _FALSE; + } + } +#endif + return _TRUE; +} + +static u8 _halmac_sdio_cmd52_read(void *p, u32 offset) +{ + struct dvobj_priv *d; + u8 val; + u8 ret; + + + d = (struct dvobj_priv *)p; + _halmac_mac_reg_page0_chk(__func__, d, offset); + ret = rtw_sdio_read_cmd52(d, offset, &val, 1); + if (_FAIL == ret) { + RTW_INFO("%s: [ERROR] I/O FAIL!\n", __FUNCTION__); + return SDIO_ERR_VAL8; + } + + return val; +} + +static void _halmac_sdio_cmd52_write(void *p, u32 offset, u8 val) +{ + struct dvobj_priv *d; + u8 ret; + + + d = (struct dvobj_priv *)p; + _halmac_mac_reg_page0_chk(__func__, d, offset); + ret = rtw_sdio_write_cmd52(d, offset, &val, 1); + if (_FAIL == ret) + RTW_INFO("%s: [ERROR] I/O FAIL!\n", __FUNCTION__); +} + +static u8 _halmac_sdio_reg_read_8(void *p, u32 offset) +{ + struct dvobj_priv *d; + u8 *pbuf; + u8 val; + int err; + + + d = (struct dvobj_priv *)p; + val = SDIO_ERR_VAL8; + _halmac_mac_reg_page0_chk(__func__, d, offset); + pbuf = rtw_zmalloc(1); + if (!pbuf) + return val; + + err = d->intf_ops->read(d, offset, pbuf, 1, 0); + if (err) { + RTW_INFO("%s: [ERROR] I/O FAIL!\n", __FUNCTION__); + goto exit; + } + + val = *pbuf; + +exit: + rtw_mfree(pbuf, 1); + + return val; +} + +static u16 _halmac_sdio_reg_read_16(void *p, u32 offset) +{ + struct dvobj_priv *d; + u8 *pbuf; + u16 val; + int err; + + + d = (struct dvobj_priv *)p; + val = SDIO_ERR_VAL16; + _halmac_mac_reg_page0_chk(__func__, d, offset); + pbuf = rtw_zmalloc(2); + if (!pbuf) + return val; + + err = d->intf_ops->read(d, offset, pbuf, 2, 0); + if (err) { + RTW_INFO("%s: [ERROR] I/O FAIL!\n", __FUNCTION__); + goto exit; + } + + val = le16_to_cpu(*(u16 *)pbuf); + +exit: + rtw_mfree(pbuf, 2); + + return val; +} + +static u32 _halmac_sdio_reg_read_32(void *p, u32 offset) +{ + struct dvobj_priv *d; + u8 *pbuf; + u32 val; + int err; + + + d = (struct dvobj_priv *)p; + val = SDIO_ERR_VAL32; + _halmac_mac_reg_page0_chk(__func__, d, offset); + pbuf = rtw_zmalloc(4); + if (!pbuf) + return val; + + err = d->intf_ops->read(d, offset, pbuf, 4, 0); + if (err) { + RTW_INFO("%s: [ERROR] I/O FAIL!\n", __FUNCTION__); + goto exit; + } + + val = le32_to_cpu(*(u32 *)pbuf); + +exit: + rtw_mfree(pbuf, 4); + + return val; +} + +static u8 _halmac_sdio_reg_read_n(void *p, u32 offset, u32 size, u8 *data) +{ + struct dvobj_priv *d = (struct dvobj_priv *)p; + PSDIO_DATA psdio = &d->intf_data; + + u8 *pbuf; + int err; + u8 rst = _FALSE; + u32 sdio_read_size; + + sdio_read_size = RND4(size); + if (sdio_read_size > psdio->block_transfer_len) + sdio_read_size = _RND(sdio_read_size, psdio->block_transfer_len); + + pbuf = rtw_zmalloc(sdio_read_size); + if ((!pbuf) || (!data)) + return rst; + + err = d->intf_ops->read(d, offset, pbuf, sdio_read_size, 0); + if (err) { + RTW_ERR("%s: [ERROR] I/O FAIL!\n", __func__); + goto exit; + } + + _rtw_memcpy(data, pbuf, size); + rst = _TRUE; +exit: + rtw_mfree(pbuf, sdio_read_size); + + return rst; +} + +static void _halmac_sdio_reg_write_8(void *p, u32 offset, u8 val) +{ + struct dvobj_priv *d; + u8 *pbuf; + int err; + + + d = (struct dvobj_priv *)p; + _halmac_mac_reg_page0_chk(__func__, d, offset); + pbuf = rtw_zmalloc(1); + if (!pbuf) + return; + _rtw_memcpy(pbuf, &val, 1); + + err = d->intf_ops->write(d, offset, pbuf, 1, 0); + if (err) + RTW_INFO("%s: [ERROR] I/O FAIL!\n", __FUNCTION__); + + rtw_mfree(pbuf, 1); +} + +static void _halmac_sdio_reg_write_16(void *p, u32 offset, u16 val) +{ + struct dvobj_priv *d; + u8 *pbuf; + int err; + + + d = (struct dvobj_priv *)p; + _halmac_mac_reg_page0_chk(__func__, d, offset); + val = cpu_to_le16(val); + pbuf = rtw_zmalloc(2); + if (!pbuf) + return; + _rtw_memcpy(pbuf, &val, 2); + + err = d->intf_ops->write(d, offset, pbuf, 2, 0); + if (err) + RTW_INFO("%s: [ERROR] I/O FAIL!\n", __FUNCTION__); + + rtw_mfree(pbuf, 2); +} + +static void _halmac_sdio_reg_write_32(void *p, u32 offset, u32 val) +{ + struct dvobj_priv *d; + u8 *pbuf; + int err; + + + d = (struct dvobj_priv *)p; + _halmac_mac_reg_page0_chk(__func__, d, offset); + val = cpu_to_le32(val); + pbuf = rtw_zmalloc(4); + if (!pbuf) + return; + _rtw_memcpy(pbuf, &val, 4); + + err = d->intf_ops->write(d, offset, pbuf, 4, 0); + if (err) + RTW_INFO("%s: [ERROR] I/O FAIL!\n", __FUNCTION__); + + rtw_mfree(pbuf, 4); +} + +#else /* !CONFIG_SDIO_HCI */ + +static u8 _halmac_reg_read_8(void *p, u32 offset) +{ + struct dvobj_priv *d; + PADAPTER adapter; + + + d = (struct dvobj_priv *)p; + adapter = dvobj_get_primary_adapter(d); + + return rtw_read8(adapter, offset); +} + +static u16 _halmac_reg_read_16(void *p, u32 offset) +{ + struct dvobj_priv *d; + PADAPTER adapter; + + + d = (struct dvobj_priv *)p; + adapter = dvobj_get_primary_adapter(d); + + return rtw_read16(adapter, offset); +} + +static u32 _halmac_reg_read_32(void *p, u32 offset) +{ + struct dvobj_priv *d; + PADAPTER adapter; + + + d = (struct dvobj_priv *)p; + adapter = dvobj_get_primary_adapter(d); + + return rtw_read32(adapter, offset); +} + +static void _halmac_reg_write_8(void *p, u32 offset, u8 val) +{ + struct dvobj_priv *d; + PADAPTER adapter; + int err; + + + d = (struct dvobj_priv *)p; + adapter = dvobj_get_primary_adapter(d); + + err = rtw_write8(adapter, offset, val); + if (err == _FAIL) + RTW_INFO("%s: [ERROR] I/O FAIL!\n", __FUNCTION__); +} + +static void _halmac_reg_write_16(void *p, u32 offset, u16 val) +{ + struct dvobj_priv *d; + PADAPTER adapter; + int err; + + + d = (struct dvobj_priv *)p; + adapter = dvobj_get_primary_adapter(d); + + err = rtw_write16(adapter, offset, val); + if (err == _FAIL) + RTW_INFO("%s: [ERROR] I/O FAIL!\n", __FUNCTION__); +} + +static void _halmac_reg_write_32(void *p, u32 offset, u32 val) +{ + struct dvobj_priv *d; + PADAPTER adapter; + int err; + + + d = (struct dvobj_priv *)p; + adapter = dvobj_get_primary_adapter(d); + + err = rtw_write32(adapter, offset, val); + if (err == _FAIL) + RTW_INFO("%s: [ERROR] I/O FAIL!\n", __FUNCTION__); +} +#endif /* !CONFIG_SDIO_HCI */ + +static u8 _halmac_mfree(void *p, void *buffer, u32 size) +{ + rtw_mfree(buffer, size); + return _TRUE; +} + +static void *_halmac_malloc(void *p, u32 size) +{ + return rtw_zmalloc(size); +} + +static u8 _halmac_memcpy(void *p, void *dest, void *src, u32 size) +{ + _rtw_memcpy(dest, src, size); + return _TRUE; +} + +static u8 _halmac_memset(void *p, void *addr, u8 value, u32 size) +{ + _rtw_memset(addr, value, size); + return _TRUE; +} + +static void _halmac_udelay(void *p, u32 us) +{ + rtw_udelay_os(us); +} + +static u8 _halmac_mutex_init(void *p, HALMAC_MUTEX *pMutex) +{ + _rtw_mutex_init(pMutex); + return _TRUE; +} + +static u8 _halmac_mutex_deinit(void *p, HALMAC_MUTEX *pMutex) +{ + _rtw_mutex_free(pMutex); + return _TRUE; +} + +static u8 _halmac_mutex_lock(void *p, HALMAC_MUTEX *pMutex) +{ + int err; + + err = _enter_critical_mutex(pMutex, NULL); + if (err) + return _FALSE; + + return _TRUE; +} + +static u8 _halmac_mutex_unlock(void *p, HALMAC_MUTEX *pMutex) +{ + _exit_critical_mutex(pMutex, NULL); + return _TRUE; +} + +static u8 _halmac_msg_print(void *p, u32 msg_type, u8 msg_level, s8 *fmt, ...) +{ +#define MSG_LEN 100 +#define MSG_PREFIX "[HALMAC]" + va_list args; + u8 str[MSG_LEN] = {0}; + + + str[0] = '\n'; + va_start(args, fmt); + vsnprintf(str, MSG_LEN, fmt, args); + va_end(args); + + if (msg_level <= HALMAC_DBG_ERR) + RTW_ERR(MSG_PREFIX "%s", str); + else if (msg_level <= HALMAC_DBG_WARN) + RTW_WARN(MSG_PREFIX "%s", str); + else + RTW_DBG(MSG_PREFIX "%s", str); + + return _TRUE; +} + +static u8 _halmac_buff_print(void *p, u32 msg_type, u8 msg_level, s8 *buf, u32 size) +{ +#define MSG_PREFIX "[HALMAC]" + + if (msg_level <= HALMAC_DBG_WARN) + RTW_INFO_DUMP(MSG_PREFIX, buf, size); + else + RTW_DBG_DUMP(MSG_PREFIX, buf, size); + + return _TRUE; +} + + +const char *const RTW_HALMAC_FEATURE_NAME[] = { + "HALMAC_FEATURE_CFG_PARA", + "HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE", + "HALMAC_FEATURE_DUMP_LOGICAL_EFUSE", + "HALMAC_FEATURE_UPDATE_PACKET", + "HALMAC_FEATURE_UPDATE_DATAPACK", + "HALMAC_FEATURE_RUN_DATAPACK", + "HALMAC_FEATURE_CHANNEL_SWITCH", + "HALMAC_FEATURE_IQK", + "HALMAC_FEATURE_POWER_TRACKING", + "HALMAC_FEATURE_PSD", + "HALMAC_FEATURE_ALL" +}; + +static inline u8 is_valid_id_status(HALMAC_FEATURE_ID id, HALMAC_CMD_PROCESS_STATUS status) +{ + switch (id) { + case HALMAC_FEATURE_CFG_PARA: + RTW_INFO("%s: %s\n", __FUNCTION__, RTW_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE: + RTW_INFO("%s: %s\n", __FUNCTION__, RTW_HALMAC_FEATURE_NAME[id]); + if (HALMAC_CMD_PROCESS_DONE != status) + RTW_INFO("%s: id(%d) unspecified status(%d)!\n", + __FUNCTION__, id, status); + break; + case HALMAC_FEATURE_DUMP_LOGICAL_EFUSE: + RTW_INFO("%s: %s\n", __FUNCTION__, RTW_HALMAC_FEATURE_NAME[id]); + if (HALMAC_CMD_PROCESS_DONE != status) + RTW_INFO("%s: id(%d) unspecified status(%d)!\n", + __FUNCTION__, id, status); + break; + case HALMAC_FEATURE_UPDATE_PACKET: + RTW_INFO("%s: %s\n", __FUNCTION__, RTW_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_UPDATE_DATAPACK: + RTW_INFO("%s: %s\n", __FUNCTION__, RTW_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_RUN_DATAPACK: + RTW_INFO("%s: %s\n", __FUNCTION__, RTW_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_CHANNEL_SWITCH: + RTW_INFO("%s: %s\n", __FUNCTION__, RTW_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_IQK: + RTW_INFO("%s: %s\n", __FUNCTION__, RTW_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_POWER_TRACKING: + RTW_INFO("%s: %s\n", __FUNCTION__, RTW_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_PSD: + RTW_INFO("%s: %s\n", __FUNCTION__, RTW_HALMAC_FEATURE_NAME[id]); + break; + case HALMAC_FEATURE_ALL: + RTW_INFO("%s: %s\n", __FUNCTION__, RTW_HALMAC_FEATURE_NAME[id]); + break; + default: + RTW_ERR("%s: unknown feature id(%d)\n", __FUNCTION__, id); + return _FALSE; + } + + return _TRUE; +} + +static int init_halmac_event_with_waittime(struct dvobj_priv *d, HALMAC_FEATURE_ID id, u8 *buf, u32 size, u32 time) +{ + struct submit_ctx *sctx; + + + if (!d->hmpriv.indicator[id].sctx) { + sctx = (struct submit_ctx *)rtw_zmalloc(sizeof(*sctx)); + if (!sctx) + return -1; + } else { + RTW_WARN("%s: id(%d) sctx is not NULL!!\n", __FUNCTION__, id); + sctx = d->hmpriv.indicator[id].sctx; + d->hmpriv.indicator[id].sctx = NULL; + } + + rtw_sctx_init(sctx, time); + d->hmpriv.indicator[id].buffer = buf; + d->hmpriv.indicator[id].buf_size = size; + d->hmpriv.indicator[id].ret_size = 0; + d->hmpriv.indicator[id].status = 0; + /* fill sctx at least to sure other variables are all ready! */ + d->hmpriv.indicator[id].sctx = sctx; + + return 0; +} + +static inline int init_halmac_event(struct dvobj_priv *d, HALMAC_FEATURE_ID id, u8 *buf, u32 size) +{ + return init_halmac_event_with_waittime(d, id, buf, size, DEFAULT_INDICATOR_TIMELMT); +} + +static void free_halmac_event(struct dvobj_priv *d, HALMAC_FEATURE_ID id) +{ + struct submit_ctx *sctx; + + + if (!d->hmpriv.indicator[id].sctx) + return; + + sctx = d->hmpriv.indicator[id].sctx; + d->hmpriv.indicator[id].sctx = NULL; + rtw_mfree((u8 *)sctx, sizeof(*sctx)); +} + +static int wait_halmac_event(struct dvobj_priv *d, HALMAC_FEATURE_ID id) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + struct submit_ctx *sctx; + int ret; + + + sctx = d->hmpriv.indicator[id].sctx; + if (!sctx) + return -1; + + ret = rtw_sctx_wait(sctx, RTW_HALMAC_FEATURE_NAME[id]); + free_halmac_event(d, id); + if (_SUCCESS == ret) + return 0; + + /* timeout! We have to reset halmac state */ + RTW_ERR("%s: Wait id(%d, %s) TIMEOUT! Reset HALMAC state!\n", + __FUNCTION__, id, RTW_HALMAC_FEATURE_NAME[id]); + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + api->halmac_reset_feature(mac, id); + + return -1; +} + +/* + * Return: + * Always return _TRUE, HALMAC don't care the return value. + */ +static u8 _halmac_event_indication(void *p, HALMAC_FEATURE_ID feature_id, HALMAC_CMD_PROCESS_STATUS process_status, u8 *buf, u32 size) +{ + struct dvobj_priv *d; + PADAPTER adapter; + PHAL_DATA_TYPE hal; + struct halmac_indicator *tbl, *indicator; + struct submit_ctx *sctx; + u32 cpsz; + u8 ret; + + + d = (struct dvobj_priv *)p; + adapter = dvobj_get_primary_adapter(d); + hal = GET_HAL_DATA(adapter); + tbl = d->hmpriv.indicator; + + /* Filter(Skip) middle status indication */ + ret = is_valid_id_status(feature_id, process_status); + if (_FALSE == ret) + goto exit; + + indicator = &tbl[feature_id]; + indicator->status = process_status; + indicator->ret_size = size; + if (!indicator->sctx) { + RTW_WARN("%s: No feature id(%d, %s) waiting!!\n", __FUNCTION__, feature_id, RTW_HALMAC_FEATURE_NAME[feature_id]); + goto exit; + } + sctx = indicator->sctx; + + if (HALMAC_CMD_PROCESS_ERROR == process_status) { + RTW_ERR("%s: Something wrong id(%d, %s)!!\n", __FUNCTION__, feature_id, RTW_HALMAC_FEATURE_NAME[feature_id]); + rtw_sctx_done_err(&sctx, RTW_SCTX_DONE_UNKNOWN); + goto exit; + } + + if (size > indicator->buf_size) { + RTW_WARN("%s: id(%d, %s) buffer is not enough(%d<%d), data will be truncated!\n", + __FUNCTION__, feature_id, RTW_HALMAC_FEATURE_NAME[feature_id], indicator->buf_size, size); + cpsz = indicator->buf_size; + } else { + cpsz = size; + } + if (cpsz && indicator->buffer) + _rtw_memcpy(indicator->buffer, buf, cpsz); + + rtw_sctx_done(&sctx); + +exit: + return _TRUE; +} + +HALMAC_PLATFORM_API rtw_halmac_platform_api = { + /* R/W register */ +#ifdef CONFIG_SDIO_HCI + .SDIO_CMD52_READ = _halmac_sdio_cmd52_read, + .SDIO_CMD53_READ_8 = _halmac_sdio_reg_read_8, + .SDIO_CMD53_READ_16 = _halmac_sdio_reg_read_16, + .SDIO_CMD53_READ_32 = _halmac_sdio_reg_read_32, + .SDIO_CMD53_READ_N = _halmac_sdio_reg_read_n, + .SDIO_CMD52_WRITE = _halmac_sdio_cmd52_write, + .SDIO_CMD53_WRITE_8 = _halmac_sdio_reg_write_8, + .SDIO_CMD53_WRITE_16 = _halmac_sdio_reg_write_16, + .SDIO_CMD53_WRITE_32 = _halmac_sdio_reg_write_32, + +#endif /* CONFIG_SDIO_HCI */ +#if defined(CONFIG_USB_HCI) || defined(CONFIG_PCIE_HCI) + .REG_READ_8 = _halmac_reg_read_8, + .REG_READ_16 = _halmac_reg_read_16, + .REG_READ_32 = _halmac_reg_read_32, + .REG_WRITE_8 = _halmac_reg_write_8, + .REG_WRITE_16 = _halmac_reg_write_16, + .REG_WRITE_32 = _halmac_reg_write_32, +#endif /* CONFIG_USB_HCI || CONFIG_PCIE_HCI */ + + /* Write data */ +#if 0 + /* impletement in HAL-IC level */ + .SEND_RSVD_PAGE = sdio_write_data_rsvd_page, + .SEND_H2C_PKT = sdio_write_data_h2c, +#endif + /* Memory allocate */ + .RTL_FREE = _halmac_mfree, + .RTL_MALLOC = _halmac_malloc, + .RTL_MEMCPY = _halmac_memcpy, + .RTL_MEMSET = _halmac_memset, + + /* Sleep */ + .RTL_DELAY_US = _halmac_udelay, + + /* Process Synchronization */ + .MUTEX_INIT = _halmac_mutex_init, + .MUTEX_DEINIT = _halmac_mutex_deinit, + .MUTEX_LOCK = _halmac_mutex_lock, + .MUTEX_UNLOCK = _halmac_mutex_unlock, + + .MSG_PRINT = _halmac_msg_print, + .BUFF_PRINT = _halmac_buff_print, + .EVENT_INDICATION = _halmac_event_indication, +}; + +u8 rtw_halmac_read8(struct intf_hdl *pintfhdl, u32 addr) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + + + /* WARNING: pintf_dev should not be null! */ + mac = dvobj_to_halmac(pintfhdl->pintf_dev); + api = HALMAC_GET_API(mac); + + return api->halmac_reg_read_8(mac, addr); +} + +u16 rtw_halmac_read16(struct intf_hdl *pintfhdl, u32 addr) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + + + /* WARNING: pintf_dev should not be null! */ + mac = dvobj_to_halmac(pintfhdl->pintf_dev); + api = HALMAC_GET_API(mac); + + return api->halmac_reg_read_16(mac, addr); +} + +u32 rtw_halmac_read32(struct intf_hdl *pintfhdl, u32 addr) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + + + /* WARNING: pintf_dev should not be null! */ + mac = dvobj_to_halmac(pintfhdl->pintf_dev); + api = HALMAC_GET_API(mac); + + return api->halmac_reg_read_32(mac, addr); +} + +void rtw_halmac_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem) +{ +#if defined(CONFIG_SDIO_HCI) + PHALMAC_ADAPTER mac; + PHALMAC_API api; + + if (pmem == NULL) { + RTW_ERR("pmem is NULL\n"); + return; + } + /* WARNING: pintf_dev should not be null! */ + mac = dvobj_to_halmac(pintfhdl->pintf_dev); + api = HALMAC_GET_API(mac); + + api->halmac_reg_sdio_cmd53_read_n(mac, addr, cnt, pmem); +#endif +} + +#ifdef CONFIG_SDIO_INDIRECT_ACCESS +u8 rtw_halmac_iread8(struct intf_hdl *pintfhdl, u32 addr) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + + /* WARNING: pintf_dev should not be null! */ + mac = dvobj_to_halmac(pintfhdl->pintf_dev); + api = HALMAC_GET_API(mac); + + /*return api->halmac_reg_read_indirect_8(mac, addr);*/ + return api->halmac_reg_read_8(mac, addr); +} + +u16 rtw_halmac_iread16(struct intf_hdl *pintfhdl, u32 addr) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + u16 val16 = 0; + + /* WARNING: pintf_dev should not be null! */ + mac = dvobj_to_halmac(pintfhdl->pintf_dev); + api = HALMAC_GET_API(mac); + + /*return api->halmac_reg_read_indirect_16(mac, addr);*/ + return api->halmac_reg_read_16(mac, addr); +} + +u32 rtw_halmac_iread32(struct intf_hdl *pintfhdl, u32 addr) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + + + /* WARNING: pintf_dev should not be null! */ + mac = dvobj_to_halmac(pintfhdl->pintf_dev); + api = HALMAC_GET_API(mac); + + return api->halmac_reg_read_indirect_32(mac, addr); +} +#endif + +int rtw_halmac_write8(struct intf_hdl *pintfhdl, u32 addr, u8 value) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + + + /* WARNING: pintf_dev should not be null! */ + mac = dvobj_to_halmac(pintfhdl->pintf_dev); + api = HALMAC_GET_API(mac); + + status = api->halmac_reg_write_8(mac, addr, value); + + if (status == HALMAC_RET_SUCCESS) + return 0; + + return -1; +} + +int rtw_halmac_write16(struct intf_hdl *pintfhdl, u32 addr, u16 value) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + + + /* WARNING: pintf_dev should not be null! */ + mac = dvobj_to_halmac(pintfhdl->pintf_dev); + api = HALMAC_GET_API(mac); + + status = api->halmac_reg_write_16(mac, addr, value); + + if (status == HALMAC_RET_SUCCESS) + return 0; + + return -1; +} + +int rtw_halmac_write32(struct intf_hdl *pintfhdl, u32 addr, u32 value) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + + + /* WARNING: pintf_dev should not be null! */ + mac = dvobj_to_halmac(pintfhdl->pintf_dev); + api = HALMAC_GET_API(mac); + + status = api->halmac_reg_write_32(mac, addr, value); + + if (status == HALMAC_RET_SUCCESS) + return 0; + + return -1; +} + +static int init_priv(struct halmacpriv *priv) +{ + struct halmac_indicator *indicator; + u32 count, size; + + + size = sizeof(*priv); + _rtw_memset(priv, 0, size); + + count = HALMAC_FEATURE_ALL + 1; + size = sizeof(*indicator) * count; + indicator = (struct halmac_indicator *)rtw_zmalloc(size); + if (!indicator) + return -1; + priv->indicator = indicator; + + return 0; +} + +static void deinit_priv(struct halmacpriv *priv) +{ + struct halmac_indicator *indicator; + + + indicator = priv->indicator; + priv->indicator = NULL; + if (indicator) { + u32 count, size; + + count = HALMAC_FEATURE_ALL + 1; +#ifdef CONFIG_RTW_DEBUG + { + struct submit_ctx *sctx; + u32 i; + + for (i = 0; i < count; i++) { + if (!indicator[i].sctx) + continue; + + RTW_INFO("%s: <WARN> %s id(%d) sctx still exist!!\n", + __FUNCTION__, RTW_HALMAC_FEATURE_NAME[i], i); + sctx = indicator[i].sctx; + indicator[i].sctx = NULL; + rtw_mfree((u8 *)sctx, sizeof(*sctx)); + } + } +#endif /* !CONFIG_RTW_DEBUG */ + size = sizeof(*indicator) * count; + rtw_mfree((u8 *)indicator, size); + } +} + +void rtw_dump_halmac_info(void *sel) +{ + HALMAC_RET_STATUS status; + HALMAC_VER halmac_version; + + status = halmac_get_version(&halmac_version); + if (status != HALMAC_RET_SUCCESS) + return; + + RTW_PRINT_SEL(sel, "HALMAC VER -%x.%x.%x\n", halmac_version.major_ver, halmac_version.prototype_ver, halmac_version.minor_ver); +} + +int rtw_halmac_init_adapter(struct dvobj_priv *d, PHALMAC_PLATFORM_API pf_api) +{ + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + HALMAC_INTERFACE intf; + HALMAC_RET_STATUS status; + int err = 0; + + + halmac = dvobj_to_halmac(d); + if (halmac) { + err = 0; + goto out; + } + + err = init_priv(&d->hmpriv); + if (err) + goto out; + +#ifdef CONFIG_SDIO_HCI + intf = HALMAC_INTERFACE_SDIO; +#elif defined(CONFIG_USB_HCI) + intf = HALMAC_INTERFACE_USB; +#elif defined(CONFIG_PCIE_HCI) + intf = HALMAC_INTERFACE_PCIE; +#else +#warning "INTERFACE(CONFIG_XXX_HCI) not be defined!!" + intf = HALMAC_INTERFACE_UNDEFINE; +#endif + status = halmac_init_adapter(d, pf_api, intf, &halmac, &api); + if (HALMAC_RET_SUCCESS != status) { + RTW_INFO("%s: halmac_init_adapter fail!(status=%d)\n", __FUNCTION__, status); + err = -1; + goto out; + } + + dvobj_set_halmac(d, halmac); + +out: + if (err) + rtw_halmac_deinit_adapter(d); + + return err; +} + +int rtw_halmac_deinit_adapter(struct dvobj_priv *d) +{ + PHALMAC_ADAPTER halmac; + HALMAC_RET_STATUS status; + int err = 0; + + + halmac = dvobj_to_halmac(d); + if (!halmac) { + err = 0; + goto out; + } + + deinit_priv(&d->hmpriv); + + status = halmac_deinit_adapter(halmac); + dvobj_set_halmac(d, NULL); + if (status != HALMAC_RET_SUCCESS) { + err = -1; + goto out; + } + +out: + return err; +} + +/* + * Description: + * Power on device hardware. + * [Notice!] If device's power state is on before, + * it would be power off first and turn on power again. + * + * Return: + * 0 power on success + * -1 power on fail + * -2 power state unchange + */ +int rtw_halmac_poweron(struct dvobj_priv *d) +{ + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + int err = -1; + + + halmac = dvobj_to_halmac(d); + if (!halmac) + goto out; + + api = HALMAC_GET_API(halmac); + + status = api->halmac_pre_init_system_cfg(halmac); + if (status != HALMAC_RET_SUCCESS) + goto out; + +#ifdef CONFIG_SDIO_HCI + status = api->halmac_sdio_cmd53_4byte(halmac, 1); + if (status != HALMAC_RET_SUCCESS) + goto out; +#endif + + status = api->halmac_mac_power_switch(halmac, HALMAC_MAC_POWER_ON); + if (HALMAC_RET_PWR_UNCHANGE == status) { + /* + * Work around for warm reboot but device not power off, + * but it would also fall into this case when auto power on is enabled. + */ + api->halmac_mac_power_switch(halmac, HALMAC_MAC_POWER_OFF); + status = api->halmac_mac_power_switch(halmac, HALMAC_MAC_POWER_ON); + RTW_WARN("%s: Power state abnormal, try to recover...%s\n", + __FUNCTION__, (HALMAC_RET_SUCCESS == status)?"OK":"FAIL!"); + } + if (HALMAC_RET_SUCCESS != status) { + if (HALMAC_RET_PWR_UNCHANGE == status) + err = -2; + goto out; + } + + status = api->halmac_init_system_cfg(halmac); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +/* + * Description: + * Power off device hardware. + * + * Return: + * 0 Power off success + * -1 Power off fail + */ +int rtw_halmac_poweroff(struct dvobj_priv *d) +{ + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + int err = -1; + + + halmac = dvobj_to_halmac(d); + if (!halmac) + goto out; + + api = HALMAC_GET_API(halmac); + + status = api->halmac_mac_power_switch(halmac, HALMAC_MAC_POWER_OFF); + if ((HALMAC_RET_SUCCESS != status) + && (HALMAC_RET_PWR_UNCHANGE != status)) + goto out; + + err = 0; +out: + return err; +} + +/* + * Note: + * When this function return, the register REG_RCR may be changed. + */ +int rtw_halmac_config_rx_info(struct dvobj_priv *d, HALMAC_DRV_INFO info) +{ + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + int err = -1; + + + halmac = dvobj_to_halmac(d); + api = HALMAC_GET_API(halmac); + + status = api->halmac_cfg_drv_info(halmac, info); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +#ifdef CONFIG_SUPPORT_TRX_SHARED +static inline HALMAC_RX_FIFO_EXPANDING_MODE _trx_share_mode_drv2halmac(u8 trx_share_mode) +{ + if (0 == trx_share_mode) + return HALMAC_RX_FIFO_EXPANDING_MODE_DISABLE; + else if (1 == trx_share_mode) + return HALMAC_RX_FIFO_EXPANDING_MODE_1_BLOCK; + else if (2 == trx_share_mode) + return HALMAC_RX_FIFO_EXPANDING_MODE_2_BLOCK; + else if (3 == trx_share_mode) + return HALMAC_RX_FIFO_EXPANDING_MODE_3_BLOCK; + else + return HALMAC_RX_FIFO_EXPANDING_MODE_DISABLE; +} +static HALMAC_RX_FIFO_EXPANDING_MODE _rtw_get_trx_share_mode(_adapter *adapter) +{ + struct registry_priv *registry_par = &adapter->registrypriv; + + return _trx_share_mode_drv2halmac(registry_par->trx_share_mode); +} +void dump_trx_share_mode(void *sel, _adapter *adapter) +{ + struct registry_priv *registry_par = &adapter->registrypriv; + u8 mode = _trx_share_mode_drv2halmac(registry_par->trx_share_mode); + + if (HALMAC_RX_FIFO_EXPANDING_MODE_1_BLOCK == mode) + RTW_PRINT_SEL(sel, "TRx share mode : %s\n", "RX_FIFO_EXPANDING_MODE_1"); + else if (HALMAC_RX_FIFO_EXPANDING_MODE_2_BLOCK == mode) + RTW_PRINT_SEL(sel, "TRx share mode : %s\n", "RX_FIFO_EXPANDING_MODE_2"); + else if (HALMAC_RX_FIFO_EXPANDING_MODE_3_BLOCK == mode) + RTW_PRINT_SEL(sel, "TRx share mode : %s\n", "RX_FIFO_EXPANDING_MODE_3"); + else + RTW_PRINT_SEL(sel, "TRx share mode : %s\n", "DISABLE"); +} +#endif + +static u8 _get_drv_rsvd_page(HALMAC_DRV_RSVD_PG_NUM rsvd_page_number) +{ + if (HALMAC_RSVD_PG_NUM16 == rsvd_page_number) + return 16; + else if (HALMAC_RSVD_PG_NUM24 == rsvd_page_number) + return 24; + else if (HALMAC_RSVD_PG_NUM32 == rsvd_page_number) + return 32; + + RTW_ERR("%s unknown HALMAC_RSVD_PG type :%d\n", __func__, rsvd_page_number); + rtw_warn_on(1); + return 0; +} + +static HALMAC_TRX_MODE _choose_trx_mode(struct dvobj_priv *d) +{ + PADAPTER p; + + + p = dvobj_get_primary_adapter(d); + + if (p->registrypriv.wifi_spec) + return HALMAC_TRX_MODE_WMM; + +#ifdef CONFIG_SUPPORT_TRX_SHARED + if (_rtw_get_trx_share_mode(p)) + return HALMAC_TRX_MODE_TRXSHARE; +#endif + + return HALMAC_TRX_MODE_NORMAL; +} + +static inline HALMAC_RF_TYPE _rf_type_drv2halmac(RT_RF_TYPE_DEF_E rf_drv) +{ + HALMAC_RF_TYPE rf_mac; + + + switch (rf_drv) { + case RF_1T2R: + rf_mac = HALMAC_RF_1T2R; + break; + case RF_2T4R: + rf_mac = HALMAC_RF_2T4R; + break; + case RF_2T2R: + rf_mac = HALMAC_RF_2T2R; + break; + case RF_1T1R: + rf_mac = HALMAC_RF_1T1R; + break; + case RF_2T2R_GREEN: + rf_mac = HALMAC_RF_2T2R_GREEN; + break; + case RF_2T3R: + rf_mac = HALMAC_RF_2T3R; + break; + case RF_3T3R: + rf_mac = HALMAC_RF_3T3R; + break; + case RF_3T4R: + rf_mac = HALMAC_RF_3T4R; + break; + case RF_4T4R: + rf_mac = HALMAC_RF_4T4R; + break; + default: + rf_mac = (HALMAC_RF_TYPE)rf_drv; + break; + } + + return rf_mac; +} + +static int _send_general_info(struct dvobj_priv *d) +{ + PADAPTER adapter; + PHAL_DATA_TYPE hal; + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + HALMAC_GENERAL_INFO info; + HALMAC_RET_STATUS status; + u8 val8; + + + adapter = dvobj_get_primary_adapter(d); + hal = GET_HAL_DATA(adapter); + halmac = dvobj_to_halmac(d); + if (!halmac) + return -1; + api = HALMAC_GET_API(halmac); + + _rtw_memset(&info, 0, sizeof(info)); + info.rfe_type = (u8)hal->rfe_type; + rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, &val8); + info.rf_type = _rf_type_drv2halmac(val8); + + status = api->halmac_send_general_info(halmac, &info); + switch (status) { + case HALMAC_RET_SUCCESS: + break; + case HALMAC_RET_NO_DLFW: + RTW_WARN("%s: halmac_send_general_info() fail because fw not dl!\n", + __FUNCTION__); + /* go through */ + default: + return -1; + } + + return 0; +} + +/* + * Description: + * Downlaod Firmware Flow + * + * Parameters: + * d pointer of struct dvobj_priv + * fw firmware array + * fwsize firmware size + * re_dl re-download firmware or not + * 0: run in init hal flow, not re-download + * 1: it is a stand alone operation, not in init hal flow + * + * Return: + * 0 Success + * others Fail + */ +static int download_fw(struct dvobj_priv *d, u8 *fw, u32 fwsize, u8 re_dl) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + int err = 0; + PHAL_DATA_TYPE hal; + HALMAC_FW_VERSION fw_vesion; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + hal = GET_HAL_DATA(dvobj_get_primary_adapter(d)); + + if ((!fw) || (!fwsize)) + return -1; + + /* 1. Driver Stop Tx */ + /* ToDo */ + + /* 2. Driver Check Tx FIFO is empty */ + /* ToDo */ + + /* 3. Config MAX download size */ +#ifdef CONFIG_USB_HCI + /* for USB do not exceed MAX_CMDBUF_SZ */ + api->halmac_cfg_max_dl_size(mac, 0x1000); +#elif defined CONFIG_PCIE_HCI + /* required a even length from u32 */ + api->halmac_cfg_max_dl_size(mac, (MAX_CMDBUF_SZ - TXDESC_OFFSET) & 0xFFFFFFFE); +#endif + + /* 4. Download Firmware */ + status = api->halmac_download_firmware(mac, fw, fwsize); + if (HALMAC_RET_SUCCESS != status) + return -1; + + /* 5. Driver resume TX if needed */ + /* ToDo */ + + if (re_dl) { + HALMAC_TRX_MODE mode; + + /* 6. Init TRX Configuration */ + mode = _choose_trx_mode(d); + status = api->halmac_init_trx_cfg(mac, mode); + if (HALMAC_RET_SUCCESS != status) + return -1; + + /* 7. Config RX Aggregation */ + err = rtw_halmac_rx_agg_switch(d, _TRUE); + if (err) + return -1; + + /* 8. Send General Info */ + err = _send_general_info(d); + if (err) + return -1; + } + + /* 9. Reset driver variables if needed */ + hal->LastHMEBoxNum = 0; + + /* 10. Get FW version */ + status = api->halmac_get_fw_version(mac, &fw_vesion); + if (status == HALMAC_RET_SUCCESS) { + hal->firmware_version = fw_vesion.version; + hal->firmware_sub_version = fw_vesion.sub_version; + } + + return err; +} + +static HALMAC_RET_STATUS init_mac_flow(struct dvobj_priv *d) +{ + PADAPTER p; + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + HALMAC_WLAN_ADDR hwa; + HALMAC_TRX_MODE trx_mode; + HALMAC_RET_STATUS status; + u8 nettype; + int err; + PHAL_DATA_TYPE hal; + HALMAC_DRV_RSVD_PG_NUM rsvd_page_number = HALMAC_RSVD_PG_NUM16;/*HALMAC_RSVD_PG_NUM24/HALMAC_RSVD_PG_NUM32*/ + + p = dvobj_get_primary_adapter(d); + hal = GET_HAL_DATA(p); + halmac = dvobj_to_halmac(d); + api = HALMAC_GET_API(halmac); + +#ifdef CONFIG_SUPPORT_TRX_SHARED + status = api->halmac_cfg_rx_fifo_expanding_mode(halmac, _rtw_get_trx_share_mode(p)); + if (status != HALMAC_RET_SUCCESS) + goto out; +#endif + +#ifdef CONFIG_PNO_SUPPORT + rsvd_page_number = HALMAC_RSVD_PG_NUM32; +#endif + status = api->halmac_cfg_drv_rsvd_pg_num(halmac, rsvd_page_number); + if (status != HALMAC_RET_SUCCESS) + goto out; + hal->drv_rsvd_page_number = _get_drv_rsvd_page(rsvd_page_number); + +#ifdef CONFIG_USB_HCI + status = api->halmac_set_bulkout_num(halmac, d->RtNumOutPipes); + if (status != HALMAC_RET_SUCCESS) + goto out; +#endif /* CONFIG_USB_HCI */ + + trx_mode = _choose_trx_mode(d); + status = api->halmac_init_mac_cfg(halmac, trx_mode); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = rtw_halmac_rx_agg_switch(d, _TRUE); + if (err) + goto out; + + nettype = dvobj_to_regsty(d)->wireless_mode; + if (is_supported_vht(nettype) == _TRUE) + status = api->halmac_cfg_operation_mode(halmac, HALMAC_WIRELESS_MODE_AC); + else if (is_supported_ht(nettype) == _TRUE) + status = api->halmac_cfg_operation_mode(halmac, HALMAC_WIRELESS_MODE_N); + else if (IsSupportedTxOFDM(nettype) == _TRUE) + status = api->halmac_cfg_operation_mode(halmac, HALMAC_WIRELESS_MODE_G); + else + status = api->halmac_cfg_operation_mode(halmac, HALMAC_WIRELESS_MODE_B); + if (status != HALMAC_RET_SUCCESS) + goto out; + +out: + return status; +} + +/* + * Notices: + * Make sure + * 1. rtw_hal_get_hwreg(HW_VAR_RF_TYPE) + * 2. HAL_DATA_TYPE.rfe_type + * already ready for use before calling this function. + */ +static int _halmac_init_hal(struct dvobj_priv *d, u8 *fw, u32 fwsize) +{ + PADAPTER adapter; + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + u32 ok = _TRUE; + u8 fw_ok = _FALSE; + int err, err_ret = -1; + + + adapter = dvobj_get_primary_adapter(d); + halmac = dvobj_to_halmac(d); + if (!halmac) + goto out; + api = HALMAC_GET_API(halmac); + + /* StatePowerOff */ + + /* SKIP: halmac_init_adapter (Already done before) */ + + /* halmac_pre_Init_system_cfg */ + /* halmac_mac_power_switch(on) */ + /* halmac_Init_system_cfg */ + ok = rtw_hal_power_on(adapter); + if (_FAIL == ok) + goto out; + + /* StatePowerOn */ + + /* DownloadFW */ + if (fw && fwsize) { + err = download_fw(d, fw, fwsize, 0); + if (err) + goto out; + fw_ok = _TRUE; + } + + /* InitMACFlow */ + status = init_mac_flow(d); + if (status != HALMAC_RET_SUCCESS) + goto out; + + /* halmac_send_general_info */ + if (_TRUE == fw_ok) { + err = _send_general_info(d); + if (err) + goto out; + } + + /* Init Phy parameter-MAC */ + ok = rtw_hal_init_mac_register(adapter); + if (_FALSE == ok) + goto out; + + /* StateMacInitialized */ + + /* halmac_cfg_drv_info */ + err = rtw_halmac_config_rx_info(d, HALMAC_DRV_INFO_PHY_STATUS); + if (err) + goto out; + + /* halmac_set_hw_value(HALMAC_HW_EN_BB_RF) */ + /* Init BB, RF */ + ok = rtw_hal_init_phy(adapter); + if (_FALSE == ok) + goto out; + + status = api->halmac_init_interface_cfg(halmac); + if (status != HALMAC_RET_SUCCESS) + goto out; + + /* SKIP: halmac_verify_platform_api */ + /* SKIP: halmac_h2c_lb */ + + /* StateRxIdle */ + + err_ret = 0; +out: + return err_ret; +} + +int rtw_halmac_init_hal(struct dvobj_priv *d) +{ + return _halmac_init_hal(d, NULL, 0); +} + +/* + * Notices: + * Make sure + * 1. rtw_hal_get_hwreg(HW_VAR_RF_TYPE) + * 2. HAL_DATA_TYPE.rfe_type + * already ready for use before calling this function. + */ +int rtw_halmac_init_hal_fw(struct dvobj_priv *d, u8 *fw, u32 fwsize) +{ + return _halmac_init_hal(d, fw, fwsize); +} + +/* + * Notices: + * Make sure + * 1. rtw_hal_get_hwreg(HW_VAR_RF_TYPE) + * 2. HAL_DATA_TYPE.rfe_type + * already ready for use before calling this function. + */ +int rtw_halmac_init_hal_fw_file(struct dvobj_priv *d, u8 *fwpath) +{ + u8 *fw = NULL; + u32 fwmaxsize, size = 0; + int err = 0; + + + fwmaxsize = FIRMWARE_MAX_SIZE; + fw = rtw_zmalloc(fwmaxsize); + if (!fw) + return -1; + + size = rtw_retrieve_from_file(fwpath, fw, fwmaxsize); + if (!size) { + err = -1; + goto exit; + } + + err = _halmac_init_hal(d, fw, size); + +exit: + rtw_mfree(fw, fwmaxsize); + fw = NULL; + + return err; +} + +int rtw_halmac_deinit_hal(struct dvobj_priv *d) +{ + PADAPTER adapter; + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + int err = -1; + + + adapter = dvobj_get_primary_adapter(d); + halmac = dvobj_to_halmac(d); + if (!halmac) + goto out; + api = HALMAC_GET_API(halmac); + + status = api->halmac_deinit_interface_cfg(halmac); + if (status != HALMAC_RET_SUCCESS) + goto out; + + rtw_hal_power_off(adapter); + + err = 0; +out: + return err; +} + +int rtw_halmac_self_verify(struct dvobj_priv *d) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + int err = -1; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + status = api->halmac_verify_platform_api(mac); + if (status != HALMAC_RET_SUCCESS) + goto out; + + status = api->halmac_h2c_lb(mac); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +int rtw_halmac_redl_fw(struct dvobj_priv *d, u8 *fw, u32 fwsize) +{ + int err = 0; + + return err; +} + +/* + * Return: + * 0 Success + * -22 Invalid arguemnt + */ +int rtw_halmac_dlfw(struct dvobj_priv *d, u8 *fw, u32 fwsize) +{ + PADAPTER adapter; + HALMAC_RET_STATUS status; + u32 ok = _TRUE; + int err, err_ret = -1; + + + if (!fw || !fwsize) + return -22; + + adapter = dvobj_get_primary_adapter(d); + + /* re-download firmware */ + if (rtw_is_hw_init_completed(adapter)) + return download_fw(d, fw, fwsize, 1); + + /* Download firmware before hal init */ + /* Power on, download firmware and init mac */ + ok = rtw_hal_power_on(adapter); + if (_FAIL == ok) + goto out; + + err = download_fw(d, fw, fwsize, 0); + if (err) { + err_ret = err; + goto out; + } + + status = init_mac_flow(d); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = _send_general_info(d); + if (err) + goto out; + + err_ret = 0; + +out: + return err_ret; +} + +int rtw_halmac_dlfw_from_file(struct dvobj_priv *d, u8 *fwpath) +{ + u8 *fw = NULL; + u32 fwmaxsize, size = 0; + int err = 0; + + + fwmaxsize = FIRMWARE_MAX_SIZE; + fw = rtw_zmalloc(fwmaxsize); + if (!fw) + return -1; + + size = rtw_retrieve_from_file(fwpath, fw, fwmaxsize); + if (size) + err = rtw_halmac_dlfw(d, fw, size); + else + err = -1; + + rtw_mfree(fw, fwmaxsize); + fw = NULL; + + return err; +} + +/* + * Description: + * Power on/off BB/RF domain. + * + * Parameters: + * enable _TRUE/_FALSE for power on/off + * + * Return: + * 0 Success + * others Fail + */ +int rtw_halmac_phy_power_switch(struct dvobj_priv *d, u8 enable) +{ + PADAPTER adapter; + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + + + adapter = dvobj_get_primary_adapter(d); + halmac = dvobj_to_halmac(d); + if (!halmac) + return -1; + api = HALMAC_GET_API(halmac); + + status = api->halmac_set_hw_value(halmac, HALMAC_HW_EN_BB_RF, &enable); + if (status != HALMAC_RET_SUCCESS) + return -1; + + return 0; +} + +static u8 _is_fw_read_cmd_down(PADAPTER adapter, u8 msgbox_num) +{ + u8 read_down = _FALSE; + int retry_cnts = 100; + u8 valid; + + /* RTW_INFO("_is_fw_read_cmd_down, reg_1cc(%x), msg_box(%d)...\n", rtw_read8(adapter, REG_HMETFR), msgbox_num); */ + + do { + valid = rtw_read8(adapter, REG_HMETFR) & BIT(msgbox_num); + if (0 == valid) + read_down = _TRUE; + else + rtw_msleep_os(1); + } while ((!read_down) && (retry_cnts--)); + + return read_down; +} + +int rtw_halmac_send_h2c(struct dvobj_priv *d, u8 *h2c) +{ + PADAPTER adapter = dvobj_get_primary_adapter(d); + PHAL_DATA_TYPE hal = GET_HAL_DATA(adapter); + u8 h2c_box_num = 0; + u32 msgbox_addr = 0; + u32 msgbox_ex_addr = 0; + u32 h2c_cmd = 0; + u32 h2c_cmd_ex = 0; + s32 ret = _FAIL; + + if (adapter->bFWReady == _FALSE) { + RTW_INFO("%s: return H2C cmd because fw is not ready\n", __FUNCTION__); + return ret; + } + + if (!h2c) { + RTW_INFO("%s: pbuf is NULL\n", __FUNCTION__); + return ret; + } + + if (rtw_is_surprise_removed(adapter)) { + RTW_INFO("%s: surprise removed\n", __FUNCTION__); + return ret; + } + + _enter_critical_mutex(&d->h2c_fwcmd_mutex, NULL); + + /* pay attention to if race condition happened in H2C cmd setting */ + h2c_box_num = hal->LastHMEBoxNum; + + if (!_is_fw_read_cmd_down(adapter, h2c_box_num)) { + RTW_INFO(" fw read cmd failed...\n"); + goto exit; + } + + /* Write Ext command(byte 4 -7) */ + msgbox_ex_addr = REG_HMEBOX_E0 + (h2c_box_num * EX_MESSAGE_BOX_SIZE); + _rtw_memcpy((u8 *)(&h2c_cmd_ex), h2c + 4, EX_MESSAGE_BOX_SIZE); + h2c_cmd_ex = le32_to_cpu(h2c_cmd_ex); + rtw_write32(adapter, msgbox_ex_addr, h2c_cmd_ex); + + /* Write command (byte 0 -3 ) */ + msgbox_addr = REG_HMEBOX0 + (h2c_box_num * MESSAGE_BOX_SIZE); + _rtw_memcpy((u8 *)(&h2c_cmd), h2c, 4); + h2c_cmd = le32_to_cpu(h2c_cmd); + rtw_write32(adapter, msgbox_addr, h2c_cmd); + + /* update last msg box number */ + hal->LastHMEBoxNum = (h2c_box_num + 1) % MAX_H2C_BOX_NUMS; + ret = _SUCCESS; + +#ifdef DBG_H2C_CONTENT + RTW_INFO_DUMP("[H2C] - ", h2c, RTW_HALMAC_H2C_MAX_SIZE); +#endif +exit: + _exit_critical_mutex(&d->h2c_fwcmd_mutex, NULL); + return ret; +} + +int rtw_halmac_c2h_handle(struct dvobj_priv *d, u8 *c2h, u32 size) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + status = api->halmac_get_c2h_info(mac, c2h, size); + if (HALMAC_RET_SUCCESS != status) + return -1; + + return 0; +} + +int rtw_halmac_get_available_efuse_size(struct dvobj_priv *d, u32 *size) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + u32 val; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + status = api->halmac_get_efuse_available_size(mac, &val); + if (HALMAC_RET_SUCCESS != status) + return -1; + + *size = val; + return 0; +} + +int rtw_halmac_get_physical_efuse_size(struct dvobj_priv *d, u32 *size) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + u32 val; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + status = api->halmac_get_efuse_size(mac, &val); + if (HALMAC_RET_SUCCESS != status) + return -1; + + *size = val; + return 0; +} + +int rtw_halmac_read_physical_efuse_map(struct dvobj_priv *d, u8 *map, u32 size) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + HALMAC_FEATURE_ID id; + int ret; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + id = HALMAC_FEATURE_DUMP_PHYSICAL_EFUSE; + + ret = init_halmac_event(d, id, map, size); + if (ret) + return -1; + + status = api->halmac_dump_efuse_map(mac, HALMAC_EFUSE_R_AUTO); + if (HALMAC_RET_SUCCESS != status) { + free_halmac_event(d, id); + return -1; + } + + ret = wait_halmac_event(d, id); + if (ret) + return -1; + + return 0; +} + +int rtw_halmac_read_physical_efuse(struct dvobj_priv *d, u32 offset, u32 cnt, u8 *data) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + u8 v; + u32 i; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + for (i = 0; i < cnt; i++) { + status = api->halmac_read_efuse(mac, offset + i, &v); + if (HALMAC_RET_SUCCESS != status) + return -1; + data[i] = v; + } + + return 0; +} + +int rtw_halmac_write_physical_efuse(struct dvobj_priv *d, u32 offset, u32 cnt, u8 *data) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + u32 i; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + for (i = 0; i < cnt; i++) { + status = api->halmac_write_efuse(mac, offset + i, data[i]); + if (HALMAC_RET_SUCCESS != status) + return -1; + } + + return 0; +} + +int rtw_halmac_get_logical_efuse_size(struct dvobj_priv *d, u32 *size) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + u32 val; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + status = api->halmac_get_logical_efuse_size(mac, &val); + if (HALMAC_RET_SUCCESS != status) + return -1; + + *size = val; + return 0; +} + +int rtw_halmac_read_logical_efuse_map(struct dvobj_priv *d, u8 *map, u32 size) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + HALMAC_FEATURE_ID id; + int ret; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + id = HALMAC_FEATURE_DUMP_LOGICAL_EFUSE; + + ret = init_halmac_event(d, id, map, size); + if (ret) + return -1; + + status = api->halmac_dump_logical_efuse_map(mac, HALMAC_EFUSE_R_DRV); + if (HALMAC_RET_SUCCESS != status) { + free_halmac_event(d, id); + return -1; + } + + ret = wait_halmac_event(d, id); + if (ret) + return -1; + + return 0; +} + +int rtw_halmac_write_logical_efuse_map(struct dvobj_priv *d, u8 *map, u32 size, u8 *maskmap, u32 masksize) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_PG_EFUSE_INFO pginfo; + HALMAC_RET_STATUS status; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + pginfo.pEfuse_map = map; + pginfo.efuse_map_size = size; + pginfo.pEfuse_mask = maskmap; + pginfo.efuse_mask_size = masksize; + + status = api->halmac_pg_efuse_by_map(mac, &pginfo, HALMAC_EFUSE_R_AUTO); + if (HALMAC_RET_SUCCESS != status) + return -1; + + return 0; +} + +int rtw_halmac_read_logical_efuse(struct dvobj_priv *d, u32 offset, u32 cnt, u8 *data) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + u8 v; + u32 i; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + for (i = 0; i < cnt; i++) { + status = api->halmac_read_logical_efuse(mac, offset + i, &v); + if (HALMAC_RET_SUCCESS != status) + return -1; + data[i] = v; + } + + return 0; +} + +int rtw_halmac_write_logical_efuse(struct dvobj_priv *d, u32 offset, u32 cnt, u8 *data) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + u32 i; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + for (i = 0; i < cnt; i++) { + status = api->halmac_write_logical_efuse(mac, offset + i, data[i]); + if (HALMAC_RET_SUCCESS != status) + return -1; + } + + return 0; +} + +int rtw_halmac_write_bt_physical_efuse(struct dvobj_priv *d, u32 offset, u32 cnt, u8 *data) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + u32 i; + u8 bank = 1; + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + for (i = 0; i < cnt; i++) { + status = api->halmac_write_efuse_bt(mac, offset + i, data[i], bank); + if (HALMAC_RET_SUCCESS != status) { + printk("%s: halmac_write_efuse_bt status = %d\n", __FUNCTION__, status); + return -1; + } + } + printk("%s: halmac_write_efuse_bt status = HALMAC_RET_SUCCESS %d\n", __FUNCTION__, status); + return 0; +} + + +int rtw_halmac_read_bt_physical_efuse_map(struct dvobj_priv *d, u8 *map, u32 size) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + HALMAC_FEATURE_ID id; + int ret; + int bank = 1; + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + status = api->halmac_dump_efuse_map_bt(mac, bank, size, map); + if (HALMAC_RET_SUCCESS != status) { + printk("%s: halmac_dump_efuse_map_bt fail!\n", __FUNCTION__); + return -1; + } + + printk("%s: OK!\n", __FUNCTION__); + + return 0; +} + +static inline u8 _hw_port_drv2halmac(enum _hw_port hwport) +{ + u8 port = 0; + + + switch (hwport) { + case HW_PORT0: + port = 0; + break; + case HW_PORT1: + port = 1; + break; + case HW_PORT2: + port = 2; + break; + case HW_PORT3: + port = 3; + break; + case HW_PORT4: + port = 4; + break; + default: + port = hwport; + break; + } + + return port; +} + +int rtw_halmac_set_mac_address(struct dvobj_priv *d, enum _hw_port hwport, u8 *addr) +{ + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + u8 port; + HALMAC_WLAN_ADDR hwa; + HALMAC_RET_STATUS status; + int err = -1; + + + halmac = dvobj_to_halmac(d); + api = HALMAC_GET_API(halmac); + + port = _hw_port_drv2halmac(hwport); + _rtw_memset(&hwa, 0, sizeof(hwa)); + _rtw_memcpy(hwa.Address, addr, 6); + + status = api->halmac_cfg_mac_addr(halmac, port, &hwa); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +int rtw_halmac_set_bssid(struct dvobj_priv *d, enum _hw_port hwport, u8 *addr) +{ + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + u8 port; + HALMAC_WLAN_ADDR hwa; + HALMAC_RET_STATUS status; + int err = -1; + + halmac = dvobj_to_halmac(d); + api = HALMAC_GET_API(halmac); + port = _hw_port_drv2halmac(hwport); + + _rtw_memset(&hwa, 0, sizeof(HALMAC_WLAN_ADDR)); + _rtw_memcpy(hwa.Address, addr, 6); + status = api->halmac_cfg_bssid(halmac, port, &hwa); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +int rtw_halmac_set_bandwidth(struct dvobj_priv *d, u8 channel, u8 pri_ch_idx, u8 bw) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + status = api->halmac_cfg_ch_bw(mac, channel, pri_ch_idx, bw); + if (HALMAC_RET_SUCCESS != status) + return -1; + + return 0; +} + +int rtw_halmac_get_hw_value(struct dvobj_priv *d, HALMAC_HW_ID hw_id, VOID *pvalue) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + status = api->halmac_get_hw_value(mac, hw_id, pvalue); + if (HALMAC_RET_SUCCESS != status) + return -1; + + return 0; +} + +static HAL_FIFO_SEL _fifo_sel_drv2halmac(u8 fifo_sel) +{ + if (0 == fifo_sel) + return HAL_FIFO_SEL_TX; + else if (1 == fifo_sel) + return HAL_FIFO_SEL_RX; + else if (2 == fifo_sel) + return HAL_FIFO_SEL_RSVD_PAGE; + else if (3 == fifo_sel) + return HAL_FIFO_SEL_REPORT; + else if (4 == fifo_sel) + return HAL_FIFO_SEL_LLT; + else + return HAL_FIFO_SEL_RSVD_PAGE; +} + +#define CONFIG_HALMAC_FIFO_DUMP +int rtw_halmac_dump_fifo(struct dvobj_priv *d, u8 fifo_sel, u32 addr, u32 size, u8 *buffer) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + u8 *pfifo_map = NULL; + u32 fifo_size = 0; + s8 ret = 0;/* 0:success, -1:error */ + u8 mem_created = _FALSE; + + HAL_FIFO_SEL halmac_fifo_sel; + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + if ((size != 0) && (buffer == NULL)) + return -1; + + halmac_fifo_sel = _fifo_sel_drv2halmac(fifo_sel); + + if ((size) && (buffer)) { + pfifo_map = buffer; + fifo_size = size; + } else { + fifo_size = api->halmac_get_fifo_size(mac, halmac_fifo_sel); + + if (fifo_size) + pfifo_map = rtw_zvmalloc(fifo_size); + if (pfifo_map == NULL) + return -1; + mem_created = _TRUE; + } + + status = api->halmac_dump_fifo(mac, halmac_fifo_sel, addr, fifo_size, pfifo_map); + if (HALMAC_RET_SUCCESS != status) { + ret = -1; + goto _exit; + } + +#ifdef CONFIG_HALMAC_FIFO_DUMP + { + static const char * const fifo_sel_str[] = { + "TX", "RX", "RSVD_PAGE", "REPORT", "LLT" + }; + + RTW_INFO("%s FIFO DUMP [start_addr:0x%04x , size:%d]\n", fifo_sel_str[halmac_fifo_sel], addr, fifo_size); + RTW_INFO_DUMP("\n", pfifo_map, fifo_size); + RTW_INFO(" ==================================================\n"); + } +#endif + +_exit: + if (mem_created && pfifo_map) + rtw_vmfree(pfifo_map, fifo_size); + return ret; + +} + +int rtw_halmac_rx_agg_switch(struct dvobj_priv *d, u8 enable) +{ + PADAPTER adapter; + PHAL_DATA_TYPE hal; + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + HALMAC_RXAGG_CFG rxaggcfg; + HALMAC_RET_STATUS status; + int err = -1; + + + adapter = dvobj_get_primary_adapter(d); + hal = GET_HAL_DATA(adapter); + halmac = dvobj_to_halmac(d); + api = HALMAC_GET_API(halmac); + _rtw_memset((void *)&rxaggcfg, 0, sizeof(rxaggcfg)); + + if (_TRUE == enable) { +#ifdef CONFIG_SDIO_HCI + rxaggcfg.mode = HALMAC_RX_AGG_MODE_DMA; + rxaggcfg.threshold.drv_define = 0; +#elif defined(CONFIG_USB_HCI) && defined(CONFIG_USB_RX_AGGREGATION) + switch (hal->rxagg_mode) { + case RX_AGG_DISABLE: + rxaggcfg.mode = HALMAC_RX_AGG_MODE_NONE; + break; + + case RX_AGG_DMA: + rxaggcfg.mode = HALMAC_RX_AGG_MODE_DMA; + if (hal->rxagg_dma_size || hal->rxagg_dma_timeout) { + rxaggcfg.threshold.drv_define = 1; + rxaggcfg.threshold.timeout = hal->rxagg_dma_timeout; + rxaggcfg.threshold.size = hal->rxagg_dma_size; + } + break; + + case RX_AGG_USB: + case RX_AGG_MIX: + rxaggcfg.mode = HALMAC_RX_AGG_MODE_USB; + if (hal->rxagg_usb_size || hal->rxagg_usb_timeout) { + rxaggcfg.threshold.drv_define = 1; + rxaggcfg.threshold.timeout = hal->rxagg_usb_timeout; + rxaggcfg.threshold.size = hal->rxagg_usb_size; + } + break; + } +#endif /* CONFIG_USB_HCI */ + } else + rxaggcfg.mode = HALMAC_RX_AGG_MODE_NONE; + + status = api->halmac_cfg_rx_aggregation(halmac, &rxaggcfg); + if (status != HALMAC_RET_SUCCESS) + goto out; + + err = 0; +out: + return err; +} + +/* + * Description: + * Get RX driver info size. RX driver info is a small memory space between + * scriptor and RX payload. + * + * +-------------------------+ + * | RX descriptor | + * | usually 24 bytes | + * +-------------------------+ + * | RX driver info | + * | depends on driver cfg | + * +-------------------------+ + * | RX paylad | + * | | + * +-------------------------+ + * + * Parameter: + * d pointer to struct dvobj_priv of driver + * sz rx driver info size in bytes. + * + * Rteurn: + * 0 Success + * other Fail + */ +int rtw_halmac_get_drv_info_sz(struct dvobj_priv *d, u8 *sz) +{ + HALMAC_RET_STATUS status; + PHALMAC_ADAPTER halmac = dvobj_to_halmac(d); + PHALMAC_API api = HALMAC_GET_API(halmac); + u8 dw = 0; + + status = api->halmac_get_hw_value(halmac, HALMAC_HW_DRV_INFO_SIZE, &dw); + if (status != HALMAC_RET_SUCCESS) + return -1; + + *sz = dw * 8; + return 0; +} +int rtw_halmac_get_rsvd_drv_pg_bndy(struct dvobj_priv *dvobj, u16 *drv_pg) +{ + HALMAC_RET_STATUS status; + PHALMAC_ADAPTER halmac = dvobj_to_halmac(dvobj); + PHALMAC_API api = HALMAC_GET_API(halmac); + + status = api->halmac_get_hw_value(halmac, HALMAC_HW_RSVD_PG_BNDY, drv_pg); + if (status != HALMAC_RET_SUCCESS) + return -1; + + return 0; +} + +int rtw_halmac_download_rsvd_page(struct dvobj_priv *dvobj, u8 pg_offset, u8 *pbuf, u32 size) +{ + HALMAC_RET_STATUS status = HALMAC_RET_SUCCESS; + PHALMAC_ADAPTER halmac = dvobj_to_halmac(dvobj); + PHALMAC_API api = HALMAC_GET_API(halmac); + + status = api->halmac_dl_drv_rsvd_page(halmac, pg_offset, pbuf, size); + if (status != HALMAC_RET_SUCCESS) + return -1; + + return 0; + +} + +/* + * Description + * Fill following spec info from HALMAC API: + * sec_cam_ent_num + * + * Return + * 0 Success + * others Fail + */ +int rtw_halmac_fill_hal_spec(struct dvobj_priv *dvobj, struct hal_spec_t *spec) +{ + HALMAC_RET_STATUS status; + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + u8 cam = 0; /* Security Cam Entry Number */ + + + halmac = dvobj_to_halmac(dvobj); + api = HALMAC_GET_API(halmac); + + /* Prepare data from HALMAC */ + status = api->halmac_get_hw_value(halmac, HALMAC_HW_CAM_ENTRY_NUM, &cam); + if (status != HALMAC_RET_SUCCESS) + return -1; + + /* Fill data to hal_spec_t */ + spec->sec_cam_ent_num = cam; + + return 0; +} + +#ifdef CONFIG_SDIO_HCI + +/* + * Description: + * Update queue allocated page number to driver + * + * Parameter: + * d pointer to struct dvobj_priv of driver + * + * Rteurn: + * 0 Success, "page" is valid. + * others Fail, "page" is invalid. + */ +int rtw_halmac_query_tx_page_num(struct dvobj_priv *d) +{ + PADAPTER adapter; + struct halmacpriv *hmpriv; + PHALMAC_ADAPTER halmac; + PHALMAC_API api; + HALMAC_RQPN_MAP rqpn; + HALMAC_DMA_MAPPING dmaqueue; + HALMAC_TXFF_ALLOCATION fifosize; + HALMAC_RET_STATUS status; + u8 i; + + + adapter = dvobj_get_primary_adapter(d); + hmpriv = &d->hmpriv; + halmac = dvobj_to_halmac(d); + api = HALMAC_GET_API(halmac); + _rtw_memset((void *)&rqpn, 0, sizeof(rqpn)); + _rtw_memset((void *)&fifosize, 0, sizeof(fifosize)); + + status = api->halmac_get_hw_value(halmac, HALMAC_HW_RQPN_MAPPING, &rqpn); + if (status != HALMAC_RET_SUCCESS) + return -1; + status = api->halmac_get_hw_value(halmac, HALMAC_HW_TXFF_ALLOCATION, &fifosize); + if (status != HALMAC_RET_SUCCESS) + return -1; + + for (i = 0; i < HW_QUEUE_ENTRY; i++) { + hmpriv->txpage[i] = 0; + + /* Driver index mapping to HALMAC DMA queue */ + dmaqueue = HALMAC_DMA_MAPPING_UNDEFINE; + switch (i) { + case VO_QUEUE_INX: + dmaqueue = rqpn.dma_map_vo; + break; + case VI_QUEUE_INX: + dmaqueue = rqpn.dma_map_vi; + break; + case BE_QUEUE_INX: + dmaqueue = rqpn.dma_map_be; + break; + case BK_QUEUE_INX: + dmaqueue = rqpn.dma_map_bk; + break; + case MGT_QUEUE_INX: + dmaqueue = rqpn.dma_map_mg; + break; + case HIGH_QUEUE_INX: + dmaqueue = rqpn.dma_map_hi; + break; + case BCN_QUEUE_INX: + case TXCMD_QUEUE_INX: + /* Unlimited */ + hmpriv->txpage[i] = 0xFFFF; + continue; + } + + switch (dmaqueue) { + case HALMAC_DMA_MAPPING_EXTRA: + hmpriv->txpage[i] = fifosize.extra_queue_pg_num; + break; + case HALMAC_DMA_MAPPING_LOW: + hmpriv->txpage[i] = fifosize.low_queue_pg_num; + break; + case HALMAC_DMA_MAPPING_NORMAL: + hmpriv->txpage[i] = fifosize.normal_queue_pg_num; + break; + case HALMAC_DMA_MAPPING_HIGH: + hmpriv->txpage[i] = fifosize.high_queue_pg_num; + break; + case HALMAC_DMA_MAPPING_UNDEFINE: + break; + } + hmpriv->txpage[i] += fifosize.pub_queue_pg_num; + } + + return 0; +} + +/* + * Description: + * Get specific queue allocated page number + * + * Parameter: + * d pointer to struct dvobj_priv of driver + * queue target queue to query, VO/VI/BE/BK/.../TXCMD_QUEUE_INX + * page return allocated page number + * + * Rteurn: + * 0 Success, "page" is valid. + * others Fail, "page" is invalid. + */ +int rtw_halmac_get_tx_queue_page_num(struct dvobj_priv *d, u8 queue, u32 *page) +{ + *page = 0; + if (queue < HW_QUEUE_ENTRY) + *page = d->hmpriv.txpage[queue]; + + return 0; +} + +/* + * Return: + * address for SDIO command + */ +u32 rtw_halmac_sdio_get_tx_addr(struct dvobj_priv *d, u8 *desc, u32 size) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + u32 addr; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + status = api->halmac_get_sdio_tx_addr(mac, desc, size, &addr); + if (HALMAC_RET_SUCCESS != status) + return 0; + + return addr; +} + +int rtw_halmac_sdio_tx_allowed(struct dvobj_priv *d, u8 *buf, u32 size) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + status = api->halmac_tx_allowed_sdio(mac, buf, size); + if (HALMAC_RET_SUCCESS != status) + return -1; + + return 0; +} + +u32 rtw_halmac_sdio_get_rx_addr(struct dvobj_priv *d, u8 *seq) +{ + u8 id; + +#define RTW_SDIO_ADDR_RX_RX0FF_PRFIX 0x0E000 +#define RTW_SDIO_ADDR_RX_RX0FF_GEN(a) (RTW_SDIO_ADDR_RX_RX0FF_PRFIX|(a&0x3)) + + id = *seq; + (*seq)++; + return RTW_SDIO_ADDR_RX_RX0FF_GEN(id); +} +#endif /* CONFIG_SDIO_HCI */ + +#ifdef CONFIG_USB_HCI +u8 rtw_halmac_usb_get_bulkout_id(struct dvobj_priv *d, u8 *buf, u32 size) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + u8 bulkout_id; + + + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + + status = api->halmac_get_usb_bulkout_id(mac, buf, size, &bulkout_id); + if (HALMAC_RET_SUCCESS != status) + return 0; + + return bulkout_id; +} + +static inline HALMAC_USB_MODE _usb_mode_drv2halmac(enum RTW_USB_SPEED usb_mode) +{ + HALMAC_USB_MODE halmac_usb_mode = HALMAC_USB_MODE_U2; + + switch (usb_mode) { + case RTW_USB_SPEED_2: + halmac_usb_mode = HALMAC_USB_MODE_U2; + break; + case RTW_USB_SPEED_3: + halmac_usb_mode = HALMAC_USB_MODE_U3; + break; + default: + halmac_usb_mode = HALMAC_USB_MODE_U2; + break; + } + + return halmac_usb_mode; +} + +u8 rtw_halmac_switch_usb_mode(struct dvobj_priv *d, enum RTW_USB_SPEED usb_mode) +{ + PHALMAC_ADAPTER mac; + PHALMAC_API api; + HALMAC_RET_STATUS status; + PADAPTER adapter; + HALMAC_USB_MODE halmac_usb_mode; + + adapter = dvobj_get_primary_adapter(d); + mac = dvobj_to_halmac(d); + api = HALMAC_GET_API(mac); + halmac_usb_mode = _usb_mode_drv2halmac(usb_mode); + status = api->halmac_set_hw_value(mac, HALMAC_HW_USB_MODE, (void *)&halmac_usb_mode); + + if (HALMAC_RET_SUCCESS != status) + return _FAIL; + + return _SUCCESS; +} +#endif /* CONFIG_USB_HCI */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_halmac.h b/linux-bsp/drivers/rtl8188eus/hal/hal_halmac.h new file mode 100644 index 0000000..980e8a4 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_halmac.h @@ -0,0 +1,121 @@ +/****************************************************************************** + * + * Copyright(c) 2015 - 2016 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#ifndef _HAL_HALMAC_H_ +#define _HAL_HALMAC_H_ + +#include <drv_types.h> /* adapter_to_dvobj(), struct intf_hdl and etc. */ +#include <hal_data.h> /* struct hal_spec_t */ +#include "halmac/halmac_api.h" /* PHALMAC_ADAPTER and etc. */ + +/* HALMAC Definition for Driver */ +#define RTW_HALMAC_H2C_MAX_SIZE HALMAC_H2C_CMD_ORIGINAL_SIZE_88XX +#define RTW_HALMAC_BA_SSN_RPT_SIZE 4 + +#define dvobj_set_halmac(d, mac) ((d)->halmac = (mac)) +#define dvobj_to_halmac(d) ((PHALMAC_ADAPTER)((d)->halmac)) +#define adapter_to_halmac(p) dvobj_to_halmac(adapter_to_dvobj(p)) + +/* for H2C cmd */ +#define MAX_H2C_BOX_NUMS 4 +#define MESSAGE_BOX_SIZE 4 +#define EX_MESSAGE_BOX_SIZE 4 + +typedef enum _RTW_HALMAC_MODE { + RTW_HALMAC_MODE_NORMAL, + RTW_HALMAC_MODE_WIFI_TEST, +} RTW_HALMAC_MODE; + +extern HALMAC_PLATFORM_API rtw_halmac_platform_api; + +/* HALMAC API for Driver(HAL) */ +u8 rtw_halmac_read8(struct intf_hdl *, u32 addr); +u16 rtw_halmac_read16(struct intf_hdl *, u32 addr); +u32 rtw_halmac_read32(struct intf_hdl *, u32 addr); +void rtw_halmac_read_mem(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem); +#ifdef CONFIG_SDIO_INDIRECT_ACCESS +u8 rtw_halmac_iread8(struct intf_hdl *pintfhdl, u32 addr); +u16 rtw_halmac_iread16(struct intf_hdl *pintfhdl, u32 addr); +u32 rtw_halmac_iread32(struct intf_hdl *pintfhdl, u32 addr); +#endif +int rtw_halmac_write8(struct intf_hdl *, u32 addr, u8 value); +int rtw_halmac_write16(struct intf_hdl *, u32 addr, u16 value); +int rtw_halmac_write32(struct intf_hdl *, u32 addr, u32 value); + +void rtw_dump_halmac_info(void *sel); +int rtw_halmac_init_adapter(struct dvobj_priv *, PHALMAC_PLATFORM_API); +int rtw_halmac_deinit_adapter(struct dvobj_priv *); +int rtw_halmac_poweron(struct dvobj_priv *); +int rtw_halmac_poweroff(struct dvobj_priv *); +int rtw_halmac_init_hal(struct dvobj_priv *); +int rtw_halmac_init_hal_fw(struct dvobj_priv *, u8 *fw, u32 fwsize); +int rtw_halmac_init_hal_fw_file(struct dvobj_priv *, u8 *fwpath); +int rtw_halmac_deinit_hal(struct dvobj_priv *); +int rtw_halmac_self_verify(struct dvobj_priv *); +int rtw_halmac_dlfw(struct dvobj_priv *, u8 *fw, u32 fwsize); +int rtw_halmac_dlfw_from_file(struct dvobj_priv *, u8 *fwpath); +int rtw_halmac_phy_power_switch(struct dvobj_priv *, u8 enable); +int rtw_halmac_send_h2c(struct dvobj_priv *, u8 *h2c); +int rtw_halmac_c2h_handle(struct dvobj_priv *, u8 *c2h, u32 size); +int rtw_halmac_get_available_efuse_size(struct dvobj_priv *d, u32 *size); + +int rtw_halmac_get_physical_efuse_size(struct dvobj_priv *, u32 *size); +int rtw_halmac_read_physical_efuse_map(struct dvobj_priv *, u8 *map, u32 size); +int rtw_halmac_read_physical_efuse(struct dvobj_priv *, u32 offset, u32 cnt, u8 *data); +int rtw_halmac_write_physical_efuse(struct dvobj_priv *, u32 offset, u32 cnt, u8 *data); +int rtw_halmac_get_logical_efuse_size(struct dvobj_priv *, u32 *size); +int rtw_halmac_read_logical_efuse_map(struct dvobj_priv *, u8 *map, u32 size); +int rtw_halmac_write_logical_efuse_map(struct dvobj_priv *, u8 *map, u32 size, u8 *maskmap, u32 masksize); +int rtw_halmac_read_logical_efuse(struct dvobj_priv *, u32 offset, u32 cnt, u8 *data); +int rtw_halmac_write_logical_efuse(struct dvobj_priv *, u32 offset, u32 cnt, u8 *data); + +int rtw_halmac_write_bt_physical_efuse(struct dvobj_priv *, u32 offset, u32 cnt, u8 *data); +int rtw_halmac_read_bt_physical_efuse_map(struct dvobj_priv *, u8 *map, u32 size); + +int rtw_halmac_config_rx_info(struct dvobj_priv *, HALMAC_DRV_INFO); +int rtw_halmac_set_mac_address(struct dvobj_priv *, enum _hw_port, u8 *addr); +int rtw_halmac_set_bssid(struct dvobj_priv *, enum _hw_port hwport, u8 *addr); + +int rtw_halmac_set_bandwidth(struct dvobj_priv *, u8 channel, u8 pri_ch_idx, u8 bw); +int rtw_halmac_dump_fifo(struct dvobj_priv *d, u8 fifo_sel, u32 addr, u32 size, u8 *buffer); +int rtw_halmac_rx_agg_switch(struct dvobj_priv *, u8 enable); +int rtw_halmac_get_hw_value(struct dvobj_priv *, HALMAC_HW_ID hw_id, VOID *pvalue); +int rtw_halmac_get_wow_reason(struct dvobj_priv *, u8 *reason); +int rtw_halmac_get_drv_info_sz(struct dvobj_priv *, u8 *sz); +int rtw_halmac_get_rsvd_drv_pg_bndy(struct dvobj_priv *dvobj, u16 *drv_pg); +int rtw_halmac_download_rsvd_page(struct dvobj_priv *dvobj, u8 pg_offset, u8 *pbuf, u32 size); +int rtw_halmac_fill_hal_spec(struct dvobj_priv *, struct hal_spec_t *); + +#ifdef CONFIG_SDIO_HCI +int rtw_halmac_query_tx_page_num(struct dvobj_priv *); +int rtw_halmac_get_tx_queue_page_num(struct dvobj_priv *, u8 queue, u32 *page); +u32 rtw_halmac_sdio_get_tx_addr(struct dvobj_priv *, u8 *desc, u32 size); +int rtw_halmac_sdio_tx_allowed(struct dvobj_priv *, u8 *buf, u32 size); +u32 rtw_halmac_sdio_get_rx_addr(struct dvobj_priv *, u8 *seq); +#endif /* CONFIG_SDIO_HCI */ + +#ifdef CONFIG_USB_HCI +u8 rtw_halmac_usb_get_bulkout_id(struct dvobj_priv *, u8 *buf, u32 size); +u8 rtw_halmac_switch_usb_mode(struct dvobj_priv *d, enum RTW_USB_SPEED usb_mode); +#endif /* CONFIG_USB_HCI */ + +#ifdef CONFIG_SUPPORT_TRX_SHARED +void dump_trx_share_mode(void *sel, _adapter *adapter); +#endif +#endif /* _HAL_HALMAC_H_ */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_hci/hal_usb.c b/linux-bsp/drivers/rtl8188eus/hal/hal_hci/hal_usb.c new file mode 100644 index 0000000..7e6202a --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_hci/hal_usb.c @@ -0,0 +1,529 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _HAL_USB_C_ + +#include <drv_types.h> +#include <hal_data.h> + +int usb_init_recv_priv(_adapter *padapter, u16 ini_in_buf_sz) +{ + struct recv_priv *precvpriv = &padapter->recvpriv; + int i, res = _SUCCESS; + struct recv_buf *precvbuf; + +#ifdef PLATFORM_LINUX + tasklet_init(&precvpriv->recv_tasklet, + (void(*)(unsigned long))usb_recv_tasklet, + (unsigned long)padapter); +#endif /* PLATFORM_LINUX */ + +#ifdef PLATFORM_FREEBSD +#ifdef CONFIG_RX_INDICATE_QUEUE + TASK_INIT(&precvpriv->rx_indicate_tasklet, 0, rtw_rx_indicate_tasklet, padapter); +#endif /* CONFIG_RX_INDICATE_QUEUE */ +#endif /* PLATFORM_FREEBSD */ + +#ifdef CONFIG_USB_INTERRUPT_IN_PIPE +#ifdef PLATFORM_LINUX + precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if (precvpriv->int_in_urb == NULL) { + res = _FAIL; + RTW_INFO("alloc_urb for interrupt in endpoint fail !!!!\n"); + goto exit; + } +#endif /* PLATFORM_LINUX */ + precvpriv->int_in_buf = rtw_zmalloc(ini_in_buf_sz); + if (precvpriv->int_in_buf == NULL) { + res = _FAIL; + RTW_INFO("alloc_mem for interrupt in endpoint fail !!!!\n"); + goto exit; + } +#endif /* CONFIG_USB_INTERRUPT_IN_PIPE */ + + /* init recv_buf */ + _rtw_init_queue(&precvpriv->free_recv_buf_queue); + _rtw_init_queue(&precvpriv->recv_buf_pending_queue); +#ifndef CONFIG_USE_USB_BUFFER_ALLOC_RX + /* this is used only when RX_IOBUF is sk_buff */ + skb_queue_head_init(&precvpriv->free_recv_skb_queue); +#endif + + RTW_INFO("NR_RECVBUFF: %d\n", NR_RECVBUFF); + RTW_INFO("MAX_RECVBUF_SZ: %d\n", MAX_RECVBUF_SZ); + precvpriv->pallocated_recv_buf = rtw_zmalloc(NR_RECVBUFF * sizeof(struct recv_buf) + 4); + if (precvpriv->pallocated_recv_buf == NULL) { + res = _FAIL; + goto exit; + } + + precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_recv_buf), 4); + + precvbuf = (struct recv_buf *)precvpriv->precv_buf; + + for (i = 0; i < NR_RECVBUFF ; i++) { + _rtw_init_listhead(&precvbuf->list); + + _rtw_spinlock_init(&precvbuf->recvbuf_lock); + + precvbuf->alloc_sz = MAX_RECVBUF_SZ; + + res = rtw_os_recvbuf_resource_alloc(padapter, precvbuf); + if (res == _FAIL) + break; + + precvbuf->ref_cnt = 0; + precvbuf->adapter = padapter; + + /* rtw_list_insert_tail(&precvbuf->list, &(precvpriv->free_recv_buf_queue.queue)); */ + + precvbuf++; + } + + precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF; + +#if defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) + + skb_queue_head_init(&precvpriv->rx_skb_queue); + +#ifdef CONFIG_RX_INDICATE_QUEUE + memset(&precvpriv->rx_indicate_queue, 0, sizeof(struct ifqueue)); + mtx_init(&precvpriv->rx_indicate_queue.ifq_mtx, "rx_indicate_queue", NULL, MTX_DEF); +#endif /* CONFIG_RX_INDICATE_QUEUE */ + +#ifdef CONFIG_PREALLOC_RECV_SKB + { + int i; + SIZE_PTR tmpaddr = 0; + SIZE_PTR alignment = 0; + struct sk_buff *pskb = NULL; + + RTW_INFO("NR_PREALLOC_RECV_SKB: %d\n", NR_PREALLOC_RECV_SKB); +#ifdef CONFIG_FIX_NR_BULKIN_BUFFER + RTW_INFO("Enable CONFIG_FIX_NR_BULKIN_BUFFER\n"); +#endif + + for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) { +#ifdef CONFIG_PREALLOC_RX_SKB_BUFFER + pskb = rtw_alloc_skb_premem(MAX_RECVBUF_SZ); +#else + pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); +#endif /* CONFIG_PREALLOC_RX_SKB_BUFFER */ + + if (pskb) { +#ifdef PLATFORM_FREEBSD + pskb->dev = padapter->pifp; +#else + pskb->dev = padapter->pnetdev; +#endif /* PLATFORM_FREEBSD */ + +#ifndef CONFIG_PREALLOC_RX_SKB_BUFFER + tmpaddr = (SIZE_PTR)pskb->data; + alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1); + skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment)); +#endif + skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); + } + } + } +#endif /* CONFIG_PREALLOC_RECV_SKB */ + +#endif /* defined(PLATFORM_LINUX) || defined(PLATFORM_FREEBSD) */ + +exit: + + return res; +} + +void usb_free_recv_priv(_adapter *padapter, u16 ini_in_buf_sz) +{ + int i; + struct recv_buf *precvbuf; + struct recv_priv *precvpriv = &padapter->recvpriv; + + precvbuf = (struct recv_buf *)precvpriv->precv_buf; + + for (i = 0; i < NR_RECVBUFF ; i++) { + rtw_os_recvbuf_resource_free(padapter, precvbuf); + precvbuf++; + } + + if (precvpriv->pallocated_recv_buf) + rtw_mfree(precvpriv->pallocated_recv_buf, NR_RECVBUFF * sizeof(struct recv_buf) + 4); + +#ifdef CONFIG_USB_INTERRUPT_IN_PIPE +#ifdef PLATFORM_LINUX + if (precvpriv->int_in_urb) + usb_free_urb(precvpriv->int_in_urb); +#endif + if (precvpriv->int_in_buf) + rtw_mfree(precvpriv->int_in_buf, ini_in_buf_sz); +#endif /* CONFIG_USB_INTERRUPT_IN_PIPE */ + +#ifdef PLATFORM_LINUX + + if (skb_queue_len(&precvpriv->rx_skb_queue)) + RTW_WARN("rx_skb_queue not empty\n"); + + rtw_skb_queue_purge(&precvpriv->rx_skb_queue); + + if (skb_queue_len(&precvpriv->free_recv_skb_queue)) + RTW_WARN("free_recv_skb_queue not empty, %d\n", skb_queue_len(&precvpriv->free_recv_skb_queue)); + +#if !defined(CONFIG_USE_USB_BUFFER_ALLOC_RX) +#if defined(CONFIG_PREALLOC_RECV_SKB) && defined(CONFIG_PREALLOC_RX_SKB_BUFFER) + { + struct sk_buff *skb; + + while ((skb = skb_dequeue(&precvpriv->free_recv_skb_queue)) != NULL) { + if (rtw_free_skb_premem(skb) != 0) + rtw_skb_free(skb); + } + } +#else + rtw_skb_queue_purge(&precvpriv->free_recv_skb_queue); +#endif /* defined(CONFIG_PREALLOC_RX_SKB_BUFFER) && defined(CONFIG_PREALLOC_RECV_SKB) */ +#endif /* !defined(CONFIG_USE_USB_BUFFER_ALLOC_RX) */ + +#endif /* PLATFORM_LINUX */ + +#ifdef PLATFORM_FREEBSD + struct sk_buff *pskb; + while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) + rtw_skb_free(pskb); + +#if !defined(CONFIG_USE_USB_BUFFER_ALLOC_RX) + rtw_skb_queue_purge(&precvpriv->free_recv_skb_queue); +#endif + +#ifdef CONFIG_RX_INDICATE_QUEUE + struct mbuf *m; + for (;;) { + IF_DEQUEUE(&precvpriv->rx_indicate_queue, m); + if (m == NULL) + break; + m_freem(m); + } + mtx_destroy(&precvpriv->rx_indicate_queue.ifq_mtx); +#endif /* CONFIG_RX_INDICATE_QUEUE */ + +#endif /* PLATFORM_FREEBSD */ +} + +#ifdef CONFIG_FW_C2H_REG +void usb_c2h_hisr_hdl(_adapter *adapter, u8 *buf) +{ + u8 *c2h_evt = buf; + u8 id, seq, plen; + u8 *payload; + + if (rtw_hal_c2h_reg_hdr_parse(adapter, buf, &id, &seq, &plen, &payload) != _SUCCESS) + return; + + if (0) + RTW_PRINT("%s C2H == %d\n", __func__, id); + + if (rtw_hal_c2h_id_handle_directly(adapter, id, seq, plen, payload)) { + /* Handle directly */ + rtw_hal_c2h_handler(adapter, id, seq, plen, payload); + + /* Replace with special pointer to trigger c2h_evt_clear only */ + if (rtw_cbuf_push(adapter->evtpriv.c2h_queue, (void*)&adapter->evtpriv) != _SUCCESS) + RTW_ERR("%s rtw_cbuf_push fail\n", __func__); + } else { + c2h_evt = rtw_malloc(C2H_REG_LEN); + if (c2h_evt != NULL) { + _rtw_memcpy(c2h_evt, buf, C2H_REG_LEN); + if (rtw_cbuf_push(adapter->evtpriv.c2h_queue, (void*)c2h_evt) != _SUCCESS) + RTW_ERR("%s rtw_cbuf_push fail\n", __func__); + } else { + /* Error handling for malloc fail */ + if (rtw_cbuf_push(adapter->evtpriv.c2h_queue, (void*)NULL) != _SUCCESS) + RTW_ERR("%s rtw_cbuf_push fail\n", __func__); + } + } + _set_workitem(&adapter->evtpriv.c2h_wk); +} +#endif + +#ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ +int usb_write_async(struct usb_device *udev, u32 addr, void *pdata, u16 len) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + int ret; + + requesttype = VENDOR_WRITE;/* write_out */ + request = REALTEK_USB_VENQT_CMD_REQ; + index = REALTEK_USB_VENQT_CMD_IDX;/* n/a */ + + wvalue = (u16)(addr & 0x0000ffff); + + ret = _usbctrl_vendorreq_async_write(udev, request, wvalue, index, pdata, len, requesttype); + + return ret; +} + +int usb_async_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val) +{ + u8 data; + int ret; + struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev; + struct usb_device *udev = pdvobjpriv->pusbdev; + + data = val; + ret = usb_write_async(udev, addr, &data, 1); + + return ret; +} + +int usb_async_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val) +{ + u16 data; + int ret; + struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev; + struct usb_device *udev = pdvobjpriv->pusbdev; + + data = val; + ret = usb_write_async(udev, addr, &data, 2); + + return ret; +} + +int usb_async_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val) +{ + u32 data; + int ret; + struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)pintfhdl->pintf_dev; + struct usb_device *udev = pdvobjpriv->pusbdev; + + data = val; + ret = usb_write_async(udev, addr, &data, 4); + + return ret; +} +#endif /* CONFIG_USB_SUPPORT_ASYNC_VDN_REQ */ + +u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u8 data = 0; + + + request = 0x05; + requesttype = 0x01;/* read_in */ + index = 0;/* n/a */ + + wvalue = (u16)(addr & 0x0000ffff); + len = 1; + usbctrl_vendorreq(pintfhdl, request, wvalue, index, + &data, len, requesttype); + + + return data; +} + +u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u16 data = 0; + + + request = 0x05; + requesttype = 0x01;/* read_in */ + index = 0;/* n/a */ + + wvalue = (u16)(addr & 0x0000ffff); + len = 2; + usbctrl_vendorreq(pintfhdl, request, wvalue, index, + &data, len, requesttype); + + + return data; + +} + +u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u32 data = 0; + + + request = 0x05; + requesttype = 0x01;/* read_in */ + index = 0;/* n/a */ + + wvalue = (u16)(addr & 0x0000ffff); + len = 4; + usbctrl_vendorreq(pintfhdl, request, wvalue, index, + &data, len, requesttype); + + + return data; +} + +int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u8 data; + int ret; + + + request = 0x05; + requesttype = 0x00;/* write_out */ + index = 0;/* n/a */ + + wvalue = (u16)(addr & 0x0000ffff); + len = 1; + + data = val; + ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, + &data, len, requesttype); + + + return ret; +} + +int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u16 data; + int ret; + + + request = 0x05; + requesttype = 0x00;/* write_out */ + index = 0;/* n/a */ + + wvalue = (u16)(addr & 0x0000ffff); + len = 2; + + data = val; + ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, + &data, len, requesttype); + + + return ret; + +} + +int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u32 data; + int ret; + + + request = 0x05; + requesttype = 0x00;/* write_out */ + index = 0;/* n/a */ + + wvalue = (u16)(addr & 0x0000ffff); + len = 4; + data = val; + ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, + &data, len, requesttype); + + + return ret; + +} + +int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata) +{ + u8 request; + u8 requesttype; + u16 wvalue; + u16 index; + u16 len; + u8 buf[VENDOR_CMD_MAX_DATA_LEN] = {0}; + int ret; + + + request = 0x05; + requesttype = 0x00;/* write_out */ + index = 0;/* n/a */ + + wvalue = (u16)(addr & 0x0000ffff); + len = length; + _rtw_memcpy(buf, pdata, len); + ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, + buf, len, requesttype); + + + return ret; +} + +void usb_set_intf_ops(_adapter *padapter, struct _io_ops *pops) +{ + _rtw_memset((u8 *)pops, 0, sizeof(struct _io_ops)); + + pops->_read8 = &usb_read8; + pops->_read16 = &usb_read16; + pops->_read32 = &usb_read32; + pops->_read_mem = &usb_read_mem; + pops->_read_port = &usb_read_port; + + pops->_write8 = &usb_write8; + pops->_write16 = &usb_write16; + pops->_write32 = &usb_write32; + pops->_writeN = &usb_writeN; + +#ifdef CONFIG_USB_SUPPORT_ASYNC_VDN_REQ + pops->_write8_async = &usb_async_write8; + pops->_write16_async = &usb_async_write16; + pops->_write32_async = &usb_async_write32; +#endif + pops->_write_mem = &usb_write_mem; + pops->_write_port = &usb_write_port; + + pops->_read_port_cancel = &usb_read_port_cancel; + pops->_write_port_cancel = &usb_write_port_cancel; + +#ifdef CONFIG_USB_INTERRUPT_IN_PIPE + pops->_read_interrupt = &usb_read_interrupt; +#endif + +} diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_intf.c b/linux-bsp/drivers/rtl8188eus/hal/hal_intf.c new file mode 100644 index 0000000..f22d62a --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_intf.c @@ -0,0 +1,1416 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#define _HAL_INTF_C_ + +#include <drv_types.h> +#include <hal_data.h> + +const u32 _chip_type_to_odm_ic_type[] = { + 0, + ODM_RTL8188E, + ODM_RTL8192E, + ODM_RTL8812, + ODM_RTL8821, + ODM_RTL8723B, + ODM_RTL8814A, + ODM_RTL8703B, + ODM_RTL8188F, + ODM_RTL8822B, + ODM_RTL8723D, + ODM_RTL8821C, + 0, +}; + +void rtw_hal_chip_configure(_adapter *padapter) +{ + padapter->hal_func.intf_chip_configure(padapter); +} + +/* + * Description: + * Read chip internal ROM data + * + * Return: + * _SUCCESS success + * _FAIL fail + */ +u8 rtw_hal_read_chip_info(_adapter *padapter) +{ + u8 rtn = _SUCCESS; + u8 hci_type = rtw_get_intf_type(padapter); + u32 start = rtw_get_current_time(); + + /* before access eFuse, make sure card enable has been called */ + if ((hci_type == RTW_SDIO || hci_type == RTW_GSPI) + && !rtw_is_hw_init_completed(padapter)) + rtw_hal_power_on(padapter); + + rtn = padapter->hal_func.read_adapter_info(padapter); + + if ((hci_type == RTW_SDIO || hci_type == RTW_GSPI) + && !rtw_is_hw_init_completed(padapter)) + rtw_hal_power_off(padapter); + + RTW_INFO("%s in %d ms\n", __func__, rtw_get_passing_time_ms(start)); + + return rtn; +} + +void rtw_hal_read_chip_version(_adapter *padapter) +{ + padapter->hal_func.read_chip_version(padapter); + rtw_odm_init_ic_type(padapter); +} + +void rtw_hal_def_value_init(_adapter *padapter) +{ + if (is_primary_adapter(padapter)) { + padapter->hal_func.init_default_value(padapter); + + rtw_init_hal_com_default_value(padapter); + + { + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct hal_spec_t *hal_spec = GET_HAL_SPEC(padapter); + + /* hal_spec is ready here */ + dvobj->macid_ctl.num = rtw_min(hal_spec->macid_num, MACID_NUM_SW_LIMIT); + + dvobj->cam_ctl.sec_cap = hal_spec->sec_cap; + dvobj->cam_ctl.num = rtw_min(hal_spec->sec_cam_ent_num, SEC_CAM_ENT_NUM_SW_LIMIT); + } + } +} + +u8 rtw_hal_data_init(_adapter *padapter) +{ + if (is_primary_adapter(padapter)) { + padapter->hal_data_sz = sizeof(HAL_DATA_TYPE); + padapter->HalData = rtw_zvmalloc(padapter->hal_data_sz); + if (padapter->HalData == NULL) { + RTW_INFO("cant not alloc memory for HAL DATA\n"); + return _FAIL; + } + } + return _SUCCESS; +} + +void rtw_hal_data_deinit(_adapter *padapter) +{ + if (is_primary_adapter(padapter)) { + if (padapter->HalData) { +#ifdef CONFIG_LOAD_PHY_PARA_FROM_FILE + phy_free_filebuf(padapter); +#endif + rtw_vmfree(padapter->HalData, padapter->hal_data_sz); + padapter->HalData = NULL; + padapter->hal_data_sz = 0; + } + } +} + +void rtw_hal_free_data(_adapter *padapter) +{ + /* free HAL Data */ + rtw_hal_data_deinit(padapter); +} +void rtw_hal_dm_init(_adapter *padapter) +{ + if (is_primary_adapter(padapter)) { + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + + padapter->hal_func.dm_init(padapter); + + _rtw_spinlock_init(&pHalData->IQKSpinLock); + + phy_load_tx_power_ext_info(padapter, 1); + } +} +void rtw_hal_dm_deinit(_adapter *padapter) +{ + if (is_primary_adapter(padapter)) { + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + + padapter->hal_func.dm_deinit(padapter); + + _rtw_spinlock_free(&pHalData->IQKSpinLock); + } +} +void rtw_hal_sw_led_init(_adapter *padapter) +{ + if (padapter->hal_func.InitSwLeds) + padapter->hal_func.InitSwLeds(padapter); +} + +void rtw_hal_sw_led_deinit(_adapter *padapter) +{ + if (padapter->hal_func.DeInitSwLeds) + padapter->hal_func.DeInitSwLeds(padapter); +} + +u32 rtw_hal_power_on(_adapter *padapter) +{ + return padapter->hal_func.hal_power_on(padapter); +} +void rtw_hal_power_off(_adapter *padapter) +{ + struct macid_ctl_t *macid_ctl = &padapter->dvobj->macid_ctl; + + _rtw_memset(macid_ctl->h2c_msr, 0, MACID_NUM_SW_LIMIT); + + padapter->hal_func.hal_power_off(padapter); +} + + +void rtw_hal_init_opmode(_adapter *padapter) +{ + NDIS_802_11_NETWORK_INFRASTRUCTURE networkType = Ndis802_11InfrastructureMax; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + sint fw_state; + + fw_state = get_fwstate(pmlmepriv); + + if (fw_state & WIFI_ADHOC_STATE) + networkType = Ndis802_11IBSS; + else if (fw_state & WIFI_STATION_STATE) + networkType = Ndis802_11Infrastructure; + else if (fw_state & WIFI_AP_STATE) + networkType = Ndis802_11APMode; + else + return; + + rtw_setopmode_cmd(padapter, networkType, _FALSE); +} + +uint rtw_hal_init(_adapter *padapter) +{ + uint status = _SUCCESS; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + int i; + + status = padapter->hal_func.hal_init(padapter); + + if (status == _SUCCESS) { + pHalData->hw_init_completed = _TRUE; + rtw_restore_mac_addr(padapter); + + if (padapter->registrypriv.notch_filter == 1) + rtw_hal_notch_filter(padapter, 1); + + for (i = 0; i < dvobj->iface_nums; i++) + rtw_sec_restore_wep_key(dvobj->padapters[i]); + + rtw_led_control(padapter, LED_CTL_POWER_ON); + + init_hw_mlme_ext(padapter); + + rtw_hal_init_opmode(padapter); + +#ifdef CONFIG_RF_POWER_TRIM + rtw_bb_rf_gain_offset(padapter); +#endif /*CONFIG_RF_POWER_TRIM*/ + + } else { + pHalData->hw_init_completed = _FALSE; + RTW_INFO("rtw_hal_init: hal_init fail\n"); + } + + + return status; + +} + +uint rtw_hal_deinit(_adapter *padapter) +{ + uint status = _SUCCESS; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + int i; + + status = padapter->hal_func.hal_deinit(padapter); + + if (status == _SUCCESS) { + rtw_led_control(padapter, LED_CTL_POWER_OFF); + pHalData->hw_init_completed = _FALSE; + } else + RTW_INFO("\n rtw_hal_deinit: hal_init fail\n"); + + + return status; +} + +void rtw_hal_set_hwreg(_adapter *padapter, u8 variable, u8 *val) +{ + padapter->hal_func.set_hw_reg_handler(padapter, variable, val); +} + +void rtw_hal_get_hwreg(_adapter *padapter, u8 variable, u8 *val) +{ + padapter->hal_func.GetHwRegHandler(padapter, variable, val); +} + +u8 rtw_hal_set_def_var(_adapter *padapter, HAL_DEF_VARIABLE eVariable, PVOID pValue) +{ + return padapter->hal_func.SetHalDefVarHandler(padapter, eVariable, pValue); +} +u8 rtw_hal_get_def_var(_adapter *padapter, HAL_DEF_VARIABLE eVariable, PVOID pValue) +{ + return padapter->hal_func.get_hal_def_var_handler(padapter, eVariable, pValue); +} + +void rtw_hal_set_odm_var(_adapter *padapter, HAL_ODM_VARIABLE eVariable, PVOID pValue1, BOOLEAN bSet) +{ + padapter->hal_func.SetHalODMVarHandler(padapter, eVariable, pValue1, bSet); +} +void rtw_hal_get_odm_var(_adapter *padapter, HAL_ODM_VARIABLE eVariable, PVOID pValue1, PVOID pValue2) +{ + padapter->hal_func.GetHalODMVarHandler(padapter, eVariable, pValue1, pValue2); +} + +/* FOR SDIO & PCIE */ +void rtw_hal_enable_interrupt(_adapter *padapter) +{ +#if defined(CONFIG_PCI_HCI) || defined(CONFIG_SDIO_HCI) || defined (CONFIG_GSPI_HCI) + padapter->hal_func.enable_interrupt(padapter); +#endif /* #if defined(CONFIG_PCI_HCI) || defined (CONFIG_SDIO_HCI) || defined (CONFIG_GSPI_HCI) */ +} + +/* FOR SDIO & PCIE */ +void rtw_hal_disable_interrupt(_adapter *padapter) +{ +#if defined(CONFIG_PCI_HCI) || defined(CONFIG_SDIO_HCI) || defined (CONFIG_GSPI_HCI) + padapter->hal_func.disable_interrupt(padapter); +#endif /* #if defined(CONFIG_PCI_HCI) || defined (CONFIG_SDIO_HCI) || defined (CONFIG_GSPI_HCI) */ +} + + +u8 rtw_hal_check_ips_status(_adapter *padapter) +{ + u8 val = _FALSE; + if (padapter->hal_func.check_ips_status) + val = padapter->hal_func.check_ips_status(padapter); + else + RTW_INFO("%s: hal_func.check_ips_status is NULL!\n", __FUNCTION__); + + return val; +} + +s32 rtw_hal_fw_dl(_adapter *padapter, u8 wowlan) +{ + return padapter->hal_func.fw_dl(padapter, wowlan); +} + +#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) +void rtw_hal_clear_interrupt(_adapter *padapter) +{ +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + padapter->hal_func.clear_interrupt(padapter); +#endif +} +#endif + +#if defined(CONFIG_USB_HCI) || defined(CONFIG_PCI_HCI) +u32 rtw_hal_inirp_init(_adapter *padapter) +{ + if (is_primary_adapter(padapter)) + return padapter->hal_func.inirp_init(padapter); + return _SUCCESS; +} +u32 rtw_hal_inirp_deinit(_adapter *padapter) +{ + + if (is_primary_adapter(padapter)) + return padapter->hal_func.inirp_deinit(padapter); + + return _SUCCESS; +} +#endif /* #if defined(CONFIG_USB_HCI) || defined (CONFIG_PCI_HCI) */ + +#if defined(CONFIG_PCI_HCI) +void rtw_hal_irp_reset(_adapter *padapter) +{ + padapter->hal_func.irp_reset(GET_PRIMARY_ADAPTER(padapter)); +} +#endif /* #if defined(CONFIG_PCI_HCI) */ + +/* for USB Auto-suspend */ +u8 rtw_hal_intf_ps_func(_adapter *padapter, HAL_INTF_PS_FUNC efunc_id, u8 *val) +{ + if (padapter->hal_func.interface_ps_func) + return padapter->hal_func.interface_ps_func(padapter, efunc_id, val); + return _FAIL; +} + +s32 rtw_hal_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe) +{ + return padapter->hal_func.hal_xmitframe_enqueue(padapter, pxmitframe); +} + +s32 rtw_hal_xmit(_adapter *padapter, struct xmit_frame *pxmitframe) +{ + return padapter->hal_func.hal_xmit(padapter, pxmitframe); +} + +/* + * [IMPORTANT] This function would be run in interrupt context. + */ +s32 rtw_hal_mgnt_xmit(_adapter *padapter, struct xmit_frame *pmgntframe) +{ + s32 ret = _FAIL; + u8 *pframe, subtype; + struct rtw_ieee80211_hdr *pwlanhdr; + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + + update_mgntframe_attrib_addr(padapter, pmgntframe); + pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; + subtype = get_frame_sub_type(pframe); /* bit(7)~bit(2) */ + + /* pwlanhdr = (struct rtw_ieee80211_hdr *)pframe; */ + /* _rtw_memcpy(pmgntframe->attrib.ra, pwlanhdr->addr1, ETH_ALEN); */ + +#ifdef CONFIG_IEEE80211W + if (padapter->securitypriv.binstallBIPkey == _TRUE && (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC || + subtype == WIFI_ACTION)) { + if (IS_MCAST(pmgntframe->attrib.ra) && pmgntframe->attrib.key_type != IEEE80211W_NO_KEY) { + pmgntframe->attrib.encrypt = _BIP_; + /* pmgntframe->attrib.bswenc = _TRUE; */ + } else if (pmgntframe->attrib.key_type != IEEE80211W_NO_KEY) { + psta = rtw_get_stainfo(pstapriv, pmgntframe->attrib.ra); + if (psta && psta->bpairwise_key_installed == _TRUE) { + pmgntframe->attrib.encrypt = _AES_; + pmgntframe->attrib.bswenc = _TRUE; + } else { + RTW_INFO("%s, %d, bpairwise_key_installed is FALSE\n", __func__, __LINE__); + goto no_mgmt_coalesce; + } + } + RTW_INFO("encrypt=%d, bswenc=%d\n", pmgntframe->attrib.encrypt, pmgntframe->attrib.bswenc); + rtw_mgmt_xmitframe_coalesce(padapter, pmgntframe->pkt, pmgntframe); + } +#endif /* CONFIG_IEEE80211W */ +no_mgmt_coalesce: + ret = padapter->hal_func.mgnt_xmit(padapter, pmgntframe); + return ret; +} + +s32 rtw_hal_init_xmit_priv(_adapter *padapter) +{ + return padapter->hal_func.init_xmit_priv(padapter); +} +void rtw_hal_free_xmit_priv(_adapter *padapter) +{ + padapter->hal_func.free_xmit_priv(padapter); +} + +s32 rtw_hal_init_recv_priv(_adapter *padapter) +{ + return padapter->hal_func.init_recv_priv(padapter); +} +void rtw_hal_free_recv_priv(_adapter *padapter) +{ + padapter->hal_func.free_recv_priv(padapter); +} + +void rtw_update_ramask(_adapter *padapter, struct sta_info *psta, u32 mac_id, u8 rssi_level, u8 is_update_bw) +{ + struct macid_cfg h2c_macid_cfg; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter); + u8 disable_cck_rate = FALSE, MimoPs_enable = FALSE; + u32 ratr_bitmap_msb = 0, ratr_bitmap_lsb = 0; + u64 mask = 0, rate_bitmap = 0; + u8 bw, short_gi; + + if (psta == NULL) { + RTW_ERR(FUNC_ADPT_FMT" macid:%u, sta is NULL\n", FUNC_ADPT_ARG(padapter), mac_id); + rtw_warn_on(1); + return; + } + _rtw_memset(&h2c_macid_cfg, 0, sizeof(struct macid_cfg)); + + bw = rtw_get_tx_bw_mode(padapter, psta); + short_gi = query_ra_short_GI(psta, bw); + + ratr_bitmap_msb = (u32)(psta->ra_mask >> 32); + ratr_bitmap_lsb = (u32)(psta->ra_mask); + + phydm_update_hal_ra_mask(&hal_data->odmpriv, psta->wireless_mode, hal_data->rf_type, bw, MimoPs_enable, disable_cck_rate, &ratr_bitmap_msb, &ratr_bitmap_lsb, rssi_level); + mask = (((u64)ratr_bitmap_msb) << 32) | ((u64)ratr_bitmap_lsb); + + +#ifdef CONFIG_BT_COEXIST + if (hal_data->EEPROMBluetoothCoexist == 1) { + rate_bitmap = rtw_btcoex_GetRaMask(padapter); + mask &= ~rate_bitmap; + } +#endif /* CONFIG_BT_COEXIST */ + +#ifdef CONFIG_CMCC_TEST +#ifdef CONFIG_BT_COEXIST + if (pmlmeext->cur_wireless_mode & WIRELESS_11G) { + if (mac_id == 0) { + RTW_INFO("CMCC_BT update raid entry, mask=0x%x\n", mask); + /*mask &=0xffffffc0; //disable CCK & <12M OFDM rate for 11G mode for CMCC */ + mask &= 0xffffff00; /*disable CCK & <24M OFDM rate for 11G mode for CMCC */ + RTW_INFO("CMCC_BT update raid entry, mask=0x%x\n", mask); + } + } +#endif +#endif + + /*set correct initial date rate for each mac_id */ + hal_data->INIDATA_RATE[mac_id] = psta->init_rate; + + + RTW_INFO("%s => mac_id:%d, networkType:0x%02x, mask:0x%016llx\n\t ==> rssi_level:%d, rate_bitmap:0x%016llx, shortGIrate=%d\n\t ==> bw:%d, ignore_bw:0x%d\n", + __func__, mac_id, psta->wireless_mode, mask, rssi_level, rate_bitmap, short_gi, bw, (!is_update_bw)); + + rtw_macid_ctl_set_bw(macid_ctl, mac_id, bw); + rtw_macid_ctl_set_vht_en(macid_ctl, mac_id, is_supported_vht(psta->wireless_mode)); + rtw_macid_ctl_set_rate_bmp0(macid_ctl, mac_id, mask); + rtw_macid_ctl_set_rate_bmp1(macid_ctl, mac_id, mask >> 32); + rtw_update_tx_rate_bmp(adapter_to_dvobj(padapter)); + + h2c_macid_cfg.mac_id = mac_id; + h2c_macid_cfg.rate_id = psta->raid; + h2c_macid_cfg.bandwidth = bw; + h2c_macid_cfg.ignore_bw = (!is_update_bw); + h2c_macid_cfg.short_gi = short_gi; + h2c_macid_cfg.ra_mask = mask; + + padapter->hal_func.update_ra_mask_handler(padapter, psta, &h2c_macid_cfg); +} + +void rtw_hal_update_ra_mask(struct sta_info *psta, u8 rssi_level, u8 is_update_bw) +{ + _adapter *padapter; + struct mlme_priv *pmlmepriv; + + if (!psta) + return; + + padapter = psta->padapter; + + pmlmepriv = &(padapter->mlmepriv); + + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE) + add_RATid(padapter, psta, rssi_level, is_update_bw); + else { + psta->raid = rtw_hal_networktype_to_raid(padapter, psta); + rtw_update_ramask(padapter, psta, psta->mac_id, rssi_level, is_update_bw); + } +} + +/* Start specifical interface thread */ +void rtw_hal_start_thread(_adapter *padapter) +{ +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) +#ifndef CONFIG_SDIO_TX_TASKLET + padapter->hal_func.run_thread(padapter); +#endif +#endif +} +/* Start specifical interface thread */ +void rtw_hal_stop_thread(_adapter *padapter) +{ +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) +#ifndef CONFIG_SDIO_TX_TASKLET + + padapter->hal_func.cancel_thread(padapter); + +#endif +#endif +} + +u32 rtw_hal_read_bbreg(_adapter *padapter, u32 RegAddr, u32 BitMask) +{ + u32 data = 0; + if (padapter->hal_func.read_bbreg) + data = padapter->hal_func.read_bbreg(padapter, RegAddr, BitMask); + return data; +} +void rtw_hal_write_bbreg(_adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data) +{ + if (padapter->hal_func.write_bbreg) + padapter->hal_func.write_bbreg(padapter, RegAddr, BitMask, Data); +} + +u32 rtw_hal_read_rfreg(_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask) +{ + u32 data = 0; + + if (padapter->hal_func.read_rfreg) { + data = padapter->hal_func.read_rfreg(padapter, eRFPath, RegAddr, BitMask); + + if (match_rf_read_sniff_ranges(eRFPath, RegAddr, BitMask)) { + RTW_INFO("DBG_IO rtw_hal_read_rfreg(%u, 0x%04x, 0x%08x) read:0x%08x(0x%08x)\n" + , eRFPath, RegAddr, BitMask, (data << PHY_CalculateBitShift(BitMask)), data); + } + } + + return data; +} + +void rtw_hal_write_rfreg(_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask, u32 Data) +{ + if (padapter->hal_func.write_rfreg) { + + if (match_rf_write_sniff_ranges(eRFPath, RegAddr, BitMask)) { + RTW_INFO("DBG_IO rtw_hal_write_rfreg(%u, 0x%04x, 0x%08x) write:0x%08x(0x%08x)\n" + , eRFPath, RegAddr, BitMask, (Data << PHY_CalculateBitShift(BitMask)), Data); + } + + padapter->hal_func.write_rfreg(padapter, eRFPath, RegAddr, BitMask, Data); + +#ifdef CONFIG_PCI_HCI + if (!IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(padapter)) /*For N-Series IC, suggest by Jenyu*/ + rtw_udelay_os(2); +#endif + } +} + +#if defined(CONFIG_PCI_HCI) +s32 rtw_hal_interrupt_handler(_adapter *padapter) +{ + s32 ret = _FAIL; + ret = padapter->hal_func.interrupt_handler(padapter); + return ret; +} +#endif +#if defined(CONFIG_USB_HCI) && defined(CONFIG_SUPPORT_USB_INT) +void rtw_hal_interrupt_handler(_adapter *padapter, u16 pkt_len, u8 *pbuf) +{ + padapter->hal_func.interrupt_handler(padapter, pkt_len, pbuf); +} +#endif + +void rtw_hal_set_chnl_bw(_adapter *padapter, u8 channel, CHANNEL_WIDTH Bandwidth, u8 Offset40, u8 Offset80) +{ + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + struct PHY_DM_STRUCT *pDM_Odm = &(pHalData->odmpriv); + u8 cch_160 = Bandwidth == CHANNEL_WIDTH_160 ? channel : 0; + u8 cch_80 = Bandwidth == CHANNEL_WIDTH_80 ? channel : 0; + u8 cch_40 = Bandwidth == CHANNEL_WIDTH_40 ? channel : 0; + u8 cch_20 = Bandwidth == CHANNEL_WIDTH_20 ? channel : 0; + + odm_acquire_spin_lock(pDM_Odm, RT_IQK_SPINLOCK); + if (pDM_Odm->rf_calibrate_info.is_iqk_in_progress == _TRUE) + RTW_ERR("%s, %d, IQK may race condition\n", __func__, __LINE__); + odm_release_spin_lock(pDM_Odm, RT_IQK_SPINLOCK); + + /* MP mode channel don't use secondary channel */ + if (rtw_mi_mp_mode_check(padapter) == _FALSE) { + #if 0 + if (cch_160 != 0) + cch_80 = rtw_get_scch_by_cch_offset(cch_160, CHANNEL_WIDTH_160, Offset80); + #endif + if (cch_80 != 0) + cch_40 = rtw_get_scch_by_cch_offset(cch_80, CHANNEL_WIDTH_80, Offset80); + if (cch_40 != 0) + cch_20 = rtw_get_scch_by_cch_offset(cch_40, CHANNEL_WIDTH_40, Offset40); + } + + pHalData->cch_80 = cch_80; + pHalData->cch_40 = cch_40; + pHalData->cch_20 = cch_20; + + if (0) + RTW_INFO("%s cch:%u, %s, offset40:%u, offset80:%u (%u, %u, %u)\n", __func__ + , channel, ch_width_str(Bandwidth), Offset40, Offset80 + , pHalData->cch_80, pHalData->cch_40, pHalData->cch_20); + + padapter->hal_func.set_chnl_bw_handler(padapter, channel, Bandwidth, Offset40, Offset80); +} + +void rtw_hal_set_tx_power_level(_adapter *padapter, u8 channel) +{ + if (padapter->hal_func.set_tx_power_level_handler) + padapter->hal_func.set_tx_power_level_handler(padapter, channel); +} + +void rtw_hal_get_tx_power_level(_adapter *padapter, s32 *powerlevel) +{ + if (padapter->hal_func.get_tx_power_level_handler) + padapter->hal_func.get_tx_power_level_handler(padapter, powerlevel); +} + +void rtw_hal_dm_watchdog(_adapter *padapter) +{ +#ifdef CONFIG_MCC_MODE + if (MCC_EN(padapter)) { + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) + return; + } +#endif /* CONFIG_MCC_MODE */ + + padapter->hal_func.hal_dm_watchdog(padapter); + +} + +#ifdef CONFIG_LPS_LCLK_WD_TIMER +void rtw_hal_dm_watchdog_in_lps(_adapter *padapter) +{ +#if defined(CONFIG_CONCURRENT_MODE) +#ifndef CONFIG_FW_MULTI_PORT_SUPPORT + if (padapter->hw_port != HW_PORT0) + return; +#endif +#endif + + if (adapter_to_pwrctl(padapter)->bFwCurrentInPSMode == _TRUE) { + padapter->hal_func.hal_dm_watchdog_in_lps(padapter);/* this function caller is in interrupt context */ + } +} +#endif + +void rtw_hal_bcn_related_reg_setting(_adapter *padapter) +{ + padapter->hal_func.SetBeaconRelatedRegistersHandler(padapter); +} + +#ifdef CONFIG_HOSTAPD_MLME +s32 rtw_hal_hostap_mgnt_xmit_entry(_adapter *padapter, _pkt *pkt) +{ + if (padapter->hal_func.hostap_mgnt_xmit_entry) + return padapter->hal_func.hostap_mgnt_xmit_entry(padapter, pkt); + return _FAIL; +} +#endif /* CONFIG_HOSTAPD_MLME */ + +#ifdef DBG_CONFIG_ERROR_DETECT +void rtw_hal_sreset_init(_adapter *padapter) +{ + padapter->hal_func.sreset_init_value(padapter); +} +void rtw_hal_sreset_reset(_adapter *padapter) +{ + padapter = GET_PRIMARY_ADAPTER(padapter); + padapter->hal_func.silentreset(padapter); +} + +void rtw_hal_sreset_reset_value(_adapter *padapter) +{ + padapter->hal_func.sreset_reset_value(padapter); +} + +void rtw_hal_sreset_xmit_status_check(_adapter *padapter) +{ + padapter->hal_func.sreset_xmit_status_check(padapter); +} +void rtw_hal_sreset_linked_status_check(_adapter *padapter) +{ + padapter->hal_func.sreset_linked_status_check(padapter); +} +u8 rtw_hal_sreset_get_wifi_status(_adapter *padapter) +{ + return padapter->hal_func.sreset_get_wifi_status(padapter); +} + +bool rtw_hal_sreset_inprogress(_adapter *padapter) +{ + padapter = GET_PRIMARY_ADAPTER(padapter); + return padapter->hal_func.sreset_inprogress(padapter); +} +#endif /* DBG_CONFIG_ERROR_DETECT */ + +#ifdef CONFIG_IOL +int rtw_hal_iol_cmd(ADAPTER *adapter, struct xmit_frame *xmit_frame, u32 max_waiting_ms, u32 bndy_cnt) +{ + if (adapter->hal_func.IOL_exec_cmds_sync) + return adapter->hal_func.IOL_exec_cmds_sync(adapter, xmit_frame, max_waiting_ms, bndy_cnt); + return _FAIL; +} +#endif + +#ifdef CONFIG_XMIT_THREAD_MODE +s32 rtw_hal_xmit_thread_handler(_adapter *padapter) +{ + return padapter->hal_func.xmit_thread_handler(padapter); +} +#endif + +#ifdef CONFIG_RECV_THREAD_MODE +s32 rtw_hal_recv_hdl(_adapter *adapter) +{ + return adapter->hal_func.recv_hdl(adapter); +} +#endif + +void rtw_hal_notch_filter(_adapter *adapter, bool enable) +{ + if (adapter->hal_func.hal_notch_filter) + adapter->hal_func.hal_notch_filter(adapter, enable); +} + +#ifdef CONFIG_FW_C2H_REG +inline bool rtw_hal_c2h_valid(_adapter *adapter, u8 *buf) +{ + HAL_DATA_TYPE *HalData = GET_HAL_DATA(adapter); + HAL_VERSION *hal_ver = &HalData->version_id; + bool ret = _FAIL; + + ret = C2H_ID_88XX(buf) || C2H_PLEN_88XX(buf); + + return ret; +} + +inline s32 rtw_hal_c2h_evt_read(_adapter *adapter, u8 *buf) +{ + HAL_DATA_TYPE *HalData = GET_HAL_DATA(adapter); + HAL_VERSION *hal_ver = &HalData->version_id; + s32 ret = _FAIL; + + ret = c2h_evt_read_88xx(adapter, buf); + + return ret; +} + +bool rtw_hal_c2h_reg_hdr_parse(_adapter *adapter, u8 *buf, u8 *id, u8 *seq, u8 *plen, u8 **payload) +{ + HAL_DATA_TYPE *HalData = GET_HAL_DATA(adapter); + HAL_VERSION *hal_ver = &HalData->version_id; + bool ret = _FAIL; + + *id = C2H_ID_88XX(buf); + *seq = C2H_SEQ_88XX(buf); + *plen = C2H_PLEN_88XX(buf); + *payload = C2H_PAYLOAD_88XX(buf); + ret = _SUCCESS; + + return ret; +} +#endif /* CONFIG_FW_C2H_REG */ + +#ifdef CONFIG_FW_C2H_PKT +bool rtw_hal_c2h_pkt_hdr_parse(_adapter *adapter, u8 *buf, u16 len, u8 *id, u8 *seq, u8 *plen, u8 **payload) +{ + HAL_DATA_TYPE *HalData = GET_HAL_DATA(adapter); + HAL_VERSION *hal_ver = &HalData->version_id; + bool ret = _FAIL; + + if (!buf || len > 256 || len < 3) + goto exit; + + *id = C2H_ID_88XX(buf); + *seq = C2H_SEQ_88XX(buf); + *plen = len - 2; + *payload = C2H_PAYLOAD_88XX(buf); + ret = _SUCCESS; + +exit: + return ret; +} +#endif /* CONFIG_FW_C2H_PKT */ + +#if defined(CONFIG_MP_INCLUDED) && defined(CONFIG_RTL8723B) +#include <rtw_bt_mp.h> /* for MPTBT_FwC2hBtMpCtrl */ +#endif +s32 c2h_handler(_adapter *adapter, u8 id, u8 seq, u8 plen, u8 *payload) +{ + HAL_DATA_TYPE *hal_data = GET_HAL_DATA(adapter); + struct PHY_DM_STRUCT *odm = &hal_data->odmpriv; + u8 sub_id = 0; + s32 ret = _SUCCESS; + + switch (id) { + case C2H_DBG: + RTW_INFO_DUMP("C2H_DBG: ", payload, plen); + break; + case C2H_FW_SCAN_COMPLETE: + RTW_INFO("[C2H], FW Scan Complete\n"); + break; + +#ifdef CONFIG_BT_COEXIST + case C2H_BT_INFO: + rtw_btcoex_BtInfoNotify(adapter, plen, payload); + break; + case C2H_BT_MP_INFO: + #if defined(CONFIG_MP_INCLUDED) && defined(CONFIG_RTL8723B) + MPTBT_FwC2hBtMpCtrl(adapter, payload, plen); + #endif + rtw_btcoex_BtMpRptNotify(adapter, plen, payload); + break; + case C2H_MAILBOX_STATUS: + RTW_INFO_DUMP("C2H_MAILBOX_STATUS: ", payload, plen); + break; +#endif /* CONFIG_BT_COEXIST */ + + case C2H_IQK_FINISH: + c2h_iqk_offload(adapter, payload, plen); + break; + +#if defined(CONFIG_TDLS) && defined(CONFIG_TDLS_CH_SW) + case C2H_FW_CHNL_SWITCH_COMPLETE: + rtw_tdls_chsw_oper_done(adapter); + break; + case C2H_BCN_EARLY_RPT: + rtw_tdls_ch_sw_back_to_base_chnl(adapter); + break; +#endif + +#ifdef CONFIG_MCC_MODE + case C2H_MCC: + rtw_hal_mcc_c2h_handler(adapter, plen, payload); + break; +#endif + +#ifdef CONFIG_RTW_MAC_HIDDEN_RPT + case C2H_MAC_HIDDEN_RPT: + c2h_mac_hidden_rpt_hdl(adapter, payload, plen); + break; + case C2H_MAC_HIDDEN_RPT_2: + c2h_mac_hidden_rpt_2_hdl(adapter, payload, plen); + break; +#endif + + case C2H_DEFEATURE_DBG: + c2h_defeature_dbg_hdl(adapter, payload, plen); + break; + +#ifdef CONFIG_RTW_CUSTOMER_STR + case C2H_CUSTOMER_STR_RPT: + c2h_customer_str_rpt_hdl(adapter, payload, plen); + break; + case C2H_CUSTOMER_STR_RPT_2: + c2h_customer_str_rpt_2_hdl(adapter, payload, plen); + break; +#endif + + case C2H_EXTEND: + sub_id = payload[0]; + /* no handle, goto default */ + + default: + if (phydm_c2H_content_parsing(odm, id, plen, payload) != TRUE) + ret = _FAIL; + break; + } + +exit: + if (ret != _SUCCESS) { + if (id == C2H_EXTEND) + RTW_WARN("%s: unknown C2H(0x%02x, 0x%02x)\n", __func__, id, sub_id); + else + RTW_WARN("%s: unknown C2H(0x%02x)\n", __func__, id); + } + + return ret; +} + +#ifndef RTW_HALMAC +s32 rtw_hal_c2h_handler(_adapter *adapter, u8 id, u8 seq, u8 plen, u8 *payload) +{ + s32 ret = _FAIL; + + ret = adapter->hal_func.c2h_handler(adapter, id, seq, plen, payload); + if (ret != _SUCCESS) + ret = c2h_handler(adapter, id, seq, plen, payload); + + return ret; +} + +s32 rtw_hal_c2h_id_handle_directly(_adapter *adapter, u8 id, u8 seq, u8 plen, u8 *payload) +{ + switch (id) { + case C2H_CCX_TX_RPT: + case C2H_BT_MP_INFO: + case C2H_FW_CHNL_SWITCH_COMPLETE: + case C2H_IQK_FINISH: + case C2H_MCC: + case C2H_BCN_EARLY_RPT: + case C2H_AP_REQ_TXRPT: + case C2H_SPC_STAT: + return _TRUE; + default: + return _FALSE; + } +} +#endif /* !RTW_HALMAC */ + +s32 rtw_hal_is_disable_sw_channel_plan(PADAPTER padapter) +{ + return GET_HAL_DATA(padapter)->bDisableSWChannelPlan; +} + +s32 rtw_hal_macid_sleep(PADAPTER padapter, u8 macid) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + u8 support; + + support = _FALSE; + rtw_hal_get_def_var(padapter, HAL_DEF_MACID_SLEEP, &support); + if (_FALSE == support) + return _FAIL; + + if (macid >= macid_ctl->num) { + RTW_ERR(FUNC_ADPT_FMT": Invalid macid(%u)\n", + FUNC_ADPT_ARG(padapter), macid); + return _FAIL; + } + + rtw_hal_set_hwreg(padapter, HW_VAR_MACID_SLEEP, &macid); + + return _SUCCESS; +} + +s32 rtw_hal_macid_wakeup(PADAPTER padapter, u8 macid) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct macid_ctl_t *macid_ctl = dvobj_to_macidctl(dvobj); + u8 support; + + support = _FALSE; + rtw_hal_get_def_var(padapter, HAL_DEF_MACID_SLEEP, &support); + if (_FALSE == support) + return _FAIL; + + if (macid >= macid_ctl->num) { + RTW_ERR(FUNC_ADPT_FMT": Invalid macid(%u)\n", + FUNC_ADPT_ARG(padapter), macid); + return _FAIL; + } + + rtw_hal_set_hwreg(padapter, HW_VAR_MACID_WAKEUP, &macid); + + return _SUCCESS; +} + +s32 rtw_hal_fill_h2c_cmd(PADAPTER padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer) +{ + _adapter *pri_adapter = GET_PRIMARY_ADAPTER(padapter); + + if (pri_adapter->bFWReady == _TRUE) + return padapter->hal_func.fill_h2c_cmd(padapter, ElementID, CmdLen, pCmdBuffer); + else if (padapter->registrypriv.mp_mode == 0) + RTW_PRINT(FUNC_ADPT_FMT" FW doesn't exit when no MP mode, by pass H2C id:0x%02x\n" + , FUNC_ADPT_ARG(padapter), ElementID); + return _FAIL; +} + +void rtw_hal_fill_fake_txdesc(_adapter *padapter, u8 *pDesc, u32 BufferLen, + u8 IsPsPoll, u8 IsBTQosNull, u8 bDataFrame) +{ + padapter->hal_func.fill_fake_txdesc(padapter, pDesc, BufferLen, IsPsPoll, IsBTQosNull, bDataFrame); + +} +u8 rtw_hal_get_txbuff_rsvd_page_num(_adapter *adapter, bool wowlan) +{ + return adapter->hal_func.hal_get_tx_buff_rsvd_page_num(adapter, wowlan); +} + +#ifdef CONFIG_GPIO_API +void rtw_hal_update_hisr_hsisr_ind(_adapter *padapter, u32 flag) +{ + if (padapter->hal_func.update_hisr_hsisr_ind) + padapter->hal_func.update_hisr_hsisr_ind(padapter, flag); +} + +int rtw_hal_gpio_func_check(_adapter *padapter, u8 gpio_num) +{ + int ret = _SUCCESS; + + if (padapter->hal_func.hal_gpio_func_check) + ret = padapter->hal_func.hal_gpio_func_check(padapter, gpio_num); + + return ret; +} + +void rtw_hal_gpio_multi_func_reset(_adapter *padapter, u8 gpio_num) +{ + if (padapter->hal_func.hal_gpio_multi_func_reset) + padapter->hal_func.hal_gpio_multi_func_reset(padapter, gpio_num); +} +#endif + +void rtw_hal_fw_correct_bcn(_adapter *padapter) +{ + if (padapter->hal_func.fw_correct_bcn) + padapter->hal_func.fw_correct_bcn(padapter); +} + +void rtw_hal_set_tx_power_index(PADAPTER padapter, u32 powerindex, u8 rfpath, u8 rate) +{ + return padapter->hal_func.set_tx_power_index_handler(padapter, powerindex, rfpath, rate); +} + +u8 rtw_hal_get_tx_power_index(PADAPTER padapter, u8 rfpath, u8 rate, u8 bandwidth, u8 channel, struct txpwr_idx_comp *tic) +{ + return padapter->hal_func.get_tx_power_index_handler(padapter, rfpath, rate, bandwidth, channel, tic); +} + +#ifdef RTW_HALMAC +/* + * Description: + * Initialize MAC registers + * + * Return: + * _TRUE success + * _FALSE fail + */ +u8 rtw_hal_init_mac_register(PADAPTER adapter) +{ + return adapter->hal_func.init_mac_register(adapter); +} + +/* + * Description: + * Initialize PHY(BB/RF) related functions + * + * Return: + * _TRUE success + * _FALSE fail + */ +u8 rtw_hal_init_phy(PADAPTER adapter) +{ + return adapter->hal_func.init_phy(adapter); +} +#endif /* RTW_HALMAC */ + +#ifdef CONFIG_RFKILL_POLL +bool rtw_hal_rfkill_poll(_adapter *adapter, u8 *valid) +{ + bool ret; + + if (adapter->hal_func.hal_radio_onoff_check) + ret = adapter->hal_func.hal_radio_onoff_check(adapter, valid); + else { + *valid = 0; + ret = _FALSE; + } + return ret; +} +#endif + +#define rtw_hal_error_msg(ops_fun) \ + RTW_PRINT("### %s - Error : Please hook hal_func.%s ###\n", __FUNCTION__, ops_fun) + +u8 rtw_hal_ops_check(_adapter *padapter) +{ + u8 ret = _SUCCESS; +#if 1 + /*** initialize section ***/ + if (NULL == padapter->hal_func.read_chip_version) { + rtw_hal_error_msg("read_chip_version"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.init_default_value) { + rtw_hal_error_msg("init_default_value"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.intf_chip_configure) { + rtw_hal_error_msg("intf_chip_configure"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.read_adapter_info) { + rtw_hal_error_msg("read_adapter_info"); + ret = _FAIL; + } + + if (NULL == padapter->hal_func.hal_power_on) { + rtw_hal_error_msg("hal_power_on"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.hal_power_off) { + rtw_hal_error_msg("hal_power_off"); + ret = _FAIL; + } + + if (NULL == padapter->hal_func.hal_init) { + rtw_hal_error_msg("hal_init"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.hal_deinit) { + rtw_hal_error_msg("hal_deinit"); + ret = _FAIL; + } + + /*** xmit section ***/ + if (NULL == padapter->hal_func.init_xmit_priv) { + rtw_hal_error_msg("init_xmit_priv"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.free_xmit_priv) { + rtw_hal_error_msg("free_xmit_priv"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.hal_xmit) { + rtw_hal_error_msg("hal_xmit"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.mgnt_xmit) { + rtw_hal_error_msg("mgnt_xmit"); + ret = _FAIL; + } +#ifdef CONFIG_XMIT_THREAD_MODE + if (NULL == padapter->hal_func.xmit_thread_handler) { + rtw_hal_error_msg("xmit_thread_handler"); + ret = _FAIL; + } +#endif + if (NULL == padapter->hal_func.hal_xmitframe_enqueue) { + rtw_hal_error_msg("hal_xmitframe_enqueue"); + ret = _FAIL; + } +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) +#ifndef CONFIG_SDIO_TX_TASKLET + if (NULL == padapter->hal_func.run_thread) { + rtw_hal_error_msg("run_thread"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.cancel_thread) { + rtw_hal_error_msg("cancel_thread"); + ret = _FAIL; + } +#endif +#endif + + /*** recv section ***/ + if (NULL == padapter->hal_func.init_recv_priv) { + rtw_hal_error_msg("init_recv_priv"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.free_recv_priv) { + rtw_hal_error_msg("free_recv_priv"); + ret = _FAIL; + } +#ifdef CONFIG_RECV_THREAD_MODE + if (NULL == padapter->hal_func.recv_hdl) { + rtw_hal_error_msg("recv_hdl"); + ret = _FAIL; + } +#endif +#if defined(CONFIG_USB_HCI) || defined(CONFIG_PCI_HCI) + if (NULL == padapter->hal_func.inirp_init) { + rtw_hal_error_msg("inirp_init"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.inirp_deinit) { + rtw_hal_error_msg("inirp_deinit"); + ret = _FAIL; + } +#endif /* #if defined(CONFIG_USB_HCI) || defined (CONFIG_PCI_HCI) */ + + + /*** interrupt hdl section ***/ +#if defined(CONFIG_PCI_HCI) + if (NULL == padapter->hal_func.irp_reset) { + rtw_hal_error_msg("irp_reset"); + ret = _FAIL; + } +#endif/*#if defined(CONFIG_PCI_HCI)*/ +#if (defined(CONFIG_PCI_HCI)) || (defined(CONFIG_USB_HCI) && defined(CONFIG_SUPPORT_USB_INT)) + if (NULL == padapter->hal_func.interrupt_handler) { + rtw_hal_error_msg("interrupt_handler"); + ret = _FAIL; + } +#endif /*#if (defined(CONFIG_PCI_HCI)) || (defined(CONFIG_USB_HCI) && defined(CONFIG_SUPPORT_USB_INT))*/ + +#if defined(CONFIG_PCI_HCI) || defined(CONFIG_SDIO_HCI) || defined (CONFIG_GSPI_HCI) + if (NULL == padapter->hal_func.enable_interrupt) { + rtw_hal_error_msg("enable_interrupt"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.disable_interrupt) { + rtw_hal_error_msg("disable_interrupt"); + ret = _FAIL; + } +#endif /* defined(CONFIG_PCI_HCI) || defined (CONFIG_SDIO_HCI) || defined (CONFIG_GSPI_HCI) */ + + + /*** DM section ***/ + if (NULL == padapter->hal_func.dm_init) { + rtw_hal_error_msg("dm_init"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.dm_deinit) { + rtw_hal_error_msg("dm_deinit"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.hal_dm_watchdog) { + rtw_hal_error_msg("hal_dm_watchdog"); + ret = _FAIL; + } +#ifdef CONFIG_LPS_LCLK_WD_TIMER + if (NULL == padapter->hal_func.hal_dm_watchdog_in_lps) { + rtw_hal_error_msg("hal_dm_watchdog_in_lps"); + ret = _FAIL; + } +#endif + + /*** xxx section ***/ + if (NULL == padapter->hal_func.set_chnl_bw_handler) { + rtw_hal_error_msg("set_chnl_bw_handler"); + ret = _FAIL; + } + + if (NULL == padapter->hal_func.set_hw_reg_handler) { + rtw_hal_error_msg("set_hw_reg_handler"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.GetHwRegHandler) { + rtw_hal_error_msg("GetHwRegHandler"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.get_hal_def_var_handler) { + rtw_hal_error_msg("get_hal_def_var_handler"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.SetHalDefVarHandler) { + rtw_hal_error_msg("SetHalDefVarHandler"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.GetHalODMVarHandler) { + rtw_hal_error_msg("GetHalODMVarHandler"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.SetHalODMVarHandler) { + rtw_hal_error_msg("SetHalODMVarHandler"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.update_ra_mask_handler) { + rtw_hal_error_msg("update_ra_mask_handler"); + ret = _FAIL; + } + + if (NULL == padapter->hal_func.SetBeaconRelatedRegistersHandler) { + rtw_hal_error_msg("SetBeaconRelatedRegistersHandler"); + ret = _FAIL; + } + + if (NULL == padapter->hal_func.fill_h2c_cmd) { + rtw_hal_error_msg("fill_h2c_cmd"); + ret = _FAIL; + } + +#ifdef RTW_HALMAC + if (NULL == padapter->hal_func.hal_mac_c2h_handler) { + rtw_hal_error_msg("hal_mac_c2h_handler"); + ret = _FAIL; + } +#elif !defined(CONFIG_RTL8188E) + if (NULL == padapter->hal_func.c2h_handler) { + rtw_hal_error_msg("c2h_handler"); + ret = _FAIL; + } +#endif + +#if defined(CONFIG_LPS) || defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) + if (NULL == padapter->hal_func.fill_fake_txdesc) { + rtw_hal_error_msg("fill_fake_txdesc"); + ret = _FAIL; + } +#endif + if (NULL == padapter->hal_func.hal_get_tx_buff_rsvd_page_num) { + rtw_hal_error_msg("hal_get_tx_buff_rsvd_page_num"); + ret = _FAIL; + } + +#if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) +#if defined(CONFIG_SDIO_HCI) || defined(CONFIG_GSPI_HCI) + if (NULL == padapter->hal_func.clear_interrupt) { + rtw_hal_error_msg("clear_interrupt"); + ret = _FAIL; + } +#endif +#endif /* CONFIG_WOWLAN */ + + if (NULL == padapter->hal_func.fw_dl) { + rtw_hal_error_msg("fw_dl"); + ret = _FAIL; + } + + if ((IS_HARDWARE_TYPE_8814A(padapter) + || IS_HARDWARE_TYPE_8822BU(padapter) || IS_HARDWARE_TYPE_8822BS(padapter)) + && NULL == padapter->hal_func.fw_correct_bcn) { + rtw_hal_error_msg("fw_correct_bcn"); + ret = _FAIL; + } + + if (IS_HARDWARE_TYPE_8822B(padapter) || IS_HARDWARE_TYPE_8821C(padapter)) { + if (!padapter->hal_func.set_tx_power_index_handler) { + rtw_hal_error_msg("set_tx_power_index_handler"); + ret = _FAIL; + } + } + + if (!padapter->hal_func.get_tx_power_index_handler) { + rtw_hal_error_msg("get_tx_power_index_handler"); + ret = _FAIL; + } + + /*** SReset section ***/ +#ifdef DBG_CONFIG_ERROR_DETECT + if (NULL == padapter->hal_func.sreset_init_value) { + rtw_hal_error_msg("sreset_init_value"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.sreset_reset_value) { + rtw_hal_error_msg("sreset_reset_value"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.silentreset) { + rtw_hal_error_msg("silentreset"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.sreset_xmit_status_check) { + rtw_hal_error_msg("sreset_xmit_status_check"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.sreset_linked_status_check) { + rtw_hal_error_msg("sreset_linked_status_check"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.sreset_get_wifi_status) { + rtw_hal_error_msg("sreset_get_wifi_status"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.sreset_inprogress) { + rtw_hal_error_msg("sreset_inprogress"); + ret = _FAIL; + } +#endif /* #ifdef DBG_CONFIG_ERROR_DETECT */ + +#ifdef RTW_HALMAC + if (NULL == padapter->hal_func.init_mac_register) { + rtw_hal_error_msg("init_mac_register"); + ret = _FAIL; + } + if (NULL == padapter->hal_func.init_phy) { + rtw_hal_error_msg("init_phy"); + ret = _FAIL; + } +#endif /* RTW_HALMAC */ + +#ifdef CONFIG_RFKILL_POLL + if (padapter->hal_func.hal_radio_onoff_check == NULL) { + rtw_hal_error_msg("hal_radio_onoff_check"); + ret = _FAIL; + } +#endif +#endif + return ret; +} diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_mcc.c b/linux-bsp/drivers/rtl8188eus/hal/hal_mcc.c new file mode 100644 index 0000000..6d1a217 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_mcc.c @@ -0,0 +1,1877 @@ +/****************************************************************************** + * + * Copyright(c) 2015 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + ******************************************************************************/ +#ifdef CONFIG_MCC_MODE +#define _HAL_MCC_C_ + +#include <drv_types.h> /* PADAPTER */ +#include <rtw_mcc.h> /* mcc structure */ +#include <hal_data.h> /* HAL_DATA */ +#include <rtw_pwrctrl.h> /* power control */ + +#define MCC_DURATION_IDX 0 +#define MCC_TSF_SYNC_OFFSET_IDX 1 +#define MCC_START_TIME_OFFSET_IDX 2 +#define MCC_INTERVAL_IDX 3 +#define MCC_GUARD_OFFSET0_IDX 4 +#define MCC_GUARD_OFFSET1_IDX 5 +#define TU 1024 /* 1 TU equals 1024 microseconds */ +/* port 1 druration, TSF sync offset, start time offset, interval (unit:TU (1024 microseconds))*/ +u8 mcc_switch_channel_policy_table[][6]={ + {35, 50, 30, 100, 0, 0}, + {19, 50, 40, 100, 2, 2}, + {25, 50, 30, 100, 5, 5}, +}; + +const int mcc_max_policy_num = sizeof(mcc_switch_channel_policy_table) /sizeof(u8) /6; + +static void dump_iqk_val_table(PADAPTER padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct hal_iqk_reg_backup *iqk_reg_backup = pHalData->iqk_reg_backup; + u8 total_rf_path = pHalData->NumTotalRFPath; + u8 rf_path_idx = 0; + u8 backup_chan_idx = 0; + u8 backup_reg_idx = 0; + + RTW_INFO("=============dump IQK backup table================\n"); + for (backup_chan_idx = 0; backup_chan_idx < MAX_IQK_INFO_BACKUP_CHNL_NUM; backup_chan_idx++) { + for (rf_path_idx = 0; rf_path_idx < total_rf_path; rf_path_idx++) { + for(backup_reg_idx = 0; backup_reg_idx < MAX_IQK_INFO_BACKUP_REG_NUM; backup_reg_idx++) { + RTW_INFO("ch:%d. bw:%d. rf path:%d. reg[%d] = 0x%02x \n" + , iqk_reg_backup[backup_chan_idx].central_chnl + , iqk_reg_backup[backup_chan_idx].bw_mode + , rf_path_idx + , backup_reg_idx + , iqk_reg_backup[backup_chan_idx].reg_backup[rf_path_idx][backup_reg_idx] + ); + } + } + } + RTW_INFO("=============================================\n"); +} + +static void rtw_hal_mcc_build_p2p_noa_attr(PADAPTER padapter, u8 *ie, u32 *ie_len) +{ + struct mcc_adapter_priv *pmccadapriv = &padapter->mcc_adapterpriv; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct mcc_obj_priv *pmccobjpriv = &(dvobj->mcc_objpriv); + u8 p2p_noa_attr_ie[MAX_P2P_IE_LEN] = {0x00}; + u32 p2p_noa_attr_len = 0; + u8 noa_desc_num = 1; + u8 opp_ps = 0; /* Disable OppPS */ + u8 noa_count = 255; + u32 noa_duration = 0x20; + u32 noa_interval = 0x64; + u8 noa_index = 0; + u8 mcc_policy_idx = 0; + + mcc_policy_idx = pmccobjpriv->policy_index; + noa_duration = mcc_switch_channel_policy_table[mcc_policy_idx][MCC_DURATION_IDX]; + noa_interval = mcc_switch_channel_policy_table[mcc_policy_idx][MCC_INTERVAL_IDX]; + + /* P2P OUI(4 bytes) */ + _rtw_memcpy(p2p_noa_attr_ie, P2P_OUI, 4); + p2p_noa_attr_len = p2p_noa_attr_len + 4; + + /* attrute ID(1 byte) */ + p2p_noa_attr_ie[p2p_noa_attr_len] = P2P_ATTR_NOA; + p2p_noa_attr_len = p2p_noa_attr_len + 1; + + /* attrute length(2 bytes) length = noa_desc_num*13 + 2 */ + RTW_PUT_LE16(p2p_noa_attr_ie + p2p_noa_attr_len, (noa_desc_num*13 + 2)); + p2p_noa_attr_len = p2p_noa_attr_len + 2; + + /* Index (1 byte) */ + p2p_noa_attr_ie[p2p_noa_attr_len] = noa_index; + p2p_noa_attr_len = p2p_noa_attr_len + 1; + + /* CTWindow and OppPS Parameters (1 byte) */ + p2p_noa_attr_ie[p2p_noa_attr_len] = opp_ps; + p2p_noa_attr_len = p2p_noa_attr_len+ 1; + + /* NoA Count (1 byte) */ + p2p_noa_attr_ie[p2p_noa_attr_len] = noa_count; + p2p_noa_attr_len = p2p_noa_attr_len + 1; + + /* NoA Duration (4 bytes) unit: microseconds */ + RTW_PUT_LE32(p2p_noa_attr_ie + p2p_noa_attr_len, (noa_duration * TU)); + p2p_noa_attr_len = p2p_noa_attr_len + 4; + + /* NoA Interval (4 bytes) unit: microseconds */ + RTW_PUT_LE32(p2p_noa_attr_ie + p2p_noa_attr_len, (noa_interval * TU)); + p2p_noa_attr_len = p2p_noa_attr_len + 4; + + /* NoA Start Time (4 bytes) unit: microseconds */ + RTW_PUT_LE32(p2p_noa_attr_ie + p2p_noa_attr_len, pmccadapriv->noa_start_time); + if (0) + RTW_INFO("indxe:%d, start_time=0x%02x:0x%02x:0x%02x:0x%02x\n" + , noa_index + , p2p_noa_attr_ie[p2p_noa_attr_len] + , p2p_noa_attr_ie[p2p_noa_attr_len + 1] + , p2p_noa_attr_ie[p2p_noa_attr_len + 2] + , p2p_noa_attr_ie[p2p_noa_attr_len + 3]); + + p2p_noa_attr_len = p2p_noa_attr_len + 4; + rtw_set_ie(ie, _VENDOR_SPECIFIC_IE_, p2p_noa_attr_len, (u8 *)p2p_noa_attr_ie, ie_len); +} + + +/** + * rtw_hal_mcc_update_go_p2p_ie - update go p2p ie(add NoA attribute) + * @padapter: the adapter to be update go p2p ie + */ +static void rtw_hal_mcc_update_go_p2p_ie(PADAPTER padapter) +{ + struct mcc_adapter_priv *pmccadapriv = &padapter->mcc_adapterpriv; + u8 *pos = NULL; + + + /* no noa attribute, build it */ + if (pmccadapriv->p2p_go_noa_ie_len == 0) + rtw_hal_mcc_build_p2p_noa_attr(padapter, pmccadapriv->p2p_go_noa_ie, &pmccadapriv->p2p_go_noa_ie_len); + else { + /* has noa attribut, modify it */ + /* update index */ + pos = pmccadapriv->p2p_go_noa_ie + pmccadapriv->p2p_go_noa_ie_len - 15; + /* 0~255 */ + (*pos) = ((*pos) + 1) % 256; + if (1) + RTW_INFO("indxe:%d\n", (*pos)); + + /* update start time */ + pos = pmccadapriv->p2p_go_noa_ie + pmccadapriv->p2p_go_noa_ie_len - 4; + RTW_PUT_LE32(pos, pmccadapriv->noa_start_time); + if (0) + RTW_INFO("start_time=0x%02x:0x%02x:0x%02x:0x%02x\n" + , ((u8*)(pos))[0] + , ((u8*)(pos))[1] + , ((u8*)(pos))[2] + , ((u8*)(pos))[3]); + + } + + if (0) { + u8 i = 0; + RTW_INFO("p2p_go_noa_ie_len:%d\n", pmccadapriv->p2p_go_noa_ie_len); + + for (i = 0;i < pmccadapriv->p2p_go_noa_ie_len; i++) { + if ((i+1)%8 != 0) + printk("0x%02x ", pmccadapriv->p2p_go_noa_ie[i]); + else + printk("0x%02x\n", pmccadapriv->p2p_go_noa_ie[i]); + } + printk("\n"); + } + update_beacon(padapter, _VENDOR_SPECIFIC_IE_, P2P_OUI, _TRUE); +} + +/** + * rtw_hal_mcc_remove_go_p2p_ie - remove go p2p ie(add NoA attribute) + * @padapter: the adapter to be update go p2p ie + */ +static void rtw_hal_mcc_remove_go_p2p_ie(PADAPTER padapter) +{ + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct mcc_adapter_priv *pmccadapriv = &padapter->mcc_adapterpriv; + + /* chech has noa ie or not */ + if (pmccadapriv->p2p_go_noa_ie_len == 0) + return; + + pmccadapriv->p2p_go_noa_ie_len = 0; + update_beacon(padapter, _VENDOR_SPECIFIC_IE_, P2P_OUI, _TRUE); +} + +/* restore IQK value for all interface */ +void rtw_hal_mcc_restore_iqk_val(PADAPTER padapter) +{ + u8 take_care_iqk = _FALSE; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + _adapter *iface = NULL; + u8 i = 0; + + rtw_hal_get_hwreg(padapter, HW_VAR_CH_SW_NEED_TO_TAKE_CARE_IQK_INFO, &take_care_iqk); + if (take_care_iqk == _TRUE && MCC_EN(padapter)) { + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (iface == NULL) + continue; + + rtw_hal_ch_sw_iqk_info_restore(iface, CH_SW_USE_CASE_MCC); + } + } + + if (0) + dump_iqk_val_table(padapter); +} + +u8 rtw_hal_check_mcc_status(PADAPTER padapter, u8 mcc_status) +{ + struct mcc_obj_priv *pmccobjpriv = &(adapter_to_dvobj(padapter)->mcc_objpriv); + + if (pmccobjpriv->mcc_status & (mcc_status)) + return _TRUE; + else + return _FALSE; +} + +void rtw_hal_set_mcc_status(PADAPTER padapter, u8 mcc_status) +{ + struct mcc_obj_priv *pmccobjpriv = &(adapter_to_dvobj(padapter)->mcc_objpriv); + + pmccobjpriv->mcc_status |= (mcc_status); +} + +void rtw_hal_clear_mcc_status(PADAPTER padapter, u8 mcc_status) +{ + struct mcc_obj_priv *pmccobjpriv = &(adapter_to_dvobj(padapter)->mcc_objpriv); + + pmccobjpriv->mcc_status &= (~mcc_status); +} + +void rtw_hal_mcc_update_switch_channel_policy_table(PADAPTER padapter) +{ + struct registry_priv *registry_par = &padapter->registrypriv; + u8 idx = 0; + + if (registry_par->rtw_mcc_policy_table_idx < 0) + return; + + if (registry_par->rtw_mcc_policy_table_idx >= mcc_max_policy_num) { + RTW_INFO("[MCC] mcc_policy_table_idx error, do not update policy table\n"); + return; + } + + idx = registry_par->rtw_mcc_policy_table_idx; + + if (registry_par->rtw_mcc_duration > 0) + mcc_switch_channel_policy_table[idx][MCC_DURATION_IDX] = registry_par->rtw_mcc_duration; + + if (registry_par->rtw_mcc_tsf_sync_offset > 0) + mcc_switch_channel_policy_table[idx][MCC_TSF_SYNC_OFFSET_IDX] = registry_par->rtw_mcc_tsf_sync_offset; + + if (registry_par->rtw_mcc_start_time_offset > 0) + mcc_switch_channel_policy_table[idx][MCC_START_TIME_OFFSET_IDX] = registry_par->rtw_mcc_start_time_offset; + + if (registry_par->rtw_mcc_interval > 0) + mcc_switch_channel_policy_table[idx][MCC_INTERVAL_IDX] = registry_par->rtw_mcc_interval; + + if (registry_par->rtw_mcc_guard_offset0 >= 0) + mcc_switch_channel_policy_table[idx][MCC_GUARD_OFFSET0_IDX] = registry_par->rtw_mcc_guard_offset0; + + if (registry_par->rtw_mcc_guard_offset1 >= 0) + mcc_switch_channel_policy_table[idx][MCC_GUARD_OFFSET1_IDX] = registry_par->rtw_mcc_guard_offset1; + +} + +static void rtw_hal_config_mcc_switch_channel_setting(PADAPTER padapter) +{ + struct mcc_adapter_priv *pmccadapriv = &padapter->mcc_adapterpriv; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct mcc_obj_priv *pmccobjpriv = &(dvobj->mcc_objpriv); + struct registry_priv *registry_par = &padapter->registrypriv; + u8 interval = pmlmepriv->cur_network.network.Configuration.BeaconPeriod; + u8 i = 0; + s8 mcc_policy_idx = 0; + + rtw_hal_mcc_update_switch_channel_policy_table(padapter); + mcc_policy_idx = registry_par->rtw_mcc_policy_table_idx; + + if (mcc_policy_idx < 0 || mcc_policy_idx >= mcc_max_policy_num) { + pmccobjpriv->policy_index = 0; + RTW_INFO("[MCC] can't find table(%d,%d,%d), use default policy(%d)\n" + , pmccobjpriv->duration, interval, mcc_policy_idx, pmccobjpriv->policy_index); + } else + pmccobjpriv->policy_index = mcc_policy_idx; + + RTW_INFO("[MCC] policy(%d): %d,%d,%d,%d,%d,%d\n" + , pmccobjpriv->policy_index + , mcc_switch_channel_policy_table[pmccobjpriv->policy_index][MCC_DURATION_IDX] + , mcc_switch_channel_policy_table[pmccobjpriv->policy_index][MCC_TSF_SYNC_OFFSET_IDX] + , mcc_switch_channel_policy_table[pmccobjpriv->policy_index][MCC_START_TIME_OFFSET_IDX] + , mcc_switch_channel_policy_table[pmccobjpriv->policy_index][MCC_INTERVAL_IDX] + , mcc_switch_channel_policy_table[pmccobjpriv->policy_index][MCC_GUARD_OFFSET0_IDX] + , mcc_switch_channel_policy_table[pmccobjpriv->policy_index][MCC_GUARD_OFFSET1_IDX]); + +} + +static void rtw_hal_config_mcc_role_setting(PADAPTER padapter) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); + struct mcc_obj_priv *pmccobjpriv = &(pdvobjpriv->mcc_objpriv); + struct mcc_adapter_priv *pmccadapriv = &padapter->mcc_adapterpriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct wlan_network *cur_network = &(pmlmepriv->cur_network); + struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_info *psta = NULL; + struct registry_priv *preg = &padapter->registrypriv; + u8 policy_index = 0; + u8 mcc_duration = 0; + u8 mcc_interval = 0; + + policy_index = pmccobjpriv->policy_index; + mcc_duration = mcc_switch_channel_policy_table[pmccobjpriv->policy_index][MCC_DURATION_IDX] + - mcc_switch_channel_policy_table[pmccobjpriv->policy_index][MCC_GUARD_OFFSET0_IDX] + - mcc_switch_channel_policy_table[pmccobjpriv->policy_index][MCC_GUARD_OFFSET1_IDX]; + mcc_interval = mcc_switch_channel_policy_table[pmccobjpriv->policy_index][MCC_INTERVAL_IDX]; + + /* GO/AP is 1nd order GC/STA is 2nd order */ + switch (pmccadapriv->role) { + case MCC_ROLE_STA: + case MCC_ROLE_GC: + pmccadapriv->order = 1; + pmccadapriv->mcc_duration = mcc_duration; + + switch (pmlmeext->cur_bwmode) { + case CHANNEL_WIDTH_20: + /* + * target tx byte(bytes) = target tx tp(Mbits/sec) * 1024 * 1024 / 8 * (duration(ms) / 1024) + * = target tx tp(Mbits/sec) * 128 * duration(ms) + * note: + * target tx tp(Mbits/sec) * 1024 * 1024 / 8 ==> Mbits to bytes + * duration(ms) / 1024 ==> msec to sec + */ + pmccadapriv->mcc_target_tx_bytes_to_port = preg->rtw_mcc_sta_bw20_target_tx_tp * 128 * pmccadapriv->mcc_duration; + break; + case CHANNEL_WIDTH_40: + pmccadapriv->mcc_target_tx_bytes_to_port = preg->rtw_mcc_sta_bw40_target_tx_tp * 128 * pmccadapriv->mcc_duration; + break; + case CHANNEL_WIDTH_80: + pmccadapriv->mcc_target_tx_bytes_to_port = preg->rtw_mcc_sta_bw80_target_tx_tp * 128 * pmccadapriv->mcc_duration; + break; + case CHANNEL_WIDTH_160: + case CHANNEL_WIDTH_80_80: + RTW_INFO(FUNC_ADPT_FMT": not support bwmode = %d\n" + , FUNC_ADPT_ARG(padapter), pmlmeext->cur_bwmode); + break; + } + + /* assign used mac to avoid affecting RA */ + pmccadapriv->mgmt_queue_macid = MCC_ROLE_STA_GC_MGMT_QUEUE_MACID; + + psta = rtw_get_stainfo(pstapriv, cur_network->network.MacAddress); + if (psta) { + /* combine AP/GO macid and mgmt queue macid to bitmap */ + pmccadapriv->mcc_macid_bitmap = BIT(psta->mac_id) | BIT(pmccadapriv->mgmt_queue_macid); + } else { + RTW_INFO(FUNC_ADPT_FMT":AP/GO station info is NULL\n", FUNC_ADPT_ARG(padapter)); + rtw_warn_on(1); + } + break; + case MCC_ROLE_AP: + case MCC_ROLE_GO: + pmccadapriv->order = 0; + /* total druation value equals interval */ + pmccadapriv->mcc_duration = mcc_interval - mcc_duration; + pmccadapriv->p2p_go_noa_ie_len = 0; /* not NoA attribute at init time */ + + switch (pmlmeext->cur_bwmode) { + case CHANNEL_WIDTH_20: + pmccadapriv->mcc_target_tx_bytes_to_port = preg->rtw_mcc_ap_bw20_target_tx_tp * 128 * pmccadapriv->mcc_duration; + break; + case CHANNEL_WIDTH_40: + pmccadapriv->mcc_target_tx_bytes_to_port = preg->rtw_mcc_ap_bw40_target_tx_tp * 128 * pmccadapriv->mcc_duration; + break; + case CHANNEL_WIDTH_80: + pmccadapriv->mcc_target_tx_bytes_to_port = preg->rtw_mcc_ap_bw80_target_tx_tp * 128 * pmccadapriv->mcc_duration; + break; + case CHANNEL_WIDTH_160: + case CHANNEL_WIDTH_80_80: + RTW_INFO(FUNC_ADPT_FMT": not support bwmode = %d\n" + , FUNC_ADPT_ARG(padapter), pmlmeext->cur_bwmode); + break; + } + + + psta = rtw_get_bcmc_stainfo(padapter); + + if (psta != NULL) + pmccadapriv->mgmt_queue_macid = psta->mac_id; + else { + pmccadapriv->mgmt_queue_macid = MCC_ROLE_SOFTAP_GO_MGMT_QUEUE_MACID; + RTW_INFO(FUNC_ADPT_FMT":bcmc station is NULL, use macid %d\n" + , FUNC_ADPT_ARG(padapter), pmccadapriv->mgmt_queue_macid); + } + + /* combine client macid and mgmt queue macid to bitmap */ + pmccadapriv->mcc_macid_bitmap = (0xff << 8) | BIT(pmccadapriv->mgmt_queue_macid); + break; + default: + RTW_INFO("Unknown role\n"); + rtw_warn_on(1); + break; + } + + pmccobjpriv->iface[pmccadapriv->order] = padapter; + RTW_INFO(FUNC_ADPT_FMT": order:%d, role:%d, mcc duration:%d, target tx bytes:%d, mgmt queue macid:%d, bitmap:0x%02x\n" + , FUNC_ADPT_ARG(padapter), pmccadapriv->order, pmccadapriv->role, pmccadapriv->mcc_duration + , pmccadapriv->mcc_target_tx_bytes_to_port, pmccadapriv->mgmt_queue_macid, pmccadapriv->mcc_macid_bitmap); +} + +static void rtw_hal_clear_mcc_macid(PADAPTER padapter) +{ + u16 media_status_rpt; + struct mcc_adapter_priv *pmccadapriv = &padapter->mcc_adapterpriv; + + switch (pmccadapriv->role) { + case MCC_ROLE_STA: + case MCC_ROLE_GC: + break; + case MCC_ROLE_AP: + case MCC_ROLE_GO: + /* nothing to do */ + break; + default: + RTW_INFO("Unknown role\n"); + rtw_warn_on(1); + break; + } +} +static u8 rtw_hal_decide_mcc_role(PADAPTER padapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + _adapter *iface = NULL; + struct mcc_adapter_priv *pmccadapriv = NULL; + struct wifidirect_info *pwdinfo = NULL; + struct mlme_priv *pmlmepriv = NULL; + u8 ret = _SUCCESS, i = 0; + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (iface == NULL) + continue; + + pmccadapriv = &iface->mcc_adapterpriv; + + if (MLME_IS_GO(iface)) + pmccadapriv->role = MCC_ROLE_GO; + else if (MLME_IS_AP(iface)) + pmccadapriv->role = MCC_ROLE_AP; + else if (MLME_IS_GC(iface)) + pmccadapriv->role = MCC_ROLE_GC; + else if (MLME_IS_STA(iface)) + pmccadapriv->role = MCC_ROLE_STA; + else { + pwdinfo = &iface->wdinfo; + pmlmepriv = &iface->mlmepriv; + + RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(iface)); + RTW_INFO("Unknown:P2P state:%d, mlme state:0x%2x, mlmext info state:0x%02x\n", + pwdinfo->role, pmlmepriv->fw_state, iface->mlmeextpriv.mlmext_info.state); + rtw_warn_on(1); + ret = _FAIL; + goto exit; + } + + if (ret == _SUCCESS) + rtw_hal_config_mcc_role_setting(iface); + } + +exit: + return ret; +} + +static void rtw_hal_init_mcc_parameter(PADAPTER padapter) +{ +} + +static void rtw_hal_construct_CTS(PADAPTER padapter, u8 *pframe, u32 *pLength) +{ + u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + /* frame type, length = 1*/ + set_frame_sub_type(pframe, WIFI_RTS); + + /* frame control flag, length = 1 */ + *(pframe + 1) = 0; + + /* frame duration, length = 2 */ + *(pframe + 2) = 0x00; + *(pframe + 3) = 0x78; + + /* frame recvaddr, length = 6 */ + _rtw_memcpy((pframe + 4), broadcast_addr, ETH_ALEN); + _rtw_memcpy((pframe + 4 + ETH_ALEN), adapter_mac_addr(padapter), ETH_ALEN); + _rtw_memcpy((pframe + 4 + ETH_ALEN*2), adapter_mac_addr(padapter), ETH_ALEN); + *pLength = 22; +} + +u8 rtw_hal_dl_mcc_fw_rsvd_page(_adapter *adapter, u8 *pframe, u16 *index, + u8 tx_desc, u32 page_size, u8 *page_num, u32 *total_pkt_len, + RSVDPAGE_LOC *rsvd_page_loc) +{ + u32 len = 0; + _adapter *iface = NULL; + struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); + struct mcc_obj_priv *pmccobjpriv = &(dvobj->mcc_objpriv); + struct mlme_ext_info *pmlmeinfo = NULL; + struct mlme_ext_priv *pmlmeext = NULL; + u8 ret = _SUCCESS, i = 0, order = 0, CurtPktPageNum = 0; + u8 bssid[ETH_ALEN] = {0}; + + /* check proccess mcc start setting */ + if (!rtw_hal_check_mcc_status(adapter, MCC_STATUS_PROCESS_MCC_START_SETTING)) { + ret = _FAIL; + goto exit; + } + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (iface == NULL) + continue; + + order = iface->mcc_adapterpriv.order; + dvobj->mcc_objpriv.mcc_loc_rsvd_paga[order] = *page_num; + + switch (iface->mcc_adapterpriv.role) { + case MCC_ROLE_STA: + case MCC_ROLE_GC: + /* Build NULL DATA */ + RTW_INFO("LocNull(order:%d): %d\n" + , order, dvobj->mcc_objpriv.mcc_loc_rsvd_paga[order]); + len = 0; + pmlmeext = &iface->mlmeextpriv; + pmlmeinfo = &pmlmeext->mlmext_info; + + _rtw_memcpy(bssid, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); + rtw_hal_construct_NullFunctionData(iface + , &pframe[*index], &len, bssid, _FALSE, 0, 0, _FALSE); + rtw_hal_fill_fake_txdesc(iface, &pframe[*index-tx_desc], + len, _FALSE, _FALSE, _FALSE); + + CurtPktPageNum = (u8)PageNum(tx_desc + len, page_size); + *page_num += CurtPktPageNum; + *index += (CurtPktPageNum * page_size); + *total_pkt_len = *index + len; + break; + case MCC_ROLE_AP: + /* Bulid CTS */ + RTW_INFO("LocCTS(order:%d): %d\n" + , order, dvobj->mcc_objpriv.mcc_loc_rsvd_paga[order]); + + len = 0; + rtw_hal_construct_CTS(iface, &pframe[*index], &len); + rtw_hal_fill_fake_txdesc(iface, &pframe[*index-tx_desc], + len, _FALSE, _FALSE, _FALSE); + + CurtPktPageNum = (u8)PageNum(tx_desc + len, page_size); + *page_num += CurtPktPageNum; + *index += (CurtPktPageNum * page_size); + *total_pkt_len = *index + len; + break; + case MCC_ROLE_GO: + /* To DO */ + break; + } + } +exit: + return ret; +} + +/* +* 1. Download MCC rsvd page +* 2. Re-Download beacon after download rsvd page +*/ +static void rtw_hal_set_fw_mcc_rsvd_page(PADAPTER padapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct mcc_adapter_priv *pmccadapriv = &padapter->mcc_adapterpriv; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + PADAPTER port0_iface = dvobj_get_port0_adapter(dvobj); + PADAPTER iface = NULL; + struct mcc_obj_priv *pmccobjpriv = &(dvobj->mcc_objpriv); + u8 mstatus = RT_MEDIA_CONNECT, i = 0; + + RTW_INFO(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); + + rtw_hal_set_hwreg(port0_iface, HW_VAR_H2C_FW_JOINBSSRPT, (u8 *)(&mstatus)); + + /* Re-Download beacon */ + for (i = 0; i < dvobj->iface_nums; i++) { + iface = pmccobjpriv->iface[i]; + pmccadapriv = &iface->mcc_adapterpriv; + if (pmccadapriv->role == MCC_ROLE_AP + || pmccadapriv->role == MCC_ROLE_GO) + tx_beacon_hdl(iface, NULL); + } +} + +static void rtw_hal_set_mcc_rsvdpage_cmd(_adapter *padapter) +{ + u8 cmd[H2C_MCC_LOCATION_LEN] = {0}, i = 0, order = 0; + _adapter *iface = NULL; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct mcc_obj_priv *pmccobjpriv = &(dvobj->mcc_objpriv); + + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (iface == NULL) + continue; + + order = iface->mcc_adapterpriv.order; + if (order >= H2C_MCC_LOCATION_LEN) { + RTW_INFO(FUNC_ADPT_FMT" only support 3 interface at most(%d)\n" + , FUNC_ADPT_ARG(padapter), order); + continue; + } + + SET_H2CCMD_MCC_RSVDPAGE_LOC((cmd + order), (pmccobjpriv->mcc_loc_rsvd_paga[order])); + } + +#ifdef CONFIG_MCC_MODE_DEBUG + RTW_INFO("=========================\n"); + RTW_INFO("MCC RSVD PAGE LOC:\n"); + for (i = 0; i < H2C_MCC_LOCATION_LEN; i++) + pr_dbg("0x%x ", cmd[i]); + pr_dbg("\n"); + RTW_INFO("=========================\n"); +#endif /* CONFIG_MCC_MODE_DEBUG */ + + rtw_hal_fill_h2c_cmd(padapter, H2C_MCC_LOCATION, H2C_MCC_LOCATION_LEN, cmd); +} + +static void rtw_hal_set_mcc_noa_cmd(PADAPTER padapter) +{ + struct mcc_adapter_priv *pmccadapriv = &padapter->mcc_adapterpriv; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct mcc_obj_priv *pmccobjpriv = &(dvobj->mcc_objpriv); + u8 cmd[H2C_MCC_NOA_PARAM_LEN] = {0}; + u8 policy_idx = pmccobjpriv->policy_index; + u8 noa_fw_eable = 1; + u8 noa_tsf_sync_offset = mcc_switch_channel_policy_table[policy_idx][MCC_TSF_SYNC_OFFSET_IDX]; + u8 noa_start_time_offset = mcc_switch_channel_policy_table[policy_idx][MCC_START_TIME_OFFSET_IDX]; + u8 noa_interval = mcc_switch_channel_policy_table[policy_idx][MCC_INTERVAL_IDX]; + u8 guard_offset0 = mcc_switch_channel_policy_table[policy_idx][MCC_GUARD_OFFSET0_IDX]; + u8 guard_offset1 = mcc_switch_channel_policy_table[policy_idx][MCC_GUARD_OFFSET1_IDX]; + u8 swchannel_early_time = MCC_SWCH_FW_EARLY_TIME; + u8 i = 0; + + /* FW set NOA enable */ + SET_H2CCMD_MCC_NOA_FW_EN(cmd, noa_fw_eable); + /* TSF Sync offset */ + SET_H2CCMD_MCC_NOA_TSF_SYNC_OFFSET(cmd, noa_tsf_sync_offset); + /* NoA start time offset */ + SET_H2CCMD_MCC_NOA_START_TIME(cmd, (noa_start_time_offset + guard_offset0)); + /* NoA interval */ + SET_H2CCMD_MCC_NOA_INTERVAL(cmd, noa_interval); + /* Early time to inform driver by C2H before switch channel */ + SET_H2CCMD_MCC_EARLY_TIME(cmd, swchannel_early_time); + +#ifdef CONFIG_MCC_MODE_DEBUG + RTW_INFO("=========================\n"); + RTW_INFO("NoA:\n"); + for (i = 0; i < H2C_MCC_NOA_PARAM_LEN; i++) + pr_dbg("0x%x ", cmd[i]); + pr_dbg("\n"); + RTW_INFO("=========================\n"); +#endif /* CONFIG_MCC_MODE_DEBUG */ + + rtw_hal_fill_h2c_cmd(padapter, H2C_MCC_NOA_PARAM, H2C_MCC_NOA_PARAM_LEN, cmd); +} + +static void rtw_hal_set_mcc_IQK_offload_cmd(PADAPTER padapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct mcc_obj_priv *pmccobjpriv = &(dvobj->mcc_objpriv); + struct mcc_adapter_priv *pmccadapriv = NULL; + _adapter *iface = NULL; + u8 cmd[H2C_MCC_IQK_PARAM_LEN] = {0}, bready = 0, i = 0, order = 0; + u16 TX_X = 0, TX_Y = 0, RX_X = 0, RX_Y = 0; + u8 total_rf_path = GET_HAL_DATA(padapter)->NumTotalRFPath; + u8 rf_path_idx = 0, last_order = MAX_MCC_NUM - 1, last_rf_path_index = total_rf_path - 1; + + /* by order, last order & last_rf_path_index must set ready bit = 1 */ + for (i = 0; i < dvobj->iface_nums; i++) { + iface = pmccobjpriv->iface[i]; + if (iface == NULL) + continue; + + pmccadapriv = &iface->mcc_adapterpriv; + order = pmccadapriv->order; + + for (rf_path_idx = 0; rf_path_idx < total_rf_path; rf_path_idx ++) { + + _rtw_memset(cmd, 0, H2C_MCC_IQK_PARAM_LEN); + TX_X = pmccadapriv->mcc_iqk_arr[rf_path_idx].TX_X & 0x7ff;/* [10:0] */ + TX_Y = pmccadapriv->mcc_iqk_arr[rf_path_idx].TX_Y & 0x7ff;/* [10:0] */ + RX_X = pmccadapriv->mcc_iqk_arr[rf_path_idx].RX_X & 0x3ff;/* [9:0] */ + RX_Y = pmccadapriv->mcc_iqk_arr[rf_path_idx].RX_Y & 0x3ff;/* [9:0] */ + + /* ready or not */ + if (order == last_order && rf_path_idx == last_rf_path_index) + bready = 1; + else + bready = 0; + + SET_H2CCMD_MCC_IQK_READY(cmd, bready); + SET_H2CCMD_MCC_IQK_ORDER(cmd, order); + SET_H2CCMD_MCC_IQK_PATH(cmd, rf_path_idx); + + /* fill RX_X[7:0] to (cmd+1)[7:0] bitlen=8 */ + SET_H2CCMD_MCC_IQK_RX_L(cmd, (u8)(RX_X & 0xff)); + /* fill RX_X[9:8] to (cmd+2)[1:0] bitlen=2 */ + SET_H2CCMD_MCC_IQK_RX_M1(cmd, (u8)((RX_X >> 8) & 0x03)); + /* fill RX_Y[5:0] to (cmd+2)[7:2] bitlen=6 */ + SET_H2CCMD_MCC_IQK_RX_M2(cmd, (u8)(RX_Y & 0x3f)); + /* fill RX_Y[9:6] to (cmd+3)[3:0] bitlen=4 */ + SET_H2CCMD_MCC_IQK_RX_H(cmd, (u8)((RX_Y >> 6) & 0x0f)); + + + /* fill TX_X[7:0] to (cmd+4)[7:0] bitlen=8 */ + SET_H2CCMD_MCC_IQK_TX_L(cmd, (u8)(TX_X & 0xff)); + /* fill TX_X[10:8] to (cmd+5)[2:0] bitlen=3 */ + SET_H2CCMD_MCC_IQK_TX_M1(cmd, (u8)((TX_X >> 8) & 0x07)); + /* fill TX_Y[4:0] to (cmd+5)[7:3] bitlen=5 */ + SET_H2CCMD_MCC_IQK_TX_M2(cmd, (u8)(TX_Y & 0x1f)); + /* fill TX_Y[10:5] to (cmd+6)[5:0] bitlen=6 */ + SET_H2CCMD_MCC_IQK_TX_H(cmd, (u8)((TX_Y >> 5) & 0x3f)); + +#ifdef CONFIG_MCC_MODE_DEBUG + RTW_INFO("=========================\n"); + RTW_INFO(FUNC_ADPT_FMT" IQK:\n", FUNC_ADPT_ARG(iface)); + RTW_INFO("TX_X: 0x%02x\n", TX_X); + RTW_INFO("TX_Y: 0x%02x\n", TX_Y); + RTW_INFO("RX_X: 0x%02x\n", RX_X); + RTW_INFO("RX_Y: 0x%02x\n", RX_Y); + RTW_INFO("cmd[0]:0x%02x\n", cmd[0]); + RTW_INFO("cmd[1]:0x%02x\n", cmd[1]); + RTW_INFO("cmd[2]:0x%02x\n", cmd[2]); + RTW_INFO("cmd[3]:0x%02x\n", cmd[3]); + RTW_INFO("cmd[4]:0x%02x\n", cmd[4]); + RTW_INFO("cmd[5]:0x%02x\n", cmd[5]); + RTW_INFO("cmd[6]:0x%02x\n", cmd[6]); + RTW_INFO("=========================\n"); +#endif /* CONFIG_MCC_MODE_DEBUG */ + + rtw_hal_fill_h2c_cmd(padapter, H2C_MCC_IQK_PARAM, H2C_MCC_IQK_PARAM_LEN, cmd); + } + } +} + + +static void rtw_hal_set_mcc_macid_cmd(PADAPTER padapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct mcc_adapter_priv *pmccadapriv = NULL; + _adapter *iface = NULL; + u8 cmd[H2C_MCC_MACID_BITMAP_LEN] = {0}, i = 0, order = 0; + u16 bitmap = 0; + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (iface == NULL) + continue; + + pmccadapriv = &iface->mcc_adapterpriv; + order = pmccadapriv->order; + bitmap = pmccadapriv->mcc_macid_bitmap; + + if (order >= (H2C_MCC_MACID_BITMAP_LEN/2)) { + RTW_INFO(FUNC_ADPT_FMT" only support 3 interface at most(%d)\n" + , FUNC_ADPT_ARG(padapter), order); + continue; + } + SET_H2CCMD_MCC_MACID_BITMAP_L((cmd + order * 2), (u8)(bitmap & 0xff)); + SET_H2CCMD_MCC_MACID_BITMAP_H((cmd + order * 2), (u8)((bitmap >> 8) & 0xff)); + } + +#ifdef CONFIG_MCC_MODE_DEBUG + RTW_INFO("=========================\n"); + RTW_INFO("MACID BITMAP: "); + for (i = 0; i < H2C_MCC_MACID_BITMAP_LEN; i++) + pr_dbg("0x%x ", cmd[i]); + pr_dbg("\n"); + RTW_INFO("=========================\n"); +#endif /* CONFIG_MCC_MODE_DEBUG */ + rtw_hal_fill_h2c_cmd(padapter, H2C_MCC_MACID_BITMAP, H2C_MCC_MACID_BITMAP_LEN, cmd); +} + +static void rtw_hal_set_mcc_ctrl_cmd(PADAPTER padapter, u8 stop) +{ + u8 cmd[H2C_MCC_CTRL_LEN] = {0}, i = 0; + u8 order = 0, totalnum = 0, chidx = 0, bw = 0, bw40sc = 0, bw80sc = 0; + u8 duration = 0, role = 0, incurch = 0, rfetype = 0, distxnull = 0, c2hrpt = 0, chscan = 0; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct mcc_obj_priv *pmccobjpriv = &(dvobj->mcc_objpriv); + struct mlme_ext_priv *pmlmeext = NULL; + struct mlme_ext_info *pmlmeinfo = NULL; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + _adapter *iface = NULL; + + RTW_INFO(FUNC_ADPT_FMT": stop=%d\n", FUNC_ADPT_ARG(padapter), stop); + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = pmccobjpriv->iface[i]; + if (iface == NULL) + continue; + + if (stop) { + if (iface != padapter) + continue; + } + + + order = iface->mcc_adapterpriv.order; + if (!stop) + totalnum = dvobj->iface_nums; + else + totalnum = 0xff; /* 0xff means stop */ + + pmlmeext = &iface->mlmeextpriv; + chidx = pmlmeext->cur_channel; + bw = pmlmeext->cur_bwmode; + bw40sc = pmlmeext->cur_ch_offset; + + /* decide 80 band width offset */ + if (bw == CHANNEL_WIDTH_80) { + u8 center_ch = rtw_get_center_ch(chidx, bw, bw40sc); + + if (center_ch > chidx) + bw80sc = HAL_PRIME_CHNL_OFFSET_LOWER; + else if (center_ch < chidx) + bw80sc = HAL_PRIME_CHNL_OFFSET_UPPER; + else + bw80sc = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + } else + bw80sc = HAL_PRIME_CHNL_OFFSET_DONT_CARE; + + duration = iface->mcc_adapterpriv.mcc_duration; + role = iface->mcc_adapterpriv.role; + + incurch = _FALSE; + + if (IS_HARDWARE_TYPE_8812(padapter)) + rfetype = pHalData->rfe_type; /* RFETYPE (only for 8812)*/ + else + rfetype = 0; + + /* STA/GC TX NULL data to inform AP/GC for ps mode */ + switch (role) { + case MCC_ROLE_GO: + case MCC_ROLE_AP: + distxnull = MCC_DISABLE_TX_NULL; + break; + case MCC_ROLE_GC: + case MCC_ROLE_STA: + distxnull = MCC_ENABLE_TX_NULL; + break; + } + + c2hrpt = MCC_C2H_REPORT_ALL_STATUS; + chscan = MCC_CHIDX; + + SET_H2CCMD_MCC_CTRL_ORDER(cmd, order); + SET_H2CCMD_MCC_CTRL_TOTALNUM(cmd, totalnum); + SET_H2CCMD_MCC_CTRL_CHIDX(cmd, chidx); + SET_H2CCMD_MCC_CTRL_BW(cmd, bw); + SET_H2CCMD_MCC_CTRL_BW40SC(cmd, bw40sc); + SET_H2CCMD_MCC_CTRL_BW80SC(cmd, bw80sc); + SET_H2CCMD_MCC_CTRL_DURATION(cmd, duration); + SET_H2CCMD_MCC_CTRL_ROLE(cmd, role); + SET_H2CCMD_MCC_CTRL_INCURCH(cmd, incurch); + SET_H2CCMD_MCC_CTRL_RFETYPE(cmd, rfetype); + SET_H2CCMD_MCC_CTRL_DISTXNULL(cmd, distxnull); + SET_H2CCMD_MCC_CTRL_C2HRPT(cmd, c2hrpt); + SET_H2CCMD_MCC_CTRL_CHSCAN(cmd, chscan); + +#ifdef CONFIG_MCC_MODE_DEBUG + RTW_INFO("=========================\n"); + RTW_INFO(FUNC_ADPT_FMT" MCC INFO:\n", FUNC_ADPT_ARG(iface)); + RTW_INFO("cmd[0]:0x%02x\n", cmd[0]); + RTW_INFO("cmd[1]:0x%02x\n", cmd[1]); + RTW_INFO("cmd[2]:0x%02x\n", cmd[2]); + RTW_INFO("cmd[3]:0x%02x\n", cmd[3]); + RTW_INFO("cmd[4]:0x%02x\n", cmd[4]); + RTW_INFO("cmd[5]:0x%02x\n", cmd[5]); + RTW_INFO("cmd[6]:0x%02x\n", cmd[6]); + RTW_INFO("=========================\n"); +#endif /* CONFIG_MCC_MODE_DEBUG */ + + rtw_hal_fill_h2c_cmd(padapter, H2C_MCC_CTRL, H2C_MCC_CTRL_LEN, cmd); + } +} + +static u8 rtw_hal_set_mcc_start_setting(PADAPTER padapter, u8 status) +{ + u8 ret = _SUCCESS; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); + + if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { + rtw_warn_on(1); + RTW_INFO("PS mode is not active before start mcc, force exit ps mode\n"); + LeaveAllPowerSaveModeDirect(padapter); + } + + if (dvobj->iface_nums > MAX_MCC_NUM) { + RTW_INFO("%s: current iface num(%d) > MAX_MCC_NUM(%d)\n", __func__, dvobj->iface_nums, MAX_MCC_NUM); + ret = _FAIL; + goto exit; + } + + /* configure mcc switch channel setting */ + rtw_hal_config_mcc_switch_channel_setting(padapter); + + if (rtw_hal_decide_mcc_role(padapter) == _FAIL) { + ret = _FAIL; + goto exit; + } + + /* set mcc status to indicate process mcc start setting */ + rtw_hal_set_mcc_status(padapter, MCC_STATUS_PROCESS_MCC_START_SETTING); + + /* only download rsvd page for connect */ + if (status == MCC_SETCMD_STATUS_START_CONNECT) { + /* download mcc rsvd page */ + rtw_hal_set_fw_mcc_rsvd_page(padapter); + rtw_hal_set_mcc_rsvdpage_cmd(padapter); + } + + /* configure NoA setting */ + rtw_hal_set_mcc_noa_cmd(padapter); + + /* IQK value offload */ + rtw_hal_set_mcc_IQK_offload_cmd(padapter); + + /* set mac id to fw */ + rtw_hal_set_mcc_macid_cmd(padapter); + + /* set mcc parameter */ + rtw_hal_set_mcc_ctrl_cmd(padapter, _FALSE); + +exit: + return ret; +} + +static void rtw_hal_set_mcc_stop_setting(PADAPTER padapter, u8 status) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + _adapter *iface = NULL; + u8 i = 0; + /* + * when adapter disconnect, stop mcc mod + * total=0xf means stop mcc mode + */ + + switch (status) { + default: + /* let fw switch to other interface channel */ + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (iface == NULL) + continue; + /* use other interface to set cmd */ + if (iface != padapter) { + rtw_hal_set_mcc_ctrl_cmd(iface, _TRUE); + break; + } + } + break; + } +} + +static void rtw_hal_mcc_status_hdl(PADAPTER padapter, u8 status) +{ + switch (status) { + case MCC_SETCMD_STATUS_STOP_DISCONNECT: + rtw_hal_clear_mcc_status(padapter, MCC_STATUS_NEED_MCC | MCC_STATUS_DOING_MCC); + break; + case MCC_SETCMD_STATUS_STOP_SCAN_START: + rtw_hal_set_mcc_status(padapter, MCC_STATUS_NEED_MCC); + rtw_hal_clear_mcc_status(padapter, MCC_STATUS_DOING_MCC); + break; + + case MCC_SETCMD_STATUS_START_CONNECT: + case MCC_SETCMD_STATUS_START_SCAN_DONE: + rtw_hal_set_mcc_status(padapter, MCC_STATUS_NEED_MCC | MCC_STATUS_DOING_MCC); + break; + default: + RTW_INFO(FUNC_ADPT_FMT" error status(%d)\n", FUNC_ADPT_ARG(padapter), status); + break; + } +} + +static void rtw_hal_mcc_stop_posthdl(PADAPTER padapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + _adapter *iface = NULL; + u8 i = 0; + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (iface == NULL) + continue; + /* release network queue */ + rtw_netif_wake_queue(iface->pnetdev); + iface->mcc_adapterpriv.mcc_tx_bytes_from_kernel = 0; + iface->mcc_adapterpriv.mcc_last_tx_bytes_from_kernel = 0; + iface->mcc_adapterpriv.mcc_tx_bytes_to_port = 0; + + if (iface->mcc_adapterpriv.role == MCC_ROLE_GO) + rtw_hal_mcc_remove_go_p2p_ie(iface); + } +} + +static void rtw_hal_mcc_start_posthdl(PADAPTER padapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + _adapter *iface = NULL; + u8 i = 0; + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (iface == NULL) + continue; + iface->mcc_adapterpriv.mcc_tx_bytes_from_kernel = 0; + iface->mcc_adapterpriv.mcc_last_tx_bytes_from_kernel = 0; + iface->mcc_adapterpriv.mcc_tx_bytes_to_port = 0; + } +} + +/* + * rtw_hal_set_mcc_setting - set mcc setting + * @padapter: currnet padapter to stop/start MCC + * @stop: stop mcc or not + * @return val: 1 for SUCCESS, 0 for fail + */ +static u8 rtw_hal_set_mcc_setting(PADAPTER padapter, u8 status) +{ + u8 ret = _FAIL; + struct mcc_obj_priv *pmccobjpriv = &(adapter_to_dvobj(padapter)->mcc_objpriv); + u8 stop = (status < MCC_SETCMD_STATUS_START_CONNECT) ? _TRUE : _FALSE; + u32 start_time = rtw_get_current_time(); + + RTW_INFO("===> "FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); + + rtw_sctx_init(&pmccobjpriv->mcc_sctx, MCC_EXPIRE_TIME); + pmccobjpriv->mcc_c2h_status = MCC_RPT_MAX; + + if (stop == _FALSE) { + /* handle mcc start */ + if (rtw_hal_set_mcc_start_setting(padapter, status) == _FAIL) + goto exit; + + /* wait for C2H */ + if (!rtw_sctx_wait(&pmccobjpriv->mcc_sctx, __func__)) + RTW_INFO(FUNC_ADPT_FMT": wait for mcc start C2H time out\n", FUNC_ADPT_ARG(padapter)); + else + ret = _SUCCESS; + + if (ret == _SUCCESS) { + RTW_INFO(FUNC_ADPT_FMT": mcc start sucecssfully\n", FUNC_ADPT_ARG(padapter)); + rtw_hal_mcc_start_posthdl(padapter); + } + } else { + + /* set mcc status to indicate process mcc start setting */ + rtw_hal_set_mcc_status(padapter, MCC_STATUS_PROCESS_MCC_STOP_SETTING); + + /* handle mcc stop */ + rtw_hal_set_mcc_stop_setting(padapter, status); + + /* wait for C2H */ + if (!rtw_sctx_wait(&pmccobjpriv->mcc_sctx, __func__)) + RTW_INFO(FUNC_ADPT_FMT": wait for mcc stop C2H time out\n", FUNC_ADPT_ARG(padapter)); + else { + ret = _SUCCESS; + rtw_hal_mcc_stop_posthdl(padapter); + } + } + +exit: + + rtw_hal_mcc_status_hdl(padapter, status); + /* clear mcc status */ + rtw_hal_clear_mcc_status(padapter + , MCC_STATUS_PROCESS_MCC_START_SETTING | MCC_STATUS_PROCESS_MCC_STOP_SETTING); + + RTW_INFO(FUNC_ADPT_FMT" in %dms <===\n" + , FUNC_ADPT_ARG(padapter), rtw_get_passing_time_ms(start_time)); + return ret; +} + +/** + * rtw_hal_mcc_check_case_not_limit_traffic - handler flow ctrl for special case + * @cur_iface: fw stay channel setting of this iface + * @next_iface: fw will swich channel setting of this iface + */ +static void rtw_hal_mcc_check_case_not_limit_traffic(PADAPTER cur_iface, PADAPTER next_iface) +{ + u8 cur_bw = cur_iface->mlmeextpriv.cur_bwmode; + u8 next_bw = next_iface->mlmeextpriv.cur_bwmode; + + /* for both interface are VHT80, doesn't limit_traffic according to iperf results */ + if (cur_bw == CHANNEL_WIDTH_80 && next_bw == CHANNEL_WIDTH_80) { + cur_iface->mcc_adapterpriv.mcc_tp_limit = _FALSE; + next_iface->mcc_adapterpriv.mcc_tp_limit = _FALSE; + } +} + + +/** + * rtw_hal_mcc_sw_ch_fw_notify_hdl - handler flow ctrl + */ +static void rtw_hal_mcc_sw_ch_fw_notify_hdl(PADAPTER padapter) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); + struct mcc_obj_priv *pmccobjpriv = &(pdvobjpriv->mcc_objpriv); + struct mcc_adapter_priv *cur_mccadapriv = NULL, *next_mccadapriv = NULL; + _adapter *iface = NULL, *cur_iface = NULL, *next_iface = NULL; + struct registry_priv *preg = &padapter->registrypriv; + u8 cur_op_ch = pdvobjpriv->oper_channel; + u8 i = 0, iface_num = pdvobjpriv->iface_nums, cur_order = 0, next_order = 0; + static u8 cnt = 1; + u32 single_tx_cri = preg->rtw_mcc_single_tx_cri; + + for (i = 0; i < iface_num; i++) { + iface = pdvobjpriv->padapters[i]; + if (cur_op_ch == iface->mlmeextpriv.cur_channel) { + cur_iface = iface; + cur_mccadapriv = &cur_iface->mcc_adapterpriv; + cur_order = cur_mccadapriv->order; + next_order = (cur_order + 1) % iface_num; + next_iface = pmccobjpriv->iface[next_order]; + next_mccadapriv = &next_iface->mcc_adapterpriv; + break; + } + } + + /* check other interface tx busy traffic or not under every 2 switch channel notify(Mbits/100ms) */ + if (cnt == 2) { + cur_mccadapriv->mcc_tp = (cur_mccadapriv->mcc_tx_bytes_from_kernel + - cur_mccadapriv->mcc_last_tx_bytes_from_kernel) * 10 * 8 / 1024 / 1024; + cur_mccadapriv->mcc_last_tx_bytes_from_kernel = cur_mccadapriv->mcc_tx_bytes_from_kernel; + + next_mccadapriv->mcc_tp = (next_mccadapriv->mcc_tx_bytes_from_kernel + - next_mccadapriv->mcc_last_tx_bytes_from_kernel) * 10 * 8 / 1024 / 1024; + next_mccadapriv->mcc_last_tx_bytes_from_kernel = next_mccadapriv->mcc_tx_bytes_from_kernel; + + cnt = 1; + } else + cnt = 2; + + /* check single TX or cuncurrnet TX */ + if (next_mccadapriv->mcc_tp < single_tx_cri) { + /* single TX, does not stop */ + cur_mccadapriv->mcc_tx_stop = _FALSE; + cur_mccadapriv->mcc_tp_limit = _FALSE; + } else { + /* concurrent TX, stop */ + cur_mccadapriv->mcc_tx_stop = _TRUE; + cur_mccadapriv->mcc_tp_limit = _TRUE; + } + + if (cur_mccadapriv->mcc_tp < single_tx_cri) { + next_mccadapriv->mcc_tx_stop = _FALSE; + next_mccadapriv->mcc_tp_limit = _FALSE; + } else { + next_mccadapriv->mcc_tx_stop = _FALSE; + next_mccadapriv->mcc_tp_limit = _TRUE; + next_mccadapriv->mcc_tx_bytes_to_port = 0; + } + + /* stop current iface kernel queue or not */ + if (cur_mccadapriv->mcc_tx_stop) + rtw_netif_stop_queue(cur_iface->pnetdev); + else + rtw_netif_wake_queue(cur_iface->pnetdev); + + /* stop next iface kernel queue or not */ + if (next_mccadapriv->mcc_tx_stop) + rtw_netif_stop_queue(next_iface->pnetdev); + else + rtw_netif_wake_queue(next_iface->pnetdev); + + /* start xmit tasklet */ + rtw_os_xmit_schedule(next_iface); + + rtw_hal_mcc_check_case_not_limit_traffic(cur_iface, next_iface); + + if (0) { + RTW_INFO("order:%d, mcc_tx_stop:%d, mcc_tp:%d\n", + cur_mccadapriv->order, cur_mccadapriv->mcc_tx_stop, cur_mccadapriv->mcc_tp); + dump_os_queue(0, cur_iface); + RTW_INFO("order:%d, mcc_tx_stop:%d, mcc_tp:%d\n", + next_mccadapriv->order, next_mccadapriv->mcc_tx_stop, next_mccadapriv->mcc_tp); + dump_os_queue(0, next_iface); + } +} + +static void rtw_hal_mcc_update_noa_start_time_hdl(PADAPTER padapter, u8 buflen, u8 *tmpBuf) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); + struct mcc_obj_priv *pmccobjpriv = &(pdvobjpriv->mcc_objpriv); + struct mcc_adapter_priv *pmccadapriv = NULL; + PADAPTER iface = NULL; + u8 i = 0; + u8 policy_idx = pmccobjpriv->policy_index; + u8 noa_tsf_sync_offset = mcc_switch_channel_policy_table[policy_idx][MCC_TSF_SYNC_OFFSET_IDX]; + u8 noa_start_time_offset = mcc_switch_channel_policy_table[policy_idx][MCC_START_TIME_OFFSET_IDX]; + + for (i = 0; i < pdvobjpriv->iface_nums; i++) { + iface = pdvobjpriv->padapters[i]; + if (iface == NULL) + continue; + + pmccadapriv = &iface->mcc_adapterpriv; + /* GO & channel match */ + if (pmccadapriv->role == MCC_ROLE_GO) { + /* convert GO TBTT from FW to noa_start_time(TU convert to mircosecond) */ + pmccadapriv->noa_start_time = RTW_GET_LE32(tmpBuf + 2) + noa_start_time_offset * TU; + + if (0) { + RTW_INFO("TBTT:0x%02x\n", RTW_GET_LE32(tmpBuf + 2)); + RTW_INFO("noa_tsf_sync_offset:%d, noa_start_time_offset:%d\n", noa_tsf_sync_offset, noa_start_time_offset); + RTW_INFO(FUNC_ADPT_FMT"buf=0x%02x:0x%02x:0x%02x:0x%02x, noa_start_time=0x%02x\n" + , FUNC_ADPT_ARG(iface) + , tmpBuf[2] + , tmpBuf[3] + , tmpBuf[4] + , tmpBuf[5] + ,pmccadapriv->noa_start_time); + } + + rtw_hal_mcc_update_go_p2p_ie(iface); + + break; + } + } + +} + +/** + * rtw_hal_mcc_c2h_handler - mcc c2h handler + */ +void rtw_hal_mcc_c2h_handler(PADAPTER padapter, u8 buflen, u8 *tmpBuf) +{ + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); + struct mcc_obj_priv *pmccobjpriv = &(adapter_to_dvobj(padapter)->mcc_objpriv); + struct mcc_adapter_priv *pmccadapriv = &padapter->mcc_adapterpriv; + struct submit_ctx *mcc_sctx = &pmccobjpriv->mcc_sctx; + _irqL irqL; + + /* RTW_INFO("[length]=%d, [C2H data]="MAC_FMT"\n", buflen, MAC_ARG(tmpBuf)); */ + /* To avoid reg is set, but driver recive c2h to set wrong oper_channel */ + if (MCC_RPT_STOPMCC == pmccobjpriv->mcc_c2h_status) { + RTW_INFO(FUNC_ADPT_FMT" MCC alread stops return\n", FUNC_ADPT_ARG(padapter)); + return; + } + + pmccobjpriv->mcc_c2h_status = tmpBuf[0]; + switch (pmccobjpriv->mcc_c2h_status) { + case MCC_RPT_SUCCESS: + pdvobjpriv->oper_channel = tmpBuf[1]; + _enter_critical_bh(&pmccobjpriv->mcc_lock, &irqL); + pmccobjpriv->cur_mcc_success_cnt++; + _exit_critical_bh(&pmccobjpriv->mcc_lock, &irqL); + break; + case MCC_RPT_TXNULL_FAIL: + RTW_INFO("[MCC] TXNULL FAIL\n"); + break; + case MCC_RPT_STOPMCC: + RTW_INFO("[MCC] MCC stop (time:%d)\n", rtw_get_current_time()); + pmccobjpriv->mcc_c2h_status = MCC_RPT_STOPMCC; + rtw_sctx_done(&mcc_sctx); + break; + case MCC_RPT_READY: + _enter_critical_bh(&pmccobjpriv->mcc_lock, &irqL); + /* initialize counter & time */ + pmccobjpriv->mcc_launch_time = rtw_get_current_time(); + pmccobjpriv->mcc_c2h_status = MCC_RPT_READY; + pmccobjpriv->cur_mcc_success_cnt = 0; + pmccobjpriv->prev_mcc_success_cnt = 0; + pmccobjpriv->mcc_tolerance_time = MCC_TOLERANCE_TIME; + _exit_critical_bh(&pmccobjpriv->mcc_lock, &irqL); + + RTW_INFO("[MCC] MCC ready (time:%d)\n", pmccobjpriv->mcc_launch_time); + rtw_sctx_done(&mcc_sctx); + break; + case MCC_RPT_SWICH_CHANNEL_NOTIFY: + pdvobjpriv->oper_channel = tmpBuf[1]; + rtw_hal_mcc_sw_ch_fw_notify_hdl(padapter); + break; + case MCC_RPT_UPDATE_NOA_START_TIME: + rtw_hal_mcc_update_noa_start_time_hdl(padapter, buflen, tmpBuf); + break; + default: + /* RTW_INFO("[MCC] Other MCC status(%d)\n", pmccobjpriv->mcc_c2h_status); */ + break; + } +} + + +/** + * rtw_hal_mcc_sw_status_check - check mcc swich channel status + * @padapter: primary adapter + */ +void rtw_hal_mcc_sw_status_check(PADAPTER padapter) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct mcc_obj_priv *pmccobjpriv = &(dvobj->mcc_objpriv); + struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(dvobj); + u8 cur_cnt = 0, prev_cnt = 0, diff_cnt = 0, check_ret = _FAIL; + _irqL irqL; + +/* #define MCC_RESTART 1 */ + + if (!MCC_EN(padapter)) + return; + + _enter_critical_mutex(&pmccobjpriv->mcc_mutex, NULL); + + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) { + + if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) { + rtw_warn_on(1); + RTW_INFO("PS mode is not active under mcc, force exit ps mode\n"); + LeaveAllPowerSaveModeDirect(padapter); + } + + if (rtw_get_passing_time_ms(pmccobjpriv->mcc_launch_time) > 2000) { + _enter_critical_bh(&pmccobjpriv->mcc_lock, &irqL); + + cur_cnt = pmccobjpriv->cur_mcc_success_cnt; + prev_cnt = pmccobjpriv->prev_mcc_success_cnt; + if (cur_cnt < prev_cnt) + diff_cnt = (cur_cnt + 255) - prev_cnt; + else + diff_cnt = cur_cnt - prev_cnt; + + if (diff_cnt < 30) { + pmccobjpriv->mcc_tolerance_time--; + RTW_INFO("%s: diff_cnt:%d, tolerance_time:%d\n", + __func__, diff_cnt, pmccobjpriv->mcc_tolerance_time); + } else + pmccobjpriv->mcc_tolerance_time = MCC_TOLERANCE_TIME; + + pmccobjpriv->prev_mcc_success_cnt = pmccobjpriv->cur_mcc_success_cnt; + + if (pmccobjpriv->mcc_tolerance_time != 0) + check_ret = _SUCCESS; + + _exit_critical_bh(&pmccobjpriv->mcc_lock, &irqL); + + if (check_ret != _SUCCESS) { + RTW_INFO("============ MCC swich channel check fail (%d)=============\n", diff_cnt); + /* restart MCC */ + #ifdef MCC_RESTART + rtw_hal_set_mcc_setting(padapter, MCC_SETCMD_STATUS_STOP_DISCONNECT); + rtw_hal_set_mcc_setting(padapter, MCC_SETCMD_STATUS_START_CONNECT); + #endif /* MCC_RESTART */ + } + } else { + _enter_critical_bh(&pmccobjpriv->mcc_lock, &irqL); + pmccobjpriv->prev_mcc_success_cnt = pmccobjpriv->cur_mcc_success_cnt; + _exit_critical_bh(&pmccobjpriv->mcc_lock, &irqL); + } + + } + _exit_critical_mutex(&pmccobjpriv->mcc_mutex, NULL); +} + +/** + * rtw_hal_mcc_change_scan_flag - change scan flag under mcc + * + * MCC mode under sitesurvey goto AP channel to tx bcn & data + * MCC mode under sitesurvey doesn't support TX data for station mode (FW not support) + * + * @padapter: the adapter to be change scan flag + * @ch: pointer to rerurn ch + * @bw: pointer to rerurn bw + * @offset: pointer to rerurn offset + */ +u8 rtw_hal_mcc_change_scan_flag(PADAPTER padapter, u8 *ch, u8 *bw, u8 *offset) +{ + u8 need_ch_setting_union = _TRUE, i = 0, flags = 0, role = 0; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + struct mcc_adapter_priv *pmccadapriv = NULL; + struct mlme_ext_priv *pmlmeext = NULL; + + if (!MCC_EN(padapter)) + goto exit; + + if (!rtw_hal_check_mcc_status(padapter, MCC_STATUS_NEED_MCC)) + goto exit; + + for (i = 0; i < dvobj->iface_nums; i++) { + if (!dvobj->padapters[i]) + continue; + + pmlmeext = &dvobj->padapters[i]->mlmeextpriv; + pmccadapriv = &dvobj->padapters[i]->mcc_adapterpriv; + role = pmccadapriv->role; + + switch (role) { + case MCC_ROLE_AP: + case MCC_ROLE_GO: + *ch = pmlmeext->cur_channel; + *bw = pmlmeext->cur_bwmode; + *offset = pmlmeext->cur_ch_offset; + need_ch_setting_union = _FALSE; + break; + case MCC_ROLE_STA: + case MCC_ROLE_GC: + break; + default: + RTW_INFO("unknown role\n"); + rtw_warn_on(1); + break; + } + + /* check other scan flag */ + flags = mlmeext_scan_backop_flags(pmlmeext); + if (mlmeext_chk_scan_backop_flags(pmlmeext, SS_BACKOP_PS_ANNC)) + flags &= ~SS_BACKOP_PS_ANNC; + + if (mlmeext_chk_scan_backop_flags(pmlmeext, SS_BACKOP_TX_RESUME)) + flags &= ~SS_BACKOP_TX_RESUME; + + mlmeext_assign_scan_backop_flags(pmlmeext, flags); + + } +exit: + return need_ch_setting_union; +} + +/** + * rtw_hal_mcc_calc_tx_bytes_from_kernel - calculte tx bytes from kernel to check concurrent tx or not + * @padapter: the adapter to be record tx bytes + * @len: data len + */ +inline void rtw_hal_mcc_calc_tx_bytes_from_kernel(PADAPTER padapter, u32 len) +{ + struct mcc_adapter_priv *pmccadapriv = &padapter->mcc_adapterpriv; + + if (MCC_EN(padapter)) { + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) { + pmccadapriv->mcc_tx_bytes_from_kernel += len; + if (0) + RTW_INFO("%s(order:%d): mcc tx bytes from kernel:%lld\n" + , __func__, pmccadapriv->order, pmccadapriv->mcc_tx_bytes_from_kernel); + } + } +} + +/** + * rtw_hal_mcc_calc_tx_bytes_to_port - calculte tx bytes to write port in order to flow crtl + * @padapter: the adapter to be record tx bytes + * @len: data len + */ +inline void rtw_hal_mcc_calc_tx_bytes_to_port(PADAPTER padapter, u32 len) +{ + if (MCC_EN(padapter)) { + struct mcc_obj_priv *pmccobjpriv = &(adapter_to_dvobj(padapter)->mcc_objpriv); + struct mcc_adapter_priv *pmccadapriv = &padapter->mcc_adapterpriv; + + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) + pmccadapriv->mcc_tx_bytes_to_port += len; + if (0) + RTW_INFO("%s(order:%d): mcc tx bytes to port:%d, mcc target tx bytes to port:%d\n" + , __func__, pmccadapriv->order, pmccadapriv->mcc_tx_bytes_to_port + , pmccadapriv->mcc_target_tx_bytes_to_port); + } +} + +/** + * rtw_hal_mcc_stop_tx_bytes_to_port - stop write port to hw or not + * @padapter: the adapter to be stopped + */ +inline u8 rtw_hal_mcc_stop_tx_bytes_to_port(PADAPTER padapter) +{ + if (MCC_EN(padapter)) { + struct mcc_obj_priv *pmccobjpriv = &(adapter_to_dvobj(padapter)->mcc_objpriv); + struct mcc_adapter_priv *pmccadapriv = &padapter->mcc_adapterpriv; + + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) { + if (pmccadapriv->mcc_tp_limit) { + if (pmccadapriv->mcc_tx_bytes_to_port >= pmccadapriv->mcc_target_tx_bytes_to_port) { + pmccadapriv->mcc_tx_stop = _TRUE; + rtw_netif_stop_queue(padapter->pnetdev); + return _TRUE; + } + } + } + } + + return _FALSE; +} + +/** + * rtw_hal_set_mcc_setting_scan_start - setting mcc under scan start + * @padapter: the adapter to be setted + * @ch_setting_changed: softap channel setting to be changed or not + */ +u8 rtw_hal_set_mcc_setting_scan_start(PADAPTER padapter) +{ + u8 ret = _FAIL; + + if (MCC_EN(padapter)) { + struct mcc_obj_priv *pmccobjpriv = &(adapter_to_dvobj(padapter)->mcc_objpriv); + + _enter_critical_mutex(&pmccobjpriv->mcc_mutex, NULL); + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_NEED_MCC)) { + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) { + ret = rtw_hal_set_mcc_setting(padapter, MCC_SETCMD_STATUS_STOP_SCAN_START); + /* issue null data to all station connected to AP before scan */ + rtw_hal_mcc_issue_null_data(padapter, 0, 1); + } + } + _exit_critical_mutex(&pmccobjpriv->mcc_mutex, NULL); + } + + return ret; +} + +/** + * rtw_hal_set_mcc_setting_scan_complete - setting mcc after scan commplete + * @padapter: the adapter to be setted + * @ch_setting_changed: softap channel setting to be changed or not + */ +u8 rtw_hal_set_mcc_setting_scan_complete(PADAPTER padapter) +{ + u8 ret = _FAIL; + + if (MCC_EN(padapter)) { + struct mcc_obj_priv *pmccobjpriv = &(adapter_to_dvobj(padapter)->mcc_objpriv); + + _enter_critical_mutex(&pmccobjpriv->mcc_mutex, NULL); + + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_NEED_MCC)) + ret = rtw_hal_set_mcc_setting(padapter, MCC_SETCMD_STATUS_START_SCAN_DONE); + + _exit_critical_mutex(&pmccobjpriv->mcc_mutex, NULL); + } + + return ret; +} + + +/** + * rtw_hal_set_mcc_setting_start_bss_network - setting mcc under softap start + * @padapter: the adapter to be setted + * @chbw_grouped: channel bw offset can not be allowed or not + */ +u8 rtw_hal_set_mcc_setting_start_bss_network(PADAPTER padapter, u8 chbw_allow) +{ + u8 ret = _FAIL; + + if (MCC_EN(padapter)) { + /* channel bw offset can not be allowed, start MCC */ + if (chbw_allow == _FALSE) { + struct mcc_obj_priv *pmccobjpriv = &(adapter_to_dvobj(padapter)->mcc_objpriv); + + rtw_hal_mcc_restore_iqk_val(padapter); + _enter_critical_mutex(&pmccobjpriv->mcc_mutex, NULL); + ret = rtw_hal_set_mcc_setting(padapter, MCC_SETCMD_STATUS_START_CONNECT); + _exit_critical_mutex(&pmccobjpriv->mcc_mutex, NULL); + } + } + + return ret; +} + +/** + * rtw_hal_set_mcc_setting_disconnect - setting mcc under mlme disconnect(stop softap/disconnect from AP) + * @padapter: the adapter to be setted + */ +u8 rtw_hal_set_mcc_setting_disconnect(PADAPTER padapter) +{ + u8 ret = _FAIL; + + if (MCC_EN(padapter)) { + struct mcc_obj_priv *pmccobjpriv = &(adapter_to_dvobj(padapter)->mcc_objpriv); + + _enter_critical_mutex(&pmccobjpriv->mcc_mutex, NULL); + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_NEED_MCC)) { + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) + ret = rtw_hal_set_mcc_setting(padapter, MCC_SETCMD_STATUS_STOP_DISCONNECT); + } + _exit_critical_mutex(&pmccobjpriv->mcc_mutex, NULL); + } + + return ret; +} + +/** + * rtw_hal_set_mcc_setting_join_done_chk_ch - setting mcc under join done + * @padapter: the adapter to be checked + */ +u8 rtw_hal_set_mcc_setting_join_done_chk_ch(PADAPTER padapter) +{ + u8 ret = _FAIL; + + if (MCC_EN(padapter)) { + struct mi_state mstate; + + rtw_mi_status_no_self(padapter, &mstate); + + if (MSTATE_STA_LD_NUM(&mstate) || MSTATE_STA_LG_NUM(&mstate) || MSTATE_AP_NUM(&mstate)) { + bool chbw_allow = _TRUE; + u8 u_ch, u_offset, u_bw; + struct mlme_ext_priv *cur_mlmeext = &padapter->mlmeextpriv; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + + if (rtw_mi_get_ch_setting_union_no_self(padapter, &u_ch, &u_bw, &u_offset) <= 0) { + dump_adapters_status(RTW_DBGDUMP , dvobj); + rtw_warn_on(1); + } + + RTW_INFO(FUNC_ADPT_FMT" union no self: %u,%u,%u\n" + , FUNC_ADPT_ARG(padapter), u_ch, u_bw, u_offset); + + /* chbw_allow? */ + chbw_allow = rtw_is_chbw_grouped(cur_mlmeext->cur_channel + , cur_mlmeext->cur_bwmode, cur_mlmeext->cur_ch_offset + , u_ch, u_bw, u_offset); + + RTW_INFO(FUNC_ADPT_FMT" chbw_allow:%d\n" + , FUNC_ADPT_ARG(padapter), chbw_allow); + + /* if chbw_allow = false, start MCC setting */ + if (chbw_allow == _FALSE) { + struct mcc_obj_priv *pmccobjpriv = &dvobj->mcc_objpriv; + + rtw_hal_mcc_restore_iqk_val(padapter); + _enter_critical_mutex(&pmccobjpriv->mcc_mutex, NULL); + ret = rtw_hal_set_mcc_setting(padapter, MCC_SETCMD_STATUS_START_CONNECT); + _exit_critical_mutex(&pmccobjpriv->mcc_mutex, NULL); + } + } + } + + return ret; +} + +/** + * rtw_hal_set_mcc_setting_chk_start_clnt_join - check change channel under start clnt join + * @padapter: the adapter to be checked + * @ch: pointer to rerurn ch + * @bw: pointer to rerurn bw + * @offset: pointer to rerurn offset + * @chbw_allow: allow to use adapter's channel setting + */ +u8 rtw_hal_set_mcc_setting_chk_start_clnt_join(PADAPTER padapter, u8 *ch, u8 *bw, u8 *offset, u8 chbw_allow) +{ + u8 ret = _FAIL; + + /* if chbw_allow = false under en_mcc = TRUE, we do not change channel related setting */ + if (MCC_EN(padapter)) { + /* restore union channel related setting to current channel related setting */ + if (chbw_allow == _FALSE) { + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + + *ch = pmlmeext->cur_channel; + *bw = pmlmeext->cur_bwmode; + *offset = pmlmeext->cur_ch_offset; + + RTW_INFO(FUNC_ADPT_FMT" en_mcc:%d(%d,%d,%d,)\n" + , FUNC_ADPT_ARG(padapter), padapter->registrypriv.en_mcc + , *ch, *bw, *offset); + ret = _SUCCESS; + } + } + + return ret; +} + +static void rtw_hal_mcc_dump_noa_content(void *sel, PADAPTER padapter) +{ + struct mcc_adapter_priv *pmccadapriv = NULL; + u8 *pos = NULL; + pmccadapriv = &padapter->mcc_adapterpriv; + /* last position for NoA attribute */ + pos = pmccadapriv->p2p_go_noa_ie + pmccadapriv->p2p_go_noa_ie_len; + + + RTW_PRINT_SEL(sel, "\nStart to dump NoA Content\n"); + RTW_PRINT_SEL(sel, "NoA Counts:%d\n", *(pos - 13)); + RTW_PRINT_SEL(sel, "NoA Duration(TU):%d\n", (RTW_GET_LE32(pos - 12))/TU); + RTW_PRINT_SEL(sel, "NoA Interval(TU):%d\n", (RTW_GET_LE32(pos - 8))/TU); + RTW_PRINT_SEL(sel, "NoA Start time(microseconds):0x%02x\n", RTW_GET_LE32(pos - 4)); + RTW_PRINT_SEL(sel, "End to dump NoA Content\n"); +} + +void rtw_hal_dump_mcc_info(void *sel, struct dvobj_priv *dvobj) +{ + struct mcc_obj_priv *pmccobjpriv = &(dvobj->mcc_objpriv); + struct mcc_adapter_priv *pmccadapriv = NULL; + _adapter *iface = NULL, *adapter = NULL; + struct registry_priv *regpriv = NULL; + u8 i = 0; + + /* regpriv is common for all adapter */ + adapter = dvobj->padapters[IFACE_ID0]; + + RTW_PRINT_SEL(sel, "**********************************************\n"); + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + if (!iface) + continue; + + regpriv = &iface->registrypriv; + pmccadapriv = &iface->mcc_adapterpriv; + if (pmccadapriv) { + RTW_PRINT_SEL(sel, "adapter mcc info:\n"); + RTW_PRINT_SEL(sel, "ifname:%s\n", ADPT_ARG(iface)); + RTW_PRINT_SEL(sel, "order:%d\n", pmccadapriv->order); + RTW_PRINT_SEL(sel, "duration:%d\n", pmccadapriv->mcc_duration); + RTW_PRINT_SEL(sel, "target tx bytes:%d\n", pmccadapriv->mcc_target_tx_bytes_to_port); + RTW_PRINT_SEL(sel, "current TP:%d\n", pmccadapriv->mcc_tp); + RTW_PRINT_SEL(sel, "mgmt queue macid:%d\n", pmccadapriv->mgmt_queue_macid); + RTW_PRINT_SEL(sel, "macid bitmap:0x%02x\n\n", pmccadapriv->mcc_macid_bitmap); + RTW_PRINT_SEL(sel, "registry data:\n"); + RTW_PRINT_SEL(sel, "en_mcc:%d\n", regpriv->en_mcc); + RTW_PRINT_SEL(sel, "ap target tx TP(BW:20M):%d Mbps\n", regpriv->rtw_mcc_ap_bw20_target_tx_tp); + RTW_PRINT_SEL(sel, "ap target tx TP(BW:40M):%d Mbps\n", regpriv->rtw_mcc_ap_bw40_target_tx_tp); + RTW_PRINT_SEL(sel, "ap target tx TP(BW:80M):%d Mbps\n", regpriv->rtw_mcc_ap_bw80_target_tx_tp); + RTW_PRINT_SEL(sel, "sta target tx TP(BW:20M):%d Mbps\n", regpriv->rtw_mcc_sta_bw20_target_tx_tp); + RTW_PRINT_SEL(sel, "sta target tx TP(BW:40M ):%d Mbps\n", regpriv->rtw_mcc_sta_bw40_target_tx_tp); + RTW_PRINT_SEL(sel, "sta target tx TP(BW:80M):%d Mbps\n", regpriv->rtw_mcc_sta_bw80_target_tx_tp); + RTW_PRINT_SEL(sel, "single tx criteria:%d Mbps\n", regpriv->rtw_mcc_single_tx_cri); + if (MLME_IS_GO(iface)) + rtw_hal_mcc_dump_noa_content(sel, iface); + RTW_PRINT_SEL(sel, "**********************************************\n"); + } + } + RTW_PRINT_SEL(sel, "------------------------------------------\n"); + RTW_PRINT_SEL(sel, "policy index:%d\n", pmccobjpriv->policy_index); + RTW_PRINT_SEL(sel, "------------------------------------------\n"); + RTW_PRINT_SEL(sel, "define data:\n"); + RTW_PRINT_SEL(sel, "ap target tx TP(BW:20M):%d Mbps\n", MCC_AP_BW20_TARGET_TX_TP); + RTW_PRINT_SEL(sel, "ap target tx TP(BW:40M):%d Mbps\n", MCC_AP_BW40_TARGET_TX_TP); + RTW_PRINT_SEL(sel, "ap target tx TP(BW:80M):%d Mbps\n", MCC_AP_BW80_TARGET_TX_TP); + RTW_PRINT_SEL(sel, "sta target tx TP(BW:20M):%d Mbps\n", MCC_STA_BW20_TARGET_TX_TP); + RTW_PRINT_SEL(sel, "sta target tx TP(BW:40M):%d Mbps\n", MCC_STA_BW40_TARGET_TX_TP); + RTW_PRINT_SEL(sel, "sta target tx TP(BW:80M):%d Mbps\n", MCC_STA_BW80_TARGET_TX_TP); + RTW_PRINT_SEL(sel, "single tx criteria:%d Mbps\n", MCC_SINGLE_TX_CRITERIA); + RTW_PRINT_SEL(sel, "------------------------------------------\n"); +} + +inline void update_mcc_mgntframe_attrib(_adapter *padapter, struct pkt_attrib *pattrib) +{ + if (MCC_EN(padapter)) { + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) { + /* use QSLT_MGNT to check mgnt queue or bcn queue */ + if (pattrib->qsel == QSLT_MGNT) { + pattrib->mac_id = padapter->mcc_adapterpriv.mgmt_queue_macid; + pattrib->qsel = QSLT_VO; + } + } + } +} + +inline u8 rtw_hal_mcc_link_status_chk(_adapter *padapter, const char *msg) +{ + u8 ret = _TRUE, i = 0; + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + _adapter *iface; + struct mlme_ext_priv *mlmeext; + + if (MCC_EN(padapter)) { + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_NEED_MCC)) { + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + mlmeext = &iface->mlmeextpriv; + if (mlmeext_scan_state(mlmeext) != SCAN_DISABLE) { + #ifdef DBG_EXPIRATION_CHK + RTW_INFO(FUNC_ADPT_FMT" don't enter %s under scan for MCC mode\n", FUNC_ADPT_ARG(padapter), msg); + #endif + ret = _FALSE; + goto exit; + } + } + } + } + +exit: + return ret; +} + +void rtw_hal_mcc_issue_null_data(_adapter *padapter, u8 chbw_allow, u8 ps_mode) +{ + struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); + _adapter *iface = NULL; + u32 start = rtw_get_current_time(); + u8 i = 0; + + if (!MCC_EN(padapter)) + return; + + if (rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) + return; + + if (chbw_allow == _TRUE) + return; + + for (i = 0; i < dvobj->iface_nums; i++) { + iface = dvobj->padapters[i]; + /* issue null data to inform ap station will leave */ + if (is_client_associated_to_ap(iface)) { + struct mlme_ext_priv *mlmeext = &iface->mlmeextpriv; + u8 ch = mlmeext->cur_channel; + u8 bw = mlmeext->cur_bwmode; + u8 offset = mlmeext->cur_ch_offset; + + set_channel_bwmode(iface, ch, bw, offset); + issue_nulldata(iface, NULL, ps_mode, 3, 50); + } + } + RTW_INFO("%s(%d ms)\n", __func__, rtw_get_passing_time_ms(start)); +} + +u8 *rtw_hal_mcc_append_go_p2p_ie(PADAPTER padapter, u8 *pframe, u32 *len) +{ + struct mcc_adapter_priv *pmccadapriv = &padapter->mcc_adapterpriv; + + if (!MCC_EN(padapter)) + return pframe; + + if (!rtw_hal_check_mcc_status(padapter, MCC_STATUS_DOING_MCC)) + return pframe; + + if (pmccadapriv->p2p_go_noa_ie_len == 0) + return pframe; + + _rtw_memcpy(pframe, pmccadapriv->p2p_go_noa_ie, pmccadapriv->p2p_go_noa_ie_len); + *len = *len + pmccadapriv->p2p_go_noa_ie_len; + + return pframe + pmccadapriv->p2p_go_noa_ie_len; +} + +void rtw_hal_dump_mcc_policy_table(void *sel) +{ + u8 idx = 0; + RTW_PRINT_SEL(sel, "duration\t,tsf sync offset\t,start time offset\t,interval\t,guard offset0\t,guard offset1\n"); + + for (idx = 0; idx < mcc_max_policy_num; idx ++) { + RTW_PRINT_SEL(sel, "%d\t\t,%d\t\t\t,%d\t\t\t,%d\t\t,%d\t\t,%d\n" + , mcc_switch_channel_policy_table[idx][MCC_DURATION_IDX] + , mcc_switch_channel_policy_table[idx][MCC_TSF_SYNC_OFFSET_IDX] + , mcc_switch_channel_policy_table[idx][MCC_START_TIME_OFFSET_IDX] + , mcc_switch_channel_policy_table[idx][MCC_INTERVAL_IDX] + , mcc_switch_channel_policy_table[idx][MCC_GUARD_OFFSET0_IDX] + , mcc_switch_channel_policy_table[idx][MCC_GUARD_OFFSET1_IDX]); + } +} + +#endif /* CONFIG_MCC_MODE */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_mp.c b/linux-bsp/drivers/rtl8188eus/hal/hal_mp.c new file mode 100644 index 0000000..8ddb33e --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_mp.c @@ -0,0 +1,2212 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _HAL_MP_C_ + +#include <drv_types.h> + +#ifdef CONFIG_MP_INCLUDED + +#ifdef RTW_HALMAC + #include <hal_data.h> /* struct HAL_DATA_TYPE, RF register definition and etc. */ +#else /* !RTW_HALMAC */ + #ifdef CONFIG_RTL8188E + #include <rtl8188e_hal.h> + #endif + #ifdef CONFIG_RTL8723B + #include <rtl8723b_hal.h> + #endif + #ifdef CONFIG_RTL8192E + #include <rtl8192e_hal.h> + #endif + #ifdef CONFIG_RTL8814A + #include <rtl8814a_hal.h> + #endif + #if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) + #include <rtl8812a_hal.h> + #endif + #ifdef CONFIG_RTL8703B + #include <rtl8703b_hal.h> + #endif + #ifdef CONFIG_RTL8723D + #include <rtl8723d_hal.h> + #endif + #ifdef CONFIG_RTL8188F + #include <rtl8188f_hal.h> + #endif +#endif /* !RTW_HALMAC */ + + +u8 MgntQuery_NssTxRate(u16 Rate) +{ + u8 NssNum = RF_TX_NUM_NONIMPLEMENT; + + if ((Rate >= MGN_MCS8 && Rate <= MGN_MCS15) || + (Rate >= MGN_VHT2SS_MCS0 && Rate <= MGN_VHT2SS_MCS9)) + NssNum = RF_2TX; + else if ((Rate >= MGN_MCS16 && Rate <= MGN_MCS23) || + (Rate >= MGN_VHT3SS_MCS0 && Rate <= MGN_VHT3SS_MCS9)) + NssNum = RF_3TX; + else if ((Rate >= MGN_MCS24 && Rate <= MGN_MCS31) || + (Rate >= MGN_VHT4SS_MCS0 && Rate <= MGN_VHT4SS_MCS9)) + NssNum = RF_4TX; + else + NssNum = RF_1TX; + + return NssNum; +} + +void hal_mpt_SwitchRfSetting(PADAPTER pAdapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + u8 ChannelToSw = pMptCtx->MptChannelToSw; + ULONG ulRateIdx = pMptCtx->mpt_rate_index; + ULONG ulbandwidth = pMptCtx->MptBandWidth; + + /* <20120525, Kordan> Dynamic mechanism for APK, asked by Dennis.*/ + if (IS_HARDWARE_TYPE_8188ES(pAdapter) && (1 <= ChannelToSw && ChannelToSw <= 11) && + (ulRateIdx == MPT_RATE_MCS0 || ulRateIdx == MPT_RATE_1M || ulRateIdx == MPT_RATE_6M)) { + pMptCtx->backup0x52_RF_A = (u1Byte)phy_query_rf_reg(pAdapter, ODM_RF_PATH_A, RF_0x52, 0x000F0); + pMptCtx->backup0x52_RF_B = (u1Byte)phy_query_rf_reg(pAdapter, ODM_RF_PATH_B, RF_0x52, 0x000F0); + + if ((PlatformEFIORead4Byte(pAdapter, 0xF4) & BIT29) == BIT29) { + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_0x52, 0x000F0, 0xB); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_0x52, 0x000F0, 0xB); + } else { + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_0x52, 0x000F0, 0xD); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_0x52, 0x000F0, 0xD); + } + } else if (IS_HARDWARE_TYPE_8188EE(pAdapter)) { /* <20140903, VincentL> Asked by RF Eason and Edlu*/ + if (ChannelToSw == 3 && ulbandwidth == MPT_BW_40MHZ) { + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_0x52, 0x000F0, 0xB); /*RF 0x52 = 0x0007E4BD*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_0x52, 0x000F0, 0xB); /*RF 0x52 = 0x0007E4BD*/ + } else { + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_0x52, 0x000F0, 0x9); /*RF 0x52 = 0x0007E49D*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_0x52, 0x000F0, 0x9); /*RF 0x52 = 0x0007E49D*/ + } + } else if (IS_HARDWARE_TYPE_8188E(pAdapter)) { + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_0x52, 0x000F0, pMptCtx->backup0x52_RF_A); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_0x52, 0x000F0, pMptCtx->backup0x52_RF_B); + } +} + +s32 hal_mpt_SetPowerTracking(PADAPTER padapter, u8 enable) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct PHY_DM_STRUCT *pDM_Odm = &(pHalData->odmpriv); + + + if (!netif_running(padapter->pnetdev)) { + return _FAIL; + } + + if (check_fwstate(&padapter->mlmepriv, WIFI_MP_STATE) == _FALSE) { + return _FAIL; + } + if (enable) + pDM_Odm->rf_calibrate_info.txpowertrack_control = _TRUE; + else + pDM_Odm->rf_calibrate_info.txpowertrack_control = _FALSE; + + return _SUCCESS; +} + +void hal_mpt_GetPowerTracking(PADAPTER padapter, u8 *enable) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); + struct PHY_DM_STRUCT *pDM_Odm = &(pHalData->odmpriv); + + + *enable = pDM_Odm->rf_calibrate_info.txpowertrack_control; +} + + +void hal_mpt_CCKTxPowerAdjust(PADAPTER Adapter, BOOLEAN bInCH14) +{ + u32 TempVal = 0, TempVal2 = 0, TempVal3 = 0; + u32 CurrCCKSwingVal = 0, CCKSwingIndex = 12; + u8 i; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); + u1Byte u1Channel = pHalData->current_channel; + ULONG ulRateIdx = pMptCtx->mpt_rate_index; + u1Byte DataRate = 0xFF; + + /* Do not modify CCK TX filter parameters for 8822B*/ + if(IS_HARDWARE_TYPE_8822B(Adapter) || IS_HARDWARE_TYPE_8821C(Adapter) || IS_HARDWARE_TYPE_8723D(Adapter)) + return; + + DataRate = mpt_to_mgnt_rate(ulRateIdx); + + if (u1Channel == 14 && IS_CCK_RATE(DataRate)) + pHalData->bCCKinCH14 = TRUE; + else + pHalData->bCCKinCH14 = FALSE; + + if (IS_HARDWARE_TYPE_8703B(Adapter)) { + if ((u1Channel == 14) && IS_CCK_RATE(DataRate)) { + /* Channel 14 in CCK, need to set 0xA26~0xA29 to 0 for 8703B */ + phy_set_bb_reg(Adapter, rCCK0_TxFilter2, bMaskHWord, 0); + phy_set_bb_reg(Adapter, rCCK0_DebugPort, bMaskLWord, 0); + + } else { + /* Normal setting for 8703B, just recover to the default setting. */ + /* This hardcore values reference from the parameter which BB team gave. */ + for (i = 0 ; i < 2 ; ++i) + phy_set_bb_reg(Adapter, pHalData->RegForRecover[i].offset, bMaskDWord, pHalData->RegForRecover[i].value); + + } + } else if (IS_HARDWARE_TYPE_8723D(Adapter)) { + /* 2.4G CCK TX DFIR */ + /* 2016.01.20 Suggest from RS BB mingzhi*/ + if ((u1Channel == 14)) { + phy_set_bb_reg(Adapter, rCCK0_TxFilter2, bMaskDWord, 0x0000B81C); + phy_set_bb_reg(Adapter, rCCK0_DebugPort, bMaskDWord, 0x00000000); + phy_set_bb_reg(Adapter, 0xAAC, bMaskDWord, 0x00003667); + } else { + for (i = 0 ; i < 3 ; ++i) { + phy_set_bb_reg(Adapter, + pHalData->RegForRecover[i].offset, + bMaskDWord, + pHalData->RegForRecover[i].value); + } + } + } else if (IS_HARDWARE_TYPE_8188F(Adapter)) { + /* get current cck swing value and check 0xa22 & 0xa23 later to match the table.*/ + CurrCCKSwingVal = read_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord); + CCKSwingIndex = 20; /* default index */ + + if (!pHalData->bCCKinCH14) { + /* Readback the current bb cck swing value and compare with the table to */ + /* get the current swing index */ + for (i = 0; i < CCK_TABLE_SIZE_88F; i++) { + if (((CurrCCKSwingVal & 0xff) == (u32)cck_swing_table_ch1_ch13_88f[i][0]) && + (((CurrCCKSwingVal & 0xff00) >> 8) == (u32)cck_swing_table_ch1_ch13_88f[i][1])) { + CCKSwingIndex = i; + break; + } + } + write_bbreg(Adapter, 0xa22, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][0]); + write_bbreg(Adapter, 0xa23, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][1]); + write_bbreg(Adapter, 0xa24, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][2]); + write_bbreg(Adapter, 0xa25, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][3]); + write_bbreg(Adapter, 0xa26, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][4]); + write_bbreg(Adapter, 0xa27, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][5]); + write_bbreg(Adapter, 0xa28, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][6]); + write_bbreg(Adapter, 0xa29, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][7]); + write_bbreg(Adapter, 0xa9a, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][8]); + write_bbreg(Adapter, 0xa9b, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][9]); + write_bbreg(Adapter, 0xa9c, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][10]); + write_bbreg(Adapter, 0xa9d, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][11]); + write_bbreg(Adapter, 0xaa0, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][12]); + write_bbreg(Adapter, 0xaa1, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][13]); + write_bbreg(Adapter, 0xaa2, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][14]); + write_bbreg(Adapter, 0xaa3, bMaskByte0, cck_swing_table_ch1_ch13_88f[CCKSwingIndex][15]); + RTW_INFO("%s , cck_swing_table_ch1_ch13_88f[%d]\n", __func__, CCKSwingIndex); + } else { + for (i = 0; i < CCK_TABLE_SIZE_88F; i++) { + if (((CurrCCKSwingVal & 0xff) == (u32)cck_swing_table_ch14_88f[i][0]) && + (((CurrCCKSwingVal & 0xff00) >> 8) == (u32)cck_swing_table_ch14_88f[i][1])) { + CCKSwingIndex = i; + break; + } + } + write_bbreg(Adapter, 0xa22, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][0]); + write_bbreg(Adapter, 0xa23, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][1]); + write_bbreg(Adapter, 0xa24, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][2]); + write_bbreg(Adapter, 0xa25, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][3]); + write_bbreg(Adapter, 0xa26, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][4]); + write_bbreg(Adapter, 0xa27, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][5]); + write_bbreg(Adapter, 0xa28, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][6]); + write_bbreg(Adapter, 0xa29, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][7]); + write_bbreg(Adapter, 0xa9a, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][8]); + write_bbreg(Adapter, 0xa9b, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][9]); + write_bbreg(Adapter, 0xa9c, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][10]); + write_bbreg(Adapter, 0xa9d, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][11]); + write_bbreg(Adapter, 0xaa0, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][12]); + write_bbreg(Adapter, 0xaa1, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][13]); + write_bbreg(Adapter, 0xaa2, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][14]); + write_bbreg(Adapter, 0xaa3, bMaskByte0, cck_swing_table_ch14_88f[CCKSwingIndex][15]); + RTW_INFO("%s , cck_swing_table_ch14_88f[%d]\n", __func__, CCKSwingIndex); + } + } else { + + /* get current cck swing value and check 0xa22 & 0xa23 later to match the table.*/ + CurrCCKSwingVal = read_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord); + + if (!pHalData->bCCKinCH14) { + /* Readback the current bb cck swing value and compare with the table to */ + /* get the current swing index */ + for (i = 0; i < CCK_TABLE_SIZE; i++) { + if (((CurrCCKSwingVal & 0xff) == (u32)cck_swing_table_ch1_ch13[i][0]) && + (((CurrCCKSwingVal & 0xff00) >> 8) == (u32)cck_swing_table_ch1_ch13[i][1])) { + CCKSwingIndex = i; + break; + } + } + + /*Write 0xa22 0xa23*/ + TempVal = cck_swing_table_ch1_ch13[CCKSwingIndex][0] + + (cck_swing_table_ch1_ch13[CCKSwingIndex][1] << 8); + + + /*Write 0xa24 ~ 0xa27*/ + TempVal2 = 0; + TempVal2 = cck_swing_table_ch1_ch13[CCKSwingIndex][2] + + (cck_swing_table_ch1_ch13[CCKSwingIndex][3] << 8) + + (cck_swing_table_ch1_ch13[CCKSwingIndex][4] << 16) + + (cck_swing_table_ch1_ch13[CCKSwingIndex][5] << 24); + + /*Write 0xa28 0xa29*/ + TempVal3 = 0; + TempVal3 = cck_swing_table_ch1_ch13[CCKSwingIndex][6] + + (cck_swing_table_ch1_ch13[CCKSwingIndex][7] << 8); + } else { + for (i = 0; i < CCK_TABLE_SIZE; i++) { + if (((CurrCCKSwingVal & 0xff) == (u32)cck_swing_table_ch14[i][0]) && + (((CurrCCKSwingVal & 0xff00) >> 8) == (u32)cck_swing_table_ch14[i][1])) { + CCKSwingIndex = i; + break; + } + } + + /*Write 0xa22 0xa23*/ + TempVal = cck_swing_table_ch14[CCKSwingIndex][0] + + (cck_swing_table_ch14[CCKSwingIndex][1] << 8); + + /*Write 0xa24 ~ 0xa27*/ + TempVal2 = 0; + TempVal2 = cck_swing_table_ch14[CCKSwingIndex][2] + + (cck_swing_table_ch14[CCKSwingIndex][3] << 8) + + (cck_swing_table_ch14[CCKSwingIndex][4] << 16) + + (cck_swing_table_ch14[CCKSwingIndex][5] << 24); + + /*Write 0xa28 0xa29*/ + TempVal3 = 0; + TempVal3 = cck_swing_table_ch14[CCKSwingIndex][6] + + (cck_swing_table_ch14[CCKSwingIndex][7] << 8); + } + + write_bbreg(Adapter, rCCK0_TxFilter1, bMaskHWord, TempVal); + write_bbreg(Adapter, rCCK0_TxFilter2, bMaskDWord, TempVal2); + write_bbreg(Adapter, rCCK0_DebugPort, bMaskLWord, TempVal3); + } + +} + +void hal_mpt_SetChannel(PADAPTER pAdapter) +{ + u8 eRFPath; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + struct PHY_DM_STRUCT *pDM_Odm = &(pHalData->odmpriv); + struct mp_priv *pmp = &pAdapter->mppriv; + u8 channel = pmp->channel; + u8 bandwidth = pmp->bandwidth; + + hal_mpt_SwitchRfSetting(pAdapter); + + pHalData->bSwChnl = _TRUE; + pHalData->bSetChnlBW = _TRUE; + rtw_hal_set_chnl_bw(pAdapter, channel, bandwidth, 0, 0); + + hal_mpt_CCKTxPowerAdjust(pAdapter, pHalData->bCCKinCH14); + +} + +/* + * Notice + * Switch bandwitdth may change center frequency(channel) + */ +void hal_mpt_SetBandwidth(PADAPTER pAdapter) +{ + struct mp_priv *pmp = &pAdapter->mppriv; + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + u8 channel = pmp->channel; + u8 bandwidth = pmp->bandwidth; + + pHalData->bSwChnl = _TRUE; + pHalData->bSetChnlBW = _TRUE; + rtw_hal_set_chnl_bw(pAdapter, channel, bandwidth, 0, 0); + + hal_mpt_SwitchRfSetting(pAdapter); +} + +void mpt_SetTxPower_Old(PADAPTER pAdapter, MPT_TXPWR_DEF Rate, u8 *pTxPower) +{ + switch (Rate) { + case MPT_CCK: { + u4Byte TxAGC = 0, pwr = 0; + u1Byte rf; + + pwr = pTxPower[ODM_RF_PATH_A]; + if (pwr < 0x3f) { + TxAGC = (pwr << 16) | (pwr << 8) | (pwr); + phy_set_bb_reg(pAdapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, pTxPower[ODM_RF_PATH_A]); + phy_set_bb_reg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, TxAGC); + } + pwr = pTxPower[ODM_RF_PATH_B]; + if (pwr < 0x3f) { + TxAGC = (pwr << 16) | (pwr << 8) | (pwr); + phy_set_bb_reg(pAdapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, pTxPower[ODM_RF_PATH_B]); + phy_set_bb_reg(pAdapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, TxAGC); + } + } + break; + + case MPT_OFDM_AND_HT: { + u4Byte TxAGC = 0; + u1Byte pwr = 0, rf; + + pwr = pTxPower[0]; + if (pwr < 0x3f) { + TxAGC |= ((pwr << 24) | (pwr << 16) | (pwr << 8) | pwr); + RTW_INFO("HT Tx-rf(A) Power = 0x%x\n", TxAGC); + phy_set_bb_reg(pAdapter, rTxAGC_A_Rate18_06, bMaskDWord, TxAGC); + phy_set_bb_reg(pAdapter, rTxAGC_A_Rate54_24, bMaskDWord, TxAGC); + phy_set_bb_reg(pAdapter, rTxAGC_A_Mcs03_Mcs00, bMaskDWord, TxAGC); + phy_set_bb_reg(pAdapter, rTxAGC_A_Mcs07_Mcs04, bMaskDWord, TxAGC); + phy_set_bb_reg(pAdapter, rTxAGC_A_Mcs11_Mcs08, bMaskDWord, TxAGC); + phy_set_bb_reg(pAdapter, rTxAGC_A_Mcs15_Mcs12, bMaskDWord, TxAGC); + } + TxAGC = 0; + pwr = pTxPower[1]; + if (pwr < 0x3f) { + TxAGC |= ((pwr << 24) | (pwr << 16) | (pwr << 8) | pwr); + RTW_INFO("HT Tx-rf(B) Power = 0x%x\n", TxAGC); + phy_set_bb_reg(pAdapter, rTxAGC_B_Rate18_06, bMaskDWord, TxAGC); + phy_set_bb_reg(pAdapter, rTxAGC_B_Rate54_24, bMaskDWord, TxAGC); + phy_set_bb_reg(pAdapter, rTxAGC_B_Mcs03_Mcs00, bMaskDWord, TxAGC); + phy_set_bb_reg(pAdapter, rTxAGC_B_Mcs07_Mcs04, bMaskDWord, TxAGC); + phy_set_bb_reg(pAdapter, rTxAGC_B_Mcs11_Mcs08, bMaskDWord, TxAGC); + phy_set_bb_reg(pAdapter, rTxAGC_B_Mcs15_Mcs12, bMaskDWord, TxAGC); + } + } + break; + + default: + break; + } + RTW_INFO("<===mpt_SetTxPower_Old()\n"); +} + +void +mpt_SetTxPower( + PADAPTER pAdapter, + MPT_TXPWR_DEF Rate, + pu1Byte pTxPower +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + u1Byte path = 0 , i = 0, MaxRate = MGN_6M; + u1Byte StartPath = ODM_RF_PATH_A, EndPath = ODM_RF_PATH_B; + + if (IS_HARDWARE_TYPE_8814A(pAdapter)) + EndPath = ODM_RF_PATH_D; + else if (IS_HARDWARE_TYPE_8188F(pAdapter) || IS_HARDWARE_TYPE_8723D(pAdapter) || IS_HARDWARE_TYPE_8821C(pAdapter)) + EndPath = ODM_RF_PATH_A; + + switch (Rate) { + case MPT_CCK: { + u1Byte rate[] = {MGN_1M, MGN_2M, MGN_5_5M, MGN_11M}; + + for (path = StartPath; path <= EndPath; path++) + for (i = 0; i < sizeof(rate); ++i) + PHY_SetTxPowerIndex(pAdapter, pTxPower[path], path, rate[i]); + } + break; + case MPT_OFDM: { + u1Byte rate[] = { + MGN_6M, MGN_9M, MGN_12M, MGN_18M, + MGN_24M, MGN_36M, MGN_48M, MGN_54M, + }; + + for (path = StartPath; path <= EndPath; path++) + for (i = 0; i < sizeof(rate); ++i) + PHY_SetTxPowerIndex(pAdapter, pTxPower[path], path, rate[i]); + } + break; + case MPT_HT: { + u1Byte rate[] = { + MGN_MCS0, MGN_MCS1, MGN_MCS2, MGN_MCS3, MGN_MCS4, + MGN_MCS5, MGN_MCS6, MGN_MCS7, MGN_MCS8, MGN_MCS9, + MGN_MCS10, MGN_MCS11, MGN_MCS12, MGN_MCS13, MGN_MCS14, + MGN_MCS15, MGN_MCS16, MGN_MCS17, MGN_MCS18, MGN_MCS19, + MGN_MCS20, MGN_MCS21, MGN_MCS22, MGN_MCS23, MGN_MCS24, + MGN_MCS25, MGN_MCS26, MGN_MCS27, MGN_MCS28, MGN_MCS29, + MGN_MCS30, MGN_MCS31, + }; + if (pHalData->rf_type == RF_3T3R) + MaxRate = MGN_MCS23; + else if (pHalData->rf_type == RF_2T2R) + MaxRate = MGN_MCS15; + else + MaxRate = MGN_MCS7; + for (path = StartPath; path <= EndPath; path++) { + for (i = 0; i < sizeof(rate); ++i) { + if (rate[i] > MaxRate) + break; + PHY_SetTxPowerIndex(pAdapter, pTxPower[path], path, rate[i]); + } + } + } + break; + case MPT_VHT: { + u1Byte rate[] = { + MGN_VHT1SS_MCS0, MGN_VHT1SS_MCS1, MGN_VHT1SS_MCS2, MGN_VHT1SS_MCS3, MGN_VHT1SS_MCS4, + MGN_VHT1SS_MCS5, MGN_VHT1SS_MCS6, MGN_VHT1SS_MCS7, MGN_VHT1SS_MCS8, MGN_VHT1SS_MCS9, + MGN_VHT2SS_MCS0, MGN_VHT2SS_MCS1, MGN_VHT2SS_MCS2, MGN_VHT2SS_MCS3, MGN_VHT2SS_MCS4, + MGN_VHT2SS_MCS5, MGN_VHT2SS_MCS6, MGN_VHT2SS_MCS7, MGN_VHT2SS_MCS8, MGN_VHT2SS_MCS9, + MGN_VHT3SS_MCS0, MGN_VHT3SS_MCS1, MGN_VHT3SS_MCS2, MGN_VHT3SS_MCS3, MGN_VHT3SS_MCS4, + MGN_VHT3SS_MCS5, MGN_VHT3SS_MCS6, MGN_VHT3SS_MCS7, MGN_VHT3SS_MCS8, MGN_VHT3SS_MCS9, + MGN_VHT4SS_MCS0, MGN_VHT4SS_MCS1, MGN_VHT4SS_MCS2, MGN_VHT4SS_MCS3, MGN_VHT4SS_MCS4, + MGN_VHT4SS_MCS5, MGN_VHT4SS_MCS6, MGN_VHT4SS_MCS7, MGN_VHT4SS_MCS8, MGN_VHT4SS_MCS9, + }; + if (pHalData->rf_type == RF_3T3R) + MaxRate = MGN_VHT3SS_MCS9; + else if (pHalData->rf_type == RF_2T2R || pHalData->rf_type == RF_2T4R) + MaxRate = MGN_VHT2SS_MCS9; + else + MaxRate = MGN_VHT1SS_MCS9; + + for (path = StartPath; path <= EndPath; path++) { + for (i = 0; i < sizeof(rate); ++i) { + if (rate[i] > MaxRate) + break; + PHY_SetTxPowerIndex(pAdapter, pTxPower[path], path, rate[i]); + } + } + } + break; + default: + RTW_INFO("<===mpt_SetTxPower: Illegal channel!!\n"); + break; + } +} + +void hal_mpt_SetTxPower(PADAPTER pAdapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + + if (pHalData->rf_chip < RF_TYPE_MAX) { + if (IS_HARDWARE_TYPE_8188E(pAdapter) || + IS_HARDWARE_TYPE_8723B(pAdapter) || + IS_HARDWARE_TYPE_8192E(pAdapter) || + IS_HARDWARE_TYPE_8703B(pAdapter) || + IS_HARDWARE_TYPE_8188F(pAdapter)) { + u8 path = (pHalData->antenna_tx_path == ANTENNA_A) ? (ODM_RF_PATH_A) : (ODM_RF_PATH_B); + + RTW_INFO("===> MPT_ProSetTxPower: Old\n"); + + mpt_SetTxPower_Old(pAdapter, MPT_CCK, pMptCtx->TxPwrLevel); + mpt_SetTxPower_Old(pAdapter, MPT_OFDM_AND_HT, pMptCtx->TxPwrLevel); + + } else { + RTW_INFO("===> MPT_ProSetTxPower: Jaguar/Jaguar2\n"); + mpt_SetTxPower(pAdapter, MPT_CCK, pMptCtx->TxPwrLevel); + mpt_SetTxPower(pAdapter, MPT_OFDM, pMptCtx->TxPwrLevel); + mpt_SetTxPower(pAdapter, MPT_HT, pMptCtx->TxPwrLevel); + mpt_SetTxPower(pAdapter, MPT_VHT, pMptCtx->TxPwrLevel); + + } + } else + RTW_INFO("RFChipID < RF_TYPE_MAX, the RF chip is not supported - %d\n", pHalData->rf_chip); + + odm_clear_txpowertracking_state(pDM_Odm); +} + +void hal_mpt_SetDataRate(PADAPTER pAdapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + u32 DataRate; + + DataRate = mpt_to_mgnt_rate(pMptCtx->mpt_rate_index); + + hal_mpt_SwitchRfSetting(pAdapter); + + hal_mpt_CCKTxPowerAdjust(pAdapter, pHalData->bCCKinCH14); +#ifdef CONFIG_RTL8723B + if (IS_HARDWARE_TYPE_8723B(pAdapter) || IS_HARDWARE_TYPE_8188F(pAdapter)) { + if (IS_CCK_RATE(DataRate)) { + if (pMptCtx->mpt_rf_path == ODM_RF_PATH_A) + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x51, 0xF, 0x6); + else + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x71, 0xF, 0x6); + } else { + if (pMptCtx->mpt_rf_path == ODM_RF_PATH_A) + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x51, 0xF, 0xE); + else + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x71, 0xF, 0xE); + } + } + + if ((IS_HARDWARE_TYPE_8723BS(pAdapter) && + ((pHalData->PackageType == PACKAGE_TFBGA79) || (pHalData->PackageType == PACKAGE_TFBGA90)))) { + if (pMptCtx->mpt_rf_path == ODM_RF_PATH_A) + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x51, 0xF, 0xE); + else + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x71, 0xF, 0xE); + } +#endif +} + +#define RF_PATH_AB 22 + +#ifdef CONFIG_RTL8814A +VOID mpt_ToggleIG_8814A(PADAPTER pAdapter) +{ + u1Byte Path = 0; + u4Byte IGReg = rA_IGI_Jaguar, IGvalue = 0; + + for (Path; Path <= ODM_RF_PATH_D; Path++) { + switch (Path) { + case ODM_RF_PATH_B: + IGReg = rB_IGI_Jaguar; + break; + case ODM_RF_PATH_C: + IGReg = rC_IGI_Jaguar2; + break; + case ODM_RF_PATH_D: + IGReg = rD_IGI_Jaguar2; + break; + default: + IGReg = rA_IGI_Jaguar; + break; + } + + IGvalue = phy_query_bb_reg(pAdapter, IGReg, bMaskByte0); + phy_set_bb_reg(pAdapter, IGReg, bMaskByte0, IGvalue + 2); + phy_set_bb_reg(pAdapter, IGReg, bMaskByte0, IGvalue); + } +} + +VOID mpt_SetRFPath_8814A(PADAPTER pAdapter) +{ + + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMPT_CONTEXT pMptCtx = &pAdapter->mppriv.mpt_ctx; + R_ANTENNA_SELECT_OFDM *p_ofdm_tx; /* OFDM Tx register */ + R_ANTENNA_SELECT_CCK *p_cck_txrx; + u8 ForcedDataRate = mpt_to_mgnt_rate(pMptCtx->mpt_rate_index); + u8 HtStbcCap = pAdapter->registrypriv.stbc_cap; + /*/PRT_HIGH_THROUGHPUT pHTInfo = GET_HT_INFO(pMgntInfo);*/ + /*/PRT_VERY_HIGH_THROUGHPUT pVHTInfo = GET_VHT_INFO(pMgntInfo);*/ + + u32 ulAntennaTx = pHalData->antenna_tx_path; + u32 ulAntennaRx = pHalData->AntennaRxPath; + u8 NssforRate = MgntQuery_NssTxRate(ForcedDataRate); + + if ((NssforRate == RF_2TX) || ((NssforRate == RF_1TX) && IS_HT_RATE(ForcedDataRate)) || ((NssforRate == RF_1TX) && IS_VHT_RATE(ForcedDataRate))) { + RTW_INFO("===> SetAntenna 2T ForcedDataRate %d NssforRate %d AntennaTx %d\n", ForcedDataRate, NssforRate, ulAntennaTx); + + switch (ulAntennaTx) { + case ANTENNA_BC: + pMptCtx->mpt_rf_path = ODM_RF_PATH_BC; + /*pHalData->ValidTxPath = 0x06; linux no use */ + phy_set_bb_reg(pAdapter, rTxAnt_23Nsts_Jaguar2, 0x0000fff0, 0x106); /*/ 0x940[15:4]=12'b0000_0100_0011*/ + break; + + case ANTENNA_CD: + pMptCtx->mpt_rf_path = ODM_RF_PATH_CD; + /*pHalData->ValidTxPath = 0x0C;*/ + phy_set_bb_reg(pAdapter, rTxAnt_23Nsts_Jaguar2, 0x0000fff0, 0x40c); /*/ 0x940[15:4]=12'b0000_0100_0011*/ + break; + case ANTENNA_AB: + default: + pMptCtx->mpt_rf_path = ODM_RF_PATH_AB; + /*pHalData->ValidTxPath = 0x03;*/ + phy_set_bb_reg(pAdapter, rTxAnt_23Nsts_Jaguar2, 0x0000fff0, 0x043); /*/ 0x940[15:4]=12'b0000_0100_0011*/ + break; + } + + } else if (NssforRate == RF_3TX) { + RTW_INFO("===> SetAntenna 3T ForcedDataRate %d NssforRate %d AntennaTx %d\n", ForcedDataRate, NssforRate, ulAntennaTx); + + switch (ulAntennaTx) { + case ANTENNA_BCD: + pMptCtx->mpt_rf_path = ODM_RF_PATH_BCD; + /*pHalData->ValidTxPath = 0x0e;*/ + phy_set_bb_reg(pAdapter, rTxAnt_23Nsts_Jaguar2, 0x0fff0000, 0x90e); /*/ 0x940[27:16]=12'b0010_0100_0111*/ + break; + + case ANTENNA_ABC: + default: + pMptCtx->mpt_rf_path = ODM_RF_PATH_ABC; + /*pHalData->ValidTxPath = 0x0d;*/ + phy_set_bb_reg(pAdapter, rTxAnt_23Nsts_Jaguar2, 0x0fff0000, 0x247); /*/ 0x940[27:16]=12'b0010_0100_0111*/ + break; + } + + } else { /*/if(NssforRate == RF_1TX)*/ + RTW_INFO("===> SetAntenna 1T ForcedDataRate %d NssforRate %d AntennaTx %d\n", ForcedDataRate, NssforRate, ulAntennaTx); + switch (ulAntennaTx) { + case ANTENNA_BCD: + pMptCtx->mpt_rf_path = ODM_RF_PATH_BCD; + /*pHalData->ValidTxPath = 0x0e;*/ + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0xf0000000, 0x7); + phy_set_bb_reg(pAdapter, rTxAnt_1Nsts_Jaguar2, 0x000f00000, 0xe); + phy_set_bb_reg(pAdapter, rTxPath_Jaguar, 0xf0, 0xe); + break; + + case ANTENNA_BC: + pMptCtx->mpt_rf_path = ODM_RF_PATH_BC; + /*pHalData->ValidTxPath = 0x06;*/ + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0xf0000000, 0x6); + phy_set_bb_reg(pAdapter, rTxAnt_1Nsts_Jaguar2, 0x000f00000, 0x6); + phy_set_bb_reg(pAdapter, rTxPath_Jaguar, 0xf0, 0x6); + break; + case ANTENNA_B: + pMptCtx->mpt_rf_path = ODM_RF_PATH_B; + /*pHalData->ValidTxPath = 0x02;*/ + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0xf0000000, 0x4); /*/ 0xa07[7:4] = 4'b0100*/ + phy_set_bb_reg(pAdapter, rTxAnt_1Nsts_Jaguar2, 0xfff00000, 0x002); /*/ 0x93C[31:20]=12'b0000_0000_0010*/ + phy_set_bb_reg(pAdapter, rTxPath_Jaguar, 0xf0, 0x2); /* 0x80C[7:4] = 4'b0010*/ + break; + + case ANTENNA_C: + pMptCtx->mpt_rf_path = ODM_RF_PATH_C; + /*pHalData->ValidTxPath = 0x04;*/ + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0xf0000000, 0x2); /*/ 0xa07[7:4] = 4'b0010*/ + phy_set_bb_reg(pAdapter, rTxAnt_1Nsts_Jaguar2, 0xfff00000, 0x004); /*/ 0x93C[31:20]=12'b0000_0000_0100*/ + phy_set_bb_reg(pAdapter, rTxPath_Jaguar, 0xf0, 0x4); /*/ 0x80C[7:4] = 4'b0100*/ + break; + + case ANTENNA_D: + pMptCtx->mpt_rf_path = ODM_RF_PATH_D; + /*pHalData->ValidTxPath = 0x08;*/ + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0xf0000000, 0x1); /*/ 0xa07[7:4] = 4'b0001*/ + phy_set_bb_reg(pAdapter, rTxAnt_1Nsts_Jaguar2, 0xfff00000, 0x008); /*/ 0x93C[31:20]=12'b0000_0000_1000*/ + phy_set_bb_reg(pAdapter, rTxPath_Jaguar, 0xf0, 0x8); /*/ 0x80C[7:4] = 4'b1000*/ + break; + + case ANTENNA_A: + default: + pMptCtx->mpt_rf_path = ODM_RF_PATH_A; + /*pHalData->ValidTxPath = 0x01;*/ + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0xf0000000, 0x8); /*/ 0xa07[7:4] = 4'b1000*/ + phy_set_bb_reg(pAdapter, rTxAnt_1Nsts_Jaguar2, 0xfff00000, 0x001); /*/ 0x93C[31:20]=12'b0000_0000_0001*/ + phy_set_bb_reg(pAdapter, rTxPath_Jaguar, 0xf0, 0x1); /*/ 0x80C[7:4] = 4'b0001*/ + break; + } + } + + switch (ulAntennaRx) { + case ANTENNA_A: + /*pHalData->ValidRxPath = 0x01;*/ + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x2); + phy_set_bb_reg(pAdapter, rRxPath_Jaguar, bMaskByte0, 0x11); + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x3); + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0x0C000000, 0x0); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_A_0x0[19:16] = 3, RX mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_B_0x0[19:16] = 1, Standby mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_C, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_C_0x0[19:16] = 1, Standby mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_D, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_D_0x0[19:16] = 1, Standby mode*/ + /*/ CCA related PD_delay_th*/ + phy_set_bb_reg(pAdapter, rAGC_table_Jaguar, 0x0F000000, 0x5); + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, 0x0000000F, 0xA); + break; + + case ANTENNA_B: + /*pHalData->ValidRxPath = 0x02;*/ + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x2); + phy_set_bb_reg(pAdapter, rRxPath_Jaguar, bMaskByte0, 0x22); + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x3); + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0x0C000000, 0x1); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_A_0x0[19:16] = 1, Standby mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_B_0x0[19:16] = 3, RX mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_C, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_C_0x0[19:16] = 1, Standby mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_D, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_D_0x0[19:16] = 1, Standby mode*/ + /*/ CCA related PD_delay_th*/ + phy_set_bb_reg(pAdapter, rAGC_table_Jaguar, 0x0F000000, 0x5); + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, 0x0000000F, 0xA); + break; + + case ANTENNA_C: + /*pHalData->ValidRxPath = 0x04;*/ + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x2); + phy_set_bb_reg(pAdapter, rRxPath_Jaguar, bMaskByte0, 0x44); + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x3); + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0x0C000000, 0x2); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_A_0x0[19:16] = 1, Standby mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_B_0x0[19:16] = 1, Standby mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_C, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_C_0x0[19:16] = 3, RX mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_D, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_D_0x0[19:16] = 1, Standby mode*/ + /*/ CCA related PD_delay_th*/ + phy_set_bb_reg(pAdapter, rAGC_table_Jaguar, 0x0F000000, 0x5); + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, 0x0000000F, 0xA); + break; + + case ANTENNA_D: + /*pHalData->ValidRxPath = 0x08;*/ + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x2); + phy_set_bb_reg(pAdapter, rRxPath_Jaguar, bMaskByte0, 0x88); + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x3); + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0x0C000000, 0x3); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_A_0x0[19:16] = 1, Standby mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_B_0x0[19:16] = 1, Standby mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_C, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_C_0x0[19:16] = 1, Standby mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_D, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_D_0x0[19:16] = 3, RX mode*/ + /*/ CCA related PD_delay_th*/ + phy_set_bb_reg(pAdapter, rAGC_table_Jaguar, 0x0F000000, 0x5); + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, 0x0000000F, 0xA); + break; + + case ANTENNA_BC: + /*pHalData->ValidRxPath = 0x06;*/ + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x2); + phy_set_bb_reg(pAdapter, rRxPath_Jaguar, bMaskByte0, 0x66); + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x3); + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0x0f000000, 0x6); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_A_0x0[19:16] = 1, Standby mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_B_0x0[19:16] = 3, RX mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_C, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_C_0x0[19:16] = 3, Rx mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_D, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_D_0x0[19:16] = 1, Standby mode*/ + /*/ CCA related PD_delay_th*/ + phy_set_bb_reg(pAdapter, rAGC_table_Jaguar, 0x0F000000, 0x5); + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, 0x0000000F, 0xA); + break; + + case ANTENNA_CD: + /*pHalData->ValidRxPath = 0x0C;*/ + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x2); + phy_set_bb_reg(pAdapter, rRxPath_Jaguar, bMaskByte0, 0xcc); + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x3); + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0x0f000000, 0xB); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_A_0x0[19:16] = 1, Standby mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_B_0x0[19:16] = 1, Standby mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_C, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_C_0x0[19:16] = 3, Rx mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_D, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_D_0x0[19:16] = 3, RX mode*/ + /*/ CCA related PD_delay_th*/ + phy_set_bb_reg(pAdapter, rAGC_table_Jaguar, 0x0F000000, 0x5); + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, 0x0000000F, 0xA); + break; + + case ANTENNA_BCD: + /*pHalData->ValidRxPath = 0x0e;*/ + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x2); + phy_set_bb_reg(pAdapter, rRxPath_Jaguar, bMaskByte0, 0xee); + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x3); + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0x0f000000, 0x6); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_A_0x0[19:16] = 1, Standby mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_B_0x0[19:16] = 3, RX mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_C, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_C_0x0[19:16] = 3, RX mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_D, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_D_0x0[19:16] = 3, Rx mode*/ + /*/ CCA related PD_delay_th*/ + phy_set_bb_reg(pAdapter, rAGC_table_Jaguar, 0x0F000000, 0x3); + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, 0x0000000F, 0x8); + break; + + case ANTENNA_ABCD: + /*pHalData->ValidRxPath = 0x0f;*/ + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x2); + phy_set_bb_reg(pAdapter, rRxPath_Jaguar, bMaskByte0, 0xff); + phy_set_bb_reg(pAdapter, 0x1000, bMaskByte2, 0x3); + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, 0x0f000000, 0x1); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_A_0x0[19:16] = 3, RX mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_B_0x0[19:16] = 3, RX mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_C, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_C_0x0[19:16] = 3, RX mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_D, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_D_0x0[19:16] = 3, RX mode*/ + /*/ CCA related PD_delay_th*/ + phy_set_bb_reg(pAdapter, rAGC_table_Jaguar, 0x0F000000, 0x3); + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, 0x0000000F, 0x8); + break; + + default: + break; + } + + PHY_Set_SecCCATH_by_RXANT_8814A(pAdapter, ulAntennaRx); + + mpt_ToggleIG_8814A(pAdapter); +} +#endif /* CONFIG_RTL8814A */ +#if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) +VOID +mpt_SetSingleTone_8814A( + IN PADAPTER pAdapter, + IN BOOLEAN bSingleTone, + IN BOOLEAN bEnPMacTx) +{ + + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + u1Byte StartPath = ODM_RF_PATH_A, EndPath = ODM_RF_PATH_A; + static u4Byte regIG0 = 0, regIG1 = 0, regIG2 = 0, regIG3 = 0; + + if (bSingleTone) { + regIG0 = phy_query_bb_reg(pAdapter, rA_TxScale_Jaguar, bMaskDWord); /*/ 0xC1C[31:21]*/ + regIG1 = phy_query_bb_reg(pAdapter, rB_TxScale_Jaguar, bMaskDWord); /*/ 0xE1C[31:21]*/ + regIG2 = phy_query_bb_reg(pAdapter, rC_TxScale_Jaguar2, bMaskDWord); /*/ 0x181C[31:21]*/ + regIG3 = phy_query_bb_reg(pAdapter, rD_TxScale_Jaguar2, bMaskDWord); /*/ 0x1A1C[31:21]*/ + + switch (pMptCtx->mpt_rf_path) { + case ODM_RF_PATH_A: + case ODM_RF_PATH_B: + case ODM_RF_PATH_C: + case ODM_RF_PATH_D: + StartPath = pMptCtx->mpt_rf_path; + EndPath = pMptCtx->mpt_rf_path; + break; + case ODM_RF_PATH_AB: + EndPath = ODM_RF_PATH_B; + break; + case ODM_RF_PATH_BC: + StartPath = ODM_RF_PATH_B; + EndPath = ODM_RF_PATH_C; + break; + case ODM_RF_PATH_ABC: + EndPath = ODM_RF_PATH_C; + break; + case ODM_RF_PATH_BCD: + StartPath = ODM_RF_PATH_B; + EndPath = ODM_RF_PATH_D; + break; + case ODM_RF_PATH_ABCD: + EndPath = ODM_RF_PATH_D; + break; + } + + if (bEnPMacTx == FALSE) { + hal_mpt_SetContinuousTx(pAdapter, _TRUE); + issue_nulldata(pAdapter, NULL, 1, 3, 500); + } + + phy_set_bb_reg(pAdapter, rCCAonSec_Jaguar, BIT1, 0x1); /*/ Disable CCA*/ + + for (StartPath; StartPath <= EndPath; StartPath++) { + phy_set_rf_reg(pAdapter, StartPath, RF_AC_Jaguar, 0xF0000, 0x2); /*/ Tx mode: RF0x00[19:16]=4'b0010 */ + phy_set_rf_reg(pAdapter, StartPath, RF_AC_Jaguar, 0x1F, 0x0); /*/ Lowest RF gain index: RF_0x0[4:0] = 0*/ + + phy_set_rf_reg(pAdapter, StartPath, lna_low_gain_3, BIT1, 0x1); /*/ RF LO enabled*/ + } + + phy_set_bb_reg(pAdapter, rA_TxScale_Jaguar, 0xFFE00000, 0); /*/ 0xC1C[31:21]*/ + phy_set_bb_reg(pAdapter, rB_TxScale_Jaguar, 0xFFE00000, 0); /*/ 0xE1C[31:21]*/ + phy_set_bb_reg(pAdapter, rC_TxScale_Jaguar2, 0xFFE00000, 0); /*/ 0x181C[31:21]*/ + phy_set_bb_reg(pAdapter, rD_TxScale_Jaguar2, 0xFFE00000, 0); /*/ 0x1A1C[31:21]*/ + } else { + switch (pMptCtx->mpt_rf_path) { + case ODM_RF_PATH_A: + case ODM_RF_PATH_B: + case ODM_RF_PATH_C: + case ODM_RF_PATH_D: + StartPath = pMptCtx->mpt_rf_path; + EndPath = pMptCtx->mpt_rf_path; + break; + case ODM_RF_PATH_AB: + EndPath = ODM_RF_PATH_B; + break; + case ODM_RF_PATH_BC: + StartPath = ODM_RF_PATH_B; + EndPath = ODM_RF_PATH_C; + break; + case ODM_RF_PATH_ABC: + EndPath = ODM_RF_PATH_C; + break; + case ODM_RF_PATH_BCD: + StartPath = ODM_RF_PATH_B; + EndPath = ODM_RF_PATH_D; + break; + case ODM_RF_PATH_ABCD: + EndPath = ODM_RF_PATH_D; + break; + } + for (StartPath; StartPath <= EndPath; StartPath++) + phy_set_rf_reg(pAdapter, StartPath, lna_low_gain_3, BIT1, 0x0); /* RF LO disabled */ + + phy_set_bb_reg(pAdapter, rCCAonSec_Jaguar, BIT1, 0x0); /* Enable CCA*/ + + if (bEnPMacTx == FALSE) + hal_mpt_SetContinuousTx(pAdapter, _FALSE); + + phy_set_bb_reg(pAdapter, rA_TxScale_Jaguar, bMaskDWord, regIG0); /* 0xC1C[31:21]*/ + phy_set_bb_reg(pAdapter, rB_TxScale_Jaguar, bMaskDWord, regIG1); /* 0xE1C[31:21]*/ + phy_set_bb_reg(pAdapter, rC_TxScale_Jaguar2, bMaskDWord, regIG2); /* 0x181C[31:21]*/ + phy_set_bb_reg(pAdapter, rD_TxScale_Jaguar2, bMaskDWord, regIG3); /* 0x1A1C[31:21]*/ + } +} + +#endif + +#if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) +void mpt_SetRFPath_8812A(PADAPTER pAdapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMPT_CONTEXT pMptCtx = &pAdapter->mppriv.mpt_ctx; + struct mp_priv *pmp = &pAdapter->mppriv; + u8 channel = pmp->channel; + u8 bandwidth = pmp->bandwidth; + u8 eLNA_2g = pHalData->ExternalLNA_2G; + u32 ulAntennaTx, ulAntennaRx; + + ulAntennaTx = pHalData->antenna_tx_path; + ulAntennaRx = pHalData->AntennaRxPath; + + switch (ulAntennaTx) { + case ANTENNA_A: + pMptCtx->mpt_rf_path = ODM_RF_PATH_A; + phy_set_bb_reg(pAdapter, rTxPath_Jaguar, bMaskLWord, 0x1111); + if (pHalData->rfe_type == 3 && IS_HARDWARE_TYPE_8812(pAdapter)) + phy_set_bb_reg(pAdapter, r_ANTSEL_SW_Jaguar, bMask_AntselPathFollow_Jaguar, 0x0); + break; + case ANTENNA_B: + pMptCtx->mpt_rf_path = ODM_RF_PATH_B; + phy_set_bb_reg(pAdapter, rTxPath_Jaguar, bMaskLWord, 0x2222); + if (pHalData->rfe_type == 3 && IS_HARDWARE_TYPE_8812(pAdapter)) + phy_set_bb_reg(pAdapter, r_ANTSEL_SW_Jaguar, bMask_AntselPathFollow_Jaguar, 0x1); + break; + case ANTENNA_AB: + pMptCtx->mpt_rf_path = ODM_RF_PATH_AB; + phy_set_bb_reg(pAdapter, rTxPath_Jaguar, bMaskLWord, 0x3333); + if (pHalData->rfe_type == 3 && IS_HARDWARE_TYPE_8812(pAdapter)) + phy_set_bb_reg(pAdapter, r_ANTSEL_SW_Jaguar, bMask_AntselPathFollow_Jaguar, 0x0); + break; + default: + pMptCtx->mpt_rf_path = ODM_RF_PATH_AB; + RTW_INFO("Unknown Tx antenna.\n"); + break; + } + + switch (ulAntennaRx) { + u32 reg0xC50 = 0; + case ANTENNA_A: + phy_set_bb_reg(pAdapter, rRxPath_Jaguar, bMaskByte0, 0x11); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_AC_Jaguar, 0xF0000, 0x1); /*/ RF_B_0x0[19:16] = 1, Standby mode*/ + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, bCCK_RX_Jaguar, 0x0); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC_Jaguar, BIT19 | BIT18 | BIT17 | BIT16, 0x3); + + /*/ <20121101, Kordan> To prevent gain table from not switched, asked by Ynlin.*/ + reg0xC50 = phy_query_bb_reg(pAdapter, rA_IGI_Jaguar, bMaskByte0); + phy_set_bb_reg(pAdapter, rA_IGI_Jaguar, bMaskByte0, reg0xC50 + 2); + phy_set_bb_reg(pAdapter, rA_IGI_Jaguar, bMaskByte0, reg0xC50); + + /* set PWED_TH for BB Yn user guide R29 */ + if (IS_HARDWARE_TYPE_8812(pAdapter)) { + if (channel <= 14) { /* 2.4G */ + if (bandwidth == CHANNEL_WIDTH_20 + && eLNA_2g == 0) { + /* 0x830[3:1]=3'b010 */ + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, BIT1 | BIT2 | BIT3, 0x02); + } else + /* 0x830[3:1]=3'b100 */ + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, BIT1 | BIT2 | BIT3, 0x04); + } else + /* 0x830[3:1]=3'b100 for 5G */ + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, BIT1 | BIT2 | BIT3, 0x04); + } + break; + case ANTENNA_B: + phy_set_bb_reg(pAdapter, rRxPath_Jaguar, bMaskByte0, 0x22); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC_Jaguar, 0xF0000, 0x1);/*/ RF_A_0x0[19:16] = 1, Standby mode */ + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, bCCK_RX_Jaguar, 0x1); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_AC_Jaguar, BIT19 | BIT18 | BIT17 | BIT16, 0x3); + + /*/ <20121101, Kordan> To prevent gain table from not switched, asked by Ynlin.*/ + reg0xC50 = phy_query_bb_reg(pAdapter, rB_IGI_Jaguar, bMaskByte0); + phy_set_bb_reg(pAdapter, rB_IGI_Jaguar, bMaskByte0, reg0xC50 + 2); + phy_set_bb_reg(pAdapter, rB_IGI_Jaguar, bMaskByte0, reg0xC50); + + /* set PWED_TH for BB Yn user guide R29 */ + if (IS_HARDWARE_TYPE_8812(pAdapter)) { + if (channel <= 14) { + if (bandwidth == CHANNEL_WIDTH_20 + && eLNA_2g == 0) { + /* 0x830[3:1]=3'b010 */ + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, BIT1 | BIT2 | BIT3, 0x02); + } else + /* 0x830[3:1]=3'b100 */ + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, BIT1 | BIT2 | BIT3, 0x04); + } else + /* 0x830[3:1]=3'b100 for 5G */ + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, BIT1 | BIT2 | BIT3, 0x04); + } + break; + case ANTENNA_AB: + phy_set_bb_reg(pAdapter, rRxPath_Jaguar, bMaskByte0, 0x33); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_B, RF_AC_Jaguar, 0xF0000, 0x3); /*/ RF_B_0x0[19:16] = 3, Rx mode*/ + phy_set_bb_reg(pAdapter, rCCK_RX_Jaguar, bCCK_RX_Jaguar, 0x0); + /* set PWED_TH for BB Yn user guide R29 */ + phy_set_bb_reg(pAdapter, rPwed_TH_Jaguar, BIT1 | BIT2 | BIT3, 0x04); + break; + default: + RTW_INFO("Unknown Rx antenna.\n"); + break; + } +} +#endif + +#ifdef CONFIG_RTL8723B +void mpt_SetRFPath_8723B(PADAPTER pAdapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + u32 ulAntennaTx, ulAntennaRx; + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + struct odm_rf_calibration_structure *pRFCalibrateInfo = &(pDM_Odm->rf_calibrate_info); + + ulAntennaTx = pHalData->antenna_tx_path; + ulAntennaRx = pHalData->AntennaRxPath; + + if (pHalData->rf_chip >= RF_TYPE_MAX) { + RTW_INFO("This RF chip ID is not supported\n"); + return; + } + + switch (pAdapter->mppriv.antenna_tx) { + u8 p = 0, i = 0; + case ANTENNA_A: { /*/ Actually path S1 (Wi-Fi)*/ + pMptCtx->mpt_rf_path = ODM_RF_PATH_A; + phy_set_bb_reg(pAdapter, rS0S1_PathSwitch, BIT9 | BIT8 | BIT7, 0x0); + phy_set_bb_reg(pAdapter, 0xB2C, BIT31, 0x0); /* AGC Table Sel*/ + + /*/<20130522, Kordan> 0x51 and 0x71 should be set immediately after path switched, or they might be overwritten.*/ + if ((pHalData->PackageType == PACKAGE_TFBGA79) || (pHalData->PackageType == PACKAGE_TFBGA90)) + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x51, bRFRegOffsetMask, 0x6B10E); + else + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x51, bRFRegOffsetMask, 0x6B04E); + + for (i = 0; i < 3; ++i) { + u4Byte offset = pRFCalibrateInfo->tx_iqc_8723b[ODM_RF_PATH_A][i][0]; + u4Byte data = pRFCalibrateInfo->tx_iqc_8723b[ODM_RF_PATH_A][i][1]; + + if (offset != 0) { + phy_set_bb_reg(pAdapter, offset, bMaskDWord, data); + RTW_INFO("Switch to S1 TxIQC(offset, data) = (0x%X, 0x%X)\n", offset, data); + } + } + for (i = 0; i < 2; ++i) { + u4Byte offset = pRFCalibrateInfo->rx_iqc_8723b[ODM_RF_PATH_A][i][0]; + u4Byte data = pRFCalibrateInfo->rx_iqc_8723b[ODM_RF_PATH_A][i][1]; + + if (offset != 0) { + phy_set_bb_reg(pAdapter, offset, bMaskDWord, data); + RTW_INFO("Switch to S1 RxIQC (offset, data) = (0x%X, 0x%X)\n", offset, data); + } + } + } + break; + case ANTENNA_B: { /*/ Actually path S0 (BT)*/ + u4Byte offset; + u4Byte data; + + pMptCtx->mpt_rf_path = ODM_RF_PATH_B; + phy_set_bb_reg(pAdapter, rS0S1_PathSwitch, BIT9 | BIT8 | BIT7, 0x5); + phy_set_bb_reg(pAdapter, 0xB2C, BIT31, 0x1); /*/ AGC Table Sel.*/ + /* <20130522, Kordan> 0x51 and 0x71 should be set immediately after path switched, or they might be overwritten.*/ + if ((pHalData->PackageType == PACKAGE_TFBGA79) || (pHalData->PackageType == PACKAGE_TFBGA90)) + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x51, bRFRegOffsetMask, 0x6B10E); + else + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x51, bRFRegOffsetMask, 0x6B04E); + + for (i = 0; i < 3; ++i) { + /*/ <20130603, Kordan> Because BB suppors only 1T1R, we restore IQC to S1 instead of S0.*/ + offset = pRFCalibrateInfo->tx_iqc_8723b[ODM_RF_PATH_A][i][0]; + data = pRFCalibrateInfo->tx_iqc_8723b[ODM_RF_PATH_B][i][1]; + if (pRFCalibrateInfo->tx_iqc_8723b[ODM_RF_PATH_B][i][0] != 0) { + phy_set_bb_reg(pAdapter, offset, bMaskDWord, data); + RTW_INFO("Switch to S0 TxIQC (offset, data) = (0x%X, 0x%X)\n", offset, data); + } + } + /*/ <20130603, Kordan> Because BB suppors only 1T1R, we restore IQC to S1 instead of S0.*/ + for (i = 0; i < 2; ++i) { + offset = pRFCalibrateInfo->rx_iqc_8723b[ODM_RF_PATH_A][i][0]; + data = pRFCalibrateInfo->rx_iqc_8723b[ODM_RF_PATH_B][i][1]; + if (pRFCalibrateInfo->rx_iqc_8723b[ODM_RF_PATH_B][i][0] != 0) { + phy_set_bb_reg(pAdapter, offset, bMaskDWord, data); + RTW_INFO("Switch to S0 RxIQC (offset, data) = (0x%X, 0x%X)\n", offset, data); + } + } + } + break; + default: + pMptCtx->mpt_rf_path = RF_PATH_AB; + break; + } +} +#endif + +#ifdef CONFIG_RTL8703B +void mpt_SetRFPath_8703B(PADAPTER pAdapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + u4Byte ulAntennaTx, ulAntennaRx; + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + struct odm_rf_calibration_structure *pRFCalibrateInfo = &(pDM_Odm->rf_calibrate_info); + + ulAntennaTx = pHalData->antenna_tx_path; + ulAntennaRx = pHalData->AntennaRxPath; + + if (pHalData->rf_chip >= RF_TYPE_MAX) { + RTW_INFO("This RF chip ID is not supported\n"); + return; + } + + switch (pAdapter->mppriv.antenna_tx) { + u1Byte p = 0, i = 0; + + case ANTENNA_A: { /* Actually path S1 (Wi-Fi) */ + pMptCtx->mpt_rf_path = ODM_RF_PATH_A; + phy_set_bb_reg(pAdapter, rS0S1_PathSwitch, BIT9 | BIT8 | BIT7, 0x0); + phy_set_bb_reg(pAdapter, 0xB2C, BIT31, 0x0); /* AGC Table Sel*/ + + for (i = 0; i < 3; ++i) { + u4Byte offset = pRFCalibrateInfo->tx_iqc_8703b[i][0]; + u4Byte data = pRFCalibrateInfo->tx_iqc_8703b[i][1]; + + if (offset != 0) { + phy_set_bb_reg(pAdapter, offset, bMaskDWord, data); + RTW_INFO("Switch to S1 TxIQC(offset, data) = (0x%X, 0x%X)\n", offset, data); + } + + } + for (i = 0; i < 2; ++i) { + u4Byte offset = pRFCalibrateInfo->rx_iqc_8703b[i][0]; + u4Byte data = pRFCalibrateInfo->rx_iqc_8703b[i][1]; + + if (offset != 0) { + phy_set_bb_reg(pAdapter, offset, bMaskDWord, data); + RTW_INFO("Switch to S1 RxIQC (offset, data) = (0x%X, 0x%X)\n", offset, data); + } + } + } + break; + case ANTENNA_B: { /* Actually path S0 (BT)*/ + pMptCtx->mpt_rf_path = ODM_RF_PATH_B; + phy_set_bb_reg(pAdapter, rS0S1_PathSwitch, BIT9 | BIT8 | BIT7, 0x5); + phy_set_bb_reg(pAdapter, 0xB2C, BIT31, 0x1); /* AGC Table Sel */ + + for (i = 0; i < 3; ++i) { + u4Byte offset = pRFCalibrateInfo->tx_iqc_8703b[i][0]; + u4Byte data = pRFCalibrateInfo->tx_iqc_8703b[i][1]; + + if (pRFCalibrateInfo->tx_iqc_8703b[i][0] != 0) { + phy_set_bb_reg(pAdapter, offset, bMaskDWord, data); + RTW_INFO("Switch to S0 TxIQC (offset, data) = (0x%X, 0x%X)\n", offset, data); + } + } + for (i = 0; i < 2; ++i) { + u4Byte offset = pRFCalibrateInfo->rx_iqc_8703b[i][0]; + u4Byte data = pRFCalibrateInfo->rx_iqc_8703b[i][1]; + + if (pRFCalibrateInfo->rx_iqc_8703b[i][0] != 0) { + phy_set_bb_reg(pAdapter, offset, bMaskDWord, data); + RTW_INFO("Switch to S0 RxIQC (offset, data) = (0x%X, 0x%X)\n", offset, data); + } + } + } + break; + default: + pMptCtx->mpt_rf_path = RF_PATH_AB; + break; + } + +} +#endif + +#ifdef CONFIG_RTL8723D +void mpt_SetRFPath_8723D(PADAPTER pAdapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + u1Byte p = 0, i = 0; + u4Byte ulAntennaTx, ulAntennaRx, offset = 0, data = 0, val32 = 0; + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + struct PHY_DM_STRUCT *pDM_Odm = &pHalData->odmpriv; + struct odm_rf_calibration_structure *pRFCalibrateInfo = &(pDM_Odm->rf_calibrate_info); + + ulAntennaTx = pHalData->antenna_tx_path; + ulAntennaRx = pHalData->AntennaRxPath; + + if (pHalData->rf_chip >= RF_TYPE_MAX) { + RTW_INFO("This RF chip ID is not supported\n"); + return; + } + + switch (pAdapter->mppriv.antenna_tx) { + /* Actually path S1 (Wi-Fi) */ + case ANTENNA_A: { + pMptCtx->mpt_rf_path = ODM_RF_PATH_A; + phy_set_bb_reg(pAdapter, rS0S1_PathSwitch, BIT9|BIT8|BIT7|BIT6, 0); + } + break; + /* Actually path S0 (BT) */ + case ANTENNA_B: { + pMptCtx->mpt_rf_path = ODM_RF_PATH_B; + phy_set_bb_reg(pAdapter, rS0S1_PathSwitch, BIT9|BIT8|BIT7|BIT6, 0xA); + + } + break; + default: + pMptCtx->mpt_rf_path = RF_PATH_AB; + break; + } +} +#endif + +VOID mpt_SetRFPath_819X(PADAPTER pAdapter) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + u4Byte ulAntennaTx, ulAntennaRx; + R_ANTENNA_SELECT_OFDM *p_ofdm_tx; /* OFDM Tx register */ + R_ANTENNA_SELECT_CCK *p_cck_txrx; + u1Byte r_rx_antenna_ofdm = 0, r_ant_select_cck_val = 0; + u1Byte chgTx = 0, chgRx = 0; + u4Byte r_ant_sel_cck_val = 0, r_ant_select_ofdm_val = 0, r_ofdm_tx_en_val = 0; + + ulAntennaTx = pHalData->antenna_tx_path; + ulAntennaRx = pHalData->AntennaRxPath; + + p_ofdm_tx = (R_ANTENNA_SELECT_OFDM *)&r_ant_select_ofdm_val; + p_cck_txrx = (R_ANTENNA_SELECT_CCK *)&r_ant_select_cck_val; + + p_ofdm_tx->r_ant_ht1 = 0x1; + p_ofdm_tx->r_ant_ht2 = 0x2;/*Second TX RF path is A*/ + p_ofdm_tx->r_ant_non_ht = 0x3;/*/ 0x1+0x2=0x3 */ + + switch (ulAntennaTx) { + case ANTENNA_A: + p_ofdm_tx->r_tx_antenna = 0x1; + r_ofdm_tx_en_val = 0x1; + p_ofdm_tx->r_ant_l = 0x1; + p_ofdm_tx->r_ant_ht_s1 = 0x1; + p_ofdm_tx->r_ant_non_ht_s1 = 0x1; + p_cck_txrx->r_ccktx_enable = 0x8; + chgTx = 1; + /*/ From SD3 Willis suggestion !!! Set RF A=TX and B as standby*/ + /*/if (IS_HARDWARE_TYPE_8192S(pAdapter))*/ + { + phy_set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2); + phy_set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 1); + r_ofdm_tx_en_val = 0x3; + /*/ Power save*/ + /*/cosa r_ant_select_ofdm_val = 0x11111111;*/ + /*/ We need to close RFB by SW control*/ + if (pHalData->rf_type == RF_2T2R) { + phy_set_bb_reg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0); + phy_set_bb_reg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 1); + phy_set_bb_reg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0); + phy_set_bb_reg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 1); + phy_set_bb_reg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 0); + } + } + pMptCtx->mpt_rf_path = ODM_RF_PATH_A; + break; + case ANTENNA_B: + p_ofdm_tx->r_tx_antenna = 0x2; + r_ofdm_tx_en_val = 0x2; + p_ofdm_tx->r_ant_l = 0x2; + p_ofdm_tx->r_ant_ht_s1 = 0x2; + p_ofdm_tx->r_ant_non_ht_s1 = 0x2; + p_cck_txrx->r_ccktx_enable = 0x4; + chgTx = 1; + /*/ From SD3 Willis suggestion !!! Set RF A as standby*/ + /*/if (IS_HARDWARE_TYPE_8192S(pAdapter))*/ + { + phy_set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 1); + phy_set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2); + + /*/ 2008/10/31 MH From SD3 Willi's suggestion. We must read RF 1T table.*/ + /*/ 2009/01/08 MH From Sd3 Willis. We need to close RFA by SW control*/ + if (pHalData->rf_type == RF_2T2R || pHalData->rf_type == RF_1T2R) { + phy_set_bb_reg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 1); + phy_set_bb_reg(pAdapter, rFPGA0_XA_RFInterfaceOE, BIT10, 0); + phy_set_bb_reg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0); + /*/phy_set_bb_reg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0);*/ + phy_set_bb_reg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 0); + phy_set_bb_reg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 1); + } + } + pMptCtx->mpt_rf_path = ODM_RF_PATH_B; + break; + case ANTENNA_AB:/*/ For 8192S*/ + p_ofdm_tx->r_tx_antenna = 0x3; + r_ofdm_tx_en_val = 0x3; + p_ofdm_tx->r_ant_l = 0x3; + p_ofdm_tx->r_ant_ht_s1 = 0x3; + p_ofdm_tx->r_ant_non_ht_s1 = 0x3; + p_cck_txrx->r_ccktx_enable = 0xC; + chgTx = 1; + /*/ From SD3Willis suggestion !!! Set RF B as standby*/ + /*/if (IS_HARDWARE_TYPE_8192S(pAdapter))*/ + { + phy_set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter2, 0xe, 2); + phy_set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter2, 0xe, 2); + /* Disable Power save*/ + /*cosa r_ant_select_ofdm_val = 0x3321333;*/ + /* 2009/01/08 MH From Sd3 Willis. We need to enable RFA/B by SW control*/ + if (pHalData->rf_type == RF_2T2R) { + phy_set_bb_reg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0); + + phy_set_bb_reg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0); + /*/phy_set_bb_reg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0);*/ + phy_set_bb_reg(pAdapter, rFPGA0_XAB_RFParameter, BIT1, 1); + phy_set_bb_reg(pAdapter, rFPGA0_XAB_RFParameter, BIT17, 1); + } + } + pMptCtx->mpt_rf_path = ODM_RF_PATH_AB; + break; + default: + break; + } +#if 0 + /* r_rx_antenna_ofdm, bit0=A, bit1=B, bit2=C, bit3=D */ + /* r_cckrx_enable : CCK default, 0=A, 1=B, 2=C, 3=D */ + /* r_cckrx_enable_2 : CCK option, 0=A, 1=B, 2=C, 3=D */ +#endif + switch (ulAntennaRx) { + case ANTENNA_A: + r_rx_antenna_ofdm = 0x1; /* A*/ + p_cck_txrx->r_cckrx_enable = 0x0; /* default: A*/ + p_cck_txrx->r_cckrx_enable_2 = 0x0; /* option: A*/ + chgRx = 1; + break; + case ANTENNA_B: + r_rx_antenna_ofdm = 0x2; /*/ B*/ + p_cck_txrx->r_cckrx_enable = 0x1; /*/ default: B*/ + p_cck_txrx->r_cckrx_enable_2 = 0x1; /*/ option: B*/ + chgRx = 1; + break; + case ANTENNA_AB:/*/ For 8192S and 8192E/U...*/ + r_rx_antenna_ofdm = 0x3;/*/ AB*/ + p_cck_txrx->r_cckrx_enable = 0x0;/*/ default:A*/ + p_cck_txrx->r_cckrx_enable_2 = 0x1;/*/ option:B*/ + chgRx = 1; + break; + default: + break; + } + + + if (chgTx && chgRx) { + switch (pHalData->rf_chip) { + case RF_8225: + case RF_8256: + case RF_6052: + /*/r_ant_sel_cck_val = r_ant_select_cck_val;*/ + phy_set_bb_reg(pAdapter, rFPGA1_TxInfo, 0x7fffffff, r_ant_select_ofdm_val); /*/OFDM Tx*/ + phy_set_bb_reg(pAdapter, rFPGA0_TxInfo, 0x0000000f, r_ofdm_tx_en_val); /*/OFDM Tx*/ + phy_set_bb_reg(pAdapter, rOFDM0_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm); /*/OFDM Rx*/ + phy_set_bb_reg(pAdapter, rOFDM1_TRxPathEnable, 0x0000000f, r_rx_antenna_ofdm); /*/OFDM Rx*/ + if (IS_HARDWARE_TYPE_8192E(pAdapter)) { + phy_set_bb_reg(pAdapter, rOFDM0_TRxPathEnable, 0x000000F0, r_rx_antenna_ofdm); /*/OFDM Rx*/ + phy_set_bb_reg(pAdapter, rOFDM1_TRxPathEnable, 0x000000F0, r_rx_antenna_ofdm); /*/OFDM Rx*/ + } + phy_set_bb_reg(pAdapter, rCCK0_AFESetting, bMaskByte3, r_ant_select_cck_val);/*/r_ant_sel_cck_val); /CCK TxRx*/ + break; + + default: + RTW_INFO("Unsupported RFChipID for switching antenna.\n"); + break; + } + } +} /* MPT_ProSetRFPath */ + + +void hal_mpt_SetAntenna(PADAPTER pAdapter) + +{ + RTW_INFO("Do %s\n", __func__); +#ifdef CONFIG_RTL8814A + if (IS_HARDWARE_TYPE_8814A(pAdapter)) { + mpt_SetRFPath_8814A(pAdapter); + return; + } +#endif +#ifdef CONFIG_RTL8822B + if (IS_HARDWARE_TYPE_8822B(pAdapter)) { + rtl8822b_mp_config_rfpath(pAdapter); + return; + } +#endif +#ifdef CONFIG_RTL8821C + if (IS_HARDWARE_TYPE_8821C(pAdapter)) { + rtl8821c_mp_config_rfpath(pAdapter); + return; + } +#endif +#if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) + if (IS_HARDWARE_TYPE_JAGUAR(pAdapter)) { + mpt_SetRFPath_8812A(pAdapter); + return; + } +#endif +#ifdef CONFIG_RTL8723B + if (IS_HARDWARE_TYPE_8723B(pAdapter)) { + mpt_SetRFPath_8723B(pAdapter); + return; + } +#endif + +#ifdef CONFIG_RTL8703B + if (IS_HARDWARE_TYPE_8703B(pAdapter)) { + mpt_SetRFPath_8703B(pAdapter); + return; + } +#endif + +#ifdef CONFIG_RTL8723D + if (IS_HARDWARE_TYPE_8723D(pAdapter)) { + mpt_SetRFPath_8723D(pAdapter); + return; + } +#endif + /* else if (IS_HARDWARE_TYPE_8821B(pAdapter)) + mpt_SetRFPath_8821B(pAdapter); + Prepare for 8822B + else if (IS_HARDWARE_TYPE_8822B(Context)) + mpt_SetRFPath_8822B(Context); + */ + mpt_SetRFPath_819X(pAdapter); + RTW_INFO("mpt_SetRFPath_819X Do %s\n", __func__); +} + +s32 hal_mpt_SetThermalMeter(PADAPTER pAdapter, u8 target_ther) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + if (!netif_running(pAdapter->pnetdev)) { + return _FAIL; + } + + + if (check_fwstate(&pAdapter->mlmepriv, WIFI_MP_STATE) == _FALSE) { + return _FAIL; + } + + + target_ther &= 0xff; + if (target_ther < 0x07) + target_ther = 0x07; + else if (target_ther > 0x1d) + target_ther = 0x1d; + + pHalData->eeprom_thermal_meter = target_ther; + + return _SUCCESS; +} + + +void hal_mpt_TriggerRFThermalMeter(PADAPTER pAdapter) +{ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x42, BIT17 | BIT16, 0x03); + +} + + +u8 hal_mpt_ReadRFThermalMeter(PADAPTER pAdapter) + +{ + u32 ThermalValue = 0; + + ThermalValue = (u1Byte)phy_query_rf_reg(pAdapter, ODM_RF_PATH_A, 0x42, 0xfc00); /*0x42: RF Reg[15:10]*/ + return (u8)ThermalValue; + +} + + +void hal_mpt_GetThermalMeter(PADAPTER pAdapter, u8 *value) +{ +#if 0 + fw_cmd(pAdapter, IOCMD_GET_THERMAL_METER); + rtw_msleep_os(1000); + fw_cmd_data(pAdapter, value, 1); + *value &= 0xFF; +#else + hal_mpt_TriggerRFThermalMeter(pAdapter); + rtw_msleep_os(1000); + *value = hal_mpt_ReadRFThermalMeter(pAdapter); +#endif + +} + + +void hal_mpt_SetSingleCarrierTx(PADAPTER pAdapter, u8 bStart) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + + pAdapter->mppriv.mpt_ctx.bSingleCarrier = bStart; + + if (bStart) {/*/ Start Single Carrier.*/ + /*/ Start Single Carrier.*/ + /*/ 1. if OFDM block on?*/ + if (!phy_query_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn)) + phy_set_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 1); /*set OFDM block on*/ + + /*/ 2. set CCK test mode off, set to CCK normal mode*/ + phy_set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, 0); + + /*/ 3. turn on scramble setting*/ + phy_set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, 1); + + /*/ 4. Turn On Continue Tx and turn off the other test modes.*/ +#if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) || defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) + if (IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(pAdapter)) + phy_set_bb_reg(pAdapter, rSingleTone_ContTx_Jaguar, BIT18 | BIT17 | BIT16, OFDM_SingleCarrier); + else +#endif /* CONFIG_RTL8812A || CONFIG_RTL8821A || CONFIG_RTL8814A || CONFIG_RTL8822B || CONFIG_RTL8821C */ + phy_set_bb_reg(pAdapter, rOFDM1_LSTF, BIT30 | BIT29 | BIT28, OFDM_SingleCarrier); + + } else { + /*/ Stop Single Carrier.*/ + /*/ Stop Single Carrier.*/ + /*/ Turn off all test modes.*/ +#if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) || defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) + if (IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(pAdapter)) + phy_set_bb_reg(pAdapter, rSingleTone_ContTx_Jaguar, BIT18 | BIT17 | BIT16, OFDM_ALL_OFF); + else +#endif /* CONFIG_RTL8812A || CONFIG_RTL8821A || CONFIG_RTL8814A || CONFIG_RTL8822B || CONFIG_RTL8821C */ + phy_set_bb_reg(pAdapter, rOFDM1_LSTF, BIT30 | BIT29 | BIT28, OFDM_ALL_OFF); + + rtw_msleep_os(10); + /*/BB Reset*/ + phy_set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); + phy_set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); + } +} + + +void hal_mpt_SetSingleToneTx(PADAPTER pAdapter, u8 bStart) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + u4Byte ulAntennaTx = pHalData->antenna_tx_path; + static u4Byte regRF = 0, regBB0 = 0, regBB1 = 0, regBB2 = 0, regBB3 = 0; + u8 rfPath; + + switch (ulAntennaTx) { + case ANTENNA_B: + rfPath = ODM_RF_PATH_B; + break; + case ANTENNA_C: + rfPath = ODM_RF_PATH_C; + break; + case ANTENNA_D: + rfPath = ODM_RF_PATH_D; + break; + case ANTENNA_A: + default: + rfPath = ODM_RF_PATH_A; + break; + } + + pAdapter->mppriv.mpt_ctx.is_single_tone = bStart; + if (bStart) { + /*/ Start Single Tone.*/ + /*/ <20120326, Kordan> To amplify the power of tone for Xtal calibration. (asked by Edlu)*/ + if (IS_HARDWARE_TYPE_8188E(pAdapter)) { + regRF = phy_query_rf_reg(pAdapter, rfPath, lna_low_gain_3, bRFRegOffsetMask); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, lna_low_gain_3, BIT1, 0x1); /*/ RF LO enabled*/ + phy_set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x0); + phy_set_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x0); + } else if (IS_HARDWARE_TYPE_8192E(pAdapter)) { /*/ USB need to do RF LO disable first, PCIE isn't required to follow this order.*/ + /*/Set MAC REG 88C: Prevent SingleTone Fail*/ + phy_set_mac_reg(pAdapter, 0x88C, 0xF00000, 0xF); + phy_set_rf_reg(pAdapter, pMptCtx->mpt_rf_path, lna_low_gain_3, BIT1, 0x1); /*/ RF LO disabled*/ + phy_set_rf_reg(pAdapter, pMptCtx->mpt_rf_path, RF_AC, 0xF0000, 0x2); /*/ Tx mode*/ + } else if (IS_HARDWARE_TYPE_8723B(pAdapter)) { + if (pMptCtx->mpt_rf_path == ODM_RF_PATH_A) { + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC, 0xF0000, 0x2); /*/ Tx mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x56, 0xF, 0x1); /*/ RF LO enabled*/ + } else { + /*/ S0/S1 both use PATH A to configure*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC, 0xF0000, 0x2); /*/ Tx mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x76, 0xF, 0x1); /*/ RF LO enabled*/ + } + } else if (IS_HARDWARE_TYPE_8703B(pAdapter)) { + if (pMptCtx->mpt_rf_path == ODM_RF_PATH_A) { + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC, 0xF0000, 0x2); /* Tx mode */ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x53, 0xF000, 0x1); /* RF LO enabled */ + } + } else if (IS_HARDWARE_TYPE_8188F(pAdapter)) { + /*Set BB REG 88C: Prevent SingleTone Fail*/ + phy_set_bb_reg(pAdapter, rFPGA0_AnalogParameter4, 0xF00000, 0xF); + phy_set_rf_reg(pAdapter, pMptCtx->mpt_rf_path, lna_low_gain_3, BIT1, 0x1); + phy_set_rf_reg(pAdapter, pMptCtx->mpt_rf_path, RF_AC, 0xF0000, 0x2); + + } else if (IS_HARDWARE_TYPE_8723D(pAdapter)) { + if (pMptCtx->mpt_rf_path == ODM_RF_PATH_A) { + phy_set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn|bOFDMEn, 0); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC, BIT16, 0x0); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x53, BIT0, 0x1); + } else {/* S0/S1 both use PATH A to configure */ + phy_set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn|bOFDMEn, 0); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC, BIT16, 0x0); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x63, BIT0, 0x1); + } + } else if (IS_HARDWARE_TYPE_JAGUAR(pAdapter) || IS_HARDWARE_TYPE_8822B(pAdapter)) { +#if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) || defined(CONFIG_RTL8822B) + u1Byte p = ODM_RF_PATH_A; + + regRF = phy_query_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC_Jaguar, bRFRegOffsetMask); + regBB0 = phy_query_bb_reg(pAdapter, rA_RFE_Pinmux_Jaguar, bMaskDWord); + regBB1 = phy_query_bb_reg(pAdapter, rB_RFE_Pinmux_Jaguar, bMaskDWord); + regBB2 = phy_query_bb_reg(pAdapter, rA_RFE_Pinmux_Jaguar + 4, bMaskDWord); + regBB3 = phy_query_bb_reg(pAdapter, rB_RFE_Pinmux_Jaguar + 4, bMaskDWord); + + phy_set_bb_reg(pAdapter, rOFDMCCKEN_Jaguar, BIT29 | BIT28, 0x0); /*/ Disable CCK and OFDM*/ + + if (pMptCtx->mpt_rf_path == ODM_RF_PATH_AB) { + for (p = ODM_RF_PATH_A; p <= ODM_RF_PATH_B; ++p) { + phy_set_rf_reg(pAdapter, p, RF_AC_Jaguar, 0xF0000, 0x2); /*/ Tx mode: RF0x00[19:16]=4'b0010 */ + phy_set_rf_reg(pAdapter, p, RF_AC_Jaguar, 0x1F, 0x0); /*/ Lowest RF gain index: RF_0x0[4:0] = 0*/ + phy_set_rf_reg(pAdapter, p, lna_low_gain_3, BIT1, 0x1); /*/ RF LO enabled*/ + } + } else { + phy_set_rf_reg(pAdapter, pMptCtx->mpt_rf_path, RF_AC_Jaguar, 0xF0000, 0x2); /*/ Tx mode: RF0x00[19:16]=4'b0010 */ + phy_set_rf_reg(pAdapter, pMptCtx->mpt_rf_path, RF_AC_Jaguar, 0x1F, 0x0); /*/ Lowest RF gain index: RF_0x0[4:0] = 0*/ + phy_set_rf_reg(pAdapter, pMptCtx->mpt_rf_path, lna_low_gain_3, BIT1, 0x1); /*/ RF LO enabled*/ + } + + phy_set_bb_reg(pAdapter, rA_RFE_Pinmux_Jaguar, 0xFF00F0, 0x77007); /*/ 0xCB0[[23:16, 7:4] = 0x77007*/ + phy_set_bb_reg(pAdapter, rB_RFE_Pinmux_Jaguar, 0xFF00F0, 0x77007); /*/ 0xCB0[[23:16, 7:4] = 0x77007*/ + + if (pHalData->external_pa_5g) { + phy_set_bb_reg(pAdapter, rA_RFE_Pinmux_Jaguar + 4, 0xFF00000, 0x12); /*/ 0xCB4[23:16] = 0x12*/ + phy_set_bb_reg(pAdapter, rB_RFE_Pinmux_Jaguar + 4, 0xFF00000, 0x12); /*/ 0xEB4[23:16] = 0x12*/ + } else if (pHalData->ExternalPA_2G) { + phy_set_bb_reg(pAdapter, rA_RFE_Pinmux_Jaguar + 4, 0xFF00000, 0x11); /*/ 0xCB4[23:16] = 0x11*/ + phy_set_bb_reg(pAdapter, rB_RFE_Pinmux_Jaguar + 4, 0xFF00000, 0x11); /*/ 0xEB4[23:16] = 0x11*/ + } +#endif + } +#if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8821C) + else if (IS_HARDWARE_TYPE_8814A(pAdapter) || IS_HARDWARE_TYPE_8821C(pAdapter)) + mpt_SetSingleTone_8814A(pAdapter, TRUE, FALSE); +#endif + + else /*/ Turn On SingleTone and turn off the other test modes.*/ + phy_set_bb_reg(pAdapter, rOFDM1_LSTF, BIT30 | BIT29 | BIT28, OFDM_SingleTone); + + write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); + write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); + + } else {/*/ Stop Single Ton e.*/ + + if (IS_HARDWARE_TYPE_8188E(pAdapter)) { + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, lna_low_gain_3, bRFRegOffsetMask, regRF); + phy_set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn, 0x1); + phy_set_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 0x1); + } else if (IS_HARDWARE_TYPE_8192E(pAdapter)) { + phy_set_rf_reg(pAdapter, pMptCtx->mpt_rf_path, RF_AC, 0xF0000, 0x3);/*/ Tx mode*/ + phy_set_rf_reg(pAdapter, pMptCtx->mpt_rf_path, lna_low_gain_3, BIT1, 0x0);/*/ RF LO disabled */ + /*/ RESTORE MAC REG 88C: Enable RF Functions*/ + phy_set_mac_reg(pAdapter, 0x88C, 0xF00000, 0x0); + } else if (IS_HARDWARE_TYPE_8723B(pAdapter)) { + if (pMptCtx->mpt_rf_path == ODM_RF_PATH_A) { + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC, 0xF0000, 0x3); /*/ Rx mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x56, 0xF, 0x0); /*/ RF LO disabled*/ + } else { + /*/ S0/S1 both use PATH A to configure*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC, 0xF0000, 0x3); /*/ Rx mode*/ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x76, 0xF, 0x0); /*/ RF LO disabled*/ + } + } else if (IS_HARDWARE_TYPE_8703B(pAdapter)) { + if (pMptCtx->mpt_rf_path == ODM_RF_PATH_A) { + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC, 0xF0000, 0x3); /* Rx mode */ + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x53, 0xF000, 0x0); /* RF LO disabled */ + } + } else if (IS_HARDWARE_TYPE_8188F(pAdapter)) { + phy_set_rf_reg(pAdapter, pMptCtx->mpt_rf_path, RF_AC, 0xF0000, 0x3); /*Tx mode*/ + phy_set_rf_reg(pAdapter, pMptCtx->mpt_rf_path, lna_low_gain_3, BIT1, 0x0); /*RF LO disabled*/ + /*Set BB REG 88C: Prevent SingleTone Fail*/ + phy_set_bb_reg(pAdapter, rFPGA0_AnalogParameter4, 0xF00000, 0xc); + } else if (IS_HARDWARE_TYPE_8723D(pAdapter)) { + if (pMptCtx->mpt_rf_path == ODM_RF_PATH_A) { + phy_set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn|bOFDMEn, 0x3); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC, BIT16, 0x1); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x53, BIT0, 0x0); + } else { /* S0/S1 both use PATH A to configure */ + phy_set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn|bOFDMEn, 0x3); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, RF_AC, BIT16, 0x1); + phy_set_rf_reg(pAdapter, ODM_RF_PATH_A, 0x63, BIT0, 0x0); + } + } else if (IS_HARDWARE_TYPE_JAGUAR(pAdapter) || IS_HARDWARE_TYPE_8822B(pAdapter)) { +#if defined(CONFIG_RTL8812A) || defined(CONFIG_RTL8821A) || defined(CONFIG_RTL8822B) + u1Byte p = ODM_RF_PATH_A; + + phy_set_bb_reg(pAdapter, rOFDMCCKEN_Jaguar, BIT29 | BIT28, 0x3); /*/ Disable CCK and OFDM*/ + + if (pMptCtx->mpt_rf_path == ODM_RF_PATH_AB) { + for (p = ODM_RF_PATH_A; p <= ODM_RF_PATH_B; ++p) { + phy_set_rf_reg(pAdapter, p, RF_AC_Jaguar, bRFRegOffsetMask, regRF); + phy_set_rf_reg(pAdapter, p, lna_low_gain_3, BIT1, 0x0); /*/ RF LO disabled*/ + } + } else { + phy_set_rf_reg(pAdapter, p, RF_AC_Jaguar, bRFRegOffsetMask, regRF); + phy_set_rf_reg(pAdapter, p, lna_low_gain_3, BIT1, 0x0); /*/ RF LO disabled*/ + } + + phy_set_bb_reg(pAdapter, rA_RFE_Pinmux_Jaguar, bMaskDWord, regBB0); + phy_set_bb_reg(pAdapter, rB_RFE_Pinmux_Jaguar, bMaskDWord, regBB1); + phy_set_bb_reg(pAdapter, rA_RFE_Pinmux_Jaguar + 4, bMaskDWord, regBB2); + phy_set_bb_reg(pAdapter, rB_RFE_Pinmux_Jaguar + 4, bMaskDWord, regBB3); +#endif + } +#if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) + else if (IS_HARDWARE_TYPE_8814A(pAdapter) || IS_HARDWARE_TYPE_8821C(pAdapter)) + mpt_SetSingleTone_8814A(pAdapter, FALSE, FALSE); + + else/*/ Turn off all test modes.*/ + phy_set_bb_reg(pAdapter, rSingleTone_ContTx_Jaguar, BIT18 | BIT17 | BIT16, OFDM_ALL_OFF); +#endif + write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); + write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); + + } +} + +void hal_mpt_SetCarrierSuppressionTx(PADAPTER pAdapter, u8 bStart) +{ + u8 Rate; + + pAdapter->mppriv.mpt_ctx.is_carrier_suppression = bStart; + + Rate = HwRateToMPTRate(pAdapter->mppriv.rateidx); + if (bStart) {/* Start Carrier Suppression.*/ + if (Rate <= MPT_RATE_11M) { + /*/ 1. if CCK block on?*/ + if (!read_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn)) + write_bbreg(pAdapter, rFPGA0_RFMOD, bCCKEn, bEnable);/*set CCK block on*/ + + /*/Turn Off All Test Mode*/ + if (IS_HARDWARE_TYPE_JAGUAR(pAdapter) || IS_HARDWARE_TYPE_8814A(pAdapter) /*|| IS_HARDWARE_TYPE_8822B(pAdapter)*/) + phy_set_bb_reg(pAdapter, 0x914, BIT18 | BIT17 | BIT16, OFDM_ALL_OFF); /* rSingleTone_ContTx_Jaguar*/ + else + phy_set_bb_reg(pAdapter, rOFDM1_LSTF, BIT30 | BIT29 | BIT28, OFDM_ALL_OFF); + + write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); /*/transmit mode*/ + write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x0); /*/turn off scramble setting*/ + + /*/Set CCK Tx Test Rate*/ + write_bbreg(pAdapter, rCCK0_System, bCCKTxRate, 0x0); /*/Set FTxRate to 1Mbps*/ + } + + /*Set for dynamic set Power index*/ + write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); + write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); + + } else {/* Stop Carrier Suppression.*/ + + if (Rate <= MPT_RATE_11M) { + write_bbreg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); /*normal mode*/ + write_bbreg(pAdapter, rCCK0_System, bCCKScramble, 0x1); /*turn on scramble setting*/ + + /*BB Reset*/ + write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); + write_bbreg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); + } + /*Stop for dynamic set Power index*/ + write_bbreg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); + write_bbreg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); + } + RTW_INFO("\n MPT_ProSetCarrierSupp() is finished.\n"); +} + +u32 hal_mpt_query_phytxok(PADAPTER pAdapter) +{ + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + RT_PMAC_TX_INFO PMacTxInfo = pMptCtx->PMacTxInfo; + u16 count = 0; + + if (IS_MPT_CCK_RATE(PMacTxInfo.TX_RATE)) + count = phy_query_bb_reg(pAdapter, 0xF50, bMaskLWord); /* [15:0]*/ + else + count = phy_query_bb_reg(pAdapter, 0xF50, bMaskHWord); /* [31:16]*/ + + if (count > 50000) { + rtw_reset_phy_trx_ok_counters(pAdapter); + pAdapter->mppriv.tx.sended += count; + count = 0; + } + + return pAdapter->mppriv.tx.sended + count; + +} + +static VOID mpt_StopCckContTx( + PADAPTER pAdapter +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + u1Byte u1bReg; + + pMptCtx->bCckContTx = FALSE; + pMptCtx->bOfdmContTx = FALSE; + + phy_set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, 0x0); /*normal mode*/ + phy_set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, 0x1); /*turn on scramble setting*/ + + if (!IS_HARDWARE_TYPE_JAGUAR2(pAdapter)) { + phy_set_bb_reg(pAdapter, 0xa14, 0x300, 0x0); /* 0xa15[1:0] = 2b00*/ + phy_set_bb_reg(pAdapter, rOFDM0_TRMuxPar, 0x10000, 0x0); /* 0xc08[16] = 0*/ + + phy_set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter2, BIT14, 0); + phy_set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter2, BIT14, 0); + phy_set_bb_reg(pAdapter, 0x0B34, BIT14, 0); + } + + /*BB Reset*/ + phy_set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); + phy_set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); + + phy_set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); + phy_set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); + +} /* mpt_StopCckContTx */ + + +static VOID mpt_StopOfdmContTx( + PADAPTER pAdapter +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + u1Byte u1bReg; + u4Byte data; + + pMptCtx->bCckContTx = FALSE; + pMptCtx->bOfdmContTx = FALSE; + + if (IS_HARDWARE_TYPE_JAGUAR(pAdapter) || IS_HARDWARE_TYPE_JAGUAR2(pAdapter)) + phy_set_bb_reg(pAdapter, 0x914, BIT18 | BIT17 | BIT16, OFDM_ALL_OFF); + else + phy_set_bb_reg(pAdapter, rOFDM1_LSTF, BIT30 | BIT29 | BIT28, OFDM_ALL_OFF); + + rtw_mdelay_os(10); + + if (!IS_HARDWARE_TYPE_JAGUAR(pAdapter) && !IS_HARDWARE_TYPE_JAGUAR2(pAdapter)) { + phy_set_bb_reg(pAdapter, 0xa14, 0x300, 0x0); /* 0xa15[1:0] = 0*/ + phy_set_bb_reg(pAdapter, rOFDM0_TRMuxPar, 0x10000, 0x0); /* 0xc08[16] = 0*/ + } + + /*BB Reset*/ + phy_set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x0); + phy_set_bb_reg(pAdapter, rPMAC_Reset, bBBResetB, 0x1); + + phy_set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000100); + phy_set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000100); +} /* mpt_StopOfdmContTx */ + + +static VOID mpt_StartCckContTx( + PADAPTER pAdapter +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + u4Byte cckrate; + + /* 1. if CCK block on */ + if (!phy_query_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn)) + phy_set_bb_reg(pAdapter, rFPGA0_RFMOD, bCCKEn, 1);/*set CCK block on*/ + + /*Turn Off All Test Mode*/ + if (IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(pAdapter)) + phy_set_bb_reg(pAdapter, 0x914, BIT18 | BIT17 | BIT16, OFDM_ALL_OFF); + else + phy_set_bb_reg(pAdapter, rOFDM1_LSTF, BIT30 | BIT29 | BIT28, OFDM_ALL_OFF); + + cckrate = pAdapter->mppriv.rateidx; + + phy_set_bb_reg(pAdapter, rCCK0_System, bCCKTxRate, cckrate); + + phy_set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, 0x2); /*transmit mode*/ + phy_set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, 0x1); /*turn on scramble setting*/ + + if (!IS_HARDWARE_TYPE_JAGUAR_AND_JAGUAR2(pAdapter)) { + phy_set_bb_reg(pAdapter, 0xa14, 0x300, 0x3); /* 0xa15[1:0] = 11 force cck rxiq = 0*/ + phy_set_bb_reg(pAdapter, rOFDM0_TRMuxPar, 0x10000, 0x1); /* 0xc08[16] = 1 force ofdm rxiq = ofdm txiq*/ + phy_set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter2, BIT14, 1); + phy_set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter2, BIT14, 1); + phy_set_bb_reg(pAdapter, 0x0B34, BIT14, 1); + } + + phy_set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); + phy_set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); + + pMptCtx->bCckContTx = TRUE; + pMptCtx->bOfdmContTx = FALSE; + +} /* mpt_StartCckContTx */ + + +static VOID mpt_StartOfdmContTx( + PADAPTER pAdapter +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(pAdapter); + PMPT_CONTEXT pMptCtx = &(pAdapter->mppriv.mpt_ctx); + + /* 1. if OFDM block on?*/ + if (!phy_query_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn)) + phy_set_bb_reg(pAdapter, rFPGA0_RFMOD, bOFDMEn, 1);/*set OFDM block on*/ + + /* 2. set CCK test mode off, set to CCK normal mode*/ + phy_set_bb_reg(pAdapter, rCCK0_System, bCCKBBMode, 0); + + /* 3. turn on scramble setting*/ + phy_set_bb_reg(pAdapter, rCCK0_System, bCCKScramble, 1); + + if (!IS_HARDWARE_TYPE_JAGUAR(pAdapter) && !IS_HARDWARE_TYPE_JAGUAR2(pAdapter)) { + phy_set_bb_reg(pAdapter, 0xa14, 0x300, 0x3); /* 0xa15[1:0] = 2b'11*/ + phy_set_bb_reg(pAdapter, rOFDM0_TRMuxPar, 0x10000, 0x1); /* 0xc08[16] = 1*/ + } + + /* 4. Turn On Continue Tx and turn off the other test modes.*/ + if (IS_HARDWARE_TYPE_JAGUAR(pAdapter) || IS_HARDWARE_TYPE_JAGUAR2(pAdapter)) + phy_set_bb_reg(pAdapter, 0x914, BIT18 | BIT17 | BIT16, OFDM_ContinuousTx); + else + phy_set_bb_reg(pAdapter, rOFDM1_LSTF, BIT30 | BIT29 | BIT28, OFDM_ContinuousTx); + + phy_set_bb_reg(pAdapter, rFPGA0_XA_HSSIParameter1, bMaskDWord, 0x01000500); + phy_set_bb_reg(pAdapter, rFPGA0_XB_HSSIParameter1, bMaskDWord, 0x01000500); + + pMptCtx->bCckContTx = FALSE; + pMptCtx->bOfdmContTx = TRUE; +} /* mpt_StartOfdmContTx */ + + +#if defined(CONFIG_RTL8814A) || defined(CONFIG_RTL8821B) || defined(CONFIG_RTL8822B) || defined(CONFIG_RTL8821C) +/* for HW TX mode */ +void mpt_ProSetPMacTx(PADAPTER Adapter) +{ + PMPT_CONTEXT pMptCtx = &(Adapter->mppriv.mpt_ctx); + RT_PMAC_TX_INFO PMacTxInfo = pMptCtx->PMacTxInfo; + u32 u4bTmp; + + dbg_print("SGI %d bSPreamble %d bSTBC %d bLDPC %d NDP_sound %d\n", PMacTxInfo.bSGI, PMacTxInfo.bSPreamble, PMacTxInfo.bSTBC, PMacTxInfo.bLDPC, PMacTxInfo.NDP_sound); + dbg_print("TXSC %d BandWidth %d PacketPeriod %d PacketCount %d PacketLength %d PacketPattern %d\n", PMacTxInfo.TX_SC, PMacTxInfo.BandWidth, PMacTxInfo.PacketPeriod, PMacTxInfo.PacketCount, + PMacTxInfo.PacketLength, PMacTxInfo.PacketPattern); +#if 0 + PRINT_DATA("LSIG ", PMacTxInfo.LSIG, 3); + PRINT_DATA("HT_SIG", PMacTxInfo.HT_SIG, 6); + PRINT_DATA("VHT_SIG_A", PMacTxInfo.VHT_SIG_A, 6); + PRINT_DATA("VHT_SIG_B", PMacTxInfo.VHT_SIG_B, 4); + dbg_print("VHT_SIG_B_CRC %x\n", PMacTxInfo.VHT_SIG_B_CRC); + PRINT_DATA("VHT_Delimiter", PMacTxInfo.VHT_Delimiter, 4); + + PRINT_DATA("Src Address", Adapter->mac_addr, 6); + PRINT_DATA("Dest Address", PMacTxInfo.MacAddress, 6); +#endif + + if (PMacTxInfo.bEnPMacTx == FALSE) { + if (PMacTxInfo.Mode == CONTINUOUS_TX) { + phy_set_bb_reg(Adapter, 0xb04, 0xf, 2); /* TX Stop*/ + if (IS_MPT_CCK_RATE(PMacTxInfo.TX_RATE)) + mpt_StopCckContTx(Adapter); + else + mpt_StopOfdmContTx(Adapter); + } else if (IS_MPT_CCK_RATE(PMacTxInfo.TX_RATE)) { + u4bTmp = phy_query_bb_reg(Adapter, 0xf50, bMaskLWord); + phy_set_bb_reg(Adapter, 0xb1c, bMaskLWord, u4bTmp + 50); + phy_set_bb_reg(Adapter, 0xb04, 0xf, 2); /*TX Stop*/ + } else + phy_set_bb_reg(Adapter, 0xb04, 0xf, 2); /* TX Stop*/ + + if (PMacTxInfo.Mode == OFDM_Single_Tone_TX) { + /* Stop HW TX -> Stop Continuous TX -> Stop RF Setting*/ + if (IS_MPT_CCK_RATE(PMacTxInfo.TX_RATE)) + mpt_StopCckContTx(Adapter); + else + mpt_StopOfdmContTx(Adapter); + + mpt_SetSingleTone_8814A(Adapter, FALSE, TRUE); + } + + return; + } + + if (PMacTxInfo.Mode == CONTINUOUS_TX) { + PMacTxInfo.PacketCount = 1; + + if (IS_MPT_CCK_RATE(PMacTxInfo.TX_RATE)) + mpt_StartCckContTx(Adapter); + else + mpt_StartOfdmContTx(Adapter); + } else if (PMacTxInfo.Mode == OFDM_Single_Tone_TX) { + /* Continuous TX -> HW TX -> RF Setting */ + PMacTxInfo.PacketCount = 1; + + if (IS_MPT_CCK_RATE(PMacTxInfo.TX_RATE)) + mpt_StartCckContTx(Adapter); + else + mpt_StartOfdmContTx(Adapter); + } else if (PMacTxInfo.Mode == PACKETS_TX) { + if (IS_MPT_CCK_RATE(PMacTxInfo.TX_RATE) && PMacTxInfo.PacketCount == 0) + PMacTxInfo.PacketCount = 0xffff; + } + + if (IS_MPT_CCK_RATE(PMacTxInfo.TX_RATE)) { + /* 0xb1c[0:15] TX packet count 0xb1C[31:16] SFD*/ + u4bTmp = PMacTxInfo.PacketCount | (PMacTxInfo.SFD << 16); + phy_set_bb_reg(Adapter, 0xb1c, bMaskDWord, u4bTmp); + /* 0xb40 7:0 SIGNAL 15:8 SERVICE 31:16 LENGTH*/ + u4bTmp = PMacTxInfo.SignalField | (PMacTxInfo.ServiceField << 8) | (PMacTxInfo.LENGTH << 16); + phy_set_bb_reg(Adapter, 0xb40, bMaskDWord, u4bTmp); + u4bTmp = PMacTxInfo.CRC16[0] | (PMacTxInfo.CRC16[1] << 8); + phy_set_bb_reg(Adapter, 0xb44, bMaskLWord, u4bTmp); + + if (PMacTxInfo.bSPreamble) + phy_set_bb_reg(Adapter, 0xb0c, BIT27, 0); + else + phy_set_bb_reg(Adapter, 0xb0c, BIT27, 1); + } else { + phy_set_bb_reg(Adapter, 0xb18, 0xfffff, PMacTxInfo.PacketCount); + + u4bTmp = PMacTxInfo.LSIG[0] | ((PMacTxInfo.LSIG[1]) << 8) | ((PMacTxInfo.LSIG[2]) << 16) | ((PMacTxInfo.PacketPattern) << 24); + phy_set_bb_reg(Adapter, 0xb08, bMaskDWord, u4bTmp); /* Set 0xb08[23:0] = LSIG, 0xb08[31:24] = Data init octet*/ + + if (PMacTxInfo.PacketPattern == 0x12) + u4bTmp = 0x3000000; + else + u4bTmp = 0; + } + + if (IS_MPT_HT_RATE(PMacTxInfo.TX_RATE)) { + u4bTmp |= PMacTxInfo.HT_SIG[0] | ((PMacTxInfo.HT_SIG[1]) << 8) | ((PMacTxInfo.HT_SIG[2]) << 16); + phy_set_bb_reg(Adapter, 0xb0c, bMaskDWord, u4bTmp); + u4bTmp = PMacTxInfo.HT_SIG[3] | ((PMacTxInfo.HT_SIG[4]) << 8) | ((PMacTxInfo.HT_SIG[5]) << 16); + phy_set_bb_reg(Adapter, 0xb10, 0xffffff, u4bTmp); + } else if (IS_MPT_VHT_RATE(PMacTxInfo.TX_RATE)) { + u4bTmp |= PMacTxInfo.VHT_SIG_A[0] | ((PMacTxInfo.VHT_SIG_A[1]) << 8) | ((PMacTxInfo.VHT_SIG_A[2]) << 16); + phy_set_bb_reg(Adapter, 0xb0c, bMaskDWord, u4bTmp); + u4bTmp = PMacTxInfo.VHT_SIG_A[3] | ((PMacTxInfo.VHT_SIG_A[4]) << 8) | ((PMacTxInfo.VHT_SIG_A[5]) << 16); + phy_set_bb_reg(Adapter, 0xb10, 0xffffff, u4bTmp); + + _rtw_memcpy(&u4bTmp, PMacTxInfo.VHT_SIG_B, 4); + phy_set_bb_reg(Adapter, 0xb14, bMaskDWord, u4bTmp); + } + + if (IS_MPT_VHT_RATE(PMacTxInfo.TX_RATE)) { + u4bTmp = (PMacTxInfo.VHT_SIG_B_CRC << 24) | PMacTxInfo.PacketPeriod; /* for TX interval */ + phy_set_bb_reg(Adapter, 0xb20, bMaskDWord, u4bTmp); + + _rtw_memcpy(&u4bTmp, PMacTxInfo.VHT_Delimiter, 4); + phy_set_bb_reg(Adapter, 0xb24, bMaskDWord, u4bTmp); + + /* 0xb28 - 0xb34 24 byte Probe Request MAC Header*/ + /*& Duration & Frame control*/ + phy_set_bb_reg(Adapter, 0xb28, bMaskDWord, 0x00000040); + + /* Address1 [0:3]*/ + u4bTmp = PMacTxInfo.MacAddress[0] | (PMacTxInfo.MacAddress[1] << 8) | (PMacTxInfo.MacAddress[2] << 16) | (PMacTxInfo.MacAddress[3] << 24); + phy_set_bb_reg(Adapter, 0xb2C, bMaskDWord, u4bTmp); + + /* Address3 [3:0]*/ + phy_set_bb_reg(Adapter, 0xb38, bMaskDWord, u4bTmp); + + /* Address2[0:1] & Address1 [5:4]*/ + u4bTmp = PMacTxInfo.MacAddress[4] | (PMacTxInfo.MacAddress[5] << 8) | (Adapter->mac_addr[0] << 16) | (Adapter->mac_addr[1] << 24); + phy_set_bb_reg(Adapter, 0xb30, bMaskDWord, u4bTmp); + + /* Address2 [5:2]*/ + u4bTmp = Adapter->mac_addr[2] | (Adapter->mac_addr[3] << 8) | (Adapter->mac_addr[4] << 16) | (Adapter->mac_addr[5] << 24); + phy_set_bb_reg(Adapter, 0xb34, bMaskDWord, u4bTmp); + + /* Sequence Control & Address3 [5:4]*/ + /*u4bTmp = PMacTxInfo.MacAddress[4]|(PMacTxInfo.MacAddress[5] << 8) ;*/ + /*phy_set_bb_reg(Adapter, 0xb38, bMaskDWord, u4bTmp);*/ + } else { + phy_set_bb_reg(Adapter, 0xb20, bMaskDWord, PMacTxInfo.PacketPeriod); /* for TX interval*/ + /* & Duration & Frame control */ + phy_set_bb_reg(Adapter, 0xb24, bMaskDWord, 0x00000040); + + /* 0xb24 - 0xb38 24 byte Probe Request MAC Header*/ + /* Address1 [0:3]*/ + u4bTmp = PMacTxInfo.MacAddress[0] | (PMacTxInfo.MacAddress[1] << 8) | (PMacTxInfo.MacAddress[2] << 16) | (PMacTxInfo.MacAddress[3] << 24); + phy_set_bb_reg(Adapter, 0xb28, bMaskDWord, u4bTmp); + + /* Address3 [3:0]*/ + phy_set_bb_reg(Adapter, 0xb34, bMaskDWord, u4bTmp); + + /* Address2[0:1] & Address1 [5:4]*/ + u4bTmp = PMacTxInfo.MacAddress[4] | (PMacTxInfo.MacAddress[5] << 8) | (Adapter->mac_addr[0] << 16) | (Adapter->mac_addr[1] << 24); + phy_set_bb_reg(Adapter, 0xb2c, bMaskDWord, u4bTmp); + + /* Address2 [5:2] */ + u4bTmp = Adapter->mac_addr[2] | (Adapter->mac_addr[3] << 8) | (Adapter->mac_addr[4] << 16) | (Adapter->mac_addr[5] << 24); + phy_set_bb_reg(Adapter, 0xb30, bMaskDWord, u4bTmp); + + /* Sequence Control & Address3 [5:4]*/ + u4bTmp = PMacTxInfo.MacAddress[4] | (PMacTxInfo.MacAddress[5] << 8); + phy_set_bb_reg(Adapter, 0xb38, bMaskDWord, u4bTmp); + } + + phy_set_bb_reg(Adapter, 0xb48, bMaskByte3, PMacTxInfo.TX_RATE_HEX); + + /* 0xb4c 3:0 TXSC 5:4 BW 7:6 m_STBC 8 NDP_Sound*/ + u4bTmp = (PMacTxInfo.TX_SC) | ((PMacTxInfo.BandWidth) << 4) | ((PMacTxInfo.m_STBC - 1) << 6) | ((PMacTxInfo.NDP_sound) << 8); + phy_set_bb_reg(Adapter, 0xb4c, 0x1ff, u4bTmp); + + if (IS_HARDWARE_TYPE_8814A(Adapter) || IS_HARDWARE_TYPE_8822B(Adapter)) { + u4Byte offset = 0xb44; + + if (IS_MPT_OFDM_RATE(PMacTxInfo.TX_RATE)) + phy_set_bb_reg(Adapter, offset, 0xc0000000, 0); + else if (IS_MPT_HT_RATE(PMacTxInfo.TX_RATE)) + phy_set_bb_reg(Adapter, offset, 0xc0000000, 1); + else if (IS_MPT_VHT_RATE(PMacTxInfo.TX_RATE)) + phy_set_bb_reg(Adapter, offset, 0xc0000000, 2); + } + + phy_set_bb_reg(Adapter, 0xb00, BIT8, 1); /* Turn on PMAC*/ + /* phy_set_bb_reg(Adapter, 0xb04, 0xf, 2); */ /* TX Stop */ + if (IS_MPT_CCK_RATE(PMacTxInfo.TX_RATE)) { + phy_set_bb_reg(Adapter, 0xb04, 0xf, 8); /*TX CCK ON*/ + phy_set_bb_reg(Adapter, 0xA84, BIT31, 0); + } else + phy_set_bb_reg(Adapter, 0xb04, 0xf, 4); /* TX Ofdm ON */ + + if (PMacTxInfo.Mode == OFDM_Single_Tone_TX) + mpt_SetSingleTone_8814A(Adapter, TRUE, TRUE); + +} + +#endif + +void hal_mpt_SetContinuousTx(PADAPTER pAdapter, u8 bStart) +{ + u8 Rate; + + RT_TRACE(_module_mp_, _drv_info_, + ("SetContinuousTx: rate:%d\n", pAdapter->mppriv.rateidx)); + Rate = HwRateToMPTRate(pAdapter->mppriv.rateidx); + pAdapter->mppriv.mpt_ctx.is_start_cont_tx = bStart; + + if (Rate <= MPT_RATE_11M) { + if (bStart) + mpt_StartCckContTx(pAdapter); + else + mpt_StopCckContTx(pAdapter); + + } else if (Rate >= MPT_RATE_6M) { + if (bStart) + mpt_StartOfdmContTx(pAdapter); + else + mpt_StopOfdmContTx(pAdapter); + } +} + +#endif /* CONFIG_MP_INCLUDE*/ diff --git a/linux-bsp/drivers/rtl8188eus/hal/hal_phy.c b/linux-bsp/drivers/rtl8188eus/hal/hal_phy.c new file mode 100644 index 0000000..5c87dbb --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/hal_phy.c @@ -0,0 +1,260 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ +#define _HAL_PHY_C_ + +#include <drv_types.h> + +/* ******************************************************************************** + * Constant. + * ******************************************************************************** + * 2008/11/20 MH For Debug only, RF */ +static RF_SHADOW_T RF_Shadow[RF6052_MAX_PATH][RF6052_MAX_REG]; + +/** +* Function: PHY_CalculateBitShift +* +* OverView: Get shifted position of the BitMask +* +* Input: +* u4Byte BitMask, +* +* Output: none +* Return: u4Byte Return the shift bit bit position of the mask +*/ +u32 +PHY_CalculateBitShift( + u32 BitMask +) +{ + u32 i; + + for (i = 0; i <= 31; i++) { + if (((BitMask >> i) & 0x1) == 1) + break; + } + + return i; +} + + +/* + * ==> RF shadow Operation API Code Section!!! + * + *----------------------------------------------------------------------------- + * Function: PHY_RFShadowRead + * PHY_RFShadowWrite + * PHY_RFShadowCompare + * PHY_RFShadowRecorver + * PHY_RFShadowCompareAll + * PHY_RFShadowRecorverAll + * PHY_RFShadowCompareFlagSet + * PHY_RFShadowRecorverFlagSet + * + * Overview: When we set RF register, we must write shadow at first. + * When we are running, we must compare shadow abd locate error addr. + * Decide to recorver or not. + * + * Input: NONE + * + * Output: NONE + * + * Return: NONE + * + * Revised History: + * When Who Remark + * 11/20/2008 MHC Create Version 0. + * + *---------------------------------------------------------------------------*/ +u32 +PHY_RFShadowRead( + IN PADAPTER Adapter, + IN u8 eRFPath, + IN u32 Offset) +{ + return RF_Shadow[eRFPath][Offset].Value; + +} /* PHY_RFShadowRead */ + + +VOID +PHY_RFShadowWrite( + IN PADAPTER Adapter, + IN u8 eRFPath, + IN u32 Offset, + IN u32 Data) +{ + RF_Shadow[eRFPath][Offset].Value = (Data & bRFRegOffsetMask); + RF_Shadow[eRFPath][Offset].Driver_Write = _TRUE; + +} /* PHY_RFShadowWrite */ + + +BOOLEAN +PHY_RFShadowCompare( + IN PADAPTER Adapter, + IN u8 eRFPath, + IN u32 Offset) +{ + u32 reg; + /* Check if we need to check the register */ + if (RF_Shadow[eRFPath][Offset].Compare == _TRUE) { + reg = rtw_hal_read_rfreg(Adapter, eRFPath, Offset, bRFRegOffsetMask); + /* Compare shadow and real rf register for 20bits!! */ + if (RF_Shadow[eRFPath][Offset].Value != reg) { + /* Locate error position. */ + RF_Shadow[eRFPath][Offset].ErrorOrNot = _TRUE; + } + return RF_Shadow[eRFPath][Offset].ErrorOrNot ; + } + return _FALSE; +} /* PHY_RFShadowCompare */ + + +VOID +PHY_RFShadowRecorver( + IN PADAPTER Adapter, + IN u8 eRFPath, + IN u32 Offset) +{ + /* Check if the address is error */ + if (RF_Shadow[eRFPath][Offset].ErrorOrNot == _TRUE) { + /* Check if we need to recorver the register. */ + if (RF_Shadow[eRFPath][Offset].Recorver == _TRUE) { + rtw_hal_write_rfreg(Adapter, eRFPath, Offset, bRFRegOffsetMask, + RF_Shadow[eRFPath][Offset].Value); + } + } + +} /* PHY_RFShadowRecorver */ + + +VOID +PHY_RFShadowCompareAll( + IN PADAPTER Adapter) +{ + u8 eRFPath = 0 ; + u32 Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter); + + for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) { + for (Offset = 0; Offset < maxReg; Offset++) + PHY_RFShadowCompare(Adapter, eRFPath, Offset); + } + +} /* PHY_RFShadowCompareAll */ + + +VOID +PHY_RFShadowRecorverAll( + IN PADAPTER Adapter) +{ + u8 eRFPath = 0; + u32 Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter); + + for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) { + for (Offset = 0; Offset < maxReg; Offset++) + PHY_RFShadowRecorver(Adapter, eRFPath, Offset); + } + +} /* PHY_RFShadowRecorverAll */ + + +VOID +PHY_RFShadowCompareFlagSet( + IN PADAPTER Adapter, + IN u8 eRFPath, + IN u32 Offset, + IN u8 Type) +{ + /* Set True or False!!! */ + RF_Shadow[eRFPath][Offset].Compare = Type; + +} /* PHY_RFShadowCompareFlagSet */ + + +VOID +PHY_RFShadowRecorverFlagSet( + IN PADAPTER Adapter, + IN u8 eRFPath, + IN u32 Offset, + IN u8 Type) +{ + /* Set True or False!!! */ + RF_Shadow[eRFPath][Offset].Recorver = Type; + +} /* PHY_RFShadowRecorverFlagSet */ + + +VOID +PHY_RFShadowCompareFlagSetAll( + IN PADAPTER Adapter) +{ + u8 eRFPath = 0; + u32 Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter); + + for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) { + for (Offset = 0; Offset < maxReg; Offset++) { + /* 2008/11/20 MH For S3S4 test, we only check reg 26/27 now!!!! */ + if (Offset != 0x26 && Offset != 0x27) + PHY_RFShadowCompareFlagSet(Adapter, eRFPath, Offset, _FALSE); + else + PHY_RFShadowCompareFlagSet(Adapter, eRFPath, Offset, _TRUE); + } + } + +} /* PHY_RFShadowCompareFlagSetAll */ + + +VOID +PHY_RFShadowRecorverFlagSetAll( + IN PADAPTER Adapter) +{ + u8 eRFPath = 0; + u32 Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter); + + for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) { + for (Offset = 0; Offset < maxReg; Offset++) { + /* 2008/11/20 MH For S3S4 test, we only check reg 26/27 now!!!! */ + if (Offset != 0x26 && Offset != 0x27) + PHY_RFShadowRecorverFlagSet(Adapter, eRFPath, Offset, _FALSE); + else + PHY_RFShadowRecorverFlagSet(Adapter, eRFPath, Offset, _TRUE); + } + } + +} /* PHY_RFShadowCompareFlagSetAll */ + +VOID +PHY_RFShadowRefresh( + IN PADAPTER Adapter) +{ + u8 eRFPath = 0; + u32 Offset = 0, maxReg = GET_RF6052_REAL_MAX_REG(Adapter); + + for (eRFPath = 0; eRFPath < RF6052_MAX_PATH; eRFPath++) { + for (Offset = 0; Offset < maxReg; Offset++) { + RF_Shadow[eRFPath][Offset].Value = 0; + RF_Shadow[eRFPath][Offset].Compare = _FALSE; + RF_Shadow[eRFPath][Offset].Recorver = _FALSE; + RF_Shadow[eRFPath][Offset].ErrorOrNot = _FALSE; + RF_Shadow[eRFPath][Offset].Driver_Write = _FALSE; + } + } + +} /* PHY_RFShadowRead */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/led/hal_usb_led.c b/linux-bsp/drivers/rtl8188eus/hal/led/hal_usb_led.c new file mode 100644 index 0000000..099ea74 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/led/hal_usb_led.c @@ -0,0 +1,4287 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#include <drv_types.h> +#include <hal_data.h> + +/* + * Description: + * Implementation of LED blinking behavior. + * It toggle off LED and schedule corresponding timer if necessary. + * */ +void +SwLedBlink( + PLED_USB pLed +) +{ + _adapter *padapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u8 bStopBlinking = _FALSE; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(padapter, pLed); + } else { + SwLedOff(padapter, pLed); + } + + /* Determine if we shall change LED state again. */ + pLed->BlinkTimes--; + switch (pLed->CurrLedState) { + + case LED_BLINK_NORMAL: + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + break; + + case LED_BLINK_StartToBlink: + if (check_fwstate(pmlmepriv, _FW_LINKED) && check_fwstate(pmlmepriv, WIFI_STATION_STATE)) + bStopBlinking = _TRUE; + if (check_fwstate(pmlmepriv, _FW_LINKED) && + (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) + bStopBlinking = _TRUE; + else if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + break; + + case LED_BLINK_WPS: + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + break; + + + default: + bStopBlinking = _TRUE; + break; + + } + + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else if ((check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) && (pLed->bLedOn == _FALSE)) + SwLedOn(padapter, pLed); + else if ((check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) && pLed->bLedOn == _TRUE) + SwLedOff(padapter, pLed); + + pLed->BlinkTimes = 0; + pLed->bLedBlinkInProgress = _FALSE; + } else { + /* Assign LED state to toggle. */ + if (pLed->BlinkingLedState == RTW_LED_ON) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + /* Schedule a timer to toggle LED state. */ + switch (pLed->CurrLedState) { + case LED_BLINK_NORMAL: + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + break; + + case LED_BLINK_SLOWLY: + case LED_BLINK_StartToBlink: + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); + break; + + case LED_BLINK_WPS: { + if (pLed->BlinkingLedState == RTW_LED_ON) + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL); + else + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL); + } + break; + + default: + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); + break; + } + } +} + +void +SwLedBlink1( + PLED_USB pLed +) +{ + _adapter *padapter = pLed->padapter; + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + struct led_priv *ledpriv = &(padapter->ledpriv); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + PLED_USB pLed1 = &(ledpriv->SwLed1); + u8 bStopBlinking = _FALSE; + + u32 uLedBlinkNoLinkInterval = LED_BLINK_NO_LINK_INTERVAL_ALPHA; /* add by ylb 20121012 for customer led for alpha */ + if (pHalData->CustomerID == RT_CID_819x_ALPHA_Dlink) + uLedBlinkNoLinkInterval = LED_BLINK_NO_LINK_INTERVAL_ALPHA_500MS; + + if (pHalData->CustomerID == RT_CID_819x_CAMEO) + pLed = &(ledpriv->SwLed1); + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(padapter, pLed); + } else { + SwLedOff(padapter, pLed); + } + + + if (pHalData->CustomerID == RT_CID_DEFAULT) { + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + if (!pLed1->bSWLedCtrl) { + SwLedOn(padapter, pLed1); + pLed1->bSWLedCtrl = _TRUE; + } else if (!pLed1->bLedOn) + SwLedOn(padapter, pLed1); + } else { + if (!pLed1->bSWLedCtrl) { + SwLedOff(padapter, pLed1); + pLed1->bSWLedCtrl = _TRUE; + } else if (pLed1->bLedOn) + SwLedOff(padapter, pLed1); + } + } + + switch (pLed->CurrLedState) { + case LED_BLINK_SLOWLY: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), uLedBlinkNoLinkInterval);/* change by ylb 20121012 for customer led for alpha */ + break; + + case LED_BLINK_NORMAL: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); + break; + + case LED_BLINK_SCAN: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + pLed->bLedLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_NORMAL; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); + + } else if (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) { + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), uLedBlinkNoLinkInterval); + } + pLed->bLedScanBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } + } + break; + + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + pLed->bLedLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_NORMAL; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); + } else if (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) { + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), uLedBlinkNoLinkInterval); + } + pLed->BlinkTimes = 0; + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + } + break; + + case LED_BLINK_WPS: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + break; + + case LED_BLINK_WPS_STOP: /* WPS success */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); + bStopBlinking = _FALSE; + } else + bStopBlinking = _TRUE; + + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else { + pLed->bLedLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_NORMAL; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); + } + pLed->bLedWPSBlinkInProgress = _FALSE; + } + break; + + default: + break; + } + +} + +void +SwLedBlink2( + PLED_USB pLed +) +{ + _adapter *padapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u8 bStopBlinking = _FALSE; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(padapter, pLed); + } else { + SwLedOff(padapter, pLed); + } + + switch (pLed->CurrLedState) { + case LED_BLINK_SCAN: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + SwLedOn(padapter, pLed); + + } else if (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + SwLedOff(padapter, pLed); + } + pLed->bLedScanBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } + } + break; + + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + SwLedOn(padapter, pLed); + + } else if (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + SwLedOff(padapter, pLed); + } + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + } + break; + + default: + break; + } + +} + +void +SwLedBlink3( + PLED_USB pLed +) +{ + _adapter *padapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u8 bStopBlinking = _FALSE; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(padapter, pLed); + } else { + if (pLed->CurrLedState != LED_BLINK_WPS_STOP) + SwLedOff(padapter, pLed); + } + + switch (pLed->CurrLedState) { + case LED_BLINK_SCAN: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (!pLed->bLedOn) + SwLedOn(padapter, pLed); + + } else if (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedOn) + SwLedOff(padapter, pLed); + + } + pLed->bLedScanBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } + } + break; + + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + + if (!pLed->bLedOn) + SwLedOn(padapter, pLed); + + } else if (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + + if (pLed->bLedOn) + SwLedOff(padapter, pLed); + + + } + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + } + break; + + case LED_BLINK_WPS: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + break; + + case LED_BLINK_WPS_STOP: /* WPS success */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); + bStopBlinking = _FALSE; + } else + bStopBlinking = _TRUE; + + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) + SwLedOff(padapter, pLed); + else { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + SwLedOn(padapter, pLed); + } + pLed->bLedWPSBlinkInProgress = _FALSE; + } + break; + + + default: + break; + } + +} + + +void +SwLedBlink4( + PLED_USB pLed +) +{ + _adapter *padapter = pLed->padapter; + struct led_priv *ledpriv = &(padapter->ledpriv); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + PLED_USB pLed1 = &(ledpriv->SwLed1); + u8 bStopBlinking = _FALSE; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(padapter, pLed); + } else { + SwLedOff(padapter, pLed); + } + + if (!pLed1->bLedWPSBlinkInProgress && pLed1->BlinkingLedState == LED_UNKNOWN) { + pLed1->BlinkingLedState = RTW_LED_OFF; + pLed1->CurrLedState = RTW_LED_OFF; + SwLedOff(padapter, pLed1); + } + + switch (pLed->CurrLedState) { + case LED_BLINK_SLOWLY: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + break; + + case LED_BLINK_StartToBlink: + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + } + break; + + case LED_BLINK_SCAN: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _FALSE; + + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(padapter, pLed); + else { + pLed->bLedNoLinkBlinkInProgress = _FALSE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + } + pLed->bLedScanBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(padapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } + } + break; + + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(padapter, pLed); + else { + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + } + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(padapter, pLed); + else { + + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + } + break; + + case LED_BLINK_WPS: + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + } + break; + + case LED_BLINK_WPS_STOP: /* WPS authentication fail */ + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + break; + + case LED_BLINK_WPS_STOP_OVERLAP: /* WPS session overlap */ + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) { + if (pLed->bLedOn) + pLed->BlinkTimes = 1; + else + bStopBlinking = _TRUE; + } + + if (bStopBlinking) { + pLed->BlinkTimes = 10; + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + } + break; + + case LED_BLINK_ALWAYS_ON: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(padapter, pLed); + else { + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + } + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) { + SwLedOff(padapter, pLed); + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + } + break; + + default: + break; + } + + + +} + +void +SwLedBlink5( + PLED_USB pLed +) +{ + _adapter *padapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u8 bStopBlinking = _FALSE; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(padapter, pLed); + } else { + SwLedOff(padapter, pLed); + } + + switch (pLed->CurrLedState) { + case LED_BLINK_SCAN: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedOn) + SwLedOff(padapter, pLed); + } else { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (!pLed->bLedOn) + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + + pLed->bLedScanBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(padapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } + } + break; + + + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + + if (bStopBlinking) { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedOn) + SwLedOff(padapter, pLed); + } else { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (!pLed->bLedOn) + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(padapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + } + break; + + default: + break; + } + + + +} + +void +SwLedBlink6( + PLED_USB pLed +) +{ + _adapter *padapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + u8 bStopBlinking = _FALSE; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(padapter, pLed); + } else { + SwLedOff(padapter, pLed); + } + +} + +void +SwLedBlink7( + PLED_USB pLed +) +{ + PADAPTER Adapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + BOOLEAN bStopBlinking = _FALSE; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(Adapter, pLed); + } else { + if (pLed->CurrLedState != LED_BLINK_WPS_STOP) + SwLedOff(Adapter, pLed); + } + + switch (pLed->CurrLedState) { + case LED_BLINK_SCAN: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + + if (bStopBlinking) { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on) + SwLedOff(Adapter, pLed); + else if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (!pLed->bLedOn) + SwLedOn(Adapter, pLed); + + } else if (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedOn) + SwLedOff(Adapter, pLed); + + } + pLed->bLedScanBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on) + SwLedOff(Adapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_NETGEAR); + } + } + break; + + case LED_BLINK_WPS: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_NETGEAR); + break; + + case LED_BLINK_WPS_STOP: /* WPS success */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_NETGEAR); + bStopBlinking = _FALSE; + } else + bStopBlinking = _TRUE; + + if (bStopBlinking) { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on) + SwLedOff(Adapter, pLed); + else { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + SwLedOn(Adapter, pLed); + } + pLed->bLedWPSBlinkInProgress = _FALSE; + } + break; + + + default: + break; + } + + +} + +void +SwLedBlink8( + PLED_USB pLed +) +{ + PADAPTER Adapter = pLed->padapter; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(Adapter, pLed); + } else { + SwLedOff(Adapter, pLed); + } + + +} + +/* page added for Belkin AC950. 20120813 */ +void +SwLedBlink9( + PLED_USB pLed +) +{ + PADAPTER Adapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + BOOLEAN bStopBlinking = _FALSE; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(Adapter, pLed); + } else { + SwLedOff(Adapter, pLed); + } + /* RTW_INFO("%s, pLed->CurrLedState=%d, pLed->BlinkingLedState=%d\n", __FUNCTION__, pLed->CurrLedState, pLed->BlinkingLedState); */ + + + switch (pLed->CurrLedState) { + case RTW_LED_ON: + SwLedOn(Adapter, pLed); + break; + + case RTW_LED_OFF: + SwLedOff(Adapter, pLed); + break; + + case LED_BLINK_SLOWLY: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + break; + + case LED_BLINK_StartToBlink: + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + } + break; + + case LED_BLINK_SCAN: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + + if (bStopBlinking) { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on) + SwLedOff(Adapter, pLed); + else if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + pLed->bLedLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); + } else if (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) { + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + } + pLed->BlinkTimes = 0; + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(Adapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } + } + break; + + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + if (bStopBlinking) { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(Adapter, pLed); + else { + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(Adapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + } + break; + + case LED_BLINK_WPS: + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + } + break; + + case LED_BLINK_WPS_STOP: /* WPS authentication fail */ + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + break; + + case LED_BLINK_WPS_STOP_OVERLAP: /* WPS session overlap */ + pLed->BlinkTimes--; + pLed->BlinkCounter--; + if (pLed->BlinkCounter == 0) { + pLed->BlinkingLedState = RTW_LED_OFF; + pLed->CurrLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + } else { + if (pLed->BlinkTimes == 0) { + if (pLed->bLedOn) + pLed->BlinkTimes = 1; + else + bStopBlinking = _TRUE; + } + + if (bStopBlinking) { + pLed->BlinkTimes = 10; + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + } + } + break; + + case LED_BLINK_ALWAYS_ON: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + if (bStopBlinking) { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(Adapter, pLed); + else { + if (IS_HARDWARE_TYPE_8812AU(Adapter)) { + pLed->BlinkingLedState = RTW_LED_ON; + pLed->CurrLedState = LED_BLINK_ALWAYS_ON; + } else { + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + } + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + } + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) { + SwLedOff(Adapter, pLed); + } else { + if (IS_HARDWARE_TYPE_8812AU(Adapter)) + pLed->BlinkingLedState = RTW_LED_ON; + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + } + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + } + break; + + case LED_BLINK_LINK_IN_PROCESS: + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ON_BELKIN); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_OFF_BELKIN); + } + break; + + case LED_BLINK_AUTH_ERROR: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + if (bStopBlinking == _FALSE) { + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_ERROR_INTERVAL_BELKIN); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_ERROR_INTERVAL_BELKIN); + } + } else { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_ERROR_INTERVAL_BELKIN); + } + break; + + default: + break; + } + +} + +/* page added for Netgear A6200V2. 20120827 */ +void +SwLedBlink10( + PLED_USB pLed +) +{ + PADAPTER Adapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + BOOLEAN bStopBlinking = _FALSE; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(Adapter, pLed); + } else { + SwLedOff(Adapter, pLed); + } + + + switch (pLed->CurrLedState) { + case RTW_LED_ON: + SwLedOn(Adapter, pLed); + break; + + case RTW_LED_OFF: + SwLedOff(Adapter, pLed); + break; + + case LED_BLINK_SLOWLY: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + break; + + case LED_BLINK_StartToBlink: + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + } + break; + + case LED_BLINK_SCAN: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + + if (bStopBlinking) { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on) + SwLedOff(Adapter, pLed); + else if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + pLed->bLedNoLinkBlinkInProgress = _FALSE; + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + } + pLed->BlinkTimes = 0; + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(Adapter, pLed); + else { + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_NETGEAR); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_SLOWLY_INTERVAL_NETGEAR + LED_BLINK_LINK_INTERVAL_NETGEAR); + } + } + } + break; + + case LED_BLINK_WPS: + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_NETGEAR); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL + LED_BLINK_LINK_INTERVAL_NETGEAR); + } + break; + + case LED_BLINK_WPS_STOP: /* WPS authentication fail */ + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + break; + + case LED_BLINK_WPS_STOP_OVERLAP: /* WPS session overlap */ + pLed->BlinkTimes--; + pLed->BlinkCounter--; + if (pLed->BlinkCounter == 0) { + pLed->BlinkingLedState = RTW_LED_OFF; + pLed->CurrLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + } else { + if (pLed->BlinkTimes == 0) { + if (pLed->bLedOn) + pLed->BlinkTimes = 1; + else + bStopBlinking = _TRUE; + } + + if (bStopBlinking) { + pLed->BlinkTimes = 10; + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); + } else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + } + } + break; + + case LED_BLINK_ALWAYS_ON: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + if (bStopBlinking) { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(Adapter, pLed); + else { + if (IS_HARDWARE_TYPE_8812AU(Adapter)) { + pLed->BlinkingLedState = RTW_LED_ON; + pLed->CurrLedState = LED_BLINK_ALWAYS_ON; + } else { + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + } + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + } + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) { + SwLedOff(Adapter, pLed); + } else { + if (IS_HARDWARE_TYPE_8812AU(Adapter)) + pLed->BlinkingLedState = RTW_LED_ON; + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + } + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + } + break; + + case LED_BLINK_LINK_IN_PROCESS: + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ON_BELKIN); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_OFF_BELKIN); + } + break; + + case LED_BLINK_AUTH_ERROR: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + if (bStopBlinking == _FALSE) { + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_ERROR_INTERVAL_BELKIN); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_ERROR_INTERVAL_BELKIN); + } + } else { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_ERROR_INTERVAL_BELKIN); + } + break; + + default: + break; + } + + +} + +void +SwLedBlink11( + PLED_USB pLed +) +{ + PADAPTER Adapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + BOOLEAN bStopBlinking = _FALSE; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(Adapter, pLed); + } else { + SwLedOff(Adapter, pLed); + } + + switch (pLed->CurrLedState) { + case LED_BLINK_TXRX: + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(Adapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } + + break; + + case LED_BLINK_WPS: + if (pLed->BlinkTimes == 5) { + SwLedOn(Adapter, pLed); + _set_timer(&(pLed->BlinkTimer), LED_CM11_LINK_ON_INTERVEL); + } else { + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_CM11_BLINK_INTERVAL); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_CM11_BLINK_INTERVAL); + } + } + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + if (bStopBlinking == _TRUE) + pLed->BlinkTimes = 5; + break; + + case LED_BLINK_WPS_STOP: /* WPS authentication fail */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } else { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + SwLedOn(Adapter, pLed); + _set_timer(&(pLed->BlinkTimer), 0); + } + break; + + default: + break; + } + +} + +void +SwLedBlink12( + PLED_USB pLed +) +{ + PADAPTER Adapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + BOOLEAN bStopBlinking = _FALSE; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(Adapter, pLed); + } else { + SwLedOff(Adapter, pLed); + } + + switch (pLed->CurrLedState) { + case LED_BLINK_SLOWLY: + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + break; + + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + + if (bStopBlinking) { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedOn) + SwLedOff(Adapter, pLed); + } else { + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + } + + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(Adapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + } + break; + + default: + break; + } + + + +} + +VOID +SwLedBlink13( + IN PLED_USB pLed +) +{ + PADAPTER Adapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + BOOLEAN bStopBlinking = _FALSE; + static u8 LinkBlinkCnt = 0; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(Adapter, pLed); + } else { + if (pLed->CurrLedState != LED_BLINK_WPS_STOP) + SwLedOff(Adapter, pLed); + } + switch (pLed->CurrLedState) { + case LED_BLINK_LINK_IN_PROCESS: + if (!pLed->bLedWPSBlinkInProgress) + LinkBlinkCnt++; + + if (LinkBlinkCnt > 15) { + LinkBlinkCnt = 0; + pLed->bLedBlinkInProgress = _FALSE; + break; + } + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 500); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), 500); + } + + break; + + case LED_BLINK_WPS: + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_WPS_BLINK_ON_INTERVAL_NETGEAR); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_WPS_BLINK_OFF_INTERVAL_NETGEAR); + } + + break; + + case LED_BLINK_WPS_STOP: /* WPS success */ + SwLedOff(Adapter, pLed); + pLed->bLedWPSBlinkInProgress = _FALSE; + break; + + default: + LinkBlinkCnt = 0; + break; + } + + +} + +VOID +SwLedBlink14( + IN PLED_USB pLed +) +{ + PADAPTER Adapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + BOOLEAN bStopBlinking = _FALSE; + static u8 LinkBlinkCnt = 0; + + /* Change LED according to BlinkingLedState specified. */ + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(Adapter, pLed); + } else { + if (pLed->CurrLedState != LED_BLINK_WPS_STOP) + SwLedOff(Adapter, pLed); + } + switch (pLed->CurrLedState) { + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + if (bStopBlinking) { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(Adapter, pLed); + else + SwLedOn(Adapter, pLed); + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(Adapter, pLed); + else { + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + if (IS_HARDWARE_TYPE_8812AU(Adapter)) + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); + else + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + if (IS_HARDWARE_TYPE_8812AU(Adapter)) + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + else + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + } + } + + break; + + default: + LinkBlinkCnt = 0; + break; + } + +} + +VOID +SwLedBlink15( + IN PLED_USB pLed +) +{ + PADAPTER Adapter = pLed->padapter; + struct mlme_priv *pmlmepriv = &(Adapter->mlmepriv); + BOOLEAN bStopBlinking = _FALSE; + static u8 LinkBlinkCnt = 0; + /* Change LED according to BlinkingLedState specified. */ + + if (pLed->BlinkingLedState == RTW_LED_ON) { + SwLedOn(Adapter, pLed); + } else { + if (pLed->CurrLedState != LED_BLINK_WPS_STOP) + SwLedOff(Adapter, pLed); + } + switch (pLed->CurrLedState) { + case LED_BLINK_WPS: + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_WPS_BLINK_ON_INTERVAL_DLINK); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_WPS_BLINK_OFF_INTERVAL_DLINK); + } + break; + + case LED_BLINK_WPS_STOP: /* WPS success */ + + if (pLed->BlinkingLedState == RTW_LED_OFF) { + pLed->bLedWPSBlinkInProgress = _FALSE; + return; + } + + pLed->CurrLedState = LED_BLINK_WPS_STOP; + pLed->BlinkingLedState = RTW_LED_OFF; + + _set_timer(&(pLed->BlinkTimer), LED_WPS_BLINK_LINKED_ON_INTERVAL_DLINK); + break; + + case LED_BLINK_NO_LINK: { + static BOOLEAN bLedOn = _TRUE; + if (bLedOn) { + bLedOn = _FALSE; + pLed->BlinkingLedState = RTW_LED_OFF; + } else { + bLedOn = _TRUE; + pLed->BlinkingLedState = RTW_LED_ON; + } + pLed->bLedBlinkInProgress = _TRUE; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL); + } + break; + + case LED_BLINK_LINK_IDEL: { + static BOOLEAN bLedOn = _TRUE; + if (bLedOn) { + bLedOn = _FALSE; + pLed->BlinkingLedState = RTW_LED_OFF; + } else { + bLedOn = _TRUE; + pLed->BlinkingLedState = RTW_LED_ON; + + } + pLed->bLedBlinkInProgress = _TRUE; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_IDEL_INTERVAL); + } + break; + + case LED_BLINK_SCAN: { + static u8 BlinkTime = 0; + if (BlinkTime % 2 == 0) + pLed->BlinkingLedState = RTW_LED_ON; + else + pLed->BlinkingLedState = RTW_LED_OFF; + BlinkTime++; + + if (BlinkTime < 24) { + pLed->bLedBlinkInProgress = _TRUE; + + if (pLed->BlinkingLedState == RTW_LED_ON) + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_OFF_INTERVAL); + else + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_ON_INTERVAL); + } else { + /* if(pLed->OLDLedState ==LED_NO_LINK_BLINK) */ + if (check_fwstate(pmlmepriv, _FW_LINKED) == _FALSE) { + pLed->CurrLedState = LED_BLINK_NO_LINK; + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), 100); + } + BlinkTime = 0; + } + } + break; + + case LED_BLINK_TXRX: + pLed->BlinkTimes--; + if (pLed->BlinkTimes == 0) + bStopBlinking = _TRUE; + if (bStopBlinking) { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(Adapter, pLed); + else + SwLedOn(Adapter, pLed); + pLed->bLedBlinkInProgress = _FALSE; + } else { + if (adapter_to_pwrctl(Adapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(Adapter)->rfoff_reason > RF_CHANGE_BY_PS) + SwLedOff(Adapter, pLed); + else { + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + } + break; + + default: + LinkBlinkCnt = 0; + break; + } + +} + +/* + * Description: + * Handler function of LED Blinking. + * We dispatch acture LED blink action according to LedStrategy. + * */ +void BlinkHandler(PLED_USB pLed) +{ + _adapter *padapter = pLed->padapter; + struct led_priv *ledpriv = &(padapter->ledpriv); + + /* RTW_INFO("%s (%s:%d)\n",__FUNCTION__, current->comm, current->pid); */ + + if (RTW_CANNOT_RUN(padapter) || (!rtw_is_hw_init_completed(padapter))) { + /*RTW_INFO("%s bDriverStopped:%s, bSurpriseRemoved:%s\n" + , __func__ + , rtw_is_drv_stopped(padapter)?"True":"False" + , rtw_is_surprise_removed(padapter)?"True":"False" );*/ + return; + } + + switch (ledpriv->LedStrategy) { + case SW_LED_MODE0: + SwLedBlink(pLed); + break; + + case SW_LED_MODE1: + SwLedBlink1(pLed); + break; + + case SW_LED_MODE2: + SwLedBlink2(pLed); + break; + + case SW_LED_MODE3: + SwLedBlink3(pLed); + break; + + case SW_LED_MODE4: + SwLedBlink4(pLed); + break; + + case SW_LED_MODE5: + SwLedBlink5(pLed); + break; + + case SW_LED_MODE6: + SwLedBlink6(pLed); + break; + + case SW_LED_MODE7: + SwLedBlink7(pLed); + break; + + case SW_LED_MODE8: + SwLedBlink8(pLed); + break; + + case SW_LED_MODE9: + SwLedBlink9(pLed); + break; + + case SW_LED_MODE10: + SwLedBlink10(pLed); + break; + + case SW_LED_MODE11: + SwLedBlink11(pLed); + break; + + case SW_LED_MODE12: + SwLedBlink12(pLed); + break; + + case SW_LED_MODE13: + SwLedBlink13(pLed); + break; + + case SW_LED_MODE14: + SwLedBlink14(pLed); + break; + + case SW_LED_MODE15: + SwLedBlink15(pLed); + break; + + default: + /* SwLedBlink(pLed); */ + break; + } +} + +/* + * Description: + * Callback function of LED BlinkTimer, + * it just schedules to corresponding BlinkWorkItem/led_blink_hdl + * */ +void BlinkTimerCallback(void *data) +{ + PLED_USB pLed = (PLED_USB)data; + _adapter *padapter = pLed->padapter; + + /* RTW_INFO("%s\n", __FUNCTION__); */ + + if (RTW_CANNOT_RUN(padapter) || (!rtw_is_hw_init_completed(padapter))) { + /*RTW_INFO("%s bDriverStopped:%s, bSurpriseRemoved:%s\n" + , __func__ + , rtw_is_drv_stopped(padapter)?"True":"False" + , rtw_is_surprise_removed(padapter)?"True":"False" );*/ + return; + } + +#ifdef CONFIG_LED_HANDLED_BY_CMD_THREAD + rtw_led_blink_cmd(padapter, (PVOID)pLed); +#else + _set_workitem(&(pLed->BlinkWorkItem)); +#endif +} + +/* + * Description: + * Callback function of LED BlinkWorkItem. + * We dispatch acture LED blink action according to LedStrategy. + * */ +void BlinkWorkItemCallback(_workitem *work) +{ + PLED_USB pLed = container_of(work, LED_USB, BlinkWorkItem); + BlinkHandler(pLed); +} + +static void +SwLedControlMode0( + _adapter *padapter, + LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + PLED_USB pLed = &(ledpriv->SwLed1); + + /* Decide led state */ + switch (LedAction) { + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == _FALSE) { + pLed->bLedBlinkInProgress = _TRUE; + + pLed->CurrLedState = LED_BLINK_NORMAL; + pLed->BlinkTimes = 2; + + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + } + break; + + case LED_CTL_START_TO_LINK: + if (pLed->bLedBlinkInProgress == _FALSE) { + pLed->bLedBlinkInProgress = _TRUE; + + pLed->CurrLedState = LED_BLINK_StartToBlink; + pLed->BlinkTimes = 24; + + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); + } else + pLed->CurrLedState = LED_BLINK_StartToBlink; + break; + + case LED_CTL_LINK: + pLed->CurrLedState = RTW_LED_ON; + if (pLed->bLedBlinkInProgress == _FALSE) { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), 0); + } + break; + + case LED_CTL_NO_LINK: + pLed->CurrLedState = RTW_LED_OFF; + if (pLed->bLedBlinkInProgress == _FALSE) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 0); + } + break; + + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + SwLedOff(padapter, pLed); + break; + + case LED_CTL_START_WPS: + if (pLed->bLedBlinkInProgress == _FALSE || pLed->CurrLedState == RTW_LED_ON) { + pLed->bLedBlinkInProgress = _TRUE; + + pLed->CurrLedState = LED_BLINK_WPS; + pLed->BlinkTimes = 20; + + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LONG_INTERVAL); + } + } + break; + + case LED_CTL_STOP_WPS: + if (pLed->bLedBlinkInProgress) { + pLed->CurrLedState = RTW_LED_OFF; + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + break; + + + default: + break; + } + + +} + +/* ALPHA, added by chiyoko, 20090106 */ +static void +SwLedControlMode1( + _adapter *padapter, + LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + PLED_USB pLed = &(ledpriv->SwLed0); + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + + u32 uLedBlinkNoLinkInterval = LED_BLINK_NO_LINK_INTERVAL_ALPHA; /* add by ylb 20121012 for customer led for alpha */ + if (pHalData->CustomerID == RT_CID_819x_ALPHA_Dlink) + uLedBlinkNoLinkInterval = LED_BLINK_NO_LINK_INTERVAL_ALPHA_500MS; + + if (pHalData->CustomerID == RT_CID_819x_CAMEO) + pLed = &(ledpriv->SwLed1); + + switch (LedAction) { + case LED_CTL_POWER_ON: + case LED_CTL_START_TO_LINK: + case LED_CTL_NO_LINK: + if (pLed->bLedNoLinkBlinkInProgress == _FALSE) { + if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), uLedBlinkNoLinkInterval);/* change by ylb 20121012 for customer led for alpha */ + } + break; + + case LED_CTL_LINK: + if (pLed->bLedLinkBlinkInProgress == _FALSE) { + if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + pLed->bLedLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_NORMAL; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); + } + break; + + case LED_CTL_SITE_SURVEY: + if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) + ; + else if (pLed->bLedScanBlinkInProgress == _FALSE) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + pLed->bLedScanBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && adapter_to_pwrctl(padapter)->rfoff_reason == RF_CHANGE_BY_IPS) + _set_timer(&(pLed->BlinkTimer), LED_INITIAL_INTERVAL); + else + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + + } + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == _FALSE) { + if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedLinkBlinkInProgress = _FALSE; + } + pLed->bLedBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + break; + + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedWPSBlinkInProgress == _FALSE) { + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + pLed->bLedWPSBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } + break; + + + case LED_CTL_STOP_WPS: + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + if (pLed->bLedWPSBlinkInProgress) + _cancel_timer_ex(&(pLed->BlinkTimer)); + else + pLed->bLedWPSBlinkInProgress = _TRUE; + + pLed->CurrLedState = LED_BLINK_WPS_STOP; + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), 0); + } + break; + + case LED_CTL_STOP_WPS_FAIL: + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), uLedBlinkNoLinkInterval);/* change by ylb 20121012 for customer led for alpha */ + break; + + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedNoLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + + SwLedOff(padapter, pLed); + break; + + default: + break; + + } + +} + +/* Arcadyan/Sitecom , added by chiyoko, 20090216 */ +static void +SwLedControlMode2( + _adapter *padapter, + LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + PLED_USB pLed = &(ledpriv->SwLed0); + + switch (LedAction) { + case LED_CTL_SITE_SURVEY: + if (pmlmepriv->LinkDetectInfo.bBusyTraffic) + ; + else if (pLed->bLedScanBlinkInProgress == _FALSE) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + pLed->bLedScanBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if ((pLed->bLedBlinkInProgress == _FALSE) && (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) { + if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) + return; + + pLed->bLedBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + break; + + case LED_CTL_LINK: + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + + _set_timer(&(pLed->BlinkTimer), 0); + break; + + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedWPSBlinkInProgress == _FALSE) { + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + pLed->bLedWPSBlinkInProgress = _TRUE; + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), 0); + } + break; + + case LED_CTL_STOP_WPS: + pLed->bLedWPSBlinkInProgress = _FALSE; + if (adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 0); + } else { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), 0); + } + break; + + case LED_CTL_STOP_WPS_FAIL: + pLed->bLedWPSBlinkInProgress = _FALSE; + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 0); + break; + + case LED_CTL_START_TO_LINK: + case LED_CTL_NO_LINK: + if (!IS_LED_BLINKING(pLed)) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 0); + } + break; + + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + + SwLedOff(padapter, pLed); + break; + + default: + break; + + } + +} + +/* COREGA, added by chiyoko, 20090316 */ +static void +SwLedControlMode3( + _adapter *padapter, + LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + PLED_USB pLed = &(ledpriv->SwLed0); + + switch (LedAction) { + case LED_CTL_SITE_SURVEY: + if (pmlmepriv->LinkDetectInfo.bBusyTraffic) + ; + else if (pLed->bLedScanBlinkInProgress == _FALSE) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + pLed->bLedScanBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if ((pLed->bLedBlinkInProgress == _FALSE) && (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) { + if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) + return; + + pLed->bLedBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + break; + + case LED_CTL_LINK: + if (IS_LED_WPS_BLINKING(pLed)) + return; + + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + + _set_timer(&(pLed->BlinkTimer), 0); + break; + + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedWPSBlinkInProgress == _FALSE) { + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + pLed->bLedWPSBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } + break; + + case LED_CTL_STOP_WPS: + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } else + pLed->bLedWPSBlinkInProgress = _TRUE; + + pLed->CurrLedState = LED_BLINK_WPS_STOP; + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), 0); + } + + break; + + case LED_CTL_STOP_WPS_FAIL: + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 0); + break; + + case LED_CTL_START_TO_LINK: + case LED_CTL_NO_LINK: + if (!IS_LED_BLINKING(pLed)) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 0); + } + break; + + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + + SwLedOff(padapter, pLed); + break; + + default: + break; + + } + +} + + +/* Edimax-Belkin, added by chiyoko, 20090413 */ +static void +SwLedControlMode4( + _adapter *padapter, + LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + PLED_USB pLed = &(ledpriv->SwLed0); + PLED_USB pLed1 = &(ledpriv->SwLed1); + + switch (LedAction) { + case LED_CTL_START_TO_LINK: + if (pLed1->bLedWPSBlinkInProgress) { + pLed1->bLedWPSBlinkInProgress = _FALSE; + _cancel_timer_ex(&(pLed1->BlinkTimer)); + + pLed1->BlinkingLedState = RTW_LED_OFF; + pLed1->CurrLedState = RTW_LED_OFF; + + if (pLed1->bLedOn) + _set_timer(&(pLed->BlinkTimer), 0); + } + + if (pLed->bLedStartToLinkBlinkInProgress == _FALSE) { + if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + + pLed->bLedStartToLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_StartToBlink; + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + } + } + break; + + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + /* LED1 settings */ + if (LedAction == LED_CTL_LINK) { + if (pLed1->bLedWPSBlinkInProgress) { + pLed1->bLedWPSBlinkInProgress = _FALSE; + _cancel_timer_ex(&(pLed1->BlinkTimer)); + + pLed1->BlinkingLedState = RTW_LED_OFF; + pLed1->CurrLedState = RTW_LED_OFF; + + if (pLed1->bLedOn) + _set_timer(&(pLed->BlinkTimer), 0); + } + } + + if (pLed->bLedNoLinkBlinkInProgress == _FALSE) { + if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + } + break; + + case LED_CTL_SITE_SURVEY: + if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) + ; + else if (pLed->bLedScanBlinkInProgress == _FALSE) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + pLed->bLedScanBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == _FALSE) { + if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + pLed->bLedBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + break; + + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed1->bLedWPSBlinkInProgress) { + pLed1->bLedWPSBlinkInProgress = _FALSE; + _cancel_timer_ex(&(pLed1->BlinkTimer)); + + pLed1->BlinkingLedState = RTW_LED_OFF; + pLed1->CurrLedState = RTW_LED_OFF; + + if (pLed1->bLedOn) + _set_timer(&(pLed->BlinkTimer), 0); + } + + if (pLed->bLedWPSBlinkInProgress == _FALSE) { + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + pLed->bLedWPSBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SLOWLY_INTERVAL); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + } + } + break; + + case LED_CTL_STOP_WPS: /* WPS connect success */ + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + + break; + + case LED_CTL_STOP_WPS_FAIL: /* WPS authentication fail */ + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + + /* LED1 settings */ + if (pLed1->bLedWPSBlinkInProgress) + _cancel_timer_ex(&(pLed1->BlinkTimer)); + else + pLed1->bLedWPSBlinkInProgress = _TRUE; + + pLed1->CurrLedState = LED_BLINK_WPS_STOP; + if (pLed1->bLedOn) + pLed1->BlinkingLedState = RTW_LED_OFF; + else + pLed1->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + + break; + + case LED_CTL_STOP_WPS_FAIL_OVERLAP: /* WPS session overlap */ + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + + /* LED1 settings */ + if (pLed1->bLedWPSBlinkInProgress) + _cancel_timer_ex(&(pLed1->BlinkTimer)); + else + pLed1->bLedWPSBlinkInProgress = _TRUE; + + pLed1->CurrLedState = LED_BLINK_WPS_STOP_OVERLAP; + pLed1->BlinkTimes = 10; + if (pLed1->bLedOn) + pLed1->BlinkingLedState = RTW_LED_OFF; + else + pLed1->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + + break; + + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + + if (pLed->bLedNoLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + if (pLed->bLedStartToLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedStartToLinkBlinkInProgress = _FALSE; + } + + if (pLed1->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed1->BlinkTimer)); + pLed1->bLedWPSBlinkInProgress = _FALSE; + } + + pLed1->BlinkingLedState = LED_UNKNOWN; + SwLedOff(padapter, pLed); + SwLedOff(padapter, pLed1); + break; + + case LED_CTL_CONNECTION_NO_TRANSFER: + if (pLed->bLedBlinkInProgress == _FALSE) { + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + pLed->bLedBlinkInProgress = _TRUE; + + pLed->CurrLedState = LED_BLINK_ALWAYS_ON; + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + } + break; + + default: + break; + + } + +} + + + +/* Sercomm-Belkin, added by chiyoko, 20090415 */ +static void +SwLedControlMode5( + _adapter *padapter, + LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + PHAL_DATA_TYPE pHalData = GET_HAL_DATA(padapter); + PLED_USB pLed = &(ledpriv->SwLed0); + + if (pHalData->CustomerID == RT_CID_819x_CAMEO) + pLed = &(ledpriv->SwLed1); + + switch (LedAction) { + case LED_CTL_POWER_ON: + case LED_CTL_NO_LINK: + case LED_CTL_LINK: /* solid blue */ + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), 0); + break; + + case LED_CTL_SITE_SURVEY: + if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) + ; + else if (pLed->bLedScanBlinkInProgress == _FALSE) { + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + pLed->bLedScanBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + } + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == _FALSE) { + if (pLed->CurrLedState == LED_BLINK_SCAN) + return; + pLed->bLedBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + break; + + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + + SwLedOff(padapter, pLed); + break; + + default: + break; + + } + +} + +/* WNC-Corega, added by chiyoko, 20090902 */ +static void +SwLedControlMode6( + _adapter *padapter, + LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + PLED_USB pLed0 = &(ledpriv->SwLed0); + + switch (LedAction) { + case LED_CTL_POWER_ON: + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + _cancel_timer_ex(&(pLed0->BlinkTimer)); + pLed0->CurrLedState = RTW_LED_ON; + pLed0->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed0->BlinkTimer), 0); + break; + + case LED_CTL_POWER_OFF: + SwLedOff(padapter, pLed0); + break; + + default: + break; + } + +} + +/* Netgear, added by sinda, 2011/11/11 */ +void +SwLedControlMode7( + PADAPTER Adapter, + LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(Adapter->ledpriv); + struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; + PLED_USB pLed = &(ledpriv->SwLed0); + + switch (LedAction) { + case LED_CTL_SITE_SURVEY: + if (pmlmepriv->LinkDetectInfo.bBusyTraffic) + ; + else if (pLed->bLedScanBlinkInProgress == _FALSE) { + if (IS_LED_WPS_BLINKING(pLed)) + return; + + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + pLed->bLedScanBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkTimes = 6; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_NETGEAR); + } + break; + + case LED_CTL_LINK: + if (IS_LED_WPS_BLINKING(pLed)) + return; + + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + + _set_timer(&(pLed->BlinkTimer), 0); + break; + + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedWPSBlinkInProgress == _FALSE) { + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + pLed->bLedWPSBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_NETGEAR); + } + break; + + case LED_CTL_STOP_WPS: + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } else + pLed->bLedWPSBlinkInProgress = _TRUE; + + pLed->CurrLedState = LED_BLINK_WPS_STOP; + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_NETGEAR); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), 0); + } + + break; + + + case LED_CTL_STOP_WPS_FAIL: + case LED_CTL_STOP_WPS_FAIL_OVERLAP: /* WPS session overlap */ + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 0); + break; + + case LED_CTL_START_TO_LINK: + case LED_CTL_NO_LINK: + if (!IS_LED_BLINKING(pLed)) { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 0); + } + break; + + case LED_CTL_POWER_OFF: + case LED_CTL_POWER_ON: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + + _set_timer(&(pLed->BlinkTimer), 0); + break; + + default: + break; + + } + +} + +void +SwLedControlMode8( + PADAPTER Adapter, + LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(Adapter->ledpriv); + struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; + PLED_USB pLed0 = &(ledpriv->SwLed0); + + switch (LedAction) { + case LED_CTL_LINK: + _cancel_timer_ex(&(pLed0->BlinkTimer)); + pLed0->CurrLedState = RTW_LED_ON; + pLed0->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed0->BlinkTimer), 0); + break; + + case LED_CTL_NO_LINK: + _cancel_timer_ex(&(pLed0->BlinkTimer)); + pLed0->CurrLedState = RTW_LED_OFF; + pLed0->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed0->BlinkTimer), 0); + break; + + case LED_CTL_POWER_OFF: + SwLedOff(Adapter, pLed0); + break; + + default: + break; + } + + +} + +/* page added for Belkin AC950, 20120813 */ +void +SwLedControlMode9( + IN PADAPTER Adapter, + IN LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(Adapter->ledpriv); + struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; + PLED_USB pLed = &(ledpriv->SwLed0); + PLED_USB pLed1 = &(ledpriv->SwLed1); + PLED_USB pLed2 = &(ledpriv->SwLed2); + BOOLEAN bWPSOverLap = _FALSE; + /* RTW_INFO("LedAction=%d\n", LedAction); */ + switch (LedAction) { + case LED_CTL_START_TO_LINK: + if (pLed2->bLedBlinkInProgress == _FALSE) { + pLed2->bLedBlinkInProgress = _TRUE; + pLed2->BlinkingLedState = RTW_LED_ON; + pLed2->CurrLedState = LED_BLINK_LINK_IN_PROCESS; + + _set_timer(&(pLed2->BlinkTimer), 0); + } + break; + + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + /* LED1 settings */ + if (LedAction == LED_CTL_NO_LINK) { + /* if(pMgntInfo->AuthStatus == AUTH_STATUS_FAILED) */ + if (0) { + pLed1->CurrLedState = LED_BLINK_AUTH_ERROR; + if (pLed1->bLedOn) + pLed1->BlinkingLedState = RTW_LED_OFF; + else + pLed1->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed1->BlinkTimer), 0); + } else { + pLed1->CurrLedState = RTW_LED_OFF; + pLed1->BlinkingLedState = RTW_LED_OFF; + if (pLed1->bLedOn) + _set_timer(&(pLed1->BlinkTimer), 0); + } + } else { + pLed1->CurrLedState = RTW_LED_OFF; + pLed1->BlinkingLedState = RTW_LED_OFF; + if (pLed1->bLedOn) + _set_timer(&(pLed1->BlinkTimer), 0); + } + + /* LED2 settings */ + if (LedAction == LED_CTL_LINK) { + if (Adapter->securitypriv.dot11PrivacyAlgrthm != _NO_PRIVACY_) { + if (pLed2->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed2->BlinkTimer)); + pLed2->bLedBlinkInProgress = _FALSE; + } + pLed2->CurrLedState = RTW_LED_ON; + pLed2->bLedNoLinkBlinkInProgress = _TRUE; + if (!pLed2->bLedOn) + _set_timer(&(pLed2->BlinkTimer), 0); + } else { + if (pLed2->bLedWPSBlinkInProgress != _TRUE) { + pLed2->CurrLedState = RTW_LED_OFF; + pLed2->BlinkingLedState = RTW_LED_OFF; + if (pLed2->bLedOn) + _set_timer(&(pLed2->BlinkTimer), 0); + } + } + } else { /* NO_LINK */ + if (pLed2->bLedWPSBlinkInProgress == _FALSE) { + pLed2->CurrLedState = RTW_LED_OFF; + pLed2->BlinkingLedState = RTW_LED_OFF; + if (pLed2->bLedOn) + _set_timer(&(pLed2->BlinkTimer), 0); + } + } + + /* LED0 settings */ + if (pLed->bLedNoLinkBlinkInProgress == _FALSE) { + if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + + pLed->bLedNoLinkBlinkInProgress = _TRUE; + if (IS_HARDWARE_TYPE_8812AU(Adapter)) { + if (LedAction == LED_CTL_LINK) { + pLed->BlinkingLedState = RTW_LED_ON; + pLed->CurrLedState = LED_BLINK_SLOWLY; + } else { + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + } + } else { + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + } + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + } + + break; + + case LED_CTL_SITE_SURVEY: + if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)) + ; + else { /* if(pLed->bLedScanBlinkInProgress ==FALSE) */ + if (IS_LED_WPS_BLINKING(pLed)) + return; + + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + pLed->bLedScanBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkTimes = 24; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + + } + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == _FALSE) { + if (pLed->CurrLedState == LED_BLINK_SCAN || IS_LED_WPS_BLINKING(pLed)) + return; + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + pLed->bLedBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + break; + + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + pLed2->bLedBlinkInProgress = _TRUE; + pLed2->BlinkingLedState = RTW_LED_ON; + pLed2->CurrLedState = LED_BLINK_LINK_IN_PROCESS; + pLed2->bLedWPSBlinkInProgress = _TRUE; + + _set_timer(&(pLed2->BlinkTimer), 500); + + break; + + case LED_CTL_STOP_WPS: /* WPS connect success */ + /* LED2 settings */ + if (pLed2->bLedWPSBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed2->BlinkTimer)); + pLed2->bLedBlinkInProgress = _FALSE; + pLed2->bLedWPSBlinkInProgress = _FALSE; + } + pLed2->CurrLedState = RTW_LED_ON; + pLed2->bLedNoLinkBlinkInProgress = _TRUE; + if (!pLed2->bLedOn) + _set_timer(&(pLed2->BlinkTimer), 0); + + /* LED1 settings */ + _cancel_timer_ex(&(pLed1->BlinkTimer)); + pLed1->CurrLedState = RTW_LED_OFF; + pLed1->BlinkingLedState = RTW_LED_OFF; + if (pLed1->bLedOn) + _set_timer(&(pLed1->BlinkTimer), 0); + + + break; + + case LED_CTL_STOP_WPS_FAIL: /* WPS authentication fail */ + /* LED1 settings */ + /* if(bWPSOverLap == _FALSE) */ + { + pLed1->CurrLedState = LED_BLINK_AUTH_ERROR; + pLed1->BlinkTimes = 50; + if (pLed1->bLedOn) + pLed1->BlinkingLedState = RTW_LED_OFF; + else + pLed1->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed1->BlinkTimer), 0); + } + /* else */ + /* { */ + /* bWPSOverLap = _FALSE; */ + /* pLed1->CurrLedState = RTW_LED_OFF; */ + /* pLed1->BlinkingLedState = RTW_LED_OFF; */ + /* _set_timer(&(pLed1->BlinkTimer), 0); */ + /* } */ + + /* LED2 settings */ + pLed2->CurrLedState = RTW_LED_OFF; + pLed2->BlinkingLedState = RTW_LED_OFF; + pLed2->bLedWPSBlinkInProgress = _FALSE; + if (pLed2->bLedOn) + _set_timer(&(pLed2->BlinkTimer), 0); + + break; + + case LED_CTL_STOP_WPS_FAIL_OVERLAP: /* WPS session overlap */ + /* LED1 settings */ + bWPSOverLap = _TRUE; + pLed1->CurrLedState = LED_BLINK_WPS_STOP_OVERLAP; + pLed1->BlinkTimes = 10; + pLed1->BlinkCounter = 50; + if (pLed1->bLedOn) + pLed1->BlinkingLedState = RTW_LED_OFF; + else + pLed1->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed1->BlinkTimer), 0); + + /* LED2 settings */ + pLed2->CurrLedState = RTW_LED_OFF; + pLed2->BlinkingLedState = RTW_LED_OFF; + pLed2->bLedWPSBlinkInProgress = _FALSE; + if (pLed2->bLedOn) + _set_timer(&(pLed2->BlinkTimer), 0); + + break; + + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + + if (pLed->bLedNoLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + if (pLed->bLedStartToLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedStartToLinkBlinkInProgress = _FALSE; + } + + if (pLed1->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed1->BlinkTimer)); + pLed1->bLedWPSBlinkInProgress = _FALSE; + } + + + pLed1->BlinkingLedState = LED_UNKNOWN; + SwLedOff(Adapter, pLed); + SwLedOff(Adapter, pLed1); + break; + + case LED_CTL_CONNECTION_NO_TRANSFER: + if (pLed->bLedBlinkInProgress == _FALSE) { + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + pLed->bLedBlinkInProgress = _TRUE; + + pLed->CurrLedState = LED_BLINK_ALWAYS_ON; + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + } + break; + + default: + break; + + } + +} + +/* page added for Netgear A6200V2, 20120827 */ +void +SwLedControlMode10( + PADAPTER Adapter, + LED_CTL_MODE LedAction +) +{ + HAL_DATA_TYPE *pHalData = GET_HAL_DATA(Adapter); + struct led_priv *ledpriv = &(Adapter->ledpriv); + struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; + PLED_USB pLed = &(ledpriv->SwLed0); + PLED_USB pLed1 = &(ledpriv->SwLed1); + + switch (LedAction) { + case LED_CTL_START_TO_LINK: + if (pLed1->bLedBlinkInProgress == _FALSE) { + pLed1->bLedBlinkInProgress = _TRUE; + pLed1->BlinkingLedState = RTW_LED_ON; + pLed1->CurrLedState = LED_BLINK_LINK_IN_PROCESS; + + _set_timer(&(pLed1->BlinkTimer), 0); + } + break; + + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + if (LedAction == LED_CTL_LINK) { + if (pLed->bLedWPSBlinkInProgress == _TRUE || pLed1->bLedWPSBlinkInProgress == _TRUE) + ; + else { + if (pHalData->current_band_type == BAND_ON_2_4G) + /* LED0 settings */ + { + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + _set_timer(&(pLed->BlinkTimer), 0); + + pLed1->CurrLedState = RTW_LED_OFF; + pLed1->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed1->BlinkTimer), 0); + } else if (pHalData->current_band_type == BAND_ON_5G) + /* LED1 settings */ + { + pLed1->CurrLedState = RTW_LED_ON; + pLed1->BlinkingLedState = RTW_LED_ON; + if (pLed1->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed1->BlinkTimer)); + pLed1->bLedBlinkInProgress = _FALSE; + } + _set_timer(&(pLed1->BlinkTimer), 0); + + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 0); + } + } + } else if (LedAction == LED_CTL_NO_LINK) { /* TODO by page */ + if (pLed->bLedWPSBlinkInProgress == _TRUE || pLed1->bLedWPSBlinkInProgress == _TRUE) + ; + else { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedOn) + _set_timer(&(pLed->BlinkTimer), 0); + + pLed1->CurrLedState = RTW_LED_OFF; + pLed1->BlinkingLedState = RTW_LED_OFF; + if (pLed1->bLedOn) + _set_timer(&(pLed1->BlinkTimer), 0); + } + } + + break; + + case LED_CTL_SITE_SURVEY: + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + ; /* don't blink when media connect */ + else { /* if(pLed->bLedScanBlinkInProgress ==FALSE) */ + if (IS_LED_WPS_BLINKING(pLed) || IS_LED_WPS_BLINKING(pLed1)) + return; + + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + pLed->bLedScanBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkTimes = 12; + pLed->BlinkingLedState = LED_BLINK_SCAN; + _set_timer(&(pLed->BlinkTimer), 0); + + if (pLed1->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed1->BlinkTimer)); + pLed1->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed1->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed1->BlinkTimer)); + pLed1->bLedBlinkInProgress = _FALSE; + } + pLed1->bLedScanBlinkInProgress = _TRUE; + pLed1->CurrLedState = LED_BLINK_SCAN; + pLed1->BlinkTimes = 12; + pLed1->BlinkingLedState = LED_BLINK_SCAN; + _set_timer(&(pLed1->BlinkTimer), LED_BLINK_LINK_SLOWLY_INTERVAL_NETGEAR); + + } + break; + + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + /* LED0 settings */ + if (pLed->bLedBlinkInProgress == _FALSE) { + pLed->bLedBlinkInProgress = _TRUE; + pLed->bLedWPSBlinkInProgress = _TRUE; + pLed->BlinkingLedState = LED_BLINK_WPS; + pLed->CurrLedState = LED_BLINK_WPS; + _set_timer(&(pLed->BlinkTimer), 0); + } + + /* LED1 settings */ + if (pLed1->bLedBlinkInProgress == _FALSE) { + pLed1->bLedBlinkInProgress = _TRUE; + pLed1->bLedWPSBlinkInProgress = _TRUE; + pLed1->BlinkingLedState = LED_BLINK_WPS; + pLed1->CurrLedState = LED_BLINK_WPS; + _set_timer(&(pLed1->BlinkTimer), LED_BLINK_NORMAL_INTERVAL + LED_BLINK_LINK_INTERVAL_NETGEAR); + } + + + break; + + case LED_CTL_STOP_WPS: /* WPS connect success */ + if (pHalData->current_band_type == BAND_ON_2_4G) + /* LED0 settings */ + { + pLed->bLedWPSBlinkInProgress = _FALSE; + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + _set_timer(&(pLed->BlinkTimer), 0); + + pLed1->CurrLedState = RTW_LED_OFF; + pLed1->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed1->BlinkTimer), 0); + } else if (pHalData->current_band_type == BAND_ON_5G) + /* LED1 settings */ + { + pLed1->bLedWPSBlinkInProgress = _FALSE; + pLed1->CurrLedState = RTW_LED_ON; + pLed1->BlinkingLedState = RTW_LED_ON; + if (pLed1->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed1->BlinkTimer)); + pLed1->bLedBlinkInProgress = _FALSE; + } + _set_timer(&(pLed1->BlinkTimer), 0); + + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 0); + } + + break; + + case LED_CTL_STOP_WPS_FAIL: /* WPS authentication fail */ + /* LED1 settings */ + pLed1->bLedWPSBlinkInProgress = _FALSE; + pLed1->CurrLedState = RTW_LED_OFF; + pLed1->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed1->BlinkTimer), 0); + + /* LED0 settings */ + pLed->bLedWPSBlinkInProgress = _FALSE; + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedOn) + _set_timer(&(pLed->BlinkTimer), 0); + + break; + + + default: + break; + + } + +} + +/* Edimax-ASUS, added by Page, 20121221 */ +void +SwLedControlMode11( + PADAPTER Adapter, + LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(Adapter->ledpriv); + struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; + PLED_USB pLed = &(ledpriv->SwLed0); + + switch (LedAction) { + case LED_CTL_POWER_ON: + case LED_CTL_START_TO_LINK: + case LED_CTL_NO_LINK: + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), 0); + break; + + case LED_CTL_LINK: + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + pLed->bLedBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_TXRX; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_SCAN_INTERVAL_ALPHA); + break; + + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + pLed->bLedWPSBlinkInProgress = _TRUE; + pLed->bLedBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + pLed->BlinkTimes = 5; + _set_timer(&(pLed->BlinkTimer), 0); + + break; + + + case LED_CTL_STOP_WPS: + case LED_CTL_STOP_WPS_FAIL: + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + pLed->CurrLedState = LED_BLINK_WPS_STOP; + _set_timer(&(pLed->BlinkTimer), 0); + break; + + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + + if (pLed->bLedNoLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedLinkBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedLinkBlinkInProgress = _FALSE; + } + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + + SwLedOff(Adapter, pLed); + break; + + default: + break; + + } + +} + +/* page added for NEC */ + +VOID +SwLedControlMode12( + PADAPTER Adapter, + LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(Adapter->ledpriv); + struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; + PLED_USB pLed = &(ledpriv->SwLed0); + + switch (LedAction) { + case LED_CTL_POWER_ON: + case LED_CTL_NO_LINK: + case LED_CTL_LINK: + case LED_CTL_SITE_SURVEY: + + if (pLed->bLedNoLinkBlinkInProgress == _FALSE) { + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + + pLed->bLedNoLinkBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_SLOWLY; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NO_LINK_INTERVAL_ALPHA); + } + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == _FALSE) { + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + pLed->bLedBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + break; + + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + + if (pLed->bLedNoLinkBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedNoLinkBlinkInProgress = _FALSE; + } + + SwLedOff(Adapter, pLed); + break; + + default: + break; + + } + +} + +/* Maddest add for NETGEAR R6100 */ + +VOID +SwLedControlMode13( + IN PADAPTER Adapter, + IN LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(Adapter->ledpriv); + struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; + PLED_USB pLed = &(ledpriv->SwLed0); + + switch (LedAction) { + case LED_CTL_LINK: + if (pLed->bLedWPSBlinkInProgress) + return; + + + pLed->CurrLedState = RTW_LED_ON; + pLed->BlinkingLedState = RTW_LED_ON; + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + + _set_timer(&(pLed->BlinkTimer), 0); + break; + + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedWPSBlinkInProgress == _FALSE) { + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + pLed->bLedWPSBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_WPS_BLINK_OFF_INTERVAL_NETGEAR); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_WPS_BLINK_ON_INTERVAL_NETGEAR); + } + } + break; + + case LED_CTL_STOP_WPS: + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } else + pLed->bLedWPSBlinkInProgress = _TRUE; + + pLed->bLedWPSBlinkInProgress = _FALSE; + pLed->CurrLedState = LED_BLINK_WPS_STOP; + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + + _set_timer(&(pLed->BlinkTimer), 0); + } + + break; + + + case LED_CTL_STOP_WPS_FAIL: + case LED_CTL_STOP_WPS_FAIL_OVERLAP: /* WPS session overlap */ + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 0); + break; + + case LED_CTL_START_TO_LINK: + if ((pLed->bLedBlinkInProgress == _FALSE) && (pLed->bLedWPSBlinkInProgress == _FALSE)) { + pLed->bLedBlinkInProgress = _TRUE; + pLed->BlinkingLedState = RTW_LED_ON; + pLed->CurrLedState = LED_BLINK_LINK_IN_PROCESS; + + _set_timer(&(pLed->BlinkTimer), 0); + } + break; + + case LED_CTL_NO_LINK: + + if (pLed->bLedWPSBlinkInProgress) + return; + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + /* if(!IS_LED_BLINKING(pLed)) */ + { + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 0); + } + break; + + case LED_CTL_POWER_OFF: + case LED_CTL_POWER_ON: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + + if (LedAction == LED_CTL_POWER_ON) + _set_timer(&(pLed->BlinkTimer), 0); + else + SwLedOff(Adapter, pLed); + break; + + default: + break; + + } + + +} + +/* Maddest add for DNI Buffalo */ + +VOID +SwLedControlMode14( + IN PADAPTER Adapter, + IN LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(Adapter->ledpriv); + PLED_USB pLed = &(ledpriv->SwLed0); + + switch (LedAction) { + case LED_CTL_POWER_OFF: + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + SwLedOff(Adapter, pLed); + break; + + case LED_CTL_POWER_ON: + SwLedOn(Adapter, pLed); + break; + + case LED_CTL_LINK: + case LED_CTL_NO_LINK: + if (IS_HARDWARE_TYPE_8812AU(Adapter)) + SwLedOn(Adapter, pLed); + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedBlinkInProgress == _FALSE) { + pLed->bLedBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + if (IS_HARDWARE_TYPE_8812AU(Adapter)) + _set_timer(&(pLed->BlinkTimer), LED_BLINK_LINK_INTERVAL_ALPHA); + else + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + if (IS_HARDWARE_TYPE_8812AU(Adapter)) + _set_timer(&(pLed->BlinkTimer), LED_BLINK_NORMAL_INTERVAL); + else + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + } + } + break; + + default: + break; + } +} + +/* Maddest add for Dlink */ + +VOID +SwLedControlMode15( + IN PADAPTER Adapter, + IN LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(Adapter->ledpriv); + struct mlme_priv *pmlmepriv = &Adapter->mlmepriv; + PLED_USB pLed = &(ledpriv->SwLed0); + + switch (LedAction) { + case LED_CTL_START_WPS: /* wait until xinpin finish */ + case LED_CTL_START_WPS_BOTTON: + if (pLed->bLedWPSBlinkInProgress == _FALSE) { + if (pLed->bLedBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress == _TRUE) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + pLed->bLedWPSBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_WPS; + if (pLed->bLedOn) { + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), LED_WPS_BLINK_OFF_INTERVAL_NETGEAR); + } else { + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_WPS_BLINK_ON_INTERVAL_NETGEAR); + } + } + break; + + case LED_CTL_STOP_WPS: + if (pLed->bLedWPSBlinkInProgress) + _cancel_timer_ex(&(pLed->BlinkTimer)); + + pLed->CurrLedState = LED_BLINK_WPS_STOP; + /* if(check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE) */ + { + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), 0); + } + + break; + + case LED_CTL_STOP_WPS_FAIL: + case LED_CTL_STOP_WPS_FAIL_OVERLAP: /* WPS session overlap */ + if (pLed->bLedWPSBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedWPSBlinkInProgress = _FALSE; + } + + pLed->CurrLedState = RTW_LED_OFF; + pLed->BlinkingLedState = RTW_LED_OFF; + _set_timer(&(pLed->BlinkTimer), 0); + break; + + case LED_CTL_NO_LINK: + if (pLed->bLedWPSBlinkInProgress) + return; + + /*if(Adapter->securitypriv.dot11PrivacyAlgrthm > _NO_PRIVACY_) + { + if(SecIsTxKeyInstalled(Adapter, pMgntInfo->Bssid)) + { + } + else + { + if(pMgntInfo->LEDAssocState ==LED_ASSOC_SECURITY_BEGIN) + return; + } + }*/ + + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + if (pLed->bLedScanBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedScanBlinkInProgress = _FALSE; + } + /* if(!IS_LED_BLINKING(pLed)) */ + { + pLed->CurrLedState = LED_BLINK_NO_LINK; + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), 30); + } + break; + + case LED_CTL_LINK: + + if (pLed->bLedWPSBlinkInProgress) + return; + + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + + pLed->CurrLedState = LED_BLINK_LINK_IDEL; + pLed->BlinkingLedState = RTW_LED_ON; + + _set_timer(&(pLed->BlinkTimer), 30); + break; + + case LED_CTL_SITE_SURVEY: + if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) + return; + + if (pLed->bLedWPSBlinkInProgress == _TRUE) + return; + + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + pLed->CurrLedState = LED_BLINK_SCAN; + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), 0); + break; + + case LED_CTL_TX: + case LED_CTL_RX: + if (pLed->bLedWPSBlinkInProgress) + return; + + if (pLed->bLedBlinkInProgress) { + _cancel_timer_ex(&(pLed->BlinkTimer)); + pLed->bLedBlinkInProgress = _FALSE; + } + + pLed->bLedBlinkInProgress = _TRUE; + pLed->CurrLedState = LED_BLINK_TXRX; + pLed->BlinkTimes = 2; + if (pLed->bLedOn) + pLed->BlinkingLedState = RTW_LED_OFF; + else + pLed->BlinkingLedState = RTW_LED_ON; + _set_timer(&(pLed->BlinkTimer), LED_BLINK_FASTER_INTERVAL_ALPHA); + break; + + default: + break; + } +} + +void +LedControlUSB( + _adapter *padapter, + LED_CTL_MODE LedAction +) +{ + struct led_priv *ledpriv = &(padapter->ledpriv); + +#if (MP_DRIVER == 1) + if (padapter->registrypriv.mp_mode == 1) + return; +#endif + + if (RTW_CANNOT_RUN(padapter) || (!rtw_is_hw_init_completed(padapter))) { + /*RTW_INFO("%s bDriverStopped:%s, bSurpriseRemoved:%s\n" + , __func__ + , rtw_is_drv_stopped(padapter)?"True":"False" + , rtw_is_surprise_removed(padapter)?"True":"False" );*/ + return; + } + + if (ledpriv->bRegUseLed == _FALSE) + return; + + /* if(priv->bInHctTest) */ + /* return; */ + +#ifdef CONFIG_CONCURRENT_MODE + /* Only do led action for PRIMARY_ADAPTER */ + if (padapter->adapter_type != PRIMARY_ADAPTER) + return; +#endif + + if ((adapter_to_pwrctl(padapter)->rf_pwrstate != rf_on && + adapter_to_pwrctl(padapter)->rfoff_reason > RF_CHANGE_BY_PS) && + (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX || + LedAction == LED_CTL_SITE_SURVEY || + LedAction == LED_CTL_LINK || + LedAction == LED_CTL_NO_LINK || + LedAction == LED_CTL_POWER_ON)) + return; + + switch (ledpriv->LedStrategy) { + case SW_LED_MODE0: + SwLedControlMode0(padapter, LedAction); + break; + + case SW_LED_MODE1: + SwLedControlMode1(padapter, LedAction); + break; + + case SW_LED_MODE2: + SwLedControlMode2(padapter, LedAction); + break; + + case SW_LED_MODE3: + SwLedControlMode3(padapter, LedAction); + break; + + case SW_LED_MODE4: + SwLedControlMode4(padapter, LedAction); + break; + + case SW_LED_MODE5: + SwLedControlMode5(padapter, LedAction); + break; + + case SW_LED_MODE6: + SwLedControlMode6(padapter, LedAction); + break; + + case SW_LED_MODE7: + SwLedControlMode7(padapter, LedAction); + break; + + case SW_LED_MODE8: + SwLedControlMode8(padapter, LedAction); + break; + + case SW_LED_MODE9: + SwLedControlMode9(padapter, LedAction); + break; + + case SW_LED_MODE10: + SwLedControlMode10(padapter, LedAction); + break; + + case SW_LED_MODE11: + SwLedControlMode11(padapter, LedAction); + break; + + case SW_LED_MODE12: + SwLedControlMode12(padapter, LedAction); + break; + + case SW_LED_MODE13: + SwLedControlMode13(padapter, LedAction); + break; + + case SW_LED_MODE14: + SwLedControlMode14(padapter, LedAction); + break; + + case SW_LED_MODE15: + SwLedControlMode15(padapter, LedAction); + break; + + default: + break; + } + +} + +/* + * Description: + * Reset status of LED_871x object. + * */ +void ResetLedStatus(PLED_USB pLed) +{ + + pLed->CurrLedState = RTW_LED_OFF; /* Current LED state. */ + pLed->bLedOn = _FALSE; /* true if LED is ON, false if LED is OFF. */ + + pLed->bLedBlinkInProgress = _FALSE; /* true if it is blinking, false o.w.. */ + pLed->bLedWPSBlinkInProgress = _FALSE; + + pLed->BlinkTimes = 0; /* Number of times to toggle led state for blinking. */ + pLed->BlinkCounter = 0; + pLed->BlinkingLedState = LED_UNKNOWN; /* Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */ + + pLed->bLedNoLinkBlinkInProgress = _FALSE; + pLed->bLedLinkBlinkInProgress = _FALSE; + pLed->bLedStartToLinkBlinkInProgress = _FALSE; + pLed->bLedScanBlinkInProgress = _FALSE; +} + +/* +* Description: +* Initialize an LED_871x object. +* */ +void +InitLed( + _adapter *padapter, + PLED_USB pLed, + LED_PIN LedPin +) +{ + pLed->padapter = padapter; + pLed->LedPin = LedPin; + + ResetLedStatus(pLed); + _init_timer(&(pLed->BlinkTimer), padapter->pnetdev, BlinkTimerCallback, pLed); + _init_workitem(&(pLed->BlinkWorkItem), BlinkWorkItemCallback, pLed); +} + + +/* + * Description: + * DeInitialize an LED_871x object. + * */ +void +DeInitLed( + PLED_USB pLed +) +{ + _cancel_workitem_sync(&(pLed->BlinkWorkItem)); + _cancel_timer_ex(&(pLed->BlinkTimer)); + ResetLedStatus(pLed); +} diff --git a/linux-bsp/drivers/rtl8188eus/hal/phydm/halhwimg.h b/linux-bsp/drivers/rtl8188eus/hal/phydm/halhwimg.h new file mode 100644 index 0000000..14a9f63 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/phydm/halhwimg.h @@ -0,0 +1,123 @@ +#pragma once +#ifndef __INC_HW_IMG_H +#define __INC_HW_IMG_H + +/* + * 2011/03/15 MH Add for different IC HW image file selection. code size consideration. + * */ +#if RT_PLATFORM == PLATFORM_LINUX + + #if (DEV_BUS_TYPE == RT_PCI_INTERFACE) + /* For 92C */ + #define RTL8192CE_HWIMG_SUPPORT 1 + #define RTL8192CE_TEST_HWIMG_SUPPORT 0 + #define RTL8192CU_HWIMG_SUPPORT 0 + #define RTL8192CU_TEST_HWIMG_SUPPORT 0 + + /* For 92D */ + #define RTL8192DE_HWIMG_SUPPORT 1 + #define RTL8192DE_TEST_HWIMG_SUPPORT 0 + #define RTL8192DU_HWIMG_SUPPORT 0 + #define RTL8192DU_TEST_HWIMG_SUPPORT 0 + + /* For 8723 */ + #define RTL8723E_HWIMG_SUPPORT 1 + #define RTL8723U_HWIMG_SUPPORT 0 + #define RTL8723S_HWIMG_SUPPORT 0 + + /* For 88E */ + #define RTL8188EE_HWIMG_SUPPORT 0 + #define RTL8188EU_HWIMG_SUPPORT 0 + #define RTL8188ES_HWIMG_SUPPORT 0 + + #elif (DEV_BUS_TYPE == RT_USB_INTERFACE) + /* For 92C */ + #define RTL8192CE_HWIMG_SUPPORT 0 + #define RTL8192CE_TEST_HWIMG_SUPPORT 0 + #define RTL8192CU_HWIMG_SUPPORT 1 + #define RTL8192CU_TEST_HWIMG_SUPPORT 0 + + /* For 92D */ + #define RTL8192DE_HWIMG_SUPPORT 0 + #define RTL8192DE_TEST_HWIMG_SUPPORT 0 + #define RTL8192DU_HWIMG_SUPPORT 1 + #define RTL8192DU_TEST_HWIMG_SUPPORT 0 + + /* For 8723 */ + #define RTL8723E_HWIMG_SUPPORT 0 + #define RTL8723U_HWIMG_SUPPORT 1 + #define RTL8723S_HWIMG_SUPPORT 0 + + /* For 88E */ + #define RTL8188EE_HWIMG_SUPPORT 0 + #define RTL8188EU_HWIMG_SUPPORT 0 + #define RTL8188ES_HWIMG_SUPPORT 0 + + #elif (DEV_BUS_TYPE == RT_SDIO_INTERFACE) + /* For 92C */ + #define RTL8192CE_HWIMG_SUPPORT 0 + #define RTL8192CE_TEST_HWIMG_SUPPORT 0 + #define RTL8192CU_HWIMG_SUPPORT 1 + #define RTL8192CU_TEST_HWIMG_SUPPORT 0 + + /* For 92D */ + #define RTL8192DE_HWIMG_SUPPORT 0 + #define RTL8192DE_TEST_HWIMG_SUPPORT 0 + #define RTL8192DU_HWIMG_SUPPORT 1 + #define RTL8192DU_TEST_HWIMG_SUPPORT 0 + + /* For 8723 */ + #define RTL8723E_HWIMG_SUPPORT 0 + #define RTL8723U_HWIMG_SUPPORT 0 + #define RTL8723S_HWIMG_SUPPORT 1 + + /* For 88E */ + #define RTL8188EE_HWIMG_SUPPORT 0 + #define RTL8188EU_HWIMG_SUPPORT 0 + #define RTL8188ES_HWIMG_SUPPORT 0 + #endif + +#else /* PLATFORM_WINDOWS & MacOSX */ + + /* For 92C */ + #define RTL8192CE_HWIMG_SUPPORT 1 + #define RTL8192CE_TEST_HWIMG_SUPPORT 1 + #define RTL8192CU_HWIMG_SUPPORT 1 + #define RTL8192CU_TEST_HWIMG_SUPPORT 1 + + /* For 92D */ + #define RTL8192DE_HWIMG_SUPPORT 1 + #define RTL8192DE_TEST_HWIMG_SUPPORT 1 + #define RTL8192DU_HWIMG_SUPPORT 1 + #define RTL8192DU_TEST_HWIMG_SUPPORT 1 + + #if defined(UNDER_CE) + /* For 8723 */ + #define RTL8723E_HWIMG_SUPPORT 0 + #define RTL8723U_HWIMG_SUPPORT 0 + #define RTL8723S_HWIMG_SUPPORT 1 + + /* For 88E */ + #define RTL8188EE_HWIMG_SUPPORT 0 + #define RTL8188EU_HWIMG_SUPPORT 0 + #define RTL8188ES_HWIMG_SUPPORT 0 + + #else + + /* For 8723 */ + #define RTL8723E_HWIMG_SUPPORT 1 + /* #define RTL_8723E_TEST_HWIMG_SUPPORT 1 */ + #define RTL8723U_HWIMG_SUPPORT 1 + /* #define RTL_8723U_TEST_HWIMG_SUPPORT 1 */ + #define RTL8723S_HWIMG_SUPPORT 1 + /* #define RTL_8723S_TEST_HWIMG_SUPPORT 1 */ + + /* For 88E */ + #define RTL8188EE_HWIMG_SUPPORT 1 + #define RTL8188EU_HWIMG_SUPPORT 1 + #define RTL8188ES_HWIMG_SUPPORT 1 + #endif + +#endif + +#endif /* __INC_HW_IMG_H */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ap.c b/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ap.c new file mode 100644 index 0000000..ebddba1 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ap.c @@ -0,0 +1,2665 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#include "mp_precomp.h" +#include "phydm_precomp.h" + +#ifndef index_mapping_NUM_88E + #define index_mapping_NUM_88E 15 +#endif + +/* #if(DM_ODM_SUPPORT_TYPE & ODM_WIN) */ + +#define CALCULATE_SWINGTALBE_OFFSET(_offset, _direction, _size, _delta_thermal) \ + do {\ + for (_offset = 0; _offset < _size; _offset++) { \ + \ + if (_delta_thermal < thermal_threshold[_direction][_offset]) { \ + \ + if (_offset != 0)\ + _offset--;\ + break;\ + } \ + } \ + if (_offset >= _size)\ + _offset = _size-1;\ + } while (0) + + +void configure_txpower_track( + void *p_dm_void, + struct _TXPWRTRACK_CFG *p_config +) +{ + struct PHY_DM_STRUCT *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void; +#if RTL8812A_SUPPORT +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + /* if (IS_HARDWARE_TYPE_8812(p_dm_odm->adapter)) */ + if (p_dm_odm->support_ic_type == ODM_RTL8812) + configure_txpower_track_8812a(p_config); + /* else */ +#endif +#endif + +#if RTL8814A_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8814A) + configure_txpower_track_8814a(p_config); +#endif + + +#if RTL8188E_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8188E) + configure_txpower_track_8188e(p_config); +#endif + +#if RTL8197F_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8197F) + configure_txpower_track_8197f(p_config); +#endif + +#if RTL8822B_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8822B) + configure_txpower_track_8822b(p_config); +#endif + + +} + +#if (RTL8192E_SUPPORT == 1) +void +odm_txpowertracking_callback_thermal_meter_92e( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + void *p_dm_void +#else + struct _ADAPTER *adapter +#endif +) +{ + struct PHY_DM_STRUCT *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void; + u8 thermal_value = 0, delta, delta_IQK, delta_LCK, channel, is_decrease, rf_mimo_mode; + u8 thermal_value_avg_count = 0; + u8 OFDM_min_index = 10; /* OFDM BB Swing should be less than +2.5dB, which is required by Arthur */ + s8 OFDM_index[2], index ; + u32 thermal_value_avg = 0, reg0x18; + u32 i = 0, j = 0, rf; + s32 value32, CCK_index = 0, ele_A, ele_D, ele_C, X, Y; + struct rtl8192cd_priv *priv = p_dm_odm->priv; + + rf_mimo_mode = p_dm_odm->rf_type; + /* ODM_RT_TRACE(p_dm_odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("%s:%d rf_mimo_mode:%d\n", __FUNCTION__, __LINE__, rf_mimo_mode)); */ + +#ifdef MP_TEST + if ((OPMODE & WIFI_MP_STATE) || priv->pshare->rf_ft_var.mp_specific) { + channel = priv->pshare->working_channel; + if (priv->pshare->mp_txpwr_tracking == false) + return; + } else +#endif + { + channel = (priv->pmib->dot11RFEntry.dot11channel); + } + + thermal_value = (unsigned char)odm_get_rf_reg(p_dm_odm, RF_PATH_A, ODM_RF_T_METER_92E, 0xfc00); /* 0x42: RF Reg[15:10] 88E */ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("\nReadback Thermal Meter = 0x%x pre thermal meter 0x%x EEPROMthermalmeter 0x%x\n", thermal_value, priv->pshare->thermal_value, priv->pmib->dot11RFEntry.ther)); + + + switch (rf_mimo_mode) { + case MIMO_1T1R: + rf = 1; + break; + case MIMO_2T2R: + rf = 2; + break; + default: + rf = 2; + break; + } + + /* Query OFDM path A default setting Bit[31:21] */ + ele_D = phy_query_bb_reg(priv, REG_OFDM_0_XA_TX_IQ_IMBALANCE, MASKOFDM_D); + for (i = 0; i < OFDM_TABLE_SIZE_92E; i++) { + if (ele_D == (ofdm_swing_table_92e[i] >> 22)) { + OFDM_index[0] = (unsigned char)i; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("PathA 0xC80[31:22] = 0x%x, OFDM_index=%d\n", ele_D, OFDM_index[0])); + break; + } + } + + /* Query OFDM path B default setting */ + if (rf_mimo_mode == MIMO_2T2R) { + ele_D = phy_query_bb_reg(priv, REG_OFDM_0_XB_TX_IQ_IMBALANCE, MASKOFDM_D); + for (i = 0; i < OFDM_TABLE_SIZE_92E; i++) { + if (ele_D == (ofdm_swing_table_92e[i] >> 22)) { + OFDM_index[1] = (unsigned char)i; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("PathB 0xC88[31:22] = 0x%x, OFDM_index=%d\n", ele_D, OFDM_index[1])); + break; + } + } + } + + /* calculate average thermal meter */ + { + priv->pshare->thermal_value_avg_88xx[priv->pshare->thermal_value_avg_index_88xx] = thermal_value; + priv->pshare->thermal_value_avg_index_88xx++; + if (priv->pshare->thermal_value_avg_index_88xx == AVG_THERMAL_NUM_88XX) + priv->pshare->thermal_value_avg_index_88xx = 0; + + for (i = 0; i < AVG_THERMAL_NUM_88XX; i++) { + if (priv->pshare->thermal_value_avg_88xx[i]) { + thermal_value_avg += priv->pshare->thermal_value_avg_88xx[i]; + thermal_value_avg_count++; + } + } + + if (thermal_value_avg_count) { + thermal_value = (unsigned char)(thermal_value_avg / thermal_value_avg_count); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("AVG Thermal Meter = 0x%x\n", thermal_value)); + } + } + + /* Initialize */ + if (!priv->pshare->thermal_value) { + priv->pshare->thermal_value = priv->pmib->dot11RFEntry.ther; + priv->pshare->thermal_value_iqk = thermal_value; + priv->pshare->thermal_value_lck = thermal_value; + } + + if (thermal_value != priv->pshare->thermal_value) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("\n******** START POWER TRACKING ********\n")); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("\nReadback Thermal Meter = 0x%x pre thermal meter 0x%x EEPROMthermalmeter 0x%x\n", thermal_value, priv->pshare->thermal_value, priv->pmib->dot11RFEntry.ther)); + + delta = RTL_ABS(thermal_value, priv->pmib->dot11RFEntry.ther); + delta_IQK = RTL_ABS(thermal_value, priv->pshare->thermal_value_iqk); + delta_LCK = RTL_ABS(thermal_value, priv->pshare->thermal_value_lck); + is_decrease = ((thermal_value < priv->pmib->dot11RFEntry.ther) ? 1 : 0); + +#ifdef _TRACKING_TABLE_FILE + if (priv->pshare->rf_ft_var.pwr_track_file) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("diff: (%s)%d ==> get index from table : %d)\n", (is_decrease ? "-" : "+"), delta, get_tx_tracking_index(priv, channel, i, delta, is_decrease, 0))); + + if (is_decrease) { + for (i = 0; i < rf; i++) { + OFDM_index[i] = priv->pshare->OFDM_index0[i] + get_tx_tracking_index(priv, channel, i, delta, is_decrease, 0); + OFDM_index[i] = ((OFDM_index[i] > (OFDM_TABLE_SIZE_92E- 1)) ? (OFDM_TABLE_SIZE_92E - 1) : OFDM_index[i]); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, (">>> decrese power ---> new OFDM_INDEX:%d (%d + %d)\n", OFDM_index[i], priv->pshare->OFDM_index0[i], get_tx_tracking_index(priv, channel, i, delta, is_decrease, 0))); + CCK_index = priv->pshare->CCK_index0 + get_tx_tracking_index(priv, channel, i, delta, is_decrease, 1); + CCK_index = ((CCK_index > (CCK_TABLE_SIZE_92E - 1)) ? (CCK_TABLE_SIZE_92E - 1) : CCK_index); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, (">>> Decrese power ---> new CCK_INDEX:%d (%d + %d)\n", CCK_index, priv->pshare->CCK_index0, get_tx_tracking_index(priv, channel, i, delta, is_decrease, 1))); + } + } else { + for (i = 0; i < rf; i++) { + OFDM_index[i] = priv->pshare->OFDM_index0[i] - get_tx_tracking_index(priv, channel, i, delta, is_decrease, 0); + OFDM_index[i] = ((OFDM_index[i] < OFDM_min_index) ? OFDM_min_index : OFDM_index[i]); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, (">>> Increse power ---> new OFDM_INDEX:%d (%d - %d)\n", OFDM_index[i], priv->pshare->OFDM_index0[i], get_tx_tracking_index(priv, channel, i, delta, is_decrease, 0))); + CCK_index = priv->pshare->CCK_index0 - get_tx_tracking_index(priv, channel, i, delta, is_decrease, 1); + CCK_index = ((CCK_index < 0) ? 0 : CCK_index); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, (">>> Increse power ---> new CCK_INDEX:%d (%d - %d)\n", CCK_index, priv->pshare->CCK_index0, get_tx_tracking_index(priv, channel, i, delta, is_decrease, 1))); + } + } + } +#endif /* CFG_TRACKING_TABLE_FILE */ + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("ofdm_swing_table_92e[(unsigned int)OFDM_index[0]] = %x\n", ofdm_swing_table_92e[(unsigned int)OFDM_index[0]])); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("ofdm_swing_table_92e[(unsigned int)OFDM_index[1]] = %x\n", ofdm_swing_table_92e[(unsigned int)OFDM_index[1]])); + + /* Adujst OFDM Ant_A according to IQK result */ + ele_D = (ofdm_swing_table_92e[(unsigned int)OFDM_index[0]] & 0xFFC00000) >> 22; + X = priv->pshare->rege94; + Y = priv->pshare->rege9c; + + if (X != 0) { + if ((X & 0x00000200) != 0) + X = X | 0xFFFFFC00; + ele_A = ((X * ele_D) >> 8) & 0x000003FF; + + /* new element C = element D x Y */ + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + ele_C = ((Y * ele_D) >> 8) & 0x000003FF; + + /* wirte new elements A, C, D to regC80 and regC94, element B is always 0 */ + value32 = (ele_D << 22) | ((ele_C & 0x3F) << 16) | ele_A; + phy_set_bb_reg(priv, REG_OFDM_0_XA_TX_IQ_IMBALANCE, MASKDWORD, value32); + + value32 = (ele_C & 0x000003C0) >> 6; + phy_set_bb_reg(priv, REG_OFDM_0_XC_TX_AFE, MASKH4BITS, value32); + + value32 = ((X * ele_D) >> 7) & 0x01; + phy_set_bb_reg(priv, REG_OFDM_0_ECCA_THRESHOLD, BIT(24), value32); + } else { + phy_set_bb_reg(priv, REG_OFDM_0_XA_TX_IQ_IMBALANCE, MASKDWORD, ofdm_swing_table_92e[(unsigned int)OFDM_index[0]]); + phy_set_bb_reg(priv, REG_OFDM_0_XC_TX_AFE, MASKH4BITS, 0x00); + phy_set_bb_reg(priv, REG_OFDM_0_ECCA_THRESHOLD, BIT(24), 0x00); + } + + set_CCK_swing_index(priv, CCK_index); + + if (rf == 2) { + ele_D = (ofdm_swing_table_92e[(unsigned int)OFDM_index[1]] & 0xFFC00000) >> 22; + X = priv->pshare->regeb4; + Y = priv->pshare->regebc; + + if (X != 0) { + if ((X & 0x00000200) != 0) /* consider minus */ + X = X | 0xFFFFFC00; + ele_A = ((X * ele_D) >> 8) & 0x000003FF; + + /* new element C = element D x Y */ + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + ele_C = ((Y * ele_D) >> 8) & 0x00003FF; + + /* wirte new elements A, C, D to regC88 and regC9C, element B is always 0 */ + value32 = (ele_D << 22) | ((ele_C & 0x3F) << 16) | ele_A; + phy_set_bb_reg(priv, REG_OFDM_0_XB_TX_IQ_IMBALANCE, MASKDWORD, value32); + + value32 = (ele_C & 0x000003C0) >> 6; + phy_set_bb_reg(priv, REG_OFDM_0_XD_TX_AFE, MASKH4BITS, value32); + + value32 = ((X * ele_D) >> 7) & 0x01; + phy_set_bb_reg(priv, REG_OFDM_0_ECCA_THRESHOLD, BIT(28), value32); + } else { + phy_set_bb_reg(priv, REG_OFDM_0_XB_TX_IQ_IMBALANCE, MASKDWORD, ofdm_swing_table_92e[(unsigned int)OFDM_index[1]]); + phy_set_bb_reg(priv, REG_OFDM_0_XD_TX_AFE, MASKH4BITS, 0x00); + phy_set_bb_reg(priv, REG_OFDM_0_ECCA_THRESHOLD, BIT(28), 0x00); + } + + } + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("0xc80 = 0x%x\n", phy_query_bb_reg(priv, REG_OFDM_0_XA_TX_IQ_IMBALANCE, MASKDWORD))); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("0xc88 = 0x%x\n", phy_query_bb_reg(priv, REG_OFDM_0_XB_TX_IQ_IMBALANCE, MASKDWORD))); + + if (delta_IQK > 3) { + priv->pshare->thermal_value_iqk = thermal_value; +#ifdef MP_TEST + if (!(priv->pshare->rf_ft_var.mp_specific && (OPMODE & (WIFI_MP_CTX_BACKGROUND | WIFI_MP_CTX_PACKET)))) +#endif + phy_iq_calibrate_8192e(p_dm_odm, false); + } + + if (delta_LCK > 8) { + RTL_W8(0x522, 0xff); + reg0x18 = phy_query_rf_reg(priv, RF_PATH_A, 0x18, MASK20BITS, 1); + phy_set_rf_reg(priv, RF_PATH_A, 0xB4, BIT(14), 1); + phy_set_rf_reg(priv, RF_PATH_A, 0x18, BIT(15), 1); + delay_ms(1); + phy_set_rf_reg(priv, RF_PATH_A, 0xB4, BIT(14), 0); + phy_set_rf_reg(priv, RF_PATH_A, 0x18, MASK20BITS, reg0x18); + RTL_W8(0x522, 0x0); + priv->pshare->thermal_value_lck = thermal_value; + } + } + + /* update thermal meter value */ + priv->pshare->thermal_value = thermal_value; + for (i = 0 ; i < rf ; i++) + priv->pshare->OFDM_index[i] = OFDM_index[i]; + priv->pshare->CCK_index = CCK_index; + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("\n******** END:%s() ********\n", __FUNCTION__)); +} +#endif + + + +#if (RTL8197F_SUPPORT == 1 || RTL8822B_SUPPORT == 1) +void +odm_txpowertracking_callback_thermal_meter_jaguar_series3( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + void *p_dm_void +#else + struct _ADAPTER *adapter +#endif +) +{ +#if 1 + struct PHY_DM_STRUCT *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void; + u8 thermal_value = 0, delta, delta_LCK, delta_IQK, channel, is_increase; + u8 thermal_value_avg_count = 0, p = 0, i = 0; + u32 thermal_value_avg = 0; + struct rtl8192cd_priv *priv = p_dm_odm->priv; + struct _TXPWRTRACK_CFG c; + struct odm_rf_calibration_structure *p_rf_calibrate_info = &(p_dm_odm->rf_calibrate_info); + + /*4 1. The following TWO tables decide the final index of OFDM/CCK swing table.*/ + u8 *delta_swing_table_idx_tup_a = NULL, *delta_swing_table_idx_tdown_a = NULL; + u8 *delta_swing_table_idx_tup_b = NULL, *delta_swing_table_idx_tdown_b = NULL; + u8 *delta_swing_table_idx_tup_cck_a = NULL, *delta_swing_table_idx_tdown_cck_a = NULL; + u8 *delta_swing_table_idx_tup_cck_b = NULL, *delta_swing_table_idx_tdown_cck_b = NULL; + /*for 8814 add by Yu Chen*/ + u8 *delta_swing_table_idx_tup_c = NULL, *delta_swing_table_idx_tdown_c = NULL; + u8 *delta_swing_table_idx_tup_d = NULL, *delta_swing_table_idx_tdown_d = NULL; + u8 *delta_swing_table_idx_tup_cck_c = NULL, *delta_swing_table_idx_tdown_cck_c = NULL; + u8 *delta_swing_table_idx_tup_cck_d = NULL, *delta_swing_table_idx_tdown_cck_d = NULL; + +#ifdef MP_TEST + if ((OPMODE & WIFI_MP_STATE) || priv->pshare->rf_ft_var.mp_specific) { + channel = priv->pshare->working_channel; + if (priv->pshare->mp_txpwr_tracking == false) + return; + } else +#endif + { + channel = (priv->pmib->dot11RFEntry.dot11channel); + } + + configure_txpower_track(p_dm_odm, &c); + + (*c.get_delta_all_swing_table)(p_dm_odm, (u8 **)&delta_swing_table_idx_tup_a, (u8 **)&delta_swing_table_idx_tdown_a, + (u8 **)&delta_swing_table_idx_tup_b, (u8 **)&delta_swing_table_idx_tdown_b, + (u8 **)&delta_swing_table_idx_tup_cck_a, (u8 **)&delta_swing_table_idx_tdown_cck_a, + (u8 **)&delta_swing_table_idx_tup_cck_b, (u8 **)&delta_swing_table_idx_tdown_cck_b); + + thermal_value = (u8)odm_get_rf_reg(p_dm_odm, ODM_RF_PATH_A, c.thermal_reg_addr, 0xfc00); /*0x42: RF Reg[15:10] 88E*/ + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Readback Thermal Meter = 0x%x(%d) EEPROMthermalmeter 0x%x(%d)\n" + , thermal_value, thermal_value, priv->pmib->dot11RFEntry.ther, priv->pmib->dot11RFEntry.ther)); + + /* Initialize */ + if (!p_dm_odm->rf_calibrate_info.thermal_value) + p_dm_odm->rf_calibrate_info.thermal_value = priv->pmib->dot11RFEntry.ther; + + if (!p_dm_odm->rf_calibrate_info.thermal_value_lck) + p_dm_odm->rf_calibrate_info.thermal_value_lck = priv->pmib->dot11RFEntry.ther; + + if (!p_dm_odm->rf_calibrate_info.thermal_value_iqk) + p_dm_odm->rf_calibrate_info.thermal_value_iqk = priv->pmib->dot11RFEntry.ther; + + /* calculate average thermal meter */ + p_dm_odm->rf_calibrate_info.thermal_value_avg[p_dm_odm->rf_calibrate_info.thermal_value_avg_index] = thermal_value; + p_dm_odm->rf_calibrate_info.thermal_value_avg_index++; + + if (p_dm_odm->rf_calibrate_info.thermal_value_avg_index == c.average_thermal_num) /*Average times = c.average_thermal_num*/ + p_dm_odm->rf_calibrate_info.thermal_value_avg_index = 0; + + for (i = 0; i < c.average_thermal_num; i++) { + if (p_dm_odm->rf_calibrate_info.thermal_value_avg[i]) { + thermal_value_avg += p_dm_odm->rf_calibrate_info.thermal_value_avg[i]; + thermal_value_avg_count++; + } + } + + if (thermal_value_avg_count) {/*Calculate Average thermal_value after average enough times*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("thermal_value_avg=0x%x(%d) thermal_value_avg_count = %d\n" + , thermal_value_avg, thermal_value_avg, thermal_value_avg_count)); + + thermal_value = (u8)(thermal_value_avg / thermal_value_avg_count); + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("AVG Thermal Meter = 0x%X(%d), EEPROMthermalmeter = 0x%X(%d)\n", thermal_value, thermal_value, priv->pmib->dot11RFEntry.ther, priv->pmib->dot11RFEntry.ther)); + } + + /*4 Calculate delta, delta_LCK, delta_IQK.*/ + delta = RTL_ABS(thermal_value, priv->pmib->dot11RFEntry.ther); + delta_LCK = RTL_ABS(thermal_value, p_dm_odm->rf_calibrate_info.thermal_value_lck); + delta_IQK = RTL_ABS(thermal_value, p_dm_odm->rf_calibrate_info.thermal_value_iqk); + is_increase = ((thermal_value < priv->pmib->dot11RFEntry.ther) ? 0 : 1); + + if (delta > 29) { /* power track table index(thermal diff.) upper bound*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("delta(%d) > 29, set delta to 29\n", delta)); + delta = 29; + } + + + /*4 if necessary, do LCK.*/ + + if (delta_LCK > c.threshold_iqk) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("delta_LCK(%d) >= threshold_iqk(%d)\n", delta_LCK, c.threshold_iqk)); + p_dm_odm->rf_calibrate_info.thermal_value_lck = thermal_value; + if (c.phy_lc_calibrate) + (*c.phy_lc_calibrate)(p_dm_odm); + } + + if (delta_IQK > c.threshold_iqk) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("delta_IQK(%d) >= threshold_iqk(%d)\n", delta_IQK, c.threshold_iqk)); + p_dm_odm->rf_calibrate_info.thermal_value_iqk = thermal_value; + if (c.do_iqk) + (*c.do_iqk)(p_dm_odm, true, 0, 0); + } + + if (!priv->pmib->dot11RFEntry.ther) /*Don't do power tracking since no calibrated thermal value*/ + return; + + /*4 Do Power Tracking*/ + + if (thermal_value != p_dm_odm->rf_calibrate_info.thermal_value) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("\n\n******** START POWER TRACKING ********\n")); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x EEPROMthermalmeter 0x%x\n", + thermal_value, p_dm_odm->rf_calibrate_info.thermal_value, priv->pmib->dot11RFEntry.ther)); + +#ifdef _TRACKING_TABLE_FILE + if (priv->pshare->rf_ft_var.pwr_track_file) { + if (is_increase) { /*thermal is higher than base*/ + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + switch (p) { + case ODM_RF_PATH_B: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_b[%d] = %d delta_swing_table_idx_tup_cck_b[%d] = %d\n", delta, delta_swing_table_idx_tup_b[delta], delta, delta_swing_table_idx_tup_cck_b[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_b[delta]; + p_rf_calibrate_info->absolute_cck_swing_idx[p] = delta_swing_table_idx_tup_cck_b[delta]; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and pRF->absolute_ofdm_swing_idx[ODM_RF_PATH_B] = %d pRF->absolute_cck_swing_idx[ODM_RF_PATH_B] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p], p_rf_calibrate_info->absolute_cck_swing_idx[p])); + break; + + case ODM_RF_PATH_C: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_c[%d] = %d delta_swing_table_idx_tup_cck_c[%d] = %d\n", delta, delta_swing_table_idx_tup_c[delta], delta, delta_swing_table_idx_tup_cck_c[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_c[delta]; + p_rf_calibrate_info->absolute_cck_swing_idx[p] = delta_swing_table_idx_tup_cck_c[delta]; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and pRF->absolute_ofdm_swing_idx[ODM_RF_PATH_C] = %d pRF->absolute_cck_swing_idx[ODM_RF_PATH_C] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p], p_rf_calibrate_info->absolute_cck_swing_idx[p])); + break; + + case ODM_RF_PATH_D: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_d[%d] = %d delta_swing_table_idx_tup_cck_d[%d] = %d\n", delta, delta_swing_table_idx_tup_d[delta], delta, delta_swing_table_idx_tup_cck_d[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_d[delta]; + p_rf_calibrate_info->absolute_cck_swing_idx[p] = delta_swing_table_idx_tup_cck_d[delta]; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and pRF->absolute_ofdm_swing_idx[ODM_RF_PATH_D] = %d pRF->absolute_cck_swing_idx[ODM_RF_PATH_D] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p], p_rf_calibrate_info->absolute_cck_swing_idx[p])); + break; + default: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_a[%d] = %d delta_swing_table_idx_tup_cck_a[%d] = %d\n", delta, delta_swing_table_idx_tup_a[delta], delta, delta_swing_table_idx_tup_cck_a[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_a[delta]; + p_rf_calibrate_info->absolute_cck_swing_idx[p] = delta_swing_table_idx_tup_cck_a[delta]; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and pRF->absolute_ofdm_swing_idx[ODM_RF_PATH_A] = %d pRF->absolute_cck_swing_idx[ODM_RF_PATH_A] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p], p_rf_calibrate_info->absolute_cck_swing_idx[p])); + break; + } + } + } else { /* thermal is lower than base*/ + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + switch (p) { + case ODM_RF_PATH_B: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_b[%d] = %d delta_swing_table_idx_tdown_cck_b[%d] = %d\n", delta, delta_swing_table_idx_tdown_b[delta], delta, delta_swing_table_idx_tdown_cck_b[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_b[delta]; + p_rf_calibrate_info->absolute_cck_swing_idx[p] = -1 * delta_swing_table_idx_tdown_cck_b[delta]; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and pRF->absolute_ofdm_swing_idx[ODM_RF_PATH_B] = %d pRF->absolute_cck_swing_idx[ODM_RF_PATH_B] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p], p_rf_calibrate_info->absolute_cck_swing_idx[p])); + break; + + case ODM_RF_PATH_C: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_c[%d] = %d delta_swing_table_idx_tdown_cck_c[%d] = %d\n", delta, delta_swing_table_idx_tdown_c[delta], delta, delta_swing_table_idx_tdown_cck_c[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_c[delta]; + p_rf_calibrate_info->absolute_cck_swing_idx[p] = -1 * delta_swing_table_idx_tdown_cck_c[delta]; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and pRF->absolute_ofdm_swing_idx[ODM_RF_PATH_C] = %d pRF->absolute_cck_swing_idx[ODM_RF_PATH_C] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p], p_rf_calibrate_info->absolute_cck_swing_idx[p])); + break; + + case ODM_RF_PATH_D: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_d[%d] = %d delta_swing_table_idx_tdown_cck_d[%d] = %d\n", delta, delta_swing_table_idx_tdown_d[delta], delta, delta_swing_table_idx_tdown_cck_d[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_d[delta]; + p_rf_calibrate_info->absolute_cck_swing_idx[p] = -1 * delta_swing_table_idx_tdown_cck_d[delta]; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and pRF->absolute_ofdm_swing_idx[ODM_RF_PATH_D] = %d pRF->absolute_cck_swing_idx[ODM_RF_PATH_D] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p], p_rf_calibrate_info->absolute_cck_swing_idx[p])); + break; + + default: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_a[%d] = %d delta_swing_table_idx_tdown_cck_a[%d] = %d\n", delta, delta_swing_table_idx_tdown_a[delta], delta, delta_swing_table_idx_tdown_cck_a[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_a[delta]; + p_rf_calibrate_info->absolute_cck_swing_idx[p] = -1 * delta_swing_table_idx_tdown_cck_a[delta]; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and pRF->absolute_ofdm_swing_idx[ODM_RF_PATH_A] = %d pRF->absolute_cck_swing_idx[ODM_RF_PATH_A] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p], p_rf_calibrate_info->absolute_cck_swing_idx[p])); + break; + } + } + } + + if (is_increase) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, (">>> increse power --->\n")); + if (GET_CHIP_VER(priv) == VERSION_8197F) { + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, BBSWING, p, 0); + } else if (GET_CHIP_VER(priv) == VERSION_8822B) { + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, MIX_MODE, p, 0); + } + } else { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, (">>> decrese power --->\n")); + if (GET_CHIP_VER(priv) == VERSION_8197F) { + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, BBSWING, p, 0); + } else if (GET_CHIP_VER(priv) == VERSION_8822B) { + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, MIX_MODE, p, 0); + } + } + } +#endif + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("\n******** END:%s() ********\n\n", __func__)); + /*update thermal meter value*/ + p_dm_odm->rf_calibrate_info.thermal_value = thermal_value; + + } + +#endif +} +#endif + +/*#if (RTL8814A_SUPPORT == 1)*/ +#if (RTL8814A_SUPPORT == 1) + +void +odm_txpowertracking_callback_thermal_meter_jaguar_series2( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + void *p_dm_void +#else + struct _ADAPTER *adapter +#endif +) +{ + struct PHY_DM_STRUCT *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void; + u8 thermal_value = 0, delta, delta_LCK, delta_IQK, channel, is_increase; + u8 thermal_value_avg_count = 0, p = 0, i = 0; + u32 thermal_value_avg = 0, reg0x18; + u32 bb_swing_reg[4] = {REG_A_TX_SCALE_JAGUAR, REG_B_TX_SCALE_JAGUAR, REG_C_TX_SCALE_JAGUAR2, REG_D_TX_SCALE_JAGUAR2}; + s32 ele_D; + u32 bb_swing_idx; + struct rtl8192cd_priv *priv = p_dm_odm->priv; + struct _TXPWRTRACK_CFG c; + bool is_tssi_enable = false; + struct odm_rf_calibration_structure *p_rf_calibrate_info = &(p_dm_odm->rf_calibrate_info); + + /* 4 1. The following TWO tables decide the final index of OFDM/CCK swing table. */ + u8 *delta_swing_table_idx_tup_a = NULL, *delta_swing_table_idx_tdown_a = NULL; + u8 *delta_swing_table_idx_tup_b = NULL, *delta_swing_table_idx_tdown_b = NULL; + /* for 8814 add by Yu Chen */ + u8 *delta_swing_table_idx_tup_c = NULL, *delta_swing_table_idx_tdown_c = NULL; + u8 *delta_swing_table_idx_tup_d = NULL, *delta_swing_table_idx_tdown_d = NULL; + +#ifdef MP_TEST + if ((OPMODE & WIFI_MP_STATE) || priv->pshare->rf_ft_var.mp_specific) { + channel = priv->pshare->working_channel; + if (priv->pshare->mp_txpwr_tracking == false) + return; + } else +#endif + { + channel = (priv->pmib->dot11RFEntry.dot11channel); + } + + configure_txpower_track(p_dm_odm, &c); + p_rf_calibrate_info->default_ofdm_index = priv->pshare->OFDM_index0[ODM_RF_PATH_A]; + + (*c.get_delta_swing_table)(p_dm_odm, (u8 **)&delta_swing_table_idx_tup_a, (u8 **)&delta_swing_table_idx_tdown_a, + (u8 **)&delta_swing_table_idx_tup_b, (u8 **)&delta_swing_table_idx_tdown_b); + + if (p_dm_odm->support_ic_type & ODM_RTL8814A) /* for 8814 path C & D */ + (*c.get_delta_swing_table8814only)(p_dm_odm, (u8 **)&delta_swing_table_idx_tup_c, (u8 **)&delta_swing_table_idx_tdown_c, + (u8 **)&delta_swing_table_idx_tup_d, (u8 **)&delta_swing_table_idx_tdown_d); + + thermal_value = (u8)odm_get_rf_reg(p_dm_odm, ODM_RF_PATH_A, c.thermal_reg_addr, 0xfc00); /* 0x42: RF Reg[15:10] 88E */ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("\nReadback Thermal Meter = 0x%x, pre thermal meter 0x%x, EEPROMthermalmeter 0x%x\n", thermal_value, p_dm_odm->rf_calibrate_info.thermal_value, priv->pmib->dot11RFEntry.ther)); + + /* Initialize */ + if (!p_dm_odm->rf_calibrate_info.thermal_value) + p_dm_odm->rf_calibrate_info.thermal_value = priv->pmib->dot11RFEntry.ther; + + if (!p_dm_odm->rf_calibrate_info.thermal_value_lck) + p_dm_odm->rf_calibrate_info.thermal_value_lck = priv->pmib->dot11RFEntry.ther; + + if (!p_dm_odm->rf_calibrate_info.thermal_value_iqk) + p_dm_odm->rf_calibrate_info.thermal_value_iqk = priv->pmib->dot11RFEntry.ther; + + is_tssi_enable = (bool)odm_get_rf_reg(p_dm_odm, ODM_RF_PATH_A, REG_RF_TX_GAIN_OFFSET, BIT(7)); /* check TSSI enable */ + + /* 4 Query OFDM BB swing default setting Bit[31:21] */ + for (p = ODM_RF_PATH_A ; p < c.rf_path_count ; p++) { + ele_D = odm_get_bb_reg(p_dm_odm, bb_swing_reg[p], 0xffe00000); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("0x%x:0x%x ([31:21] = 0x%x)\n", bb_swing_reg[p], odm_get_bb_reg(p_dm_odm, bb_swing_reg[p], MASKDWORD), ele_D)); + + for (bb_swing_idx = 0; bb_swing_idx < TXSCALE_TABLE_SIZE; bb_swing_idx++) {/* 4 */ + if (ele_D == tx_scaling_table_jaguar[bb_swing_idx]) { + p_dm_odm->rf_calibrate_info.OFDM_index[p] = (u8)bb_swing_idx; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("OFDM_index[%d]=%d\n", p, p_dm_odm->rf_calibrate_info.OFDM_index[p])); + break; + } + } + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("kfree_offset[%d]=%d\n", p, p_rf_calibrate_info->kfree_offset[p])); + + } + + /* calculate average thermal meter */ + p_dm_odm->rf_calibrate_info.thermal_value_avg[p_dm_odm->rf_calibrate_info.thermal_value_avg_index] = thermal_value; + p_dm_odm->rf_calibrate_info.thermal_value_avg_index++; + if (p_dm_odm->rf_calibrate_info.thermal_value_avg_index == c.average_thermal_num) /* Average times = c.average_thermal_num */ + p_dm_odm->rf_calibrate_info.thermal_value_avg_index = 0; + + for (i = 0; i < c.average_thermal_num; i++) { + if (p_dm_odm->rf_calibrate_info.thermal_value_avg[i]) { + thermal_value_avg += p_dm_odm->rf_calibrate_info.thermal_value_avg[i]; + thermal_value_avg_count++; + } + } + + if (thermal_value_avg_count) { /* Calculate Average thermal_value after average enough times */ + thermal_value = (u8)(thermal_value_avg / thermal_value_avg_count); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("AVG Thermal Meter = 0x%X, EEPROMthermalmeter = 0x%X\n", thermal_value, priv->pmib->dot11RFEntry.ther)); + } + + /* 4 Calculate delta, delta_LCK, delta_IQK. */ + delta = RTL_ABS(thermal_value, priv->pmib->dot11RFEntry.ther); + delta_LCK = RTL_ABS(thermal_value, p_dm_odm->rf_calibrate_info.thermal_value_lck); + delta_IQK = RTL_ABS(thermal_value, p_dm_odm->rf_calibrate_info.thermal_value_iqk); + is_increase = ((thermal_value < priv->pmib->dot11RFEntry.ther) ? 0 : 1); + + /* 4 if necessary, do LCK. */ + if (!(p_dm_odm->support_ic_type & ODM_RTL8821)) { + if (delta_LCK > c.threshold_iqk) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("delta_LCK(%d) >= threshold_iqk(%d)\n", delta_LCK, c.threshold_iqk)); + p_dm_odm->rf_calibrate_info.thermal_value_lck = thermal_value; + + /*Use RTLCK, so close power tracking driver LCK*/ +#if (RTL8814A_SUPPORT != 1) + if (!(p_dm_odm->support_ic_type & ODM_RTL8814A)) { + if (c.phy_lc_calibrate) + (*c.phy_lc_calibrate)(p_dm_odm); + } +#endif + } + } + + if (delta_IQK > c.threshold_iqk) { + panic_printk("%s(%d)\n", __FUNCTION__, __LINE__); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("delta_IQK(%d) >= threshold_iqk(%d)\n", delta_IQK, c.threshold_iqk)); + p_dm_odm->rf_calibrate_info.thermal_value_iqk = thermal_value; + if (c.do_iqk) + (*c.do_iqk)(p_dm_odm, true, 0, 0); + } + + if (!priv->pmib->dot11RFEntry.ther) /*Don't do power tracking since no calibrated thermal value*/ + return; + + /* 4 Do Power Tracking */ + + if (is_tssi_enable == true) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter PURE TSSI MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, TSSI_MODE, p, 0); + } else if (thermal_value != p_dm_odm->rf_calibrate_info.thermal_value) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("\n******** START POWER TRACKING ********\n")); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("\nReadback Thermal Meter = 0x%x pre thermal meter 0x%x EEPROMthermalmeter 0x%x\n", thermal_value, p_dm_odm->rf_calibrate_info.thermal_value, priv->pmib->dot11RFEntry.ther)); + +#ifdef _TRACKING_TABLE_FILE + if (priv->pshare->rf_ft_var.pwr_track_file) { + if (is_increase) { /* thermal is higher than base */ + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + switch (p) { + case ODM_RF_PATH_B: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_b[%d] = %d\n", delta, delta_swing_table_idx_tup_b[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_b[delta]; /* Record delta swing for mix mode power tracking */ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and p_dm_odm->absolute_ofdm_swing_idx[ODM_RF_PATH_B] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + case ODM_RF_PATH_C: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_c[%d] = %d\n", delta, delta_swing_table_idx_tup_c[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_c[delta]; /* Record delta swing for mix mode power tracking */ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and p_dm_odm->absolute_ofdm_swing_idx[ODM_RF_PATH_C] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + case ODM_RF_PATH_D: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_d[%d] = %d\n", delta, delta_swing_table_idx_tup_d[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_d[delta]; /* Record delta swing for mix mode power tracking */ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and p_dm_odm->absolute_ofdm_swing_idx[ODM_RF_PATH_D] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + default: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_a[%d] = %d\n", delta, delta_swing_table_idx_tup_a[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_a[delta]; /* Record delta swing for mix mode power tracking */ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and p_dm_odm->absolute_ofdm_swing_idx[ODM_RF_PATH_A] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + } + } + } else { /* thermal is lower than base */ + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + switch (p) { + case ODM_RF_PATH_B: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_b[%d] = %d\n", delta, delta_swing_table_idx_tdown_b[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_b[delta]; /* Record delta swing for mix mode power tracking */ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and p_dm_odm->absolute_ofdm_swing_idx[ODM_RF_PATH_B] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + case ODM_RF_PATH_C: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_c[%d] = %d\n", delta, delta_swing_table_idx_tdown_c[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_c[delta]; /* Record delta swing for mix mode power tracking */ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and p_dm_odm->absolute_ofdm_swing_idx[ODM_RF_PATH_C] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + case ODM_RF_PATH_D: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_d[%d] = %d\n", delta, delta_swing_table_idx_tdown_d[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_d[delta]; /* Record delta swing for mix mode power tracking */ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and p_dm_odm->absolute_ofdm_swing_idx[ODM_RF_PATH_D] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + default: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_a[%d] = %d\n", delta, delta_swing_table_idx_tdown_a[delta])); + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_a[delta]; /* Record delta swing for mix mode power tracking */ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and p_dm_odm->absolute_ofdm_swing_idx[ODM_RF_PATH_A] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + } + } + } + + if (is_increase) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, (">>> increse power --->\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, MIX_MODE, p, 0); + } else { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, (">>> decrese power --->\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, MIX_MODE, p, 0); + } + } +#endif + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("\n******** END:%s() ********\n", __FUNCTION__)); + /* update thermal meter value */ + p_dm_odm->rf_calibrate_info.thermal_value = thermal_value; + + } +} +#endif + +#if (RTL8812A_SUPPORT == 1 || RTL8881A_SUPPORT == 1) +void +odm_txpowertracking_callback_thermal_meter_jaguar_series( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + void *p_dm_void +#else + struct _ADAPTER *adapter +#endif +) +{ + struct PHY_DM_STRUCT *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void; + unsigned char thermal_value = 0, delta, delta_LCK, channel, is_decrease; + unsigned char thermal_value_avg_count = 0; + unsigned int thermal_value_avg = 0, reg0x18; + unsigned int bb_swing_reg[4] = {0xc1c, 0xe1c, 0x181c, 0x1a1c}; + int ele_D, value32; + char OFDM_index[2], index; + unsigned int i = 0, j = 0, rf_path, max_rf_path = 2, rf; + struct rtl8192cd_priv *priv = p_dm_odm->priv; + unsigned char OFDM_min_index = 7; /* OFDM BB Swing should be less than +2.5dB, which is required by Arthur and Mimic */ + + + +#ifdef MP_TEST + if ((OPMODE & WIFI_MP_STATE) || priv->pshare->rf_ft_var.mp_specific) { + channel = priv->pshare->working_channel; + if (priv->pshare->mp_txpwr_tracking == false) + return; + } else +#endif + { + channel = (priv->pmib->dot11RFEntry.dot11channel); + } + +#if RTL8881A_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8881A) { + max_rf_path = 1; + if ((get_bonding_type_8881A() == BOND_8881AM || get_bonding_type_8881A() == BOND_8881AN) + && priv->pshare->rf_ft_var.use_intpa8881A && (*p_dm_odm->p_band_type == ODM_BAND_2_4G)) + OFDM_min_index = 6; /* intPA - upper bond set to +3 dB (base: -2 dB)ot11RFEntry.phy_band_select == PHY_BAND_2G)) */ + else + OFDM_min_index = 10; /* OFDM BB Swing should be less than +1dB, which is required by Arthur and Mimic */ + } +#endif + + + thermal_value = (unsigned char)phy_query_rf_reg(priv, RF_PATH_A, 0x42, 0xfc00, 1); /* 0x42: RF Reg[15:10] 88E */ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("\nReadback Thermal Meter = 0x%x pre thermal meter 0x%x EEPROMthermalmeter 0x%x\n", thermal_value, priv->pshare->thermal_value, priv->pmib->dot11RFEntry.ther)); + + + /* 4 Query OFDM BB swing default setting Bit[31:21] */ + for (rf_path = 0 ; rf_path < max_rf_path ; rf_path++) { + ele_D = phy_query_bb_reg(priv, bb_swing_reg[rf_path], 0xffe00000); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("0x%x:0x%x ([31:21] = 0x%x)\n", bb_swing_reg[rf_path], phy_query_bb_reg(priv, bb_swing_reg[rf_path], MASKDWORD), ele_D)); + for (i = 0; i < OFDM_TABLE_SIZE_8812; i++) {/* 4 */ + if (ele_D == ofdm_swing_table_8812[i]) { + OFDM_index[rf_path] = (unsigned char)i; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("OFDM_index[%d]=%d\n", rf_path, OFDM_index[rf_path])); + break; + } + } + } +#if 0 + /* Query OFDM path A default setting Bit[31:21] */ + ele_D = phy_query_bb_reg(priv, 0xc1c, 0xffe00000); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("0xc1c:0x%x ([31:21] = 0x%x)\n", phy_query_bb_reg(priv, 0xc1c, MASKDWORD), ele_D)); + for (i = 0; i < OFDM_TABLE_SIZE_8812; i++) {/* 4 */ + if (ele_D == ofdm_swing_table_8812[i]) { + OFDM_index[0] = (unsigned char)i; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("OFDM_index[0]=%d\n", OFDM_index[0])); + break; + } + } + /* Query OFDM path B default setting */ + if (rf == 2) { + ele_D = phy_query_bb_reg(priv, 0xe1c, 0xffe00000); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("0xe1c:0x%x ([32:21] = 0x%x)\n", phy_query_bb_reg(priv, 0xe1c, MASKDWORD), ele_D)); + for (i = 0; i < OFDM_TABLE_SIZE_8812; i++) { + if (ele_D == ofdm_swing_table_8812[i]) { + OFDM_index[1] = (unsigned char)i; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("OFDM_index[1]=%d\n", OFDM_index[1])); + break; + } + } + } +#endif + /* Initialize */ + if (!priv->pshare->thermal_value) { + priv->pshare->thermal_value = priv->pmib->dot11RFEntry.ther; + priv->pshare->thermal_value_lck = thermal_value; + } + + /* calculate average thermal meter */ + { + priv->pshare->thermal_value_avg_8812[priv->pshare->thermal_value_avg_index_8812] = thermal_value; + priv->pshare->thermal_value_avg_index_8812++; + if (priv->pshare->thermal_value_avg_index_8812 == AVG_THERMAL_NUM_8812) + priv->pshare->thermal_value_avg_index_8812 = 0; + + for (i = 0; i < AVG_THERMAL_NUM_8812; i++) { + if (priv->pshare->thermal_value_avg_8812[i]) { + thermal_value_avg += priv->pshare->thermal_value_avg_8812[i]; + thermal_value_avg_count++; + } + } + + if (thermal_value_avg_count) { + thermal_value = (unsigned char)(thermal_value_avg / thermal_value_avg_count); + /* printk("AVG Thermal Meter = 0x%x\n", thermal_value); */ + } + } + + + /* 4 If necessary, do power tracking */ + + if (!priv->pmib->dot11RFEntry.ther) /*Don't do power tracking since no calibrated thermal value*/ + return; + + if (thermal_value != priv->pshare->thermal_value) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("\n******** START POWER TRACKING ********\n")); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("\nReadback Thermal Meter = 0x%x pre thermal meter 0x%x EEPROMthermalmeter 0x%x\n", thermal_value, priv->pshare->thermal_value, priv->pmib->dot11RFEntry.ther)); + delta = RTL_ABS(thermal_value, priv->pmib->dot11RFEntry.ther); + delta_LCK = RTL_ABS(thermal_value, priv->pshare->thermal_value_lck); + is_decrease = ((thermal_value < priv->pmib->dot11RFEntry.ther) ? 1 : 0); + /* if (*p_dm_odm->p_band_type == ODM_BAND_5G) */ + { +#ifdef _TRACKING_TABLE_FILE + if (priv->pshare->rf_ft_var.pwr_track_file) { + for (rf_path = 0; rf_path < max_rf_path; rf_path++) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("diff: (%s)%d ==> get index from table : %d)\n", (is_decrease ? "-" : "+"), delta, get_tx_tracking_index(priv, channel, rf_path, delta, is_decrease, 0))); + if (is_decrease) { + OFDM_index[rf_path] = priv->pshare->OFDM_index0[rf_path] + get_tx_tracking_index(priv, channel, rf_path, delta, is_decrease, 0); + OFDM_index[rf_path] = ((OFDM_index[rf_path] > (OFDM_TABLE_SIZE_8812 - 1)) ? (OFDM_TABLE_SIZE_8812 - 1) : OFDM_index[rf_path]); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, (">>> decrese power ---> new OFDM_INDEX:%d (%d + %d)\n", OFDM_index[rf_path], priv->pshare->OFDM_index0[rf_path], get_tx_tracking_index(priv, channel, rf_path, delta, is_decrease, 0))); +#if 0/* RTL8881A_SUPPORT */ + if (p_dm_odm->support_ic_type == ODM_RTL8881A) { + if (priv->pshare->rf_ft_var.pwrtrk_tx_agc_enable) { + if (priv->pshare->add_tx_agc) { /* tx_agc has been added */ + add_tx_power88xx_ac(priv, 0); + priv->pshare->add_tx_agc = 0; + priv->pshare->add_tx_agc_index = 0; + } + } + } +#endif + } else { + + OFDM_index[rf_path] = priv->pshare->OFDM_index0[rf_path] - get_tx_tracking_index(priv, channel, rf_path, delta, is_decrease, 0); +#if 0/* RTL8881A_SUPPORT */ + if (p_dm_odm->support_ic_type == ODM_RTL8881A) { + if (priv->pshare->rf_ft_var.pwrtrk_tx_agc_enable) { + if (OFDM_index[i] < OFDM_min_index) { + priv->pshare->add_tx_agc_index = (OFDM_min_index - OFDM_index[i]) / 2; /* Calculate Remnant tx_agc value, 2 index for 1 tx_agc */ + add_tx_power88xx_ac(priv, priv->pshare->add_tx_agc_index); + priv->pshare->add_tx_agc = 1; /* add_tx_agc Flag = 1 */ + OFDM_index[i] = OFDM_min_index; + } else { + if (priv->pshare->add_tx_agc) { /* tx_agc been added */ + priv->pshare->add_tx_agc = 0; + priv->pshare->add_tx_agc_index = 0; + add_tx_power88xx_ac(priv, 0); /* minus the added TPI */ + } + } + } + } +#else + OFDM_index[rf_path] = ((OFDM_index[rf_path] < OFDM_min_index) ? OFDM_min_index : OFDM_index[rf_path]); +#endif + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, (">>> increse power ---> new OFDM_INDEX:%d (%d - %d)\n", OFDM_index[rf_path], priv->pshare->OFDM_index0[rf_path], get_tx_tracking_index(priv, channel, rf_path, delta, is_decrease, 0))); + } + } + } +#endif + /* 4 Set new BB swing index */ + for (rf_path = 0; rf_path < max_rf_path; rf_path++) { + phy_set_bb_reg(priv, bb_swing_reg[rf_path], 0xffe00000, ofdm_swing_table_8812[(unsigned int)OFDM_index[rf_path]]); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("Readback 0x%x[31:21] = 0x%x, OFDM_index:%d\n", bb_swing_reg[rf_path], phy_query_bb_reg(priv, bb_swing_reg[rf_path], 0xffe00000), OFDM_index[rf_path])); + } + + } + if (delta_LCK > 8) { + RTL_W8(0x522, 0xff); + reg0x18 = phy_query_rf_reg(priv, RF_PATH_A, 0x18, MASK20BITS, 1); + phy_set_rf_reg(priv, RF_PATH_A, 0xB4, BIT(14), 1); + phy_set_rf_reg(priv, RF_PATH_A, 0x18, BIT(15), 1); + delay_ms(200); /* frequency deviation */ + phy_set_rf_reg(priv, RF_PATH_A, 0xB4, BIT(14), 0); + phy_set_rf_reg(priv, RF_PATH_A, 0x18, MASK20BITS, reg0x18); +#ifdef CONFIG_RTL_8812_SUPPORT + if (GET_CHIP_VER(priv) == VERSION_8812E) + update_bbrf_val8812(priv, priv->pmib->dot11RFEntry.dot11channel); +#endif + RTL_W8(0x522, 0x0); + priv->pshare->thermal_value_lck = thermal_value; + } + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("\n******** END:%s() ********\n", __FUNCTION__)); + + /* update thermal meter value */ + priv->pshare->thermal_value = thermal_value; + for (rf_path = 0; rf_path < max_rf_path; rf_path++) + priv->pshare->OFDM_index[rf_path] = OFDM_index[rf_path]; + } +} + +#endif + + +void +odm_txpowertracking_callback_thermal_meter( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + void *p_dm_void +#else + struct _ADAPTER *adapter +#endif +) +{ + struct PHY_DM_STRUCT *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void; + struct odm_rf_calibration_structure *p_rf_calibrate_info = &(p_dm_odm->rf_calibrate_info); + + +#if (RTL8197F_SUPPORT == 1 || RTL8822B_SUPPORT == 1) + if (p_dm_odm->support_ic_type == ODM_RTL8197F || p_dm_odm->support_ic_type == ODM_RTL8822B) { + odm_txpowertracking_callback_thermal_meter_jaguar_series3(p_dm_odm); + return; + } +#endif +#if (RTL8814A_SUPPORT == 1) /*use this function to do power tracking after 8814 by YuChen*/ + if (p_dm_odm->support_ic_type & ODM_RTL8814A) { + odm_txpowertracking_callback_thermal_meter_jaguar_series2(p_dm_odm); + return; + } +#endif +#if (RTL8881A_SUPPORT || RTL8812A_SUPPORT == 1) + if (p_dm_odm->support_ic_type & ODM_RTL8812 || p_dm_odm->support_ic_type & ODM_RTL8881A) { + odm_txpowertracking_callback_thermal_meter_jaguar_series(p_dm_odm); + return; + } +#endif + +#if (RTL8192E_SUPPORT == 1) + if (p_dm_odm->support_ic_type == ODM_RTL8192E) { + odm_txpowertracking_callback_thermal_meter_92e(p_dm_odm); + return; + } +#endif + +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(adapter); + /* PMGNT_INFO p_mgnt_info = &adapter->mgnt_info; */ +#endif + + + u8 thermal_value = 0, delta, delta_LCK, delta_IQK, offset; + u8 thermal_value_avg_count = 0; + u32 thermal_value_avg = 0; + /* s32 ele_A=0, ele_D, TempCCk, X, value32; + * s32 Y, ele_C=0; + * s8 OFDM_index[2], CCK_index=0, OFDM_index_old[2]={0,0}, CCK_index_old=0, index; + * s8 deltaPowerIndex = 0; */ + u32 i = 0;/* , j = 0; */ + bool is2T = false; + /* bool bInteralPA = false; */ + + u8 OFDM_max_index = 34, rf = (is2T) ? 2 : 1; /* OFDM BB Swing should be less than +3.0dB, which is required by Arthur */ + u8 indexforchannel = 0;/*get_right_chnl_place_for_iqk(p_hal_data->current_channel)*/ + enum _POWER_DEC_INC { POWER_DEC, POWER_INC }; +#if (DM_ODM_SUPPORT_TYPE == ODM_CE) + struct PHY_DM_STRUCT *p_dm_odm = &p_hal_data->odmpriv; +#endif +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + struct PHY_DM_STRUCT *p_dm_odm = &p_hal_data->DM_OutSrc; +#endif + + struct _TXPWRTRACK_CFG c; + + + /* 4 1. The following TWO tables decide the final index of OFDM/CCK swing table. */ + s8 delta_swing_table_idx[2][index_mapping_NUM_88E] = { + /* {{Power decreasing(lower temperature)}, {Power increasing(higher temperature)}} */ + {0, 0, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11}, {0, 0, 1, 2, 3, 4, 4, 4, 4, 5, 7, 8, 9, 9, 10} + }; + u8 thermal_threshold[2][index_mapping_NUM_88E] = { + /* {{Power decreasing(lower temperature)}, {Power increasing(higher temperature)}} */ + {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 27}, {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 25, 25, 25} + }; + +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + struct rtl8192cd_priv *priv = p_dm_odm->priv; +#endif + + /* 4 2. Initilization ( 7 steps in total ) */ + + configure_txpower_track(p_dm_odm, &c); + + p_dm_odm->rf_calibrate_info.txpowertracking_callback_cnt++; /* cosa add for debug */ + p_dm_odm->rf_calibrate_info.is_txpowertracking_init = true; + +#if (MP_DRIVER == 1) + p_dm_odm->rf_calibrate_info.txpowertrack_control = p_hal_data->txpowertrack_control; /* <Kordan> We should keep updating the control variable according to HalData. + * <Kordan> rf_calibrate_info.rega24 will be initialized when ODM HW configuring, but MP configures with para files. */ + p_dm_odm->rf_calibrate_info.rega24 = 0x090e1317; +#endif + +#if (DM_ODM_SUPPORT_TYPE == ODM_AP) && defined(MP_TEST) + if ((OPMODE & WIFI_MP_STATE) || p_dm_odm->priv->pshare->rf_ft_var.mp_specific) { + if (p_dm_odm->priv->pshare->mp_txpwr_tracking == false) + return; + } +#endif + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("===>odm_txpowertracking_callback_thermal_meter_8188e, p_dm_odm->bb_swing_idx_cck_base: %d, p_dm_odm->bb_swing_idx_ofdm_base: %d\n", p_rf_calibrate_info->bb_swing_idx_cck_base, p_rf_calibrate_info->bb_swing_idx_ofdm_base)); + /* + if (!p_dm_odm->rf_calibrate_info.tm_trigger) { + odm_set_rf_reg(p_dm_odm, RF_PATH_A, c.thermal_reg_addr, BIT(17) | BIT(16), 0x3); + p_dm_odm->rf_calibrate_info.tm_trigger = 1; + return; + } + */ + thermal_value = (u8)odm_get_rf_reg(p_dm_odm, RF_PATH_A, c.thermal_reg_addr, 0xfc00); /* 0x42: RF Reg[15:10] 88E */ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + if (!thermal_value || !p_dm_odm->rf_calibrate_info.txpowertrack_control) +#else + if (!p_dm_odm->rf_calibrate_info.txpowertrack_control) +#endif + return; + + /* 4 3. Initialize ThermalValues of rf_calibrate_info */ + + if (!p_dm_odm->rf_calibrate_info.thermal_value) { + p_dm_odm->rf_calibrate_info.thermal_value_lck = thermal_value; + p_dm_odm->rf_calibrate_info.thermal_value_iqk = thermal_value; + } + + if (p_dm_odm->rf_calibrate_info.is_reloadtxpowerindex) + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("reload ofdm index for band switch\n")); + + /* 4 4. Calculate average thermal meter */ + + p_dm_odm->rf_calibrate_info.thermal_value_avg[p_dm_odm->rf_calibrate_info.thermal_value_avg_index] = thermal_value; + p_dm_odm->rf_calibrate_info.thermal_value_avg_index++; + if (p_dm_odm->rf_calibrate_info.thermal_value_avg_index == c.average_thermal_num) + p_dm_odm->rf_calibrate_info.thermal_value_avg_index = 0; + + for (i = 0; i < c.average_thermal_num; i++) { + if (p_dm_odm->rf_calibrate_info.thermal_value_avg[i]) { + thermal_value_avg += p_dm_odm->rf_calibrate_info.thermal_value_avg[i]; + thermal_value_avg_count++; + } + } + + if (thermal_value_avg_count) { + /* Give the new thermo value a weighting */ + thermal_value_avg += (thermal_value * 4); + + thermal_value = (u8)(thermal_value_avg / (thermal_value_avg_count + 4)); + p_rf_calibrate_info->thermal_value_delta = thermal_value - priv->pmib->dot11RFEntry.ther; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("AVG Thermal Meter = 0x%x\n", thermal_value)); + } + + /* 4 5. Calculate delta, delta_LCK, delta_IQK. */ + + delta = (thermal_value > p_dm_odm->rf_calibrate_info.thermal_value) ? (thermal_value - p_dm_odm->rf_calibrate_info.thermal_value) : (p_dm_odm->rf_calibrate_info.thermal_value - thermal_value); + delta_LCK = (thermal_value > p_dm_odm->rf_calibrate_info.thermal_value_lck) ? (thermal_value - p_dm_odm->rf_calibrate_info.thermal_value_lck) : (p_dm_odm->rf_calibrate_info.thermal_value_lck - thermal_value); + delta_IQK = (thermal_value > p_dm_odm->rf_calibrate_info.thermal_value_iqk) ? (thermal_value - p_dm_odm->rf_calibrate_info.thermal_value_iqk) : (p_dm_odm->rf_calibrate_info.thermal_value_iqk - thermal_value); + + /* 4 6. If necessary, do LCK. */ + if (!(p_dm_odm->support_ic_type & ODM_RTL8821)) { + /*if((delta_LCK > p_hal_data->delta_lck) && (p_hal_data->delta_lck != 0))*/ + if (delta_LCK >= c.threshold_iqk) { + /*Delta temperature is equal to or larger than 20 centigrade.*/ + p_dm_odm->rf_calibrate_info.thermal_value_lck = thermal_value; + (*c.phy_lc_calibrate)(p_dm_odm); + } + } + + /* 3 7. If necessary, move the index of swing table to adjust Tx power. */ + + if (delta > 0 && p_dm_odm->rf_calibrate_info.txpowertrack_control) { +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) + delta = thermal_value > p_hal_data->eeprom_thermal_meter ? (thermal_value - p_hal_data->eeprom_thermal_meter) : (p_hal_data->eeprom_thermal_meter - thermal_value); +#else + delta = (thermal_value > p_dm_odm->priv->pmib->dot11RFEntry.ther) ? (thermal_value - p_dm_odm->priv->pmib->dot11RFEntry.ther) : (p_dm_odm->priv->pmib->dot11RFEntry.ther - thermal_value); +#endif + + + /* 4 7.1 The Final Power index = BaseIndex + power_index_offset */ + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) + if (thermal_value > p_hal_data->eeprom_thermal_meter) { +#else + if (thermal_value > p_dm_odm->priv->pmib->dot11RFEntry.ther) { +#endif + CALCULATE_SWINGTALBE_OFFSET(offset, POWER_INC, index_mapping_NUM_88E, delta); + p_dm_odm->rf_calibrate_info.delta_power_index_last = p_dm_odm->rf_calibrate_info.delta_power_index; + p_dm_odm->rf_calibrate_info.delta_power_index = delta_swing_table_idx[POWER_INC][offset]; + + } else { + + CALCULATE_SWINGTALBE_OFFSET(offset, POWER_DEC, index_mapping_NUM_88E, delta); + p_dm_odm->rf_calibrate_info.delta_power_index_last = p_dm_odm->rf_calibrate_info.delta_power_index; + p_dm_odm->rf_calibrate_info.delta_power_index = (-1) * delta_swing_table_idx[POWER_DEC][offset]; + } + + if (p_dm_odm->rf_calibrate_info.delta_power_index == p_dm_odm->rf_calibrate_info.delta_power_index_last) + p_dm_odm->rf_calibrate_info.power_index_offset = 0; + else + p_dm_odm->rf_calibrate_info.power_index_offset = p_dm_odm->rf_calibrate_info.delta_power_index - p_dm_odm->rf_calibrate_info.delta_power_index_last; + + for (i = 0; i < rf; i++) + p_dm_odm->rf_calibrate_info.OFDM_index[i] = p_rf_calibrate_info->bb_swing_idx_ofdm_base + p_dm_odm->rf_calibrate_info.power_index_offset; + p_dm_odm->rf_calibrate_info.CCK_index = p_rf_calibrate_info->bb_swing_idx_cck_base + p_dm_odm->rf_calibrate_info.power_index_offset; + + p_rf_calibrate_info->bb_swing_idx_cck = p_dm_odm->rf_calibrate_info.CCK_index; + p_rf_calibrate_info->bb_swing_idx_ofdm[RF_PATH_A] = p_dm_odm->rf_calibrate_info.OFDM_index[RF_PATH_A]; + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("The 'CCK' final index(%d) = BaseIndex(%d) + power_index_offset(%d)\n", p_rf_calibrate_info->bb_swing_idx_cck, p_rf_calibrate_info->bb_swing_idx_cck_base, p_dm_odm->rf_calibrate_info.power_index_offset)); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("The 'OFDM' final index(%d) = BaseIndex(%d) + power_index_offset(%d)\n", p_rf_calibrate_info->bb_swing_idx_ofdm[RF_PATH_A], p_rf_calibrate_info->bb_swing_idx_ofdm_base, p_dm_odm->rf_calibrate_info.power_index_offset)); + + /* 4 7.1 Handle boundary conditions of index. */ + + + for (i = 0; i < rf; i++) { + if (p_dm_odm->rf_calibrate_info.OFDM_index[i] > OFDM_max_index) + p_dm_odm->rf_calibrate_info.OFDM_index[i] = OFDM_max_index; + else if (p_dm_odm->rf_calibrate_info.OFDM_index[i] < 0) + p_dm_odm->rf_calibrate_info.OFDM_index[i] = 0; + } + + if (p_dm_odm->rf_calibrate_info.CCK_index > c.swing_table_size_cck - 1) + p_dm_odm->rf_calibrate_info.CCK_index = c.swing_table_size_cck - 1; + else if (p_dm_odm->rf_calibrate_info.CCK_index < 0) + p_dm_odm->rf_calibrate_info.CCK_index = 0; + } else { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("The thermal meter is unchanged or TxPowerTracking OFF: thermal_value: %d, p_dm_odm->rf_calibrate_info.thermal_value: %d)\n", thermal_value, p_dm_odm->rf_calibrate_info.thermal_value)); + p_dm_odm->rf_calibrate_info.power_index_offset = 0; + } + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("TxPowerTracking: [CCK] Swing Current index: %d, Swing base index: %d\n", p_dm_odm->rf_calibrate_info.CCK_index, p_rf_calibrate_info->bb_swing_idx_cck_base)); + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("TxPowerTracking: [OFDM] Swing Current index: %d, Swing base index: %d\n", p_dm_odm->rf_calibrate_info.OFDM_index[RF_PATH_A], p_rf_calibrate_info->bb_swing_idx_ofdm_base)); + + if (p_dm_odm->rf_calibrate_info.power_index_offset != 0 && p_dm_odm->rf_calibrate_info.txpowertrack_control) { + /* 4 7.2 Configure the Swing Table to adjust Tx Power. */ + + p_dm_odm->rf_calibrate_info.is_tx_power_changed = true; /* Always true after Tx Power is adjusted by power tracking. */ + /* */ + /* 2012/04/23 MH According to Luke's suggestion, we can not write BB digital */ + /* to increase TX power. Otherwise, EVM will be bad. */ + /* */ + /* 2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. */ + if (thermal_value > p_dm_odm->rf_calibrate_info.thermal_value) { + /* ODM_RT_TRACE(p_dm_odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, */ + /* ("Temperature Increasing: delta_pi: %d, delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", */ + /* p_dm_odm->rf_calibrate_info.power_index_offset, delta, thermal_value, p_hal_data->eeprom_thermal_meter, p_dm_odm->rf_calibrate_info.thermal_value)); */ + } else if (thermal_value < p_dm_odm->rf_calibrate_info.thermal_value) { /* Low temperature */ + /* ODM_RT_TRACE(p_dm_odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, */ + /* ("Temperature Decreasing: delta_pi: %d, delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", */ + /* p_dm_odm->rf_calibrate_info.power_index_offset, delta, thermal_value, p_hal_data->eeprom_thermal_meter, p_dm_odm->rf_calibrate_info.thermal_value)); */ + } +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + if (thermal_value > p_hal_data->eeprom_thermal_meter) +#else + if (thermal_value > p_dm_odm->priv->pmib->dot11RFEntry.ther) +#endif + { + /* ODM_RT_TRACE(p_dm_odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("Temperature(%d) hugher than PG value(%d), increases the power by tx_agc\n", thermal_value, p_hal_data->eeprom_thermal_meter)); */ + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, TXAGC, 0, 0); + } else { + /* ODM_RT_TRACE(p_dm_odm,ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD,("Temperature(%d) lower than PG value(%d), increases the power by tx_agc\n", thermal_value, p_hal_data->eeprom_thermal_meter)); */ + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, BBSWING, RF_PATH_A, indexforchannel); + if (is2T) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, BBSWING, RF_PATH_B, indexforchannel); + } + + p_rf_calibrate_info->bb_swing_idx_cck_base = p_rf_calibrate_info->bb_swing_idx_cck; + p_rf_calibrate_info->bb_swing_idx_ofdm_base = p_rf_calibrate_info->bb_swing_idx_ofdm[RF_PATH_A]; + p_dm_odm->rf_calibrate_info.thermal_value = thermal_value; + + } + +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + /* if((delta_IQK > p_hal_data->delta_iqk) && (p_hal_data->delta_iqk != 0)) */ + if ((delta_IQK >= 8)) /* Delta temperature is equal to or larger than 20 centigrade. */ + (*c.do_iqk)(p_dm_odm, delta_IQK, thermal_value, 8); +#endif + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("<===dm_TXPowerTrackingCallback_ThermalMeter_8188E\n")); + + p_dm_odm->rf_calibrate_info.tx_powercount = 0; +} + +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) + + +void +phy_path_a_stand_by( + struct _ADAPTER *p_adapter +) +{ + RTPRINT(FINIT, INIT_IQK, ("path-A standby mode!\n")); + + phy_set_bb_reg(p_adapter, REG_FPGA0_IQK, 0xffffff00, 0x0); + phy_set_bb_reg(p_adapter, 0x840, MASKDWORD, 0x00010000); + phy_set_bb_reg(p_adapter, REG_FPGA0_IQK, 0xffffff00, 0x808000); +} + +/* 1 7. IQK + * #define MAX_TOLERANCE 5 + * #define IQK_DELAY_TIME 1 */ /* ms */ + +u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ +phy_path_a_iqk_8192c( + struct _ADAPTER *p_adapter, + bool config_path_b +) +{ + + u32 reg_eac, reg_e94, reg_e9c, reg_ea4; + u8 result = 0x00; + HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(p_adapter); + + RTPRINT(FINIT, INIT_IQK, ("path A IQK!\n")); + + /* path-A IQK setting */ + RTPRINT(FINIT, INIT_IQK, ("path-A IQK setting!\n")); + if (p_adapter->interface_index == 0) { + phy_set_bb_reg(p_adapter, REG_TX_IQK_TONE_A, MASKDWORD, 0x10008c1f); + phy_set_bb_reg(p_adapter, REG_RX_IQK_TONE_A, MASKDWORD, 0x10008c1f); + } else { + phy_set_bb_reg(p_adapter, REG_TX_IQK_TONE_A, MASKDWORD, 0x10008c22); + phy_set_bb_reg(p_adapter, REG_RX_IQK_TONE_A, MASKDWORD, 0x10008c22); + } + + phy_set_bb_reg(p_adapter, REG_TX_IQK_PI_A, MASKDWORD, 0x82140102); + + phy_set_bb_reg(p_adapter, REG_RX_IQK_PI_A, MASKDWORD, config_path_b ? 0x28160202 : + IS_81xxC_VENDOR_UMC_B_CUT(p_hal_data->version_id) ? 0x28160202 : 0x28160502); + + /* path-B IQK setting */ + if (config_path_b) { + phy_set_bb_reg(p_adapter, REG_TX_IQK_TONE_B, MASKDWORD, 0x10008c22); + phy_set_bb_reg(p_adapter, REG_RX_IQK_TONE_B, MASKDWORD, 0x10008c22); + phy_set_bb_reg(p_adapter, REG_TX_IQK_PI_B, MASKDWORD, 0x82140102); + phy_set_bb_reg(p_adapter, REG_RX_IQK_PI_B, MASKDWORD, 0x28160202); + } + + /* LO calibration setting */ + RTPRINT(FINIT, INIT_IQK, ("LO calibration setting!\n")); + phy_set_bb_reg(p_adapter, REG_IQK_AGC_RSP, MASKDWORD, 0x001028d1); + + /* One shot, path A LOK & IQK */ + RTPRINT(FINIT, INIT_IQK, ("One shot, path A LOK & IQK!\n")); + phy_set_bb_reg(p_adapter, REG_IQK_AGC_PTS, MASKDWORD, 0xf9000000); + phy_set_bb_reg(p_adapter, REG_IQK_AGC_PTS, MASKDWORD, 0xf8000000); + + /* delay x ms */ + RTPRINT(FINIT, INIT_IQK, ("delay %d ms for One shot, path A LOK & IQK.\n", IQK_DELAY_TIME)); + platform_stall_execution(IQK_DELAY_TIME * 1000); + + /* Check failed */ + reg_eac = phy_query_bb_reg(p_adapter, REG_RX_POWER_AFTER_IQK_A_2, MASKDWORD); + RTPRINT(FINIT, INIT_IQK, ("0xeac = 0x%x\n", reg_eac)); + reg_e94 = phy_query_bb_reg(p_adapter, REG_TX_POWER_BEFORE_IQK_A, MASKDWORD); + RTPRINT(FINIT, INIT_IQK, ("0xe94 = 0x%x\n", reg_e94)); + reg_e9c = phy_query_bb_reg(p_adapter, REG_TX_POWER_AFTER_IQK_A, MASKDWORD); + RTPRINT(FINIT, INIT_IQK, ("0xe9c = 0x%x\n", reg_e9c)); + reg_ea4 = phy_query_bb_reg(p_adapter, REG_RX_POWER_BEFORE_IQK_A_2, MASKDWORD); + RTPRINT(FINIT, INIT_IQK, ("0xea4 = 0x%x\n", reg_ea4)); + + if (!(reg_eac & BIT(28)) && + (((reg_e94 & 0x03FF0000) >> 16) != 0x142) && + (((reg_e9c & 0x03FF0000) >> 16) != 0x42)) + result |= 0x01; + else /* if Tx not OK, ignore Rx */ + return result; + + if (!(reg_eac & BIT(27)) && /* if Tx is OK, check whether Rx is OK */ + (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) && + (((reg_eac & 0x03FF0000) >> 16) != 0x36)) + result |= 0x02; + else + RTPRINT(FINIT, INIT_IQK, ("path A Rx IQK fail!!\n")); + + return result; + + +} + +u8 /* bit0 = 1 => Tx OK, bit1 = 1 => Rx OK */ +phy_path_b_iqk_8192c( + struct _ADAPTER *p_adapter +) +{ + u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc; + u8 result = 0x00; + RTPRINT(FINIT, INIT_IQK, ("path B IQK!\n")); + + /* One shot, path B LOK & IQK */ + RTPRINT(FINIT, INIT_IQK, ("One shot, path A LOK & IQK!\n")); + phy_set_bb_reg(p_adapter, REG_IQK_AGC_CONT, MASKDWORD, 0x00000002); + phy_set_bb_reg(p_adapter, REG_IQK_AGC_CONT, MASKDWORD, 0x00000000); + + /* delay x ms */ + RTPRINT(FINIT, INIT_IQK, ("delay %d ms for One shot, path B LOK & IQK.\n", IQK_DELAY_TIME)); + platform_stall_execution(IQK_DELAY_TIME * 1000); + + /* Check failed */ + reg_eac = phy_query_bb_reg(p_adapter, REG_RX_POWER_AFTER_IQK_A_2, MASKDWORD); + RTPRINT(FINIT, INIT_IQK, ("0xeac = 0x%x\n", reg_eac)); + reg_eb4 = phy_query_bb_reg(p_adapter, REG_TX_POWER_BEFORE_IQK_B, MASKDWORD); + RTPRINT(FINIT, INIT_IQK, ("0xeb4 = 0x%x\n", reg_eb4)); + reg_ebc = phy_query_bb_reg(p_adapter, REG_TX_POWER_AFTER_IQK_B, MASKDWORD); + RTPRINT(FINIT, INIT_IQK, ("0xebc = 0x%x\n", reg_ebc)); + reg_ec4 = phy_query_bb_reg(p_adapter, REG_RX_POWER_BEFORE_IQK_B_2, MASKDWORD); + RTPRINT(FINIT, INIT_IQK, ("0xec4 = 0x%x\n", reg_ec4)); + reg_ecc = phy_query_bb_reg(p_adapter, REG_RX_POWER_AFTER_IQK_B_2, MASKDWORD); + RTPRINT(FINIT, INIT_IQK, ("0xecc = 0x%x\n", reg_ecc)); + + if (!(reg_eac & BIT(31)) && + (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) && + (((reg_ebc & 0x03FF0000) >> 16) != 0x42)) + result |= 0x01; + else + return result; + + if (!(reg_eac & BIT(30)) && + (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) && + (((reg_ecc & 0x03FF0000) >> 16) != 0x36)) + result |= 0x02; + else + RTPRINT(FINIT, INIT_IQK, ("path B Rx IQK fail!!\n")); + + + return result; + +} + +void +phy_path_a_fill_iqk_matrix( + struct _ADAPTER *p_adapter, + bool is_iqk_ok, + s32 result[][8], + u8 final_candidate, + bool is_tx_only +) +{ + u32 oldval_0, X, TX0_A, reg; + s32 Y, TX0_C; + HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(p_adapter); + + RTPRINT(FINIT, INIT_IQK, ("path A IQ Calibration %s !\n", (is_iqk_ok) ? "Success" : "Failed")); + + if (final_candidate == 0xFF) + return; + + else if (is_iqk_ok) { + oldval_0 = (phy_query_bb_reg(p_adapter, REG_OFDM_0_XA_TX_IQ_IMBALANCE, MASKDWORD) >> 22) & 0x3FF; + + X = result[final_candidate][0]; + if ((X & 0x00000200) != 0) + X = X | 0xFFFFFC00; + TX0_A = (X * oldval_0) >> 8; + RTPRINT(FINIT, INIT_IQK, ("X = 0x%x, TX0_A = 0x%x, oldval_0 0x%x\n", X, TX0_A, oldval_0)); + phy_set_bb_reg(p_adapter, REG_OFDM_0_XA_TX_IQ_IMBALANCE, 0x3FF, TX0_A); + phy_set_bb_reg(p_adapter, REG_OFDM_0_ECCA_THRESHOLD, BIT(31), ((X * oldval_0 >> 7) & 0x1)); + + Y = result[final_candidate][1]; + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + + /* path B IQK result + 3 */ + if (p_adapter->interface_index == 1 && p_hal_data->current_band_type == BAND_ON_5G) + Y += 3; + + TX0_C = (Y * oldval_0) >> 8; + RTPRINT(FINIT, INIT_IQK, ("Y = 0x%x, TX = 0x%x\n", Y, TX0_C)); + phy_set_bb_reg(p_adapter, REG_OFDM_0_XC_TX_AFE, 0xF0000000, ((TX0_C & 0x3C0) >> 6)); + phy_set_bb_reg(p_adapter, REG_OFDM_0_XA_TX_IQ_IMBALANCE, 0x003F0000, (TX0_C & 0x3F)); + phy_set_bb_reg(p_adapter, REG_OFDM_0_ECCA_THRESHOLD, BIT(29), ((Y * oldval_0 >> 7) & 0x1)); + + if (is_tx_only) { + RTPRINT(FINIT, INIT_IQK, ("phy_path_a_fill_iqk_matrix only Tx OK\n")); + return; + } + + reg = result[final_candidate][2]; + phy_set_bb_reg(p_adapter, REG_OFDM_0_XA_RX_IQ_IMBALANCE, 0x3FF, reg); + + reg = result[final_candidate][3] & 0x3F; + phy_set_bb_reg(p_adapter, REG_OFDM_0_XA_RX_IQ_IMBALANCE, 0xFC00, reg); + + reg = (result[final_candidate][3] >> 6) & 0xF; + phy_set_bb_reg(p_adapter, REG_OFDM_0_RX_IQ_EXT_ANTA, 0xF0000000, reg); + } +} + +void +phy_path_b_fill_iqk_matrix( + struct _ADAPTER *p_adapter, + bool is_iqk_ok, + s32 result[][8], + u8 final_candidate, + bool is_tx_only /* do Tx only */ +) +{ + u32 oldval_1, X, TX1_A, reg; + s32 Y, TX1_C; + HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(p_adapter); + + RTPRINT(FINIT, INIT_IQK, ("path B IQ Calibration %s !\n", (is_iqk_ok) ? "Success" : "Failed")); + + if (final_candidate == 0xFF) + return; + + else if (is_iqk_ok) { + oldval_1 = (phy_query_bb_reg(p_adapter, REG_OFDM_0_XB_TX_IQ_IMBALANCE, MASKDWORD) >> 22) & 0x3FF; + + X = result[final_candidate][4]; + if ((X & 0x00000200) != 0) + X = X | 0xFFFFFC00; + TX1_A = (X * oldval_1) >> 8; + RTPRINT(FINIT, INIT_IQK, ("X = 0x%x, TX1_A = 0x%x\n", X, TX1_A)); + phy_set_bb_reg(p_adapter, REG_OFDM_0_XB_TX_IQ_IMBALANCE, 0x3FF, TX1_A); + phy_set_bb_reg(p_adapter, REG_OFDM_0_ECCA_THRESHOLD, BIT(27), ((X * oldval_1 >> 7) & 0x1)); + + Y = result[final_candidate][5]; + if ((Y & 0x00000200) != 0) + Y = Y | 0xFFFFFC00; + if (p_hal_data->current_band_type == BAND_ON_5G) + Y += 3; /* temp modify for preformance */ + TX1_C = (Y * oldval_1) >> 8; + RTPRINT(FINIT, INIT_IQK, ("Y = 0x%x, TX1_C = 0x%x\n", Y, TX1_C)); + phy_set_bb_reg(p_adapter, REG_OFDM_0_XD_TX_AFE, 0xF0000000, ((TX1_C & 0x3C0) >> 6)); + phy_set_bb_reg(p_adapter, REG_OFDM_0_XB_TX_IQ_IMBALANCE, 0x003F0000, (TX1_C & 0x3F)); + phy_set_bb_reg(p_adapter, REG_OFDM_0_ECCA_THRESHOLD, BIT(25), ((Y * oldval_1 >> 7) & 0x1)); + + if (is_tx_only) + return; + + reg = result[final_candidate][6]; + phy_set_bb_reg(p_adapter, REG_OFDM_0_XB_RX_IQ_IMBALANCE, 0x3FF, reg); + + reg = result[final_candidate][7] & 0x3F; + phy_set_bb_reg(p_adapter, REG_OFDM_0_XB_RX_IQ_IMBALANCE, 0xFC00, reg); + + reg = (result[final_candidate][7] >> 6) & 0xF; + phy_set_bb_reg(p_adapter, REG_OFDM_0_AGC_RSSI_TABLE, 0x0000F000, reg); + } +} + + +bool +phy_simularity_compare_92c( + struct _ADAPTER *p_adapter, + s32 result[][8], + u8 c1, + u8 c2 +) +{ + u32 i, j, diff, simularity_bit_map, bound = 0; + HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(p_adapter); + u8 final_candidate[2] = {0xFF, 0xFF}; /* for path A and path B */ + bool is_result = true, is2T = IS_92C_SERIAL(p_hal_data->version_id); + + if (is2T) + bound = 8; + else + bound = 4; + + simularity_bit_map = 0; + + for (i = 0; i < bound; i++) { + diff = (result[c1][i] > result[c2][i]) ? (result[c1][i] - result[c2][i]) : (result[c2][i] - result[c1][i]); + if (diff > MAX_TOLERANCE) { + if ((i == 2 || i == 6) && !simularity_bit_map) { + if (result[c1][i] + result[c1][i + 1] == 0) + final_candidate[(i / 4)] = c2; + else if (result[c2][i] + result[c2][i + 1] == 0) + final_candidate[(i / 4)] = c1; + else + simularity_bit_map = simularity_bit_map | (1 << i); + } else + simularity_bit_map = simularity_bit_map | (1 << i); + } + } + + if (simularity_bit_map == 0) { + for (i = 0; i < (bound / 4); i++) { + if (final_candidate[i] != 0xFF) { + for (j = i * 4; j < (i + 1) * 4 - 2; j++) + result[3][j] = result[final_candidate[i]][j]; + is_result = false; + } + } + return is_result; + } else if (!(simularity_bit_map & 0x0F)) { /* path A OK */ + for (i = 0; i < 4; i++) + result[3][i] = result[c1][i]; + return false; + } else if (!(simularity_bit_map & 0xF0) && is2T) { /* path B OK */ + for (i = 4; i < 8; i++) + result[3][i] = result[c1][i]; + return false; + } else + return false; + +} + +/* +return false => do IQK again +*/ +bool +phy_simularity_compare( + struct _ADAPTER *p_adapter, + s32 result[][8], + u8 c1, + u8 c2 +) +{ + return phy_simularity_compare_92c(p_adapter, result, c1, c2); + +} + +void +_phy_iq_calibrate_8192c( + struct _ADAPTER *p_adapter, + s32 result[][8], + u8 t, + bool is2T +) +{ + HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(p_adapter); + u32 i; + u8 path_aok, path_bok; + u32 ADDA_REG[IQK_ADDA_REG_NUM] = { + REG_FPGA0_XCD_SWITCH_CONTROL, REG_BLUE_TOOTH, + REG_RX_WAIT_CCA, REG_TX_CCK_RFON, + REG_TX_CCK_BBON, REG_TX_OFDM_RFON, + REG_TX_OFDM_BBON, REG_TX_TO_RX, + REG_TX_TO_TX, REG_RX_CCK, + REG_RX_OFDM, REG_RX_WAIT_RIFS, + REG_RX_TO_RX, REG_STANDBY, + REG_SLEEP, REG_PMPD_ANAEN + }; + u32 IQK_MAC_REG[IQK_MAC_REG_NUM] = { + REG_TXPAUSE, REG_BCN_CTRL, + REG_BCN_CTRL_1, REG_GPIO_MUXCFG + }; + + /* since 92C & 92D have the different define in IQK_BB_REG */ + u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = { + REG_OFDM_0_TRX_PATH_ENABLE, REG_OFDM_0_TR_MUX_PAR, + REG_FPGA0_XCD_RF_INTERFACE_SW, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B, + REG_FPGA0_XAB_RF_INTERFACE_SW, REG_FPGA0_XA_RF_INTERFACE_OE, + REG_FPGA0_XB_RF_INTERFACE_OE, /*REG_FPGA0_RFMOD*/ REG_CCK_0_AFE_SETTING + }; + + u32 IQK_BB_REG_92D[IQK_BB_REG_NUM_92D] = { /* for normal */ + REG_FPGA0_XAB_RF_INTERFACE_SW, REG_FPGA0_XA_RF_INTERFACE_OE, + REG_FPGA0_XB_RF_INTERFACE_OE, REG_OFDM_0_TR_MUX_PAR, + REG_FPGA0_XCD_RF_INTERFACE_SW, REG_OFDM_0_TRX_PATH_ENABLE, + /*REG_FPGA0_RFMOD*/ REG_CCK_0_AFE_SETTING, REG_FPGA0_ANALOG_PARAMETER4, + REG_OFDM_0_XA_AGC_CORE1, REG_OFDM_0_XB_AGC_CORE1 + }; +#if MP_DRIVER + const u32 retry_count = 9; +#else + const u32 retry_count = 2; +#endif + /* Neil Chen--2011--05--19-- + * 3 path Div */ + u8 rf_path_switch = 0x0; + + /* Note: IQ calibration must be performed after loading */ + /* PHY_REG.txt , and radio_a, radio_b.txt */ + + u32 bbvalue; + + if (t == 0) { + /* bbvalue = phy_query_bb_reg(p_adapter, REG_FPGA0_RFMOD, MASKDWORD); */ + /* RTPRINT(FINIT, INIT_IQK, ("_phy_iq_calibrate_8192c()==>0x%08x\n",bbvalue)); */ + + RTPRINT(FINIT, INIT_IQK, ("IQ Calibration for %s\n", (is2T ? "2T2R" : "1T1R"))); + + /* Save ADDA parameters, turn path A ADDA on */ + phy_save_adda_registers(p_adapter, ADDA_REG, p_hal_data->ADDA_backup, IQK_ADDA_REG_NUM); + phy_save_mac_registers(p_adapter, IQK_MAC_REG, p_hal_data->IQK_MAC_backup); + phy_save_adda_registers(p_adapter, IQK_BB_REG_92C, p_hal_data->IQK_BB_backup, IQK_BB_REG_NUM); + } + + phy_path_adda_on(p_adapter, ADDA_REG, true, is2T); + + if (t == 0) + p_hal_data->is_rf_pi_enable = (u8)phy_query_bb_reg(p_adapter, REG_FPGA0_XA_HSSI_PARAMETER1, BIT(8)); + + if (!p_hal_data->is_rf_pi_enable) { + /* Switch BB to PI mode to do IQ Calibration. */ + phy_pi_mode_switch(p_adapter, true); + } + + /* MAC settings */ + phy_mac_setting_calibration(p_adapter, IQK_MAC_REG, p_hal_data->IQK_MAC_backup); + + /* phy_set_bb_reg(p_adapter, REG_FPGA0_RFMOD, BIT24, 0x00); */ + phy_set_bb_reg(p_adapter, REG_CCK_0_AFE_SETTING, MASKDWORD, (0x0f000000 | (phy_query_bb_reg(p_adapter, REG_CCK_0_AFE_SETTING, MASKDWORD)))); + phy_set_bb_reg(p_adapter, REG_OFDM_0_TRX_PATH_ENABLE, MASKDWORD, 0x03a05600); + phy_set_bb_reg(p_adapter, REG_OFDM_0_TR_MUX_PAR, MASKDWORD, 0x000800e4); + phy_set_bb_reg(p_adapter, REG_FPGA0_XCD_RF_INTERFACE_SW, MASKDWORD, 0x22204000); + { + phy_set_bb_reg(p_adapter, REG_FPGA0_XAB_RF_INTERFACE_SW, BIT(10), 0x01); + phy_set_bb_reg(p_adapter, REG_FPGA0_XAB_RF_INTERFACE_SW, BIT(26), 0x01); + phy_set_bb_reg(p_adapter, REG_FPGA0_XA_RF_INTERFACE_OE, BIT(10), 0x00); + phy_set_bb_reg(p_adapter, REG_FPGA0_XB_RF_INTERFACE_OE, BIT(10), 0x00); + } + + if (is2T) { + phy_set_bb_reg(p_adapter, REG_FPGA0_XA_LSSI_PARAMETER, MASKDWORD, 0x00010000); + phy_set_bb_reg(p_adapter, REG_FPGA0_XB_LSSI_PARAMETER, MASKDWORD, 0x00010000); + } + + { + /* Page B init */ + phy_set_bb_reg(p_adapter, REG_CONFIG_ANT_A, MASKDWORD, 0x00080000); + + if (is2T) + phy_set_bb_reg(p_adapter, REG_CONFIG_ANT_B, MASKDWORD, 0x00080000); + } + /* IQ calibration setting */ + RTPRINT(FINIT, INIT_IQK, ("IQK setting!\n")); + phy_set_bb_reg(p_adapter, REG_FPGA0_IQK, 0xffffff00, 0x808000); + phy_set_bb_reg(p_adapter, REG_TX_IQK, MASKDWORD, 0x01007c00); + phy_set_bb_reg(p_adapter, REG_RX_IQK, MASKDWORD, 0x01004800); + + for (i = 0 ; i < retry_count ; i++) { + path_aok = phy_path_a_iqk_8192c(p_adapter, is2T); + if (path_aok == 0x03) { + RTPRINT(FINIT, INIT_IQK, ("path A IQK Success!!\n")); + result[t][0] = (phy_query_bb_reg(p_adapter, REG_TX_POWER_BEFORE_IQK_A, MASKDWORD) & 0x3FF0000) >> 16; + result[t][1] = (phy_query_bb_reg(p_adapter, REG_TX_POWER_AFTER_IQK_A, MASKDWORD) & 0x3FF0000) >> 16; + result[t][2] = (phy_query_bb_reg(p_adapter, REG_RX_POWER_BEFORE_IQK_A_2, MASKDWORD) & 0x3FF0000) >> 16; + result[t][3] = (phy_query_bb_reg(p_adapter, REG_RX_POWER_AFTER_IQK_A_2, MASKDWORD) & 0x3FF0000) >> 16; + break; + } else if (i == (retry_count - 1) && path_aok == 0x01) { /* Tx IQK OK */ + RTPRINT(FINIT, INIT_IQK, ("path A IQK Only Tx Success!!\n")); + + result[t][0] = (phy_query_bb_reg(p_adapter, REG_TX_POWER_BEFORE_IQK_A, MASKDWORD) & 0x3FF0000) >> 16; + result[t][1] = (phy_query_bb_reg(p_adapter, REG_TX_POWER_AFTER_IQK_A, MASKDWORD) & 0x3FF0000) >> 16; + } + } + + if (0x00 == path_aok) + RTPRINT(FINIT, INIT_IQK, ("path A IQK failed!!\n")); + + if (is2T) { + phy_path_a_stand_by(p_adapter); + + /* Turn path B ADDA on */ + phy_path_adda_on(p_adapter, ADDA_REG, false, is2T); + + for (i = 0 ; i < retry_count ; i++) { + path_bok = phy_path_b_iqk_8192c(p_adapter); + if (path_bok == 0x03) { + RTPRINT(FINIT, INIT_IQK, ("path B IQK Success!!\n")); + result[t][4] = (phy_query_bb_reg(p_adapter, REG_TX_POWER_BEFORE_IQK_B, MASKDWORD) & 0x3FF0000) >> 16; + result[t][5] = (phy_query_bb_reg(p_adapter, REG_TX_POWER_AFTER_IQK_B, MASKDWORD) & 0x3FF0000) >> 16; + result[t][6] = (phy_query_bb_reg(p_adapter, REG_RX_POWER_BEFORE_IQK_B_2, MASKDWORD) & 0x3FF0000) >> 16; + result[t][7] = (phy_query_bb_reg(p_adapter, REG_RX_POWER_AFTER_IQK_B_2, MASKDWORD) & 0x3FF0000) >> 16; + break; + } else if (i == (retry_count - 1) && path_bok == 0x01) { /* Tx IQK OK */ + RTPRINT(FINIT, INIT_IQK, ("path B Only Tx IQK Success!!\n")); + result[t][4] = (phy_query_bb_reg(p_adapter, REG_TX_POWER_BEFORE_IQK_B, MASKDWORD) & 0x3FF0000) >> 16; + result[t][5] = (phy_query_bb_reg(p_adapter, REG_TX_POWER_AFTER_IQK_B, MASKDWORD) & 0x3FF0000) >> 16; + } + } + + if (0x00 == path_bok) + RTPRINT(FINIT, INIT_IQK, ("path B IQK failed!!\n")); + } + + /* Back to BB mode, load original value */ + RTPRINT(FINIT, INIT_IQK, ("IQK:Back to BB mode, load original value!\n")); + phy_set_bb_reg(p_adapter, REG_FPGA0_IQK, 0xffffff00, 0); + + if (t != 0) { + if (!p_hal_data->is_rf_pi_enable) { + /* Switch back BB to SI mode after finish IQ Calibration. */ + phy_pi_mode_switch(p_adapter, false); + } + + /* Reload ADDA power saving parameters */ + phy_reload_adda_registers(p_adapter, ADDA_REG, p_hal_data->ADDA_backup, IQK_ADDA_REG_NUM); + + /* Reload MAC parameters */ + phy_reload_mac_registers(p_adapter, IQK_MAC_REG, p_hal_data->IQK_MAC_backup); + + /* Reload BB parameters */ + phy_reload_adda_registers(p_adapter, IQK_BB_REG_92C, p_hal_data->IQK_BB_backup, IQK_BB_REG_NUM); + + /*Restore RX initial gain*/ + phy_set_bb_reg(p_adapter, REG_FPGA0_XA_LSSI_PARAMETER, MASKDWORD, 0x00032ed3); + if (is2T) + phy_set_bb_reg(p_adapter, REG_FPGA0_XB_LSSI_PARAMETER, MASKDWORD, 0x00032ed3); + /* load 0xe30 IQC default value */ + phy_set_bb_reg(p_adapter, REG_TX_IQK_TONE_A, MASKDWORD, 0x01008c00); + phy_set_bb_reg(p_adapter, REG_RX_IQK_TONE_A, MASKDWORD, 0x01008c00); + + } + RTPRINT(FINIT, INIT_IQK, ("_phy_iq_calibrate_8192c() <==\n")); + +} + + +void +_phy_lccalibrate92c( + struct _ADAPTER *p_adapter, + bool is2T +) +{ + u8 tmp_reg; + u32 rf_amode = 0, rf_bmode = 0, lc_cal; + /* HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(p_adapter); */ + + /* Check continuous TX and Packet TX */ + tmp_reg = platform_efio_read_1byte(p_adapter, 0xd03); + + if ((tmp_reg & 0x70) != 0) /* Deal with contisuous TX case */ + platform_efio_write_1byte(p_adapter, 0xd03, tmp_reg & 0x8F); /* disable all continuous TX */ + else /* Deal with Packet TX case */ + platform_efio_write_1byte(p_adapter, REG_TXPAUSE, 0xFF); /* block all queues */ + + if ((tmp_reg & 0x70) != 0) { + /* 1. Read original RF mode */ + /* path-A */ + rf_amode = phy_query_rf_reg(p_adapter, RF_PATH_A, RF_AC, MASK12BITS); + + /* path-B */ + if (is2T) + rf_bmode = phy_query_rf_reg(p_adapter, RF_PATH_B, RF_AC, MASK12BITS); + + /* 2. Set RF mode = standby mode */ + /* path-A */ + phy_set_rf_reg(p_adapter, RF_PATH_A, RF_AC, MASK12BITS, (rf_amode & 0x8FFFF) | 0x10000); + + /* path-B */ + if (is2T) + phy_set_rf_reg(p_adapter, RF_PATH_B, RF_AC, MASK12BITS, (rf_bmode & 0x8FFFF) | 0x10000); + } + + /* 3. Read RF reg18 */ + lc_cal = phy_query_rf_reg(p_adapter, RF_PATH_A, RF_CHNLBW, MASK12BITS); + + /* 4. Set LC calibration begin bit15 */ + phy_set_rf_reg(p_adapter, RF_PATH_A, RF_CHNLBW, MASK12BITS, lc_cal | 0x08000); + + delay_ms(100); + + + /* Restore original situation */ + if ((tmp_reg & 0x70) != 0) { /* Deal with contisuous TX case */ + /* path-A */ + platform_efio_write_1byte(p_adapter, 0xd03, tmp_reg); + phy_set_rf_reg(p_adapter, RF_PATH_A, RF_AC, MASK12BITS, rf_amode); + + /* path-B */ + if (is2T) + phy_set_rf_reg(p_adapter, RF_PATH_B, RF_AC, MASK12BITS, rf_bmode); + } else /* Deal with Packet TX case */ + platform_efio_write_1byte(p_adapter, REG_TXPAUSE, 0x00); +} + + +void +phy_lc_calibrate( + struct _ADAPTER *p_adapter, + bool is2T +) +{ + _phy_lccalibrate92c(p_adapter, is2T); +} + + + +/* Analog Pre-distortion calibration */ +#define APK_BB_REG_NUM 8 +#define APK_CURVE_REG_NUM 4 +#define PATH_NUM 2 + +void +_phy_ap_calibrate_8192c( + struct _ADAPTER *p_adapter, + s8 delta, + bool is2T +) +{ + HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(p_adapter); + + u32 reg_d[PATH_NUM]; + u32 tmp_reg, index, offset, i, apkbound; + u8 path, pathbound = PATH_NUM; + u32 BB_backup[APK_BB_REG_NUM]; + u32 BB_REG[APK_BB_REG_NUM] = { + REG_FPGA1_TX_BLOCK, REG_OFDM_0_TRX_PATH_ENABLE, + REG_FPGA0_RFMOD, REG_OFDM_0_TR_MUX_PAR, + REG_FPGA0_XCD_RF_INTERFACE_SW, REG_FPGA0_XAB_RF_INTERFACE_SW, + REG_FPGA0_XA_RF_INTERFACE_OE, REG_FPGA0_XB_RF_INTERFACE_OE + }; + u32 BB_AP_MODE[APK_BB_REG_NUM] = { + 0x00000020, 0x00a05430, 0x02040000, + 0x000800e4, 0x00204000 + }; + u32 BB_normal_AP_MODE[APK_BB_REG_NUM] = { + 0x00000020, 0x00a05430, 0x02040000, + 0x000800e4, 0x22204000 + }; + + u32 AFE_backup[IQK_ADDA_REG_NUM]; + u32 AFE_REG[IQK_ADDA_REG_NUM] = { + REG_FPGA0_XCD_SWITCH_CONTROL, REG_BLUE_TOOTH, + REG_RX_WAIT_CCA, REG_TX_CCK_RFON, + REG_TX_CCK_BBON, REG_TX_OFDM_RFON, + REG_TX_OFDM_BBON, REG_TX_TO_RX, + REG_TX_TO_TX, REG_RX_CCK, + REG_RX_OFDM, REG_RX_WAIT_RIFS, + REG_RX_TO_RX, REG_STANDBY, + REG_SLEEP, REG_PMPD_ANAEN + }; + + u32 MAC_backup[IQK_MAC_REG_NUM]; + u32 MAC_REG[IQK_MAC_REG_NUM] = { + REG_TXPAUSE, REG_BCN_CTRL, + REG_BCN_CTRL_1, REG_GPIO_MUXCFG + }; + + u32 APK_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = { + {0x0852c, 0x1852c, 0x5852c, 0x1852c, 0x5852c}, + {0x2852e, 0x0852e, 0x3852e, 0x0852e, 0x0852e} + }; + + u32 APK_normal_RF_init_value[PATH_NUM][APK_BB_REG_NUM] = { + {0x0852c, 0x0a52c, 0x3a52c, 0x5a52c, 0x5a52c}, /* path settings equal to path b settings */ + {0x0852c, 0x0a52c, 0x5a52c, 0x5a52c, 0x5a52c} + }; + + u32 APK_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = { + {0x52019, 0x52014, 0x52013, 0x5200f, 0x5208d}, + {0x5201a, 0x52019, 0x52016, 0x52033, 0x52050} + }; + + u32 APK_normal_RF_value_0[PATH_NUM][APK_BB_REG_NUM] = { + {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a}, /* path settings equal to path b settings */ + {0x52019, 0x52017, 0x52010, 0x5200d, 0x5206a} + }; +#if 0 + u32 APK_RF_value_A[PATH_NUM][APK_BB_REG_NUM] = { + {0x1adb0, 0x1adb0, 0x1ada0, 0x1ad90, 0x1ad80}, + {0x00fb0, 0x00fb0, 0x00fa0, 0x00f90, 0x00f80} + }; +#endif + u32 AFE_on_off[PATH_NUM] = { + 0x04db25a4, 0x0b1b25a4 + }; /* path A on path B off / path A off path B on */ + + u32 APK_offset[PATH_NUM] = { + REG_CONFIG_ANT_A, REG_CONFIG_ANT_B + }; + + u32 APK_normal_offset[PATH_NUM] = { + REG_CONFIG_PMPD_ANT_A, REG_CONFIG_PMPD_ANT_B + }; + + u32 APK_value[PATH_NUM] = { + 0x92fc0000, 0x12fc0000 + }; + + u32 APK_normal_value[PATH_NUM] = { + 0x92680000, 0x12680000 + }; + + s8 APK_delta_mapping[APK_BB_REG_NUM][13] = { + {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-4, -3, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-6, -4, -2, -2, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6}, + {-11, -9, -7, -5, -3, -1, 0, 0, 0, 0, 0, 0, 0} + }; + + u32 APK_normal_setting_value_1[13] = { + 0x01017018, 0xf7ed8f84, 0x1b1a1816, 0x2522201e, 0x322e2b28, + 0x433f3a36, 0x5b544e49, 0x7b726a62, 0xa69a8f84, 0xdfcfc0b3, + 0x12680000, 0x00880000, 0x00880000 + }; + + u32 APK_normal_setting_value_2[16] = { + 0x01c7021d, 0x01670183, 0x01000123, 0x00bf00e2, 0x008d00a3, + 0x0068007b, 0x004d0059, 0x003a0042, 0x002b0031, 0x001f0025, + 0x0017001b, 0x00110014, 0x000c000f, 0x0009000b, 0x00070008, + 0x00050006 + }; + + u32 APK_result[PATH_NUM][APK_BB_REG_NUM]; /* val_1_1a, val_1_2a, val_2a, val_3a, val_4a + * u32 AP_curve[PATH_NUM][APK_CURVE_REG_NUM]; */ + + s32 BB_offset, delta_V, delta_offset; + +#if MP_DRIVER == 1 + PMPT_CONTEXT p_mpt_ctx = &(p_adapter->mpt_ctx); + + p_mpt_ctx->APK_bound[0] = 45; + p_mpt_ctx->APK_bound[1] = 52; +#endif + + RTPRINT(FINIT, INIT_IQK, ("==>_phy_ap_calibrate_8192c() delta %d\n", delta)); + RTPRINT(FINIT, INIT_IQK, ("AP Calibration for %s\n", (is2T ? "2T2R" : "1T1R"))); + if (!is2T) + pathbound = 1; + + /* 2 FOR NORMAL CHIP SETTINGS */ + + /* Temporarily do not allow normal driver to do the following settings because these offset + * and value will cause RF internal PA to be unpredictably disabled by HW, such that RF Tx signal + * will disappear after disable/enable card many times on 88CU. RF SD and DD have not find the + * root cause, so we remove these actions temporarily. Added by tynli and SD3 Allen. 2010.05.31. */ +#if MP_DRIVER != 1 + return; +#endif + /* settings adjust for normal chip */ + for (index = 0; index < PATH_NUM; index++) { + APK_offset[index] = APK_normal_offset[index]; + APK_value[index] = APK_normal_value[index]; + AFE_on_off[index] = 0x6fdb25a4; + } + + for (index = 0; index < APK_BB_REG_NUM; index++) { + for (path = 0; path < pathbound; path++) { + APK_RF_init_value[path][index] = APK_normal_RF_init_value[path][index]; + APK_RF_value_0[path][index] = APK_normal_RF_value_0[path][index]; + } + BB_AP_MODE[index] = BB_normal_AP_MODE[index]; + } + + apkbound = 6; + + /* save BB default value */ + for (index = 0; index < APK_BB_REG_NUM ; index++) { + if (index == 0) /* skip */ + continue; + BB_backup[index] = phy_query_bb_reg(p_adapter, BB_REG[index], MASKDWORD); + } + + /* save MAC default value */ + phy_save_mac_registers(p_adapter, MAC_REG, MAC_backup); + + /* save AFE default value */ + phy_save_adda_registers(p_adapter, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); + + for (path = 0; path < pathbound; path++) { + + + if (path == RF_PATH_A) { + /* path A APK */ + /* load APK setting */ + /* path-A */ + offset = REG_PDP_ANT_A; + for (index = 0; index < 11; index++) { + phy_set_bb_reg(p_adapter, offset, MASKDWORD, APK_normal_setting_value_1[index]); + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0x%x value 0x%x\n", offset, phy_query_bb_reg(p_adapter, offset, MASKDWORD))); + + offset += 0x04; + } + + phy_set_bb_reg(p_adapter, REG_CONFIG_PMPD_ANT_B, MASKDWORD, 0x12680000); + + offset = REG_CONFIG_ANT_A; + for (; index < 13; index++) { + phy_set_bb_reg(p_adapter, offset, MASKDWORD, APK_normal_setting_value_1[index]); + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0x%x value 0x%x\n", offset, phy_query_bb_reg(p_adapter, offset, MASKDWORD))); + + offset += 0x04; + } + + /* page-B1 */ + phy_set_bb_reg(p_adapter, REG_FPGA0_IQK, 0xffffff00, 0x400000); + + /* path A */ + offset = REG_PDP_ANT_A; + for (index = 0; index < 16; index++) { + phy_set_bb_reg(p_adapter, offset, MASKDWORD, APK_normal_setting_value_2[index]); + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0x%x value 0x%x\n", offset, phy_query_bb_reg(p_adapter, offset, MASKDWORD))); + + offset += 0x04; + } + phy_set_bb_reg(p_adapter, REG_FPGA0_IQK, 0xffffff00, 0); + } else if (path == RF_PATH_B) { + /* path B APK */ + /* load APK setting */ + /* path-B */ + offset = REG_PDP_ANT_B; + for (index = 0; index < 10; index++) { + phy_set_bb_reg(p_adapter, offset, MASKDWORD, APK_normal_setting_value_1[index]); + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0x%x value 0x%x\n", offset, phy_query_bb_reg(p_adapter, offset, MASKDWORD))); + + offset += 0x04; + } + phy_set_bb_reg(p_adapter, REG_CONFIG_PMPD_ANT_A, MASKDWORD, 0x12680000); + + phy_set_bb_reg(p_adapter, REG_CONFIG_PMPD_ANT_B, MASKDWORD, 0x12680000); + + offset = REG_CONFIG_ANT_A; + index = 11; + for (; index < 13; index++) { /* offset 0xb68, 0xb6c */ + phy_set_bb_reg(p_adapter, offset, MASKDWORD, APK_normal_setting_value_1[index]); + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0x%x value 0x%x\n", offset, phy_query_bb_reg(p_adapter, offset, MASKDWORD))); + + offset += 0x04; + } + + /* page-B1 */ + phy_set_bb_reg(p_adapter, REG_FPGA0_IQK, 0xffffff00, 0x400000); + + /* path B */ + offset = 0xb60; + for (index = 0; index < 16; index++) { + phy_set_bb_reg(p_adapter, offset, MASKDWORD, APK_normal_setting_value_2[index]); + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0x%x value 0x%x\n", offset, phy_query_bb_reg(p_adapter, offset, MASKDWORD))); + + offset += 0x04; + } + phy_set_bb_reg(p_adapter, REG_FPGA0_IQK, 0xffffff00, 0); + } + + /* save RF default value */ + reg_d[path] = phy_query_rf_reg(p_adapter, path, RF_TXBIAS_A, RFREGOFFSETMASK); + + /* path A AFE all on, path B AFE All off or vise versa */ + for (index = 0; index < IQK_ADDA_REG_NUM ; index++) + phy_set_bb_reg(p_adapter, AFE_REG[index], MASKDWORD, AFE_on_off[path]); + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0xe70 %x\n", phy_query_bb_reg(p_adapter, REG_RX_WAIT_CCA, MASKDWORD))); + + /* BB to AP mode */ + if (path == 0) { + for (index = 0; index < APK_BB_REG_NUM ; index++) { + + if (index == 0) /* skip */ + continue; + else if (index < 5) + phy_set_bb_reg(p_adapter, BB_REG[index], MASKDWORD, BB_AP_MODE[index]); + else if (BB_REG[index] == 0x870) + phy_set_bb_reg(p_adapter, BB_REG[index], MASKDWORD, BB_backup[index] | BIT(10) | BIT(26)); + else + phy_set_bb_reg(p_adapter, BB_REG[index], BIT(10), 0x0); + } + + phy_set_bb_reg(p_adapter, REG_TX_IQK_TONE_A, MASKDWORD, 0x01008c00); + phy_set_bb_reg(p_adapter, REG_RX_IQK_TONE_A, MASKDWORD, 0x01008c00); + } else { /* path B */ + phy_set_bb_reg(p_adapter, REG_TX_IQK_TONE_B, MASKDWORD, 0x01008c00); + phy_set_bb_reg(p_adapter, REG_RX_IQK_TONE_B, MASKDWORD, 0x01008c00); + + } + + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0x800 %x\n", phy_query_bb_reg(p_adapter, 0x800, MASKDWORD))); + + /* MAC settings */ + phy_mac_setting_calibration(p_adapter, MAC_REG, MAC_backup); + + if (path == RF_PATH_A) /* path B to standby mode */ + phy_set_rf_reg(p_adapter, RF_PATH_B, RF_AC, RFREGOFFSETMASK, 0x10000); + else { /* path A to standby mode */ + phy_set_rf_reg(p_adapter, RF_PATH_A, RF_AC, RFREGOFFSETMASK, 0x10000); + phy_set_rf_reg(p_adapter, RF_PATH_A, RF_MODE1, RFREGOFFSETMASK, 0x1000f); + phy_set_rf_reg(p_adapter, RF_PATH_A, RF_MODE2, RFREGOFFSETMASK, 0x20103); + } + + delta_offset = ((delta + 14) / 2); + if (delta_offset < 0) + delta_offset = 0; + else if (delta_offset > 12) + delta_offset = 12; + + /* AP calibration */ + for (index = 0; index < APK_BB_REG_NUM; index++) { + if (index != 1) /* only DO PA11+PAD01001, AP RF setting */ + continue; + + tmp_reg = APK_RF_init_value[path][index]; +#if 1 + if (!p_hal_data->is_apk_thermal_meter_ignore) { + BB_offset = (tmp_reg & 0xF0000) >> 16; + + if (!(tmp_reg & BIT(15))) /* sign bit 0 */ + BB_offset = -BB_offset; + + delta_V = APK_delta_mapping[index][delta_offset]; + + BB_offset += delta_V; + + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() APK index %d tmp_reg 0x%x delta_V %d delta_offset %d\n", index, tmp_reg, delta_V, delta_offset)); + + if (BB_offset < 0) { + tmp_reg = tmp_reg & (~BIT(15)); + BB_offset = -BB_offset; + } else + tmp_reg = tmp_reg | BIT(15); + tmp_reg = (tmp_reg & 0xFFF0FFFF) | (BB_offset << 16); + } +#endif + +#if DEV_BUS_TYPE == RT_PCI_INTERFACE + if (IS_81xxC_VENDOR_UMC_B_CUT(p_hal_data->version_id)) + phy_set_rf_reg(p_adapter, path, RF_IPA_A, RFREGOFFSETMASK, 0x894ae); + else +#endif + phy_set_rf_reg(p_adapter, path, RF_IPA_A, RFREGOFFSETMASK, 0x8992e); + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0xc %x\n", phy_query_rf_reg(p_adapter, path, RF_IPA_A, RFREGOFFSETMASK))); + phy_set_rf_reg(p_adapter, path, RF_AC, RFREGOFFSETMASK, APK_RF_value_0[path][index]); + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0x0 %x\n", phy_query_rf_reg(p_adapter, path, RF_AC, RFREGOFFSETMASK))); + phy_set_rf_reg(p_adapter, path, RF_TXBIAS_A, RFREGOFFSETMASK, tmp_reg); + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0xd %x\n", phy_query_rf_reg(p_adapter, path, RF_TXBIAS_A, RFREGOFFSETMASK))); + + /* PA11+PAD01111, one shot */ + i = 0; + do { + phy_set_bb_reg(p_adapter, REG_FPGA0_IQK, 0xffffff00, 0x800000); + { + phy_set_bb_reg(p_adapter, APK_offset[path], MASKDWORD, APK_value[0]); + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0x%x value 0x%x\n", APK_offset[path], phy_query_bb_reg(p_adapter, APK_offset[path], MASKDWORD))); + delay_ms(3); + phy_set_bb_reg(p_adapter, APK_offset[path], MASKDWORD, APK_value[1]); + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0x%x value 0x%x\n", APK_offset[path], phy_query_bb_reg(p_adapter, APK_offset[path], MASKDWORD))); + + delay_ms(20); + } + phy_set_bb_reg(p_adapter, REG_FPGA0_IQK, 0xffffff00, 0); + + if (path == RF_PATH_A) + tmp_reg = phy_query_bb_reg(p_adapter, REG_APK, 0x03E00000); + else + tmp_reg = phy_query_bb_reg(p_adapter, REG_APK, 0xF8000000); + RTPRINT(FINIT, INIT_IQK, ("_phy_ap_calibrate_8192c() offset 0xbd8[25:21] %x\n", tmp_reg)); + + + i++; + } while (tmp_reg > apkbound && i < 4); + + APK_result[path][index] = tmp_reg; + } + } + + /* reload MAC default value */ + phy_reload_mac_registers(p_adapter, MAC_REG, MAC_backup); + + /* reload BB default value */ + for (index = 0; index < APK_BB_REG_NUM ; index++) { + + if (index == 0) /* skip */ + continue; + phy_set_bb_reg(p_adapter, BB_REG[index], MASKDWORD, BB_backup[index]); + } + + /* reload AFE default value */ + phy_reload_adda_registers(p_adapter, AFE_REG, AFE_backup, IQK_ADDA_REG_NUM); + + /* reload RF path default value */ + for (path = 0; path < pathbound; path++) { + phy_set_rf_reg(p_adapter, path, RF_TXBIAS_A, RFREGOFFSETMASK, reg_d[path]); + if (path == RF_PATH_B) { + phy_set_rf_reg(p_adapter, RF_PATH_A, RF_MODE1, RFREGOFFSETMASK, 0x1000f); + phy_set_rf_reg(p_adapter, RF_PATH_A, RF_MODE2, RFREGOFFSETMASK, 0x20101); + } + + /* note no index == 0 */ + if (APK_result[path][1] > 6) + APK_result[path][1] = 6; + RTPRINT(FINIT, INIT_IQK, ("apk path %d result %d 0x%x \t", path, 1, APK_result[path][1])); + } + + RTPRINT(FINIT, INIT_IQK, ("\n")); + + + for (path = 0; path < pathbound; path++) { + phy_set_rf_reg(p_adapter, path, RF_BS_PA_APSET_G1_G4, RFREGOFFSETMASK, + ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (APK_result[path][1] << 5) | APK_result[path][1])); + if (path == RF_PATH_A) + phy_set_rf_reg(p_adapter, path, RF_BS_PA_APSET_G5_G8, RFREGOFFSETMASK, + ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x00 << 5) | 0x05)); + else + phy_set_rf_reg(p_adapter, path, RF_BS_PA_APSET_G5_G8, RFREGOFFSETMASK, + ((APK_result[path][1] << 15) | (APK_result[path][1] << 10) | (0x02 << 5) | 0x05)); + + phy_set_rf_reg(p_adapter, path, RF_BS_PA_APSET_G9_G11, RFREGOFFSETMASK, ((0x08 << 15) | (0x08 << 10) | (0x08 << 5) | 0x08)); + } + + p_hal_data->is_ap_kdone = true; + + RTPRINT(FINIT, INIT_IQK, ("<==_phy_ap_calibrate_8192c()\n")); +} + + +void +phy_iq_calibrate_8192c( + struct _ADAPTER *p_adapter, + bool is_recovery +) +{ + HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(p_adapter); + s32 result[4][8]; /* last is final result */ + u8 i, final_candidate, indexforchannel; + bool is_patha_ok, is_pathb_ok; + s32 rege94, rege9c, regea4, regeac, regeb4, regebc, regec4, regecc, reg_tmp = 0; + bool is12simular, is13simular, is23simular; + bool is_start_cont_tx = false, is_single_tone = false, is_carrier_suppression = false; + u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = { + REG_OFDM_0_XA_RX_IQ_IMBALANCE, REG_OFDM_0_XB_RX_IQ_IMBALANCE, + REG_OFDM_0_ECCA_THRESHOLD, REG_OFDM_0_AGC_RSSI_TABLE, + REG_OFDM_0_XA_TX_IQ_IMBALANCE, REG_OFDM_0_XB_TX_IQ_IMBALANCE, + REG_OFDM_0_XC_TX_AFE, REG_OFDM_0_XD_TX_AFE, + REG_OFDM_0_RX_IQ_EXT_ANTA + }; + + if (odm_check_power_status(p_adapter) == false) + return; + +#if MP_DRIVER == 1 + is_start_cont_tx = p_adapter->mpt_ctx.is_start_cont_tx; + is_single_tone = p_adapter->mpt_ctx.is_single_tone; + is_carrier_suppression = p_adapter->mpt_ctx.is_carrier_suppression; +#endif + + /* ignore IQK when continuous Tx */ + if (is_start_cont_tx || is_single_tone || is_carrier_suppression) + return; + +#ifdef DISABLE_BB_RF + return; +#endif + if (p_adapter->is_slave_of_dmsp) + return; + + if (is_recovery) { + phy_reload_adda_registers(p_adapter, IQK_BB_REG_92C, p_hal_data->IQK_BB_backup_recover, 9); + return; + + } + + RTPRINT(FINIT, INIT_IQK, ("IQK:Start!!!\n")); + + for (i = 0; i < 8; i++) { + result[0][i] = 0; + result[1][i] = 0; + result[2][i] = 0; + result[3][i] = 0; + } + final_candidate = 0xff; + is_patha_ok = false; + is_pathb_ok = false; + is12simular = false; + is23simular = false; + is13simular = false; + + acquire_cck_and_rw_page_a_control(p_adapter); + /*RT_TRACE(COMP_INIT,DBG_LOUD,("Acquire Mutex in IQCalibrate\n"));*/ + for (i = 0; i < 3; i++) { + /*For 88C 1T1R*/ + _phy_iq_calibrate_8192c(p_adapter, result, i, false); + + if (i == 1) { + is12simular = phy_simularity_compare(p_adapter, result, 0, 1); + if (is12simular) { + final_candidate = 0; + break; + } + } + + if (i == 2) { + is13simular = phy_simularity_compare(p_adapter, result, 0, 2); + if (is13simular) { + final_candidate = 0; + break; + } + + is23simular = phy_simularity_compare(p_adapter, result, 1, 2); + if (is23simular) + final_candidate = 1; + else { + for (i = 0; i < 8; i++) + reg_tmp += result[3][i]; + + if (reg_tmp != 0) + final_candidate = 3; + else + final_candidate = 0xFF; + } + } + } + /* RT_TRACE(COMP_INIT,DBG_LOUD,("Release Mutex in IQCalibrate\n")); */ + release_cck_and_rw_pagea_control(p_adapter); + + for (i = 0; i < 4; i++) { + rege94 = result[i][0]; + rege9c = result[i][1]; + regea4 = result[i][2]; + regeac = result[i][3]; + regeb4 = result[i][4]; + regebc = result[i][5]; + regec4 = result[i][6]; + regecc = result[i][7]; + RTPRINT(FINIT, INIT_IQK, ("IQK: rege94=%x rege9c=%x regea4=%x regeac=%x regeb4=%x regebc=%x regec4=%x regecc=%x\n ", rege94, rege9c, regea4, regeac, regeb4, regebc, regec4, regecc)); + } + + if (final_candidate != 0xff) { + p_hal_data->rege94 = rege94 = result[final_candidate][0]; + p_hal_data->rege9c = rege9c = result[final_candidate][1]; + regea4 = result[final_candidate][2]; + regeac = result[final_candidate][3]; + p_hal_data->regeb4 = regeb4 = result[final_candidate][4]; + p_hal_data->regebc = regebc = result[final_candidate][5]; + regec4 = result[final_candidate][6]; + regecc = result[final_candidate][7]; + RTPRINT(FINIT, INIT_IQK, ("IQK: final_candidate is %x\n", final_candidate)); + RTPRINT(FINIT, INIT_IQK, ("IQK: rege94=%x rege9c=%x regea4=%x regeac=%x regeb4=%x regebc=%x regec4=%x regecc=%x\n ", rege94, rege9c, regea4, regeac, regeb4, regebc, regec4, regecc)); + is_patha_ok = is_pathb_ok = true; + } else { + rege94 = regeb4 = p_hal_data->rege94 = p_hal_data->regeb4 = 0x100; /* X default value */ + rege9c = regebc = p_hal_data->rege9c = p_hal_data->regebc = 0x0; /* Y default value */ + } + + if ((rege94 != 0)/*&&(regea4 != 0)*/) { + if (p_hal_data->current_band_type == BAND_ON_5G) + phy_path_a_fill_iqk_matrix_5g_normal(p_adapter, is_patha_ok, result, final_candidate, (regea4 == 0)); + else + phy_path_a_fill_iqk_matrix(p_adapter, is_patha_ok, result, final_candidate, (regea4 == 0)); + + } + + if (IS_92C_SERIAL(p_hal_data->version_id) || IS_92D_SINGLEPHY(p_hal_data->version_id)) { + if ((regeb4 != 0)/*&&(regec4 != 0)*/) { + if (p_hal_data->current_band_type == BAND_ON_5G) + phy_path_b_fill_iqk_matrix_5g_normal(p_adapter, is_pathb_ok, result, final_candidate, (regec4 == 0)); + else + phy_path_b_fill_iqk_matrix(p_adapter, is_pathb_ok, result, final_candidate, (regec4 == 0)); + } + } + + phy_save_adda_registers(p_adapter, IQK_BB_REG_92C, p_hal_data->IQK_BB_backup_recover, 9); + +} + + +void +phy_lc_calibrate_8192c( + struct _ADAPTER *p_adapter +) +{ + HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(p_adapter); + bool is_start_cont_tx = false, is_single_tone = false, is_carrier_suppression = false; + PMGNT_INFO p_mgnt_info = &p_adapter->MgntInfo; + PMGNT_INFO p_mgnt_info_buddy_adapter; + u32 timeout = 2000, timecount = 0; + struct _ADAPTER *buddy_adapter = p_adapter->buddy_adapter; + +#if MP_DRIVER == 1 + is_start_cont_tx = p_adapter->mpt_ctx.is_start_cont_tx; + is_single_tone = p_adapter->mpt_ctx.is_single_tone; + is_carrier_suppression = p_adapter->mpt_ctx.is_carrier_suppression; +#endif + +#ifdef DISABLE_BB_RF + return; +#endif + + /* ignore LCK when continuous Tx */ + if (is_start_cont_tx || is_single_tone || is_carrier_suppression) + return; + + if (buddy_adapter != NULL && + ((p_adapter->interface_index == 0 && p_hal_data->current_band_type == BAND_ON_2_4G) || + (p_adapter->interface_index == 1 && p_hal_data->current_band_type == BAND_ON_5G))) { + p_mgnt_info_buddy_adapter = &buddy_adapter->MgntInfo; + while (p_mgnt_info_buddy_adapter->is_scan_in_progress && timecount < timeout) { + delay_ms(50); + timecount += 50; + } + } + + while (p_mgnt_info->is_scan_in_progress && timecount < timeout) { + delay_ms(50); + timecount += 50; + } + + p_hal_data->is_lck_in_progress = true; + + RTPRINT(FINIT, INIT_IQK, ("LCK:Start!!!interface %d currentband %x delay %d ms\n", p_adapter->interface_index, p_hal_data->current_band_type, timecount)); + + /* if(IS_92C_SERIAL(p_hal_data->version_id) || IS_92D_SINGLEPHY(p_hal_data->version_id)) */ + if (IS_2T2R(p_hal_data->version_id)) + phy_lc_calibrate(p_adapter, true); + else { + /* For 88C 1T1R */ + phy_lc_calibrate(p_adapter, false); + } + + p_hal_data->is_lck_in_progress = false; + + RTPRINT(FINIT, INIT_IQK, ("LCK:Finish!!!interface %d\n", p_adapter->interface_index)); + + +} + +void +phy_ap_calibrate_8192c( + struct _ADAPTER *p_adapter, + s8 delta +) +{ + HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(p_adapter); + + /* default disable APK, because Tx NG issue, suggest by Jenyu, 2011.11.25 */ + return; + +#ifdef DISABLE_BB_RF + return; +#endif + +#if FOR_BRAZIL_PRETEST != 1 + if (p_hal_data->is_ap_kdone) +#endif + return; + + if (IS_92C_SERIAL(p_hal_data->version_id)) + _phy_ap_calibrate_8192c(p_adapter, delta, true); + else { + /* For 88C 1T1R */ + _phy_ap_calibrate_8192c(p_adapter, delta, false); + } +} + + +#endif + + +/* 3============================================================ + * 3 IQ Calibration + * 3============================================================ */ + +void +odm_reset_iqk_result( + void *p_dm_void +) +{ + return; +} +#if 1/* !(DM_ODM_SUPPORT_TYPE & ODM_AP) */ +u8 odm_get_right_chnl_place_for_iqk(u8 chnl) +{ + u8 channel_all[ODM_TARGET_CHNL_NUM_2G_5G] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 149, 151, 153, 155, 157, 159, 161, 163, 165 + }; + u8 place = chnl; + + + if (chnl > 14) { + for (place = 14; place < sizeof(channel_all); place++) { + if (channel_all[place] == chnl) + return place - 13; + } + } + return 0; + +} +#endif + +void +odm_iq_calibrate( + struct PHY_DM_STRUCT *p_dm_odm +) +{ + struct _ADAPTER *adapter = p_dm_odm->adapter; + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + if (*p_dm_odm->p_is_fcs_mode_enable) + return; +#endif + + + + if (p_dm_odm->is_linked) { + if ((*p_dm_odm->p_channel != p_dm_odm->pre_channel) && (!*p_dm_odm->p_is_scan_in_process)) { + p_dm_odm->pre_channel = *p_dm_odm->p_channel; + p_dm_odm->linked_interval = 0; + } + + if (p_dm_odm->linked_interval < 3) + p_dm_odm->linked_interval++; + + if (p_dm_odm->linked_interval == 2) { + +#if (RTL8814A_SUPPORT == 1) + if (p_dm_odm->support_ic_type == ODM_RTL8814A) + phy_iq_calibrate_8814a(p_dm_odm, false); +#endif + +#if (RTL8822B_SUPPORT == 1) + if (p_dm_odm->support_ic_type == ODM_RTL8822B) + phy_iq_calibrate_8822b(p_dm_odm, false); +#endif + +#if (RTL8821C_SUPPORT == 1) + if (p_dm_odm->support_ic_type == ODM_RTL8821C) + phy_iq_calibrate_8821c(p_dm_odm, false); +#endif + +#if (RTL8821A_SUPPORT == 1) + if (p_dm_odm->support_ic_type == ODM_RTL8821) + phy_iq_calibrate_8821a(p_dm_odm, false); +#endif + +#if (RTL8812A_SUPPORT == 1) + if (p_dm_odm->support_ic_type == ODM_RTL8812) + _phy_iq_calibrate_8812a(p_dm_odm, false); +#endif + } + } else + p_dm_odm->linked_interval = 0; + +} + +void phydm_rf_init(void *p_dm_void) +{ + struct PHY_DM_STRUCT *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void; + odm_txpowertracking_init(p_dm_odm); + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) + odm_clear_txpowertracking_state(p_dm_odm); +#endif + +#if (DM_ODM_SUPPORT_TYPE & (ODM_AP)) +#if (RTL8814A_SUPPORT == 1) + if (p_dm_odm->support_ic_type & ODM_RTL8814A) + phy_iq_calibrate_8814a_init(p_dm_odm); +#endif +#endif + +} + +void phydm_rf_watchdog(void *p_dm_void) +{ + struct PHY_DM_STRUCT *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void; +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) + odm_txpowertracking_check(p_dm_odm); + if (p_dm_odm->support_ic_type & ODM_IC_11AC_SERIES) + odm_iq_calibrate(p_dm_odm); +#endif +} diff --git a/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ap.h b/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ap.h new file mode 100644 index 0000000..30017f1 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ap.h @@ -0,0 +1,178 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#ifndef __HAL_PHY_RF_H__ +#define __HAL_PHY_RF_H__ + +#include "phydm_powertracking_ap.h" +#if (RTL8814A_SUPPORT == 1) + #include "rtl8814a/phydm_iqk_8814a.h" +#endif + +#if (RTL8822B_SUPPORT == 1) + #include "rtl8822b/phydm_iqk_8822b.h" +#endif + +#if (RTL8821C_SUPPORT == 1) + #include "rtl8822b/phydm_iqk_8821c.h" +#endif + +enum pwrtrack_method { + BBSWING, + TXAGC, + MIX_MODE, + TSSI_MODE +}; + +typedef void (*func_set_pwr)(void *, enum pwrtrack_method, u8, u8); +typedef void(*func_iqk)(void *, u8, u8, u8); +typedef void (*func_lck)(void *); +/* refine by YuChen for 8814A */ +typedef void (*func_swing)(void *, u8 **, u8 **, u8 **, u8 **); +typedef void (*func_swing8814only)(void *, u8 **, u8 **, u8 **, u8 **); +typedef void (*func_all_swing)(void *, u8 **, u8 **, u8 **, u8 **, u8 **, u8 **, u8 **, u8 **); + + +struct _TXPWRTRACK_CFG { + u8 swing_table_size_cck; + u8 swing_table_size_ofdm; + u8 threshold_iqk; + u8 threshold_dpk; + u8 average_thermal_num; + u8 rf_path_count; + u32 thermal_reg_addr; + func_set_pwr odm_tx_pwr_track_set_pwr; + func_iqk do_iqk; + func_lck phy_lc_calibrate; + func_swing get_delta_swing_table; + func_swing8814only get_delta_swing_table8814only; + func_all_swing get_delta_all_swing_table; +}; + +void +configure_txpower_track( + void *p_dm_void, + struct _TXPWRTRACK_CFG *p_config +); + + +void +odm_txpowertracking_callback_thermal_meter( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + void *p_dm_void +#else + struct _ADAPTER *adapter +#endif +); + +#if (RTL8192E_SUPPORT == 1) +void +odm_txpowertracking_callback_thermal_meter_92e( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + void *p_dm_void +#else + struct _ADAPTER *adapter +#endif +); +#endif + +#if (RTL8814A_SUPPORT == 1) +void +odm_txpowertracking_callback_thermal_meter_jaguar_series2( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + void *p_dm_void +#else + struct _ADAPTER *adapter +#endif +); + +#elif ODM_IC_11AC_SERIES_SUPPORT +void +odm_txpowertracking_callback_thermal_meter_jaguar_series( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + void *p_dm_void +#else + struct _ADAPTER *adapter +#endif +); + +#elif (RTL8197F_SUPPORT == 1 || RTL8822B_SUPPORT == 1) +void +odm_txpowertracking_callback_thermal_meter_jaguar_series3( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + void *p_dm_void +#else + struct _ADAPTER *adapter +#endif +); + +#endif + +#define IS_CCK_RATE(_rate) (ODM_MGN_1M == _rate || _rate == ODM_MGN_2M || _rate == ODM_MGN_5_5M || _rate == ODM_MGN_11M) + + +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) +#define MAX_TOLERANCE 5 +#define IQK_DELAY_TIME 1 /* ms */ + +/* +* BB/MAC/RF other monitor API +* */ + +void phy_set_monitor_mode8192c(struct _ADAPTER *p_adapter, + bool is_enable_monitor_mode); + +/* + * IQ calibrate + * */ +void +phy_iq_calibrate_8192c(struct _ADAPTER *p_adapter, + bool is_recovery); + +/* + * LC calibrate + * */ +void +phy_lc_calibrate_8192c(struct _ADAPTER *p_adapter); + +/* + * AP calibrate + * */ +void +phy_ap_calibrate_8192c(struct _ADAPTER *p_adapter, + s8 delta); +#endif + +#define ODM_TARGET_CHNL_NUM_2G_5G 59 + + +void +odm_reset_iqk_result( + void *p_dm_void +); +u8 +odm_get_right_chnl_place_for_iqk( + u8 chnl +); + +void phydm_rf_init(void *p_dm_void); +void phydm_rf_watchdog(void *p_dm_void); + +#endif /* #ifndef __HAL_PHY_RF_H__ */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ce.c b/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ce.c new file mode 100644 index 0000000..7451d58 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ce.c @@ -0,0 +1,799 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#include "mp_precomp.h" +#include "phydm_precomp.h" + +#define CALCULATE_SWINGTALBE_OFFSET(_offset, _direction, _size, _delta_thermal) \ + do {\ + for (_offset = 0; _offset < _size; _offset++) { \ + \ + if (_delta_thermal < thermal_threshold[_direction][_offset]) { \ + \ + if (_offset != 0)\ + _offset--;\ + break;\ + } \ + } \ + if (_offset >= _size)\ + _offset = _size-1;\ + } while (0) + +void configure_txpower_track( + void *p_dm_void, + struct _TXPWRTRACK_CFG *p_config +) +{ + struct PHY_DM_STRUCT *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void; + +#if RTL8192E_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8192E) + configure_txpower_track_8192e(p_config); +#endif +#if RTL8821A_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8821) + configure_txpower_track_8821a(p_config); +#endif +#if RTL8812A_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8812) + configure_txpower_track_8812a(p_config); +#endif +#if RTL8188E_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8188E) + configure_txpower_track_8188e(p_config); +#endif + +#if RTL8723B_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8723B) + configure_txpower_track_8723b(p_config); +#endif + +#if RTL8814A_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8814A) + configure_txpower_track_8814a(p_config); +#endif + +#if RTL8703B_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8703B) + configure_txpower_track_8703b(p_config); +#endif + +#if RTL8188F_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8188F) + configure_txpower_track_8188f(p_config); +#endif +#if RTL8723D_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8723D) + configure_txpower_track_8723d(p_config); +#endif +#if RTL8822B_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8822B) + configure_txpower_track_8822b(p_config); +#endif +#if RTL8821C_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8821C) + configure_txpower_track_8821c(p_config); +#endif + +} + +/* ********************************************************************** + * <20121113, Kordan> This function should be called when tx_agc changed. + * Otherwise the previous compensation is gone, because we record the + * delta of temperature between two TxPowerTracking watch dogs. + * + * NOTE: If Tx BB swing or Tx scaling is varified during run-time, still + * need to call this function. + * ********************************************************************** */ +void +odm_clear_txpowertracking_state( + void *p_dm_void +) +{ + struct PHY_DM_STRUCT *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void; + PHAL_DATA_TYPE p_hal_data = GET_HAL_DATA(p_dm_odm->adapter); + u8 p = 0; + struct odm_rf_calibration_structure *p_rf_calibrate_info = &(p_dm_odm->rf_calibrate_info); + + p_rf_calibrate_info->bb_swing_idx_cck_base = p_rf_calibrate_info->default_cck_index; + p_rf_calibrate_info->bb_swing_idx_cck = p_rf_calibrate_info->default_cck_index; + p_dm_odm->rf_calibrate_info.CCK_index = 0; + + for (p = ODM_RF_PATH_A; p < MAX_RF_PATH; ++p) { + p_rf_calibrate_info->bb_swing_idx_ofdm_base[p] = p_rf_calibrate_info->default_ofdm_index; + p_rf_calibrate_info->bb_swing_idx_ofdm[p] = p_rf_calibrate_info->default_ofdm_index; + p_rf_calibrate_info->OFDM_index[p] = p_rf_calibrate_info->default_ofdm_index; + + p_rf_calibrate_info->power_index_offset[p] = 0; + p_rf_calibrate_info->delta_power_index[p] = 0; + p_rf_calibrate_info->delta_power_index_last[p] = 0; + + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = 0; /* Initial Mix mode power tracking*/ + p_rf_calibrate_info->remnant_ofdm_swing_idx[p] = 0; + p_rf_calibrate_info->kfree_offset[p] = 0; + } + + p_rf_calibrate_info->modify_tx_agc_flag_path_a = false; /*Initial at Modify Tx Scaling mode*/ + p_rf_calibrate_info->modify_tx_agc_flag_path_b = false; /*Initial at Modify Tx Scaling mode*/ + p_rf_calibrate_info->modify_tx_agc_flag_path_c = false; /*Initial at Modify Tx Scaling mode*/ + p_rf_calibrate_info->modify_tx_agc_flag_path_d = false; /*Initial at Modify Tx Scaling mode*/ + p_rf_calibrate_info->remnant_cck_swing_idx = 0; + p_rf_calibrate_info->thermal_value = p_hal_data->eeprom_thermal_meter; + + p_rf_calibrate_info->modify_tx_agc_value_cck = 0; /* modify by Mingzhi.Guo */ + p_rf_calibrate_info->modify_tx_agc_value_ofdm = 0; /* modify by Mingzhi.Guo */ + +} + +void +odm_txpowertracking_callback_thermal_meter( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + struct PHY_DM_STRUCT *p_dm_odm +#else + struct _ADAPTER *adapter +#endif +) +{ + +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(adapter); +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + struct PHY_DM_STRUCT *p_dm_odm = &p_hal_data->DM_OutSrc; +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + struct PHY_DM_STRUCT *p_dm_odm = &p_hal_data->odmpriv; +#endif +#endif + + struct odm_rf_calibration_structure *p_rf_calibrate_info = &(p_dm_odm->rf_calibrate_info); + + u8 thermal_value = 0, delta, delta_LCK, delta_IQK, p = 0, i = 0; + s8 diff_DPK[4] = {0}; + u8 thermal_value_avg_count = 0; + u32 thermal_value_avg = 0, regc80, regcd0, regcd4, regab4; + + u8 OFDM_min_index = 0; /* OFDM BB Swing should be less than +3.0dB, which is required by Arthur */ + u8 indexforchannel = 0; /* get_right_chnl_place_for_iqk(p_hal_data->current_channel) */ + u8 power_tracking_type = p_hal_data->rf_power_tracking_type; + u8 xtal_offset_eanble = 0; + + struct _TXPWRTRACK_CFG c; + + /* 4 1. The following TWO tables decide the final index of OFDM/CCK swing table. */ + u8 *delta_swing_table_idx_tup_a = NULL; + u8 *delta_swing_table_idx_tdown_a = NULL; + u8 *delta_swing_table_idx_tup_b = NULL; + u8 *delta_swing_table_idx_tdown_b = NULL; + /*for 8814 add by Yu Chen*/ + u8 *delta_swing_table_idx_tup_c = NULL; + u8 *delta_swing_table_idx_tdown_c = NULL; + u8 *delta_swing_table_idx_tup_d = NULL; + u8 *delta_swing_table_idx_tdown_d = NULL; + /*for Xtal Offset by James.Tung*/ + s8 *delta_swing_table_xtal_up = NULL; + s8 *delta_swing_table_xtal_down = NULL; + + /* 4 2. Initilization ( 7 steps in total ) */ + + configure_txpower_track(p_dm_odm, &c); + + (*c.get_delta_swing_table)(p_dm_odm, (u8 **)&delta_swing_table_idx_tup_a, (u8 **)&delta_swing_table_idx_tdown_a, + (u8 **)&delta_swing_table_idx_tup_b, (u8 **)&delta_swing_table_idx_tdown_b); + + if (p_dm_odm->support_ic_type & ODM_RTL8814A) /*for 8814 path C & D*/ + (*c.get_delta_swing_table8814only)(p_dm_odm, (u8 **)&delta_swing_table_idx_tup_c, (u8 **)&delta_swing_table_idx_tdown_c, + (u8 **)&delta_swing_table_idx_tup_d, (u8 **)&delta_swing_table_idx_tdown_d); + + if (p_dm_odm->support_ic_type & (ODM_RTL8703B | ODM_RTL8723D)) /*for Xtal Offset*/ + (*c.get_delta_swing_xtal_table)(p_dm_odm, (s8 **)&delta_swing_table_xtal_up, (s8 **)&delta_swing_table_xtal_down); + + p_rf_calibrate_info->txpowertracking_callback_cnt++; /*cosa add for debug*/ + p_rf_calibrate_info->is_txpowertracking_init = true; + + /*p_rf_calibrate_info->txpowertrack_control = p_hal_data->txpowertrack_control; + <Kordan> We should keep updating the control variable according to HalData. + <Kordan> rf_calibrate_info.rega24 will be initialized when ODM HW configuring, but MP configures with para files. */ +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) +#if (MP_DRIVER == 1) + p_rf_calibrate_info->rega24 = 0x090e1317; +#endif +#elif (DM_ODM_SUPPORT_TYPE & ODM_CE) + if (p_dm_odm->mp_mode == true) + p_rf_calibrate_info->rega24 = 0x090e1317; +#endif + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("===>odm_txpowertracking_callback_thermal_meter\n p_rf_calibrate_info->bb_swing_idx_cck_base: %d, p_rf_calibrate_info->bb_swing_idx_ofdm_base[A]: %d, p_rf_calibrate_info->default_ofdm_index: %d\n", + p_rf_calibrate_info->bb_swing_idx_cck_base, p_rf_calibrate_info->bb_swing_idx_ofdm_base[ODM_RF_PATH_A], p_rf_calibrate_info->default_ofdm_index)); + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("p_rf_calibrate_info->txpowertrack_control=%d, p_hal_data->eeprom_thermal_meter %d\n", p_rf_calibrate_info->txpowertrack_control, p_hal_data->eeprom_thermal_meter)); + thermal_value = (u8)odm_get_rf_reg(p_dm_odm, ODM_RF_PATH_A, c.thermal_reg_addr, 0xfc00); /* 0x42: RF Reg[15:10] 88E */ + + /*add log by zhao he, check c80/c94/c14/ca0 value*/ + if (p_dm_odm->support_ic_type == ODM_RTL8723D) { + regc80 = odm_get_bb_reg(p_dm_odm, 0xc80, MASKDWORD); + regcd0 = odm_get_bb_reg(p_dm_odm, 0xcd0, MASKDWORD); + regcd4 = odm_get_bb_reg(p_dm_odm, 0xcd4, MASKDWORD); + regab4 = odm_get_bb_reg(p_dm_odm, 0xab4, 0x000007FF); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xc80 = 0x%x 0xcd0 = 0x%x 0xcd4 = 0x%x 0xab4 = 0x%x\n", regc80, regcd0, regcd4, regab4)); + } + + if (!p_rf_calibrate_info->txpowertrack_control) + return; + + + /*4 3. Initialize ThermalValues of rf_calibrate_info*/ + + if (p_rf_calibrate_info->is_reloadtxpowerindex) + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("reload ofdm index for band switch\n")); + + /*4 4. Calculate average thermal meter*/ + + p_rf_calibrate_info->thermal_value_avg[p_rf_calibrate_info->thermal_value_avg_index] = thermal_value; + p_rf_calibrate_info->thermal_value_avg_index++; + if (p_rf_calibrate_info->thermal_value_avg_index == c.average_thermal_num) /*Average times = c.average_thermal_num*/ + p_rf_calibrate_info->thermal_value_avg_index = 0; + + for (i = 0; i < c.average_thermal_num; i++) { + if (p_rf_calibrate_info->thermal_value_avg[i]) { + thermal_value_avg += p_rf_calibrate_info->thermal_value_avg[i]; + thermal_value_avg_count++; + } + } + + if (thermal_value_avg_count) { /* Calculate Average thermal_value after average enough times */ + thermal_value = (u8)(thermal_value_avg / thermal_value_avg_count); + p_rf_calibrate_info->thermal_value_delta = thermal_value - p_hal_data->eeprom_thermal_meter; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("AVG Thermal Meter = 0x%X, EFUSE Thermal base = 0x%X\n", thermal_value, p_hal_data->eeprom_thermal_meter)); + } + + /* 4 5. Calculate delta, delta_LCK, delta_IQK. */ + + /* "delta" here is used to determine whether thermal value changes or not. */ + delta = (thermal_value > p_rf_calibrate_info->thermal_value) ? (thermal_value - p_rf_calibrate_info->thermal_value) : (p_rf_calibrate_info->thermal_value - thermal_value); + delta_LCK = (thermal_value > p_rf_calibrate_info->thermal_value_lck) ? (thermal_value - p_rf_calibrate_info->thermal_value_lck) : (p_rf_calibrate_info->thermal_value_lck - thermal_value); + delta_IQK = (thermal_value > p_rf_calibrate_info->thermal_value_iqk) ? (thermal_value - p_rf_calibrate_info->thermal_value_iqk) : (p_rf_calibrate_info->thermal_value_iqk - thermal_value); + + if (p_rf_calibrate_info->thermal_value_iqk == 0xff) { /*no PG, use thermal value for IQK*/ + p_rf_calibrate_info->thermal_value_iqk = thermal_value; + delta_IQK = (thermal_value > p_rf_calibrate_info->thermal_value_iqk) ? (thermal_value - p_rf_calibrate_info->thermal_value_iqk) : (p_rf_calibrate_info->thermal_value_iqk - thermal_value); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("no PG, use thermal_value for IQK\n")); + } + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + diff_DPK[p] = (s8)thermal_value - (s8)p_rf_calibrate_info->dpk_thermal[p]; + + /*4 6. If necessary, do LCK.*/ + + if (!(p_dm_odm->support_ic_type & ODM_RTL8821)) { /*no PG, do LCK at initial status*/ + if (p_rf_calibrate_info->thermal_value_lck == 0xff) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("no PG, do LCK\n")); + p_rf_calibrate_info->thermal_value_lck = thermal_value; + + /*Use RTLCK, so close power tracking driver LCK*/ + if (!(p_dm_odm->support_ic_type & ODM_RTL8814A)) { + if (c.phy_lc_calibrate) + (*c.phy_lc_calibrate)(p_dm_odm); + } + + delta_LCK = (thermal_value > p_rf_calibrate_info->thermal_value_lck) ? (thermal_value - p_rf_calibrate_info->thermal_value_lck) : (p_rf_calibrate_info->thermal_value_lck - thermal_value); + } + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("(delta, delta_LCK, delta_IQK) = (%d, %d, %d)\n", delta, delta_LCK, delta_IQK)); + + /* Delta temperature is equal to or larger than 20 centigrade.*/ + if (delta_LCK >= c.threshold_iqk) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("delta_LCK(%d) >= threshold_iqk(%d)\n", delta_LCK, c.threshold_iqk)); + p_rf_calibrate_info->thermal_value_lck = thermal_value; + + /*Use RTLCK, so close power tracking driver LCK*/ + if (!(p_dm_odm->support_ic_type & ODM_RTL8814A)) { + if (c.phy_lc_calibrate) + (*c.phy_lc_calibrate)(p_dm_odm); + } + } + } + + /*3 7. If necessary, move the index of swing table to adjust Tx power.*/ + + if (delta > 0 && p_rf_calibrate_info->txpowertrack_control) { + /* "delta" here is used to record the absolute value of differrence. */ +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) + delta = thermal_value > p_hal_data->eeprom_thermal_meter ? (thermal_value - p_hal_data->eeprom_thermal_meter) : (p_hal_data->eeprom_thermal_meter - thermal_value); +#else + delta = (thermal_value > p_dm_odm->priv->pmib->dot11RFEntry.ther) ? (thermal_value - p_dm_odm->priv->pmib->dot11RFEntry.ther) : (p_dm_odm->priv->pmib->dot11RFEntry.ther - thermal_value); +#endif + if (delta >= TXPWR_TRACK_TABLE_SIZE) + delta = TXPWR_TRACK_TABLE_SIZE - 1; + + /*4 7.1 The Final Power index = BaseIndex + power_index_offset*/ + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) + if (thermal_value > p_hal_data->eeprom_thermal_meter) { +#else + if (thermal_value > p_dm_odm->priv->pmib->dot11RFEntry.ther) { +#endif + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + p_rf_calibrate_info->delta_power_index_last[p] = p_rf_calibrate_info->delta_power_index[p]; /*recording poer index offset*/ + switch (p) { + case ODM_RF_PATH_B: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_b[%d] = %d\n", delta, delta_swing_table_idx_tup_b[delta])); + + p_rf_calibrate_info->delta_power_index[p] = delta_swing_table_idx_tup_b[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_b[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_B] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + case ODM_RF_PATH_C: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_c[%d] = %d\n", delta, delta_swing_table_idx_tup_c[delta])); + + p_rf_calibrate_info->delta_power_index[p] = delta_swing_table_idx_tup_c[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_c[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_C] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + case ODM_RF_PATH_D: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_d[%d] = %d\n", delta, delta_swing_table_idx_tup_d[delta])); + + p_rf_calibrate_info->delta_power_index[p] = delta_swing_table_idx_tup_d[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_d[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_D] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + default: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_a[%d] = %d\n", delta, delta_swing_table_idx_tup_a[delta])); + + p_rf_calibrate_info->delta_power_index[p] = delta_swing_table_idx_tup_a[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_a[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_A] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + } + } + + if (p_dm_odm->support_ic_type & (ODM_RTL8703B | ODM_RTL8723D)) { + /*Save xtal_offset from Xtal table*/ + p_rf_calibrate_info->xtal_offset_last = p_rf_calibrate_info->xtal_offset; /*recording last Xtal offset*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("[Xtal] delta_swing_table_xtal_up[%d] = %d\n", delta, delta_swing_table_xtal_up[delta])); + p_rf_calibrate_info->xtal_offset = delta_swing_table_xtal_up[delta]; + + if (p_rf_calibrate_info->xtal_offset_last == p_rf_calibrate_info->xtal_offset) + xtal_offset_eanble = 0; + else + xtal_offset_eanble = 1; + } + + } else { + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + p_rf_calibrate_info->delta_power_index_last[p] = p_rf_calibrate_info->delta_power_index[p]; /*recording poer index offset*/ + + switch (p) { + case ODM_RF_PATH_B: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_b[%d] = %d\n", delta, delta_swing_table_idx_tdown_b[delta])); + p_rf_calibrate_info->delta_power_index[p] = -1 * delta_swing_table_idx_tdown_b[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_b[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_B] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + case ODM_RF_PATH_C: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_c[%d] = %d\n", delta, delta_swing_table_idx_tdown_c[delta])); + p_rf_calibrate_info->delta_power_index[p] = -1 * delta_swing_table_idx_tdown_c[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_c[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_C] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + case ODM_RF_PATH_D: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_d[%d] = %d\n", delta, delta_swing_table_idx_tdown_d[delta])); + p_rf_calibrate_info->delta_power_index[p] = -1 * delta_swing_table_idx_tdown_d[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_d[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_D] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + default: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_a[%d] = %d\n", delta, delta_swing_table_idx_tdown_a[delta])); + p_rf_calibrate_info->delta_power_index[p] = -1 * delta_swing_table_idx_tdown_a[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_a[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_A] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + } + } + + if (p_dm_odm->support_ic_type & (ODM_RTL8703B | ODM_RTL8723D)) { + /*Save xtal_offset from Xtal table*/ + p_rf_calibrate_info->xtal_offset_last = p_rf_calibrate_info->xtal_offset; /*recording last Xtal offset*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("[Xtal] delta_swing_table_xtal_down[%d] = %d\n", delta, delta_swing_table_xtal_down[delta])); + p_rf_calibrate_info->xtal_offset = delta_swing_table_xtal_down[delta]; + + if (p_rf_calibrate_info->xtal_offset_last == p_rf_calibrate_info->xtal_offset) + xtal_offset_eanble = 0; + else + xtal_offset_eanble = 1; + } + + } + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("\n\n=========================== [path-%d] Calculating power_index_offset===========================\n", p)); + + if (p_rf_calibrate_info->delta_power_index[p] == p_rf_calibrate_info->delta_power_index_last[p]) /*If Thermal value changes but lookup table value still the same*/ + p_rf_calibrate_info->power_index_offset[p] = 0; + else + p_rf_calibrate_info->power_index_offset[p] = p_rf_calibrate_info->delta_power_index[p] - p_rf_calibrate_info->delta_power_index_last[p]; /*Power index diff between 2 times Power Tracking*/ + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("[path-%d] power_index_offset(%d) = delta_power_index(%d) - delta_power_index_last(%d)\n", p, p_rf_calibrate_info->power_index_offset[p], p_rf_calibrate_info->delta_power_index[p], p_rf_calibrate_info->delta_power_index_last[p])); + + p_rf_calibrate_info->OFDM_index[p] = p_rf_calibrate_info->bb_swing_idx_ofdm_base[p] + p_rf_calibrate_info->power_index_offset[p]; + p_rf_calibrate_info->CCK_index = p_rf_calibrate_info->bb_swing_idx_cck_base + p_rf_calibrate_info->power_index_offset[p]; + + p_rf_calibrate_info->bb_swing_idx_cck = p_rf_calibrate_info->CCK_index; + p_rf_calibrate_info->bb_swing_idx_ofdm[p] = p_rf_calibrate_info->OFDM_index[p]; + + /*************Print BB Swing base and index Offset*************/ + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("The 'CCK' final index(%d) = BaseIndex(%d) + power_index_offset(%d)\n", p_rf_calibrate_info->bb_swing_idx_cck, p_rf_calibrate_info->bb_swing_idx_cck_base, p_rf_calibrate_info->power_index_offset[p])); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("The 'OFDM' final index(%d) = BaseIndex[%d](%d) + power_index_offset(%d)\n", p_rf_calibrate_info->bb_swing_idx_ofdm[p], p, p_rf_calibrate_info->bb_swing_idx_ofdm_base[p], p_rf_calibrate_info->power_index_offset[p])); + + /*4 7.1 Handle boundary conditions of index.*/ + + if (p_rf_calibrate_info->OFDM_index[p] > c.swing_table_size_ofdm - 1) + p_rf_calibrate_info->OFDM_index[p] = c.swing_table_size_ofdm - 1; + else if (p_rf_calibrate_info->OFDM_index[p] <= OFDM_min_index) + p_rf_calibrate_info->OFDM_index[p] = OFDM_min_index; + } + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("\n\n========================================================================================================\n")); + + if (p_rf_calibrate_info->CCK_index > c.swing_table_size_cck - 1) + p_rf_calibrate_info->CCK_index = c.swing_table_size_cck - 1; + else if (p_rf_calibrate_info->CCK_index <= 0) + p_rf_calibrate_info->CCK_index = 0; + } else { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("The thermal meter is unchanged or TxPowerTracking OFF(%d): thermal_value: %d, p_rf_calibrate_info->thermal_value: %d\n", + p_rf_calibrate_info->txpowertrack_control, thermal_value, p_rf_calibrate_info->thermal_value)); + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + p_rf_calibrate_info->power_index_offset[p] = 0; + } + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("TxPowerTracking: [CCK] Swing Current index: %d, Swing base index: %d\n", + p_rf_calibrate_info->CCK_index, p_rf_calibrate_info->bb_swing_idx_cck_base)); /*Print Swing base & current*/ + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("TxPowerTracking: [OFDM] Swing Current index: %d, Swing base index[%d]: %d\n", + p_rf_calibrate_info->OFDM_index[p], p, p_rf_calibrate_info->bb_swing_idx_ofdm_base[p])); + } + + if ((p_dm_odm->support_ic_type & ODM_RTL8814A)) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("power_tracking_type=%d\n", power_tracking_type)); + + if (power_tracking_type == 0) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking MIX_MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, MIX_MODE, p, 0); + } else if (power_tracking_type == 1) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking MIX(2G) TSSI(5G) MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, MIX_2G_TSSI_5G_MODE, p, 0); + } else if (power_tracking_type == 2) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking MIX(5G) TSSI(2G)MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, MIX_5G_TSSI_2G_MODE, p, 0); + } else if (power_tracking_type == 3) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking TSSI MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, TSSI_MODE, p, 0); + } + p_rf_calibrate_info->thermal_value = thermal_value; /*Record last Power Tracking Thermal value*/ + + } else if ((p_rf_calibrate_info->power_index_offset[ODM_RF_PATH_A] != 0 || + p_rf_calibrate_info->power_index_offset[ODM_RF_PATH_B] != 0 || + p_rf_calibrate_info->power_index_offset[ODM_RF_PATH_C] != 0 || + p_rf_calibrate_info->power_index_offset[ODM_RF_PATH_D] != 0) && + p_rf_calibrate_info->txpowertrack_control && (p_hal_data->eeprom_thermal_meter != 0xff)) { + /* 4 7.2 Configure the Swing Table to adjust Tx Power. */ + + p_rf_calibrate_info->is_tx_power_changed = true; /*Always true after Tx Power is adjusted by power tracking.*/ + /* */ + /* 2012/04/23 MH According to Luke's suggestion, we can not write BB digital */ + /* to increase TX power. Otherwise, EVM will be bad. */ + /* */ + /* 2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. */ + if (thermal_value > p_rf_calibrate_info->thermal_value) { + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature Increasing(%d): delta_pi: %d, delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + p, p_rf_calibrate_info->power_index_offset[p], delta, thermal_value, p_hal_data->eeprom_thermal_meter, p_rf_calibrate_info->thermal_value)); + } + } else if (thermal_value < p_rf_calibrate_info->thermal_value) { /*Low temperature*/ + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature Decreasing(%d): delta_pi: %d, delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + p, p_rf_calibrate_info->power_index_offset[p], delta, thermal_value, p_hal_data->eeprom_thermal_meter, p_rf_calibrate_info->thermal_value)); + } + } + +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + if (thermal_value > p_hal_data->eeprom_thermal_meter) +#else + if (thermal_value > p_dm_odm->priv->pmib->dot11RFEntry.ther) +#endif + { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature(%d) higher than PG value(%d)\n", thermal_value, p_hal_data->eeprom_thermal_meter)); + + if (p_dm_odm->support_ic_type == ODM_RTL8188E || p_dm_odm->support_ic_type == ODM_RTL8192E || p_dm_odm->support_ic_type == ODM_RTL8821 || + p_dm_odm->support_ic_type == ODM_RTL8812 || p_dm_odm->support_ic_type == ODM_RTL8723B || p_dm_odm->support_ic_type == ODM_RTL8814A || + p_dm_odm->support_ic_type == ODM_RTL8703B || p_dm_odm->support_ic_type == ODM_RTL8188F || p_dm_odm->support_ic_type == ODM_RTL8822B || + p_dm_odm->support_ic_type == ODM_RTL8723D || p_dm_odm->support_ic_type == ODM_RTL8821C) { + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking MIX_MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, MIX_MODE, p, 0); + } else { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking BBSWING_MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, BBSWING, p, indexforchannel); + } + } else { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature(%d) lower than PG value(%d)\n", thermal_value, p_hal_data->eeprom_thermal_meter)); + + if (p_dm_odm->support_ic_type == ODM_RTL8188E || p_dm_odm->support_ic_type == ODM_RTL8192E || p_dm_odm->support_ic_type == ODM_RTL8821 || + p_dm_odm->support_ic_type == ODM_RTL8812 || p_dm_odm->support_ic_type == ODM_RTL8723B || p_dm_odm->support_ic_type == ODM_RTL8814A || + p_dm_odm->support_ic_type == ODM_RTL8703B || p_dm_odm->support_ic_type == ODM_RTL8188F || p_dm_odm->support_ic_type == ODM_RTL8822B || + p_dm_odm->support_ic_type == ODM_RTL8723D || p_dm_odm->support_ic_type == ODM_RTL8821C) { + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking MIX_MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, MIX_MODE, p, indexforchannel); + } else { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking BBSWING_MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, BBSWING, p, indexforchannel); + } + + } + + p_rf_calibrate_info->bb_swing_idx_cck_base = p_rf_calibrate_info->bb_swing_idx_cck; /*Record last time Power Tracking result as base.*/ + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + p_rf_calibrate_info->bb_swing_idx_ofdm_base[p] = p_rf_calibrate_info->bb_swing_idx_ofdm[p]; + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("p_rf_calibrate_info->thermal_value = %d thermal_value= %d\n", p_rf_calibrate_info->thermal_value, thermal_value)); + + p_rf_calibrate_info->thermal_value = thermal_value; /*Record last Power Tracking Thermal value*/ + + } + + + if (p_dm_odm->support_ic_type == ODM_RTL8703B || p_dm_odm->support_ic_type == ODM_RTL8723D) { + + if (xtal_offset_eanble != 0 && p_rf_calibrate_info->txpowertrack_control && (p_hal_data->eeprom_thermal_meter != 0xff)) { + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter Xtal Tracking**********\n")); + +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + if (thermal_value > p_hal_data->eeprom_thermal_meter) { +#else + if (thermal_value > p_dm_odm->priv->pmib->dot11RFEntry.ther) { +#endif + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature(%d) higher than PG value(%d)\n", thermal_value, p_hal_data->eeprom_thermal_meter)); + (*c.odm_txxtaltrack_set_xtal)(p_dm_odm); + } else { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature(%d) lower than PG value(%d)\n", thermal_value, p_hal_data->eeprom_thermal_meter)); + (*c.odm_txxtaltrack_set_xtal)(p_dm_odm); + } + } + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********End Xtal Tracking**********\n")); + } + +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + + if (!IS_HARDWARE_TYPE_8723B(adapter)) { + /*Delta temperature is equal to or larger than 20 centigrade (When threshold is 8).*/ + if (delta_IQK >= c.threshold_iqk) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("delta_IQK(%d) >= threshold_iqk(%d)\n", delta_IQK, c.threshold_iqk)); + if (!p_rf_calibrate_info->is_iqk_in_progress) + (*c.do_iqk)(p_dm_odm, delta_IQK, thermal_value, 8); + } + } + if (p_rf_calibrate_info->dpk_thermal[ODM_RF_PATH_A] != 0) { + if (diff_DPK[ODM_RF_PATH_A] >= c.threshold_dpk) { + odm_set_bb_reg(p_dm_odm, 0x82c, BIT(31), 0x1); + odm_set_bb_reg(p_dm_odm, 0xcc4, BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10), (diff_DPK[ODM_RF_PATH_A] / c.threshold_dpk)); + odm_set_bb_reg(p_dm_odm, 0x82c, BIT(31), 0x0); + } else if ((diff_DPK[ODM_RF_PATH_A] <= -1 * c.threshold_dpk)) { + s32 value = 0x20 + (diff_DPK[ODM_RF_PATH_A] / c.threshold_dpk); + + odm_set_bb_reg(p_dm_odm, 0x82c, BIT(31), 0x1); + odm_set_bb_reg(p_dm_odm, 0xcc4, BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10), value); + odm_set_bb_reg(p_dm_odm, 0x82c, BIT(31), 0x0); + } else { + odm_set_bb_reg(p_dm_odm, 0x82c, BIT(31), 0x1); + odm_set_bb_reg(p_dm_odm, 0xcc4, BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10), 0); + odm_set_bb_reg(p_dm_odm, 0x82c, BIT(31), 0x0); + } + } + if (p_rf_calibrate_info->dpk_thermal[ODM_RF_PATH_B] != 0) { + if (diff_DPK[ODM_RF_PATH_B] >= c.threshold_dpk) { + odm_set_bb_reg(p_dm_odm, 0x82c, BIT(31), 0x1); + odm_set_bb_reg(p_dm_odm, 0xec4, BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10), (diff_DPK[ODM_RF_PATH_B] / c.threshold_dpk)); + odm_set_bb_reg(p_dm_odm, 0x82c, BIT(31), 0x0); + } else if ((diff_DPK[ODM_RF_PATH_B] <= -1 * c.threshold_dpk)) { + s32 value = 0x20 + (diff_DPK[ODM_RF_PATH_B] / c.threshold_dpk); + + odm_set_bb_reg(p_dm_odm, 0x82c, BIT(31), 0x1); + odm_set_bb_reg(p_dm_odm, 0xec4, BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10), value); + odm_set_bb_reg(p_dm_odm, 0x82c, BIT(31), 0x0); + } else { + odm_set_bb_reg(p_dm_odm, 0x82c, BIT(31), 0x1); + odm_set_bb_reg(p_dm_odm, 0xec4, BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10), 0); + odm_set_bb_reg(p_dm_odm, 0x82c, BIT(31), 0x0); + } + } + +#endif + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("<===odm_txpowertracking_callback_thermal_meter\n")); + + p_rf_calibrate_info->tx_powercount = 0; +} + + + +/* 3============================================================ + * 3 IQ Calibration + * 3============================================================ */ + +void +odm_reset_iqk_result( + void *p_dm_void +) +{ + return; +} +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) +u8 odm_get_right_chnl_place_for_iqk(u8 chnl) +{ + u8 channel_all[ODM_TARGET_CHNL_NUM_2G_5G] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 149, 151, 153, 155, 157, 159, 161, 163, 165 + }; + u8 place = chnl; + + + if (chnl > 14) { + for (place = 14; place < sizeof(channel_all); place++) { + if (channel_all[place] == chnl) + return place - 13; + } + } + return 0; + +} +#endif + +void +odm_iq_calibrate( + struct PHY_DM_STRUCT *p_dm_odm +) +{ + struct _ADAPTER *adapter = p_dm_odm->adapter; + +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + if (*p_dm_odm->p_is_fcs_mode_enable) + return; +#endif + +#if (DM_ODM_SUPPORT_TYPE & (ODM_CE)) + if (IS_HARDWARE_TYPE_8812AU(adapter)) + return; +#endif + + if (p_dm_odm->is_linked) { + if ((*p_dm_odm->p_channel != p_dm_odm->pre_channel) && (!*p_dm_odm->p_is_scan_in_process)) { + p_dm_odm->pre_channel = *p_dm_odm->p_channel; + p_dm_odm->linked_interval = 0; + } + + if (p_dm_odm->linked_interval < 3) + p_dm_odm->linked_interval++; + + if (p_dm_odm->linked_interval == 2) { + if (IS_HARDWARE_TYPE_8814A(adapter)) { +#if (RTL8814A_SUPPORT == 1) + phy_iq_calibrate_8814a(p_dm_odm, false); +#endif + } + +#if (RTL8822B_SUPPORT == 1) + else if (IS_HARDWARE_TYPE_8822B(adapter)) + phy_iq_calibrate_8822b(p_dm_odm, false); +#endif + +#if (RTL8821C_SUPPORT == 1) + else if (IS_HARDWARE_TYPE_8821C(adapter)) + phy_iq_calibrate_8821c(p_dm_odm, false); +#endif + +#if (RTL8821A_SUPPORT == 1) + else if (IS_HARDWARE_TYPE_8821(adapter)) + phy_iq_calibrate_8821a(p_dm_odm, false); +#endif + } + } else + p_dm_odm->linked_interval = 0; +} + +void phydm_rf_init(void *p_dm_void) +{ + struct PHY_DM_STRUCT *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void; + odm_txpowertracking_init(p_dm_odm); + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) + odm_clear_txpowertracking_state(p_dm_odm); +#endif + +#if (DM_ODM_SUPPORT_TYPE & (ODM_AP)) +#if (RTL8814A_SUPPORT == 1) + if (p_dm_odm->support_ic_type & ODM_RTL8814A) + phy_iq_calibrate_8814a_init(p_dm_odm); +#endif +#endif + +} + +void phydm_rf_watchdog(void *p_dm_void) +{ + struct PHY_DM_STRUCT *p_dm_odm = (struct PHY_DM_STRUCT *)p_dm_void; +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) + odm_txpowertracking_check(p_dm_odm); + if (p_dm_odm->support_ic_type & ODM_IC_11AC_SERIES) + odm_iq_calibrate(p_dm_odm); +#endif +} diff --git a/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ce.h b/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ce.h new file mode 100644 index 0000000..71d104a --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_ce.h @@ -0,0 +1,117 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#ifndef __HAL_PHY_RF_H__ +#define __HAL_PHY_RF_H__ + +#include "phydm_kfree.h" +#if (RTL8814A_SUPPORT == 1) + #include "rtl8814a/phydm_iqk_8814a.h" +#endif + +#if (RTL8822B_SUPPORT == 1) + #include "rtl8822b/phydm_iqk_8822b.h" +#endif + +#if (RTL8821C_SUPPORT == 1) + #include "rtl8821c/phydm_iqk_8821c.h" +#endif + +#include "phydm_powertracking_ce.h" + + +enum spur_cal_method { + PLL_RESET, + AFE_PHASE_SEL +}; + +enum pwrtrack_method { + BBSWING, + TXAGC, + MIX_MODE, + TSSI_MODE, + MIX_2G_TSSI_5G_MODE, + MIX_5G_TSSI_2G_MODE +}; + +typedef void (*func_set_pwr)(void *, enum pwrtrack_method, u8, u8); +typedef void(*func_iqk)(void *, u8, u8, u8); +typedef void (*func_lck)(void *); +typedef void (*func_swing)(void *, u8 **, u8 **, u8 **, u8 **); +typedef void (*func_swing8814only)(void *, u8 **, u8 **, u8 **, u8 **); +typedef void(*func_swing_xtal)(void *, s8 **, s8 **); +typedef void(*func_set_xtal)(void *); + +struct _TXPWRTRACK_CFG { + u8 swing_table_size_cck; + u8 swing_table_size_ofdm; + u8 threshold_iqk; + u8 threshold_dpk; + u8 average_thermal_num; + u8 rf_path_count; + u32 thermal_reg_addr; + func_set_pwr odm_tx_pwr_track_set_pwr; + func_iqk do_iqk; + func_lck phy_lc_calibrate; + func_swing get_delta_swing_table; + func_swing8814only get_delta_swing_table8814only; + func_swing_xtal get_delta_swing_xtal_table; + func_set_xtal odm_txxtaltrack_set_xtal; +}; + +void +configure_txpower_track( + void *p_dm_void, + struct _TXPWRTRACK_CFG *p_config +); + + +void +odm_clear_txpowertracking_state( + void *p_dm_void +); + +void +odm_txpowertracking_callback_thermal_meter( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + void *p_dm_void +#else + struct _ADAPTER *adapter +#endif +); + + + +#define ODM_TARGET_CHNL_NUM_2G_5G 59 + + +void +odm_reset_iqk_result( + void *p_dm_void +); +u8 +odm_get_right_chnl_place_for_iqk( + u8 chnl +); + +void phydm_rf_init(void *p_dm_void); +void phydm_rf_watchdog(void *p_dm_void); + +#endif /* #ifndef __HAL_PHY_RF_H__ */ diff --git a/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_win.c b/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_win.c new file mode 100644 index 0000000..c7c6108 --- /dev/null +++ b/linux-bsp/drivers/rtl8188eus/hal/phydm/halphyrf_win.c @@ -0,0 +1,784 @@ +/****************************************************************************** + * + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * + ******************************************************************************/ + +#include "mp_precomp.h" +#include "phydm_precomp.h" + +#define CALCULATE_SWINGTALBE_OFFSET(_offset, _direction, _size, _delta_thermal) \ + do {\ + for (_offset = 0; _offset < _size; _offset++) { \ + \ + if (_delta_thermal < thermal_threshold[_direction][_offset]) { \ + \ + if (_offset != 0)\ + _offset--;\ + break;\ + } \ + } \ + if (_offset >= _size)\ + _offset = _size-1;\ + } while (0) + +void configure_txpower_track( + struct PHY_DM_STRUCT *p_dm_odm, + struct _TXPWRTRACK_CFG *p_config +) +{ +#if RTL8192E_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8192E) + configure_txpower_track_8192e(p_config); +#endif +#if RTL8821A_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8821) + configure_txpower_track_8821a(p_config); +#endif +#if RTL8812A_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8812) + configure_txpower_track_8812a(p_config); +#endif +#if RTL8188E_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8188E) + configure_txpower_track_8188e(p_config); +#endif + +#if RTL8188F_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8188F) + configure_txpower_track_8188f(p_config); +#endif + +#if RTL8723B_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8723B) + configure_txpower_track_8723b(p_config); +#endif + +#if RTL8814A_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8814A) + configure_txpower_track_8814a(p_config); +#endif + +#if RTL8703B_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8703B) + configure_txpower_track_8703b(p_config); +#endif + +#if RTL8822B_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8822B) + configure_txpower_track_8822b(p_config); +#endif + +#if RTL8723D_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8723D) + configure_txpower_track_8723d(p_config); +#endif + +#if RTL8821C_SUPPORT + if (p_dm_odm->support_ic_type == ODM_RTL8821C) + configure_txpower_track_8821c(p_config); +#endif + +} + +/* ********************************************************************** + * <20121113, Kordan> This function should be called when tx_agc changed. + * Otherwise the previous compensation is gone, because we record the + * delta of temperature between two TxPowerTracking watch dogs. + * + * NOTE: If Tx BB swing or Tx scaling is varified during run-time, still + * need to call this function. + * ********************************************************************** */ +void +odm_clear_txpowertracking_state( + struct PHY_DM_STRUCT *p_dm_odm +) +{ + PHAL_DATA_TYPE p_hal_data = GET_HAL_DATA(p_dm_odm->adapter); + u8 p = 0; + struct odm_rf_calibration_structure *p_rf_calibrate_info = &(p_dm_odm->rf_calibrate_info); + + p_rf_calibrate_info->bb_swing_idx_cck_base = p_rf_calibrate_info->default_cck_index; + p_rf_calibrate_info->bb_swing_idx_cck = p_rf_calibrate_info->default_cck_index; + p_rf_calibrate_info->CCK_index = 0; + + for (p = ODM_RF_PATH_A; p < MAX_RF_PATH; ++p) { + p_rf_calibrate_info->bb_swing_idx_ofdm_base[p] = p_rf_calibrate_info->default_ofdm_index; + p_rf_calibrate_info->bb_swing_idx_ofdm[p] = p_rf_calibrate_info->default_ofdm_index; + p_rf_calibrate_info->OFDM_index[p] = p_rf_calibrate_info->default_ofdm_index; + + p_rf_calibrate_info->power_index_offset[p] = 0; + p_rf_calibrate_info->delta_power_index[p] = 0; + p_rf_calibrate_info->delta_power_index_last[p] = 0; + + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = 0; /* Initial Mix mode power tracking*/ + p_rf_calibrate_info->remnant_ofdm_swing_idx[p] = 0; + p_rf_calibrate_info->kfree_offset[p] = 0; + } + + p_rf_calibrate_info->modify_tx_agc_flag_path_a = false; /*Initial at Modify Tx Scaling mode*/ + p_rf_calibrate_info->modify_tx_agc_flag_path_b = false; /*Initial at Modify Tx Scaling mode*/ + p_rf_calibrate_info->modify_tx_agc_flag_path_c = false; /*Initial at Modify Tx Scaling mode*/ + p_rf_calibrate_info->modify_tx_agc_flag_path_d = false; /*Initial at Modify Tx Scaling mode*/ + p_rf_calibrate_info->remnant_cck_swing_idx = 0; + p_rf_calibrate_info->thermal_value = p_hal_data->eeprom_thermal_meter; + + p_rf_calibrate_info->modify_tx_agc_value_cck = 0; /* modify by Mingzhi.Guo */ + p_rf_calibrate_info->modify_tx_agc_value_ofdm = 0; /* modify by Mingzhi.Guo */ + +} + +void +odm_txpowertracking_callback_thermal_meter( +#if (DM_ODM_SUPPORT_TYPE & ODM_AP) + struct PHY_DM_STRUCT *p_dm_odm +#else + struct _ADAPTER *adapter +#endif +) +{ +#if !(DM_ODM_SUPPORT_TYPE & ODM_AP) + HAL_DATA_TYPE *p_hal_data = GET_HAL_DATA(adapter); +#if (DM_ODM_SUPPORT_TYPE == ODM_WIN) + struct PHY_DM_STRUCT *p_dm_odm = &p_hal_data->DM_OutSrc; +#elif (DM_ODM_SUPPORT_TYPE == ODM_CE) + struct PHY_DM_STRUCT *p_dm_odm = &p_hal_data->odmpriv; +#endif +#endif + + struct odm_rf_calibration_structure *p_rf_calibrate_info = &(p_dm_odm->rf_calibrate_info); + + u8 thermal_value = 0, delta, delta_LCK, delta_IQK, p = 0, i = 0; + s8 diff_DPK[4] = {0}; + u8 thermal_value_avg_count = 0; + u32 thermal_value_avg = 0, regc80, regcd0, regcd4, regab4; + + u8 OFDM_min_index = 0; /* OFDM BB Swing should be less than +3.0dB, which is required by Arthur */ + u8 indexforchannel = 0; /* get_right_chnl_place_for_iqk(p_hal_data->current_channel) */ + u8 power_tracking_type = p_hal_data->RfPowerTrackingType; + u8 xtal_offset_eanble = 0; + + struct _TXPWRTRACK_CFG c; + + /* 4 1. The following TWO tables decide the final index of OFDM/CCK swing table. */ + u8 *delta_swing_table_idx_tup_a = NULL; + u8 *delta_swing_table_idx_tdown_a = NULL; + u8 *delta_swing_table_idx_tup_b = NULL; + u8 *delta_swing_table_idx_tdown_b = NULL; + /*for 8814 add by Yu Chen*/ + u8 *delta_swing_table_idx_tup_c = NULL; + u8 *delta_swing_table_idx_tdown_c = NULL; + u8 *delta_swing_table_idx_tup_d = NULL; + u8 *delta_swing_table_idx_tdown_d = NULL; + /*for Xtal Offset by James.Tung*/ + s8 *delta_swing_table_xtal_up = NULL; + s8 *delta_swing_table_xtal_down = NULL; + + /* 4 2. Initilization ( 7 steps in total ) */ + + configure_txpower_track(p_dm_odm, &c); + + (*c.get_delta_swing_table)(p_dm_odm, (u8 **)&delta_swing_table_idx_tup_a, (u8 **)&delta_swing_table_idx_tdown_a, + (u8 **)&delta_swing_table_idx_tup_b, (u8 **)&delta_swing_table_idx_tdown_b); + + if (p_dm_odm->support_ic_type & ODM_RTL8814A) /*for 8814 path C & D*/ + (*c.get_delta_swing_table8814only)(p_dm_odm, (u8 **)&delta_swing_table_idx_tup_c, (u8 **)&delta_swing_table_idx_tdown_c, + (u8 **)&delta_swing_table_idx_tup_d, (u8 **)&delta_swing_table_idx_tdown_d); + + if (p_dm_odm->support_ic_type & (ODM_RTL8703B | ODM_RTL8723D)) /*for Xtal Offset*/ + (*c.get_delta_swing_xtal_table)(p_dm_odm, (s8 **)&delta_swing_table_xtal_up, (s8 **)&delta_swing_table_xtal_down); + + + p_rf_calibrate_info->txpowertracking_callback_cnt++; /*cosa add for debug*/ + p_rf_calibrate_info->is_txpowertracking_init = true; + + /*p_rf_calibrate_info->txpowertrack_control = p_hal_data->txpowertrack_control; + <Kordan> We should keep updating the control variable according to HalData. + <Kordan> rf_calibrate_info.rega24 will be initialized when ODM HW configuring, but MP configures with para files. */ +#if (DM_ODM_SUPPORT_TYPE & ODM_WIN) +#if (MP_DRIVER == 1) + p_rf_calibrate_info->rega24 = 0x090e1317; +#endif +#elif (DM_ODM_SUPPORT_TYPE & ODM_CE) + if (p_dm_odm->mp_mode == true) + p_rf_calibrate_info->rega24 = 0x090e1317; +#endif + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("===>odm_txpowertracking_callback_thermal_meter\n p_rf_calibrate_info->bb_swing_idx_cck_base: %d, p_rf_calibrate_info->bb_swing_idx_ofdm_base[A]: %d, p_rf_calibrate_info->default_ofdm_index: %d\n", + p_rf_calibrate_info->bb_swing_idx_cck_base, p_rf_calibrate_info->bb_swing_idx_ofdm_base[ODM_RF_PATH_A], p_rf_calibrate_info->default_ofdm_index)); + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("p_rf_calibrate_info->txpowertrack_control=%d, p_hal_data->eeprom_thermal_meter %d\n", p_rf_calibrate_info->txpowertrack_control, p_hal_data->eeprom_thermal_meter)); + thermal_value = (u8)odm_get_rf_reg(p_dm_odm, ODM_RF_PATH_A, c.thermal_reg_addr, 0xfc00); /* 0x42: RF Reg[15:10] 88E */ + + /*add log by zhao he, check c80/c94/c14/ca0 value*/ + if (p_dm_odm->support_ic_type == ODM_RTL8723D) { + regc80 = odm_get_bb_reg(p_dm_odm, 0xc80, MASKDWORD); + regcd0 = odm_get_bb_reg(p_dm_odm, 0xcd0, MASKDWORD); + regcd4 = odm_get_bb_reg(p_dm_odm, 0xcd4, MASKDWORD); + regab4 = odm_get_bb_reg(p_dm_odm, 0xab4, 0x000007FF); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD, ("0xc80 = 0x%x 0xcd0 = 0x%x 0xcd4 = 0x%x 0xab4 = 0x%x\n", regc80, regcd0, regcd4, regab4)); + } + + if (!p_rf_calibrate_info->txpowertrack_control) + return; + + + /*4 3. Initialize ThermalValues of rf_calibrate_info*/ + + if (p_rf_calibrate_info->is_reloadtxpowerindex) + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("reload ofdm index for band switch\n")); + + /*4 4. Calculate average thermal meter*/ + + p_rf_calibrate_info->thermal_value_avg[p_rf_calibrate_info->thermal_value_avg_index] = thermal_value; + p_rf_calibrate_info->thermal_value_avg_index++; + if (p_rf_calibrate_info->thermal_value_avg_index == c.average_thermal_num) /*Average times = c.average_thermal_num*/ + p_rf_calibrate_info->thermal_value_avg_index = 0; + + for (i = 0; i < c.average_thermal_num; i++) { + if (p_rf_calibrate_info->thermal_value_avg[i]) { + thermal_value_avg += p_rf_calibrate_info->thermal_value_avg[i]; + thermal_value_avg_count++; + } + } + + if (thermal_value_avg_count) { /* Calculate Average thermal_value after average enough times */ + thermal_value = (u8)(thermal_value_avg / thermal_value_avg_count); + p_rf_calibrate_info->thermal_value_delta = thermal_value - p_hal_data->eeprom_thermal_meter; + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("AVG Thermal Meter = 0x%X, EFUSE Thermal base = 0x%X\n", thermal_value, p_hal_data->eeprom_thermal_meter)); + } + + /* 4 5. Calculate delta, delta_LCK, delta_IQK. */ + + /* "delta" here is used to determine whether thermal value changes or not. */ + delta = (thermal_value > p_rf_calibrate_info->thermal_value) ? (thermal_value - p_rf_calibrate_info->thermal_value) : (p_rf_calibrate_info->thermal_value - thermal_value); + delta_LCK = (thermal_value > p_rf_calibrate_info->thermal_value_lck) ? (thermal_value - p_rf_calibrate_info->thermal_value_lck) : (p_rf_calibrate_info->thermal_value_lck - thermal_value); + delta_IQK = (thermal_value > p_rf_calibrate_info->thermal_value_iqk) ? (thermal_value - p_rf_calibrate_info->thermal_value_iqk) : (p_rf_calibrate_info->thermal_value_iqk - thermal_value); + + if (p_rf_calibrate_info->thermal_value_iqk == 0xff) { /*no PG, use thermal value for IQK*/ + p_rf_calibrate_info->thermal_value_iqk = thermal_value; + delta_IQK = (thermal_value > p_rf_calibrate_info->thermal_value_iqk) ? (thermal_value - p_rf_calibrate_info->thermal_value_iqk) : (p_rf_calibrate_info->thermal_value_iqk - thermal_value); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("no PG, use thermal_value for IQK\n")); + } + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + diff_DPK[p] = (s8)thermal_value - (s8)p_rf_calibrate_info->dpk_thermal[p]; + + /*4 6. If necessary, do LCK.*/ + + if (!(p_dm_odm->support_ic_type & ODM_RTL8821)) { /*no PG, do LCK at initial status*/ + if (p_rf_calibrate_info->thermal_value_lck == 0xff) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("no PG, do LCK\n")); + p_rf_calibrate_info->thermal_value_lck = thermal_value; + + /*Use RTLCK, so close power tracking driver LCK*/ + if (!(p_dm_odm->support_ic_type & ODM_RTL8814A)) { + if (c.phy_lc_calibrate) + (*c.phy_lc_calibrate)(p_dm_odm); + } + + delta_LCK = (thermal_value > p_rf_calibrate_info->thermal_value_lck) ? (thermal_value - p_rf_calibrate_info->thermal_value_lck) : (p_rf_calibrate_info->thermal_value_lck - thermal_value); + } + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("(delta, delta_LCK, delta_IQK) = (%d, %d, %d)\n", delta, delta_LCK, delta_IQK)); + + /* Delta temperature is equal to or larger than 20 centigrade.*/ + if (delta_LCK >= c.threshold_iqk) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("delta_LCK(%d) >= threshold_iqk(%d)\n", delta_LCK, c.threshold_iqk)); + p_rf_calibrate_info->thermal_value_lck = thermal_value; + + /*Use RTLCK, so close power tracking driver LCK*/ + if (!(p_dm_odm->support_ic_type & ODM_RTL8814A)) { + if (c.phy_lc_calibrate) + (*c.phy_lc_calibrate)(p_dm_odm); + } + } + } + + /*3 7. If necessary, move the index of swing table to adjust Tx power.*/ + + if (delta > 0 && p_rf_calibrate_info->txpowertrack_control) { + /* "delta" here is used to record the absolute value of differrence. */ +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) + delta = thermal_value > p_hal_data->eeprom_thermal_meter ? (thermal_value - p_hal_data->eeprom_thermal_meter) : (p_hal_data->eeprom_thermal_meter - thermal_value); +#else + delta = (thermal_value > p_dm_odm->priv->pmib->dot11RFEntry.ther) ? (thermal_value - p_dm_odm->priv->pmib->dot11RFEntry.ther) : (p_dm_odm->priv->pmib->dot11RFEntry.ther - thermal_value); +#endif + if (delta >= TXPWR_TRACK_TABLE_SIZE) + delta = TXPWR_TRACK_TABLE_SIZE - 1; + + /*4 7.1 The Final Power index = BaseIndex + power_index_offset*/ + +#if (DM_ODM_SUPPORT_TYPE & (ODM_WIN | ODM_CE)) + if (thermal_value > p_hal_data->eeprom_thermal_meter) { +#else + if (thermal_value > p_dm_odm->priv->pmib->dot11RFEntry.ther) { +#endif + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + p_rf_calibrate_info->delta_power_index_last[p] = p_rf_calibrate_info->delta_power_index[p]; /*recording poer index offset*/ + switch (p) { + case ODM_RF_PATH_B: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_b[%d] = %d\n", delta, delta_swing_table_idx_tup_b[delta])); + + p_rf_calibrate_info->delta_power_index[p] = delta_swing_table_idx_tup_b[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_b[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_B] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + case ODM_RF_PATH_C: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_c[%d] = %d\n", delta, delta_swing_table_idx_tup_c[delta])); + + p_rf_calibrate_info->delta_power_index[p] = delta_swing_table_idx_tup_c[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_c[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_C] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + case ODM_RF_PATH_D: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_d[%d] = %d\n", delta, delta_swing_table_idx_tup_d[delta])); + + p_rf_calibrate_info->delta_power_index[p] = delta_swing_table_idx_tup_d[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_d[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_D] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + default: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tup_a[%d] = %d\n", delta, delta_swing_table_idx_tup_a[delta])); + + p_rf_calibrate_info->delta_power_index[p] = delta_swing_table_idx_tup_a[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = delta_swing_table_idx_tup_a[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is higher and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_A] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + } + } + + if (p_dm_odm->support_ic_type & (ODM_RTL8703B | ODM_RTL8723D)) { + /*Save xtal_offset from Xtal table*/ + p_rf_calibrate_info->xtal_offset_last = p_rf_calibrate_info->xtal_offset; /*recording last Xtal offset*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("[Xtal] delta_swing_table_xtal_up[%d] = %d\n", delta, delta_swing_table_xtal_up[delta])); + p_rf_calibrate_info->xtal_offset = delta_swing_table_xtal_up[delta]; + + if (p_rf_calibrate_info->xtal_offset_last == p_rf_calibrate_info->xtal_offset) + xtal_offset_eanble = 0; + else + xtal_offset_eanble = 1; + } + + } else { + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + p_rf_calibrate_info->delta_power_index_last[p] = p_rf_calibrate_info->delta_power_index[p]; /*recording poer index offset*/ + + switch (p) { + case ODM_RF_PATH_B: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_b[%d] = %d\n", delta, delta_swing_table_idx_tdown_b[delta])); + p_rf_calibrate_info->delta_power_index[p] = -1 * delta_swing_table_idx_tdown_b[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_b[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_B] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + case ODM_RF_PATH_C: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_c[%d] = %d\n", delta, delta_swing_table_idx_tdown_c[delta])); + p_rf_calibrate_info->delta_power_index[p] = -1 * delta_swing_table_idx_tdown_c[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_c[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_C] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + case ODM_RF_PATH_D: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_d[%d] = %d\n", delta, delta_swing_table_idx_tdown_d[delta])); + p_rf_calibrate_info->delta_power_index[p] = -1 * delta_swing_table_idx_tdown_d[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_d[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_D] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + + default: + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("delta_swing_table_idx_tdown_a[%d] = %d\n", delta, delta_swing_table_idx_tdown_a[delta])); + p_rf_calibrate_info->delta_power_index[p] = -1 * delta_swing_table_idx_tdown_a[delta]; + p_rf_calibrate_info->absolute_ofdm_swing_idx[p] = -1 * delta_swing_table_idx_tdown_a[delta]; /*Record delta swing for mix mode power tracking*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("******Temp is lower and p_rf_calibrate_info->absolute_ofdm_swing_idx[ODM_RF_PATH_A] = %d\n", p_rf_calibrate_info->absolute_ofdm_swing_idx[p])); + break; + } + } + + if (p_dm_odm->support_ic_type & (ODM_RTL8703B | ODM_RTL8723D)) { + /*Save xtal_offset from Xtal table*/ + p_rf_calibrate_info->xtal_offset_last = p_rf_calibrate_info->xtal_offset; /*recording last Xtal offset*/ + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("[Xtal] delta_swing_table_xtal_down[%d] = %d\n", delta, delta_swing_table_xtal_down[delta])); + p_rf_calibrate_info->xtal_offset = delta_swing_table_xtal_down[delta]; + + if (p_rf_calibrate_info->xtal_offset_last == p_rf_calibrate_info->xtal_offset) + xtal_offset_eanble = 0; + else + xtal_offset_eanble = 1; + } + + } + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("\n\n=========================== [path-%d] Calculating power_index_offset===========================\n", p)); + + if (p_rf_calibrate_info->delta_power_index[p] == p_rf_calibrate_info->delta_power_index_last[p]) /*If Thermal value changes but lookup table value still the same*/ + p_rf_calibrate_info->power_index_offset[p] = 0; + else + p_rf_calibrate_info->power_index_offset[p] = p_rf_calibrate_info->delta_power_index[p] - p_rf_calibrate_info->delta_power_index_last[p]; /*Power index diff between 2 times Power Tracking*/ + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("[path-%d] power_index_offset(%d) = delta_power_index(%d) - delta_power_index_last(%d)\n", p, p_rf_calibrate_info->power_index_offset[p], p_rf_calibrate_info->delta_power_index[p], p_rf_calibrate_info->delta_power_index_last[p])); + + p_rf_calibrate_info->OFDM_index[p] = p_rf_calibrate_info->bb_swing_idx_ofdm_base[p] + p_rf_calibrate_info->power_index_offset[p]; + p_rf_calibrate_info->CCK_index = p_rf_calibrate_info->bb_swing_idx_cck_base + p_rf_calibrate_info->power_index_offset[p]; + + p_rf_calibrate_info->bb_swing_idx_cck = p_rf_calibrate_info->CCK_index; + p_rf_calibrate_info->bb_swing_idx_ofdm[p] = p_rf_calibrate_info->OFDM_index[p]; + + /*************Print BB Swing base and index Offset*************/ + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("The 'CCK' final index(%d) = BaseIndex(%d) + power_index_offset(%d)\n", p_rf_calibrate_info->bb_swing_idx_cck, p_rf_calibrate_info->bb_swing_idx_cck_base, p_rf_calibrate_info->power_index_offset[p])); + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("The 'OFDM' final index(%d) = BaseIndex[%d](%d) + power_index_offset(%d)\n", p_rf_calibrate_info->bb_swing_idx_ofdm[p], p, p_rf_calibrate_info->bb_swing_idx_ofdm_base[p], p_rf_calibrate_info->power_index_offset[p])); + + /*4 7.1 Handle boundary conditions of index.*/ + + if (p_rf_calibrate_info->OFDM_index[p] > c.swing_table_size_ofdm - 1) + p_rf_calibrate_info->OFDM_index[p] = c.swing_table_size_ofdm - 1; + else if (p_rf_calibrate_info->OFDM_index[p] <= OFDM_min_index) + p_rf_calibrate_info->OFDM_index[p] = OFDM_min_index; + } + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("\n\n========================================================================================================\n")); + + if (p_rf_calibrate_info->CCK_index > c.swing_table_size_cck - 1) + p_rf_calibrate_info->CCK_index = c.swing_table_size_cck - 1; + else if (p_rf_calibrate_info->CCK_index <= 0) + p_rf_calibrate_info->CCK_index = 0; + } else { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("The thermal meter is unchanged or TxPowerTracking OFF(%d): thermal_value: %d, p_rf_calibrate_info->thermal_value: %d\n", + p_rf_calibrate_info->txpowertrack_control, thermal_value, p_rf_calibrate_info->thermal_value)); + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + p_rf_calibrate_info->power_index_offset[p] = 0; + } + + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("TxPowerTracking: [CCK] Swing Current index: %d, Swing base index: %d\n", + p_rf_calibrate_info->CCK_index, p_rf_calibrate_info->bb_swing_idx_cck_base)); /*Print Swing base & current*/ + + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("TxPowerTracking: [OFDM] Swing Current index: %d, Swing base index[%d]: %d\n", + p_rf_calibrate_info->OFDM_index[p], p, p_rf_calibrate_info->bb_swing_idx_ofdm_base[p])); + } + + if ((p_dm_odm->support_ic_type & ODM_RTL8814A)) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("power_tracking_type=%d\n", power_tracking_type)); + + if (power_tracking_type == 0) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking MIX_MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, MIX_MODE, p, 0); + } else if (power_tracking_type == 1) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking MIX(2G) TSSI(5G) MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, MIX_2G_TSSI_5G_MODE, p, 0); + } else if (power_tracking_type == 2) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking MIX(5G) TSSI(2G)MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, MIX_5G_TSSI_2G_MODE, p, 0); + } else if (power_tracking_type == 3) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, ("**********Enter POWER Tracking TSSI MODE**********\n")); + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) + (*c.odm_tx_pwr_track_set_pwr)(p_dm_odm, TSSI_MODE, p, 0); + } + p_rf_calibrate_info->thermal_value = thermal_value; /*Record last Power Tracking Thermal value*/ + + } else if ((p_rf_calibrate_info->power_index_offset[ODM_RF_PATH_A] != 0 || + p_rf_calibrate_info->power_index_offset[ODM_RF_PATH_B] != 0 || + p_rf_calibrate_info->power_index_offset[ODM_RF_PATH_C] != 0 || + p_rf_calibrate_info->power_index_offset[ODM_RF_PATH_D] != 0) && + p_rf_calibrate_info->txpowertrack_control && (p_hal_data->eeprom_thermal_meter != 0xff)) { + /* 4 7.2 Configure the Swing Table to adjust Tx Power. */ + + p_rf_calibrate_info->is_tx_power_changed = true; /*Always true after Tx Power is adjusted by power tracking.*/ + /* */ + /* 2012/04/23 MH According to Luke's suggestion, we can not write BB digital */ + /* to increase TX power. Otherwise, EVM will be bad. */ + /* */ + /* 2012/04/25 MH Add for tx power tracking to set tx power in tx agc for 88E. */ + if (thermal_value > p_rf_calibrate_info->thermal_value) { + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature Increasing(%d): delta_pi: %d, delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + p, p_rf_calibrate_info->power_index_offset[p], delta, thermal_value, p_hal_data->eeprom_thermal_meter, p_rf_calibrate_info->thermal_value)); + } + } else if (thermal_value < p_rf_calibrate_info->thermal_value) { /*Low temperature*/ + for (p = ODM_RF_PATH_A; p < c.rf_path_count; p++) { + ODM_RT_TRACE(p_dm_odm, ODM_COMP_TX_PWR_TRACK, ODM_DBG_LOUD, + ("Temperature Decreasing(%d): delta_pi: %d, delta_t: %d, Now_t: %d, EFUSE_t: %d, Last_t: %d\n", + p, p_rf_calibrate_info->power_index_offset[p], delta, thermal_value, p_hal_data->eeprom_thermal_meter, p_rf_calibrate_info->thermal_value)); + } + } + +#if !(DM_ODM_SUPPORT_TYPE &